Ejemplo n.º 1
0
    def __init__(self):
        super().__init__()

        self.set_orientation(Gtk.Orientation.VERTICAL)
        self.set_valign(Gtk.Align.FILL)
        self.set_halign(Gtk.Align.FILL)
        self.set_vexpand(True)
        self.set_hexpand(True)
        self.set_name('ItemsViewBox')

        self._bound_history = None
        self._last_entered_item = None
        self._last_selected_index = None
        self._show_index = None
        self._autoscroll_timeout_id = 0

        self._histories_manager = HistoriesManager()

        placeholder = Gtk.Label()
        placeholder.set_markup('<span font-size="xx-large">%s</span>' %
                               _('Nothing'))
        placeholder.show()

        self._listbox = Gtk.ListBox()
        self._listbox.set_name('ItemsViewList')
        self._listbox.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
        self._listbox.set_activate_on_single_click(False)
        self._listbox.set_placeholder(placeholder)
        self._listbox.connect('row-selected', self._on_row_selected)
        self._listbox.connect('row-activated', self._on_row_activated)
        self._listbox.connect('motion-notify-event', self._on_motion_event)
        self._listbox.connect('leave-notify-event', self._on_leave_event)
        self._listbox.connect('button-press-event',
                              self._on_button_press_event)
        self._listbox.connect('button-release-event',
                              self._on_button_release_event)

        self._items_counter = ItemsCounter(self._listbox)
        self._load_rest_btn = Gtk.LinkButton()
        self._load_rest_btn.set_label('load all history')
        self._load_rest_btn.set_no_show_all(True)
        self._load_rest_btn.connect('activate-link',
                                    lambda _: self.load_rest_items())
        self._load_rest_btn.hide()

        scrolled = Gtk.ScrolledWindow()
        scrolled.set_name('ItemsViewScrolledWindow')
        scrolled.set_vexpand(True)
        scrolled.set_hexpand(True)
        scrolled.add(self._listbox)

        bottom_box = Gtk.Box()
        bottom_box.set_orientation(Gtk.Orientation.HORIZONTAL)
        bottom_box.add(self._items_counter)
        bottom_box.add(self._load_rest_btn)
        bottom_box.add(self._histories_manager)

        box = Gtk.Box()
        box.set_orientation(Gtk.Orientation.VERTICAL)
        box.add(scrolled)
        box.add(bottom_box)

        self.add(box)
        self.show_all()
Ejemplo n.º 2
0
    def __init__(self):
        super().__init__()

        self.set_orientation(Gtk.Orientation.VERTICAL)
        self.set_valign(Gtk.Align.FILL)
        self.set_halign(Gtk.Align.FILL)
        self.set_vexpand(True)
        self.set_hexpand(True)
        self.set_name('ItemsViewBox')

        self._bound_history = None
        self._last_entered_item = None
        self._last_selected_index = None
        self._show_index = None
        self._autoscroll_timeout_id = 0

        self._histories_manager = HistoriesManager()

        placeholder = Gtk.Label()
        placeholder.set_markup(
            '<span font-size="xx-large">%s</span>' % _('Nothing')
        )
        placeholder.show()

        self._listbox = Gtk.ListBox()
        self._listbox.set_name('ItemsViewList')
        self._listbox.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
        self._listbox.set_activate_on_single_click(False)
        self._listbox.set_placeholder(placeholder)
        self._listbox.connect('row-selected', self._on_row_selected)
        self._listbox.connect('row-activated', self._on_row_activated)
        self._listbox.connect('motion-notify-event', self._on_motion_event)
        self._listbox.connect('leave-notify-event', self._on_leave_event)
        self._listbox.connect('button-press-event', self._on_button_press_event)
        self._listbox.connect('button-release-event', self._on_button_release_event)

        self._items_counter = ItemsCounter(self._listbox)
        self._load_rest_btn = Gtk.LinkButton()
        self._load_rest_btn.set_label('load all history')
        self._load_rest_btn.set_no_show_all(True)
        self._load_rest_btn.connect(
            'activate-link',
            lambda _: self.load_rest_items()
        )
        self._load_rest_btn.hide()

        scrolled = Gtk.ScrolledWindow()
        scrolled.set_name('ItemsViewScrolledWindow')
        scrolled.set_vexpand(True)
        scrolled.set_hexpand(True)
        scrolled.add(self._listbox)

        bottom_box = Gtk.Box()
        bottom_box.set_orientation(Gtk.Orientation.HORIZONTAL)
        bottom_box.add(self._items_counter)
        bottom_box.add(self._load_rest_btn)
        bottom_box.add(self._histories_manager)

        box = Gtk.Box()
        box.set_orientation(Gtk.Orientation.VERTICAL)
        box.add(scrolled)
        box.add(bottom_box)

        self.add(box)
        self.show_all()
Ejemplo n.º 3
0
class ItemsView(Gtk.Box):

    AUTOSCROLL_BORDER_OFFSET = 100
    AUTOSCROLL_TIMEOUT_MS = 50
    AUTOSCROLL_STEP = 10

    __gsignals__ = {
        'item-activated': (GObject.SIGNAL_RUN_FIRST, None, (object, )),
        'item-selected': (GObject.SIGNAL_RUN_FIRST, None, (object, )),
        'item-entered': (GObject.SIGNAL_RUN_FIRST, None, (object, )),
        'item-left': (GObject.SIGNAL_RUN_FIRST, None, (object, ))
    }

    def __init__(self):
        super().__init__()

        self.set_orientation(Gtk.Orientation.VERTICAL)
        self.set_valign(Gtk.Align.FILL)
        self.set_halign(Gtk.Align.FILL)
        self.set_vexpand(True)
        self.set_hexpand(True)
        self.set_name('ItemsViewBox')

        self._bound_history = None
        self._last_entered_item = None
        self._last_selected_index = None
        self._show_index = None
        self._autoscroll_timeout_id = 0

        self._histories_manager = HistoriesManager()

        placeholder = Gtk.Label()
        placeholder.set_markup('<span font-size="xx-large">%s</span>' %
                               _('Nothing'))
        placeholder.show()

        self._listbox = Gtk.ListBox()
        self._listbox.set_name('ItemsViewList')
        self._listbox.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
        self._listbox.set_activate_on_single_click(False)
        self._listbox.set_placeholder(placeholder)
        self._listbox.connect('row-selected', self._on_row_selected)
        self._listbox.connect('row-activated', self._on_row_activated)
        self._listbox.connect('motion-notify-event', self._on_motion_event)
        self._listbox.connect('leave-notify-event', self._on_leave_event)
        self._listbox.connect('button-press-event',
                              self._on_button_press_event)
        self._listbox.connect('button-release-event',
                              self._on_button_release_event)

        self._items_counter = ItemsCounter(self._listbox)
        self._load_rest_btn = Gtk.LinkButton()
        self._load_rest_btn.set_label('load all history')
        self._load_rest_btn.set_no_show_all(True)
        self._load_rest_btn.connect('activate-link',
                                    lambda _: self.load_rest_items())
        self._load_rest_btn.hide()

        scrolled = Gtk.ScrolledWindow()
        scrolled.set_name('ItemsViewScrolledWindow')
        scrolled.set_vexpand(True)
        scrolled.set_hexpand(True)
        scrolled.add(self._listbox)

        bottom_box = Gtk.Box()
        bottom_box.set_orientation(Gtk.Orientation.HORIZONTAL)
        bottom_box.add(self._items_counter)
        bottom_box.add(self._load_rest_btn)
        bottom_box.add(self._histories_manager)

        box = Gtk.Box()
        box.set_orientation(Gtk.Orientation.VERTICAL)
        box.add(scrolled)
        box.add(bottom_box)

        self.add(box)
        self.show_all()

    def __len__(self):
        return len(self._listbox.get_children())

    def _on_leave_event(self, listbox, event):
        if self._last_entered_item:
            self.emit('item-left', self._last_entered_item)
            self._last_entered_item = None

    def _on_motion_event(self, listbox, event):
        def do_autoscroll_and_selection():
            adjustment = self._listbox.get_adjustment()
            new_value = adjustment.get_value() + ItemsView.AUTOSCROLL_STEP
            adjustment.set_value(new_value)
            row = self._listbox.get_row_at_y(new_value +
                                             adjustment.get_page_increment())
            if not row.is_selected(): self._listbox.select_row(row)

            return True

        def maybe_toggle_selection(row):
            if event.state == Gdk.ModifierType.BUTTON3_MASK:
                self.toggle_selection(row)

        if event.state == Gdk.ModifierType.BUTTON3_MASK:
            adjustment = self._listbox.get_adjustment()
            autoscroll_border = (adjustment.get_value() +
                                 adjustment.get_page_increment() -
                                 ItemsView.AUTOSCROLL_BORDER_OFFSET)
            if event.y > autoscroll_border:
                if not self._autoscroll_timeout_id:
                    self._autoscroll_timeout_id = GLib.timeout_add(
                        ItemsView.AUTOSCROLL_TIMEOUT_MS,
                        do_autoscroll_and_selection)
            elif event.y < autoscroll_border and self._autoscroll_timeout_id:
                GLib.source_remove(self._autoscroll_timeout_id)
                self._autoscroll_timeout_id = 0

        row = self._listbox.get_row_at_y(event.y)

        if row:
            item = row.get_child().item

            if not self._last_entered_item:
                self._last_entered_item = item
                maybe_toggle_selection(row)
                self.emit('item-entered', item)
            elif self._last_entered_item != item:
                maybe_toggle_selection(row)
                self.emit('item-left', self._last_entered_item)
                self.emit('item-entered', item)
                self._last_entered_item = item
        elif self._last_entered_item:
            self.emit('item-left', self._last_entered_item)
            self._last_entered_item = None

    def _on_button_press_event(self, listbox, event):
        row = self._listbox.get_row_at_y(event.y)
        if not row or event.button != 3: return
        self.toggle_selection(row)

    def _on_button_release_event(self, listbox, event):
        if self._autoscroll_timeout_id:
            GLib.source_remove(self._autoscroll_timeout_id)
            self._autoscroll_timeout_id = 0

    def _on_row_selected(self, listbox, row):
        if row: self.emit('item-selected', row.get_child().item)

    def _on_row_activated(self, listbox, row):
        if not row: return
        item = row.get_child().item
        if item: self.activate_item(item)

    def _on_changed(self, history_items):
        self.show_items()
        self.set_active_item()
        self.resume_selection() or self.select_first()
        self._last_selected_index = 0

    def _remove(self, history_items, item=None):
        self.save_selection()
        result = False
        if not item: return result

        row = self._get_row_for_item(item)
        if row:
            row.remove(row.get_child())
            row.destroy()
            result = True

        return result

    def _get_row_for_item(self, item):
        result = False

        for row in self._listbox.get_children():
            if row.get_child().item == item:
                result = row
                break

        return result

    def save_selection(self):
        def get_current_index(child):
            result = None

            for i, ch in enumerate(self._listbox.get_children()):
                if ch != child: continue
                result = i
                break

            return result

        selected_row = self._listbox.get_selected_rows()

        try:
            selected_row = selected_row[0]
        except IndexError:
            return

        self._last_selected_index = get_current_index(selected_row)

    def resume_selection(self):
        if not self._last_selected_index: return False
        children = self._listbox.get_children()

        if len(children) == self._last_selected_index:
            self._last_selected_index -= 1

        for i, row in enumerate(children):
            if i == self._last_selected_index:
                self._listbox.select_row(row)
                # i'm sorry
                GLib.timeout_add(200, lambda *a, **ka: row.grab_focus())
                break

        return True

    def bind(self, history_items):
        if self._bound_history:
            raise AlreadyBound()

        self._bound_history = history_items
        self._bound_history.connect('changed', self._on_changed)
        self._bound_history.connect('removed', self._remove)
        self._items_counter.set_history_items(self._bound_history)
        self._items_counter.update()

        self.show_items()

    def show_items(self):
        limit = common.SETTINGS[common.ITEMS_VIEW_LIMIT]
        items = self._bound_history
        if limit: items = items[:limit]
        self.clear()

        for item in items:
            self._listbox.add(item.widget)

        if len(items) < len(self._bound_history):
            self._load_rest_btn.show()
        else:
            self._load_rest_btn.hide()

        self.show_all()

    def load_rest_items(self):
        limit = common.SETTINGS[common.ITEMS_VIEW_LIMIT]
        if not limit: return

        for item in self._bound_history[limit:]:
            self._listbox.add(item.widget)

        self._load_rest_btn.hide()
        self.show_all()
        return True

    def set_active_item(self):
        def on_clipboard(clipboard, text):
            for row in self._listbox.get_children():
                item_widget = row.get_child()
                item = item_widget.item

                if item.raw != text:
                    row.set_activatable(True)
                    item_widget.set_sensitive(True)
                    item_widget.set_active(False)
                else:
                    row.set_activatable(False)
                    item_widget.set_active(True)

        if len(self) < 1: return

        clipboard = Gtk.Clipboard.get_default(Gdk.Display.get_default())
        text = clipboard.wait_for_text()
        on_clipboard(clipboard, text)

    def select_first(self, grab_focus=False):
        self._listbox.unselect_all()
        self.set_active_item()

        for row in self._listbox.get_children():
            if not row.get_activatable() or not row.get_mapped(): continue

            self._listbox.select_row(row)
            if grab_focus: row.grab_focus()
            break

        self.reset_scroll()

    def get_selected(self):
        result = []
        rows = self._listbox.get_selected_rows()

        for row in rows:
            result.append(row.get_child().item)

        return result

    def clear(self):
        self._listbox.unselect_all()

        if self._autoscroll_timeout_id:
            GLib.source_remove(self._autoscroll_timeout_id)
            self._autoscroll_timeout_id = 0

        for row in self._listbox.get_children():
            child = row.get_child()
            if child: row.remove(child)
            row.destroy()

    def reset_scroll(self):
        adjustment = self._listbox.get_adjustment()
        lower = adjustment.get_lower()
        adjustment.set_value(lower)

    def toggle_selection(self, row):
        if row.is_selected(): self._listbox.unselect_row(row)
        else: self._listbox.select_row(row)

    def activate_item(self, item):
        if item: self.emit('item-activated', item)

    def get_by_number(self, number):
        result = None
        curr_index = None
        children = self._listbox.get_children()

        for index, row in enumerate(children):
            visible = utils.is_visible_on_scroll(
                self._listbox.get_adjustment(), row)

            if visible:
                if curr_index is None:
                    curr_index = 0
                else:
                    curr_index += 1

            if not curr_index is None and curr_index == number:
                result = row.get_child().item
                break

        return result

    def show_shortcut_hints(self, show):
        curr_index = None
        children = self._listbox.get_children()

        if show:
            for index, row in enumerate(children):
                visible = utils.is_visible_on_scroll(
                    self._listbox.get_adjustment(), row)

                if visible:
                    if curr_index is None:
                        curr_index = 0
                    else:
                        curr_index += 1

                    row.get_child().show_shortcut_hint(curr_index + 1)
        else:
            for row in children:
                row.get_child().show_shortcut_hint(None)

    @property
    def histories_manager(self):
        return self._histories_manager

    @property
    def listbox(self):
        return self._listbox

    @property
    def n_selected(self):
        selected = self.get_selected()
        return len(selected)
Ejemplo n.º 4
0
class ItemsView(Gtk.Box):

    AUTOSCROLL_BORDER_OFFSET = 100
    AUTOSCROLL_TIMEOUT_MS = 50
    AUTOSCROLL_STEP = 10

    __gsignals__ = {
        'item-activated': (GObject.SIGNAL_RUN_FIRST, None, (object,)),
        'item-selected': (GObject.SIGNAL_RUN_FIRST, None, (object,)),
        'item-entered': (GObject.SIGNAL_RUN_FIRST, None, (object,)),
        'item-left': (GObject.SIGNAL_RUN_FIRST, None, (object,))
    }

    def __init__(self):
        super().__init__()

        self.set_orientation(Gtk.Orientation.VERTICAL)
        self.set_valign(Gtk.Align.FILL)
        self.set_halign(Gtk.Align.FILL)
        self.set_vexpand(True)
        self.set_hexpand(True)
        self.set_name('ItemsViewBox')

        self._bound_history = None
        self._last_entered_item = None
        self._last_selected_index = None
        self._show_index = None
        self._autoscroll_timeout_id = 0

        self._histories_manager = HistoriesManager()

        placeholder = Gtk.Label()
        placeholder.set_markup(
            '<span font-size="xx-large">%s</span>' % _('Nothing')
        )
        placeholder.show()

        self._listbox = Gtk.ListBox()
        self._listbox.set_name('ItemsViewList')
        self._listbox.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
        self._listbox.set_activate_on_single_click(False)
        self._listbox.set_placeholder(placeholder)
        self._listbox.connect('row-selected', self._on_row_selected)
        self._listbox.connect('row-activated', self._on_row_activated)
        self._listbox.connect('motion-notify-event', self._on_motion_event)
        self._listbox.connect('leave-notify-event', self._on_leave_event)
        self._listbox.connect('button-press-event', self._on_button_press_event)
        self._listbox.connect('button-release-event', self._on_button_release_event)

        self._items_counter = ItemsCounter(self._listbox)
        self._load_rest_btn = Gtk.LinkButton()
        self._load_rest_btn.set_label('load all history')
        self._load_rest_btn.set_no_show_all(True)
        self._load_rest_btn.connect(
            'activate-link',
            lambda _: self.load_rest_items()
        )
        self._load_rest_btn.hide()

        scrolled = Gtk.ScrolledWindow()
        scrolled.set_name('ItemsViewScrolledWindow')
        scrolled.set_vexpand(True)
        scrolled.set_hexpand(True)
        scrolled.add(self._listbox)

        bottom_box = Gtk.Box()
        bottom_box.set_orientation(Gtk.Orientation.HORIZONTAL)
        bottom_box.add(self._items_counter)
        bottom_box.add(self._load_rest_btn)
        bottom_box.add(self._histories_manager)

        box = Gtk.Box()
        box.set_orientation(Gtk.Orientation.VERTICAL)
        box.add(scrolled)
        box.add(bottom_box)

        self.add(box)
        self.show_all()

    def __len__(self):
        return len(self._listbox.get_children())

    def _on_leave_event(self, listbox, event):
        if self._last_entered_item:
            self.emit('item-left', self._last_entered_item)
            self._last_entered_item = None

    def _on_motion_event(self, listbox, event):

        def do_autoscroll_and_selection():
            adjustment = self._listbox.get_adjustment()
            new_value = adjustment.get_value() + ItemsView.AUTOSCROLL_STEP
            adjustment.set_value(new_value)
            row = self._listbox.get_row_at_y(
                new_value + adjustment.get_page_increment()
            )
            if not row.is_selected(): self._listbox.select_row(row)

            return True

        def maybe_toggle_selection(row):
            if event.state == Gdk.ModifierType.BUTTON3_MASK:
                self.toggle_selection(row)

        if event.state == Gdk.ModifierType.BUTTON3_MASK:
            adjustment = self._listbox.get_adjustment()
            autoscroll_border = (
                adjustment.get_value() +
                adjustment.get_page_increment() -
                ItemsView.AUTOSCROLL_BORDER_OFFSET
            )
            if event.y > autoscroll_border:
                if not self._autoscroll_timeout_id:
                    self._autoscroll_timeout_id = GLib.timeout_add(
                        ItemsView.AUTOSCROLL_TIMEOUT_MS,
                        do_autoscroll_and_selection
                    )
            elif event.y < autoscroll_border and self._autoscroll_timeout_id:
                GLib.source_remove(self._autoscroll_timeout_id)
                self._autoscroll_timeout_id = 0

        row = self._listbox.get_row_at_y(event.y)
        
        if row:
            item = row.get_child().item

            if not self._last_entered_item:
                self._last_entered_item = item
                maybe_toggle_selection(row)
                self.emit('item-entered', item)
            elif self._last_entered_item != item:
                maybe_toggle_selection(row)
                self.emit('item-left', self._last_entered_item)
                self.emit('item-entered', item)
                self._last_entered_item = item
        elif self._last_entered_item:
            self.emit('item-left', self._last_entered_item)
            self._last_entered_item = None

    def _on_button_press_event(self, listbox, event):
        row = self._listbox.get_row_at_y(event.y)
        if not row or event.button != 3: return
        self.toggle_selection(row)

    def _on_button_release_event(self, listbox, event):
        if self._autoscroll_timeout_id:
            GLib.source_remove(self._autoscroll_timeout_id)
            self._autoscroll_timeout_id = 0

    def _on_row_selected(self, listbox, row):
        if row: self.emit('item-selected', row.get_child().item)

    def _on_row_activated(self, listbox, row):
        if not row: return
        item = row.get_child().item
        if item: self.activate_item(item)

    def _on_changed(self, history_items):
        self.show_items()
        self.set_active_item()
        self.resume_selection() or self.select_first()
        self._last_selected_index = 0

    def _remove(self, history_items, item=None):
        self.save_selection()
        result = False
        if not item: return result

        row = self._get_row_for_item(item)
        if row:
            row.remove(row.get_child())
            row.destroy()
            result = True

        return result

    def _get_row_for_item(self, item):
        result = False

        for row in self._listbox.get_children():
            if row.get_child().item == item:
                result = row
                break

        return result

    def save_selection(self):

        def get_current_index(child):
            result = None

            for i, ch in enumerate(self._listbox.get_children()):
                if ch != child: continue
                result = i
                break

            return result

        selected_row = self._listbox.get_selected_rows()

        try:
            selected_row = selected_row[0]
        except IndexError:
            return

        self._last_selected_index = get_current_index(selected_row)

    def resume_selection(self):
        if not self._last_selected_index: return False
        children = self._listbox.get_children()

        if len(children) == self._last_selected_index:
            self._last_selected_index -= 1

        for i, row in enumerate(children):
            if i == self._last_selected_index:
                self._listbox.select_row(row)
                # i'm sorry
                GLib.timeout_add(200, lambda *a, **ka: row.grab_focus())
                break

        return True

    def bind(self, history_items):
        if self._bound_history:
            raise AlreadyBound()

        self._bound_history = history_items
        self._bound_history.connect('changed', self._on_changed)
        self._bound_history.connect('removed', self._remove)
        self._items_counter.set_history_items(self._bound_history)
        self._items_counter.update()

        self.show_items()

    def show_items(self):
        limit = common.SETTINGS[common.ITEMS_VIEW_LIMIT]
        items = self._bound_history
        if limit: items = items[:limit]
        self.clear()

        for item in items:
            self._listbox.add(item.widget)

        if len(items) < len(self._bound_history): 
            self._load_rest_btn.show()
        else:
            self._load_rest_btn.hide()

        self.show_all()

    def load_rest_items(self):
        limit = common.SETTINGS[common.ITEMS_VIEW_LIMIT]
        if not limit: return

        for item in self._bound_history[limit:]:
            self._listbox.add(item.widget)

        self._load_rest_btn.hide()
        self.show_all()
        return True

    def set_active_item(self):

        def on_clipboard(clipboard, text):
            for row in self._listbox.get_children():
                item_widget = row.get_child()
                item = item_widget.item

                if item.raw != text:
                    row.set_activatable(True)
                    item_widget.set_sensitive(True)
                    item_widget.set_active(False)
                else:
                    row.set_activatable(False)
                    item_widget.set_active(True)

        if len(self) < 1: return

        clipboard = Gtk.Clipboard.get_default(Gdk.Display.get_default())
        text = clipboard.wait_for_text()
        on_clipboard(clipboard, text)

    def select_first(self, grab_focus=False):
        self._listbox.unselect_all()
        self.set_active_item()

        for row in self._listbox.get_children():
            if not row.get_activatable() or not row.get_mapped(): continue

            self._listbox.select_row(row)
            if grab_focus: row.grab_focus()
            break

        self.reset_scroll()

    def get_selected(self):
        result = []
        rows = self._listbox.get_selected_rows()

        for row in rows:
            result.append(row.get_child().item)

        return result

    def clear(self):
        self._listbox.unselect_all()

        if self._autoscroll_timeout_id:
            GLib.source_remove(self._autoscroll_timeout_id)
            self._autoscroll_timeout_id = 0

        for row in self._listbox.get_children():
            child = row.get_child()
            if child: row.remove(child)
            row.destroy()

    def reset_scroll(self):
        adjustment = self._listbox.get_adjustment()
        lower = adjustment.get_lower()
        adjustment.set_value(lower)

    def toggle_selection(self, row):
        if row.is_selected(): self._listbox.unselect_row(row)
        else: self._listbox.select_row(row) 

    def activate_item(self, item):
        if item: self.emit('item-activated', item)

    def get_by_number(self, number):
        result = None
        curr_index = None
        children = self._listbox.get_children()

        for index, row in enumerate(children):
            visible = utils.is_visible_on_scroll(
                self._listbox.get_adjustment(),
                row
            )
            
            if visible:
                if curr_index is None:
                    curr_index = 0
                else:
                    curr_index += 1

            if not curr_index is None and curr_index == number:
                result = row.get_child().item
                break

        return result

    def show_shortcut_hints(self, show):
        curr_index = None
        children = self._listbox.get_children()

        if show:
            for index, row in enumerate(children):
                visible = utils.is_visible_on_scroll(
                    self._listbox.get_adjustment(),
                    row
                )
                
                if visible:
                    if curr_index is None:
                        curr_index = 0
                    else:
                        curr_index += 1

                    row.get_child().show_shortcut_hint(curr_index + 1)
        else:
            for row in children:
                row.get_child().show_shortcut_hint(None)

    @property
    def histories_manager(self):
        return self._histories_manager

    @property
    def listbox(self):
        return self._listbox

    @property
    def n_selected(self):
        selected = self.get_selected()
        return len(selected)