1# Orca
2#
3# Copyright 2005-2009 Sun Microsystems Inc.
4#
5# This library is free software; you can redistribute it and/or
6# modify it under the terms of the GNU Lesser General Public
7# License as published by the Free Software Foundation; either
8# version 2.1 of the License, or (at your option) any later version.
9#
10# This library is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13# Lesser General Public License for more details.
14#
15# You should have received a copy of the GNU Lesser General Public
16# License along with this library; if not, write to the
17# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
18# Boston MA  02110-1301 USA.
19
20"""Displays a GUI for the user to set Orca preferences."""
21
22__id__        = "$Id$"
23__version__   = "$Revision$"
24__date__      = "$Date$"
25__copyright__ = "Copyright (c) 2005-2009 Sun Microsystems Inc."
26__license__   = "LGPL"
27
28import os
29from gi.repository import Gdk
30from gi.repository import GLib
31from gi.repository import Gtk
32from gi.repository import GObject
33from gi.repository import Pango
34import pyatspi
35import time
36
37from . import acss
38from . import debug
39from . import guilabels
40from . import messages
41from . import orca
42from . import orca_gtkbuilder
43from . import orca_gui_profile
44from . import orca_state
45from . import orca_platform
46from . import settings
47from . import settings_manager
48from . import input_event
49from . import keybindings
50from . import pronunciation_dict
51from . import braille
52from . import speech
53from . import speechserver
54from . import text_attribute_names
55
56_settingsManager = settings_manager.getManager()
57
58try:
59    import louis
60except ImportError:
61    louis = None
62from .orca_platform import tablesdir
63if louis and not tablesdir:
64    louis = None
65
66(HANDLER, DESCRIP, MOD_MASK1, MOD_USED1, KEY1, CLICK_COUNT1, OLDTEXT1, \
67 TEXT1, MODIF, EDITABLE) = list(range(10))
68
69(NAME, IS_SPOKEN, IS_BRAILLED, VALUE) = list(range(4))
70
71(ACTUAL, REPLACEMENT) = list(range(2))
72
73# Must match the order of voice types in the GtkBuilder file.
74#
75(DEFAULT, UPPERCASE, HYPERLINK, SYSTEM) = list(range(4))
76
77# Must match the order that the timeFormatCombo is populated.
78#
79(TIME_FORMAT_LOCALE, TIME_FORMAT_12_HM, TIME_FORMAT_12_HMS, TIME_FORMAT_24_HMS,
80 TIME_FORMAT_24_HMS_WITH_WORDS, TIME_FORMAT_24_HM,
81 TIME_FORMAT_24_HM_WITH_WORDS) = list(range(7))
82
83# Must match the order that the dateFormatCombo is populated.
84#
85(DATE_FORMAT_LOCALE, DATE_FORMAT_NUMBERS_DM, DATE_FORMAT_NUMBERS_MD,
86 DATE_FORMAT_NUMBERS_DMY, DATE_FORMAT_NUMBERS_MDY, DATE_FORMAT_NUMBERS_YMD,
87 DATE_FORMAT_FULL_DM, DATE_FORMAT_FULL_MD, DATE_FORMAT_FULL_DMY,
88 DATE_FORMAT_FULL_MDY, DATE_FORMAT_FULL_YMD, DATE_FORMAT_ABBREVIATED_DM,
89 DATE_FORMAT_ABBREVIATED_MD, DATE_FORMAT_ABBREVIATED_DMY,
90 DATE_FORMAT_ABBREVIATED_MDY, DATE_FORMAT_ABBREVIATED_YMD) = list(range(16))
91
92class OrcaSetupGUI(orca_gtkbuilder.GtkBuilderWrapper):
93
94    def __init__(self, fileName, windowName, prefsDict):
95        """Initialize the Orca configuration GUI.
96
97        Arguments:
98        - fileName: name of the GtkBuilder file.
99        - windowName: name of the component to get from the GtkBuilder file.
100        - prefsDict: dictionary of preferences to use during initialization
101        """
102
103        orca_gtkbuilder.GtkBuilderWrapper.__init__(self, fileName, windowName)
104        self.prefsDict = prefsDict
105
106        self._defaultProfile = ['Default', 'default']
107
108        # Initialize variables to None to keep pylint happy.
109        #
110        self.bbindings = None
111        self.cellRendererText = None
112        self.defaultVoice = None
113        self.disableKeyGrabPref = None
114        self.getTextAttributesView = None
115        self.hyperlinkVoice = None
116        self.initializingSpeech = None
117        self.kbindings = None
118        self.keyBindingsModel = None
119        self.keyBindView = None
120        self.newBinding = None
121        self.pendingKeyBindings = None
122        self.planeCellRendererText = None
123        self.pronunciationModel = None
124        self.pronunciationView = None
125        self.screenHeight = None
126        self.screenWidth = None
127        self.speechFamiliesChoice = None
128        self.speechFamiliesChoices = None
129        self.speechFamiliesModel = None
130        self.speechLanguagesChoice = None
131        self.speechLanguagesChoices = None
132        self.speechLanguagesModel = None
133        self.speechFamilies = []
134        self.speechServersChoice = None
135        self.speechServersChoices = None
136        self.speechServersModel = None
137        self.speechSystemsChoice = None
138        self.speechSystemsChoices = None
139        self.speechSystemsModel = None
140        self.systemVoice = None
141        self.uppercaseVoice = None
142        self.window = None
143        self.workingFactories = None
144        self.savedGain = None
145        self.savedPitch = None
146        self.savedRate = None
147        self._isInitialSetup = False
148        self.selectedFamilyChoices = {}
149        self.selectedLanguageChoices = {}
150        self.profilesCombo = None
151        self.profilesComboModel = None
152        self.startingProfileCombo = None
153        self._capturedKey = []
154        self.script = None
155
156    def init(self, script):
157        """Initialize the Orca configuration GUI. Read the users current
158        set of preferences and set the GUI state to match. Setup speech
159        support and populate the combo box lists on the Speech Tab pane
160        accordingly.
161        """
162
163        self.script = script
164
165        # Restore the default rate/pitch/gain,
166        # in case the user played with the sliders.
167        #
168        try:
169            voices = _settingsManager.getSetting('voices')
170            defaultVoice = voices[settings.DEFAULT_VOICE]
171        except KeyError:
172            defaultVoice = {}
173        try:
174            self.savedGain = defaultVoice[acss.ACSS.GAIN]
175        except KeyError:
176            self.savedGain = 10.0
177        try:
178            self.savedPitch = defaultVoice[acss.ACSS.AVERAGE_PITCH]
179        except KeyError:
180            self.savedPitch = 5.0
181        try:
182            self.savedRate = defaultVoice[acss.ACSS.RATE]
183        except KeyError:
184            self.savedRate = 50.0
185
186        # ***** Key Bindings treeview initialization *****
187
188        self.keyBindView = self.get_widget("keyBindingsTreeview")
189
190        if self.keyBindView.get_columns():
191            for column in self.keyBindView.get_columns():
192                self.keyBindView.remove_column(column)
193
194        self.keyBindingsModel = Gtk.TreeStore(
195            GObject.TYPE_STRING,  # Handler name
196            GObject.TYPE_STRING,  # Human Readable Description
197            GObject.TYPE_STRING,  # Modifier mask 1
198            GObject.TYPE_STRING,  # Used Modifiers 1
199            GObject.TYPE_STRING,  # Modifier key name 1
200            GObject.TYPE_STRING,  # Click count 1
201            GObject.TYPE_STRING,  # Original Text of the Key Binding Shown 1
202            GObject.TYPE_STRING,  # Text of the Key Binding Shown 1
203            GObject.TYPE_BOOLEAN, # Key Modified by User
204            GObject.TYPE_BOOLEAN) # Row with fields editable or not
205
206        self.planeCellRendererText = Gtk.CellRendererText()
207
208        self.cellRendererText = Gtk.CellRendererText()
209        self.cellRendererText.set_property("ellipsize", Pango.EllipsizeMode.END)
210
211        # HANDLER - invisble column
212        #
213        column = Gtk.TreeViewColumn("Handler",
214                                    self.planeCellRendererText,
215                                    text=HANDLER)
216        column.set_resizable(True)
217        column.set_visible(False)
218        column.set_sort_column_id(HANDLER)
219        self.keyBindView.append_column(column)
220
221        # DESCRIP
222        #
223        column = Gtk.TreeViewColumn(guilabels.KB_HEADER_FUNCTION,
224                                    self.cellRendererText,
225                                    text=DESCRIP)
226        column.set_resizable(True)
227        column.set_min_width(380)
228        column.set_sort_column_id(DESCRIP)
229        self.keyBindView.append_column(column)
230
231        # MOD_MASK1 - invisble column
232        #
233        column = Gtk.TreeViewColumn("Mod.Mask 1",
234                                    self.planeCellRendererText,
235                                    text=MOD_MASK1)
236        column.set_visible(False)
237        column.set_resizable(True)
238        column.set_sort_column_id(MOD_MASK1)
239        self.keyBindView.append_column(column)
240
241        # MOD_USED1 - invisble column
242        #
243        column = Gtk.TreeViewColumn("Use Mod.1",
244                                    self.planeCellRendererText,
245                                    text=MOD_USED1)
246        column.set_visible(False)
247        column.set_resizable(True)
248        column.set_sort_column_id(MOD_USED1)
249        self.keyBindView.append_column(column)
250
251        # KEY1 - invisble column
252        #
253        column = Gtk.TreeViewColumn("Key1",
254                                    self.planeCellRendererText,
255                                    text=KEY1)
256        column.set_resizable(True)
257        column.set_visible(False)
258        column.set_sort_column_id(KEY1)
259        self.keyBindView.append_column(column)
260
261        # CLICK_COUNT1 - invisble column
262        #
263        column = Gtk.TreeViewColumn("ClickCount1",
264                                    self.planeCellRendererText,
265                                    text=CLICK_COUNT1)
266        column.set_resizable(True)
267        column.set_visible(False)
268        column.set_sort_column_id(CLICK_COUNT1)
269        self.keyBindView.append_column(column)
270
271        # OLDTEXT1 - invisble column which will store a copy of the
272        # original keybinding in TEXT1 prior to the Apply or OK
273        # buttons being pressed.  This will prevent automatic
274        # resorting each time a cell is edited.
275        #
276        column = Gtk.TreeViewColumn("OldText1",
277                                    self.planeCellRendererText,
278                                    text=OLDTEXT1)
279        column.set_resizable(True)
280        column.set_visible(False)
281        column.set_sort_column_id(OLDTEXT1)
282        self.keyBindView.append_column(column)
283
284        # TEXT1
285        #
286        rendererText = Gtk.CellRendererText()
287        rendererText.connect("editing-started",
288                             self.editingKey,
289                             self.keyBindingsModel)
290        rendererText.connect("editing-canceled",
291                             self.editingCanceledKey)
292        rendererText.connect('edited',
293                             self.editedKey,
294                             self.keyBindingsModel,
295                             MOD_MASK1, MOD_USED1, KEY1, CLICK_COUNT1, TEXT1)
296
297        column = Gtk.TreeViewColumn(guilabels.KB_HEADER_KEY_BINDING,
298                                    rendererText,
299                                    text=TEXT1,
300                                    editable=EDITABLE)
301
302        column.set_resizable(True)
303        column.set_sort_column_id(OLDTEXT1)
304        self.keyBindView.append_column(column)
305
306        # MODIF
307        #
308        rendererToggle = Gtk.CellRendererToggle()
309        rendererToggle.connect('toggled',
310                               self.keyModifiedToggle,
311                               self.keyBindingsModel,
312                               MODIF)
313        column = Gtk.TreeViewColumn(guilabels.KB_MODIFIED,
314                                    rendererToggle,
315                                    active=MODIF,
316                                    activatable=EDITABLE)
317        #column.set_visible(False)
318        column.set_resizable(True)
319        column.set_sort_column_id(MODIF)
320        self.keyBindView.append_column(column)
321
322        # EDITABLE - invisble column
323        #
324        rendererToggle = Gtk.CellRendererToggle()
325        rendererToggle.set_property('activatable', False)
326        column = Gtk.TreeViewColumn("Modified",
327                                    rendererToggle,
328                                    active=EDITABLE)
329        column.set_visible(False)
330        column.set_resizable(True)
331        column.set_sort_column_id(EDITABLE)
332        self.keyBindView.append_column(column)
333
334        # Populates the treeview with all the keybindings:
335        #
336        self._populateKeyBindings()
337
338        self.window = self.get_widget("orcaSetupWindow")
339
340        self._setKeyEchoItems()
341
342        self.speechSystemsModel  = \
343                        self._initComboBox(self.get_widget("speechSystems"))
344        self.speechServersModel  = \
345                        self._initComboBox(self.get_widget("speechServers"))
346        self.speechLanguagesModel = \
347                        self._initComboBox(self.get_widget("speechLanguages"))
348        self.speechFamiliesModel = \
349                        self._initComboBox(self.get_widget("speechFamilies"))
350        self._initSpeechState()
351
352        # TODO - JD: Will this ever be the case??
353        self._isInitialSetup = \
354            not os.path.exists(_settingsManager.getPrefsDir())
355
356        appPage = self.script.getAppPreferencesGUI()
357        if appPage:
358            label = Gtk.Label(label=self.script.app.name)
359            self.get_widget("notebook").append_page(appPage, label)
360
361        self._initGUIState()
362
363    def _getACSSForVoiceType(self, voiceType):
364        """Return the ACSS value for the given voice type.
365
366        Arguments:
367        - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
368
369        Returns the voice dictionary for the given voice type.
370        """
371
372        if voiceType == DEFAULT:
373            voiceACSS = self.defaultVoice
374        elif voiceType == UPPERCASE:
375            voiceACSS = self.uppercaseVoice
376        elif voiceType == HYPERLINK:
377            voiceACSS = self.hyperlinkVoice
378        elif voiceType == SYSTEM:
379            voiceACSS = self.systemVoice
380        else:
381            voiceACSS = self.defaultVoice
382
383        return voiceACSS
384
385    def writeUserPreferences(self):
386        """Write out the user's generic Orca preferences.
387        """
388        pronunciationDict = self.getModelDict(self.pronunciationModel)
389        keyBindingsDict = self.getKeyBindingsModelDict(self.keyBindingsModel)
390        self.prefsDict.update(self.script.getPreferencesFromGUI())
391        _settingsManager.saveSettings(self.script,
392                                      self.prefsDict,
393                                      pronunciationDict,
394                                      keyBindingsDict)
395
396    def _getKeyValueForVoiceType(self, voiceType, key, useDefault=True):
397        """Look for the value of the given key in the voice dictionary
398           for the given voice type.
399
400        Arguments:
401        - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
402        - key: the key to look for in the voice dictionary.
403        - useDefault: if True, and the key isn't found for the given voice
404                      type, the look for it in the default voice dictionary
405                      as well.
406
407        Returns the value of the given key, or None if it's not set.
408        """
409
410        if voiceType == DEFAULT:
411            voice = self.defaultVoice
412        elif voiceType == UPPERCASE:
413            voice = self.uppercaseVoice
414            if key not in voice:
415                if not useDefault:
416                    return None
417                voice = self.defaultVoice
418        elif voiceType == HYPERLINK:
419            voice = self.hyperlinkVoice
420            if key not in voice:
421                if not useDefault:
422                    return None
423                voice = self.defaultVoice
424        elif voiceType == SYSTEM:
425            voice = self.systemVoice
426            if key not in voice:
427                if not useDefault:
428                    return None
429                voice = self.defaultVoice
430        else:
431            voice = self.defaultVoice
432
433        if key in voice:
434            return voice[key]
435        else:
436            return None
437
438    def _getFamilyNameForVoiceType(self, voiceType):
439        """Gets the name of the voice family for the given voice type.
440
441        Arguments:
442        - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
443
444        Returns the name of the voice family for the given voice type,
445        or None if not set.
446        """
447
448        familyName = None
449        family = self._getKeyValueForVoiceType(voiceType, acss.ACSS.FAMILY)
450
451        if family and speechserver.VoiceFamily.NAME in family:
452            familyName = family[speechserver.VoiceFamily.NAME]
453
454        return familyName
455
456    def _setFamilyNameForVoiceType(self, voiceType, name, language, dialect, variant):
457        """Sets the name of the voice family for the given voice type.
458
459        Arguments:
460        - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
461        - name: the name of the voice family to set.
462        - language: the locale of the voice family to set.
463        - dialect: the dialect of the voice family to set.
464        """
465
466        family = self._getKeyValueForVoiceType(voiceType,
467                                               acss.ACSS.FAMILY,
468                                               False)
469
470        voiceACSS = self._getACSSForVoiceType(voiceType)
471        if family:
472            family[speechserver.VoiceFamily.NAME] = name
473            family[speechserver.VoiceFamily.LANG] = language
474            family[speechserver.VoiceFamily.DIALECT] = dialect
475            family[speechserver.VoiceFamily.VARIANT] = variant
476        else:
477            voiceACSS[acss.ACSS.FAMILY] = {}
478            voiceACSS[acss.ACSS.FAMILY][speechserver.VoiceFamily.NAME] = name
479            voiceACSS[acss.ACSS.FAMILY][speechserver.VoiceFamily.LANG] = language
480            voiceACSS[acss.ACSS.FAMILY][speechserver.VoiceFamily.DIALECT] = dialect
481            voiceACSS[acss.ACSS.FAMILY][speechserver.VoiceFamily.VARIANT] = variant
482        voiceACSS['established'] = True
483
484        #settings.voices[voiceType] = voiceACSS
485
486    def _getRateForVoiceType(self, voiceType):
487        """Gets the speaking rate value for the given voice type.
488
489        Arguments:
490        - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
491
492        Returns the rate value for the given voice type, or None if
493        not set.
494        """
495
496        return self._getKeyValueForVoiceType(voiceType, acss.ACSS.RATE)
497
498    def _setRateForVoiceType(self, voiceType, value):
499        """Sets the speaking rate value for the given voice type.
500
501        Arguments:
502        - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
503        - value: the rate value to set.
504        """
505
506        voiceACSS = self._getACSSForVoiceType(voiceType)
507        voiceACSS[acss.ACSS.RATE] = value
508        voiceACSS['established'] = True
509        #settings.voices[voiceType] = voiceACSS
510
511    def _getPitchForVoiceType(self, voiceType):
512        """Gets the pitch value for the given voice type.
513
514        Arguments:
515        - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
516
517        Returns the pitch value for the given voice type, or None if
518        not set.
519        """
520
521        return self._getKeyValueForVoiceType(voiceType,
522                                             acss.ACSS.AVERAGE_PITCH)
523
524    def _setPitchForVoiceType(self, voiceType, value):
525        """Sets the pitch value for the given voice type.
526
527        Arguments:
528        - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
529        - value: the pitch value to set.
530        """
531
532        voiceACSS = self._getACSSForVoiceType(voiceType)
533        voiceACSS[acss.ACSS.AVERAGE_PITCH] = value
534        voiceACSS['established'] = True
535        #settings.voices[voiceType] = voiceACSS
536
537    def _getVolumeForVoiceType(self, voiceType):
538        """Gets the volume (gain) value for the given voice type.
539
540        Arguments:
541        - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
542
543        Returns the volume (gain) value for the given voice type, or
544        None if not set.
545        """
546
547        return self._getKeyValueForVoiceType(voiceType, acss.ACSS.GAIN)
548
549    def _setVolumeForVoiceType(self, voiceType, value):
550        """Sets the volume (gain) value for the given voice type.
551
552        Arguments:
553        - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
554        - value: the volume (gain) value to set.
555        """
556
557        voiceACSS = self._getACSSForVoiceType(voiceType)
558        voiceACSS[acss.ACSS.GAIN] = value
559        voiceACSS['established'] = True
560        #settings.voices[voiceType] = voiceACSS
561
562    def _setVoiceSettingsForVoiceType(self, voiceType):
563        """Sets the family, rate, pitch and volume GUI components based
564        on the given voice type.
565
566        Arguments:
567        - voiceType: one of DEFAULT, UPPERCASE, HYPERLINK, SYSTEM
568        """
569
570        familyName = self._getFamilyNameForVoiceType(voiceType)
571        self._setSpeechFamiliesChoice(familyName)
572
573        rate = self._getRateForVoiceType(voiceType)
574        if rate is not None:
575            self.get_widget("rateScale").set_value(rate)
576        else:
577            self.get_widget("rateScale").set_value(50.0)
578
579        pitch = self._getPitchForVoiceType(voiceType)
580        if pitch is not None:
581            self.get_widget("pitchScale").set_value(pitch)
582        else:
583            self.get_widget("pitchScale").set_value(5.0)
584
585        volume = self._getVolumeForVoiceType(voiceType)
586        if volume is not None:
587            self.get_widget("volumeScale").set_value(volume)
588        else:
589            self.get_widget("volumeScale").set_value(10.0)
590
591    def _setSpeechFamiliesChoice(self, familyName):
592        """Sets the active item in the families ("Person:") combo box
593        to the given family name.
594
595        Arguments:
596        - familyName: the family name to use to set the active combo box item.
597        """
598
599        if len(self.speechFamilies) == 0:
600            return
601
602        languageSet = False
603        familySet = False
604        for family in self.speechFamilies:
605            name = family[speechserver.VoiceFamily.NAME]
606            if name == familyName:
607                lang = family[speechserver.VoiceFamily.LANG]
608                dialect = family[speechserver.VoiceFamily.DIALECT]
609
610                if dialect:
611                    language = lang + '-' + dialect
612                else:
613                    language = lang
614
615                i = 0
616                for languageChoice in self.speechLanguagesChoices:
617                    if languageChoice == language:
618                        self.get_widget("speechLanguages").set_active(i)
619                        self.speechLanguagesChoice = self.speechLanguagesChoices[i]
620                        languageSet = True
621
622                        self._setupFamilies()
623
624                        i = 0
625                        for familyChoice in self.speechFamiliesChoices:
626                            name = familyChoice[speechserver.VoiceFamily.NAME]
627                            if name == familyName:
628                                self.get_widget("speechFamilies").set_active(i)
629                                self.speechFamiliesChoice = self.speechFamiliesChoices[i]
630                                familySet = True
631                                break
632                            i += 1
633
634                        break
635
636                    i += 1
637
638                break
639
640        if not languageSet:
641            debug.println(debug.LEVEL_FINEST,
642                          "Could not find speech language match for %s" \
643                          % familyName)
644            self.get_widget("speechLanguages").set_active(0)
645            self.speechLanguagesChoice = self.speechLanguagesChoices[0]
646
647        if languageSet:
648            self.selectedLanguageChoices[self.speechServersChoice] = i
649
650        if not familySet:
651            debug.println(debug.LEVEL_FINEST,
652                          "Could not find speech family match for %s" \
653                          % familyName)
654            self.get_widget("speechFamilies").set_active(0)
655            self.speechFamiliesChoice = self.speechFamiliesChoices[0]
656
657        if familySet:
658            self.selectedFamilyChoices[self.speechServersChoice,
659                    self.speechLanguagesChoice] = i
660
661    def _setupFamilies(self):
662        """Gets the list of voice variants for the current speech server and
663        current language.
664        If there are variants, get the information associated with
665        each voice variant and add an entry for it to the variants
666        GtkComboBox list.
667        """
668
669        self.speechFamiliesModel.clear()
670
671        currentLanguage = self.speechLanguagesChoice
672
673        i = 0
674        self.speechFamiliesChoices = []
675        for family in self.speechFamilies:
676            lang = family[speechserver.VoiceFamily.LANG]
677            dialect = family[speechserver.VoiceFamily.DIALECT]
678
679            if dialect:
680                language = lang + '-' + dialect
681            else:
682                language = lang
683
684            if language != currentLanguage:
685                continue
686
687            name = family[speechserver.VoiceFamily.NAME]
688            self.speechFamiliesChoices.append(family)
689            self.speechFamiliesModel.append((i, name))
690            i += 1
691
692        if i == 0:
693            debug.println(debug.LEVEL_SEVERE, "No speech family was available for %s." % str(currentLanguage))
694            debug.printStack(debug.LEVEL_FINEST)
695            self.speechFamiliesChoice = None
696            return
697
698        # If user manually selected a family for the current speech server
699        # this choice it's restored. In other case the first family
700        # (usually the default one) is selected
701        #
702        selectedIndex = 0
703        if (self.speechServersChoice, self.speechLanguagesChoice) \
704                in self.selectedFamilyChoices:
705            selectedIndex = self.selectedFamilyChoices[self.speechServersChoice,
706                    self.speechLanguagesChoice]
707
708        self.get_widget("speechFamilies").set_active(selectedIndex)
709
710    def _setSpeechLanguagesChoice(self, languageName):
711        """Sets the active item in the languages ("Language:") combo box
712        to the given language name.
713
714        Arguments:
715        - languageName: the language name to use to set the active combo box item.
716        """
717
718        print("setSpeechLanguagesChoice")
719
720        if len(self.speechLanguagesChoices) == 0:
721            return
722
723        valueSet = False
724        i = 0
725        for language in self.speechLanguagesChoices:
726            if language == languageName:
727                self.get_widget("speechLanguages").set_active(i)
728                self.speechLanguagesChoice = self.speechLanguagesChoices[i]
729                valueSet = True
730                break
731            i += 1
732
733        if not valueSet:
734            debug.println(debug.LEVEL_FINEST,
735                          "Could not find speech language match for %s" \
736                          % languageName)
737            self.get_widget("speechLanguages").set_active(0)
738            self.speechLanguagesChoice = self.speechLanguagesChoices[0]
739
740        if valueSet:
741            self.selectedLanguageChoices[self.speechServersChoice] = i
742
743        self._setupFamilies()
744
745    def _setupVoices(self):
746        """Gets the list of voices for the current speech server.
747        If there are families, get the information associated with
748        each voice family and add an entry for it to the families
749        GtkComboBox list.
750        """
751
752        self.speechLanguagesModel.clear()
753
754        self.speechFamilies = self.speechServersChoice.getVoiceFamilies()
755
756        self.speechLanguagesChoices = []
757
758        if len(self.speechFamilies) == 0:
759            debug.println(debug.LEVEL_SEVERE, "No speech voice was available.")
760            debug.printStack(debug.LEVEL_FINEST)
761            self.speechLanguagesChoice = None
762            return
763
764        done = {}
765        i = 0
766        for family in self.speechFamilies:
767            lang = family[speechserver.VoiceFamily.LANG]
768            dialect = family[speechserver.VoiceFamily.DIALECT]
769            if (lang,dialect) in done:
770                continue
771            done[lang,dialect] = True
772
773            if dialect:
774                language = lang + '-' + dialect
775            else:
776                language = lang
777
778            # TODO: get translated language name from CLDR or such
779            msg = language
780            if msg == "":
781                # Unsupported locale
782                msg = "default language"
783
784            self.speechLanguagesChoices.append(language)
785            self.speechLanguagesModel.append((i, msg))
786            i += 1
787
788        # If user manually selected a language for the current speech server
789        # this choice it's restored. In other case the first language
790        # (usually the default one) is selected
791        #
792        selectedIndex = 0
793        if self.speechServersChoice in self.selectedLanguageChoices:
794            selectedIndex = self.selectedLanguageChoices[self.speechServersChoice]
795
796        self.get_widget("speechLanguages").set_active(selectedIndex)
797        if self.initializingSpeech:
798            self.speechLanguagesChoice = self.speechLanguagesChoices[selectedIndex]
799
800        self._setupFamilies()
801
802        # The family name will be selected as part of selecting the
803        # voice type.  Whenever the families change, we'll reset the
804        # voice type selection to the first one ("Default").
805        #
806        comboBox = self.get_widget("voiceTypesCombo")
807        types = [guilabels.SPEECH_VOICE_TYPE_DEFAULT,
808                 guilabels.SPEECH_VOICE_TYPE_UPPERCASE,
809                 guilabels.SPEECH_VOICE_TYPE_HYPERLINK,
810                 guilabels.SPEECH_VOICE_TYPE_SYSTEM]
811        self.populateComboBox(comboBox, types)
812        comboBox.set_active(DEFAULT)
813        voiceType = comboBox.get_active()
814        self._setVoiceSettingsForVoiceType(voiceType)
815
816    def _setSpeechServersChoice(self, serverInfo):
817        """Sets the active item in the speech servers combo box to the
818        given server.
819
820        Arguments:
821        - serversChoices: the list of available speech servers.
822        - serverInfo: the speech server to use to set the active combo
823        box item.
824        """
825
826        if len(self.speechServersChoices) == 0:
827            return
828
829        # We'll fallback to whatever we happen to be using in the event
830        # that this preference has never been set.
831        #
832        if not serverInfo:
833            serverInfo = speech.getInfo()
834
835        valueSet = False
836        i = 0
837        for server in self.speechServersChoices:
838            if serverInfo == server.getInfo():
839                self.get_widget("speechServers").set_active(i)
840                self.speechServersChoice = server
841                valueSet = True
842                break
843            i += 1
844
845        if not valueSet:
846            debug.println(debug.LEVEL_FINEST,
847                          "Could not find speech server match for %s" \
848                          %  repr(serverInfo))
849            self.get_widget("speechServers").set_active(0)
850            self.speechServersChoice = self.speechServersChoices[0]
851
852        self._setupVoices()
853
854    def _setupSpeechServers(self):
855        """Gets the list of speech servers for the current speech factory.
856        If there are servers, get the information associated with each
857        speech server and add an entry for it to the speechServers
858        GtkComboBox list.  Set the current choice to be the first item.
859        """
860
861        self.speechServersModel.clear()
862        self.speechServersChoices = \
863                self.speechSystemsChoice.SpeechServer.getSpeechServers()
864        if len(self.speechServersChoices) == 0:
865            debug.println(debug.LEVEL_SEVERE, "Speech not available.")
866            debug.printStack(debug.LEVEL_FINEST)
867            self.speechServersChoice = None
868            self.speechLanguagesChoices = []
869            self.speechLanguagesChoice = None
870            self.speechFamiliesChoices = []
871            self.speechFamiliesChoice = None
872            return
873
874        i = 0
875        for server in self.speechServersChoices:
876            name = server.getInfo()[0]
877            self.speechServersModel.append((i, name))
878            i += 1
879
880        self._setSpeechServersChoice(self.prefsDict["speechServerInfo"])
881
882        debug.println(
883            debug.LEVEL_FINEST,
884            "orca_gui_prefs._setupSpeechServers: speechServersChoice: %s" \
885            % self.speechServersChoice.getInfo())
886
887    def _setSpeechSystemsChoice(self, systemName):
888        """Set the active item in the speech systems combo box to the
889        given system name.
890
891        Arguments:
892        - factoryChoices: the list of available speech factories (systems).
893        - systemName: the speech system name to use to set the active combo
894        box item.
895        """
896
897        systemName = systemName.strip("'")
898
899        if len(self.speechSystemsChoices) == 0:
900            self.speechSystemsChoice = None
901            return
902
903        valueSet = False
904        i = 0
905        for speechSystem in self.speechSystemsChoices:
906            name = speechSystem.__name__
907            if name.endswith(systemName):
908                self.get_widget("speechSystems").set_active(i)
909                self.speechSystemsChoice = self.speechSystemsChoices[i]
910                valueSet = True
911                break
912            i += 1
913
914        if not valueSet:
915            debug.println(debug.LEVEL_FINEST,
916                          "Could not find speech system match for %s" \
917                          % systemName)
918            self.get_widget("speechSystems").set_active(0)
919            self.speechSystemsChoice = self.speechSystemsChoices[0]
920
921        self._setupSpeechServers()
922
923    def _setupSpeechSystems(self, factories):
924        """Sets up the speech systems combo box and sets the selection
925        to the preferred speech system.
926
927        Arguments:
928        -factories: the list of known speech factories (working or not)
929        """
930        self.speechSystemsModel.clear()
931        self.workingFactories = []
932        for factory in factories:
933            try:
934                servers = factory.SpeechServer.getSpeechServers()
935                if len(servers):
936                    self.workingFactories.append(factory)
937            except:
938                debug.printException(debug.LEVEL_FINEST)
939
940        self.speechSystemsChoices = []
941        if len(self.workingFactories) == 0:
942            debug.println(debug.LEVEL_SEVERE, "Speech not available.")
943            debug.printStack(debug.LEVEL_FINEST)
944            self.speechSystemsChoice = None
945            self.speechServersChoices = []
946            self.speechServersChoice = None
947            self.speechLanguagesChoices = []
948            self.speechLanguagesChoice = None
949            self.speechFamiliesChoices = []
950            self.speechFamiliesChoice = None
951            return
952
953        i = 0
954        for workingFactory in self.workingFactories:
955            self.speechSystemsChoices.append(workingFactory)
956            name = workingFactory.SpeechServer.getFactoryName()
957            self.speechSystemsModel.append((i, name))
958            i += 1
959
960        if self.prefsDict["speechServerFactory"]:
961            self._setSpeechSystemsChoice(self.prefsDict["speechServerFactory"])
962        else:
963            self.speechSystemsChoice = None
964
965        debug.println(
966            debug.LEVEL_FINEST,
967            "orca_gui_prefs._setupSpeechSystems: speechSystemsChoice: %s" \
968            % self.speechSystemsChoice)
969
970    def _initSpeechState(self):
971        """Initialize the various speech components.
972        """
973
974        voices = self.prefsDict["voices"]
975        self.defaultVoice   = acss.ACSS(voices.get(settings.DEFAULT_VOICE))
976        self.uppercaseVoice = acss.ACSS(voices.get(settings.UPPERCASE_VOICE))
977        self.hyperlinkVoice = acss.ACSS(voices.get(settings.HYPERLINK_VOICE))
978        self.systemVoice    = acss.ACSS(voices.get(settings.SYSTEM_VOICE))
979
980        # Just a note on general naming pattern:
981        #
982        # *        = The name of the combobox
983        # *Model   = the name of the comobox model
984        # *Choices = the Orca/speech python objects
985        # *Choice  = a value from *Choices
986        #
987        # Where * = speechSystems, speechServers, speechLanguages, speechFamilies
988        #
989        factories = speech.getSpeechServerFactories()
990        if len(factories) == 0 or not self.prefsDict.get('enableSpeech', True):
991            self.workingFactories = []
992            self.speechSystemsChoice = None
993            self.speechServersChoices = []
994            self.speechServersChoice = None
995            self.speechLanguagesChoices = []
996            self.speechLanguagesChoice = None
997            self.speechFamiliesChoices = []
998            self.speechFamiliesChoice = None
999            return
1000
1001        try:
1002            speech.init()
1003        except:
1004            self.workingFactories = []
1005            self.speechSystemsChoice = None
1006            self.speechServersChoices = []
1007            self.speechServersChoice = None
1008            self.speechLanguagesChoices = []
1009            self.speechLanguagesChoice = None
1010            self.speechFamiliesChoices = []
1011            self.speechFamiliesChoice = None
1012            return
1013
1014        # This cascades into systems->servers->voice_type->families...
1015        #
1016        self.initializingSpeech = True
1017        self._setupSpeechSystems(factories)
1018        self.initializingSpeech = False
1019
1020    def _setSpokenTextAttributes(self, view, setAttributes,
1021                                 state, moveToTop=False):
1022        """Given a set of spoken text attributes, update the model used by the
1023        text attribute tree view.
1024
1025        Arguments:
1026        - view: the text attribute tree view.
1027        - setAttributes: the list of spoken text attributes to update.
1028        - state: the state (True or False) that they all should be set to.
1029        - moveToTop: if True, move these attributes to the top of the list.
1030        """
1031
1032        model = view.get_model()
1033        view.set_model(None)
1034
1035        [attrList, attrDict] = \
1036           self.script.utilities.stringToKeysAndDict(setAttributes)
1037        [allAttrList, allAttrDict] = self.script.utilities.stringToKeysAndDict(
1038            _settingsManager.getSetting('allTextAttributes'))
1039
1040        for i in range(0, len(attrList)):
1041            for path in range(0, len(allAttrList)):
1042                localizedKey = text_attribute_names.getTextAttributeName(
1043                    attrList[i], self.script)
1044                localizedValue = text_attribute_names.getTextAttributeName(
1045                    attrDict[attrList[i]], self.script)
1046                if localizedKey == model[path][NAME]:
1047                    thisIter = model.get_iter(path)
1048                    model.set_value(thisIter, NAME, localizedKey)
1049                    model.set_value(thisIter, IS_SPOKEN, state)
1050                    model.set_value(thisIter, VALUE, localizedValue)
1051                    if moveToTop:
1052                        thisIter = model.get_iter(path)
1053                        otherIter = model.get_iter(i)
1054                        model.move_before(thisIter, otherIter)
1055                    break
1056
1057        view.set_model(model)
1058
1059    def _setBrailledTextAttributes(self, view, setAttributes, state):
1060        """Given a set of brailled text attributes, update the model used
1061        by the text attribute tree view.
1062
1063        Arguments:
1064        - view: the text attribute tree view.
1065        - setAttributes: the list of brailled text attributes to update.
1066        - state: the state (True or False) that they all should be set to.
1067        """
1068
1069        model = view.get_model()
1070        view.set_model(None)
1071
1072        [attrList, attrDict] = \
1073            self.script.utilities.stringToKeysAndDict(setAttributes)
1074        [allAttrList, allAttrDict] = self.script.utilities.stringToKeysAndDict(
1075                _settingsManager.getSetting('allTextAttributes'))
1076
1077        for i in range(0, len(attrList)):
1078            for path in range(0, len(allAttrList)):
1079                localizedKey = text_attribute_names.getTextAttributeName(
1080                    attrList[i], self.script)
1081                if localizedKey == model[path][NAME]:
1082                    thisIter = model.get_iter(path)
1083                    model.set_value(thisIter, IS_BRAILLED, state)
1084                    break
1085
1086        view.set_model(model)
1087
1088    def _getAppNameForAttribute(self, attributeName):
1089        """Converts the given Atk attribute name into the application's
1090        equivalent. This is necessary because an application or toolkit
1091        (e.g. Gecko) might invent entirely new names for the same text
1092        attributes.
1093
1094        Arguments:
1095        - attribName: The name of the text attribute
1096
1097        Returns the application's equivalent name if found or attribName
1098        otherwise.
1099        """
1100
1101        return self.script.utilities.getAppNameForAttribute(attributeName)
1102
1103    def _updateTextDictEntry(self):
1104        """The user has updated the text attribute list in some way. Update
1105        the "enabledSpokenTextAttributes" and "enabledBrailledTextAttributes"
1106        preference strings to reflect the current state of the corresponding
1107        text attribute lists.
1108        """
1109
1110        model = self.getTextAttributesView.get_model()
1111        spokenAttrStr = ""
1112        brailledAttrStr = ""
1113        noRows = model.iter_n_children(None)
1114        for path in range(0, noRows):
1115            localizedKey = model[path][NAME]
1116            key = text_attribute_names.getTextAttributeKey(localizedKey)
1117
1118            # Convert the normalized, Atk attribute name back into what
1119            # the app/toolkit uses.
1120            #
1121            key = self._getAppNameForAttribute(key)
1122
1123            localizedValue = model[path][VALUE]
1124            value = text_attribute_names.getTextAttributeKey(localizedValue)
1125
1126            if model[path][IS_SPOKEN]:
1127                spokenAttrStr += key + ":" + value + "; "
1128            if model[path][IS_BRAILLED]:
1129                brailledAttrStr += key + ":" + value + "; "
1130
1131        self.prefsDict["enabledSpokenTextAttributes"] = spokenAttrStr
1132        self.prefsDict["enabledBrailledTextAttributes"] = brailledAttrStr
1133
1134    def contractedBrailleToggled(self, checkbox):
1135        grid = self.get_widget('contractionTableGrid')
1136        grid.set_sensitive(checkbox.get_active())
1137        self.prefsDict["enableContractedBraille"] = checkbox.get_active()
1138
1139    def contractionTableComboChanged(self, combobox):
1140        model = combobox.get_model()
1141        myIter = combobox.get_active_iter()
1142        self.prefsDict["brailleContractionTable"] = model[myIter][1]
1143
1144    def flashPersistenceToggled(self, checkbox):
1145        grid = self.get_widget('flashMessageDurationGrid')
1146        grid.set_sensitive(not checkbox.get_active())
1147        self.prefsDict["flashIsPersistent"] = checkbox.get_active()
1148
1149    def textAttributeSpokenToggled(self, cell, path, model):
1150        """The user has toggled the state of one of the text attribute
1151        checkboxes to be spoken. Update our model to reflect this, then
1152        update the "enabledSpokenTextAttributes" preference string.
1153
1154        Arguments:
1155        - cell: the cell that changed.
1156        - path: the path of that cell.
1157        - model: the model that the cell is part of.
1158        """
1159
1160        thisIter = model.get_iter(path)
1161        model.set(thisIter, IS_SPOKEN, not model[path][IS_SPOKEN])
1162        self._updateTextDictEntry()
1163
1164    def textAttributeBrailledToggled(self, cell, path, model):
1165        """The user has toggled the state of one of the text attribute
1166        checkboxes to be brailled. Update our model to reflect this,
1167        then update the "enabledBrailledTextAttributes" preference string.
1168
1169        Arguments:
1170        - cell: the cell that changed.
1171        - path: the path of that cell.
1172        - model: the model that the cell is part of.
1173        """
1174
1175        thisIter = model.get_iter(path)
1176        model.set(thisIter, IS_BRAILLED, not model[path][IS_BRAILLED])
1177        self._updateTextDictEntry()
1178
1179    def textAttrValueEdited(self, cell, path, new_text, model):
1180        """The user has edited the value of one of the text attributes.
1181        Update our model to reflect this, then update the
1182        "enabledSpokenTextAttributes" and "enabledBrailledTextAttributes"
1183        preference strings.
1184
1185        Arguments:
1186        - cell: the cell that changed.
1187        - path: the path of that cell.
1188        - new_text: the new text attribute value string.
1189        - model: the model that the cell is part of.
1190        """
1191
1192        thisIter = model.get_iter(path)
1193        model.set(thisIter, VALUE, new_text)
1194        self._updateTextDictEntry()
1195
1196    def textAttrCursorChanged(self, widget):
1197        """Set the search column in the text attribute tree view
1198        depending upon which column the user currently has the cursor in.
1199        """
1200
1201        [path, focusColumn] = self.getTextAttributesView.get_cursor()
1202        if focusColumn:
1203            noColumns = len(self.getTextAttributesView.get_columns())
1204            for i in range(0, noColumns):
1205                col = self.getTextAttributesView.get_column(i)
1206                if focusColumn == col:
1207                    self.getTextAttributesView.set_search_column(i)
1208                    break
1209
1210    def _createTextAttributesTreeView(self):
1211        """Create the text attributes tree view. The view is the
1212        textAttributesTreeView GtkTreeView widget. The view will consist
1213        of a list containing three columns:
1214          IS_SPOKEN - a checkbox whose state indicates whether this text
1215                      attribute will be spoken or not.
1216          NAME      - the text attribute name.
1217          VALUE     - if set, (and this attributes is enabled for speaking),
1218                      then this attribute will be spoken unless it equals
1219                      this value.
1220        """
1221
1222        self.getTextAttributesView = self.get_widget("textAttributesTreeView")
1223
1224        if self.getTextAttributesView.get_columns():
1225            for column in self.getTextAttributesView.get_columns():
1226                self.getTextAttributesView.remove_column(column)
1227
1228        model = Gtk.ListStore(GObject.TYPE_STRING,
1229                              GObject.TYPE_BOOLEAN,
1230                              GObject.TYPE_BOOLEAN,
1231                              GObject.TYPE_STRING)
1232
1233        # Initially setup the list store model based on the values of all
1234        # the known text attributes.
1235        #
1236        [allAttrList, allAttrDict] = self.script.utilities.stringToKeysAndDict(
1237            _settingsManager.getSetting('allTextAttributes'))
1238        for i in range(0, len(allAttrList)):
1239            thisIter = model.append()
1240            localizedKey = text_attribute_names.getTextAttributeName(
1241                allAttrList[i], self.script)
1242            localizedValue = text_attribute_names.getTextAttributeName(
1243                allAttrDict[allAttrList[i]], self.script)
1244            model.set_value(thisIter, NAME, localizedKey)
1245            model.set_value(thisIter, IS_SPOKEN, False)
1246            model.set_value(thisIter, IS_BRAILLED, False)
1247            model.set_value(thisIter, VALUE, localizedValue)
1248
1249        self.getTextAttributesView.set_model(model)
1250
1251        # Attribute Name column (NAME).
1252        column = Gtk.TreeViewColumn(guilabels.TEXT_ATTRIBUTE_NAME)
1253        column.set_min_width(250)
1254        column.set_resizable(True)
1255        renderer = Gtk.CellRendererText()
1256        column.pack_end(renderer, True)
1257        column.add_attribute(renderer, 'text', NAME)
1258        self.getTextAttributesView.insert_column(column, 0)
1259
1260        # Attribute Speak column (IS_SPOKEN).
1261        speakAttrColumnLabel = guilabels.PRESENTATION_SPEAK
1262        column = Gtk.TreeViewColumn(speakAttrColumnLabel)
1263        renderer = Gtk.CellRendererToggle()
1264        column.pack_start(renderer, False)
1265        column.add_attribute(renderer, 'active', IS_SPOKEN)
1266        renderer.connect("toggled",
1267                         self.textAttributeSpokenToggled,
1268                         model)
1269        self.getTextAttributesView.insert_column(column, 1)
1270        column.clicked()
1271
1272        # Attribute Mark in Braille column (IS_BRAILLED).
1273        markAttrColumnLabel = guilabels.PRESENTATION_MARK_IN_BRAILLE
1274        column = Gtk.TreeViewColumn(markAttrColumnLabel)
1275        renderer = Gtk.CellRendererToggle()
1276        column.pack_start(renderer, False)
1277        column.add_attribute(renderer, 'active', IS_BRAILLED)
1278        renderer.connect("toggled",
1279                         self.textAttributeBrailledToggled,
1280                         model)
1281        self.getTextAttributesView.insert_column(column, 2)
1282        column.clicked()
1283
1284        # Attribute Value column (VALUE)
1285        column = Gtk.TreeViewColumn(guilabels.PRESENTATION_PRESENT_UNLESS)
1286        renderer = Gtk.CellRendererText()
1287        renderer.set_property('editable', True)
1288        column.pack_end(renderer, True)
1289        column.add_attribute(renderer, 'text', VALUE)
1290        renderer.connect("edited", self.textAttrValueEdited, model)
1291
1292        self.getTextAttributesView.insert_column(column, 4)
1293
1294        # Check all the enabled (spoken) text attributes.
1295        #
1296        self._setSpokenTextAttributes(
1297            self.getTextAttributesView,
1298            _settingsManager.getSetting('enabledSpokenTextAttributes'),
1299            True, True)
1300
1301        # Check all the enabled (brailled) text attributes.
1302        #
1303        self._setBrailledTextAttributes(
1304            self.getTextAttributesView,
1305            _settingsManager.getSetting('enabledBrailledTextAttributes'),
1306            True)
1307
1308        # Connect a handler for when the user changes columns within the
1309        # view, so that we can adjust the search column for item lookups.
1310        #
1311        self.getTextAttributesView.connect("cursor_changed",
1312                                           self.textAttrCursorChanged)
1313
1314    def pronActualValueEdited(self, cell, path, new_text, model):
1315        """The user has edited the value of one of the actual strings in
1316        the pronunciation dictionary. Update our model to reflect this.
1317
1318        Arguments:
1319        - cell: the cell that changed.
1320        - path: the path of that cell.
1321        - new_text: the new pronunciation dictionary actual string.
1322        - model: the model that the cell is part of.
1323        """
1324
1325        thisIter = model.get_iter(path)
1326        model.set(thisIter, ACTUAL, new_text)
1327
1328    def pronReplacementValueEdited(self, cell, path, new_text, model):
1329        """The user has edited the value of one of the replacement strings
1330        in the pronunciation dictionary. Update our model to reflect this.
1331
1332        Arguments:
1333        - cell: the cell that changed.
1334        - path: the path of that cell.
1335        - new_text: the new pronunciation dictionary replacement string.
1336        - model: the model that the cell is part of.
1337        """
1338
1339        thisIter = model.get_iter(path)
1340        model.set(thisIter, REPLACEMENT, new_text)
1341
1342    def pronunciationFocusChange(self, widget, event, isFocused):
1343        """Callback for the pronunciation tree's focus-{in,out}-event signal."""
1344
1345        _settingsManager.setSetting('usePronunciationDictionary', not isFocused)
1346
1347    def pronunciationCursorChanged(self, widget):
1348        """Set the search column in the pronunciation dictionary tree view
1349        depending upon which column the user currently has the cursor in.
1350        """
1351
1352        [path, focusColumn] = self.pronunciationView.get_cursor()
1353        if focusColumn:
1354            noColumns = len(self.pronunciationView.get_columns())
1355            for i in range(0, noColumns):
1356                col = self.pronunciationView.get_column(i)
1357                if focusColumn == col:
1358                    self.pronunciationView.set_search_column(i)
1359                    break
1360
1361    def _createPronunciationTreeView(self):
1362        """Create the pronunciation dictionary tree view. The view is the
1363        pronunciationTreeView GtkTreeView widget. The view will consist
1364        of a list containing two columns:
1365          ACTUAL      - the actual text string (word).
1366          REPLACEMENT - the string that is used to pronounce that word.
1367        """
1368
1369        self.pronunciationView = self.get_widget("pronunciationTreeView")
1370
1371        if self.pronunciationView.get_columns():
1372            for column in self.pronunciationView.get_columns():
1373                self.pronunciationView.remove_column(column)
1374
1375        model = Gtk.ListStore(GObject.TYPE_STRING,
1376                              GObject.TYPE_STRING)
1377
1378        # Initially setup the list store model based on the values of all
1379        # existing entries in the pronunciation dictionary -- unless it's
1380        # the default script.
1381        #
1382        if not self.script.app:
1383            _profile = self.prefsDict.get('activeProfile')[1]
1384            pronDict = _settingsManager.getPronunciations(_profile)
1385        else:
1386            pronDict = pronunciation_dict.pronunciation_dict
1387        for pronKey in sorted(pronDict.keys()):
1388            thisIter = model.append()
1389            try:
1390                actual, replacement = pronDict[pronKey]
1391            except:
1392                # Try to do something sensible for the previous format of
1393                # pronunciation dictionary entries. See bug #464754 for
1394                # more details.
1395                #
1396                actual = pronKey
1397                replacement = pronDict[pronKey]
1398            model.set(thisIter,
1399                      ACTUAL, actual,
1400                      REPLACEMENT, replacement)
1401
1402        self.pronunciationView.set_model(model)
1403
1404        # Pronunciation Dictionary actual string (word) column (ACTUAL).
1405        column = Gtk.TreeViewColumn(guilabels.DICTIONARY_ACTUAL_STRING)
1406        column.set_min_width(250)
1407        column.set_resizable(True)
1408        renderer = Gtk.CellRendererText()
1409        renderer.set_property('editable', True)
1410        column.pack_end(renderer, True)
1411        column.add_attribute(renderer, 'text', ACTUAL)
1412        renderer.connect("edited", self.pronActualValueEdited, model)
1413        self.pronunciationView.insert_column(column, 0)
1414
1415        # Pronunciation Dictionary replacement string column (REPLACEMENT)
1416        column = Gtk.TreeViewColumn(guilabels.DICTIONARY_REPLACEMENT_STRING)
1417        renderer = Gtk.CellRendererText()
1418        renderer.set_property('editable', True)
1419        column.pack_end(renderer, True)
1420        column.add_attribute(renderer, 'text', REPLACEMENT)
1421        renderer.connect("edited", self.pronReplacementValueEdited, model)
1422        self.pronunciationView.insert_column(column, 1)
1423
1424        self.pronunciationModel = model
1425
1426        # Connect a handler for when the user changes columns within the
1427        # view, so that we can adjust the search column for item lookups.
1428        #
1429        self.pronunciationView.connect("cursor_changed",
1430                                       self.pronunciationCursorChanged)
1431
1432        self.pronunciationView.connect(
1433            "focus_in_event", self.pronunciationFocusChange, True)
1434        self.pronunciationView.connect(
1435            "focus_out_event", self.pronunciationFocusChange, False)
1436
1437    def _initGUIState(self):
1438        """Adjust the settings of the various components on the
1439        configuration GUI depending upon the users preferences.
1440        """
1441
1442        prefs = self.prefsDict
1443
1444        # Speech pane.
1445        #
1446        enable = prefs["enableSpeech"]
1447        self.get_widget("speechSupportCheckButton").set_active(enable)
1448        self.get_widget("speechOptionsGrid").set_sensitive(enable)
1449
1450        enable = prefs["onlySpeakDisplayedText"]
1451        self.get_widget("onlySpeakDisplayedTextCheckButton").set_active(enable)
1452        self.get_widget("contextOptionsGrid").set_sensitive(not enable)
1453
1454        if prefs["verbalizePunctuationStyle"] == \
1455                               settings.PUNCTUATION_STYLE_NONE:
1456            self.get_widget("noneButton").set_active(True)
1457        elif prefs["verbalizePunctuationStyle"] == \
1458                               settings.PUNCTUATION_STYLE_SOME:
1459            self.get_widget("someButton").set_active(True)
1460        elif prefs["verbalizePunctuationStyle"] == \
1461                               settings.PUNCTUATION_STYLE_MOST:
1462            self.get_widget("mostButton").set_active(True)
1463        else:
1464            self.get_widget("allButton").set_active(True)
1465
1466        if prefs["speechVerbosityLevel"] == settings.VERBOSITY_LEVEL_BRIEF:
1467            self.get_widget("speechBriefButton").set_active(True)
1468        else:
1469            self.get_widget("speechVerboseButton").set_active(True)
1470
1471        self.get_widget("onlySpeakDisplayedTextCheckButton").set_active(
1472            prefs["onlySpeakDisplayedText"])
1473
1474        self.get_widget("enableSpeechIndentationCheckButton").set_active(\
1475            prefs["enableSpeechIndentation"])
1476
1477        self.get_widget("speakBlankLinesCheckButton").set_active(\
1478            prefs["speakBlankLines"])
1479        self.get_widget("speakMultiCaseStringsAsWordsCheckButton").set_active(\
1480            prefs["speakMultiCaseStringsAsWords"])
1481        self.get_widget("speakNumbersAsDigitsCheckButton").set_active(
1482            prefs.get("speakNumbersAsDigits", settings.speakNumbersAsDigits))
1483        self.get_widget("enableTutorialMessagesCheckButton").set_active(\
1484            prefs["enableTutorialMessages"])
1485        self.get_widget("enablePauseBreaksCheckButton").set_active(\
1486            prefs["enablePauseBreaks"])
1487        self.get_widget("enablePositionSpeakingCheckButton").set_active(\
1488            prefs["enablePositionSpeaking"])
1489        self.get_widget("enableMnemonicSpeakingCheckButton").set_active(\
1490            prefs["enableMnemonicSpeaking"])
1491        self.get_widget("speakMisspelledIndicatorCheckButton").set_active(
1492            prefs.get("speakMisspelledIndicator", settings.speakMisspelledIndicator))
1493        self.get_widget("speakDescriptionCheckButton").set_active(
1494            prefs.get("speakDescription", settings.speakDescription))
1495        self.get_widget("speakContextBlockquoteCheckButton").set_active(
1496            prefs.get("speakContextBlockquote", settings.speakContextList))
1497        self.get_widget("speakContextLandmarkCheckButton").set_active(
1498            prefs.get("speakContextLandmark", settings.speakContextLandmark))
1499        self.get_widget("speakContextNonLandmarkFormCheckButton").set_active(
1500            prefs.get("speakContextNonLandmarkForm", settings.speakContextNonLandmarkForm))
1501        self.get_widget("speakContextListCheckButton").set_active(
1502            prefs.get("speakContextList", settings.speakContextList))
1503        self.get_widget("speakContextPanelCheckButton").set_active(
1504            prefs.get("speakContextPanel", settings.speakContextPanel))
1505        self.get_widget("speakContextTableCheckButton").set_active(
1506            prefs.get("speakContextTable", settings.speakContextTable))
1507
1508        enable = prefs.get("messagesAreDetailed", settings.messagesAreDetailed)
1509        self.get_widget("messagesAreDetailedCheckButton").set_active(enable)
1510
1511        enable = prefs.get("useColorNames", settings.useColorNames)
1512        self.get_widget("useColorNamesCheckButton").set_active(enable)
1513
1514        enable = prefs.get("readFullRowInGUITable", settings.readFullRowInGUITable)
1515        self.get_widget("readFullRowInGUITableCheckButton").set_active(enable)
1516
1517        enable = prefs.get("readFullRowInDocumentTable", settings.readFullRowInDocumentTable)
1518        self.get_widget("readFullRowInDocumentTableCheckButton").set_active(enable)
1519
1520        enable = prefs.get("readFullRowInSpreadSheet", settings.readFullRowInSpreadSheet)
1521        self.get_widget("readFullRowInSpreadSheetCheckButton").set_active(enable)
1522
1523        style = prefs.get("capitalizationStyle", settings.capitalizationStyle)
1524        combobox = self.get_widget("capitalizationStyle")
1525        options = [guilabels.CAPITALIZATION_STYLE_NONE,
1526                   guilabels.CAPITALIZATION_STYLE_ICON,
1527                   guilabels.CAPITALIZATION_STYLE_SPELL]
1528        self.populateComboBox(combobox, options)
1529        if style == settings.CAPITALIZATION_STYLE_ICON:
1530            value = guilabels.CAPITALIZATION_STYLE_ICON
1531        elif style == settings.CAPITALIZATION_STYLE_SPELL:
1532            value = guilabels.CAPITALIZATION_STYLE_SPELL
1533        else:
1534            value = guilabels.CAPITALIZATION_STYLE_NONE
1535        combobox.set_active(options.index(value))
1536
1537        combobox2 = self.get_widget("dateFormatCombo")
1538        sdtime = time.strftime
1539        ltime = time.localtime
1540        self.populateComboBox(combobox2,
1541          [sdtime(messages.DATE_FORMAT_LOCALE, ltime()),
1542           sdtime(messages.DATE_FORMAT_NUMBERS_DM, ltime()),
1543           sdtime(messages.DATE_FORMAT_NUMBERS_MD, ltime()),
1544           sdtime(messages.DATE_FORMAT_NUMBERS_DMY, ltime()),
1545           sdtime(messages.DATE_FORMAT_NUMBERS_MDY, ltime()),
1546           sdtime(messages.DATE_FORMAT_NUMBERS_YMD, ltime()),
1547           sdtime(messages.DATE_FORMAT_FULL_DM, ltime()),
1548           sdtime(messages.DATE_FORMAT_FULL_MD, ltime()),
1549           sdtime(messages.DATE_FORMAT_FULL_DMY, ltime()),
1550           sdtime(messages.DATE_FORMAT_FULL_MDY, ltime()),
1551           sdtime(messages.DATE_FORMAT_FULL_YMD, ltime()),
1552           sdtime(messages.DATE_FORMAT_ABBREVIATED_DM, ltime()),
1553           sdtime(messages.DATE_FORMAT_ABBREVIATED_MD, ltime()),
1554           sdtime(messages.DATE_FORMAT_ABBREVIATED_DMY, ltime()),
1555           sdtime(messages.DATE_FORMAT_ABBREVIATED_MDY, ltime()),
1556           sdtime(messages.DATE_FORMAT_ABBREVIATED_YMD, ltime())
1557          ])
1558
1559        indexdate = DATE_FORMAT_LOCALE
1560        dateFormat = self.prefsDict["presentDateFormat"]
1561        if dateFormat == messages.DATE_FORMAT_LOCALE:
1562            indexdate = DATE_FORMAT_LOCALE
1563        elif dateFormat == messages.DATE_FORMAT_NUMBERS_DM:
1564            indexdate = DATE_FORMAT_NUMBERS_DM
1565        elif dateFormat == messages.DATE_FORMAT_NUMBERS_MD:
1566            indexdate = DATE_FORMAT_NUMBERS_MD
1567        elif dateFormat == messages.DATE_FORMAT_NUMBERS_DMY:
1568            indexdate = DATE_FORMAT_NUMBERS_DMY
1569        elif dateFormat == messages.DATE_FORMAT_NUMBERS_MDY:
1570            indexdate = DATE_FORMAT_NUMBERS_MDY
1571        elif dateFormat == messages.DATE_FORMAT_NUMBERS_YMD:
1572            indexdate = DATE_FORMAT_NUMBERS_YMD
1573        elif dateFormat == messages.DATE_FORMAT_FULL_DM:
1574            indexdate = DATE_FORMAT_FULL_DM
1575        elif dateFormat == messages.DATE_FORMAT_FULL_MD:
1576            indexdate = DATE_FORMAT_FULL_MD
1577        elif dateFormat == messages.DATE_FORMAT_FULL_DMY:
1578            indexdate = DATE_FORMAT_FULL_DMY
1579        elif dateFormat == messages.DATE_FORMAT_FULL_MDY:
1580            indexdate = DATE_FORMAT_FULL_MDY
1581        elif dateFormat == messages.DATE_FORMAT_FULL_YMD:
1582            indexdate = DATE_FORMAT_FULL_YMD
1583        elif dateFormat == messages.DATE_FORMAT_ABBREVIATED_DM:
1584            indexdate = DATE_FORMAT_ABBREVIATED_DM
1585        elif dateFormat == messages.DATE_FORMAT_ABBREVIATED_MD:
1586            indexdate = DATE_FORMAT_ABBREVIATED_MD
1587        elif dateFormat == messages.DATE_FORMAT_ABBREVIATED_DMY:
1588            indexdate = DATE_FORMAT_ABBREVIATED_DMY
1589        elif dateFormat == messages.DATE_FORMAT_ABBREVIATED_MDY:
1590            indexdate = DATE_FORMAT_ABBREVIATED_MDY
1591        elif dateFormat == messages.DATE_FORMAT_ABBREVIATED_YMD:
1592            indexdate = DATE_FORMAT_ABBREVIATED_YMD
1593        combobox2.set_active (indexdate)
1594
1595        combobox3 = self.get_widget("timeFormatCombo")
1596        self.populateComboBox(combobox3,
1597          [sdtime(messages.TIME_FORMAT_LOCALE, ltime()),
1598           sdtime(messages.TIME_FORMAT_12_HM, ltime()),
1599           sdtime(messages.TIME_FORMAT_12_HMS, ltime()),
1600           sdtime(messages.TIME_FORMAT_24_HMS, ltime()),
1601           sdtime(messages.TIME_FORMAT_24_HMS_WITH_WORDS, ltime()),
1602           sdtime(messages.TIME_FORMAT_24_HM, ltime()),
1603           sdtime(messages.TIME_FORMAT_24_HM_WITH_WORDS, ltime())])
1604        indextime = TIME_FORMAT_LOCALE
1605        timeFormat = self.prefsDict["presentTimeFormat"]
1606        if timeFormat == messages.TIME_FORMAT_LOCALE:
1607            indextime = TIME_FORMAT_LOCALE
1608        elif timeFormat == messages.TIME_FORMAT_12_HM:
1609            indextime = TIME_FORMAT_12_HM
1610        elif timeFormat == messages.TIME_FORMAT_12_HMS:
1611            indextime = TIME_FORMAT_12_HMS
1612        elif timeFormat == messages.TIME_FORMAT_24_HMS:
1613            indextime = TIME_FORMAT_24_HMS
1614        elif timeFormat == messages.TIME_FORMAT_24_HMS_WITH_WORDS:
1615            indextime = TIME_FORMAT_24_HMS_WITH_WORDS
1616        elif timeFormat == messages.TIME_FORMAT_24_HM:
1617            indextime = TIME_FORMAT_24_HM
1618        elif timeFormat == messages.TIME_FORMAT_24_HM_WITH_WORDS:
1619            indextime = TIME_FORMAT_24_HM_WITH_WORDS
1620        combobox3.set_active (indextime)
1621
1622        self.get_widget("speakProgressBarUpdatesCheckButton").set_active(
1623            prefs.get("speakProgressBarUpdates", settings.speakProgressBarUpdates))
1624        self.get_widget("brailleProgressBarUpdatesCheckButton").set_active(
1625            prefs.get("brailleProgressBarUpdates", settings.brailleProgressBarUpdates))
1626        self.get_widget("beepProgressBarUpdatesCheckButton").set_active(
1627            prefs.get("beepProgressBarUpdates", settings.beepProgressBarUpdates))
1628
1629        interval = prefs["progressBarUpdateInterval"]
1630        self.get_widget("progressBarUpdateIntervalSpinButton").set_value(interval)
1631
1632        comboBox = self.get_widget("progressBarVerbosity")
1633        levels = [guilabels.PROGRESS_BAR_ALL,
1634                  guilabels.PROGRESS_BAR_APPLICATION,
1635                  guilabels.PROGRESS_BAR_WINDOW]
1636        self.populateComboBox(comboBox, levels)
1637        comboBox.set_active(prefs["progressBarVerbosity"])
1638
1639        enable = prefs["enableMouseReview"]
1640        self.get_widget("enableMouseReviewCheckButton").set_active(enable)
1641
1642        # Braille pane.
1643        #
1644        self.get_widget("enableBrailleCheckButton").set_active( \
1645                        prefs["enableBraille"])
1646        state = prefs["brailleRolenameStyle"] == \
1647                            settings.BRAILLE_ROLENAME_STYLE_SHORT
1648        self.get_widget("abbrevRolenames").set_active(state)
1649
1650        self.get_widget("disableBrailleEOLCheckButton").set_active(
1651            prefs["disableBrailleEOL"])
1652
1653        if louis is None:
1654            self.get_widget( \
1655                "contractedBrailleCheckButton").set_sensitive(False)
1656        else:
1657            self.get_widget("contractedBrailleCheckButton").set_active( \
1658                prefs["enableContractedBraille"])
1659            # Set up contraction table combo box and set it to the
1660            # currently used one.
1661            #
1662            tablesCombo = self.get_widget("contractionTableCombo")
1663            tableDict = braille.listTables()
1664            selectedTableIter = None
1665            selectedTable = prefs["brailleContractionTable"] or \
1666                             braille.getDefaultTable()
1667            if tableDict:
1668                tablesModel = Gtk.ListStore(str, str)
1669                names = sorted(tableDict.keys())
1670                for name in names:
1671                    fname = tableDict[name]
1672                    it = tablesModel.append([name, fname])
1673                    if os.path.join(braille.tablesdir, fname) == \
1674                            selectedTable:
1675                        selectedTableIter = it
1676                cell = self.planeCellRendererText
1677                tablesCombo.clear()
1678                tablesCombo.pack_start(cell, True)
1679                tablesCombo.add_attribute(cell, 'text', 0)
1680                tablesCombo.set_model(tablesModel)
1681                if selectedTableIter:
1682                    tablesCombo.set_active_iter(selectedTableIter)
1683                else:
1684                    tablesCombo.set_active(0)
1685            else:
1686                tablesCombo.set_sensitive(False)
1687        if prefs["brailleVerbosityLevel"] == settings.VERBOSITY_LEVEL_BRIEF:
1688            self.get_widget("brailleBriefButton").set_active(True)
1689        else:
1690            self.get_widget("brailleVerboseButton").set_active(True)
1691
1692        self.get_widget("enableBrailleWordWrapCheckButton").set_active(
1693            prefs.get("enableBrailleWordWrap", settings.enableBrailleWordWrap))
1694
1695        selectionIndicator = prefs["brailleSelectorIndicator"]
1696        if selectionIndicator == settings.BRAILLE_UNDERLINE_7:
1697            self.get_widget("brailleSelection7Button").set_active(True)
1698        elif selectionIndicator == settings.BRAILLE_UNDERLINE_8:
1699            self.get_widget("brailleSelection8Button").set_active(True)
1700        elif selectionIndicator == settings.BRAILLE_UNDERLINE_BOTH:
1701            self.get_widget("brailleSelectionBothButton").set_active(True)
1702        else:
1703            self.get_widget("brailleSelectionNoneButton").set_active(True)
1704
1705        linkIndicator = prefs["brailleLinkIndicator"]
1706        if linkIndicator == settings.BRAILLE_UNDERLINE_7:
1707            self.get_widget("brailleLink7Button").set_active(True)
1708        elif linkIndicator == settings.BRAILLE_UNDERLINE_8:
1709            self.get_widget("brailleLink8Button").set_active(True)
1710        elif linkIndicator == settings.BRAILLE_UNDERLINE_BOTH:
1711            self.get_widget("brailleLinkBothButton").set_active(True)
1712        else:
1713            self.get_widget("brailleLinkNoneButton").set_active(True)
1714
1715        enable = prefs.get("enableFlashMessages", settings.enableFlashMessages)
1716        self.get_widget("enableFlashMessagesCheckButton").set_active(enable)
1717
1718        enable = prefs.get("flashIsPersistent", settings.flashIsPersistent)
1719        self.get_widget("flashIsPersistentCheckButton").set_active(enable)
1720
1721        enable = prefs.get("flashIsDetailed", settings.flashIsDetailed)
1722        self.get_widget("flashIsDetailedCheckButton").set_active(enable)
1723
1724        duration = prefs["brailleFlashTime"]
1725        self.get_widget("brailleFlashTimeSpinButton").set_value(duration / 1000)
1726
1727        # Key Echo pane.
1728        #
1729        self.get_widget("keyEchoCheckButton").set_active( \
1730                        prefs["enableKeyEcho"])
1731        self.get_widget("enableAlphabeticKeysCheckButton").set_active(
1732                        prefs.get("enableAlphabeticKeys", settings.enableAlphabeticKeys))
1733        self.get_widget("enableNumericKeysCheckButton").set_active(
1734                        prefs.get("enableNumericKeys", settings.enableNumericKeys))
1735        self.get_widget("enablePunctuationKeysCheckButton").set_active(
1736                        prefs.get("enablePunctuationKeys", settings.enablePunctuationKeys))
1737        self.get_widget("enableSpaceCheckButton").set_active(
1738                        prefs.get("enableSpace", settings.enableSpace))
1739        self.get_widget("enableModifierKeysCheckButton").set_active( \
1740                        prefs["enableModifierKeys"])
1741        self.get_widget("enableFunctionKeysCheckButton").set_active( \
1742                        prefs["enableFunctionKeys"])
1743        self.get_widget("enableActionKeysCheckButton").set_active( \
1744                        prefs["enableActionKeys"])
1745        self.get_widget("enableNavigationKeysCheckButton").set_active( \
1746                        prefs["enableNavigationKeys"])
1747        self.get_widget("enableDiacriticalKeysCheckButton").set_active( \
1748                        prefs["enableDiacriticalKeys"])
1749        self.get_widget("enableEchoByCharacterCheckButton").set_active( \
1750                        prefs["enableEchoByCharacter"])
1751        self.get_widget("enableEchoByWordCheckButton").set_active( \
1752                        prefs["enableEchoByWord"])
1753        self.get_widget("enableEchoBySentenceCheckButton").set_active( \
1754                        prefs["enableEchoBySentence"])
1755
1756        # Text attributes pane.
1757        #
1758        self._createTextAttributesTreeView()
1759
1760        brailleIndicator = prefs["textAttributesBrailleIndicator"]
1761        if brailleIndicator == settings.BRAILLE_UNDERLINE_7:
1762            self.get_widget("textBraille7Button").set_active(True)
1763        elif brailleIndicator == settings.BRAILLE_UNDERLINE_8:
1764            self.get_widget("textBraille8Button").set_active(True)
1765        elif brailleIndicator == settings.BRAILLE_UNDERLINE_BOTH:
1766            self.get_widget("textBrailleBothButton").set_active(True)
1767        else:
1768            self.get_widget("textBrailleNoneButton").set_active(True)
1769
1770        # Pronunciation dictionary pane.
1771        #
1772        self._createPronunciationTreeView()
1773
1774        # General pane.
1775        #
1776        self.get_widget("presentToolTipsCheckButton").set_active(
1777            prefs["presentToolTips"])
1778
1779        if prefs["keyboardLayout"] == settings.GENERAL_KEYBOARD_LAYOUT_DESKTOP:
1780            self.get_widget("generalDesktopButton").set_active(True)
1781        else:
1782            self.get_widget("generalLaptopButton").set_active(True)
1783
1784        combobox = self.get_widget("sayAllStyle")
1785        self.populateComboBox(combobox, [guilabels.SAY_ALL_STYLE_LINE,
1786                                         guilabels.SAY_ALL_STYLE_SENTENCE])
1787        combobox.set_active(prefs["sayAllStyle"])
1788        self.get_widget("rewindAndFastForwardInSayAllCheckButton").set_active(
1789            prefs.get("rewindAndFastForwardInSayAll", settings.rewindAndFastForwardInSayAll))
1790        self.get_widget("structNavInSayAllCheckButton").set_active(
1791            prefs.get("structNavInSayAll", settings.structNavInSayAll))
1792        self.get_widget("sayAllContextBlockquoteCheckButton").set_active(
1793            prefs.get("sayAllContextBlockquote", settings.sayAllContextBlockquote))
1794        self.get_widget("sayAllContextLandmarkCheckButton").set_active(
1795            prefs.get("sayAllContextLandmark", settings.sayAllContextLandmark))
1796        self.get_widget("sayAllContextNonLandmarkFormCheckButton").set_active(
1797            prefs.get("sayAllContextNonLandmarkForm", settings.sayAllContextNonLandmarkForm))
1798        self.get_widget("sayAllContextListCheckButton").set_active(
1799            prefs.get("sayAllContextList", settings.sayAllContextList))
1800        self.get_widget("sayAllContextPanelCheckButton").set_active(
1801            prefs.get("sayAllContextPanel", settings.sayAllContextPanel))
1802        self.get_widget("sayAllContextTableCheckButton").set_active(
1803            prefs.get("sayAllContextTable", settings.sayAllContextTable))
1804
1805        # Orca User Profiles
1806        #
1807        self.profilesCombo = self.get_widget('availableProfilesComboBox1')
1808        self.startingProfileCombo = self.get_widget('availableProfilesComboBox2')
1809        self.profilesComboModel = self.get_widget('model9')
1810        self.__initProfileCombo()
1811        if self.script.app:
1812            self.get_widget('profilesFrame').set_sensitive(False)
1813
1814    def __initProfileCombo(self):
1815        """Adding available profiles and setting active as the active one"""
1816
1817        availableProfiles = self.__getAvailableProfiles()
1818        self.profilesComboModel.clear()
1819
1820        if not len(availableProfiles):
1821            self.profilesComboModel.append(self._defaultProfile)
1822        else:
1823            for profile in availableProfiles:
1824                self.profilesComboModel.append(profile)
1825
1826        activeProfile = self.prefsDict.get('activeProfile') or self._defaultProfile
1827        startingProfile = self.prefsDict.get('startingProfile') or self._defaultProfile
1828
1829        activeProfileIter = self.getComboBoxIndex(self.profilesCombo,
1830                                                  activeProfile[0])
1831        startingProfileIter = self.getComboBoxIndex(self.startingProfileCombo,
1832                                                  startingProfile[0])
1833        self.profilesCombo.set_active(activeProfileIter)
1834        self.startingProfileCombo.set_active(startingProfileIter)
1835
1836    def __getAvailableProfiles(self):
1837        """Get available user profiles."""
1838        return _settingsManager.availableProfiles()
1839
1840    def _updateOrcaModifier(self):
1841        combobox = self.get_widget("orcaModifierComboBox")
1842        keystring = ", ".join(self.prefsDict["orcaModifierKeys"])
1843        combobox.set_active(self.getComboBoxIndex(combobox, keystring))
1844
1845    def populateComboBox(self, combobox, items):
1846        """Populates the combobox with the items provided.
1847
1848        Arguments:
1849        - combobox: the GtkComboBox to populate
1850        - items: the list of strings with which to populate it
1851        """
1852
1853        model = Gtk.ListStore(str)
1854        for item in items:
1855            model.append([item])
1856        combobox.set_model(model)
1857
1858    def getComboBoxIndex(self, combobox, searchStr, col=0):
1859        """ For each of the entries in the given combo box, look for searchStr.
1860            Return the index of the entry if searchStr is found.
1861
1862        Arguments:
1863        - combobox: the GtkComboBox to search.
1864        - searchStr: the string to search for.
1865
1866        Returns the index of the first entry in combobox with searchStr, or
1867        0 if not found.
1868        """
1869
1870        model = combobox.get_model()
1871        myiter = model.get_iter_first()
1872        for i in range(0, len(model)):
1873            name = model.get_value(myiter, col)
1874            if name == searchStr:
1875                return i
1876            myiter = model.iter_next(myiter)
1877
1878        return 0
1879
1880    def getComboBoxList(self, combobox):
1881        """Get the list of values from the active combox
1882        """
1883        active = combobox.get_active()
1884        model = combobox.get_model()
1885        activeIter = model.get_iter(active)
1886        activeLabel = model.get_value(activeIter, 0)
1887        activeName = model.get_value(activeIter, 1)
1888        return [activeLabel, activeName]
1889
1890    def getKeyBindingsModelDict(self, model, modifiedOnly=True):
1891        modelDict = {}
1892        node = model.get_iter_first()
1893        while node:
1894            child = model.iter_children(node)
1895            while child:
1896                key, modified = model.get(child, HANDLER, MODIF)
1897                if modified or not modifiedOnly:
1898                    value = []
1899                    value.append(list(model.get(
1900                            child, KEY1, MOD_MASK1, MOD_USED1, CLICK_COUNT1)))
1901                    modelDict[key] = value
1902                child = model.iter_next(child)
1903            node = model.iter_next(node)
1904
1905        return modelDict
1906
1907    def getModelDict(self, model):
1908        """Get the list of values from a list[str,str] model
1909        """
1910        pronunciation_dict.pronunciation_dict = {}
1911        currentIter = model.get_iter_first()
1912        while currentIter is not None:
1913            key, value = model.get(currentIter, ACTUAL, REPLACEMENT)
1914            if key and value:
1915                pronunciation_dict.setPronunciation(key, value)
1916            currentIter = model.iter_next(currentIter)
1917        modelDict = pronunciation_dict.pronunciation_dict
1918        return modelDict
1919
1920    def showGUI(self):
1921        """Show the Orca configuration GUI window. This assumes that
1922        the GUI has already been created.
1923        """
1924
1925        orcaSetupWindow = self.get_widget("orcaSetupWindow")
1926
1927        accelGroup = Gtk.AccelGroup()
1928        orcaSetupWindow.add_accel_group(accelGroup)
1929        helpButton = self.get_widget("helpButton")
1930        (keyVal, modifierMask) = Gtk.accelerator_parse("F1")
1931        helpButton.add_accelerator("clicked",
1932                                   accelGroup,
1933                                   keyVal,
1934                                   modifierMask,
1935                                   0)
1936
1937        try:
1938            ts = orca_state.lastInputEvent.timestamp
1939        except:
1940            ts = 0
1941        if ts == 0:
1942            ts = Gtk.get_current_event_time()
1943        orcaSetupWindow.present_with_time(ts)
1944
1945        # We always want to re-order the text attributes page so that enabled
1946        # items are consistently at the top.
1947        #
1948        self._setSpokenTextAttributes(
1949                self.getTextAttributesView,
1950                _settingsManager.getSetting('enabledSpokenTextAttributes'),
1951                True, True)
1952
1953        if self.script.app:
1954            title = guilabels.PREFERENCES_APPLICATION_TITLE % self.script.app.name
1955            orcaSetupWindow.set_title(title)
1956
1957        orcaSetupWindow.show()
1958
1959    def _initComboBox(self, combobox):
1960        """Initialize the given combo box to take a list of int/str pairs.
1961
1962        Arguments:
1963        - combobox: the GtkComboBox to initialize.
1964        """
1965
1966        cell = Gtk.CellRendererText()
1967        combobox.pack_start(cell, True)
1968        # We only want to display one column; not two.
1969        #
1970        try:
1971            columnToDisplay = combobox.get_cells()[0]
1972            combobox.add_attribute(columnToDisplay, 'text', 1)
1973        except:
1974            combobox.add_attribute(cell, 'text', 1)
1975        model = Gtk.ListStore(int, str)
1976        combobox.set_model(model)
1977
1978        # Force the display comboboxes to be left aligned.
1979        #
1980        if isinstance(combobox, Gtk.ComboBoxText):
1981            size = combobox.size_request()
1982            cell.set_fixed_size(size[0] - 29, -1)
1983
1984        return model
1985
1986    def _setKeyEchoItems(self):
1987        """[In]sensitize the checkboxes for the various types of key echo,
1988        depending upon whether the value of the key echo check button is set.
1989        """
1990
1991        enable = self.get_widget("keyEchoCheckButton").get_active()
1992        self.get_widget("enableAlphabeticKeysCheckButton").set_sensitive(enable)
1993        self.get_widget("enableNumericKeysCheckButton").set_sensitive(enable)
1994        self.get_widget("enablePunctuationKeysCheckButton").set_sensitive(enable)
1995        self.get_widget("enableSpaceCheckButton").set_sensitive(enable)
1996        self.get_widget("enableModifierKeysCheckButton").set_sensitive(enable)
1997        self.get_widget("enableFunctionKeysCheckButton").set_sensitive(enable)
1998        self.get_widget("enableActionKeysCheckButton").set_sensitive(enable)
1999        self.get_widget("enableNavigationKeysCheckButton").set_sensitive(enable)
2000        self.get_widget("enableDiacriticalKeysCheckButton").set_sensitive( \
2001          enable)
2002
2003    def _presentMessage(self, text, interrupt=False):
2004        """If the text field is not None, presents the given text, optionally
2005        interrupting anything currently being spoken.
2006
2007        Arguments:
2008        - text: the text to present
2009        - interrupt: if True, interrupt any speech currently being spoken
2010        """
2011
2012        self.script.speakMessage(text, interrupt=interrupt)
2013        try:
2014            self.script.displayBrailleMessage(text, flashTime=-1)
2015        except:
2016            pass
2017
2018    def _createNode(self, appName):
2019        """Create a new root node in the TreeStore model with the name of the
2020            application.
2021
2022        Arguments:
2023        - appName: the name of the TreeStore Node (the same of the application)
2024        """
2025
2026        model = self.keyBindingsModel
2027
2028        myiter = model.append(None)
2029        model.set_value(myiter, DESCRIP, appName)
2030        model.set_value(myiter, MODIF, False)
2031
2032        return myiter
2033
2034    def _getIterOf(self, appName):
2035        """Returns the Gtk.TreeIter of the TreeStore model
2036        that matches the application name passed as argument
2037
2038        Arguments:
2039        - appName: a string with the name of the application of the node wanted
2040                    it's the same that the field DESCRIP of the model treeStore
2041        """
2042
2043        model = self.keyBindingsModel
2044
2045        for row in model:
2046            if ((model.iter_depth(row.iter) == 0) \
2047                and (row[DESCRIP] == appName)):
2048                return row.iter
2049
2050        return None
2051
2052    def _clickCountToString(self, clickCount):
2053        """Given a numeric clickCount, returns a string for inclusion
2054        in the list of keybindings.
2055
2056        Argument:
2057        - clickCount: the number of clicks associated with the keybinding.
2058        """
2059
2060        clickCountString = ""
2061        if clickCount == 2:
2062            clickCountString = " (%s)" % guilabels.CLICK_COUNT_DOUBLE
2063        elif clickCount == 3:
2064            clickCountString = " (%s)" % guilabels.CLICK_COUNT_TRIPLE
2065
2066        return clickCountString
2067
2068    def _insertRow(self, handl, kb, parent=None, modif=False):
2069        """Appends a new row with the new keybinding data to the treeview
2070
2071        Arguments:
2072        - handl:  the name of the handler associated to the keyBinding
2073        - kb:     the new keybinding.
2074        - parent: the parent node of the treeview, where to append the kb
2075        - modif:  whether to check the modified field or not.
2076
2077        Returns a Gtk.TreeIter pointing at the new row.
2078        """
2079
2080        model = self.keyBindingsModel
2081
2082        if parent is None:
2083            parent = self._getIterOf(guilabels.KB_GROUP_DEFAULT)
2084
2085        if parent is not None:
2086            myiter = model.append(parent)
2087            if not kb.keysymstring:
2088                text = None
2089            else:
2090                clickCount = self._clickCountToString(kb.click_count)
2091                modifierNames = keybindings.getModifierNames(kb.modifiers)
2092                keysymstring = kb.keysymstring
2093                text = keybindings.getModifierNames(kb.modifiers) \
2094                       + keysymstring \
2095                       + clickCount
2096
2097            model.set_value(myiter, HANDLER, handl)
2098            model.set_value(myiter, DESCRIP, kb.handler.description)
2099            model.set_value(myiter, MOD_MASK1, str(kb.modifier_mask))
2100            model.set_value(myiter, MOD_USED1, str(kb.modifiers))
2101            model.set_value(myiter, KEY1, kb.keysymstring)
2102            model.set_value(myiter, CLICK_COUNT1, str(kb.click_count))
2103            if text is not None:
2104                model.set_value(myiter, OLDTEXT1, text)
2105                model.set_value(myiter, TEXT1, text)
2106            model.set_value(myiter, MODIF, modif)
2107            model.set_value(myiter, EDITABLE, True)
2108
2109            return myiter
2110        else:
2111            return None
2112
2113    def _insertRowBraille(self, handl, com, inputEvHand,
2114                          parent=None, modif=False):
2115        """Appends a new row with the new braille binding data to the treeview
2116
2117        Arguments:
2118        - handl:       the name of the handler associated to the brailleBinding
2119        - com:         the BrlTTY command
2120        - inputEvHand: the inputEventHandler with the new brailleBinding
2121        - parent:      the parent node of the treeview, where to append the kb
2122        - modif:       whether to check the modified field or not.
2123
2124        Returns a Gtk.TreeIter pointing at the new row.
2125        """
2126
2127        model = self.keyBindingsModel
2128
2129        if parent is None:
2130            parent = self._getIterOf(guilabels.KB_GROUP_BRAILLE)
2131
2132        if parent is not None:
2133            myiter = model.append(parent)
2134            model.set_value(myiter, HANDLER, handl)
2135            model.set_value(myiter, DESCRIP, inputEvHand.description)
2136            model.set_value(myiter, KEY1, str(com))
2137            model.set_value(myiter, TEXT1, braille.command_name[com])
2138            model.set_value(myiter, MODIF, modif)
2139            model.set_value(myiter, EDITABLE, False)
2140            return myiter
2141        else:
2142            return None
2143
2144    def _markModified(self):
2145        """ Mark as modified the user custom key bindings:
2146        """
2147
2148        try:
2149            self.script.setupInputEventHandlers()
2150            keyBinds = keybindings.KeyBindings()
2151            keyBinds = _settingsManager.overrideKeyBindings(self.script, keyBinds)
2152            keyBind = keybindings.KeyBinding(None, None, None, None)
2153            treeModel = self.keyBindingsModel
2154
2155            myiter = treeModel.get_iter_first()
2156            while myiter is not None:
2157                iterChild = treeModel.iter_children(myiter)
2158                while iterChild is not None:
2159                    descrip = treeModel.get_value(iterChild, DESCRIP)
2160                    keyBind.handler = \
2161                        input_event.InputEventHandler(None, descrip)
2162                    if keyBinds.hasKeyBinding(keyBind,
2163                                              typeOfSearch="description"):
2164                        treeModel.set_value(iterChild, MODIF, True)
2165                    iterChild = treeModel.iter_next(iterChild)
2166                myiter = treeModel.iter_next(myiter)
2167        except:
2168            debug.printException(debug.LEVEL_SEVERE)
2169
2170    def _populateKeyBindings(self, clearModel=True):
2171        """Fills the TreeView with the list of Orca keybindings
2172
2173        Arguments:
2174        - clearModel: if True, initially clear out the key bindings model.
2175        """
2176
2177        self.keyBindView.set_model(None)
2178        self.keyBindView.set_headers_visible(False)
2179        self.keyBindView.hide()
2180        if clearModel:
2181            self.keyBindingsModel.clear()
2182            self.kbindings = None
2183
2184        try:
2185            appName = self.script.app.name
2186        except:
2187            appName = ""
2188
2189        iterApp = self._createNode(appName)
2190        iterOrca = self._createNode(guilabels.KB_GROUP_DEFAULT)
2191        iterUnbound = self._createNode(guilabels.KB_GROUP_UNBOUND)
2192
2193        if not self.kbindings:
2194            self.kbindings = keybindings.KeyBindings()
2195            self.script.setupInputEventHandlers()
2196            allKeyBindings = self.script.getKeyBindings()
2197            defKeyBindings = self.script.getDefaultKeyBindings()
2198            for kb in allKeyBindings.keyBindings:
2199                if not self.kbindings.hasKeyBinding(kb, "strict"):
2200                    handl = self.script.getInputEventHandlerKey(kb.handler)
2201                    if not defKeyBindings.hasKeyBinding(kb, "description"):
2202                        self._insertRow(handl, kb, iterApp)
2203                    elif kb.keysymstring:
2204                        self._insertRow(handl, kb, iterOrca)
2205                    else:
2206                        self._insertRow(handl, kb, iterUnbound)
2207                    self.kbindings.add(kb)
2208
2209        if not self.keyBindingsModel.iter_has_child(iterApp):
2210            self.keyBindingsModel.remove(iterApp)
2211
2212        if not self.keyBindingsModel.iter_has_child(iterUnbound):
2213            self.keyBindingsModel.remove(iterUnbound)
2214
2215        self._updateOrcaModifier()
2216        self._markModified()
2217        iterBB = self._createNode(guilabels.KB_GROUP_BRAILLE)
2218        self.bbindings = self.script.getBrailleBindings()
2219        for com, inputEvHand in self.bbindings.items():
2220            handl = self.script.getInputEventHandlerKey(inputEvHand)
2221            self._insertRowBraille(handl, com, inputEvHand, iterBB)
2222
2223        self.keyBindView.set_model(self.keyBindingsModel)
2224        self.keyBindView.set_headers_visible(True)
2225        self.keyBindView.expand_all()
2226        self.keyBindingsModel.set_sort_column_id(OLDTEXT1, Gtk.SortType.ASCENDING)
2227        self.keyBindView.show()
2228
2229        # Keep track of new/unbound keybindings that have yet to be applied.
2230        #
2231        self.pendingKeyBindings = {}
2232
2233    def _cleanupSpeechServers(self):
2234        """Remove unwanted factories and drivers for the current active
2235        factory, when the user dismisses the Orca Preferences dialog."""
2236
2237        for workingFactory in self.workingFactories:
2238            if not (workingFactory == self.speechSystemsChoice):
2239                workingFactory.SpeechServer.shutdownActiveServers()
2240            else:
2241                servers = workingFactory.SpeechServer.getSpeechServers()
2242                for server in servers:
2243                    if not (server == self.speechServersChoice):
2244                        server.shutdown()
2245
2246    def speechSupportChecked(self, widget):
2247        """Signal handler for the "toggled" signal for the
2248           speechSupportCheckButton GtkCheckButton widget. The user has
2249           [un]checked the 'Enable Speech' checkbox. Set the 'enableSpeech'
2250           preference to the new value. Set the rest of the speech pane items
2251           [in]sensensitive depending upon whether this checkbox is checked.
2252
2253        Arguments:
2254        - widget: the component that generated the signal.
2255        """
2256
2257        enable = widget.get_active()
2258        self.prefsDict["enableSpeech"] = enable
2259        self.get_widget("speechOptionsGrid").set_sensitive(enable)
2260
2261    def onlySpeakDisplayedTextToggled(self, widget):
2262        """Signal handler for the "toggled" signal for the GtkCheckButton
2263        onlySpeakDisplayedText. In addition to updating the preferences,
2264        set the sensitivity of the contextOptionsGrid.
2265
2266        Arguments:
2267        - widget: the component that generated the signal.
2268        """
2269
2270        enable = widget.get_active()
2271        self.prefsDict["onlySpeakDisplayedText"] = enable
2272        self.get_widget("contextOptionsGrid").set_sensitive(not enable)
2273
2274    def speechSystemsChanged(self, widget):
2275        """Signal handler for the "changed" signal for the speechSystems
2276           GtkComboBox widget. The user has selected a different speech
2277           system. Clear the existing list of speech servers, and setup
2278           a new list of speech servers based on the new choice. Setup a
2279           new list of voices for the first speech server in the list.
2280
2281        Arguments:
2282        - widget: the component that generated the signal.
2283        """
2284
2285        if self.initializingSpeech:
2286            return
2287
2288        selectedIndex = widget.get_active()
2289        self.speechSystemsChoice = self.speechSystemsChoices[selectedIndex]
2290        self._setupSpeechServers()
2291
2292    def speechServersChanged(self, widget):
2293        """Signal handler for the "changed" signal for the speechServers
2294           GtkComboBox widget. The user has selected a different speech
2295           server. Clear the existing list of voices, and setup a new
2296           list of voices based on the new choice.
2297
2298        Arguments:
2299        - widget: the component that generated the signal.
2300        """
2301
2302        if self.initializingSpeech:
2303            return
2304
2305        selectedIndex = widget.get_active()
2306        self.speechServersChoice = self.speechServersChoices[selectedIndex]
2307
2308        # Whenever the speech servers change, we need to make sure we
2309        # clear whatever family was in use by the current voice types.
2310        # Otherwise, we can end up with family names from one server
2311        # bleeding over (e.g., "Paul" from Fonix ends up getting in
2312        # the "Default" voice type after we switch to eSpeak).
2313        #
2314        try:
2315            del self.defaultVoice[acss.ACSS.FAMILY]
2316            del self.uppercaseVoice[acss.ACSS.FAMILY]
2317            del self.hyperlinkVoice[acss.ACSS.FAMILY]
2318            del self.systemVoice[acss.ACSS.FAMILY]
2319        except:
2320            pass
2321
2322        self._setupVoices()
2323
2324    def speechLanguagesChanged(self, widget):
2325        """Signal handler for the "value_changed" signal for the languages
2326           GtkComboBox widget. The user has selected a different voice
2327           language. Save the new voice language name based on the new choice.
2328
2329        Arguments:
2330        - widget: the component that generated the signal.
2331        """
2332
2333        if self.initializingSpeech:
2334            return
2335
2336        selectedIndex = widget.get_active()
2337        try:
2338            self.speechLanguagesChoice = self.speechLanguagesChoices[selectedIndex]
2339            if (self.speechServersChoice, self.speechLanguagesChoice) in \
2340                    self.selectedFamilyChoices:
2341                i = self.selectedFamilyChoices[self.speechServersChoice, \
2342                        self.speechLanguagesChoice]
2343                family = self.speechFamiliesChoices[i]
2344                name = family[speechserver.VoiceFamily.NAME]
2345                language = family[speechserver.VoiceFamily.LANG]
2346                dialect = family[speechserver.VoiceFamily.DIALECT]
2347                variant = family[speechserver.VoiceFamily.VARIANT]
2348                voiceType = self.get_widget("voiceTypesCombo").get_active()
2349                self._setFamilyNameForVoiceType(voiceType, name, language, dialect, variant)
2350        except:
2351            debug.printException(debug.LEVEL_SEVERE)
2352
2353        # Remember the last family manually selected by the user for the
2354        # current speech server.
2355        #
2356        if not selectedIndex == -1:
2357            self.selectedLanguageChoices[self.speechServersChoice] = selectedIndex
2358
2359        self._setupFamilies()
2360
2361    def speechFamiliesChanged(self, widget):
2362        """Signal handler for the "value_changed" signal for the families
2363           GtkComboBox widget. The user has selected a different voice
2364           family. Save the new voice family name based on the new choice.
2365
2366        Arguments:
2367        - widget: the component that generated the signal.
2368        """
2369
2370        if self.initializingSpeech:
2371            return
2372
2373        selectedIndex = widget.get_active()
2374        try:
2375            family = self.speechFamiliesChoices[selectedIndex]
2376            name = family[speechserver.VoiceFamily.NAME]
2377            language = family[speechserver.VoiceFamily.LANG]
2378            dialect = family[speechserver.VoiceFamily.DIALECT]
2379            variant = family[speechserver.VoiceFamily.VARIANT]
2380            voiceType = self.get_widget("voiceTypesCombo").get_active()
2381            self._setFamilyNameForVoiceType(voiceType, name, language, dialect, variant)
2382        except:
2383            debug.printException(debug.LEVEL_SEVERE)
2384
2385        # Remember the last family manually selected by the user for the
2386        # current speech server.
2387        #
2388        if not selectedIndex == -1:
2389            self.selectedFamilyChoices[self.speechServersChoice, \
2390                    self.speechLanguagesChoice] = selectedIndex
2391
2392    def voiceTypesChanged(self, widget):
2393        """Signal handler for the "changed" signal for the voiceTypes
2394           GtkComboBox widget. The user has selected a different voice
2395           type. Setup the new family, rate, pitch and volume component
2396           values based on the new choice.
2397
2398        Arguments:
2399        - widget: the component that generated the signal.
2400        """
2401
2402        if self.initializingSpeech:
2403            return
2404
2405        voiceType = widget.get_active()
2406        self._setVoiceSettingsForVoiceType(voiceType)
2407
2408    def rateValueChanged(self, widget):
2409        """Signal handler for the "value_changed" signal for the rateScale
2410           GtkScale widget. The user has changed the current rate value.
2411           Save the new rate value based on the currently selected voice
2412           type.
2413
2414        Arguments:
2415        - widget: the component that generated the signal.
2416        """
2417
2418        rate = widget.get_value()
2419        voiceType = self.get_widget("voiceTypesCombo").get_active()
2420        self._setRateForVoiceType(voiceType, rate)
2421        voices = _settingsManager.getSetting('voices')
2422        voices[settings.DEFAULT_VOICE][acss.ACSS.RATE] = rate
2423        _settingsManager.setSetting('voices', voices)
2424
2425    def pitchValueChanged(self, widget):
2426        """Signal handler for the "value_changed" signal for the pitchScale
2427           GtkScale widget. The user has changed the current pitch value.
2428           Save the new pitch value based on the currently selected voice
2429           type.
2430
2431        Arguments:
2432        - widget: the component that generated the signal.
2433        """
2434
2435        pitch = widget.get_value()
2436        voiceType = self.get_widget("voiceTypesCombo").get_active()
2437        self._setPitchForVoiceType(voiceType, pitch)
2438        voices = _settingsManager.getSetting('voices')
2439        voices[settings.DEFAULT_VOICE][acss.ACSS.AVERAGE_PITCH] = pitch
2440        _settingsManager.setSetting('voices', voices)
2441
2442    def volumeValueChanged(self, widget):
2443        """Signal handler for the "value_changed" signal for the voiceScale
2444           GtkScale widget. The user has changed the current volume value.
2445           Save the new volume value based on the currently selected voice
2446           type.
2447
2448        Arguments:
2449        - widget: the component that generated the signal.
2450        """
2451
2452        volume = widget.get_value()
2453        voiceType = self.get_widget("voiceTypesCombo").get_active()
2454        self._setVolumeForVoiceType(voiceType, volume)
2455        voices = _settingsManager.getSetting('voices')
2456        voices[settings.DEFAULT_VOICE][acss.ACSS.GAIN] = volume
2457        _settingsManager.setSetting('voices', voices)
2458
2459    def checkButtonToggled(self, widget):
2460        """Signal handler for "toggled" signal for basic GtkCheckButton
2461           widgets. The user has altered the state of the checkbox.
2462           Set the preference to the new value.
2463
2464        Arguments:
2465        - widget: the component that generated the signal.
2466        """
2467
2468        # To use this default handler please make sure:
2469        # The name of the setting that will be changed is: settingName
2470        # The id of the widget in the ui should be: settingNameCheckButton
2471        #
2472        settingName = Gtk.Buildable.get_name(widget)
2473        # strip "CheckButton" from the end.
2474        settingName = settingName[:-11]
2475        self.prefsDict[settingName] = widget.get_active()
2476
2477    def keyEchoChecked(self, widget):
2478        """Signal handler for the "toggled" signal for the
2479           keyEchoCheckbutton GtkCheckButton widget. The user has
2480           [un]checked the 'Enable Key Echo' checkbox. Set the
2481           'enableKeyEcho' preference to the new value. [In]sensitize
2482           the checkboxes for the various types of key echo, depending
2483           upon whether this value is checked or unchecked.
2484
2485        Arguments:
2486        - widget: the component that generated the signal.
2487        """
2488
2489        self.prefsDict["enableKeyEcho"] = widget.get_active()
2490        self._setKeyEchoItems()
2491
2492    def brailleSelectionChanged(self, widget):
2493        """Signal handler for the "toggled" signal for the
2494           brailleSelectionNoneButton, brailleSelection7Button,
2495           brailleSelection8Button or brailleSelectionBothButton
2496           GtkRadioButton widgets. The user has toggled the braille
2497           selection indicator value. If this signal was generated
2498           as the result of a radio button getting selected (as
2499           opposed to a radio button losing the selection), set the
2500           'brailleSelectorIndicator' preference to the new value.
2501
2502        Arguments:
2503        - widget: the component that generated the signal.
2504        """
2505
2506        if widget.get_active():
2507            if widget.get_label() == guilabels.BRAILLE_DOT_7:
2508                self.prefsDict["brailleSelectorIndicator"] = \
2509                    settings.BRAILLE_UNDERLINE_7
2510            elif widget.get_label() == guilabels.BRAILLE_DOT_8:
2511                self.prefsDict["brailleSelectorIndicator"] = \
2512                    settings.BRAILLE_UNDERLINE_8
2513            elif widget.get_label() == guilabels.BRAILLE_DOT_7_8:
2514                self.prefsDict["brailleSelectorIndicator"] = \
2515                    settings.BRAILLE_UNDERLINE_BOTH
2516            else:
2517                self.prefsDict["brailleSelectorIndicator"] = \
2518                    settings.BRAILLE_UNDERLINE_NONE
2519
2520    def brailleLinkChanged(self, widget):
2521        """Signal handler for the "toggled" signal for the
2522           brailleLinkNoneButton, brailleLink7Button,
2523           brailleLink8Button or brailleLinkBothButton
2524           GtkRadioButton widgets. The user has toggled the braille
2525           link indicator value. If this signal was generated
2526           as the result of a radio button getting selected (as
2527           opposed to a radio button losing the selection), set the
2528           'brailleLinkIndicator' preference to the new value.
2529
2530        Arguments:
2531        - widget: the component that generated the signal.
2532        """
2533
2534        if widget.get_active():
2535            if widget.get_label() == guilabels.BRAILLE_DOT_7:
2536                self.prefsDict["brailleLinkIndicator"] = \
2537                    settings.BRAILLE_UNDERLINE_7
2538            elif widget.get_label() == guilabels.BRAILLE_DOT_8:
2539                self.prefsDict["brailleLinkIndicator"] = \
2540                    settings.BRAILLE_UNDERLINE_8
2541            elif widget.get_label() == guilabels.BRAILLE_DOT_7_8:
2542                self.prefsDict["brailleLinkIndicator"] = \
2543                    settings.BRAILLE_UNDERLINE_BOTH
2544            else:
2545                self.prefsDict["brailleLinkIndicator"] = \
2546                    settings.BRAILLE_UNDERLINE_NONE
2547
2548    def brailleIndicatorChanged(self, widget):
2549        """Signal handler for the "toggled" signal for the
2550           textBrailleNoneButton, textBraille7Button, textBraille8Button
2551           or textBrailleBothButton GtkRadioButton widgets. The user has
2552           toggled the text attributes braille indicator value. If this signal
2553           was generated as the result of a radio button getting selected
2554           (as opposed to a radio button losing the selection), set the
2555           'textAttributesBrailleIndicator' preference to the new value.
2556
2557        Arguments:
2558        - widget: the component that generated the signal.
2559        """
2560
2561        if widget.get_active():
2562            if widget.get_label() == guilabels.BRAILLE_DOT_7:
2563                self.prefsDict["textAttributesBrailleIndicator"] = \
2564                    settings.BRAILLE_UNDERLINE_7
2565            elif widget.get_label() == guilabels.BRAILLE_DOT_8:
2566                self.prefsDict["textAttributesBrailleIndicator"] = \
2567                    settings.BRAILLE_UNDERLINE_8
2568            elif widget.get_label() == guilabels.BRAILLE_DOT_7_8:
2569                self.prefsDict["textAttributesBrailleIndicator"] = \
2570                    settings.BRAILLE_UNDERLINE_BOTH
2571            else:
2572                self.prefsDict["textAttributesBrailleIndicator"] = \
2573                    settings.BRAILLE_UNDERLINE_NONE
2574
2575    def punctuationLevelChanged(self, widget):
2576        """Signal handler for the "toggled" signal for the noneButton,
2577           someButton or allButton GtkRadioButton widgets. The user has
2578           toggled the speech punctuation level value. If this signal
2579           was generated as the result of a radio button getting selected
2580           (as opposed to a radio button losing the selection), set the
2581           'verbalizePunctuationStyle' preference to the new value.
2582
2583        Arguments:
2584        - widget: the component that generated the signal.
2585        """
2586
2587        if widget.get_active():
2588            if widget.get_label() == guilabels.PUNCTUATION_STYLE_NONE:
2589                self.prefsDict["verbalizePunctuationStyle"] = \
2590                    settings.PUNCTUATION_STYLE_NONE
2591            elif widget.get_label() == guilabels.PUNCTUATION_STYLE_SOME:
2592                self.prefsDict["verbalizePunctuationStyle"] = \
2593                    settings.PUNCTUATION_STYLE_SOME
2594            elif widget.get_label() == guilabels.PUNCTUATION_STYLE_MOST:
2595                self.prefsDict["verbalizePunctuationStyle"] = \
2596                    settings.PUNCTUATION_STYLE_MOST
2597            else:
2598                self.prefsDict["verbalizePunctuationStyle"] = \
2599                    settings.PUNCTUATION_STYLE_ALL
2600
2601    def orcaModifierChanged(self, widget):
2602        """Signal handler for the changed signal for the orcaModifierComboBox
2603           Set the 'orcaModifierKeys' preference to the new value.
2604
2605        Arguments:
2606        - widget: the component that generated the signal.
2607        """
2608
2609        model = widget.get_model()
2610        myIter = widget.get_active_iter()
2611        orcaModifier = model[myIter][0]
2612        self.prefsDict["orcaModifierKeys"] = orcaModifier.split(', ')
2613
2614    def progressBarVerbosityChanged(self, widget):
2615        """Signal handler for the changed signal for the progressBarVerbosity
2616           GtkComboBox widget. Set the 'progressBarVerbosity' preference to
2617           the new value.
2618
2619        Arguments:
2620        - widget: the component that generated the signal.
2621        """
2622
2623        model = widget.get_model()
2624        myIter = widget.get_active_iter()
2625        progressBarVerbosity = model[myIter][0]
2626        if progressBarVerbosity == guilabels.PROGRESS_BAR_ALL:
2627            self.prefsDict["progressBarVerbosity"] = \
2628                settings.PROGRESS_BAR_ALL
2629        elif progressBarVerbosity == guilabels.PROGRESS_BAR_WINDOW:
2630            self.prefsDict["progressBarVerbosity"] = \
2631                settings.PROGRESS_BAR_WINDOW
2632        else:
2633            self.prefsDict["progressBarVerbosity"] = \
2634                settings.PROGRESS_BAR_APPLICATION
2635
2636    def capitalizationStyleChanged(self, widget):
2637        model = widget.get_model()
2638        myIter = widget.get_active_iter()
2639        capitalizationStyle = model[myIter][0]
2640        if capitalizationStyle == guilabels.CAPITALIZATION_STYLE_ICON:
2641            self.prefsDict["capitalizationStyle"] = settings.CAPITALIZATION_STYLE_ICON
2642        elif capitalizationStyle == guilabels.CAPITALIZATION_STYLE_SPELL:
2643            self.prefsDict["capitalizationStyle"] = settings.CAPITALIZATION_STYLE_SPELL
2644        else:
2645            self.prefsDict["capitalizationStyle"] = settings.CAPITALIZATION_STYLE_NONE
2646        speech.updateCapitalizationStyle()
2647
2648    def sayAllStyleChanged(self, widget):
2649        """Signal handler for the "changed" signal for the sayAllStyle
2650           GtkComboBox widget. Set the 'sayAllStyle' preference to the
2651           new value.
2652
2653        Arguments:
2654        - widget: the component that generated the signal.
2655        """
2656
2657        model = widget.get_model()
2658        myIter = widget.get_active_iter()
2659        sayAllStyle = model[myIter][0]
2660        if sayAllStyle == guilabels.SAY_ALL_STYLE_LINE:
2661            self.prefsDict["sayAllStyle"] = settings.SAYALL_STYLE_LINE
2662        elif sayAllStyle == guilabels.SAY_ALL_STYLE_SENTENCE:
2663            self.prefsDict["sayAllStyle"] = settings.SAYALL_STYLE_SENTENCE
2664
2665    def dateFormatChanged(self, widget):
2666        """Signal handler for the "changed" signal for the dateFormat
2667           GtkComboBox widget. Set the 'dateFormat' preference to the
2668           new value.
2669
2670        Arguments:
2671        - widget: the component that generated the signal.
2672        """
2673
2674        dateFormatCombo = widget.get_active()
2675        if dateFormatCombo == DATE_FORMAT_LOCALE:
2676            newFormat = messages.DATE_FORMAT_LOCALE
2677        elif dateFormatCombo == DATE_FORMAT_NUMBERS_DM:
2678            newFormat = messages.DATE_FORMAT_NUMBERS_DM
2679        elif dateFormatCombo == DATE_FORMAT_NUMBERS_MD:
2680            newFormat = messages.DATE_FORMAT_NUMBERS_MD
2681        elif dateFormatCombo == DATE_FORMAT_NUMBERS_DMY:
2682            newFormat = messages.DATE_FORMAT_NUMBERS_DMY
2683        elif dateFormatCombo == DATE_FORMAT_NUMBERS_MDY:
2684            newFormat = messages.DATE_FORMAT_NUMBERS_MDY
2685        elif dateFormatCombo == DATE_FORMAT_NUMBERS_YMD:
2686            newFormat = messages.DATE_FORMAT_NUMBERS_YMD
2687        elif dateFormatCombo == DATE_FORMAT_FULL_DM:
2688            newFormat = messages.DATE_FORMAT_FULL_DM
2689        elif dateFormatCombo == DATE_FORMAT_FULL_MD:
2690            newFormat = messages.DATE_FORMAT_FULL_MD
2691        elif dateFormatCombo == DATE_FORMAT_FULL_DMY:
2692            newFormat = messages.DATE_FORMAT_FULL_DMY
2693        elif dateFormatCombo == DATE_FORMAT_FULL_MDY:
2694            newFormat = messages.DATE_FORMAT_FULL_MDY
2695        elif dateFormatCombo == DATE_FORMAT_FULL_YMD:
2696            newFormat = messages.DATE_FORMAT_FULL_YMD
2697        elif dateFormatCombo == DATE_FORMAT_ABBREVIATED_DM:
2698            newFormat = messages.DATE_FORMAT_ABBREVIATED_DM
2699        elif dateFormatCombo == DATE_FORMAT_ABBREVIATED_MD:
2700            newFormat = messages.DATE_FORMAT_ABBREVIATED_MD
2701        elif dateFormatCombo == DATE_FORMAT_ABBREVIATED_DMY:
2702            newFormat = messages.DATE_FORMAT_ABBREVIATED_DMY
2703        elif dateFormatCombo == DATE_FORMAT_ABBREVIATED_MDY:
2704            newFormat = messages.DATE_FORMAT_ABBREVIATED_MDY
2705        elif dateFormatCombo == DATE_FORMAT_ABBREVIATED_YMD:
2706            newFormat = messages.DATE_FORMAT_ABBREVIATED_YMD
2707        self.prefsDict["presentDateFormat"] = newFormat
2708
2709    def timeFormatChanged(self, widget):
2710        """Signal handler for the "changed" signal for the timeFormat
2711           GtkComboBox widget. Set the 'timeFormat' preference to the
2712           new value.
2713
2714        Arguments:
2715        - widget: the component that generated the signal.
2716        """
2717
2718        timeFormatCombo = widget.get_active()
2719        if timeFormatCombo == TIME_FORMAT_LOCALE:
2720            newFormat = messages.TIME_FORMAT_LOCALE
2721        elif timeFormatCombo == TIME_FORMAT_12_HM:
2722            newFormat = messages.TIME_FORMAT_12_HM
2723        elif timeFormatCombo == TIME_FORMAT_12_HMS:
2724            newFormat = messages.TIME_FORMAT_12_HMS
2725        elif timeFormatCombo == TIME_FORMAT_24_HMS:
2726            newFormat = messages.TIME_FORMAT_24_HMS
2727        elif timeFormatCombo == TIME_FORMAT_24_HMS_WITH_WORDS:
2728            newFormat = messages.TIME_FORMAT_24_HMS_WITH_WORDS
2729        elif timeFormatCombo == TIME_FORMAT_24_HM:
2730            newFormat = messages.TIME_FORMAT_24_HM
2731        elif timeFormatCombo == TIME_FORMAT_24_HM_WITH_WORDS:
2732            newFormat  = messages.TIME_FORMAT_24_HM_WITH_WORDS
2733        self.prefsDict["presentTimeFormat"] =  newFormat
2734
2735    def speechVerbosityChanged(self, widget):
2736        """Signal handler for the "toggled" signal for the speechBriefButton,
2737           or speechVerboseButton GtkRadioButton widgets. The user has
2738           toggled the speech verbosity level value. If this signal was
2739           generated as the result of a radio button getting selected
2740           (as opposed to a radio button losing the selection), set the
2741           'speechVerbosityLevel' preference to the new value.
2742
2743        Arguments:
2744        - widget: the component that generated the signal.
2745        """
2746
2747        if widget.get_active():
2748            if widget.get_label() == guilabels.VERBOSITY_LEVEL_BRIEF:
2749                self.prefsDict["speechVerbosityLevel"] = \
2750                    settings.VERBOSITY_LEVEL_BRIEF
2751            else:
2752                self.prefsDict["speechVerbosityLevel"] = \
2753                    settings.VERBOSITY_LEVEL_VERBOSE
2754
2755    def progressBarUpdateIntervalValueChanged(self, widget):
2756        """Signal handler for the "value_changed" signal for the
2757           progressBarUpdateIntervalSpinButton GtkSpinButton widget.
2758
2759        Arguments:
2760        - widget: the component that generated the signal.
2761        """
2762
2763        self.prefsDict["progressBarUpdateInterval"] = widget.get_value_as_int()
2764
2765    def brailleFlashTimeValueChanged(self, widget):
2766        self.prefsDict["brailleFlashTime"] = widget.get_value_as_int() * 1000
2767
2768    def abbrevRolenamesChecked(self, widget):
2769        """Signal handler for the "toggled" signal for the abbrevRolenames
2770           GtkCheckButton widget. The user has [un]checked the 'Abbreviated
2771           Rolenames' checkbox. Set the 'brailleRolenameStyle' preference
2772           to the new value.
2773
2774        Arguments:
2775        - widget: the component that generated the signal.
2776        """
2777
2778        if widget.get_active():
2779            self.prefsDict["brailleRolenameStyle"] = \
2780                settings.BRAILLE_ROLENAME_STYLE_SHORT
2781        else:
2782            self.prefsDict["brailleRolenameStyle"] = \
2783                settings.BRAILLE_ROLENAME_STYLE_LONG
2784
2785    def brailleVerbosityChanged(self, widget):
2786        """Signal handler for the "toggled" signal for the brailleBriefButton,
2787           or brailleVerboseButton GtkRadioButton widgets. The user has
2788           toggled the braille verbosity level value. If this signal was
2789           generated as the result of a radio button getting selected
2790           (as opposed to a radio button losing the selection), set the
2791           'brailleVerbosityLevel' preference to the new value.
2792
2793        Arguments:
2794        - widget: the component that generated the signal.
2795        """
2796
2797        if widget.get_active():
2798            if widget.get_label() == guilabels.VERBOSITY_LEVEL_BRIEF:
2799                self.prefsDict["brailleVerbosityLevel"] = \
2800                    settings.VERBOSITY_LEVEL_BRIEF
2801            else:
2802                self.prefsDict["brailleVerbosityLevel"] = \
2803                    settings.VERBOSITY_LEVEL_VERBOSE
2804
2805    def keyModifiedToggle(self, cell, path, model, col):
2806        """When the user changes a checkbox field (boolean field)"""
2807
2808        model[path][col] = not model[path][col]
2809        return
2810
2811    def editingKey(self, cell, editable, path, treeModel):
2812        """Starts user input of a Key for a selected key binding"""
2813
2814        self._presentMessage(messages.KB_ENTER_NEW_KEY)
2815        orca_state.capturingKeys = True
2816        editable.connect('key-press-event', self.kbKeyPressed)
2817        return
2818
2819    def editingCanceledKey(self, editable):
2820        """Stops user input of a Key for a selected key binding"""
2821
2822        orca_state.capturingKeys = False
2823        self._capturedKey = []
2824        return
2825
2826    def _processKeyCaptured(self, keyPressedEvent):
2827        """Called when a new key event arrives and we are capturing keys.
2828        (used for key bindings redefinition)
2829        """
2830
2831        # We want the keyname rather than the printable character.
2832        # If it's not on the keypad, get the name of the unshifted
2833        # character. (i.e. "1" instead of "!")
2834        #
2835        keycode = keyPressedEvent.hardware_keycode
2836        keymap = Gdk.Keymap.get_default()
2837        entries_for_keycode = keymap.get_entries_for_keycode(keycode)
2838        entries = entries_for_keycode[-1]
2839        eventString = Gdk.keyval_name(entries[0])
2840        eventState = keyPressedEvent.state
2841
2842        orcaMods = settings.orcaModifierKeys
2843        if eventString in orcaMods:
2844            self._capturedKey = ['', keybindings.ORCA_MODIFIER_MASK, 0]
2845            return False
2846
2847        modifierKeys =  ['Alt_L', 'Alt_R', 'Control_L', 'Control_R',
2848                         'Shift_L', 'Shift_R', 'Meta_L', 'Meta_R',
2849                         'Num_Lock', 'Caps_Lock', 'Shift_Lock']
2850        if eventString in modifierKeys:
2851            return False
2852
2853        eventState = eventState & Gtk.accelerator_get_default_mod_mask()
2854        if not self._capturedKey \
2855           or eventString in ['Return', 'Escape']:
2856            self._capturedKey = [eventString, eventState, 1]
2857            return True
2858
2859        string, modifiers, clickCount = self._capturedKey
2860        isOrcaModifier = modifiers & keybindings.ORCA_MODIFIER_MASK
2861        if isOrcaModifier:
2862            eventState |= keybindings.ORCA_MODIFIER_MASK
2863            self._capturedKey = [eventString, eventState, clickCount + 1]
2864
2865        return True
2866
2867    def kbKeyPressed(self, editable, event):
2868        """Special handler for the key_pressed events when editing the
2869        keybindings.  This lets us control what gets inserted into the
2870        entry.
2871        """
2872
2873        keyProcessed = self._processKeyCaptured(event)
2874        if not keyProcessed:
2875            return True
2876
2877        if not self._capturedKey:
2878            return False
2879
2880        keyName, modifiers, clickCount = self._capturedKey
2881        if not keyName or keyName in ["Return", "Escape"]:
2882            return False
2883
2884        isOrcaModifier = modifiers & keybindings.ORCA_MODIFIER_MASK
2885        if keyName in ["Delete", "BackSpace"] and not isOrcaModifier:
2886            editable.set_text("")
2887            self._presentMessage(messages.KB_DELETED)
2888            self._capturedKey = []
2889            self.newBinding = None
2890            return True
2891
2892        self.newBinding = keybindings.KeyBinding(keyName,
2893                                                 keybindings.defaultModifierMask,
2894                                                 modifiers,
2895                                                 None,
2896                                                 clickCount)
2897        modifierNames = keybindings.getModifierNames(modifiers)
2898        clickCountString = self._clickCountToString(clickCount)
2899        newString = modifierNames + keyName + clickCountString
2900        description = self.pendingKeyBindings.get(newString)
2901
2902        if description is None:
2903            match = lambda x: x.keysymstring == keyName \
2904                          and x.modifiers == modifiers \
2905                          and x.click_count == clickCount \
2906                          and x.handler
2907            matches = list(filter(match, self.kbindings.keyBindings))
2908            if matches:
2909                description = matches[0].handler.description
2910
2911        if description:
2912            msg = messages.KB_ALREADY_BOUND % description
2913            delay = int(1000 * settings.doubleClickTimeout)
2914            GLib.timeout_add(delay, self._presentMessage, msg)
2915        else:
2916            msg = messages.KB_CAPTURED % newString
2917            editable.set_text(newString)
2918            self._presentMessage(msg)
2919
2920        return True
2921
2922    def editedKey(self, cell, path, new_text, treeModel,
2923                  modMask, modUsed, key, click_count, text):
2924        """The user changed the key for a Keybinding: update the model of
2925        the treeview.
2926        """
2927
2928        orca_state.capturingKeys = False
2929        self._capturedKey = []
2930        myiter = treeModel.get_iter_from_string(path)
2931        try:
2932            originalBinding = treeModel.get_value(myiter, text)
2933        except:
2934            originalBinding = ''
2935        modified = (originalBinding != new_text)
2936
2937        try:
2938            string = self.newBinding.keysymstring
2939            mods = self.newBinding.modifiers
2940            clickCount = self.newBinding.click_count
2941        except:
2942            string = ''
2943            mods = 0
2944            clickCount = 1
2945
2946        mods = mods & Gdk.ModifierType.MODIFIER_MASK
2947        if mods & (1 << pyatspi.MODIFIER_SHIFTLOCK) \
2948           and mods & keybindings.ORCA_MODIFIER_MASK:
2949            mods ^= (1 << pyatspi.MODIFIER_SHIFTLOCK)
2950
2951        treeModel.set(myiter,
2952                      modMask, str(keybindings.defaultModifierMask),
2953                      modUsed, str(int(mods)),
2954                      key, string,
2955                      text, new_text,
2956                      click_count, str(clickCount),
2957                      MODIF, modified)
2958        speech.stop()
2959        if new_text:
2960            message = messages.KB_CAPTURED_CONFIRMATION % new_text
2961            description = treeModel.get_value(myiter, DESCRIP)
2962            self.pendingKeyBindings[new_text] = description
2963        else:
2964            message = messages.KB_DELETED_CONFIRMATION
2965
2966        if modified:
2967            self._presentMessage(message)
2968            self.pendingKeyBindings[originalBinding] = ""
2969
2970        return
2971
2972    def presentToolTipsChecked(self, widget):
2973        """Signal handler for the "toggled" signal for the
2974           presentToolTipsCheckButton GtkCheckButton widget.
2975           The user has [un]checked the 'Present ToolTips'
2976           checkbox. Set the 'presentToolTips'
2977           preference to the new value if the user can present tooltips.
2978
2979        Arguments:
2980        - widget: the component that generated the signal.
2981        """
2982
2983        self.prefsDict["presentToolTips"] = widget.get_active()
2984
2985    def keyboardLayoutChanged(self, widget):
2986        """Signal handler for the "toggled" signal for the generalDesktopButton,
2987           or generalLaptopButton GtkRadioButton widgets. The user has
2988           toggled the keyboard layout value. If this signal was
2989           generated as the result of a radio button getting selected
2990           (as opposed to a radio button losing the selection), set the
2991           'keyboardLayout' preference to the new value. Also set the
2992           matching list of Orca modifier keys
2993
2994        Arguments:
2995        - widget: the component that generated the signal.
2996        """
2997
2998        if widget.get_active():
2999            if widget.get_label() == guilabels.KEYBOARD_LAYOUT_DESKTOP:
3000                self.prefsDict["keyboardLayout"] = \
3001                    settings.GENERAL_KEYBOARD_LAYOUT_DESKTOP
3002                self.prefsDict["orcaModifierKeys"] = \
3003                    settings.DESKTOP_MODIFIER_KEYS
3004            else:
3005                self.prefsDict["keyboardLayout"] = \
3006                    settings.GENERAL_KEYBOARD_LAYOUT_LAPTOP
3007                self.prefsDict["orcaModifierKeys"] = \
3008                    settings.LAPTOP_MODIFIER_KEYS
3009
3010    def pronunciationAddButtonClicked(self, widget):
3011        """Signal handler for the "clicked" signal for the
3012        pronunciationAddButton GtkButton widget. The user has clicked
3013        the Add button on the Pronunciation pane. A new row will be
3014        added to the end of the pronunciation dictionary list. Both the
3015        actual and replacement strings will initially be set to an empty
3016        string. Focus will be moved to that row.
3017
3018        Arguments:
3019        - widget: the component that generated the signal.
3020        """
3021
3022        model = self.pronunciationView.get_model()
3023        thisIter = model.append()
3024        model.set(thisIter, ACTUAL, "", REPLACEMENT, "")
3025        path = model.get_path(thisIter)
3026        col = self.pronunciationView.get_column(0)
3027        self.pronunciationView.grab_focus()
3028        self.pronunciationView.set_cursor(path, col, True)
3029
3030    def pronunciationDeleteButtonClicked(self, widget):
3031        """Signal handler for the "clicked" signal for the
3032        pronunciationDeleteButton GtkButton widget. The user has clicked
3033        the Delete button on the Pronunciation pane. The row in the
3034        pronunciation dictionary list with focus will be deleted.
3035
3036        Arguments:
3037        - widget: the component that generated the signal.
3038        """
3039
3040        model, oldIter = self.pronunciationView.get_selection().get_selected()
3041        model.remove(oldIter)
3042
3043    def textSelectAllButtonClicked(self, widget):
3044        """Signal handler for the "clicked" signal for the
3045        textSelectAllButton GtkButton widget. The user has clicked
3046        the Speak all button.  Check all the text attributes and
3047        then update the "enabledSpokenTextAttributes" and
3048        "enabledBrailledTextAttributes" preference strings.
3049
3050        Arguments:
3051        - widget: the component that generated the signal.
3052        """
3053
3054        attributes = _settingsManager.getSetting('allTextAttributes')
3055        self._setSpokenTextAttributes(
3056            self.getTextAttributesView, attributes, True)
3057        self._setBrailledTextAttributes(
3058            self.getTextAttributesView, attributes, True)
3059        self._updateTextDictEntry()
3060
3061    def textUnselectAllButtonClicked(self, widget):
3062        """Signal handler for the "clicked" signal for the
3063        textUnselectAllButton GtkButton widget. The user has clicked
3064        the Speak none button. Uncheck all the text attributes and
3065        then update the "enabledSpokenTextAttributes" and
3066        "enabledBrailledTextAttributes" preference strings.
3067
3068        Arguments:
3069        - widget: the component that generated the signal.
3070        """
3071
3072        attributes = _settingsManager.getSetting('allTextAttributes')
3073        self._setSpokenTextAttributes(
3074            self.getTextAttributesView, attributes, False)
3075        self._setBrailledTextAttributes(
3076            self.getTextAttributesView, attributes, False)
3077        self._updateTextDictEntry()
3078
3079    def textResetButtonClicked(self, widget):
3080        """Signal handler for the "clicked" signal for the
3081        textResetButton GtkButton widget. The user has clicked
3082        the Reset button. Reset all the text attributes to their
3083        initial state and then update the "enabledSpokenTextAttributes"
3084        and "enabledBrailledTextAttributes" preference strings.
3085
3086        Arguments:
3087        - widget: the component that generated the signal.
3088        """
3089
3090        attributes = _settingsManager.getSetting('allTextAttributes')
3091        self._setSpokenTextAttributes(
3092            self.getTextAttributesView, attributes, False)
3093        self._setBrailledTextAttributes(
3094            self.getTextAttributesView, attributes, False)
3095
3096        attributes = _settingsManager.getSetting('enabledSpokenTextAttributes')
3097        self._setSpokenTextAttributes(
3098            self.getTextAttributesView, attributes, True)
3099
3100        attributes = \
3101            _settingsManager.getSetting('enabledBrailledTextAttributes')
3102        self._setBrailledTextAttributes(
3103            self.getTextAttributesView, attributes, True)
3104
3105        self._updateTextDictEntry()
3106
3107    def textMoveToTopButtonClicked(self, widget):
3108        """Signal handler for the "clicked" signal for the
3109        textMoveToTopButton GtkButton widget. The user has clicked
3110        the Move to top button. Move the selected rows in the text
3111        attribute view to the very top of the list and then update
3112        the "enabledSpokenTextAttributes" and "enabledBrailledTextAttributes"
3113        preference strings.
3114
3115        Arguments:
3116        - widget: the component that generated the signal.
3117        """
3118
3119        textSelection = self.getTextAttributesView.get_selection()
3120        [model, paths] = textSelection.get_selected_rows()
3121        for path in paths:
3122            thisIter = model.get_iter(path)
3123            model.move_after(thisIter, None)
3124        self._updateTextDictEntry()
3125
3126    def textMoveUpOneButtonClicked(self, widget):
3127        """Signal handler for the "clicked" signal for the
3128        textMoveUpOneButton GtkButton widget. The user has clicked
3129        the Move up one button. Move the selected rows in the text
3130        attribute view up one row in the list and then update the
3131        "enabledSpokenTextAttributes" and "enabledBrailledTextAttributes"
3132        preference strings.
3133
3134        Arguments:
3135        - widget: the component that generated the signal.
3136        """
3137
3138        textSelection = self.getTextAttributesView.get_selection()
3139        [model, paths] = textSelection.get_selected_rows()
3140        for path in paths:
3141            thisIter = model.get_iter(path)
3142            indices = path.get_indices()
3143            if indices[0]:
3144                otherIter = model.iter_nth_child(None, indices[0]-1)
3145                model.swap(thisIter, otherIter)
3146        self._updateTextDictEntry()
3147
3148    def textMoveDownOneButtonClicked(self, widget):
3149        """Signal handler for the "clicked" signal for the
3150        textMoveDownOneButton GtkButton widget. The user has clicked
3151        the Move down one button. Move the selected rows in the text
3152        attribute view down one row in the list and then update the
3153        "enabledSpokenTextAttributes" and "enabledBrailledTextAttributes"
3154        preference strings.
3155
3156        Arguments:
3157        - widget: the component that generated the signal.
3158        """
3159
3160        textSelection = self.getTextAttributesView.get_selection()
3161        [model, paths] = textSelection.get_selected_rows()
3162        noRows = model.iter_n_children(None)
3163        for path in paths:
3164            thisIter = model.get_iter(path)
3165            indices = path.get_indices()
3166            if indices[0] < noRows-1:
3167                otherIter = model.iter_next(thisIter)
3168                model.swap(thisIter, otherIter)
3169        self._updateTextDictEntry()
3170
3171    def textMoveToBottomButtonClicked(self, widget):
3172        """Signal handler for the "clicked" signal for the
3173        textMoveToBottomButton GtkButton widget. The user has clicked
3174        the Move to bottom button. Move the selected rows in the text
3175        attribute view to the bottom of the list and then update the
3176        "enabledSpokenTextAttributes" and "enabledBrailledTextAttributes"
3177        preference strings.
3178
3179        Arguments:
3180        - widget: the component that generated the signal.
3181        """
3182
3183        textSelection = self.getTextAttributesView.get_selection()
3184        [model, paths] = textSelection.get_selected_rows()
3185        for path in paths:
3186            thisIter = model.get_iter(path)
3187            model.move_before(thisIter, None)
3188        self._updateTextDictEntry()
3189
3190    def helpButtonClicked(self, widget):
3191        """Signal handler for the "clicked" signal for the helpButton
3192           GtkButton widget. The user has clicked the Help button.
3193
3194        Arguments:
3195        - widget: the component that generated the signal.
3196        """
3197
3198        orca.helpForOrca(page="preferences")
3199
3200    def restoreSettings(self):
3201        """Restore the settings we saved away when opening the preferences
3202           dialog."""
3203        # Restore the default rate/pitch/gain,
3204        # in case the user played with the sliders.
3205        #
3206        voices = _settingsManager.getSetting('voices')
3207        defaultVoice = voices[settings.DEFAULT_VOICE]
3208        defaultVoice[acss.ACSS.GAIN] = self.savedGain
3209        defaultVoice[acss.ACSS.AVERAGE_PITCH] = self.savedPitch
3210        defaultVoice[acss.ACSS.RATE] =  self.savedRate
3211
3212    def saveBasicSettings(self):
3213        if not self._isInitialSetup:
3214            self.restoreSettings()
3215
3216        enable = self.get_widget("speechSupportCheckButton").get_active()
3217        self.prefsDict["enableSpeech"] = enable
3218
3219        if self.speechSystemsChoice:
3220            self.prefsDict["speechServerFactory"] = \
3221                self.speechSystemsChoice.__name__
3222
3223        if self.speechServersChoice:
3224            self.prefsDict["speechServerInfo"] = \
3225                self.speechServersChoice.getInfo()
3226
3227        if self.defaultVoice is not None:
3228            self.prefsDict["voices"] = {
3229                settings.DEFAULT_VOICE: acss.ACSS(self.defaultVoice),
3230                settings.UPPERCASE_VOICE: acss.ACSS(self.uppercaseVoice),
3231                settings.HYPERLINK_VOICE: acss.ACSS(self.hyperlinkVoice),
3232                settings.SYSTEM_VOICE: acss.ACSS(self.systemVoice),
3233            }
3234
3235    def applyButtonClicked(self, widget):
3236        """Signal handler for the "clicked" signal for the applyButton
3237           GtkButton widget. The user has clicked the Apply button.
3238           Write out the users preferences. If GNOME accessibility hadn't
3239           previously been enabled, warn the user that they will need to
3240           log out. Shut down any active speech servers that were started.
3241           Reload the users preferences to get the new speech, braille and
3242           key echo value to take effect. Do not dismiss the configuration
3243           window.
3244
3245        Arguments:
3246        - widget: the component that generated the signal.
3247        """
3248        self.saveBasicSettings()
3249
3250        activeProfile = self.getComboBoxList(self.profilesCombo)
3251        startingProfile = self.getComboBoxList(self.startingProfileCombo)
3252
3253        self.prefsDict['profile'] = activeProfile
3254        self.prefsDict['activeProfile'] = activeProfile
3255        self.prefsDict['startingProfile'] = startingProfile
3256        _settingsManager.setStartingProfile(startingProfile)
3257
3258        self.writeUserPreferences()
3259
3260        orca.loadUserSettings(self.script)
3261
3262        braille.checkBrailleSetting()
3263
3264        self._initSpeechState()
3265
3266        self._populateKeyBindings()
3267
3268        self.__initProfileCombo()
3269
3270    def cancelButtonClicked(self, widget):
3271        """Signal handler for the "clicked" signal for the cancelButton
3272           GtkButton widget. The user has clicked the Cancel button.
3273           Don't write out the preferences. Destroy the configuration window.
3274
3275        Arguments:
3276        - widget: the component that generated the signal.
3277        """
3278
3279        self.windowClosed(widget)
3280        self.get_widget("orcaSetupWindow").destroy()
3281
3282    def okButtonClicked(self, widget=None):
3283        """Signal handler for the "clicked" signal for the okButton
3284           GtkButton widget. The user has clicked the OK button.
3285           Write out the users preferences. If GNOME accessibility hadn't
3286           previously been enabled, warn the user that they will need to
3287           log out. Shut down any active speech servers that were started.
3288           Reload the users preferences to get the new speech, braille and
3289           key echo value to take effect. Hide the configuration window.
3290
3291        Arguments:
3292        - widget: the component that generated the signal.
3293        """
3294
3295        self.applyButtonClicked(widget)
3296        self._cleanupSpeechServers()
3297        self.get_widget("orcaSetupWindow").destroy()
3298
3299    def windowClosed(self, widget):
3300        """Signal handler for the "closed" signal for the orcaSetupWindow
3301           GtkWindow widget. This is effectively the same as pressing the
3302           cancel button, except the window is destroyed for us.
3303
3304        Arguments:
3305        - widget: the component that generated the signal.
3306        """
3307
3308        factory = _settingsManager.getSetting('speechServerFactory')
3309        if factory:
3310            self._setSpeechSystemsChoice(factory)
3311
3312        server = _settingsManager.getSetting('speechServerInfo')
3313        if server:
3314            self._setSpeechServersChoice(server)
3315
3316        self._cleanupSpeechServers()
3317        self.restoreSettings()
3318
3319    def windowDestroyed(self, widget):
3320        """Signal handler for the "destroyed" signal for the orcaSetupWindow
3321           GtkWindow widget. Reset orca_state.orcaOS to None, so that the
3322           GUI can be rebuilt from the GtkBuilder file the next time the user
3323           wants to display the configuration GUI.
3324
3325        Arguments:
3326        - widget: the component that generated the signal.
3327        """
3328
3329        self.keyBindView.set_model(None)
3330        self.getTextAttributesView.set_model(None)
3331        self.pronunciationView.set_model(None)
3332        self.keyBindView.set_headers_visible(False)
3333        self.getTextAttributesView.set_headers_visible(False)
3334        self.pronunciationView.set_headers_visible(False)
3335        self.keyBindView.hide()
3336        self.getTextAttributesView.hide()
3337        self.pronunciationView.hide()
3338        orca_state.orcaOS = None
3339
3340    def showProfileGUI(self, widget):
3341        """Show profile Dialog to add a new one"""
3342
3343        orca_gui_profile.showProfileUI(self)
3344
3345    def saveProfile(self, profileToSaveLabel):
3346        """Creates a new profile based on the name profileToSaveLabel and
3347        updates the Preferences dialog combo boxes accordingly."""
3348
3349        if not profileToSaveLabel:
3350            return
3351        profileToSave = profileToSaveLabel.replace(' ', '_').lower()
3352        profile = [profileToSaveLabel, profileToSave]
3353
3354        def saveActiveProfile(newProfile = True):
3355            if newProfile:
3356                activeProfileIter = self.profilesComboModel.append(profile)
3357                self.profilesCombo.set_active_iter(activeProfileIter)
3358
3359            self.prefsDict['profile'] = profile
3360            self.prefsDict['activeProfile'] = profile
3361            self.saveBasicSettings()
3362            self.writeUserPreferences()
3363
3364        availableProfiles = [p[1] for p in self.__getAvailableProfiles()]
3365        if isinstance(profileToSave, str) \
3366                and profileToSave != '' \
3367                and not profileToSave in availableProfiles \
3368                and profileToSave != self._defaultProfile[1]:
3369            saveActiveProfile()
3370        else:
3371            if profileToSave is not None:
3372                message = guilabels.PROFILE_CONFLICT_MESSAGE % \
3373                    ("<b>%s</b>" % GLib.markup_escape_text(profileToSaveLabel))
3374                dialog = Gtk.MessageDialog(None,
3375                        Gtk.DialogFlags.MODAL,
3376                        type=Gtk.MessageType.INFO,
3377                        buttons=Gtk.ButtonsType.YES_NO)
3378                dialog.set_markup("<b>%s</b>" % guilabels.PROFILE_CONFLICT_LABEL)
3379                dialog.format_secondary_markup(message)
3380                dialog.set_title(guilabels.PROFILE_CONFLICT_TITLE)
3381                response = dialog.run()
3382                if response == Gtk.ResponseType.YES:
3383                    dialog.destroy()
3384                    saveActiveProfile(False)
3385                else:
3386                    dialog.destroy()
3387
3388
3389    def removeProfileButtonClicked(self, widget):
3390        """Remove profile button clicked handler
3391
3392        If we removed the last profile, a default one will automatically get
3393        added back by the settings manager.
3394        """
3395
3396        oldProfile = self.getComboBoxList(self.profilesCombo)
3397
3398        message = guilabels.PROFILE_REMOVE_MESSAGE % \
3399            ("<b>%s</b>" % GLib.markup_escape_text(oldProfile[0]))
3400        dialog = Gtk.MessageDialog(self.window, Gtk.DialogFlags.MODAL,
3401                                   type=Gtk.MessageType.INFO,
3402                                   buttons=Gtk.ButtonsType.YES_NO)
3403        dialog.set_markup("<b>%s</b>" % guilabels.PROFILE_REMOVE_LABEL)
3404        dialog.format_secondary_markup(message)
3405        if dialog.run() == Gtk.ResponseType.YES:
3406            # If we remove the currently used starting profile, fallback on
3407            # the first listed profile, or the default one if there's
3408            # nothing better
3409            newStartingProfile = self.prefsDict.get('startingProfile')
3410            if not newStartingProfile or newStartingProfile == oldProfile:
3411                newStartingProfile = self._defaultProfile
3412                for row in self.profilesComboModel:
3413                    rowProfile = row[:]
3414                    if rowProfile != oldProfile:
3415                        newStartingProfile = rowProfile
3416                        break
3417            # Update the current profile to the active profile unless we're
3418            # removing that one, in which case we use the new starting
3419            # profile
3420            newProfile = self.prefsDict.get('activeProfile')
3421            if not newProfile or newProfile == oldProfile:
3422                newProfile = newStartingProfile
3423
3424            _settingsManager.removeProfile(oldProfile[1])
3425            self.loadProfile(newProfile)
3426
3427            # Make sure nothing is referencing the removed profile anymore
3428            startingProfile = self.prefsDict.get('startingProfile')
3429            if not startingProfile or startingProfile == oldProfile:
3430                self.prefsDict['startingProfile'] = newStartingProfile
3431                _settingsManager.setStartingProfile(newStartingProfile)
3432                self.writeUserPreferences()
3433
3434        dialog.destroy()
3435
3436    def loadProfileButtonClicked(self, widget):
3437        """Load profile button clicked handler"""
3438
3439        if self._isInitialSetup:
3440            return
3441
3442        dialog = Gtk.MessageDialog(None,
3443                Gtk.DialogFlags.MODAL,
3444                type=Gtk.MessageType.INFO,
3445                buttons=Gtk.ButtonsType.YES_NO)
3446
3447        dialog.set_markup("<b>%s</b>" % guilabels.PROFILE_LOAD_LABEL)
3448        dialog.format_secondary_markup(guilabels.PROFILE_LOAD_MESSAGE)
3449        response = dialog.run()
3450        if response == Gtk.ResponseType.YES:
3451            dialog.destroy()
3452            self.loadSelectedProfile()
3453        else:
3454            dialog.destroy()
3455
3456    def loadSelectedProfile(self):
3457        """Load selected profile"""
3458
3459        activeProfile = self.getComboBoxList(self.profilesCombo)
3460        self.loadProfile(activeProfile)
3461
3462    def loadProfile(self, profile):
3463        """Load profile"""
3464
3465        self.saveBasicSettings()
3466
3467        self.prefsDict['activeProfile'] = profile
3468        _settingsManager.setProfile(profile[1])
3469        self.prefsDict = _settingsManager.getGeneralSettings(profile[1])
3470
3471        orca.loadUserSettings(skipReloadMessage=True)
3472
3473        self._initGUIState()
3474
3475        braille.checkBrailleSetting()
3476
3477        self._initSpeechState()
3478
3479        self._populateKeyBindings()
3480
3481        self.__initProfileCombo()
3482
3483