Esempio n. 1
0
class TBaseView(TestCase):
    def setUp(self):
        self.m = Gtk.ListStore(str)
        self.c = BaseView(model=self.m)

    def test_selection_changed(self):
        events = []

        def on_selection_changed(*args):
            events.append(args)

        self.c.connect("selection-changed", on_selection_changed)

        self.m.append(row=["foo"])
        self.c.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
        self.c.get_selection().select_all()
        self.assertTrue(events)

    def test_remove(self):
        self.m.append(row=["foo"])
        self.c.remove_iters([self.m[0].iter])
        self.failIf(len(self.m))

        self.m.append(row=["foo"])
        self.c.remove_iters([])
        self.failUnless(len(self.m))

        self.c.remove_paths([self.m[0].path])
        self.failIf(len(self.m))

    def test_key_events(self):
        with visible(self.c):
            send_key_click(self.c, "<Primary>Right")
            send_key_click(self.c, "<Primary>Left")

    def test_select_func(self):
        self.m.append(row=["foo"])
        self.m.append(row=["bar"])
        self.failUnless(self.c.select_by_func(lambda r: True))
        self.failIf(self.c.select_by_func(lambda r: False))
        self.c.select_by_func(lambda r: False, scroll=False, one=True)

    def test_iter_select_func(self):
        # empty
        self.assertFalse(self.c.iter_select_by_func(lambda r: False))
        self.assertFalse(self.c.iter_select_by_func(lambda r: True))

        self.m.append(row=["foo"])
        self.m.append(row=["bar"])
        self.m.append(row=["foo"])
        self.c.remove_selection()
        self.assertTrue(self.c.iter_select_by_func(lambda r: r[0] == "foo"))
        selection = self.c.get_selection()
        model, iter_ = selection.get_selected()
        self.assertEqual(model.get_path(iter_)[:], [0])
        self.assertTrue(self.c.iter_select_by_func(lambda r: r[0] == "foo"))
        model, iter_ = selection.get_selected()
        self.assertEqual(model.get_path(iter_)[:], [2])
        self.assertTrue(self.c.iter_select_by_func(lambda r: r[0] == "foo"))
        model, iter_ = selection.get_selected()
        self.assertEqual(model.get_path(iter_)[:], [0])
        self.assertTrue(self.c.iter_select_by_func(lambda r: r[0] == "bar"))
        model, iter_ = selection.get_selected()
        self.assertEqual(model.get_path(iter_)[:], [1])
        self.assertFalse(self.c.iter_select_by_func(lambda r: r[0] == "bar"))

    def test_remove_select_single(self):
        # empty
        self.c.remove_selection()

        model = _fill_view(self.c)

        # select first and remove
        selection = self.c.get_selection()
        length = len(model)
        selection.select_path(model[0].path)
        self.c.remove_selection()
        self.assertEqual(len(model), length - 1)
        model, iter_ = selection.get_selected()

        # afterwards the first is selected
        self.assertEqual(model[iter_].path, model[0].path)

    def test_remove_select_multiple(self):
        selection = self.c.get_selection()
        selection.set_mode(Gtk.SelectionMode.MULTIPLE)

        # empty
        self.c.remove_selection()

        model = _fill_view(self.c)

        # select first two and remove
        selection = self.c.get_selection()
        length = len(model)
        selection.select_range(model[0].path, model[1].path)
        self.c.remove_selection()
        self.assertEqual(len(model), length - 2)

        # afterwards the first is selected
        model, paths = selection.get_selected_rows()
        self.assertEqual(paths, [model[0].path])

    def test_without_model(self):
        column = TreeViewColumn()
        self.c.append_column(column)

        column = self.c.get_columns()[0]
        column.set_sort_indicator(True)
        self.c.set_search_column(0)

        with self.c.without_model() as model:
            self.assertEqual(model, self.m)
            self.assertTrue(self.c.get_model() is None)

        self.assertEqual(self.c.get_search_column(), 0)
        column = self.c.get_columns()[0]
        self.assertTrue(column.get_sort_indicator())

    def test_set_drag_dest(self):
        x, y = self.c.convert_bin_window_to_widget_coords(0, 0)

        # empty model
        self.c.unset_rows_drag_dest()
        self.c.set_drag_dest(x, y)
        path, pos = self.c.get_drag_dest_row()
        self.assertTrue(path is None)

        # filled model but not realized, fall back to last path
        model = _fill_view(self.c)
        self.c.set_drag_dest(x, y)
        path, pos = self.c.get_drag_dest_row()
        self.assertEqual(model[-1].path, path)

        # realized now, so the first path
        with realized(self.c):
            x, y = self.c.convert_bin_window_to_widget_coords(0, 0)

            self.c.unset_rows_drag_dest()
            self.c.set_drag_dest(x, y, into_only=False)
            path, pos = self.c.get_drag_dest_row()
            self.assertEqual(model[0].path, path)
            self.assertEqual(pos, Gtk.TreeViewDropPosition.BEFORE)

            self.c.unset_rows_drag_dest()
            self.c.set_drag_dest(x, y, into_only=True)
            path, pos = self.c.get_drag_dest_row()
            self.assertEqual(model[0].path, path)
            self.assertEqual(pos, Gtk.TreeViewDropPosition.INTO_OR_BEFORE)

    def tearDown(self):
        self.c.destroy()
Esempio n. 2
0
    def __init__(self):
        super(PatternEditor, self).__init__(spacing=6)

        self.__headers = headers = {}
        buttons = []

        group = None
        for tags in self.PRESETS:
            tied = "~" + "~".join(tags)
            group = Gtk.RadioButton(group=group, label="_" + util.tag(tied),
                                    use_underline=True)
            headers[group] = tags
            buttons.append(group)

        group = Gtk.RadioButton(group=group, label=_("_Custom"),
                                use_underline=True)
        self.__custom = group
        headers[group] = []
        buttons.append(group)

        button_box = Gtk.HBox(spacing=6)
        self.__model = model = Gtk.ListStore(str)

        radio_box = Gtk.VBox(spacing=6)
        for button in buttons:
            radio_box.pack_start(button, False, True, 0)
            button.connect('toggled', self.__toggled, button_box, model)

        self.pack_start(radio_box, False, True, 0)

        tooltip = _("Tag pattern with optional markup "
                    "e.g. <tt>composer</tt> or\n<tt>%s</tt>"
                    % escape(self._COMPLEX_PATTERN_EXAMPLE))
        cb = TagsComboBoxEntry(self.COMPLETION, tooltip_markup=tooltip)

        view = BaseView(model=model)
        view.set_reorderable(True)
        view.set_headers_visible(False)

        ctrl_box = Gtk.VBox(spacing=6)

        add = Button(_("_Add"), Icons.LIST_ADD)
        ctrl_box.pack_start(add, False, True, 0)
        add.connect('clicked', self.__add, model, cb)

        remove = Button(_("_Remove"), Icons.LIST_REMOVE)
        ctrl_box.pack_start(remove, False, True, 0)
        remove.connect('clicked', self.__remove, view)

        selection = view.get_selection()
        selection.connect('changed', self.__selection_changed, remove)
        selection.emit('changed')

        sw = Gtk.ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        sw.add(view)

        edit_box = Gtk.VBox(spacing=6)
        edit_box.pack_start(cb, False, True, 0)
        edit_box.pack_start(sw, True, True, 0)

        button_box.pack_start(edit_box, True, True, 0)
        button_box.pack_start(ctrl_box, False, True, 0)
        self.pack_start(button_box, True, True, 0)

        render = Gtk.CellRendererText()
        render.set_property("editable", True)

        def edited_cb(render, path, text, model):
            model[path][0] = text
        render.connect("edited", edited_cb, model)

        column = Gtk.TreeViewColumn(None, render, text=0)
        view.append_column(column)
Esempio n. 3
0
    def __init__(self):
        super(PatternEditor, self).__init__(spacing=6)

        self.__headers = headers = {}
        buttons = []

        group = None
        for tags in self.PRESETS:
            tied = "~" + "~".join(tags)
            group = Gtk.RadioButton(group=group,
                                    label="_" + util.tag(tied),
                                    use_underline=True)
            headers[group] = tags
            buttons.append(group)

        group = Gtk.RadioButton(group=group,
                                label=_("_Custom"),
                                use_underline=True)
        self.__custom = group
        headers[group] = []
        buttons.append(group)

        button_box = Gtk.HBox(spacing=6)
        self.__model = model = Gtk.ListStore(str)

        radio_box = Gtk.VBox(spacing=6)
        for button in buttons:
            radio_box.pack_start(button, False, True, 0)
            button.connect('toggled', self.__toggled, button_box, model)

        self.pack_start(radio_box, False, True, 0)

        tooltip = _("Tag pattern with optional markup "
                    "e.g. <tt>composer</tt> or\n<tt>%s</tt>" %
                    escape(self._COMPLEX_PATTERN_EXAMPLE))
        cb = TagsComboBoxEntry(self.COMPLETION, tooltip_markup=tooltip)

        view = BaseView(model=model)
        view.set_reorderable(True)
        view.set_headers_visible(False)

        ctrl_box = Gtk.VBox(spacing=6)

        add = Button(_("_Add"), Icons.LIST_ADD)
        ctrl_box.pack_start(add, False, True, 0)
        add.connect('clicked', self.__add, model, cb)

        remove = Button(_("_Remove"), Icons.LIST_REMOVE)
        ctrl_box.pack_start(remove, False, True, 0)
        remove.connect('clicked', self.__remove, view)

        selection = view.get_selection()
        selection.connect('changed', self.__selection_changed, remove)
        selection.emit('changed')

        sw = Gtk.ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        sw.add(view)

        edit_box = Gtk.VBox(spacing=6)
        edit_box.pack_start(cb, False, True, 0)
        edit_box.pack_start(sw, True, True, 0)

        button_box.pack_start(edit_box, True, True, 0)
        button_box.pack_start(ctrl_box, False, True, 0)
        self.pack_start(button_box, True, True, 0)

        render = Gtk.CellRendererText()
        render.set_property("editable", True)

        def edited_cb(render, path, text, model):
            model[path][0] = text

        render.connect("edited", edited_cb, model)

        column = Gtk.TreeViewColumn(None, render, text=0)
        view.append_column(column)
Esempio n. 4
0
    def __init__(self):
        super(PatternEditor, self).__init__(spacing=12)

        self.__headers = headers = {}
        buttons = []

        group = None
        for tags in self.PRESETS:
            tied = "~" + "~".join([t[0] for t in tags])
            group = Gtk.RadioButton(group=group, label="_" + util.tag(tied),
                                    use_underline=True)
            headers[group] = tags
            buttons.append(group)

        group = Gtk.RadioButton(group=group, label=_("_Custom"),
                                use_underline=True)
        self.__custom = group
        headers[group] = []
        buttons.append(group)

        button_box = Gtk.HBox(spacing=6)
        self.__model = model = Gtk.ListStore(str, bool)

        radio_box = Gtk.VBox(spacing=6)
        for button in buttons:
            radio_box.pack_start(button, False, True, 0)
            button.connect('toggled', self.__toggled, button_box, model)

        self.pack_start(radio_box, False, True, 0)

        cb = TagsComboBoxEntry(self.COMPLETION)

        view = BaseView(model=model)
        view.set_reorderable(True)
        view.set_headers_visible(True)

        ctrl_box = Gtk.VBox(spacing=6)

        add = Gtk.Button(stock=Gtk.STOCK_ADD)
        ctrl_box.pack_start(add, False, True, 0)
        add.connect('clicked', self.__add, model, cb)

        remove = Gtk.Button(stock=Gtk.STOCK_REMOVE)
        ctrl_box.pack_start(remove, False, True, 0)
        remove.connect('clicked', self.__remove, view)

        selection = view.get_selection()
        selection.connect('changed', self.__selection_changed, remove)
        selection.emit('changed')

        sw = Gtk.ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        sw.add(view)

        edit_box = Gtk.VBox(spacing=6)
        edit_box.pack_start(cb, False, True, 0)
        edit_box.pack_start(sw, True, True, 0)

        button_box.pack_start(edit_box, True, True, 0)
        button_box.pack_start(ctrl_box, False, True, 0)
        self.pack_start(button_box, True, True, 0)

        render = Gtk.CellRendererText()
        render.set_property("editable", True)

        def edited_cb(render, path, text, model):
            model[path][0] = text
        render.connect("edited", edited_cb, model)

        column = Gtk.TreeViewColumn(_("Tag"), render, text=0)
        column.set_expand(True)
        view.append_column(column)

        toggle = Gtk.CellRendererToggle()
        toggle.connect("toggled", self.__toggeled, model)
        toggle_column = Gtk.TreeViewColumn(_("Merge"), toggle, active=1)
        view.append_column(toggle_column)
Esempio n. 5
0
class TBaseView(TestCase):
    def setUp(self):
        self.m = Gtk.ListStore(str)
        self.c = BaseView(model=self.m)

    def test_remove(self):
        self.m.append(row=["foo"])
        self.c.remove_iters([self.m[0].iter])
        self.failIf(len(self.m))

        self.m.append(row=["foo"])
        self.c.remove_iters([])
        self.failUnless(len(self.m))

        self.c.remove_paths([self.m[0].path])
        self.failIf(len(self.m))

    def test_key_events(self):
        with visible(self.c):
            send_key_click(self.c, "<Primary>Right")
            send_key_click(self.c, "<Primary>Left")

    def test_select_func(self):
        self.m.append(row=["foo"])
        self.m.append(row=["bar"])
        self.failUnless(self.c.select_by_func(lambda r: True))
        self.failIf(self.c.select_by_func(lambda r: False))
        self.c.select_by_func(lambda r: False, scroll=False, one=True)

    def test_remove_select_single(self):
        # empty
        self.c.remove_selection()

        model = _fill_view(self.c)

        # select first and remove
        selection = self.c.get_selection()
        length = len(model)
        selection.select_path(model[0].path)
        self.c.remove_selection()
        self.assertEqual(len(model), length - 1)
        model, iter_ = selection.get_selected()

        # afterwards the first is selected
        self.assertEqual(model[iter_].path, model[0].path)

    def test_remove_select_multiple(self):
        selection = self.c.get_selection()
        selection.set_mode(Gtk.SelectionMode.MULTIPLE)

        # empty
        self.c.remove_selection()

        model = _fill_view(self.c)

        # select first two and remove
        selection = self.c.get_selection()
        length = len(model)
        selection.select_range(model[0].path, model[1].path)
        self.c.remove_selection()
        self.assertEqual(len(model), length - 2)

        # afterwards the first is selected
        model, paths = selection.get_selected_rows()
        self.assertEqual(paths, [model[0].path])

    def test_without_model(self):
        column = TreeViewColumn()
        self.c.append_column(column)

        column = self.c.get_columns()[0]
        column.set_sort_indicator(True)
        self.c.set_search_column(0)

        with self.c.without_model() as model:
            self.assertEqual(model, self.m)
            self.assertTrue(self.c.get_model() is None)

        self.assertEqual(self.c.get_search_column(), 0)
        column = self.c.get_columns()[0]
        self.assertTrue(column.get_sort_indicator())

    def test_set_drag_dest(self):
        x, y = self.c.convert_bin_window_to_widget_coords(0, 0)

        # empty model
        self.c.unset_rows_drag_dest()
        self.c.set_drag_dest(x, y)
        path, pos = self.c.get_drag_dest_row()
        self.assertTrue(path is None)

        # filled model but not realized, fall back to last path
        model = _fill_view(self.c)
        self.c.set_drag_dest(x, y)
        path, pos = self.c.get_drag_dest_row()
        self.assertEqual(model[-1].path, path)

        # realized now, so the first path
        with realized(self.c):
            x, y = self.c.convert_bin_window_to_widget_coords(0, 0)

            self.c.unset_rows_drag_dest()
            self.c.set_drag_dest(x, y, into_only=False)
            path, pos = self.c.get_drag_dest_row()
            self.assertEqual(model[0].path, path)
            self.assertEqual(pos, Gtk.TreeViewDropPosition.BEFORE)

            self.c.unset_rows_drag_dest()
            self.c.set_drag_dest(x, y, into_only=True)
            path, pos = self.c.get_drag_dest_row()
            self.assertEqual(model[0].path, path)
            self.assertEqual(pos, Gtk.TreeViewDropPosition.INTO_OR_BEFORE)

    def tearDown(self):
        self.c.destroy()
Esempio n. 6
0
    def __init__(self):
        super().__init__(spacing=12)

        self.__headers = headers = {}
        buttons = []

        group = None
        for tags in self.PRESETS:
            tied = "~" + "~".join([t[0] for t in tags])
            group = Gtk.RadioButton(group=group, label="_" + util.tag(tied),
                                    use_underline=True)
            headers[group] = tags
            buttons.append(group)

        group = Gtk.RadioButton(group=group, label=_("_Custom"),
                                use_underline=True)
        self.__custom = group
        headers[group] = []
        buttons.append(group)

        button_box = Gtk.HBox(spacing=6)
        self.__model = model = Gtk.ListStore(str, bool)

        radio_box = Gtk.VBox(spacing=6)
        for button in buttons:
            radio_box.pack_start(button, False, True, 0)
            button.connect('toggled', self.__toggled, button_box, model)

        self.pack_start(radio_box, False, True, 0)

        cb = TagsComboBoxEntry(self.COMPLETION)

        view = BaseView(model=model)
        view.set_reorderable(True)
        view.set_headers_visible(True)

        ctrl_box = Gtk.VBox(spacing=6)

        add = Button(_("_Add"), Icons.LIST_ADD)
        ctrl_box.pack_start(add, False, True, 0)
        add.connect('clicked', self.__add, model, cb)

        remove = Button(_("_Remove"), Icons.LIST_REMOVE)
        ctrl_box.pack_start(remove, False, True, 0)
        remove.connect('clicked', self.__remove, view)

        selection = view.get_selection()
        selection.connect('changed', self.__selection_changed, remove)
        selection.emit('changed')

        sw = Gtk.ScrolledWindow()
        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        sw.set_shadow_type(Gtk.ShadowType.IN)
        sw.add(view)

        edit_box = Gtk.VBox(spacing=6)
        edit_box.pack_start(cb, False, True, 0)
        edit_box.pack_start(sw, True, True, 0)

        button_box.pack_start(edit_box, True, True, 0)
        button_box.pack_start(ctrl_box, False, True, 0)
        self.pack_start(button_box, True, True, 0)

        render = Gtk.CellRendererText()
        render.set_property("editable", True)

        def edited_cb(render, path, text, model):
            model[path][0] = text
        render.connect("edited", edited_cb, model)

        column = Gtk.TreeViewColumn(_("Tag"), render, text=0)
        column.set_expand(True)
        view.append_column(column)

        toggle = Gtk.CellRendererToggle()
        toggle.connect("toggled", self.__toggeled, model)
        toggle_column = Gtk.TreeViewColumn(_("Merge"), toggle, active=1)
        view.append_column(toggle_column)
Esempio n. 7
0
    def _popup_menu(self, view: BaseView, _parent):
        menu = Gtk.Menu()

        view.ensure_popup_selection()
        model, rows = view.get_selection().get_selected_rows()
        can_change = all(model[path][0].canedit for path in rows)

        if len(rows) == 1:
            row = model[rows[0]]
            entry = row[0]

            comment = entry.value
            text = comment.text

            split_menu = Gtk.Menu()

            for Item in self._SPLITTERS:
                if Item.tags and entry.tag not in Item.tags:
                    continue
                item = self.__item_for(view, Item, entry.tag, text)
                if not item:
                    continue
                vals = item.activated(entry.tag, text)
                changeable = any(not self._group_info.can_change(k)
                                 for k in item.needs)
                fixed = changeable or comment.is_special()
                if fixed:
                    item.set_sensitive(False)
                if len(vals) > 1 and vals[1][1]:
                    split_menu.append(item)
            if split_menu.get_children():
                split_menu.append(SeparatorMenuItem())

            plugins = self.handler.plugins
            print_d(f"Adding {len(plugins)} plugin(s) to menu: "
                    f"{', '.join(p.__name__ for p in plugins)}")
            for p_cls in plugins:
                item = self.__item_for(view, p_cls, entry.tag, text)
                if not item:
                    continue
                results = item.activated(entry.tag, text)
                # Only enable for the user if the plugin would do something
                item.set_sensitive(results != [(entry.tag, text)])
                menu.append(item)
            pref_item = MenuItem(_("_Configure"), Icons.PREFERENCES_SYSTEM)
            split_menu.append(pref_item)

            def show_prefs(parent):
                from quodlibet.qltk.exfalsowindow import ExFalsoWindow
                if isinstance(app.window, ExFalsoWindow):
                    from quodlibet.qltk.exfalsowindow import PreferencesWindow
                    window = PreferencesWindow(parent)
                else:
                    from quodlibet.qltk.prefs import PreferencesWindow
                    window = PreferencesWindow(parent, open_page="tagging")
                window.show()

            connect_obj(pref_item, "activate", show_prefs, self)

            split_item = MenuItem(_("_Split Tag"), Icons.EDIT_FIND_REPLACE)

            if split_menu.get_children():
                split_item.set_submenu(split_menu)
            else:
                split_item.set_sensitive(False)

            menu.append(split_item)

        copy_b = MenuItem(_("_Copy Value(s)"), Icons.EDIT_COPY)
        copy_b.connect('activate', self.__copy_tag_value, view)
        qltk.add_fake_accel(copy_b, "<Primary>c")
        menu.append(copy_b)

        remove_b = MenuItem(_("_Remove"), Icons.LIST_REMOVE)
        remove_b.connect('activate', self.__remove_tag, view)
        qltk.add_fake_accel(remove_b, "Delete")
        menu.append(remove_b)

        menu.show_all()
        # Setting the menu itself to be insensitive causes it to not
        # be dismissed; see #473.
        for c in menu.get_children():
            c.set_sensitive(can_change and c.get_property('sensitive'))
        copy_b.set_sensitive(True)
        remove_b.set_sensitive(True)
        menu.connect('selection-done', lambda m: m.destroy())

        # XXX: Keep reference
        self.__menu = menu
        return view.popup_menu(menu, 3, Gtk.get_current_event_time())
Esempio n. 8
0
    def __init__(self):
        super(PatternEditor, self).__init__(spacing=6)

        self.__headers = headers = {}
        buttons = []

        group = None
        for tags in self.PRESETS:
            tied = "~" + "~".join(tags)
            group = gtk.RadioButton(group, "_" + tag(tied))
            headers[group] = tags
            buttons.append(group)

        group = gtk.RadioButton(group, _("_Custom"))
        self.__custom = group
        headers[group] = []
        buttons.append(group)

        button_box = gtk.HBox(spacing=6)
        self.__model = model = gtk.ListStore(str)

        radio_box = gtk.VBox(spacing=6)
        for button in buttons:
            radio_box.pack_start(button, expand=False)
            button.connect('toggled', self.__toggled, button_box, model)

        self.pack_start(radio_box, expand=False)

        cb = TagsComboBoxEntry(self.COMPLETION)

        view = BaseView(model)
        view.set_reorderable(True)
        view.set_headers_visible(False)

        ctrl_box = gtk.VBox(spacing=6)

        add = gtk.Button(stock=gtk.STOCK_ADD)
        ctrl_box.pack_start(add, expand=False)
        add.connect('clicked', self.__add, model, cb)

        remove = gtk.Button(stock=gtk.STOCK_REMOVE)
        ctrl_box.pack_start(remove, expand=False)
        remove.connect('clicked', self.__remove, view)

        selection = view.get_selection()
        selection.connect('changed', self.__selection_changed, remove)
        selection.emit('changed')

        sw = gtk.ScrolledWindow()
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.set_shadow_type(gtk.SHADOW_IN)
        sw.add(view)

        edit_box = gtk.VBox(spacing=6)
        edit_box.pack_start(cb, expand=False)
        edit_box.pack_start(sw)

        button_box.pack_start(edit_box)
        button_box.pack_start(ctrl_box, expand=False)
        self.pack_start(button_box)

        render = gtk.CellRendererText()
        render.set_property("editable", True)

        def edited_cb(render, path, text, model):
            model[path][0] = text
        render.connect("edited", edited_cb, model)

        column = gtk.TreeViewColumn(None, render, text=0)
        view.append_column(column)