CoverArt Browser  v2.0
Browse your cover-art albums in Rhythmbox
/home/foss/Downloads/coverart-browser/coverart_rb3compat.py
00001 # -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
00002 #
00003 # IMPORTANT - WHILST THIS MODULE IS USED BY SEVERAL OTHER PLUGINS
00004 # THE MASTER AND MOST UP-TO-DATE IS FOUND IN THE COVERART BROWSER
00005 # PLUGIN - https://github.com/fossfreedom/coverart-browser
00006 # PLEASE SUBMIT CHANGES BACK TO HELP EXPAND THIS API
00007 #
00008 # Copyright (C) 2012 - fossfreedom
00009 # Copyright (C) 2012 - Agustin Carrasco
00010 #
00011 # This program is free software; you can redistribute it and/or modify
00012 # it under the terms of the GNU General Public License as published by
00013 # the Free Software Foundation; either version 2, or (at your option)
00014 # any later version.
00015 #
00016 # This program is distributed in the hope that it will be useful,
00017 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 # GNU General Public License for more details.
00020 #
00021 # You should have received a copy of the GNU General Public License
00022 # along with this program; if not, write to the Free Software
00023 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
00024 
00025 import sys
00026 import xml.etree.ElementTree as ET
00027 
00028 from gi.repository import Gtk
00029 from gi.repository import Gio
00030 from gi.repository import GLib
00031 from gi.repository import GObject
00032 from gi.repository import RB
00033 
00034 import rb
00035 
00036 
00037 def pygobject_version():
00038     ''' 
00039     returns float of the major and minor parts of a pygobject version 
00040     e.g. version (3, 9, 5) return float(3.9)
00041     '''
00042     to_number = lambda t: ".".join(str(v) for v in t)
00043 
00044     str_version = to_number(GObject.pygobject_version)
00045 
00046     return float(str_version.rsplit('.', 1)[0])
00047 
00048 
00049 def compare_pygobject_version(version):
00050     '''
00051     return True if version is less than pygobject_version
00052     i.e. 3.9 < 3.11
00053     '''
00054     to_number = lambda t: ".".join(str(v) for v in t)
00055 
00056     str_version = to_number(GObject.pygobject_version)
00057 
00058     split = str_version.rsplit('.', 2)
00059     split_compare = version.rsplit('.', 2)
00060 
00061     if int(split_compare[0]) < int(split[0]):
00062         return True
00063 
00064     if int(split_compare[1]) < int(split[1]):
00065         return True
00066 
00067     return False
00068 
00069 
00070 PYVER = sys.version_info[0]
00071 
00072 if PYVER >= 3:
00073     import urllib.request, urllib.parse, urllib.error
00074 else:
00075     import urllib
00076     from urlparse import urlparse as rb2urlparse
00077 
00078 if PYVER >= 3:
00079     import http.client
00080 else:
00081     import httplib
00082 
00083 
00084 def responses():
00085     if PYVER >= 3:
00086         return http.client.responses
00087     else:
00088         return httplib.responses
00089 
00090 
00091 def unicodestr(param, charset):
00092     if PYVER >= 3:
00093         return param  #str(param, charset)
00094     else:
00095         return unicode(param, charset)
00096 
00097 
00098 def unicodeencode(param, charset):
00099     if PYVER >= 3:
00100         return param  #str(param).encode(charset)
00101     else:
00102         return unicode(param).encode(charset)
00103 
00104 
00105 def unicodedecode(param, charset):
00106     if PYVER >= 3:
00107         return param
00108     else:
00109         return param.decode(charset)
00110 
00111 
00112 def urlparse(uri):
00113     if PYVER >= 3:
00114         return urllib.parse.urlparse(uri)
00115     else:
00116         return rb2urlparse(uri)
00117 
00118 
00119 def url2pathname(url):
00120     if PYVER >= 3:
00121         return urllib.request.url2pathname(url)
00122     else:
00123         return urllib.url2pathname(url)
00124 
00125 
00126 def urlopen(filename):
00127     if PYVER >= 3:
00128         return urllib.request.urlopen(filename)
00129     else:
00130         return urllib.urlopen(filename)
00131 
00132 
00133 def pathname2url(filename):
00134     if PYVER >= 3:
00135         return urllib.request.pathname2url(filename)
00136     else:
00137         return urllib.pathname2url(filename)
00138 
00139 
00140 def unquote(uri):
00141     if PYVER >= 3:
00142         return urllib.parse.unquote(uri)
00143     else:
00144         return urllib.unquote(uri)
00145 
00146 
00147 def quote(uri, safe=None):
00148     if PYVER >= 3:
00149         if safe:
00150             return urllib.parse.quote(uri, safe=safe)
00151         else:
00152             return urllib.parse.quote(uri)
00153     else:
00154         if safe:
00155             return urllib.quote(uri, safe=safe)
00156         else:
00157             return urllib.quote(uri)
00158 
00159 
00160 def quote_plus(uri):
00161     if PYVER >= 3:
00162         return urllib.parse.quote_plus(uri)
00163     else:
00164         return urllib.quote_plus(uri)
00165 
00166 
00167 def is_rb3(*args):
00168     if hasattr(RB.Shell.props, 'ui_manager'):
00169         return False
00170     else:
00171         return True
00172 
00173 
00174 class Menu(GObject.Object):
00175     '''
00176     Menu object used to create window popup menus
00177     '''
00178     __gsignals__ = {
00179         'pre-popup': (GObject.SIGNAL_RUN_LAST, None, ())
00180     }
00181 
00182     def __init__(self, plugin, shell):
00183         '''
00184         Initializes the menu.
00185         '''
00186         super(Menu, self).__init__()
00187         self.plugin = plugin
00188         self.shell = shell
00189         self._unique_num = 0
00190 
00191         self._rbmenu_items = {}
00192         self._rbmenu_objects = {}
00193 
00194     def add_menu_item(self, menubar, section_name, action):
00195         '''
00196         add a new menu item to the popup
00197         :param menubar: `str` is the name GtkMenu (or ignored for RB2.99+)
00198         :param section_name: `str` is the name of the section to add the item to (RB2.99+)
00199         :param action: `Action`  to associate with the menu item
00200         '''
00201         return self.insert_menu_item(menubar, section_name, -1, action)
00202 
00203     def insert_menu_item(self, menubar, section_name, position, action):
00204         '''
00205         add a new menu item to the popup
00206         :param menubar: `str` is the name GtkMenu (or ignored for RB2.99+)
00207         :param section_name: `str` is the name of the section to add the item to (RB2.99+)
00208         :param position: `int` position to add to GtkMenu (ignored for RB2.99+)
00209         :param action: `Action`  to associate with the menu item
00210         '''
00211         label = action.label
00212 
00213         if is_rb3(self.shell):
00214             app = self.shell.props.application
00215             item = Gio.MenuItem()
00216             action.associate_menuitem(item)
00217             item.set_label(label)
00218 
00219             if not section_name in self._rbmenu_items:
00220                 self._rbmenu_items[section_name] = []
00221             self._rbmenu_items[section_name].append(label)
00222 
00223             app.add_plugin_menu_item(section_name, label, item)
00224         else:
00225             item = Gtk.MenuItem(label=label)
00226             action.associate_menuitem(item)
00227             self._rbmenu_items[label] = item
00228             bar = self.get_menu_object(menubar)
00229 
00230             if position == -1:
00231                 bar.append(item)
00232             else:
00233                 bar.insert(item, position)
00234             bar.show_all()
00235             uim = self.shell.props.ui_manager
00236             uim.ensure_update()
00237 
00238         return item
00239 
00240     def insert_separator(self, menubar, at_position):
00241         '''
00242         add a separator to the popup (only required for RB2.98 and earlier)
00243         :param menubar: `str` is the name GtkMenu (or ignored for RB2.99+)
00244         :param position: `int` position to add to GtkMenu (ignored for RB2.99+)
00245         '''
00246         if not is_rb3(self.shell):
00247             menu_item = Gtk.SeparatorMenuItem().new()
00248             menu_item.set_visible(True)
00249             self._rbmenu_items['separator' + str(self._unique_num)] = menu_item
00250             self._unique_num = self._unique_num + 1
00251             bar = self.get_menu_object(menubar)
00252             bar.insert(menu_item, at_position)
00253             bar.show_all()
00254             uim = self.shell.props.ui_manager
00255             uim.ensure_update()
00256 
00257     def remove_menu_items(self, menubar, section_name):
00258         '''
00259         utility function to remove all menuitems associated with the menu section
00260         :param menubar: `str` is the name of the GtkMenu containing the menu items (ignored for RB2.99+)
00261         :param section_name: `str` is the name of the section containing the menu items (for RB2.99+ only)
00262         '''
00263         if is_rb3(self.shell):
00264             if not section_name in self._rbmenu_items:
00265                 return
00266 
00267             app = self.shell.props.application
00268 
00269             for menu_item in self._rbmenu_items[section_name]:
00270                 app.remove_plugin_menu_item(section_name, menu_item)
00271 
00272             if self._rbmenu_items[section_name]:
00273                 del self._rbmenu_items[section_name][:]
00274 
00275         else:
00276 
00277             if not self._rbmenu_items:
00278                 return
00279 
00280             uim = self.shell.props.ui_manager
00281             bar = self.get_menu_object(menubar)
00282 
00283             for menu_item in self._rbmenu_items:
00284                 bar.remove(self._rbmenu_items[menu_item])
00285 
00286             bar.show_all()
00287             uim.ensure_update()
00288 
00289     def load_from_file(self, rb2_ui_filename, rb3_ui_filename):
00290         '''
00291         utility function to load the menu structure
00292         :param rb2_ui_filename: `str` RB2.98 and below UI file
00293         :param rb3_ui_filename: `str` RB2.99 and higher UI file
00294         '''
00295         self.builder = Gtk.Builder()
00296         try:
00297             from coverart_browser_prefs import CoverLocale
00298 
00299             cl = CoverLocale()
00300 
00301             self.builder.set_translation_domain(cl.Locale.LOCALE_DOMAIN)
00302         except:
00303             pass
00304 
00305         if is_rb3(self.shell):
00306             ui_filename = rb3_ui_filename
00307         else:
00308             ui_filename = rb2_ui_filename
00309 
00310         self.ui_filename = ui_filename
00311 
00312         self.builder.add_from_file(rb.find_plugin_file(self.plugin,
00313                                                        ui_filename))
00314 
00315     def _connect_rb3_signals(self, signals):
00316         def _menu_connect(action_name, func):
00317             action = Gio.SimpleAction(name=action_name)
00318             action.connect('activate', func)
00319             action.set_enabled(True)
00320             self.shell.props.window.add_action(action)
00321 
00322         for key, value in signals.items():
00323             _menu_connect(key, value)
00324 
00325     def _connect_rb2_signals(self, signals):
00326         def _menu_connect(menu_item_name, func):
00327             menu_item = self.get_menu_object(menu_item_name)
00328             menu_item.connect('activate', func)
00329 
00330         for key, value in signals.items():
00331             _menu_connect(key, value)
00332 
00333     def connect_signals(self, signals):
00334         '''
00335         connect all signal handlers with their menuitem counterparts
00336         :param signals: `dict` key is the name of the menuitem 
00337              and value is the function callback when the menu is activated
00338         '''
00339         if is_rb3(self.shell):
00340             self._connect_rb3_signals(signals)
00341         else:
00342             self._connect_rb2_signals(signals)
00343 
00344     def get_gtkmenu(self, source, popup_name):
00345         '''
00346         utility function to obtain the GtkMenu from the menu UI file
00347         :param popup_name: `str` is the name menu-id in the UI file
00348         '''
00349         if popup_name in self._rbmenu_objects:
00350             return self._rbmenu_objects[popup_name]
00351         item = self.builder.get_object(popup_name)
00352 
00353         if is_rb3(self.shell):
00354             app = self.shell.props.application
00355             app.link_shared_menus(item)
00356             popup_menu = Gtk.Menu.new_from_model(item)
00357             popup_menu.attach_to_widget(source, None)
00358         else:
00359             popup_menu = item
00360 
00361         self._rbmenu_objects[popup_name] = popup_menu
00362 
00363         return popup_menu
00364 
00365     def get_menu_object(self, menu_name_or_link):
00366         '''
00367         utility function returns the GtkMenuItem/Gio.MenuItem
00368         :param menu_name_or_link: `str` to search for in the UI file
00369         '''
00370         if menu_name_or_link in self._rbmenu_objects:
00371             return self._rbmenu_objects[menu_name_or_link]
00372         item = self.builder.get_object(menu_name_or_link)
00373         if is_rb3(self.shell):
00374             if item:
00375                 popup_menu = item
00376             else:
00377                 app = self.shell.props.application
00378                 popup_menu = app.get_plugin_menu(menu_name_or_link)
00379         else:
00380             popup_menu = item
00381         print(menu_name_or_link)
00382         self._rbmenu_objects[menu_name_or_link] = popup_menu
00383 
00384         return popup_menu
00385 
00386     def set_sensitive(self, menu_or_action_item, enable):
00387         '''
00388         utility function to enable/disable a menu-item
00389         :param menu_or_action_item: `GtkMenuItem` or `Gio.SimpleAction`
00390            that is to be enabled/disabled
00391         :param enable: `bool` value to enable/disable
00392         '''
00393 
00394         if is_rb3(self.shell):
00395             item = self.shell.props.window.lookup_action(menu_or_action_item)
00396             item.set_enabled(enable)
00397         else:
00398             item = self.get_menu_object(menu_or_action_item)
00399             item.set_sensitive(enable)
00400 
00401     def popup(self, source, menu_name, button, time):
00402         '''
00403         utility function to show the popup menu
00404         '''
00405         self.emit('pre-popup')
00406         menu = self.get_gtkmenu(source, menu_name)
00407         menu.popup(None, None, None, None, button, time)
00408 
00409 
00410 class ActionGroup(object):
00411     '''
00412     container for all Actions used to associate with menu items
00413     '''
00414 
00415     # action_state
00416     STANDARD = 0
00417     TOGGLE = 1
00418 
00419     def __init__(self, shell, group_name):
00420         '''
00421         constructor
00422         :param shell: `RBShell`
00423         :param group_name: `str` unique name for the object to create
00424         '''
00425         self.group_name = group_name
00426         self.shell = shell
00427 
00428         self._actions = {}
00429 
00430         if is_rb3(self.shell):
00431             self.actiongroup = Gio.SimpleActionGroup()
00432         else:
00433             self.actiongroup = Gtk.ActionGroup(group_name)
00434             uim = self.shell.props.ui_manager
00435             uim.insert_action_group(self.actiongroup)
00436 
00437     @property
00438     def name(self):
00439         return self.group_name
00440 
00441     def remove_actions(self):
00442         '''
00443         utility function to remove all actions associated with the ActionGroup
00444         '''
00445         for action in self.actiongroup.list_actions():
00446             self.actiongroup.remove_action(action)
00447 
00448     def get_action(self, action_name):
00449         '''
00450         utility function to obtain the Action from the ActionGroup
00451         
00452         :param action_name: `str` is the Action unique name
00453         '''
00454         return self._actions[action_name]
00455 
00456     def add_action_with_accel(self, func, action_name, accel, **args):
00457         '''
00458         Creates an Action with an accelerator and adds it to the ActionGroup
00459         
00460         :param func: function callback used when user activates the action
00461         :param action_name: `str` unique name to associate with an action
00462         :param accel: `str` accelerator
00463         :param args: dict of arguments - this is passed to the function callback
00464         
00465         Notes: 
00466         see notes for add_action
00467         '''
00468         args['accel'] = accel
00469         return self.add_action(func, action_name, **args)
00470 
00471     def add_action(self, func, action_name, **args):
00472         '''
00473         Creates an Action and adds it to the ActionGroup
00474         
00475         :param func: function callback used when user activates the action
00476         :param action_name: `str` unique name to associate with an action
00477         :param args: dict of arguments - this is passed to the function callback
00478         
00479         Notes: 
00480         key value of "label" is the visual menu label to display
00481         key value of "action_type" is the RB2.99 Gio.Action type ("win" or "app")
00482            by default it assumes all actions are "win" type
00483         key value of "action_state" determines what action state to create
00484         '''
00485         if 'label' in args:
00486             label = args['label']
00487         else:
00488             label = action_name
00489 
00490         if 'accel' in args:
00491             accel = args['accel']
00492         else:
00493             accel = None
00494 
00495         state = ActionGroup.STANDARD
00496         if 'action_state' in args:
00497             state = args['action_state']
00498 
00499         if is_rb3(self.shell):
00500             if state == ActionGroup.TOGGLE:
00501                 action = Gio.SimpleAction.new_stateful(action_name, None,
00502                                                        GLib.Variant('b', False))
00503             else:
00504                 action = Gio.SimpleAction.new(action_name, None)
00505 
00506             action_type = 'win'
00507             if 'action_type' in args:
00508                 if args['action_type'] == 'app':
00509                     action_type = 'app'
00510 
00511             app = Gio.Application.get_default()
00512 
00513             if action_type == 'app':
00514                 app.add_action(action)
00515             else:
00516                 self.shell.props.window.add_action(action)
00517                 self.actiongroup.add_action(action)
00518 
00519             if accel:
00520                 app.add_accelerator(accel, action_type + "." + action_name, None)
00521         else:
00522             if 'stock_id' in args:
00523                 stock_id = args['stock_id']
00524             else:
00525                 stock_id = Gtk.STOCK_CLEAR
00526 
00527             if state == ActionGroup.TOGGLE:
00528                 action = Gtk.ToggleAction(label=label,
00529                                           name=action_name,
00530                                           tooltip='', stock_id=stock_id)
00531             else:
00532                 action = Gtk.Action(label=label,
00533                                     name=action_name,
00534                                     tooltip='', stock_id=stock_id)
00535 
00536             if accel:
00537                 self.actiongroup.add_action_with_accel(action, accel)
00538             else:
00539                 self.actiongroup.add_action(action)
00540 
00541         act = Action(self.shell, action)
00542         act.connect('activate', func, args)
00543 
00544         act.label = label
00545         act.accel = accel
00546 
00547         self._actions[action_name] = act
00548 
00549         return act
00550 
00551 
00552 class ApplicationShell(object):
00553     '''
00554     Unique class that mirrors RB.Application & RB.Shell menu functionality
00555     '''
00556     # storage for the instance reference
00557     __instance = None
00558 
00559     class __impl:
00560         """ Implementation of the singleton interface """
00561 
00562         def __init__(self, shell):
00563             self.shell = shell
00564 
00565             if is_rb3(self.shell):
00566                 self._uids = {}
00567             else:
00568                 self._uids = []
00569 
00570             self._action_groups = {}
00571 
00572         def insert_action_group(self, action_group):
00573             '''
00574             Adds an ActionGroup to the ApplicationShell
00575         
00576             :param action_group: `ActionGroup` to add
00577             '''
00578             self._action_groups[action_group.name] = action_group
00579 
00580         def lookup_action(self, action_group_name, action_name, action_type='app'):
00581             '''
00582             looks up (finds) an action created by another plugin.  If found returns
00583             an Action or None if no matching Action.
00584         
00585             :param action_group_name: `str` is the Gtk.ActionGroup name (ignored for RB2.99+)
00586             :param action_name: `str` unique name for the action to look for
00587             :param action_type: `str` RB2.99+ action type ("win" or "app")
00588             '''
00589 
00590             if is_rb3(self.shell):
00591                 if action_type == "app":
00592                     action = self.shell.props.application.lookup_action(action_name)
00593                 else:
00594                     action = self.shell.props.window.lookup_action(action_name)
00595             else:
00596                 uim = self.shell.props.ui_manager
00597                 ui_actiongroups = uim.get_action_groups()
00598 
00599                 actiongroup = None
00600                 for actiongroup in ui_actiongroups:
00601                     if actiongroup.get_name() == action_group_name:
00602                         break
00603 
00604                 action = None
00605                 if actiongroup:
00606                     action = actiongroup.get_action(action_name)
00607 
00608             if action:
00609                 return Action(self.shell, action)
00610             else:
00611                 return None
00612 
00613         def add_app_menuitems(self, ui_string, group_name, menu='tools'):
00614             '''
00615             utility function to add application menu items.
00616             
00617             For RB2.99 all application menu items are added to the "tools" section of the
00618             application menu. All Actions are assumed to be of action_type "app".
00619             
00620             For RB2.98 or less, it is added however the UI_MANAGER string
00621             is defined.
00622             
00623             :param ui_string: `str` is the Gtk UI definition.  There is not an
00624             equivalent UI definition in RB2.99 but we can parse out menu items since
00625             this string is in XML format
00626         
00627             :param group_name: `str` unique name of the ActionGroup to add menu items to
00628             :param menu: `str` RB2.99 menu section to add to - nominally either
00629               'tools' or 'view'
00630             '''
00631             if is_rb3(self.shell):
00632                 root = ET.fromstring(ui_string)
00633                 for elem in root.findall(".//menuitem"):
00634                     action_name = elem.attrib['action']
00635                     item_name = elem.attrib['name']
00636 
00637                     group = self._action_groups[group_name]
00638                     act = group.get_action(action_name)
00639 
00640                     item = Gio.MenuItem()
00641                     item.set_detailed_action('app.' + action_name)
00642                     item.set_label(act.label)
00643                     item.set_attribute_value("accel", GLib.Variant("s", act.accel))
00644                     app = Gio.Application.get_default()
00645                     index = menu + action_name
00646                     app.add_plugin_menu_item(menu,
00647                                              index, item)
00648                     self._uids[index] = menu
00649             else:
00650                 uim = self.shell.props.ui_manager
00651                 self._uids.append(uim.add_ui_from_string(ui_string))
00652                 uim.ensure_update()
00653 
00654         def add_browser_menuitems(self, ui_string, group_name):
00655             '''
00656             utility function to add popup menu items to existing browser popups
00657             
00658             For RB2.99 all menu items are are assumed to be of action_type "win".
00659             
00660             For RB2.98 or less, it is added however the UI_MANAGER string
00661             is defined.
00662             
00663             :param ui_string: `str` is the Gtk UI definition.  There is not an
00664             equivalent UI definition in RB2.99 but we can parse out menu items since
00665             this string is in XML format
00666         
00667             :param group_name: `str` unique name of the ActionGroup to add menu items to
00668             '''
00669             if is_rb3(self.shell):
00670                 root = ET.fromstring(ui_string)
00671                 for elem in root.findall("./popup"):
00672                     popup_name = elem.attrib['name']
00673 
00674                     menuelem = elem.find('.//menuitem')
00675                     action_name = menuelem.attrib['action']
00676                     item_name = menuelem.attrib['name']
00677 
00678                     group = self._action_groups[group_name]
00679                     act = group.get_action(action_name)
00680 
00681                     item = Gio.MenuItem()
00682                     item.set_detailed_action('win.' + action_name)
00683                     item.set_label(act.label)
00684                     app = Gio.Application.get_default()
00685 
00686                     if popup_name == 'QueuePlaylistViewPopup':
00687                         plugin_type = 'queue-popup'
00688                     elif popup_name == 'BrowserSourceViewPopup':
00689                         plugin_type = 'browser-popup'
00690                     elif popup_name == 'PlaylistViewPopup':
00691                         plugin_type = 'playlist-popup'
00692                     elif popup_name == 'PodcastViewPopup':
00693                         plugin_type = 'podcast-episode-popup'
00694                     else:
00695                         print("unknown type %s" % plugin_type)
00696 
00697                     index = plugin_type + action_name
00698                     app.add_plugin_menu_item(plugin_type, index, item)
00699                     self._uids[index] = plugin_type
00700             else:
00701                 uim = self.shell.props.ui_manager
00702                 self._uids.append(uim.add_ui_from_string(ui_string))
00703                 uim.ensure_update()
00704 
00705         def cleanup(self):
00706             '''
00707             utility remove any menuitems created.
00708             '''
00709             if is_rb3(self.shell):
00710                 for uid in self._uids:
00711                     Gio.Application.get_default().remove_plugin_menu_item(self._uids[uid],
00712                                                                           uid)
00713             else:
00714                 uim = self.shell.props.ui_manager
00715                 for uid in self._uids:
00716                     uim.remove_ui(uid)
00717                 uim.ensure_update();
00718 
00719     def __init__(self, shell):
00720         """ Create singleton instance """
00721         # Check whether we already have an instance
00722         if ApplicationShell.__instance is None:
00723             # Create and remember instance
00724             ApplicationShell.__instance = ApplicationShell.__impl(shell)
00725 
00726         # Store instance reference as the only member in the handle
00727         self.__dict__['_ApplicationShell__instance'] = ApplicationShell.__instance
00728 
00729     def __getattr__(self, attr):
00730         """ Delegate access to implementation """
00731         return getattr(self.__instance, attr)
00732 
00733     def __setattr__(self, attr, value):
00734         """ Delegate access to implementation """
00735         return setattr(self.__instance, attr, value)
00736 
00737 
00738 class Action(object):
00739     '''
00740     class that wraps around either a Gio.Action or a Gtk.Action
00741     '''
00742 
00743     def __init__(self, shell, action):
00744         '''
00745         constructor.
00746 
00747         :param shell: `RBShell`
00748         :param action: `Gio.Action` or `Gtk.Action`
00749         '''
00750         self.shell = shell
00751         self.action = action
00752 
00753         self._label = ''
00754         self._accel = ''
00755         self._current_state = False
00756         self._do_update_state = True
00757 
00758     def connect(self, address, func, args):
00759         self._connect_func = func
00760         self._connect_args = args
00761 
00762         if address == 'activate':
00763             func = self._activate
00764 
00765         if is_rb3(self.shell):
00766             self.action.connect(address, func, args)
00767         else:
00768             self.action.connect(address, func, None, args)
00769 
00770     def _activate(self, action, *args):
00771         if self._do_update_state:
00772             self._current_state = not self._current_state
00773             self.set_state(self._current_state)
00774 
00775         self._connect_func(action, None, self._connect_args)
00776 
00777     @property
00778     def label(self):
00779         ''' 
00780         get the menu label associated with the Action
00781         
00782         for RB2.99+ actions dont have menu labels so this is managed
00783         manually
00784         '''
00785         if not is_rb3(self.shell):
00786             return self.action.get_label()
00787         else:
00788             return self._label
00789 
00790     @label.setter
00791     def label(self, new_label):
00792         if not is_rb3(self.shell):
00793             self.action.set_label(new_label)
00794 
00795         self._label = new_label
00796 
00797     @property
00798     def accel(self):
00799         ''' 
00800         get the accelerator associated with the Action
00801         '''
00802         return self._accel
00803 
00804     @accel.setter
00805     def accel(self, new_accelerator):
00806         if new_accelerator:
00807             self._accel = new_accelerator
00808         else:
00809             self._accel = ''
00810 
00811     def get_sensitive(self):
00812         ''' 
00813         get the sensitivity (enabled/disabled) state of the Action
00814         
00815         returns boolean
00816         '''
00817         if is_rb3(self.shell):
00818             return self.action.get_enabled()
00819         else:
00820             return self.action.get_sensitive()
00821 
00822     def set_state(self, value):
00823         ''' 
00824         set the state of a stateful action - this is applicable only
00825         to RB2.99+
00826         '''
00827         if is_rb3(self.shell) and self.action.props.state_type:
00828             self.action.change_state(GLib.Variant('b', value))
00829 
00830     def activate(self):
00831         ''' 
00832         invokes the activate signal for the action
00833         '''
00834         if is_rb3(self.shell):
00835             self.action.activate(None)
00836         else:
00837             self.action.activate()
00838 
00839     def set_active(self, value):
00840         ''' 
00841         activate or deactivate a stateful action signal
00842         For consistency with earlier RB versions, this will fire the 
00843         activate signal for the action
00844         
00845         :param value: `boolean` state value
00846         '''
00847 
00848         if is_rb3(self.shell):
00849             self.action.change_state(GLib.Variant('b', value))
00850             self._current_state = value
00851             self._do_update_state = False
00852             self.activate()
00853             self._do_update_state = True
00854         else:
00855             self.action.set_active(value)
00856 
00857     def get_active(self):
00858         ''' 
00859         get the state of the action
00860         
00861         returns `boolean` state value
00862         '''
00863         if is_rb3(self.shell):
00864             returnval = self._current_state
00865         else:
00866             returnval = self.action.get_active()
00867 
00868         return returnval
00869 
00870     def associate_menuitem(self, menuitem):
00871         ''' 
00872         links a menu with the action
00873         
00874         '''
00875         if is_rb3(self.shell):
00876             menuitem.set_detailed_action('win.' + self.action.get_name())
00877         else:
00878             menuitem.set_related_action(self.action)
00879             
00880 
 All Classes Functions