diff options
author | Lucian Branescu Mihaila <lucian.branescu@gmail.com> | 2009-11-08 15:04:55 (GMT) |
---|---|---|
committer | Lucian Branescu Mihaila <lucian.branescu@gmail.com> | 2009-11-08 15:04:55 (GMT) |
commit | 0e5585f457be03e929a04345aab5529c9fe12319 (patch) | |
tree | 639dda290330f0ed76365dea837da7cdde2e1b33 | |
parent | e82bbcedd1d3bc5780a30ceb6b15712719897a6e (diff) |
Keep offline implements offline bookmarks
-rw-r--r-- | downloadmanager.py | 115 | ||||
-rw-r--r-- | webactivity.py | 22 | ||||
-rw-r--r-- | webtoolbar.py | 14 |
3 files changed, 148 insertions, 3 deletions
diff --git a/downloadmanager.py b/downloadmanager.py index a3fe6d8..2b513e7 100644 --- a/downloadmanager.py +++ b/downloadmanager.py @@ -22,6 +22,7 @@ import time import tempfile import urlparse import urllib +import zipfile import gtk import hulahop @@ -382,5 +383,117 @@ class _SaveLinkProgressListener(object): def onDataAvailable(self, request, context, inputStream, offset, count): self._external_listener.onDataAvailable(request, context, inputStream, - offset, count); + offset, count) + +def save_document(activity, browser): + '''Save the current webpage for offline use''' + cls = components.classes[ \ + '@mozilla.org/embedding/browser/nsWebBrowserPersist;1'] + persist = cls.createInstance(interfaces.nsIWebBrowserPersist) + + local = components.classes["@mozilla.org/file/local;1"] + local_file = local.createInstance(interfaces.nsILocalFile) + local_data = local.createInstance(interfaces.nsILocalFile) + + temp_dir = tempfile.mkdtemp() + + local_file.initWithPath(os.path.join(temp_dir, 'index.html')) + local_data.initWithPath(os.path.join(temp_dir, 'data')) + + persist.persistFlags = interfaces.nsIWebBrowserPersist \ + .PERSIST_FLAGS_REPLACE_EXISTING_FILES + persist.progressListener = _SaveDocumentProgressListener(activity, + temp_dir, browser.props.title)._wrapped + persist.saveDocument(browser.dom_window.document, local_file, local_data, + None, 0, 0) + +class _SaveDocumentProgressListener(object): + _com_interfaces_ = interfaces.nsIWebProgressListener + + def __init__(self, activity, temp_dir, title): + self._activity = activity + self._temp_dir = temp_dir + self._title = title + self._zip_path = os.path.join(activity.get_activity_root(), + 'instance', self._title+'.zip') + self._jobject = None + + self._wrapped = xpcom.server.WrapObject(self, + interfaces.nsIWebProgressListener) + + def onStateChange(self, web_progress, request, state_flags, status): + if state_flags & interfaces.nsIWebProgressListener.STATE_STOP: + if NS_FAILED(status): + alert = TimeoutAlert(9) + alert.props.title = _('Keep offline') + alert.props.msg = _('Saving "%s" for offline use failed') % \ + self._title + self._activity.add_alert(alert) + alert.connect('response', self.__fail_response_cb) + alert.show() + else: + try: # HACK because NS_FAILED(status) is wrong + self._create_zip() + self._create_journal_object() + except OSError: + return + + alert = Alert() + alert.props.title = _('Keep offline') + + cancel_icon = Icon(icon_name='dialog-cancel') + alert.add_button(gtk.RESPONSE_CANCEL, _('Cancel'), cancel_icon) + cancel_icon.show() + + open_icon = Icon(icon_name='filesave') + alert.add_button(gtk.RESPONSE_OK, _('Show in Journal'), + open_icon) + open_icon.show() + + self._activity.add_alert(alert) + alert.connect('response', self.__success_response_cb) + + def onStatusChange(self, web_progress, request, status, message): + pass + + def onProgressChange(self, web_progress, request, cur_self_progress, + max_self_progress, cur_total_progress, + max_total_progress): + pass + + def onLocationChange(self, web_progress, request, location): + pass + + def onSecurityChange(self, web_progress, request, state): + pass + + def __fail_response_cb(self, alert, response_id): + self._activity.remove_alert(alert) + + def __success_response_cb(self, alert, response_id): + self._activity.remove_alert(alert) + + if response_id is gtk.RESPONSE_OK: + activity.show_object_in_journal(self._jobject.object_id) + + + def _create_zip(self): + bundle = zipfile.ZipFile(self._zip_path, 'w', zipfile.ZIP_DEFLATED) + + bundle.write(os.path.join(self._temp_dir, 'index.html'), 'index.html') + data_path = os.path.join(self._temp_dir, 'data') + for i in os.listdir(data_path): + bundle.write(os.path.join(data_path, i), + os.path.join('data', i)) + bundle.close() + + def _create_journal_object(self): + self._jobject = datastore.create() + self._jobject.metadata['title'] = self._title + self._jobject.metadata['icon-color'] = \ + profile.get_color().to_string() + self._jobject.metadata['mime_type'] = 'application/zip' + self._jobject.metadata['activity'] = 'org.laptop.WebActivity' + self._jobject.file_path = self._zip_path + datastore.write(self._jobject) diff --git a/webactivity.py b/webactivity.py index 4be551e..8007bce 100644 --- a/webactivity.py +++ b/webactivity.py @@ -31,6 +31,8 @@ import sqlite3 import cjson import gconf import locale +import zipfile +import tempfile # HACK: Needed by http://dev.sugarlabs.org/ticket/456 import gnome @@ -191,6 +193,7 @@ class WebActivity(activity.Activity): self._primary_toolbar = PrimaryToolbar(self._tabbed_view, self) self._primary_toolbar.connect('add-link', self._link_add_button_cb) + self._primary_toolbar.connect('keep-offline', self._keep_offline_cb) self._tray = HTray() self.set_tray(self._tray, gtk.POS_BOTTOM) @@ -391,7 +394,21 @@ class WebActivity(activity.Activity): self._tabbed_view.props.current_browser.load_uri(uris[0]) else: _logger.error('Open uri-list: Does not support' - 'list of multiple uris by now.') + 'list of multiple uris by now.') + elif self.metadata['mime_type'] == 'application/zip': + temp_dir = tempfile.mkdtemp() + + z = zipfile.ZipFile(file_path, 'r') + os.mkdir(os.path.join(temp_dir, 'data')) + # zipfile can only expand from 2.6 onwards + for i in z.namelist(): + open(os.path.join(temp_dir, i), 'wb').write(z.read(i)) + + index_path = os.path.join(temp_dir, 'index.html') + if os.path.isfile(index_path): + self._tabbed_view.props.current_browser.load_uri(index_path) + else: + self._tabbed_view.props.current_browser.load_uri(temp_dir) else: self._tabbed_view.props.current_browser.load_uri(file_path) @@ -556,3 +573,6 @@ class WebActivity(activity.Activity): browser = self._tabbed_view.props.current_browser browser.get_source(async_cb, async_err_cb) + def _keep_offline_cb(self, toolbar): + downloadmanager.save_document(self, + self._tabbed_view.props.current_browser)
\ No newline at end of file diff --git a/webtoolbar.py b/webtoolbar.py index 854345c..7be8dfb 100644 --- a/webtoolbar.py +++ b/webtoolbar.py @@ -222,7 +222,10 @@ class PrimaryToolbar(ToolbarBox): __gsignals__ = { 'add-link': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, - ([])) + ([])), + 'keep-offline': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, + ([])), } def __init__(self, tabbed_view, act): @@ -237,6 +240,12 @@ class PrimaryToolbar(ToolbarBox): activity_button = ActivityToolbarButton(self._activity) self.toolbar.insert(activity_button, 0) + self._keep_offline = ToolButton('htmloff') + self._keep_offline.set_tooltip(_("Save offline")) + self._keep_offline.connect('clicked', self.__keep_offline_cb) + self._keep_offline.show() + activity_button.props.page.insert(self._keep_offline, -1) + self._stop_and_reload = ToolButton('media-playback-stop') self._stop_and_reload.connect('clicked', self._stop_and_reload_cb) self.toolbar.insert(self._stop_and_reload, -1) @@ -294,6 +303,9 @@ class PrimaryToolbar(ToolbarBox): def __switch_page_cb(self, tabbed_view, page, page_num): self._connect_to_browser(tabbed_view.props.current_browser) + def __keep_offline_cb(self, button): + self.emit('keep-offline') + def _connect_to_browser(self, browser): if self._progress_listener is not None: self._progress_listener.disconnect(self._location_changed_hid) |