From ccd96e612b15a524c34836e239ff4e05d9cb2f32 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Thu, 24 May 2007 17:09:27 +0000 Subject: Reimplement downloads in pyxpcom. --- diff --git a/downloadmanager.py b/downloadmanager.py new file mode 100644 index 0000000..d0a8c0b --- /dev/null +++ b/downloadmanager.py @@ -0,0 +1,157 @@ +# Copyright (C) 2007, One Laptop Per Child +# +# 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 2 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, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import os +import logging +import tempfile +from gettext import gettext as _ +import time + +from xpcom.nsError import * +from xpcom import components +from xpcom.components import interfaces +from xpcom.server.factory import Factory + +from sugar.datastore import datastore +from sugar.clipboard import clipboardservice +from sugar import profile + +_browser = None +def init(browser): + global _browser + _browser = browser + +class DownloadManager: + _com_interfaces_ = interfaces.nsIHelperAppLauncherDialog + + def promptForSaveToFile(self, launcher, window_context, + default_file, suggested_file_extension): + file_class = components.classes["@mozilla.org/file/local;1"] + dest_file = file_class.createInstance(interfaces.nsILocalFile) + + if default_file: + file_path = os.path.join(tempfile.gettempdir(), default_file) + else: + f, file_path = tempfile.mkstemp(suggested_file_extension) + del f + + dest_file.initWithPath(file_path) + + return dest_file + + def show(self, launcher, context, reason): + launcher.saveToDisk(None, False) + return NS_OK + +components.registrar.registerFactory('{64355793-988d-40a5-ba8e-fcde78cac631}"', + 'Sugar Download Manager', + '@mozilla.org/helperapplauncherdialog;1', + Factory(DownloadManager)) + +class Download: + _com_interfaces_ = interfaces.nsITransfer + + def init(self, source, target, display_name, mime_info, start_time, temp_file, + cancelable): + self._source = source + self._mime_info = mime_info + self._temp_file = temp_file + self._target_file = target.queryInterface(interfaces.nsIFileURL).file + self._jobject = None + self._cb_object_id = None + self._last_update_time = 0 + self._last_update_percent = 0 + + return NS_OK + + def onStateChange(self, web_progress, request, state_flags, status): + if state_flags == interfaces.nsIWebProgressListener.STATE_START: + self._create_journal_object() + self._create_clipboard_object() + elif state_flags == interfaces.nsIWebProgressListener.STATE_STOP: + if NS_FAILED(status): # download cancelled + pass + else: + path, file_name = os.path.split(self._target_file.path) + + self._jobject['title'] = _('File %s downloaded from\n%s.') % \ + (file_name, self._source.spec) + self._jobject.file_path = self._target_file.path + datastore.write(self._jobject) + + cb_service = clipboardservice.get_instance() + cb_service.set_object_percent(self._cb_object_id, 100) + + def onProgressChange64(self, web_progress, request, cur_self_progress, + max_self_progress, cur_total_progress, + max_total_progress): + path, file_name = os.path.split(self._target_file.path) + percent = (cur_self_progress * 100) / max_self_progress + + if (time.time() - self._last_update_time) < 10 and \ + (percent - self._last_update_percent) < 10: + return + + self._last_update_time = time.time() + self._last_update_percent = percent + + if percent < 100: + self._jobject['title'] = _('Downloading %s from\n%s. Progress %i%%.') % \ + (file_name, self._source.spec, percent) + datastore.write(self._jobject) + + cb_service = clipboardservice.get_instance() + 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) + mime_type = self._mime_info.MIMEType + + self._jobject = datastore.create() + self._jobject['title'] = _('Downloading %s from \n%s.') % \ + (file_name, self._source.spec) + + if mime_type in ['application/pdf', 'application/x-pdf']: + self._jobject['activity'] = 'org.laptop.sugar.Xbook' + self._jobject['icon'] = 'theme:object-text' + else: + self._jobject['activity'] = '' + self._jobject['icon'] = 'theme:object-link' + + self._jobject['date'] = str(time.time()) + self._jobject['keep'] = '0' + self._jobject['buddies'] = '' + self._jobject['preview'] = '' + self._jobject['icon-color'] = profile.get_color().to_string() + self._jobject.file_path = '' + datastore.write(self._jobject) + + def _create_clipboard_object(self): + path, file_name = os.path.split(self._target_file.path) + mime_type = self._mime_info.MIMEType + + cb_service = clipboardservice.get_instance() + self._cb_object_id = cb_service.add_object(file_name) + cb_service.add_object_format(self._cb_object_id, + mime_type, + 'file://' + self._target_file.path.encode('utf8'), + on_disk = True) + +components.registrar.registerFactory('{23c51569-e9a1-4a92-adeb-3723db82ef7c}"', + 'Sugar Download', + '@mozilla.org/transfer;1', + Factory(Download)) + diff --git a/webactivity.py b/webactivity.py index 50faba2..d97155e 100755 --- a/webactivity.py +++ b/webactivity.py @@ -22,9 +22,6 @@ import gtk import dbus from sugar.activity import activity -from sugar.datastore import datastore -from sugar import profile -from sugar.clipboard import clipboardservice from sugar import env import hulahop @@ -32,6 +29,7 @@ hulahop.startup(os.path.join(env.get_profile_path(), 'gecko')) from browser import Browser from webtoolbar import WebToolbar +import downloadmanager _HOMEPAGE = 'http://www.google.com' @@ -48,6 +46,8 @@ class WebActivity(activity.Activity): else: self._browser = Browser() + downloadmanager.init(self._browser) + toolbox = activity.ActivityToolbox(self) activity_toolbar = toolbox.get_activity_toolbar() @@ -99,105 +99,3 @@ class WebActivity(activity.Activity): f.close() return f.name -""" - -def start(): - if not sugar.browser.startup(env.get_profile_path(), 'gecko'): - raise "Error when initializising the web activity." - - download_manager = sugar.browser.get_download_manager() - download_manager.connect('download-started', download_started_cb) - download_manager.connect('download-completed', download_completed_cb) - download_manager.connect('download-cancelled', download_started_cb) - download_manager.connect('download-progress', download_progress_cb) - -def stop(): - sugar.browser.shutdown() - -def get_download_file_name(download): - uri = urlparse.urlparse(download.get_url()) - path, file_name = os.path.split(uri[2]) - return file_name - -def download_started_cb(download_manager, download): - jobject = datastore.create() - jobject['title'] = _('Downloading %s from \n%s.') % \ - (get_download_file_name(download), download.get_url()) - - if download.get_mime_type() in ['application/pdf', 'application/x-pdf']: - jobject['activity'] = 'org.laptop.sugar.Xbook' - jobject['icon'] = 'theme:object-text' - else: - jobject['activity'] = '' - jobject['icon'] = 'theme:object-link' - - jobject['date'] = str(time.time()) - jobject['keep'] = '0' - jobject['buddies'] = '' - jobject['preview'] = '' - jobject['icon-color'] = profile.get_color().to_string() - jobject.file_path = '' - datastore.write(jobject) - download.set_data('jobject-id', jobject.object_id) - - cb_service = clipboardservice.get_instance() - object_id = cb_service.add_object(get_download_file_name(download)) - download.set_data('object-id', object_id) - cb_service.add_object_format(object_id, - download.get_mime_type(), - 'file://' + download.get_file_name(), - on_disk = True) - -def _dl_completed_cb(download, success, err=None): - if not success: - # Log errors but still set object completed - logging.debug("Error writing completed download to datastore: %s" % err) - - object_id = download.get_data('object-id') - if not object_id: - logging.debug("Unknown download object %r" % download) - return - cb_service = clipboardservice.get_instance() - cb_service.set_object_percent(object_id, 100) - -def download_completed_cb(download_manager, download): - jobject = datastore.get(download.get_data('jobject-id')) - jobject['title'] = _('File %s downloaded from\n%s.') % \ - (get_download_file_name(download), download.get_url()) - jobject.file_path = download.get_file_name() - datastore.write(jobject, - reply_handler=lambda *args: _dl_completed_cb(download, True, *args), - error_handler=lambda *args: _dl_completed_cb(download, False, *args)) - -def download_cancelled_cb(download_manager, download): - #FIXME: Needs to update the state of the object to 'download stopped'. - #FIXME: Will do it when we complete progress on the definition of the - #FIXME: clipboard API. - raise "Cancelling downloads still not implemented." - -def _dl_progress_cb(download, percent, success, err=None): - if not success: - # Log errors but still set object completed - logging.debug("Error writing completed download to datastore: %s" % err) - - cb_service = clipboardservice.get_instance() - cb_service.set_object_percent(download.get_data('object-id'), percent) - -def download_progress_cb(download_manager, download): - object_id = download.get_data('jobject-id') - if not object_id: - logging.debug("Unknown download object %r" % download) - return - - # don't send 100% unless it's really done, which we handle - # from download_completed_cb instead - percent = download.get_percent() - if percent < 100: - jobject = datastore.get(download.get_data('jobject-id')) - jobject['title'] = _('Downloading %s from\n%s.\nProgress %i%%.') % \ - (get_download_file_name(download), download.get_url(), percent) - datastore.write(jobject, - reply_handler=lambda *args: _dl_progress_cb(download, percent, True, *args), - error_handler=lambda *args: _dl_progress_cb(download, percent, False, *args)) - -""" -- cgit v0.9.1