Esempio n. 1
0
    def __init__(self, picker):
        EventIcon.__init__(self, icon_name='computer-xo',
                           pixel_size=style.LARGE_ICON_SIZE)
        self._picker = picker
        self._color = None

        self.connect('button_press_event', self.__pressed_cb, picker)
Esempio n. 2
0
class Picker(Gtk.Grid):

    def __init__(self, icon, label):
        Gtk.Grid.__init__(self)

        self._button = EventIcon(pixel_size=style.LARGE_ICON_SIZE,
                                 icon_name=icon)
        self.attach(self._button, 0, 0, 1, 1)
        self._button.hide()

        self._label = Gtk.Label(label)
        self.attach(self._label, 0, 1, 1, 1)
        self._label.hide()

    def show_all(self):
        self._button.show()
        self._label.show()
        self.show()

    def hide_all(self):
        self._button.hide()
        self._label.hide()
        self.hide()

    def connect(self, callback, arg):
        self._button.connect('button-press-event', callback, arg)

    def set_color(self, color):
        self._button.xo_color = color

    def set_icon(self, icon):
        self._button.set_icon_name(icon)
Esempio n. 3
0
    def __init__(self):
        Gtk.Grid.__init__(self)
        self.set_row_spacing(style.DEFAULT_SPACING)
        self.set_column_spacing(style.DEFAULT_SPACING)

        self._gender = load_gender()
        self._buttons = []
        self._nocolor = XoColor('#010101,#ffffff')
        self._color = XoColor()

        for i, gender in enumerate(GENDERS):
            self._buttons.append(
                EventIcon(pixel_size=style.XLARGE_ICON_SIZE,
                          icon_name='%s-6' % (gender)))
            self._buttons[-1].connect('button-press-event',
                                      self._button_press_cb, i)
            self.attach(self._buttons[-1], i * 2, 0, 1, 1)
            self._buttons[-1].show()

        self.reset_button = EventIcon(pixel_size=style.SMALL_ICON_SIZE,
                                      icon_name='entry-cancel')
        self.reset_button.connect('button-press-event',
                                  self._reset_button_press_cb)
        self.attach(self.reset_button, 1, 0, 1, 1)
        self.reset_button.xo_color = XoColor('#010101,#a0a0a0')
        self.reset_button.show()
Esempio n. 4
0
    def __init__(self, picker):
        EventIcon.__init__(self, icon_name='computer-xo',
                           pixel_size=style.LARGE_ICON_SIZE)
        self._picker = picker
        self._color = None

        self.connect('activate', self.__activate_cb, picker)
Esempio n. 5
0
class Picker(Gtk.Grid):

    def __init__(self, icon, label):
        Gtk.Grid.__init__(self)

        self._button = EventIcon(pixel_size=style.LARGE_ICON_SIZE,
                                 icon_name=icon)
        self.attach(self._button, 0, 0, 1, 1)
        self._button.hide()

        self._label = Gtk.Label(label.replace(' ', '\n'))
        self._label.props.justify = Gtk.Justification.CENTER
        self.attach(self._label, 0, 1, 1, 1)
        self._label.hide()

    def show_all(self):
        self._button.show()
        self._label.show()
        self.show()

    def hide_all(self):
        self._button.hide()
        self._label.hide()
        self.hide()

    def connect(self, callback, arg):
        self._button.connect('activate', callback, arg)

    def set_color(self, color):
        self._button.xo_color = color

    def set_icon(self, icon):
        self._button.set_icon_name(icon)
Esempio n. 6
0
    def __init__(self, picker):
        EventIcon.__init__(self, icon_name='computer-xo',
                           pixel_size=style.LARGE_ICON_SIZE)
        self._picker = picker
        self._color = None

        self.connect('button_press_event', self.__pressed_cb, picker)
Esempio n. 7
0
    def _make_entry_widgets(self):
        '''We need to create a button for the smiley, a text entry, and a
        send button.

        All of this, along with the chatbox, goes into a grid.

        ---------------------------------------
        | chat box                            |
        | smiley button | entry | send button |
        ---------------------------------------
        '''
        if self._ebook_mode_detector.get_ebook_mode():
            self._entry_height = int(style.GRID_CELL_SIZE * 1.5)
        else:
            self._entry_height = style.GRID_CELL_SIZE
        entry_width = Gdk.Screen.width() - \
            2 * (self._entry_height + style.GRID_CELL_SIZE)
        self._chat_height = Gdk.Screen.height() - self._entry_height - \
            style.GRID_CELL_SIZE
        self._chat_width = Gdk.Screen.width()

        self.chatbox.set_size_request(self._chat_width, self._chat_height)

        self._entry_grid = Gtk.Grid()
        self._entry_grid.set_size_request(
            Gdk.Screen.width() - 2 * style.GRID_CELL_SIZE, self._entry_height)

        self.smiley_button = EventIcon(icon_name='smilies',
                                       pixel_size=self._entry_height)
        self.smiley_button.connect('button-press-event',
                                   self._smiley_button_cb)
        self._entry_grid.attach(self.smiley_button, 0, 0, 1, 1)
        self.smiley_button.show()

        self._entry = Gtk.Entry()
        self._entry.set_size_request(entry_width, self._entry_height)
        self._entry.modify_bg(Gtk.StateType.INSENSITIVE,
                              style.COLOR_WHITE.get_gdk_color())
        self._entry.modify_base(Gtk.StateType.INSENSITIVE,
                                style.COLOR_WHITE.get_gdk_color())

        self._entry.props.placeholder_text = \
            _('You must be connected to a friend before starting to chat.')
        self._entry.connect('focus-in-event', self._entry_focus_in_cb)
        self._entry.connect('focus-out-event', self._entry_focus_out_cb)
        self._entry.connect('activate', self._entry_activate_cb)
        self._entry.connect('key-press-event', self._entry_key_press_cb)
        self._entry_grid.attach(self._entry, 1, 0, 1, 1)
        self._entry.show()

        self.send_button = EventIcon(icon_name='send',
                                     pixel_size=self._entry_height)
        self.send_button.connect('button-press-event', self._send_button_cb)
        self._entry_grid.attach(self.send_button, 2, 0, 1, 1)
        self.send_button.show()

        if not self.get_shared():
            self._entry.set_sensitive(False)
            self.smiley_button.set_sensitive(False)
            self.send_button.set_sensitive(False)
Esempio n. 8
0
class Picker(Gtk.Grid):
    def __init__(self, icon, label):
        Gtk.Grid.__init__(self)

        self._button = EventIcon(pixel_size=style.LARGE_ICON_SIZE,
                                 icon_name=icon)
        self.attach(self._button, 0, 0, 1, 1)
        self._button.hide()

        self._label = Gtk.Label(label)
        self.attach(self._label, 0, 1, 1, 1)
        self._label.hide()

    def show_all(self):
        self._button.show()
        self._label.show()
        self.show()

    def hide_all(self):
        self._button.hide()
        self._label.hide()
        self.hide()

    def connect(self, callback, arg):
        self._button.connect('button-press-event', callback, arg)

    def set_color(self, color):
        self._button.xo_color = color

    def set_icon(self, icon):
        self._button.set_icon_name(icon)
Esempio n. 9
0
    def __init__(self, picker):
        EventIcon.__init__(self, icon_name='computer-xo',
                           pixel_size=style.LARGE_ICON_SIZE)
        self._picker = picker
        self._color = None

        self.connect('activate', self.__activate_cb, picker)
Esempio n. 10
0
    def __init__(self, color, gender):
        EventIcon.__init__(self, icon_name='%s-6' % (gender),
                           pixel_size=style.XLARGE_ICON_SIZE)
        self._gender = gender
        self._color = color

        self.set_gender()

        self.connect('button_press_event', self.__pressed_cb)
Esempio n. 11
0
    def _make_entry_widgets(self):
        '''We need to create a button for the smiley, a text entry, and a
        send button.

        All of this, along with the chatbox, goes into a grid.

        ---------------------------------------
        | chat box                            |
        | smiley button | entry | send button |
        ---------------------------------------
        '''
        if self._ebook_mode_detector.get_ebook_mode():
            self._entry_height = int(style.GRID_CELL_SIZE * 1.5)
        else:
            self._entry_height = style.GRID_CELL_SIZE
        entry_width = Gdk.Screen.width() - \
                      2 * (self._entry_height + style.GRID_CELL_SIZE)
        self._chat_height = Gdk.Screen.height() - self._entry_height - \
                            style.GRID_CELL_SIZE
        self._chat_width = Gdk.Screen.width()

        self.chatbox.set_size_request(self._chat_width, self._chat_height)

        self._entry_grid = Gtk.Grid()
        self._entry_grid.set_size_request(
            Gdk.Screen.width() - 2 * style.GRID_CELL_SIZE,
            self._entry_height)

        smiley_button = EventIcon(icon_name='smilies',
                                  pixel_size=self._entry_height)
        smiley_button.connect('button-press-event', self._smiley_button_cb)
        self._entry_grid.attach(smiley_button, 0, 0, 1, 1)
        smiley_button.show()

        self._entry = Gtk.Entry()
        self._entry.set_size_request(entry_width, self._entry_height)
        self._entry.modify_bg(Gtk.StateType.INSENSITIVE,
                              style.COLOR_WHITE.get_gdk_color())
        self._entry.modify_base(Gtk.StateType.INSENSITIVE,
                                style.COLOR_WHITE.get_gdk_color())

        self._entry.set_sensitive(False)
        self._entry.props.placeholder_text = \
            _('You must be connected to a friend before starting to chat.')

        self._entry.connect('focus-in-event', self._entry_focus_in_cb)
        self._entry.connect('focus-out-event', self._entry_focus_out_cb)
        self._entry.connect('activate', self._entry_activate_cb)
        self._entry.connect('key-press-event', self._entry_key_press_cb)
        self._entry_grid.attach(self._entry, 1, 0, 1, 1)
        self._entry.show()

        send_button = EventIcon(icon_name='send',
                                pixel_size=self._entry_height)
        send_button.connect('button-press-event', self._send_button_cb)
        self._entry_grid.attach(send_button, 2, 0, 1, 1)
        send_button.show()
Esempio n. 12
0
    def __init__(self, color, gender):
        EventIcon.__init__(self, icon_name='%s-6' % (gender),
                           pixel_size=style.XLARGE_ICON_SIZE)
        self._gender = gender
        self._color = color

        self.set_gender()

        self.connect('button_press_event', self.__pressed_cb)
Esempio n. 13
0
class AgePicker(Gtk.Grid):

    age_changed_signal = GObject.Signal('age-changed',
                                        arg_types=([int]))

    def __init__(self, color, gender, age):
        Gtk.Grid.__init__(self)
        self._color = color
        self._gender = gender
        self._age = age

        if self._gender is '':
            # Used for graphic only; does not set user's gender preference.
            self._gender = 'female'

        self._icon = EventIcon(icon_name='%s-%d' % (self._gender, self._age),
                               pixel_size=style.LARGE_ICON_SIZE)
        self._icon.connect('button-press-event', self.__pressed_cb)
        self.attach(self._icon, 0, 0, 1, 1)
        self._icon.show()

        label = Gtk.Label()
        label.set_text(AGE_LABELS[self._age])
        self.attach(label, 0, 1, 1, 1)
        label.show()

        self.set_age()

    def set_color(self, color, age):
        self._color = color
        self.set_age(age)

    def set_age(self, age=None):
        if age in AGES:
            age_index = AGES.index(age)
        else:
            age_index = None

        if age_index == self._age:
            self._icon.props.xo_color = self._color
        else:
            self._icon.props.xo_color = _NOCOLOR
        self._icon.show()

    age = GObject.property(type=object, setter=set_age)

    def set_gender(self, gender):
        self._icon.set_icon_name('%s-%d' % (gender, self._age))
        self._icon.show()

    gender = GObject.property(type=object, setter=set_gender)

    def __pressed_cb(self, button, event):
        self.age_changed_signal.emit(self._age)
Esempio n. 14
0
class AgePicker(Gtk.Grid):

    age_changed_signal = GObject.Signal('age-changed',
                                        arg_types=([int]))

    def __init__(self, color, gender, age):
        Gtk.Grid.__init__(self)
        self._color = color
        self._gender = gender
        self._age = age

        if self._gender is '':
            # Used for graphic only; does not set user's gender preference.
            self._gender = 'female'

        self._icon = EventIcon(icon_name='%s-%d' % (self._gender, self._age),
                               pixel_size=style.LARGE_ICON_SIZE)
        self._icon.connect('button-press-event', self.__pressed_cb)
        self.attach(self._icon, 0, 0, 1, 1)
        self._icon.show()

        label = Gtk.Label()
        label.set_text(AGE_LABELS[self._age])
        self.attach(label, 0, 1, 1, 1)
        label.show()

        self.set_age()

    def set_color(self, color, age):
        self._color = color
        self.set_age(age)

    def set_age(self, age=None):
        if age in AGES:
            age_index = AGES.index(age)
        else:
            age_index = None

        if age_index == self._age:
            self._icon.props.xo_color = self._color
        else:
            self._icon.props.xo_color = _NOCOLOR
        self._icon.show()

    age = GObject.property(type=object, setter=set_age)

    def set_gender(self, gender):
        self._icon.set_icon_name('%s-%d' % (gender, self._age))
        self._icon.show()

    gender = GObject.property(type=object, setter=set_gender)

    def __pressed_cb(self, button, event):
        self.age_changed_signal.emit(self._age)
Esempio n. 15
0
    def __init__(self, icon, label):
        Gtk.Grid.__init__(self)

        self._button = EventIcon(pixel_size=style.LARGE_ICON_SIZE,
                                 icon_name=icon)
        self.attach(self._button, 0, 0, 1, 1)
        self._button.hide()

        self._label = Gtk.Label(label)
        self.attach(self._label, 0, 1, 1, 1)
        self._label.hide()
Esempio n. 16
0
class GenderPicker(Gtk.Grid):

    gender_changed_signal = GObject.Signal('gender-changed', arg_types=([str]))

    def __init__(self):
        Gtk.Grid.__init__(self)
        self.set_row_spacing(style.DEFAULT_SPACING)
        self.set_column_spacing(style.DEFAULT_SPACING)

        self._gender = load_gender()
        self._buttons = []
        self._nocolor = XoColor('#010101,#ffffff')
        self._color = XoColor()

        for i, gender in enumerate(GENDERS):
            self._buttons.append(
                EventIcon(pixel_size=style.XLARGE_ICON_SIZE,
                          icon_name='%s-6' % (gender)))
            self._buttons[-1].connect('button-press-event',
                                      self._button_press_cb, i)
            self.attach(self._buttons[-1], i * 2, 0, 1, 1)
            self._buttons[-1].show()

        self.reset_button = EventIcon(pixel_size=style.SMALL_ICON_SIZE,
                                      icon_name='entry-cancel')
        self.reset_button.connect('button-press-event',
                                  self._reset_button_press_cb)
        self.attach(self.reset_button, 1, 0, 1, 1)
        self.reset_button.xo_color = XoColor('#010101,#a0a0a0')
        self.reset_button.show()

    def _reset_button_press_cb(self, widget, event):
        self._set_gender('')
        for i in range(len(GENDERS)):
            self._buttons[i].xo_color = self._nocolor

    def _button_press_cb(self, widget, event, gender_index):
        if event.button == 1 and event.type == Gdk.EventType.BUTTON_PRESS:
            self._set_gender(GENDERS[gender_index])
            self._buttons[gender_index].xo_color = self._color
            self._buttons[1 - gender_index].xo_color = self._nocolor

    def get_gender(self):
        return self._gender

    def _set_gender(self, gender):
        self.gender_changed_signal.emit(gender)
        self._gender = gender

    def update_color(self, color):
        self._color = color
        if self._gender in GENDERS:
            self._buttons[GENDERS.index(self._gender)].xo_color = self._color
Esempio n. 17
0
    def __init__(self, icon, label):
        Gtk.Grid.__init__(self)

        self._button = EventIcon(pixel_size=style.LARGE_ICON_SIZE,
                                 icon_name=icon)
        self.attach(self._button, 0, 0, 1, 1)
        self._button.hide()

        self._label = Gtk.Label(label.replace(' ', '\n'))
        self._label.props.justify = Gtk.Justification.CENTER
        self.attach(self._label, 0, 1, 1, 1)
        self._label.hide()
Esempio n. 18
0
class GenderPicker(Gtk.Grid):

    gender_changed_signal = GObject.Signal('gender-changed', arg_types=([str]))

    def __init__(self):
        Gtk.Grid.__init__(self)
        self.set_row_spacing(style.DEFAULT_SPACING)
        self.set_column_spacing(style.DEFAULT_SPACING)

        self._gender = load_gender()
        self._buttons = []
        self._nocolor = XoColor('#010101,#ffffff')
        self._color = XoColor()

        for i, gender in enumerate(GENDERS):
            self._buttons.append(EventIcon(pixel_size=style.XLARGE_ICON_SIZE,
                                           icon_name='%s-6' % (gender)))
            self._buttons[-1].connect('button-press-event',
                                      self._button_press_cb, i)
            self.attach(self._buttons[-1], i * 2, 0, 1, 1)
            self._buttons[-1].show()

        self.reset_button = EventIcon(pixel_size=style.SMALL_ICON_SIZE,
                                      icon_name='entry-cancel')
        self.reset_button.connect('button-press-event',
                                  self._reset_button_press_cb)
        self.attach(self.reset_button, 1, 0, 1, 1)
        self.reset_button.xo_color = XoColor('#010101,#a0a0a0')
        self.reset_button.show()

    def _reset_button_press_cb(self, widget, event):
        self._set_gender('')
        for i in range(len(GENDERS)):
            self._buttons[i].xo_color = self._nocolor

    def _button_press_cb(self, widget, event, gender_index):
        if event.button == 1 and event.type == Gdk.EventType.BUTTON_PRESS:
            self._set_gender(GENDERS[gender_index])
            self._buttons[gender_index].xo_color = self._color
            self._buttons[1 - gender_index].xo_color = self._nocolor

    def get_gender(self):
        return self._gender

    def _set_gender(self, gender):
        self.gender_changed_signal.emit(gender)
        self._gender = gender

    def update_color(self, color):
        self._color = color
        if self._gender in GENDERS:
            self._buttons[GENDERS.index(self._gender)].xo_color = self._color
Esempio n. 19
0
    def __init__(self):
        Gtk.Grid.__init__(self)
        self.set_row_spacing(style.DEFAULT_SPACING)
        self.set_column_spacing(style.DEFAULT_SPACING)

        self._gender = load_gender()
        self._buttons = []
        self._nocolor = XoColor('#010101,#ffffff')
        self._color = XoColor()

        for i, gender in enumerate(GENDERS):
            self._buttons.append(EventIcon(pixel_size=style.XLARGE_ICON_SIZE,
                                           icon_name='%s-6' % (gender)))
            self._buttons[-1].connect('button-press-event',
                                      self._button_press_cb, i)
            self.attach(self._buttons[-1], i * 2, 0, 1, 1)
            self._buttons[-1].show()

        self.reset_button = EventIcon(pixel_size=style.SMALL_ICON_SIZE,
                                      icon_name='entry-cancel')
        self.reset_button.connect('button-press-event',
                                  self._reset_button_press_cb)
        self.attach(self.reset_button, 1, 0, 1, 1)
        self.reset_button.xo_color = XoColor('#010101,#a0a0a0')
        self.reset_button.show()
Esempio n. 20
0
    def _choose_activity(self):
        if not hasattr(self, '_activity_sw'):
            grid = Gtk.Grid()
            self._reflection.activity.load_overlay_area(grid)
            grid.show()

            collapse_button = EventIcon(icon_name='delete', pixel_size=BUTTON_SIZE)
            collapse_button.set_tooltip(_('Collapse'))
            collapse_button.connect('button-press-event', self._reflection.activity.collapse_overlay_area)
            grid.attach(collapse_button, 7, 0, 1, 1)
            collapse_button.show()
            bundle_icons = utils.get_bundle_icons()
            x = 0
            y = 1
            for bundle_id in bundle_icons.keys():
                icon_path = bundle_icons[bundle_id]
                if icon_path is None:
                    continue
                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                    icon_path, style.GRID_CELL_SIZE, style.GRID_CELL_SIZE)
                image = Gtk.Image.new_from_pixbuf(pixbuf)
                button = Gtk.ToolButton()
                button.set_icon_widget(image)
                image.show()
                button.connect('clicked', self._insert_activity, bundle_id)
                grid.attach(button, x, y, 1, 1)
                button.show()
                x += 1
                if x > 6:
                    y += 1
                    x = 0
        self._reflection.activity.show_overlay_area()
        self._reflection.activity.reset_cursor()
Esempio n. 21
0
    def __init__(self, placeholder=None):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)

        self._button = EventIcon(icon_name='list-add')
        self._button.connect('button-release-event',
                             self.__button_release_event_cb)
        self._button.fill_color = style.COLOR_TOOLBAR_GREY.get_svg()
        self._button.set_tooltip(_('Add New'))
        self.pack_start(self._button, False, True, 0)
        self._button.show()

        self._entry = iconentry.IconEntry()
        self._entry.connect('key-press-event', self.__key_press_cb)
        if placeholder is None:
            placeholder = _('Add new entry')
        self._entry.set_placeholder_text(placeholder)
        self._entry.add_clear_button()
        self.pack_start(self._entry, True, True, 0)
        self._entry.show()
Esempio n. 22
0
    def __init__(self, icon, label):
        Gtk.Grid.__init__(self)

        self._button = EventIcon(pixel_size=style.LARGE_ICON_SIZE,
                                 icon_name=icon)
        self.attach(self._button, 0, 0, 1, 1)
        self._button.hide()

        self._label = Gtk.Label(label)
        self.attach(self._label, 0, 1, 1, 1)
        self._label.hide()
Esempio n. 23
0
    def __init__(self, color, gender, age):
        Gtk.Grid.__init__(self)
        self._color = color
        self._gender = gender
        self._age = age

        if self._gender is '':
            # Used for graphic only; does not set user's gender preference.
            self._gender = 'female'

        self._icon = EventIcon(icon_name='%s-%d' % (self._gender, self._age),
                               pixel_size=style.LARGE_ICON_SIZE)
        self._icon.connect('button-press-event', self.__pressed_cb)
        self.attach(self._icon, 0, 0, 1, 1)
        self._icon.show()

        label = Gtk.Label()
        label.set_text(AGE_LABELS[self._age])
        self.attach(label, 0, 1, 1, 1)
        label.show()

        self.set_age()
Esempio n. 24
0
    def __init__(self, placeholder=None):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)

        self._button = EventIcon(icon_name='list-add')
        self._button.connect('button-release-event',
                             self.__button_release_event_cb)
        self._button.fill_color = style.COLOR_TOOLBAR_GREY.get_svg()
        self._button.set_tooltip(_('Add New'))
        self.pack_start(self._button, False, True, 0)
        self._button.show()

        self._entry = iconentry.IconEntry()
        self._entry.connect('key-press-event', self.__key_press_cb)
        if placeholder is None:
            placeholder = _('Add new entry')
        self._entry.set_placeholder_text(placeholder)
        self._entry.add_clear_button()
        self.pack_start(self._entry, True, True, 0)
        self._entry.show()
    def add_button(self, icon_name, description, clicked_cb=None):
        icon = EventIcon(icon_name=icon_name,
                         pixel_size=(style.GRID_CELL_SIZE*2)/5,
                         xo_color=XoColor('#ffffff,#ffffff'))
        icon.props.palette = Palette(description)
        self._top_bar.add(icon)

        if clicked_cb:
            def closure(widget, event):
                alloc = widget.get_allocation()
                if 0 < event.x < alloc.width and 0 < event.y < alloc.height:
                    clicked_cb(widget)
            icon.connect('button-release-event', closure)
        icon.show()
        return icon
Esempio n. 26
0
    def __init__(self, color, gender, age):
        Gtk.Grid.__init__(self)
        self._color = color
        self._gender = gender
        self._age = age

        if self._gender is '':
            # Used for graphic only; does not set user's gender preference.
            self._gender = 'female'

        self._icon = EventIcon(icon_name='%s-%d' % (self._gender, self._age),
                               pixel_size=style.LARGE_ICON_SIZE)
        self._icon.connect('button-press-event', self.__pressed_cb)
        self.attach(self._icon, 0, 0, 1, 1)
        self._icon.show()

        label = Gtk.Label()
        label.set_text(AGE_LABELS[self._age])
        self.attach(label, 0, 1, 1, 1)
        label.show()

        self.set_age()
Esempio n. 27
0
    def _choose_activity(self):
        if not hasattr(self, '_activity_sw'):
            grid = Gtk.Grid()
            self._reflection.activity.load_overlay_area(grid)
            grid.show()

            collapse_button = EventIcon(icon_name='delete',
                                        pixel_size=BUTTON_SIZE)
            collapse_button.set_tooltip(_('Collapse'))
            collapse_button.connect(
                'button-press-event',
                self._reflection.activity.collapse_overlay_area)
            grid.attach(collapse_button, 7, 0, 1, 1)
            collapse_button.show()
            bundle_icons = utils.get_bundle_icons()
            x = 0
            y = 1
            for bundle_id in bundle_icons.keys():
                icon_path = bundle_icons[bundle_id]
                if icon_path is None:
                    continue
                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                    icon_path, style.GRID_CELL_SIZE, style.GRID_CELL_SIZE)
                image = Gtk.Image.new_from_pixbuf(pixbuf)
                button = Gtk.ToolButton()
                button.set_icon_widget(image)
                image.show()
                button.connect('clicked', self._insert_activity, bundle_id)
                grid.attach(button, x, y, 1, 1)
                button.show()
                x += 1
                if x > 6:
                    y += 1
                    x = 0
        self._reflection.activity.show_overlay_area()
        self._reflection.activity.reset_cursor()
Esempio n. 28
0
class AddNewBar(Gtk.Box):

    activate = GObject.Signal('activate', arg_types=[str])

    def __init__(self, placeholder=None):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)

        self._button = EventIcon(icon_name='list-add')
        self._button.connect('button-release-event',
                             self.__button_release_event_cb)
        self._button.fill_color = style.COLOR_TOOLBAR_GREY.get_svg()
        self._button.set_tooltip(_('Add New'))
        self.pack_start(self._button, False, True, 0)
        self._button.show()

        self._entry = iconentry.IconEntry()
        self._entry.connect('key-press-event', self.__key_press_cb)
        if placeholder is None:
            placeholder = _('Add new entry')
        self._entry.set_placeholder_text(placeholder)
        self._entry.add_clear_button()
        self.pack_start(self._entry, True, True, 0)
        self._entry.show()

    def get_entry(self):
        return self._entry

    def get_button(self):
        return self._button

    def __key_press_cb(self, window, event):
        if event.keyval == Gdk.KEY_Return:
            return self._maybe_activate()

    def __button_release_event_cb(self, button, event):
        self._maybe_activate()

    def _maybe_activate(self):
        if self._entry.props.text:
            self.activate.emit(self._entry.props.text)
            self._entry.props.text = ''
            return True
Esempio n. 29
0
class AddNewBar(Gtk.Box):

    activate = GObject.Signal('activate', arg_types=[str])

    def __init__(self, placeholder=None):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL)

        self._button = EventIcon(icon_name='list-add')
        self._button.connect('button-release-event',
                             self.__button_release_event_cb)
        self._button.fill_color = style.COLOR_TOOLBAR_GREY.get_svg()
        self._button.set_tooltip(_('Add New'))
        self.pack_start(self._button, False, True, 0)
        self._button.show()

        self._entry = iconentry.IconEntry()
        self._entry.connect('key-press-event', self.__key_press_cb)
        if placeholder is None:
            placeholder = _('Add new entry')
        self._entry.set_placeholder_text(placeholder)
        self._entry.add_clear_button()
        self.pack_start(self._entry, True, True, 0)
        self._entry.show()

    def get_entry(self):
        return self._entry

    def get_button(self):
        return self._button

    def __key_press_cb(self, window, event):
        if event.keyval == Gdk.KEY_Return:
            return self._maybe_activate()

    def __button_release_event_cb(self, button, event):
        self._maybe_activate()

    def _maybe_activate(self):
        if self._entry.props.text:
            self.activate.emit(self._entry.props.text)
            self._entry.props.text = ''
            return True
Esempio n. 30
0
class ReflectionGrid(Gtk.EventBox):
    def __init__(self, parent):
        Gtk.EventBox.__init__(self)

        self._reflection = parent
        self._collapse = True
        self._collapse_id = None

        self.modify_bg(Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color())
        self._title_color = self._reflection.activity.fg_color.get_html()

        self._grid = Gtk.Grid()
        self.add(self._grid)
        self._grid.show()

        self._grid.set_row_spacing(style.DEFAULT_PADDING)
        self._grid.set_column_spacing(style.DEFAULT_SPACING)
        self._grid.set_column_homogeneous(True)
        self._grid.set_border_width(style.DEFAULT_PADDING)

        row = 0

        self._expand_button = EventIcon(icon_name="expand", pixel_size=BUTTON_SIZE)
        self._collapse_id = self._expand_button.connect("button-press-event", self._expand_cb)
        self._grid.attach(self._expand_button, 0, row, 1, 1)
        self._expand_button.show()

        self._title_align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._title = Gtk.TextView()
        self._title.set_size_request(ENTRY_WIDTH, -1)
        self._title.set_wrap_mode(Gtk.WrapMode.WORD)
        self._title_tag = self._title.get_buffer().create_tag(
            "title", foreground=self._title_color, weight=Pango.Weight.BOLD, size=12288
        )
        iter_text = self._title.get_buffer().get_iter_at_offset(0)
        self._title.get_buffer().insert_with_tags(iter_text, self._reflection.data["title"], self._title_tag)
        if self._reflection.activity.initiating:
            self._title.connect("focus-out-event", self._title_focus_out_cb)
        else:
            self._title.set_editable(False)
        self._title_align.add(self._title)
        self._title.show()
        self._grid.attach(self._title_align, 1, row, 5, 1)
        self._title_align.show()

        """ Notification that a new comment has been shared. """
        self.notify_button = EventIcon(icon_name="chat", pixel_size=BUTTON_SIZE)
        self._grid.attach(self.notify_button, 6, row, 1, 1)
        row += 1

        self._time_align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._time = Gtk.Label()
        self._time.set_size_request(ENTRY_WIDTH, -1)
        self._time.set_justify(Gtk.Justification.LEFT)
        self._time.set_use_markup(True)
        try:
            time_string = util.timestamp_to_elapsed_string(int(self._reflection.data["modification_time"]))
        except Exception as e:
            logging.error(
                "Could not convert modification time %s: %s" % (self._reflection.data["modification_time"], e)
            )
            self._reflection.data["modification_time"] = self._reflection.data["creation_time"]
            time_string = util.timestamp_to_elapsed_string(int(self._reflection.data["modification_time"]))
        self._time.set_markup('<span foreground="#808080"><small><b>%s</b></small></span>' % time_string)
        self._time_align.add(self._time)
        self._time.show()
        self._grid.attach(self._time_align, 1, row, 5, 1)
        self._time_align.show()
        row += 1

        label = ""
        if "tags" in self._reflection.data:
            for tag in self._reflection.data["tags"]:
                if len(label) > 0:
                    label += ", "
                label += tag
        if self._reflection.activity.initiating and label == "":
            label = _("Add a #tag")
        self._tag_align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._tag_view = Gtk.TextView()
        self._tag_view.set_size_request(ENTRY_WIDTH, -1)
        self._tag_view.set_wrap_mode(Gtk.WrapMode.WORD)
        self._tag_view.get_buffer().set_text(label)
        if self._reflection.activity.initiating:
            self._tag_view.connect("focus-in-event", self._tag_focus_in_cb, _("Add a #tag"))
            self._tag_view.connect("focus-out-event", self._tags_focus_out_cb)
        else:
            self._tag_view.set_editable(False)
        self._tag_align.add(self._tag_view)
        self._tag_view.show()
        self._grid.attach(self._tag_align, 1, row, 5, 1)

        if self._reflection.activity.initiating:
            self._new_tag = EventIcon(icon_name="ok", pixel_size=BUTTON_SIZE)
            self._new_tag.connect("button-press-event", self._tag_button_cb)
            self._grid.attach(self._new_tag, 6, row, 1, 1)
        row += 1

        self._activities_align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._make_activities_grid()
        self._grid.attach(self._activities_align, 1, row, 5, 1)
        self._activities_align.show()

        if self._reflection.activity.initiating:
            self._new_activity = EventIcon(icon_name="add-item", pixel_size=BUTTON_SIZE)
            self._new_activity.connect("button-press-event", self._activity_button_cb)
            self._grid.attach(self._new_activity, 6, row, 1, 1)
            self._new_activity.show()
        row += 1

        self._stars_align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        grid = Gtk.Grid()
        if "stars" in self._reflection.data:
            stars = self._reflection.data["stars"]
        else:
            stars = 0
        self._star_icons = []
        for i in range(NUMBER_OF_STARS):
            if i < stars:
                icon_name = "star-filled"
            else:
                icon_name = "star-empty"
            self._star_icons.append(EventIcon(icon_name=icon_name, pixel_size=STAR_SIZE))
            if self._reflection.activity.initiating:
                self._star_icons[-1].connect("button-press-event", self._star_button_cb, i)
            grid.attach(self._star_icons[-1], i, 0, 1, 1)
            self._star_icons[-1].show()
        self._stars_align.add(grid)
        grid.show()
        self._grid.attach(self._stars_align, 1, row, 5, 1)
        row += 1

        self._content_aligns = []
        first_text = True
        first_image = True
        self._content_we_always_show = []
        if "content" in self._reflection.data:
            for i, item in enumerate(self._reflection.data["content"]):
                # Add edit and delete buttons
                align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
                obj = None
                if "text" in item:
                    obj = Gtk.TextView()
                    obj.set_size_request(ENTRY_WIDTH, -1)
                    obj.set_wrap_mode(Gtk.WrapMode.WORD)

                    obj.get_buffer().set_text(item["text"])
                    if self._reflection.activity.initiating:
                        obj.connect("focus-in-event", self._text_focus_in_cb)
                        obj.connect("focus-out-event", self._text_focus_out_cb, i)
                    else:
                        obj.set_editable(False)
                    if first_text:
                        self._content_we_always_show.append(align)
                        first_text = False
                elif "image" in item:
                    try:
                        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(item["image"], PICTURE_WIDTH, PICTURE_HEIGHT)
                        obj = Gtk.Image.new_from_pixbuf(pixbuf)
                        if first_image:
                            self._content_we_always_show.append(align)
                            first_image = False
                    except:
                        logging.error("could not open %s" % item["image"])
                if obj is not None:
                    align.add(obj)
                    obj.show()
                    self._grid.attach(align, 1, row, 5, 1)
                    self._content_aligns.append(align)
                    row += 1

        self._row = row
        if self._reflection.activity.initiating:
            self._new_entry = Gtk.Entry()
            self._new_entry.props.placeholder_text = _("Write a reflection")
            self._new_entry.connect("activate", self._entry_activate_cb)
            self._grid.attach(self._new_entry, 1, row, 5, 1)
            self._content_we_always_show.append(self._new_entry)
            self._new_image = EventIcon(icon_name="add-picture", pixel_size=BUTTON_SIZE)
            self._new_image.connect("button-press-event", self._image_button_cb)
            self._grid.attach(self._new_image, 6, row, 1, 1)
            self._content_we_always_show.append(self._new_image)

        for align in self._content_we_always_show:
            align.show()
        row += 1

        self._comment_row = row
        self._comment_aligns = []
        if "comments" in self._reflection.data:
            for comment in self._reflection.data["comments"]:
                obj = Gtk.TextView()
                obj.set_editable(False)
                obj.set_size_request(ENTRY_WIDTH, -1)
                obj.set_wrap_mode(Gtk.WrapMode.WORD)
                nick_tag = obj.get_buffer().create_tag("nick", foreground=comment["color"], weight=Pango.Weight.BOLD)
                iter_text = obj.get_buffer().get_iter_at_offset(0)
                obj.get_buffer().insert_with_tags(iter_text, comment["nick"] + ": ", nick_tag)
                iter_text = obj.get_buffer().get_end_iter()
                obj.get_buffer().insert(iter_text, comment["comment"])

                align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
                align.add(obj)
                obj.show()
                self._grid.attach(align, 1, self._comment_row, 5, 1)
                self._comment_aligns.append(align)
                self._comment_row += 1
        self._new_comment = Gtk.Entry()
        self._new_comment.props.placeholder_text = _("Make a comment")
        self._new_comment.connect("activate", self._comment_activate_cb)
        self._grid.attach(self._new_comment, 1, self._comment_row, 5, 1)

    def _star_button_cb(self, button, event, n):
        self.update_stars(n)
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event("%s|%s|%d" % (STAR_CMD, self._reflection.data["obj_id"], n))

    def update_stars(self, n):
        if "stars" in self._reflection.data:
            oldn = self._reflection.data["stars"]
        else:
            oldn = 0
        if n < oldn:  # Erase stars, including one that was clicked
            for i in range(NUMBER_OF_STARS):
                if i < n:
                    icon_name = "star-filled"
                else:
                    icon_name = "star-empty"
                self._star_icons[i].set_icon_name(icon_name)
            self._reflection.data["stars"] = n
        else:  # Add stars, including one that was clicked
            for i in range(NUMBER_OF_STARS):
                if i <= n:
                    icon_name = "star-filled"
                else:
                    icon_name = "star-empty"
                self._star_icons[i].set_icon_name(icon_name)
            self._reflection.data["stars"] = n + 1
        self._reflection.set_modification_time()

    def _text_focus_in_cb(self, widget, event):
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 0.9, 0.9, 0.9
        rgba.alpha = 1.0
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _text_focus_out_cb(self, widget, event, entry):
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        self._reflection.data["content"][entry]["text"] = text
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 1.0, 1.0, 1.0
        rgba.alpha = 1.0
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _tag_button_cb(self, button, event):
        bounds = self._tag_view.get_buffer().get_bounds()
        text = self._tag_view.get_buffer().get_text(bounds[0], bounds[1], True)
        self._process_tags(self._tag_view.get_buffer(), text)

    def _tag_focus_in_cb(self, widget, event, prompt=None):
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        if text == prompt:
            widget.get_buffer().set_text("")
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 0.9, 0.9, 0.9
        rgba.alpha = 1.0
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _tags_focus_out_cb(self, widget, event):
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        self._process_tags(widget.get_buffer(), text)
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 1.0, 1.0, 1.0
        rgba.alpha = 1.0
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _process_tags(self, text_buffer, text):
        """ process tag data from textview """
        self._reflection.data["tags"] = []
        label = ""
        tags = text.split()
        for tag in tags:
            if len(label) > 0:
                label += ", "
            tag = tag.rstrip(",")
            tag = tag.rstrip(";")
            if tag[0] == "#":
                self._reflection.data["tags"].append(tag)
                label += tag
            else:
                self._reflection.data["tags"].append("#" + tag)
                label += "#" + tag
        text_buffer.set_text(label.replace("\12", ""))
        if self._reflection.activity.sharing:
            data = json.dumps(self._reflection.data["tags"])
            self._reflection.activity.send_event("%s|%s|%s" % (TAG_CMD, self._reflection.data["obj_id"], data))
        self._reflection.set_modification_time()

        # Update journal entry
        dsobj = datastore.get(self._reflection.data["obj_id"])
        logging.error("setting tags to %s" % label)
        dsobj.metadata["tags"] = label
        datastore.write(
            dsobj,
            update_mtime=False,
            reply_handler=self.datastore_write_cb,
            error_handler=self.datastore_write_error_cb,
        )

    def add_tags(self, data):
        """ process encoded tag data from share """
        tags = json.loads(data)
        self._reflection.data["tags"] = tags[:]
        label = ""
        for tag in tags:
            if len(label) > 0:
                label += ", "
            label += tag
        self._tag_view.get_buffer().set_text(label)

    def _title_focus_out_cb(self, widget, event):
        """ process title text from textview """
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        self._reflection.data["title"] = text
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event("%s|%s|%s" % (TITLE_CMD, self._reflection.data["obj_id"], text))
        self._reflection.set_modification_time()

        # Update journal entry
        dsobj = datastore.get(self._reflection.data["obj_id"])
        dsobj.metadata["title"] = text
        datastore.write(
            dsobj,
            update_mtime=False,
            reply_handler=self.datastore_write_cb,
            error_handler=self.datastore_write_error_cb,
        )

    def datastore_write_cb(self):
        logging.debug("ds write cb")

    def datastore_write_error_cb(self, error):
        logging.error("datastore_write_error_cb: %r" % error)

    def update_title(self, text):
        """ process title text from share """
        self._reflection.data["title"] = text
        self._title.get_buffer().set_text("")
        iter_text = self._title.get_buffer().get_iter_at_offset(0)
        self._title.get_buffer().insert_with_tags(iter_text, text, self._title_tag)

    def _comment_activate_cb(self, entry):
        text = entry.props.text
        if not "comments" in self._reflection.data:
            self._reflection.data["comments"] = []
        data = {
            "nick": profile.get_nick_name(),
            "color": self._reflection.activity.fg_color.get_html(),
            "comment": text,
        }
        self._reflection.data["comments"].append(data)
        self.add_new_comment(data)
        # Send the comment
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event(
                "%s|%s|%s|%s|%s"
                % (COMMENT_CMD, self._reflection.data["obj_id"], data["nick"], data["color"], data["comment"])
            )
        entry.set_text("")

        # Update journal entry
        dsobj = datastore.get(self._reflection.data["obj_id"])
        if "comments" in dsobj.metadata:
            data = json.loads(dsobj.metadata["comments"])
        else:
            data = []
        data.append({"from": profile.get_nick_name(), "message": text, "icon-color": profile.get_color().to_string()})
        dsobj.metadata["comments"] = json.dumps(data)
        datastore.write(
            dsobj,
            update_mtime=False,
            reply_handler=self.datastore_write_cb,
            error_handler=self.datastore_write_error_cb,
        )

    def add_new_comment(self, comment):
        obj = Gtk.TextView()
        obj.set_size_request(ENTRY_WIDTH, -1)
        obj.set_wrap_mode(Gtk.WrapMode.WORD)

        nick_tag = obj.get_buffer().create_tag("nick", foreground=comment["color"], weight=Pango.Weight.BOLD)
        iter_text = obj.get_buffer().get_iter_at_offset(0)
        obj.get_buffer().insert_with_tags(iter_text, comment["nick"] + ": ", nick_tag)
        iter_text = obj.get_buffer().get_end_iter()
        obj.get_buffer().insert(iter_text, comment["comment"])

        align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        align.add(obj)
        obj.show()
        self._grid.insert_row(self._comment_row)
        self._grid.attach(align, 1, self._comment_row, 5, 1)
        self._comment_row += 1
        align.show()

    def _entry_activate_cb(self, entry):
        text = entry.props.text
        if not "content" in self._reflection.data:
            self._reflection.data["content"] = []
        self._reflection.data["content"].append({"text": text})
        self._reflection.set_modification_time()
        self.add_new_reflection(text)
        # Send the reflection
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event("%s|%s|%s" % (REFLECTION_CMD, self._reflection.data["obj_id"], text))
        entry.set_text("")

    def add_new_reflection(self, text):
        i = len(self._reflection.data["content"])
        obj = Gtk.TextView()
        obj.set_size_request(ENTRY_WIDTH, -1)
        obj.set_wrap_mode(Gtk.WrapMode.WORD)
        obj.get_buffer().set_text(text)
        obj.connect("focus-in-event", self._text_focus_in_cb)
        obj.connect("focus-out-event", self._text_focus_out_cb, i - 1)
        align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        align.add(obj)
        obj.show()
        self._grid.insert_row(self._row)
        self._grid.attach(align, 1, self._row, 5, 1)
        self._row += 1
        align.show()

    def _activity_button_cb(self, button, event):
        self._reflection.activity.busy_cursor()
        GObject.idle_add(self._choose_activity)

    def _choose_activity(self):
        if not hasattr(self, "_activity_sw"):
            grid = Gtk.Grid()
            self._reflection.activity.load_overlay_area(grid)
            grid.show()

            bundle_icons = utils.get_bundle_icons()
            x = 0
            y = 0
            for bundle_id in bundle_icons.keys():
                icon_path = bundle_icons[bundle_id]
                if icon_path is None:
                    continue
                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_path, style.GRID_CELL_SIZE, style.GRID_CELL_SIZE)
                image = Gtk.Image.new_from_pixbuf(pixbuf)
                button = Gtk.ToolButton()
                button.set_icon_widget(image)
                image.show()
                button.connect("clicked", self._insert_activity, bundle_id)
                grid.attach(button, x, y, 1, 1)
                button.show()
                x += 1
                if x > 6:
                    y += 1
                    x = 0
        self._reflection.activity.show_overlay_area()
        self._reflection.activity.reset_cursor()

    def _insert_activity(self, widget, bundle_id):
        """ Add activity from UI """
        self._reflection.activity.hide_overlay_area()
        self.add_activity(bundle_id)
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event(
                "%s|%s|%s" % (ACTIVITY_CMD, self._reflection.data["obj_id"], bundle_id)
            )

    def add_activity(self, bundle_id):
        """ Add activity from sharer """
        if not "activities" in self._reflection.data:
            self._reflection.data["activities"] = []
        self._reflection.data["activities"].append(utils.bundle_id_to_icon(bundle_id))
        self._reflection.set_modification_time()
        self._activities_align.remove(self._activities_grid)
        self._make_activities_grid()

    def _make_activities_grid(self):
        column = 0
        self._activities_grid = Gtk.Grid()
        self._activities = []
        if "activities" in self._reflection.data:
            for icon_path in self._reflection.data["activities"]:
                if icon_path is None:
                    continue
                try:
                    pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(icon_path, BUTTON_SIZE, BUTTON_SIZE)
                except Exception as e:
                    logging.error("Could not find icon %s: %s" % (icon_path, e))
                    continue
                self._activities.append(Gtk.Image.new_from_pixbuf(pixbuf))
                self._activities_grid.attach(self._activities[-1], column, 0, 1, 1)
                self._activities[-1].show()
                column += 1
        else:
            label = Gtk.Label("Add an activity")
            self._activities_grid.attach(label, 0, 0, 5, 1)
            label.show()
        self._activities_align.add(self._activities_grid)
        self._activities_grid.show()

    def _image_button_cb(self, button, event):
        self._reflection.activity.busy_cursor()
        GObject.idle_add(self._choose_image)

    def _choose_image(self):
        from sugar3.graphics.objectchooser import ObjectChooser

        try:
            from sugar3.graphics.objectchooser import FILTER_TYPE_GENERIC_MIME
        except:
            FILTER_TYPE_GENERIC_MIME = "generic_mime"
        from sugar3 import mime

        chooser = None
        name = None

        if hasattr(mime, "GENERIC_TYPE_IMAGE"):
            # See #2398
            if "image/svg+xml" not in mime.get_generic_type(mime.GENERIC_TYPE_IMAGE).mime_types:
                mime.get_generic_type(mime.GENERIC_TYPE_IMAGE).mime_types.append("image/svg+xml")
            try:
                chooser = ObjectChooser(
                    parent=self._reflection.activity,
                    what_filter=mime.GENERIC_TYPE_IMAGE,
                    filter_type=FILTER_TYPE_GENERIC_MIME,
                    show_preview=True,
                )
            except:
                chooser = ObjectChooser(parent=self._reflection.activity, what_filter=mime.GENERIC_TYPE_IMAGE)
        else:
            try:
                chooser = ObjectChooser(parent=self, what_filter=None)
            except TypeError:
                chooser = ObjectChooser(
                    None, self._reflection.activity, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT
                )

        if chooser is not None:
            try:
                result = chooser.run()
                if result == Gtk.ResponseType.ACCEPT:
                    jobject = chooser.get_selected_object()
                    if jobject and jobject.file_path:
                        name = jobject.metadata["title"]
                        mime_type = jobject.metadata["mime_type"]
                        _logger.debug("result of choose: %s (%s)" % (name, str(mime_type)))
            finally:
                chooser.destroy()
                del chooser

            if name is not None:
                pixbuf = self.add_new_picture(jobject.file_path)
                self._reflection.set_modification_time()
                if self._reflection.activity.sharing and pixbuf is not None:
                    self._reflection.activity.send_event(
                        "%s|%s|%s" % (PICTURE_CMD, os.path.basename(jobject.file_path), utils.pixbuf_to_base64(pixbuf))
                    )
                    self._reflection.activity.send_event(
                        "%s|%s|%s"
                        % (IMAGE_REFLECTION_CMD, self._reflection.data["obj_id"], os.path.basename(jobject.file_path))
                    )

        self._reflection.activity.reset_cursor()

    def add_new_picture(self, path):
        try:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(path, PICTURE_WIDTH, PICTURE_HEIGHT)
            obj = Gtk.Image.new_from_pixbuf(pixbuf)
        except:
            logging.error("could not open %s" % jobject.file_path)
            return None

        align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        align.add(obj)
        obj.show()
        self._grid.insert_row(self._row)
        self._grid.attach(align, 1, self._row, 5, 1)
        self._row += 1
        align.show()
        if not "content" in self._reflection.data:
            self._reflection.data["content"] = []
        self._reflection.data["content"].append({"image": path})

        if self._reflection.activity.sharing:
            return pixbuf

    def _expand_cb(self, button, event):
        self._grid.set_row_spacing(style.DEFAULT_SPACING)
        if self._collapse_id is not None:
            button.disconnect(self._collapse_id)
        button.set_icon_name("collapse")
        self._collapse_id = button.connect("button-press-event", self._collapse_cb)
        self._tag_align.show()
        if hasattr(self, "_new_tag"):
            self._new_tag.show()
        self._stars_align.show()
        for align in self._content_aligns:
            align.show()
        for align in self._comment_aligns:
            align.show()
        self._new_comment.show()

    def _collapse_cb(self, button, event):
        self._grid.set_row_spacing(0)
        if self._collapse_id is not None:
            button.disconnect(self._collapse_id)
        button.set_icon_name("expand")
        self._collapse_id = button.connect("button-press-event", self._expand_cb)
        self._tag_align.hide()
        if hasattr(self, "_new_tag"):
            self._new_tag.hide()
        self._stars_align.hide()
        for align in self._content_aligns:
            if not align in self._content_we_always_show:
                align.hide()
        for align in self._comment_aligns:
            align.hide()
        self._new_comment.hide()
Esempio n. 31
0
    def __init__(self, poll_activity):
        Gtk.EventBox.__init__(self)
        self.modify_bg(Gtk.StateType.NORMAL,
                       style.COLOR_WHITE.get_gdk_color())

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.add(box)

        poll_activity.reset_poll()

        label = Gtk.Label()
        label.set_markup('<span size="xx-large" color="%s">%s</span>'
                         % (darker_color_str, _('Choose a Poll')))
        label.set_halign(Gtk.Align.START)
        label.props.margin_top = style.GRID_CELL_SIZE
        label.props.margin_bottom = style.GRID_CELL_SIZE / 2
        label.props.margin_left = style.GRID_CELL_SIZE
        box.pack_start(label, False, False, 0)

        poll_selector_box = Gtk.VBox()
        poll_selector_box.props.margin_left = style.GRID_CELL_SIZE
        poll_selector_box.props.margin_right = style.GRID_CELL_SIZE

        scroll = Gtk.ScrolledWindow()
        scroll.modify_bg(Gtk.StateType.NORMAL,
                         style.COLOR_WHITE.get_gdk_color())
        scroll.set_valign(Gtk.Align.START)
        scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        scroll.set_size_request(
            -1, Gdk.Screen.height() - style.GRID_CELL_SIZE * 4)

        scroll.add_with_viewport(poll_selector_box)

        box.pack_start(scroll, True, True, 0)

        for poll in poll_activity._polls:
            sha = poll.sha

            poll_row = Gtk.HBox()
            poll_row.props.margin = 10
            poll_selector_box.pack_start(poll_row, False, False, 0)
            poll_selector_box.pack_start(Gtk.HSeparator(), False, False, 0)

            evbox = Gtk.EventBox()
            title = Gtk.Label()
            title.set_markup(
                '<span size="large">%s (%s)</span>' %
                (GObject.markup_escape_text(poll.title),
                 GObject.markup_escape_text(poll.author)))
            title.set_halign(Gtk.Align.START)
            title.set_max_width_chars(55)
            title.set_ellipsize(Pango.EllipsizeMode.END)

            evbox.add(title)
            poll_row.pack_start(evbox, True, True, 0)

            poll_icon = PollIcon(poll)
            poll_row.pack_start(poll_icon, False, False,
                                style.GRID_CELL_SIZE / 2)

            if poll.active:
                button = EventIcon(icon_name='activity-poll',
                                   pixel_size=style.STANDARD_ICON_SIZE)
                button.set_stroke_color('#888888')
            else:
                button = EventIcon(icon_name='toolbar-view',
                                   pixel_size=style.STANDARD_ICON_SIZE)
                button.set_fill_color('#888888')

            evbox.set_events(Gdk.EventMask.BUTTON_PRESS_MASK)
            evbox.connect('button-press-event',
                          poll_activity._select_poll_button_cb, sha)
            poll_icon.connect('button-press-event',
                              poll_activity._select_poll_button_cb, sha)
            button.connect('button-press-event',
                           poll_activity._select_poll_button_cb, sha)

            poll_row.pack_start(button, False, False, style.GRID_CELL_SIZE / 2)

            if poll.author == profile.get_nick_name():
                button = EventIcon(icon_name='basket',
                                   pixel_size=style.STANDARD_ICON_SIZE)
                button.set_stroke_color('#888888')
                button.connect('button-press-event',
                               poll_activity._delete_poll_button_cb, sha,
                               poll.title)
                poll_row.pack_start(button, False, False, 0)

        self.show_all()
Esempio n. 32
0
    def __init__(self, parent):
        Gtk.EventBox.__init__(self)

        self._reflection = parent
        self._collapse = True
        self._collapse_id = None

        self.modify_bg(Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color())
        self._title_color = self._reflection.activity.fg_color.get_html()

        self._grid = Gtk.Grid()
        self.add(self._grid)
        self._grid.show()

        self._grid.set_row_spacing(style.DEFAULT_PADDING)
        self._grid.set_column_spacing(style.DEFAULT_SPACING)
        self._grid.set_column_homogeneous(True)
        self._grid.set_border_width(style.DEFAULT_PADDING)

        row = 0

        self._expand_button = EventIcon(icon_name='expand',
                                        pixel_size=BUTTON_SIZE)
        self._collapse_id = self._expand_button.connect(
            'button-press-event', self._expand_cb)
        self._expand_button.set_tooltip(_('Expand'))
        self._grid.attach(self._expand_button, 0, row, 1, 1)
        self._expand_button.show()

        self._title_align = Gtk.Alignment.new(xalign=0,
                                              yalign=0.5,
                                              xscale=0,
                                              yscale=0)
        self._title = Gtk.TextView()
        self._title.set_size_request(ENTRY_WIDTH, -1)
        self._title.set_wrap_mode(Gtk.WrapMode.WORD)
        self._title_tag = self._title.get_buffer().create_tag(
            'title',
            foreground=self._title_color,
            weight=Pango.Weight.BOLD,
            size=12288)
        iter_text = self._title.get_buffer().get_iter_at_offset(0)
        self._title.get_buffer().insert_with_tags(
            iter_text, self._reflection.data['title'], self._title_tag)
        if self._reflection.activity.initiating:
            self._title.connect('focus-out-event', self._title_focus_out_cb)
        else:
            self._title.set_editable(False)
        self._title_align.add(self._title)
        self._title.show()
        self._grid.attach(self._title_align, 1, row, 5, 1)
        self._title_align.show()

        delete_button = EventIcon(icon_name='delete', pixel_size=BUTTON_SIZE)
        delete_button.set_tooltip(_('Delete'))
        delete_button.connect('button-press-event', self.__delete_cb)
        self._grid.attach(delete_button, 6, row, 1, 1)
        delete_button.show()
        ''' Notification that a new comment has been shared. '''
        self.notify_button = EventIcon(icon_name='chat',
                                       pixel_size=BUTTON_SIZE)
        self._grid.attach(self.notify_button, 6, row, 1, 1)
        row += 1

        self._time_align = Gtk.Alignment.new(xalign=0,
                                             yalign=0.5,
                                             xscale=0,
                                             yscale=0)
        self._time = Gtk.Label()
        self._time.set_size_request(ENTRY_WIDTH, -1)
        self._time.set_justify(Gtk.Justification.LEFT)
        self._time.set_use_markup(True)
        try:
            time_string = util.timestamp_to_elapsed_string(
                int(self._reflection.data['modification_time']))
        except Exception as e:
            logging.error('Could not convert modification time %s: %s' %
                          (self._reflection.data['modification_time'], e))
            self._reflection.data['modification_time'] = \
                self._reflection.data['creation_time']
            time_string = util.timestamp_to_elapsed_string(
                int(self._reflection.data['modification_time']))
        self._time.set_markup(
            '<span foreground="#808080"><small><b>%s</b></small></span>' %
            time_string)
        self._time_align.add(self._time)
        self._time.show()
        self._grid.attach(self._time_align, 1, row, 5, 1)
        self._time_align.show()
        row += 1

        label = ''
        if 'tags' in self._reflection.data:
            for tag in self._reflection.data['tags']:
                if len(label) > 0:
                    label += ', '
                label += tag
        if self._reflection.activity.initiating and label == '':
            label = _('Add a #tag')
        self._tag_align = Gtk.Alignment.new(xalign=0,
                                            yalign=0.5,
                                            xscale=0,
                                            yscale=0)
        self._tag_view = Gtk.TextView()
        self._tag_view.set_size_request(ENTRY_WIDTH, -1)
        self._tag_view.set_wrap_mode(Gtk.WrapMode.WORD)
        self._tag_view.get_buffer().set_text(label)
        if self._reflection.activity.initiating:
            self._tag_view.connect('focus-in-event', self._tag_focus_in_cb,
                                   _('Add a #tag'))
            self._tag_view.connect('focus-out-event', self._tags_focus_out_cb)
        else:
            self._tag_view.set_editable(False)
        self._tag_align.add(self._tag_view)
        self._tag_view.show()
        self._grid.attach(self._tag_align, 1, row, 5, 1)

        if self._reflection.activity.initiating:
            self._new_tag = EventIcon(icon_name='ok', pixel_size=BUTTON_SIZE)
            self._new_tag.connect('button-press-event', self._tag_button_cb)
            self._grid.attach(self._new_tag, 6, row, 1, 1)
        row += 1

        self._activities_align = Gtk.Alignment.new(xalign=0,
                                                   yalign=0.5,
                                                   xscale=0,
                                                   yscale=0)
        self._make_activities_grid()
        self._grid.attach(self._activities_align, 1, row, 5, 1)
        self._activities_align.show()

        if self._reflection.activity.initiating:
            self._new_activity = EventIcon(icon_name='add-item',
                                           pixel_size=BUTTON_SIZE)
            self._new_activity.set_tooltip(_('Add new activity'))
            self._new_activity.connect('button-press-event',
                                       self._activity_button_cb)
            self._grid.attach(self._new_activity, 6, row, 1, 1)
            self._new_activity.show()
        row += 1

        self._stars_align = Gtk.Alignment.new(xalign=0,
                                              yalign=0.5,
                                              xscale=0,
                                              yscale=0)
        grid = Gtk.Grid()
        if 'stars' in self._reflection.data:
            stars = self._reflection.data['stars']
        else:
            stars = 0
        self._star_icons = []
        for i in range(NUMBER_OF_STARS):
            if i < stars:
                icon_name = 'star-filled'
            else:
                icon_name = 'star-empty'
            self._star_icons.append(
                EventIcon(icon_name=icon_name, pixel_size=STAR_SIZE))
            if self._reflection.activity.initiating:
                self._star_icons[-1].connect('button-press-event',
                                             self._star_button_cb, i)
            grid.attach(self._star_icons[-1], i, 0, 1, 1)
            self._star_icons[-1].show()
        self._stars_align.add(grid)
        grid.show()
        self._grid.attach(self._stars_align, 1, row, 5, 1)
        row += 1

        self._content_aligns = []
        first_text = True
        first_image = True
        self._content_we_always_show = []
        if 'content' in self._reflection.data:
            for i, item in enumerate(self._reflection.data['content']):
                # Add edit and delete buttons
                align = Gtk.Alignment.new(xalign=0,
                                          yalign=0.5,
                                          xscale=0,
                                          yscale=0)
                obj = None
                if 'text' in item:
                    obj = Gtk.TextView()
                    obj.set_size_request(ENTRY_WIDTH, -1)
                    obj.set_wrap_mode(Gtk.WrapMode.WORD)

                    obj.get_buffer().set_text(item['text'])
                    if self._reflection.activity.initiating:
                        obj.connect('focus-in-event', self._text_focus_in_cb)
                        obj.connect('focus-out-event', self._text_focus_out_cb,
                                    i)
                    else:
                        obj.set_editable(False)
                    if first_text:
                        self._content_we_always_show.append(align)
                        first_text = False
                elif 'image' in item:
                    try:
                        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                            item['image'], PICTURE_WIDTH, PICTURE_HEIGHT)
                        obj = Gtk.Image.new_from_pixbuf(pixbuf)
                        if first_image:
                            self._content_we_always_show.append(align)
                            first_image = False
                    except BaseException:
                        logging.error('could not open %s' % item['image'])
                if obj is not None:
                    align.add(obj)
                    obj.show()
                    self._grid.attach(align, 1, row, 5, 1)
                    self._content_aligns.append(align)
                    row += 1

        self._row = row
        if self._reflection.activity.initiating:
            self._new_entry = Gtk.Entry()
            self._new_entry.props.placeholder_text = _('Write a reflection')
            self._new_entry.connect('activate', self._entry_activate_cb)
            self._grid.attach(self._new_entry, 1, row, 5, 1)
            self._content_we_always_show.append(self._new_entry)
            self._new_image = EventIcon(icon_name='add-picture',
                                        pixel_size=BUTTON_SIZE)
            self._new_image.set_tooltip(_('Add new image'))
            self._new_image.connect('button-press-event',
                                    self._image_button_cb)
            self._grid.attach(self._new_image, 6, row, 1, 1)
            self._content_we_always_show.append(self._new_image)

        for align in self._content_we_always_show:
            align.show()
        row += 1

        self._comment_row = row
        self._comment_aligns = []
        if 'comments' in self._reflection.data:
            for comment in self._reflection.data['comments']:
                obj = Gtk.TextView()
                obj.set_editable(False)
                obj.set_size_request(ENTRY_WIDTH, -1)
                obj.set_wrap_mode(Gtk.WrapMode.WORD)
                nick_tag = obj.get_buffer().create_tag(
                    'nick',
                    foreground=comment['color'],
                    weight=Pango.Weight.BOLD)
                iter_text = obj.get_buffer().get_iter_at_offset(0)
                obj.get_buffer().insert_with_tags(iter_text,
                                                  comment['nick'] + ': ',
                                                  nick_tag)
                iter_text = obj.get_buffer().get_end_iter()
                obj.get_buffer().insert(iter_text, comment['comment'])

                align = Gtk.Alignment.new(xalign=0,
                                          yalign=0.5,
                                          xscale=0,
                                          yscale=0)
                align.add(obj)
                obj.show()
                self._grid.attach(align, 1, self._comment_row, 5, 1)
                self._comment_aligns.append(align)
                self._comment_row += 1
        self._new_comment = Gtk.Entry()
        self._new_comment.props.placeholder_text = _('Make a comment')
        self._new_comment.connect('activate', self._comment_activate_cb)
        self._grid.attach(self._new_comment, 1, self._comment_row, 5, 1)
Esempio n. 33
0
class ReflectionGrid(Gtk.EventBox):
    def __init__(self, parent):
        Gtk.EventBox.__init__(self)

        self._reflection = parent
        self._collapse = True
        self._collapse_id = None

        self.modify_bg(Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color())
        self._title_color = self._reflection.activity.fg_color.get_html()

        self._grid = Gtk.Grid()
        self.add(self._grid)
        self._grid.show()

        self._grid.set_row_spacing(style.DEFAULT_PADDING)
        self._grid.set_column_spacing(style.DEFAULT_SPACING)
        self._grid.set_column_homogeneous(True)
        self._grid.set_border_width(style.DEFAULT_PADDING)

        row = 0

        self._expand_button = EventIcon(icon_name='expand',
                                        pixel_size=BUTTON_SIZE)
        self._collapse_id = self._expand_button.connect(
            'button-press-event', self._expand_cb)
        self._expand_button.set_tooltip(_('Expand'))
        self._grid.attach(self._expand_button, 0, row, 1, 1)
        self._expand_button.show()

        self._title_align = Gtk.Alignment.new(xalign=0,
                                              yalign=0.5,
                                              xscale=0,
                                              yscale=0)
        self._title = Gtk.TextView()
        self._title.set_size_request(ENTRY_WIDTH, -1)
        self._title.set_wrap_mode(Gtk.WrapMode.WORD)
        self._title_tag = self._title.get_buffer().create_tag(
            'title',
            foreground=self._title_color,
            weight=Pango.Weight.BOLD,
            size=12288)
        iter_text = self._title.get_buffer().get_iter_at_offset(0)
        self._title.get_buffer().insert_with_tags(
            iter_text, self._reflection.data['title'], self._title_tag)
        if self._reflection.activity.initiating:
            self._title.connect('focus-out-event', self._title_focus_out_cb)
        else:
            self._title.set_editable(False)
        self._title_align.add(self._title)
        self._title.show()
        self._grid.attach(self._title_align, 1, row, 5, 1)
        self._title_align.show()

        delete_button = EventIcon(icon_name='delete', pixel_size=BUTTON_SIZE)
        delete_button.set_tooltip(_('Delete'))
        delete_button.connect('button-press-event', self.__delete_cb)
        self._grid.attach(delete_button, 6, row, 1, 1)
        delete_button.show()
        ''' Notification that a new comment has been shared. '''
        self.notify_button = EventIcon(icon_name='chat',
                                       pixel_size=BUTTON_SIZE)
        self._grid.attach(self.notify_button, 6, row, 1, 1)
        row += 1

        self._time_align = Gtk.Alignment.new(xalign=0,
                                             yalign=0.5,
                                             xscale=0,
                                             yscale=0)
        self._time = Gtk.Label()
        self._time.set_size_request(ENTRY_WIDTH, -1)
        self._time.set_justify(Gtk.Justification.LEFT)
        self._time.set_use_markup(True)
        try:
            time_string = util.timestamp_to_elapsed_string(
                int(self._reflection.data['modification_time']))
        except Exception as e:
            logging.error('Could not convert modification time %s: %s' %
                          (self._reflection.data['modification_time'], e))
            self._reflection.data['modification_time'] = \
                self._reflection.data['creation_time']
            time_string = util.timestamp_to_elapsed_string(
                int(self._reflection.data['modification_time']))
        self._time.set_markup(
            '<span foreground="#808080"><small><b>%s</b></small></span>' %
            time_string)
        self._time_align.add(self._time)
        self._time.show()
        self._grid.attach(self._time_align, 1, row, 5, 1)
        self._time_align.show()
        row += 1

        label = ''
        if 'tags' in self._reflection.data:
            for tag in self._reflection.data['tags']:
                if len(label) > 0:
                    label += ', '
                label += tag
        if self._reflection.activity.initiating and label == '':
            label = _('Add a #tag')
        self._tag_align = Gtk.Alignment.new(xalign=0,
                                            yalign=0.5,
                                            xscale=0,
                                            yscale=0)
        self._tag_view = Gtk.TextView()
        self._tag_view.set_size_request(ENTRY_WIDTH, -1)
        self._tag_view.set_wrap_mode(Gtk.WrapMode.WORD)
        self._tag_view.get_buffer().set_text(label)
        if self._reflection.activity.initiating:
            self._tag_view.connect('focus-in-event', self._tag_focus_in_cb,
                                   _('Add a #tag'))
            self._tag_view.connect('focus-out-event', self._tags_focus_out_cb)
        else:
            self._tag_view.set_editable(False)
        self._tag_align.add(self._tag_view)
        self._tag_view.show()
        self._grid.attach(self._tag_align, 1, row, 5, 1)

        if self._reflection.activity.initiating:
            self._new_tag = EventIcon(icon_name='ok', pixel_size=BUTTON_SIZE)
            self._new_tag.connect('button-press-event', self._tag_button_cb)
            self._grid.attach(self._new_tag, 6, row, 1, 1)
        row += 1

        self._activities_align = Gtk.Alignment.new(xalign=0,
                                                   yalign=0.5,
                                                   xscale=0,
                                                   yscale=0)
        self._make_activities_grid()
        self._grid.attach(self._activities_align, 1, row, 5, 1)
        self._activities_align.show()

        if self._reflection.activity.initiating:
            self._new_activity = EventIcon(icon_name='add-item',
                                           pixel_size=BUTTON_SIZE)
            self._new_activity.set_tooltip(_('Add new activity'))
            self._new_activity.connect('button-press-event',
                                       self._activity_button_cb)
            self._grid.attach(self._new_activity, 6, row, 1, 1)
            self._new_activity.show()
        row += 1

        self._stars_align = Gtk.Alignment.new(xalign=0,
                                              yalign=0.5,
                                              xscale=0,
                                              yscale=0)
        grid = Gtk.Grid()
        if 'stars' in self._reflection.data:
            stars = self._reflection.data['stars']
        else:
            stars = 0
        self._star_icons = []
        for i in range(NUMBER_OF_STARS):
            if i < stars:
                icon_name = 'star-filled'
            else:
                icon_name = 'star-empty'
            self._star_icons.append(
                EventIcon(icon_name=icon_name, pixel_size=STAR_SIZE))
            if self._reflection.activity.initiating:
                self._star_icons[-1].connect('button-press-event',
                                             self._star_button_cb, i)
            grid.attach(self._star_icons[-1], i, 0, 1, 1)
            self._star_icons[-1].show()
        self._stars_align.add(grid)
        grid.show()
        self._grid.attach(self._stars_align, 1, row, 5, 1)
        row += 1

        self._content_aligns = []
        first_text = True
        first_image = True
        self._content_we_always_show = []
        if 'content' in self._reflection.data:
            for i, item in enumerate(self._reflection.data['content']):
                # Add edit and delete buttons
                align = Gtk.Alignment.new(xalign=0,
                                          yalign=0.5,
                                          xscale=0,
                                          yscale=0)
                obj = None
                if 'text' in item:
                    obj = Gtk.TextView()
                    obj.set_size_request(ENTRY_WIDTH, -1)
                    obj.set_wrap_mode(Gtk.WrapMode.WORD)

                    obj.get_buffer().set_text(item['text'])
                    if self._reflection.activity.initiating:
                        obj.connect('focus-in-event', self._text_focus_in_cb)
                        obj.connect('focus-out-event', self._text_focus_out_cb,
                                    i)
                    else:
                        obj.set_editable(False)
                    if first_text:
                        self._content_we_always_show.append(align)
                        first_text = False
                elif 'image' in item:
                    try:
                        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                            item['image'], PICTURE_WIDTH, PICTURE_HEIGHT)
                        obj = Gtk.Image.new_from_pixbuf(pixbuf)
                        if first_image:
                            self._content_we_always_show.append(align)
                            first_image = False
                    except BaseException:
                        logging.error('could not open %s' % item['image'])
                if obj is not None:
                    align.add(obj)
                    obj.show()
                    self._grid.attach(align, 1, row, 5, 1)
                    self._content_aligns.append(align)
                    row += 1

        self._row = row
        if self._reflection.activity.initiating:
            self._new_entry = Gtk.Entry()
            self._new_entry.props.placeholder_text = _('Write a reflection')
            self._new_entry.connect('activate', self._entry_activate_cb)
            self._grid.attach(self._new_entry, 1, row, 5, 1)
            self._content_we_always_show.append(self._new_entry)
            self._new_image = EventIcon(icon_name='add-picture',
                                        pixel_size=BUTTON_SIZE)
            self._new_image.set_tooltip(_('Add new image'))
            self._new_image.connect('button-press-event',
                                    self._image_button_cb)
            self._grid.attach(self._new_image, 6, row, 1, 1)
            self._content_we_always_show.append(self._new_image)

        for align in self._content_we_always_show:
            align.show()
        row += 1

        self._comment_row = row
        self._comment_aligns = []
        if 'comments' in self._reflection.data:
            for comment in self._reflection.data['comments']:
                obj = Gtk.TextView()
                obj.set_editable(False)
                obj.set_size_request(ENTRY_WIDTH, -1)
                obj.set_wrap_mode(Gtk.WrapMode.WORD)
                nick_tag = obj.get_buffer().create_tag(
                    'nick',
                    foreground=comment['color'],
                    weight=Pango.Weight.BOLD)
                iter_text = obj.get_buffer().get_iter_at_offset(0)
                obj.get_buffer().insert_with_tags(iter_text,
                                                  comment['nick'] + ': ',
                                                  nick_tag)
                iter_text = obj.get_buffer().get_end_iter()
                obj.get_buffer().insert(iter_text, comment['comment'])

                align = Gtk.Alignment.new(xalign=0,
                                          yalign=0.5,
                                          xscale=0,
                                          yscale=0)
                align.add(obj)
                obj.show()
                self._grid.attach(align, 1, self._comment_row, 5, 1)
                self._comment_aligns.append(align)
                self._comment_row += 1
        self._new_comment = Gtk.Entry()
        self._new_comment.props.placeholder_text = _('Make a comment')
        self._new_comment.connect('activate', self._comment_activate_cb)
        self._grid.attach(self._new_comment, 1, self._comment_row, 5, 1)

    def _star_button_cb(self, button, event, n):
        self.update_stars(n)
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event(
                STAR_CMD, {
                    "obj_id": self._reflection.data["obj_id"],
                    "stars": n
                })

    def update_stars(self, n):
        if 'stars' in self._reflection.data:
            oldn = self._reflection.data['stars']
        else:
            oldn = 0
        if n < oldn:  # Erase stars, including one that was clicked
            for i in range(NUMBER_OF_STARS):
                if i < n:
                    icon_name = 'star-filled'
                else:
                    icon_name = 'star-empty'
                self._star_icons[i].set_icon_name(icon_name)
            self._reflection.data['stars'] = n
        else:  # Add stars, including one that was clicked
            for i in range(NUMBER_OF_STARS):
                if i <= n:
                    icon_name = 'star-filled'
                else:
                    icon_name = 'star-empty'
                self._star_icons[i].set_icon_name(icon_name)
            self._reflection.data['stars'] = n + 1
        self._reflection.set_modification_time()

    def _text_focus_in_cb(self, widget, event):
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 0.9, 0.9, 0.9
        rgba.alpha = 1.
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _text_focus_out_cb(self, widget, event, entry):
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        self._reflection.data['content'][entry]['text'] = text
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 1., 1., 1.
        rgba.alpha = 1.
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _tag_button_cb(self, button, event):
        bounds = self._tag_view.get_buffer().get_bounds()
        text = self._tag_view.get_buffer().get_text(bounds[0], bounds[1], True)
        self._process_tags(self._tag_view.get_buffer(), text)

    def _tag_focus_in_cb(self, widget, event, prompt=None):
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        if text == prompt:
            widget.get_buffer().set_text('')
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 0.9, 0.9, 0.9
        rgba.alpha = 1.
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _tags_focus_out_cb(self, widget, event):
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        self._process_tags(widget.get_buffer(), text)
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 1., 1., 1.
        rgba.alpha = 1.
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _process_tags(self, text_buffer, text):
        ''' process tag data from textview '''
        self._reflection.data['tags'] = []
        label = ''
        tags = text.split()
        for tag in tags:
            if len(label) > 0:
                label += ', '
            tag = tag.rstrip(',')
            tag = tag.rstrip(';')
            if tag[0] == '#':
                self._reflection.data['tags'].append(tag)
                label += tag
            else:
                self._reflection.data['tags'].append('#' + tag)
                label += '#' + tag
        text_buffer.set_text(label.replace('\12', ''))
        if self._reflection.activity.sharing:
            data = json.dumps(self._reflection.data['tags'])
            self._reflection.activity.send_event(
                TAG_CMD, {
                    "obj_id": self._refelection.data["ob_id"],
                    "reflection": data
                })
        self._reflection.set_modification_time()

        # Update journal entry
        dsobj = datastore.get(self._reflection.data['obj_id'])
        logging.error('setting tags to %s' % label)
        dsobj.metadata['tags'] = label
        datastore.write(dsobj,
                        update_mtime=False,
                        reply_handler=self.datastore_write_cb,
                        error_handler=self.datastore_write_error_cb)

    def add_tags(self, data):
        ''' process encoded tag data from share '''
        tags = json.loads(data)
        self._reflection.data['tags'] = tags[:]
        label = ''
        for tag in tags:
            if len(label) > 0:
                label += ', '
            label += tag
        self._tag_view.get_buffer().set_text(label)

    def _title_focus_out_cb(self, widget, event):
        ''' process title text from textview '''
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        self._reflection.data['title'] = text
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event(
                TITLE_CMD, {
                    "obj_id": self._reflection.data["obj_id"],
                    "title": text
                })
        self._reflection.set_modification_time()

        # Update journal entry
        dsobj = datastore.get(self._reflection.data['obj_id'])
        dsobj.metadata['title'] = text
        datastore.write(dsobj,
                        update_mtime=False,
                        reply_handler=self.datastore_write_cb,
                        error_handler=self.datastore_write_error_cb)

    def datastore_write_cb(self):
        logging.debug('ds write cb')

    def datastore_write_error_cb(self, error):
        logging.error('datastore_write_error_cb: %r' % error)

    def update_title(self, text):
        ''' process title text from share '''
        self._reflection.data['title'] = text
        self._title.get_buffer().set_text('')
        iter_text = self._title.get_buffer().get_iter_at_offset(0)
        self._title.get_buffer().insert_with_tags(iter_text, text,
                                                  self._title_tag)

    def _comment_activate_cb(self, entry):
        text = entry.props.text
        if 'comments' not in self._reflection.data:
            self._reflection.data['comments'] = []
        data = {
            'nick': profile.get_nick_name(),
            'color': self._reflection.activity.fg_color.get_html(),
            'comment': text
        }
        self._reflection.data['comments'].append(data)
        self.add_new_comment(data)
        # Send the comment
        if self._reflection.activity.sharing:
            send_data = data.copy()
            send_data["obj_id"] = self._reflection.data["obj_id"]
            self._reflection.activity.send_event(COMMENT_CMD, send_data)

        entry.set_text('')

        # Update journal entry
        dsobj = datastore.get(self._reflection.data['obj_id'])
        if 'comments' in dsobj.metadata:
            data = json.loads(dsobj.metadata['comments'])
        else:
            data = []
        data.append({
            'from': profile.get_nick_name(),
            'message': text,
            'icon-color': profile.get_color().to_string()
        })
        dsobj.metadata['comments'] = json.dumps(data)
        datastore.write(dsobj,
                        update_mtime=False,
                        reply_handler=self.datastore_write_cb,
                        error_handler=self.datastore_write_error_cb)

    def add_new_comment(self, comment):
        obj = Gtk.TextView()
        obj.set_size_request(ENTRY_WIDTH, -1)
        obj.set_wrap_mode(Gtk.WrapMode.WORD)

        nick_tag = obj.get_buffer().create_tag('nick',
                                               foreground=comment['color'],
                                               weight=Pango.Weight.BOLD)
        iter_text = obj.get_buffer().get_iter_at_offset(0)
        obj.get_buffer().insert_with_tags(iter_text, comment['nick'] + ': ',
                                          nick_tag)
        iter_text = obj.get_buffer().get_end_iter()
        obj.get_buffer().insert(iter_text, comment['comment'])

        align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        align.add(obj)
        obj.show()
        self._grid.insert_row(self._comment_row)
        self._grid.attach(align, 1, self._comment_row, 5, 1)
        self._comment_row += 1
        align.show()

    def _entry_activate_cb(self, entry):
        text = entry.props.text
        if 'content' not in self._reflection.data:
            self._reflection.data['content'] = []
        self._reflection.data['content'].append({'text': text})
        self._reflection.set_modification_time()
        self.add_new_reflection(text)
        # Send the reflection
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event(
                REFLECTION_CMD, {
                    "obj_id": self._reflection.data["obj_id"],
                    "reflection": text
                })
        entry.set_text('')

    def add_new_reflection(self, text):
        i = len(self._reflection.data['content'])
        obj = Gtk.TextView()
        obj.set_size_request(ENTRY_WIDTH, -1)
        obj.set_wrap_mode(Gtk.WrapMode.WORD)
        obj.get_buffer().set_text(text)
        obj.connect('focus-in-event', self._text_focus_in_cb)
        obj.connect('focus-out-event', self._text_focus_out_cb, i - 1)
        align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        align.add(obj)
        obj.show()
        self._grid.insert_row(self._row)
        self._grid.attach(align, 1, self._row, 5, 1)
        self._row += 1
        align.show()

    def _activity_button_cb(self, button, event):
        self._reflection.activity.busy_cursor()
        GObject.idle_add(self._choose_activity)

    def _choose_activity(self):
        if not hasattr(self, '_activity_sw'):
            grid = Gtk.Grid()
            self._reflection.activity.load_overlay_area(grid)
            grid.show()

            bundle_icons = utils.get_bundle_icons()
            x = 0
            y = 0
            for bundle_id in bundle_icons.keys():
                icon_path = bundle_icons[bundle_id]
                if icon_path is None:
                    continue
                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                    icon_path, style.GRID_CELL_SIZE, style.GRID_CELL_SIZE)
                image = Gtk.Image.new_from_pixbuf(pixbuf)
                button = Gtk.ToolButton()
                button.set_icon_widget(image)
                image.show()
                button.connect('clicked', self._insert_activity, bundle_id)
                grid.attach(button, x, y, 1, 1)
                button.show()
                x += 1
                if x > 6:
                    y += 1
                    x = 0
        self._reflection.activity.show_overlay_area()
        self._reflection.activity.reset_cursor()

    def _insert_activity(self, widget, bundle_id):
        ''' Add activity from UI '''
        self._reflection.activity.hide_overlay_area()
        self.add_activity(bundle_id)
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event(
                ACTIVITY_CMD, {
                    "obj_id": self._reflection.data["obj_id"],
                    "bundle_id": bundle_id
                })

    def add_activity(self, bundle_id):
        ''' Add activity from sharer '''
        if 'activities' not in self._reflection.data:
            self._reflection.data['activities'] = []
        self._reflection.data['activities'].append(
            utils.bundle_id_to_icon(bundle_id))
        self._reflection.set_modification_time()
        self._activities_align.remove(self._activities_grid)
        self._make_activities_grid()

    def _make_activities_grid(self):
        column = 0
        self._activities_grid = Gtk.Grid()
        self._activities = []
        if 'activities' in self._reflection.data:
            for icon_path in self._reflection.data['activities']:
                if icon_path is None:
                    continue
                try:
                    pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                        icon_path, BUTTON_SIZE, BUTTON_SIZE)
                except Exception as e:
                    logging.error('Could not find icon %s: %s' %
                                  (icon_path, e))
                    continue
                self._activities.append(Gtk.Image.new_from_pixbuf(pixbuf))
                self._activities_grid.attach(self._activities[-1], column, 0,
                                             1, 1)
                self._activities[-1].show()
                column += 1
        else:
            label = Gtk.Label('Add an activity')
            self._activities_grid.attach(label, 0, 0, 5, 1)
            label.show()
        self._activities_align.add(self._activities_grid)
        self._activities_grid.show()

    def _image_button_cb(self, button, event):
        self._reflection.activity.busy_cursor()
        GObject.idle_add(self._choose_image)

    def _choose_image(self):
        from sugar3.graphics.objectchooser import ObjectChooser
        try:
            from sugar3.graphics.objectchooser import FILTER_TYPE_GENERIC_MIME
        except BaseException:
            FILTER_TYPE_GENERIC_MIME = 'generic_mime'
        from sugar3 import mime

        chooser = None
        name = None

        if hasattr(mime, 'GENERIC_TYPE_IMAGE'):
            # See #2398
            if 'image/svg+xml' not in \
                    mime.get_generic_type(mime.GENERIC_TYPE_IMAGE).mime_types:
                mime.get_generic_type(
                    mime.GENERIC_TYPE_IMAGE).mime_types.append('image/svg+xml')
            try:
                chooser = ObjectChooser(parent=self._reflection.activity,
                                        what_filter=mime.GENERIC_TYPE_IMAGE,
                                        filter_type=FILTER_TYPE_GENERIC_MIME,
                                        show_preview=True)
            except BaseException:
                chooser = ObjectChooser(parent=self._reflection.activity,
                                        what_filter=mime.GENERIC_TYPE_IMAGE)
        else:
            try:
                chooser = ObjectChooser(parent=self, what_filter=None)
            except TypeError:
                chooser = ObjectChooser(
                    None, self._reflection.activity, Gtk.DialogFlags.MODAL
                    | Gtk.DialogFlags.DESTROY_WITH_PARENT)

        if chooser is not None:
            try:
                result = chooser.run()
                if result == Gtk.ResponseType.ACCEPT:
                    jobject = chooser.get_selected_object()
                    if jobject and jobject.file_path:
                        name = jobject.metadata['title']
                        mime_type = jobject.metadata['mime_type']
                        _logger.debug('result of choose: %s (%s)' %
                                      (name, str(mime_type)))
            finally:
                chooser.destroy()
                del chooser

            if name is not None:
                pixbuf = self.add_new_picture(jobject.file_path)
                self._reflection.set_modification_time()
                if self._reflection.activity.sharing and pixbuf is not None:
                    self._reflection.activity.send_event(
                        PICTURE_CMD, {
                            "basename": os.path.basename(jobject.file_path),
                            "data": utils.pixbuf_to_base64(pixbuf)
                        })
                    self._reflection.activity.send_event(
                        IMAGE_REFLECTION_CMD, {
                            "obj_id": self._reflection.data["obj_id"],
                            "basename": os.path.basename(jobject.file_path)
                        })

        self._reflection.activity.reset_cursor()

    def add_new_picture(self, path):
        try:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                path, PICTURE_WIDTH, PICTURE_HEIGHT)
            obj = Gtk.Image.new_from_pixbuf(pixbuf)
        except BaseException:
            logging.error('could not open %s' % path)
            return None

        align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        align.add(obj)
        obj.show()
        self._grid.insert_row(self._row)
        self._grid.attach(align, 1, self._row, 5, 1)
        self._row += 1
        align.show()
        if 'content' not in self._reflection.data:
            self._reflection.data['content'] = []
        self._reflection.data['content'].append({'image': path})

        if self._reflection.activity.sharing:
            return pixbuf

    def _expand_cb(self, button, event):
        self._grid.set_row_spacing(style.DEFAULT_SPACING)
        if self._collapse_id is not None:
            button.disconnect(self._collapse_id)
        button.set_icon_name('collapse')
        button.set_tooltip(_('Collapse'))
        self._collapse_id = button.connect('button-press-event',
                                           self._collapse_cb)
        self._tag_align.show()
        if hasattr(self, '_new_tag'):
            self._new_tag.show()
        self._stars_align.show()
        for align in self._content_aligns:
            align.show()
        for align in self._comment_aligns:
            align.show()
        self._new_comment.show()

    def _collapse_cb(self, button, event):
        self._grid.set_row_spacing(0)
        if self._collapse_id is not None:
            button.disconnect(self._collapse_id)
        button.set_icon_name('expand')
        button.set_tooltip(_('Expand'))
        self._collapse_id = button.connect('button-press-event',
                                           self._expand_cb)
        self._tag_align.hide()
        if hasattr(self, '_new_tag'):
            self._new_tag.hide()
        self._stars_align.hide()
        for align in self._content_aligns:
            if align not in self._content_we_always_show:
                align.hide()
        for align in self._comment_aligns:
            align.hide()
        self._new_comment.hide()

    def __delete_cb(self, button, event):
        self._reflection.activity.delete_item(self._reflection.data['obj_id'])
        self.hide()
Esempio n. 34
0
class ReflectionGrid(Gtk.EventBox):

    def __init__(self, parent):
        Gtk.EventBox.__init__(self)

        self._reflection = parent
        self._collapse = True
        self._collapse_id = None

        self.modify_bg(
            Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color())
        self._title_color = self._reflection.activity.fg_color.get_html()

        self._grid = Gtk.Grid()
        self.add(self._grid)
        self._grid.show()

        self._grid.set_row_spacing(style.DEFAULT_PADDING)
        self._grid.set_column_spacing(style.DEFAULT_SPACING)
        self._grid.set_column_homogeneous(True)
        self._grid.set_border_width(style.DEFAULT_PADDING)

        row = 0

        self._expand_button = EventIcon(icon_name='expand',
                                        pixel_size=BUTTON_SIZE)
        self._collapse_id = self._expand_button.connect('button-press-event',
                                           self._expand_cb)
        self._expand_button.set_tooltip(_('Expand'))
        self._grid.attach(self._expand_button, 0, row, 1, 1)
        self._expand_button.show()

        self._title_align = Gtk.Alignment.new(
            xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._title = Gtk.TextView()
        self._title.set_size_request(ENTRY_WIDTH, -1)
        self._title.set_wrap_mode(Gtk.WrapMode.WORD)
        self._title_tag = self._title.get_buffer().create_tag(
            'title', foreground=self._title_color, weight=Pango.Weight.BOLD,
            size=12288)
        iter_text = self._title.get_buffer().get_iter_at_offset(0)
        self._title.get_buffer().insert_with_tags(
            iter_text, self._reflection.data['title'], self._title_tag)
        if self._reflection.activity.initiating:
            self._title.connect('focus-out-event', self._title_focus_out_cb)
        else:
            self._title.set_editable(False)
        self._title_align.add(self._title)
        self._title.show()
        self._grid.attach(self._title_align, 1, row, 5, 1)
        self._title_align.show()

        delete_button = EventIcon(icon_name='delete', pixel_size=BUTTON_SIZE)
        delete_button.set_tooltip(_('Delete'))
        delete_button.connect('button-press-event', self.__delete_cb)
        self._grid.attach(delete_button, 6, row, 1, 1)
        delete_button.show()

        ''' Notification that a new comment has been shared. '''
        self.notify_button = EventIcon(icon_name='chat',
                                       pixel_size=BUTTON_SIZE)
        self._grid.attach(self.notify_button, 6, row, 1, 1)
        row += 1

        self._time_align = Gtk.Alignment.new(
            xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._time = Gtk.Label()
        self._time.set_size_request(ENTRY_WIDTH, -1)
        self._time.set_justify(Gtk.Justification.LEFT)
        self._time.set_use_markup(True)
        try:
            time_string = util.timestamp_to_elapsed_string(
                int(self._reflection.data['modification_time']))
        except Exception as e:
            logging.error('Could not convert modification time %s: %s' %
                          (self._reflection.data['modification_time'], e))
            self._reflection.data['modification_time'] = \
                self._reflection.data['creation_time']
            time_string = util.timestamp_to_elapsed_string(
                int(self._reflection.data['modification_time']))
        self._time.set_markup(
            '<span foreground="#808080"><small><b>%s</b></small></span>' %
            time_string)
        self._time_align.add(self._time)
        self._time.show()
        self._grid.attach(self._time_align, 1, row, 5, 1)
        self._time_align.show()
        row += 1

        label = ''
        if 'tags' in self._reflection.data:
            for tag in self._reflection.data['tags']:
                if len(label) > 0:
                    label += ', '
                label += tag
        if self._reflection.activity.initiating and label == '':
            label = _('Add a #tag')
        self._tag_align = Gtk.Alignment.new(
            xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._tag_view = Gtk.TextView()
        self._tag_view.set_size_request(ENTRY_WIDTH, -1)
        self._tag_view.set_wrap_mode(Gtk.WrapMode.WORD)
        self._tag_view.get_buffer().set_text(label)
        if self._reflection.activity.initiating:
            self._tag_view.connect('focus-in-event', self._tag_focus_in_cb,
                                   _('Add a #tag'))
            self._tag_view.connect('focus-out-event', self._tags_focus_out_cb)
        else:
            self._tag_view.set_editable(False)
        self._tag_align.add(self._tag_view)
        self._tag_view.show()
        self._grid.attach(self._tag_align, 1, row, 5, 1)

        if self._reflection.activity.initiating:
            self._new_tag = EventIcon(icon_name='ok',
                                      pixel_size=BUTTON_SIZE)
            self._new_tag.connect('button-press-event',
                                  self._tag_button_cb)
            self._grid.attach(self._new_tag, 6, row, 1, 1)
        row += 1

        self._activities_align = Gtk.Alignment.new(
            xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._make_activities_grid()
        self._grid.attach(self._activities_align, 1, row, 5, 1)
        self._activities_align.show()

        if self._reflection.activity.initiating:
            self._new_activity = EventIcon(icon_name='add-item',
                                           pixel_size=BUTTON_SIZE)
            self._new_activity.set_tooltip(_('Add new activity'))
            self._new_activity.connect('button-press-event',
                                       self._activity_button_cb)
            self._grid.attach(self._new_activity, 6, row, 1, 1)
            self._new_activity.show()
        row += 1

        self._stars_align = Gtk.Alignment.new(
            xalign=0, yalign=0.5, xscale=0, yscale=0)
        grid = Gtk.Grid()
        if 'stars' in self._reflection.data:
            stars = self._reflection.data['stars']
        else:
            stars = 0
        self._star_icons = []
        for i in range(NUMBER_OF_STARS):
            if i < stars:
                icon_name = 'star-filled'
            else:
                icon_name = 'star-empty'
            self._star_icons.append(EventIcon(icon_name=icon_name,
                                              pixel_size=STAR_SIZE))
            if self._reflection.activity.initiating:
                self._star_icons[-1].connect('button-press-event',
                                             self._star_button_cb, i)
            grid.attach(self._star_icons[-1], i, 0, 1, 1)
            self._star_icons[-1].show()
        self._stars_align.add(grid)
        grid.show()
        self._grid.attach(self._stars_align, 1, row, 5, 1)
        row += 1

        self._content_aligns = []
        first_text = True
        first_image = True
        self._content_we_always_show = []
        if 'content' in self._reflection.data:
            for i, item in enumerate(self._reflection.data['content']):
                # Add edit and delete buttons
                align = Gtk.Alignment.new(
                    xalign=0, yalign=0.5, xscale=0, yscale=0)
                obj = None
                if 'text' in item:
                    obj = Gtk.TextView()
                    obj.set_size_request(ENTRY_WIDTH, -1)
                    obj.set_wrap_mode(Gtk.WrapMode.WORD)

                    obj.get_buffer().set_text(item['text'])
                    if self._reflection.activity.initiating:
                        obj.connect('focus-in-event', self._text_focus_in_cb)
                        obj.connect(
                            'focus-out-event', self._text_focus_out_cb, i)
                    else:
                        obj.set_editable(False)
                    if first_text:
                        self._content_we_always_show.append(align)
                        first_text = False
                elif 'image' in item:
                    try:
                        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                            item['image'], PICTURE_WIDTH, PICTURE_HEIGHT)
                        obj = Gtk.Image.new_from_pixbuf(pixbuf)
                        if first_image:
                            self._content_we_always_show.append(align)
                            first_image = False
                    except:
                        logging.error('could not open %s' % item['image'])
                if obj is not None:
                    align.add(obj)
                    obj.show()
                    self._grid.attach(align, 1, row, 5, 1)
                    self._content_aligns.append(align)
                    row += 1

        self._row = row
        if self._reflection.activity.initiating:
            self._new_entry = Gtk.Entry()
            self._new_entry.props.placeholder_text = _('Write a reflection')
            self._new_entry.connect('activate', self._entry_activate_cb)
            self._grid.attach(self._new_entry, 1, row, 5, 1)
            self._content_we_always_show.append(self._new_entry)
            self._new_image = EventIcon(icon_name='add-picture',
                                        pixel_size=BUTTON_SIZE)
            self._new_image.set_tooltip(_('Add new image'))
            self._new_image.connect('button-press-event', self._image_button_cb)
            self._grid.attach(self._new_image, 6, row, 1, 1)
            self._content_we_always_show.append(self._new_image)

        for align in self._content_we_always_show:
            align.show()
        row += 1

        self._comment_row = row
        self._comment_aligns = []
        if 'comments' in self._reflection.data:
            for comment in self._reflection.data['comments']:
                obj = Gtk.TextView()
                obj.set_editable(False)
                obj.set_size_request(ENTRY_WIDTH, -1)
                obj.set_wrap_mode(Gtk.WrapMode.WORD)
                nick_tag = obj.get_buffer().create_tag(
                    'nick', foreground=comment['color'],
                    weight=Pango.Weight.BOLD)
                iter_text = obj.get_buffer().get_iter_at_offset(0)
                obj.get_buffer().insert_with_tags(
                    iter_text, comment['nick'] + ': ', nick_tag)
                iter_text = obj.get_buffer().get_end_iter()
                obj.get_buffer().insert(iter_text, comment['comment'])

                align = Gtk.Alignment.new(
                    xalign=0, yalign=0.5, xscale=0, yscale=0)
                align.add(obj)
                obj.show()
                self._grid.attach(align, 1, self._comment_row, 5, 1)
                self._comment_aligns.append(align)
                self._comment_row += 1
        self._new_comment = Gtk.Entry()
        self._new_comment.props.placeholder_text = _('Make a comment')
        self._new_comment.connect('activate', self._comment_activate_cb)
        self._grid.attach(self._new_comment, 1, self._comment_row, 5, 1)

    def _star_button_cb(self, button, event, n):
        self.update_stars(n)
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event(STAR_CMD,
                {"obj_id": self._reflection.data["obj_id"], "stars": n})

    def update_stars(self, n):
        if 'stars' in self._reflection.data:
            oldn = self._reflection.data['stars']
        else:
            oldn = 0
        if n < oldn:  # Erase stars, including one that was clicked
            for i in range(NUMBER_OF_STARS):
                if i < n:
                    icon_name = 'star-filled'
                else:
                    icon_name = 'star-empty'
                self._star_icons[i].set_icon_name(icon_name)
            self._reflection.data['stars'] = n
        else:  # Add stars, including one that was clicked
            for i in range(NUMBER_OF_STARS):
                if i <= n:
                    icon_name = 'star-filled'
                else:
                    icon_name = 'star-empty'
                self._star_icons[i].set_icon_name(icon_name)
            self._reflection.data['stars'] = n + 1
        self._reflection.set_modification_time()

    def _text_focus_in_cb(self, widget, event):
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 0.9, 0.9, 0.9
        rgba.alpha = 1.
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _text_focus_out_cb(self, widget, event, entry):
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        self._reflection.data['content'][entry]['text'] = text
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 1., 1., 1.
        rgba.alpha = 1.
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _tag_button_cb(self, button, event):
        bounds = self._tag_view.get_buffer().get_bounds()
        text = self._tag_view.get_buffer().get_text(bounds[0], bounds[1], True)
        self._process_tags(self._tag_view.get_buffer(), text)

    def _tag_focus_in_cb(self, widget, event, prompt=None):
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        if text == prompt:
            widget.get_buffer().set_text('')
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 0.9, 0.9, 0.9
        rgba.alpha = 1.
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _tags_focus_out_cb(self, widget, event):
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        self._process_tags(widget.get_buffer(), text)
        rgba = Gdk.RGBA()
        rgba.red, rgba.green, rgba.blue = 1., 1., 1.
        rgba.alpha = 1.
        widget.override_background_color(Gtk.StateFlags.NORMAL, rgba)

    def _process_tags(self, text_buffer, text):
        ''' process tag data from textview '''
        self._reflection.data['tags'] = []
        label = ''
        tags = text.split()
        for tag in tags:
            if len(label) > 0:
                label += ', '
            tag = tag.rstrip(',')
            tag = tag.rstrip(';')
            if tag[0] == '#':
                self._reflection.data['tags'].append(tag)
                label += tag
            else:
                self._reflection.data['tags'].append('#' + tag)
                label += '#' + tag
        text_buffer.set_text(label.replace('\12', ''))
        if self._reflection.activity.sharing:
            data = json.dumps(self._reflection.data['tags'])
            self._reflection.activity.send_event(TAG_CMD,
                {"obj_id": self._refelection.data["ob_id"],
                 "reflection": data})
        self._reflection.set_modification_time()

        # Update journal entry
        dsobj = datastore.get(self._reflection.data['obj_id'])
        logging.error('setting tags to %s' % label)
        dsobj.metadata['tags'] = label
        datastore.write(dsobj,
                        update_mtime=False,
                        reply_handler=self.datastore_write_cb,
                        error_handler=self.datastore_write_error_cb)

    def add_tags(self, data):
        ''' process encoded tag data from share '''
        tags = json.loads(data)
        self._reflection.data['tags'] = tags[:]
        label = ''
        for tag in tags:
            if len(label) > 0:
                label += ', '
            label += tag
        self._tag_view.get_buffer().set_text(label)

    def _title_focus_out_cb(self, widget, event):
        ''' process title text from textview '''
        bounds = widget.get_buffer().get_bounds()
        text = widget.get_buffer().get_text(bounds[0], bounds[1], True)
        self._reflection.data['title'] = text
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event(TITLE_CMD,
                {"obj_id": self._reflection.data["obj_id"],
                 "title": text})
        self._reflection.set_modification_time()

        # Update journal entry
        dsobj = datastore.get(self._reflection.data['obj_id'])
        dsobj.metadata['title'] = text
        datastore.write(dsobj,
                        update_mtime=False,
                        reply_handler=self.datastore_write_cb,
                        error_handler=self.datastore_write_error_cb)

    def datastore_write_cb(self):
        logging.debug('ds write cb')

    def datastore_write_error_cb(self, error):
        logging.error('datastore_write_error_cb: %r' % error)

    def update_title(self, text):
        ''' process title text from share '''
        self._reflection.data['title'] = text
        self._title.get_buffer().set_text('')
        iter_text = self._title.get_buffer().get_iter_at_offset(0)
        self._title.get_buffer().insert_with_tags(
            iter_text, text, self._title_tag)

    def _comment_activate_cb(self, entry):
        text = entry.props.text
        if not 'comments' in self._reflection.data:
            self._reflection.data['comments'] = []
        data = {'nick': profile.get_nick_name(),
                'color': self._reflection.activity.fg_color.get_html(),
                'comment': text}
        self._reflection.data['comments'].append(data)
        self.add_new_comment(data)
        # Send the comment
        if self._reflection.activity.sharing:
            send_data = data.copy()
            send_data["obj_id"] = self._reflection.data["obj_id"]
            self._reflection.activity.send_event(COMMENT_CMD, send_data)

        entry.set_text('')

        # Update journal entry
        dsobj = datastore.get(self._reflection.data['obj_id'])
        if 'comments' in dsobj.metadata:
            data = json.loads(dsobj.metadata['comments'])
        else:
            data = []
        data.append({'from': profile.get_nick_name(),
                     'message': text,
                     'icon-color': profile.get_color().to_string()})
        dsobj.metadata['comments'] = json.dumps(data)
        datastore.write(dsobj,
                        update_mtime=False,
                        reply_handler=self.datastore_write_cb,
                        error_handler=self.datastore_write_error_cb)

    def add_new_comment(self, comment):
        obj = Gtk.TextView()
        obj.set_size_request(ENTRY_WIDTH, -1)
        obj.set_wrap_mode(Gtk.WrapMode.WORD)

        nick_tag = obj.get_buffer().create_tag(
            'nick', foreground=comment['color'],
            weight=Pango.Weight.BOLD)
        iter_text = obj.get_buffer().get_iter_at_offset(0)
        obj.get_buffer().insert_with_tags(
            iter_text, comment['nick'] + ': ', nick_tag)
        iter_text = obj.get_buffer().get_end_iter()
        obj.get_buffer().insert(iter_text, comment['comment'])

        align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        align.add(obj)
        obj.show()
        self._grid.insert_row(self._comment_row)
        self._grid.attach(align, 1, self._comment_row, 5, 1)
        self._comment_row += 1
        align.show()

    def _entry_activate_cb(self, entry):
        text = entry.props.text
        if not 'content' in self._reflection.data:
            self._reflection.data['content'] = []
        self._reflection.data['content'].append({'text': text})
        self._reflection.set_modification_time()
        self.add_new_reflection(text)
        # Send the reflection
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event(REFLECTION_CMD,
                {"obj_id": self._reflection.data["obj_id"],
                 "reflection": text})
        entry.set_text('')

    def add_new_reflection(self, text):
        i = len(self._reflection.data['content'])
        obj = Gtk.TextView()
        obj.set_size_request(ENTRY_WIDTH, -1)
        obj.set_wrap_mode(Gtk.WrapMode.WORD)
        obj.get_buffer().set_text(text)
        obj.connect('focus-in-event', self._text_focus_in_cb)
        obj.connect('focus-out-event', self._text_focus_out_cb, i - 1)
        align = Gtk.Alignment.new(xalign=0, yalign=0.5, xscale=0, yscale=0)
        align.add(obj)
        obj.show()
        self._grid.insert_row(self._row)
        self._grid.attach(align, 1, self._row, 5, 1)
        self._row += 1
        align.show()

    def _activity_button_cb(self, button, event):
        self._reflection.activity.busy_cursor()
        GObject.idle_add(self._choose_activity)

    def _choose_activity(self):
        if not hasattr(self, '_activity_sw'):
            grid = Gtk.Grid()
            self._reflection.activity.load_overlay_area(grid)
            grid.show()

            bundle_icons = utils.get_bundle_icons()
            x = 0
            y = 0
            for bundle_id in bundle_icons.keys():
                icon_path = bundle_icons[bundle_id]
                if icon_path is None:
                    continue
                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                    icon_path, style.GRID_CELL_SIZE, style.GRID_CELL_SIZE)
                image = Gtk.Image.new_from_pixbuf(pixbuf)
                button = Gtk.ToolButton()
                button.set_icon_widget(image)
                image.show()
                button.connect('clicked', self._insert_activity, bundle_id)
                grid.attach(button, x, y, 1, 1)
                button.show()
                x += 1
                if x > 6:
                    y += 1
                    x = 0
        self._reflection.activity.show_overlay_area()
        self._reflection.activity.reset_cursor()

    def _insert_activity(self, widget, bundle_id):
        ''' Add activity from UI '''
        self._reflection.activity.hide_overlay_area()
        self.add_activity(bundle_id)
        if self._reflection.activity.sharing:
            self._reflection.activity.send_event(ACTIVITY_CMD,
                {"obj_id": self._reflection.data["obj_id"],
                 "bundle_id": bundle_id})

    def add_activity(self, bundle_id):
        ''' Add activity from sharer '''
        if not 'activities' in self._reflection.data:
            self._reflection.data['activities'] = []
        self._reflection.data['activities'].append(
            utils.bundle_id_to_icon(bundle_id))
        self._reflection.set_modification_time()
        self._activities_align.remove(self._activities_grid)
        self._make_activities_grid()

    def _make_activities_grid(self):
        column = 0
        self._activities_grid = Gtk.Grid()
        self._activities = []
        if 'activities' in self._reflection.data:
            for icon_path in self._reflection.data['activities']:
                if icon_path is None:
                    continue
                try:
                    pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                        icon_path, BUTTON_SIZE, BUTTON_SIZE)
                except Exception as e:
                    logging.error('Could not find icon %s: %s' %
                                  (icon_path, e))
                    continue
                self._activities.append(Gtk.Image.new_from_pixbuf(pixbuf))
                self._activities_grid.attach(
                    self._activities[-1], column, 0, 1, 1)
                self._activities[-1].show()
                column += 1
        else:
            label = Gtk.Label('Add an activity')
            self._activities_grid.attach(label, 0, 0, 5, 1)
            label.show()
        self._activities_align.add(self._activities_grid)
        self._activities_grid.show()

    def _image_button_cb(self, button, event):
        self._reflection.activity.busy_cursor()
        GObject.idle_add(self._choose_image)

    def _choose_image(self):
        from sugar3.graphics.objectchooser import ObjectChooser
        try:
            from sugar3.graphics.objectchooser import FILTER_TYPE_GENERIC_MIME
        except:
            FILTER_TYPE_GENERIC_MIME = 'generic_mime'
        from sugar3 import mime

        chooser = None
        name = None

        if hasattr(mime, 'GENERIC_TYPE_IMAGE'):
            # See #2398
            if 'image/svg+xml' not in \
                    mime.get_generic_type(mime.GENERIC_TYPE_IMAGE).mime_types:
                mime.get_generic_type(
                    mime.GENERIC_TYPE_IMAGE).mime_types.append('image/svg+xml')
            try:
                chooser = ObjectChooser(parent=self._reflection.activity,
                                        what_filter=mime.GENERIC_TYPE_IMAGE,
                                        filter_type=FILTER_TYPE_GENERIC_MIME,
                                        show_preview=True)
            except:
                chooser = ObjectChooser(parent=self._reflection.activity,
                                        what_filter=mime.GENERIC_TYPE_IMAGE)
        else:
            try:
                chooser = ObjectChooser(parent=self, what_filter=None)
            except TypeError:
                chooser = ObjectChooser(
                    None, self._reflection.activity,
                    Gtk.DialogFlags.MODAL |
                    Gtk.DialogFlags.DESTROY_WITH_PARENT)

        if chooser is not None:
            try:
                result = chooser.run()
                if result == Gtk.ResponseType.ACCEPT:
                    jobject = chooser.get_selected_object()
                    if jobject and jobject.file_path:
                        name = jobject.metadata['title']
                        mime_type = jobject.metadata['mime_type']
                        _logger.debug('result of choose: %s (%s)' %
                                      (name, str(mime_type)))
            finally:
                chooser.destroy()
                del chooser

            if name is not None:
                pixbuf = self.add_new_picture(jobject.file_path)
                self._reflection.set_modification_time()
                if self._reflection.activity.sharing and pixbuf is not None:
                    self._reflection.activity.send_event(PICTURE_CMD,
                        {"basename": os.path.basename(jobject.file_path),
                         "data": utils.pixbuf_to_base64(pixbuf)})
                    self._reflection.activity.send_event(IMAGE_REFLECTION_CMD,
                        {"obj_id": self._reflection.data["obj_id"],
                         "basename": os.path.basename(jobject.file_path)})

        self._reflection.activity.reset_cursor()

    def add_new_picture(self, path):
        try:
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                path, PICTURE_WIDTH, PICTURE_HEIGHT)
            obj = Gtk.Image.new_from_pixbuf(pixbuf)
        except:
            logging.error('could not open %s' % jobject.file_path)
            return None

        align = Gtk.Alignment.new(
            xalign=0, yalign=0.5, xscale=0, yscale=0)
        align.add(obj)
        obj.show()
        self._grid.insert_row(self._row)
        self._grid.attach(align, 1, self._row, 5, 1)
        self._row += 1
        align.show()
        if not 'content' in self._reflection.data:
            self._reflection.data['content'] = []
        self._reflection.data['content'].append({'image': path})

        if self._reflection.activity.sharing:
            return pixbuf


    def _expand_cb(self, button, event):
        self._grid.set_row_spacing(style.DEFAULT_SPACING)
        if self._collapse_id is not None:
            button.disconnect(self._collapse_id)
        button.set_icon_name('collapse')
        button.set_tooltip(_('Collapse'))
        self._collapse_id = button.connect('button-press-event',
                                           self._collapse_cb)
        self._tag_align.show()
        if hasattr(self, '_new_tag'):
            self._new_tag.show()
        self._stars_align.show()
        for align in self._content_aligns:
            align.show()
        for align in self._comment_aligns:
            align.show()
        self._new_comment.show()

    def _collapse_cb(self, button, event):
        self._grid.set_row_spacing(0)
        if self._collapse_id is not None:
            button.disconnect(self._collapse_id)
        button.set_icon_name('expand')
        button.set_tooltip(_('Expand'))
        self._collapse_id = button.connect('button-press-event',
                                           self._expand_cb)
        self._tag_align.hide()
        if hasattr(self, '_new_tag'):
            self._new_tag.hide()
        self._stars_align.hide()
        for align in self._content_aligns:
            if not align in self._content_we_always_show:
                align.hide()
        for align in self._comment_aligns:
            align.hide()
        self._new_comment.hide()

    def __delete_cb(self, button, event):
        self._reflection.activity.delete_item(self._reflection.data['obj_id'])
        self.hide()
Esempio n. 35
0
    def __init__(self, poll_activity):
        Gtk.EventBox.__init__(self)
        self.modify_bg(Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color())

        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.add(box)

        poll_activity.reset_poll()

        label = Gtk.Label()
        label.set_markup('<span size="xx-large" color="%s">%s</span>' %
                         (darker_color_str, _('Choose a Poll')))
        label.set_halign(Gtk.Align.START)
        label.props.margin_top = style.GRID_CELL_SIZE
        label.props.margin_bottom = style.GRID_CELL_SIZE / 2
        label.props.margin_left = style.GRID_CELL_SIZE
        box.pack_start(label, False, False, 0)

        poll_selector_box = Gtk.VBox()
        poll_selector_box.props.margin_left = style.GRID_CELL_SIZE
        poll_selector_box.props.margin_right = style.GRID_CELL_SIZE

        scroll = Gtk.ScrolledWindow()
        scroll.modify_bg(Gtk.StateType.NORMAL,
                         style.COLOR_WHITE.get_gdk_color())
        scroll.set_valign(Gtk.Align.START)
        scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        scroll.set_size_request(-1,
                                Gdk.Screen.height() - style.GRID_CELL_SIZE * 4)

        scroll.add_with_viewport(poll_selector_box)

        box.pack_start(scroll, True, True, 0)

        for poll in poll_activity._polls:
            sha = poll.sha

            poll_row = Gtk.HBox()
            poll_row.props.margin = 10
            poll_selector_box.pack_start(poll_row, False, False, 0)
            poll_selector_box.pack_start(Gtk.HSeparator(), False, False, 0)

            evbox = Gtk.EventBox()
            title = Gtk.Label()
            title.set_markup('<span size="large">%s (%s)</span>' %
                             (GObject.markup_escape_text(poll.title),
                              GObject.markup_escape_text(poll.author)))
            title.set_halign(Gtk.Align.START)
            title.set_max_width_chars(55)
            title.set_ellipsize(Pango.EllipsizeMode.END)

            evbox.add(title)
            poll_row.pack_start(evbox, True, True, 0)

            poll_icon = PollIcon(poll)
            poll_row.pack_start(poll_icon, False, False,
                                style.GRID_CELL_SIZE / 2)

            if poll.active:
                button = EventIcon(icon_name='activity-poll',
                                   pixel_size=style.STANDARD_ICON_SIZE)
                button.set_stroke_color('#888888')
            else:
                button = EventIcon(icon_name='toolbar-view',
                                   pixel_size=style.STANDARD_ICON_SIZE)
                button.set_fill_color('#888888')

            evbox.set_events(Gdk.EventMask.BUTTON_PRESS_MASK)
            evbox.connect('button-press-event',
                          poll_activity._select_poll_button_cb, sha)
            poll_icon.connect('button-press-event',
                              poll_activity._select_poll_button_cb, sha)
            button.connect('button-press-event',
                           poll_activity._select_poll_button_cb, sha)

            poll_row.pack_start(button, False, False, style.GRID_CELL_SIZE / 2)

            if poll.author == profile.get_nick_name():
                button = EventIcon(icon_name='basket',
                                   pixel_size=style.STANDARD_ICON_SIZE)
                button.set_stroke_color('#888888')
                button.connect('button-press-event',
                               poll_activity._delete_poll_button_cb, sha,
                               poll.title)
                poll_row.pack_start(button, False, False, 0)

        self.show_all()
Esempio n. 36
0
class Chat(activity.Activity):
    def __init__(self, handle):
        pservice = presenceservice.get_instance()
        self.owner = pservice.get_owner()

        self._ebook_mode_detector = EbookModeDetector()

        self.chatbox = ChatBox(self.owner,
                               self._ebook_mode_detector.get_ebook_mode())
        self.chatbox.connect('open-on-journal', self.__open_on_journal)
        self.chatbox.connect('new-message',
                             self._search_entry_on_new_message_cb)

        super(Chat, self).__init__(handle)

        self._entry = None
        self._has_alert = False
        self._has_osk = False

        self._setup_canvas()

        self._entry.grab_focus()

        toolbar_box = ToolbarBox()
        self.set_toolbar_box(toolbar_box)

        self._activity_toolbar_button = ActivityToolbarButton(self)
        self._activity_toolbar_button.connect('clicked', self._fixed_resize_cb)

        toolbar_box.toolbar.insert(self._activity_toolbar_button, 0)
        self._activity_toolbar_button.show()

        self.search_entry = iconentry.IconEntry()
        self.search_entry.set_size_request(Gdk.Screen.width() / 3, -1)
        self.search_entry.set_icon_from_name(iconentry.ICON_ENTRY_PRIMARY,
                                             'entry-search')
        self.search_entry.add_clear_button()
        self.search_entry.connect('activate', self._search_entry_activate_cb)
        self.search_entry.connect('changed', self._search_entry_activate_cb)

        self.connect('key-press-event', self._search_entry_key_press_cb)

        self._search_item = Gtk.ToolItem()
        self._search_item.add(self.search_entry)
        toolbar_box.toolbar.insert(self._search_item, -1)

        self._search_prev = ToolButton('go-previous-paired')
        self._search_prev.set_tooltip(_('Previous'))
        self._search_prev.props.accelerator = "<Shift><Ctrl>g"
        self._search_prev.connect('clicked', self._search_prev_cb)
        self._search_prev.props.sensitive = False
        toolbar_box.toolbar.insert(self._search_prev, -1)

        self._search_next = ToolButton('go-next-paired')
        self._search_next.set_tooltip(_('Next'))
        self._search_next.props.accelerator = "<Ctrl>g"
        self._search_next.connect('clicked', self._search_next_cb)
        self._search_next.props.sensitive = False
        toolbar_box.toolbar.insert(self._search_next, -1)

        separator = Gtk.SeparatorToolItem()
        separator.props.draw = False
        separator.set_expand(True)
        toolbar_box.toolbar.insert(separator, -1)

        toolbar_box.toolbar.insert(StopButton(self), -1)
        toolbar_box.show_all()

        # Chat is room or one to one:
        self._chat_is_room = False
        self.text_channel = None

        self.element = Gst.ElementFactory.make('playbin', 'Player')

        if self.shared_activity:
            # we are joining the activity following an invite
            self._alert(_('Off-line'), _('Joining the Chat.'))
            self._entry.props.placeholder_text = \
                _('Please wait for a connection before starting to chat.')
            self.connect('joined', self._joined_cb)
            if self.get_shared():
                # we have already joined
                self._joined_cb(self)
        elif handle.uri:
            # XMPP non-sugar3 incoming chat, not sharable
            self._activity_toolbar_button.props.page.share.props.visible = \
                False
            self._one_to_one_connection(handle.uri)
        else:
            # we are creating the activity
            if not self.metadata or self.metadata.get(
                    'share-scope', activity.SCOPE_PRIVATE) == \
                    activity.SCOPE_PRIVATE:
                # if we are in private session
                self._alert(_('Off-line'), _('Share, or invite someone.'))
            else:
                # resume of shared activity from journal object without invite
                self._entry.props.placeholder_text = \
                    _('Please wait for a connection before starting to chat.')
            self.connect('shared', self._shared_cb)

    def _search_entry_key_press_cb(self, activity, event):
        keyname = Gdk.keyval_name(event.keyval).lower()
        if keyname == 'f':
            if Gdk.ModifierType.CONTROL_MASK & event.state:
                self.search_entry.grab_focus()
        elif keyname == 'escape':
            self.search_entry.props.text = ''
            self._entry.grab_focus()

    def _search_entry_on_new_message_cb(self, chatbox):
        self._search_entry_activate_cb(self.search_entry)

    def _search_entry_activate_cb(self, entry):
        for i in range(0, self.chatbox.number_of_textboxes()):
            textbox = self.chatbox.get_textbox(i)
            _buffer = textbox.get_buffer()
            start_mark = _buffer.get_mark('start')
            end_mark = _buffer.get_mark('end')
            if start_mark is None or end_mark is None:
                continue
            _buffer.delete_mark(start_mark)
            _buffer.delete_mark(end_mark)
            self.chatbox.highlight_text = (None, None, None)
        self.chatbox.set_search_text(entry.props.text)
        self._update_search_buttons()

    def _update_search_buttons(self, ):
        if len(self.chatbox.search_text) == 0:
            self._search_prev.props.sensitive = False
            self._search_next.props.sensitive = False
        else:
            # If next or previous result exists
            self._search_prev.props.sensitive = \
                self.chatbox.check_next('backward')
            self._search_next.props.sensitive = \
                self.chatbox.check_next('forward')

    def _search_prev_cb(self, button):
        if button.props.sensitive:
            self.chatbox.search('backward')
            self._update_search_buttons()

    def _search_next_cb(self, button):
        if button.props.sensitive:
            self.chatbox.search('forward')
            self._update_search_buttons()

    def _fixed_resize_cb(self, widget=None, rect=None):
        ''' If a toolbar opens or closes, we need to resize the vbox
        holding out scrolling window. '''
        if self._has_alert:
            dy = style.GRID_CELL_SIZE
        else:
            dy = 0
        if self._has_osk:
            if Gdk.Screen.width() > Gdk.Screen.height():
                dy += OSK_HEIGHT[0]
            else:
                dy += OSK_HEIGHT[1]

        if self._toolbar_expanded():
            self.chatbox.set_size_request(
                self._chat_width,
                self._chat_height - style.GRID_CELL_SIZE - dy)
            self._fixed.move(self._entry_grid, style.GRID_CELL_SIZE,
                             self._chat_height - style.GRID_CELL_SIZE - dy)
        else:
            self.chatbox.set_size_request(self._chat_width,
                                          self._chat_height - dy)
            self._fixed.move(self._entry_grid, style.GRID_CELL_SIZE,
                             self._chat_height - dy)

        self.chatbox.resize_conversation(dy)

    def _setup_canvas(self):
        ''' Create a canvas '''
        self._fixed = Gtk.Fixed()
        self._fixed.set_size_request(
            Gdk.Screen.width(),
            Gdk.Screen.height() - style.GRID_CELL_SIZE)
        self._fixed.connect('size-allocate', self._fixed_resize_cb)
        self.set_canvas(self._fixed)
        self._fixed.show()

        self._entry_widgets = self._make_entry_widgets()
        self._fixed.put(self.chatbox, 0, 0)
        self.chatbox.show()

        self._fixed.put(self._entry_grid, style.GRID_CELL_SIZE,
                        self._chat_height)
        self._entry_grid.show()

        Gdk.Screen.get_default().connect('size-changed', self._configure_cb)

    def _configure_cb(self, event):
        self._fixed.set_size_request(
            Gdk.Screen.width(),
            Gdk.Screen.height() - style.GRID_CELL_SIZE)
        if self._ebook_mode_detector.get_ebook_mode():
            self._entry_height = int(style.GRID_CELL_SIZE * 1.5)
        else:
            self._entry_height = style.GRID_CELL_SIZE
        entry_width = Gdk.Screen.width() - \
            2 * (self._entry_height + style.GRID_CELL_SIZE)
        self._entry.set_size_request(entry_width, self._entry_height)
        self._entry_grid.set_size_request(
            Gdk.Screen.width() - 2 * style.GRID_CELL_SIZE, self._entry_height)

        self._chat_height = Gdk.Screen.height() - self._entry_height - \
            style.GRID_CELL_SIZE
        self._chat_width = Gdk.Screen.width()
        self.chatbox.set_size_request(self._chat_width, self._chat_height)
        self.chatbox.resize_all()

        width = int(Gdk.Screen.width() - 2 * style.GRID_CELL_SIZE)
        if self._ebook_mode_detector.get_ebook_mode():
            height = int(Gdk.Screen.height() - 8 * style.GRID_CELL_SIZE)
        else:
            height = int(Gdk.Screen.height() - 5 * style.GRID_CELL_SIZE)
        self._smiley_table.set_size_request(width, height)
        self._smiley_toolbar.set_size_request(width, -1)
        self._smiley_window.set_size_request(width, -1)

        self._fixed_resize_cb()

    def _create_smiley_table(self, width):
        pixel_size = (style.STANDARD_ICON_SIZE + style.LARGE_ICON_SIZE) / 2
        spacing = style.DEFAULT_SPACING
        button_size = pixel_size + spacing
        smilies_columns = int(width / button_size)
        pad = (width - smilies_columns * button_size) / 2

        table = Gtk.Grid()
        table.set_row_spacing(spacing)
        table.set_column_spacing(spacing)
        table.set_border_width(pad)

        queue = []

        def _create_smiley_icon_idle_cb():
            try:
                x, y, path, code = queue.pop()
            except IndexError:
                self.unbusy()
                return False
            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                path, pixel_size, pixel_size)
            image = Gtk.Image.new_from_pixbuf(pixbuf)
            box = Gtk.EventBox()
            box.add(image)
            box.connect('button-press-event', self._add_smiley_to_entry, code)
            table.attach(box, x, y, 1, 1)
            box.show_all()
            return True

        x = 0
        y = 0
        smilies.init()
        for i in range(len(smilies.THEME)):
            path, hint, codes = smilies.THEME[i]
            queue.append([x, y, path, codes[0]])

            x += 1
            if x == smilies_columns:
                y += 1
                x = 0

        queue.reverse()
        GLib.idle_add(_create_smiley_icon_idle_cb)
        return table

    def _add_smiley_to_entry(self, icon, event, text):
        pos = self._entry.props.cursor_position
        self._entry.insert_text(text, pos)
        self._entry.grab_focus()
        self._entry.set_position(pos + len(text))
        self._hide_smiley_window()

    def _shared_cb(self, sender):
        self._setup()

    def _one_to_one_connection(self, tp_channel):
        '''Handle a private invite from a non-sugar3 XMPP client.'''
        if self.shared_activity or self.text_channel:
            return
        bus_name, connection, channel = json.loads(tp_channel)
        logger.debug('GOT XMPP: %s %s %s', bus_name, connection, channel)
        conn = {}
        conn_proxy = dbus.Bus().get_object(bus_name, connection)
        conn[TelepathyGLib.IFACE_CONNECTION_INTERFACE_ALIASING] = \
            dbus.Interface(
                conn_proxy, TelepathyGLib.IFACE_CONNECTION_INTERFACE_ALIASING)
        self._one_to_one_connection_ready_cb(bus_name, channel, conn)

    def _one_to_one_connection_ready_cb(self, bus_name, channel, conn):
        '''Callback for Connection for one to one connection'''
        text_channel = {}
        text_proxy = dbus.Bus().get_object(bus_name, channel)
        text_channel[TelepathyGLib.IFACE_CHANNEL] = \
            dbus.Interface(text_proxy, TelepathyGLib.IFACE_CHANNEL)
        text_channel[TelepathyGLib.IFACE_CHANNEL_TYPE_TEXT] = \
            dbus.Interface(text_proxy, TelepathyGLib.IFACE_CHANNEL_TYPE_TEXT)
        text_channel[TelepathyGLib.IFACE_CHANNEL_INTERFACE_GROUP] = \
            dbus.Interface(
                text_proxy, TelepathyGLib.IFACE_CHANNEL_INTERFACE_GROUP)
        self.text_channel = TextChannelWrapper(text_channel, conn)
        self.text_channel.set_received_callback(self._received_cb)
        self.text_channel.handle_pending_messages()
        self.text_channel.set_closed_callback(
            self._one_to_one_connection_closed_cb)
        self._chat_is_room = False
        self._alert(_('On-line'), _('Private chat.'))

        # XXX How do we detect the sender going offline?
        self._entry.set_sensitive(True)
        self.smiley_button.set_sensitive(True)
        self.send_button.set_sensitive(True)
        self._entry.props.placeholder_text = None
        self._entry.grab_focus()

    def _one_to_one_connection_closed_cb(self):
        '''Callback for when the text channel closes.'''
        self._alert(_('Off-line'), _('Left the chat.'))

    def _setup(self):
        self.text_channel = TextChannelWrapper(
            self.shared_activity.telepathy_text_chan,
            self.shared_activity.telepathy_conn)
        self.text_channel.set_received_callback(self._received_cb)
        self._alert(_('On-line'), _('Connected.'))
        self.shared_activity.connect('buddy-joined', self._buddy_joined_cb)
        self.shared_activity.connect('buddy-left', self._buddy_left_cb)
        self._chat_is_room = True
        self._entry.set_sensitive(True)
        self.smiley_button.set_sensitive(True)
        self.send_button.set_sensitive(True)
        self._entry.props.placeholder_text = None
        self._entry.grab_focus()

    def _joined_cb(self, sender):
        '''Joined a shared activity.'''
        if not self.shared_activity:
            return
        logger.debug('Joined a shared chat')
        for buddy in self.shared_activity.get_joined_buddies():
            self._buddy_already_exists(buddy)
        self._setup()

    def _received_cb(self, buddy, text):
        '''Show message that was received.'''
        if buddy:
            if type(buddy) is dict:
                nick = buddy['nick']
            else:
                nick = buddy.props.nick
        else:
            nick = '???'
        logger.debug('Received message from %s: %s', nick, text)
        self.chatbox.add_text(buddy, text)

        if self.owner.props.nick in text:
            self.play_sound('said_nick')
        '''
        vscroll = self.chatbox.get_vadjustment()
        if vscroll.get_property('value') != vscroll.get_property('upper'):
            self._alert(_('New message'), _('New message from %s' % nick))
        '''
        if not self.has_focus:
            self.notify_user(_('Message from %s') % buddy, text)

    def _toolbar_expanded(self):
        if self._activity_toolbar_button.is_expanded():
            return True
        return False

    def _alert(self, title, text=None):
        alert = NotifyAlert(timeout=5)
        alert.props.title = title
        alert.props.msg = text
        self.add_alert(alert)
        alert.connect('response', self._alert_cancel_cb)
        alert.show()
        self._has_alert = True
        self._fixed_resize_cb()

    def _alert_cancel_cb(self, alert, response_id):
        self.remove_alert(alert)
        self._has_alert = False
        self._fixed_resize_cb()

    def __open_on_journal(self, widget, url):
        '''Ask the journal to display a URL'''
        logger.debug('Create journal entry for URL: %s', url)
        jobject = datastore.create()
        metadata = {
            'title': '%s: %s' % (_('URL from Chat'), url),
            'title_set_by_user': '******',
            'icon-color': profile.get_color().to_string(),
            'mime_type': 'text/uri-list',
        }
        for k, v in list(metadata.items()):
            jobject.metadata[k] = v
        file_path = os.path.join(get_activity_root(), 'instance',
                                 '%i_' % time.time())
        open(file_path, 'w').write(url + '\r\n')
        os.chmod(file_path, 0o755)
        jobject.set_file_path(file_path)
        datastore.write(jobject)
        show_object_in_journal(jobject.object_id)
        jobject.destroy()
        os.unlink(file_path)

    def _buddy_joined_cb(self, sender, buddy):
        '''Show a buddy who joined'''
        if buddy == self.owner:
            return
        self.chatbox.add_text(buddy,
                              _('%s joined the chat') % buddy.props.nick,
                              status_message=True)

        self.play_sound('login')

    def _buddy_left_cb(self, sender, buddy):
        '''Show a buddy who joined'''
        if buddy == self.owner:
            return
        self.chatbox.add_text(buddy,
                              _('%s left the chat') % buddy.props.nick,
                              status_message=True)

        self.play_sound('logout')

    def _buddy_already_exists(self, buddy):
        '''Show a buddy already in the chat.'''
        if buddy == self.owner:
            return
        self.chatbox.add_text(buddy,
                              _('%s is here') % buddy.props.nick,
                              status_message=True)

    def can_close(self):
        '''Perform cleanup before closing.
        Close text channel of a one to one XMPP chat.
        '''
        if self._chat_is_room is False:
            if self.text_channel is not None:
                self.text_channel.close()
        return True

    def _make_entry_widgets(self):
        '''We need to create a button for the smiley, a text entry, and a
        send button.

        All of this, along with the chatbox, goes into a grid.

        ---------------------------------------
        | chat box                            |
        | smiley button | entry | send button |
        ---------------------------------------
        '''
        if self._ebook_mode_detector.get_ebook_mode():
            self._entry_height = int(style.GRID_CELL_SIZE * 1.5)
        else:
            self._entry_height = style.GRID_CELL_SIZE
        entry_width = Gdk.Screen.width() - \
            2 * (self._entry_height + style.GRID_CELL_SIZE)
        self._chat_height = Gdk.Screen.height() - self._entry_height - \
            style.GRID_CELL_SIZE
        self._chat_width = Gdk.Screen.width()

        self.chatbox.set_size_request(self._chat_width, self._chat_height)

        self._entry_grid = Gtk.Grid()
        self._entry_grid.set_size_request(
            Gdk.Screen.width() - 2 * style.GRID_CELL_SIZE, self._entry_height)

        self.smiley_button = EventIcon(icon_name='smilies',
                                       pixel_size=self._entry_height)
        self.smiley_button.connect('button-press-event',
                                   self._smiley_button_cb)
        self._entry_grid.attach(self.smiley_button, 0, 0, 1, 1)
        self.smiley_button.show()

        self._entry = Gtk.Entry()
        self._entry.set_size_request(entry_width, self._entry_height)
        self._entry.modify_bg(Gtk.StateType.INSENSITIVE,
                              style.COLOR_WHITE.get_gdk_color())
        self._entry.modify_base(Gtk.StateType.INSENSITIVE,
                                style.COLOR_WHITE.get_gdk_color())

        self._entry.props.placeholder_text = \
            _('You must be connected to a friend before starting to chat.')
        self._entry.connect('focus-in-event', self._entry_focus_in_cb)
        self._entry.connect('focus-out-event', self._entry_focus_out_cb)
        self._entry.connect('activate', self._entry_activate_cb)
        self._entry.connect('key-press-event', self._entry_key_press_cb)
        self._entry_grid.attach(self._entry, 1, 0, 1, 1)
        self._entry.show()

        self.send_button = EventIcon(icon_name='send',
                                     pixel_size=self._entry_height)
        self.send_button.connect('button-press-event', self._send_button_cb)
        self._entry_grid.attach(self.send_button, 2, 0, 1, 1)
        self.send_button.show()

        if not self.get_shared():
            self._entry.set_sensitive(False)
            self.smiley_button.set_sensitive(False)
            self.send_button.set_sensitive(False)

    def _get_icon_pixbuf(self, name):
        icon_theme = Gtk.IconTheme.get_default()
        icon_info = icon_theme.lookup_icon(name, style.LARGE_ICON_SIZE, 0)
        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
            icon_info.get_filename(), style.LARGE_ICON_SIZE,
            style.LARGE_ICON_SIZE)
        del icon_info
        return pixbuf

    def _entry_focus_in_cb(self, entry, event):
        self._hide_smiley_window()

        if self._ebook_mode_detector.get_ebook_mode():
            self._has_osk = True
            self._fixed_resize_cb()

    def _entry_focus_out_cb(self, entry, event):
        if self._ebook_mode_detector.get_ebook_mode():
            self._has_osk = False
            self._fixed_resize_cb()

    def _entry_key_press_cb(self, widget, event):
        '''Check for scrolling keys.

        Check if the user pressed Page Up, Page Down, Home or End and
        scroll the window according the pressed key.
        '''
        vadj = self.chatbox.get_vadjustment()
        if event.keyval == Gdk.KEY_Page_Down:
            value = vadj.get_value() + vadj.page_size
            if value > vadj.upper - vadj.page_size:
                value = vadj.upper - vadj.page_size
            vadj.set_value(value)
        elif event.keyval == Gdk.KEY_Page_Up:
            vadj.set_value(vadj.get_value() - vadj.page_size)
        elif event.keyval == Gdk.KEY_Home and \
                event.get_state() & Gdk.ModifierType.CONTROL_MASK:
            vadj.set_value(vadj.lower)
        elif event.keyval == Gdk.KEY_End and \
                event.get_state() & Gdk.ModifierType.CONTROL_MASK:
            vadj.set_value(vadj.upper - vadj.page_size)

    def _smiley_button_cb(self, widget, event):
        self._show_smiley_window()

    def _send_button_cb(self, widget, event):
        self._entry_activate_cb(self._entry)

    def _entry_activate_cb(self, entry):
        self.chatbox._scroll_auto = True

        text = entry.props.text
        if text:
            logger.debug('Adding text to chatbox: %s: %s' % (self.owner, text))
            self.chatbox.add_text(self.owner, text)
            entry.props.text = ''
            if self.text_channel:
                logger.debug('sending to text_channel: %s' % (text))
                self.text_channel.send(text)
            else:
                logger.debug('Tried to send message but text channel '
                             'not connected.')

    def write_file(self, file_path):
        '''Store chat log in Journal.

        Handling the Journal is provided by Activity - we only need
        to define this method.
        '''
        logger.debug('write_file: writing %s' % file_path)
        self.chatbox.add_log_timestamp()
        f = open(file_path, 'w')
        try:
            f.write(self.chatbox.get_log())
        finally:
            f.close()
        self.metadata['mime_type'] = 'text/plain'

    def read_file(self, file_path):
        '''Load a chat log from the Journal.
        Handling the Journal is provided by Activity - we only need
        to define this method.
        '''
        logger.debug('read_file: reading %s' % file_path)
        log = open(file_path).readlines()
        last_line_was_timestamp = False
        for line in log:
            if line.endswith('\t\t\n'):
                if last_line_was_timestamp is False:
                    timestamp = line.strip().split('\t')[0]
                    self.chatbox.add_separator(timestamp)
                    last_line_was_timestamp = True
            else:
                timestamp, nick, color, status, text = line.strip().split('\t')
                status_message = bool(int(status))
                self.chatbox.add_text({
                    'nick': nick,
                    'color': color
                }, text, status_message)
                last_line_was_timestamp = False

    def play_sound(self, event):
        SOUNDS_PATH = os.path.join(get_bundle_path(), 'sounds')
        SOUNDS = {
            'said_nick': os.path.join(SOUNDS_PATH, 'alert.wav'),
            'login': os.path.join(SOUNDS_PATH, 'login.wav'),
            'logout': os.path.join(SOUNDS_PATH, 'logout.wav')
        }

        self.element.set_state(Gst.State.NULL)
        self.element.set_property('uri', 'file://%s' % SOUNDS[event])
        self.element.set_state(Gst.State.PLAYING)

    def _create_smiley_window(self):
        grid = Gtk.Grid()
        width = int(Gdk.Screen.width() - 2 * style.GRID_CELL_SIZE)

        self._smiley_toolbar = SmileyToolbar(self)
        height = style.GRID_CELL_SIZE
        self._smiley_toolbar.set_size_request(width, height)
        grid.attach(self._smiley_toolbar, 0, 0, 1, 1)
        self._smiley_toolbar.show()

        self._smiley_table = Gtk.ScrolledWindow()
        self._smiley_table.set_policy(Gtk.PolicyType.NEVER,
                                      Gtk.PolicyType.AUTOMATIC)
        self._smiley_table.modify_bg(Gtk.StateType.NORMAL,
                                     style.COLOR_BLACK.get_gdk_color())
        if self._ebook_mode_detector.get_ebook_mode():
            height = int(Gdk.Screen.height() - 8 * style.GRID_CELL_SIZE)
        else:
            height = int(Gdk.Screen.height() - 4 * style.GRID_CELL_SIZE)
        self._smiley_table.set_size_request(width, height)

        table = self._create_smiley_table(width)
        self._smiley_table.add_with_viewport(table)
        table.show_all()

        grid.attach(self._smiley_table, 0, 1, 1, 1)
        self._smiley_table.show()

        self._smiley_window = Gtk.ScrolledWindow()
        self._smiley_window.set_policy(Gtk.PolicyType.NEVER,
                                       Gtk.PolicyType.NEVER)
        self._smiley_window.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
        self._smiley_window.set_size_request(width, -1)

        self._smiley_window.add_with_viewport(grid)

        def _key_press_event_cb(widget, event):
            if event.keyval == Gdk.KEY_Escape:
                self._hide_smiley_window()
                return True
            return False

        self.connect('key-press-event', _key_press_event_cb)

        grid.show()

        self._fixed.put(self._smiley_window, style.GRID_CELL_SIZE, 0)

    def _show_smiley_window(self):
        if not hasattr(self, '_smiley_window'):
            self.busy()
            self._create_smiley_window()
        self._smiley_window.show()

    def _hide_smiley_window(self):
        if hasattr(self, '_smiley_window'):
            self._smiley_window.hide()
Esempio n. 37
0
    def __init__(self, parent):
        Gtk.EventBox.__init__(self)

        self._reflection = parent
        self._collapse = True
        self._collapse_id = None

        self.modify_bg(
            Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color())
        self._title_color = self._reflection.activity.fg_color.get_html()

        self._grid = Gtk.Grid()
        self.add(self._grid)
        self._grid.show()

        self._grid.set_row_spacing(style.DEFAULT_PADDING)
        self._grid.set_column_spacing(style.DEFAULT_SPACING)
        self._grid.set_column_homogeneous(True)
        self._grid.set_border_width(style.DEFAULT_PADDING)

        row = 0

        self._expand_button = EventIcon(icon_name='expand',
                                        pixel_size=BUTTON_SIZE)
        self._collapse_id = self._expand_button.connect('button-press-event',
                                           self._expand_cb)
        self._expand_button.set_tooltip(_('Expand'))
        self._grid.attach(self._expand_button, 0, row, 1, 1)
        self._expand_button.show()

        self._title_align = Gtk.Alignment.new(
            xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._title = Gtk.TextView()
        self._title.set_size_request(ENTRY_WIDTH, -1)
        self._title.set_wrap_mode(Gtk.WrapMode.WORD)
        self._title_tag = self._title.get_buffer().create_tag(
            'title', foreground=self._title_color, weight=Pango.Weight.BOLD,
            size=12288)
        iter_text = self._title.get_buffer().get_iter_at_offset(0)
        self._title.get_buffer().insert_with_tags(
            iter_text, self._reflection.data['title'], self._title_tag)
        if self._reflection.activity.initiating:
            self._title.connect('focus-out-event', self._title_focus_out_cb)
        else:
            self._title.set_editable(False)
        self._title_align.add(self._title)
        self._title.show()
        self._grid.attach(self._title_align, 1, row, 5, 1)
        self._title_align.show()

        delete_button = EventIcon(icon_name='delete', pixel_size=BUTTON_SIZE)
        delete_button.set_tooltip(_('Delete'))
        delete_button.connect('button-press-event', self.__delete_cb)
        self._grid.attach(delete_button, 6, row, 1, 1)
        delete_button.show()

        ''' Notification that a new comment has been shared. '''
        self.notify_button = EventIcon(icon_name='chat',
                                       pixel_size=BUTTON_SIZE)
        self._grid.attach(self.notify_button, 6, row, 1, 1)
        row += 1

        self._time_align = Gtk.Alignment.new(
            xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._time = Gtk.Label()
        self._time.set_size_request(ENTRY_WIDTH, -1)
        self._time.set_justify(Gtk.Justification.LEFT)
        self._time.set_use_markup(True)
        try:
            time_string = util.timestamp_to_elapsed_string(
                int(self._reflection.data['modification_time']))
        except Exception as e:
            logging.error('Could not convert modification time %s: %s' %
                          (self._reflection.data['modification_time'], e))
            self._reflection.data['modification_time'] = \
                self._reflection.data['creation_time']
            time_string = util.timestamp_to_elapsed_string(
                int(self._reflection.data['modification_time']))
        self._time.set_markup(
            '<span foreground="#808080"><small><b>%s</b></small></span>' %
            time_string)
        self._time_align.add(self._time)
        self._time.show()
        self._grid.attach(self._time_align, 1, row, 5, 1)
        self._time_align.show()
        row += 1

        label = ''
        if 'tags' in self._reflection.data:
            for tag in self._reflection.data['tags']:
                if len(label) > 0:
                    label += ', '
                label += tag
        if self._reflection.activity.initiating and label == '':
            label = _('Add a #tag')
        self._tag_align = Gtk.Alignment.new(
            xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._tag_view = Gtk.TextView()
        self._tag_view.set_size_request(ENTRY_WIDTH, -1)
        self._tag_view.set_wrap_mode(Gtk.WrapMode.WORD)
        self._tag_view.get_buffer().set_text(label)
        if self._reflection.activity.initiating:
            self._tag_view.connect('focus-in-event', self._tag_focus_in_cb,
                                   _('Add a #tag'))
            self._tag_view.connect('focus-out-event', self._tags_focus_out_cb)
        else:
            self._tag_view.set_editable(False)
        self._tag_align.add(self._tag_view)
        self._tag_view.show()
        self._grid.attach(self._tag_align, 1, row, 5, 1)

        if self._reflection.activity.initiating:
            self._new_tag = EventIcon(icon_name='ok',
                                      pixel_size=BUTTON_SIZE)
            self._new_tag.connect('button-press-event',
                                  self._tag_button_cb)
            self._grid.attach(self._new_tag, 6, row, 1, 1)
        row += 1

        self._activities_align = Gtk.Alignment.new(
            xalign=0, yalign=0.5, xscale=0, yscale=0)
        self._make_activities_grid()
        self._grid.attach(self._activities_align, 1, row, 5, 1)
        self._activities_align.show()

        if self._reflection.activity.initiating:
            self._new_activity = EventIcon(icon_name='add-item',
                                           pixel_size=BUTTON_SIZE)
            self._new_activity.set_tooltip(_('Add new activity'))
            self._new_activity.connect('button-press-event',
                                       self._activity_button_cb)
            self._grid.attach(self._new_activity, 6, row, 1, 1)
            self._new_activity.show()
        row += 1

        self._stars_align = Gtk.Alignment.new(
            xalign=0, yalign=0.5, xscale=0, yscale=0)
        grid = Gtk.Grid()
        if 'stars' in self._reflection.data:
            stars = self._reflection.data['stars']
        else:
            stars = 0
        self._star_icons = []
        for i in range(NUMBER_OF_STARS):
            if i < stars:
                icon_name = 'star-filled'
            else:
                icon_name = 'star-empty'
            self._star_icons.append(EventIcon(icon_name=icon_name,
                                              pixel_size=STAR_SIZE))
            if self._reflection.activity.initiating:
                self._star_icons[-1].connect('button-press-event',
                                             self._star_button_cb, i)
            grid.attach(self._star_icons[-1], i, 0, 1, 1)
            self._star_icons[-1].show()
        self._stars_align.add(grid)
        grid.show()
        self._grid.attach(self._stars_align, 1, row, 5, 1)
        row += 1

        self._content_aligns = []
        first_text = True
        first_image = True
        self._content_we_always_show = []
        if 'content' in self._reflection.data:
            for i, item in enumerate(self._reflection.data['content']):
                # Add edit and delete buttons
                align = Gtk.Alignment.new(
                    xalign=0, yalign=0.5, xscale=0, yscale=0)
                obj = None
                if 'text' in item:
                    obj = Gtk.TextView()
                    obj.set_size_request(ENTRY_WIDTH, -1)
                    obj.set_wrap_mode(Gtk.WrapMode.WORD)

                    obj.get_buffer().set_text(item['text'])
                    if self._reflection.activity.initiating:
                        obj.connect('focus-in-event', self._text_focus_in_cb)
                        obj.connect(
                            'focus-out-event', self._text_focus_out_cb, i)
                    else:
                        obj.set_editable(False)
                    if first_text:
                        self._content_we_always_show.append(align)
                        first_text = False
                elif 'image' in item:
                    try:
                        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(
                            item['image'], PICTURE_WIDTH, PICTURE_HEIGHT)
                        obj = Gtk.Image.new_from_pixbuf(pixbuf)
                        if first_image:
                            self._content_we_always_show.append(align)
                            first_image = False
                    except:
                        logging.error('could not open %s' % item['image'])
                if obj is not None:
                    align.add(obj)
                    obj.show()
                    self._grid.attach(align, 1, row, 5, 1)
                    self._content_aligns.append(align)
                    row += 1

        self._row = row
        if self._reflection.activity.initiating:
            self._new_entry = Gtk.Entry()
            self._new_entry.props.placeholder_text = _('Write a reflection')
            self._new_entry.connect('activate', self._entry_activate_cb)
            self._grid.attach(self._new_entry, 1, row, 5, 1)
            self._content_we_always_show.append(self._new_entry)
            self._new_image = EventIcon(icon_name='add-picture',
                                        pixel_size=BUTTON_SIZE)
            self._new_image.set_tooltip(_('Add new image'))
            self._new_image.connect('button-press-event', self._image_button_cb)
            self._grid.attach(self._new_image, 6, row, 1, 1)
            self._content_we_always_show.append(self._new_image)

        for align in self._content_we_always_show:
            align.show()
        row += 1

        self._comment_row = row
        self._comment_aligns = []
        if 'comments' in self._reflection.data:
            for comment in self._reflection.data['comments']:
                obj = Gtk.TextView()
                obj.set_editable(False)
                obj.set_size_request(ENTRY_WIDTH, -1)
                obj.set_wrap_mode(Gtk.WrapMode.WORD)
                nick_tag = obj.get_buffer().create_tag(
                    'nick', foreground=comment['color'],
                    weight=Pango.Weight.BOLD)
                iter_text = obj.get_buffer().get_iter_at_offset(0)
                obj.get_buffer().insert_with_tags(
                    iter_text, comment['nick'] + ': ', nick_tag)
                iter_text = obj.get_buffer().get_end_iter()
                obj.get_buffer().insert(iter_text, comment['comment'])

                align = Gtk.Alignment.new(
                    xalign=0, yalign=0.5, xscale=0, yscale=0)
                align.add(obj)
                obj.show()
                self._grid.attach(align, 1, self._comment_row, 5, 1)
                self._comment_aligns.append(align)
                self._comment_row += 1
        self._new_comment = Gtk.Entry()
        self._new_comment.props.placeholder_text = _('Make a comment')
        self._new_comment.connect('activate', self._comment_activate_cb)
        self._grid.attach(self._new_comment, 1, self._comment_row, 5, 1)
Esempio n. 38
0
from gi.repository import Gtk

from sugar3.graphics.icon import EventIcon
from sugar3.graphics.icon import Icon

import common

test = common.Test()
test.show()

vbox = Gtk.VBox()
test.pack_start(vbox, True, True, 0)
vbox.show()

icon = Icon(icon_name="network-wireless-000")
icon.props.badge_name = 'emblem-favorite'
vbox.pack_start(icon, False, False, 0)
icon.show()

icon = EventIcon(icon_name="network-wireless-000")
icon.props.badge_name = 'emblem-favorite'
vbox.pack_start(icon, False, False, 0)
icon.show()

if __name__ == '__main__':
    common.main(test)