diff options
-rw-r--r-- | downloadmanager.py | 133 | ||||
-rwxr-xr-x | webactivity.py | 36 |
2 files changed, 106 insertions, 63 deletions
diff --git a/downloadmanager.py b/downloadmanager.py index a190d75..d9ccfac 100644 --- a/downloadmanager.py +++ b/downloadmanager.py @@ -19,6 +19,7 @@ import logging import tempfile from gettext import gettext as _ import time +import gtk from xpcom.nsError import * from xpcom import components @@ -27,9 +28,11 @@ from xpcom.server.factory import Factory import dbus from sugar.datastore import datastore -from sugar.clipboard import clipboardservice from sugar import profile from sugar import objects +from sugar.graphics.alert import Alert, TimeoutAlert +from sugar.graphics import style +from sugar.graphics.icon import Icon # #3903 - this constant can be removed and assumed to be 1 when dbus-python # 0.82.3 is the only version used @@ -47,21 +50,28 @@ DS_DBUS_PATH = '/org/laptop/sugar/DataStore' _browser = None _temp_path = '/tmp' -def init(browser, temp_path): +def init(browser, activity, temp_path): global _browser _browser = browser + global _activity + _activity = activity + global _temp_path _temp_path = temp_path -_active_ds_writes = 0 -_quit_callback = None +_active_downloads = [] def can_quit(): - return _active_ds_writes == 0 + return len(_active_downloads) == 0 -def set_quit_callback(callback): - _quit_callback = callback +def remove_all_downloads(): + for download in _active_downloads: + download._cancelable.cancel(NS_ERROR_FAILURE) + if download._dl_jobject is not None: + download._datastore_deleted_handler.remove() + datastore.delete(download._dl_jobject.object_id) + download._cleanup_datastore_write() class DownloadManager: _com_interfaces_ = interfaces.nsIHelperAppLauncherDialog @@ -97,15 +107,15 @@ components.registrar.registerFactory('{64355793-988d-40a5-ba8e-fcde78cac631}"', class Download: _com_interfaces_ = interfaces.nsITransfer - - def init(self, source, target, display_name, mime_info, start_time, temp_file, - cancelable): + + def init(self, source, target, display_name, mime_info, start_time, + temp_file, cancelable): self._source = source self._mime_type = mime_info.MIMEType self._temp_file = temp_file self._target_file = target.queryInterface(interfaces.nsIFileURL).file self._dl_jobject = None - self._cb_object_id = None + self._object_id = None self._last_update_time = 0 self._last_update_percent = 0 self._cancelable = cancelable @@ -114,17 +124,33 @@ class Download: def onStateChange(self, web_progress, request, state_flags, status): if state_flags == interfaces.nsIWebProgressListener.STATE_START: - self._create_journal_object() - self._create_clipboard_object() + self._create_journal_object() + alert = TimeoutAlert(9) + alert.props.title = _('Download started') + path, file_name = os.path.split(self._target_file.path) + alert.props.msg = _('%s'%(file_name)) + _activity.add_alert(alert) + alert.connect('response', self.__start_response_cb) + alert.show() + global _active_downloads + _active_downloads.append(self) elif state_flags == interfaces.nsIWebProgressListener.STATE_STOP: if NS_FAILED(status): # download cancelled return - - cb_service = clipboardservice.get_instance() - # Test if the object still exists in the clipboard as it could have - # been removed. - if cb_service.get_object(self._cb_object_id): - cb_service.set_object_percent(self._cb_object_id, 100) + alert = Alert() + alert.props.title = _('Download completed') + path, file_name = os.path.split(self._target_file.path) + alert.props.msg = _('%s'%(file_name)) + open_icon = Icon(icon_name='zoom-activity') + alert.add_button(gtk.RESPONSE_APPLY, _('Open'), open_icon) + open_icon.show() + ok_icon = Icon(icon_name='dialog-ok') + alert.add_button(gtk.RESPONSE_OK, _('Ok'), ok_icon) + ok_icon.show() + _activity.add_alert(alert) + alert.connect('response', self.__stop_response_cb) + alert.show() + self._object_id = self._dl_jobject.object_id path, file_name = os.path.split(self._target_file.path) @@ -137,25 +163,46 @@ class Download: sniffed_mime_type = objects.mime.get_for_file(self._target_file.path) self._dl_jobject.metadata['mime_type'] = sniffed_mime_type - global _active_ds_writes - _active_ds_writes = _active_ds_writes + 1 datastore.write(self._dl_jobject, reply_handler=self._internal_save_cb, error_handler=self._internal_save_error_cb, timeout=360 * DBUS_PYTHON_TIMEOUT_UNITS_PER_SECOND) + def __start_response_cb(self, alert, response_id): + if response_id is gtk.RESPONSE_CANCEL: + logging.debug('Download Canceled') + self._cancelable.cancel(NS_ERROR_FAILURE) + if self._dl_jobject is not None: + self._datastore_deleted_handler.remove() + datastore.delete(self._dl_jobject.object_id) + self._cleanup_datastore_write() + _activity.remove_alert(alert) + + def __stop_response_cb(self, alert, response_id): + if response_id is gtk.RESPONSE_APPLY: + logging.debug('Start application with downloaded object') + from sugar.activity import activityfactory + from sugar import activity + activities_info = activity.get_registry().get_activities_for_type( + self._mime_type) + activities = [] + for activity_info in activities_info: + activities.append(activity_info) + logging.debug('--> act=%s mime=%s'%(activities, self._mime_type)) + bundle_id = activities[0].bundle_id + logging.debug('--> bundle_id=%s'%bundle_id) + activityfactory.create_with_object_id(bundle_id, self._object_id) + _activity.remove_alert(alert) + def _cleanup_datastore_write(self): - global _active_ds_writes - _active_ds_writes = _active_ds_writes - 1 + global _active_downloads + _active_downloads.remove(self) - os.remove(self._dl_jobject.file_path) + if os.path.isfile(self._dl_jobject.file_path): + os.remove(self._dl_jobject.file_path) self._dl_jobject.destroy() self._dl_jobject = None - global _quit_callback - if _active_ds_writes == 0 and not _quit_callback is None: - _quit_callback() - def _internal_save_cb(self): self._cleanup_datastore_write() @@ -180,12 +227,6 @@ class Download: self._dl_jobject.metadata['progress'] = str(percent) datastore.write(self._dl_jobject) - cb_service = clipboardservice.get_instance() - # Test if the object still exists in the clipboard as it could have - # been removed. - if cb_service.get_object(self._cb_object_id): - cb_service.set_object_percent(self._cb_object_id, percent) - def _create_journal_object(self): path, file_name = os.path.split(self._target_file.path) @@ -205,33 +246,15 @@ class Download: bus = dbus.SessionBus() obj = bus.get_object(DS_DBUS_SERVICE, DS_DBUS_PATH) datastore_dbus = dbus.Interface(obj, DS_DBUS_INTERFACE) - datastore_dbus.connect_to_signal('Deleted', self.__datastore_deleted_cb, - arg0=self._dl_jobject.object_id) + self._datastore_deleted_handler = datastore_dbus.connect_to_signal( + 'Deleted', self.__datastore_deleted_cb, + arg0=self._dl_jobject.object_id) def __datastore_deleted_cb(self, uid): logging.debug('Downloaded entry has been deleted from the datastore: %r' % uid) # TODO: Use NS_BINDING_ABORTED instead of NS_ERROR_FAILURE. self._cancelable.cancel(NS_ERROR_FAILURE) #NS_BINDING_ABORTED) - def _create_clipboard_object(self): - path, file_name = os.path.split(self._target_file.path) - - cb_service = clipboardservice.get_instance() - self._cb_object_id = cb_service.add_object(file_name) - - # TODO: avoid by now adding two formats, as they would create two - # identical files in /tmp - #cb_service.add_object_format(self._cb_object_id, - # self._mime_type, - # 'file://' + self._target_file.path.encode('utf8'), - # on_disk = True) - - # Also add the 'text/uri-list' target for the same file path. - cb_service.add_object_format(self._cb_object_id, - 'text/uri-list', - 'file://' + self._target_file.path.encode('utf8'), - on_disk = True) - components.registrar.registerFactory('{23c51569-e9a1-4a92-adeb-3723db82ef7c}"', 'Sugar Download', '@mozilla.org/transfer;1', diff --git a/webactivity.py b/webactivity.py index 3064989..bca8531 100755 --- a/webactivity.py +++ b/webactivity.py @@ -33,6 +33,8 @@ from sugar import _sugarext from sugar.presence import presenceservice from sugar.graphics.tray import HTray from sugar import profile +from sugar.graphics.alert import Alert +from sugar.graphics.icon import Icon import hulahop hulahop.startup(os.path.join(env.get_profile_path(), 'gecko')) @@ -70,7 +72,7 @@ class WebActivity(activity.Activity): self._browser = Browser() temp_path = os.path.join(self.get_activity_root(), 'tmp') - downloadmanager.init(self._browser, temp_path) + downloadmanager.init(self._browser, self, temp_path) sessionhistory.init(self._browser) progresslistener.init(self._browser) @@ -413,12 +415,30 @@ class WebActivity(activity.Activity): buffer = self.get_buffer(screenshot) return buffer - def destroy(self): + def close(self): if downloadmanager.can_quit(): - activity.Activity.destroy(self) + activity.Activity.close(self) else: - downloadmanager.set_quit_callback(self._quit_callback_cb) - - def _quit_callback_cb(self): - _logger.debug('_quit_callback_cb') - activity.Activity.destroy(self) + logging.debug('Close is called') + alert = Alert() + alert.props.title = _('Download in progress') + alert.props.msg = _('Stopping now will cancel your download') + cancel_icon = Icon(icon_name='dialog-cancel') + alert.add_button(gtk.RESPONSE_CANCEL, _('Cancel'), cancel_icon) + stop_icon = Icon(icon_name='activity-stop') + alert.add_button(gtk.RESPONSE_CLOSE, _('Stop'), stop_icon) + stop_icon.show() + self.add_alert(alert) + alert.connect('response', self.__inprogress_response_cb) + alert.show() + self.present() + + def __inprogress_response_cb(self, alert, response_id): + self.remove_alert(alert) + if response_id is gtk.RESPONSE_CANCEL: + logging.debug('Keep on') + elif response_id == gtk.RESPONSE_CLOSE: + logging.debug('Stop downloads and quit') + downloadmanager.remove_all_downloads() + activity.Activity.close(self) + |