def _getPronunciations(self, profile, app=None): pronunciationSettings = {} if app is not None and app != '': baseGSettings = Settings( schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecific = True else: baseGSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) appSpecific = False pronunciations = baseGSettings.get_strv('pronunciations') for pronunciation in pronunciations: if appSpecific == True: pronunciationSetting = Settings( schema_id='org.gnome.orca.pronunciation', path='/org/gnome/orca/profile/%s/app/%s/pronunciation/%s/' % (profile, app, pronunciation)) else: pronunciationSetting = Settings( schema_id='org.gnome.orca.pronunciation', path='/org/gnome/orca/profile/%s/pronunciation/%s/' % (profile, pronunciation)) actualSetting = pronunciationSetting.get_string('actual') replacementSetting = pronunciationSetting.get_string('replacement') pronunciationSettings[pronunciation] = [ actualSetting, replacementSetting ] return pronunciationSettings
def _saveKeybindings(self, keybindings, profile, app=None): if app is not None and app != '': baseGSettings = Settings( schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecific = True else: baseGSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) appSpecific = False keybindingList = baseGSettings.get_strv('keybindings') for keybinding in keybindings.keys(): if appSpecific == True: keybindingSettings = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/app/%s/keybinding/%s/' % (profile, app, keybinding)) else: keybindingSettings = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/keybinding/%s/' % (profile, keybinding)) if keybinding not in keybindingList: keybindingList.append(keybinding) keybindingVal = keybindings[keybinding][0] keybindingSettings.set_string('key', keybindingVal[0]) keybindingSettings.set_string('mod-mask', keybindingVal[1]) keybindingSettings.set_string('mod-used', keybindingVal[2]) keybindingSettings.set_string('click-count', keybindingVal[3]) # Now we remove any deleted keybindings from Gsettings. for keybinding in keybindingList: if keybinding not in keybindings.keys(): if appSpecific == True: keybindingSettings = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/app/%s/keybinding/%s/' % (profile, app, keybinding)) else: keybindingSettings = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/keybinding/%s/' % (profile, keybinding)) keybindingList.remove(keybinding) keybindingSettings.reset('key') keybindingSettings.reset('mod-mask') keybindingSettings.reset('mod-used') keybindingSettings.reset('click-count') if keybindingList == []: baseGSettings.reset('keybindings') else: baseGSettings.set_strv('keybindings', keybindingList)
def _savePronunciations(self, pronunciations, profile, app=None): if app is not None and app != '': baseGSettings = Settings( schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecific = True else: baseGSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) appSpecific = False pronunciationList = baseGSettings.get_strv('pronunciations') for pronunciation in pronunciations.keys(): if appSpecific == True: pronunciationSettings = Settings( schema_id='org.gnome.orca.pronunciation', path='/org/gnome/orca/profile/%s/app/%s/pronunciation/%s/' % (profile, app, pronunciation)) else: pronunciationSettings = Settings( schema_id='org.gnome.orca.pronunciation', path='/org/gnome/orca/profile/%s/pronunciation/%s/' % (profile, pronunciation)) if pronunciation not in pronunciationList: pronunciationList.append(pronunciation) pronunciationVal = pronunciations[pronunciation] pronunciationSettings.set_string('actual', pronunciationVal[0]) pronunciationSettings.set_string('replacement', pronunciationVal[1]) # Now we remove any deleted pronunciations from GSettings. for pronunciation in pronunciationList: if pronunciation not in pronunciations.keys(): if appSpecific == True: pronunciationSettings = Settings( schema_id='org.gnome.orca.pronunciation', path= '/org/gnome/orca/profile/%s/app/%s/pronunciation/%s/' % (profile, app, pronunciation)) else: pronunciationSettings = Settings( schema_id='org.gnome.orca.pronunciation', path='/org/gnome/orca/profile/%s/pronunciation/%s/' % (profile, pronunciation)) pronunciationList.remove(pronunciation) pronunciationSettings.reset('actual') pronunciationSettings.reset('replacement') if pronunciationList == []: baseGSettings.reset('pronunciations') else: baseGSettings.set_strv('pronunciations', pronunciationList)
def availableProfiles(self): """ List available profiles. """ profileList = self.baseSettings.get_strv('profiles') profiles = [] for profile in profileList: profileSettings = Settings(schema_id='org.gnome.orca.general', path='/org/gnome/orca/profile/%s/' % profile) profiles.append(profileSettings.get_strv('profile')) return profiles
def _getPluginLayouts(self): plugin_layouts= {} self.plugviews = GSettings(schema=PLUGVIEWS_GSCHEMA) plugin_layouts['Top panel'] = self.plugviews.get_strv('top-panel-layout') plugin_layouts['Bottom panel'] = self.plugviews.get_strv('bottom-panel-layout') for plugview in self.plugviews.get_strv('available-newviews'): gspath = NEWPLUGVIEWS_PATH + plugview.lower().replace(' ', '-') + '/' newview = GSettings(schema=NEWPLUGVIEWS_GSCHEMA, path=gspath) layout = newview.get_strv('layout') if layout: plugin_layouts[plugview] = layout else: l = self.plugviews.get_strv('available-newviews') l.remove(plugview) self.plugviews.set_strv('available-newviews', l) return plugin_layouts
def _getPluginLayouts(self): plugin_layouts = {} self.plugviews = GSettings(schema=PLUGVIEWS_GSCHEMA) plugin_layouts['Top panel'] = self.plugviews.get_strv( 'top-panel-layout') plugin_layouts['Bottom panel'] = self.plugviews.get_strv( 'bottom-panel-layout') for plugview in self.plugviews.get_strv('available-newviews'): gspath = NEWPLUGVIEWS_PATH + plugview.lower().replace(' ', '-') + '/' newview = GSettings(schema=NEWPLUGVIEWS_GSCHEMA, path=gspath) layout = newview.get_strv('layout') if layout: plugin_layouts[plugview] = layout else: l = self.plugviews.get_strv('available-newviews') l.remove(plugview) self.plugviews.set_strv('available-newviews', l) return plugin_layouts
def saveAppSettings(self, appName, profile, general, pronunciations, keybindings): profiles = self.baseSettings.get_strv('profiles') if profile in profiles: profileBaseSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) apps = profileBaseSettings.get_strv('apps') if appName not in apps: apps.append(appName) profileBaseSettings.set_strv('apps', apps) self._saveGeneralSettings(general, profile, appName) if general.__contains__('voices'): self._saveVoiceSettings(general['voices'], profile, appName) self._savePronunciations(pronunciations, profile, appName) self._saveKeybindings(keybindings, profile, appName)
def getAppSettings(self, appName): prefs = {} profiles = {} availableProfiles = self.baseSettings.get_strv('profiles') for profile in availableProfiles: profileSettings = {} generalSettings = {} voiceSettings = {} pronunciationSettings = {} keybindingSettings = {} profileBaseSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) profileApps = profileBaseSettings.get_strv('apps') if appName in profileApps: generalSettings = self._getGeneralSettings(profile, appName) voiceSettings = self._getVoiceSettings(profile, appName) if voiceSettings != {}: generalSettings['voices'] = voiceSettings pronunciationSettings = self._getPronunciations( profile, appName) keybindingSettings = self._getKeybindings(profile, appName) profileSettings['general'] = generalSettings profileSettings['keybindings'] = keybindingSettings profileSettings['pronunciations'] = pronunciationSettings profiles[profile] = profileSettings if profiles != {}: prefs['profiles'] = profiles return prefs
def _getKeybindings(self, profile, app=None): keybindingSettings = {} if app is not None and app != '': baseGSettings = Settings( schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecific = True else: baseGSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) appSpecific = False keybindings = baseGSettings.get_strv('keybindings') for keybinding in keybindings: if appSpecific == True: keybindingSetting = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/app/%s/keybinding/%s/' % (profile, app, keybinding)) else: keybindingSetting = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/keybinding/%s/' % (profile, keybinding)) keySetting = keybindingSetting.get_string('key') modMaskSetting = keybindingSetting.get_string('mod-mask') modUsedSetting = keybindingSetting.get_string('mod-used') clickCountSetting = keybindingSetting.get_string('click-count') keybindingSettings[keybinding] = [[ keySetting, modMaskSetting, modUsedSetting, clickCountSetting ]] return keybindingSettings
def getGeneral(self, profile='default'): profiles = self.baseSettings.get_strv('profiles') startingProfile = self.baseSettings.get_strv('starting-profile') generalSettings = {} voiceSettings = {} generalSettings['startingProfile'] = startingProfile if profile in profiles: profileGeneralSettings = Settings( schema_id='org.gnome.orca.general', path='/org/gnome/orca/profile/%s/' % profile) generalSettings = self._getGeneralSettings(profile) voiceSettings = self._getVoiceSettings(profile) generalSettings['voices'] = voiceSettings generalSettings['activeProfile'] = profileGeneralSettings.get_strv( 'profile') self.baseSettings.set_strv('active-profile', generalSettings['activeProfile']) return generalSettings
class MultiViewModel(list, BaseViewModel): ''' Manages all plugin views. Implements a gtk.ListStore of all views. Persists plugin view placements across sessions. @cvar COL_NAME: View name column ID. @type COL_NAME: integer @cvar COL_INSTANCE: View instance column ID. @type COL_INSTANCE: integer @ivar perm_views: List of permanent views. @type perm_views: list of L{PluginView} @ivar main_view: Main view. @type main_view: L{PluginView} @ivar _ignore_insertion: A list of tuples with view and plugin names that should be ignored and not go in to gsettings. This is to avoid recursive gsettings modification. @type _ignore_insertion: list of tuples @ivar _placement_cache: A cache of recently disabled plugins with their placement. allowsthem to be enabled in to the same position. @type _placement_cache: dictionary @ivar _closed: Indicator to stop writing plugin remove events to gsettings. @type _closed: boolean ''' COL_NAME = 0 COL_INSTANCE = 1 def __init__(self, *perm_views): ''' Initialize view manager. @param perm_views: List of permanent views, at least one is required. @type perm_views: list of {PluginView} ''' BaseViewModel.__init__(self, *perm_views) for view in self.perm_views: self.append(view) self._connectSignals(view) self._ignore_insertion = [] self._placement_cache = {} self._closed = False def close(self): ''' Stops gsettings maniputaion. ''' self._closed = True def getViewNameForPlugin(self, plugin_name): ''' Get the view name for a given plugin name as defined in gsettings. Or return name of main view. @param plugin_name: Plugin's name to lookup view for. @type plugin_name: string @return: View name for plugin. @rtype: string ''' plugin_layouts = self._getPluginLayouts() for view_name in plugin_layouts: if plugin_name in plugin_layouts[view_name]: return view_name return self.main_view.view_name def _getViewByName(self, view_name): ''' Return the view instance of the given name. @param view_name: Name of view to retrieve. @type view_name: string @return: View instance or None @rtype: L{PluginView} ''' for view in self: if view.view_name == view_name: return view return None def _onPluginDragEnd(self, view, plugin): ''' Callback for the end of a drag operation of a plugin. Only is called when the drag ends on the root window. @param view: Current plugin's view. @type view: L{PluginView} @param plugin: Plugin that was dragged. @type plugin: L{Plugin} ''' new_view = self._newView() view.remove(plugin) new_view.append_page(plugin) new_view.set_tab_detachable(plugin, True) new_view.set_tab_reorderable(plugin, True) def _newView(self, view_name=None): ''' Creates a new view. @param view_name: An optional view name. Gives a more mundane one if no name is provided. @type view_name: string @return: New view @rtype: L{PluginView} ''' if not view_name: view_name = _('Plugin View') view_num = 2 while view_name in self._getViewNames(): view_name = _('Plugin View (%d)') % view_num view_num += 1 w = PluginViewWindow(view_name) view = w.plugin_view self._connectSignals(view) self.append(view) return view def _getViewOrNewView(self, view_name): ''' Get an existing or new view with the current name. @param view_name: View's name @type view_name: string @return: New or existing view. @rtype: L{PluginView} ''' view = self._getViewByName(view_name) or self._newView(view_name) return view def _onViewDelete(self, view_window, event): ''' Callback for a view window's delete event. Puts all orphaned plugins in main view. @param view_window: View window that emitted delete event. @type view_window: L{PluginViewWindow} @param event: Event object. @type event: gtk.gdk.Event ''' view = view_window.plugin_view for child in view.getPlugins(): view.remove(child) self.main_view.append_page(child) self._removeView(view) def _removeView(self, view): ''' Removes view from model. @param view: View to remove. @type view: L{PluginView} ''' if view in self.perm_views: return if view in self: self.remove(view) def _onTabPopupMenu(self, view, event, plugin): ''' Callback for popup menu signal from plugin view. Displays a context menu with available views. @param view: Plugin view that emitted this signal. @type view: L{PluginView} @param event: Relevant event object that will be used in popup menu. @type event: gtk.gdk.Event @param plugin: Plugin of tab that was clicked or pressed. @type plugin: L{Plugin} ''' menu = self.Menu(plugin, view.get_toplevel()) if hasattr(event, 'button'): menu.popup(None, None, None, None, event.button, event.time) else: tab = view.get_tab_label(plugin) x, y, w, h = view.getTabAlloc(tab) rect = gdk.Rectangle(x, y, w, h) menu.popup(None, None, lambda m, r: (r.x+r.width/2, r.y+r.height/2, True), rect, 0, event.time) def _connectSignals(self, view): ''' Convenience function for connecting all needed signal callbacks. @param view: Plugin view to connect. @type view: :{PluginView} ''' if isinstance(view.get_parent(), PluginViewWindow): view.get_parent().connect('delete-event', Proxy(self._onViewDelete)) view.connect('plugin-drag-end', Proxy(self._onPluginDragEnd)) view.connect('tab-popup-menu', Proxy(self._onTabPopupMenu)) view.connect('page-added', Proxy(self._onViewLayoutChanged), 'added') view.connect('page-removed', Proxy(self._onViewLayoutChanged), 'removed') view.connect('page-reordered', Proxy(self._onViewLayoutChanged), 'reordered') def _onViewLayoutChanged(self, view, plugin, page_num, action): ''' Callback for all layout changes. Updates gsettings. @param view: View that emitted the signal. @type view: L{PluginView} @param plugin: Plugin that moved. @type plugin: L{Plugin} @param page_num: Plugin's position in view. @type page_num: integer @param action: Action that triggered this event. @type action: string ''' if self._closed or not isinstance(plugin, Plugin): return if (view.view_name, plugin.plugin_name) in self._ignore_insertion: self._ignore_insertion.remove((view.view_name, plugin.plugin_name)) return if plugin.plugin_name in self._placement_cache: self._placement_cache.pop(plugin.plugin_name) plugin_layouts = self._getPluginLayouts() try: plugin_layout = plugin_layouts[view.view_name] except KeyError: plugin_layouts[view.view_name] = [] plugin_layout = plugin_layouts[view.view_name] if plugin.plugin_name in plugin_layout: plugin_layout.remove(plugin.plugin_name) if action in ('reordered', 'added'): plugin_layout.insert(page_num, plugin.plugin_name) elif action == 'removed': self._placement_cache[plugin.plugin_name] = (view.view_name, page_num) if len(plugin_layout) == 0: self._removeView(view) self._setPluginLayouts(plugin_layouts) def _setPluginLayouts(self, plugin_layouts): self.plugviews = GSettings(schema=PLUGVIEWS_GSCHEMA) self.plugviews.set_strv('top-panel-layout', plugin_layouts.pop('Top panel')) self.plugviews.set_strv('bottom-panel-layout', plugin_layouts.pop('Bottom panel')) for plugview in list(plugin_layouts.keys()): gspath = NEWPLUGVIEWS_PATH + plugview.lower().replace(' ', '-') + '/' newview = GSettings(schema=NEWPLUGVIEWS_GSCHEMA, path=gspath) newview.set_strv('layout', plugin_layouts[plugview]) l = self.plugviews.get_strv('available-newviews') l.append(plugview) self.plugviews.set_strv('available-newviews', l) def _getPluginLayouts(self): plugin_layouts= {} self.plugviews = GSettings(schema=PLUGVIEWS_GSCHEMA) plugin_layouts['Top panel'] = self.plugviews.get_strv('top-panel-layout') plugin_layouts['Bottom panel'] = self.plugviews.get_strv('bottom-panel-layout') for plugview in self.plugviews.get_strv('available-newviews'): gspath = NEWPLUGVIEWS_PATH + plugview.lower().replace(' ', '-') + '/' newview = GSettings(schema=NEWPLUGVIEWS_GSCHEMA, path=gspath) layout = newview.get_strv('layout') if layout: plugin_layouts[plugview] = layout else: l = self.plugviews.get_strv('available-newviews') l.remove(plugview) self.plugviews.set_strv('available-newviews', l) return plugin_layouts def addPlugin(self, plugin): ''' Add a plugin to the view. Check if it's placement is cached in this instance or read it's position from gsettings. By default a plugin is appended to the main view. @param plugin: Plugin to add. @type plugin: L{Plugin} ''' if plugin.plugin_name in self._placement_cache: view_name, index = self._placement_cache.pop(plugin.plugin_name) view = self._getViewOrNewView(view_name) else: view_name = self.getViewNameForPlugin(plugin.plugin_name) view = self._getViewOrNewView(view_name) plugin_layouts = self._getPluginLayouts() try: plugin_layout = plugin_layouts[view.view_name] except KeyError: plugin_layout = [] plugin_layouts[view.view_name] = plugin_layout index = -1 if plugin.plugin_name in plugin_layout: # The plugins that have a higher index. successive = plugin_layout[plugin_layout.index(plugin.plugin_name)+1:] for child_index, preceding_plugin in enumerate(view.getPlugins()): if preceding_plugin.plugin_name in successive: # Place new plugin just before the first successive plugin. index = child_index break self._ignore_insertion.append((view.view_name, plugin.plugin_name)) self._setPluginLayouts(plugin_layouts) view.insert_page(plugin, position=index) view.set_tab_detachable(plugin, True) view.set_tab_reorderable(plugin, True) plugin.show_all() def initialView(self): ''' Set the current tab of all views to be the first one. Used when Accercier first starts. ''' for view in self: view.set_current_page(0) def getViewedPlugins(self): ''' Get all plugins from all views. ''' rv = [] for view in self: rv.extend(view.getPlugins()) return rv def _getViewNames(self): ''' Get a list of all managed view names. @return: A list of view names. @rtype: list of string ''' return [view.view_name for view in self] def changeView(self, plugin, new_view_name): ''' Put a plugin instance in a different view. If given view name does not exist, create it. @param plugin: Plugin to move. @type plugin: L{Plugin} @param new_view_name: New view name. @type new_view_name: string ''' if not plugin or not isinstance(plugin, gtk.Widget): return old_view = plugin.get_parent() new_view = self._getViewOrNewView(new_view_name) if old_view is not new_view: old_view.remove(plugin) new_view.append_page(plugin) new_view.set_tab_detachable(plugin, True) new_view.set_tab_reorderable(plugin, True) def Menu(self, context_plugin, transient_window): ''' Helps emulate a non-static inner class. These don't exist in python, I think. @param context_plugin: Subject plugin of this menu. @type context_plugin: L{Plugin} @param transient_window: Transient parent window. Used for keeping the new view dialog modal. @type transient_window: gtk.Window @return: An inner menu class. @rtype: L{ViewManager._Menu} ''' return self._Menu(self, context_plugin, transient_window) class _Menu(gtk.Menu): ''' Implements a popup menu for a plugin that will allow putting the plugin in a different view. @cvar RADIO_GROUP: Radio menu item's group id. @type RADIO_GROUP: integer @ivar view_manager: View manager to use as data model and controller. @type view_manager: L{ViewManager} ''' RADIO_GROUP = 13 def __init__(self, view_manager, context_plugin, transient_window): ''' Initialize menu. @param view_manager: View manager to use as data model and controller. @type view_manager: L{ViewManager} @param context_plugin: Subject plugin of this menu. @type context_plugin: L{Plugin} @param transient_window: Transient parent window. Used for keeping the new view dialog modal. @type transient_window: gtk.Window ''' gtk.Menu.__init__(self) self.view_manager = view_manager if isinstance(context_plugin, gtk.Widget): self._buildMenu(context_plugin, transient_window) def _buildMenu(self, context_plugin, transient_window): ''' Build the menu according to the view managers model. @param context_plugin: Subject plugin of this menu. @type context_plugin: L{Plugin} @param transient_window: Transient parent window. Used for keeping the new view dialog modal. @type transient_window: gtk.Window ''' menu_item = None for view in self.view_manager: menu_item = gtk.RadioMenuItem(label = _(view.view_name)) menu_item.set_name(view.view_name) menu_item.connect('toggled', self._onItemToggled, view, context_plugin) menu_item.set_active(view == context_plugin.get_parent()) self.append(menu_item) menu_item.show() menu_item = gtk.SeparatorMenuItem() self.append(menu_item) menu_item.show() menu_item = gtk.MenuItem(label="<i>" + _('_New view...') + "</i>") menu_item.get_child().set_use_markup(True) menu_item.connect('activate', self._onItemActivated, context_plugin, transient_window) self.append(menu_item) menu_item.show() def _onItemToggled(self, menu_item, view, context_plugin): ''' Callback for radio item toggles. Change the views accordingly. @param menu_item: Menu item that was toggled @type menu_item: gtk.RadioMenuItem @param view: View that was chosen. @type view: L{PluginView} @param context_plugin: Subject plugin of this menu. @type context_plugin: L{Plugin} ''' self.view_manager.changeView(context_plugin, view.view_name) def _onItemActivated(self, menu_item, context_plugin, transient_window): ''' Callback for "new view" menu item. Creates a dialog for entering a view name. @param menu_item: Menu item that was activated. @type menu_item: gtk.MenuItem @param context_plugin: Subject plugin of this menu. @type context_plugin: L{Plugin} @param transient_window: Transient parent window. Used for keeping the new view dialog modal. @type transient_window: gtk.Window ''' new_view_dialog = \ self._NewViewDialog(self.view_manager, transient_window) response_id = new_view_dialog.run() plugin_name = new_view_dialog.getEntryText() if response_id == gtk.ResponseType.OK and plugin_name: self.view_manager.changeView(context_plugin, plugin_name) new_view_dialog.destroy() class _NewViewDialog(gtk.Dialog): ''' Small dialog that allows entry of a new view name. ''' def __init__(self, view_manager, transient_window): ''' @param view_manager: View manager to use as data model and controller. @type view_manager: L{ViewManager} @param transient_window: Transient parent window. Used for keeping the new view dialog modal. @type transient_window: gtk.Window ''' self.view_manager = view_manager gtk.Dialog.__init__(self, _('New View...'), transient_window) self.add_buttons(gtk.STOCK_OK, gtk.ResponseType.OK, gtk.STOCK_CLOSE, gtk.ResponseType.CLOSE) self.set_default_response(gtk.ResponseType.OK) completion = gtk.EntryCompletion() complete_model = gtk.ListStore(str) for view in self.view_manager: complete_model.append([view.view_name]) completion.set_model(complete_model) completion.set_text_column(0) self.entry = gtk.Entry() self.entry.set_completion(completion) self.entry.connect('activate', self._onEntryActivate) self.box = self.get_children()[0] self.box.add(self.entry) self.entry.show() def getEntryText(self): ''' Get the contents of the entry widget. @return: Text in entry box. @rtype: string ''' return self.entry.get_text() def _onEntryActivate(self, entry): ''' Callback for activation of the entry box. Return an OK response. @param entry: Entry box that was activated. @type entry: gtk.Entry ''' self.response(gtk.ResponseType.OK)
class MultiViewModel(list, BaseViewModel): ''' Manages all plugin views. Implements a gtk.ListStore of all views. Persists plugin view placements across sessions. @cvar COL_NAME: View name column ID. @type COL_NAME: integer @cvar COL_INSTANCE: View instance column ID. @type COL_INSTANCE: integer @ivar perm_views: List of permanent views. @type perm_views: list of L{PluginView} @ivar main_view: Main view. @type main_view: L{PluginView} @ivar _ignore_insertion: A list of tuples with view and plugin names that should be ignored and not go in to gsettings. This is to avoid recursive gsettings modification. @type _ignore_insertion: list of tuples @ivar _placement_cache: A cache of recently disabled plugins with their placement. allowsthem to be enabled in to the same position. @type _placement_cache: dictionary @ivar _closed: Indicator to stop writing plugin remove events to gsettings. @type _closed: boolean ''' COL_NAME = 0 COL_INSTANCE = 1 def __init__(self, *perm_views): ''' Initialize view manager. @param perm_views: List of permanent views, at least one is required. @type perm_views: list of {PluginView} ''' BaseViewModel.__init__(self, *perm_views) for view in self.perm_views: self.append(view) self._connectSignals(view) self._ignore_insertion = [] self._placement_cache = {} self._closed = False def close(self): ''' Stops gsettings maniputaion. ''' self._closed = True def getViewNameForPlugin(self, plugin_name): ''' Get the view name for a given plugin name as defined in gsettings. Or return name of main view. @param plugin_name: Plugin's name to lookup view for. @type plugin_name: string @return: View name for plugin. @rtype: string ''' plugin_layouts = self._getPluginLayouts() for view_name in plugin_layouts: if plugin_name in plugin_layouts[view_name]: return view_name return self.main_view.view_name def _getViewByName(self, view_name): ''' Return the view instance of the given name. @param view_name: Name of view to retrieve. @type view_name: string @return: View instance or None @rtype: L{PluginView} ''' for view in self: if view.view_name == view_name: return view return None def _onPluginDragEnd(self, view, plugin): ''' Callback for the end of a drag operation of a plugin. Only is called when the drag ends on the root window. @param view: Current plugin's view. @type view: L{PluginView} @param plugin: Plugin that was dragged. @type plugin: L{Plugin} ''' new_view = self._newView() view.remove(plugin) new_view.append_page(plugin) new_view.set_tab_detachable(plugin, True) new_view.set_tab_reorderable(plugin, True) def _newView(self, view_name=None): ''' Creates a new view. @param view_name: An optional view name. Gives a more mundane one if no name is provided. @type view_name: string @return: New view @rtype: L{PluginView} ''' if not view_name: view_name = _('Plugin View') view_num = 2 while view_name in self._getViewNames(): view_name = _('Plugin View (%d)') % view_num view_num += 1 w = PluginViewWindow(view_name) view = w.plugin_view self._connectSignals(view) self.append(view) return view def _getViewOrNewView(self, view_name): ''' Get an existing or new view with the current name. @param view_name: View's name @type view_name: string @return: New or existing view. @rtype: L{PluginView} ''' view = self._getViewByName(view_name) or self._newView(view_name) return view def _onViewDelete(self, view_window, event): ''' Callback for a view window's delete event. Puts all orphaned plugins in main view. @param view_window: View window that emitted delete event. @type view_window: L{PluginViewWindow} @param event: Event object. @type event: gtk.gdk.Event ''' view = view_window.plugin_view for child in view.getPlugins(): view.remove(child) self.main_view.append_page(child) self._removeView(view) def _removeView(self, view): ''' Removes view from model. @param view: View to remove. @type view: L{PluginView} ''' if view in self.perm_views: return if view in self: self.remove(view) def _onTabPopupMenu(self, view, event, plugin): ''' Callback for popup menu signal from plugin view. Displays a context menu with available views. @param view: Plugin view that emitted this signal. @type view: L{PluginView} @param event: Relevant event object that will be used in popup menu. @type event: gtk.gdk.Event @param plugin: Plugin of tab that was clicked or pressed. @type plugin: L{Plugin} ''' menu = self.Menu(plugin, view.get_toplevel()) if hasattr(event, 'button'): menu.popup(None, None, None, None, event.button, event.time) else: tab = view.get_tab_label(plugin) x, y, w, h = view.getTabAlloc(tab) rect = gdk.Rectangle(x, y, w, h) menu.popup( None, None, lambda m, r: (r.x + r.width / 2, r.y + r.height / 2, True), rect, 0, event.time) def _connectSignals(self, view): ''' Convenience function for connecting all needed signal callbacks. @param view: Plugin view to connect. @type view: :{PluginView} ''' if isinstance(view.get_parent(), PluginViewWindow): view.get_parent().connect('delete-event', Proxy(self._onViewDelete)) view.connect('plugin-drag-end', Proxy(self._onPluginDragEnd)) view.connect('tab-popup-menu', Proxy(self._onTabPopupMenu)) view.connect('page-added', Proxy(self._onViewLayoutChanged), 'added') view.connect('page-removed', Proxy(self._onViewLayoutChanged), 'removed') view.connect('page-reordered', Proxy(self._onViewLayoutChanged), 'reordered') def _onViewLayoutChanged(self, view, plugin, page_num, action): ''' Callback for all layout changes. Updates gsettings. @param view: View that emitted the signal. @type view: L{PluginView} @param plugin: Plugin that moved. @type plugin: L{Plugin} @param page_num: Plugin's position in view. @type page_num: integer @param action: Action that triggered this event. @type action: string ''' if self._closed or not isinstance(plugin, Plugin): return if (view.view_name, plugin.plugin_name) in self._ignore_insertion: self._ignore_insertion.remove((view.view_name, plugin.plugin_name)) return if self._placement_cache.has_key(plugin.plugin_name): self._placement_cache.pop(plugin.plugin_name) plugin_layouts = self._getPluginLayouts() try: plugin_layout = plugin_layouts[view.view_name] except KeyError: plugin_layouts[view.view_name] = [] plugin_layout = plugin_layouts[view.view_name] if plugin.plugin_name in plugin_layout: plugin_layout.remove(plugin.plugin_name) if action in ('reordered', 'added'): plugin_layout.insert(page_num, plugin.plugin_name) elif action == 'removed': self._placement_cache[plugin.plugin_name] = (view.view_name, page_num) if len(plugin_layout) == 0: self._removeView(view) self._setPluginLayouts(plugin_layouts) def _setPluginLayouts(self, plugin_layouts): self.plugviews = GSettings(schema=PLUGVIEWS_GSCHEMA) self.plugviews.set_strv('top-panel-layout', plugin_layouts.pop('Top panel')) self.plugviews.set_strv('bottom-panel-layout', plugin_layouts.pop('Bottom panel')) for plugview in plugin_layouts.keys(): gspath = NEWPLUGVIEWS_PATH + plugview.lower().replace(' ', '-') + '/' newview = GSettings(schema=NEWPLUGVIEWS_GSCHEMA, path=gspath) newview.set_strv('layout', plugin_layouts[plugview]) l = self.plugviews.get_strv('available-newviews') l.append(plugview) self.plugviews.set_strv('available-newviews', l) def _getPluginLayouts(self): plugin_layouts = {} self.plugviews = GSettings(schema=PLUGVIEWS_GSCHEMA) plugin_layouts['Top panel'] = self.plugviews.get_strv( 'top-panel-layout') plugin_layouts['Bottom panel'] = self.plugviews.get_strv( 'bottom-panel-layout') for plugview in self.plugviews.get_strv('available-newviews'): gspath = NEWPLUGVIEWS_PATH + plugview.lower().replace(' ', '-') + '/' newview = GSettings(schema=NEWPLUGVIEWS_GSCHEMA, path=gspath) layout = newview.get_strv('layout') if layout: plugin_layouts[plugview] = layout else: l = self.plugviews.get_strv('available-newviews') l.remove(plugview) self.plugviews.set_strv('available-newviews', l) return plugin_layouts def addPlugin(self, plugin): ''' Add a plugin to the view. Check if it's placement is cached in this instance or read it's position from gsettings. By default a plugin is appended to the main view. @param plugin: Plugin to add. @type plugin: L{Plugin} ''' if self._placement_cache.has_key(plugin.plugin_name): view_name, index = self._placement_cache.pop(plugin.plugin_name) view = self._getViewOrNewView(view_name) else: view_name = self.getViewNameForPlugin(plugin.plugin_name) view = self._getViewOrNewView(view_name) plugin_layouts = self._getPluginLayouts() try: plugin_layout = plugin_layouts[view.view_name] except KeyError: plugin_layout = [] plugin_layouts[view.view_name] = plugin_layout index = -1 if plugin.plugin_name in plugin_layout: # The plugins that have a higher index. successive = plugin_layout[plugin_layout. index(plugin.plugin_name) + 1:] for child_index, preceding_plugin in enumerate( view.getPlugins()): if preceding_plugin.plugin_name in successive: # Place new plugin just before the first successive plugin. index = child_index break self._ignore_insertion.append((view.view_name, plugin.plugin_name)) self._setPluginLayouts(plugin_layouts) view.insert_page(plugin, position=index) view.set_tab_detachable(plugin, True) view.set_tab_reorderable(plugin, True) plugin.show_all() def initialView(self): ''' Set the current tab of all views to be the first one. Used when Accercier first starts. ''' for view in self: view.set_current_page(0) def getViewedPlugins(self): ''' Get all plugins from all views. ''' rv = [] for view in self: rv.extend(view.getPlugins()) return rv def _getViewNames(self): ''' Get a list of all managed view names. @return: A list of view names. @rtype: list of string ''' return [view.view_name for view in self] def changeView(self, plugin, new_view_name): ''' Put a plugin instance in a different view. If given view name does not exist, create it. @param plugin: Plugin to move. @type plugin: L{Plugin} @param new_view_name: New view name. @type new_view_name: string ''' if not plugin or not isinstance(plugin, gtk.Widget): return old_view = plugin.get_parent() new_view = self._getViewOrNewView(new_view_name) if old_view is not new_view: old_view.remove(plugin) new_view.append_page(plugin) new_view.set_tab_detachable(plugin, True) new_view.set_tab_reorderable(plugin, True) def Menu(self, context_plugin, transient_window): ''' Helps emulate a non-static inner class. These don't exist in python, I think. @param context_plugin: Subject plugin of this menu. @type context_plugin: L{Plugin} @param transient_window: Transient parent window. Used for keeping the new view dialog modal. @type transient_window: gtk.Window @return: An inner menu class. @rtype: L{ViewManager._Menu} ''' return self._Menu(self, context_plugin, transient_window) class _Menu(gtk.Menu): ''' Implements a popup menu for a plugin that will allow putting the plugin in a different view. @cvar RADIO_GROUP: Radio menu item's group id. @type RADIO_GROUP: integer @ivar view_manager: View manager to use as data model and controller. @type view_manager: L{ViewManager} ''' RADIO_GROUP = 13 def __init__(self, view_manager, context_plugin, transient_window): ''' Initialize menu. @param view_manager: View manager to use as data model and controller. @type view_manager: L{ViewManager} @param context_plugin: Subject plugin of this menu. @type context_plugin: L{Plugin} @param transient_window: Transient parent window. Used for keeping the new view dialog modal. @type transient_window: gtk.Window ''' gtk.Menu.__init__(self) self.view_manager = view_manager if isinstance(context_plugin, gtk.Widget): self._buildMenu(context_plugin, transient_window) def _buildMenu(self, context_plugin, transient_window): ''' Build the menu according to the view managers model. @param context_plugin: Subject plugin of this menu. @type context_plugin: L{Plugin} @param transient_window: Transient parent window. Used for keeping the new view dialog modal. @type transient_window: gtk.Window ''' menu_item = None for view in self.view_manager: menu_item = gtk.RadioMenuItem(label=view.view_name) menu_item.set_name(view.view_name) menu_item.connect('toggled', self._onItemToggled, view, context_plugin) menu_item.set_active(view == context_plugin.get_parent()) self.append(menu_item) menu_item.show() menu_item = gtk.SeparatorMenuItem() self.append(menu_item) menu_item.show() menu_item = gtk.MenuItem(label=_('<i>_New view...</i>')) menu_item.get_child().set_use_markup(True) menu_item.connect('activate', self._onItemActivated, context_plugin, transient_window) self.append(menu_item) menu_item.show() def _onItemToggled(self, menu_item, view, context_plugin): ''' Callback for radio item toggles. Change the views accordingly. @param menu_item: Menu item that was toggled @type menu_item: gtk.RadioMenuItem @param view: View that was chosen. @type view: L{PluginView} @param context_plugin: Subject plugin of this menu. @type context_plugin: L{Plugin} ''' self.view_manager.changeView(context_plugin, view.view_name) def _onItemActivated(self, menu_item, context_plugin, transient_window): ''' Callback for "new view" menu item. Creates a dialog for entering a view name. @param menu_item: Menu item that was activated. @type menu_item: gtk.MenuItem @param context_plugin: Subject plugin of this menu. @type context_plugin: L{Plugin} @param transient_window: Transient parent window. Used for keeping the new view dialog modal. @type transient_window: gtk.Window ''' new_view_dialog = \ self._NewViewDialog(self.view_manager, transient_window) response_id = new_view_dialog.run() plugin_name = new_view_dialog.getEntryText() if response_id == gtk.ResponseType.OK and plugin_name: self.view_manager.changeView(context_plugin, plugin_name) new_view_dialog.destroy() class _NewViewDialog(gtk.Dialog): ''' Small dialog that allows entry of a new view name. ''' def __init__(self, view_manager, transient_window): ''' @param view_manager: View manager to use as data model and controller. @type view_manager: L{ViewManager} @param transient_window: Transient parent window. Used for keeping the new view dialog modal. @type transient_window: gtk.Window ''' self.view_manager = view_manager gtk.Dialog.__init__(self, _('New View...'), transient_window) self.add_buttons(gtk.STOCK_OK, gtk.ResponseType.OK, gtk.STOCK_CLOSE, gtk.ResponseType.CLOSE) self.set_default_response(gtk.ResponseType.OK) completion = gtk.EntryCompletion() complete_model = gtk.ListStore(str) for view in self.view_manager: complete_model.append([view.view_name]) completion.set_model(complete_model) completion.set_text_column(0) self.entry = gtk.Entry() self.entry.set_completion(completion) self.entry.connect('activate', self._onEntryActivate) self.box = self.get_children()[0] self.box.add(self.entry) self.entry.show() def getEntryText(self): ''' Get the contents of the entry widget. @return: Text in entry box. @rtype: string ''' return self.entry.get_text() def _onEntryActivate(self, entry): ''' Callback for activation of the entry box. Return an OK response. @param entry: Entry box that was activated. @type entry: gtk.Entry ''' self.response(gtk.ResponseType.OK)
class Backend: def __init__(self, prefsDir): self.baseSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/') self.voiceDefaults = {} def saveDefaultSettings(self, general, pronunciations, keybindings): # GSettings stores the defaults, no need to do anything here, except # for voice defaults, as the defaults can vary between speech # backends. if general.__contains__('voices'): self.voiceDefaults = general['voices'] def getAppSettings(self, appName): prefs = {} profiles = {} availableProfiles = self.baseSettings.get_strv('profiles') for profile in availableProfiles: profileSettings = {} generalSettings = {} voiceSettings = {} pronunciationSettings = {} keybindingSettings = {} profileBaseSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) profileApps = profileBaseSettings.get_strv('apps') if appName in profileApps: generalSettings = self._getGeneralSettings(profile, appName) voiceSettings = self._getVoiceSettings(profile, appName) if voiceSettings != {}: generalSettings['voices'] = voiceSettings pronunciationSettings = self._getPronunciations( profile, appName) keybindingSettings = self._getKeybindings(profile, appName) profileSettings['general'] = generalSettings profileSettings['keybindings'] = keybindingSettings profileSettings['pronunciations'] = pronunciationSettings profiles[profile] = profileSettings if profiles != {}: prefs['profiles'] = profiles return prefs def saveAppSettings(self, appName, profile, general, pronunciations, keybindings): profiles = self.baseSettings.get_strv('profiles') if profile in profiles: profileBaseSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) apps = profileBaseSettings.get_strv('apps') if appName not in apps: apps.append(appName) profileBaseSettings.set_strv('apps', apps) self._saveGeneralSettings(general, profile, appName) if general.__contains__('voices'): self._saveVoiceSettings(general['voices'], profile, appName) self._savePronunciations(pronunciations, profile, appName) self._saveKeybindings(keybindings, profile, appName) def saveProfileSettings(self, profile, general, pronunciations, keybindings): if profile is None: profile = 'default' profiles = self.baseSettings.get_strv('profiles') if profile not in profiles: profiles.append(profile) self.baseSettings.set_strv('profiles', profiles) self._saveGeneralSettings(general, profile) if general.__contains__('voices'): self._saveVoiceSettings(general['voices'], profile) self._savePronunciations(pronunciations, profile) self._saveKeybindings(keybindings, profile) def getGeneral(self, profile='default'): profiles = self.baseSettings.get_strv('profiles') startingProfile = self.baseSettings.get_strv('starting-profile') generalSettings = {} voiceSettings = {} generalSettings['startingProfile'] = startingProfile if profile in profiles: profileGeneralSettings = Settings( schema_id='org.gnome.orca.general', path='/org/gnome/orca/profile/%s/' % profile) generalSettings = self._getGeneralSettings(profile) voiceSettings = self._getVoiceSettings(profile) generalSettings['voices'] = voiceSettings generalSettings['activeProfile'] = profileGeneralSettings.get_strv( 'profile') self.baseSettings.set_strv('active-profile', generalSettings['activeProfile']) return generalSettings def getPronunciations(self, profile='default'): profiles = self.baseSettings.get_strv('profiles') pronunciationSettings = {} if profile in profiles: pronunciationSettings = self._getPronunciations(profile) return pronunciationSettings def getKeybindings(self, profile='default'): profiles = self.baseSettings.get_strv('profiles') keybindingSettings = {} if profile in profiles: keybindingSettings = self._getKeybindings(profile) return keybindingSettings def isFirstStart(self): """ Check if we're in first start. """ return self.baseSettings.get_boolean('first-start') def _setProfileKey(self, key, value): # This method is currently used for setting the startingProfile setting only. if key == 'startingProfile': self.baseSettings.set_strv('starting-profile', value) def setFirstStart(self, value=False): """Set firstStart. This user-configurable settting is primarily intended to serve as an indication as to whether or not initial configuration is needed.""" self.baseSettings.set_boolean('first-start', value) def availableProfiles(self): """ List available profiles. """ profileList = self.baseSettings.get_strv('profiles') profiles = [] for profile in profileList: profileSettings = Settings(schema_id='org.gnome.orca.general', path='/org/gnome/orca/profile/%s/' % profile) profiles.append(profileSettings.get_strv('profile')) return profiles def _getGSetting(self, gSetting, gSettingName, gSettingType): """Uses the GSettings get method suitable for the given data type.""" if gSettingType == 'bool': return gSetting.get_boolean(gSettingName) elif gSettingType == 'int': return gSetting.get_int(gSettingName) elif gSettingType == 'string': return gSetting.get_string(gSettingName) elif gSettingType == 'strv': settingStrv = gSetting.get_strv(gSettingName) if settingStrv == []: return None return settingStrv elif gSettingType == 'double': return gSetting.get_double(gSettingName) def _setGSetting(self, gSetting, gSettingName, gSettingType, gSettingVal): """Uses the GSettings set method suitable for the given data type.""" if gSettingVal is None: return debug.println( debug.LEVEL_FINEST, 'INFO: Gsettings backend: Setting %s of type %s with value %s' % (gSettingName, gSettingType, gSettingVal)) if gSettingType == 'bool': gSetting.set_boolean(gSettingName, gSettingVal) elif gSettingType == 'int': gSetting.set_int(gSettingName, gSettingVal) elif gSettingType == 'string': gSetting.set_string(gSettingName, gSettingVal) elif gSettingType == 'strv': gSetting.set_strv(gSettingName, gSettingVal) elif gSettingType == 'double': gSetting.set_double(gSettingName, gSettingVal) def _getGeneralSettings(self, profile, app=None): generalSettings = {} if app is not None and app != '': generalGSettings = Settings( schema_id='org.gnome.orca.general', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecificGSettings = Settings( schema_id='org.gnome.orca.general.app', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) speechGeneralGSettings = Settings( schema_id='org.gnome.orca.general.speech', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) brailleGeneralGSettings = Settings( schema_id='org.gnome.orca.general.braille', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) soundGeneralGSettings = Settings( schema_id='org.gnome.orca.general.sound', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecific = True else: generalGSettings = Settings(schema_id='org.gnome.orca.general', path='/org/gnome/orca/profile/%s/' % profile) speechGeneralGSettings = Settings( schema_id='org.gnome.orca.general.speech', path='/org/gnome/orca/profile/%s/' % profile) brailleGeneralGSettings = Settings( schema_id='org.gnome.orca.general.braille', path='/org/gnome/orca/profile/%s/' % profile) soundGeneralGSettings = Settings( schema_id='org.gnome.orca.general.sound', path='/org/gnome/orca/profile/%s/' % profile) appSpecific = False for setting in orcaToGSettingsMapGeneral.keys(): gSetting = orcaToGSettingsMapGeneral.get(setting) gSettingName = gSetting[0] gSettingType = gSetting[1] # GSettings will always return a value, even if the user has not # Set one, but if a setting is not set for an app, we don't want # to set anything, so the global setting is used, which may be # different from the default. if appSpecific == True: if generalGSettings.get_user_value(gSettingName) is not None: gSettingsVal = self._getGSetting(generalGSettings, gSettingName, gSettingType) debug.println( debug.LEVEL_FINEST, 'INFO: GSettings backend: Getting %s of type %s = %s' % (gSettingName, gSettingType, gSettingsVal)) generalSettings[setting] = gSettingsVal else: gSettingsVal = self._getGSetting(generalGSettings, gSettingName, gSettingType) debug.println( debug.LEVEL_FINEST, 'INFO: GSettings backend: Getting %s of type %s = %s' % (gSettingName, gSettingType, gSettingsVal)) generalSettings[setting] = gSettingsVal for setting in orcaToGSettingsMapGeneralSpeech.keys(): gSetting = orcaToGSettingsMapGeneralSpeech.get(setting) gSettingName = gSetting[0] gSettingType = gSetting[1] # GSettings will always return a value, even if the user has not # Set one, but if a setting is not set for an app, we don't want # to set anything, so the global setting is used, which may be # different from the default. if appSpecific == True: if speechGeneralGSettings.get_user_value( gSettingName) is not None: gSettingsVal = self._getGSetting(speechGeneralGSettings, gSettingName, gSettingType) debug.println( debug.LEVEL_FINEST, 'INFO: GSettings backend: Getting %s of type %s = %s' % (gSettingName, gSettingType, gSettingsVal)) generalSettings[setting] = gSettingsVal else: gSettingsVal = self._getGSetting(speechGeneralGSettings, gSettingName, gSettingType) debug.println( debug.LEVEL_FINEST, 'INFO: GSettings backend: Getting %s of type %s = %s' % (gSettingName, gSettingType, gSettingsVal)) generalSettings[setting] = gSettingsVal for setting in orcaToGSettingsMapGeneralSound.keys(): gSetting = orcaToGSettingsMapGeneralSound.get(setting) gSettingName = gSetting[0] gSettingType = gSetting[1] # GSettings will always return a value, even if the user has not # Set one, but if a setting is not set for an app, we don't want # to set anything, so the global setting is used, which may be # different from the default. if appSpecific == True: if soundGeneralGSettings.get_user_value( gSettingName) is not None: gSettingsVal = self._getGSetting(soundGeneralGSettings, gSettingName, gSettingType) debug.println( debug.LEVEL_FINEST, 'INFO: GSettings backend: Getting %s of type %s = %s' % (gSettingName, gSettingType, gSettingsVal)) generalSettings[setting] = gSettingsVal else: gSettingsVal = self._getGSetting(soundGeneralGSettings, gSettingName, gSettingType) debug.println( debug.LEVEL_FINEST, 'INFO: GSettings backend: Getting %s of type %s = %s' % (gSettingName, gSettingType, gSettingsVal)) generalSettings[setting] = gSettingsVal for setting in orcaToGSettingsMapGeneralBraille.keys(): gSetting = orcaToGSettingsMapGeneralBraille.get(setting) gSettingName = gSetting[0] gSettingType = gSetting[1] # GSettings will always return a value, even if the user has not # Set one, but if a setting is not set for an app, we don't want # to set anything, so the global setting is used, which may be # different from the default. if appSpecific == True: if brailleGeneralGSettings.get_user_value( gSettingName) is not None: gSettingsVal = self._getGSetting(brailleGeneralGSettings, gSettingName, gSettingType) debug.println( debug.LEVEL_FINEST, 'INFO: GSettings backend: Getting %s of type %s = %s' % (gSettingName, gSettingType, gSettingsVal)) generalSettings[setting] = gSettingsVal else: gSettingsVal = self._getGSetting(brailleGeneralGSettings, gSettingName, gSettingType) debug.println( debug.LEVEL_FINEST, 'INFO: GSettings backend: Getting %s of type %s = %s' % (gSettingName, gSettingType, gSettingsVal)) generalSettings[setting] = gSettingsVal if appSpecific == True: for setting in orcaToGSettingsMapGeneralApp.keys(): gSetting = orcaToGSettingsMapGeneralApp.get(setting) gSettingName = gSetting[0] gSettingType = gSetting[1] if appSpecificGSettings.get_user_value( gSettingName) is not None: gSettingsVal = self._getGSetting(appSpecificGSettings, gSettingName, gSettingType) debug.println( debug.LEVEL_FINEST, 'INFO: GSettings backend: Getting %s of type %s = %s' % (gSettingName, gSettingType, gSettingsVal)) generalSettings[setting] = gSettingsVal return generalSettings def _getVoiceSettings(self, profile, app=None): voiceSettings = {} if app is not None and app != '': appSpecific = True else: appSpecific = False for voice in ['default', 'uppercase', 'hyperlink', 'system']: if appSpecific == True: voiceGSettings = Settings( schema_id='org.gnome.orca.voice', path='/org/gnome/orca/profile/%s/app/%s/voice/%s/' % (profile, app, voice)) voiceGSettingsFamily = Settings( schema_id='org.gnome.orca.voice.family', path='/org/gnome/orca/profile/%s/app/%s/voice/%s/' % (profile, app, voice)) else: voiceGSettings = Settings( schema_id='org.gnome.orca.voice', path='/org/gnome/orca/profile/%s/voice/%s/' % (profile, voice)) voiceGSettingsFamily = Settings( schema_id='org.gnome.orca.voice.family', path='/org/gnome/orca/profile/%s/voice/%s/' % (profile, voice)) # Used to quickly determine whether a voice's settings have been # set and are different from the defaults voiceEstablished = voiceGSettings.get_boolean('established') voiceSetting = {} voiceSettingFamily = {} if appSpecific == False and self.voiceDefaults.__contains__(voice): voiceSetting = self.voiceDefaults[voice].copy() if voiceEstablished == True: if appSpecific == False and voiceSetting.__contains__( 'established'): voiceSetting.pop('established') for setting in ['average-pitch', 'gain', 'rate']: if voiceGSettings.get_user_value(setting) is not None: gSettingsVal = voiceGSettings.get_double(setting) debug.println( debug.LEVEL_FINEST, 'INFO: GSettings backend: Getting voice setting for voice %s with name %s = %s' % (voice, setting, gSettingsVal)) voiceSetting[setting] = gSettingsVal if voiceGSettingsFamily.get_boolean('family-set') == True: for setting in ['name', 'locale', 'dialect']: gSettingsVal = voiceGSettingsFamily.get_string(setting) debug.println( debug.LEVEL_FINEST, 'INFO: GSettings backend: Getting voice family setting for voice %s with name %s = %s' % (voice, setting, gSettingsVal)) voiceSettingFamily[setting] = gSettingsVal voiceSetting['family'] = voiceSettingFamily # The JSON backend uses acss the same way, not sure why, so will # just duplicate here to be compatible. if voiceSetting != {}: if appSpecific == True: voiceSettings[voice] = voiceSetting else: voiceSettings[voice] = acss.ACSS(voiceSetting) return voiceSettings def _getPronunciations(self, profile, app=None): pronunciationSettings = {} if app is not None and app != '': baseGSettings = Settings( schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecific = True else: baseGSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) appSpecific = False pronunciations = baseGSettings.get_strv('pronunciations') for pronunciation in pronunciations: if appSpecific == True: pronunciationSetting = Settings( schema_id='org.gnome.orca.pronunciation', path='/org/gnome/orca/profile/%s/app/%s/pronunciation/%s/' % (profile, app, pronunciation)) else: pronunciationSetting = Settings( schema_id='org.gnome.orca.pronunciation', path='/org/gnome/orca/profile/%s/pronunciation/%s/' % (profile, pronunciation)) actualSetting = pronunciationSetting.get_string('actual') replacementSetting = pronunciationSetting.get_string('replacement') pronunciationSettings[pronunciation] = [ actualSetting, replacementSetting ] return pronunciationSettings def _getKeybindings(self, profile, app=None): keybindingSettings = {} if app is not None and app != '': baseGSettings = Settings( schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecific = True else: baseGSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) appSpecific = False keybindings = baseGSettings.get_strv('keybindings') for keybinding in keybindings: if appSpecific == True: keybindingSetting = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/app/%s/keybinding/%s/' % (profile, app, keybinding)) else: keybindingSetting = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/keybinding/%s/' % (profile, keybinding)) keySetting = keybindingSetting.get_string('key') modMaskSetting = keybindingSetting.get_string('mod-mask') modUsedSetting = keybindingSetting.get_string('mod-used') clickCountSetting = keybindingSetting.get_string('click-count') keybindingSettings[keybinding] = [[ keySetting, modMaskSetting, modUsedSetting, clickCountSetting ]] return keybindingSettings def _saveGeneralSettings(self, generalSettings, profile, app=None): if app is not None and app != '': generalGSettings = Settings( schema_id='org.gnome.orca.general', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) speechGeneralGSettings = Settings( schema_id='org.gnome.orca.general.speech', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) brailleGeneralGSettings = Settings( schema_id='org.gnome.orca.general.braille', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) soundGeneralGSettings = Settings( schema_id='org.gnome.orca.general.sound', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecificGSettings = Settings( schema_id='org.gnome.orca.general.app', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecific = True else: generalGSettings = Settings(schema_id='org.gnome.orca.general', path='/org/gnome/orca/profile/%s/' % profile) speechGeneralGSettings = Settings( schema_id='org.gnome.orca.general.speech', path='/org/gnome/orca/profile/%s/' % profile) brailleGeneralGSettings = Settings( schema_id='org.gnome.orca.general.braille', path='/org/gnome/orca/profile/%s/' % profile) soundGeneralGSettings = Settings( schema_id='org.gnome.orca.general.sound', path='/org/gnome/orca/profile/%s/' % profile) appSpecific = False for setting in orcaToGSettingsMapGeneral.keys(): gSetting = orcaToGSettingsMapGeneral.get(setting) gSettingName = gSetting[0] gSettingType = gSetting[1] self._setGSetting(generalGSettings, gSettingName, gSettingType, generalSettings.get(setting)) for setting in orcaToGSettingsMapGeneralSpeech.keys(): gSetting = orcaToGSettingsMapGeneralSpeech.get(setting) gSettingName = gSetting[0] gSettingType = gSetting[1] self._setGSetting(speechGeneralGSettings, gSettingName, gSettingType, generalSettings.get(setting)) for setting in orcaToGSettingsMapGeneralSound.keys(): gSetting = orcaToGSettingsMapGeneralSound.get(setting) gSettingName = gSetting[0] gSettingType = gSetting[1] self._setGSetting(soundGeneralGSettings, gSettingName, gSettingType, generalSettings.get(setting)) for setting in orcaToGSettingsMapGeneralBraille.keys(): gSetting = orcaToGSettingsMapGeneralBraille.get(setting) gSettingName = gSetting[0] gSettingType = gSetting[1] self._setGSetting(brailleGeneralGSettings, gSettingName, gSettingType, generalSettings.get(setting)) if appSpecific == True: for setting in orcaToGSettingsMapGeneralApp.keys(): gSetting = orcaToGSettingsMapGeneralApp.get(setting) gSettingName = gSetting[0] gSettingType = gSetting[1] self._setGSetting(appSpecificGSettings, gSettingName, gSettingType, generalSettings.get(setting)) def _saveVoiceSettings(self, voiceSettings, profile, app=None): if app is not None and app != '': appSpecific = True else: appSpecific = False for voice in ['default', 'uppercase', 'hyperlink', 'system']: if appSpecific == True: voiceGSettings = Settings( schema_id='org.gnome.orca.voice', path='/org/gnome/orca/profile/%s/app/%s/voice/%s/' % (profile, app, voice)) voiceFamilyGSettings = Settings( schema_id='org.gnome.orca.voice.family', path='/org/gnome/orca/profile/%s/app/%s/voice/%s/' % (profile, app, voice)) else: voiceGSettings = Settings( schema_id='org.gnome.orca.voice', path='/org/gnome/orca/profile/%s/voice/%s/' % (profile, voice)) voiceFamilyGSettings = Settings( schema_id='org.gnome.orca.voice.family', path='/org/gnome/orca/profile/%s/voice/%s/' % (profile, voice)) if voiceSettings.__contains__(voice): if voiceSettings[voice].get('established') is None: for setting in ['average-pitch', 'gain', 'rate']: if voiceSettings[voice].get(setting) is not None: if appSpecific == True: voiceGSettings.set_double( setting, voiceSettings[voice].get(setting)) else: if voiceSettings[voice].get( setting) is not self.voiceDefaults[ voice].get(setting): voiceGSettings.set_double( setting, voiceSettings[voice].get(setting)) setEstablished = True if appSpecific == True: voiceGSettings.set_boolean('established', True) elif appSpecific == False and setEstablished == True: voiceGSettings.set_boolean('established', True) if voiceSettings[voice].__contains__('family'): for setting in ['name', 'locale', 'dialect']: voiceFamilyGSettings.set_string( setting, voiceSettings[voice]['family'].get(setting)) voiceFamilyGSettings.set_boolean('family-set', True) def _savePronunciations(self, pronunciations, profile, app=None): if app is not None and app != '': baseGSettings = Settings( schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecific = True else: baseGSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) appSpecific = False pronunciationList = baseGSettings.get_strv('pronunciations') for pronunciation in pronunciations.keys(): if appSpecific == True: pronunciationSettings = Settings( schema_id='org.gnome.orca.pronunciation', path='/org/gnome/orca/profile/%s/app/%s/pronunciation/%s/' % (profile, app, pronunciation)) else: pronunciationSettings = Settings( schema_id='org.gnome.orca.pronunciation', path='/org/gnome/orca/profile/%s/pronunciation/%s/' % (profile, pronunciation)) if pronunciation not in pronunciationList: pronunciationList.append(pronunciation) pronunciationVal = pronunciations[pronunciation] pronunciationSettings.set_string('actual', pronunciationVal[0]) pronunciationSettings.set_string('replacement', pronunciationVal[1]) # Now we remove any deleted pronunciations from GSettings. for pronunciation in pronunciationList: if pronunciation not in pronunciations.keys(): if appSpecific == True: pronunciationSettings = Settings( schema_id='org.gnome.orca.pronunciation', path= '/org/gnome/orca/profile/%s/app/%s/pronunciation/%s/' % (profile, app, pronunciation)) else: pronunciationSettings = Settings( schema_id='org.gnome.orca.pronunciation', path='/org/gnome/orca/profile/%s/pronunciation/%s/' % (profile, pronunciation)) pronunciationList.remove(pronunciation) pronunciationSettings.reset('actual') pronunciationSettings.reset('replacement') if pronunciationList == []: baseGSettings.reset('pronunciations') else: baseGSettings.set_strv('pronunciations', pronunciationList) def _saveKeybindings(self, keybindings, profile, app=None): if app is not None and app != '': baseGSettings = Settings( schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/app/%s/' % (profile, app)) appSpecific = True else: baseGSettings = Settings(schema_id='org.gnome.orca', path='/org/gnome/orca/profile/%s/' % profile) appSpecific = False keybindingList = baseGSettings.get_strv('keybindings') for keybinding in keybindings.keys(): if appSpecific == True: keybindingSettings = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/app/%s/keybinding/%s/' % (profile, app, keybinding)) else: keybindingSettings = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/keybinding/%s/' % (profile, keybinding)) if keybinding not in keybindingList: keybindingList.append(keybinding) keybindingVal = keybindings[keybinding][0] keybindingSettings.set_string('key', keybindingVal[0]) keybindingSettings.set_string('mod-mask', keybindingVal[1]) keybindingSettings.set_string('mod-used', keybindingVal[2]) keybindingSettings.set_string('click-count', keybindingVal[3]) # Now we remove any deleted keybindings from Gsettings. for keybinding in keybindingList: if keybinding not in keybindings.keys(): if appSpecific == True: keybindingSettings = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/app/%s/keybinding/%s/' % (profile, app, keybinding)) else: keybindingSettings = Settings( schema_id='org.gnome.orca.keybinding', path='/org/gnome/orca/profile/%s/keybinding/%s/' % (profile, keybinding)) keybindingList.remove(keybinding) keybindingSettings.reset('key') keybindingSettings.reset('mod-mask') keybindingSettings.reset('mod-used') keybindingSettings.reset('click-count') if keybindingList == []: baseGSettings.reset('keybindings') else: baseGSettings.set_strv('keybindings', keybindingList)
class PluginManager(gtk.ListStore, Tools): ''' @cvar COL_INSTANCE: Instance column ID. @type COL_INSTANCE: integer @cvar COL_CLASS: Class column ID. @type COL_CLASS: integer @cvar COL_PATH: Module path column ID. @type COL_PATH: integer @ivar node: Application's selected accessible node. @type node: L{Node} @ivar hotkey_manager: Application's hotkey manager. @type hotkey_manager: L{HotkeyManager} @ivar view_manager: Plugin view manager. @type view_manager: L{ViewManager} @ivar message_manager: Plugin message manager. @type message_manager: L{MessageManager} ''' COL_INSTANCE = 0 COL_CLASS = 1 COL_PATH = 2 def __init__(self, node, hotkey_manager, *main_views): ''' Initialize the plugin manager. @param node: The application's main node. @type node: L{Node} @param hotkey_manager: Application's hot key manager. @type hotkey_manager: L{HotkeyManager} @param main_views: List of permanent plugin views. @type main_views: list of {PluginView} ''' gtk.ListStore.__init__(self, object, # Plugin instance object, # Plugin class str) # Plugin path self.node = node self.hotkey_manager = hotkey_manager self.gsettings = GSettings(schema=GSCHEMA) self.view_manager = ViewManager(*main_views) self.message_manager = MessageManager() self.message_manager.connect('plugin-reload-request', self._onPluginReloadRequest) self.message_manager.connect('module-reload-request', self._onModuleReloadRequest) message_tab = self.message_manager.getMessageTab() self.view_manager.addElement(message_tab) self._row_changed_handler = \ self.connect('row_changed', self._onPluginRowChanged) self._loadPlugins() def close(self): ''' Close view manager and plugins. ''' self.view_manager.close() for row in self: plugin = row[self.COL_INSTANCE] if plugin: plugin._close() def _loadPlugins(self): ''' Load all plugins in global and local plugin paths. ''' # AQUI PETAA for plugin_dir, plugin_fn in self._getPluginFiles(): self._loadPluginFile(plugin_dir, plugin_fn) self.view_manager.initialView() def _getPluginFiles(self): ''' Get list of all modules in plugin paths. @return: List of plugin files with their paths. @rtype: tuple ''' plugin_file_list = [] plugin_dir_local = os.path.join(GLib.get_user_data_dir(), 'accerciser', 'plugins') plugin_dir_global = os.path.join(sys.prefix, 'share', 'accerciser', 'plugins') for plugin_dir in (plugin_dir_local, plugin_dir_global): if not os.path.isdir(plugin_dir): continue for fn in os.listdir(plugin_dir): if fn.endswith('.py') and not fn.startswith('.'): plugin_file_list.append((plugin_dir, fn[:-3])) return plugin_file_list def _getPluginLocals(self, plugin_dir, plugin_fn): ''' Get namespace of given module @param plugin_dir: Path. @type plugin_dir: string @param plugin_fn: Module. @type plugin_fn: string @return: Dictionary of modules symbols. @rtype: dictionary ''' sys.path.insert(0, plugin_dir) try: params = imp.find_module(plugin_fn, [plugin_dir]) plugin = imp.load_module(plugin_fn, *params) plugin_locals = plugin.__dict__ except Exception as e: self.message_manager.newModuleError(plugin_fn, plugin_dir, traceback.format_exception_only(e.__class__, e)[0].strip(), traceback.format_exc()) return {} sys.path.pop(0) return plugin_locals def _loadPluginFile(self, plugin_dir, plugin_fn): ''' Find plugin implementations in the given module, and store them. @param plugin_dir: Path. @type plugin_dir: string @param plugin_fn: Module. @type plugin_fn: string ''' plugin_locals = self._getPluginLocals(plugin_dir, plugin_fn) # use keys list to avoid size changes during iteration for symbol in list(plugin_locals.keys()): try: is_plugin = \ issubclass(plugin_locals[symbol], Plugin) and \ getattr(plugin_locals[symbol], 'plugin_name', None) except TypeError: continue if is_plugin: self.handler_block(self._row_changed_handler) iter_id = self.append([None, plugin_locals[symbol], plugin_dir]) self.handler_unblock(self._row_changed_handler) # if a plugin class is found, initialize disabled_list = self.gsettings.get_strv('disabled-plugins') enabled = plugin_locals[symbol].plugin_name not in \ disabled_list if enabled: self._enablePlugin(iter_id) self.row_changed(self.get_path(iter_id), iter_id) def _enablePlugin(self, iter): ''' Instantiate a plugin class pointed to by the given iter. @param iter: Iter of plugin class we should instantiate. @type iter: gtk.TreeIter ''' plugin_class = self[iter][self.COL_CLASS] plugin_instance = None try: plugin_instance = plugin_class(self.node, self.message_manager) plugin_instance.init() for key_combo in plugin_instance.global_hotkeys: self.hotkey_manager.addKeyCombo( plugin_class.plugin_name, plugin_class.plugin_name_localized or plugin_class.plugin_name , *key_combo) except Exception as e: self.message_manager.newPluginError( plugin_instance, plugin_class, traceback.format_exception_only(e.__class__, e)[0].strip(), traceback.format_exc()) try: plugin_instance._close() except: pass return self[iter][self.COL_INSTANCE] = plugin_instance if isinstance(plugin_instance, gtk.Widget): self.view_manager.addElement(plugin_instance) plugin_instance.onAccChanged(plugin_instance.node.acc) disabled_list = self.gsettings.get_strv('disabled-plugins') if plugin_instance.plugin_name in disabled_list: disabled_list.remove(plugin_instance.plugin_name) self.gsettings.set_strv('disabled-plugins', disabled_list) def _disablePlugin(self, iter): ''' Disable plugin pointed to by the given iter. @param iter: Iter of plugin instance to be disabled. @type iter: gtk.TreeIter ''' plugin_instance = self[iter][self.COL_INSTANCE] if not plugin_instance: return for key_combo in plugin_instance.global_hotkeys: self.hotkey_manager.removeKeyCombo( plugin_instance.plugin_name, *key_combo) if isinstance(plugin_instance, gtk.Widget): plugin_instance.destroy() plugin_instance._close() disabled_list = self.gsettings.get_strv('disabled-plugins') if not plugin_instance.plugin_name in disabled_list: disabled_list.append(plugin_instance.plugin_name) self.gsettings.set_strv('disabled-plugins', disabled_list) self[iter][self.COL_INSTANCE] = False def _reloadPlugin(self, iter): ''' Reload plugin pointed to by the given iter. @param iter: Iter of plugin to be reloaded. @type iter: gtk.TreeIter @return: New instance of plugin @rtype: L{Plugin} ''' old_class = self[iter][self.COL_CLASS] plugin_fn = old_class.__module__ plugin_dir = self[iter][self.COL_PATH] plugin_locals = self._getPluginLocals(plugin_dir, plugin_fn) self[iter][self.COL_CLASS] = plugin_locals.get(old_class.__name__) self._enablePlugin(iter) return self[iter][self.COL_INSTANCE] def _getIterWithClass(self, plugin_class): ''' Get iter with given plugin class. @param plugin_class: The plugin class to search for. @type plugin_class: type @return: The first iter with the given class. @rtype: gtk.TreeIter ''' for row in self: if row[self.COL_CLASS] == plugin_class: return row.iter return None def _onPluginReloadRequest(self, message_manager, message, plugin_class): ''' Callback for a plugin reload request from the message manager. @param message_manager: The message manager that emitted the signal. @type message_manager: L{MessageManager} @param message: The message widget. @type message: L{PluginMessage} @param plugin_class: The plugin class that should be reloaded. @type plugin_class: type ''' message.destroy() iter = self._getIterWithClass(plugin_class) if not iter: return self._disablePlugin(iter) plugin = self._reloadPlugin(iter) if plugin: self.view_manager.giveElementFocus(plugin) def _onModuleReloadRequest(self, message_manager, message, module, path): ''' Callback for a module reload request from the message manager. @param message_manager: The message manager that emitted the signal. @type message_manager: L{MessageManager} @param message: The message widget. @type message: L{PluginMessage} @param module: The module to be reloaded. @type module: string @param path: The path of the module. @type path: string ''' message.destroy() self._loadPluginFile(path, module) def togglePlugin(self, path): ''' Toggle the plugin, either enable or disable depending on current state. @param path: Tree path to plugin. @type path: tuple ''' iter = self.get_iter(path) if self[iter][self.COL_INSTANCE]: self._disablePlugin(iter) else: self._reloadPlugin(iter) def _onPluginRowChanged(self, model, path, iter): ''' Callback for model row changes. Persists plugins state (enabled/disabled) in gsettings. @param model: Current model, actually self. @type model: gtk.ListStore @param path: Tree path of changed row. @type path: tuple @param iter: Iter of changed row. @type iter: gtk.TreeIter ''' plugin_class = model[iter][self.COL_CLASS] if plugin_class is None: return plugin_instance = model[iter][self.COL_INSTANCE] disabled_list = self.gsettings.get_strv('disabled-plugins') if plugin_instance is None: if plugin_class.plugin_name not in disabled_list: disabled_list.append(plugin_class.plugin_name) else: if plugin_class.plugin_name in disabled_list: disabled_list.remove(plugin_class.plugin_name) def View(self): ''' Helps emulate a non-static inner class. These don't exist in python, I think. @return: An inner view class. @rtype: L{PluginManager._View} ''' return self._View(self) class _View(gtk.TreeView): ''' Implements a treeview of a {PluginManager} @ivar plugin_manager: Plugin manager to use as data model. @type plugin_manager: L{PluginManager} @ivar view_manager: View manager to use for plugin view data. @type view_manager: L{ViewManager} ''' def __init__(self, plugin_manager): ''' Initialize view. @param plugin_manager: Plugin manager to use as data model. @type plugin_manager: L{PluginManager} ''' gtk.TreeView.__init__(self) self.plugin_manager = plugin_manager self.view_manager = plugin_manager.view_manager self.set_model(plugin_manager) self.connect('button-press-event', self._onButtonPress) self.connect('popup-menu', self._onPopupMenu) crc = gtk.CellRendererToggle() tvc = gtk.TreeViewColumn() tvc.pack_start(crc, True) tvc.set_cell_data_func(crc, self._pluginStateDataFunc) crc.connect('toggled', self._onPluginToggled) self.append_column(tvc) crt = gtk.CellRendererText() tvc = gtk.TreeViewColumn(_('Name')) tvc.pack_start(crt, True) tvc.set_cell_data_func(crt, self._pluginNameDataFunc) self.append_column(tvc) crc = gtk.CellRendererText() # Translators: This is the viewport in which the plugin appears, # it is a noun. # tvc = gtk.TreeViewColumn(C_('viewport', 'View')) tvc.pack_start(crc, False) tvc.set_cell_data_func(crc, self._viewNameDataFunc) crc.set_property('editable', True) crc.connect('edited', self._onViewChanged) self.append_column(tvc) def _onButtonPress(self, widget, event): ''' Callback for plugin view context menus. @param widget: Widget that emitted signal. @type widget: gtk.Widget @param event: Event object. @type event: gtk.gdk.Event ''' if event.button == 3: path = self.get_path_at_pos(int(event.x), int(event.y))[0] self._showPopup(event.button, event.time, path) def _onPopupMenu(self, widget): ''' Callback for popup request event. Usually happens when keyboard context menu os pressed. @param widget: Widget that emitted signal. @type widget: gtk.Widget @return: Return true to stop event trickling. @rtype: boolean ''' path, col = self.get_cursor() rect = getTreePathBoundingBox(self, path, col) self._showPopup(0, gtk.get_current_event_time(), path, lambda m, r: (r.x, r.y, True), rect) return True def _showPopup(self, button, time, path, pos_func=None, data=None): ''' Convinience function for showing the view manager's popup menu. @param button: Mouse button that was clicked. @type button: integer @param time: Time of event. @type time: float @param path: Tree path of context menu. @type path: tuple @param pos_func: Function to use for determining menu placement. @type pos_func: callable @param data: Additional data. @type data: object ''' plugin = \ self.plugin_manager[path][self.plugin_manager.COL_INSTANCE] menu = self.view_manager.Menu(plugin, self.get_toplevel()) menu.popup(None, None, pos_func, data, button, time) def _viewNameDataFunc(self, column, cell, model, iter, foo=None): ''' Function for determining the displayed data in the tree's view column. @param column: Column number. @type column: integer @param cell: Cellrender. @type cell: gtk.CellRendererText @param model: Tree's model @type model: gtk.ListStore @param iter: Tree iter of current row, @type iter: gtk.TreeIter ''' plugin_class = model[iter][self.plugin_manager.COL_CLASS] if issubclass(plugin_class, gtk.Widget): view_name = \ self.view_manager.getViewNameForPlugin(plugin_class.plugin_name) cell.set_property('sensitive', True) else: view_name = N_('No view') cell.set_property('sensitive', False) cell.set_property('text', _(view_name)) def _pluginNameDataFunc(self, column, cell, model, iter, foo=None): ''' Function for determining the displayed data in the tree's plugin column. @param column: Column number. @type column: integer @param cell: Cellrender. @type cell: gtk.CellRendererText @param model: Tree's model @type model: gtk.ListStore @param iter: Tree iter of current row, @type iter: gtk.TreeIter ''' plugin_class = model[iter][self.plugin_manager.COL_CLASS] cell.set_property('text', plugin_class.plugin_name_localized or \ plugin_class.plugin_name) def _pluginStateDataFunc(self, column, cell, model, iter, foo=None): ''' Function for determining the displayed state of the plugin's checkbox. @param column: Column number. @type column: integer @param cell: Cellrender. @type cell: gtk.CellRendererText @param model: Tree's model @type model: gtk.ListStore @param iter: Tree iter of current row, @type iter: gtk.TreeIter ''' cell.set_property('active', bool(model[iter][self.plugin_manager.COL_INSTANCE])) def _onPluginToggled(self, renderer_toggle, path): ''' Callback for a "toggled" signal from a L{gtk.CellRendererToggle} in the plugin dialog. Passes along the toggle request to the L{PluginManager}. @param renderer_toggle: The toggle cellrenderer that emitted the signal. @type renderer_toggle: L{gtk.CellRendererToggle} @param path: The path that has been toggled. @type path: tuple ''' self.plugin_manager.togglePlugin(path) def _onViewChanged(self, cellrenderertext, path, new_text): ''' Callback for an "edited" signal from a L{gtk.CellRendererCombo} in the plugin dialog. Passes along the new requested view name to the L{PluginManager}. @param cellrenderertext: The combo cellrenderer that emitted the signal. @type renderer_toggle: L{gtk.CellRendererCombo} @param path: The path that has been touched. @type path: tuple @param new_text: The new text that has been entered in to the combo entry. @type new_text: string ''' plugin = \ self.plugin_manager[path][self.plugin_manager.COL_INSTANCE] self.view_manager.changeView(plugin, new_text)