commit/StationPlaylist: 35 new changesets

  • From: commits-noreply@xxxxxxxxxxxxx
  • To: nvda-addons-commits@xxxxxxxxxxxxx
  • Date: Mon, 15 Aug 2016 17:04:59 -0000

35 new commits in StationPlaylist:

https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/38c87db91bb1/
Changeset:   38c87db91bb1
Branch:      None
User:        josephsl
Date:        2016-06-21 10:03:30+00:00
Summary:     Readme: add mic alarm interval entry

Affected #:  1 file

diff --git a/readme.md b/readme.md
index 3828550..ddd2748 100755
--- a/readme.md
+++ b/readme.md
@@ -186,6 +186,7 @@ Version 8.0 supports SPL Studio 5.10 and later, with 7.x 
designed to provide som
 * In Track Tool, you can obtain information on album and CD code by pressing 
Control+NVDA+9 and Control+NVDA+0, respectively.
 * Performance improvements when obtaining column information for the first 
time in Track Tool.
 * 8.0: Added a dialog in add-on settings to configure Columns Explorer slots 
for Track Tool.
+* You can now configure microphone alarm interval from microphone alarm dialog 
(Alt+NvDA+4).
 
 ## Changes for 7.2
 


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/f3fb21bf610a/
Changeset:   f3fb21bf610a
Branch:      None
User:        josephsl
Date:        2016-07-05 18:36:01+00:00
Summary:     Merge branch 'stable'

Affected #:  6 files

diff --git a/addon/appModules/splstudio/__init__.py 
b/addon/appModules/splstudio/__init__.py
index 7459a76..b66fe2e 100755
--- a/addon/appModules/splstudio/__init__.py
+++ b/addon/appModules/splstudio/__init__.py
@@ -1501,7 +1501,7 @@ class AppModule(appModuleHandler.AppModule):
        SPLScheduled = 7
 
        # Table of child constants based on versions
-       # These are scattered throughout the screen, so one can use 
foreground.children[index] to fetch them.
+       # These are scattered throughout the screen, so one can use 
foreground.getChild(index) to fetch them (getChild tip from Jamie Teh (NV 
Access)).
        # Because 5.x (an perhaps future releases) uses different screen 
layout, look up the needed constant from the table below (row = info needed, 
column = version).
        statusObjs={
                SPLPlayStatus:[5, 6], # Play status, mic, etc.
@@ -1527,7 +1527,7 @@ class AppModule(appModuleHandler.AppModule):
                        else: statusObj = self.statusObjs[infoIndex][1]
                        # 7.0: sometimes (especially when first loaded), 
OBJID_CLIENT fails, so resort to retrieving focused object instead.
                        if fg is not None and fg.childCount > 1:
-                               self._cachedStatusObjs[infoIndex] = 
fg.children[statusObj]
+                               self._cachedStatusObjs[infoIndex] = 
fg.getChild(statusObj)
                        else: return api.getFocusObject()
                return self._cachedStatusObjs[infoIndex]
 
@@ -1542,27 +1542,27 @@ class AppModule(appModuleHandler.AppModule):
                ui.message(msg)
 
        def script_sayAutomationStatus(self, gesture):
-               obj = self.status(self.SPLPlayStatus).children[1]
+               obj = self.status(self.SPLPlayStatus).getChild(1)
                msg = obj.name if 
splconfig.SPLConfig["General"]["MessageVerbosity"] == "beginner" else 
obj.name.split()[-1]
                ui.message(msg)
 
        def script_sayMicStatus(self, gesture):
-               obj = self.status(self.SPLPlayStatus).children[2]
+               obj = self.status(self.SPLPlayStatus).getChild(2)
                msg = obj.name if 
splconfig.SPLConfig["General"]["MessageVerbosity"] == "beginner" else 
obj.name.split()[-1]
                ui.message(msg)
 
        def script_sayLineInStatus(self, gesture):
-               obj = self.status(self.SPLPlayStatus).children[3]
+               obj = self.status(self.SPLPlayStatus).getChild(3)
                msg = obj.name if 
splconfig.SPLConfig["General"]["MessageVerbosity"] == "beginner" else 
obj.name.split()[-1]
                ui.message(msg)
 
        def script_sayRecToFileStatus(self, gesture):
-               obj = self.status(self.SPLPlayStatus).children[4]
+               obj = self.status(self.SPLPlayStatus).getChild(4)
                msg = obj.name if 
splconfig.SPLConfig["General"]["MessageVerbosity"] == "beginner" else 
obj.name.split()[-1]
                ui.message(msg)
 
        def script_sayCartEditStatus(self, gesture):
-               obj = self.status(self.SPLPlayStatus).children[5]
+               obj = self.status(self.SPLPlayStatus).getChild(5)
                msg = obj.name if 
splconfig.SPLConfig["General"]["MessageVerbosity"] == "beginner" else 
obj.name.split()[-1]
                ui.message(msg)
 
@@ -1593,7 +1593,7 @@ class AppModule(appModuleHandler.AppModule):
 
        def script_sayPlaylistModified(self, gesture):
                try:
-                       obj = self.status(self.SPLSystemStatus).children[5]
+                       obj = self.status(self.SPLSystemStatus).getChild(5)
                        ui.message(obj.name)
                except IndexError:
                        # Translators: Presented when playlist modification is 
unavailable (for Studio 4.33 and earlier)
@@ -1653,13 +1653,13 @@ class AppModule(appModuleHandler.AppModule):
                ui.message(obj.name)
 
        def script_sayListenerCount(self, gesture):
-               obj = self.status(self.SPLSystemStatus).children[3]
+               obj = self.status(self.SPLSystemStatus).getChild(3)
                # Translators: Presented when there is no listener count 
information.
                ui.message(obj.name) if obj.name is not None else 
ui.message(_("Listener count not found"))
 
        def script_sayTrackPitch(self, gesture):
                try:
-                       obj = self.status(self.SPLSystemStatus).children[4]
+                       obj = self.status(self.SPLSystemStatus).getChild(4)
                        ui.message(obj.name)
                except IndexError:
                        # Translators: Presented when there is no information 
on song pitch (for Studio 4.33 and earlier).

diff --git a/addon/locale/ar/LC_MESSAGES/nvda.po 
b/addon/locale/ar/LC_MESSAGES/nvda.po
index a841acd..45ca417 100755
--- a/addon/locale/ar/LC_MESSAGES/nvda.po
+++ b/addon/locale/ar/LC_MESSAGES/nvda.po
@@ -1370,6 +1370,7 @@ msgstr ""
 
 #. Help message for SPL Controller
 #. Translators: the dialog text for SPL Controller help.
+#, fuzzy
 msgid ""
 "\n"
 "After entering SPL Controller, press:\n"
@@ -1385,7 +1386,8 @@ msgid ""
 "S: Stop with fade.\n"
 "T: Instant stop.\n"
 "E: Announce if any encoders are being monitored.\n"
-"R: Remainig time for the playing track.\n"
+"I: Announce listener count.\n"
+"R: Remaining time for the playing track.\n"
 "Shift+R: Library scan progress."
 msgstr ""
 "\n"
@@ -1442,6 +1444,11 @@ msgstr ""
 "لا يوجد مسار مشغل في الوقت الراهن. حاول استخدام التوقف المؤقت أثناء تشغيل "
 "أحد المسارات."
 
+#. Translators: Announces number of stream listeners.
+#, fuzzy, python-brace-format
+msgid "Listener count: {listenerCount}"
+msgstr "عدد المستمعين غير موجود"
+
 #. Translators: Presented when no track is playing in Station Playlist Studio.
 msgid "There is no track playing."
 msgstr "لا يوجد مسار مشغل حاليا"

diff --git a/addon/locale/de/LC_MESSAGES/nvda.po 
b/addon/locale/de/LC_MESSAGES/nvda.po
index 81f9ad3..be5b053 100644
--- a/addon/locale/de/LC_MESSAGES/nvda.po
+++ b/addon/locale/de/LC_MESSAGES/nvda.po
@@ -1444,6 +1444,7 @@ msgstr ""
 
 #. Help message for SPL Controller
 #. Translators: the dialog text for SPL Controller help.
+#, fuzzy
 msgid ""
 "\n"
 "After entering SPL Controller, press:\n"
@@ -1459,7 +1460,8 @@ msgid ""
 "S: Stop with fade.\n"
 "T: Instant stop.\n"
 "E: Announce if any encoders are being monitored.\n"
-"R: Remainig time for the playing track.\n"
+"I: Announce listener count.\n"
+"R: Remaining time for the playing track.\n"
 "Shift+R: Library scan progress."
 msgstr ""
 "\n"
@@ -1517,6 +1519,11 @@ msgstr ""
 "Es wird momentan kein Titel Widergegeben. Sie können einen Titel anhalten, "
 "während ein Titel abgespielt wird."
 
+#. Translators: Announces number of stream listeners.
+#, fuzzy, python-brace-format
+msgid "Listener count: {listenerCount}"
+msgstr "Die Anzahl der Zuhörer konnten nicht ermittelt werden."
+
 #. Translators: Presented when no track is playing in Station Playlist Studio.
 msgid "There is no track playing."
 msgstr "Es wird momentan kein Titel wiedergegeben."

diff --git a/addon/locale/es/LC_MESSAGES/nvda.po 
b/addon/locale/es/LC_MESSAGES/nvda.po
index dba920a..69e9e51 100755
--- a/addon/locale/es/LC_MESSAGES/nvda.po
+++ b/addon/locale/es/LC_MESSAGES/nvda.po
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: StationPlaylist 1.1-dev\n"
 "Report-Msgid-Bugs-To: nvda-translations@xxxxxxxxxxxxx\n"
 "POT-Creation-Date: \n"
-"PO-Revision-Date: 2016-05-16 10:25+0100\n"
+"PO-Revision-Date: 2016-06-15 18:43+0100\n"
 "Last-Translator: Juan C. Buño <oprisniki@xxxxxxxxx>\n"
 "Language-Team: Add-ons translation team <LL@xxxxxx>\n"
 "Language: es_ES\n"
@@ -1462,11 +1462,12 @@ msgid ""
 "S: Stop with fade.\n"
 "T: Instant stop.\n"
 "E: Announce if any encoders are being monitored.\n"
-"R: Remainig time for the playing track.\n"
+"I: Announce listener count.\n"
+"R: Remaining time for the playing track.\n"
 "Shift+R: Library scan progress."
 msgstr ""
 "\n"
-"Después de introducir SPL Controller, pulsa:\n"
+"Después de entrar en SPL Controller, pulsa:\n"
 "A: Enciende la automatización.\n"
 "Shift+A: Apaga la automatización.\n"
 "M: Enciende el micrófono.\n"
@@ -1479,6 +1480,7 @@ msgstr ""
 "S: Detener con fade.\n"
 "T: Detener instantáneamente.\n"
 "E: Anuncia si cualquier codificador está siendo monitorizado.\n"
+"I: anuncia el recuento de oyentes.\n"
 "R: Tiempo restante para la pista en reproducción.\n"
 "Shift+R: Progreso del escaneado de la biblioteca."
 
@@ -1520,6 +1522,11 @@ msgstr ""
 "No hay pistas en reproducción. Trata de hacer una pausa mientras se "
 "reproduce una pista."
 
+#. Translators: Announces number of stream listeners.
+#, python-brace-format
+msgid "Listener count: {listenerCount}"
+msgstr "Recuento de oyentes: {listenerCount}"
+
 #. Translators: Presented when no track is playing in Station Playlist Studio.
 msgid "There is no track playing."
 msgstr "No hay pista en reproducción."

diff --git a/addon/locale/fr/LC_MESSAGES/nvda.po 
b/addon/locale/fr/LC_MESSAGES/nvda.po
index 5f7c719..45d0769 100755
--- a/addon/locale/fr/LC_MESSAGES/nvda.po
+++ b/addon/locale/fr/LC_MESSAGES/nvda.po
@@ -1446,6 +1446,7 @@ msgstr ""
 
 #. Help message for SPL Controller
 #. Translators: the dialog text for SPL Controller help.
+#, fuzzy
 msgid ""
 "\n"
 "After entering SPL Controller, press:\n"
@@ -1461,7 +1462,8 @@ msgid ""
 "S: Stop with fade.\n"
 "T: Instant stop.\n"
 "E: Announce if any encoders are being monitored.\n"
-"R: Remainig time for the playing track.\n"
+"I: Announce listener count.\n"
+"R: Remaining time for the playing track.\n"
 "Shift+R: Library scan progress."
 msgstr ""
 "\n"
@@ -1519,6 +1521,11 @@ msgstr ""
 "Il n'y a aucune piste en cours de lecture. Essayez une pause lorsqu'une "
 "piste est jouée."
 
+#. Translators: Announces number of stream listeners.
+#, fuzzy, python-brace-format
+msgid "Listener count: {listenerCount}"
+msgstr "Nombre d'auditeurs introuvable"
+
 #. Translators: Presented when no track is playing in Station Playlist Studio.
 msgid "There is no track playing."
 msgstr "Il n'y a aucune piste en cours de lecture."

diff --git a/addon/locale/gl/LC_MESSAGES/nvda.po 
b/addon/locale/gl/LC_MESSAGES/nvda.po
index 24abe65..f8fdb74 100755
--- a/addon/locale/gl/LC_MESSAGES/nvda.po
+++ b/addon/locale/gl/LC_MESSAGES/nvda.po
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: StationPlaylist 1.1-dev\n"
 "Report-Msgid-Bugs-To: nvda-translations@xxxxxxxxxxxxx\n"
 "POT-Creation-Date: \n"
-"PO-Revision-Date: 2016-05-16 10:28+0100\n"
+"PO-Revision-Date: 2016-06-15 18:46+0100\n"
 "Last-Translator: Juan C. Buño <oprisniki@xxxxxxxxx>\n"
 "Language-Team: Add-ons translation team <oprisniki@xxxxxxxxx>\n"
 "Language: gl\n"
@@ -1452,11 +1452,12 @@ msgid ""
 "S: Stop with fade.\n"
 "T: Instant stop.\n"
 "E: Announce if any encoders are being monitored.\n"
-"R: Remainig time for the playing track.\n"
+"I: Announce listener count.\n"
+"R: Remaining time for the playing track.\n"
 "Shift+R: Library scan progress."
 msgstr ""
 "\n"
-"Despois de introducir SPL Controller, preme:\n"
+"Despois de entrar no SPL Controller, preme:\n"
 "A: Encende a automatización.\n"
 "Shift+A: Apaga a automatización.\n"
 "M: Encende o micrófono.\n"
@@ -1469,6 +1470,7 @@ msgstr ""
 "S: Deter co fade.\n"
 "T: Deter instantáneamente.\n"
 "E: Anuncia se calquera codificador está a ser monitorizado.\n"
+"I: anuncia o reconto de oíntes.\n"
 "R: Tempo restante para a pista en reprodución.\n"
 "Shift+R: Progreso do escaneado da biblioteca."
 
@@ -1510,6 +1512,11 @@ msgstr ""
 "Non hai pistas en reprodución. Tenta facer unha pausa mentras se reproduce "
 "unha pista."
 
+#. Translators: Announces number of stream listeners.
+#, python-brace-format
+msgid "Listener count: {listenerCount}"
+msgstr "Reconto de oíntes: {listenerCount}"
+
 #. Translators: Presented when no track is playing in Station Playlist Studio.
 msgid "There is no track playing."
 msgstr "Non hai pista en reprodución."


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/84d0a5a30e6b/
Changeset:   84d0a5a30e6b
Branch:      None
User:        josephsl
Date:        2016-07-11 00:11:36+00:00
Summary:     Merged stable, version bump

Affected #:  1 file

diff --git a/readme.md b/readme.md
index ddd2748..37282a5 100755
--- a/readme.md
+++ b/readme.md
@@ -188,6 +188,11 @@ Version 8.0 supports SPL Studio 5.10 and later, with 7.x 
designed to provide som
 * 8.0: Added a dialog in add-on settings to configure Columns Explorer slots 
for Track Tool.
 * You can now configure microphone alarm interval from microphone alarm dialog 
(Alt+NvDA+4).
 
+## Changes for 7.3
+
+* Slight performance improvements when looking up information such as 
automation via some SPL Assistant commands.
+* Updated translations.
+
 ## Changes for 7.2
 
 * Due to removal of old-style internal configuration format, it is mandatory 
to install add-on 7.2. Once installed, you cannot go back to an earlier version 
of the add-on.


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/26a97bb48237/
Changeset:   26a97bb48237
Branch:      None
User:        josephsl
Date:        2016-07-11 00:35:05+00:00
Summary:     SPLConfig is now powered by Config Hub.

The new ConfigHub structure, powered by ChaimMap, allows multiple profiles to 
be listed as a list of dictionaries. As this is now a class, it allows runtime 
information to be carried along, including active profile, switch history and 
others.
Specifically:
* Various module-level functions were transfered to the new ConfigHub object, 
including profile fetcher, init code and others.
* InitConfig and SaveConfig now calls object-level functions.
* The ConfigHub constructor now performs both file loading and unlock routines, 
as well as initializing various attributes.
* Profile switching was simplified. Instead of copying data around, it just 
swaps dictionaries around.
* Due to referencing nature of Python, profile cache uses copy.deepcopy.
* ConfigHub also includes profile management features, including dedicated 
methods to create, cache, rename and delete profiles.
For backward compatibility names of functions in the config module will be kept 
until 9.0 (internally they call functions in the ConfigHub object). This is 
destined for add-on 8.0 and later and cannot be backported to LTS.

Affected #:  3 files

diff --git a/addon/appModules/splstudio/chainmap.py 
b/addon/appModules/splstudio/chainmap.py
new file mode 100755
index 0000000..2e28de8
--- /dev/null
+++ b/addon/appModules/splstudio/chainmap.py
@@ -0,0 +1,137 @@
+from collections import MutableMapping
+try:
+    from thread import get_ident
+except ImportError:
+    try:
+        from threading import _get_ident as get_ident
+    except ImportError:
+        from threading import get_ident
+
+def _recursive_repr(fillvalue='...'):
+    'Decorator to make a repr function return fillvalue for a recursive call'
+
+    def decorating_function(user_function):
+        repr_running = set()
+
+        def wrapper(self):
+            key = id(self), get_ident()
+            if key in repr_running:
+                return fillvalue
+            repr_running.add(key)
+            try:
+                result = user_function(self)
+            finally:
+                repr_running.discard(key)
+            return result
+
+        # Can't use functools.wraps() here because of bootstrap issues
+        wrapper.__module__ = getattr(user_function, '__module__')
+        wrapper.__doc__ = getattr(user_function, '__doc__')
+        wrapper.__name__ = getattr(user_function, '__name__')
+        wrapper.__annotations__ = getattr(user_function, '__annotations__', {})
+        return wrapper
+
+    return decorating_function
+
+class ChainMap(MutableMapping):
+    ''' A ChainMap groups multiple dicts (or other mappings) together
+    to create a single, updateable view.
+
+    The underlying mappings are stored in a list.  That list is public and can
+    accessed or updated using the *maps* attribute.  There is no other state.
+
+    Lookups search the underlying mappings successively until a key is found.
+    In contrast, writes, updates, and deletions only operate on the first
+    mapping.
+
+    '''
+
+    def __init__(self, *maps):
+        '''Initialize a ChainMap by setting *maps* to the given mappings.
+        If no mappings are provided, a single empty dictionary is used.
+
+        '''
+        self.maps = list(maps) or [{}]          # always at least one map
+
+    def __missing__(self, key):
+        raise KeyError(key)
+
+    def __getitem__(self, key):
+        for mapping in self.maps:
+            try:
+                return mapping[key]             # can't use 'key in mapping' 
with defaultdict
+            except KeyError:
+                pass
+        return self.__missing__(key)            # support subclasses that 
define __missing__
+
+    def get(self, key, default=None):
+        return self[key] if key in self else default
+
+    def __len__(self):
+        return len(set().union(*self.maps))     # reuses stored hash values if 
possible
+
+    def __iter__(self):
+        return iter(set().union(*self.maps))
+
+    def __contains__(self, key):
+        return any(key in m for m in self.maps)
+
+    def __bool__(self):
+        return any(self.maps)
+
+    @_recursive_repr()
+    def __repr__(self):
+        return '{0.__class__.__name__}({1})'.format(
+            self, ', '.join(map(repr, self.maps)))
+
+    @classmethod
+    def fromkeys(cls, iterable, *args):
+        'Create a ChainMap with a single dict created from the iterable.'
+        return cls(dict.fromkeys(iterable, *args))
+
+    def copy(self):
+        'New ChainMap or subclass with a new copy of maps[0] and refs to 
maps[1:]'
+        return self.__class__(self.maps[0].copy(), *self.maps[1:])
+
+    __copy__ = copy
+
+    def new_child(self, m=None):                # like Django's Context.push()
+        '''
+        New ChainMap with a new map followed by all previous maps. If no
+        map is provided, an empty dict is used.
+        '''
+        if m is None:
+            m = {}
+        return self.__class__(m, *self.maps)
+
+    @property
+    def parents(self):                          # like Django's Context.pop()
+        'New ChainMap from maps[1:].'
+        return self.__class__(*self.maps[1:])
+
+    def __setitem__(self, key, value):
+        self.maps[0][key] = value
+
+    def __delitem__(self, key):
+        try:
+            del self.maps[0][key]
+        except KeyError:
+            raise KeyError('Key not found in the first mapping: 
{0!r}'.format(key))
+
+    def popitem(self):
+        'Remove and return an item pair from maps[0]. Raise KeyError is 
maps[0] is empty.'
+        try:
+            return self.maps[0].popitem()
+        except KeyError:
+            raise KeyError('No keys found in the first mapping.')
+
+    def pop(self, key, *args):
+        'Remove *key* from maps[0] and return its value. Raise KeyError if 
*key* not in maps[0].'
+        try:
+            return self.maps[0].pop(key, *args)
+        except KeyError:
+            raise KeyError('Key not found in the first mapping: 
{0!r}'.format(key))
+
+    def clear(self):
+        'Clear maps[0], leaving maps[1:] intact.'
+        self.maps[0].clear()
\ No newline at end of file

diff --git a/addon/appModules/splstudio/splconfig.py 
b/addon/appModules/splstudio/splconfig.py
index cb3b244..925b407 100755
--- a/addon/appModules/splstudio/splconfig.py
+++ b/addon/appModules/splstudio/splconfig.py
@@ -12,6 +12,7 @@ from validate import Validator
 import time
 import datetime
 import cPickle
+import copy
 import globalVars
 import ui
 import api
@@ -20,6 +21,14 @@ import wx
 import splupdate
 from splmisc import SPLCountdownTimer, _metadataAnnouncer
 
+# Until NVDA Core uses Python 3 (preferably 3.3 or later), use a backported 
version of chain map class.
+# Backported by Jonathan Eunice.
+# Python Package Index: https://pypi.python.org/pypi/chainmap/1.0.2
+try:
+       from collections import ChainMap
+except ImportError:
+       from chainmap import ChainMap
+
 # Configuration management
 SPLIni = os.path.join(globalVars.appArgs.configPath, "splstudio.ini")
 SPLProfiles = os.path.join(globalVars.appArgs.configPath, "addons", 
"stationPlaylist", "profiles")
@@ -71,14 +80,288 @@ Studio500 = boolean(default=true)
 """), encoding="UTF-8", list_values=False)
 confspec7.newlines = "\r\n"
 SPLConfig = None
-# A pool of broadcast profiles.
-SPLConfigPool = []
 # The following settings can be changed in profiles:
 _mutatableSettings7=("IntroOutroAlarms", "MicrophoneAlarm", 
"MetadataStreaming", "ColumnAnnouncement")
 # 7.0: Profile-specific confspec (might be removed once a more optimal way to 
validate sections is found).
 # Dictionary comprehension is better here.
 confspecprofiles = {sect:key for sect, key in confspec7.iteritems() if sect in 
_mutatableSettings7}
 
+# 8.0: Run-time config storage and management will use ConfigHub data 
structure, a subclass of chain map.
+# A chain map allows a dictionary to look up predefined mappings to locate a 
key.
+# When mutating a value, chain map defaults to using the topmost (zeroth) map, 
which isn't desirable if one wishes to use a specific map.
+# This also introduces a problem whereby new key/value pairs are created 
(highly undesirable if global settings are modified via scripts).
+# Therefore the ConfigHub subclass modifies item getter/setter to give 
favorable treatment to the currently active "map" (broadcast profile in use), 
with a flag indicating the name of the currently active map.
+# Using chain map also simplifies profile switching routine, as all that is 
needed is move the active map flag around.
+# Finally, because this is a class, additional methods and properties are 
used, which frees the config dictionary from the burden of carrying global 
flags such as the name of the instant switch profile and others.
+# To preserve backward compatibility with add-on 7.x, module-level functions 
formerly used for profile management will call corresponding methods in 
ConfigHub structure (to be deprecated in 9.0 and will be gone no later than 
10.0).
+
+class ConfigHub(ChainMap):
+       """A hub of broadcast profiles, a subclass of ChainMap.
+       Apart from giving favorable treatments to the active map and adding 
custom methods and properties, this structure is identical to chain map 
structure.
+       """
+
+       def __init__(self):
+               # Create a "fake" map entry, to be replaced by the normal 
profile later.
+               super(ConfigHub, self).__init__()
+               # For presentational purposes.
+               self.profileNames = []
+               # Translators: The name of the default (normal) profile.
+               self.maps[0] = self._unlockConfig(SPLIni, profileName=_("Normal 
profile"), prefill=True, validateNow=True)
+               self.profileNames.append(None) # Signifying normal profile.
+               # Always cache normal profile upon startup.
+               self._cacheConfig(self.maps[0])
+               try:
+                       profiles = filter(lambda fn: os.path.splitext(fn)[-1] 
== ".ini", os.listdir(SPLProfiles))
+                       for profile in profiles:
+                               
self.maps.append(self._unlockConfig(os.path.join(SPLProfiles, profile), 
profileName=os.path.splitext(profile)[0], validateNow=True))
+                               self.profileNames.append(self.maps[-1].name)
+               except WindowsError:
+                       pass
+       # Runtime flags (profiles and profile switching/triggers flags come 
from NVDA Core's ConfigManager).
+               self.profiles = self.maps
+               self.activeProfile = self.profiles[0].name
+               self.instantSwitch = self.profiles[0]["InstantProfile"] if 
"InstantProfile" in self.profiles[0] else None
+               self.timedSwitch = None
+               # Switch history is a stack of previously activated profile(s), 
replacing prev profile flag from 7.x days.
+               # Initially normal profile will sit in here.
+               self.switchHistory = [self.activeProfile]
+               # Record new profiles if any.
+               self.newProfiles = set()
+               # Reset flag (only engaged if reset did happen).
+               self.resetHappened = False
+
+       # Unlock (load) profiles from files.
+       # LTS: Allow new profile settings to be overridden by a parent profile.
+       # 8.0: Don't validate profiles other than normal profile in the 
beginning.
+       def _unlockConfig(self, path, profileName=None, prefill=False, 
parent=None, validateNow=False):
+               # LTS: Suppose this is one of the steps taken when copying 
settings when instantiating a new profile.
+               # If so, go through same procedure as though config passes 
validation tests, as all values from parent are in the right format.
+               if parent is not None:
+                       SPLConfigCheckpoint = ConfigObj(parent, 
encoding="UTF-8")
+                       SPLConfigCheckpoint.filename = path
+                       SPLConfigCheckpoint.name = profileName
+                       return SPLConfigCheckpoint
+               # For the rest.
+               global _configLoadStatus # To be mutated only during unlock 
routine.
+               # Optimization: Profiles other than normal profile contains 
profile-specific sections only.
+               # This speeds up profile loading routine significantly as there 
is no need to call a function to strip global settings.
+               # 7.0: What if profiles have parsing errors?
+               # If so, reset everything back to factory defaults.
+               try:
+                       SPLConfigCheckpoint = ConfigObj(path, configspec = 
confspec7 if prefill else confspecprofiles, encoding="UTF-8")
+               except:
+                       open(path, "w").close()
+                       SPLConfigCheckpoint = ConfigObj(path, configspec = 
confspec7 if prefill else confspecprofiles, encoding="UTF-8")
+                       _configLoadStatus[profileName] = "fileReset"
+               # 5.2 and later: check to make sure all values are correct.
+               # 7.0: Make sure errors are displayed as config keys are now 
sections and may need to go through subkeys.
+               # 8.0: Don't validate unless told to do so.
+               if validateNow:
+                       self._validateConfig(SPLConfigCheckpoint, 
prefill=prefill)
+               # Until it is brought in here...
+               try:
+                       _extraInitSteps(SPLConfigCheckpoint, 
profileName=profileName)
+               except KeyError:
+                       pass
+               SPLConfigCheckpoint.name = profileName
+               return SPLConfigCheckpoint
+
+       # Config validation.
+       # Separated from unlock routine in 8.0.
+       def _validateConfig(self, SPLConfigCheckpoint, prefill=False):
+               global _configLoadStatus
+               configTest = SPLConfigCheckpoint.validate(_val, copy=prefill, 
preserve_errors=True)
+               if configTest != True:
+                       if not configTest:
+                               # Case 1: restore settings to defaults when 5.x 
config validation has failed on all values.
+                               # 6.0: In case this is a user profile, apply 
base configuration.
+                               # 8.0: Call copy profile function directly to 
reduce overhead.
+                               copyProfile(_SPLDefaults7, SPLConfigCheckpoint, 
complete=SPLConfigCheckpoint.filename == SPLIni)
+                               _configLoadStatus[profileName] = "completeReset"
+                       elif isinstance(configTest, dict):
+                               # Case 2: For 5.x and later, attempt to 
reconstruct the failed values.
+                               # 6.0: Cherry-pick global settings only.
+                               # 7.0: Go through failed sections.
+                               for setting in configTest.keys():
+                                       if isinstance(configTest[setting], 
dict):
+                                               for failedKey in 
configTest[setting].keys():
+                                                       # 7.0 optimization: 
just reload from defaults dictionary, as broadcast profiles contain 
profile-specific settings only.
+                                                       
SPLConfigCheckpoint[setting][failedKey] = _SPLDefaults7[setting][failedKey]
+                               # 7.0: Disqualified from being cached this time.
+                               SPLConfigCheckpoint.write()
+                               _configLoadStatus[profileName] = "partialReset"
+
+       # Create profile: public function to access the two private ones above 
(used when creating a new profile).
+       # Mechanics borrowed from NVDA Core's config.conf with modifications 
for this add-on.
+       def createProfile(self, path, profileName=None, parent=None):
+               self.maps.append(self._unlockConfig(path, 
profileName=profileName, parent=parent, validateNow=True))
+               self.profileNames.append(profileName)
+               self.newProfiles.add(profileName)
+
+       # A class version of rename and delete operations.
+       # Mechanics powered by similar routines in NVDA Core's config.conf.
+       def renameProfile(self, oldName, newName):
+               newNamePath = newName + ".ini"
+               newProfile = os.path.join(SPLProfiles, newNamePath)
+               if oldName.lower() != newName.lower() and 
os.path.isfile(newProfile):
+                       raise RuntimeError("New profile path already exists")
+               configPos = self.profileIndexByName(oldName)
+               profilePos = self.profileNames.index(oldName)
+               oldProfile = self.profiles[configPos].filename
+               try:
+                       os.rename(oldProfile, newProfile)
+               except WindowsError:
+                       pass
+               self.profileNames[profilePos] = newName
+               self.profiles[configPos].name = newName
+               self.profiles[configPos].filename = newProfile
+               # Just in case a new profile has been renamed...
+               if oldName in self.newProfiles:
+                       self.newProfiles.discard(oldName)
+                       self.newProfiles.add(newName)
+
+       def deleteProfile(self, name):
+               # Bring normal profile to the front if it isn't.
+               # Optimization: Tell the swapper that we need index to the 
normal profile for this case.
+               configPos = self.swapProfiles(name, _("Normal profile"), 
showSwitchIndex=True) if self.profiles[0].name == name else 
self.profileIndexByName(name)
+               profilePos = self.profileNames.index(name)
+               try:
+                       os.remove(self.profiles[configPos].filename)
+               except WindowsError:
+                       pass
+               del self.profiles[configPos]
+               del self.profileNames[profilePos]
+               self.newProfiles.discard(name)
+
+       def _cacheConfig(self, conf):
+               global _SPLCache
+               if _SPLCache is None: _SPLCache = {}
+               key = None if conf.filename == SPLIni else conf.name
+               _SPLCache[key] = {}
+               # 8.0: Caching the dictionary (items) is enough.
+               # Do not just say dict(conf) because of referencing nature of 
Python, hence perform a deepcopy (copying everything to a new address).
+               _SPLCache[key] = copy.deepcopy(dict(conf))
+
+       def __setitem__(self, key, value):
+               # Give favorable treatment to the currently active map/profile.
+               pos = 0 if key in _mutatableSettings7 else [profile.name for 
profile in self.maps].index(_("Normal profile"))
+               self.maps[pos][key] = value
+
+       def __delitem__(self, key):
+               # Consult profile-specific key first before deleting anything.
+               pos = 0 if key in _mutatableSettings7 else [profile.name for 
profile in self.maps].index(_("Normal Profile"))
+               try:
+                       del self.maps[pos][key]
+               except KeyError:
+                       raise KeyError('Key not found: {0!r}'.format(key))
+
+       def save(self):
+               # Save all config profiles.
+               # 7.0: Save normal profile first.
+               # Temporarily merge normal profile.
+               # 8.0: Locate the index instead.
+               normalProfile = self.profileIndexByName(_("Normal profile"))
+               _preSave(self.profiles[normalProfile])
+               # Disk write optimization check please.
+               # 8.0: Bypass this if profiles were reset.
+               if self.resetHappened or 
shouldSave(self.profiles[normalProfile]):
+                       # 6.1: Transform column inclusion data structure (for 
normal profile) now.
+                       # 7.0: This will be repeated for broadcast profiles 
later.
+                       # 8.0: Conversion will happen here, as conversion to 
list is necessary before writing it to disk (if told to do so).
+                       
self.profiles[normalProfile]["ColumnAnnouncement"]["IncludedColumns"] = 
list(self.profiles[normalProfile]["ColumnAnnouncement"]["IncludedColumns"])
+                       self.profiles[normalProfile].write()
+               del self.profiles[normalProfile]
+               # Now save broadcast profiles.
+               for configuration in self.profiles:
+                       if configuration is not None:
+                               # 7.0: See if profiles themselves must be saved.
+                               # This must be done now, otherwise changes to 
broadcast profiles (cached) will not be saved as presave removes them.
+                               # 8.0: Bypass cache check routine if this is a 
new profile or if reset happened.
+                               # Takes advantage of the fact that Python's 
"or" operator evaluates from left to right, considerably saving time.
+                               if self.resetHappened or configuration.name in 
self.newProfiles or (configuration.name in _SPLCache and 
shouldSave(configuration)):
+                                       
configuration["ColumnAnnouncement"]["IncludedColumns"] = 
list(configuration["ColumnAnnouncement"]["IncludedColumns"])
+                                       _preSave(configuration)
+                                       configuration.write()
+               self.newProfiles.clear()
+               self.activeProfile = None
+               self.profileHistory = None
+
+                       # Class version of module-level functions.
+
+       # Reset config.
+       # Profile indicates the name of the profile to be reset.
+       def reset(self, profile=None):
+               profilePool = [] if profile is not None else self.profiles
+               if profile is not None:
+                       if not self.profileExists(profile):
+                               raise ValueError("The specified profile does 
not exist")
+                       else: profilePool.append(self.profileByName(profile))
+               for conf in profilePool:
+                       # Retrieve the profile path, as ConfigObj.reset 
nullifies it.
+                       profilePath = conf.filename
+                       conf.reset()
+                       conf.filename = profilePath
+                       resetConfig(_SPLDefaults7, conf)
+                       # Convert certain settings to a different format.
+                       conf["ColumnAnnouncement"]["IncludedColumns"] = 
set(_SPLDefaults7["ColumnAnnouncement"]["IncludedColumns"])
+               # Switch back to normal profile via a custom variant of swap 
routine.
+               if self.profiles[0].name != _("Normal profile"):
+                       npIndex = self.profileIndexByName(_("Normal profile"))
+                       self.profiles[0], self.profiles[npIndex] = 
self.profiles[npIndex], self.profiles[0]
+                       self.activeProfile = _("Normal profile")
+               # 8.0 optimization: Tell other modules that reset was done in 
order to postpone disk writes until the end.
+               self.resetHappened = True
+
+       def profileIndexByName(self, name):
+               # 8.0 optimization: Only traverse the profiles list if head 
(active profile) or tail does not yield profile name in question.
+               if name == self.profiles[0].name:
+                       return 0
+               elif name == self.profiles[-1].name:
+                       return -1
+               try:
+                       return [profile.name for profile in 
self.profiles].index(name)
+               except ValueError:
+                       raise ValueError("The specified profile does not exist")
+
+       def profileByName(self, name):
+               return self.profiles[self.profileIndexByName(name)]
+
+       # Switch between profiles.
+       # This involves promoting and demoting normal profile.
+       def switchProfile(self, prevProfile, newProfile):
+               from splconfui import _configDialogOpened
+               if _configDialogOpened:
+                       # Translators: Presented when trying to switch to an 
instant switch profile when add-on settings dialog is active.
+                       ui.message(_("Add-on settings dialog is open, cannot 
switch profiles"))
+                       return
+               self.swapProfiles(prevProfile, newProfile)
+               if prevProfile is not None:
+                       self.switchHistory.append(newProfile)
+                       # Translators: Presented when switch to instant switch 
profile was successful.
+                       ui.message(_("Switching to 
{newProfileName}").format(newProfileName = self.activeProfile))
+                       # Pause automatic update checking.
+                       if self["Update"]["AutoUpdateCheck"]:
+                               if splupdate._SPLUpdateT is not None and 
splupdate._SPLUpdateT.IsRunning: splupdate._SPLUpdateT.Stop()
+               else:
+                       self.switchHistory.pop()
+                       # Translators: Presented when switching from instant 
switch profile to a previous profile.
+                       ui.message(_("Returning to 
{previousProfile}").format(previousProfile = self.activeProfile))
+                       # Resume auto update checker if told to do so.
+                       if self["Update"]["AutoUpdateCheck"]: updateInit()
+               # Use the module-level metadata reminder method if told to do 
so now.
+               if self["General"]["MetadataReminder"] in ("startup", 
"instant"):
+                       _metadataAnnouncer(reminder=True)
+
+       # Used from config dialog and other places.
+       # Show switch index is used when deleting profiles so it doesn't have 
to look up index for old profiles.
+       def swapProfiles(self, prevProfile, newProfile, showSwitchIndex=False):
+               former, current = self.profileIndexByName(prevProfile if 
prevProfile is not None else self.switchHistory[-1]), 
self.profileIndexByName(newProfile)
+               self.profiles[current], self.profiles[former] = 
self.profiles[former], self.profiles[current]
+               self.activeProfile = newProfile
+               if showSwitchIndex: return current
+
+
+
 # Default config spec container.
 # To be moved to a different place in 8.0.
 _SPLDefaults7 = ConfigObj(None, configspec = confspec7, encoding="UTF-8")
@@ -89,27 +372,17 @@ _SPLDefaults7.validate(_val, copy=True)
 def runConfigErrorDialog(errorText, errorType):
        wx.CallAfter(gui.messageBox, errorText, errorType, wx.OK|wx.ICON_ERROR)
 
+# For following functions, "Ex" indicates "extended".
+
 # Reset settings to defaults.
 # This will be called when validation fails or when the user asks for it.
 # 6.0: The below function resets a single profile. A sister function will 
reset all of them.
 # 7.0: This calls copy profile function with default dictionary as the source 
profile.
+# 8.0: ConfigHub's reset function will be invoked.
 def resetConfig(defaults, activeConfig):
        # The only time everything should be copied is when resetting normal 
profile.
        copyProfile(defaults, activeConfig, complete=activeConfig.filename == 
SPLIni)
 
-# Reset all profiles upon request.
-def resetAllConfig():
-       for profile in SPLConfigPool:
-               # Retrieve the profile path, as ConfigObj.reset nullifies it.
-               profilePath = profile.filename
-               profile.reset()
-               profile.filename = profilePath
-               # 7.0: Without writing the profile, we end up with 
inconsistencies between profile cache and actual profile.
-               profile.write()
-               resetConfig(_SPLDefaults7, profile)
-               # Convert certain settings to a different format.
-               profile["ColumnAnnouncement"]["IncludedColumns"] = 
set(_SPLDefaults7["ColumnAnnouncement"]["IncludedColumns"])
-
 # In case one or more profiles had config issues, look up the error message 
from the following map.
 _configErrors ={
        "fileReset":"Settings reset to defaults due to configuration file 
coruption",
@@ -130,35 +403,23 @@ trackComments = {}
 
 def initConfig():
        # Load the default config from a list of profiles.
-       global SPLConfig, SPLConfigPool, _configLoadStatus, SPLActiveProfile, 
SPLSwitchProfile, trackComments
-       if SPLConfigPool is None: SPLConfigPool = []
-       # Translators: The name of the default (normal) profile.
-       if SPLActiveProfile is None: SPLActiveProfile = _("Normal profile")
-       SPLConfigPool.append(unlockConfig(SPLIni, profileName=SPLActiveProfile, 
prefill=True))
-       try:
-               profiles = filter(lambda fn: os.path.splitext(fn)[-1] == 
".ini", os.listdir(SPLProfiles))
-               for profile in profiles:
-                       
SPLConfigPool.append(unlockConfig(os.path.join(SPLProfiles, profile), 
profileName=os.path.splitext(profile)[0]))
-       except WindowsError:
-               pass
+       # 8.0: All this work will be performed when ConfigHub loads.
+       global SPLConfig, _configLoadStatus, SPLSwitchProfile, trackComments
        # 7.0: Store the config as a dictionary.
        # This opens up many possibilities, including config caching, loading 
specific sections only and others (the latter saves memory).
-       SPLConfig = dict(SPLConfigPool[0])
-       # 7.0 optimization: Store an online backup.
-       # This online backup is used to prolong SSD life (no need to save a 
config if it is same as this copy).
-       # 8.0: Only cache the normal profile for now, which results in space 
savings and allows the app module to load faster.
-       _cacheConfig(SPLConfigPool[0])
-       SPLConfig["ActiveIndex"] = 0 # Holds settings from normal profile.
+       # 8.0: To be replaced by ConfigHub object.
+       t = time.time()
+       SPLConfig = ConfigHub()
+       print time.time()-t
        # Locate instant profile.
-       if "InstantProfile" in SPLConfig:
+       if SPLConfig.instantSwitch is not None:
                try:
-                       SPLSwitchProfile = 
SPLConfigPool[getProfileIndexByName(SPLConfig["InstantProfile"])].name
+                       SPLSwitchProfile = SPLConfig.instantSwitch
                except ValueError:
-                       _configLoadStatus[SPLConfigPool[0].name] = 
"noInstantProfile"
-               # 7.1: The config module knows the fate of the instant profile.
-               del SPLConfig["InstantProfile"]
+                       _configLoadStatus[SPLConfig.activeProfile] = 
"noInstantProfile"
        # LTS: Load track comments if they exist.
        # This must be a separate file (another pickle file).
+       # 8.0: Do this much later when a track is first focused.
        try:
                trackComments = 
cPickle.load(file(os.path.join(globalVars.appArgs.configPath, 
"spltrackcomments.pickle"), "r"))
        except IOError:
@@ -168,10 +429,10 @@ def initConfig():
                title = _("Studio add-on Configuration error")
                messages = []
                # 6.1: Display just the error message if the only corrupt 
profile is the normal profile.
-               if len(_configLoadStatus) == 1 and SPLActiveProfile in 
_configLoadStatus:
+               if len(_configLoadStatus) == 1 and SPLConfig.activeProfile in 
_configLoadStatus:
                        # Translators: Error message shown when add-on 
configuration had issues.
                        messages.append("Your add-on configuration had 
following issues:\n\n")
-                       
messages.append(_configErrors[_configLoadStatus[SPLActiveProfile]])
+                       
messages.append(_configErrors[_configLoadStatus[SPLConfig.activeProfile]])
                else:
                        # Translators: Error message shown when add-on 
configuration had issues.
                        messages.append("One or more broadcast profiles had 
issues:\n\n")
@@ -194,56 +455,6 @@ def initConfig():
                # Translators: Title of the encoder settings error dialog.
                _("Encoder settings error"))
 
-# A set of new profiles to avoid this flag being recorded inside the cache.
-SPLNewProfiles = set()
-
-# Unlock (load) profiles from files.
-# LTS: Allow new profile settings to be overridden by a parent profile.
-def unlockConfig(path, profileName=None, prefill=False, parent=None):
-       # LTS: Suppose this is one of the steps taken when copying settings 
when instantiating a new profile.
-       # If so, go through same procedure as though config passes validation 
tests, as all values from parent are in the right format.
-       if parent is not None:
-               SPLConfigCheckpoint = ConfigObj(parent, encoding="UTF-8")
-               SPLConfigCheckpoint.filename = path
-               SPLConfigCheckpoint.name = profileName
-               return SPLConfigCheckpoint
-       # For the rest.
-       global _configLoadStatus # To be mutated only during unlock routine.
-       # Optimization: Profiles other than normal profile contains 
profile-specific sections only.
-       # This speeds up profile loading routine significantly as there is no 
need to call a function to strip global settings.
-       # 7.0: What if profiles have parsing errors?
-       # If so, reset everything back to factory defaults.
-       try:
-               SPLConfigCheckpoint = ConfigObj(path, configspec = confspec7 if 
prefill else confspecprofiles, encoding="UTF-8")
-       except:
-               open(path, "w").close()
-               SPLConfigCheckpoint = ConfigObj(path, configspec = confspec7 if 
prefill else confspecprofiles, encoding="UTF-8")
-               _configLoadStatus[profileName] = "fileReset"
-       # 5.2 and later: check to make sure all values are correct.
-       # 7.0: Make sure errors are displayed as config keys are now sections 
and may need to go through subkeys.
-       configTest = SPLConfigCheckpoint.validate(_val, copy=prefill, 
preserve_errors=True)
-       if configTest != True:
-               if not configTest:
-                       # Case 1: restore settings to defaults when 5.x config 
validation has failed on all values.
-                       # 6.0: In case this is a user profile, apply base 
configuration.
-                       resetConfig(_SPLDefaults7, SPLConfigCheckpoint)
-                       _configLoadStatus[profileName] = "completeReset"
-               elif isinstance(configTest, dict):
-                       # Case 2: For 5.x and later, attempt to reconstruct the 
failed values.
-                       # 6.0: Cherry-pick global settings only.
-                       # 7.0: Go through failed sections.
-                       for setting in configTest.keys():
-                               if isinstance(configTest[setting], dict):
-                                       for failedKey in 
configTest[setting].keys():
-                                               # 7.0 optimization: just reload 
from defaults dictionary, as broadcast profiles contain profile-specific 
settings only.
-                                               
SPLConfigCheckpoint[setting][failedKey] = _SPLDefaults7[setting][failedKey]
-                       # 7.0: Disqualified from being cached this time.
-                       SPLConfigCheckpoint.write()
-                       _configLoadStatus[profileName] = "partialReset"
-       _extraInitSteps(SPLConfigCheckpoint, profileName=profileName)
-       SPLConfigCheckpoint.name = profileName
-       return SPLConfigCheckpoint
-
 # Extra initialization steps such as converting value types.
 def _extraInitSteps(conf, profileName=None):
        global _configLoadStatus
@@ -277,12 +488,7 @@ def _extraInitSteps(conf, profileName=None):
 _SPLCache = {}
 
 def _cacheConfig(conf):
-       global _SPLCache
-       if _SPLCache is None: _SPLCache = {}
-       key = None if conf.filename == SPLIni else conf.name
-       _SPLCache[key] = {}
-       # 8.0: Caching the dictionary (items) is enough.
-       _SPLCache[key] = dict(conf)
+       SPLConfig._cacheConfig(conf)
 
 # Record profile triggers.
 # Each record (profile name) consists of seven fields organized as a list:
@@ -433,54 +639,35 @@ def saveProfileTriggers():
 
 # Instant profile switch helpers.
 # A number of helper functions assisting instant switch profile routine and 
others, including sorting and locating the needed profile upon request.
+# 8.0: These will become attributes of ConfigHub.
+# LTS: Kept for backward compatibility.
 
 # Fetch the profile index with a given name.
 def getProfileIndexByName(name):
        try:
-               return [profile.name for profile in SPLConfigPool].index(name)
+               return SPLConfig.profileIndexByName(name)
        except ValueError:
                raise ValueError("The specified profile does not exist")
 
 # And:
+
 def getProfileByName(name):
-       return SPLConfigPool[getProfileIndexByName(name)]
+       return SPLConfig.profileByName(name)
 
 # Copy settings across profiles.
 # Setting complete flag controls whether profile-specific settings are applied 
(true otherwise, only set when resetting profiles).
+# 8.0: Simplified thanks to in-place swapping.
 def copyProfile(sourceProfile, targetProfile, complete=False):
        for section in sourceProfile.keys() if complete else 
_mutatableSettings7:
                targetProfile[section] = dict(sourceProfile[section])
 
-# Merge sections when switching profiles.
-# This is also employed by the routine which saves changes to a profile when 
user selects a different profile from add-on settings dialog.
-# Profiles refer to indecies.
-# Active refers to whether this is a runtime switch (false if saving profiles).
-def mergeSections(profile, active=True):
-       global SPLConfig, SPLConfigPool
-       copyProfile(SPLConfigPool[profile], SPLConfig)
-       if active: SPLConfig["ActiveIndex"] = profile
-
-# A reverse of the above.
-def applySections(profile, key=None):
-       global SPLConfig, SPLConfigPool
-       if key is None:
-               copyProfile(SPLConfig, SPLConfigPool[profile])
-       else:
-               # A slash (/) will denote section/key hierarchy.
-               tree, leaf = key.split("/")
-               if tree in SPLConfig:
-                       if leaf == "": # Section only.
-                               SPLConfigPool[profile][tree] = 
dict(SPLConfig[tree])
-                       else:
-                               SPLConfigPool[profile][tree][leaf] = 
SPLConfig[tree][leaf]
-
 # Last but not least...
 # Module level version of get profile flags function.
 # Optional keyword arguments are to be added when called from dialogs such as 
add-on settings.
 # A crucial kwarg is contained, and if so, profile flags set will be returned.
 def getProfileFlags(name, active=None, instant=None, triggers=None, 
contained=False):
        flags = set()
-       if active is None: active = SPLActiveProfile
+       if active is None: active = SPLConfig.activeProfile
        if instant is None: instant = SPLSwitchProfile
        if triggers is None: triggers = profileTriggers
        if name == active:
@@ -496,16 +683,6 @@ def getProfileFlags(name, active=None, instant=None, 
triggers=None, contained=Fa
                return name if len(flags) == 0 else "{0} <{1}>".format(name, ", 
".join(flags))
        else: return flags
 
-# Is the config pool itself sorted?
-# This check is performed when displaying broadcast profiles.
-def isConfigPoolSorted():
-               profileNames = [profile.name for profile in SPLConfigPool][1:]
-               for pos in xrange(len(profileNames)-1):
-                       if profileNames[pos] > profileNames[pos+1]:
-                               return False
-               return True
-
-
 # Perform some extra work before writing the config file.
 def _preSave(conf):
        # Perform global setting processing only for the normal profile.
@@ -547,8 +724,7 @@ def shouldSave(profile):
 
 # Save configuration database.
 def saveConfig():
-       # Save all config profiles.
-       global SPLConfig, SPLConfigPool, SPLActiveProfile, SPLPrevProfile, 
SPLSwitchProfile, _SPLCache, SPLNewProfiles
+       global SPLConfig, _SPLCache
        # 7.0: Turn off auto update check timer.
        if splupdate._SPLUpdateT is not None and 
splupdate._SPLUpdateT.IsRunning(): splupdate._SPLUpdateT.Stop()
        splupdate._SPLUpdateT = None
@@ -558,104 +734,56 @@ def saveConfig():
        cPickle.dump(trackComments, 
file(os.path.join(globalVars.appArgs.configPath, "spltrackcomments.pickle"), 
"wb"))
        # Save update check state.
        splupdate.terminate()
-       # Save profile-specific settings to appropriate dictionary if this is 
the case.
-       activeIndex = SPLConfig["ActiveIndex"]
-       del SPLConfig["ActiveIndex"]
-       if activeIndex > 0:
-               applySections(activeIndex)
-       # 7.0: Save normal profile first.
-       # Temporarily merge normal profile.
-       mergeSections(0)
-       _preSave(SPLConfigPool[0])
-       # Disk write optimization check please.
-       if shouldSave(SPLConfigPool[0]):
-               # 6.1: Transform column inclusion data structure (for normal 
profile) now.
-               # 7.0: This will be repeated for broadcast profiles later.
-               # 8.0: Conversion will happen here, as conversion to list is 
necessary before writing it to disk (if told to do so).
-               SPLConfigPool[0]["ColumnAnnouncement"]["IncludedColumns"] = 
list(SPLConfigPool[0]["ColumnAnnouncement"]["IncludedColumns"])
-               SPLConfigPool[0].write()
-       del SPLConfigPool[0]
-       # Now save broadcast profiles.
-       for configuration in SPLConfigPool:
-               if configuration is not None:
-                       # 7.0: See if profiles themselves must be saved.
-                       # This must be done now, otherwise changes to broadcast 
profiles (cached) will not be saved as presave removes them.
-                       # 8.0: Bypass cache check routine if this is a new 
profile.
-                       # Takes advantage of the fact that Python's "or" 
operator evaluates from left to right, considerably saving time.
-                       if configuration.name in SPLNewProfiles or 
(configuration.name in _SPLCache and shouldSave(configuration)):
-                               
configuration["ColumnAnnouncement"]["IncludedColumns"] = 
list(configuration["ColumnAnnouncement"]["IncludedColumns"])
-                               _preSave(configuration)
-                               configuration.write()
-       SPLConfig.clear()
+       # Now save profiles.
+       # 8.0: Call the save method.
+       SPLConfig.save()
        SPLConfig = None
-       SPLConfigPool = None
-       SPLNewProfiles.clear()
-       SPLActiveProfile = None
-       SPLPrevProfile = None
-       SPLSwitchProfile = None
        _SPLCache.clear()
        _SPLCache = None
 
 
 # Switch between profiles.
-SPLActiveProfile = None
 SPLPrevProfile = None
 SPLSwitchProfile = None
 SPLTriggerProfile = None
 
 # A general-purpose profile switcher.
 # Allows the add-on to switch between profiles as a result of manual 
intervention or through profile trigger timer.
+# Profiles refer to profile names.
 # Instant profile switching is just a special case of this function.
 def switchProfile(prevProfile, newProfile):
-       global SPLConfig, SPLActiveProfile, SPLPrevProfile, _SPLCache
+       global SPLPrevProfile, _SPLCache
        from splconfui import _configDialogOpened
        if _configDialogOpened:
                # Translators: Presented when trying to switch to an instant 
switch profile when add-on settings dialog is active.
                ui.message(_("Add-on settings dialog is open, cannot switch 
profiles"))
                return
-       mergeSections(newProfile)
-       SPLActiveProfile = SPLConfigPool[newProfile].name
-       # 8.0: Cache other profiles this time.
-       if newProfile != 0 and SPLActiveProfile not in _SPLCache:
-               _cacheConfig(SPLConfigPool[newProfile])
-       SPLConfig["ActiveIndex"] = newProfile
-       if prevProfile is not None:
-               # Translators: Presented when switch to instant switch profile 
was successful.
-               ui.message(_("Switching to 
{newProfileName}").format(newProfileName = SPLActiveProfile))
-               # Pause automatic update checking.
-               if SPLConfig["Update"]["AutoUpdateCheck"]:
-                       if splupdate._SPLUpdateT is not None and 
splupdate._SPLUpdateT.IsRunning: splupdate._SPLUpdateT.Stop()
-       else:
-               # Translators: Presented when switching from instant switch 
profile to a previous profile.
-               ui.message(_("Returning to 
{previousProfile}").format(previousProfile = SPLActiveProfile))
-               # Resume auto update checker if told to do so.
-               if SPLConfig["Update"]["AutoUpdateCheck"]: updateInit()
+       SPLConfig.switchProfile(prevProfile, newProfile)
        SPLPrevProfile = prevProfile
-       # Use the module-level metadata reminder method if told to do so now.
-       if SPLConfig["General"]["MetadataReminder"] in ("startup", "instant"):
-               _metadataAnnouncer(reminder=True)
+       # 8.0: Cache other profiles this time.
+       if newProfile != _("Normal profile") and newProfile not in _SPLCache:
+               _cacheConfig(getProfileByName(selectedProfile))
 
 # Called from within the app module.
 def instantProfileSwitch():
-       global SPLConfig, SPLActiveProfile
        if SPLSwitchProfile is None:
                # Translators: Presented when trying to switch to an instant 
switch profile when the instant switch profile is not defined.
                ui.message(_("No instant switch profile is defined"))
        else:
                if SPLPrevProfile is None:
-                       if SPLActiveProfile == SPLSwitchProfile:
+                       if SPLConfig.activeProfile == SPLSwitchProfile:
                                # Translators: Presented when trying to switch 
to an instant switch profile when one is already using the instant switch 
profile.
                                ui.message(_("You are already in the instant 
switch profile"))
                                return
                        # Switch to the given profile.
-                       switchProfileIndex = 
getProfileIndexByName(SPLSwitchProfile)
                        # 6.1: Do to referencing nature of Python, use the 
profile index function to locate the index for the soon to be deactivated 
profile.
                        # 7.0: Store the profile name instead in order to 
prevent profile index mangling if profiles are deleted.
                        # Pass in the prev profile, which will be None for 
instant profile switch.
                        # 7.0: Now activate "activeProfile" argument which 
controls the behavior of the function below.
-                       switchProfile(SPLActiveProfile, switchProfileIndex)
+                       # 8.0: Work directly with profile names.
+                       switchProfile(SPLConfig.activeProfile, SPLSwitchProfile)
                else:
-                       switchProfile(None, 
getProfileIndexByName(SPLPrevProfile))
+                       switchProfile(None, SPLPrevProfile)
 
 # The triggers version of the above function.
 _SPLTriggerEndTimer = None
@@ -667,14 +795,11 @@ def triggerProfileSwitch():
        if SPLTriggerProfile is None and _triggerProfileActive:
                raise RuntimeError("Trigger profile flag cannot be active when 
the trigger profile itself isn't defined")
        if SPLPrevProfile is None:
-               if SPLActiveProfile == SPLTriggerProfile:
+               if SPLConfig.activeProfile == SPLTriggerProfile:
                        # Translators: Presented when trying to switch to an 
instant switch profile when one is already using the instant switch profile.
                        ui.message(_("A profile trigger is already active"))
                        return
-               # Switch to the given profile.
-               triggerProfileIndex = getProfileIndexByName(SPLTriggerProfile)
-               # Pass in the prev profile, which will be None for instant 
profile switch.
-               switchProfile(SPLActiveProfile, triggerProfileIndex)
+               switchProfile(SPLConfig.activeProfile, SPLTriggerProfile)
                # Set the global trigger flag to inform various subsystems such 
as add-on settings dialog.
                _triggerProfileActive = True
                # Set the next trigger date and time.
@@ -686,7 +811,7 @@ def triggerProfileSwitch():
                        _SPLTriggerEndTimer = wx.PyTimer(triggerProfileSwitch)
                        _SPLTriggerEndTimer.Start(triggerSettings[6] * 60 * 
1000, True)
        else:
-               switchProfile(None, getProfileIndexByName(SPLPrevProfile))
+               switchProfile(None, SPLPrevProfile)
                _triggerProfileActive = False
                # Stop the ending timer.
                if _SPLTriggerEndTimer is not None and 
_SPLTriggerEndTimer.IsRunning():

diff --git a/addon/appModules/splstudio/splconfui.py 
b/addon/appModules/splstudio/splconfui.py
index dca069a..f9b307b 100755
--- a/addon/appModules/splstudio/splconfui.py
+++ b/addon/appModules/splstudio/splconfui.py
@@ -32,19 +32,14 @@ class SPLConfigDialog(gui.SettingsDialog):
                sizer = wx.BoxSizer(wx.HORIZONTAL)
                # Translators: The label for a setting in SPL add-on dialog to 
select a broadcast profile.
                label = wx.StaticText(self, wx.ID_ANY, label=_("Broadcast 
&profile:"))
-               # Sort profiles for display purposes (the config pool might not 
be sorted).
-               sortedProfiles = [profile.name for profile in 
splconfig.SPLConfigPool]
-               # No need to sort if the only living profile is the normal 
configuration or there is one other profile besides this.
-               # Optimization: Only sort if config pool itself isn't  - 
usually after creating, renaming or deleting profile(s).
-               if len(sortedProfiles) > 2 and not 
splconfig.isConfigPoolSorted():
-                       firstProfile = splconfig.SPLConfigPool[0].name
-                       sortedProfiles = [firstProfile] + 
sorted(sortedProfiles[1:])
                # 7.0: Have a copy of the sorted profiles so the actual combo 
box items can show profile flags.
-               self.profileNames = list(sortedProfiles)
-               self.profiles = wx.Choice(self, wx.ID_ANY, 
choices=self.displayProfiles(sortedProfiles))
+               # 8.0: No need to sort as profile names from ConfigHub knows 
what to do.
+               self.profileNames = list(splconfig.SPLConfig.profileNames)
+               self.profileNames[0] = _("Normal profile")
+               self.profiles = wx.Choice(self, wx.ID_ANY, 
choices=self.displayProfiles(list(self.profileNames)))
                self.profiles.Bind(wx.EVT_CHOICE, self.onProfileSelection)
                try:
-                       
self.profiles.SetSelection(self.profileNames.index(splconfig.SPLActiveProfile))
+                       
self.profiles.SetSelection(self.profileNames.index(splconfig.SPLConfig.activeProfile))
                except:
                        pass
                sizer.Add(label)
@@ -77,7 +72,7 @@ class SPLConfigDialog(gui.SettingsDialog):
                sizer.Add(item)
 
                self.switchProfile = splconfig.SPLSwitchProfile
-               self.activeProfile = splconfig.SPLActiveProfile
+               self.activeProfile = splconfig.SPLConfig.activeProfile
                # Used as sanity check in case switch profile is renamed or 
deleted.
                self.switchProfileRenamed = False
                self.switchProfileDeleted = False
@@ -88,7 +83,7 @@ class SPLConfigDialog(gui.SettingsDialog):
                
self.triggerThreshold.SetValue(long(splconfig.SPLConfig["Advanced"]["ProfileTriggerThreshold"]))
                self.triggerThreshold.SetSelection(-1, -1)
                sizer.Add(self.triggerThreshold)
-               if splconfig.SPLConfig["ActiveIndex"] == 0:
+               if self.profiles.GetSelection() == 0:
                        self.renameButton.Disable()
                        self.deleteButton.Disable()
                        self.triggerButton.Disable()
@@ -358,7 +353,8 @@ class SPLConfigDialog(gui.SettingsDialog):
        def onOk(self, evt):
                global _configDialogOpened
                selectedProfile = self.profiles.GetStringSelection().split(" 
<")[0]
-               profileIndex = splconfig.getProfileIndexByName(selectedProfile)
+               if splconfig.SPLConfig.activeProfile != selectedProfile:
+                       
splconfig.SPLConfig.swapProfiles(splconfig.SPLConfig.activeProfile, 
selectedProfile)
                splconfig.SPLConfig["General"]["BeepAnnounce"] = 
self.beepAnnounceCheckbox.Value
                splconfig.SPLConfig["General"]["MessageVerbosity"] = 
self.verbosityLevels[self.verbosityList.GetSelection()][0]
                splconfig.SPLConfig["IntroOutroAlarms"]["SayEndOfTrack"] = 
self.outroCheckBox.Value
@@ -389,10 +385,6 @@ class SPLConfigDialog(gui.SettingsDialog):
                splconfig.SPLConfig["Advanced"]["SPLConPassthrough"] = 
self.splConPassthrough
                splconfig.SPLConfig["Advanced"]["CompatibilityLayer"] = 
self.compLayer
                splconfig.SPLConfig["Update"]["AutoUpdateCheck"] = 
self.autoUpdateCheck
-               splconfig.SPLConfig["ActiveIndex"] = profileIndex
-               # Reverse of merge: save profile specific sections to 
individual config dictionaries.
-               splconfig.applySections(profileIndex)
-               splconfig.SPLActiveProfile = selectedProfile
                splconfig.SPLSwitchProfile = self.switchProfile
                # Make sure to nullify prev profile if instant switch profile 
is gone.
                # 7.0: Don't do the following in the midst of a broadcast.
@@ -406,9 +398,9 @@ class SPLConfigDialog(gui.SettingsDialog):
                self._profileTriggersConfig.clear()
                self._profileTriggersConfig = None
                splconfig.triggerStart(restart=True)
-               # 8.0: Make sure NVDA knows this must be cached.
-               if profileIndex != 0 and selectedProfile not in 
splconfig._SPLCache:
-                       
splconfig._cacheConfig(splconfig.SPLConfigPool[profileIndex])
+               # 8.0: Make sure NVDA knows this must be cached (except for 
normal profile).
+               if selectedProfile != _("Normal profile") and selectedProfile 
not in splconfig._SPLCache:
+                       
splconfig._cacheConfig(splconfig.getProfileByName(selectedProfile))
                super(SPLConfigDialog,  self).onOk(evt)
 
        def onCancel(self, evt):
@@ -423,14 +415,13 @@ class SPLConfigDialog(gui.SettingsDialog):
                splconfig.triggerStart(restart=True)
                # 7.0: No matter what happens, merge appropriate profile.
                try:
-                       prevActive = self.profileNames.index(self.activeProfile)
+                       prevActive = self.activeProfile
                except ValueError:
-                       prevActive = 0
-               splconfig.mergeSections(prevActive)
+                       prevActive = _("Normal profile")
                if self.switchProfileRenamed or self.switchProfileDeleted:
                        splconfig.SPLSwitchProfile = self.switchProfile
                if self.switchProfileDeleted:
-                       splconfig.SPLActiveProfile = 
splconfig.SPLConfigPool[prevActive].name
+                       splconfig.SPLConfig.activeProfile = prevActive
                _configDialogOpened = False
                super(SPLConfigDialog,  self).onCancel(evt)
 
@@ -523,7 +514,6 @@ class SPLConfigDialog(gui.SettingsDialog):
                state = oldDisplayName.split(" <")
                oldName = state[0]
                index = self.profiles.Selection
-               configPos = splconfig.getProfileIndexByName(oldName)
                profilePos = self.profileNames.index(oldName)
                # Translators: The label of a field to enter a new name for a 
broadcast profile.
                with wx.TextEntryDialog(self, _("New name:"),
@@ -533,20 +523,14 @@ class SPLConfigDialog(gui.SettingsDialog):
                                return
                        newName = api.filterFileName(d.Value)
                if oldName == newName: return
-               newNamePath = newName + ".ini"
-               newProfile = os.path.join(SPLProfiles, newNamePath)
-               if oldName.lower() != newName.lower() and 
os.path.isfile(newProfile):
+               try:
+                       splconfig.SPLConfig.renameProfile(oldName, newName)
+               except RuntimeError:
                        # Translators: An error displayed when renaming a 
configuration profile
                        # and a profile with the new name already exists.
                        gui.messageBox(_("That profile already exists. Please 
choose a different name."),
                                _("Error"), wx.OK | wx.ICON_ERROR, self)
                        return
-               oldNamePath = oldName + ".ini"
-               oldProfile = os.path.join(SPLProfiles, oldNamePath)
-               try:
-                       os.rename(oldProfile, newProfile)
-               except WindowsError:
-                       pass
                if self.switchProfile == oldName:
                        self.switchProfile = newName
                        self.switchProfileRenamed = True
@@ -557,15 +541,9 @@ class SPLConfigDialog(gui.SettingsDialog):
                if self.activeProfile == oldName:
                        self.activeProfile = newName
                self.profileNames[profilePos] = newName
-               splconfig.SPLConfigPool[configPos].name = newName
-               splconfig.SPLConfigPool[configPos].filename = newProfile
                if oldName in splconfig._SPLCache:
                        splconfig._SPLCache[newName] = 
splconfig._SPLCache[oldName]
                        del splconfig._SPLCache[oldName]
-               # Just in case a new profile has been renamed...
-               if oldName in splconfig.SPLNewProfiles:
-                       splconfig.SPLNewProfiles.discard(oldName)
-                       splconfig.SPLNewProfiles.add(newName)
                if len(state) > 1: newName = " <".join([newName, state[1]])
                self.profiles.SetString(index, newName)
                self.profiles.Selection = index
@@ -584,7 +562,6 @@ class SPLConfigDialog(gui.SettingsDialog):
                        return
                index = self.profiles.Selection
                name = self.profiles.GetStringSelection().split(" <")[0]
-               configPos = splconfig.getProfileIndexByName(name)
                profilePos = self.profileNames.index(name)
                if gui.messageBox(
                        # Translators: The confirmation prompt displayed when 
the user requests to delete a broadcast profile.
@@ -594,12 +571,7 @@ class SPLConfigDialog(gui.SettingsDialog):
                        wx.YES | wx.NO | wx.ICON_QUESTION, self
                ) == wx.NO:
                        return
-               path = splconfig.SPLConfigPool[configPos].filename
-               del splconfig.SPLConfigPool[configPos]
-               try:
-                       os.remove(path)
-               except WindowsError:
-                       pass
+               splconfig.SPLConfig.deleteProfile(name)
                if name == self.switchProfile or name == self.activeProfile:
                        self.switchProfile = None
                        splconfig.SPLPrevProfile = None
@@ -607,7 +579,6 @@ class SPLConfigDialog(gui.SettingsDialog):
                self.profiles.Delete(index)
                del self.profileNames[profilePos]
                if name in splconfig._SPLCache: del splconfig._SPLCache[name]
-               splconfig.SPLNewProfiles.discard(name)
                if name in self._profileTriggersConfig:
                        del self._profileTriggersConfig[name]
                # 6.3: Select normal profile if the active profile is gone.
@@ -615,7 +586,7 @@ class SPLConfigDialog(gui.SettingsDialog):
                try:
                        self.profiles.Selection = 
self.profileNames.index(self.activeProfile)
                except ValueError:
-                       self.activeProfile = splconfig.SPLConfigPool[0].name
+                       self.activeProfile = _("Normal profile")
                        self.profiles.Selection = 0
                self.onProfileSelection(None)
                self.profiles.SetFocus()
@@ -732,11 +703,11 @@ class NewProfileDialog(wx.Dialog):
                self.Center(wx.BOTH | wx.CENTER_ON_SCREEN)
 
        def onOk(self, evt):
-               profileNames = [profile.name for profile in 
splconfig.SPLConfigPool]
+               parent = self.Parent
                name = api.filterFileName(self.profileName.Value)
                if not name:
                        return
-               if name in profileNames:
+               if name in parent.profileNames:
                        # Translators: An error displayed when the user 
attempts to create a profile which already exists.
                        gui.messageBox(_("That profile already exists. Please 
choose a different name."),
                                _("Error"), wx.OK | wx.ICON_ERROR, self)
@@ -750,12 +721,7 @@ class NewProfileDialog(wx.Dialog):
                        baseConfig = 
splconfig.getProfileByName(self.baseProfiles.GetStringSelection())
                        baseProfile = {sect:key for sect, key in 
baseConfig.iteritems() if sect in splconfig._mutatableSettings7}
                else: baseProfile = None
-               
splconfig.SPLConfigPool.append(splconfig.unlockConfig(newProfilePath, 
profileName=name, parent=baseProfile))
-               # Make the cache know this is a new profile.
-               # If nothing happens to this profile, the newly created profile 
will be saved to disk.
-               # 8.0: The recipient has been changed to the new profiles name 
set.
-               splconfig.SPLNewProfiles.add(name)
-               parent = self.Parent
+               splconfig.SPLConfig.createProfile(newProfilePath, 
profileName=name, parent=baseProfile)
                parent.profileNames.append(name)
                parent.profiles.Append(name)
                parent.profiles.Selection = parent.profiles.Count - 1
@@ -1405,10 +1371,7 @@ class ResetDialog(wx.Dialog):
                # LTS: Only a priveleged thread should do this, otherwise 
unexpected things may happen.
                with threading.Lock() as resetting:
                        global _configDialogOpened
-                       splconfig.resetAllConfig()
-                       splconfig.SPLConfig = dict(splconfig._SPLDefaults7)
-                       splconfig.SPLConfig["ActiveIndex"] = 0
-                       splconfig.SPLActiveProfile = 
splconfig.SPLConfigPool[0].name
+                       splconfig.SPLConfig.reset()
                        if self.resetInstantProfileCheckbox.Value:
                                if splconfig.SPLSwitchProfile is not None:
                                        splconfig.SPLSwitchProfile = None


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/e8d461d16706/
Changeset:   e8d461d16706
Branch:      None
User:        josephsl
Date:        2016-07-11 23:27:24+00:00
Summary:     Merge branch 'stable'

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index 423e038..fb230a9 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -57,9 +57,9 @@ def terminate():
 
 
 def _versionFromURL(url):
+       # 7.3: Be sure to handle both GitHub and old URL format.
        filename = url.split("/")[-1]
-       name = filename.split(".nvda-addon")[0]
-       return name[name.find("-")+1:]
+       return filename.split("stationPlaylist-")[1].split(".nvda-addon")[0]
 
 # Run the progress thread from another thread because urllib.urlopen blocks 
everyone.
 _progressThread = None


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/623334a32dbd/
Changeset:   623334a32dbd
Branch:      None
User:        josephsl
Date:        2016-07-12 01:37:50+00:00
Summary:     Welcome dialog (8.0-dev)/LTS): Changed the wording of the checkbox 
in order to align better with NVDA Core.

Changed the welcome dialog checkbox label to 'show welcome dialog' in order to 
better align with NvDA Core's own welcome dialog.

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splconfig.py 
b/addon/appModules/splstudio/splconfig.py
index 925b407..6a4e3ce 100755
--- a/addon/appModules/splstudio/splconfig.py
+++ b/addon/appModules/splstudio/splconfig.py
@@ -1064,9 +1064,9 @@ Thank you.""")
                mainSizer.Add(label,border=20,flag=wx.LEFT|wx.RIGHT|wx.TOP)
 
                sizer = wx.BoxSizer(wx.HORIZONTAL)
-               # Translators: A checkbox to turn off welcome dialog.
-               self.showWelcomeDialog=wx.CheckBox(self,wx.NewId(),label=_("Do 
not show welcome dialog when I start Studio"))
-               self.showWelcomeDialog.SetValue(not 
SPLConfig["Startup"]["WelcomeDialog"])
+               # Translators: A checkbox to show welcome dialog.
+               
self.showWelcomeDialog=wx.CheckBox(self,wx.NewId(),label=_("Show welcome dialog 
when I start Studio"))
+               
self.showWelcomeDialog.SetValue(SPLConfig["Startup"]["WelcomeDialog"])
                sizer.Add(self.showWelcomeDialog, border=10,flag=wx.TOP)
                mainSizer.Add(sizer, border=10, flag=wx.BOTTOM)
 
@@ -1079,8 +1079,7 @@ Thank you.""")
 
        def onOk(self, evt):
                global SPLConfig
-               if self.showWelcomeDialog.Value:
-                       SPLConfig["Startup"]["WelcomeDialog"] = not 
self.showWelcomeDialog.Value
+               SPLConfig["Startup"]["WelcomeDialog"] = 
self.showWelcomeDialog.Value
                self.Destroy()
 
 # Old version reminder.


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/845568d52e8d/
Changeset:   845568d52e8d
Branch:      None
User:        josephsl
Date:        2016-07-12 22:26:10+00:00
Summary:     Config Hub (8.0-dev): Oops, remove call to applied sectiosn 
functions when it is not used.

Somehow, merging from LTS brought in calls to applied sections found in 
alAlarms Center. As ConfigHub no longer needs this, simplify it by removing 
calls to the removed function.

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splconfig.py 
b/addon/appModules/splstudio/splconfig.py
index 6a4e3ce..91f58f7 100755
--- a/addon/appModules/splstudio/splconfig.py
+++ b/addon/appModules/splstudio/splconfig.py
@@ -407,10 +407,8 @@ def initConfig():
        global SPLConfig, _configLoadStatus, SPLSwitchProfile, trackComments
        # 7.0: Store the config as a dictionary.
        # This opens up many possibilities, including config caching, loading 
specific sections only and others (the latter saves memory).
-       # 8.0: To be replaced by ConfigHub object.
-       t = time.time()
+       # 8.0: Replaced by ConfigHub object.
        SPLConfig = ConfigHub()
-       print time.time()-t
        # Locate instant profile.
        if SPLConfig.instantSwitch is not None:
                try:
@@ -968,22 +966,13 @@ class SPLAlarmDialog(wx.Dialog):
                        settings = []
                        if self.level in (0, 1):
                                SPLConfig["IntroOutroAlarms"]["EndOfTrackTime"] 
= self.outroAlarmEntry.GetValue()
-                               
settings.append("IntroOutroAlarms/EndOfTrackTime")
                                SPLConfig["IntroOutroAlarms"]["SayEndOfTrack"] 
= self.outroToggleCheckBox.GetValue()
-                               
settings.append("IntroOutroAlarms/SayEndOfTrack")
                        elif self.level == 2:
                                SPLConfig["IntroOutroAlarms"]["SongRampTime"] = 
self.introAlarmEntry.GetValue()
-                               settings.append("IntroOutroAlarms/SongRampTime")
                                SPLConfig["IntroOutroAlarms"]["SaySongRamp"] = 
self.introToggleCheckBox.GetValue()
-                               settings.append("IntroOutroAlarms/SaySongRamp")
                        elif self.level == 3:
                                SPLConfig["MicrophoneAlarm"]["MicAlarm"] = 
self.micAlarmEntry.GetValue()
-                               settings.append("MicrophoneAlarm/MicAlarm")
                                
SPLConfig["MicrophoneAlarm"]["MicAlarmInterval"] = 
self.micIntervalEntry.GetValue()
-                               
settings.append("MicrophoneAlarm/MicAlarmInterval")
-                       # Apply alarm settings only.
-                       for setting in settings:
-                               applySections(SPLConfig["ActiveIndex"], 
key=setting)
                self.Destroy()
                _alarmDialogOpened = False
 


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/f79b27e3878a/
Changeset:   f79b27e3878a
Branch:      None
User:        josephsl
Date:        2016-07-12 22:31:08+00:00
Summary:     Alarms Center (8.0-dev/LTS): Make sure to handle level 0 for 
settings other than outro alarm.

Logic error: in case Alarms Center may show up: what if the only changed value 
is either initro or mic alarm? Because level 0 (Alarms Center) isn't checked, 
it will not be saved, thus handle it.
This is destined for add-on 8.0 and LTS.

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splconfig.py 
b/addon/appModules/splstudio/splconfig.py
index 91f58f7..d9cf924 100755
--- a/addon/appModules/splstudio/splconfig.py
+++ b/addon/appModules/splstudio/splconfig.py
@@ -967,10 +967,10 @@ class SPLAlarmDialog(wx.Dialog):
                        if self.level in (0, 1):
                                SPLConfig["IntroOutroAlarms"]["EndOfTrackTime"] 
= self.outroAlarmEntry.GetValue()
                                SPLConfig["IntroOutroAlarms"]["SayEndOfTrack"] 
= self.outroToggleCheckBox.GetValue()
-                       elif self.level == 2:
+                       elif self.level in (0, 2):
                                SPLConfig["IntroOutroAlarms"]["SongRampTime"] = 
self.introAlarmEntry.GetValue()
                                SPLConfig["IntroOutroAlarms"]["SaySongRamp"] = 
self.introToggleCheckBox.GetValue()
-                       elif self.level == 3:
+                       elif self.level in (0, 3):
                                SPLConfig["MicrophoneAlarm"]["MicAlarm"] = 
self.micAlarmEntry.GetValue()
                                
SPLConfig["MicrophoneAlarm"]["MicAlarmInterval"] = 
self.micIntervalEntry.GetValue()
                self.Destroy()


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/f2f11d460e8e/
Changeset:   f2f11d460e8e
Branch:      None
User:        josephsl
Date:        2016-07-20 02:45:14+00:00
Summary:     ConfigHub and instant profile switch (8.0-dev): Remove __setitem__ 
and unnecesary saves to runtime config.

It turns out __setitem__ (d[key] = this) isn't used, hence no need to keep it 
around (__getitem__ is used instead).
When saving normal profile, because runtime might be different, do not store 
instant switch flag in there (and it is now unnecessary anyway).

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splconfig.py 
b/addon/appModules/splstudio/splconfig.py
index d9cf924..a774f7b 100755
--- a/addon/appModules/splstudio/splconfig.py
+++ b/addon/appModules/splstudio/splconfig.py
@@ -242,11 +242,6 @@ class ConfigHub(ChainMap):
                # Do not just say dict(conf) because of referencing nature of 
Python, hence perform a deepcopy (copying everything to a new address).
                _SPLCache[key] = copy.deepcopy(dict(conf))
 
-       def __setitem__(self, key, value):
-               # Give favorable treatment to the currently active map/profile.
-               pos = 0 if key in _mutatableSettings7 else [profile.name for 
profile in self.maps].index(_("Normal profile"))
-               self.maps[pos][key] = value
-
        def __delitem__(self, key):
                # Consult profile-specific key first before deleting anything.
                pos = 0 if key in _mutatableSettings7 else [profile.name for 
profile in self.maps].index(_("Normal Profile"))
@@ -690,8 +685,6 @@ def _preSave(conf):
                # Cache instant profile for later use.
                if SPLSwitchProfile is not None:
                        conf["InstantProfile"] = SPLSwitchProfile
-                       # 7.0: Also update the runtime dictionary.
-                       SPLConfig["InstantProfile"] = SPLSwitchProfile
                else:
                        try:
                                del conf["InstantProfile"]


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/3f30051932ff/
Changeset:   3f30051932ff
Branch:      None
User:        josephsl
Date:        2016-07-22 16:49:31+00:00
Summary:     Merge branch 'stable'

Affected #:  1 file

diff --git a/addon/locale/fr/LC_MESSAGES/nvda.po 
b/addon/locale/fr/LC_MESSAGES/nvda.po
index 45d0769..fa2ee35 100755
--- a/addon/locale/fr/LC_MESSAGES/nvda.po
+++ b/addon/locale/fr/LC_MESSAGES/nvda.po
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: StationPlaylist 4.1\n"
 "Report-Msgid-Bugs-To: nvda-translations@xxxxxxxxxxxxx\n"
 "POT-Creation-Date: \n"
-"PO-Revision-Date: 2016-03-04 22:01+0100\n"
+"PO-Revision-Date: 2016-07-13 12:06+0100\n"
 "Last-Translator: Rémy Ruiz <remyruiz@xxxxxxxxx>\n"
 "Language-Team: Rémy Ruiz <remyruiz@xxxxxxxxx>\n"
 "Language: fr\n"
@@ -56,9 +56,9 @@ msgid "{header}: {content}"
 msgstr "{header}: {content}"
 
 #. Translators: Presented when some info is not defined for a track in Track 
Tool (example: cue not found)
-#, fuzzy, python-brace-format
+#, python-brace-format
 msgid "{header} not found"
-msgstr "{header}: {content}"
+msgstr "{header} introuvable"
 
 #. Translators: Spoken when column content is blank.
 #, python-brace-format
@@ -115,7 +115,6 @@ msgid "Status: {name}"
 msgstr "Statut : {name}"
 
 #. Translators: The text of the help command in SPL Assistant layer.
-#, fuzzy
 msgid ""
 "After entering SPL Assistant, press:\n"
 "A: Automation.\n"
@@ -152,36 +151,37 @@ msgstr ""
 "Une fois dans l'Assistant SPL, appuyez sur :\n"
 "A : Automatisation.\n"
 "C : Annoncer le nom de la piste en cours de lecture.\n"
-"D (R Si le mode de compatibilité est activé): Durée restante pour la "
-"playlist.\n"
+"D : Durée restante pour la playlist.\n"
 "E : Statut général de métadonnées en streaming.\n"
-"1 jusqu'à 4, 0 : statut de Métadonnées en streaming pour l'encodeur DSP et "
-"les quatre autres URLs.\n"
+"Maj+1 jusqu'à maj+4, maj+0 : Statut de Métadonnées en streaming pour "
+"l'encodeur DSP et les quatre autres URLs.\n"
 "H : Durée de la piste pour la tranche horaire.\n"
-"Maj+H : Durée des pistes sélectionnés.\n"
-"I (L si le mode de compatibilité est activé): Nombre d'auditeurs.\n"
+"Maj+H : Durée des pistes restantes pour la tranche horaire.\n"
+"I : Nombre d'auditeurs.\n"
 "K : Se déplacer au marqueur de position de piste.\n"
 "Contrôle+K : Définir un marqueur de position de piste.\n"
-"L (Maj+L si le mode de compatibilité est activé): Statut de l'Entrée ligne.\n"
+"L : Statut de l'Entrée ligne.\n"
 "M : Statut du Microphone.\n"
 "N : Piste suivante.\n"
 "P : Statut Lecture.\n"
 "Maj+P : Hauteur de la piste actuelle.\n"
-"R (Maj+E si le mode de compatibilité est activé): Enregistrer dans un "
-"fichier.\n"
+"R : Enregistrer dans un fichier.\n"
 "Maj+R : Contrôle du balayage de la bibliothèque.\n"
-"S : Temps planifié pour la piste.\n"
+"S : Heure prévue pour la piste.\n"
+"Maj+S : Durée jusqu'à la piste sélectionnée qui va être jouer.\n"
 "T : Mode édition chariot.\n"
 "U : Temps de fonctionnement Studio.\n"
 "W : Météo et température.\n"
 "Y : Modification de la playlist.\n"
+"1 jusqu'à 0 (6 pour Studio 5.01 ou version antérieure) : Annoncer les "
+"colonnes via l'Explorateur de Colonnes (0 est la dixième tranche de "
+"colonne).\n"
 "F9 : Marquer la piste en cours comme début d'analyse de durée de piste.\n"
 "F10 : Effectuer une analyse de durée de piste.\n"
 "F12 : Basculer vers un changement de profil immédiat.\n"
 "Maj+F1 : Ouvre le guide de l'utilisateur en ligne."
 
 #. Translators: The text of the help command in SPL Assistant layer when JFW 
layer is active.
-#, fuzzy
 msgid ""
 "After entering SPL Assistant, press:\n"
 "A: Automation.\n"
@@ -219,37 +219,40 @@ msgid ""
 msgstr ""
 "Une fois dans l'Assistant SPL, appuyez sur :\n"
 "A : Automatisation.\n"
-"C : Annoncer le nom de la piste en cours de lecture.\n"
-"D (R Si le mode de compatibilité est activé): Durée restante pour la "
-"playlist.\n"
+"C : Basculer l'explorateur de chariot.\n"
+"Maj+C : Annoncer le nom de la piste en cours de lecture.\n"
 "E : Statut général de métadonnées en streaming.\n"
-"1 jusqu'à 4, 0 : statut de Métadonnées en streaming pour l'encodeur DSP et "
-"les quatre autres URLs.\n"
+"Maj+1 jusqu'à maj+4, maj+0 : Statut de Métadonnées en streaming pour "
+"l'encodeur DSP et les quatre autres URLs.\n"
+"Maj+E : Enregistrer dans un fichier.\n"
+"F : Recherche de piste.\n"
 "H : Durée de la piste pour la tranche horaire.\n"
-"Maj+H : Durée des pistes sélectionnés.\n"
-"I (L si le mode de compatibilité est activé): Nombre d'auditeurs.\n"
+"Maj+H : Durée des pistes restantes pour la tranche horaire.\n"
 "K : Se déplacer au marqueur de position de piste.\n"
 "Contrôle+K : Définir un marqueur de position de piste.\n"
-"L (Maj+L si le mode de compatibilité est activé): Statut de l'Entrée ligne.\n"
+"L : Nombre d'auditeurs.\n"
+"L : Statut de l'Entrée ligne.\n"
 "M : Statut du Microphone.\n"
 "N : Piste suivante.\n"
 "P : Statut Lecture.\n"
 "Maj+P : Hauteur de la piste actuelle.\n"
-"R (Maj+E si le mode de compatibilité est activé): Enregistrer dans un "
-"fichier.\n"
+"R : Durée restante pour la playlist.\n"
 "Maj+R : Contrôle du balayage de la bibliothèque.\n"
-"S : Temps planifié pour la piste.\n"
+"S : Heure prévue pour la piste.\n"
+"Maj+S : Durée jusqu'à la piste sélectionnée qui va être jouer.\n"
 "T : Mode édition chariot.\n"
 "U : Temps de fonctionnement Studio.\n"
 "W : Météo et température.\n"
 "Y : Modification de la playlist.\n"
+"1 jusqu'à 0 (6 pour Studio 5.01 ou version antérieure) : Annoncer les "
+"colonnes via l'Explorateur de Colonnes (0 est la dixième tranche de "
+"colonne).\n"
 "F9 : Marquer la piste en cours comme début d'analyse de durée de piste.\n"
 "F10 : Effectuer une analyse de durée de piste.\n"
 "F12 : Basculer vers un changement de profil immédiat.\n"
 "Maj+F1 : Ouvre le guide de l'utilisateur en ligne."
 
 #. Translators: The text of the help command in SPL Assistant layer when 
Window-Eyes layer is active.
-#, fuzzy
 msgid ""
 "After entering SPL Assistant, press:\n"
 "A: Automation.\n"
@@ -289,30 +292,36 @@ msgid ""
 msgstr ""
 "Une fois dans l'Assistant SPL, appuyez sur :\n"
 "A : Automatisation.\n"
-"C : Annoncer le nom de la piste en cours de lecture.\n"
-"D (R Si le mode de compatibilité est activé): Durée restante pour la "
-"playlist.\n"
-"E : Statut général de métadonnées en streaming.\n"
-"1 jusqu'à 4, 0 : statut de Métadonnées en streaming pour l'encodeur DSP et "
-"les quatre autres URLs.\n"
+"C : Basculer l'explorateur de chariot.\n"
+"Maj+C : Annoncer le nom de la piste en cours de lecture.\n"
+"D : Durée restante pour la playlist.\n"
+"E : Temps écoulé.\n"
+"F : Recherche de piste.\n"
+"R : Durée restante pour la piste en cours de lecture.\n"
+"G : Statut général de métadonnées en streaming.\n"
+"Maj+1 jusqu'à maj+4, maj+0 : Statut de Métadonnées en streaming pour "
+"l'encodeur DSP et les quatre autres URLs.\n"
 "H : Durée de la piste pour la tranche horaire.\n"
-"Maj+H : Durée des pistes sélectionnés.\n"
-"I (L si le mode de compatibilité est activé): Nombre d'auditeurs.\n"
+"Maj+H : Durée des pistes restantes pour la tranche horaire.\n"
 "K : Se déplacer au marqueur de position de piste.\n"
 "Contrôle+K : Définir un marqueur de position de piste.\n"
-"L (Maj+L si le mode de compatibilité est activé): Statut de l'Entrée ligne.\n"
+"L : Nombre d'auditeurs.\n"
+"Maj+L : Statut de l'Entrée ligne.\n"
 "M : Statut du Microphone.\n"
 "N : Piste suivante.\n"
 "P : Statut Lecture.\n"
 "Maj+P : Hauteur de la piste actuelle.\n"
-"R (Maj+E si le mode de compatibilité est activé): Enregistrer dans un "
-"fichier.\n"
+"Maj+E : Enregistrer dans un fichier.\n"
 "Maj+R : Contrôle du balayage de la bibliothèque.\n"
-"S : Temps planifié pour la piste.\n"
+"S : Heure prévue pour la piste.\n"
+"Maj+S : Durée jusqu'à la piste sélectionnée qui va être jouer.\n"
 "T : Mode édition chariot.\n"
 "U : Temps de fonctionnement Studio.\n"
 "W : Météo et température.\n"
 "Y : Modification de la playlist.\n"
+"1 jusqu'à 0 (6 pour Studio 5.01 ou version antérieure) : Annoncer les "
+"colonnes via l'Explorateur de Colonnes (0 est la dixième tranche de "
+"colonne).\n"
 "F9 : Marquer la piste en cours comme début d'analyse de durée de piste.\n"
 "F10 : Effectuer une analyse de durée de piste.\n"
 "F12 : Basculer vers un changement de profil immédiat.\n"
@@ -375,7 +384,7 @@ msgstr "Annonce le temps de diffusion."
 
 #. Translators: Input help mode message for a command in Station Playlist 
Studio.
 msgid "Announces time including seconds."
-msgstr "Annonce le temps y compris les secondes."
+msgstr "Annonce l'heure y compris les secondes."
 
 #. Translators: Presented when the add-on config dialog is opened.
 msgid ""
@@ -619,6 +628,8 @@ msgstr ""
 #. Translators: Presented when SPL Assistant cannot be invoked.
 msgid "Failed to locate Studio main window, cannot enter SPL Assistant"
 msgstr ""
+"Impossible de localiser la fenêtre principale de Studio, L'Assistant SPL ne "
+"peut pas entrer"
 
 #. Translators: Input help mode message for a layer command in Station 
Playlist Studio.
 msgid ""
@@ -742,6 +753,8 @@ msgstr ""
 #. Translators: Presented when attempting to move to a place marker track when 
not focused in playlist viewer.
 msgid "You cannot move to a place marker track outside of playlist viewer."
 msgstr ""
+"Impossible de vous déplacer au marqueur de position de piste en dehors de la "
+"visionneuse de playlist."
 
 #. Translators: Presented when no place marker is found.
 msgid "No place marker found"
@@ -766,28 +779,25 @@ msgid "Metadata streaming on DSP encoder disabled"
 msgstr "Métadonnées en streaming sur l'encodeur DSP désactivé"
 
 #. Translators: Presented when attempting to announce specific columns but the 
focused item isn't a track.
-#, fuzzy
 msgid "Not a track"
-msgstr "Pas dans la liste des pistes"
+msgstr "Pas une piste"
 
 #. Translators: Presented when a specific column header is not found.
-#, fuzzy, python-brace-format
+#, python-brace-format
 msgid "{headerText} not found"
-msgstr "{header}: {content}"
+msgstr "{headerText} introuvable"
 
 #. Translators: The title for SPL Assistant help dialog.
 msgid "SPL Assistant help"
 msgstr "Aide Assistant SPL"
 
 #. Translators: The title for SPL Assistant help dialog.
-#, fuzzy
 msgid "SPL Assistant help for JAWS layout"
-msgstr "Aide Assistant SPL"
+msgstr "Aide Assistant SPL pour la disposition de JAWS"
 
 #. Translators: The title for SPL Assistant help dialog.
-#, fuzzy
 msgid "SPL Assistant help for Window-Eyes layout"
-msgstr "Aide Assistant SPL"
+msgstr "Aide Assistant SPL pour la disposition de Window-Eyes"
 
 #. Translators: A dialog message shown when settings were reset to defaults.
 msgid "Successfully applied default add-on settings."
@@ -811,10 +821,13 @@ msgid ""
 "Your encoder settings had errors and were reset to defaults. If you have "
 "stream labels configured for various encoders, please add them again."
 msgstr ""
+"Vos paramètres de l’encodeur comportaient des erreurs et ont été "
+"réinitialiser aux valeurs par défaut. Si vous avez configurés des étiquettes "
+"de flux pour différents encodeurs, veuillez les ajoutez à nouveau."
 
 #. Translators: Title of the encoder settings error dialog.
 msgid "Encoder settings error"
-msgstr ""
+msgstr "Erreur dans les paramètres de l'encodeur"
 
 #. Translators: Message presented indicating missing time-based profiles.
 #, python-brace-format
@@ -822,25 +835,26 @@ msgid ""
 "Could not locate the following time-based profile(s):\n"
 "{profiles}"
 msgstr ""
+"Impossible de localisé les suivants profils basé sur l'heure :\n"
+"{profiles}"
 
 #. Translators: The title of a dialog shown when some time-based profiles 
doesn't exist.
 msgid "Time-based profiles missing"
-msgstr ""
+msgstr "Profils basé sur l'heure manquants"
 
 #. Translators: A flag indicating the currently active broadcast profile.
 msgid "active"
-msgstr ""
+msgstr "active"
 
 #. Translators: A flag indicating the broadcast profile is an instant switch 
profile.
 #. Instant switch flag is set on another profile, so remove the flag first.
-#, fuzzy
 msgid "instant switch"
-msgstr "Activer le changement de profil immédiat"
+msgstr "changement immédiat"
 
 #. Translators: A flag indicating the time-based triggers profile.
 #. Calling set profile flags with discard argument is always safe here.
 msgid "time-based"
-msgstr ""
+msgstr "basé sur l'heure"
 
 #. Translators: Presented when trying to switch to an instant switch profile 
when add-on settings dialog is active.
 msgid "Add-on settings dialog is open, cannot switch profiles"
@@ -849,14 +863,14 @@ msgstr ""
 "basculer vers les profils"
 
 #. Translators: Presented when switch to instant switch profile was successful.
-#, fuzzy, python-brace-format
+#, python-brace-format
 msgid "Switching to {newProfileName}"
-msgstr "Changement de profils"
+msgstr "Changement de {newProfileName}"
 
 #. Translators: Presented when switching from instant switch profile to a 
previous profile.
-#, fuzzy, python-brace-format
+#, python-brace-format
 msgid "Returning to {previousProfile}"
-msgstr "Retour au profil précédent"
+msgstr "Retour au {previousProfile}"
 
 #. Translators: Presented when trying to switch to an instant switch profile 
when the instant switch profile is not defined.
 msgid "No instant switch profile is defined"
@@ -868,7 +882,7 @@ msgstr "Vous êtes déjà dans le changement de profil 
immédiat"
 
 #. Translators: Presented when trying to switch to an instant switch profile 
when one is already using the instant switch profile.
 msgid "A profile trigger is already active"
-msgstr ""
+msgstr "Un déclencheur de profil est déjà actif"
 
 #. Translators: Text of the dialog when another alarm dialog is open.
 msgid "Another alarm dialog is open."
@@ -999,11 +1013,11 @@ msgstr "&Supprimer"
 
 #. Translators: The label of a button to manage show profile triggers.
 msgid "&Triggers..."
-msgstr ""
+msgstr "&Déclencheurs..."
 
 #. Translators: The label for a setting in SPL Add-on settings to configure 
countdown seconds before switching profiles.
 msgid "Countdown seconds before switching profiles"
-msgstr ""
+msgstr "Secondes pour le décomptage avant les changements de profils"
 
 #. Translators: the label for a setting in SPL add-on settings to set status 
announcement between words and beeps.
 msgid "&Beep for status announcements"
@@ -1076,6 +1090,7 @@ msgstr "Annonce du balayage de la &bibliothèque :"
 #. Translators: the label for a setting in SPL add-on settings to announce 
time including hours.
 msgid "Include &hours when announcing track or playlist duration"
 msgstr ""
+"Inclure les &heures en annonçant la durée de la piste ou de la playlist"
 
 #. Translators: the label for a setting in SPL add-on settings to toggle track 
dial mode on and off.
 msgid "&Track Dial mode"
@@ -1083,7 +1098,7 @@ msgstr "Mode Cadran de &piste"
 
 #. Translators: the label for a setting in SPL add-on settings to toggle 
category sound announcement.
 msgid "&Beep for different track categories"
-msgstr ""
+msgstr "&Bip pour les différentes catégories de piste"
 
 #. Translators: the label for a setting in SPL add-on settings to be notified 
that metadata streaming is enabled.
 msgid "&Metadata streaming notification and connection"
@@ -1110,14 +1125,12 @@ msgid "&Manage track column announcements..."
 msgstr "&Gérer les annonces de colonne de piste..."
 
 #. Translators: The label of a button to configure columns explorer slots (SPL 
Assistant, number row keys to announce specific columns).
-#, fuzzy
 msgid "Columns E&xplorer..."
-msgstr "&Ordre des colonnes :"
+msgstr "E&xplorateur de colonnes..."
 
 #. Translators: The label of a button to open advanced options such as using 
SPL Controller command to invoke Assistant layer.
-#, fuzzy
 msgid "&Status announcements..."
-msgstr "Annonce le statut en bips"
+msgstr "Annonces des &statut..."
 
 #. Translators: The label of a button to open advanced options such as using 
SPL Controller command to invoke Assistant layer.
 msgid "&Advanced options..."
@@ -1142,20 +1155,19 @@ msgid "That profile already exists. Please choose a 
different name."
 msgstr "Ce profil existe déjà. Veuillez choisir un nom différent."
 
 #. Translators: Message reported when attempting to delete a profile while a 
profile is triggered.
-#, fuzzy
 msgid ""
 "An instant switch profile might be active or you are in the midst of a "
 "broadcast. If so, please press SPL Assistant, F12 to switch back to a "
 "previously active profile before opening add-on settings to delete a profile."
 msgstr ""
-"Un changement de profil immédiat peut-être actif. Dans l'affirmative, s'il "
-"vous plaît Appuyer sur Assistant SPL, F12 pour revenir à un profil "
-"précédemment actif avant d'ouvrir les paramètres du module complémentaire "
-"pour supprimer un profil."
+"Un changement de profil immédiat peut-être actif ou vous êtes au milieu "
+"d'une diffusion. Dans l'affirmative, s'il vous plaît Appuyer sur Assistant "
+"SPL, F12 pour revenir à un profil précédemment actif avant d'ouvrir les "
+"paramètres du module complémentaire pour supprimer un profil."
 
 #. Translators: Title of a dialog shown when profile cannot be deleted.
 msgid "Profile delete error"
-msgstr "Erreur lors de la suppression de profil"
+msgstr "Échec lors de la suppression de profil"
 
 #. Translators: The confirmation prompt displayed when the user requests to 
delete a broadcast profile.
 msgid "Are you sure you want to delete this profile? This cannot be undone."
@@ -1177,13 +1189,12 @@ msgid "Warning"
 msgstr "Attention"
 
 #. Translators: Presented when an alarm dialog is opened.
-#, fuzzy
 msgid ""
 "Another add-on settings dialog is open. Please close the previously opened "
 "dialog first."
 msgstr ""
-"Le dialogue de paramètres du module complémentaire est ouvert. Veuillez "
-"d'abord le fermer."
+"Un autre dialogue de paramètres du module complémentaire est ouvert. "
+"Veuillez d'abord fermer le dialogue préalablement ouvert."
 
 #. Translators: The title of the dialog to create a new broadcast profile.
 msgid "New Profile"
@@ -1204,44 +1215,47 @@ msgstr "Profil de &base :"
 #. Translators: The title of the broadcast profile triggers dialog.
 #, python-brace-format
 msgid "Profile triggers for {profileName}"
-msgstr ""
+msgstr "Déclencheurs de profil pour {profileName}"
 
 #. Translators: The label of a checkbox to toggle if selected profile is an 
instant switch profile.
-#, fuzzy
 msgid "This is an &instant switch profile"
-msgstr "Lorsque le changement de profil immédiat est actif"
+msgstr "Ceci est un changement de profil &immédiat"
 
 #. Translators: The label of a checkbox to toggle if selected profile is a 
time-based profile.
 msgid "This is a &time-based switch profile"
-msgstr ""
+msgstr "Ceci est un changement de profil basé sur l'&heure"
 
 msgid "Day"
-msgstr ""
+msgstr "Jour"
 
 msgid "Time"
-msgstr ""
+msgstr "Heure"
 
 msgid "Hour"
-msgstr ""
+msgstr "Heure"
 
 msgid "Minute"
-msgstr ""
+msgstr "Minute"
 
 msgid "Duration in minutes"
-msgstr ""
+msgstr "Durée en minutes"
 
 #. Translators: Presented if another profile occupies a time slot set by the 
user.
-#, fuzzy
 msgid ""
 "A profile trigger already exists for the entered time slot. Please choose a "
 "different date or time."
-msgstr "Ce profil existe déjà. Veuillez choisir un nom différent."
+msgstr ""
+"Un déclencheur de profil existe déjà pour la tranche horaire saisie. "
+"Veuillez choisir une date ou une heure différente."
 
 #. Er, did you specify a date?
 msgid ""
 "The time-based profile checkbox is checked but no switch dates are given. "
 "Please either specify switch date(s) or uncheck time-based profile checkbox."
 msgstr ""
+"La case à cocher profil basé sur l'heure est cochée, mais aucune date de "
+"changement n’est donnés. Veuillez spécifier la date(s) de changement(s) ou "
+"décochez profil basé sur l'heure."
 
 #. Translators: Title of a dialog to configure metadata streaming status for 
DSP encoder and four additional URL's.
 msgid "Metadata streaming options"
@@ -1257,7 +1271,7 @@ msgstr ""
 
 #. Translators: A checkbox to let metadata streaming status be applied to the 
currently active broadcast profile.
 msgid "&Apply streaming changes to the selected profile"
-msgstr ""
+msgstr "&Appliquer les modifications du flux pour le profil sélectionné"
 
 #. Translators: Title of a dialog to configure column announcements (order and 
what columns should be announced).
 msgid "Manage column announcements"
@@ -1283,23 +1297,21 @@ msgid "Move &down"
 msgstr "Déplacer vers le &bas"
 
 #. Translators: The title of Columns Explorer configuration dialog.
-#, fuzzy
 msgid "Columns Explorer"
-msgstr "&Ordre des colonnes :"
+msgstr "Explorateur de Colonnes"
 
 #. Translators: The label for a setting in SPL add-on dialog to select column 
for this column slot.
 #, python-brace-format
 msgid "Slot {position}"
-msgstr ""
+msgstr "Tranche {position}"
 
 #. Translators: Title of a dialog to configure various status announcements 
such as announcing listener count.
-#, fuzzy
 msgid "Status announcements"
-msgstr "Annonce le statut en bips"
+msgstr "Annonces des statut"
 
 #. Translators: the label for a setting in SPL add-on settings to announce 
scheduled time.
 msgid "Announce &scheduled time for the selected track"
-msgstr "Annoncer le temps &planifié pour la piste sélectionnée"
+msgstr "Annoncer l'heure &prévue pour la piste sélectionnée"
 
 #. Translators: the label for a setting in SPL add-on settings to announce 
listener count.
 msgid "Announce &listener count"
@@ -1331,16 +1343,15 @@ msgstr "Options avancées"
 
 #. Translators: A checkbox to toggle automatic add-on updates.
 msgid "Automatically check for add-on &updates"
-msgstr ""
+msgstr "Rechercher automatiquement une mise à jo&ur du module complémentaire"
 
 #. Translators: A checkbox to toggle if SPL Controller command can be used to 
invoke Assistant layer.
 msgid "Allow SPL C&ontroller command to invoke SPL Assistant layer"
 msgstr "Permettre au Commande C&ontrôleur SPL appeler la couche  Assistant SPL"
 
 #. Translators: The label for a setting in SPL add-on dialog to set keyboard 
layout for SPL Assistant.
-#, fuzzy
 msgid "SPL Assistant command &layout:"
-msgstr "Aide Assistant SPL"
+msgstr "Disposition de &la commande Assistant SPL :"
 
 #. Translators: Text of the dialog when another find dialog is open.
 msgid "Another find dialog is open."
@@ -1364,7 +1375,7 @@ msgid "Minimum duration"
 msgstr "Durée minimale"
 
 msgid "Second"
-msgstr ""
+msgstr "Seconde"
 
 msgid "Maximum duration"
 msgstr "Durée maximale"
@@ -1382,10 +1393,10 @@ msgid "Time range find error"
 msgstr "Erreur trouver dans l'intervalle de temps"
 
 msgid "Countdown started"
-msgstr ""
+msgstr "Le décomptage a commencé"
 
 msgid "Timer complete"
-msgstr ""
+msgstr "Minuteur complet"
 
 #. Translators: Status message for metadata streaming.
 msgid "No metadata streaming URL's defined"
@@ -1418,35 +1429,38 @@ msgstr "Métadonnées en streaming configuré pour l'URL 
{URL}"
 
 #. Translators: Error text shown when add-on update check fails.
 msgid "Error checking for update."
-msgstr ""
+msgstr "Échec lors de la recherche d'une mise à jour."
 
 #. Translators: Title of the add-on update check dialog.
 msgid "Check for add-on update"
-msgstr ""
+msgstr "Rechercher une mise à jour du module complémentaire"
 
 #. No need to interact with the user.
 #. Translators: Text shown when update check fails for some odd reason.
 msgid "Add-on update check failed."
-msgstr ""
+msgstr "Échec lors de la recherche d'une mise à jour du module complémentaire."
 
 #. Translators: Presented when no add-on update is available.
 msgid "No add-on update available."
-msgstr ""
+msgstr "Aucune mise à jour disponible du module complémentaire."
 
 #. Translators: An error text shown when one is using a newer version of the 
add-on.
 msgid ""
 "You appear to be running a version newer than the latest released version. "
 "Please reinstall the official version to downgrade."
 msgstr ""
+"Vous sembler exécuter une version plus récente que la dernière version. S’il "
+"vous plaît réinstaller la version officielle adapter vers le bas."
 
 #. Translators: Text shown if an add-on update is available.
 #, python-brace-format
 msgid "Studio add-on {newVersion} is available. Would you like to update?"
 msgstr ""
+"Un module complémentaire pour Studio {newVersion} est disponible. Vous "
+"souhaitez le mettre à jour ?"
 
 #. Help message for SPL Controller
 #. Translators: the dialog text for SPL Controller help.
-#, fuzzy
 msgid ""
 "\n"
 "After entering SPL Controller, press:\n"
@@ -1479,6 +1493,8 @@ msgstr ""
 "U : Pause.\n"
 "S : Arrêt avec fondu.\n"
 "T : Arrêt instantané.\n"
+"E : Annoncer si des encodeurs sont surveillés.\n"
+"I : Annoncer le nombre d'auditeurs.\n"
 "R : Temps restant pour la piste en cours de lecture.\n"
 "Maj+R : Balayage de la bibliothèque en cours."
 
@@ -1522,9 +1538,9 @@ msgstr ""
 "piste est jouée."
 
 #. Translators: Announces number of stream listeners.
-#, fuzzy, python-brace-format
+#, python-brace-format
 msgid "Listener count: {listenerCount}"
-msgstr "Nombre d'auditeurs introuvable"
+msgstr "Nombre d'auditeurs : {listenerCount}"
 
 #. Translators: Presented when no track is playing in Station Playlist Studio.
 msgid "There is no track playing."
@@ -1544,36 +1560,33 @@ msgid "Number of encoders monitored: 
{numberOfEncoders}: {streamLabels}"
 msgstr "Nombre d'encodeurs monitorés : {numberOfEncoders} : {streamLabels}"
 
 #. Translators: Text of the dialog when another alarm dialog is open.
-#, fuzzy
 msgid "Another encoder settings dialog is open."
-msgstr "Un autre dialogue rechercher  est ouvert."
+msgstr "Un autre dialogue de paramètres de l'encodeur est ouvert."
 
 #. Translators: The title of the encoder settings dialog (example: Encoder 
settings for SAM 1").
 #, python-brace-format
 msgid "Encoder settings for {name}"
-msgstr ""
+msgstr "Paramètres de l'encodeur pour {name}"
 
 #. Translators: An edit field in encoder settings to set stream label for this 
encoder.
 msgid "Stream &label"
-msgstr ""
+msgstr "Étiquette de f&lux"
 
 #. Translators: A checkbox in encoder settings to set if NvDA should switch 
focus to Studio window when connected.
-#, fuzzy
 msgid "&Focus to Studio when connected"
-msgstr "Basculer vers Studio après la connexion"
+msgstr "Mettez le &focus vers Studio lorsqu'il est connecté"
 
 #. Translators: A checkbox in encoder settings to set if NvDA should play the 
next track when connected.
-#, fuzzy
 msgid "&Play first track when connected"
-msgstr "Lire la première piste après la connexion"
+msgstr "&Lire la première piste lorsqu'il est connecté"
 
 #. Translators: A checkbox in encoder settings to set if NvDA should monitor 
the status of this encoder in the background.
 msgid "Enable background connection &monitoring"
-msgstr ""
+msgstr "Activer la connexion en arrière-plan lors de la &surveillance"
 
 #. Translators: A checkbox in encoder settings to set if NvDA should play 
connection progress tone.
 msgid "Play connection status &beep while connecting"
-msgstr ""
+msgstr "Lire le statut de la connexion en &bip lors de la connexion"
 
 #. Translators: Status message for encoder monitoring.
 #, python-brace-format
@@ -1668,6 +1681,8 @@ msgid ""
 "Shows encoder configuration dialog to configure various encoder settings "
 "such as stream label."
 msgstr ""
+"Affiche le dialogue de configuration de l'encodeur pour configurer "
+"différents paramètres de l’encodeur comme l'étiquette de flux."
 
 #. Add-on summary, usually the user visible name of the addon.
 #. Translators: Summary for this add-on to be shown on installation and add-on 
information.
@@ -1684,14 +1699,14 @@ msgstr ""
 
 #, python-brace-format
 msgid "Position: {pos}"
-msgstr ""
+msgstr "Position : {pos}"
 
 #, python-brace-format
 msgid "Label: {label}"
-msgstr ""
+msgstr "Étiquette : {label}"
 
 msgid "No stream label"
-msgstr ""
+msgstr "Pas d'étiquette de flux"
 
 #. Translators: Presented when an Encoder is trying to connect to a streaming 
server.
 msgid "Connecting..."
@@ -1706,11 +1721,11 @@ msgstr "Se connecter à un serveur de flux."
 
 #, python-brace-format
 msgid "Encoder Settings: {setting}"
-msgstr ""
+msgstr "Paramètres de l'Encodeur : {setting}"
 
 #, python-brace-format
 msgid "Transfer Rate: {transferRate}"
-msgstr ""
+msgstr "Taux de Transfert : {transferRate}"
 
 #. Add-on description
 #. Translators: Long description to be shown for this add-on on add-on 
information from add-ons manager


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/a524cd431815/
Changeset:   a524cd431815
Branch:      None
User:        josephsl
Date:        2016-07-26 08:23:46+00:00
Summary:     Merged 7.x, laying foundation for update channel selection 
(disabled for now)

Affected #:  6 files

diff --git a/addon/appModules/splstudio/__init__.py 
b/addon/appModules/splstudio/__init__.py
index b66fe2e..9caffb9 100755
--- a/addon/appModules/splstudio/__init__.py
+++ b/addon/appModules/splstudio/__init__.py
@@ -581,7 +581,9 @@ class AppModule(appModuleHandler.AppModule):
                self.noMoreHandle = threading.Event()
                threading.Thread(target=self._locateSPLHwnd).start()
                # Check for add-on update if told to do so.
-               if splconfig.SPLConfig["Update"]["AutoUpdateCheck"]:
+               # LTS: Only do this if channel hasn't changed.
+               # To be unlocked in 8.0 beta 1.
+               if splconfig.SPLConfig["Update"]["AutoUpdateCheck"]: # 7lts: or 
splupdate._updateNow:
                        # 7.0: Have a timer call the update function indirectly.
                        queueHandler.queueFunction(queueHandler.eventQueue, 
splconfig.updateInit)
                # Display startup dialogs if any.
@@ -1810,7 +1812,13 @@ class AppModule(appModuleHandler.AppModule):
        def script_updateCheck(self, gesture):
                self.finish()
                if splupdate._SPLUpdateT is not None and 
splupdate._SPLUpdateT.IsRunning(): splupdate._SPLUpdateT.Stop()
-               
splupdate.updateCheck(continuous=splconfig.SPLConfig["Update"]["AutoUpdateCheck"])
+               # Display the update check progress dialog (inspired by add-on 
installation dialog in NvDA Core).
+               splupdate._progressDialog = 
gui.IndeterminateProgressDialog(gui.mainFrame,
+               # Translators: The title of the dialog presented while checking 
for add-on updates.
+               _("Add-on update"),
+               # Translators: The message displayed while checking for newer 
version of Studio add-on.
+               _("Checking for new version of Studio add-on..."))
+               threading.Thread(target=splupdate.updateCheck, 
kwargs={"continuous":splconfig.SPLConfig["Update"]["AutoUpdateCheck"], 
"confUpdateInterval":splconfig.SPLConfig["Update"]["UpdateInterval"]}).start()
 
 
        __SPLAssistantGestures={

diff --git a/addon/appModules/splstudio/splconfig.py 
b/addon/appModules/splstudio/splconfig.py
index a774f7b..03c57a7 100755
--- a/addon/appModules/splstudio/splconfig.py
+++ b/addon/appModules/splstudio/splconfig.py
@@ -73,6 +73,7 @@ CompatibilityLayer = option("off", "jfw", "wineyes", 
default="off")
 ProfileTriggerThreshold = integer(min=5, max=60, default=15)
 [Update]
 AutoUpdateCheck = boolean(default=true)
+UpdateInterval = integer(min=1, max=30, default=7)
 [Startup]
 AudioDuckingReminder = boolean(default=true)
 WelcomeDialog = boolean(default=true)
@@ -816,17 +817,24 @@ def triggerProfileSwitch():
 # Its only job is to call the update check function (splupdate) with the auto 
check enabled.
 # The update checker will not be engaged if an instant switch profile is 
active or it is not time to check for it yet (check will be done every 24 
hours).
 def autoUpdateCheck():
-       splupdate.updateCheck(auto=True, 
continuous=SPLConfig["Update"]["AutoUpdateCheck"])
+       splupdate.updateCheck(auto=True, 
continuous=SPLConfig["Update"]["AutoUpdateCheck"], 
confUpdateInterval=SPLConfig["Update"]["UpdateInterval"])
 
 # The timer itself.
 # A bit simpler than NVDA Core's auto update checker.
 def updateInit():
+       # LTS: Launch updater if channel change is detected.
+       # To be unlocked in 8.0 beta 1.
+       #if splupdate._updateNow:
+               #splupdate.updateCheck(auto=True) # No repeat here.
+               #splupdate._SPLUpdateT = wx.PyTimer(autoUpdateCheck)
+               #splupdate._updateNow = False
+               #return
        currentTime = time.time()
-       nextCheck = splupdate.SPLAddonCheck+86400.0
+       nextCheck = 
splupdate.SPLAddonCheck+(SPLConfig["Update"]["UpdateInterval"]* 86400.0)
        if splupdate.SPLAddonCheck < currentTime < nextCheck:
                interval = int(nextCheck - currentTime)
        elif splupdate.SPLAddonCheck < nextCheck < currentTime:
-               interval = 86400
+               interval = SPLConfig["Update"]["UpdateInterval"]* 86400
                # Call the update check now.
                splupdate.updateCheck(auto=True) # No repeat here.
        splupdate._SPLUpdateT = wx.PyTimer(autoUpdateCheck)

diff --git a/addon/appModules/splstudio/splconfui.py 
b/addon/appModules/splstudio/splconfui.py
index f9b307b..4829e3d 100755
--- a/addon/appModules/splstudio/splconfui.py
+++ b/addon/appModules/splstudio/splconfui.py
@@ -337,8 +337,12 @@ class SPLConfigDialog(gui.SettingsDialog):
                self.splConPassthrough = 
splconfig.SPLConfig["Advanced"]["SPLConPassthrough"]
                self.compLayer = 
splconfig.SPLConfig["Advanced"]["CompatibilityLayer"]
                self.autoUpdateCheck = 
splconfig.SPLConfig["Update"]["AutoUpdateCheck"]
+               self.updateInterval = 
splconfig.SPLConfig["Update"]["UpdateInterval"]
                sizer.Add(item)
                settingsSizer.Add(sizer, border=10, flag=wx.BOTTOM)
+               # To be unlocked in 8.0 beta 1.
+               #self.updateChannel = splupdate.SPLUpdateChannel
+               #self.pendingChannelChange = False
 
                # Translators: The label for a button in SPL add-on 
configuration dialog to reset settings to defaults.
                item = resetButton = wx.Button(self, label=_("Reset 
settings..."))
@@ -385,6 +389,10 @@ class SPLConfigDialog(gui.SettingsDialog):
                splconfig.SPLConfig["Advanced"]["SPLConPassthrough"] = 
self.splConPassthrough
                splconfig.SPLConfig["Advanced"]["CompatibilityLayer"] = 
self.compLayer
                splconfig.SPLConfig["Update"]["AutoUpdateCheck"] = 
self.autoUpdateCheck
+               splconfig.SPLConfig["Update"]["UpdateInterval"] = 
self.updateInterval
+               # To be unlocked in 8.0 beta 1.
+               #self.pendingChannelChange = splupdate.SPLUpdateChannel != 
self.updateChannel
+               #splupdate.SPLUpdateChannel = self.updateChannel
                splconfig.SPLSwitchProfile = self.switchProfile
                # Make sure to nullify prev profile if instant switch profile 
is gone.
                # 7.0: Don't do the following in the midst of a broadcast.
@@ -434,9 +442,17 @@ class SPLConfigDialog(gui.SettingsDialog):
                                dataLo = 0x00010000 if 
splconfig.SPLConfig["MetadataStreaming"]["MetadataEnabled"][url] else 0xffff0000
                                user32.SendMessageW(hwnd, 1024, dataLo | url, 
36)
                # Coordinate auto update timer restart routine if told to do so.
-               if not splconfig.SPLConfig["Update"]["AutoUpdateCheck"]:
+               # To be unlocked in 8.0 beta 1.
+               if not splconfig.SPLConfig["Update"]["AutoUpdateCheck"]: # 
7lts: or self.pendingChannelChange:
                        if splupdate._SPLUpdateT is not None and 
splupdate._SPLUpdateT.IsRunning(): splupdate._SPLUpdateT.Stop()
                        splupdate._SPLUpdateT = None
+                       # To be unlocked in 8.0 beta 1.
+                       #if self.pendingChannelChange:
+                               #splupdate._pendingChannelChange = True
+                               # Translators: A dialog message shown when 
add-on update channel has changed.
+                               #wx.CallAfter(gui.messageBox, _("You have 
changed the add-on update channel. You must restart NVDA for the change to take 
effect. Be sure to answer yes when you are asked to install the new version 
when prompted after restarting NVDA."),
+                               # Translators: Title of the update channel 
dialog.
+                               #_("Add-on update channel changed"), 
wx.OK|wx.ICON_INFORMATION)
                else:
                        if splupdate._SPLUpdateT is None: splconfig.updateInit()
 
@@ -1265,13 +1281,32 @@ class AdvancedOptionsDialog(wx.Dialog):
 
                mainSizer = wx.BoxSizer(wx.VERTICAL)
 
-               sizer = wx.BoxSizer(wx.HORIZONTAL)
+               sizer = wx.BoxSizer(wx.VERTICAL)
                # Translators: A checkbox to toggle automatic add-on updates.
                
self.autoUpdateCheckbox=wx.CheckBox(self,wx.NewId(),label=_("Automatically 
check for add-on &updates"))
                self.autoUpdateCheckbox.SetValue(self.Parent.autoUpdateCheck)
                sizer.Add(self.autoUpdateCheckbox, border=10,flag=wx.TOP)
+               # Translators: The label for a setting in SPL add-on 
settings/advanced options to select automatic update interval in days.
+               label = wx.StaticText(self, wx.ID_ANY, label=_("Update 
&interval in days"))
+               sizer.Add(label)
+               self.updateInterval= wx.SpinCtrl(self, wx.ID_ANY, min=1, max=30)
+               self.updateInterval.SetValue(long(parent.updateInterval))
+               self.updateInterval.SetSelection(-1, -1)
+               sizer.Add(self.updateInterval)
                mainSizer.Add(sizer, border=10, flag=wx.BOTTOM)
 
+               # LTS and 8.x only.
+               # To be unlocked in 8.0 beta 1.
+               #sizer = wx.BoxSizer(wx.HORIZONTAL)
+               # Translators: The label for a combo box to select update 
channel.
+               #label = wx.StaticText(self, wx.ID_ANY, label=_("&Add-on update 
channel:"))
+               #self.channels= wx.Choice(self, wx.ID_ANY, choices=["stable", 
"longterm"])
+               #self.updateChannels = ("stable", "lts")
+               
#self.channels.SetSelection(self.updateChannels.index(self.Parent.updateChannel))
+               #sizer.Add(label)
+               #sizer.Add(self.channels)
+               #mainSizer.Add(sizer, border=10, flag=wx.BOTTOM)
+
                sizer = wx.BoxSizer(wx.HORIZONTAL)
                # Translators: A checkbox to toggle if SPL Controller command 
can be used to invoke Assistant layer.
                
self.splConPassthroughCheckbox=wx.CheckBox(self,wx.NewId(),label=_("Allow SPL 
C&ontroller command to invoke SPL Assistant layer"))
@@ -1308,6 +1343,9 @@ class AdvancedOptionsDialog(wx.Dialog):
                parent.splConPassthrough = self.splConPassthroughCheckbox.Value
                parent.compLayer = 
self.compatibilityLayouts[self.compatibilityList.GetSelection()][0]
                parent.autoUpdateCheck = self.autoUpdateCheckbox.Value
+               parent.updateInterval = self.updateInterval.Value
+               # To be unlocked in 8.0 beta 1.
+               #parent.updateChannel = ("stable", 
"lts")[self.channels.GetSelection()]
                parent.profiles.SetFocus()
                parent.Enable()
                self.Destroy()

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index fb230a9..5c83953 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -26,6 +26,10 @@ SPLAddonCheck = 0
 SPLAddonState = {}
 # Update URL (the only way to change it is installing a different version from 
a different branch).
 SPLUpdateURL = "http://addons.nvda-project.org/files/get.php?file=spl-dev";
+# To be unlocked in 8.0 beta 1.
+#_pendingChannelChange = False
+#_updateNow = False
+#SPLUpdateChannel = "stable"
 # Update check timer.
 _SPLUpdateT = None
 # How long it should wait between automatic checks.
@@ -35,16 +39,29 @@ _retryAfterFailure = False
 # Stores update state.
 _updatePickle = os.path.join(globalVars.appArgs.configPath, "splupdate.pickle")
 
+# Remove comment in 8.0 beta 1.
+"""channels={
+       "stable":"http://addons.nvda-project.org/files/get.php?file=spl";,
+       "lts":"http://spl.nvda-kr.org/files/get.php?file=spl-lts7";,
+}"""
+
 # Come forth, update check routines.
 def initialize():
-       global SPLAddonState, SPLAddonSize, SPLAddonCheck
+       # To be unlocked in 8.0 beta 1.
+       global SPLAddonState, SPLAddonCheck #, _updateNow, SPLUpdateChannel
        try:
                SPLAddonState = cPickle.load(file(_updatePickle, "r"))
                SPLAddonCheck = SPLAddonState["PDT"]
                if "PSZ" in SPLAddonState: del SPLAddonState["PSZ"]
                if "PCH" in SPLAddonState: del SPLAddonState["PCH"]
+               # Unlock in 8.0 beta 1.
+               #_updateNow = "pendingChannelChange" in SPLAddonState
+               #if "UpdateChannel" in SPLAddonState:
+                       #SPLUpdateChannel = SPLAddonState["UpdateChannel"]
        except IOError:
                SPLAddonState["PDT"] = 0
+               #_updateNow = False
+               #SPLUpdateChannel = "stable"
 
 def terminate():
        global SPLAddonState
@@ -52,6 +69,10 @@ def terminate():
        stateChanged = SPLAddonState["PDT"] != SPLAddonCheck
        if stateChanged:
                SPLAddonState["PDT"] = SPLAddonCheck
+               # To be unlocked in 8.0 beta 1.
+               #SPLAddonState["UpdateChannel"] = SPLUpdateChannel
+               #if _pendingChannelChange:
+                       #SPLAddonState["pendingChannelChange"] = True
                cPickle.dump(SPLAddonState, file(_updatePickle, "wb"))
        SPLAddonState = None
 
@@ -61,60 +82,45 @@ def _versionFromURL(url):
        filename = url.split("/")[-1]
        return filename.split("stationPlaylist-")[1].split(".nvda-addon")[0]
 
-# Run the progress thread from another thread because urllib.urlopen blocks 
everyone.
-_progressThread = None
-
-def _updateProgress():
-       tones.beep(440, 40)
-
-def updateProgress():
-       global _progressThread
-       _progressThread = wx.PyTimer(updateProgress)
-       _progressThread.Start(1000)
-
-def stopUpdateProgress():
-       global _progressThread
-       _progressThread.Stop()
-       _progressThread = None
-
 def updateQualify(url):
        # The add-on version is of the form "major.minor". The "-dev" suffix 
indicates development release.
        # Anything after "-dev" indicates a try or a custom build.
        # LTS: Support upgrading between LTS releases.
        # 7.0: Just worry about version label differences (suggested by Jamie 
Teh from NV Access).
-       curVersion =SPLAddonVersion
+       curVersion = "7.0" if longterm else curVersion = SPLAddonVersion
        version = _versionFromURL(url.url)
-       # In case we are running the latest version, check the content length 
(size).
-       if version == curVersion:
-               return None
-       elif version > curVersion:
-               return version
-       else:
-               return ""
+       return None if version == curVersion else version
+
+_progressDialog = None
 
 # The update check routine.
 # Auto is whether to respond with UI (manual check only), continuous takes in 
auto update check variable for restarting the timer.
-# LTS: The "lts" flag is used to obtain update metadata from somewhere else 
(typically the LTS server).
-def updateCheck(auto=False, continuous=False, lts=False):
-       global _SPLUpdateT, SPLAddonCheck, _retryAfterFailure
+# ConfUpdateInterval comes from add-on config dictionary.
+def updateCheck(auto=False, continuous=False, confUpdateInterval=1):
+       # Unlock in 8.0 beta 1.
+       #if _pendingChannelChange:
+               #wx.CallAfter(gui.messageBox, _("Did you recently tell SPL 
add-on to use a different update channel? If so, please restart NVDA before 
checking for add-on updates."), _("Update channel changed"), wx.ICON_ERROR)
+               #return
+       global _SPLUpdateT, SPLAddonCheck, _retryAfterFailure, _progressDialog
        # Regardless of whether it is an auto check, update the check time.
        # However, this shouldnt' be done if this is a retry after a failed 
attempt.
        if not _retryAfterFailure: SPLAddonCheck = time.time()
+       updateInterval = confUpdateInterval*_updateInterval*1000
        # Should the timer be set again?
-       if continuous and not _retryAfterFailure: 
_SPLUpdateT.Start(_updateInterval*1000, True)
+       if continuous and not _retryAfterFailure: 
_SPLUpdateT.Start(updateInterval, True)
        # Auto disables UI portion of this function if no updates are pending.
-       if not auto: tones.beep(110, 40)
        # All the information will be stored in the URL object, so just close 
it once the headers are downloaded.
-       if not auto:
-               threading.Thread(target=updateProgress).start()
        updateCandidate = False
        try:
                url = urllib.urlopen(SPLUpdateURL)
+               # Replace in 8.0 beta 1.
+               #url = urllib.urlopen(channels[SPLUpdateChannel])
                url.close()
        except IOError:
                _retryAfterFailure = True
                if not auto:
-                       stopUpdateProgress()
+                       wx.CallAfter(_progressDialog.done)
+                       _progressDialog = None
                        # Translators: Error text shown when add-on update 
check fails.
                        wx.CallAfter(gui.messageBox, _("Error checking for 
update."), _("Check for add-on update"), wx.ICON_ERROR)
                if continuous: _SPLUpdateT.Start(600000, True)
@@ -125,7 +131,7 @@ def updateCheck(auto=False, continuous=False, lts=False):
                SPLAddonCheck = time.time()
        if url.code != 200:
                if auto:
-                       if continuous: _SPLUpdateT.Start(_updateInterval*1000, 
True)
+                       if continuous: _SPLUpdateT.Start(updateInterval, True)
                        return # No need to interact with the user.
                # Translators: Text shown when update check fails for some odd 
reason.
                checkMessage = _("Add-on update check failed.")
@@ -134,28 +140,22 @@ def updateCheck(auto=False, continuous=False, lts=False):
                qualified = updateQualify(url)
                if qualified is None:
                        if auto:
-                               if continuous: 
_SPLUpdateT.Start(_updateInterval*1000, True)
+                               if continuous: 
_SPLUpdateT.Start(updateInterval, True)
                                return
                        # Translators: Presented when no add-on update is 
available.
                        checkMessage = _("No add-on update available.")
-               elif qualified == "":
-                       if auto:
-                               if continuous: 
_SPLUpdateT.Start(_updateInterval*1000, True)
-                               return
-                       # Translators: An error text shown when one is using a 
newer version of the add-on.
-                       checkMessage = _("You appear to be running a version 
newer than the latest released version. Please reinstall the official version 
to downgrade.")
                else:
                        # Translators: Text shown if an add-on update is 
available.
                        checkMessage = _("Studio add-on {newVersion} is 
available. Would you like to update?").format(newVersion = qualified)
                        updateCandidate = True
-       if not auto: stopUpdateProgress()
+       if not auto:
+               wx.CallAfter(_progressDialog.done)
+               _progressDialog = None
        # Translators: Title of the add-on update check dialog.
        if not updateCandidate: wx.CallAfter(gui.messageBox, checkMessage, 
_("Check for add-on update"))
        else: wx.CallAfter(getUpdateResponse, checkMessage, _("Check for add-on 
update"), url.info().getheader("Content-Length"))
 
 def getUpdateResponse(message, caption, size):
-       global SPLAddonSize
        if gui.messageBox(message, caption, wx.YES | wx.NO | wx.CANCEL | 
wx.CENTER | wx.ICON_QUESTION) == wx.YES:
-               SPLAddonSize = hex(int(size))
                os.startfile(SPLUpdateURL)
 

diff --git a/addon/globalPlugins/SPLStudioUtils/__init__.py 
b/addon/globalPlugins/SPLStudioUtils/__init__.py
index fa2da9c..faa4f39 100755
--- a/addon/globalPlugins/SPLStudioUtils/__init__.py
+++ b/addon/globalPlugins/SPLStudioUtils/__init__.py
@@ -10,6 +10,7 @@ import globalPluginHandler
 import api
 from controlTypes import ROLE_LISTITEM
 import ui
+import globalVars
 from NVDAObjects.IAccessible import getNVDAObjectFromEvent
 import winUser
 import tones
@@ -97,7 +98,7 @@ class GlobalPlugin(globalPluginHandler.GlobalPlugin):
        # Translators: Script category for Station Playlist commands in input 
gestures dialog.
        scriptCategory = _("StationPlaylist Studio")
 
-                       #Global layer environment (see the app module for more 
information).
+       #Global layer environment (see the app module for more information).
        SPLController = False # Control SPL from anywhere.
 
        def getScript(self, gesture):
@@ -118,6 +119,8 @@ class GlobalPlugin(globalPluginHandler.GlobalPlugin):
 
        # Switch focus to SPL Studio window from anywhere.
        def script_focusToSPLWindow(self, gesture):
+               # 7.4: Forget it if this is the case like the following.
+               if globalVars.appArgs.secure: return
                # Don't do anything if we're already focus on SPL Studio.
                if "splstudio" in 
api.getForegroundObject().appModule.appModuleName: return
                else:
@@ -135,6 +138,8 @@ class GlobalPlugin(globalPluginHandler.GlobalPlugin):
        # The SPL Controller:
        # This layer set allows the user to control various aspects of SPL 
Studio from anywhere.
        def script_SPLControllerPrefix(self, gesture):
+               # 7.4: Red flag...
+               if globalVars.appArgs.secure: return
                global SPLWin
                # Error checks:
                # 1. If SPL Studio is not running, print an error message.

diff --git a/buildVars.py b/buildVars.py
index 8379b4c..0b8c63c 100755
--- a/buildVars.py
+++ b/buildVars.py
@@ -14,10 +14,10 @@ addon_info = {
        "addon_name" : "stationPlaylist",
        # Add-on summary, usually the user visible name of the addon.
        # Translators: Summary for this add-on to be shown on installation and 
add-on information.
-       "addon_summary" : _("Station Playlist Studio"),
+       "addon_summary" : _("StationPlaylist Studio"),
        # Add-on description
        # Translators: Long description to be shown for this add-on on add-on 
information from add-ons manager
-       "addon_description" : _("""Enhances support for Station Playlist Studio.
+       "addon_description" : _("""Enhances support for StationPlaylist Studio.
 In addition, adds global commands for the studio from everywhere."""),
        # version
        "addon_version" : "8.0-dev",


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/9c4d41b9b8bc/
Changeset:   9c4d41b9b8bc
Branch:      None
User:        josephsl
Date:        2016-07-26 08:50:33+00:00
Summary:     Merge branch '7.x'

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index 5c83953..00a649c 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -40,8 +40,8 @@ _retryAfterFailure = False
 _updatePickle = os.path.join(globalVars.appArgs.configPath, "splupdate.pickle")
 
 # Remove comment in 8.0 beta 1.
+# Not all update channels are listed. The one not listed here is the default 
("stable" for this branch).
 """channels={
-       "stable":"http://addons.nvda-project.org/files/get.php?file=spl";,
        "lts":"http://spl.nvda-kr.org/files/get.php?file=spl-lts7";,
 }"""
 
@@ -114,7 +114,8 @@ def updateCheck(auto=False, continuous=False, 
confUpdateInterval=1):
        try:
                url = urllib.urlopen(SPLUpdateURL)
                # Replace in 8.0 beta 1.
-               #url = urllib.urlopen(channels[SPLUpdateChannel])
+               # Look up the channel if different from the default.
+               #url = urllib.urlopen(SPLUpdateURL if SPLUpdateChannel not in 
channels else channels[SPLUpdateChannel])
                url.close()
        except IOError:
                _retryAfterFailure = True


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/22720ecce785/
Changeset:   22720ecce785
Branch:      None
User:        josephsl
Date:        2016-07-28 00:47:35+00:00
Summary:     Changed doc URL to reflect switching to GitHub

Affected #:  2 files

diff --git a/addon/appModules/splstudio/__init__.py 
b/addon/appModules/splstudio/__init__.py
index 9caffb9..31713fd 100755
--- a/addon/appModules/splstudio/__init__.py
+++ b/addon/appModules/splstudio/__init__.py
@@ -1807,7 +1807,7 @@ class AppModule(appModuleHandler.AppModule):
                wx.CallAfter(gui.messageBox, SPLAssistantHelp[compatibility], 
title)
 
        def script_openOnlineDoc(self, gesture):
-               
os.startfile("https://bitbucket.org/nvdaaddonteam/stationplaylist/wiki/SPLDevAddonGuide";)
+               
os.startfile("https://github.com/josephsl/stationplaylist/wiki/SPLDevAddonGuide";)
 
        def script_updateCheck(self, gesture):
                self.finish()

diff --git a/readme.md b/readme.md
index 37282a5..89b3fda 100755
--- a/readme.md
+++ b/readme.md
@@ -461,4 +461,4 @@ Version 4.0 supports SPL Studio 5.00 and later, with 3.x 
designed to provide som
 
 [3]: http://spl.nvda-kr.org/files/get.php?file=spl-lts7
 
-[4]: https://bitbucket.org/nvdaaddonteam/stationplaylist/wiki/SPLAddonGuide
+[4]: https://github.com/josephsl/stationplaylist/wiki/SPLAddonGuide


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/8a79691086e8/
Changeset:   8a79691086e8
Branch:      None
User:        josephsl
Date:        2016-07-28 06:59:49+00:00
Summary:     Merge branch '7.x'

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index 00a649c..504a5b3 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -87,9 +87,8 @@ def updateQualify(url):
        # Anything after "-dev" indicates a try or a custom build.
        # LTS: Support upgrading between LTS releases.
        # 7.0: Just worry about version label differences (suggested by Jamie 
Teh from NV Access).
-       curVersion = "7.0" if longterm else curVersion = SPLAddonVersion
        version = _versionFromURL(url.url)
-       return None if version == curVersion else version
+       return None if version == SPLAddonVersion else version
 
 _progressDialog = None
 


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/0559961abe50/
Changeset:   0559961abe50
Branch:      None
User:        josephsl
Date:        2016-07-28 07:07:59+00:00
Summary:     Merge branch '7.x'

Affected #:  2 files

diff --git a/addon/appModules/splstudio/__init__.py 
b/addon/appModules/splstudio/__init__.py
index 31713fd..d093d8b 100755
--- a/addon/appModules/splstudio/__init__.py
+++ b/addon/appModules/splstudio/__init__.py
@@ -1815,7 +1815,7 @@ class AppModule(appModuleHandler.AppModule):
                # Display the update check progress dialog (inspired by add-on 
installation dialog in NvDA Core).
                splupdate._progressDialog = 
gui.IndeterminateProgressDialog(gui.mainFrame,
                # Translators: The title of the dialog presented while checking 
for add-on updates.
-               _("Add-on update"),
+               _("Add-on update check"),
                # Translators: The message displayed while checking for newer 
version of Studio add-on.
                _("Checking for new version of Studio add-on..."))
                threading.Thread(target=splupdate.updateCheck, 
kwargs={"continuous":splconfig.SPLConfig["Update"]["AutoUpdateCheck"], 
"confUpdateInterval":splconfig.SPLConfig["Update"]["UpdateInterval"]}).start()

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index 504a5b3..d0fb211 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -122,7 +122,7 @@ def updateCheck(auto=False, continuous=False, 
confUpdateInterval=1):
                        wx.CallAfter(_progressDialog.done)
                        _progressDialog = None
                        # Translators: Error text shown when add-on update 
check fails.
-                       wx.CallAfter(gui.messageBox, _("Error checking for 
update."), _("Check for add-on update"), wx.ICON_ERROR)
+                       wx.CallAfter(gui.messageBox, _("Error checking for 
update."), _("Studio add-on update"), wx.ICON_ERROR)
                if continuous: _SPLUpdateT.Start(600000, True)
                return
        if _retryAfterFailure:
@@ -152,8 +152,8 @@ def updateCheck(auto=False, continuous=False, 
confUpdateInterval=1):
                wx.CallAfter(_progressDialog.done)
                _progressDialog = None
        # Translators: Title of the add-on update check dialog.
-       if not updateCandidate: wx.CallAfter(gui.messageBox, checkMessage, 
_("Check for add-on update"))
-       else: wx.CallAfter(getUpdateResponse, checkMessage, _("Check for add-on 
update"), url.info().getheader("Content-Length"))
+       if not updateCandidate: wx.CallAfter(gui.messageBox, checkMessage, 
_("Studio add-on update"))
+       else: wx.CallAfter(getUpdateResponse, checkMessage, _("Studio add-on 
update"), url.info().getheader("Content-Length"))
 
 def getUpdateResponse(message, caption, size):
        if gui.messageBox(message, caption, wx.YES | wx.NO | wx.CANCEL | 
wx.CENTER | wx.ICON_QUESTION) == wx.YES:


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/649873dd5cc4/
Changeset:   649873dd5cc4
Branch:      None
User:        josephsl
Date:        2016-08-01 08:01:02+00:00
Summary:     Merge branch 'stable'

Affected #:  14 files

diff --git a/addon/doc/ar/readme.md b/addon/doc/ar/readme.md
new file mode 100644
index 0000000..437e9b8
--- /dev/null
+++ b/addon/doc/ar/readme.md
@@ -0,0 +1,724 @@
+# StationPlaylist Studio #
+
+* مطورو الإضافة: Geoff Shang, Joseph Lee وآخرون
+* تحميل [الإصدار النهائي][1]
+* تحميل [الإصدار التجريبي][2]
+
+تقوم هذه الإضافة البرمجية بتحسين استخدام الكفيف لتطبيق Station Playlist
+Studio, فضلا عن إضافة أدوات للتحكم في الأستوديو من أي مكان.
+
+للاطلاع على المزيد حول هذه الإضافة, يرجى قراءة [دليل الإضافات البرمجية][3].
+
+ملحوظة هامة: تتطلب هذه الإضافة NVDA2015.3 وما بعده وإصدار spl 5.00 وما
+بعده. إذا قمت بتثبيت nvda2016.1 وما بعده على نظام ويندوز 8 وما بعده, يرجى
+تعطيل دعم خفض الأصوات الأخرى.
+
+## مفاتيح الاختصار
+
+* Alt+Shift+T من نافذة الاستوديو: للإعلان عن الوقت المنقضي للمسار أو التراك
+  المشغل حاليا.
+* Control+Alt+T (مسح بإصبعين لأسفل بنمط SPL) من نافذة الاستوديو: للإعلان عن
+  الوقت المتبقي للمسار أو التراك المشغل حاليا.
+* NVDA+Shift+F12 (مسح بإصبعين لأعلى بنمط SPL) من نافذة الاستوديو: للإعلان عن
+  وقت المذيع.
+* Control+NVDA+1 من نافذة الاستوديو: التنقل بين كيفية الإعلان عن الرسائل
+  (كرسائل الآلية ورسائل نهاية البحث في المكتبة) بالصفير أو بالكلمات.
+* Control+NVDA+2 (مسح بإصبعين يمين بنمط SPL) من نافذة الاستوديو: لفتح محاورة
+  نهاية المسار أو التراك.
+* Alt+NVDA+2 (مسح بأصبعين يسار بنمطSPL) من نافذة الاستوديو: لفتح محاورة
+  إعدادات التنبيه بمقدمة الأغنية.
+* Control+NVDA+3 من نافذة الاستوديو: لفتح نمط استكشاف التنويهات والمفاتيح
+  المنوطة بكل تنويه أو إعلان
+* Control+NVDA+4 من نافذة الاستوديو: لفتح محاورة تنبيه الميكروفون.
+* اضغط ctrl+NVDA+F من نافذة الأستديو لفتح محاورة اختيار المسارات بحسب المطرب
+  أو الأغنية. اضغط NVDA+f3 للبحث نحو التالي واضغط Shift+NVDA+f3 للبحث نحو
+  السابق. 
+* Alt+NVDA+R من نافذة الاستوديو: لخطوات إعدادات الإعلان عن البحث في المكتبة
+* Control+Shift+X من نافذة الاستوديو: لخطوات إعدادات ميقات البرايل.
+* Control+Alt+right/left arrow (while focused on a track): Announce
+  next/previous track column.
+* Control+NVDA+0 or Alt+NVDA+0 from Studio window: Opens the Studio add-on
+  configuration dialog.
+* Control+NVDA+- (hyphen) من نافذة الاستوديو: إرسال الاستفسارات لمطور
+  الإضافة باستخدام منظم البريد الافتراضي لديك.
+
+## الأوامر غير المعينة
+
+الأوامر التالية لا يتم تعيينها افتراضيا. وإذا أردت تعيينها فعليك الذهاب إلى
+محاورة اختصارات NVDA لإضافة الاختصارات المخصصة. 
+
+* التحول إلى نافذة الأستديو من أي برنامج آخر. 
+* نمط التحكم في تطبيق SPL. 
+* نمط SPL المساعد من الأستوديو. 
+* الإعلان عن الوقت متضمن الثواني من SPL Studio.
+* التبديل بين تشغيل وتعطيل إدارة المسار (تعمل بشكل جيد عند تنشيط أحد
+  المسارات، لتعيين اختصار لهذه الخاصية, اختر مسار, ثم افتح محاورة تخصيص
+  اختصارات NVDA).
+* الإعلان عن درجة الحرارة
+* الإعلان عن عنوان المسار التالي إذا كان مجدول.
+* الإعلان عن عنوان المسار المشغل حاليا
+* تحديد المسار الحالي لبدأ تحليل وقت المسار
+* إجراء تحليل وقت المسار
+* البحث عن نص بأعمدة محددة
+* البحث عن مسارات تقع بين معدل وقت معين عبر باحث عن معدلات الوقت.
+* تشغيل أو تعطيل حالة بث البيانات بسرعة
+
+## أوامر إضافية عند استخدام Sam encoder أو SPL.
+
+تتوفر المفاتيح التالية عند استخدام Sam encoder أو SPL:
+
+* F9: الاتصال بالخادم الذي سيتم بث الملفات من خلاله.
+* F10: (SAM encoder فقط) قطع الاتصال بالخادم.
+* Control+F9/Control+F10 (تشفير SAM فقط): اتصال أو قطع اتصال كل التشفيرات,
+  على التوالي.
+* F11: ينتقل بين تشغيل وتعطيل الرجوع لنافذة الاستوديو بعد الاتصال بالخادم.
+* shift+F11: ينتقل بين تشغيل وتعطيل إمكانية تشغيل أول مسار بعد الاتصال
+  بالخادم.
+* Control+F11: التبديل بين تشغيل وتعطيل المراقبة الخلفية للتشفير المحدد.
+* F12: Opens a dialog to enter custom label for the selected encoder or
+  stream.
+* Control+F12: يفتح محاورة لاختيار التشفير الذي قمت بحذفه (لإعادة ترتيب
+  أسماء الفيديوهات التي ستبث وإعدادات التشفير).
+* Control+NVDA+0 or Alt+NVDA+0: Opens encoder settings dialog to configure
+  options such as stream label.
+
+فضلا عن ذلك, إتاحة أوامر لمراجعة الأعمدة وتشمل:
+
+* Control+NVDA+1: موقع التشفير
+* Control+NVDA+2: البث
+* Control+NVDA+3 من sam encoder: تنسيق التشفير.
+* Control+NVDA+3 (من نافذة التشفير): إعدادات التشفير
+* control+nvda+4 (من نافذة تشفير sam) حالة اتصال التشفير.
+* control+nvda+4 من تشفير spl: معدل النقل أو حالة الاتصال.
+* control+nvda+5 من تشفير SAM: وصف حالة الاتصال
+
+## مساعد نمط أوامر SPL 
+
+This layer command set allows you to obtain various status on SPL Studio,
+such as whether a track is playing, total duration of all tracks for the
+hour and so on. From any SPL Studio window, press the SPL Assistant layer
+command, then press one of the keys from the list below (one or more
+commands are exclusive to playlist viewer). You can also configure NvDA to
+emulate commands from other screen readers.
+
+The available commands are:
+
+* A: التشغيل الآلي.
+* C (Shift+C in JAWS and Window-Eyes layouts): Title for the currently
+  playing track.
+* C (JAWS and Window-Eyes layouts): Toggle cart explorer (playlist viewer
+  only).
+* D (R in JAWS layout): Remaining duration for the playlist (if an error
+  message is given, move to playlist viewer and then issue this command).
+* E (G in Window-Eyes layout): Metadata streaming status.
+* Shift+1 through Shift+4, Shift+0: Status for individual metadata streaming
+  URL's (0 is for DSP encoder).
+* E (Window-Eyes layout): Elapsed time for the currently playing track.
+* F: Find track (playlist viewer only).
+* H: مدة الموسيقى للساعة الحالية.
+* Shift+H: Remaining track duration for the hour slot.
+* I (L in JAWS or Window-Eyes layouts): Listener count.
+* K: Move to the marked track (playlist viewer only).
+* Control+K: Set the current track as the place marker track (playlist
+  viewer only).
+* L (Shift+L in JAWS and Window-Eyes layouts): Line in.
+* M:  الميكروفون
+* N: لتشغيل المسار التالي.
+* P: حالة التشغيل (المسار يعمل أم متوقف).
+* shift+P: حدة المسار الحالي.
+* R (Shift+E in JAWS and Window-Eyes layouts): Record to file
+  enabled/disabled.
+* shift+r: مراقبة حالة التقدم في البحث بالمكتبة.
+* s: موعد بداية تشغيل المسار (إذا كان في جدول).
+* Shift+S: Time until selected track will play.
+* T: تعطيل أو تشغيل نمط تعيين مفاتيح للتنويهات.
+* U: وقت الاستوديو
+* Control+Shift+U: Check for add-on updates.
+* W: حالة التقس ودرجة الحرارة إذا كانت معدة.
+* y: حالة قائمة التشغيل المعدلة.
+* 1 through 0 (6 for Studio 5.0x): Announce column content for a specified
+  column.
+* F9: Mark current track for track time analysis (playlist viewer only).
+* F10: Perform track time analysis (playlist viewer only).
+* f12: الانتقال بين الملف الحالي وملف لم يتم تعريفه من قبل.
+* F1: نمط المساعدة
+* shift+f1: فتح دليل المستخدم على الإنترنت
+
+## نمط التحكم في تطبيق SPL 
+
+هو عبارة عن نمط يزودك بمجموعة من المفاتيح كي تتمكن من التحكم في التطبيق من
+أي مكان. اضغط أمر نمط التحكم في SPL وسينطق NVDA, "نمط التحكم في Station
+PlayList Studio." اضغط أي من الأوامر التي سيلي ذكرها للتحكم في مختلف إعدادات
+الاستوديو بالتطبيق كالتحكم في تشغيل أو تعطيل الميكروفون, أو تشغيل المسار
+التالي.
+
+والأوامر التي يتيحها هذا النمط هي:
+
+* اضغط P لتشغيل المسار التالي.
+* اضغط U لعمل توقف مؤقت أو إعادة التشغيل مرة أخرى.
+* اضغط S لوقف تشغيل المسار بطريقة التلاشي (fade out), أو اضغط حرف T لتوقف
+  المسار فورا.
+* اضغط M أو Shift+M لتشغيل أو تعطيل الميكروفون, على التوالي, أو N لتشغيل
+  الميكروفون دون التلاشي
+* اضغط a لتفعيل خاصية التشغيل الآلي, واضغط Shift+A لتعطيلها.
+* اضغط L لتفعيل مدخل الصوت واضغط shift+l لتعطيله.
+* Press R to hear remaining time for the currently playing track.
+* اضغط Shift+R للإعلان عن مدى التقدم في البحث في المكتبة.
+* اضغط E للحصول على عدد وأسماء التشفيرات الجاري مراقبتها.
+* Press I to obtain listener count.
+* اضغط f1 لإظهار محاورة مساعدة بقائمة بالأوامر المتاحة.
+
+## تنبيهات المسار
+
+افتراضيا, سيصدر NVDA صوت صفير قرب نهاية المسار بخمس ثواني (النهاية) أو/و
+المقدمة. لتغيير هذه القيمة من خمس ثواني أو لتعطيل هذا الإعداد, اضغط على
+Control+NVDA+2  أو Alt+NVDA+2 لفتح محاورة نهاية المسار أو نهاية الأغنية على
+التوالي. كما يمكنك استخدام إعدادات الإضافة لإعداد ما إذا كنت ستسمع صفير, أم
+رسالة أو كلاهما عند تشغيل التنبيهات.
+
+## تنبيه الميكروفون
+
+يمكنك إعداد NVDA كي يصدر صوت عندما يكون الميكروفون مشغل لفترة. اضغط
+NVDA+control+4 لإعداد وقت إصدار الصوت بالثوان (الرقم 0 يعطل إصدار الصوت).
+
+## الباحث عن المسارات
+
+إذا أردت البحث عن أغنية باسم المطرب أو باسم الأغنية, من قائمة المسارات, اضغط
+Control+NVDA+ F. اكتب اسم المطرب أو اسم الأغنية وسوف يضعك NVDA عندها إن وجدت
+أو سيظهر رسالة خطأ إن لم يجد الأغنية التي تبحث عنها. وللبحث عن مطرب أو أغنية
+سابقا اضغط NVDA+f3 أو اضغط NVDA+Shift+f3 للبحث في التالي أو السابق. 
+
+ملحوظة: الباحث عن المسارات حساس لحالة الأحرف. 
+
+## مستكشف التنويهات
+
+وفقا لإصدار البرنامج, يتيح لك برنامج SPL تعيين مفتاح ل96 تنويه. يتيح لك NVDA
+سماع أي تنويه معين لهذه الأوامر.
+
+لمعرفة المفتاح المنوط بكل تنويه, من نافذة SPL, اضغط Control+NVDA+3. بالضغط
+على هذا الاختصار مرة واحدة سيخبرك بالمفتاح المنوط بالتنويه وبالضغط عليه
+مرتين سيقوم بتشغيل التنويه. اضغط Control+NvDA+3 للخروج من نمط مستكشف
+التنويهات. انظر دليل الإضافة لمعرفة المزيد عن مستكشف التنويهات.
+
+## طلب المسار
+
+You can use arrow keys to review various information about a track. To turn
+Track Dial on, while a track is focused in the main playlist viewer, press
+the command you assigned for toggling Track Dial. Then use left and right
+arrow keys to review information such as artist, duration and so
+on. Alternatively, press Control+Alt+left or right arrows to navigate
+between columns without invoking Track Dial.
+
+## تحليل وقت المسار
+
+للحصول على مدة المسارات المحددة لتشغيلها, قم بتحديد المسار الحالي لبدأ عملية
+تحليل الوقت (من مساعد spl اضغط على f9), ثم اضغط على f10 بعد الانتهاء من
+التحديد.
+
+## Columns Explorer
+
+By pressing SPL Assistant, 1 through 0 (6 for Studio 5.01 and earlier), you
+can obtain contents of specific columns. By default, these are artist,
+title, duration, intro, category and filename (Studio 5.10 adds year, album,
+genre and time scheduled). You can configure which columns will be explored
+via columns explorer dialog found in add-on settings dialog.
+
+## محاورة الإعدادات
+
+From studio window, you can press Control+NVDA+0 or Alt+NVDA+0 to open the
+add-on configuration dialog. Alternatively, go to NVDA's preferences menu
+and select SPL Studio Settings item. This dialog is also used to manage
+broadcast profiles.
+
+## نمط اللمس لتطبيق SPL
+
+إذا كنت تستخدم الاستوديو من حاسوب بشاشة لمس يعمل بنظام التشغيل ويندوز 8 وما
+بعده ولديك NVDA 2012.3 وما بعده, يمكنك أداء بعض الأوامر من شاشة اللمس. أولا
+استخدم لمسة ب3 أصابع للانتقال لنمط اللمس, ثم استخدم أوامر اللمس المسرودة
+أعلاه لأداء المهام.
+
+## Changes for 7.3
+
+* Slight performance improvements when looking up information such as
+  automation via some SPL Assistant commands.
+* ترجمة الإضافة لمزيد من اللغات
+
+## Changes for 7.2
+
+* Due to removal of old-style internal configuration format, it is mandatory
+  to install add-on 7.2. Once installed, you cannot go back to an earlier
+  version of the add-on.
+* Added a command in SPL Controller to report listener count (I).
+* You can now open SPL add-on settings and encoder settings dialogs by
+  pressing Alt+NVDA+0. You can still use Control+NVDA+0 to open these
+  dialogs (to be removed in add-on 8.0).
+* In Track Tool, you can use Control+Alt+left or right arrow keys to
+  navigate between columns.
+* Contents of various Studio dialogs such as About dialog in Studio 5.1x are
+  now announced.
+* In SPL Encoders, NVDA will silence connection tone if auto-connect is
+  enabled and then turned off from encoder context menu while the selected
+  encoder is connecting.
+* ترجمة الإضافة لمزيد من اللغات
+
+## Changes for 7.1
+
+* Fixed erorrs encountered when upgrading from add-on 5.5 and below to 7.0.
+* When answering "no" when resetting add-on settings, you'll be returned to
+  add-on settings dialog and NVDA will remember instant switch profile
+  setting.
+* NVDA will ask you to reconfigure stream labels and other encoder options
+  if encoder configuration file becomes corrupted.
+
+## Changes for 7.0
+
+* Added add-on update check feature. This can be done manually (SPL
+  Assistant, Control+Shift+U) or automatically (configurable via advanced
+  options dialog from add-on settings).
+* It is no longer required to stay in the playlist viewer window in order to
+  invoke most SPL Assistant layer commands or obtain time announcements such
+  as remaining time for the track and broadcaster time.
+* Changes to SPL Assistant commands, including playlist duration (D),
+  reassignment of hour selection duration from Shift+H to Shift+S and
+  Shift+H now used to announce duration of remaining tracks for the current
+  hour slot, metadata streaming status command reassigned (1 through 4, 0 is
+  now Shift+1 through Shift+4, Shift+0).
+* It is now possible to invoke track finder via SPL Assistant (F).
+* SPL Assistant, numbers 1 through 0 (6 for Studio 5.01 and earlier) can be
+  used to announce specific column information. These column slots can be
+  changed under Columns Explorer item in add-on settings dialog.
+* Fixed numerous errors reported by users when installing add-on 7.0 for the
+  first time when no prior version of this add-on was installed.
+* Improvements to Track Dial, including improved responsiveness when moving
+  through columns and tracking how columns are presented on screen.
+* Added ability to press Control+Alt+left or right arrow keys to move
+  between track columns.
+* It is now possible to use a different screen reader command layout for SPL
+  Assistant commands. Go to advanced options dialog from add-on settings to
+  configure this option between NVDA, JAWS and Window-Eyes layouts. See the
+  SPL Assistant commands above for details.
+* NVDA can be configured to switch to a specific broadcast profile at a
+  specific day and time. Use the new triggers dialog in add-on settings to
+  configure this.
+* NVDA will report name of the profile one is switching to via instant
+  switch (SPL Assistant, F12) or as a result of time-based profile becoming
+  active.
+* Moved instant switch toggle (now a checkbox) to the new triggers dialog.
+* Entries in profiles combo box in add-on settings dialog now shows profile
+  flags such as active, whether it is an instant switch profile and so on.
+* If a serious problem with reading broadcast profile files are found, NVDA
+  will present an error dialog and reset settings to defaults instead of
+  doing nothing or sounding an error tone.
+* Settings will be saved to disk if and only if you change settings. This
+  prolongs life of SSD's (solid state drives) by preventing unnecessary
+  saves to disk if no settings have changed.
+* In add-on settings dialog, the controls used to toggle announcement of
+  scheduled time, listener count, cart name and track name has been moved to
+  a dedicated status announcements dialog (select status announcement button
+  to open this dialog).
+* Added a new setting in add-on settings dialog to let NVDA play beep for
+  different track categories when moving between tracks in playlist viewer.
+* Attempting to open metadata configuration option in add-on settings dialog
+  while quick metadata streaming dialog is open will no longer cause NVDA to
+  do nothing or play an error tone. NvDA will now ask you to close metadata
+  streaming dialog before you can open add-on settings.
+* When announcing time such as remaining time for the playing track, hours
+  are also announced. Consequently, the hour announcement setting is enabled
+  by default.
+* Pressing SPL Controller, R now causes NVDA to announce remaining time in
+  hours, minutes and seconds (minutes and seconds if this is such a case).
+* In encoders, pressing Control+NVDA+0 will present encoder settings dialog
+  for configuring various options such as stream label, focusing to Studio
+  when connected and so on.
+* In encoders, it is now possible to turn off connection progress tone
+  (configurable from encoder settings dialog).
+
+## Changes for 6.4
+
+* Fixed a major problem when switching back from an instant switch profile
+  and the instant switch profile becomes active again, seen after deleting a
+  profile that was positioned right before the previously active
+  profile. When attempting to delete a profile, a warning dialog will be
+  shown if an instant switch profile is active.
+
+## مستجدات الإصدار 6.3
+
+* تحسينات أمنية داخلية
+* عند بدأ تشغيل الإصدار 6.3 وما بعده من الإضافة لأول مرة على نظام ويندوز 8
+  وما بعده مع NVDA2016.1 وما بعده, ستظهر محاورة تطلب منك تعطيل نمط خفض
+  الأصوات الأخرى وذلك بالضغط على NVDA+shift+d ويمكنك تحديد المربع الذي يمنع
+  ظهور هذا التنبيه في المرات القادمة.
+* إضافة اختصار لإرسال الأخطاء البرمجية, والاقتراحات والاستفسارات الأخرى
+  لمطور الإضافة (Control+NVDA+dash (hyphen, "-")).
+* ترجمة الإضافة لمزيد من اللغات
+
+## مستجدات الإصدار 6.2
+
+* معالجة مشكلة كانت تحدث مع اختصار بقية قائمة التشغيل (D من مساعد spl (r في
+  النمط التوافقي)) حيث كان يتم الإعلان عن مدة الساعة الحالية بدلا من الإعلان
+  عن مدة قائمة التشغيل كلها (حيث يمكن تعديل ذلك من الإعدادات المتقدمة
+  بمحاورة إعدادات الإضافة).
+* يمكن ل NVDA الآن الإعلان عن المسار المشغل حاليا من أي برنامج (يمكن إعداد
+  ذلك من إعدادات الإضافة).
+* أصبح الإعداد المستخدم في في جعل أمر المتحكم في spl يستدعي مساعد Spl مقدم
+  (حيث كان ذلك الإعداد مفعل في كل الأوقات).
+* في تشفير sam, سيعمل الاختصاران Control+F9 و Control+F10 الآن بشكل صحيح.
+* في التشفيرات, عند تنشيط تشفير معين وكان هذا التشفير معد كي تتم مراقبته في
+  الخلفية, فسيبدأ NVDA عملية المراقبة آليا.
+
+## مستجدات الإصدار 6.1
+
+* من الآن ستكون إعدادات بيانات البث وتضمين ترتيب إعلان الأعمدة في أوضاع.
+* عند تغير الوضع, سيعلن عن بيانات البث الصحيحة.
+* عند فتح محاورة إعدادات بيانات البث السريعة (لم يعين لها مفتاح), سيتم تطبيق
+  التعديلاتللوضع النشط.
+* عند بدأ تشغيل البرنامج, تغيرت طريقة عرض الأخطاء إذا كان الوضع الذي به خطأ
+  هو الوضع العادي.
+* عند تغيير اختصارات إعدادات معينة كاختصار الإعلان عن الحالة, تمت معالجة خطأ
+  عدم الاحتفاظ بالإعدادات المعدلة عند الانتقال لوضع آخر.
+* عند استخدام أي من الأوامر المساعدة ل SPL باختصار مخصص (كاختصار المسار
+  التالي), لم يعد يتطلب منك أن تبقى في عارض قائمة التشغيل لاستخدام هذه
+  الأوامر (يمكن تنفيذهم من أي مكان من نوافذ أخرى).
+
+## مستجدات الإصدار 5.0
+
+* أوامر جديدة بمساعد spl, وتشمل تلك الأوامر الإعلان عن عنوان المسار المشغل
+  حاليا (c), الإعلان عن حالة بث البيانات (e, من 1 إلى 4 و 0) وفتح دليل
+  المستخدم على الإنترنت (Shift+F1).
+* إمكانية عمل حزمة من الإعدادات المفضلة كملفات شخصية لاستخدامها أثناء العرض
+  وللانتقال إلى ملف شخصي لم يعرف من قبل. انظر دليل الإضافة للمزيد من
+  التفاصيل عن ملفات النشرات الصوتية.
+* إضافة إعداد جديد للتحكم في طول الرسالة (سيتم تقليل بعض الرسائل عند تشغيل
+  مستوى متقدم من الإطناب).
+* إضافة إعداد جديد للسماح ل NVDA بالإعلان عن الساعات, والدقائق, والثواني
+  لأوامر مدة المسار أو قائمة التشغيل (الخصائص المندرجة تحت هذا الإعداد تشمل
+  الإعلان عن الوقت المنقضي والوقت المتبقي للمسار المشغل حاليا, وتحليل وقت
+  المسار وخصائص أخرى).
+* يمكن ل NVDA إخبارك بالوقت الإجمالي لنطاق من المسارات عبر خاصية تحليل وقت
+  المسار. اضغط على f9 بمساعد spl لتحديد المسار الحالي كبداية للتحديد, انتقل
+  إلى نهاية المسارات المراد وضعها في نطاق ثم اضغط الأمر f10. يمكن إعادة
+  تخصيص هذه الأوامر فلا يجب على المستخدم استدعاء نمط مساعد أوامر spl لإجراء
+  تحليل وقت المسار.
+* إضافة محاورة للبحث عن عمود (لم يتم تعيين أمر له) للبحث عن نص بأعمدة محددة
+  مثل المطرب أو جزء من اسم ملف.
+* إضافة محاورة جديدة للبحث عن الوقت الإجمالي لنطاق من المسارات (لم يتم تعيين
+  أمر له) وهذا الأمر مفيد عندما تريد ملء وقت متبقي بالساعة فستبحث عن مسار
+  بمدة الوقت المتبقي.
+* إضافة إمكانية إعادة ترتيب الإعلان عن أعمدة المسار وللإيجاز في الإعلان عن
+  بعض الأعمدة إذا كان مربع التحديد"استخدام ترتيب الشاشة" غير محدد من محاورة
+  إعدادات الإضافة. استخدم محاورة "إدارة الإعلان عن الأعمدة" لإعادة ترتيب
+  الأعمدة.
+* إضافة محاورة (لم يتم تعيين أمر لها) لتنقل بين تعطيل وتشغيل الإعلان عن حالة
+  بث البيانات بسرعة.
+* إضافة إعداد لتحديد متى يتم الإعلان عن حالة بث البيانات ولتشغيل الإعلان عن
+  حالة بث البيانات.
+* إضافة إمكانية تحديد مسار كعلامة مرجعية للعودة إليه فيما بعد (control+k
+  بمساعد spl لتحديد المسار كعلامة مرجعية و k بمساعد spl للانتقال إلى المسار
+  المحدد).
+* تحسين الأداء عند البحث عن مسار تالي أو سابق يحتوي على نص البحث.
+* إضافة إعداد للإعلان عن تنشيط الميكروفون ويكون ما بين الصفير أو الرسائل أو
+  كلاهما.
+* أصبح من الممكن إعداد تنبيه الميكروفون بين 0 (للتعطيل) وساعتين (7200 ثانية)
+  واستخدام الأسهم للتنقل بين قيم هذا الإعداد.
+* إضافة إعداد لإتاحة إعلان بتنشيط الميكروفون يسمع كل فترة.
+* يمكنك الآن استخدام أمر تشغيل وتعطيل إدارة المسارات بنافذة الاستوديو لإدارة
+  مسار لم تقم بتعيين أمر لإدارته.
+* إضافة إمكانية استخدام نمط أوامر SPL لاستدعاء مساعد SPL (والذي يمكن العثور
+  عليه بمحاورة الإعدادات المتقدمة للإضافة بمحاورة إعدادات الإضافة).
+* إضافة إمكانية استخدام NVDA لبعض الأوامر التي يستخدمها SPL مع بعض قارآت
+  الشاشة الأخرى. لإعداد ذلك, اذهب إلى إعدادات الإضافة, اختر إعدادات متقدمة
+  وقم بتحديد نمط التوافق مع قارآت الشاشة.
+* في التشفيرات, سيتم تذكر الإعدادات مثل إعداد تنشيط التطبيق عند الاتصال.
+* أصبح من الممكن عرض أعمدة متعددة من نافذة التشفير (مثل حالة اتصال التشفير)
+  عبر الضغط على Control+NVDa زائد رقم الأمر, عد إلى أوامر التشفير المذكورة
+  أعلاه.
+* معالجة خطأ برمجي نادر كان يحدث عند الانتقال للتطبيق أو إغلاق إحدى محاورات
+  NVDA (مثل محاورات الإضافة) وهو منع أوامر المسارات من العمل بشكل جيد (مثل
+  أمر إدارة المسارات).
+
+## مستجدات الإصدار 5.6
+
+* في studio 5.10 وما بعده, لم يعد يعلن NVDA عن رسالة "غير محدد" عند تشغيل
+  المسار المحدد.
+* نظرا لوجود مشكلة في تطبيق studio نفسه, سيعلن NVDA الآن عن اسم التراك
+  المشغل حاليا آليا. تمت إضافة خيار لتعطيل وتشغيل هذا الإعداد بمحاورة
+  إعدادات الإضافة.
+
+## مستجدات الإصدار 3.0
+
+* سيتم تذكر إعداد التشغيل بعد الاتصال عند البعد عن نافذة التشفير.
+
+## مستجدات الإصدار 5.4
+
+* إجراء فحص للمكتبة من محاورة إدراج المسارات لم يعد ينتج عنه عدم إعلان NVDA
+  عن حالة الفحص أو تشغيل نغمات الخطأ إذا كان NVDA معد للإعلان عن مدى التقدم
+  في فحص المكتبة أو عدد الفحص.
+* ترجمة الإضافة لمزيد من اللغات
+
+## مستجدات الإصدار 5.3
+
+* توفير حل لمشكلة تشفير SAM (عدم تشغيل المسار التالي إذا كان يوجد مسار مشغل
+  بالفعل وعندما يكون التشفير متصل(.
+* لم يعد NVDA يصدر صوت الخطأ أو لم يفعل شيء إذا تم ضغط F1 المنوط بتشغيل نمط
+  المساعدة ل SPL.
+
+## مستجدات الإصدار 5.2
+
+* لم يعد يسمح NVDA بفتح محاورتي الإعدادات والتنبيهات. ستظهر رسالة تحذيرية
+  تخبرك بضرورة إغلاق المحاورة المفتوحة أولا قبل الشروع في فتح محاورة أخرى.
+* عند مراقبة تشفير أو أكثر, فإن الضغط على E سيعلن الآن عن عدد التشفير ومعرف
+  التشفير واسم ملف التشغيل إن وجد.
+* يدعم NVDA كل أوامر الاتصال وقطع الاتصال (Control+F9/Control+F10) بتشفيرات
+  سام SAM encoders.
+* لم يعد يقوم NVDA بتشغيل المسار التالي إذا كان أحد التشفيرات متصل أثناء
+  تشغيل مسار من الاستوديو وأنه تم إخبار الاستوديو بتشغيل مسارات أثناء اتصال
+  التشفيرات.
+* ترجمة الإضافة لمزيد من اللغات
+
+## مستجدات الإصدار 5.1
+
+* أصبح من الممكن مراجعة الأعمدة الفردية بأداة المسار عبر خاصية إدارة المسار
+  (بضغط المفتاح المخصص لهذا الغرض). لاحظ أنه يجب تنشيط الاستوديو قبل الشروع
+  في استخدام هذا النمط.
+* إضافة مربع تحديد بإعدادات الإضافة للتبديل بين تشغيل وتعطيل الإعلان عن اسم
+  التنويه الجاري تشغيله.
+* تشغيل أو تعطيل الميكروفون عبر نمط أوامر SPL لم يعد يتسبب في إصدار نغمات
+  خطأ أو عدم إصدار صوت تشغيل أو تعطيل الميكروفون.
+* إذا تم تخصيص أمر لمساعد نمط أوامر SPL وتم ضغط هذا الأمر مباشرة بعد الدخول
+  في نمط المساعدة, فسيخرج NVDA من هذا النمط.
+
+## مستجدات الإصدار 5.0
+
+* إضافة محاورة لإعدادات إضافة SPL, والتي يمكن الوصول إليها من قائمة
+  التفضيلات ب NVDA أو بالضغط على Control+NVDA+0 من نافذة التطبيق.
+* إضافة إمكانية العودة بكافة الإعدادات للوضع الافتراضي من محاورة الإعدادات.
+* إذا وجد خطأ ببعض الإعدادات, فستعود الإعدادات التي بها الخطأ إلى الوضع
+  الافتراضي.
+* إضافة نمط شاشة لمس لتطبيق SPL وأوامر لمس لأداء مهام مختلفة.
+* تعديلات بمساعد نمط أوامر SPL ويشمل ذلك التعديل إضافة أمر للمساعدة (F1)
+  وحذف الأوامر المنوطة بتعطيل أو تشغيل الإعلان عن عدد المستمعين (Shift+I)
+  والإعلان عن الوقت المجدول (Shift+S). 
+* إعادة تسمية "التبديل بين تعطيل وتشغيل الحالة" إلى "الإعلان عن الحالة" حيث
+  أن الصفير يستخدم في الإعلان عن معلومات أخرى للحالة كالانتهاء من فحص
+  المكتبة.
+* الاحتفاظ من الآن بإعداد الإعلان عن الحالة عبر الجلسات. حيث كنت من قبل
+  تحتاج إلى تشغيل هذا الإعداد يدويا عند بدأ الاستوديو.
+* يمكنك الآن استخدام خاصية إدارة المسارات لمراجعة الأعمدة بمدخل أحد المسارات
+  بعارض قائمة التشغيل الرئيسي بالاستوديو (لتعطيل أو تشغيل هذه الخاصية قم
+  بالضغط على الاختصار الذي قمت بتعيينه لذلك الأمر).
+* يمكنك الآن تخصيص اختصارات للإعلان عن درجة الحرارة أو للإعلان عن عنوان
+  المسار التالي إذا كان مجدول.
+* إضافة مربع تحديد بمحاورتي نهاية المسار والتنبيه بمقدمة الأغنية لتفعيل أو
+  تعطيل هذه التنبيهات (قم بالتحديد للتشغيل). يمكن "إعداد" هذه التنبيهات من
+  إعدادات الإضافة.
+* معالجة مشكلة فتح محاورة التنبيه أو أمر البحث عن مسار أثناء وجود أي من هذه
+  المحاورات مفتوحة والتي كانت تتسبب في ظهور هذه المحاورات أكثر من مرة. الآن
+  سيطلب منك إغلاق المحاورة المفتوحة مسبقا أولا.
+* تعديلات وإصلاحات بمستكشف التنويهات, استكشاف بنوك تنويهات خاطئة عندما يكون
+  المستخدم غير موجود بعارض قائمة التشغيل. من الآن سيعمل مستكشف التنويهات على
+  التأكد من أن المستخدم موجود بعارض قائمة التشغيل.
+* إضافة إمكانية استخدام نمط أوامر SPL لاستدعاء مساعد SPL (تجريبي, انظر ملف
+  المساعدة الخاص بالإضافة لمعرفة كيفية تفعيل هذه الخاصية).
+* في نوافذ التشفير, سيعلن أمر الوقتوالتاريخ ب NVDA (افتراضيا nvda+f12) عن
+  الوقت بالثواني.
+* يمكنك الآن مراقبة التشفيرات الفردية لحالة الاتصال والرسائل الأخرى بالضغط
+  على Control+F11 وذلك أثناء تنشيط التشفير الذي تود مراقبته (يعمل أفضفل عند
+  استخدام SAM encoders).
+* إضافة اختصار بنمط spl controller للإعلان عن حالة مراقبة التشفير (E).
+* جاري العمل على معالجة مشكلة نطق NVDA أسماء ملفات تشغيل للتشفير الخطأ,
+  وخاصة بعد حذف أحد التشفيرات (لإعادة ترتيب أسماء ملفات التشغيل, اضغط على
+  Control+F12, ثم قم باختيار موضع التشفير الذي قمت بحذفه).
+
+## مستجدات الإصدار 4.4/3.9
+
+* وظيفة البحث في المكتبة تعمل الآن في الإصدار 5.10 (مطلوب آخر نسخة من
+  الإصدار 5.10).
+
+## مستجدات الإصدار 4.3/3.8
+
+* عند الانتقال إلى جزء آخر من التطبيق كالانتقال إلى محاورة إدراج مسارات
+  أثناء تنشيط مستكشف التنويهات, فإن NVDA لم يعد يعلن عن رسائل التنويهات عند
+  ضغط المفاتيح الخاصة بذلك (على سبيل المثال, تحديد مكان مسار من محاورة إدراج
+  المسارات).
+* مفاتيح اختصارات مساعدة جديدة, تشمل التنقل بين الإعلان عن الأوقات المجدولة
+  وعدد المستمعين (Shift+S و Shift+i بالترتيب, لم يتم حفظها عبر الجلسات).
+* عند الخروج من التطبيق أثناء فتح أكثر من محاورة تحذير, فسيعلم NVDA بأنه قد
+  تم الخروج من التطبيق ولم يقم بحفظ أية تعديلات على المحاورات التحذيرية
+  المفتوحة.
+* ترجمة الإضافة لمزيد من اللغات
+
+## مستجدات الإصدار 4.2/3.7
+
+* لم يعد ينسى NVDA الاحتفاظ بتعريفات encoder الجديدة والتي تم تغييرها عندما
+  يقوم المستخدم بتسجيل الخروج من ويندوز أو عند إعادة تشغيل الجهاز.
+* عند حدوث خلل في ملف إعدادات الإضافة عند بدأ تشغيل NVDA, فسيسترجع NVDA
+  الإعدادات الافتراضية وستظهر رسالة تخبر المستخدم بذلك.
+* في الإصدار 3.7, تم تصحيح الخطأ الذي كان يحدث عند حزف المسارات بالإصدار
+  4.33 من الاستوديو (نفس الإصلاح تم لمستخدمي الإصدار 5.0x بالإصدار 4.1 من
+  الإضافة).
+
+## مستجدات الإصدار 4.1
+
+* في استوديو 5.0x, حزف مسار من عارض قائمة التشغيل الرئيسية لم يعد يتسبب في
+  إعلان NVDA عن المسار الموجود أسفل المسار الجديد النشط (تلاحظ هذه المشكلة
+  بوضوح إذا تم حزف المسار السابق للمسار الأخير حيث كان NVDA يقول في هذه
+  الحالة "مجهول").
+* معالجة العديد من قضايا البحث في المكتبة في إستوديو 5.10, ومن بين هذه
+  القضايا الإعلان عن مجموع العناصر بالمكتبة أثناء التحرك بمفتاح الانتقال
+  بمحاورة إدراج المسارات والقول "جاري البحث" عند محاولة ملاحظة البحث في
+  المكتبة عبر مساعد SPL 
+* عند استخدام سطر إلكتروني مع الإصدار 5.10 من SPL وعندما يكون المسار محدد,
+  فإن الضغط على المسافة لتحديد مسار آخر لم يعد يتسبب في عدم انعكاس حالة
+  المسار الجديد على السطر الإلكتروني.
+
+## مستجدات الإصدار 4.0/3.6
+
+الإصدار 4.0 من الإضافة يدعم الإصدار SPL Studio 5.00 وما بعدها, مع الإصدار
+3.x والذي صمم لتوفير بعض الخصائص الجديدة من إصدار الإضافة 4.0 للمستخدمين
+الذين يثبتون إصدار قديم من تطبيق SPL.
+
+* مفاتيح مساعدة جديدة لتطبيق SPL, وقت محدد للمسار (S), الوقت المتبقي لقائمة
+  التشغيل (D) ودرجة الحرارة (W إذا كانت ضمن الإعدادات).
+* مفاتيح اختصار جديدة بمساعد أوامر SPL, وتشمل شريط التقدم للبحث في المكتبة
+  (Shift+R) وتشغيل الميكروفون دون التلاشي (N). 
+* عند تشغيل أو تعطيل الميكروفون عبر مساعد أوامر SPL, فسيصدر صوت للتنبيه
+  بحالة تعطيل أو تشغيل الميكروفون.
+* الإعدادات مثل وقت نهاية المسار سيتم حفظها في ملف إعدادات صنع خصيصا لهذا
+  الغرض يوجد بمجلدك الشخصي وستحفظ الإعدادات مع ترقية الإضافة (4.0 وما
+  بعدها).
+* إضافة مفتاح الاختصار (Alt+NvDA+2 لضبط وقت التنبيه بمقدمة الأغنية وهو ما
+  بين 1 إلى 9 ثوان.
+* في محاورات نهاية المسار والتنبيه بالمقدمة, يمكنك استخدام السهم الأعلى
+  والأسفل لتغيير إعدادات التنبيه. إذا قمت بإدخال قيمة خاطئة, فسيضبط وقت
+  التنبيه على أقصى قيمة.
+* إضافة الأمر (Control+NVDA+4) لضبط الوقت الذي سيصدر بعده NVDA يخبرك به إن
+  الميكروفون مشغل لفترة.
+* إضافة خاصية للإعلان عن الوقت بالساعات, والدقائق والثوان (لم يتم توفير
+  مفتاح اختصار بعد)
+* أصبح بالإمكان تتبع البحث في المكتبة من خلال محاورة إدراج مسار أو من أي
+  مكان, مع وضع أمر لخيارات الإعلان عن البحث في المكتبة (Alt+NVDA+R) 
+* دعم أداة المسار, ويشمل ذلك إصدار صوت إذا كان للمسار بداية محددة وأوامر
+  للإعلان عن المعلومات المتوفرة على المسار مثل الإعلان عن مدة المسار ومكانه
+  بقائمة المسارات.
+* دعم StationPlaylist Encoder (Studio 5.00 وما بعده), مع توفير نفس الدعم
+  الذي نقدمه ل SAM Encoder.
+* في نوافذ encoder, لم يعد يصدر NVDA نغمات الخطأ عند إخبار NVDA بالانتقال
+  إلى نافذة الستوديو على الاتصال بالخادم أثناء تصغير نافذة الاستوديو.
+* لم تعد تسمع أخطاء عند حزف مواد معرفة.
+* أصبح بالإمكان مراقبة بداية ونهاية الأغنية بالبرايل وذلك باستخدام خيارات
+  ميقات البرايل (Control+Shift+X).
+* معالجة مشكلة كانت تحدث عند محاولة الانتقال لنافذة التطبيق من أي برنامج آخر
+  بعد تصغير كافة النوافذ مما كان يتسبب في ظهور شيء آخر.
+* عند استخدام الإصدار 5.01 من SPL أو ما قبله, فإن NVDA لم يعد يعلن عن بعض
+  معلومات الحالة لمرات متعددة, من أمثلة ذلك الوقت المحدد.
+
+## مستجدات الإصدار 3.4
+
+* التعامل بشكل صحيح مع التنويهات التي تم تعيين اختصار لها يشمل مفتاح التحكم
+  على سبيل المثال (control+f1) بنمط استكشاف التنويهات.
+* معالجة خطأ كان يحدث عند قراءة NVDA معلومات خاطئة عندما كنت تريد الحصول على
+  معلومات عن الوقت المتبقي والمنقضي في الإصدار 5.10 من SPL Studio 
+* ترجمة الإضافة لمزيد من اللغات
+
+## مستجدات الإصدار 3.0
+
+* في نمط استكشاف التنويهات, التعامل مع الاختصارات التي تشمل مفتاح التحكم
+  بشكل صحيح.
+* ترجمة الإضافة لمزيد من اللغات
+
+## مستجدات الإصدار 3.3
+
+* لم يعد من الضروري البقاء بنافذة sam encoder حتى إجراء الاتصال بخادم البث
+  باستخدام sam encoder.
+* معالجة مشكلة عدم عمل بعض اختصارات encoder عند الانتقال لنافذة sam من
+  البرامج الأخرى على سبيل المثال (أوامر تعريف البث).
+
+## مستجدات الإصدار 3.2
+
+* إضافة اختصار للإعلان عن الوقت المتبقي من المسار الحالي (r).
+* تصحيح رسالة المساعدة التفاعلية لاختصار shift+f11 بنافذة sam encoder.
+* إذا تم استخدام الاستوديو القياسي بنمط استكشاف التنويهات, سيقوم NVDA بتنبيه
+  المستخدم عن عدم إتاحة مفاتيح صف الأرقام العلوي لتعيين اختصارات للتنويهات.
+* في الإصدار 5.10, عدم صدور صوت الخطأ أثناء البحث عن المسارات.
+* ترجمة الإضافة لمزيد من اللغات وتحديث الترجمة.
+
+## مستجدات الإصدار 3.1
+
+* في نافذة sam encoder, وضع اختصار (shift+f11) لتشغيل أول مسار بعد الاتصال
+  بالخادم.
+* معالجة العديد من الأخطاء عند الاتصال بخادم ب sam encoder, ومن بين هذه
+  المشكلات عدم القدرة على تنفيذ أوامر NVDA, وصمت NVDA بعد إجراء الاتصال
+  بالخادم, إصدار صوت الخطء بدلا من صوت الصفير للإعلان عن إتمام الاتصال.
+
+## مستجدات الإصدار 3.0
+
+* تم إضافة مستكشف التنويهات للتعرف على المفتاح المنوط بتشغيل كل تنويه (يمكن
+  تعيين مفاتيح ل96 تنويه).
+* تمت إضافة أوامر جديدة, بما في ذلك وقت المذيع (NVDA+Shift+F12) وعدد
+  المستمعين (i) وعنوان المسار التالي (n) في وضع مساعد أوامر SPL.
+* سيتم الإعلان عن الرسائل ذات الحالتين على السطر الإلكتروني بغض النظر عن وضع
+  الإعلان عن تلك الرسائل سواء كان صفير أم نطق.
+* عندما تقوم بتصغير نافذة StationPlaylist وتريد الانتقال إلى نافذة البرنامج
+  من أي مكان, فإن NVDA سيخبرك بأن النافذة مصغرة.
+* لم تعد تسمع صوت الخطأ عندما يكون الإعلان عن الحالة في وضع الصفير وعندما
+  تكون رسائل الحالة رسائل أخرى غير تشغيل وتعطيل (مثال: تشغيل التنويهات أو
+  الإعلانات).
+* لم تعد تسمع صوت الخطأ عند رغبتك في الحصول على معلومات مثل الوقت المتبقي
+  أثناء تنشيط نوافذ الاستوديو الأخرى غير نافذة قائمة المسارات (مثل محاورة
+  الخيارات). إذا تعذر الحصول على المعلومات المطلوبة, فإن NVDA سيخبرك بهذا.
+* أصبح من الممكن البحث عن مسار باسم المطرب حيث كنت في السابق لا تتمكن إلا من
+  البحث بعنوان المسار فقط.
+* دعم إضافة SAM Encoder الموجودة بتطبيق Winamp, بما في ذلك إمكانية تسمية
+  الملف الذي يبث عبر الخادم والتنقل بين تشغيل وتعطيل خاصية الرجوع لنافذة
+  الاستوديو بعد الاتصال بالخادم.
+* يتوفر ملف المساعدة للإضافة من مدير الإضافات البرمجية.
+
+## مستجدات الإصدار 2.1
+
+* معالجة خطأ كان يحدث عندما يكون المستخدم غير قادر على الحصول على معلومات
+  مثل تلك التي تعبر عن حالة الآلية وذلك عند تشغيل SPL Studio لأول مرة أثناء
+  تشغيل NVDA.
+
+## مستجدات الإصدار 2.0
+
+* قد تم إلغاء بعض الاختصارات العامة والخاصة بالبرنامج حتى يتسنى للمستخدم
+  تخصيص الأوامر من محاورة اختصارات NVDA (يحتاج الإصدار 2.0 من الإضافة
+  استخدام إصدار NVDA 2013.3 أو أعلى). 
+* إضافة المزيد من مساعد أوامر SPL كالإعلان عن حالة نمط التحرير
+* الآن يمكنك التحول إلى SPL أستديو حتى وإن كانت جميع النوافذ مصغرة (قد لا
+  يعمل أحيانا). 
+* امتداد وقت التحذير بنهاية المسار إلى 59 ثانية
+* يمكنك الآن البحث عن مسار في قائمة التشغيل بالضغط على Control+NVDA+F وكل من
+  NVDA+f3 أو NVDA+Shift+F3 للتنقل بين المسار التالي أو السابق على التوالي. 
+* أصبح NVDA يعلن أسماء مربعات التحرير والسرد الصحيحة (مثل محاورة الخيارات
+  وشاشة تنزيل البرنامج الأولى). 
+* معالجة خطأ كان يحدث عند قراءة NVDA معلومات خاطئة عندما كنت تريد الحصول على
+  معلومات عن الوقت المتبقي في الإصدار الخامس من SPL Studio 
+
+## مستجدات الإصدار 1.2
+
+* عند تثبيت الإصدار 4.x من تطبيق StationPlayList على أنظمة التشغيل 8/8.1 على
+  بعض الحواسيب, أصبح من الممكن الاستماع مرة أخرى إلى الوقت المنقضي والوقت
+  المتبقي للمسار.
+* ترجمة الإضافة لمزيد من اللغات
+
+## مستجدات الإصدار 1.1
+
+* إضافة مفتاح الاختصار (Control+NvDA+2) لوضع صوت تنبيهي لمعرفة نهاية المسار.
+* إصلاح خطأ برمجي يتعلق بعدم الإعلان عن بعض أسماء مربعات التحرير (وبخاصة
+  حقول التحرير بمحاورة الخيارات).
+* ترجمة الإضافة لمزيد من اللغات
+
+
+## مستجدات الإصدار 1.0
+
+* إصدار أولي
+
+[[!tag dev stable]]
+
+[1]: http://addons.nvda-project.org/files/get.php?file=spl
+
+[2]: http://addons.nvda-project.org/files/get.php?file=spl-dev [2]: ;
+
+[3]: http://addons.nvda-project.org/files/get.php?file=spl-dev [2]: ;
+

diff --git a/addon/doc/bg/readme.md b/addon/doc/bg/readme.md
new file mode 100644
index 0000000..7d4446e
--- /dev/null
+++ b/addon/doc/bg/readme.md
@@ -0,0 +1,795 @@
+# StationPlaylist Studio #
+
+* Автори: Geoff Shang, Joseph Lee и други сътрудници
+* Изтегляне [стабилна версия][1]
+* Изтегляне [работна версия][2]
+
+This add-on package provides improved usage of StationPlaylist Studio, as
+well as providing utilities to control the Studio from anywhere.
+
+За повече информация относно добавката прочетете [ръководството за
+добавката][3].
+
+IMPORTANT: This add-on requires NVDA 2015.3 or later and StationPlaylist
+Studio 5.00 or later. If you have installed NVDA 2016.1 or later on Windows
+8 and later, disable audio ducking mode.
+
+## Бързи клавиши
+
+* Alt+Shift+T, докато сте в прозореца на програмата: съобщава изминало време
+  за текущо просвирвания запис.
+* Control+Alt+T (two finger flick down in SPL touch mode) from Studio
+  window: announce remaining time for the currently playing trakc.
+* NVDA+Shift+F12 (two finger flick up in SPL touch mode) from Studio window:
+  announces broadcaster time such as 5 minutes to top of the hour.
+* Control+NVDA+1 from Studio window: toggles announcement of status messages
+  (such as automation and end of library scan) between words and beeps.
+* Control+NVDA+2 (two finger flick right in SPL mode) from Studio window:
+  Opens end of track setting dialog.
+* Alt+NVDA+2 (two finger flick left in SPL mode) from Studio window: Opens
+  song intro alarm setting dialog.
+* Control+NVDA+3 докато сте в прозореца на програмата: Превключва прегледа
+  на джингъли за изследване на назначенията на джингълите.
+* Control+NVDA+4 от прозореца на Studio: Отваря диалоговия прозорец за
+  предупреждението за микрофона.
+* Control+NVDA+F докато сте в прозореца на програмата: Отваря прозорец за
+  търсене на базата на името на изпълнител или песен. Натиснете NVDA+F3 за
+  търсене напред или NVDA+Shift+F3 за търсене назад.
+* Alt+NVDA+R от прозореца на Studio: Преминава през настройките за
+  съобщаването на сканирането на библиотеката.
+* Control+Shift+X от прозореца на Studio: Преминава през настройките за
+  брайловия таймер.
+* Control+Alt+right/left arrow (while focused on a track): Announce
+  next/previous track column.
+* Control+NVDA+0 or Alt+NVDA+0 from Studio window: Opens the Studio add-on
+  configuration dialog.
+* Control+NVDA+- (hyphen) from Studio window: Send feedback to add-on
+  developer using the default email client.
+
+## Неприсвоени команди
+
+Следните команди не са присвоени по подразбиране; Ако искате да ги
+присвоите, използвайте диалоговия прозорец за жестове на въвеждане, за да
+добавите команди по избор.
+
+* Превключване към прозореца на SPL Studio от всяка програма.
+* Слой за контролера на SPL
+* Помощен слой на SPL от SPL Studio.
+* Съобщаване на времето, включително и секундите от SPL Studio.
+* Toggling track dial on or off (works properly while a track is focused; to
+  assign a command to this, move to a track in Studio, then open NVDA's
+  input gestures dialog.).
+* Announcing temperature.
+* Announcing title of next track if scheduled.
+* Announcing title of the currently playing track.
+* Marking current track for start of track time analysis.
+* Performing track time analysis.
+* Find text in specific columns.
+* Find tracks with duration that falls within a given range via time range
+  finder.
+* Quickly enable or disable metadata streaming.
+
+## Допълнителни команди при използването на Sam или SPL енкодерите
+
+Следните команди са налични при използването на Sam или SPL енкодерите:
+
+* F9: Свързване с излъчващ сървър.
+* F10 (само за SAM енкодера): Прекъсване на връзката с излъчващия сървър.
+* Control+F9/Control+F10 (SAM encoder only): Connect or disconnect all
+  encoders, respectivley.
+* F11: Определя дали NVDA ще превключва към прозореца на програмата ако
+  избрания енкодер е свързан.
+* Shift+F11: Определя дали ще се просвирва първият избран запис когато
+  енкодера е свързан към излъчващ сървър.
+* Control+F11: Toggles background monitoring of the selected encoder.
+* F12: Opens a dialog to enter custom label for the selected encoder or
+  stream.
+* Control+F12: opens a dialog to select the encoder you have deleted (to
+  realign stream labels and encoder settings).
+* Control+NVDA+0 or Alt+NVDA+0: Opens encoder settings dialog to configure
+  options such as stream label.
+
+In addition, column review commands are available, including:
+
+* Control+NVDA+1: Encoder position.
+* Control+NVDA+2: stream label.
+* Control+NVDA+3 from SAM Encoder: Encoder format.
+* Control+NVDA+3 from SPL Encoder: Encoder settings.
+* Control+NvDA+4 from SAM Encoder: Encoder connection status.
+* Control+NVDA+4 from SPL Encoder: Transfer rate or connection status.
+* Control+NVDA+5 from SAM Encoder: Connection status description.
+
+## Помощен слой на SPL
+
+This layer command set allows you to obtain various status on SPL Studio,
+such as whether a track is playing, total duration of all tracks for the
+hour and so on. From any SPL Studio window, press the SPL Assistant layer
+command, then press one of the keys from the list below (one or more
+commands are exclusive to playlist viewer). You can also configure NvDA to
+emulate commands from other screen readers.
+
+The available commands are:
+
+* A: Автоматизация.
+* C (Shift+C in JAWS and Window-Eyes layouts): Title for the currently
+  playing track.
+* C (JAWS and Window-Eyes layouts): Toggle cart explorer (playlist viewer
+  only).
+* D (R in JAWS layout): Remaining duration for the playlist (if an error
+  message is given, move to playlist viewer and then issue this command).
+* E (G in Window-Eyes layout): Metadata streaming status.
+* Shift+1 through Shift+4, Shift+0: Status for individual metadata streaming
+  URL's (0 is for DSP encoder).
+* E (Window-Eyes layout): Elapsed time for the currently playing track.
+* F: Find track (playlist viewer only).
+* H: продължителност на записите от текущия час.
+* Shift+H: Remaining track duration for the hour slot.
+* I (L in JAWS or Window-Eyes layouts): Listener count.
+* K: Move to the marked track (playlist viewer only).
+* Control+K: Set the current track as the place marker track (playlist
+  viewer only).
+* L (Shift+L in JAWS and Window-Eyes layouts): Line in.
+* M: микрофон.
+* N: заглавието на следващия запис на опашката.
+* P: състояние на възпроизвеждането (активно или спряно).
+* Shift+P: Pitch of the current track.
+* R (Shift+E in JAWS and Window-Eyes layouts): Record to file
+  enabled/disabled.
+* Shift+R: Наблюдаване на напредъка при сканирането на библиотеката.
+* S: Записът ще се възпроизведе в (планирано).
+* Shift+S: Time until selected track will play.
+* T: Включване/изключване на Cart режима на редактиране.
+* U: Изминало време в Studio.
+* Control+Shift+U: Check for add-on updates.
+* W: Време и температура, ако са конфигурирани.
+* Y: Playlist modified status.
+* 1 through 0 (6 for Studio 5.0x): Announce column content for a specified
+  column.
+* F9: Mark current track for track time analysis (playlist viewer only).
+* F10: Perform track time analysis (playlist viewer only).
+* F12: Switch between current and a predefined profile.
+* F1: Layer help.
+* Shift+F1: Opens online user guide.
+
+## Контролер на SPL
+
+Контролерът на SPL е набор от команди за слоя, които може да използвате, за
+да управлявате SPL Studio от всякъде. Натиснете командата за слоя на
+контролера за SPL и NVDA ще съобщи, "Контролер на SPL." Натиснете клавиш,
+отговарящ на някоя от командите по-долу, за да управлявате някоя от многото
+настройки, например заглушаване или активиране на микрофона или просвирване
+на следващия запис.
+
+Наличните команди на контролера на SPL са:
+
+* Натиснете P, за да просвирите следващия маркиран запис.
+* Натиснете U, за да поставите на пауза текущия запис или да възобновите
+  възпроизвеждането.
+* Натиснете S, за да спрете записа със затихване, или натиснете T, за да
+  спрете записа незабавно.
+* Натиснете M или Shift+M за да включите или съответно изключите микрофона,
+  или натиснете N за да задействате микрофона без засилване.
+* Натиснете A, за да разрешите автоматизацията или Shift+A, за да я
+  забраните.
+* Натиснете L, за да разрешите линейния вход или Shift+L, за да го
+  забраните.
+* Press R to hear remaining time for the currently playing track.
+* Натиснете Shift+R за да получите доклад за напредъка по сканирането на
+  библиотеката.
+* Press E to get count and labels for encoders being monitored.
+* Press I to obtain listener count.
+* Натиснете F1 за да изведете помощен прозорец, който изброява наличните
+  команди.
+
+## Track alarms
+
+By default, NvDA will play a beep if five seconds are left in the track
+(outro) and/or intro. To configure this value as well as to enable or
+disable them, press Control+NVDA+2 or Alt+NVDA+2 to open end of track and
+song ramp dialogs, respectively. In addition, use Studio add-on settings
+dialog to configure if you'll hear a beep, a message or both when alarms are
+turned on.
+
+## Предупреждение за микрофона
+
+Можете да укажете на NVDA да възпроизвежда звук, когато микрофонът е бил
+активен от известно време. Натиснете Control+NVDA+4 за да конфигурирате
+времето за предупреждението в секунди (0 го забранява).
+
+## Търсене на записи
+
+Ако желаете бързо да намерите запис от изпълнител или по името на записа, от
+списъка за изпълнение, натиснете Control+NVDA+F. Въведете името на
+изпълнителя или името на песента. NVDA ще ви позиционира върху записа Ако е
+намерен или ще изведе грешка, ако не може да се намери записа, който
+търсите. За да намерите предходно търсен запис или изпълнител, натиснете
+NVDA+F3 или NVDA+Shift+F3, за да търсите съответно напред или назад.
+
+Забележка: Търсенето на записи взема предвид малките и главните букви.
+
+## Разглеждане на джингъли
+
+В зависимост от изданието, SPL Studio позволява да бъдат определени до 96
+джингъли за използване по време на предаване. NVDA ви позволява да чуете кой
+джингъл е назначен за коя от тези команди.
+
+За да изследвате джингълите, от SPL Studio, натиснете
+Control+NVDA+3. Натискането на командата за джингъла ви казва кой е
+асоциирания джингъл. Двукратно натискане просвирва джингъла. Натиснете
+Control+NvDA+3 за да излезете от този режим. За повече информация се
+обърнете към ръководството на добавката.
+
+## Track Dial
+
+You can use arrow keys to review various information about a track. To turn
+Track Dial on, while a track is focused in the main playlist viewer, press
+the command you assigned for toggling Track Dial. Then use left and right
+arrow keys to review information such as artist, duration and so
+on. Alternatively, press Control+Alt+left or right arrows to navigate
+between columns without invoking Track Dial.
+
+## Track time analysis
+
+To obtain length to play selected tracks, mark current track for start of
+track time analysis (SPL Assistant, F9), then press SPL Assistant, F10 when
+reaching end of selection.
+
+## Columns Explorer
+
+By pressing SPL Assistant, 1 through 0 (6 for Studio 5.01 and earlier), you
+can obtain contents of specific columns. By default, these are artist,
+title, duration, intro, category and filename (Studio 5.10 adds year, album,
+genre and time scheduled). You can configure which columns will be explored
+via columns explorer dialog found in add-on settings dialog.
+
+## Configuration dialog
+
+From studio window, you can press Control+NVDA+0 or Alt+NVDA+0 to open the
+add-on configuration dialog. Alternatively, go to NVDA's preferences menu
+and select SPL Studio Settings item. This dialog is also used to manage
+broadcast profiles.
+
+## SPL touch mode
+
+If you are using Studio on a touchscreen computer running Windows 8 or later
+and have NVDA 2012.3 or later installed, you can perform some Studio
+commands from the touchscreen. First use three finger tap to switch to SPL
+mode, then use the touch commands listed above to perform commands.
+
+## Changes for 7.3
+
+* Slight performance improvements when looking up information such as
+  automation via some SPL Assistant commands.
+* Обновени преводи.
+
+## Changes for 7.2
+
+* Due to removal of old-style internal configuration format, it is mandatory
+  to install add-on 7.2. Once installed, you cannot go back to an earlier
+  version of the add-on.
+* Added a command in SPL Controller to report listener count (I).
+* You can now open SPL add-on settings and encoder settings dialogs by
+  pressing Alt+NVDA+0. You can still use Control+NVDA+0 to open these
+  dialogs (to be removed in add-on 8.0).
+* In Track Tool, you can use Control+Alt+left or right arrow keys to
+  navigate between columns.
+* Contents of various Studio dialogs such as About dialog in Studio 5.1x are
+  now announced.
+* In SPL Encoders, NVDA will silence connection tone if auto-connect is
+  enabled and then turned off from encoder context menu while the selected
+  encoder is connecting.
+* Обновени преводи.
+
+## Changes for 7.1
+
+* Fixed erorrs encountered when upgrading from add-on 5.5 and below to 7.0.
+* When answering "no" when resetting add-on settings, you'll be returned to
+  add-on settings dialog and NVDA will remember instant switch profile
+  setting.
+* NVDA will ask you to reconfigure stream labels and other encoder options
+  if encoder configuration file becomes corrupted.
+
+## Changes for 7.0
+
+* Added add-on update check feature. This can be done manually (SPL
+  Assistant, Control+Shift+U) or automatically (configurable via advanced
+  options dialog from add-on settings).
+* It is no longer required to stay in the playlist viewer window in order to
+  invoke most SPL Assistant layer commands or obtain time announcements such
+  as remaining time for the track and broadcaster time.
+* Changes to SPL Assistant commands, including playlist duration (D),
+  reassignment of hour selection duration from Shift+H to Shift+S and
+  Shift+H now used to announce duration of remaining tracks for the current
+  hour slot, metadata streaming status command reassigned (1 through 4, 0 is
+  now Shift+1 through Shift+4, Shift+0).
+* It is now possible to invoke track finder via SPL Assistant (F).
+* SPL Assistant, numbers 1 through 0 (6 for Studio 5.01 and earlier) can be
+  used to announce specific column information. These column slots can be
+  changed under Columns Explorer item in add-on settings dialog.
+* Fixed numerous errors reported by users when installing add-on 7.0 for the
+  first time when no prior version of this add-on was installed.
+* Improvements to Track Dial, including improved responsiveness when moving
+  through columns and tracking how columns are presented on screen.
+* Added ability to press Control+Alt+left or right arrow keys to move
+  between track columns.
+* It is now possible to use a different screen reader command layout for SPL
+  Assistant commands. Go to advanced options dialog from add-on settings to
+  configure this option between NVDA, JAWS and Window-Eyes layouts. See the
+  SPL Assistant commands above for details.
+* NVDA can be configured to switch to a specific broadcast profile at a
+  specific day and time. Use the new triggers dialog in add-on settings to
+  configure this.
+* NVDA will report name of the profile one is switching to via instant
+  switch (SPL Assistant, F12) or as a result of time-based profile becoming
+  active.
+* Moved instant switch toggle (now a checkbox) to the new triggers dialog.
+* Entries in profiles combo box in add-on settings dialog now shows profile
+  flags such as active, whether it is an instant switch profile and so on.
+* If a serious problem with reading broadcast profile files are found, NVDA
+  will present an error dialog and reset settings to defaults instead of
+  doing nothing or sounding an error tone.
+* Settings will be saved to disk if and only if you change settings. This
+  prolongs life of SSD's (solid state drives) by preventing unnecessary
+  saves to disk if no settings have changed.
+* In add-on settings dialog, the controls used to toggle announcement of
+  scheduled time, listener count, cart name and track name has been moved to
+  a dedicated status announcements dialog (select status announcement button
+  to open this dialog).
+* Added a new setting in add-on settings dialog to let NVDA play beep for
+  different track categories when moving between tracks in playlist viewer.
+* Attempting to open metadata configuration option in add-on settings dialog
+  while quick metadata streaming dialog is open will no longer cause NVDA to
+  do nothing or play an error tone. NvDA will now ask you to close metadata
+  streaming dialog before you can open add-on settings.
+* When announcing time such as remaining time for the playing track, hours
+  are also announced. Consequently, the hour announcement setting is enabled
+  by default.
+* Pressing SPL Controller, R now causes NVDA to announce remaining time in
+  hours, minutes and seconds (minutes and seconds if this is such a case).
+* In encoders, pressing Control+NVDA+0 will present encoder settings dialog
+  for configuring various options such as stream label, focusing to Studio
+  when connected and so on.
+* In encoders, it is now possible to turn off connection progress tone
+  (configurable from encoder settings dialog).
+
+## Changes for 6.4
+
+* Fixed a major problem when switching back from an instant switch profile
+  and the instant switch profile becomes active again, seen after deleting a
+  profile that was positioned right before the previously active
+  profile. When attempting to delete a profile, a warning dialog will be
+  shown if an instant switch profile is active.
+
+## Changes for 6.3
+
+* Internal security enhancements.
+* When add-on 6.3 or later is first launched on a computer running Windows 8
+  or later with NVDA 2016.1 or later installed, an alert dialog will be
+  shown asking you to disable audio ducking mode (NVDA+Shift+D). Select the
+  checkbox to suppress this dialog in the future.
+* Added a command to send bug reports, feature suggestions and other
+  feedback to add-on developer (Control+NVDA+dash (hyphen, "-")).
+* Обновени преводи.
+
+## Changes for 6.2
+
+* Fixed an issue with playlist remainder command (SPL Assistant, D (R if
+  compatibility mode is on)) where the duration for the current hour was
+  announced as opposed to the entire playlist (the behavior of this command
+  can be configured from advanced settings found in add-on settings dialog).
+* NvDA can now announce name of the currently playing track while using
+  another program (configurable from add-on settings).
+* The setting used to let SPL Controller command invoke SPL Assistant is now
+  honored (previously it was enabled at all times).
+* In SAM encoders, Control+F9 and Control+F10 commands now works correctly.
+* In encoders, when an encoder is first focused and if this encoder is
+  configured to be monitored in the background, NVDA will now start the
+  background monitor automatically.
+
+## Changes for 6.1
+
+* Column announcement order and inclusion, as well as metadata streaming
+  settings are now profile-specific settings.
+* When changing profiles, the correct metadata streams will be enabled.
+* When opening quick metadata streaming settings dialog (command
+  unassigned), the changed settings are now applied to the active profile.
+* When starting Studio, changed how the errors are displayed if the only
+  corrupt profile is the normal profile.
+* When changing certain settings using shortcut keys such as status
+  announcements, fixed an issue where the changed settings are not retained
+  when switching to and from an instant switch profile.
+* When using a SPL Assistant command with a custom gesture defined (such as
+  next track command), it is no longer required to stay in the Studio's
+  playlist viewer to use these commands (they can be performed from other
+  Studio windows).
+
+## Changes for 6.0
+
+* New SPL Assistant commands, including announcing title of the currently
+  playing track (C), announcing status of metadata streaming (E, 1 through 4
+  and 0) and opening the online user guide (Shift+F1).
+* Ability to package favorite settings as broadcast profiles to be used
+  during a show and to switch to a predefined profile. See the add-on guide
+  for details on broadcast profiles.
+* Added a new setting in add-on settings to control message verbosity (some
+  messages will be shortened when advanced verbosity is selected).
+* Added a new setting in add-on settings to let NVDA announce hours, minutes
+  and seconds for track or playlist duration commands (affected features
+  include announcing elapsed and remaining time for the currently playing
+  track, track time analysis and others).
+* You can now ask NVDA to report total length of a range of tracks via track
+  time analysis feature. Press SPL Assistant, F9 to mark current track as
+  start marker, move to end of track range and press SPL Assistant,
+  F10. These commands can be reassigned so one doesn't have to invoke SPL
+  Assistant layer to perform track time analysis.
+* Added a column search dialog (command unassigned) to find text in specific
+  columns such as artist or part of file name.
+* Added a time range finder dialog (command unassigned) to find a track with
+  duration that falls within a specified range, useful if wishing to find a
+  track to fill an hour slot.
+* Added ability to reorder track column announcement and to suppress
+  announcement of specific columns if "use screen order" is unchecked from
+  add-on settings dialog. Use "manage column announcement" dialog to reorder
+  columns.
+* Added a dialog (command unassigned) to quickly toggle metadata streaming.
+* Added a setting in add-on settings dialog to configure when metadata
+  streaming status should be announced and to enable metadata streaming.
+* Added ability to mark a track as a place marker to return to it later (SPL
+  Assistant, Control+K to set, SPL Assistant, K to move to the marked
+  track).
+* Improved performance when searching for next or previous track text
+  containing the searched text.
+* Added a setting in add-on settings dialog to configure alarm notification
+  (beep, message or both).
+* It is now possible to configure microphone alarm between 0 (disabled) and
+  two hours (7200 seconds) and to use up and down arrow keys to configure
+  this setting.
+* Added a setting in add-on settings dialog to allow microphone active
+  notification to be given periodically.
+* You can now use Track Dial toggle command in Studio to toggle Track Dial
+  in Track Tool provided that you didn't assign a command to toggle Track
+  Dial in Track Tool.
+* Added ability to use SPL Controller layer command to invoke SPL Assistant
+  layer (configurable from advanced Settings dialog found in add-on settings
+  dialog).
+* Added ability for NvDA to use certain SPL Assistant commands used by other
+  screen readers. To configure this, go to add-on settings, select Advanced
+  Settings and check screen reader compatibility mode checkbox.
+* In encoders, settings such as focusing to Studio when connected are now
+  remembered.
+* It is now possible to view various columns from encoder window (such as
+  encoder connection status) via Control+NVDA+number command; consult the
+  encoder commands above.
+* Fixed a rare bug where switching to Studio or closing an NVDA dialog
+  (including Studio add-on dialogs) prevented track commands (such as
+  toggling Track Dial) from working as expected.
+
+## Changes for 5.6
+
+* In Studio 5.10 and later, NVDA no longer announces "not selected" when the
+  selected track is playing.
+* Due to an issue with Studio itself, NVDA will now announce name of the
+  currently playing track automatically. An option to toggle this behavior
+  has been added in studio add-on settings dialog.
+
+## Changes for 5.5
+
+* Play after connecting setting will be remembered when moving away from the
+  encoder window.
+
+## Changes for 5.4
+
+* Performing library scan from Insert Tracks dialog no longer causes NVDA to
+  not announce scan status or play error tones if NVDA is configured to
+  announce library scan progress or scan count.
+* Обновени преводи.
+
+## Changes for 5.3
+
+* The fix for SAM Encoder (not playing the next track if a track is playing
+  and when the encoder connects) is now available for SPL Encoder users.
+* NVDA no longer plays errors or does not do anything when SPL Assistant, F1
+  (Assistant help dialog) is pressed.
+
+## Changes for 5.2
+
+* NVDA will no longer allow both settings and alarm dialogs to be opened. A
+  warning will be shown asking you to close the previously opened dialog
+  before opening another dialog.
+* When monitoring one or more encoders, pressing SPL Controller, E will now
+  announce encoder count, encoder ID and stream label(s) if any.
+* NVDA supports connect/disconnect all commands (Control+F9/Control+F10) in
+  SAM encoders.
+* NVDA will no longer play the next track if an encoder connects while
+  Studio is playing a track and Studio is told to play tracks when an
+  encoder is connected.
+* Обновени преводи.
+
+## Changes for 5.1
+
+* It is now possible to review individual columns in Track Tool via Track
+  Dial (toggle key unassigned). Note that Studio must be active before using
+  this mode.
+* Added a check box in Studio add-on settings dialog to toggle announcement
+  of name of the currently playing cart.
+* Toggling microphone on and off via SPL Controller no longer causes error
+  tones to be played or toggle sound to not be played.
+* If a custom command is assigned for an SPL Assistant layer command and
+  this command is pressed right after entering SPL Assistant, NvDA will now
+  promptly exit SPL Assistant.
+
+## Changes for 5.0
+
+* A dedicated settings dialog for SPL add-on has been added, accessible from
+  NVDA's preferences menu or by pressing Control+NVDA+0 from SPL window.
+* Added ability to reset all settings to defaults via configuration dialog.
+* If some of the settings have errors, only the affected settings will be
+  reset to factory defaults.
+* Added a dedicated SPL touchscreen mode and touch commands to perform
+  various Studio commands.
+* Changes to SPL Assistant layer include addition of layer help command (F1)
+  and removal of commands to toggle listener count (Shift+I) and scheduled
+  time announcement (Shift+S). You can configure these settings in add-on
+  settings dialog.
+* Renamed "toggle announcement" to "status announcement" as beeps are used
+  for announcing other status information such as completion of library
+  scans.
+* Status announcement setting is now retained across sessions. Previously
+  you had to configure this setting manually when Studio starts.
+* You can now use Track Dial feature to review columns in a track entry in
+  Studio's main playlist viewer (to toggle this feature, press the command
+  you assigned for this feature).
+* You can now assign custom commands to hear temperature information or to
+  announce title for the upcoming track if scheduled.
+* Added a checkbox in end of track and song intro alarm dialogs to enable or
+  disable these alarms (check to enable). These can also be "configured"
+  from add-on settings.
+* Fixed an issue where pressing alarm dialog or track finder commands while
+  another alarm or find dialog is opened would cause another instance of the
+  same dialog to appear. NVDA will pop up a message asking you to close the
+  previously opened dialog first.
+* Cart explorer changes and fixes, including exploring wrong cart banks when
+  user is not focused on playlist viewer. Cart explorer will now check to
+  make sure that you are in playlist viewer.
+* Added ability to use SPL Controller layer command to invoke SPL Assistant
+  (experimental; consult the add-on guide on how to enable this).
+* In encoder windows, NVDA's time and date announcement command (NVDA+F12 by
+  default) will announce time including seconds.
+* You can now monitor individual encoders for connection status and for
+  other messages by pressing Control+F11 while the encoder you wish to
+  monitor is focused (works better when using SAM encoders).
+* Added a command in SPL Controller layer to announce status of encoders
+  being monitored (E).
+* A workaround is now available to fix an issue where NvDA was announcing
+  stream labels for the wrong encoders, especially after deleting an encoder
+  (to realign stream labels, press Control+F12, then select the position of
+  the encoder you have removed).
+
+## Промени във версии 4.4/3.9
+
+* Функцията за сканиране на библиотеката вече работи в Studio 5.10 (изисква
+  най-новата компилация на Studio 5.10).
+
+## Промени във версии 4.3/3.8
+
+* При преминаване към друга част на Studio, като например прозореца за
+  вмъкване на записи, докато е активен прегледът на джингъли, NVDA няма да
+  съобщава известията за джингълите при натискане на клавишите за джингълите
+  (например, при намиране на запис в прозореца за вмъкване на записи).
+* Нови клавишни команди за Помощника на SPL, включително за превключване на
+  обявяването на планираното време и броя на слушателите (съответно Shift+S
+  и Shift+I, които не се запазват между сесиите).
+* При изход от Studio при отворени диалогови прозорци за аларми, NVDA ще
+  засече, че Studio е била затворена и няма да запише новите променени
+  стойности за алармите.
+* Обновени преводи.
+
+## Промени във версии 4.2/3.7
+
+* NVDA вече няма да забравя да запазва новите и променените етикети за
+  енкодера когато потребителят излиза от системата или рестартира компютъра.
+* Когато конфигурацията на добавката се повреди при стартиране на NVDA,
+  екранният четец ще възстанови конфигурацията по подразбиране и ще изведе
+  съобщение, с което ще информира потребителя за този факт.
+* Във версия 3.7 на добавката бе отстранен проблем с фокуса забелязан при
+  изтриване на записи в Studio 4.33 (същата корекция е налична за
+  потребителите на Studio 5.0 x във версия 4.1 на добавката).
+
+## Промени във версия 4.1
+
+* В Studio 5.0 x, изтриване на запис от основния списъчен изглед вече няма
+  да предизвиква NVDA да прочита записа под последно фокусирания запис
+  (по-забележимо ако е бил изтрит предпоследният запис, в който случай NVDA
+  съобщаваше "непознат").
+* Поправени са няколко проблема със сканирането на библиотеката в Studio
+  5.10, включително съобщаването на общият брой на елементите в библиотеката
+  при обхождане с табулатора в диалоговия прозорец за вмъкване на записи и
+  съобщаване на "извършва се сканиране" при опит за наблюдаване на
+  сканирането на библиотеката чрез SPL помощника.
+* Когато се използва брайлов дисплей със Studio 5.10 и ако даден запис е
+  отметнат, натискането на интервал за отмятане на запис по-долу, вече не
+  предизвиква брайловия дисплей да не отразява новото състояние на елемента.
+
+## Промени във версии 4.0/3.6
+
+Версия 4.0 поддържа SPL Studio 5.00 и по-нови, а 3.x е предназначена да
+предоставят някои нови функции от 4.0 за потребителите използващи по-стари
+версии на Studio.
+
+* Нови клавиши за SPL Помощника, включително за планираното време за записа
+  (S), оставащото времетраене на списъка за изпълнение (D) и температурата
+  (W, ако е конфигурирано). В допълнение, за Studio 5.x е добавено промяна
+  на списъка за изпълнение (Y) и височина на записа (Shift+P).
+* Нови команди за контролния панел на SPL, включително за напредъка на
+  сканиранията на библиотеката (Shift+R) и за разрешаването на микрофона без
+  засилване (N). Също така, натискането на F1 извежда диалогов прозорец с
+  наличните команди.
+* При разрешаването или забраняването на микрофона през контролния панел на
+  SPL, ще се възпроизвежда сигнал, посочващ дали микрофонът е включен или
+  изключен.
+* Настройки като времето за края на записа се записват в специален
+  конфигурационен файл във вашата потребителска конфигурационна директория и
+  се запазват при обновяване на добавката (версия 4.0 и по-нови).
+* Добавена е команда (Alt+NVDA+2) за задаване на време за предупреждение за
+  въведение в мелодията (между 1 и 9 секунди).
+* В диалоговите прозорци за предупреждението за края на записа и за
+  въведението можете да използвате стрелките за нагоре и надолу за да
+  промените настройките за предупреждението. Ако бъде въведена неправилна
+  стойност, стойността за предупреждението се задава на максималната
+  стойност.
+* Добавена е команда (Control+NVDA+4) за задаване на време след което NVDA
+  ще възпроизвежда звук когато микрофонът е бил активен от известно време.
+* Добавена е възможност за съобщаване на времето в часове, минути и секунди
+  (командата не е назначена).
+* Вече е възможно да се следи сканирането на библиотеката от диалоговия
+  прозорец за вмъкване на записи или от което и да е друго място и
+  специалната команда (Alt+NVDA+R) за превключване на опциите за
+  наблюдаването на сканирането на библиотеката.
+* Поддръжка за Инструмента за записа (Track Tool), включително за
+  възпроизвеждане на сигнал, ако даден запис има зададено въведение и
+  команди за съобщаване на информация за записа, като продължителност и
+  позицията на маркера.
+* Поддръжка за StationPlaylist Encoder (Studio 5.00 и по-нови),
+  предоставяйки същото ниво на поддръжка, като това в SAM Encoder.
+* В прозорците на енкодера, NVDA вече не възпроизвежда сигнала си за грешка,
+  когато на NVDA е указано да премине към Studio при свързване към излъчващ
+  сървър докато прозорецът на Studio е намален.
+* Вече няма грешки след изтриването на поток със зададен към него етикет за
+  потока.
+* Вече е възможно да се наблюдават въведението и края на записа чрез брайл с
+  помощта на опциите за брайловия таймер (Control+Shift+X).
+* Поправен проблем, при който при опит за превключване към прозореца на
+  Studio, след като всички прозорци са били намалени, предизвиква появата на
+  нещо друго.
+* При използване на Studio 5.01 и по-стари, NVDA вече няма да съобщава по
+  няколко пъти дадена информация за състоянието, като например планираното
+  време.
+
+## Промени във версия 3.5
+
+* Когато NVDA бъде стартиран или рестартиран докато фокусът е върху
+  прозореца с основния списък за изпълнение на Studio 5.10, NVDA няма да
+  възпроизвежда звуци при грешка и/или да съобщава следващата и предишната
+  песни, когато се преглеждат песните чрез стрелките.
+* Отстранен е проблем, възникващ при опит да се получат оставащото и
+  изминалото време за песен в по-нови компилации на Studio 5.10.
+* Обновени преводи.
+
+## Промени във версия 3.4
+
+* В разглеждането на джингъли, джингълите включващи клавиша Control (като
+  Ctrl+F1) сега се обработват коректно.
+* Обновени преводи.
+
+## Промени във версия 3.3
+
+* При свързване към излъчващ сървър с използване на SAM encoder, вече не се
+  налага да останете в прозореца на енкодера докато връзката бъде
+  осъществена.
+* Отстранен е проблем, при който командите за енкодера (например за
+  етикетиране на потока) преставаха да работят при превключване към
+  прозореца на SAM от други програми.
+
+## Промени във версия 3.2
+
+* Добавена е команда в контролера на SPL за докладване на оставащо време за
+  текущо просвирвания запис (R).
+* В прозореца на SAM encoder, съобщението в помощен режим за командата
+  Shift+F11 беше поправено.
+* В прегледа на джингъли, ако се използва Studio Standard, NVDA ще ви
+  уведоми, че командите за номер на ред са недостъпни за назначенията на
+  джингъли.
+* В Studio 5.10, търсачката за записи вече не просвирва сигнали за грешка
+  при търсене в записите.
+* Нови и обновени преводи.
+
+## Промени във версия 3.1
+
+* В прозореца на SAM Encoder беше добавена команда (Shift+F11) за указване
+  на Studio да просвири първият запис при свързване.
+* Отстранени са множество грешки при свързване към сървър със SAM Encoder,
+  включително невъзможността за изпълнение на командите на NVDA, пропуска за
+  съобщаване на успешно свързване и сигнали за грешка вместо за успешно
+  свързване.
+
+## Промени във версия 3.0
+
+* Добавен е преглед на джингъли, където може да изследвате назначенията на
+  джингълите (до 96 джингъла могат да бъдат назначени).
+* Добавени са нови команди, включително време на излъчване (NVDA+Shift+F12)
+  и брой на слушателите (i) и заглавие на следващ запис (n) в помощника на
+  SPL.
+* Съобщенията за превключване на настройките като автоматизацията вече се
+  изобразяват на брайл без значение от настройката за известяване на
+  превключването.
+* NVDA ще ви съобщи когато се опитва да превключи към SPL от други програми,
+  но в същото време прозореца на StationPlaylist е минимизиран в системния
+  жлеб (областта за уведомяване).
+* Вече не се чуват сигнали за грешка когато съобщаването на превключванията
+  е зададено на бибипкане и се изговарят съобщения за състоянието, различни
+  от включено и превключване (например: просвирване на джингъли).
+* Вече не се чуват сигнали за грешка когато се опитваме да получим
+  информация като оставащо време докато друг прозорец на Studio различен от
+  списъка със записи (например прозореца за настройка) е на фокус. Ако
+  нужната информация не е намерена, NVDA ще ви съобщи този факт.
+* Вече е възможно да търсите запис по име на изпълнител. Преди можеше да се
+  извърши търсене само по име на запис.
+* Поддръжка за SAM Encoder, включително възможност за етикетиране на
+  енкодера и команда за превключване към Studio когато избраният енкодер е
+  свързан.
+* Помощ за добавката е налична от мениджъра на добавки.
+
+## Промени във версия 2.1
+
+* Отстранен е проблем, при който беше невъзможно да се получи информация за
+  състоянието, например това на автоматизацията, когато SPL 5.x се стартира
+  за първи път след като NVDA вече е бил стартиран.
+
+## Промени във версия 2.0
+
+* Някои глобални и локални клавишни комбинации са премахнати, така че да
+  можете да зададете команда по избор от прозореца за жестове на въвеждане
+  (версия 2.0 на добавката изисква NVDA 2013.3 или по-нова).
+* Добавени са още команди за SPL помощника, като например за състоянието на
+  режима за редактиране cart.
+* Сега можете да преминете към SPL Studio дори ако всички прозорци са
+  намалени (може да не работи в някои случаи).
+* Разширен е диапазона на алармата за край на записа до 59 секунди.
+* Вече можете да търсите за даден запис в списъка за изпълнение
+  (Control+NVDA+F за търсене, NVDA+F3 или NVDA+Shift+F3 за търсене съответно
+  напред и назад).
+* NVDA вече съобщава правилните имена на Разгъващите се списъци (например
+  диалоговия прозорец с опциите и екраните за първоначалната настройка на
+  SPL).
+* Отстранен е проблем, при който NVDA съобщаваше грешна информация при опит
+  за получаване на оставащото време за запис в SPL Studio 5.
+
+## Промени във версия 1.2
+
+* Когато използвате Station Playlist 4.x под Windows 8/8.1, отново е
+  възможно да получите информация за изминало и оставащо време за текущия
+  запис.
+* Обновени преводи.
+
+## Промени във версия 1.1
+
+* Добавена е команда (Control+NvDA+2) за задаване на време за
+  предупреждението за край на записа.
+* Отстранен е проблем, при който имената на определени полета за писане не
+  бяха съобщавани (например някои полета за писане в диалога за настройка на
+  програмата).
+* Добавени са множество преводи.
+
+
+## Промени във версия 1.0
+
+* Първоначално издание
+
+[[!tag dev stable]]
+
+[1]: http://addons.nvda-project.org/files/get.php?file=spl
+
+[2]: http://addons.nvda-project.org/files/get.php?file=spl-dev
+
+[3]: https://bitbucket.org/nvdaaddonteam/stationplaylist/wiki/SPLAddonGuide
+

This diff is so big that we needed to truncate the remainder.

https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/a346d699a6ac/
Changeset:   a346d699a6ac
Branch:      None
User:        josephsl
Date:        2016-08-12 17:47:15+00:00
Summary:     Merged 7.x

Affected #:  4 files

diff --git a/addon/appModules/splstudio/__init__.py 
b/addon/appModules/splstudio/__init__.py
index d093d8b..9851d0f 100755
--- a/addon/appModules/splstudio/__init__.py
+++ b/addon/appModules/splstudio/__init__.py
@@ -582,8 +582,7 @@ class AppModule(appModuleHandler.AppModule):
                threading.Thread(target=self._locateSPLHwnd).start()
                # Check for add-on update if told to do so.
                # LTS: Only do this if channel hasn't changed.
-               # To be unlocked in 8.0 beta 1.
-               if splconfig.SPLConfig["Update"]["AutoUpdateCheck"]: # 7lts: or 
splupdate._updateNow:
+               if splconfig.SPLConfig["Update"]["AutoUpdateCheck"] or 
splupdate._updateNow:
                        # 7.0: Have a timer call the update function indirectly.
                        queueHandler.queueFunction(queueHandler.eventQueue, 
splconfig.updateInit)
                # Display startup dialogs if any.

diff --git a/addon/appModules/splstudio/splconfig.py 
b/addon/appModules/splstudio/splconfig.py
index 03c57a7..c3e5462 100755
--- a/addon/appModules/splstudio/splconfig.py
+++ b/addon/appModules/splstudio/splconfig.py
@@ -823,12 +823,11 @@ def autoUpdateCheck():
 # A bit simpler than NVDA Core's auto update checker.
 def updateInit():
        # LTS: Launch updater if channel change is detected.
-       # To be unlocked in 8.0 beta 1.
-       #if splupdate._updateNow:
-               #splupdate.updateCheck(auto=True) # No repeat here.
-               #splupdate._SPLUpdateT = wx.PyTimer(autoUpdateCheck)
-               #splupdate._updateNow = False
-               #return
+       if splupdate._updateNow:
+               splupdate.updateCheck(auto=True) # No repeat here.
+               splupdate._SPLUpdateT = wx.PyTimer(autoUpdateCheck)
+               splupdate._updateNow = False
+               return
        currentTime = time.time()
        nextCheck = 
splupdate.SPLAddonCheck+(SPLConfig["Update"]["UpdateInterval"]* 86400.0)
        if splupdate.SPLAddonCheck < currentTime < nextCheck:

diff --git a/addon/appModules/splstudio/splconfui.py 
b/addon/appModules/splstudio/splconfui.py
index 4829e3d..ac51f2d 100755
--- a/addon/appModules/splstudio/splconfui.py
+++ b/addon/appModules/splstudio/splconfui.py
@@ -338,11 +338,9 @@ class SPLConfigDialog(gui.SettingsDialog):
                self.compLayer = 
splconfig.SPLConfig["Advanced"]["CompatibilityLayer"]
                self.autoUpdateCheck = 
splconfig.SPLConfig["Update"]["AutoUpdateCheck"]
                self.updateInterval = 
splconfig.SPLConfig["Update"]["UpdateInterval"]
-               sizer.Add(item)
-               settingsSizer.Add(sizer, border=10, flag=wx.BOTTOM)
-               # To be unlocked in 8.0 beta 1.
-               #self.updateChannel = splupdate.SPLUpdateChannel
-               #self.pendingChannelChange = False
+               self.updateChannel = splupdate.SPLUpdateChannel
+               self.pendingChannelChange = False
+               settingsSizer.Add(item)
 
                # Translators: The label for a button in SPL add-on 
configuration dialog to reset settings to defaults.
                item = resetButton = wx.Button(self, label=_("Reset 
settings..."))
@@ -390,9 +388,8 @@ class SPLConfigDialog(gui.SettingsDialog):
                splconfig.SPLConfig["Advanced"]["CompatibilityLayer"] = 
self.compLayer
                splconfig.SPLConfig["Update"]["AutoUpdateCheck"] = 
self.autoUpdateCheck
                splconfig.SPLConfig["Update"]["UpdateInterval"] = 
self.updateInterval
-               # To be unlocked in 8.0 beta 1.
-               #self.pendingChannelChange = splupdate.SPLUpdateChannel != 
self.updateChannel
-               #splupdate.SPLUpdateChannel = self.updateChannel
+               self.pendingChannelChange = splupdate.SPLUpdateChannel != 
self.updateChannel
+               splupdate.SPLUpdateChannel = self.updateChannel
                splconfig.SPLSwitchProfile = self.switchProfile
                # Make sure to nullify prev profile if instant switch profile 
is gone.
                # 7.0: Don't do the following in the midst of a broadcast.
@@ -442,17 +439,15 @@ class SPLConfigDialog(gui.SettingsDialog):
                                dataLo = 0x00010000 if 
splconfig.SPLConfig["MetadataStreaming"]["MetadataEnabled"][url] else 0xffff0000
                                user32.SendMessageW(hwnd, 1024, dataLo | url, 
36)
                # Coordinate auto update timer restart routine if told to do so.
-               # To be unlocked in 8.0 beta 1.
-               if not splconfig.SPLConfig["Update"]["AutoUpdateCheck"]: # 
7lts: or self.pendingChannelChange:
+               if not splconfig.SPLConfig["Update"]["AutoUpdateCheck"] or 
self.pendingChannelChange:
                        if splupdate._SPLUpdateT is not None and 
splupdate._SPLUpdateT.IsRunning(): splupdate._SPLUpdateT.Stop()
                        splupdate._SPLUpdateT = None
-                       # To be unlocked in 8.0 beta 1.
-                       #if self.pendingChannelChange:
-                               #splupdate._pendingChannelChange = True
+                       if self.pendingChannelChange:
+                               splupdate._pendingChannelChange = True
                                # Translators: A dialog message shown when 
add-on update channel has changed.
-                               #wx.CallAfter(gui.messageBox, _("You have 
changed the add-on update channel. You must restart NVDA for the change to take 
effect. Be sure to answer yes when you are asked to install the new version 
when prompted after restarting NVDA."),
+                               wx.CallAfter(gui.messageBox, _("You have 
changed the add-on update channel. You must restart NVDA for the change to take 
effect. Be sure to answer yes when you are asked to install the new version 
when prompted after restarting NVDA."),
                                # Translators: Title of the update channel 
dialog.
-                               #_("Add-on update channel changed"), 
wx.OK|wx.ICON_INFORMATION)
+                               _("Add-on update channel changed"), 
wx.OK|wx.ICON_INFORMATION)
                else:
                        if splupdate._SPLUpdateT is None: splconfig.updateInit()
 
@@ -1296,16 +1291,15 @@ class AdvancedOptionsDialog(wx.Dialog):
                mainSizer.Add(sizer, border=10, flag=wx.BOTTOM)
 
                # LTS and 8.x only.
-               # To be unlocked in 8.0 beta 1.
-               #sizer = wx.BoxSizer(wx.HORIZONTAL)
+               sizer = wx.BoxSizer(wx.HORIZONTAL)
                # Translators: The label for a combo box to select update 
channel.
-               #label = wx.StaticText(self, wx.ID_ANY, label=_("&Add-on update 
channel:"))
-               #self.channels= wx.Choice(self, wx.ID_ANY, choices=["stable", 
"longterm"])
-               #self.updateChannels = ("stable", "lts")
-               
#self.channels.SetSelection(self.updateChannels.index(self.Parent.updateChannel))
-               #sizer.Add(label)
-               #sizer.Add(self.channels)
-               #mainSizer.Add(sizer, border=10, flag=wx.BOTTOM)
+               label = wx.StaticText(self, wx.ID_ANY, label=_("&Add-on update 
channel:"))
+               self.channels= wx.Choice(self, wx.ID_ANY, choices=["stable", 
"longterm"])
+               self.updateChannels = ("stable", "lts")
+               
self.channels.SetSelection(self.updateChannels.index(self.Parent.updateChannel))
+               sizer.Add(label)
+               sizer.Add(self.channels)
+               mainSizer.Add(sizer, border=10, flag=wx.BOTTOM)
 
                sizer = wx.BoxSizer(wx.HORIZONTAL)
                # Translators: A checkbox to toggle if SPL Controller command 
can be used to invoke Assistant layer.
@@ -1344,8 +1338,7 @@ class AdvancedOptionsDialog(wx.Dialog):
                parent.compLayer = 
self.compatibilityLayouts[self.compatibilityList.GetSelection()][0]
                parent.autoUpdateCheck = self.autoUpdateCheckbox.Value
                parent.updateInterval = self.updateInterval.Value
-               # To be unlocked in 8.0 beta 1.
-               #parent.updateChannel = ("stable", 
"lts")[self.channels.GetSelection()]
+               parent.updateChannel = ("stable", 
"lts")[self.channels.GetSelection()]
                parent.profiles.SetFocus()
                parent.Enable()
                self.Destroy()

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index d0fb211..d666e11 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -26,10 +26,9 @@ SPLAddonCheck = 0
 SPLAddonState = {}
 # Update URL (the only way to change it is installing a different version from 
a different branch).
 SPLUpdateURL = "http://addons.nvda-project.org/files/get.php?file=spl-dev";
-# To be unlocked in 8.0 beta 1.
-#_pendingChannelChange = False
-#_updateNow = False
-#SPLUpdateChannel = "stable"
+_pendingChannelChange = False
+_updateNow = False
+SPLUpdateChannel = "dev"
 # Update check timer.
 _SPLUpdateT = None
 # How long it should wait between automatic checks.
@@ -39,29 +38,26 @@ _retryAfterFailure = False
 # Stores update state.
 _updatePickle = os.path.join(globalVars.appArgs.configPath, "splupdate.pickle")
 
-# Remove comment in 8.0 beta 1.
 # Not all update channels are listed. The one not listed here is the default 
("stable" for this branch).
-"""channels={
+channels={
        "lts":"http://spl.nvda-kr.org/files/get.php?file=spl-lts7";,
-}"""
+}
 
 # Come forth, update check routines.
 def initialize():
-       # To be unlocked in 8.0 beta 1.
-       global SPLAddonState, SPLAddonCheck #, _updateNow, SPLUpdateChannel
+       global SPLAddonState, SPLAddonCheck, _updateNow, SPLUpdateChannel
        try:
                SPLAddonState = cPickle.load(file(_updatePickle, "r"))
                SPLAddonCheck = SPLAddonState["PDT"]
                if "PSZ" in SPLAddonState: del SPLAddonState["PSZ"]
                if "PCH" in SPLAddonState: del SPLAddonState["PCH"]
-               # Unlock in 8.0 beta 1.
-               #_updateNow = "pendingChannelChange" in SPLAddonState
-               #if "UpdateChannel" in SPLAddonState:
-                       #SPLUpdateChannel = SPLAddonState["UpdateChannel"]
+               _updateNow = "pendingChannelChange" in SPLAddonState
+               if "UpdateChannel" in SPLAddonState:
+                       SPLUpdateChannel = SPLAddonState["UpdateChannel"]
        except IOError:
                SPLAddonState["PDT"] = 0
-               #_updateNow = False
-               #SPLUpdateChannel = "stable"
+               _updateNow = False
+               SPLUpdateChannel = "stable"
 
 def terminate():
        global SPLAddonState
@@ -69,10 +65,9 @@ def terminate():
        stateChanged = SPLAddonState["PDT"] != SPLAddonCheck
        if stateChanged:
                SPLAddonState["PDT"] = SPLAddonCheck
-               # To be unlocked in 8.0 beta 1.
-               #SPLAddonState["UpdateChannel"] = SPLUpdateChannel
-               #if _pendingChannelChange:
-                       #SPLAddonState["pendingChannelChange"] = True
+               SPLAddonState["UpdateChannel"] = SPLUpdateChannel
+               if _pendingChannelChange:
+                       SPLAddonState["pendingChannelChange"] = True
                cPickle.dump(SPLAddonState, file(_updatePickle, "wb"))
        SPLAddonState = None
 
@@ -96,11 +91,11 @@ _progressDialog = None
 # Auto is whether to respond with UI (manual check only), continuous takes in 
auto update check variable for restarting the timer.
 # ConfUpdateInterval comes from add-on config dictionary.
 def updateCheck(auto=False, continuous=False, confUpdateInterval=1):
-       # Unlock in 8.0 beta 1.
-       #if _pendingChannelChange:
-               #wx.CallAfter(gui.messageBox, _("Did you recently tell SPL 
add-on to use a different update channel? If so, please restart NVDA before 
checking for add-on updates."), _("Update channel changed"), wx.ICON_ERROR)
-               #return
-       global _SPLUpdateT, SPLAddonCheck, _retryAfterFailure, _progressDialog
+       if _pendingChannelChange:
+               wx.CallAfter(gui.messageBox, _("Did you recently tell SPL 
add-on to use a different update channel? If so, please restart NVDA before 
checking for add-on updates."), _("Update channel changed"), wx.ICON_ERROR)
+               return
+       global _SPLUpdateT, SPLAddonCheck, _retryAfterFailure, _progressDialog, 
_updateNow
+       if _updateNow: _updateNow = False
        # Regardless of whether it is an auto check, update the check time.
        # However, this shouldnt' be done if this is a retry after a failed 
attempt.
        if not _retryAfterFailure: SPLAddonCheck = time.time()
@@ -111,10 +106,8 @@ def updateCheck(auto=False, continuous=False, 
confUpdateInterval=1):
        # All the information will be stored in the URL object, so just close 
it once the headers are downloaded.
        updateCandidate = False
        try:
-               url = urllib.urlopen(SPLUpdateURL)
-               # Replace in 8.0 beta 1.
                # Look up the channel if different from the default.
-               #url = urllib.urlopen(SPLUpdateURL if SPLUpdateChannel not in 
channels else channels[SPLUpdateChannel])
+               url = urllib.urlopen(SPLUpdateURL if SPLUpdateChannel not in 
channels else channels[SPLUpdateChannel])
                url.close()
        except IOError:
                _retryAfterFailure = True


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/caa0d7967463/
Changeset:   caa0d7967463
Branch:      None
User:        josephsl
Date:        2016-08-12 17:59:32+00:00
Summary:     Officially move to year.month scheme.

From 1.0 to 7.x, major.minor scheme was used. Starting with 8.0/16.10, 
year.month scheme is used, as the add-on is basically in maintenance mode and 
to better communicate when the add-on was released. Due to incompatible 
differences, LTS is designed version 15.0 (7 plus 8).
This change will take effect on August 15, 2016.

Affected #:  2 files

diff --git a/buildVars.py b/buildVars.py
index 0b8c63c..43dbe41 100755
--- a/buildVars.py
+++ b/buildVars.py
@@ -20,7 +20,7 @@ addon_info = {
        "addon_description" : _("""Enhances support for StationPlaylist Studio.
 In addition, adds global commands for the studio from everywhere."""),
        # version
-       "addon_version" : "8.0-dev",
+       "addon_version" : "16.10-dev",
        # Author(s)
        "addon_author" : u"Geoff Shang, Joseph Lee and other contributors",
        # URL for the add-on documentation support

diff --git a/readme.md b/readme.md
index 89b3fda..e71cf54 100755
--- a/readme.md
+++ b/readme.md
@@ -9,7 +9,7 @@ This add-on package provides improved usage of StationPlaylist 
Studio, as well a
 
 For more information about the add-on, read the [add-on guide][4]. For 
developers seeking to know how to build the add-on, see buildInstructions.txt 
located at the root of the add-on source code repository.
 
-IMPORTANT: This add-on requires NVDA 2015.3 or later and StationPlaylist 
Studio 5.00 or later. If you have installed NVDA 2016.1 or later on Windows 8 
and later, disable audio ducking mode. Also, add-on 8.0 requires Studio 5.10 
and later, and for broadcasters using Studio 5.0x, a long-term support version 
(7.x) is available.
+IMPORTANT: This add-on requires NVDA 2015.3 or later and StationPlaylist 
Studio 5.00 or later. If you have installed NVDA 2016.1 or later on Windows 8 
and later, disable audio ducking mode. Also, add-on 8.0/16.10 requires Studio 
5.10 and later, and for broadcasters using Studio 5.0x, a long-term support 
version (7.x) is available.
 
 ## Shortcut keys
 
@@ -170,10 +170,11 @@ From studio window, you can press Alt+NVDA+0 to open the 
add-on configuration di
 
 If you are using Studio on a touchscreen computer running Windows 8 or later 
and have NVDA 2012.3 or later installed, you can perform some Studio commands 
from the touchscreen. First use three finger tap to switch to SPL mode, then 
use the touch commands listed above to perform commands.
 
-## Changes for 8.0-dev/7.x-LTS
+## Changes for 8.0/16.10-dev/15.0-LTS
 
-Version 8.0 supports SPL Studio 5.10 and later, with 7.x designed to provide 
some new features from 8.0 for users using earlier versions of Studio. Unless 
otherwise noted, entries below apply to both 8.0 and 7.x. A warning dialog will 
be shown the first time you use add-on 8.0 with Studio 5.0x installed, asking 
you to use 7.x LTS version.
+Version 8.0 (also known as 16.10) supports SPL Studio 5.10 and later, with 
15.0-LTS (formerly 7.x) designed to provide some new features from 8.0 for 
users using earlier versions of Studio. Unless otherwise noted, entries below 
apply to both 8.0 and 7.x. A warning dialog will be shown the first time you 
use add-on 8.0 with Studio 5.0x installed, asking you to use 7.x LTS version.
 
+* Version scheme has changed to reflect release year.month instead of 
major.minor. During transition period (until mid-2017), version 8.0 is 
synonymous with version 16.10, with 7.x LTS being designated 15.0 due to 
incompatible changes.
 * Add-on source code is now hosted on GitHub (repository located at 
https://github.com/josephsl/stationPlaylist).
 * Added a welcome dialog that launches when Studio starts after installing the 
add-on. A command (Alt+NvDA+F1) has been added to reopen this dialog once 
dismissed.
 * Changes to various add-on commands, including removal of status announcement 
toggle (Control+NvDA+1), reassigned end of track alarm to Alt+NVDA+1, Cart 
Explorer toggle is now Alt+NvDA+3, microphone alarm dialog is Alt+NVDA+4 and 
add-on/encoder settings dialog is Alt+NvDA+0. This was done to allow 
Control+NVDA+number row to be assigned to Columns Explorer.


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/5fccdd04b077/
Changeset:   5fccdd04b077
Branch:      None
User:        josephsl
Date:        2016-08-12 18:20:39+00:00
Summary:     Merge branch '7.x'

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splconfui.py 
b/addon/appModules/splstudio/splconfui.py
index ac51f2d..1fed460 100755
--- a/addon/appModules/splstudio/splconfui.py
+++ b/addon/appModules/splstudio/splconfui.py
@@ -341,6 +341,7 @@ class SPLConfigDialog(gui.SettingsDialog):
                self.updateChannel = splupdate.SPLUpdateChannel
                self.pendingChannelChange = False
                settingsSizer.Add(item)
+               settingsSizer.Add(sizer, border=10, flag=wx.BOTTOM)
 
                # Translators: The label for a button in SPL add-on 
configuration dialog to reset settings to defaults.
                item = resetButton = wx.Button(self, label=_("Reset 
settings..."))


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/ba3bba74cd4f/
Changeset:   ba3bba74cd4f
Branch:      None
User:        josephsl
Date:        2016-08-15 15:52:01+00:00
Summary:     Merged stable

Affected #:  4 files

diff --git a/addon/appModules/splstudio/splconfui.py 
b/addon/appModules/splstudio/splconfui.py
index 1fed460..68ea19c 100755
--- a/addon/appModules/splstudio/splconfui.py
+++ b/addon/appModules/splstudio/splconfui.py
@@ -1296,7 +1296,7 @@ class AdvancedOptionsDialog(wx.Dialog):
                # Translators: The label for a combo box to select update 
channel.
                label = wx.StaticText(self, wx.ID_ANY, label=_("&Add-on update 
channel:"))
                self.channels= wx.Choice(self, wx.ID_ANY, choices=["stable", 
"longterm"])
-               self.updateChannels = ("stable", "lts")
+               self.updateChannels = ("beta", "stable", "lts")
                
self.channels.SetSelection(self.updateChannels.index(self.Parent.updateChannel))
                sizer.Add(label)
                sizer.Add(self.channels)
@@ -1339,7 +1339,7 @@ class AdvancedOptionsDialog(wx.Dialog):
                parent.compLayer = 
self.compatibilityLayouts[self.compatibilityList.GetSelection()][0]
                parent.autoUpdateCheck = self.autoUpdateCheckbox.Value
                parent.updateInterval = self.updateInterval.Value
-               parent.updateChannel = ("stable", 
"lts")[self.channels.GetSelection()]
+               parent.updateChannel = ("beta", "stable", 
"lts")[self.channels.GetSelection()]
                parent.profiles.SetFocus()
                parent.Enable()
                self.Destroy()

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index d666e11..f7ddeff 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -40,7 +40,8 @@ _updatePickle = os.path.join(globalVars.appArgs.configPath, 
"splupdate.pickle")
 
 # Not all update channels are listed. The one not listed here is the default 
("stable" for this branch).
 channels={
-       "lts":"http://spl.nvda-kr.org/files/get.php?file=spl-lts7";,
+       "lts":"http://spl.nvda-kr.org/files/get.php?file=spl-lts16";,
+       "beta":"http://spl.nvda-kr.org/files/get.php?file=spl-beta";,
 }
 
 # Come forth, update check routines.

diff --git a/addon/installTasks.py b/addon/installTasks.py
index d55b148..cc0622f 100755
--- a/addon/installTasks.py
+++ b/addon/installTasks.py
@@ -16,3 +16,5 @@ def onInstall():
                        shutil.copytree(profiles, newProfiles)
                except IOError:
                        pass
+       # 7.4 only: prepare LTS presentation file (an empty text file)
+       open(os.path.join(os.path.dirname(__file__), "ltsprep"), "w").close()

diff --git a/readme.md b/readme.md
index e71cf54..2fa90ea 100755
--- a/readme.md
+++ b/readme.md
@@ -189,6 +189,14 @@ Version 8.0 (also known as 16.10) supports SPL Studio 5.10 
and later, with 15.0-
 * 8.0: Added a dialog in add-on settings to configure Columns Explorer slots 
for Track Tool.
 * You can now configure microphone alarm interval from microphone alarm dialog 
(Alt+NvDA+4).
 
+## Version 7.4/16.08
+
+Version 7.4 is also known as 16.08 following the year.month version number for 
stable releases. 7.4 is the last version in the 7.x series and the entire 
major.minor version numbers.
+
+* It is possible to select add-on update channel, to be removed later in 2017. 
For 7.4, available channels are beta, stable and long-term.
+* SPL Controller command and the command to focus to Studio will not be 
available from secure screens.
+* New and updated translations and added localized documentation in various 
languages.
+
 ## Changes for 7.3
 
 * Slight performance improvements when looking up information such as 
automation via some SPL Assistant commands.


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/95a8dd4c1e60/
Changeset:   95a8dd4c1e60
Branch:      None
User:        josephsl
Date:        2016-08-15 15:58:25+00:00
Summary:     8.0 beta 0: add dev and beta channels

Affected #:  2 files

diff --git a/addon/appModules/splstudio/splconfui.py 
b/addon/appModules/splstudio/splconfui.py
index 68ea19c..d818ce3 100755
--- a/addon/appModules/splstudio/splconfui.py
+++ b/addon/appModules/splstudio/splconfui.py
@@ -1295,8 +1295,8 @@ class AdvancedOptionsDialog(wx.Dialog):
                sizer = wx.BoxSizer(wx.HORIZONTAL)
                # Translators: The label for a combo box to select update 
channel.
                label = wx.StaticText(self, wx.ID_ANY, label=_("&Add-on update 
channel:"))
-               self.channels= wx.Choice(self, wx.ID_ANY, choices=["stable", 
"longterm"])
-               self.updateChannels = ("beta", "stable", "lts")
+               self.channels= wx.Choice(self, wx.ID_ANY, choices=["beta", 
"stable", "longterm"])
+               self.updateChannels = ("dev", "beta", "stable", "lts")
                
self.channels.SetSelection(self.updateChannels.index(self.Parent.updateChannel))
                sizer.Add(label)
                sizer.Add(self.channels)
@@ -1339,7 +1339,7 @@ class AdvancedOptionsDialog(wx.Dialog):
                parent.compLayer = 
self.compatibilityLayouts[self.compatibilityList.GetSelection()][0]
                parent.autoUpdateCheck = self.autoUpdateCheckbox.Value
                parent.updateInterval = self.updateInterval.Value
-               parent.updateChannel = ("beta", "stable", 
"lts")[self.channels.GetSelection()]
+               parent.updateChannel = ("dev", "beta", "stable", 
"lts")[self.channels.GetSelection()]
                parent.profiles.SetFocus()
                parent.Enable()
                self.Destroy()

diff --git a/addon/installTasks.py b/addon/installTasks.py
index cc0622f..e0f5bdc 100755
--- a/addon/installTasks.py
+++ b/addon/installTasks.py
@@ -17,4 +17,4 @@ def onInstall():
                except IOError:
                        pass
        # 7.4 only: prepare LTS presentation file (an empty text file)
-       open(os.path.join(os.path.dirname(__file__), "ltsprep"), "w").close()
+       #open(os.path.join(os.path.dirname(__file__), "ltsprep"), "w").close()


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/da8e7944fb2d/
Changeset:   da8e7944fb2d
Branch:      None
User:        josephsl
Date:        2016-08-15 16:02:16+00:00
Summary:     Merged stable

Affected #:  1 file

diff --git a/readme.md b/readme.md
index 2fa90ea..7e91f1c 100755
--- a/readme.md
+++ b/readme.md
@@ -193,7 +193,7 @@ Version 8.0 (also known as 16.10) supports SPL Studio 5.10 
and later, with 15.0-
 
 Version 7.4 is also known as 16.08 following the year.month version number for 
stable releases. 7.4 is the last version in the 7.x series and the entire 
major.minor version numbers.
 
-* It is possible to select add-on update channel, to be removed later in 2017. 
For 7.4, available channels are beta, stable and long-term.
+* It is possible to select add-on update channel from add-on settings/advanced 
settings, to be removed later in 2017. For 7.4, available channels are beta, 
stable and long-term.
 * SPL Controller command and the command to focus to Studio will not be 
available from secure screens.
 * New and updated translations and added localized documentation in various 
languages.
 


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/e50f2f84dad7/
Changeset:   e50f2f84dad7
Branch:      None
User:        josephsl
Date:        2016-08-15 16:03:22+00:00
Summary:     Add channel label for dev channel

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splconfui.py 
b/addon/appModules/splstudio/splconfui.py
index d818ce3..22fdcd4 100755
--- a/addon/appModules/splstudio/splconfui.py
+++ b/addon/appModules/splstudio/splconfui.py
@@ -1295,7 +1295,7 @@ class AdvancedOptionsDialog(wx.Dialog):
                sizer = wx.BoxSizer(wx.HORIZONTAL)
                # Translators: The label for a combo box to select update 
channel.
                label = wx.StaticText(self, wx.ID_ANY, label=_("&Add-on update 
channel:"))
-               self.channels= wx.Choice(self, wx.ID_ANY, choices=["beta", 
"stable", "longterm"])
+               self.channels= wx.Choice(self, wx.ID_ANY, choices=["beta", 
"development", "stable", "longterm"])
                self.updateChannels = ("dev", "beta", "stable", "lts")
                
self.channels.SetSelection(self.updateChannels.index(self.Parent.updateChannel))
                sizer.Add(label)


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/370c68db4921/
Changeset:   370c68db4921
Branch:      None
User:        josephsl
Date:        2016-08-15 16:16:50+00:00
Summary:     7.4: Oops, add a right parenthesis for lts prep path, added a 
missing update interval check entry in readme

Affected #:  2 files

diff --git a/addon/appModules/splstudio/splconfig.py 
b/addon/appModules/splstudio/splconfig.py
index 1788a7f..d2e2dd5 100755
--- a/addon/appModules/splstudio/splconfig.py
+++ b/addon/appModules/splstudio/splconfig.py
@@ -852,7 +852,7 @@ def showStartupDialogs():
        if os.path.exists(os.path.join(globalVars.appArgs.configPath, "addons", 
"stationPlaylist", "ltsprep")):
                if gui.messageBox("The next major version of the add-on (15.x) 
will be the last version to support Studio versions earlier than 5.10, with 
add-on 15.x being designated as a long-term support version. Would you like to 
switch to long-term support release?", "Long-Term Support version", wx.YES | 
wx.NO | wx.CANCEL | wx.CENTER | wx.ICON_QUESTION) == wx.YES:
                        splupdate.SPLUpdateChannel = "lts"
-                       os.remove(os.path.join(globalVars.appArgs.configPath, 
"addons", "stationPlaylist", "ltsprep")
+                       os.remove(os.path.join(globalVars.appArgs.configPath, 
"addons", "stationPlaylist", "ltsprep"))
        try:
                import audioDucking
                if SPLConfig["Startup"]["AudioDuckingReminder"] and 
audioDucking.isAudioDuckingSupported():

diff --git a/readme.md b/readme.md
index dcdd8d1..bbf7cd0 100755
--- a/readme.md
+++ b/readme.md
@@ -171,7 +171,8 @@ If you are using Studio on a touchscreen computer running 
Windows 8 or later and
 
 Version 7.4 is also known as 16.08 following the year.month version number for 
stable releases. 7.4 is the last version in the 7.x series and the entire 
major.minor version numbers.
 
-* It is possible to select add-on update channel from add-on settings/advanced 
settings, to be removed later in 2017. For 7.4, available channels are beta, 
stable and long-term.
+* It is possible to select add-on update channel from add-on settings/advanced 
options, to be removed later in 2017. For 7.4, available channels are beta, 
stable and long-term.
+* Added a setting in add-on settings/Advanced options to configure update 
check interval between 1 and 30 days (default is 7 or weekly checks).
 * SPL Controller command and the command to focus to Studio will not be 
available from secure screens.
 * New and updated translations and added localized documentation in various 
languages.
 


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/4d589aa87305/
Changeset:   4d589aa87305
Branch:      None
User:        josephsl
Date:        2016-08-15 16:19:36+00:00
Summary:     Merged stable

Affected #:  2 files

diff --git a/addon/appModules/splstudio/splconfig.py 
b/addon/appModules/splstudio/splconfig.py
index c3e5462..49e5c89 100755
--- a/addon/appModules/splstudio/splconfig.py
+++ b/addon/appModules/splstudio/splconfig.py
@@ -1116,6 +1116,11 @@ def showStartupDialogs(oldVer=False):
                gui.mainFrame.prePopup()
                WelcomeDialog(gui.mainFrame).Show()
                gui.mainFrame.postPopup()
+       # 7.4 only: Show branch selection dialog.
+       #if os.path.exists(os.path.join(globalVars.appArgs.configPath, 
"addons", "stationPlaylist", "ltsprep")):
+               #if gui.messageBox("The next major version of the add-on (15.x) 
will be the last version to support Studio versions earlier than 5.10, with 
add-on 15.x being designated as a long-term support version. Would you like to 
switch to long-term support release?", "Long-Term Support version", wx.YES | 
wx.NO | wx.CANCEL | wx.CENTER | wx.ICON_QUESTION) == wx.YES:
+                       #splupdate.SPLUpdateChannel = "lts"
+                       #os.remove(os.path.join(globalVars.appArgs.configPath, 
"addons", "stationPlaylist", "ltsprep"))
        try:
                import audioDucking
                if SPLConfig["Startup"]["AudioDuckingReminder"] and 
audioDucking.isAudioDuckingSupported():

diff --git a/readme.md b/readme.md
index 7e91f1c..95d9e43 100755
--- a/readme.md
+++ b/readme.md
@@ -193,7 +193,8 @@ Version 8.0 (also known as 16.10) supports SPL Studio 5.10 
and later, with 15.0-
 
 Version 7.4 is also known as 16.08 following the year.month version number for 
stable releases. 7.4 is the last version in the 7.x series and the entire 
major.minor version numbers.
 
-* It is possible to select add-on update channel from add-on settings/advanced 
settings, to be removed later in 2017. For 7.4, available channels are beta, 
stable and long-term.
+* It is possible to select add-on update channel from add-on settings/advanced 
options, to be removed later in 2017. For 7.4, available channels are beta, 
stable and long-term.
+* Added a setting in add-on settings/Advanced options to configure update 
check interval between 1 and 30 days (default is 7 or weekly checks).
 * SPL Controller command and the command to focus to Studio will not be 
available from secure screens.
 * New and updated translations and added localized documentation in various 
languages.
 


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/89bfc43ed6f2/
Changeset:   89bfc43ed6f2
Branch:      None
User:        josephsl
Date:        2016-08-15 16:32:10+00:00
Summary:     7.4: Make sure to nullify the correct key from add-on state pickle.

Without nullifying pending update change, an endless loop of update 
notification will be displayed each time add-on restarts.

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index df16bd5..46762d2 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -53,6 +53,7 @@ def initialize():
                if "PSZ" in SPLAddonState: del SPLAddonState["PSZ"]
                if "PCH" in SPLAddonState: del SPLAddonState["PCH"]
                _updateNow = "pendingChannelChange" in SPLAddonState
+               del SPLAddonState["pendingChannelChange"]
                if "UpdateChannel" in SPLAddonState:
                        SPLUpdateChannel = SPLAddonState["UpdateChannel"]
        except IOError:


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/efe7caab2ec8/
Changeset:   efe7caab2ec8
Branch:      None
User:        josephsl
Date:        2016-08-15 16:32:27+00:00
Summary:     Merge branch 'stable'

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index f7ddeff..9320cb0 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -53,6 +53,7 @@ def initialize():
                if "PSZ" in SPLAddonState: del SPLAddonState["PSZ"]
                if "PCH" in SPLAddonState: del SPLAddonState["PCH"]
                _updateNow = "pendingChannelChange" in SPLAddonState
+               del SPLAddonState["pendingChannelChange"]
                if "UpdateChannel" in SPLAddonState:
                        SPLUpdateChannel = SPLAddonState["UpdateChannel"]
        except IOError:


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/99414763bad3/
Changeset:   99414763bad3
Branch:      None
User:        josephsl
Date:        2016-08-15 16:34:39+00:00
Summary:     7.4: Catch key error for pending update change key

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index 46762d2..412812e 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -56,7 +56,7 @@ def initialize():
                del SPLAddonState["pendingChannelChange"]
                if "UpdateChannel" in SPLAddonState:
                        SPLUpdateChannel = SPLAddonState["UpdateChannel"]
-       except IOError:
+       except IOError, KeyError:
                SPLAddonState["PDT"] = 0
                _updateNow = False
                SPLUpdateChannel = "stable"


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/94b55a3cb10f/
Changeset:   94b55a3cb10f
Branch:      None
User:        josephsl
Date:        2016-08-15 16:34:46+00:00
Summary:     Merge branch 'stable'

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index 9320cb0..27a1309 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -56,7 +56,7 @@ def initialize():
                del SPLAddonState["pendingChannelChange"]
                if "UpdateChannel" in SPLAddonState:
                        SPLUpdateChannel = SPLAddonState["UpdateChannel"]
-       except IOError:
+       except IOError, KeyError:
                SPLAddonState["PDT"] = 0
                _updateNow = False
                SPLUpdateChannel = "stable"


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/9f53bf855e6a/
Changeset:   9f53bf855e6a
Branch:      None
User:        josephsl
Date:        2016-08-15 16:37:20+00:00
Summary:     7.4: Catch possible key error in pending channel change key

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index 46762d2..412812e 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -56,7 +56,7 @@ def initialize():
                del SPLAddonState["pendingChannelChange"]
                if "UpdateChannel" in SPLAddonState:
                        SPLUpdateChannel = SPLAddonState["UpdateChannel"]
-       except IOError:
+       except IOError, KeyError:
                SPLAddonState["PDT"] = 0
                _updateNow = False
                SPLUpdateChannel = "stable"


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/3a22f8cab4d5/
Changeset:   3a22f8cab4d5
Branch:      None
User:        josephsl
Date:        2016-08-15 16:38:19+00:00
Summary:     7.4: Let's try again: catch pending channel change key error

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index 412812e..85d52f7 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -53,10 +53,10 @@ def initialize():
                if "PSZ" in SPLAddonState: del SPLAddonState["PSZ"]
                if "PCH" in SPLAddonState: del SPLAddonState["PCH"]
                _updateNow = "pendingChannelChange" in SPLAddonState
-               del SPLAddonState["pendingChannelChange"]
+               if "pendingChannelChange" in SPLAddonState: del 
SPLAddonState["pendingChannelChange"]
                if "UpdateChannel" in SPLAddonState:
                        SPLUpdateChannel = SPLAddonState["UpdateChannel"]
-       except IOError, KeyError:
+       except IOError:
                SPLAddonState["PDT"] = 0
                _updateNow = False
                SPLUpdateChannel = "stable"


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/e74573473b1a/
Changeset:   e74573473b1a
Branch:      None
User:        josephsl
Date:        2016-08-15 16:38:32+00:00
Summary:     Merge branch 'stable'

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index 27a1309..98fa2c3 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -53,7 +53,7 @@ def initialize():
                if "PSZ" in SPLAddonState: del SPLAddonState["PSZ"]
                if "PCH" in SPLAddonState: del SPLAddonState["PCH"]
                _updateNow = "pendingChannelChange" in SPLAddonState
-               del SPLAddonState["pendingChannelChange"]
+               if "pendingChannelChange" in SPLAddonState: del 
SPLAddonState["pendingChannelChange"]
                if "UpdateChannel" in SPLAddonState:
                        SPLUpdateChannel = SPLAddonState["UpdateChannel"]
        except IOError, KeyError:


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/f87d98d0005d/
Changeset:   f87d98d0005d
Branch:      None
User:        josephsl
Date:        2016-08-15 16:55:17+00:00
Summary:     7.4: when checking for state change, make sure to check channel 
change as well, otherwise channel change will not be applied.

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index 85d52f7..565de9c 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -64,7 +64,7 @@ def initialize():
 def terminate():
        global SPLAddonState
        # Store new values if it is absolutely required.
-       stateChanged = SPLAddonState["PDT"] != SPLAddonCheck
+       stateChanged = (SPLAddonState["PDT"] != SPLAddonCheck or 
SPLAddonState["UpdateChannel"] != SPLUpdateChannel)
        if stateChanged:
                SPLAddonState["PDT"] = SPLAddonCheck
                SPLAddonState["UpdateChannel"] = SPLUpdateChannel


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/a6eb978a2a93/
Changeset:   a6eb978a2a93
Branch:      None
User:        josephsl
Date:        2016-08-15 16:55:43+00:00
Summary:     Merge branch 'stable'

Affected #:  1 file

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index 98fa2c3..f3c80e6 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -64,7 +64,7 @@ def initialize():
 def terminate():
        global SPLAddonState
        # Store new values if it is absolutely required.
-       stateChanged = SPLAddonState["PDT"] != SPLAddonCheck
+       stateChanged = (SPLAddonState["PDT"] != SPLAddonCheck or 
SPLAddonState["UpdateChannel"] != SPLUpdateChannel)
        if stateChanged:
                SPLAddonState["PDT"] = SPLAddonCheck
                SPLAddonState["UpdateChannel"] = SPLUpdateChannel


https://bitbucket.org/nvdaaddonteam/stationplaylist/commits/7c5815337090/
Changeset:   7c5815337090
Branch:      master
User:        josephsl
Date:        2016-08-15 17:02:51+00:00
Summary:     8.0: Reorder channels list

Affected #:  2 files

diff --git a/addon/appModules/splstudio/splconfui.py 
b/addon/appModules/splstudio/splconfui.py
index 22fdcd4..0f1e518 100755
--- a/addon/appModules/splstudio/splconfui.py
+++ b/addon/appModules/splstudio/splconfui.py
@@ -1295,7 +1295,7 @@ class AdvancedOptionsDialog(wx.Dialog):
                sizer = wx.BoxSizer(wx.HORIZONTAL)
                # Translators: The label for a combo box to select update 
channel.
                label = wx.StaticText(self, wx.ID_ANY, label=_("&Add-on update 
channel:"))
-               self.channels= wx.Choice(self, wx.ID_ANY, choices=["beta", 
"development", "stable", "longterm"])
+               self.channels= wx.Choice(self, wx.ID_ANY, 
choices=["development", "beta", "stable", "longterm"])
                self.updateChannels = ("dev", "beta", "stable", "lts")
                
self.channels.SetSelection(self.updateChannels.index(self.Parent.updateChannel))
                sizer.Add(label)

diff --git a/addon/appModules/splstudio/splupdate.py 
b/addon/appModules/splstudio/splupdate.py
index f3c80e6..d71e717 100755
--- a/addon/appModules/splstudio/splupdate.py
+++ b/addon/appModules/splstudio/splupdate.py
@@ -59,7 +59,7 @@ def initialize():
        except IOError, KeyError:
                SPLAddonState["PDT"] = 0
                _updateNow = False
-               SPLUpdateChannel = "stable"
+               SPLUpdateChannel = "dev"
 
 def terminate():
        global SPLAddonState

Repository URL: https://bitbucket.org/nvdaaddonteam/stationplaylist/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.

Other related posts:

  • » commit/StationPlaylist: 35 new changesets - commits-noreply