# Copyright (C) 2008, One Laptop Per Child # Copyright (C) 2009, Tomeu Vizoso, Simon Schampijer # # 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 logging import os import tempfile import urllib2 from gettext import gettext as _ from gi.repository import Gtk from gi.repository import Gdk from gi.repository import WebKit from sugar3.graphics.palette import Palette, Invoker from sugar3 import profile from sugarmenuitem import SugarMenuItem class ContentInvoker(Invoker): def __init__(self, browser): Invoker.__init__(self) self._position_hint = self.AT_CURSOR self._browser = browser self._browser.connect('button-press-event', self.__button_press_cb) self.attach(self._browser) def get_default_position(self): return self.AT_CURSOR def get_rect(self): allocation = self._browser.get_allocation() window = self._browser.get_window() if window is not None: res, x, y = window.get_origin() else: logging.warning( "Trying to position palette with invoker that's not realized.") x = 0 y = 0 x += allocation.x y += allocation.y width = allocation.width height = allocation.height rect = Gdk.Rectangle() rect.x = x rect.y = y rect.width = width rect.height = height return rect def get_toplevel(self): return None def __button_press_cb(self, browser, event): logging.debug('===> event: %s', event.button) if event.button != 3: return False hit_test = self._browser.get_hit_test_result(event) if hit_test.props.context & WebKit.HitTestResultContext.LINK: logging.debug('===> click LINK') link_uri = hit_test.props.link_uri if isinstance(hit_test.props.inner_node, WebKit.DOMHTMLImageElement): title = hit_test.props.inner_node.get_title() elif isinstance(hit_test.props.inner_node, WebKit.DOMNode): title = hit_test.props.inner_node.get_text_content() self.palette = LinkPalette(self._browser, title, link_uri, None) self.notify_right_click() elif hit_test.props.context & WebKit.HitTestResultContext.IMAGE: logging.debug('===> click IMAGE %s %s', hit_test.props.image_uri, hit_test.props.inner_node) title = hit_test.props.inner_node.get_title() self.palette = ImagePalette(self._browser, title, hit_test.props.image_uri, '') self.notify_right_click() elif hit_test.props.context & WebKit.HitTestResultContext.SELECTION: # TODO: find a way to get the selected text so we can use # it as the title of the Palette. # The function webkit_web_view_get_selected_text was removed # https://bugs.webkit.org/show_bug.cgi?id=62512 title = None # text = hit_test.props.inner_node.get_text_content() # import epdb;epdb.set_trace() # if len(text) > 20: # title = text[:20] + '...' # else: # title = text self.palette = SelectionPalette(self._browser, title, None, None) self.notify_right_click() return True class SelectionPalette(Palette): def __init__(self, browser, title, url, owner_document): Palette.__init__(self) self._browser = browser self._title = title self._url = url self._owner_document = owner_document menu_box = Gtk.VBox() self.set_content(menu_box) menu_box.show() self._content.set_border_width(1) self.props.primary_text = title menu_item = SugarMenuItem(_('Copy text'), 'edit-copy') menu_item.icon.props.xo_color = profile.get_color() menu_item.connect('clicked', self.__copy_activate_cb) menu_box.pack_end(menu_item, False, False, 0) menu_item.show() def __copy_activate_cb(self, menu_item): self.popdown(immediate=True) self._browser.copy_clipboard() class LinkPalette(Palette): def __init__(self, browser, title, url, owner_document): Palette.__init__(self) self._browser = browser self._title = title self._url = url self._owner_document = owner_document # FIXME: this sometimes fails because Gtk tries to parse it as # markup text and some URLs has # "?template=gallery&page=gallery" for example if title not in (None, ''): self.props.primary_text = title self.props.secondary_text = url else: self.props.primary_text = url menu_box = Gtk.VBox() self.set_content(menu_box) menu_box.show() self._content.set_border_width(1) menu_item = SugarMenuItem(_('Follow link'), 'browse-follow-link') menu_item.connect('clicked', self.__follow_activate_cb) menu_box.pack_end(menu_item, False, False, 0) menu_item.show() menu_item = SugarMenuItem(_('Follow link in new tab'), 'browse-follow-link-new-tab') menu_item.connect('clicked', self.__follow_activate_cb, True) menu_box.pack_end(menu_item, False, False, 0) menu_item.show() menu_item = SugarMenuItem(_('Keep link'), 'document-save') menu_item.icon.props.xo_color = profile.get_color() menu_item.connect('clicked', self.__download_activate_cb) menu_box.pack_end(menu_item, False, False, 0) menu_item.show() menu_item = SugarMenuItem(_('Copy link'), 'edit-copy') menu_item.icon.props.xo_color = profile.get_color() menu_item.connect('clicked', self.__copy_activate_cb) menu_box.pack_end(menu_item, False, False, 0) menu_item.show() def __follow_activate_cb(self, menu_item, new_tab=False): self.popdown(immediate=True) if new_tab: new_browser = self._browser.open_new_tab(self._url) else: self._browser.load_uri(self._url) self._browser.grab_focus() def __copy_activate_cb(self, menu_item): self.popdown(immediate=True) clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) clipboard.set_text(self._url, -1) def __download_activate_cb(self, menu_item): self.popdown(immediate=True) nr = WebKit.NetworkRequest() nr.set_uri(self._url) download = WebKit.Download(network_request=nr) self._browser.emit('download-requested', download) class ImagePalette(Palette): def __init__(self, browser, title, url, owner_document): Palette.__init__(self) self._browser = browser self._title = title self._url = url self._owner_document = owner_document if title not in (None, ''): self.props.primary_text = title self.props.secondary_text = url else: self.props.primary_text = url menu_box = Gtk.VBox() self.set_content(menu_box) menu_box.show() self._content.set_border_width(1) menu_item = SugarMenuItem(_('Copy image'), 'edit-copy') menu_item.icon.props.xo_color = profile.get_color() menu_item.connect('clicked', self.__copy_activate_cb) menu_box.pack_end(menu_item, False, False, 0) menu_item.show() menu_item = SugarMenuItem(_('Keep image'), 'document-save') menu_item.icon.props.xo_color = profile.get_color() menu_item.connect('clicked', self.__download_activate_cb) menu_box.pack_end(menu_item, False, False, 0) menu_item.show() def __copy_activate_cb(self, menu_item): self.popdown(immediate=True) # Download the image temp_file = tempfile.NamedTemporaryFile(delete=False) data = urllib2.urlopen(self._url).read() temp_file.write(data) temp_file.close() # Copy it inside the clipboard image = Gtk.Image.new_from_file(temp_file.name) os.unlink(temp_file.name) clipboard = Gtk.Clipboard() clipboard.set_image(image.get_pixbuf()) def __download_activate_cb(self, menu_item): self.popdown(immediate=True) nr = WebKit.NetworkRequest() nr.set_uri(self._url) download = WebKit.Download(network_request=nr) self._browser.emit('download-requested', download)