Esempio n. 1
0
    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
Esempio n. 2
0
    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)
Esempio n. 3
0
    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)
Esempio n. 4
0
    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
Esempio n. 5
0
  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
Esempio n. 6
0
    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
Esempio n. 7
0
    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)
Esempio n. 8
0
    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
Esempio n. 9
0
    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
Esempio n. 10
0
    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
Esempio n. 11
0
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)
Esempio n. 12
0
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)
Esempio n. 13
0
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)
Esempio n. 14
0
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)