Skip to content
Commits on Source (6)
......@@ -54,6 +54,11 @@ gnome-orca (3.24.0-1+hypra2) UNRELEASED; urgency=medium
1001-Mark-character-with-SSML-say-as-when-speaking-single.patch.
* 1003-Speak-key-events-as-characters.patch: New patch to also speak keys
as characters when appropriate
* Add patches for profile migration:
+ 0001-Let-user-keybindings-override-defaults.patch
+ 0002-Add-support-for-settings-migration.patch
+ 0003-Add-support-for-migrating-keybindings.patch
+ 2006_3-16-to-3-24-migration.patch
-- Samuel Thibault <sthibault@debian.org> Wed, 13 Jun 2018 17:23:04 +0200
......
From 2c33f3f76b55193dd229630b25e646706f6e62aa Mon Sep 17 00:00:00 2001
From: Colomban Wendling <cwendling@hypra.fr>
Date: Tue, 15 Jan 2019 17:04:06 +0100
Subject: [PATCH 1/2] Let user keybindings override defaults
If the user configuration uses a keybinding that is in the default
configuration, keep the user keybinding instead of the default one.
This is particularly useful when adding a new default keybinding to
make sure it won't conflict with a customized user configuration.
---
src/orca/keybindings.py | 17 ++++++++++++++++-
src/orca/settings_manager.py | 2 +-
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/src/orca/keybindings.py b/src/orca/keybindings.py
index 5bb5dfba0..47ded43d9 100644
--- a/src/orca/keybindings.py
+++ b/src/orca/keybindings.py
@@ -284,10 +284,16 @@ class KeyBindings:
result += "]"
return result
- def add(self, keyBinding):
+ def add(self, keyBinding, exclusive=False):
"""Adds the given KeyBinding instance to this set of keybindings.
+
+ if exclusive is True, other keybindings using the same combo will
+ be unbound.
"""
+ if exclusive and len(keyBinding.keysymstring) > 0:
+ self.unbind(keyBinding.keysymstring, keyBinding.modifiers,
+ keyBinding.click_count)
self.keyBindings.append(keyBinding)
def remove(self, keyBinding):
@@ -310,6 +316,15 @@ class KeyBindings:
del self.keyBindings[i - 1]
i = i - 1
+ def unbind(self, keysym, mods, clicks):
+ for kb in self.keyBindings:
+ if kb.keysymstring == keysym \
+ and kb.modifiers == mods \
+ and kb.click_count == clicks:
+ kb.keysymstring = ''
+ kb.modifiers = 0
+ kb.click_count = 0
+
def hasKeyBinding (self, newKeyBinding, typeOfSearch="strict"):
"""Return True if keyBinding is already in self.keyBindings.
diff --git a/src/orca/settings_manager.py b/src/orca/settings_manager.py
index 73f8290cf..993db4943 100644
--- a/src/orca/settings_manager.py
+++ b/src/orca/settings_manager.py
@@ -506,7 +506,7 @@ class SettingsManager(object):
bindingTuple = self._adjustBindingTupleValues(bindingTuple)
keysym, mask, mods, clicks = bindingTuple
newBinding = KeyBinding(keysym, mask, mods, handler, clicks)
- scriptKeyBindings.add(newBinding)
+ scriptKeyBindings.add(newBinding, exclusive=True)
return scriptKeyBindings
--
2.20.1
From bf43dc1b638724db8d15edeca68855abe77710cc Mon Sep 17 00:00:00 2001
From: Colomban Wendling <cwendling@hypra.fr>
Date: Thu, 17 Jan 2019 15:11:11 +0100
Subject: [PATCH 2/2] Add support for settings migration
This adds support for adding migration logic when loading user settings
from an older version.
If the user settings version doesn't match the running settings version
the migration methods kick in, with full power to transform options.
To implement a migration path for an option, implement the method
SettingsMigration._migrateOptName(self, userSettings, name)
which should transform userSettings as appropriate and return it. It
allows any transformation, including renaming a setting.
---
src/orca/Makefile.am | 1 +
src/orca/backends/json_backend.py | 41 ++++++++++++++++++-
src/orca/settings.py | 3 ++
src/orca/settings_migration.py | 66 +++++++++++++++++++++++++++++++
4 files changed, 109 insertions(+), 2 deletions(-)
create mode 100644 src/orca/settings_migration.py
diff --git a/src/orca/Makefile.am b/src/orca/Makefile.am
index 7041dc3b2..2bb5b73fa 100644
--- a/src/orca/Makefile.am
+++ b/src/orca/Makefile.am
@@ -59,6 +59,7 @@ orca_python_PYTHON = \
script_utilities.py \
settings.py \
settings_manager.py \
+ settings_migration.py \
sound.py \
sound_generator.py \
speech.py \
diff --git a/src/orca/backends/json_backend.py b/src/orca/backends/json_backend.py
index dd0e07e7e..eaf07c926 100644
--- a/src/orca/backends/json_backend.py
+++ b/src/orca/backends/json_backend.py
@@ -29,7 +29,7 @@ __license__ = "LGPL"
from json import load, dump
import os
-from orca import settings, acss
+from orca import settings, settings_migration, acss
class Backend:
@@ -52,7 +52,8 @@ class Backend:
def saveDefaultSettings(self, general, pronunciations, keybindings):
""" Save default settings for all the properties from
orca.settings. """
- prefs = {'general': general,
+ prefs = {'version': settings.settingsVersion,
+ 'general': general,
'profiles': self._defaultProfiles,
'pronunciations': pronunciations,
'keybindings': keybindings}
@@ -72,6 +73,9 @@ class Backend:
settingsFile = open(fileName, 'r')
prefs = load(settingsFile)
settingsFile.close()
+ if self._updatePrefs(prefs, isAppSettings=True):
+ with open(fileName, 'w') as settingsFile:
+ dump(prefs, settingsFile, indent=4)
else:
prefs = {}
@@ -83,6 +87,7 @@ class Backend:
profiles[profile] = {'general': general,
'pronunciations': pronunciations,
'keybindings': keybindings}
+ prefs['version'] = settings.settingsVersion
prefs['profiles'] = profiles
fileName = os.path.join(self.appPrefsDir, "%s.conf" % appName)
@@ -102,11 +107,37 @@ class Backend:
with open(self.settingsFile, 'r+') as settingsFile:
prefs = load(settingsFile)
+ prefs['version'] = settings.settingsVersion
prefs['profiles'][profile] = general
settingsFile.seek(0)
settingsFile.truncate()
dump(prefs, settingsFile, indent=4)
+ def _updatePrefs(self, prefs, isAppSettings):
+ """Updates prefs to a new settings version if needed, and return
+ whether prefs have changed.
+
+ isAppSettings: whether `prefs` comes from an app settings file, as
+ the layout is slightly different"""
+ version = prefs.get('version', 0)
+ if version == settings.settingsVersion:
+ return False
+
+ m = settings_migration.SettingsMigration(version, settings.settingsVersion)
+ if 'general' in prefs:
+ prefs['general'] = m.migrateGeneral(prefs['general'])
+ for profileName in prefs['profiles'].keys():
+ if not isAppSettings:
+ prefs['profiles'][profileName] = \
+ m.migrateGeneral(prefs['profiles'][profileName])
+ elif 'general' in prefs['profiles'][profileName]:
+ prefs['profiles'][profileName]['general'] = \
+ m.migrateGeneral(prefs['profiles'][profileName]['general'])
+
+ prefs['version'] = settings.settingsVersion
+
+ return True
+
def _getSettings(self):
""" Load from config file all settings """
settingsFile = open(self.settingsFile)
@@ -114,6 +145,11 @@ class Backend:
prefs = load(settingsFile)
except ValueError:
return
+
+ if self._updatePrefs(prefs, isAppSettings=False):
+ with open(self.settingsFile, 'w') as settingsFile:
+ dump(prefs, settingsFile, indent=4)
+
self.general = prefs['general'].copy()
self.pronunciations = prefs['pronunciations']
self.keybindings = prefs['keybindings']
@@ -171,6 +207,7 @@ class Backend:
with open(self.settingsFile, 'r+') as settingsFile:
prefs = load(settingsFile)
+ prefs['version'] = settings.settingsVersion
prefs['general'][key] = value
settingsFile.seek(0)
settingsFile.truncate()
diff --git a/src/orca/settings.py b/src/orca/settings.py
index 2974ab29a..2a3fb8561 100644
--- a/src/orca/settings.py
+++ b/src/orca/settings.py
@@ -187,6 +187,9 @@ UPPERCASE_VOICE = "uppercase"
HYPERLINK_VOICE = "hyperlink"
SYSTEM_VOICE = "system"
+# version of the settings, allowing to check compatibility
+settingsVersion = 1
+
voicesKeys = {
"DEFAULT_VOICE" : "default",
"UPPERCASE_VOICE" : "uppercase",
diff --git a/src/orca/settings_migration.py b/src/orca/settings_migration.py
new file mode 100644
index 000000000..0d4d52e40
--- /dev/null
+++ b/src/orca/settings_migration.py
@@ -0,0 +1,66 @@
+# Orca
+#
+# Copyright 2019 Hypra
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA 02110-1301 USA.
+
+"""Settings migration module. This will transform settings between two version
+of the configuration."""
+
+__id__ = "$Id$"
+__version__ = "$Revision$"
+__date__ = "$Date$"
+__copyright__ = "Copyright (c) 2019 Hypra"
+__license__ = "LGPL"
+
+from . import debug
+from . import settings
+
+
+class SettingsMigration(object):
+ """
+ To add a new migration path for a setting, add a method like this:
+
+ def _migrateTheOptionName(self, general, name):
+ if self.fromVersion < theVersionThatIntroducedTheSetting:
+ # perform any changes required
+ general[...] = ...
+ return general
+
+ In normal situation, one can assume that
+ - The source and target versions are different
+ - The target version is the current one (settings.settingsVersion)
+ - We're *upgrading*. Support for downgrading is theoretically possible,
+ but unlikely be implemented for all options.
+ """
+
+ def __init__(self, fromVersion, toVersion=settings.settingsVersion):
+ self.fromVersion = fromVersion
+ self.toVersion = toVersion
+
+ def migrateGeneral(self, general):
+ if self.fromVersion != self.toVersion:
+ debug.println(debug.LEVEL_CONFIGURATION,
+ "CONFIGURATION MIGRATION: " +
+ "Migrating general settings from v%s to v%s" %
+ (self.fromVersion, self.toVersion))
+ for name in general:
+ migratorName = '_migrate' + name[0].upper() + name[1:]
+ migrator = getattr(self, migratorName, None)
+ if migrator:
+ general = migrator(general, name)
+
+ return general
--- a/src/orca/Makefile.in
+++ b/src/orca/Makefile.in
@@ -398,6 +398,7 @@ orca_python_PYTHON = \
script_utilities.py \
settings.py \
settings_manager.py \
+ settings_migration.py \
sound.py \
sound_generator.py \
speech.py \
--
2.20.1
Add support for migrating keybindings as well
--- a/src/orca/settings_migration.py
+++ b/src/orca/settings_migration.py
@@ -51,16 +51,22 @@ class SettingsMigration(object):
self.fromVersion = fromVersion
self.toVersion = toVersion
- def migrateGeneral(self, general):
+ def _doMigration(self, dct, groupName, methodPrefix):
if self.fromVersion != self.toVersion:
debug.println(debug.LEVEL_CONFIGURATION,
"CONFIGURATION MIGRATION: " +
- "Migrating general settings from v%s to v%s" %
- (self.fromVersion, self.toVersion))
- for name in general:
- migratorName = '_migrate' + name[0].upper() + name[1:]
+ "Migrating %s settings from v%s to v%s" %
+ (groupName, self.fromVersion, self.toVersion))
+ for name in dct:
+ migratorName = methodPrefix + name[0].upper() + name[1:]
migrator = getattr(self, migratorName, None)
if migrator:
- general = migrator(general, name)
+ dct = migrator(dct, name)
- return general
+ return dct
+
+ def migrateGeneral(self, general):
+ return self._doMigration(general, 'general', '_migrate')
+
+ def migrateKeybindings(self, keybindings):
+ return self._doMigration(keybindings, 'keybindings', '_migrateKeybinding')
--- a/src/orca/backends/json_backend.py
+++ b/src/orca/backends/json_backend.py
@@ -126,6 +126,8 @@ class Backend:
m = settings_migration.SettingsMigration(version, settings.settingsVersion)
if 'general' in prefs:
prefs['general'] = m.migrateGeneral(prefs['general'])
+ if 'keybindings' in prefs:
+ prefs['keybindings'] = m.migrateKeybindings(prefs['keybindings'])
for profileName in prefs['profiles'].keys():
if not isAppSettings:
prefs['profiles'][profileName] = \
@@ -133,6 +135,9 @@ class Backend:
elif 'general' in prefs['profiles'][profileName]:
prefs['profiles'][profileName]['general'] = \
m.migrateGeneral(prefs['profiles'][profileName]['general'])
+ if 'keybindings' in prefs['profiles'][profileName]:
+ prefs['profiles'][profileName]['keybindings'] = \
+ m.migrateKeybindings(prefs['profiles'][profileName]['keybindings'])
prefs['version'] = settings.settingsVersion
--- a/src/orca/settings_migration.py
+++ b/src/orca/settings_migration.py
@@ -70,3 +70,52 @@ class SettingsMigration(object):
def migrateKeybindings(self, keybindings):
return self._doMigration(keybindings, 'keybindings', '_migrateKeybinding')
+
+ def _migrateOrcaModifierKeys(self, general, name):
+ """ Migrates 'orcaModifierKeys' for shiftlock support """
+ if self.fromVersion < 1:
+ # before v1, LAPTOP_MODIFIER_KEYS contained only one element
+ if any(i in settings.LAPTOP_MODIFIER_KEYS for i in general[name]):
+ general[name] = settings.LAPTOP_MODIFIER_KEYS
+ return general
+
+ def _migrateKeybindingToggleCaretNavigationHandler(self, general, name):
+ """ Renames 'toggleCaretNavigationHandler' to 'toggle_enabled' """
+ general['toggle_enabled'] = general[name]
+ del general[name]
+ return general
+
+ def _migrateKeybindings(self, general, name):
+ """
+ Hack to change keybindings of some specific profiles
+
+ Remaps Orca+b to flatReviewSayAll if it's not bound to something
+ else than the default already.
+ """
+ from .keybindings import defaultModifierMask, ORCA_MODIFIER_MASK
+
+ if self.fromVersion < 1:
+ try:
+ profile = general['profile'][1]
+ except KeyError:
+ profile = 'default'
+ if any(profile.startswith(i) for i in ['nvda_', 'jaws_']):
+ binding = list(map(str, ('b', defaultModifierMask,
+ ORCA_MODIFIER_MASK, 1)))
+ handler = 'flatReviewSayAllHandler'
+ for handlerString, bindingTuples in general[name].items():
+ if handlerString == handler:
+ break
+ if binding in bindingTuples:
+ break
+ else:
+ # If the binding is not in use in this profile and this
+ # profile doesn't have a binding for this handler, add
+ # it to override the default.
+ general[name][handler] = [ binding, ]
+ # Unbind the default if it wasn't overridden
+ if not 'goToNextBookmark' in general[name].keys():
+ unbound = ['', '0', '0', '0']
+ general[name]['goToNextBookmark'] = [ unbound, ]
+
+ return general
......@@ -32,3 +32,7 @@ mozilla-invalid-images.patch
1002-french-y-pronunciation.patch
1002-Avoid-double-character-representation-expansion.patch
1003-Speak-key-events-as-characters.patch
0001-Let-user-keybindings-override-defaults.patch
0002-Add-support-for-settings-migration.patch
0003-Add-support-for-migrating-keybindings.patch
2006_3-16-to-3-24-migration.patch