#!/usr/bin/env python

from gi.repository import Gdk
from gi.repository import GObject
from gi.repository import Gtk

class CellTextView(Gtk.TextView, Gtk.CellEditable):

    __gproperties__ = {
        "editing-canceled": (bool,
                             "Editing canceled",
                             "Editing canceled",
                             False,
                             GObject.PARAM_READWRITE),

    }
    __gtype_name__ = "CellTextView"

    def do_editing_done(self, *args):
        pass

    def do_remove_widget(self, *args):
        pass

    def do_start_editing(self, *args):
        pass

    def get_text(self):
        text_buffer = self.get_buffer()
        start, end = text_buffer.get_bounds()
        return text_buffer.get_text(start, end, False)

    def set_text(self, text):
        self.get_buffer().set_text(text)


class MultilineCellRenderer(Gtk.CellRendererText):

    __gtype_name__ = "MultilineCellRenderer"

    def __init__(self):
        GObject.GObject.__init__(self)
        self._in_editor_menu = False

    def _on_editor_focus_out_event(self, editor, *args):
        if self._in_editor_menu: return
        editor.remove_widget()
        self.emit("editing-canceled")

    def _on_editor_key_press_event(self, editor, event):
        if (event.get_state() &
            (Gdk.ModifierType.SHIFT_MASK |
             Gdk.ModifierType.CONTROL_MASK)): return
        if event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter):
            editor.editing_done()
            editor.remove_widget()
            self.emit("edited", editor.multiline_path, editor.get_text())
            return True
        if event.keyval == Gdk.KEY_Escape:
            editor.editing_done()
            editor.remove_widget()
            self.emit("editing-canceled")
            return True

    def _on_editor_populate_popup(self, editor, menu):
        self._in_editor_menu = True
        def on_menu_unmap(menu, self):
            self._in_editor_menu = False
        menu.connect("unmap", on_menu_unmap, self)

    def do_start_editing(self, event, widget, path, bg_area, cell_area, flags):
        editor = CellTextView()
        editor.modify_font(self.props.font_desc)
        editor.set_text(self.props.text)
        editor.set_size_request(cell_area.width, cell_area.height)
        editor.set_border_width(min(self.props.xpad, self.props.ypad))
        editor.multiline_path = path
        editor.connect("focus-out-event", self._on_editor_focus_out_event)
        editor.connect("key-press-event", self._on_editor_key_press_event)
        editor.connect("populate-popup", self._on_editor_populate_popup)
        editor.show()
        return editor


if __name__ == "__main__":
    tree_view = Gtk.TreeView()
    tree_view.set_headers_visible(False)
    store = Gtk.ListStore(str)
    store.append(("foo\nfoo",))
    tree_view.set_model(store)
    renderer = MultilineCellRenderer()
    renderer.props.editable = True
    def on_edited(renderer, path, new_value, store, col):
        tree_iter = store.get_iter(path)
        store.set(tree_iter, col, new_value)
    renderer.connect("edited", on_edited, store, 0)
    column = Gtk.TreeViewColumn("", renderer, text=0)
    tree_view.append_column(column)
    window = Gtk.Window()
    window.connect("delete-event", Gtk.main_quit)
    window.set_position(Gtk.WindowPosition.CENTER)
    window.set_default_size(200, 50)
    window.add(tree_view)
    window.show_all()
    Gtk.main()
