Ticket #3455: first_palettes.patch

File first_palettes.patch, 13.4 KB (added by erikos, 12 years ago)

First patch towards palette support for link and images

  • browser.py

    diff --git a/browser.py b/browser.py
    index d7a8734..a1067b0 100644
    a b from sugar3.graphics import style 
    3434from sugar3.graphics.icon import Icon
    3535
    3636from widgets import BrowserNotebook
     37from palettes import ContentInvoker
    3738import globalhistory
    3839import downloadmanager
    3940from pdfviewer import PDFTabPage
    class Browser(WebKit.WebView): 
    496497        self.connect('new-window-policy-decision-requested',
    497498                     self.__new_window_policy_cb)
    498499
     500        ContentInvoker(self)
     501
    499502    def get_history(self):
    500503        """Return the browsing history of this browser."""
    501504        back_forward_list = self.get_back_forward_list()
  • palettes.py

    diff --git a/palettes.py b/palettes.py
    index 01c34d4..9802593 100644
    a b  
    1515# along with this program; if not, write to the Free Software
    1616# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    1717
     18import logging
    1819import os
    1920import tempfile
    2021import urlparse
    2122from gettext import gettext as _
    2223
    2324from gi.repository import Gtk
     25from gi.repository import Gdk
    2426from gi.repository import GObject
     27from gi.repository import WebKit
    2528
    2629from sugar3.graphics.palette import Palette, Invoker
    27 from sugar3.graphics.menuitem import MenuItem
    2830from sugar3.graphics.icon import Icon
    2931from sugar3 import profile
    3032from sugar3.activity import activity
    3133
    32 import downloadmanager
    33 
    34 
    35 class MouseOutListener(GObject.GObject):
    36     _com_interfaces_ = interfaces.nsIDOMEventListener
    37 
    38     __gsignals__ = {
    39         'mouse-out': (GObject.SignalFlags.RUN_FIRST,
    40                       None,
    41                       ([])),
    42     }
    43 
    44     def __init__(self, target):
    45         GObject.GObject.__init__(self)
    46         self.target = target
    47 
    48     def handleEvent(self, event):
    49         self.emit('mouse-out')
    50 
     34from sugarmenuitem import SugarMenuItem
    5135
    5236class ContentInvoker(Invoker):
    53     _com_interfaces_ = interfaces.nsIDOMEventListener
    54 
    5537    def __init__(self, browser):
    5638        Invoker.__init__(self)
    5739        self._position_hint = self.AT_CURSOR
    5840        self._browser = browser
    59         self._mouseout_listener = None
    6041        self._popdown_handler_id = None
     42        self._browser.connect('button-press-event', self.__button_press_cb)
     43        self.attach(self._browser)
    6144
    6245    def get_default_position(self):
    6346        return self.AT_CURSOR
    6447
    6548    def get_rect(self):
    66         return ()
    67 
    68     def get_toplevel(self):
    69         return None
     49        allocation = self._browser.get_allocation()
     50        window = self._browser.get_window()
     51        if window is not None:
     52            res, x, y = window.get_origin()
     53        else:
     54            logging.warning(
     55                "Trying to position palette with invoker that's not realized.")
     56            x = 0
     57            y = 0
    7058
    71     def handleEvent(self, event):
    72         if event.button != 2:
    73             return
     59        x += allocation.x
     60        y += allocation.y
    7461
    75         target = event.target
     62        width = allocation.width
     63        height = allocation.height
    7664
    77         if target.tagName.lower() == 'a':
     65        rect = Gdk.Rectangle()
     66        rect.x = x
     67        rect.y = y
     68        rect.width = width
     69        rect.height = height
     70        return rect
    7871
    79             if target.firstChild:
    80                 title = target.firstChild.nodeValue
    81             else:
    82                 title = None
     72    def get_toplevel(self):
     73        return None
    8374
    84             self.palette = LinkPalette(self._browser, title, target.href,
    85                                        target.ownerDocument)
     75    def __button_press_cb(self, browser, event):
     76        logging.debug('===> event=%s', event.button)
     77        if event.button != 3:
     78            return False
     79        hit_test = self._browser.get_hit_test_result(event)
     80        if hit_test.props.context & WebKit.HitTestResultContext.LINK:
     81            logging.debug('===> click LINK')
     82            link_uri = hit_test.props.link_uri
     83            self.palette = LinkPalette(self._browser, None, link_uri, None)
    8684            self.notify_right_click()
    87         elif target.tagName.lower() == 'img':
    88             if target.title:
    89                 title = target.title
    90             elif target.title:
    91                 title = target.alt
    92             elif target.name:
    93                 title = target.name
    94             else:
    95                 title = os.path.basename(urlparse.urlparse(target.src).path)
    96 
    97             self.palette = ImagePalette(title, target.src,
    98                                         target.ownerDocument)
     85        elif hit_test.props.context & WebKit.HitTestResultContext.IMAGE:
     86            logging.debug('===< click IMAGE %s %s', hit_test.props.image_uri, hit_test.props.inner_node)
     87            self.palette = ImagePalette('', hit_test.props.image_uri, '')
    9988            self.notify_right_click()
    100         else:
    101             return
    102 
    103         if self._popdown_handler_id is not None:
    104             self._popdown_handler_id = self.palette.connect( \
    105                 'popdown', self.__palette_popdown_cb)
    106 
    107         self._mouseout_listener = MouseOutListener(target)
    108         wrapper = xpcom.server.WrapObject(self._mouseout_listener,
    109                                           interfaces.nsIDOMEventListener)
    110         target.addEventListener('mouseout', wrapper, False)
    111         self._mouseout_listener.connect('mouse-out', self.__moved_out_cb)
    112 
    113     def __moved_out_cb(self, listener):
    114         self.palette.popdown()
    115 
    116     def __palette_popdown_cb(self, palette):
    117         if self._mouseout_listener is not None:
    118             wrapper = xpcom.server.WrapObject(self._mouseout_listener,
    119                                               interfaces.nsIDOMEventListener)
    120             self._mouseout_listener.target.removeEventListener('mouseout',
    121                                                                wrapper, False)
    122             del self._mouseout_listener
     89        return True
    12390
    12491
    12592class LinkPalette(Palette):
    class LinkPalette(Palette): 
    137104        else:
    138105            self.props.primary_text = url
    139106
    140         menu_item = MenuItem(_('Follow link'), 'browse-follow-link')
    141         menu_item.connect('activate', self.__follow_activate_cb)
    142         self.menu.append(menu_item)
     107        menu_box = Gtk.VBox()
     108        self.set_content(menu_box)
     109        menu_box.show()
     110        self._content.set_border_width(1)
     111
     112        menu_item = SugarMenuItem(_('Follow link'), 'browse-follow-link')
     113        menu_item.connect('clicked', self.__follow_activate_cb)
     114        menu_box.pack_end(menu_item, False, False, 0)
    143115        menu_item.show()
    144116
    145         menu_item = MenuItem(_('Follow link in new tab'),
    146                              'browse-follow-link-new-tab')
    147         menu_item.connect('activate', self.__follow_activate_cb, True)
    148         self.menu.append(menu_item)
     117        menu_item = SugarMenuItem(_('Follow link in new tab'),
     118                                  'browse-follow-link-new-tab')
     119        menu_item.connect('clicked', self.__follow_activate_cb, True)
     120        menu_box.pack_end(menu_item, False, False, 0)
    149121        menu_item.show()
    150122
    151         menu_item = MenuItem(_('Keep link'))
    152         icon = Icon(icon_name='document-save', xo_color=profile.get_color(),
    153                     icon_size=Gtk.IconSize.MENU)
    154         menu_item.set_image(icon)
    155         menu_item.connect('activate', self.__download_activate_cb)
    156         self.menu.append(menu_item)
     123        menu_item = SugarMenuItem(_('Keep link'), 'document-save')
     124        menu_item.icon.props.xo_color = profile.get_color()
     125        menu_item.connect('clicked', self.__download_activate_cb)
     126        menu_box.pack_end(menu_item, False, False, 0)
    157127        menu_item.show()
    158128
    159         menu_item = MenuItem(_('Copy link'))
    160         icon = Icon(icon_name='edit-copy', xo_color=profile.get_color(),
    161                     icon_size=Gtk.IconSize.MENU)
    162         menu_item.set_image(icon)
    163         menu_item.connect('activate', self.__copy_activate_cb)
    164         self.menu.append(menu_item)
     129        menu_item = SugarMenuItem(_('Copy link'), 'edit-copy')
     130        menu_item.icon.props.xo_color = profile.get_color()
     131        menu_item.connect('clicked', self.__copy_activate_cb)
     132        menu_box.pack_end(menu_item, False, False, 0)
    165133        menu_item.show()
    166134
    167135    def __follow_activate_cb(self, menu_item, new_tab=False):
    class LinkPalette(Palette): 
    172140            self._browser.grab_focus()
    173141
    174142    def __copy_activate_cb(self, menu_item):
     143        pass
     144        # issue with gtk_clipboard_set_with_data
     145        # see http://www.daa.com.au/pipermail/pygtk/2011-July/019940.html
     146        '''
    175147        clipboard = Gtk.Clipboard()
    176         targets = Gtk.target_list_add_uri_targets()
     148        targets = Gtk.TargetList.add_uri_targets()
    177149        targets = Gtk.target_list_add_text_targets(targets)
    178150        targets.append(('text/x-moz-url', 0, 0))
    179151
    180152        clipboard.set_with_data(targets,
    181153                                self.__clipboard_get_func_cb,
    182154                                self.__clipboard_clear_func_cb)
    183 
     155        '''
    184156    def __clipboard_get_func_cb(self, clipboard, selection_data, info, data):
    185157        uri_targets = \
    186158            [target[0] for target in Gtk.target_list_add_uri_targets()]
    class LinkPalette(Palette): 
    198170        pass
    199171
    200172    def __download_activate_cb(self, menu_item):
    201         downloadmanager.save_link(self._url, self._title, self._owner_document)
     173        pass # downloadmanager.save_link(self._url, self._title, self._owner_document)
    202174
    203175
    204176class ImagePalette(Palette):
    class ImagePalette(Palette): 
    212184        self.props.primary_text = title
    213185        self.props.secondary_text = url
    214186
    215         menu_item = MenuItem(_('Keep image'))
    216         icon = Icon(icon_name='document-save', xo_color=profile.get_color(),
    217                     icon_size=Gtk.IconSize.MENU)
    218         menu_item.set_image(icon)
    219         menu_item.connect('activate', self.__download_activate_cb)
    220         self.menu.append(menu_item)
     187        menu_box = Gtk.VBox()
     188        self.set_content(menu_box)
     189        menu_box.show()
     190        self._content.set_border_width(1)
     191
     192        menu_item = SugarMenuItem(_('Keep image'), 'document-save')
     193        menu_item.icon.props.xo_color = profile.get_color()
     194        menu_item.connect('clicked', self.__download_activate_cb)
     195        menu_box.pack_end(menu_item, False, False, 0)
    221196        menu_item.show()
    222197
    223         menu_item = MenuItem(_('Copy image'))
    224         icon = Icon(icon_name='edit-copy', xo_color=profile.get_color(),
    225                     icon_size=Gtk.IconSize.MENU)
    226         menu_item.set_image(icon)
    227         menu_item.connect('activate', self.__copy_activate_cb)
    228         self.menu.append(menu_item)
     198        menu_item = SugarMenuItem(_('Copy image'), 'edit-copy')
     199        menu_item.icon.props.xo_color = profile.get_color()
     200        menu_item.connect('clicked', self.__copy_activate_cb)
     201        menu_box.pack_end(menu_item, False, False, 0)
    229202        menu_item.show()
    230203
    231204    def __copy_activate_cb(self, menu_item):
     205        pass
     206        '''
    232207        file_name = os.path.basename(urlparse.urlparse(self._url).path)
    233208        if '.' in file_name:
    234209            base_name, extension = file_name.split('.')
    class ImagePalette(Palette): 
    242217                                               suffix=extension)
    243218        os.close(fd)
    244219        os.chmod(temp_file, 0664)
    245 
    246         cls = components.classes['@mozilla.org/network/io-service;1']
    247         io_service = cls.getService(interfaces.nsIIOService)
    248         uri = io_service.newURI(self._url, None, None)
    249 
    250         cls = components.classes['@mozilla.org/file/local;1']
    251         target_file = cls.createInstance(interfaces.nsILocalFile)
    252         target_file.initWithPath(temp_file)
    253 
    254         cls = components.classes[ \
    255                 '@mozilla.org/embedding/browser/nsWebBrowserPersist;1']
    256         persist = cls.createInstance(interfaces.nsIWebBrowserPersist)
    257         persist.persistFlags = 1  # PERSIST_FLAGS_FROM_CACHE
    258         listener = xpcom.server.WrapObject(_ImageProgressListener(temp_file),
    259                                            interfaces.nsIWebProgressListener)
    260         persist.progressListener = listener
    261         persist.saveURI(uri, None, None, None, None, target_file)
     220        # write data
     221        '''
    262222
    263223    def __download_activate_cb(self, menu_item):
    264         downloadmanager.save_link(self._url, self._title, self._owner_document)
    265 
    266 
    267 class _ImageProgressListener(object):
    268     _com_interfaces_ = interfaces.nsIWebProgressListener
    269 
    270     def __init__(self, temp_file):
    271         self._temp_file = temp_file
    272 
    273     def onLocationChange(self, webProgress, request, location):
    274         pass
    275 
    276     def onProgressChange(self, webProgress, request, curSelfProgress,
    277                          maxSelfProgress, curTotalProgress, maxTotalProgress):
    278         pass
    279 
    280     def onSecurityChange(self, webProgress, request, state):
    281         pass
    282 
    283     def onStatusChange(self, webProgress, request, status, message):
    284         pass
    285 
    286     def onStateChange(self, webProgress, request, stateFlags, status):
    287         if (stateFlags & interfaces.nsIWebProgressListener.STATE_IS_REQUEST and
    288             stateFlags & interfaces.nsIWebProgressListener.STATE_STOP):
    289             clipboard = Gtk.Clipboard()
    290             clipboard.set_with_data([('text/uri-list', 0, 0)],
    291                                     _clipboard_get_func_cb,
    292                                     _clipboard_clear_func_cb,
    293                                     self._temp_file)
     224        pass # downloadmanager.save_link(self._url, self._title, self._owner_document)
    294225
    295226
    296227def _clipboard_get_func_cb(clipboard, selection_data, info, temp_file):