Some more usability fixes for the clipboard.

This commit is contained in:
Tomeu Vizoso 2007-01-11 23:57:06 +01:00
parent d0ce5a07d5
commit 334be3331b
12 changed files with 168 additions and 83 deletions

View File

@ -27,6 +27,9 @@ class ClipboardObject:
def get_preview(self): def get_preview(self):
return self._get_type_info().get_preview() return self._get_type_info().get_preview()
def get_activity(self):
return self._get_type_info().get_activity()
def get_percent(self): def get_percent(self):
return self._percent return self._percent

View File

@ -26,6 +26,7 @@ NAME_KEY = 'NAME'
PERCENT_KEY = 'PERCENT' PERCENT_KEY = 'PERCENT'
ICON_KEY = 'ICON' ICON_KEY = 'ICON'
PREVIEW_KEY = 'PREVIEW' PREVIEW_KEY = 'PREVIEW'
ACTIVITY_KEY = 'ACTIVITY'
FORMATS_KEY = 'FORMATS' FORMATS_KEY = 'FORMATS'
class ClipboardDBusServiceHelper(dbus.service.Object): class ClipboardDBusServiceHelper(dbus.service.Object):
@ -63,7 +64,8 @@ class ClipboardDBusServiceHelper(dbus.service.Object):
self.object_state_changed(object_id, {NAME_KEY: cb_object.get_name(), self.object_state_changed(object_id, {NAME_KEY: cb_object.get_name(),
PERCENT_KEY: cb_object.get_percent(), PERCENT_KEY: cb_object.get_percent(),
ICON_KEY: cb_object.get_icon(), ICON_KEY: cb_object.get_icon(),
PREVIEW_KEY: cb_object.get_preview()}) PREVIEW_KEY: cb_object.get_preview(),
ACTIVITY_KEY: cb_object.get_activity()})
@dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE,
in_signature="s", out_signature="") in_signature="s", out_signature="")
@ -80,7 +82,8 @@ class ClipboardDBusServiceHelper(dbus.service.Object):
self.object_state_changed(object_id, {NAME_KEY: cb_object.get_name(), self.object_state_changed(object_id, {NAME_KEY: cb_object.get_name(),
PERCENT_KEY: percent, PERCENT_KEY: percent,
ICON_KEY: cb_object.get_icon(), ICON_KEY: cb_object.get_icon(),
PREVIEW_KEY: cb_object.get_preview()}) PREVIEW_KEY: cb_object.get_preview(),
ACTIVITY_KEY: cb_object.get_activity()})
logging.debug('Changed object with object_id ' + object_id + logging.debug('Changed object with object_id ' + object_id +
' with percent ' + str(percent)) ' with percent ' + str(percent))
@ -99,6 +102,7 @@ class ClipboardDBusServiceHelper(dbus.service.Object):
PERCENT_KEY: cb_object.get_percent(), PERCENT_KEY: cb_object.get_percent(),
ICON_KEY: cb_object.get_icon(), ICON_KEY: cb_object.get_icon(),
PREVIEW_KEY: cb_object.get_preview(), PREVIEW_KEY: cb_object.get_preview(),
ACTIVITY_KEY: cb_object.get_activity(),
FORMATS_KEY: format_types} FORMATS_KEY: format_types}
return result_dict return result_dict

View File

@ -14,6 +14,9 @@ class FileType:
def get_preview(self): def get_preview(self):
raise NotImplementedError raise NotImplementedError
def get_activity(self):
raise NotImplementedError
def matches_mime_type(cls, mime_type): def matches_mime_type(cls, mime_type):
raise NotImplementedError raise NotImplementedError
matches_mime_type = classmethod(matches_mime_type) matches_mime_type = classmethod(matches_mime_type)
@ -39,6 +42,9 @@ class TextFileType(FileType):
return '' return ''
def get_activity(self):
return ''
def matches_mime_type(cls, mime_type): def matches_mime_type(cls, mime_type):
return mime_type in cls._types return mime_type in cls._types
matches_mime_type = classmethod(matches_mime_type) matches_mime_type = classmethod(matches_mime_type)
@ -56,6 +62,9 @@ class ImageFileType(FileType):
def get_preview(self): def get_preview(self):
return '' return ''
def get_activity(self):
return ''
def matches_mime_type(cls, mime_type): def matches_mime_type(cls, mime_type):
return mime_type in cls._types return mime_type in cls._types
matches_mime_type = classmethod(matches_mime_type) matches_mime_type = classmethod(matches_mime_type)
@ -79,6 +88,9 @@ class UriFileType(FileType):
return '' return ''
def get_activity(self):
return ''
def matches_mime_type(cls, mime_type): def matches_mime_type(cls, mime_type):
return mime_type in cls._types return mime_type in cls._types
matches_mime_type = classmethod(matches_mime_type) matches_mime_type = classmethod(matches_mime_type)
@ -96,6 +108,9 @@ class PdfFileType(FileType):
def get_preview(self): def get_preview(self):
return '' return ''
def get_activity(self):
return 'org.laptop.sugar.Xbook'
def matches_mime_type(cls, mime_type): def matches_mime_type(cls, mime_type):
return mime_type in cls._types return mime_type in cls._types
matches_mime_type = classmethod(matches_mime_type) matches_mime_type = classmethod(matches_mime_type)
@ -113,6 +128,9 @@ class MsWordFileType(FileType):
def get_preview(self): def get_preview(self):
return '' return ''
def get_activity(self):
return 'org.laptop.AbiWordActivity'
def matches_mime_type(cls, mime_type): def matches_mime_type(cls, mime_type):
return mime_type in cls._types return mime_type in cls._types
matches_mime_type = classmethod(matches_mime_type) matches_mime_type = classmethod(matches_mime_type)
@ -130,6 +148,29 @@ class RtfFileType(FileType):
def get_preview(self): def get_preview(self):
return '' return ''
def get_activity(self):
return 'org.laptop.AbiWordActivity'
def matches_mime_type(cls, mime_type):
return mime_type in cls._types
matches_mime_type = classmethod(matches_mime_type)
class OOTextFileType(FileType):
_types = set(['application/vnd.oasis.opendocument.text'])
def get_name(self):
return _('OpenOffice text file')
def get_icon(self):
return 'activity-abiword'
def get_preview(self):
return ''
def get_activity(self):
return 'org.laptop.AbiWordActivity'
def matches_mime_type(cls, mime_type): def matches_mime_type(cls, mime_type):
return mime_type in cls._types return mime_type in cls._types
matches_mime_type = classmethod(matches_mime_type) matches_mime_type = classmethod(matches_mime_type)
@ -144,6 +185,9 @@ class UnknownFileType(FileType):
def get_preview(self): def get_preview(self):
return '' return ''
def get_activity(self):
return ''
def matches_mime_type(cls, mime_type): def matches_mime_type(cls, mime_type):
return true return true
matches_mime_type = classmethod(matches_mime_type) matches_mime_type = classmethod(matches_mime_type)
@ -154,6 +198,7 @@ class TypeRegistry:
self._types.append(PdfFileType) self._types.append(PdfFileType)
self._types.append(MsWordFileType) self._types.append(MsWordFileType)
self._types.append(RtfFileType) self._types.append(RtfFileType)
self._types.append(OOTextFileType)
self._types.append(UriFileType) self._types.append(UriFileType)
self._types.append(ImageFileType) self._types.append(ImageFileType)
self._types.append(TextFileType) self._types.append(TextFileType)

View File

@ -2,6 +2,7 @@ import logging
from sugar.graphics.menuicon import MenuIcon from sugar.graphics.menuicon import MenuIcon
from view.clipboardmenu import ClipboardMenu from view.clipboardmenu import ClipboardMenu
from sugar.graphics.iconcolor import IconColor
from sugar.activity import ActivityFactory from sugar.activity import ActivityFactory
from sugar.clipboard import clipboardservice from sugar.clipboard import clipboardservice
from sugar import util from sugar import util
@ -14,31 +15,29 @@ class ClipboardIcon(MenuIcon):
self._name = name self._name = name
self._percent = 0 self._percent = 0
self._preview = None self._preview = None
self._activity = None
self.connect('activated', self._icon_activated_cb) self.connect('activated', self._icon_activated_cb)
self._menu = None self._menu = None
def create_menu(self): def create_menu(self):
self._menu = ClipboardMenu(self._name, self._percent, self._preview) self._menu = ClipboardMenu(self._name, self._percent, self._preview,
self._activity)
self._menu.connect('action', self._popup_action_cb) self._menu.connect('action', self._popup_action_cb)
return self._menu return self._menu
def set_state(self, name, percent, icon_name, preview): def set_state(self, name, percent, icon_name, preview, activity):
self._name = name self._name = name
self._percent = percent self._percent = percent
self._preview = preview self._preview = preview
self.set_icon_name(icon_name) self._activity = activity
self.set_property("icon_name", icon_name)
if self._menu: if self._menu:
self._menu.set_state(name, percent, preview) self._menu.set_state(name, percent, preview, activity)
def _get_activity_for_mime_type(self, mime_type): if activity and percent < 100:
# FIXME: We should use some kind of registry that could be extended by self.set_property('color', IconColor("#000000,#424242"))
# newly installed activities.
if mime_type == "application/pdf":
return "org.laptop.sugar.Xbook"
elif mime_type in ["application/msword", "text/rtf", "application/rtf"]:
return "org.laptop.AbiWordActivity"
else: else:
return None self.set_property('color', IconColor("#000000,#FFFFFF"))
def _activity_create_success_cb(self, handler, activity): def _activity_create_success_cb(self, handler, activity):
activity.start(util.unique_id()) activity.start(util.unique_id())
@ -47,26 +46,20 @@ class ClipboardIcon(MenuIcon):
def _activity_create_error_cb(self, handler, err): def _activity_create_error_cb(self, handler, err):
pass pass
def _icon_activated_cb(self, icon): def _open_file(self):
if self._percent < 100: if self._percent < 100 or not self._activity:
return
cb_service = clipboardservice.get_instance()
(name, percent, icon, preview, format_types) = \
cb_service.get_object(self._object_id)
if not format_types:
return return
logging.debug("_icon_activated_cb: " + self._object_id) logging.debug("_icon_activated_cb: " + self._object_id)
activity_type = self._get_activity_for_mime_type(format_types[0])
if not activity_type:
return
# Launch the activity to handle this item # Launch the activity to handle this item
handler = ActivityFactory.create(activity_type) handler = ActivityFactory.create(self._activity)
handler.connect('success', self._activity_create_success_cb) handler.connect('success', self._activity_create_success_cb)
handler.connect('error', self._activity_create_error_cb) handler.connect('error', self._activity_create_error_cb)
def _icon_activated_cb(self, icon):
self._open_file()
def _popup_action_cb(self, popup, action): def _popup_action_cb(self, popup, action):
self.popdown() self.popdown()
@ -75,6 +68,8 @@ class ClipboardIcon(MenuIcon):
elif action == ClipboardMenu.ACTION_DELETE: elif action == ClipboardMenu.ACTION_DELETE:
cb_service = clipboardservice.get_instance() cb_service = clipboardservice.get_instance()
cb_service.delete_object(self._object_id) cb_service.delete_object(self._object_id)
elif action == ClipboardMenu.ACTION_OPEN:
self._open_file()
def get_object_id(self): def get_object_id(self):
return self._object_id return self._object_id

View File

@ -1,3 +1,4 @@
import logging
import gtk import gtk
import gobject import gobject
import hippo import hippo
@ -10,16 +11,28 @@ from sugar.graphics import style
class ClipboardMenuItem(ClipboardBubble): class ClipboardMenuItem(ClipboardBubble):
def __init__(self, percent = 0, stylesheet="clipboard.Bubble"): def __init__(self, percent = 0, stylesheet="clipboard.Bubble"):
ClipboardBubble.__init__(self, percent = percent) self._text_item = None
ClipboardBubble.__init__(self, percent=percent)
style.apply_stylesheet(self, stylesheet) style.apply_stylesheet(self, stylesheet)
self._text_item = hippo.CanvasText(text=str(percent) + ' %')
style.apply_stylesheet(self._text_item, 'clipboard.MenuItem.Title')
self.append(self._text_item)
def do_set_property(self, pspec, value):
if pspec.name == 'percent':
if self._text_item:
self._text_item.set_property('text', str(value) + ' %')
ClipboardBubble.do_set_property(self, pspec, value)
class ClipboardMenu(Menu): class ClipboardMenu(Menu):
ACTION_DELETE = 0 ACTION_DELETE = 0
ACTION_SHARE = 1 ACTION_OPEN = 1
ACTION_STOP_DOWNLOAD = 2 ACTION_STOP_DOWNLOAD = 2
def __init__(self, name, percent, preview): def __init__(self, name, percent, preview, activity):
Menu.__init__(self, name) Menu.__init__(self, name)
if percent < 100: if percent < 100:
@ -29,18 +42,36 @@ class ClipboardMenu(Menu):
self._progress_bar = None self._progress_bar = None
self._remove_icon = None self._remove_icon = None
self._open_icon = None
self._stop_icon = None self._stop_icon = None
self.add_item(preview, wrap=True) self.add_item(preview, wrap=True)
self._update_icons(percent) self._update_icons(percent, activity)
def _update_icons(self, percent): def _update_icons(self, percent, activity):
if percent == 100:
if percent == 100 and activity:
if not self._remove_icon: if not self._remove_icon:
self._remove_icon = CanvasIcon(icon_name='stock-remove') self._remove_icon = CanvasIcon(icon_name='stock-remove')
self.add_action(self._remove_icon, ClipboardMenu.ACTION_DELETE) self.add_action(self._remove_icon, ClipboardMenu.ACTION_DELETE)
if not self._open_icon:
self._open_icon = CanvasIcon(icon_name='stock-keep')
self.add_action(self._open_icon, ClipboardMenu.ACTION_OPEN)
if self._stop_icon:
self.remove_action(self._stop_icon)
self._stop_icon = None
elif percent == 100 and not activity:
if not self._remove_icon:
self._remove_icon = CanvasIcon(icon_name='stock-remove')
self.add_action(self._remove_icon, ClipboardMenu.ACTION_DELETE)
if self._open_icon:
self.remove_action(self._open_icon)
self._open_icon = None
if self._stop_icon: if self._stop_icon:
self.remove_action(self._stop_icon) self.remove_action(self._stop_icon)
self._stop_icon = None self._stop_icon = None
@ -53,8 +84,12 @@ class ClipboardMenu(Menu):
self.remove_action(self._remove_icon) self.remove_action(self._remove_icon)
self._remove_icon = None self._remove_icon = None
def set_state(self, name, percent, preview): if self._open_icon:
self.remove_action(self._open_icon)
self._open_icon = None
def set_state(self, name, percent, preview, activity):
self.set_title(name) self.set_title(name)
if self._progress_bar: if self._progress_bar:
self._progress_bar.set_property('percent', percent) self._progress_bar.set_property('percent', percent)
self._update_icons(percent) self._update_icons(percent, activity)

View File

@ -53,18 +53,18 @@ class EventFrame(gobject.GObject):
self._hover = EventFrame.HOVER_NONE self._hover = EventFrame.HOVER_NONE
self._active = False self._active = False
invisible = self._create_invisible(0, 0, gtk.gdk.screen_width(), 1) invisible = self._create_invisible(0, 0, gtk.gdk.screen_width(), 6)
self._windows.append(invisible) self._windows.append(invisible)
invisible = self._create_invisible(0, 0, 1, gtk.gdk.screen_height()) invisible = self._create_invisible(0, 0, 6, gtk.gdk.screen_height())
self._windows.append(invisible) self._windows.append(invisible)
invisible = self._create_invisible(gtk.gdk.screen_width() - 1, 0, invisible = self._create_invisible(gtk.gdk.screen_width() - 6, 0,
gtk.gdk.screen_width(), gtk.gdk.screen_width(),
gtk.gdk.screen_height()) gtk.gdk.screen_height())
self._windows.append(invisible) self._windows.append(invisible)
invisible = self._create_invisible(0, gtk.gdk.screen_height() - 1, invisible = self._create_invisible(0, gtk.gdk.screen_height() - 6,
gtk.gdk.screen_width(), gtk.gdk.screen_width(),
gtk.gdk.screen_height()) gtk.gdk.screen_height())
self._windows.append(invisible) self._windows.append(invisible)

View File

@ -89,9 +89,9 @@ class ClipboardBox(hippo.CanvasBox):
logging.debug('ClipboardBox: ' + object_id + ' was deleted.') logging.debug('ClipboardBox: ' + object_id + ' was deleted.')
def _object_state_changed_cb(self, cb_service, object_id, name, percent, def _object_state_changed_cb(self, cb_service, object_id, name, percent,
icon_name, preview): icon_name, preview, activity):
icon = self._icons[object_id] icon = self._icons[object_id]
icon.set_state(name, percent, icon_name, preview) icon.set_state(name, percent, icon_name, preview, activity)
logging.debug('ClipboardBox: ' + object_id + ' state was changed.') logging.debug('ClipboardBox: ' + object_id + ' state was changed.')
def drag_motion_cb(self, widget, context, x, y, time): def drag_motion_cb(self, widget, context, x, y, time):
@ -188,7 +188,7 @@ class ClipboardBox(hippo.CanvasBox):
def _get_targets_for_dnd(self, object_id): def _get_targets_for_dnd(self, object_id):
cb_service = clipboardservice.get_instance() cb_service = clipboardservice.get_instance()
(name, percent, icon, preview, format_types) = \ (name, percent, icon, preview, activity, format_types) = \
cb_service.get_object(object_id) cb_service.get_object(object_id)
targets = [] targets = []

View File

@ -70,7 +70,7 @@ clipboard_bubble = {
} }
clipboard_menu_item_title = { clipboard_menu_item_title = {
'xalign': hippo.ALIGNMENT_START, 'xalign': hippo.ALIGNMENT_CENTER,
'padding-left': 5, 'padding-left': 5,
'color' : 0xFFFFFFFF, 'color' : 0xFFFFFFFF,
'font' : style.get_font_description('Bold', 1.2) 'font' : style.get_font_description('Bold', 1.2)

View File

@ -6,6 +6,7 @@ NAME_KEY = 'NAME'
PERCENT_KEY = 'PERCENT' PERCENT_KEY = 'PERCENT'
ICON_KEY = 'ICON' ICON_KEY = 'ICON'
PREVIEW_KEY = 'PREVIEW' PREVIEW_KEY = 'PREVIEW'
ACTIVITY_KEY = 'ACTIVITY'
FORMATS_KEY = 'FORMATS' FORMATS_KEY = 'FORMATS'
DBUS_SERVICE = "org.laptop.Clipboard" DBUS_SERVICE = "org.laptop.Clipboard"
@ -20,7 +21,7 @@ class ClipboardService(gobject.GObject):
'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([str])), ([str])),
'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([str, str, int, str, str])), ([str, str, int, str, str, str])),
} }
def __init__(self): def __init__(self):
@ -64,7 +65,8 @@ class ClipboardService(gobject.GObject):
def _object_state_changed_cb(self, object_id, values): def _object_state_changed_cb(self, object_id, values):
self.emit('object-state-changed', object_id, values[NAME_KEY], self.emit('object-state-changed', object_id, values[NAME_KEY],
values[PERCENT_KEY], values[ICON_KEY], values[PREVIEW_KEY]) values[PERCENT_KEY], values[ICON_KEY], values[PREVIEW_KEY],
values[ACTIVITY_KEY])
def add_object(self, object_id, name): def add_object(self, object_id, name):
self._dbus_service.add_object(object_id, name) self._dbus_service.add_object(object_id, name)
@ -86,7 +88,7 @@ class ClipboardService(gobject.GObject):
return (result_dict[NAME_KEY], result_dict[PERCENT_KEY], return (result_dict[NAME_KEY], result_dict[PERCENT_KEY],
result_dict[ICON_KEY], result_dict[PREVIEW_KEY], result_dict[ICON_KEY], result_dict[PREVIEW_KEY],
result_dict[FORMATS_KEY]) result_dict[ACTIVITY_KEY], result_dict[FORMATS_KEY])
def get_object_data(self, object_id, formatType): def get_object_data(self, object_id, formatType):
return self._dbus_service.get_object_data(object_id, formatType, return self._dbus_service.get_object_data(object_id, formatType,

View File

@ -86,13 +86,26 @@ class ClipboardBubble(hippo.CanvasBox, hippo.CanvasItem):
width -= line_width * 2 width -= line_width * 2
height -= line_width * 2 height -= line_width * 2
self._paint_ellipse(cr, x, y, width, height, self._fill_color) cr.move_to(x + self._radius, y);
cr.arc(x + width - self._radius, y + self._radius,
self._radius, math.pi * 1.5, math.pi * 2);
cr.arc(x + width - self._radius, x + height - self._radius,
self._radius, 0, math.pi * 0.5);
cr.arc(x + self._radius, y + height - self._radius,
self._radius, math.pi * 0.5, math.pi);
cr.arc(x + self._radius, y + self._radius, self._radius,
math.pi, math.pi * 1.5);
color = self._int_to_rgb(self._fill_color)
cr.set_source_rgb(*color)
cr.fill_preserve();
color = self._int_to_rgb(self._stroke_color) color = self._int_to_rgb(self._stroke_color)
cr.set_source_rgb(*color) cr.set_source_rgb(*color)
cr.set_line_width(line_width) cr.set_line_width(line_width)
cr.stroke(); cr.stroke();
if self._percent > 0:
self._paint_progress_bar(cr, x, y, width, height, line_width) self._paint_progress_bar(cr, x, y, width, height, line_width)
def _paint_progress_bar(self, cr, x, y, width, height, line_width): def _paint_progress_bar(self, cr, x, y, width, height, line_width):
@ -101,31 +114,21 @@ class ClipboardBubble(hippo.CanvasBox, hippo.CanvasItem):
prog_width = (width - (line_width * 2)) * (self._percent / 100.0) prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
prog_height = (height - (line_width * 2)) prog_height = (height - (line_width * 2))
self._paint_ellipse(cr, prog_x, prog_y, width, height, self._progress_color) x = prog_x
y = prog_y
width = prog_width
height = prog_height
def _paint_ellipse(self, cr, x, y, width, height, fill_color): cr.move_to(x + self._radius, y);
cr.move_to(x + self._radius, y) cr.arc(x + width - self._radius, y + self._radius,
cr.arc(x + width - self._radius, self._radius, math.pi * 1.5, math.pi * 2);
y + self._radius, cr.arc(x + width - self._radius, x + height - self._radius,
self._radius, self._radius, 0, math.pi * 0.5);
math.pi * 1.5, cr.arc(x + self._radius, y + height - self._radius,
math.pi * 2) self._radius, math.pi * 0.5, math.pi);
cr.arc(x + width - self._radius, cr.arc(x + self._radius, y + self._radius, self._radius,
x + height - self._radius, math.pi, math.pi * 1.5);
self._radius,
0,
math.pi * 0.5)
cr.arc(x + self._radius,
y + height - self._radius,
self._radius,
math.pi * 0.5,
math.pi)
cr.arc(x + self._radius,
y + self._radius,
self._radius,
math.pi,
math.pi * 1.5);
color = self._int_to_rgb(fill_color) color = self._int_to_rgb(self._progress_color)
cr.set_source_rgb(*color) cr.set_source_rgb(*color)
cr.fill_preserve(); cr.fill_preserve();

View File

@ -54,6 +54,9 @@ class _IconCache:
def get_handle(self, name, color, size): def get_handle(self, name, color, size):
info = self._theme.lookup_icon(name, int(size), 0) info = self._theme.lookup_icon(name, int(size), 0)
if not info:
raise "Icon '" + name + "' not found."
if color: if color:
key = (info.get_filename(), color.to_string()) key = (info.get_filename(), color.to_string())
else: else:
@ -160,8 +163,3 @@ class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem):
def _button_press_event_cb(self, item, event): def _button_press_event_cb(self, item, event):
item.emit_activated() item.emit_activated()
def set_icon_name(self, icon_name):
self._icon_name = icon_name
self._buffer = None
self.emit_paint_needed(0, 0, -1, -1)

View File

@ -110,4 +110,4 @@ class Menu(gtk.Window):
self.emit('action', action) self.emit('action', action)
def set_title(self, title): def set_title(self, title):
self._title_item.set_text(title) self._title_item.set_property('text', title)