[Sugar-devel] [PATCH sugar] Add copy-to option in the Journal
Simon Schampijer
simon at schampijer.de
Tue May 24 18:53:36 EDT 2011
This will be part of replacing the keep button. The discussion is taking place
at: http://lists.sugarlabs.org/archive/sugar-devel/2011-May/031316.html
There are mockups and the implementation details.
Signed-off-by: Simon Schampijer <simon at laptop.org>
---
src/jarabe/journal/journalactivity.py | 1 +
src/jarabe/journal/journaltoolbox.py | 86 +++++++-----------
src/jarabe/journal/listview.py | 13 +++
src/jarabe/journal/model.py | 2 +
src/jarabe/journal/palettes.py | 155 +++++++++++++++++++++++++++++----
5 files changed, 185 insertions(+), 72 deletions(-)
diff --git a/src/jarabe/journal/journalactivity.py b/src/jarabe/journal/journalactivity.py
index a33038a..bb1c7f6 100644
--- a/src/jarabe/journal/journalactivity.py
+++ b/src/jarabe/journal/journalactivity.py
@@ -171,6 +171,7 @@ class JournalActivity(JournalWindow):
self._list_view = ListView()
self._list_view.connect('detail-clicked', self.__detail_clicked_cb)
self._list_view.connect('clear-clicked', self.__clear_clicked_cb)
+ self._list_view.connect('volume-error', self.__volume_error_cb)
self._main_view.pack_start(self._list_view)
self._list_view.show()
diff --git a/src/jarabe/journal/journaltoolbox.py b/src/jarabe/journal/journaltoolbox.py
index d825bc9..18d8cdf 100644
--- a/src/jarabe/journal/journaltoolbox.py
+++ b/src/jarabe/journal/journaltoolbox.py
@@ -26,6 +26,7 @@ import gobject
import gio
import gtk
+from sugar.graphics.palette import Palette
from sugar.graphics.toolbox import Toolbox
from sugar.graphics.toolcombobox import ToolComboBox
from sugar.graphics.toolbutton import ToolButton
@@ -37,11 +38,12 @@ from sugar.graphics.xocolor import XoColor
from sugar.graphics import iconentry
from sugar.graphics import style
from sugar import mime
-from sugar import profile
from jarabe.model import bundleregistry
from jarabe.journal import misc
from jarabe.journal import model
+from jarabe.journal.palettes import ClipboardMenu
+from jarabe.journal.palettes import VolumeMenu
_AUTOSEARCH_TIMEOUT = 1000
@@ -378,7 +380,7 @@ class EntryToolbar(gtk.Toolbar):
self._copy.set_icon_widget(icon)
icon.show()
- self._copy.set_tooltip(_('Copy'))
+ self._copy.set_tooltip(_('Copy to'))
self._copy.connect('clicked', self._copy_clicked_cb)
self.add(self._copy)
self._copy.show()
@@ -402,19 +404,7 @@ class EntryToolbar(gtk.Toolbar):
misc.resume(self._metadata)
def _copy_clicked_cb(self, button):
- clipboard = gtk.Clipboard()
- clipboard.set_with_data([('text/uri-list', 0, 0)],
- self.__clipboard_get_func_cb,
- self.__clipboard_clear_func_cb)
-
- def __clipboard_get_func_cb(self, clipboard, selection_data, info, data):
- # Get hold of a reference so the temp file doesn't get deleted
- self._temp_file_path = model.get_file(self._metadata['uid'])
- selection_data.set_uris(['file://' + self._temp_file_path])
-
- def __clipboard_clear_func_cb(self, clipboard, data):
- # Release and delete the temp file
- self._temp_file_path = None
+ button.palette.popup(immediate=True, state=Palette.SECONDARY)
def _erase_button_clicked_cb(self, button):
registry = bundleregistry.get_registry()
@@ -427,24 +417,6 @@ class EntryToolbar(gtk.Toolbar):
def _resume_menu_item_activate_cb(self, menu_item, service_name):
misc.resume(self._metadata, service_name)
- def _copy_menu_item_activate_cb(self, menu_item, mount_point):
- file_path = model.get_file(self._metadata['uid'])
-
- if not file_path or not os.path.exists(file_path):
- logging.warn('Entries without a file cannot be copied.')
- self.emit('volume-error',
- _('Entries without a file cannot be copied.'),
- _('Warning'))
- return
-
- try:
- model.copy(self._metadata, mount_point)
- except IOError, e:
- logging.exception('Error while copying the entry. %s', e.strerror)
- self.emit('volume-error',
- _('Error while copying the entry. %s') % e.strerror,
- _('Error'))
-
def _refresh_copy_palette(self):
palette = self._copy.get_palette()
@@ -452,35 +424,43 @@ class EntryToolbar(gtk.Toolbar):
palette.menu.remove(menu_item)
menu_item.destroy()
- if self._metadata['mountpoint'] != '/':
- journal_item = MenuItem(_('Journal'))
- journal_item.set_image(Icon(
- icon_name='activity-journal',
- xo_color=profile.get_color(),
- icon_size=gtk.ICON_SIZE_MENU))
- journal_item.connect('activate',
- self._copy_menu_item_activate_cb, '/')
- journal_item.show()
- palette.menu.append(journal_item)
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+
+ clipboard_menu = ClipboardMenu(self._metadata)
+ clipboard_menu.set_image(Icon(icon_name='transfer-from',
+ xo_color=color,
+ icon_size=gtk.ICON_SIZE_MENU))
+ clipboard_menu.connect('volume-error', self.__volume_error_cb)
+ palette.menu.append(clipboard_menu)
+ clipboard_menu.show()
+
+ journal_menu = VolumeMenu(self._metadata, _('Journal'), '/')
+ journal_menu.set_image(Icon(icon_name='activity-journal',
+ xo_color=color,
+ icon_size=gtk.ICON_SIZE_MENU))
+ journal_menu.connect('volume-error', self.__volume_error_cb)
+ palette.menu.append(journal_menu)
+ journal_menu.show()
volume_monitor = gio.volume_monitor_get()
+ icon_theme = gtk.icon_theme_get_default()
for mount in volume_monitor.get_mounts():
if self._metadata['mountpoint'] == mount.get_root().get_path():
continue
- menu_item = MenuItem(mount.get_name())
-
- icon_theme = gtk.icon_theme_get_default()
+ volume_menu = VolumeMenu(self._metadata, mount.get_name(),
+ mount.get_root().get_path())
for name in mount.get_icon().props.names:
if icon_theme.has_icon(name):
- menu_item.set_image(Icon(icon_name=name,
- icon_size=gtk.ICON_SIZE_MENU))
+ volume_menu.set_image(Icon(icon_name=name,
+ icon_size=gtk.ICON_SIZE_MENU))
break
+ volume_menu.connect('volume-error', self.__volume_error_cb)
+ palette.menu.append(volume_menu)
+ volume_menu.show()
- menu_item.connect('activate',
- self._copy_menu_item_activate_cb,
- mount.get_root().get_path())
- palette.menu.append(menu_item)
- menu_item.show()
+ def __volume_error_cb(self, menu_item, message, severity):
+ self.emit('volume-error', message, severity)
def _refresh_resume_palette(self):
if self._metadata.get('activity_id', ''):
diff --git a/src/jarabe/journal/listview.py b/src/jarabe/journal/listview.py
index 0aee1b7..f779fc4 100644
--- a/src/jarabe/journal/listview.py
+++ b/src/jarabe/journal/listview.py
@@ -469,6 +469,8 @@ class ListView(BaseListView):
__gsignals__ = {
'detail-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([object])),
+ 'volume-error': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str, str])),
}
def __init__(self):
@@ -484,6 +486,7 @@ class ListView(BaseListView):
self.cell_icon.connect('clicked', self.__icon_clicked_cb)
self.cell_icon.connect('detail-clicked', self.__detail_clicked_cb)
+ self.cell_icon.connect('volume-error', self.__volume_error_cb)
cell_detail = CellRendererDetail(self.tree_view)
cell_detail.connect('clicked', self.__detail_cell_clicked_cb)
@@ -525,6 +528,9 @@ class ListView(BaseListView):
def __detail_clicked_cb(self, cell, uid):
self.emit('detail-clicked', uid)
+ def __volume_error_cb(self, cell, message, severity):
+ self.emit('volume-error', message, severity)
+
def __icon_clicked_cb(self, cell, path):
row = self.tree_view.get_model()[path]
metadata = model.get(row[ListModel.COLUMN_UID])
@@ -579,6 +585,8 @@ class CellRendererActivityIcon(CellRendererIcon):
__gsignals__ = {
'detail-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([str])),
+ 'volume-error': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str, str])),
}
def __init__(self, tree_view):
@@ -603,11 +611,16 @@ class CellRendererActivityIcon(CellRendererIcon):
palette = ObjectPalette(metadata, detail=True)
palette.connect('detail-clicked',
self.__detail_clicked_cb)
+ palette.connect('volume-error',
+ self.__volume_error_cb)
return palette
def __detail_clicked_cb(self, palette, uid):
self.emit('detail-clicked', uid)
+ def __volume_error_cb(self, palette, message, severity):
+ self.emit('volume-error', message, severity)
+
def set_show_palette(self, show_palette):
self._show_palette = show_palette
diff --git a/src/jarabe/journal/model.py b/src/jarabe/journal/model.py
index fd25681..1891c84 100644
--- a/src/jarabe/journal/model.py
+++ b/src/jarabe/journal/model.py
@@ -616,6 +616,8 @@ def copy(metadata, mount_point):
"""
metadata = get(metadata['uid'])
file_path = get_file(metadata['uid'])
+ if file_path is None:
+ file_path = ''
metadata['mountpoint'] = mount_point
del metadata['uid']
diff --git a/src/jarabe/journal/palettes.py b/src/jarabe/journal/palettes.py
index 9ae1afb..0b3f7d2 100644
--- a/src/jarabe/journal/palettes.py
+++ b/src/jarabe/journal/palettes.py
@@ -16,10 +16,12 @@
from gettext import gettext as _
import logging
+import os
import gobject
import gtk
import gconf
+import gio
from sugar.graphics import style
from sugar.graphics.palette import Palette
@@ -42,12 +44,13 @@ class ObjectPalette(Palette):
__gsignals__ = {
'detail-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([str])),
+ 'volume-error': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str, str])),
}
def __init__(self, metadata, detail=False):
self._metadata = metadata
- self._temp_file_path = None
activity_icon = Icon(icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR)
activity_icon.props.file = misc.get_icon_name(metadata)
@@ -87,14 +90,17 @@ class ObjectPalette(Palette):
client = gconf.client_get_default()
color = XoColor(client.get_string('/desktop/sugar/user/color'))
- menu_item = MenuItem(_('Copy'))
+ menu_item = MenuItem(_('Copy to'))
icon = Icon(icon_name='edit-copy', xo_color=color,
icon_size=gtk.ICON_SIZE_MENU)
menu_item.set_image(icon)
- menu_item.connect('activate', self.__copy_activate_cb)
self.menu.append(menu_item)
menu_item.show()
+ copy_menu = CopyMenu(metadata)
+ copy_menu.connect('volume-error', self.__volume_error_cb)
+ menu_item.set_submenu(copy_menu)
+
menu_item = MenuItem(_('Send to'), 'document-send')
self.menu.append(menu_item)
menu_item.show()
@@ -117,28 +123,15 @@ class ObjectPalette(Palette):
def __start_activate_cb(self, menu_item):
misc.resume(self._metadata)
- def __copy_activate_cb(self, menu_item):
- clipboard = gtk.Clipboard()
- clipboard.set_with_data([('text/uri-list', 0, 0)],
- self.__clipboard_get_func_cb,
- self.__clipboard_clear_func_cb)
-
- def __clipboard_get_func_cb(self, clipboard, selection_data, info, data):
- # Get hold of a reference so the temp file doesn't get deleted
- self._temp_file_path = model.get_file(self._metadata['uid'])
- logging.debug('__clipboard_get_func_cb %r', self._temp_file_path)
- selection_data.set_uris(['file://' + self._temp_file_path])
-
- def __clipboard_clear_func_cb(self, clipboard, data):
- # Release and delete the temp file
- self._temp_file_path = None
-
def __erase_activate_cb(self, menu_item):
model.delete(self._metadata['uid'])
def __detail_activate_cb(self, menu_item):
self.emit('detail-clicked', self._metadata['uid'])
+ def __volume_error_cb(self, menu_item, message, severity):
+ self.emit('volume-error', message, severity)
+
def __friend_selected_cb(self, menu_item, buddy):
logging.debug('__friend_selected_cb')
file_name = model.get_file(self._metadata['uid'])
@@ -154,6 +147,130 @@ class ObjectPalette(Palette):
mime_type)
+class CopyMenu(gtk.Menu):
+ __gtype_name__ = 'JournalCopyMenu'
+
+ __gsignals__ = {
+ 'volume-error': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str, str])),
+ }
+
+ def __init__(self, metadata):
+ gobject.GObject.__init__(self)
+
+ self._metadata = metadata
+
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+
+ clipboard_menu = ClipboardMenu(self._metadata)
+ clipboard_menu.set_image(Icon(icon_name='transfer-from',
+ xo_color=color,
+ icon_size=gtk.ICON_SIZE_MENU))
+ clipboard_menu.connect('volume-error', self.__volume_error_cb)
+ self.append(clipboard_menu)
+ clipboard_menu.show()
+
+ journal_menu = VolumeMenu(self._metadata, _('Journal'), '/')
+ journal_menu.set_image(Icon(icon_name='activity-journal',
+ xo_color=color,
+ icon_size=gtk.ICON_SIZE_MENU))
+ journal_menu.connect('volume-error', self.__volume_error_cb)
+ self.append(journal_menu)
+ journal_menu.show()
+
+ volume_monitor = gio.volume_monitor_get()
+ icon_theme = gtk.icon_theme_get_default()
+ for mount in volume_monitor.get_mounts():
+ if self._metadata['mountpoint'] == mount.get_root().get_path():
+ continue
+ volume_menu = VolumeMenu(self._metadata, mount.get_name(),
+ mount.get_root().get_path())
+ for name in mount.get_icon().props.names:
+ if icon_theme.has_icon(name):
+ volume_menu.set_image(Icon(icon_name=name,
+ icon_size=gtk.ICON_SIZE_MENU))
+ break
+ volume_menu.connect('volume-error', self.__volume_error_cb)
+ self.append(volume_menu)
+ volume_menu.show()
+
+ def __volume_error_cb(self, menu_item, message, severity):
+ self.emit('volume-error', message, severity)
+
+
+class VolumeMenu(MenuItem):
+ __gtype_name__ = 'JournalVolumeMenu'
+
+ __gsignals__ = {
+ 'volume-error': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str, str])),
+ }
+
+ def __init__(self, metadata, label, mount_point):
+ MenuItem.__init__(self, label)
+ self._metadata = metadata
+ self.connect('activate', self.__copy_to_volume_cb, mount_point)
+
+ def __copy_to_volume_cb(self, menu_item, mount_point):
+ file_path = model.get_file(self._metadata['uid'])
+ if mount_point != '/':
+ if not file_path or not os.path.exists(file_path):
+ logging.warn('Entries without a file cannot be copied.')
+ self.emit('volume-error',
+ _('Entries without a file cannot be copied.'),
+ _('Warning'))
+ return
+
+ try:
+ model.copy(self._metadata, mount_point)
+ except IOError, e:
+ logging.exception('Error while copying the entry. %s', e.strerror)
+ self.emit('volume-error',
+ _('Error while copying the entry. %s') % e.strerror,
+ _('Error'))
+
+
+class ClipboardMenu(MenuItem):
+ __gtype_name__ = 'JournalClipboardMenu'
+
+ __gsignals__ = {
+ 'volume-error': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str, str])),
+ }
+
+ def __init__(self, metadata):
+ MenuItem.__init__(self, _('Clipboard'))
+
+ self._temp_file_path = None
+ self._metadata = metadata
+ self.connect('activate', self.__copy_to_clipboard_cb)
+
+ def __copy_to_clipboard_cb(self, menu_item):
+ file_path = model.get_file(self._metadata['uid'])
+ if not file_path or not os.path.exists(file_path):
+ logging.warn('Entries without a file cannot be copied.')
+ self.emit('volume-error',
+ _('Entries without a file cannot be copied.'),
+ _('Warning'))
+ return
+
+ clipboard = gtk.Clipboard()
+ clipboard.set_with_data([('text/uri-list', 0, 0)],
+ self.__clipboard_get_func_cb,
+ self.__clipboard_clear_func_cb)
+
+ def __clipboard_get_func_cb(self, clipboard, selection_data, info, data):
+ # Get hold of a reference so the temp file doesn't get deleted
+ self._temp_file_path = model.get_file(self._metadata['uid'])
+ logging.debug('__clipboard_get_func_cb %r', self._temp_file_path)
+ selection_data.set_uris(['file://' + self._temp_file_path])
+
+ def __clipboard_clear_func_cb(self, clipboard, data):
+ # Release and delete the temp file
+ self._temp_file_path = None
+
+
class FriendsMenu(gtk.Menu):
__gtype_name__ = 'JournalFriendsMenu'
--
1.7.4
More information about the Sugar-devel
mailing list