Index: ChangeLog
===================================================================
--- ChangeLog	(revision 2313)
+++ ChangeLog	(working copy)
@@ -1,3 +1,31 @@
+2007-04-23  Rich Burridge <rich.burridge@sun.com>
+
+        * src/orca/app_gui_prefs.py:   (new)
+          src/orca/default.py:
+          src/orca/Makefile.am:
+          src/orca/orca.py:
+          src/orca/orca_gui_prefs.py:
+          src/orca/orca_prefs.py:
+          src/orca/settings.py:
+          Fixed bug #372273 – Add ability to configure app-specific 
+          settings via GUI.
+
+          Adjusted <ORCA MODIFIER>+Control+Space to now bring up
+          the application specific preferences dialog. The previous
+          usage (reload user settings) is now gone.
+
+          The application specific preferences dialog does not have a 
+          general pane and the Speech systems and servers controls on 
+          the speech tab are grayed out.
+
+          Application specific settings are written to
+          ~/.orca/app-settings/<APPNAME>.py  Only the differences from
+          the generic Orca user preferences are written out.
+
+          If you want to have application specific customizations that
+          won't get overridden, then these need to be saved in
+          ~/.orca/app-settings/<APPNAME>-customizations.py
+
 2007-04-23  Willie Walker <william.walker@sun.com>
 
         * configure.in, README: mark as v2.19.2pre.
Index: src/orca/settings.py
===================================================================
--- src/orca/settings.py	(revision 2313)
+++ src/orca/settings.py	(working copy)
@@ -142,6 +142,7 @@
 #
 guiPreferencesModule    = "orca_gui_prefs"
 consolePreferencesModule= "orca_console_prefs"
+appGuiPreferencesModule = "app_gui_prefs"
 
 # The name of the module that hold the user interface for quitting Orca.
 # This module is expected to have the method, showQuitUI, which will
Index: src/orca/orca_prefs.py
===================================================================
--- src/orca/orca_prefs.py	(revision 2313)
+++ src/orca/orca_prefs.py	(working copy)
@@ -377,18 +377,9 @@
 
     return prefsDict
 
-def writePreferences(prefsDict, treeModel=None):
-    """Creates the directory and files to hold user preferences.  Note
-    that callers of this method may want to consider using an ordered
-    dictionary so that the keys are output in a deterministic order.
+def _setupPreferencesDirs():
+    """Creates the directories and standard files to hold user preferences."""
 
-    Arguments:
-    - prefsDict: a dictionary where the keys are orca preferences
-    names and the values are the values for the preferences.
-
-    Returns True if accessibility was enabled as a result of this
-    call."""
-
     # Set up the user's preferences directory (~/.orca by default).
     #
     orcaDir = settings.userPrefsDir
@@ -410,41 +401,71 @@
     if not os.path.exists(initFile):
         os.close(os.open(initFile, os.O_CREAT, 0700))
 
+def _getValueForKey(prefsDict, key):
+    """Return the value associated with this preferences dictionary key
+
+    Arguments:
+    - prefsDict: a dictionary where the keys are orca preferences
+    names and the values are the values for the preferences.
+    - key: the preferences dictionary key.
+
+    Return the value of the given preferences dictionary key.
+    """
+    if prefsDict.has_key(key):
+        if key == "voices":
+            value = _getVoicesString(prefsDict[key])
+        elif key == "speechServerInfo":
+            value = _getSpeechServerString(prefsDict[key])
+        elif key == "speechServerFactory":
+            value = _getSpeechServerFactoryString(prefsDict[key])
+        elif key.endswith("VerbosityLevel"):
+            value = _getVerbosityString(prefsDict[key])
+        elif key == "brailleRolenameStyle":
+            value = _getBrailleRolenameStyleString(prefsDict[key])
+        elif key == "verbalizePunctuationStyle":
+            value = _getVerbalizePunctuationStyleString(prefsDict[key])
+        elif key == "sayAllStyle":
+            value = _getSayAllStyleString(prefsDict[key])
+        elif key == "magCursorColor":
+            value = _getMagCursorColorString(prefsDict[key])
+        elif key == "magSmoothingMode":
+            value = _getMagSmoothingModeString(prefsDict[key])
+        elif key == "magMouseTrackingMode":
+            value = _getMagMouseTrackingModeString(prefsDict[key])
+        elif key == "magSourceDisplay" or key == "magTargetDisplay":
+            value = _getDisplayString(prefsDict[key])
+        elif key == "keyboardLayout":
+            value = _getKeyboardLayoutString(prefsDict[key])
+        elif key == "orcaModifierKeys":
+            value = _getOrcaModifierKeysString(prefsDict[key])
+        else:
+            value = prefsDict[key]
+
+    return value
+
+def writePreferences(prefsDict, treeModel=None):
+    """Creates the directory and files to hold user preferences.  Note
+    that callers of this method may want to consider using an ordered
+    dictionary so that the keys are output in a deterministic order.
+
+    Arguments:
+    - prefsDict: a dictionary where the keys are orca preferences
+    names and the values are the values for the preferences.
+
+    Returns True if accessibility was enabled as a result of this
+    call."""
+
+    _setupPreferencesDirs()
+
     # Write ~/.orca/user-settings.py
     #
+    orcaDir = settings.userPrefsDir
     prefs = open(os.path.join(orcaDir, "user-settings.py"), "w")
     _writePreferencesPreamble(prefs)
+
     for key in settings.userCustomizableSettings:
-        if prefsDict.has_key(key):
-            if key == "voices":
-                value = _getVoicesString(prefsDict[key])
-            elif key == "speechServerInfo":
-                value = _getSpeechServerString(prefsDict[key])
-            elif key == "speechServerFactory":
-                value = _getSpeechServerFactoryString(prefsDict[key])
-            elif key.endswith("VerbosityLevel"):
-                value = _getVerbosityString(prefsDict[key])
-            elif key == "brailleRolenameStyle":
-                value = _getBrailleRolenameStyleString(prefsDict[key])
-            elif key == "verbalizePunctuationStyle":
-                value = _getVerbalizePunctuationStyleString(prefsDict[key])
-            elif key == "sayAllStyle":
-                value = _getSayAllStyleString(prefsDict[key])
-            elif key == "magCursorColor":
-                value = _getMagCursorColorString(prefsDict[key])
-            elif key == "magSmoothingMode":
-                value = _getMagSmoothingModeString(prefsDict[key])
-            elif key == "magMouseTrackingMode":
-                value = _getMagMouseTrackingModeString(prefsDict[key])
-            elif key == "magSourceDisplay" or key == "magTargetDisplay":
-                value = _getDisplayString(prefsDict[key])
-            elif key == "keyboardLayout":
-                value = _getKeyboardLayoutString(prefsDict[key])
-            elif key == "orcaModifierKeys":
-                value = _getOrcaModifierKeysString(prefsDict[key])
-            else:
-                value = prefsDict[key]
-            prefs.writelines("orca.settings.%s = %s\n" % (key, value))
+        value = _getValueForKey(prefsDict, key)
+        prefs.writelines("orca.settings.%s = %s\n" % (key, value))
 
     if treeModel:
         _writeKeyBindingsMap(prefs, treeModel)
@@ -456,3 +477,71 @@
     # as a result of this call.
     #
     return _enableAccessibility()
+
+def _writeAppPreferencesPreamble(prefs, appName):
+    """Writes the preamble to the ~/.orca/app-settings/<APPNAME>.py file.
+
+    Arguments:
+    - prefs: file handle for application preferences.
+    - appName: the application name.
+    """
+
+    prefs.writelines("# %s.py - custom Orca application settings\n" % appName)
+    prefs.writelines("# Generated by orca.  DO NOT EDIT THIS FILE!!!\n")
+    prefs.writelines("# If you want permanent customizations that will not\n")
+    prefs.writelines("# be overwritten, edit %s-customizations.py.\n" % appName)
+    prefs.writelines("#\n")
+    prefs.writelines("import orca.settings\n")
+    prefs.writelines("import orca.acss\n")
+    prefs.writelines("\n")
+
+def _writeAppPreferencesPostamble(prefs, appName):
+    """Writes the postamble to the ~/.orca/app-settings/<APPNAME>.py file.
+    
+    Arguments:
+    - prefs: file handle for application preferences.
+    - appName: the application name.
+    """
+    
+    prefs.writelines("\ntry:\n")
+    prefs.writelines("    __import__(\"%s-customizations\")\n" % appName)
+    prefs.writelines("except ImportError:\n")
+    prefs.writelines("    pass\n")
+
+def writeAppPreferences(prefsDict, appName, treeModel=None):
+    """Creates the directory and files to hold application specific
+    user preferences.  Write out any preferences that are different
+    from the generic Orca preferences for this user. Note that callers 
+    of this method may want to consider using an ordered dictionary so 
+    that the keys are output in a deterministic order.
+
+    Arguments:
+    - prefsDict: a dictionary where the keys are orca preferences
+    names and the values are the values for the preferences.
+    - appName: the application these preferences are for.
+    - treeModel: key bindings treemodel.
+    """
+
+    _setupPreferencesDirs()
+
+    oldPrefsDict = readPreferences()
+
+    # Write ~/.orca/app-settings/<APPNAME>.py
+    #
+    orcaDir = settings.userPrefsDir
+    orcaSettingsDir = os.path.join(orcaDir, "app-settings")
+    appFileName = "%s.py" % appName
+    prefs = open(os.path.join(orcaSettingsDir, appFileName), "w")
+    _writeAppPreferencesPreamble(prefs, appName)
+
+    for key in settings.userCustomizableSettings:
+        value = _getValueForKey(prefsDict, key)
+        oldValue = _getValueForKey(oldPrefsDict, key)
+        if oldValue != value:
+            prefs.writelines("orca.settings.%s = %s\n" % (key, value))
+
+    if treeModel:
+        _writeKeyBindingsMap(prefs, treeModel)
+
+    _writeAppPreferencesPostamble(prefs, appName)
+    prefs.close()
Index: src/orca/app_gui_prefs.py
===================================================================
--- src/orca/app_gui_prefs.py	(revision 0)
+++ src/orca/app_gui_prefs.py	(revision 0)
@@ -0,0 +1,131 @@
+# Orca
+#
+# Copyright 2007 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+"""Displays a GUI for the user to set Orca application-specific preferences."""
+
+__id__        = "$Id:$"
+__version__   = "$Revision:$"
+__date__      = "$Date:$"
+__copyright__ = "Copyright (c) 2007 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import gettext
+import gtk
+import locale
+import os
+import sys
+
+import braille
+import orca_gui_prefs
+import orca_prefs
+import orca_state
+import platform
+import settings
+import speech
+
+from orca_i18n import _  # for gettext support
+
+OS = None
+
+class orcaSetupGUI(orca_gui_prefs.orcaSetupGUI):
+
+    def _initGUIState(self):
+        """Adjust the settings of the various components on the
+        configuration GUI depending upon the users preferences.
+        """
+
+        orca_gui_prefs.orcaSetupGUI._initGUIState(self)
+
+        # Before we show the GUI to the user we want to remove the
+        # General tab and gray out the Speech systems and servers 
+        # controls on the speech tab.
+        #
+        self.notebook.remove_page(0)
+        self.speechSystemsLabel.set_sensitive(False)
+        self.speechSystems.set_sensitive(False)
+        self.speechServersLabel.set_sensitive(False)
+        self.speechServers.set_sensitive(False)
+
+        # Adjust the title of the app-specific Orca Preferences dialog to
+        # include the name of the application.
+        #
+        self.app = orca_state.locusOfFocus.app
+        self.applicationName = self.app.name
+        title = _("Orca Preferences for %s") % self.applicationName
+        self.orcaSetupWindow.set_title(title)
+
+    def _showGUI(self):
+        """Show the app-specific Orca configuration GUI window. This 
+        assumes that the GUI has already been created.
+        """
+
+        orca_gui_prefs.orcaSetupGUI._showGUI(self)
+
+    def writeUserPreferences(self):
+        """Write out the user's application-specific Orca preferences.
+        """
+
+        moduleName = settings.getScriptModuleName(self.app)
+        orca_prefs.writeAppPreferences(self.prefsDict, moduleName,
+                                       self.keyBindingsModel)
+
+def showPreferencesUI():
+    global OS
+
+    # There must be an application with focus for this to work.
+    #
+    if not orca_state.locusOfFocus or not orca_state.locusOfFocus.app:
+        message = _("No application has focus.")
+        braille.displayMessage(message)
+        speech.speak(message)
+        return
+
+    # The name of the application that currently has focus.
+    #
+    applicationName = orca_state.locusOfFocus.app.name
+
+    # Translators: Orca Preferences in this case, is a configuration GUI 
+    # for allowing users to set application specific settings from within
+    # Orca for the application that currently has focus.
+    #
+    line = _("Starting Orca Preferences for %s. This may take a while.") % \
+           applicationName
+    braille.displayMessage(line)
+    speech.speak(line)
+
+    if not OS:
+        gladeFile = os.path.join(platform.prefix,
+                                 platform.datadirname,
+                                 platform.package,
+                                 "glade",
+                                 "orca-setup.glade")
+        OS = orcaSetupGUI(gladeFile, "orcaSetupWindow")
+        OS._init()
+
+    OS._showGUI()
+
+def main():
+    locale.setlocale(locale.LC_ALL, '')
+
+    showPreferencesUI()
+
+    gtk.main()
+    sys.exit(0)
+
+if __name__ == "__main__":
+    main()
Index: src/orca/orca.py
===================================================================
--- src/orca/orca.py	(revision 2313)
+++ src/orca/orca.py	(working copy)
@@ -892,6 +892,26 @@
 
     return True
 
+def _showAppPreferencesGUI(script=None, inputEvent=None):
+    """Displays the user interace to configure the settings for a
+    specific applications within Orca and set up those app-specific 
+    user preferences using a GUI.
+
+    Returns True to indicate the input event has been consumed.
+    """
+
+    try:
+        module = __import__(settings.appGuiPreferencesModule,
+                            globals(),
+                            locals(),
+                            [''])
+        module.showPreferencesUI()
+    except:
+        debug.printException(debug.LEVEL_SEVERE)
+        pass
+
+    return True
+
 def _showPreferencesGUI(script=None, inputEvent=None):
     """Displays the user interace to configure Orca and set up
     user preferences using a GUI.
Index: src/orca/default.py
===================================================================
--- src/orca/default.py	(revision 2313)
+++ src/orca/default.py	(working copy)
@@ -611,12 +611,14 @@
                 #
                 _("Displays the preferences configuration dialog."))
 
-        self.inputEventHandlers["loadUserSettingsHandler"] = \
+        self.inputEventHandlers["appPreferencesSettingsHandler"] = \
             input_event.InputEventHandler(
-                orca.loadUserSettings,
-                # Translators: this is basically a 'warm restart' of Orca.
+                orca._showAppPreferencesGUI,
+                # Translators: the application preferences configuration 
+                # dialog is the dialog that allows users to set their 
+                # preferences for a specific application within Orca.
                 #
-                _("Reloads user settings and reinitializes services as necessary."))
+                _("Displays the application preferences configuration dialog."))
 
         self.inputEventHandlers["toggleSilenceSpeechHandler"] = \
             input_event.InputEventHandler(
@@ -1314,7 +1316,7 @@
                  | 1 << atspi.Accessibility.MODIFIER_CONTROL),
                 (1 << settings.MODIFIER_ORCA | \
                      1 << atspi.Accessibility.MODIFIER_CONTROL),
-                self.inputEventHandlers["loadUserSettingsHandler"]))
+                self.inputEventHandlers["appPreferencesSettingsHandler"]))
 
         keyBindings.add(
             keybindings.KeyBinding(
Index: src/orca/Makefile.am
===================================================================
--- src/orca/Makefile.am	(revision 2313)
+++ src/orca/Makefile.am	(working copy)
@@ -9,6 +9,7 @@
 orca_python_PYTHON = \
 	__init__.py \
 	acss.py \
+	app_gui_prefs.py \
 	atspi.py \
 	braille.py \
 	braillegenerator.py \
Index: src/orca/orca_gui_prefs.py
===================================================================
--- src/orca/orca_gui_prefs.py	(revision 2313)
+++ src/orca/orca_gui_prefs.py	(working copy)
@@ -309,6 +309,14 @@
 
         return voiceACSS
 
+    def writeUserPreferences(self):
+        """Write out the user's generic Orca preferences.
+        """
+
+        if orca_prefs.writePreferences(self.prefsDict, self.keyBindingsModel):
+            self._say(_("Accessibility support for GNOME has just been enabled."))
+            self._say(_("You need to log out and log back in for the change to take effect."))
+
     def _getKeyValueForVoiceType(self, voiceType, key, useDefault=True):
         """Look for the value of the given key in the voice dictionary
            for the given voice type.
@@ -2120,9 +2128,7 @@
 
         settings.setGKSUGrabDisabled(self.disableKeyGrabPref)
 
-        if orca_prefs.writePreferences(self.prefsDict, self.keyBindingsModel):
-            self._say(_("Accessibility support for GNOME has just been enabled."))
-            self._say(_("You need to log out and log back in for the change to take effect."))
+        self.writeUserPreferences()
 
         orca.loadUserSettings()
 
