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()
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
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
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()
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)
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()
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)
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()