Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
sugar/src/jarabe/journal/palettes.py /
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
664 lines (545 sloc)
25.2 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Copyright (C) 2008 One Laptop Per Child | |
| # Copyright (C) 2014 Ignacio Rodriguez | |
| # | |
| # This program is free software: you can redistribute it and/or modify | |
| # it under the terms of the GNU General Public License as published by | |
| # the Free Software Foundation, either version 3 of the License, or | |
| # (at your option) any later version. | |
| # | |
| # This program is distributed in the hope that it will be useful, | |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| # GNU General Public License for more details. | |
| # | |
| # You should have received a copy of the GNU General Public License | |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| from gettext import gettext as _ | |
| from gettext import ngettext | |
| import logging | |
| import os | |
| from gi.repository import GObject | |
| from gi.repository import GLib | |
| from gi.repository import Gtk | |
| from gi.repository import Gdk | |
| from gi.repository import Gio | |
| from gi.repository import SugarExt | |
| from sugar3.graphics import style | |
| from sugar3.graphics.palette import Palette | |
| from sugar3.graphics.menuitem import MenuItem | |
| from sugar3.graphics.icon import Icon | |
| from sugar3.graphics.xocolor import XoColor | |
| from sugar3.graphics.alert import Alert | |
| from sugar3 import mime | |
| from sugar3 import profile | |
| from jarabe.model import friends | |
| from jarabe.model import filetransfer | |
| from jarabe.model import mimeregistry | |
| from jarabe.journal import misc | |
| from jarabe.journal import model | |
| from jarabe.journal import journalwindow | |
| from jarabe.webservice import accountsmanager | |
| from jarabe.journal.misc import get_mount_color | |
| PROJECT_BUNDLE_ID = 'org.sugarlabs.Project' | |
| class ObjectPalette(Palette): | |
| __gtype_name__ = 'ObjectPalette' | |
| __gsignals__ = { | |
| 'detail-clicked': (GObject.SignalFlags.RUN_FIRST, None, | |
| ([str])), | |
| 'volume-error': (GObject.SignalFlags.RUN_FIRST, None, | |
| ([str, str])), | |
| 'choose-project': (GObject.SignalFlags.RUN_FIRST, None, | |
| ([object])), | |
| } | |
| def __init__(self, journalactivity, metadata, detail=False): | |
| self._journalactivity = journalactivity | |
| self._metadata = metadata | |
| activity_icon = Icon(pixel_size=style.STANDARD_ICON_SIZE) | |
| activity_icon.props.file = misc.get_icon_name(metadata) | |
| color = misc.get_icon_color(metadata) | |
| activity_icon.props.xo_color = color | |
| if 'title' in metadata: | |
| title = metadata['title'] | |
| else: | |
| title = _('Untitled') | |
| Palette.__init__(self, primary_text=title, | |
| icon=activity_icon) | |
| description = metadata.get('description', '') | |
| if description: | |
| self.set_secondary_text(description) | |
| if misc.can_resume(metadata): | |
| if metadata.get('activity_id', ''): | |
| resume_label = _('Resume') | |
| resume_with_label = _('Resume with') | |
| else: | |
| resume_label = _('Start') | |
| resume_with_label = _('Start with') | |
| menu_item = MenuItem(resume_label, 'activity-start') | |
| menu_item.connect('activate', self.__start_activate_cb) | |
| self.menu.append(menu_item) | |
| menu_item.show() | |
| menu_item = MenuItem(resume_with_label, 'activity-start') | |
| self.menu.append(menu_item) | |
| menu_item.show() | |
| start_with_menu = StartWithMenu(self._metadata) | |
| menu_item.set_submenu(start_with_menu) | |
| elif metadata.get('activity', None) == PROJECT_BUNDLE_ID: | |
| open_label = _('Open') | |
| menu_item = MenuItem(open_label, 'project-box') | |
| menu_item.connect('activate', self.__open_project_activate_cb) | |
| self.menu.append(menu_item) | |
| menu_item.show() | |
| else: | |
| menu_item = MenuItem(_('No activity to start entry')) | |
| menu_item.set_sensitive(False) | |
| self.menu.append(menu_item) | |
| menu_item.show() | |
| menu_item = MenuItem(_('Copy to')) | |
| icon = Icon(icon_name='edit-copy', xo_color=color, | |
| pixel_size=style.SMALL_ICON_SIZE) | |
| menu_item.set_image(icon) | |
| self.menu.append(menu_item) | |
| menu_item.show() | |
| copy_menu = CopyMenu(self._journalactivity, self.__get_uid_list_cb) | |
| copy_menu.connect('volume-error', self.__volume_error_cb) | |
| menu_item.set_submenu(copy_menu) | |
| if not metadata.get('activity', None) == PROJECT_BUNDLE_ID: | |
| menu_item = MenuItem(_('Send to project...'), 'project-box') | |
| menu_item.connect('activate', self.__copy_to_project_activated_cb) | |
| self.menu.append(menu_item) | |
| menu_item.show() | |
| if self._metadata['mountpoint'] == '/': | |
| menu_item = MenuItem(_('Duplicate')) | |
| icon = Icon(icon_name='edit-duplicate', xo_color=color, | |
| pixel_size=style.SMALL_ICON_SIZE) | |
| menu_item.set_image(icon) | |
| menu_item.connect('activate', self.__duplicate_activate_cb) | |
| self.menu.append(menu_item) | |
| menu_item.show() | |
| menu_item = MenuItem(_('Send to'), 'document-send') | |
| self.menu.append(menu_item) | |
| menu_item.show() | |
| friends_menu = FriendsMenu() | |
| friends_menu.connect('friend-selected', self.__friend_selected_cb) | |
| menu_item.set_submenu(friends_menu) | |
| if detail is True: | |
| menu_item = MenuItem(_('View Details'), 'go-right') | |
| menu_item.connect('activate', self.__detail_activate_cb) | |
| self.menu.append(menu_item) | |
| menu_item.show() | |
| menu_item = MenuItem(_('Erase'), 'list-remove') | |
| menu_item.connect('activate', self.__erase_activate_cb) | |
| self.menu.append(menu_item) | |
| menu_item.show() | |
| def __get_uid_list_cb(self): | |
| return [self._metadata['uid']] | |
| def __copy_to_project_activated_cb(self, menu_item): | |
| self.emit('choose-project', self._metadata) | |
| self.destroy() | |
| def __open_project_activate_cb(self, menu_item): | |
| self._journalactivity.project_view_activated_cb( | |
| list_view=None, | |
| metadata=self._metadata) | |
| def __start_activate_cb(self, menu_item): | |
| misc.resume(self._metadata, | |
| alert_window=journalwindow.get_journal_window()) | |
| def __duplicate_activate_cb(self, menu_item): | |
| try: | |
| model.copy(self._metadata, '/') | |
| except IOError as 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 __erase_activate_cb(self, menu_item): | |
| alert = Alert() | |
| erase_string = _('Erase') | |
| alert.props.title = erase_string | |
| alert.props.msg = _('Do you want to permanently erase \"%s\"?') \ | |
| % self._metadata['title'] | |
| icon = Icon(icon_name='dialog-cancel') | |
| alert.add_button(Gtk.ResponseType.CANCEL, _('Cancel'), icon) | |
| icon.show() | |
| ok_icon = Icon(icon_name='dialog-ok') | |
| alert.add_button(Gtk.ResponseType.OK, erase_string, ok_icon) | |
| ok_icon.show() | |
| alert.connect('response', self.__erase_alert_response_cb) | |
| journalwindow.get_journal_window().add_alert(alert) | |
| alert.show() | |
| def __erase_alert_response_cb(self, alert, response_id): | |
| journalwindow.get_journal_window().remove_alert(alert) | |
| if response_id is Gtk.ResponseType.OK: | |
| uid = self._metadata['uid'] | |
| list_model = self._journalactivity.get_list_view().get_model() | |
| if list_model.is_selected(uid): | |
| list_model.set_selected(uid, False) | |
| model.delete(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']) | |
| if not file_name or not os.path.exists(file_name): | |
| logging.warn('Entries without a file cannot be sent.') | |
| self.emit('volume-error', | |
| _('Entries without a file cannot be sent.'), | |
| _('Warning')) | |
| return | |
| title = str(self._metadata['title']) | |
| description = str(self._metadata.get('description', '')) | |
| mime_type = str(self._metadata['mime_type']) | |
| if not mime_type: | |
| mime_type = mime.get_for_file(file_name) | |
| filetransfer.start_transfer(buddy, file_name, title, description, | |
| mime_type) | |
| def popup(self, immediate=False, state=None): | |
| if self._journalactivity.get_list_view().is_dragging(): | |
| return | |
| Palette.popup(self, immediate) | |
| class CopyMenu(Gtk.Menu): | |
| __gtype_name__ = 'JournalCopyMenu' | |
| __gsignals__ = { | |
| 'volume-error': (GObject.SignalFlags.RUN_FIRST, None, | |
| ([str, str])), | |
| } | |
| def __init__(self, journalactivity, get_uid_list_cb): | |
| Gtk.Menu.__init__(self) | |
| CopyMenuBuilder(journalactivity, get_uid_list_cb, | |
| self.__volume_error_cb, self) | |
| def __volume_error_cb(self, menu_item, message, severity): | |
| self.emit('volume-error', message, severity) | |
| class CopyMenuBuilder(): | |
| def __init__(self, journalactivity, get_uid_list_cb, __volume_error_cb, | |
| menu, add_clipboard_menu=True, add_webservices_menu=True): | |
| self._journalactivity = journalactivity | |
| self._get_uid_list_cb = get_uid_list_cb | |
| self.__volume_error_cb = __volume_error_cb | |
| self._menu = menu | |
| self._add_clipboard_menu = add_clipboard_menu | |
| self._add_webservices_menu = add_webservices_menu | |
| self._mount_added_hid = None | |
| self._mount_removed_hid = None | |
| self._create_menu_items() | |
| def _create_menu_items(self): | |
| if self._add_clipboard_menu: | |
| clipboard_menu = ClipboardMenu(self._get_uid_list_cb) | |
| clipboard_menu.set_image(Icon(icon_name='toolbar-edit', | |
| pixel_size=style.SMALL_ICON_SIZE)) | |
| clipboard_menu.connect('volume-error', self.__volume_error_cb) | |
| self._menu.append(clipboard_menu) | |
| clipboard_menu.show() | |
| if self._journalactivity.get_mount_point() != '/': | |
| color = profile.get_color() | |
| journal_menu = VolumeMenu(self._journalactivity, | |
| self._get_uid_list_cb, _('Journal'), '/') | |
| journal_menu.set_image(Icon(icon_name='activity-journal', | |
| xo_color=color, | |
| pixel_size=style.SMALL_ICON_SIZE)) | |
| journal_menu.connect('volume-error', self.__volume_error_cb) | |
| self._menu.append(journal_menu) | |
| journal_menu.show() | |
| documents_path = model.get_documents_path() | |
| if documents_path is not None and \ | |
| self._journalactivity.get_mount_point() != documents_path: | |
| documents_menu = VolumeMenu(self._journalactivity, | |
| self._get_uid_list_cb, _('Documents'), | |
| documents_path) | |
| documents_menu.set_image(Icon(icon_name='user-documents', | |
| pixel_size=style.SMALL_ICON_SIZE)) | |
| documents_menu.connect('volume-error', self.__volume_error_cb) | |
| self._menu.append(documents_menu) | |
| documents_menu.show() | |
| volume_monitor = Gio.VolumeMonitor.get() | |
| self._volumes = {} | |
| for mount in volume_monitor.get_mounts(): | |
| self._add_mount(mount) | |
| self._mount_added_hid = volume_monitor.connect('mount-added', | |
| self.__mount_added_cb) | |
| self._mount_removed_hid = volume_monitor.connect( | |
| 'mount-removed', | |
| self.__mount_removed_cb) | |
| if self._add_webservices_menu: | |
| for account in accountsmanager.get_configured_accounts(): | |
| if hasattr(account, 'get_shared_journal_entry'): | |
| entry = account.get_shared_journal_entry() | |
| if hasattr(entry, 'get_share_menu'): | |
| self._menu.append(entry.get_share_menu( | |
| self._get_uid_list_cb)) | |
| def update_mount_point(self): | |
| for menu_item in self._menu.get_children(): | |
| if isinstance(menu_item, MenuItem): | |
| self._menu.remove(menu_item) | |
| self._create_menu_items() | |
| def __mount_added_cb(self, volume_monitor, mount): | |
| self._add_mount(mount) | |
| def _add_mount(self, mount): | |
| mount_path = mount.get_root().get_path() | |
| if mount_path in self._volumes: | |
| return | |
| if self._journalactivity.get_mount_point() == mount_path: | |
| return | |
| volume_menu = VolumeMenu(self._journalactivity, | |
| self._get_uid_list_cb, mount.get_name(), | |
| mount.get_root().get_path()) | |
| icon_name = misc.get_mount_icon_name(mount, Gtk.IconSize.MENU) | |
| icon = Icon(pixel_size=style.SMALL_ICON_SIZE, | |
| icon_name=icon_name, | |
| xo_color=get_mount_color(mount)) | |
| volume_menu.set_image(icon) | |
| volume_menu.connect('volume-error', self.__volume_error_cb) | |
| self._menu.append(volume_menu) | |
| self._volumes[mount.get_root().get_path()] = volume_menu | |
| volume_menu.show() | |
| def __mount_removed_cb(self, volume_monitor, mount): | |
| volume_menu = self._volumes[mount.get_root().get_path()] | |
| self._menu.remove(volume_menu) | |
| del self._volumes[mount.get_root().get_path()] | |
| class VolumeMenu(MenuItem): | |
| __gtype_name__ = 'JournalVolumeMenu' | |
| __gsignals__ = { | |
| 'volume-error': (GObject.SignalFlags.RUN_FIRST, None, | |
| ([str, str])), | |
| } | |
| def __init__(self, journalactivity, get_uid_list_cb, label, mount_point): | |
| MenuItem.__init__(self, label) | |
| self._get_uid_list_cb = get_uid_list_cb | |
| self._journalactivity = journalactivity | |
| self._mount_point = mount_point | |
| self.connect('activate', self.__copy_to_volume_cb) | |
| def __copy_to_volume_cb(self, menu_item): | |
| uid_list = self._get_uid_list_cb() | |
| if len(uid_list) == 1: | |
| uid = uid_list[0] | |
| file_path = model.get_file(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: | |
| metadata = model.get(uid) | |
| model.copy(metadata, self._mount_point) | |
| except IOError as e: | |
| logging.exception('Error while copying the entry. %s', | |
| e.strerror) | |
| self.emit('volume-error', | |
| _('Error while copying the entry. %s') % e.strerror, | |
| _('Error')) | |
| else: | |
| BatchOperator( | |
| self._journalactivity, uid_list, _('Copy'), | |
| self._get_confirmation_alert_message(len(uid_list)), | |
| self._perform_copy) | |
| def _get_confirmation_alert_message(self, entries_len): | |
| return ngettext('Do you want to copy %d entry?', | |
| 'Do you want to copy %d entries?', | |
| entries_len) % (entries_len) | |
| def _perform_copy(self, metadata): | |
| file_path = model.get_file(metadata['uid']) | |
| if not file_path or not os.path.exists(file_path): | |
| logging.warn('Entries without a file cannot be copied.') | |
| return | |
| try: | |
| model.copy(metadata, self._mount_point) | |
| except IOError as e: | |
| logging.exception('Error while copying the entry. %s', | |
| e.strerror) | |
| class ClipboardMenu(MenuItem): | |
| __gtype_name__ = 'JournalClipboardMenu' | |
| __gsignals__ = { | |
| 'volume-error': (GObject.SignalFlags.RUN_FIRST, None, | |
| ([str, str])), | |
| } | |
| def __init__(self, get_uid_list_cb): | |
| MenuItem.__init__(self, _('Clipboard')) | |
| self._temp_file_path = None | |
| self._get_uid_list_cb = get_uid_list_cb | |
| self.connect('activate', self.__copy_to_clipboard_cb) | |
| def __copy_to_clipboard_cb(self, menu_item): | |
| clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) | |
| uid_list = self._get_uid_list_cb() | |
| if len(uid_list) == 1: | |
| uid = uid_list[0] | |
| file_path = model.get_file(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 | |
| # XXX SL#4307 - until set_with_data bindings are fixed upstream | |
| if hasattr(clipboard, 'set_with_data'): | |
| clipboard.set_with_data( | |
| [Gtk.TargetEntry.new('text/uri-list', 0, 0)], | |
| self.__clipboard_get_func_cb, | |
| self.__clipboard_clear_func_cb, | |
| None) | |
| else: | |
| SugarExt.clipboard_set_with_data( | |
| clipboard, | |
| [Gtk.TargetEntry.new('text/uri-list', 0, 0)], | |
| self.__clipboard_get_func_cb, | |
| self.__clipboard_clear_func_cb, | |
| None) | |
| def __clipboard_get_func_cb(self, clipboard, selection_data, info, data): | |
| # Get hold of a reference so the temp file doesn't get deleted | |
| for uid in self._get_uid_list_cb(): | |
| self._temp_file_path = model.get_file(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' | |
| __gsignals__ = { | |
| 'friend-selected': (GObject.SignalFlags.RUN_FIRST, None, | |
| ([object])), | |
| } | |
| def __init__(self): | |
| Gtk.Menu.__init__(self) | |
| if filetransfer.file_transfer_available(): | |
| friends_model = friends.get_model() | |
| for friend in friends_model: | |
| if friend.is_present(): | |
| menu_item = MenuItem(text_label=friend.get_nick(), | |
| icon_name='computer-xo', | |
| xo_color=friend.get_color()) | |
| menu_item.connect('activate', self.__item_activate_cb, | |
| friend) | |
| self.append(menu_item) | |
| menu_item.show() | |
| if not self.get_children(): | |
| menu_item = MenuItem(_('No friends present')) | |
| menu_item.set_sensitive(False) | |
| self.append(menu_item) | |
| menu_item.show() | |
| else: | |
| menu_item = MenuItem(_('No valid connection found')) | |
| menu_item.set_sensitive(False) | |
| self.append(menu_item) | |
| menu_item.show() | |
| def __item_activate_cb(self, menu_item, friend): | |
| self.emit('friend-selected', friend) | |
| class StartWithMenu(Gtk.Menu): | |
| __gtype_name__ = 'JournalStartWithMenu' | |
| def __init__(self, metadata): | |
| Gtk.Menu.__init__(self) | |
| self._metadata = metadata | |
| for activity_info in misc.get_activities(metadata): | |
| menu_item = MenuItem(activity_info.get_name()) | |
| menu_item.set_image(Icon(file=activity_info.get_icon(), | |
| pixel_size=style.SMALL_ICON_SIZE)) | |
| menu_item.connect('activate', self.__item_activate_cb, | |
| activity_info.get_bundle_id()) | |
| self.append(menu_item) | |
| menu_item.show() | |
| if not self.get_children(): | |
| if metadata.get('activity_id', ''): | |
| resume_label = _('No activity to resume entry') | |
| else: | |
| resume_label = _('No activity to start entry') | |
| menu_item = MenuItem(resume_label) | |
| menu_item.set_sensitive(False) | |
| self.append(menu_item) | |
| menu_item.show() | |
| def __item_activate_cb(self, menu_item, service_name): | |
| mime_type = self._metadata.get('mime_type', '') | |
| if mime_type: | |
| mime_registry = mimeregistry.get_registry() | |
| mime_registry.set_default_activity(mime_type, service_name) | |
| misc.resume(self._metadata, bundle_id=service_name, | |
| alert_window=journalwindow.get_journal_window()) | |
| class BuddyPalette(Palette): | |
| def __init__(self, buddy): | |
| self._buddy = buddy | |
| nick, colors = buddy | |
| buddy_icon = Icon(icon_name='computer-xo', | |
| pixel_size=style.STANDARD_ICON_SIZE, | |
| xo_color=XoColor(colors)) | |
| Palette.__init__(self, primary_text=nick, icon=buddy_icon) | |
| # TODO: Support actions on buddies, like make friend, invite, etc. | |
| class BatchOperator(GObject.GObject): | |
| """ | |
| This class implements the course of actions that happens when clicking | |
| upon an BatchOperation (eg. Batch-Copy-Toolbar-button; | |
| Batch-Copy-To-Journal-button; | |
| Batch-Copy-To-Documents-button; | |
| Batch-Copy-To-Mounted-Drive-button; | |
| Batch-Copy-To-Clipboard-button; | |
| Batch-Erase-Button; | |
| """ | |
| def __init__(self, journalactivity, | |
| uid_list, | |
| alert_title, alert_message, | |
| operation_cb): | |
| GObject.GObject.__init__(self) | |
| self._journalactivity = journalactivity | |
| self._uid_list = uid_list[:] | |
| self._alert_title = alert_title | |
| self._alert_message = alert_message | |
| self._operation_cb = operation_cb | |
| self._show_confirmation_alert() | |
| def _show_confirmation_alert(self): | |
| self._journalactivity.freeze_ui() | |
| GLib.idle_add(self.__show_confirmation_alert_internal) | |
| def __show_confirmation_alert_internal(self): | |
| # Show a alert requesting confirmation before run the batch operation | |
| self._confirmation_alert = Alert() | |
| self._confirmation_alert.props.title = self._alert_title | |
| self._confirmation_alert.props.msg = self._alert_message | |
| stop_icon = Icon(icon_name='dialog-cancel') | |
| self._confirmation_alert.add_button(Gtk.ResponseType.CANCEL, | |
| _('Stop'), stop_icon) | |
| stop_icon.show() | |
| ok_icon = Icon(icon_name='dialog-ok') | |
| self._confirmation_alert.add_button(Gtk.ResponseType.OK, | |
| _('Continue'), ok_icon) | |
| ok_icon.show() | |
| self._journalactivity.add_alert(self._confirmation_alert) | |
| self._confirmation_alert.connect('response', | |
| self.__confirmation_response_cb) | |
| self._confirmation_alert.show() | |
| def __confirmation_response_cb(self, alert, response): | |
| if response == Gtk.ResponseType.CANCEL: | |
| self._journalactivity.unfreeze_ui() | |
| self._journalactivity.remove_alert(alert) | |
| # this is only in the case the operation already started | |
| # and the user want stop it. | |
| self._stop_batch_execution() | |
| elif not hasattr(self, '_object_index'): | |
| self._object_index = 0 | |
| GLib.idle_add(self._operate_by_uid_internal) | |
| def _operate_by_uid_internal(self): | |
| # If there is still some uid left, proceed with the operation. | |
| # Else, proceed to post-operations. | |
| if self._object_index < len(self._uid_list): | |
| uid = self._uid_list[self._object_index] | |
| metadata = model.get(uid) | |
| title = None | |
| if 'title' in metadata: | |
| title = metadata['title'] | |
| if title is None or title == '': | |
| title = _('Untitled') | |
| alert_message = _('%(index)d of %(total)d : %(object_title)s') % { | |
| 'index': self._object_index + 1, | |
| 'total': len(self._uid_list), | |
| 'object_title': title} | |
| self._confirmation_alert.props.msg = alert_message | |
| GLib.idle_add(self._operate_per_metadata, metadata) | |
| else: | |
| self._finish_batch_execution() | |
| def _operate_per_metadata(self, metadata): | |
| self._operation_cb(metadata) | |
| # process the next | |
| self._object_index = self._object_index + 1 | |
| GLib.idle_add(self._operate_by_uid_internal) | |
| def _stop_batch_execution(self): | |
| self._object_index = len(self._uid_list) | |
| def _finish_batch_execution(self): | |
| del self._object_index | |
| self._journalactivity.unfreeze_ui() | |
| self._journalactivity.remove_alert(self._confirmation_alert) | |
| self._journalactivity.update_selected_items_ui() |