예제 #1
0
파일: comboentry.py 프로젝트: fuinha/kiwi
class _ComboEntryPopup(PopupWindow):

    FRAME_PADDING = (0, 0, 0, 0)

    gsignal('text-selected', str)

    def __init__(self, comboentry):
        self._comboentry = comboentry

        super(_ComboEntryPopup, self).__init__(comboentry)

        # Number of visible rows in the popup window, sensible
        # default value from other toolkits
        self._visible_rows = 10
        self._initial_text = None
        self._filter_model = None

    def get_main_widget(self):
        vbox = gtk.VBox()
        vbox.show()

        self._sw = gtk.ScrolledWindow()
        self._sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
        vbox.pack_start(self._sw)
        self._sw.show()

        self._model = gtk.ListStore(str)
        self._treeview = gtk.TreeView(self._model)
        self._treeview.set_enable_search(False)
        self._treeview.connect('motion-notify-event',
                               self._on_treeview__motion_notify_event)
        self._treeview.connect('button-release-event',
                               self._on_treeview__button_release_event)
        self._treeview.add_events(gdk.BUTTON_PRESS_MASK)
        self._selection = self._treeview.get_selection()
        self._selection.set_mode(gtk.SELECTION_BROWSE)
        self._renderer = ComboDetailsCellRenderer()
        self._treeview.append_column(
            gtk.TreeViewColumn('Foo', self._renderer,
                               label=0, data=1))
        self._treeview.set_headers_visible(False)
        self._sw.add(self._treeview)
        self._treeview.show()

        self._label = gtk.Label()

        return vbox

    def get_widget_for_popup(self):
        return self._comboentry.entry

    def popup(self, text=None, filter=False):
        """
        Shows the list of options. And optionally selects an item
        :param text: text to select
        :param filter: filter the list of options. A filter_model must be
        set using :class:`set_model`()
        """
        self.GRAB_WINDOW = not filter
        self.GRAB_ADD = not filter
        treeview = self._treeview

        if filter and self._filter_model:
            model = self._filter_model
        else:
            model = self._model

        if not len(model):
            return

        treeview.set_model(model)
        treeview.set_hover_expand(True)
        selection = treeview.get_selection()
        selection.unselect_all()
        if text:
            for row in model:
                if text in row:
                    selection.select_iter(row.iter)
                    treeview.scroll_to_cell(row.path, use_align=True,
                                            row_align=0.5)
                    treeview.set_cursor(row.path)
                    break

        popped = super(_ComboEntryPopup, self).popup()
        if not popped:
            return False

        treeview.set_size_request(-1, -1)
        if not filter:
            # Grab window
            self.grab_focus()
            if not self._treeview.has_focus():
                self._treeview.grab_focus()

        return True

    def set_label_text(self, text):
        if text is None:
            text = ''
            self._label.hide()
        else:
            self._label.show()
        self._label.set_text(text)

    def set_model(self, model):
        if isinstance(model, gtk.TreeModelFilter):
            self._filter_model = model
            model = model.get_model()

        self._treeview.set_model(model)
        self._model = model

    def confirm(self):
        model, treeiter = self._selection.get_selected()
        if treeiter:
            self.emit('text-selected', model[treeiter][0])

    def handle_key_press_event(self, event):
        if event.keyval == keysyms.Tab:
            self.popdown()
            # XXX: private member of comboentry
            self._comboentry._button.grab_focus()
            return True
        return False

    # Callbacks

    def _on_treeview__motion_notify_event(self, treeview, event):
        retval = treeview.get_path_at_pos(int(event.x),
                                          int(event.y))
        if not retval:
            return
        path, column, x, y = retval
        self._selection.select_path(path)
        self._treeview.set_cursor(path)

    def _on_treeview__button_release_event(self, treeview, event):
        retval = treeview.get_path_at_pos(int(event.x),
                                          int(event.y))
        if not retval:
            return
        path, column, x, y = retval

        model = treeview.get_model()
        self.emit('text-selected', model[path][0])

    def get_size(self, allocation, monitor):
        treeview = self._treeview
        treeview.realize()

        rows = len(self._treeview.get_model())
        if rows > self._visible_rows:
            rows = self._visible_rows
            self._sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        else:
            self._sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)

        cell_height = treeview.get_cell_area(0, treeview.get_column(0)).height
        height = cell_height * rows
        # Use half of the available screen space
        max_height = monitor.height / 2
        if height > max_height:
            height = int(max_height)
        elif height < 0:
            height = 0

        return allocation.width, height

    def get_selected_iter(self):
        model, treeiter = self._selection.get_selected()

        # if the model currently being used is a TreeModelFilter, convert
        # the iter to be a TreeModel iter (witch is what the user expects)
        if isinstance(model, gtk.TreeModelFilter) and treeiter:
            treeiter = model.convert_iter_to_child_iter(treeiter)
        return treeiter

    def set_selected_iter(self, treeiter):
        """
        Selects an item in the comboentry given a treeiter
        :param treeiter: the tree iter to select
        """
        model = self._treeview.get_model()

        # Since the user passed a TreeModel iter, if the model currently
        # being used is a TreeModelFilter, convert it to be a TreeModelFilter
        # iter
        if isinstance(model, gtk.TreeModelFilter):
            # See #3099 for an explanation why this is needed and a
            # testcase
            tmodel = model.get_model()
            if tmodel.iter_is_valid(treeiter):
                # revert back to the unfiltered model so we can select
                # the right object
                self._treeview.set_model(tmodel)
                self._selection = self._treeview.get_selection()
            else:
                treeiter = model.convert_child_iter_to_iter(treeiter)
        self._selection.select_iter(treeiter)

    def set_details_callback(self, callable):
        self._renderer.set_details_callback(callable)
예제 #2
0
class _ComboEntryPopup(gtk.Window):
    gsignal('text-selected', str)
    def __init__(self, comboentry):
        gtk.Window.__init__(self, gtk.WINDOW_POPUP)
        self.add_events(gdk.BUTTON_PRESS_MASK)
        self.connect('key-press-event', self._on__key_press_event)
        self.connect('button-press-event', self._on__button_press_event)
        self._comboentry = comboentry

        # Number of visible rows in the popup window, sensible
        # default value from other toolkits
        self._visible_rows = 10
        self._initial_text = None
        self._popping_up = False
        self._filter_model = None

        frame = gtk.Frame()
        frame.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
        self.add(frame)
        frame.show()

        vbox = gtk.VBox()
        frame.add(vbox)
        vbox.show()

        self._sw = gtk.ScrolledWindow()
        self._sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
        vbox.pack_start(self._sw)
        self._sw.show()

        self._model = gtk.ListStore(str)
        self._treeview = gtk.TreeView(self._model)
        self._treeview.set_enable_search(False)
        self._treeview.connect('motion-notify-event',
                               self._on_treeview__motion_notify_event)
        self._treeview.connect('button-release-event',
                               self._on_treeview__button_release_event)
        self._treeview.add_events(gdk.BUTTON_PRESS_MASK)
        self._selection = self._treeview.get_selection()
        self._selection.set_mode(gtk.SELECTION_BROWSE)
        self._renderer = ComboDetailsCellRenderer()
        self._treeview.append_column(
            gtk.TreeViewColumn('Foo', self._renderer,
                               label=0, data=1))
        self._treeview.set_headers_visible(False)
        self._sw.add(self._treeview)
        self._treeview.show()

        self._label = gtk.Label()
        vbox.pack_start(self._label, False, False)

        self.set_resizable(False)
        self.set_screen(comboentry.get_screen())

    def popup(self, text=None, filter=False):
        """
        Shows the list of options. And optionally selects an item
        @param text: text to select
        @param filter: filter the list of options. A filter_model must be
        set using L{set_model}()
        """
        combo = self._comboentry
        if not (combo.flags() & gtk.REALIZED):
            return

        treeview = self._treeview

        if filter and self._filter_model:
            model = self._filter_model
        else:
            model = self._model

        if not len(model):
            return

        treeview.set_model(model)

        toplevel = combo.get_toplevel()
        if isinstance(toplevel, gtk.Window) and toplevel.group:
            toplevel.group.add_window(self)

        # width is meant for the popup window
        # height is meant for the treeview, since it calculates using
        # the height of the cells on the rows
        x, y, width, height = self._get_position()
        self.set_size_request(width, -1)
        treeview.set_size_request(-1, height)
        self.move(x, y)
        self.show()

        treeview.set_hover_expand(True)
        selection = treeview.get_selection()
        selection.unselect_all()
        if text:
            for row in model:
                if text in row:
                    selection.select_iter(row.iter)
                    treeview.scroll_to_cell(row.path, use_align=True,
                                            row_align=0.5)
                    treeview.set_cursor(row.path)
                    break

        self._popping_up = True

        if filter:
            # do not grab if its a completion
            return

        # Grab window
        self.grab_focus()

        if not (self._treeview.flags() & gtk.HAS_FOCUS):
            self._treeview.grab_focus()

        if not self._popup_grab_window():
            self.hide()
            return

        self.grab_add()

    def popdown(self):
        combo = self._comboentry
        if not (combo.flags() & gtk.REALIZED):
            return

        self.grab_remove()
        self.hide()

    def set_label_text(self, text):
        if text is None:
            text = ''
            self._label.hide()
        else:
            self._label.show()
        self._label.set_text(text)

    def set_model(self, model):
        if isinstance(model, gtk.TreeModelFilter):
            self._filter_model = model
            model = model.get_model()

        self._treeview.set_model(model)
        self._model = model

    # Callbacks

    def _on__key_press_event(self, window, event):
        """
        Mimics Combobox behavior

        Escape or Alt+Up: Close
        Enter, Return or Space: Select
        """

        keyval = event.keyval
        state = event.state & gtk.accelerator_get_default_mod_mask()
        if (keyval == keysyms.Escape or
            ((keyval == keysyms.Up or keyval == keysyms.KP_Up) and
             state == gdk.MOD1_MASK)):
            self.popdown()
            return True
        elif keyval == keysyms.Tab:
            self.popdown()
            # XXX: private member of comboentry
            self._comboentry._button.grab_focus()
            return True
        elif (keyval == keysyms.Return or
              keyval == keysyms.space or
              keyval == keysyms.KP_Enter or
              keyval == keysyms.KP_Space):
            model, treeiter = self._selection.get_selected()
            self.emit('text-selected', model[treeiter][0])
            return True

        return False

    def _on__button_press_event(self, window, event):
        # If we're clicking outside of the window
        # close the popup
        if (event.window != self.window or
            (tuple(self.allocation.intersect(
                   gdk.Rectangle(x=int(event.x), y=int(event.y),
                                 width=1, height=1)))) == (0, 0, 0, 0)):
            self.popdown()

    def _on_treeview__motion_notify_event(self, treeview, event):
        retval = treeview.get_path_at_pos(int(event.x),
                                          int(event.y))
        if not retval:
            return
        path, column, x, y = retval
        self._selection.select_path(path)
        self._treeview.set_cursor(path)

    def _on_treeview__button_release_event(self, treeview, event):
        retval = treeview.get_path_at_pos(int(event.x),
                                          int(event.y))
        if not retval:
            return
        path, column, x, y = retval

        model = treeview.get_model()
        self.emit('text-selected', model[path][0])

    def _popup_grab_window(self):
        activate_time = 0L
        if gdk.pointer_grab(self.window, True,
                            (gdk.BUTTON_PRESS_MASK |
                             gdk.BUTTON_RELEASE_MASK |
                             gdk.POINTER_MOTION_MASK),
                             None, None, activate_time) == 0:
            if gdk.keyboard_grab(self.window, True, activate_time) == 0:
                return True
            else:
                self.window.get_display().pointer_ungrab(activate_time);
                return False
        return False

    def _get_position(self):
        treeview = self._treeview
        treeview.realize()

        sample = self._comboentry

        # We need to fetch the coordinates of the entry window
        # since comboentry itself does not have a window
        x, y = sample.entry.window.get_origin()
        width = sample.allocation.width

        hpolicy = vpolicy = gtk.POLICY_NEVER
        self._sw.set_policy(hpolicy, vpolicy)

        pwidth = self.size_request()[0]
        if pwidth > width:
            self._sw.set_policy(gtk.POLICY_ALWAYS, vpolicy)
            pwidth, pheight = self.size_request()

        rows = len(self._treeview.get_model())

        if rows > self._visible_rows:
            rows = self._visible_rows
            self._sw.set_policy(hpolicy, gtk.POLICY_ALWAYS)

        cell_height = treeview.get_cell_area(0, treeview.get_column(0)).height
        height = cell_height * rows

        screen = self._comboentry.get_screen()
        monitor_num = screen.get_monitor_at_window(sample.entry.window)
        monitor = screen.get_monitor_geometry(monitor_num)

        if x < monitor.x:
            x = monitor.x
        elif x + width > monitor.x + monitor.width:
            x = monitor.x + monitor.width - width

        if y + sample.entry.allocation.height + height <= monitor.y + monitor.height:
            y += sample.entry.allocation.height
        elif y - height >= monitor.y:
            y -= height
        elif (monitor.y + monitor.height - (y + sample.entry.allocation.height) >
              y - monitor.y):
            y += sample.entry.allocation.height
            height = monitor.y + monitor.height - y
        else :
            height = y - monitor.y
            y = monitor.y

        # Use half of the available screen space
        max_height = monitor.height / 2
        if height > max_height:
            height = int(max_height)
        elif height < 0:
            height = 0

        return x, y, width, height

    def get_selected_iter(self):
        model, treeiter = self._selection.get_selected()

        # if the model currently being used is a TreeModelFilter, convert
        # the iter to be a TreeModel iter (witch is what the user expects)
        if isinstance(model, gtk.TreeModelFilter) and treeiter:
            treeiter = model.convert_iter_to_child_iter(treeiter)
        return treeiter

    def set_selected_iter(self, treeiter):
        """
        Selects an item in the comboentry given a treeiter
        @param treeiter: the tree iter to select
        """
        model = self._treeview.get_model()

        # Since the user passed a TreeModel iter, if the model currently
        # being used is a TreeModelFilter, convert it to be a TreeModelFilter
        # iter
        if isinstance(model, gtk.TreeModelFilter):
            # See #3099 for an explanation why this is needed and a
            # testcase
            tmodel = model.get_model()
            if tmodel.iter_is_valid(treeiter):
               # revert back to the unfiltered model so we can select
               # the right object
               self._treeview.set_model(tmodel)
               self._selection = self._treeview.get_selection()
            else:
                treeiter = model.convert_child_iter_to_iter(treeiter)
        self._selection.select_iter(treeiter)

    def set_details_callback(self, callable):
        self._renderer.set_details_callback(callable)
예제 #3
0
class _ComboEntryPopup(PopupWindow):

    FRAME_PADDING = (0, 0, 0, 0)

    gsignal('text-selected', str)

    def __init__(self, comboentry):
        self._comboentry = comboentry

        super(_ComboEntryPopup, self).__init__(comboentry)

        # Number of visible rows in the popup window, sensible
        # default value from other toolkits
        self._visible_rows = 10
        self._initial_text = None
        self._filter_model = None

    def get_main_widget(self):
        vbox = gtk.VBox()
        vbox.show()

        self._sw = gtk.ScrolledWindow()
        self._sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
        vbox.pack_start(self._sw)
        self._sw.show()

        self._model = gtk.ListStore(str)
        self._treeview = gtk.TreeView(self._model)
        self._treeview.set_enable_search(False)
        self._treeview.connect('motion-notify-event',
                               self._on_treeview__motion_notify_event)
        self._treeview.connect('button-release-event',
                               self._on_treeview__button_release_event)
        self._treeview.add_events(gdk.BUTTON_PRESS_MASK)
        self._selection = self._treeview.get_selection()
        self._selection.set_mode(gtk.SELECTION_BROWSE)
        self._renderer = ComboDetailsCellRenderer()
        self._treeview.append_column(
            gtk.TreeViewColumn('Foo', self._renderer, label=0, data=1))
        self._treeview.set_headers_visible(False)
        self._sw.add(self._treeview)
        self._treeview.show()

        self._label = gtk.Label()

        return vbox

    def get_widget_for_popup(self):
        return self._comboentry.entry

    def popup(self, text=None, filter=False):
        """
        Shows the list of options. And optionally selects an item
        :param text: text to select
        :param filter: filter the list of options. A filter_model must be
        set using :class:`set_model`()
        """
        self.GRAB_WINDOW = not filter
        self.GRAB_ADD = not filter
        treeview = self._treeview

        if filter and self._filter_model:
            model = self._filter_model
        else:
            model = self._model

        if not len(model):
            return

        treeview.set_model(model)
        treeview.set_hover_expand(True)
        selection = treeview.get_selection()
        selection.unselect_all()
        if text:
            for row in model:
                if text in row:
                    selection.select_iter(row.iter)
                    treeview.scroll_to_cell(row.path,
                                            use_align=True,
                                            row_align=0.5)
                    treeview.set_cursor(row.path)
                    break

        popped = super(_ComboEntryPopup, self).popup()
        if not popped:
            return False

        treeview.set_size_request(-1, -1)
        if not filter:
            # Grab window
            self.grab_focus()
            if not self._treeview.has_focus():
                self._treeview.grab_focus()

        return True

    def set_label_text(self, text):
        if text is None:
            text = ''
            self._label.hide()
        else:
            self._label.show()
        self._label.set_text(text)

    def set_model(self, model):
        if isinstance(model, gtk.TreeModelFilter):
            self._filter_model = model
            model = model.get_model()

        self._treeview.set_model(model)
        self._model = model

    def confirm(self):
        model, treeiter = self._selection.get_selected()
        if treeiter:
            self.emit('text-selected', model[treeiter][0])

    def handle_key_press_event(self, event):
        if event.keyval == keysyms.Tab:
            self.popdown()
            # XXX: private member of comboentry
            self._comboentry._button.grab_focus()
            return True
        return False

    # Callbacks

    def _on_treeview__motion_notify_event(self, treeview, event):
        retval = treeview.get_path_at_pos(int(event.x), int(event.y))
        if not retval:
            return
        path, column, x, y = retval
        self._selection.select_path(path)
        self._treeview.set_cursor(path)

    def _on_treeview__button_release_event(self, treeview, event):
        retval = treeview.get_path_at_pos(int(event.x), int(event.y))
        if not retval:
            return
        path, column, x, y = retval

        model = treeview.get_model()
        self.emit('text-selected', model[path][0])

    def get_size(self, allocation, monitor):
        treeview = self._treeview
        treeview.realize()

        rows = len(self._treeview.get_model())
        if rows > self._visible_rows:
            rows = self._visible_rows
            self._sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
        else:
            self._sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)

        cell_height = treeview.get_cell_area(0, treeview.get_column(0)).height
        height = cell_height * rows
        # Use half of the available screen space
        max_height = monitor.height / 2
        if height > max_height:
            height = int(max_height)
        elif height < 0:
            height = 0

        return allocation.width, height

    def get_selected_iter(self):
        model, treeiter = self._selection.get_selected()

        # if the model currently being used is a TreeModelFilter, convert
        # the iter to be a TreeModel iter (witch is what the user expects)
        if isinstance(model, gtk.TreeModelFilter) and treeiter:
            treeiter = model.convert_iter_to_child_iter(treeiter)
        return treeiter

    def set_selected_iter(self, treeiter):
        """
        Selects an item in the comboentry given a treeiter
        :param treeiter: the tree iter to select
        """
        model = self._treeview.get_model()

        # Since the user passed a TreeModel iter, if the model currently
        # being used is a TreeModelFilter, convert it to be a TreeModelFilter
        # iter
        if isinstance(model, gtk.TreeModelFilter):
            # See #3099 for an explanation why this is needed and a
            # testcase
            tmodel = model.get_model()
            if tmodel.iter_is_valid(treeiter):
                # revert back to the unfiltered model so we can select
                # the right object
                self._treeview.set_model(tmodel)
                self._selection = self._treeview.get_selection()
            else:
                treeiter = model.convert_child_iter_to_iter(treeiter)
        self._selection.select_iter(treeiter)

    def set_details_callback(self, callable):
        self._renderer.set_details_callback(callable)