[orca: 1/2] Add support for removing user profiles



commit 98be9c4bcbfaaffe5d7019e0e66bebec8de7b293
Author: Colomban Wendling <hypra ban netlib re>
Date:   Thu Sep 20 16:51:41 2018 +0000

    Add support for removing user profiles

 src/orca/backends/json_backend.py | 43 ++++++++++++++++++-----
 src/orca/guilabels.py             | 27 +++++++++++++++
 src/orca/orca-setup.ui            | 17 +++++++++
 src/orca/orca_gui_prefs.py        | 72 ++++++++++++++++++++++++++++++++++-----
 src/orca/settings_manager.py      |  3 ++
 5 files changed, 144 insertions(+), 18 deletions(-)
---
diff --git a/src/orca/backends/json_backend.py b/src/orca/backends/json_backend.py
index b6c9246b9..dd0e07e7e 100644
--- a/src/orca/backends/json_backend.py
+++ b/src/orca/backends/json_backend.py
@@ -43,21 +43,22 @@ class Backend:
         self.settingsFile = os.path.join(prefsDir, "user-settings.conf")
         self.appPrefsDir = os.path.join(prefsDir, "app-settings")
 
+        self._defaultProfiles = {'default': { 'profile':  settings.profile,
+                                                          'pronunciations': {},
+                                                          'keybindings': {}
+                                            }
+                                }
+
     def saveDefaultSettings(self, general, pronunciations, keybindings):
         """ Save default settings for all the properties from
             orca.settings. """
-        defaultProfiles = {'default': { 'profile':  settings.profile,
-                                                    'pronunciations': {},
-                                                    'keybindings': {}
-                                      }
-                          }
         prefs = {'general': general,
-                 'profiles': defaultProfiles,
+                 'profiles': self._defaultProfiles,
                  'pronunciations': pronunciations,
                  'keybindings': keybindings}
 
         self.general = general
-        self.profiles = defaultProfiles
+        self.profiles = self._defaultProfiles
         self.pronunciations = pronunciations
         self.keybindings = keybindings
 
@@ -118,11 +119,15 @@ class Backend:
         self.keybindings = prefs['keybindings']
         self.profiles = prefs['profiles'].copy()
 
-    def getGeneral(self, profile='default'):
+    def getGeneral(self, profile=None):
         """ Get general settings from default settings and
             override with profile values. """
         self._getSettings()
         generalSettings = self.general.copy()
+        defaultProfile = generalSettings.get('startingProfile',
+                                             ['Default', 'default'])
+        if profile is None:
+            profile = defaultProfile[1]
         profileSettings = self.profiles[profile].copy()
         for key, value in profileSettings.items():
             if key == 'voices':
@@ -133,7 +138,7 @@ class Backend:
         try:
             generalSettings['activeProfile'] = profileSettings['profile']
         except KeyError:
-            generalSettings['activeProfile'] = ["Default", "default"] 
+            generalSettings['activeProfile'] = defaultProfile
         return generalSettings
 
     def getPronunciations(self, profile='default'):
@@ -188,3 +193,23 @@ class Backend:
             profiles.append(profileDict.get('profile'))
 
         return profiles
+
+    def removeProfile(self, profile):
+        """Remove an existing profile"""
+        def removeProfileFrom(dict):
+            del dict[profile]
+            # if we removed the last profile, restore the default ones
+            if len(dict) == 0:
+                for profileName in self._defaultProfiles:
+                    dict[profileName] = self._defaultProfiles[profileName].copy()
+
+        if profile in self.profiles:
+            removeProfileFrom(self.profiles)
+
+        with open(self.settingsFile, 'r+') as settingsFile:
+            prefs = load(settingsFile)
+            if profile in prefs['profiles']:
+                removeProfileFrom(prefs['profiles'])
+                settingsFile.seek(0)
+                settingsFile.truncate()
+                dump(prefs, settingsFile, indent=4)
diff --git a/src/orca/guilabels.py b/src/orca/guilabels.py
index f4954cb7d..a3a681f8f 100644
--- a/src/orca/guilabels.py
+++ b/src/orca/guilabels.py
@@ -371,6 +371,33 @@ PROFILE_SAVE_AS_TITLE = _("Save Profile As")
 # name of a new settings profile being saved via the 'Save Profile As' dialog.
 PROFILE_NAME_LABEL = _("_Profile Name:")
 
+# Translators: Profiles in Orca make it possible for users to quickly switch
+# amongst a group of pre-defined settings (e.g. an 'English' profile for reading
+# text written in English using an English-language speech synthesizer and
+# braille rules, and a similar 'Spanish' profile for reading Spanish text.
+# The following is a title in a dialog informing the user that he/she
+# is about to remove a user profile, and action that cannot be undone.
+PROFILE_REMOVE_TITLE = _("Remove User Profile")
+
+# Translators: Profiles in Orca make it possible for users to quickly switch
+# amongst a group of pre-defined settings (e.g. an 'English' profile for reading
+# text written in English using an English-language speech synthesizer and
+# braille rules, and a similar 'Spanish' profile for reading Spanish text.
+# The following is a label in a dialog informing the user that he/she
+# is about to remove a user profile, and action that cannot be undone.
+PROFILE_REMOVE_LABEL = _("Remove user profile")
+
+# Translators: Profiles in Orca make it possible for users to quickly switch
+# amongst a group of pre-defined settings (e.g. an 'English' profile for reading
+# text written in English using an English-language speech synthesizer and
+# braille rules, and a similar 'Spanish' profile for reading Spanish text.
+# The following is a message in a dialog informing the user that he/she
+# is about to remove a user profile, an action that cannot be undone.
+PROFILE_REMOVE_MESSAGE = _("You are about to remove profile %s. " \
+                           "All unsaved settings and settings saved in this " \
+                           "profile will be lost. Do you want to continue " \
+                           "and remove this profile and all related settings?")
+
 # Translators: Orca has a setting which determines which progress bar updates
 # should be announced. Choosing "All" means that Orca will present progress bar
 # updates regardless of what application and window they happen to be in.
diff --git a/src/orca/orca-setup.ui b/src/orca/orca-setup.ui
index 9995f20a7..db562bd65 100644
--- a/src/orca/orca-setup.ui
+++ b/src/orca/orca-setup.ui
@@ -402,6 +402,23 @@
                                 <property name="top_attach">0</property>
                               </packing>
                             </child>
+                            <child>
+                              <object class="GtkButton" id="removeProfileButton">
+                                <property name="label" translatable="yes" comments="Translators: This is the 
label for a button in a dialog.">_Remove</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="use_underline">True</property>
+                                <signal name="clicked" handler="removeProfileButtonClicked" swapped="no"/>
+                              </object>
+                              <packing>
+                                <property name="left_attach">4</property>
+                                <property name="top_attach">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <placeholder/>
+                            </child>
                             <child>
                               <placeholder/>
                             </child>
diff --git a/src/orca/orca_gui_prefs.py b/src/orca/orca_gui_prefs.py
index 90426406c..11aa84c8b 100644
--- a/src/orca/orca_gui_prefs.py
+++ b/src/orca/orca_gui_prefs.py
@@ -103,6 +103,8 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
         orca_gtkbuilder.GtkBuilderWrapper.__init__(self, fileName, windowName)
         self.prefsDict = prefsDict
 
+        self._defaultProfile = ['Default', 'default']
+
         # Initialize variables to None to keep pylint happy.
         #
         self.bbindings = None
@@ -1651,15 +1653,14 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
         availableProfiles = self.__getAvailableProfiles()
         self.profilesComboModel.clear()
 
-        defaultValue = ['Default', 'default']
         if not len(availableProfiles):
-            self.profilesComboModel.append(defaultValue)
+            self.profilesComboModel.append(self._defaultProfile)
         else:
             for profile in availableProfiles:
                 self.profilesComboModel.append(profile)
 
-        activeProfile = self.prefsDict.get('activeProfile') or defaultValue
-        startingProfile = self.prefsDict.get('startingProfile') or defaultValue
+        activeProfile = self.prefsDict.get('activeProfile') or self._defaultProfile
+        startingProfile = self.prefsDict.get('startingProfile') or self._defaultProfile
 
         activeProfileIter = self.getComboBoxIndex(self.profilesCombo,
                                                   activeProfile[0])
@@ -3159,7 +3160,7 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
         if isinstance(profileToSave, str) \
                 and profileToSave != '' \
                 and not profileToSave in availableProfiles \
-                and profileToSave != 'default':
+                and profileToSave != self._defaultProfile[1]:
             saveActiveProfile()
         else:
             if profileToSave is not None:
@@ -3180,6 +3181,54 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
                     dialog.destroy()
                 
 
+    def removeProfileButtonClicked(self, widget):
+        """Remove profile button clicked handler
+
+        If we removed the last profile, a default one will automatically get
+        added back by the settings manager.
+        """
+
+        oldProfile = self.getComboBoxList(self.profilesCombo)
+
+        message = guilabels.PROFILE_REMOVE_MESSAGE % \
+            ("<b>%s</b>" % GLib.markup_escape_text(oldProfile[0]))
+        dialog = Gtk.MessageDialog(self.window, Gtk.DialogFlags.MODAL,
+                                   type=Gtk.MessageType.INFO,
+                                   buttons=Gtk.ButtonsType.YES_NO)
+        dialog.set_markup("<b>%s</b>" % guilabels.PROFILE_REMOVE_LABEL)
+        dialog.format_secondary_markup(message)
+        dialog.set_title(guilabels.PROFILE_REMOVE_TITLE)
+        if dialog.run() == Gtk.ResponseType.YES:
+            # If we remove the currently used starting profile, fallback on
+            # the first listed profile, or the default one if there's
+            # nothing better
+            newStartingProfile = self.prefsDict.get('startingProfile')
+            if not newStartingProfile or newStartingProfile == oldProfile:
+                newStartingProfile = self._defaultProfile
+                for row in self.profilesComboModel:
+                    rowProfile = row[:]
+                    if rowProfile != oldProfile:
+                        newStartingProfile = rowProfile
+                        break
+            # Update the current profile to the active profile unless we're
+            # removing that one, in which case we use the new starting
+            # profile
+            newProfile = self.prefsDict.get('activeProfile')
+            if not newProfile or newProfile == oldProfile:
+                newProfile = newStartingProfile
+
+            _settingsManager.removeProfile(oldProfile[1])
+            self.loadProfile(newProfile)
+
+            # Make sure nothing is referencing the removed profile anymore
+            startingProfile = self.prefsDict.get('startingProfile')
+            if not startingProfile or startingProfile == oldProfile:
+                self.prefsDict['startingProfile'] = newStartingProfile
+                _settingsManager.setStartingProfile(newStartingProfile)
+                self.writeUserPreferences()
+
+        dialog.destroy()
+
     def loadProfileButtonClicked(self, widget):
         """Load profile button clicked handler"""
 
@@ -3203,12 +3252,17 @@ class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
     def loadSelectedProfile(self):
         """Load selected profile"""
 
+        activeProfile = self.getComboBoxList(self.profilesCombo)
+        self.loadProfile(activeProfile)
+
+    def loadProfile(self, profile):
+        """Load profile"""
+
         self.saveBasicSettings()
 
-        activeProfile = self.getComboBoxList(self.profilesCombo)
-        self.prefsDict['activeProfile'] = activeProfile
-        _settingsManager.setProfile(activeProfile[1])
-        self.prefsDict = _settingsManager.getGeneralSettings(activeProfile[1])
+        self.prefsDict['activeProfile'] = profile
+        _settingsManager.setProfile(profile[1])
+        self.prefsDict = _settingsManager.getGeneralSettings(profile[1])
 
         orca.loadUserSettings(skipReloadMessage=True)
 
diff --git a/src/orca/settings_manager.py b/src/orca/settings_manager.py
index 0ead65d4a..73f8290cf 100644
--- a/src/orca/settings_manager.py
+++ b/src/orca/settings_manager.py
@@ -369,6 +369,9 @@ class SettingsManager(object):
             orca_i18n.setLocaleForMessages(newVoiceLocale)
             orca_i18n.setLocaleForGUI(newVoiceLocale)
 
+    def removeProfile(self, profile):
+        self._backend.removeProfile(profile)
+
     def _setSettingsRuntime(self, settingsDict):
         for key, value in settingsDict.items():
             setattr(settings, str(key), value)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]