CoverArt Browser
v2.0
Browse your cover-art albums in Rhythmbox
|
00001 # -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*- 00002 # 00003 # Copyright (C) 2012 - fossfreedom 00004 # Copyright (C) 2012 - Agustin Carrasco 00005 # 00006 # This program is free software; you can redistribute it and/or modify 00007 # it under the terms of thie GNU General Public License as published by 00008 # the Free Software Foundation; either version 2, or (at your option) 00009 # any later version. 00010 # 00011 # This program is distributed in the hope that it will be useful, 00012 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 # GNU General Public License for more details. 00015 # 00016 # You should have received a copy of the GNU General Public License 00017 # along with this program; if not, write to the Free Software 00018 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 00019 00020 from gi.repository import Peas 00021 from gi.repository import GObject 00022 import lxml.etree as ET 00023 00024 import rb 00025 from coverart_rb3compat import ActionGroup 00026 from coverart_rb3compat import ApplicationShell 00027 from coverart_utils import CaseInsensitiveDict 00028 00029 00030 class ExternalPlugin(GObject.Object): 00031 ''' 00032 class for all supported ExternalPlugins 00033 ''' 00034 00035 def __init__(self, **kargs): 00036 super(ExternalPlugin, self).__init__(**kargs) 00037 00038 # dict of attributes associated with the external plugin 00039 self.attributes = {} 00040 self.attributes['is_album_menu'] = False 00041 self.attributes['new_menu_name'] = '' 00042 self.attributes['action_type'] = '' 00043 self.attributes['action_group_name'] = '' 00044 00045 def appendattribute(self, key, val): 00046 ''' 00047 append another attribute to the dict 00048 00049 :param key: `str` name of attribute 00050 :param val: `str` value of attribute 00051 ''' 00052 00053 if key == 'is_album_menu': 00054 if val == 'yes': 00055 self.attributes[key] = True 00056 else: 00057 self.attributes[key] = False 00058 else: 00059 self.attributes[key] = val 00060 00061 def is_activated(self): 00062 ''' 00063 method to test whether the plugin is actually loaded. Returns a bool 00064 ''' 00065 peas = Peas.Engine.get_default() 00066 loaded_plugins = peas.get_loaded_plugins() 00067 00068 if self.attributes['plugin_name'] in CaseInsensitiveDict(loaded_plugins): 00069 print("found %s" % self.attributes['plugin_name']) 00070 return True 00071 00072 print("search for %s" % self.attributes['plugin_name']) 00073 print(loaded_plugins) 00074 00075 return False 00076 00077 def create_menu_item(self, menubar, section_name, at_position, 00078 save_actiongroup, save_menu, for_album=False): 00079 ''' 00080 method to create the menu item appropriate to the plugin. 00081 A plugin can have many menu items - all menuitems are enclosed 00082 in a section. 00083 00084 :param menubar: `str` name for the GtkMenu - ignored for RB2.99 00085 :param section_name: `str` unique name of the section holding the menu items 00086 :param at_position: `int` position within the GtkMenu to create menu - ignored for RB2.99 00087 :param save_actiongroup: `ActionGroup` container for all menu-item Actions 00088 :param save_menu: `Menu` whole popupmenu including sub-menus 00089 :param for_album: `bool` create the menu for the album - if not given 00090 then its assumed the menu item is appropriate just for tracks 00091 ''' 00092 if for_album and not self.attributes['is_album_menu']: 00093 return False 00094 00095 if not self.is_activated(): 00096 return False 00097 00098 action = ApplicationShell(save_menu.shell).lookup_action(self.attributes['action_group_name'], 00099 self.attributes['action_name'], 00100 self.attributes['action_type']) 00101 00102 if action: 00103 self.attributes['action'] = action 00104 00105 if self.attributes['new_menu_name'] != '': 00106 self.attributes['label'] = self.attributes['new_menu_name'] 00107 else: 00108 self.attributes['label'] = action.label 00109 #self.attributes['sensitive']=action.get_sensitive() 00110 else: 00111 print("action not found") 00112 print(self.attributes) 00113 return False 00114 00115 action = save_actiongroup.add_action(func=self.menuitem_callback, 00116 action_name=self.attributes['action_name'], album=for_album, 00117 shell=save_menu.shell, label=self.attributes['label']) 00118 00119 new_menu_item = save_menu.insert_menu_item(menubar, section_name, 00120 at_position, action) 00121 return new_menu_item 00122 00123 def do_deactivate(self): 00124 pass 00125 00126 def set_entry_view_selected_entries(self, shell): 00127 ''' 00128 method called just before the external plugin action is activated 00129 00130 Normally only called for album menus to mimic selecting all the 00131 EntryView rows 00132 ''' 00133 page = shell.props.selected_page 00134 if not hasattr(page, "get_entry_view"): 00135 return 00136 00137 page.get_entry_view().select_all() 00138 00139 def activate(self, shell): 00140 ''' 00141 method called to initiate the external plugin action 00142 the action is defined by defining the action_group_name, action_name and action_type 00143 ''' 00144 00145 action = ApplicationShell(shell).lookup_action(self.attributes['action_group_name'], 00146 self.attributes['action_name'], 00147 self.attributes['action_type']) 00148 00149 if action: 00150 action.activate() 00151 00152 def menuitem_callback(self, action, param, args): 00153 ''' 00154 method called when a menu-item is clicked. Basically, an Action 00155 is activated by the user 00156 00157 :param action: `Gio.SimpleAction` or `Gtk.Action` 00158 :param param: Not used 00159 :param args: dict associated with the action 00160 ''' 00161 for_album = args['album'] 00162 shell = args['shell'] 00163 if for_album: 00164 self.set_entry_view_selected_entries(shell) 00165 00166 self.attributes['action'].activate() 00167 00168 00169 class CreateExternalPluginMenu(GObject.Object): 00170 ''' 00171 This is the key class called to initialise all supported plugins 00172 00173 :param section_name: `str` unique name of the section holding the menu items 00174 :param at_position: `int` position within the GtkMenu to create menu - ignored for RB2.99 00175 :param popup: `Menu` whole popupmenu including sub-menus 00176 ''' 00177 00178 def __init__(self, section_name, at_position, popup, **kargs): 00179 super(CreateExternalPluginMenu, self).__init__(**kargs) 00180 00181 self.menu = popup 00182 self.section_name = section_name 00183 self.at_position = at_position 00184 00185 self._actiongroup = ActionGroup(popup.shell, section_name + '_externalplugins') 00186 00187 # all supported plugins will be defined in the following array by parsing 00188 # the plugins XML file for the definition. 00189 00190 self.supported_plugins = [] 00191 00192 extplugins = rb.find_plugin_file(popup.plugin, 'ui/coverart_external_plugins.xml') 00193 root = ET.parse(open(extplugins)).getroot() 00194 00195 base = 'rb3/plugin' 00196 00197 for elem in root.xpath(base): 00198 pluginname = elem.attrib['name'] 00199 00200 basemenu = base + "[@name='" + pluginname + "']/menu" 00201 00202 for menuelem in root.xpath(basemenu): 00203 ext = ExternalPlugin() 00204 ext.appendattribute('plugin_name', pluginname) 00205 00206 label = menuelem.attrib['label'] 00207 if label != "": 00208 ext.appendattribute('new_menu_name', label) 00209 baseattrib = basemenu + "[@label='" + label + "']/attribute" 00210 else: 00211 baseattrib = basemenu + "/attribute" 00212 00213 for attribelem in root.xpath(baseattrib): 00214 key = attribelem.attrib['name'] 00215 val = attribelem.text 00216 ext.appendattribute(key, val) 00217 00218 self.supported_plugins.append(ext) 00219 00220 def create_menu(self, menu_name, for_album=False): 00221 ''' 00222 method to create the menu items for all supported plugins 00223 00224 :param menu_name: `str` unique name (GtkMenu) id for the menu to create 00225 :for_album: `bool` - create a menu applicable for Albums 00226 by default a menu is assumed to be applicable to a track in an 00227 EntryView 00228 ''' 00229 self.menu_name = menu_name 00230 00231 self._actiongroup.remove_actions() 00232 self.menu.remove_menu_items(self.menu_name, self.section_name) 00233 00234 items_added = False 00235 00236 for plugin in self.supported_plugins: 00237 new_menu_item = plugin.create_menu_item(self.menu_name, self.section_name, 00238 self.at_position, self._actiongroup, self.menu, for_album) 00239 00240 if (not items_added) and new_menu_item: 00241 items_added = True 00242 00243 if items_added: 00244 self.menu.insert_separator(self.menu_name, self.at_position)