[orca/orca-gnome3: 19/87] Removed cyclic dependence
- From: Alejandro Leiva <aleiva src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [orca/orca-gnome3: 19/87] Removed cyclic dependence
- Date: Fri, 1 Apr 2011 11:14:24 +0000 (UTC)
commit ef9710ccce41d496c31646919b0639dca162be4b
Author: José Ignacio �lvarez Ruiz <jialvarez emergya es>
Date: Tue Mar 8 13:51:17 2011 +0100
Removed cyclic dependence
src/orca/Makefile.am | 1 -
src/orca/__init__.py | 6 -
src/orca/app_gui_prefs.py | 16 +-
src/orca/{gui_manager => baseplugins}/__init__.py | 0
src/orca/braille_generator.py | 9 +-
src/orca/chat.py | 9 +-
src/orca/default.py | 5847 ++++++++++++++++++++
src/orca/event_manager.py | 8 +-
src/orca/gui_manager/abstract_view.py | 35 -
src/orca/gui_manager/controller.py | 53 -
.../controllers/gtk2/orca_controller_main_gtk2.py | 61 -
.../gtk2/orca_controller_splash_gtk2.py | 59 -
src/orca/gui_manager/factory.py | 70 -
.../gui_manager/views/gtk2/gfx/orca-splash.png | Bin 106028 -> 0 bytes
.../gui_manager/views/gtk2/orca_gui_main_gtk2.py | 200 -
.../gui_manager/views/gtk2/orca_gui_splash_gtk2.py | 102 -
.../views/gtk2/ui/orca-advanced-magnification.ui | 1033 ----
src/orca/gui_manager/views/gtk2/ui/orca-find.ui | 420 --
src/orca/gui_manager/views/gtk2/ui/orca-mainwin.ui | 100 -
.../views/gtk2/ui/orca-preferences-warning.ui | 111 -
src/orca/gui_manager/views/gtk2/ui/orca-profile.ui | 109 -
src/orca/gui_manager/views/gtk2/ui/orca-quit.ui | 125 -
src/orca/gui_manager/views/gtk2/ui/orca-setup.ui | 4366 ---------------
src/orca/gui_manager/views/gtk2/ui/orca-splash.ui | 24 -
src/orca/gui_manager/views/qt/main_window.py | 45 -
src/orca/interfaces.py | 164 +-
src/orca/mag.py | 10 +-
src/orca/manager.py | 63 +-
src/orca/mouse_review.py | 6 +-
src/orca/orca.py | 7 +
src/orca/orca_console_prefs.py | 9 +-
src/orca/orca_gui_prefs.py | 20 +-
src/orca/orca_gui_profile.py | 9 +-
src/orca/plugin_manager.py | 53 -
src/orca/script.py | 21 +-
src/orca/script_manager.py | 16 +-
src/orca/scripts/default.py | 55 +-
src/orca/self_voicing.py | 80 +
src/orca/settings.py | 10 +-
src/orca/settings_manager.py | 9 +-
src/orca/speech_generator.py | 9 +-
src/orca/store_config.py | 46 +-
src/orca/test.py | 85 +
43 files changed, 6174 insertions(+), 7307 deletions(-)
---
diff --git a/src/orca/Makefile.am b/src/orca/Makefile.am
index 0d198c9..93219b8 100644
--- a/src/orca/Makefile.am
+++ b/src/orca/Makefile.am
@@ -58,7 +58,6 @@ orca_python_PYTHON = \
phonnames.py \
orca_platform.py \
plug_event_manager.py \
- plugin_manager.py \
pronunciation_dict.py \
punctuation_settings.py \
rolenames.py \
diff --git a/src/orca/__init__.py b/src/orca/__init__.py
index 7c958ff..e69de29 100644
--- a/src/orca/__init__.py
+++ b/src/orca/__init__.py
@@ -1,6 +0,0 @@
-"""Orca Screen Reader"""
-
-__copyright__ = "Copyright (c) 2005-2006 Sun Microsystems Inc."
-__license__ = "LGPL"
-
-
diff --git a/src/orca/app_gui_prefs.py b/src/orca/app_gui_prefs.py
index 8c28dbe..9fbe66b 100644
--- a/src/orca/app_gui_prefs.py
+++ b/src/orca/app_gui_prefs.py
@@ -45,20 +45,8 @@ import speech
from orca_i18n import _ # for gettext support
-if hasattr(orca, '_scriptManager'):
- _scriptManager = getattr(orca, '_scriptManager')
-else:
- from script_manager import ScriptManager
- _scriptManager = ScriptManager()
-
-if hasattr(orca, '_settingsManager'):
- _settingsManager = getattr(orca, '_settingsManager')
-else:
- from settings_manager import SettingsManager
- _settingsManager = SettingsManager()
- if _settingsManager is None:
- print "Could not load the settings manager. Exiting."
- sys.exit(1)
+_scriptManager = getattr(orca, '_scriptManager')
+_settingsManager = getattr(orca, '_settingsManager')
applicationName = None
appScript = None
diff --git a/src/orca/gui_manager/__init__.py b/src/orca/baseplugins/__init__.py
similarity index 100%
rename from src/orca/gui_manager/__init__.py
rename to src/orca/baseplugins/__init__.py
diff --git a/src/orca/braille_generator.py b/src/orca/braille_generator.py
index 7778ce7..213e582 100644
--- a/src/orca/braille_generator.py
+++ b/src/orca/braille_generator.py
@@ -36,14 +36,7 @@ import settings
from orca_i18n import ngettext # for ngettext support
-if hasattr(orca, '_settingsManager'):
- _settingsManager = getattr(orca, '_settingsManager')
-else:
- from settings_manager import SettingsManager
- _settingsManager = SettingsManager()
- if _settingsManager is None:
- print "Could not load the settings manager. Exiting."
- sys.exit(1)
+_settingsManager = getattr(orca, '_settingsManager')
class Space:
"""A dummy class to indicate we want to insert a space into an
diff --git a/src/orca/chat.py b/src/orca/chat.py
index 2c0c723..b41513b 100644
--- a/src/orca/chat.py
+++ b/src/orca/chat.py
@@ -36,14 +36,7 @@ import speech
from orca_i18n import _
-if hasattr(orca, '_settingsManager'):
- _settingsManager = getattr(orca, '_settingsManager')
-else:
- from settings_manager import SettingsManager
- _settingsManager = SettingsManager()
- if _settingsManager is None:
- print "Could not load the settings manager. Exiting."
- sys.exit(1)
+_settingsManager = getattr(orca, '_settingsManager')
#############################################################################
# #
diff --git a/src/orca/default.py b/src/orca/default.py
new file mode 100644
index 0000000..3eecc9f
--- /dev/null
+++ b/src/orca/default.py
@@ -0,0 +1,5847 @@
+# Orca
+#
+# Copyright 2004-2009 Sun Microsystems Inc.
+# Copyright 2010 Joanmarie Diggs
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA 02110-1301 USA.
+
+"""The default Script for presenting information to the user using
+both speech and Braille. This is based primarily on the de-facto
+standard implementation of the AT-SPI, which is the GAIL support
+for GTK."""
+
+__id__ = "$Id$"
+__version__ = "$Revision$"
+__date__ = "$Date$"
+__copyright__ = "Copyright (c) 2004-2009 Sun Microsystems Inc." \
+ "Copyright (c) 2010 Joanmarie Diggs"
+__license__ = "LGPL"
+
+import locale
+import time
+
+import orca.orca as orca
+_settingsManager = getattr(orca, '_settingsManager')
+
+import pyatspi
+import orca.braille as braille
+import orca.debug as debug
+import orca.eventsynthesizer as eventsynthesizer
+import orca.find as find
+import orca.flat_review as flat_review
+import orca.input_event as input_event
+import orca.keybindings as keybindings
+try:
+ import orca.gsmag as mag
+except:
+ import orca.mag as mag
+import orca.outline as outline
+import orca.orca_state as orca_state
+import orca.phonnames as phonnames
+import orca.script as script
+import orca.settings as settings
+import orca.speech as speech
+import orca.speechserver as speechserver
+import orca.mouse_review as mouse_review
+import orca.text_attribute_names as text_attribute_names
+import orca.notification_messages as notification_messages
+
+from orca.orca_i18n import _ # for gettext support
+from orca.orca_i18n import ngettext # for ngettext support
+from orca.orca_i18n import C_ # to provide qualified translatable strings
+
+########################################################################
+# #
+# The Default script class. #
+# #
+########################################################################
+
+class Script(script.Script):
+
+ EMBEDDED_OBJECT_CHARACTER = u'\ufffc'
+ NO_BREAK_SPACE_CHARACTER = u'\u00a0'
+
+ # generatorCache
+ #
+ DISPLAYED_LABEL = 'displayedLabel'
+ DISPLAYED_TEXT = 'displayedText'
+ KEY_BINDING = 'keyBinding'
+ NESTING_LEVEL = 'nestingLevel'
+ NODE_LEVEL = 'nodeLevel'
+ REAL_ACTIVE_DESCENDANT = 'realActiveDescendant'
+
+ def __init__(self, app):
+ """Creates a new script for the given application.
+
+ Arguments:
+ - app: the application to create a script for.
+ """
+ script.Script.__init__(self, app)
+
+ self.flatReviewContext = None
+ self.windowActivateTime = None
+ self.lastReviewCurrentEvent = None
+ self.exitLearnModeKeyBinding = None
+ self.targetCursorCell = None
+
+ self.justEnteredFlatReviewMode = False
+
+ self.digits = '0123456789'
+ self.whitespace = ' \t\n\r\v\f'
+
+ # Used to determine whether the used double clicked on the
+ # "where am I" key.
+ #
+ self.lastWhereAmIEvent = None
+
+ # Used to determine whether the used double clicked on the
+ # "say all" key.
+ #
+ self.lastSayAllEvent = None
+
+ # Unicode currency symbols (populated by the
+ # getUnicodeCurrencySymbols() routine).
+ #
+ self._unicodeCurrencySymbols = []
+
+ # Used by the visualAppearanceChanged routine for updating whether
+ # progress bars are spoken.
+ #
+ self.lastProgressBarTime = {}
+ self.lastProgressBarValue = {}
+
+ self.lastSelectedMenu = None
+
+ # A dictionary of non-standardly-named text attributes and their
+ # Atk equivalents.
+ #
+ self.attributeNamesDict = {}
+
+ # Keep track of the last time we issued a mouse routing command
+ # so that we can guess if a change resulted from our moving the
+ # pointer.
+ #
+ self.lastMouseRoutingTime = None
+
+ # The last location of the mouse, which we might want if routing
+ # the pointer elsewhere.
+ #
+ self.oldMouseCoordinates = [0, 0]
+
+ def setupInputEventHandlers(self):
+ """Defines InputEventHandler fields for this script that can be
+ called by the key and braille bindings."""
+
+ self.inputEventHandlers["routePointerToItemHandler"] = \
+ input_event.InputEventHandler(
+ Script.routePointerToItem,
+ # Translators: this command will move the mouse pointer
+ # to the current item without clicking on it.
+ #
+ _("Routes the pointer to the current item."))
+
+ self.inputEventHandlers["leftClickReviewItemHandler"] = \
+ input_event.InputEventHandler(
+ Script.leftClickReviewItem,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. A left click means to generate
+ # a left mouse button click on the current item.
+ #
+ _("Performs left click on current flat review item."))
+
+ self.inputEventHandlers["rightClickReviewItemHandler"] = \
+ input_event.InputEventHandler(
+ Script.rightClickReviewItem,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. A right click means to generate
+ # a right mouse button click on the current item.
+ #
+ _("Performs right click on current flat review item."))
+
+ self.inputEventHandlers["sayAllHandler"] = \
+ input_event.InputEventHandler(
+ Script.sayAll,
+ # Translators: the Orca "SayAll" command allows the
+ # user to press a key and have the entire document in
+ # a window be automatically spoken to the user. If
+ # the user presses any key during a SayAll operation,
+ # the speech will be interrupted and the cursor will
+ # be positioned at the point where the speech was
+ # interrupted.
+ #
+ _("Speaks entire document."))
+
+ self.inputEventHandlers["whereAmIBasicHandler"] = \
+ input_event.InputEventHandler(
+ Script.whereAmIBasic,
+ # Translators: the "Where am I" feature of Orca allows
+ # a user to press a key and then have information
+ # about their current context spoken and brailled to
+ # them. For example, the information may include the
+ # name of the current pushbutton with focus as well as
+ # its mnemonic.
+ #
+ _("Performs the basic where am I operation."))
+
+ self.inputEventHandlers["whereAmIDetailedHandler"] = \
+ input_event.InputEventHandler(
+ Script.whereAmIDetailed,
+ # Translators: the "Where am I" feature of Orca allows
+ # a user to press a key and then have information
+ # about their current context spoken and brailled to
+ # them. For example, the information may include the
+ # name of the current pushbutton with focus as well as
+ # its mnemonic.
+ #
+ _("Performs the detailed where am I operation."))
+
+ # [[[WDW - I'd prefer to call this presentTitleHandler, but
+ # we're keeping it at getTitleHandler for backwards
+ # compatibility for people who have customized their key
+ # bindings.]]]
+ #
+ self.inputEventHandlers["getTitleHandler"] = \
+ input_event.InputEventHandler(
+ Script.presentTitle,
+ # Translators: This command will cause the window's
+ # title to be spoken.
+ #
+ _("Speaks the title bar."))
+
+ # [[[WDW - I'd prefer to call this presentStatusBarHandler,
+ # but we're keeping it at getStatusBarHandler for backwards
+ # compatibility for people who have customized their key
+ # bindings.]]]
+ #
+ self.inputEventHandlers["getStatusBarHandler"] = \
+ input_event.InputEventHandler(
+ Script.presentStatusBar,
+ # Translators: This command will cause the window's
+ # status bar contents to be spoken.
+ #
+ _("Speaks the status bar."))
+
+ self.inputEventHandlers["findHandler"] = \
+ input_event.InputEventHandler(
+ orca.showFindGUI,
+ # Translators: the Orca "Find" dialog allows a user to
+ # search for text in a window and then move focus to
+ # that text. For example, they may want to find the
+ # "OK" button.
+ #
+ _("Opens the Orca Find dialog."))
+
+ self.inputEventHandlers["findNextHandler"] = \
+ input_event.InputEventHandler(
+ Script.findNext,
+ # Translators: the Orca "Find" dialog allows a user to
+ # search for text in a window and then move focus to
+ # that text. For example, they may want to find the
+ # "OK" button. This string is used for finding the
+ # next occurence of a string.
+ #
+ _("Searches for the next instance of a string."))
+
+ self.inputEventHandlers["findPreviousHandler"] = \
+ input_event.InputEventHandler(
+ Script.findPrevious,
+ # Translators: the Orca "Find" dialog allows a user to
+ # search for text in a window and then move focus to
+ # that text. For example, they may want to find the
+ # "OK" button. This string is used for finding the
+ # previous occurence of a string.
+ #
+ _("Searches for the previous instance of a string."))
+
+ self.inputEventHandlers["showZonesHandler"] = \
+ input_event.InputEventHandler(
+ Script.showZones,
+ # Translators: this is a debug message that Orca users
+ # will not normally see. It describes a debug routine that
+ # paints rectangles around the interesting (e.g., text)
+ # zones in the active window for the application that
+ # currently has focus.
+ #
+ _("Paints and prints the visible zones in the active window."))
+
+ self.inputEventHandlers["toggleFlatReviewModeHandler"] = \
+ input_event.InputEventHandler(
+ Script.toggleFlatReviewMode,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}.
+ #
+ _("Enters and exits flat review mode."))
+
+ self.inputEventHandlers["reviewPreviousLineHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewPreviousLine,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}.
+ #
+ _("Moves flat review to the beginning of the previous line."))
+
+ self.inputEventHandlers["reviewHomeHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewHome,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. The home position is the
+ # beginning of the content in the window.
+ #
+ _("Moves flat review to the home position."))
+
+ self.inputEventHandlers["reviewCurrentLineHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewCurrentLine,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. This particular command will
+ # cause Orca to speak the current line.
+ #
+ _("Speaks the current flat review line."))
+
+ self.inputEventHandlers["reviewSpellCurrentLineHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewSpellCurrentLine,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. This particular command will
+ # cause Orca to spell the current line.
+ #
+ _("Spells the current flat review line."))
+
+ self.inputEventHandlers["reviewPhoneticCurrentLineHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewPhoneticCurrentLine,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. This particular command will
+ # cause Orca to "phonetically spell" the current line,
+ # saying "Alpha" for "a", "Bravo" for "b" and so on.
+ #
+ _("Phonetically spells the current flat review line."))
+
+ self.inputEventHandlers["reviewNextLineHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewNextLine,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}.
+ #
+ _("Moves flat review to the beginning of the next line."))
+
+ self.inputEventHandlers["reviewEndHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewEnd,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. The end position is the last
+ # bit of information in the window.
+ #
+ _("Moves flat review to the end position."))
+
+ self.inputEventHandlers["reviewPreviousItemHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewPreviousItem,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. Previous will go backwards
+ # in the window until you reach the top (i.e., it will
+ # wrap across lines if necessary).
+ #
+ _("Moves flat review to the previous item or word."))
+
+ self.inputEventHandlers["reviewAboveHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewAbove,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. Above in this case means
+ # geographically above, as if you drew a vertical line
+ # in the window.
+ #
+ _("Moves flat review to the word above the current word."))
+
+ self.inputEventHandlers["reviewCurrentItemHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewCurrentItem,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. This command will speak the
+ # current word or item.
+ #
+ _("Speaks the current flat review item or word."))
+
+ self.inputEventHandlers["reviewSpellCurrentItemHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewSpellCurrentItem,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. This command will spell out
+ # the current word or item letter by letter.
+ #
+ _("Spells the current flat review item or word."))
+
+ self.inputEventHandlers["reviewPhoneticCurrentItemHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewPhoneticCurrentItem,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. This command will spell out
+ # the current word or item phonetically, saying "Alpha"
+ # for "a", "Bravo" for "b" and so on.
+ #
+ _("Phonetically spells the current flat review item or word."))
+
+ self.inputEventHandlers["reviewCurrentAccessibleHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewCurrentAccessible,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. The flat review object is
+ # typically something like a pushbutton, a label, or
+ # some other GUI widget. The 'speaks' means it will
+ # speak the text associated with the object.
+ #
+ _("Speaks the current flat review object."))
+
+ self.inputEventHandlers["reviewNextItemHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewNextItem,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. Next will go forwards
+ # in the window until you reach the end (i.e., it will
+ # wrap across lines if necessary).
+ #
+ _("Moves flat review to the next item or word."))
+
+ self.inputEventHandlers["reviewBelowHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewBelow,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. Below in this case means
+ # geographically below, as if you drew a vertical line
+ # downward on the screen.
+ #
+ _("Moves flat review to the word below the current word."))
+
+ self.inputEventHandlers["reviewPreviousCharacterHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewPreviousCharacter,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. Previous will go backwards
+ # in the window until you reach the top (i.e., it will
+ # wrap across lines if necessary).
+ #
+ _("Moves flat review to the previous character."))
+
+ self.inputEventHandlers["reviewEndOfLineHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewEndOfLine,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}.
+ #
+ _("Moves flat review to the end of the line."))
+
+ self.inputEventHandlers["reviewCurrentCharacterHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewCurrentCharacter,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. Previous will go backwards
+ # in the window until you reach the top (i.e., it will
+ # wrap across lines if necessary). The 'speaks' in
+ # this case will be the spoken language form of the
+ # character currently being reviewed.
+ #
+ _("Speaks the current flat review character."))
+
+ self.inputEventHandlers["reviewSpellCurrentCharacterHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewSpellCurrentCharacter,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. Previous will go backwards
+ # in the window until you reach the top (i.e., it will
+ # wrap across lines if necessary). This command will
+ # cause Orca to speak a phonetic representation of the
+ # character currently being reviewed, saying "Alpha"
+ # for "a", "Bravo" for "b" and so on.
+ #
+ _("Phonetically speaks the current flat review character."))
+
+ self.inputEventHandlers["reviewUnicodeCurrentCharacterHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewUnicodeCurrentCharacter,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. Previous will go backwards
+ # in the window until you reach the top (i.e., it will
+ # wrap across lines if necessary). This command will
+ # cause Orca to speak information about the current character
+ # Like its unicode value and other relevant information
+ #
+ _("Speaks unicode value of the current flat review character."))
+
+
+ self.inputEventHandlers["reviewNextCharacterHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewNextCharacter,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. Next will go forwards
+ # in the window until you reach the end (i.e., it will
+ # wrap across lines if necessary).
+ #
+ _("Moves flat review to the next character."))
+
+ self.inputEventHandlers["toggleTableCellReadModeHandler"] = \
+ input_event.InputEventHandler(
+ Script.toggleTableCellReadMode,
+ # Translators: when users are navigating a table, they
+ # sometimes want the entire row of a table read, or
+ # they just want the current cell to be presented to them.
+ #
+ _("Toggles whether to read just the current table cell " \
+ "or the whole row."))
+
+ self.inputEventHandlers["readCharAttributesHandler"] = \
+ input_event.InputEventHandler(
+ Script.readCharAttributes,
+ # Translators: the attributes being presented are the
+ # text attributes, such as bold, italic, font name,
+ # font size, etc.
+ #
+ _("Reads the attributes associated with the current text " \
+ "character."))
+
+ self.inputEventHandlers["reportScriptInfoHandler"] = \
+ input_event.InputEventHandler(
+ Script.reportScriptInfo,
+ # Translators: this is a debug message that Orca users
+ # will not normally see. It describes a debug routine
+ # that outputs useful information on the current script
+ # via speech and braille. This information will be
+ # helpful to script writers.
+ #
+ _("Reports information on current script."))
+
+ self.inputEventHandlers["panBrailleLeftHandler"] = \
+ input_event.InputEventHandler(
+ Script.panBrailleLeft,
+ # Translators: a refreshable braille display is an
+ # external hardware device that presents braille
+ # character to the user. There are a limited number
+ # of cells on the display (typically 40 cells). Orca
+ # provides the feature to build up a longer logical
+ # line and allow the user to press buttons on the
+ # braille display so they can pan left and right over
+ # this line.
+ #
+ _("Pans the braille display to the left."),
+ False) # Do not enable learn mode for this action
+
+ self.inputEventHandlers["panBrailleRightHandler"] = \
+ input_event.InputEventHandler(
+ Script.panBrailleRight,
+ # Translators: a refreshable braille display is an
+ # external hardware device that presents braille
+ # character to the user. There are a limited number
+ # of cells on the display (typically 40 cells). Orca
+ # provides the feature to build up a longer logical
+ # line and allow the user to press buttons on the
+ # braille display so they can pan left and right over
+ # this line.
+ #
+ _("Pans the braille display to the right."),
+ False) # Do not enable learn mode for this action
+
+ self.inputEventHandlers["reviewBottomLeftHandler"] = \
+ input_event.InputEventHandler(
+ Script.reviewBottomLeft,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. The bottom left is the bottom
+ # left of the window currently being reviewed.
+ #
+ _("Moves flat review to the bottom left."))
+
+ self.inputEventHandlers["goBrailleHomeHandler"] = \
+ input_event.InputEventHandler(
+ Script.goBrailleHome,
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. Flat review is modal, and
+ # the user can be exploring the window without changing
+ # which object in the window which has focus. The
+ # feature used here will return the flat review to the
+ # object with focus.
+ #
+ _("Returns to object with keyboard focus."))
+
+ self.inputEventHandlers["contractedBrailleHandler"] = \
+ input_event.InputEventHandler(
+ Script.setContractedBraille,
+ # Translators: braille can be displayed in many ways.
+ # Contracted braille provides a more efficient means
+ # to represent text, especially long documents. The
+ # feature used here is an option to toggle between
+ # contracted and uncontracted.
+ #
+ _("Turns contracted braille on and off."))
+
+ self.inputEventHandlers["processRoutingKeyHandler"] = \
+ input_event.InputEventHandler(
+ Script.processRoutingKey,
+ # Translators: hardware braille displays often have
+ # buttons near each braille cell. These are called
+ # cursor routing keys and are a way for a user to
+ # tell the machine they are interested in a particular
+ # character on the display.
+ #
+ _("Processes a cursor routing key."))
+
+ self.inputEventHandlers["processBrailleCutBeginHandler"] = \
+ input_event.InputEventHandler(
+ Script.processBrailleCutBegin,
+ # Translators: this is used to indicate the start point
+ # of a text selection.
+ #
+ _("Marks the beginning of a text selection."))
+
+ self.inputEventHandlers["processBrailleCutLineHandler"] = \
+ input_event.InputEventHandler(
+ Script.processBrailleCutLine,
+ # Translators: this is used to indicate the end point
+ # of a text selection.
+ #
+ _("Marks the end of a text selection."))
+
+ self.inputEventHandlers["enterLearnModeHandler"] = \
+ input_event.InputEventHandler(
+ Script.enterLearnMode,
+ # Translators: Orca has a "Learn Mode" that will allow
+ # the user to type any key on the keyboard and hear what
+ # the effects of that key would be. The effects might
+ # be what Orca would do if it had a handler for the
+ # particular key combination, or they might just be to
+ # echo the name of the key if Orca doesn't have a handler.
+ #
+ _("Enters learn mode. Press escape to exit learn mode."))
+
+ self.inputEventHandlers["enterListShortcutsModeHandler"] = \
+ input_event.InputEventHandler(
+ Script.enterListShortcutsMode,
+ # Translators: Orca has a "List Shortcuts Mode" that will allow
+ # the user to list a group of keyboard shortcuts. The Orca
+ # default shortcuts can be listed by pressing 1, and Orca
+ # shortcuts for the application under focus can be listed by
+ # pressing 2. User can press Up/ Down to navigate and hear
+ # the list, changeover to another list by pressing 1/2,
+ # and exit the "List Shortcuts Mode" by pressing Escape.
+ #
+ _("Enters list shortcuts mode. Press escape to exit " \
+ "list shortcuts mode."),False)
+ # Do not enable learn mode for this action
+
+ self.inputEventHandlers["decreaseSpeechRateHandler"] = \
+ input_event.InputEventHandler(
+ speech.decreaseSpeechRate,
+ # Translators: the speech rate is how fast the speech
+ # synthesis engine will generate speech.
+ #
+ _("Decreases the speech rate."))
+
+ self.inputEventHandlers["increaseSpeechRateHandler"] = \
+ input_event.InputEventHandler(
+ speech.increaseSpeechRate,
+ # Translators: the speech rate is how fast the speech
+ # synthesis engine will generate speech.
+ #
+ _("Increases the speech rate."))
+
+ self.inputEventHandlers["decreaseSpeechPitchHandler"] = \
+ input_event.InputEventHandler(
+ speech.decreaseSpeechPitch,
+ # Translators: the speech pitch is how high or low in
+ # pitch/frequency the speech synthesis engine will
+ # generate speech.
+ #
+ _("Decreases the speech pitch."))
+
+ self.inputEventHandlers["increaseSpeechPitchHandler"] = \
+ input_event.InputEventHandler(
+ speech.increaseSpeechPitch,
+ # Translators: the speech pitch is how high or low in
+ # pitch/frequency the speech synthesis engine will
+ # generate speech.
+ #
+ _("Increases the speech pitch."))
+
+ self.inputEventHandlers["shutdownHandler"] = \
+ input_event.InputEventHandler(
+ orca.quitOrca,
+ _("Quits Orca"))
+
+ self.inputEventHandlers["preferencesSettingsHandler"] = \
+ input_event.InputEventHandler(
+ orca.showPreferencesGUI,
+ # Translators: the preferences configuration dialog is
+ # the dialog that allows users to set their preferences
+ # for Orca.
+ #
+ _("Displays the preferences configuration dialog."))
+
+ self.inputEventHandlers["appPreferencesSettingsHandler"] = \
+ input_event.InputEventHandler(
+ orca.showAppPreferencesGUI,
+ # Translators: the application preferences configuration
+ # dialog is the dialog that allows users to set their
+ # preferences for a specific application within Orca.
+ #
+ _("Displays the application preferences configuration dialog."))
+
+ self.inputEventHandlers["toggleSilenceSpeechHandler"] = \
+ input_event.InputEventHandler(
+ orca.toggleSilenceSpeech,
+ # Translators: Orca allows the user to turn speech synthesis
+ # on or off. We call it 'silencing'.
+ #
+ _("Toggles the silencing of speech."))
+
+ self.inputEventHandlers[ \
+ "toggleSpeakingIndentationJustificationHandler"] = \
+ input_event.InputEventHandler(
+ Script.toggleSpeakingIndentationJustification,
+ # Translators: Orca allows the user to enable/disable
+ # the speaking of indentation and justification.
+ #
+ _("Toggles the speaking of indentation and justification."))
+
+ self.inputEventHandlers["cycleSpeakingPunctuationLevelHandler"] = \
+ input_event.InputEventHandler(
+ Script.cycleSpeakingPunctuationLevel,
+ # Translators: Orca allows users to cycle through
+ # punctuation levels.
+ # None, some, most, or all, punctuation will be spoken.
+ #
+ _("Cycles to the next speaking of punctuation level."))
+
+ self.inputEventHandlers["cycleKeyEchoHandler"] = \
+ input_event.InputEventHandler(
+ Script.cycleKeyEcho,
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo.
+ # The following string refers to a command that allows the
+ # user to quickly choose which type of echo is being used.
+ #
+ _("Cycles to the next key echo level."))
+
+ self.inputEventHandlers["listAppsHandler"] = \
+ input_event.InputEventHandler(
+ Script.printAppsHandler,
+ # Translators: this is a debug message that Orca users
+ # will not normally see. It describes a debug routine
+ # that prints a list of all known applications currently
+ # running on the desktop, to stdout.
+ #
+ _("Prints a debug listing of all known applications to the " \
+ "console where Orca is running."))
+
+ self.inputEventHandlers["cycleDebugLevelHandler"] = \
+ input_event.InputEventHandler(
+ orca.cycleDebugLevel,
+ # Translators: this is a debug message that Orca users
+ # will not normally see. It describes a debug routine
+ # that allows the user to adjust the level of debug
+ # information that Orca generates at run time.
+ #
+ _("Cycles the debug level at run time."))
+
+ self.inputEventHandlers["printAncestryHandler"] = \
+ input_event.InputEventHandler(
+ Script.printAncestryHandler,
+ # Translators: this is a debug message that Orca users
+ # will not normally see. It describes a debug routine
+ # that will take the component in the currently running
+ # application that has focus, and print debug information
+ # to the console giving its component ancestry (i.e. all
+ # the components that are its descendants in the component
+ # tree).
+ #
+ _("Prints debug information about the ancestry of the object " \
+ "with focus."))
+
+ self.inputEventHandlers["printHierarchyHandler"] = \
+ input_event.InputEventHandler(
+ Script.printHierarchyHandler,
+ # Translators: this is a debug message that Orca users
+ # will not normally see. It describes a debug routine
+ # that will take the currently running application, and
+ # print debug information to the console giving its
+ # component hierarchy (i.e. all the components and all
+ # their descendants in the component tree).
+ #
+ _("Prints debug information about the application with focus."))
+
+ self.inputEventHandlers["printMemoryUsageHandler"] = \
+ input_event.InputEventHandler(
+ Script.printMemoryUsageHandler,
+ # Translators: this is a debug message that Orca users
+ # will not normally see. It describes a debug routine
+ # that will print Orca memory usage information.
+ #
+ _("Prints memory usage information."))
+
+ self.inputEventHandlers["bookmarkCurrentWhereAmI"] = \
+ input_event.InputEventHandler(
+ Script.bookmarkCurrentWhereAmI,
+ # Translators: this command announces information regarding
+ # the relationship of the given bookmark to the current
+ # position
+ #
+ _("Bookmark where am I with respect to current position."))
+
+ self.inputEventHandlers["goToBookmark"] = \
+ input_event.InputEventHandler(
+ Script.goToBookmark,
+ # Translators: this command moves the current position to the
+ # location stored at the bookmark.
+ #
+ _("Go to bookmark."))
+
+ self.inputEventHandlers["addBookmark"] = \
+ input_event.InputEventHandler(
+ Script.addBookmark,
+ # Translators: this event handler binds an in-page accessible
+ # object location to the given input key command.
+ #
+ _("Add bookmark."))
+
+ self.inputEventHandlers["saveBookmarks"] = \
+ input_event.InputEventHandler(
+ Script.saveBookmarks,
+ # Translators: this event handler saves all bookmarks for the
+ # current application to disk.
+ #
+ _("Save bookmarks."))
+
+ self.inputEventHandlers["goToNextBookmark"] = \
+ input_event.InputEventHandler(
+ Script.goToNextBookmark,
+ # Translators: this event handler cycles through the registered
+ # bookmarks and takes the user to the next bookmark location.
+ #
+ _("Go to next bookmark location."))
+
+ self.inputEventHandlers["goToPrevBookmark"] = \
+ input_event.InputEventHandler(
+ Script.goToPrevBookmark,
+ # Translators: this event handler cycles through the
+ # registered bookmarks and takes the user to the previous
+ # bookmark location.
+ #
+ _("Go to previous bookmark location."))
+
+ self.inputEventHandlers["toggleColorEnhancementsHandler"] = \
+ input_event.InputEventHandler(
+ mag.toggleColorEnhancements,
+ # Translators: "color enhancements" are changes users can
+ # make to the appearance of the screen to make things easier
+ # to see, such as inverting the colors or applying a tint.
+ # This command toggles these enhancements on/off.
+ #
+ _("Toggles color enhancements."))
+
+ self.inputEventHandlers["toggleMouseEnhancementsHandler"] = \
+ input_event.InputEventHandler(
+ mag.toggleMouseEnhancements,
+ # Translators: "mouse enhancements" are changes users can
+ # make to the appearance of the mouse pointer to make it
+ # easier to see, such as increasing its size, changing its
+ # color, and surrounding it with crosshairs. This command
+ # toggles these enhancements on/off.
+ #
+ _("Toggles mouse enhancements."))
+
+ self.inputEventHandlers["increaseMagnificationHandler"] = \
+ input_event.InputEventHandler(
+ mag.increaseMagnification,
+ # Translators: this command increases the magnification
+ # level.
+ #
+ _("Increases the magnification level."))
+
+ self.inputEventHandlers["decreaseMagnificationHandler"] = \
+ input_event.InputEventHandler(
+ mag.decreaseMagnification,
+ # Translators: this command decreases the magnification
+ # level.
+ #
+ _("Decreases the magnification level."))
+
+ self.inputEventHandlers["toggleMagnifierHandler"] = \
+ input_event.InputEventHandler(
+ mag.toggleMagnifier,
+ # Translators: Orca allows the user to turn the magnifier
+ # on or off. This command not only toggles magnification,
+ # but also all of the color and pointer customizations
+ # made through the magnifier.
+ #
+ _("Toggles the magnifier."))
+
+ self.inputEventHandlers["cycleZoomerTypeHandler"] = \
+ input_event.InputEventHandler(
+ mag.cycleZoomerType,
+ # Translators: the user can choose between several different
+ # types of magnification, including full screen and split
+ # screen. The "position" here refers to location of the
+ # magnifier.
+ #
+ _("Cycles to the next magnifier position."))
+
+ self.inputEventHandlers["toggleMouseReviewHandler"] = \
+ input_event.InputEventHandler(
+ mouse_review.toggle,
+ # Translators: Orca allows the item under the pointer to
+ # be spoken. This toggles the feature.
+ #
+ _("Toggle mouse review mode."))
+
+ self.inputEventHandlers["presentTimeHandler"] = \
+ input_event.InputEventHandler(
+ Script.presentTime,
+ # Translators: Orca can present the current time to the
+ # user when the user presses
+ # a shortcut key.
+ #
+ _("Present current time."))
+
+ self.inputEventHandlers["presentDateHandler"] = \
+ input_event.InputEventHandler(
+ Script.presentDate,
+ # Translators: Orca can present the current date to the
+ # user when the user presses
+ # a shortcut key.
+ #
+ _("Present current date."))
+
+ self.inputEventHandlers["bypassNextCommandHandler"] = \
+ input_event.InputEventHandler(
+ Script.bypassNextCommand,
+ # Translators: Orca normally intercepts all keyboard
+ # commands and only passes them along to the current
+ # application when they are not Orca commands. This
+ # command causes the next command issued to be passed
+ # along to the current application, bypassing Orca's
+ # interception of it.
+ #
+ _("Passes the next command on to the current application."))
+
+ self.inputEventHandlers.update(notification_messages.inputEventHandlers)
+
+ def getInputEventHandlerKey(self, inputEventHandler):
+ """Returns the name of the key that contains an inputEventHadler
+ passed as argument
+ """
+
+ for keyName, handler in self.inputEventHandlers.iteritems():
+ if handler == inputEventHandler:
+ return keyName
+
+ return None
+
+ def getListeners(self):
+ """Sets up the AT-SPI event listeners for this script.
+ """
+ listeners = script.Script.getListeners(self)
+ listeners["focus:"] = \
+ self.onFocus
+ #listeners["keyboard:modifiers"] = \
+ # self.noOp
+ listeners["mouse:button"] = \
+ self.onMouseButton
+ listeners["object:property-change:accessible-name"] = \
+ self.onNameChanged
+ listeners["object:text-caret-moved"] = \
+ self.onCaretMoved
+ listeners["object:text-changed:delete"] = \
+ self.onTextDeleted
+ listeners["object:text-changed:insert"] = \
+ self.onTextInserted
+ listeners["object:active-descendant-changed"] = \
+ self.onActiveDescendantChanged
+ listeners["object:link-selected"] = \
+ self.onLinkSelected
+ listeners["object:state-changed:active"] = \
+ self.onStateChanged
+ listeners["object:state-changed:focused"] = \
+ self.onStateChanged
+ listeners["object:state-changed:showing"] = \
+ self.onStateChanged
+ listeners["object:state-changed:checked"] = \
+ self.onStateChanged
+ listeners["object:state-changed:pressed"] = \
+ self.onStateChanged
+ listeners["object:state-changed:indeterminate"] = \
+ self.onStateChanged
+ listeners["object:state-changed:expanded"] = \
+ self.onStateChanged
+ listeners["object:state-changed:selected"] = \
+ self.onStateChanged
+ listeners["object:text-attributes-changed"] = \
+ self.onTextAttributesChanged
+ listeners["object:text-selection-changed"] = \
+ self.onTextSelectionChanged
+ listeners["object:selection-changed"] = \
+ self.onSelectionChanged
+ listeners["object:property-change:accessible-value"] = \
+ self.onValueChanged
+ listeners["object:value-changed"] = \
+ self.onValueChanged
+ listeners["window:activate"] = \
+ self.onWindowActivated
+ listeners["window:deactivate"] = \
+ self.onWindowDeactivated
+ listeners["window:create"] = \
+ self.noOp
+
+ return listeners
+
+ def __getDesktopBindings(self):
+ """Returns an instance of keybindings.KeyBindings that use the
+ numeric keypad for focus tracking and flat review.
+ """
+
+ import orca.desktop_keyboardmap as desktop_keyboardmap
+ keyBindings = keybindings.KeyBindings()
+ keyBindings.load(desktop_keyboardmap.keymap, self.inputEventHandlers)
+ return keyBindings
+
+ def __getLaptopBindings(self):
+ """Returns an instance of keybindings.KeyBindings that use the
+ the main keyboard keys for focus tracking and flat review.
+ """
+
+ import orca.laptop_keyboardmap as laptop_keyboardmap
+ keyBindings = keybindings.KeyBindings()
+ keyBindings.load(laptop_keyboardmap.keymap, self.inputEventHandlers)
+ return keyBindings
+
+ def getKeyBindings(self):
+ """Defines the key bindings for this script.
+
+ Returns an instance of keybindings.KeyBindings.
+ """
+
+ keyBindings = script.Script.getKeyBindings(self)
+
+ layout = _settingsManager.getSetting('keyboardLayout')
+ if layout == settings.GENERAL_KEYBOARD_LAYOUT_DESKTOP:
+ for keyBinding in self.__getDesktopBindings().keyBindings:
+ keyBindings.add(keyBinding)
+ else:
+ for keyBinding in self.__getLaptopBindings().keyBindings:
+ keyBindings.add(keyBinding)
+
+ import orca.common_keyboardmap as common_keyboardmap
+ keyBindings.load(common_keyboardmap.keymap, self.inputEventHandlers)
+
+ if _settingsManager.getSetting('debugMemoryUsage'):
+ keyBindings.add(
+ keybindings.KeyBinding(
+ "",
+ settings.defaultModifierMask,
+ settings.NO_MODIFIER_MASK,
+ self.inputEventHandlers["printMemoryUsageHandler"]))
+
+ try:
+ keyBindings = settings.overrideKeyBindings(self, keyBindings)
+ except:
+ debug.println(debug.LEVEL_WARNING,
+ "WARNING: problem overriding keybindings:")
+ debug.printException(debug.LEVEL_WARNING)
+
+ return keyBindings
+
+ def getBrailleBindings(self):
+ """Defines the braille bindings for this script.
+
+ Returns a dictionary where the keys are BrlTTY commands and the
+ values are InputEventHandler instances.
+ """
+ brailleBindings = script.Script.getBrailleBindings(self)
+ try:
+ brailleBindings[braille.brlapi.KEY_CMD_FWINLT] = \
+ self.inputEventHandlers["panBrailleLeftHandler"]
+ brailleBindings[braille.brlapi.KEY_CMD_FWINRT] = \
+ self.inputEventHandlers["panBrailleRightHandler"]
+ brailleBindings[braille.brlapi.KEY_CMD_LNUP] = \
+ self.inputEventHandlers["reviewAboveHandler"]
+ brailleBindings[braille.brlapi.KEY_CMD_LNDN] = \
+ self.inputEventHandlers["reviewBelowHandler"]
+ brailleBindings[braille.brlapi.KEY_CMD_FREEZE] = \
+ self.inputEventHandlers["toggleFlatReviewModeHandler"]
+ brailleBindings[braille.brlapi.KEY_CMD_TOP_LEFT] = \
+ self.inputEventHandlers["reviewHomeHandler"]
+ brailleBindings[braille.brlapi.KEY_CMD_BOT_LEFT] = \
+ self.inputEventHandlers["reviewBottomLeftHandler"]
+ brailleBindings[braille.brlapi.KEY_CMD_HOME] = \
+ self.inputEventHandlers["goBrailleHomeHandler"]
+ brailleBindings[braille.brlapi.KEY_CMD_SIXDOTS] = \
+ self.inputEventHandlers["contractedBrailleHandler"]
+ brailleBindings[braille.brlapi.KEY_CMD_ROUTE] = \
+ self.inputEventHandlers["processRoutingKeyHandler"]
+ brailleBindings[braille.brlapi.KEY_CMD_CUTBEGIN] = \
+ self.inputEventHandlers["processBrailleCutBeginHandler"]
+ brailleBindings[braille.brlapi.KEY_CMD_CUTLINE] = \
+ self.inputEventHandlers["processBrailleCutLineHandler"]
+ except:
+ debug.println(debug.LEVEL_CONFIGURATION,
+ "WARNING: braille bindings unavailable:")
+ debug.printException(debug.LEVEL_CONFIGURATION)
+ return brailleBindings
+
+ def processKeyboardEvent(self, keyboardEvent):
+ """Processes the given keyboard event. It uses the super
+ class equivalent to do most of the work. The only thing done here
+ is to detect when the user is trying to get out of learn mode.
+
+ Arguments:
+ - keyboardEvent: an instance of input_event.KeyboardEvent
+ """
+
+ return script.Script.processKeyboardEvent(self, keyboardEvent)
+
+ def locusOfFocusChanged(self, event, oldLocusOfFocus, newLocusOfFocus):
+ """Called when the visual object with focus changes.
+
+ Arguments:
+ - event: if not None, the Event that caused the change
+ - oldLocusOfFocus: Accessible that is the old locus of focus
+ - newLocusOfFocus: Accessible that is the new locus of focus
+ """
+
+ if newLocusOfFocus \
+ and newLocusOfFocus.getState().contains(pyatspi.STATE_DEFUNCT):
+ return
+
+ try:
+ if self.findCommandRun:
+ # Then the Orca Find dialog has just given up focus
+ # to the original window. We don't want to speak
+ # the window title, current line, etc.
+ return
+ except:
+ pass
+
+ if newLocusOfFocus:
+ mag.magnifyAccessible(event, newLocusOfFocus)
+
+ # We always automatically go back to focus tracking mode when
+ # the focus changes.
+ #
+ if self.flatReviewContext:
+ self.toggleFlatReviewMode()
+
+ # [[[TODO: WDW - HACK because parents that manage their descendants
+ # can give us a different object each time we ask for the same
+ # exact child. So...we do a check here to see if the old object
+ # and new object have the same index in the parent and if they
+ # have the same name. If so, then they are likely to be the same
+ # object. The reason we check for the name here is a small sanity
+ # check. This whole algorithm could fail because one might be
+ # deleting/adding identical elements from/to a list or table, thus
+ # the objects really could be different even though they seem the
+ # same. Logged as bug 319675.]]]
+ #
+ if self.utilities.isSameObject(oldLocusOfFocus, newLocusOfFocus):
+ return
+
+ # Well...now that we got that behind us, let's do what we're supposed
+ # to do.
+ #
+ if oldLocusOfFocus:
+ oldParent = oldLocusOfFocus.parent
+ else:
+ oldParent = None
+
+ if newLocusOfFocus:
+ newParent = newLocusOfFocus.parent
+ else:
+ newParent = None
+
+ # Clear the point of reference.
+ # If the point of reference is a cell, we want to keep the
+ # table-related points of reference.
+ #
+ if oldParent is not None and oldParent == newParent and \
+ newParent.getRole() in [pyatspi.ROLE_TABLE,
+ pyatspi.ROLE_TREE_TABLE]:
+ for key in self.pointOfReference.keys():
+ if key not in ('lastRow', 'lastColumn'):
+ del self.pointOfReference[key]
+ else:
+ self.pointOfReference = {}
+
+ if newLocusOfFocus:
+ self.updateBraille(newLocusOfFocus)
+
+ # Check to see if we are in the Pronunciation Dictionary in the
+ # Orca Preferences dialog. If so, then we do not want to use the
+ # pronunciation dictionary to replace the actual words in the
+ # first column of this table.
+ #
+ # [[[TODO: WDW - this should be pushed into script_utilities'
+ # adjustForPronunciation method.]]]
+ #
+ rolesList = [pyatspi.ROLE_TABLE_CELL, \
+ pyatspi.ROLE_TABLE, \
+ pyatspi.ROLE_SCROLL_PANE, \
+ pyatspi.ROLE_PANEL, \
+ pyatspi.ROLE_PANEL]
+ if self.utilities.hasMatchingHierarchy(newLocusOfFocus, rolesList) \
+ and newLocusOfFocus.getApplication().name == "orca":
+ orca_state.usePronunciationDictionary = False
+ else:
+ orca_state.usePronunciationDictionary = True
+
+ # We might be automatically speaking the unbound labels
+ # in a dialog box as the result of the dialog box suddenly
+ # appearing. If so, don't interrupt this because of a
+ # focus event that occurs when something like the "OK"
+ # button gets focus shortly after the window appears.
+ #
+ shouldNotInterrupt = (event and event.type.startswith("focus:")) \
+ and self.windowActivateTime \
+ and ((time.time() - self.windowActivateTime) < 1.0)
+
+ # [[[TODO: WDW - this should move to the generator.]]]
+ #
+ if newLocusOfFocus.getRole() == pyatspi.ROLE_LINK:
+ voice = self.voices[settings.HYPERLINK_VOICE]
+ else:
+ voice = self.voices[settings.DEFAULT_VOICE]
+
+ utterances = self.speechGenerator.generateSpeech(
+ newLocusOfFocus,
+ priorObj=oldLocusOfFocus)
+ speech.speak(utterances, voice, not shouldNotInterrupt)
+
+ # If this is a table cell, save the current row and column
+ # information in the table cell's table, so that we can use
+ # it the next time.
+ #
+ if newLocusOfFocus.getRole() == pyatspi.ROLE_TABLE_CELL:
+ try:
+ table = newParent.queryTable()
+ except:
+ pass
+ else:
+ index = self.utilities.cellIndex(newLocusOfFocus)
+ column = table.getColumnAtIndex(index)
+ self.pointOfReference['lastColumn'] = column
+ row = table.getRowAtIndex(index)
+ self.pointOfReference['lastRow'] = row
+ else:
+ orca_state.noFocusTimeStamp = time.time()
+
+ def visualAppearanceChanged(self, event, obj):
+ """Called when the visual appearance of an object changes. This
+ method should not be called for objects whose visual appearance
+ changes solely because of focus -- setLocusOfFocus is used for that.
+ Instead, it is intended mostly for objects whose notional 'value' has
+ changed, such as a checkbox changing state, a progress bar advancing,
+ a slider moving, text inserted, caret moved, etc.
+
+ Arguments:
+ - event: if not None, the Event that caused this to happen
+ - obj: the Accessible whose visual appearance changed.
+ """
+ # Check if this event is for a progress bar.
+ #
+ if obj.getRole() == pyatspi.ROLE_PROGRESS_BAR:
+ self.handleProgressBarUpdate(event, obj)
+
+ if self.flatReviewContext:
+ if self.utilities.isSameObject(
+ obj,
+ self.flatReviewContext.getCurrentAccessible()):
+ self.updateBrailleReview()
+ return
+
+ # If this object is CONTROLLED_BY the object that currently
+ # has focus, speak/braille this object.
+ #
+ relations = obj.getRelationSet()
+ for relation in relations:
+ if relation.getRelationType() \
+ == pyatspi.RELATION_CONTROLLED_BY:
+ target = relation.getTarget(0)
+ if target == orca_state.locusOfFocus:
+ self.updateBraille(target)
+ utterances = self.speechGenerator.generateSpeech(
+ target, alreadyFocused=True)
+ utterances.extend(self.tutorialGenerator.getTutorial(
+ target, True))
+ speech.speak(utterances)
+ return
+
+ # If this object is a label, and if it has a LABEL_FOR relation
+ # to the focused object, then we should speak/braille the
+ # focused object, as if it had just got focus.
+ #
+ if obj.getRole() == pyatspi.ROLE_LABEL \
+ and obj.getState().contains(pyatspi.STATE_SHOWING):
+ for relation in relations:
+ if relation.getRelationType() \
+ == pyatspi.RELATION_LABEL_FOR:
+ target = relation.getTarget(0)
+ if target == orca_state.locusOfFocus:
+ self.updateBraille(target)
+ utterances = self.speechGenerator.generateSpeech(
+ target, alreadyFocused=True)
+ utterances.extend(self.tutorialGenerator.getTutorial(
+ target, True))
+ speech.speak(utterances)
+ return
+
+ if not self.utilities.isSameObject(obj, orca_state.locusOfFocus):
+ return
+
+ # Radio buttons normally change their state when you arrow to them,
+ # so we handle the announcement of their state changes in the focus
+ # handling code. However, we do need to handle radio buttons where
+ # the user needs to press the space key so select them. We see this
+ # in the disk selection area of the OpenSolaris gui-install application
+ # for example.
+ #
+ if obj.getRole() == pyatspi.ROLE_RADIO_BUTTON:
+ eventStr, mods = self.utilities.lastKeyAndModifiers()
+ if not eventStr in [" ", "space"]:
+ return
+
+ if event:
+ debug.println(debug.LEVEL_FINE,
+ "VISUAL CHANGE: '%s' '%s' (event='%s')" \
+ % (obj.name, obj.getRole(), event.type))
+ else:
+ debug.println(debug.LEVEL_FINE,
+ "VISUAL CHANGE: '%s' '%s' (event=None)" \
+ % (obj.name, obj.getRole()))
+
+ mag.magnifyAccessible(event, obj)
+ self.updateBraille(obj)
+ utterances = self.speechGenerator.generateSpeech(
+ obj, alreadyFocused=True)
+ utterances.extend(self.tutorialGenerator.getTutorial(obj, True))
+ speech.speak(utterances)
+
+ def activate(self):
+ """Called when this script is activated."""
+
+ braille.setupKeyRanges(self.brailleBindings.keys())
+
+ def updateBraille(self, obj, extraRegion=None):
+ """Updates the braille display to show the give object.
+
+ Arguments:
+ - obj: the Accessible
+ - extra: extra Region to add to the end
+ """
+
+ if not obj:
+ return
+
+ self.clearBraille()
+
+ line = self.getNewBrailleLine()
+ braille.addLine(line)
+
+ # For multiline text areas, we only show the context if we
+ # are on the very first line. Otherwise, we show only the
+ # line.
+ #
+ try:
+ text = obj.queryText()
+ except NotImplementedError:
+ text = None
+
+ result = self.brailleGenerator.generateBraille(obj)
+ self.addBrailleRegionsToLine(result[0], line)
+
+ if extraRegion:
+ self.addBrailleRegionToLine(extraRegion, line)
+
+ if extraRegion:
+ self.setBrailleFocus(extraRegion)
+ else:
+ self.setBrailleFocus(result[1])
+
+ self.refreshBraille(True)
+
+ ########################################################################
+ # #
+ # INPUT EVENT HANDLERS (AKA ORCA COMMANDS) #
+ # #
+ ########################################################################
+
+ def bypassNextCommand(self, inputEvent=None):
+ """Causes the next keyboard command to be ignored by Orca
+ and passed along to the current application.
+
+ Returns True to indicate the input event has been consumed.
+ """
+
+ # Translators: Orca normally intercepts all keyboard
+ # commands and only passes them along to the current
+ # application when they are not Orca commands. This
+ # command causes the next command issued to be passed
+ # along to the current application, bypassing Orca's
+ # interception of it.
+ #
+ self.presentMessage(_("Bypass mode enabled."))
+ orca_state.bypassNextCommand = True
+ return True
+
+ def enterLearnMode(self, inputEvent=None):
+ """Turns learn mode on. The user must press the escape key to exit
+ learn mode.
+
+ Returns True to indicate the input event has been consumed.
+ """
+
+ if _settingsManager.getSetting('learnModeEnabled'):
+ return True
+
+ self.speakMessage(
+ # Translators: Orca has a "Learn Mode" that will allow
+ # the user to type any key on the keyboard and hear what
+ # the effects of that key would be. The effects might
+ # be what Orca would do if it had a handler for the
+ # particular key combination, or they might just be to
+ # echo the name of the key if Orca doesn't have a handler.
+ # This text here is what is spoken to the user.
+ #
+ _("Entering learn mode. Press any key to hear its function. " \
+ "To exit learn mode, press the escape key."))
+
+ # Translators: Orca has a "Learn Mode" that will allow
+ # the user to type any key on the keyboard and hear what
+ # the effects of that key would be. The effects might
+ # be what Orca would do if it had a handler for the
+ # particular key combination, or they might just be to
+ # echo the name of the key if Orca doesn't have a handler.
+ # This text here is what is to be presented on the braille
+ # display.
+ #
+ self.displayBrailleMessage(_("Learn mode. Press escape to exit."))
+ _settingsManager.setSetting('learnModeEnabled', True)
+ return True
+
+ def enterListShortcutsMode(self, inputEvent):
+ """Turns list shortcuts mode on. The user must press the escape key to
+ exit list shortcuts mode. Key bindings for learn mode & list shortcuts
+ mode are Orca+H & Orca+H(double click) respectively. So, while enabling
+ list shortcuts mode, learn mode is enabled as a side effect. We start by
+ disabling it.
+
+ Returns True to indicate the input event has been consumed.
+ """
+ _settingsManager.setSetting('learnModeEnabled', False)
+ if _settingsManager.getSetting('listShortcutsModeEnabled'):
+ return True
+
+ # Translators: Orca has a 'List Shortcuts' mode by which a user can
+ # navigate through a list of the bound commands in Orca. This is the
+ # message that is presented to the user as confirmation that this
+ # mode has been entered.
+ #
+ mode = _("List shortcuts mode.")
+
+ # Translators: Orca has a 'List Shortcuts' mode by which a user can
+ # navigate through a list of the bound commands in Orca. Pressing 1
+ # presents the commands/shortcuts available for all applications.
+ # These are the "default" commands/shortcuts. Pressing 2 presents
+ # commands/shortcuts Orca provides for the application with focus.
+ # The following message is presented to the user upon entering this
+ # mode.
+ #
+ message = _("Press 1 for Orca's default shortcuts. Press 2 for " \
+ "Orca's shortcuts for the current application. " \
+ "Press escape to exit.")
+
+ message = mode + " " + message
+ self.speakMessage(message)
+ self.displayBrailleMessage(message, -1, -1)
+ _settingsManager.setSetting('listShortcutsModeEnabled', True)
+ return True
+
+ def findNext(self, inputEvent):
+ """Searches forward for the next instance of the string
+ searched for via the Orca Find dialog. Other than direction
+ and the starting point, the search options initially specified
+ (case sensitivity, window wrap, and full/partial match) are
+ preserved.
+ """
+
+ lastQuery = find.getLastQuery()
+ if lastQuery:
+ lastQuery.searchBackwards = False
+ lastQuery.startAtTop = False
+ self.find(lastQuery)
+ else:
+ orca.showFindGUI()
+
+ def findPrevious(self, inputEvent):
+ """Searches backwards for the next instance of the string
+ searched for via the Orca Find dialog. Other than direction
+ and the starting point, the search options initially specified
+ (case sensitivity, window wrap, and full/or partial match) are
+ preserved.
+ """
+
+ lastQuery = find.getLastQuery()
+ if lastQuery:
+ lastQuery.searchBackwards = True
+ lastQuery.startAtTop = False
+ self.find(lastQuery)
+ else:
+ orca.showFindGUI()
+
+ def addBookmark(self, inputEvent):
+ """ Add an in-page accessible object bookmark for this key.
+ Delegates to Bookmark.addBookmark """
+ bookmarks = self.getBookmarks()
+ bookmarks.addBookmark(inputEvent)
+
+ def bookmarkCurrentWhereAmI(self, inputEvent):
+ """ Report "Where am I" information for this bookmark relative to the
+ current pointer location. Delegates to
+ Bookmark.bookmarkCurrentWhereAmI"""
+ bookmarks = self.getBookmarks()
+ bookmarks.bookmarkCurrentWhereAmI(inputEvent)
+
+ def goToBookmark(self, inputEvent):
+ """ Go to the bookmark indexed by inputEvent.hw_code. Delegates to
+ Bookmark.goToBookmark """
+ bookmarks = self.getBookmarks()
+ bookmarks.goToBookmark(inputEvent)
+
+ def goToNextBookmark(self, inputEvent):
+ """ Go to the next bookmark location. If no bookmark has yet to be
+ selected, the first bookmark will be used. Delegates to
+ Bookmark.goToNextBookmark """
+ bookmarks = self.getBookmarks()
+ bookmarks.goToNextBookmark(inputEvent)
+
+ def goToPrevBookmark(self, inputEvent):
+ """ Go to the previous bookmark location. If no bookmark has yet to
+ be selected, the first bookmark will be used. Delegates to
+ Bookmark.goToPrevBookmark """
+ bookmarks = self.getBookmarks()
+ bookmarks.goToPrevBookmark(inputEvent)
+
+ def saveBookmarks(self, inputEvent):
+ """ Save the bookmarks for this script. Delegates to
+ Bookmark.saveBookmarks """
+ bookmarks = self.getBookmarks()
+ bookmarks.saveBookmarks(inputEvent)
+
+ def panBrailleLeft(self, inputEvent=None, panAmount=0):
+ """Pans the braille display to the left. If panAmount is non-zero,
+ the display is panned by that many cells. If it is 0, the display
+ is panned one full display width. In flat review mode, panning
+ beyond the beginning will take you to the end of the previous line.
+
+ In focus tracking mode, the cursor stays at its logical position.
+ In flat review mode, the review cursor moves to character
+ associated with cell 0."""
+
+ if self.flatReviewContext:
+ if self.isBrailleBeginningShowing():
+ self.flatReviewContext.goBegin(flat_review.Context.LINE)
+ self.reviewPreviousCharacter(inputEvent)
+ else:
+ self.panBrailleInDirection(panAmount, panToLeft=True)
+
+ # This will update our target cursor cell
+ #
+ self._setFlatReviewContextToBeginningOfBrailleDisplay()
+
+ [charString, x, y, width, height] = \
+ self.flatReviewContext.getCurrent(flat_review.Context.CHAR)
+ self.drawOutline(x, y, width, height)
+
+ self.targetCursorCell = 1
+ self.updateBrailleReview(self.targetCursorCell)
+ elif self.isBrailleBeginningShowing() and orca_state.locusOfFocus \
+ and self.utilities.isTextArea(orca_state.locusOfFocus):
+
+ # If we're at the beginning of a line of a multiline text
+ # area, then force it's caret to the end of the previous
+ # line. The assumption here is that we're currently
+ # viewing the line that has the caret -- which is a pretty
+ # good assumption for focus tacking mode. When we set the
+ # caret position, we will get a caret event, which will
+ # then update the braille.
+ #
+ text = orca_state.locusOfFocus.queryText()
+ [lineString, startOffset, endOffset] = text.getTextAtOffset(
+ text.caretOffset,
+ pyatspi.TEXT_BOUNDARY_LINE_START)
+ movedCaret = False
+ if startOffset > 0:
+ movedCaret = text.setCaretOffset(startOffset - 1)
+
+ # If we didn't move the caret and we're in a terminal, we
+ # jump into flat review to review the text. See
+ # http://bugzilla.gnome.org/show_bug.cgi?id=482294.
+ #
+ if (not movedCaret) \
+ and (orca_state.locusOfFocus.getRole() \
+ == pyatspi.ROLE_TERMINAL):
+ context = self.getFlatReviewContext()
+ context.goBegin(flat_review.Context.LINE)
+ self.reviewPreviousCharacter(inputEvent)
+ else:
+ self.panBrailleInDirection(panAmount, panToLeft=True)
+ # We might be panning through a flashed message.
+ #
+ braille.resetFlashTimer()
+ self.refreshBraille(False, stopFlash=False)
+
+ return True
+
+ def panBrailleLeftOneChar(self, inputEvent=None):
+ """Nudges the braille display one character to the left.
+
+ In focus tracking mode, the cursor stays at its logical position.
+ In flat review mode, the review cursor moves to character
+ associated with cell 0."""
+
+ self.panBrailleLeft(inputEvent, 1)
+
+ def panBrailleRight(self, inputEvent=None, panAmount=0):
+ """Pans the braille display to the right. If panAmount is non-zero,
+ the display is panned by that many cells. If it is 0, the display
+ is panned one full display width. In flat review mode, panning
+ beyond the end will take you to the begininng of the next line.
+
+ In focus tracking mode, the cursor stays at its logical position.
+ In flat review mode, the review cursor moves to character
+ associated with cell 0."""
+
+ if self.flatReviewContext:
+ if self.isBrailleEndShowing():
+ self.flatReviewContext.goEnd(flat_review.Context.LINE)
+ self.reviewNextCharacter(inputEvent)
+ else:
+ self.panBrailleInDirection(panAmount, panToLeft=False)
+
+ # This will update our target cursor cell
+ #
+ self._setFlatReviewContextToBeginningOfBrailleDisplay()
+
+ [charString, x, y, width, height] = \
+ self.flatReviewContext.getCurrent(flat_review.Context.CHAR)
+
+ self.drawOutline(x, y, width, height)
+
+ self.targetCursorCell = 1
+ self.updateBrailleReview(self.targetCursorCell)
+ elif self.isBrailleEndShowing() and orca_state.locusOfFocus \
+ and self.utilities.isTextArea(orca_state.locusOfFocus):
+ # If we're at the end of a line of a multiline text area, then
+ # force it's caret to the beginning of the next line. The
+ # assumption here is that we're currently viewing the line that
+ # has the caret -- which is a pretty good assumption for focus
+ # tacking mode. When we set the caret position, we will get a
+ # caret event, which will then update the braille.
+ #
+ text = orca_state.locusOfFocus.queryText()
+ [lineString, startOffset, endOffset] = text.getTextAtOffset(
+ text.caretOffset,
+ pyatspi.TEXT_BOUNDARY_LINE_START)
+ if endOffset < text.characterCount:
+ text.setCaretOffset(endOffset)
+ else:
+ self.panBrailleInDirection(panAmount, panToLeft=False)
+ # We might be panning through a flashed message.
+ #
+ braille.resetFlashTimer()
+ self.refreshBraille(False, stopFlash=False)
+
+ return True
+
+ def panBrailleRightOneChar(self, inputEvent=None):
+ """Nudges the braille display one character to the right.
+
+ In focus tracking mode, the cursor stays at its logical position.
+ In flat review mode, the review cursor moves to character
+ associated with cell 0."""
+
+ self.panBrailleRight(inputEvent, 1)
+
+ def goBrailleHome(self, inputEvent=None):
+ """Returns to the component with focus."""
+
+ if self.flatReviewContext:
+ return self.toggleFlatReviewMode(inputEvent)
+ else:
+ return braille.returnToRegionWithFocus(inputEvent)
+
+ def setContractedBraille(self, inputEvent=None):
+ """Toggles contracted braille."""
+
+ self._setContractedBraille(inputEvent)
+ return True
+
+ def processRoutingKey(self, inputEvent=None):
+ """Processes a cursor routing key."""
+
+ braille.processRoutingKey(inputEvent)
+ return True
+
+ def processBrailleCutBegin(self, inputEvent=None):
+ """Clears the selection and moves the caret offset in the currently
+ active text area.
+ """
+
+ obj, caretOffset = self.getBrailleCaretContext(inputEvent)
+
+ if caretOffset >= 0:
+ self.utilities.clearTextSelection(obj)
+ self.utilities.setCaretOffset(obj, caretOffset)
+
+ return True
+
+ def processBrailleCutLine(self, inputEvent=None):
+ """Extends the text selection in the currently active text
+ area and also copies the selected text to the system clipboard."""
+
+ obj, caretOffset = self.getBrailleCaretContext(inputEvent)
+
+ if caretOffset >= 0:
+ self.utilities.adjustTextSelection(obj, caretOffset)
+ texti = obj.queryText()
+ startOffset, endOffset = texti.getSelection(0)
+ import gtk
+ clipboard = gtk.clipboard_get()
+ clipboard.set_text(texti.getText(startOffset, endOffset))
+
+ return True
+
+ def routePointerToItem(self, inputEvent=None):
+ """Moves the mouse pointer to the current item."""
+
+ # Store the original location for scripts which want to restore
+ # it later.
+ #
+ self.oldMouseCoordinates = self.utilities.absoluteMouseCoordinates()
+ self.lastMouseRoutingTime = time.time()
+ if self.flatReviewContext:
+ self.flatReviewContext.routeToCurrent()
+ else:
+ try:
+ eventsynthesizer.routeToCharacter(orca_state.locusOfFocus)
+ except:
+ try:
+ eventsynthesizer.routeToObject(orca_state.locusOfFocus)
+ except:
+ # Translators: Orca has a command that allows the user to
+ # move the mouse pointer to the current object. This is a
+ # detailed message which will be presented if for some
+ # reason Orca cannot identify/find the current location.
+ #
+ full = _("Could not find current location.")
+ # Translators: Orca has a command that allows the user to
+ # move the mouse pointer to the current object. This is a
+ # brief message which will be presented if for some reason
+ # Orca cannot identify/find the current location.
+ #
+ brief = C_("location", "Not found")
+ self.presentMessage(full, brief)
+
+ return True
+
+ def presentStatusBar(self, inputEvent):
+ """Speaks and brailles the contents of the status bar and/or default
+ button of the window with focus.
+ """
+
+ obj = orca_state.locusOfFocus
+ self.updateBraille(obj)
+ voice = self.voices[settings.DEFAULT_VOICE]
+
+ frame, dialog = self.utilities.frameAndDialog(obj)
+ if frame:
+ # In windows with lots of objects (Thunderbird, Firefox, etc.)
+ # If we wait until we've checked for both the status bar and
+ # a default button, there may be a noticable delay. Therefore,
+ # speak the status bar info immediately and then go looking
+ # for a default button.
+ #
+ msg = self.speechGenerator.generateStatusBar(frame)
+ if msg:
+ self.presentMessage(msg, voice=voice)
+
+ window = dialog or frame
+ if window:
+ msg = self.speechGenerator.generateDefaultButton(window)
+ if msg:
+ self.presentMessage(msg, voice=voice)
+
+ def presentTitle(self, inputEvent):
+ """Speaks and brailles the title of the window with focus."""
+
+ title = self.speechGenerator.generateTitle(orca_state.locusOfFocus)
+ for (string, voice) in title:
+ self.presentMessage(string, voice=voice)
+
+ def readCharAttributes(self, inputEvent=None):
+ """Reads the attributes associated with the current text character.
+ Calls outCharAttributes to speak a list of attributes. By default,
+ a certain set of attributes will be spoken. If this is not desired,
+ then individual application scripts should override this method to
+ only speak the subset required.
+ """
+
+ try:
+ text = orca_state.locusOfFocus.queryText()
+ except:
+ pass
+ else:
+ caretOffset = text.caretOffset
+
+ # Creates dictionaries of the default attributes, plus the set
+ # of attributes specific to the character at the caret offset.
+ # Combine these two dictionaries and then extract just the
+ # entries we are interested in.
+ #
+ defAttributes = text.getDefaultAttributes()
+ debug.println(debug.LEVEL_FINEST, \
+ "readCharAttributes: default text attributes: %s" % \
+ defAttributes)
+ [defUser, defDict] = \
+ self.utilities.stringToKeysAndDict(defAttributes)
+ allAttributes = defDict
+
+ charAttributes = text.getAttributes(caretOffset)
+ if charAttributes[0]:
+ [charList, charDict] = \
+ self.utilities.stringToKeysAndDict(charAttributes[0])
+
+ # It looks like some applications like Evolution and Star
+ # Office don't implement getDefaultAttributes(). In that
+ # case, the best we can do is use the specific text
+ # attributes for this character returned by getAttributes().
+ #
+ if allAttributes:
+ for key in charDict.keys():
+ allAttributes[key] = charDict[key]
+ else:
+ allAttributes = charDict
+
+ # Get a dictionary of text attributes that the user cares about.
+ #
+ [userAttrList, userAttrDict] = self.utilities.stringToKeysAndDict(
+ _settingsManager.getSetting('enabledSpokenTextAttributes'))
+
+ # Create a dictionary of just the items we are interested in.
+ # Always include size and family-name. For the others, if the
+ # value is the default, then ignore it.
+ #
+ attributes = {}
+ for key in userAttrList:
+ if key in allAttributes:
+ textAttr = allAttributes.get(key)
+ userAttr = userAttrDict.get(key)
+ if textAttr != userAttr or len(userAttr) == 0:
+ attributes[key] = textAttr
+
+ self.outputCharAttributes(userAttrList, attributes)
+
+ # If this is a hypertext link, then let the user know:
+ #
+ if self.utilities.linkIndex(
+ orca_state.locusOfFocus, caretOffset) >= 0:
+ # Translators: this indicates that this piece of
+ # text is a hypertext link.
+ #
+ speech.speak(_("link"))
+
+ return True
+
+ def reportScriptInfo(self, inputEvent=None):
+ """Output useful information on the current script via speech
+ and braille. This information will be helpful to script writers.
+ """
+
+ return self.utilities.scriptInfo()
+
+ def leftClickReviewItem(self, inputEvent=None):
+ """Performs a left mouse button click on the current item."""
+
+ if self.flatReviewContext:
+ self.flatReviewContext.clickCurrent(1)
+ else:
+ try:
+ eventsynthesizer.clickCharacter(orca_state.locusOfFocus, 1)
+ except:
+ try:
+ eventsynthesizer.clickObject(orca_state.locusOfFocus, 1)
+ except:
+ # Translators: Orca has a command that allows the user
+ # to move the mouse pointer to the current object. If
+ # for some reason Orca cannot identify the current
+ # location, it will speak this message.
+ #
+ self.speakMessage(_("Could not find current location."))
+ return True
+
+ def rightClickReviewItem(self, inputEvent=None):
+ """Performs a right mouse button click on the current item."""
+
+ if self.flatReviewContext:
+ self.flatReviewContext.clickCurrent(3)
+ else:
+ try:
+ eventsynthesizer.clickCharacter(orca_state.locusOfFocus, 3)
+ except:
+ try:
+ eventsynthesizer.clickObject(orca_state.locusOfFocus, 3)
+ except:
+ # Translators: Orca has a command that allows the user to
+ # move the mouse pointer to the current object. This is a
+ # detailed message which will be presented if for some
+ # reason Orca cannot identify/find the current location.
+ #
+ full = _("Could not find current location.")
+ # Translators: Orca has a command that allows the user to
+ # move the mouse pointer to the current object. This is a
+ # brief message which will be presented if for some reason
+ # Orca cannot identify/find the current location.
+ #
+ brief = C_("location", "Not found")
+ self.presentMessage(full, brief)
+
+ return True
+
+ def spellCurrentItem(self, itemString):
+ """Spell the current flat review word or line.
+
+ Arguments:
+ - itemString: the string to spell.
+ """
+
+ for (charIndex, character) in enumerate(itemString.decode("UTF-8")):
+ if character.isupper():
+ speech.speak(character.encode("UTF-8"),
+ self.voices[settings.UPPERCASE_VOICE])
+ else:
+ speech.speak(character.encode("UTF-8"))
+
+ def _reviewCurrentItem(self, inputEvent, targetCursorCell=0,
+ speechType=1):
+ """Presents the current item to the user.
+
+ Arguments:
+ - inputEvent - the current input event.
+ - targetCursorCell - if non-zero, the target braille cursor cell.
+ - speechType - the desired presentation: speak (1), spell (2), or
+ phonetic (3).
+ """
+
+ context = self.getFlatReviewContext()
+ [wordString, x, y, width, height] = \
+ context.getCurrent(flat_review.Context.WORD)
+ self.drawOutline(x, y, width, height)
+
+ # Don't announce anything from speech if the user used
+ # the Braille display as an input device.
+ #
+ if not isinstance(inputEvent, input_event.BrailleEvent):
+ if (not wordString) \
+ or (not len(wordString)) \
+ or (wordString == "\n"):
+ # Translators: "blank" is a short word to mean the
+ # user has navigated to an empty line.
+ #
+ speech.speak(_("blank"))
+ else:
+ [lineString, x, y, width, height] = \
+ context.getCurrent(flat_review.Context.LINE)
+ if lineString == "\n":
+ # Translators: "blank" is a short word to mean the
+ # user has navigated to an empty line.
+ #
+ speech.speak(_("blank"))
+ elif wordString.isspace():
+ # Translators: "white space" is a short phrase to mean the
+ # user has navigated to a line with only whitespace on it.
+ #
+ speech.speak(_("white space"))
+ elif wordString.decode("UTF-8").isupper() and speechType == 1:
+ speech.speak(wordString,
+ self.voices[settings.UPPERCASE_VOICE])
+ elif speechType == 2:
+ self.spellCurrentItem(wordString)
+ elif speechType == 3:
+ self.phoneticSpellCurrentItem(wordString)
+ elif speechType == 1:
+ wordString = self.utilities.adjustForRepeats(wordString)
+ speech.speak(wordString)
+
+ self.updateBrailleReview(targetCursorCell)
+
+ return True
+
+ def reviewCurrentAccessible(self, inputEvent):
+ context = self.getFlatReviewContext()
+ [zoneString, x, y, width, height] = \
+ context.getCurrent(flat_review.Context.ZONE)
+ self.drawOutline(x, y, width, height)
+
+ # Don't announce anything from speech if the user used
+ # the Braille display as an input device.
+ #
+ if not isinstance(inputEvent, input_event.BrailleEvent):
+ utterances = self.speechGenerator.generateSpeech(
+ context.getCurrentAccessible())
+ utterances.extend(self.tutorialGenerator.getTutorial(
+ context.getCurrentAccessible(), False))
+ speech.speak(utterances)
+ return True
+
+ def reviewPreviousItem(self, inputEvent):
+ """Moves the flat review context to the previous item. Places
+ the flat review cursor at the beginning of the item."""
+
+ context = self.getFlatReviewContext()
+
+ moved = context.goPrevious(flat_review.Context.WORD,
+ flat_review.Context.WRAP_LINE)
+
+ if moved:
+ self._reviewCurrentItem(inputEvent)
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ return True
+
+ def reviewNextItem(self, inputEvent):
+ """Moves the flat review context to the next item. Places
+ the flat review cursor at the beginning of the item."""
+
+ context = self.getFlatReviewContext()
+
+ moved = context.goNext(flat_review.Context.WORD,
+ flat_review.Context.WRAP_LINE)
+
+ if moved:
+ self._reviewCurrentItem(inputEvent)
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ return True
+
+ def reviewCurrentCharacter(self, inputEvent):
+ """Brailles and speaks the current flat review character."""
+
+ self._reviewCurrentCharacter(inputEvent, 1)
+ self.lastReviewCurrentEvent = inputEvent
+
+ return True
+
+ def reviewSpellCurrentCharacter(self, inputEvent):
+ """Brailles and 'spells' (phonetically) the current flat review
+ character.
+ """
+
+ self._reviewCurrentCharacter(inputEvent, 2)
+ self.lastReviewCurrentEvent = inputEvent
+
+ return True
+
+ def reviewUnicodeCurrentCharacter(self, inputEvent):
+ """Brailles and speaks unicode information about the current flat
+ review character.
+ """
+
+ self._reviewCurrentCharacter(inputEvent, 3)
+ self.lastReviewCurrentEvent = inputEvent
+
+ return True
+
+ def _reviewCurrentCharacter(self, inputEvent, speechType=1):
+ """Presents the current flat review character via braille and speech.
+
+ Arguments:
+ - inputEvent - the current input event.
+ - speechType - the desired presentation:
+ speak (1),
+ phonetic (2)
+ unicode value information (3)
+ """
+
+ context = self.getFlatReviewContext()
+
+ [charString, x, y, width, height] = \
+ context.getCurrent(flat_review.Context.CHAR)
+ self.drawOutline(x, y, width, height)
+
+ # Don't announce anything from speech if the user used
+ # the Braille display as an input device.
+ #
+ if not isinstance(inputEvent, input_event.BrailleEvent):
+ if (not charString) or (not len(charString)):
+ # Translators: "blank" is a short word to mean the
+ # user has navigated to an empty line.
+ #
+ speech.speak(_("blank"))
+ else:
+ [lineString, x, y, width, height] = \
+ context.getCurrent(flat_review.Context.LINE)
+ if lineString == "\n" and speechType != 3:
+ # Translators: "blank" is a short word to mean the
+ # user has navigated to an empty line.
+ #
+ speech.speak(_("blank"))
+ elif speechType == 3:
+ self.speakUnicodeCharacter(charString)
+ elif speechType == 2:
+ self.phoneticSpellCurrentItem(charString)
+ elif charString.decode("UTF-8").isupper():
+ speech.speakCharacter(charString,
+ self.voices[settings.UPPERCASE_VOICE])
+ else:
+ speech.speakCharacter(charString)
+
+ self.updateBrailleReview()
+
+ return True
+
+ def reviewPreviousCharacter(self, inputEvent):
+ """Moves the flat review context to the previous character. Places
+ the flat review cursor at character."""
+
+ context = self.getFlatReviewContext()
+
+ moved = context.goPrevious(flat_review.Context.CHAR,
+ flat_review.Context.WRAP_LINE)
+
+ if moved:
+ self._reviewCurrentCharacter(inputEvent)
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ return True
+
+ def reviewEndOfLine(self, inputEvent):
+ """Moves the flat review context to the end of the line. Places
+ the flat review cursor at the end of the line."""
+
+ context = self.getFlatReviewContext()
+ context.goEnd(flat_review.Context.LINE)
+
+ self.reviewCurrentCharacter(inputEvent)
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ return True
+
+ def reviewNextCharacter(self, inputEvent):
+ """Moves the flat review context to the next character. Places
+ the flat review cursor at character."""
+
+ context = self.getFlatReviewContext()
+
+ moved = context.goNext(flat_review.Context.CHAR,
+ flat_review.Context.WRAP_LINE)
+
+ if moved:
+ self._reviewCurrentCharacter(inputEvent)
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ return True
+
+ def reviewAbove(self, inputEvent):
+ """Moves the flat review context to the character most directly
+ above the current flat review cursor. Places the flat review
+ cursor at character."""
+
+ context = self.getFlatReviewContext()
+
+ moved = context.goAbove(flat_review.Context.CHAR,
+ flat_review.Context.WRAP_LINE)
+
+ if moved:
+ self._reviewCurrentItem(inputEvent, self.targetCursorCell)
+
+ return True
+
+ def reviewBelow(self, inputEvent):
+ """Moves the flat review context to the character most directly
+ below the current flat review cursor. Places the flat review
+ cursor at character."""
+
+ context = self.getFlatReviewContext()
+
+ moved = context.goBelow(flat_review.Context.CHAR,
+ flat_review.Context.WRAP_LINE)
+
+ if moved:
+ self._reviewCurrentItem(inputEvent, self.targetCursorCell)
+
+ return True
+
+ def reviewCurrentLine(self, inputEvent):
+ """Brailles and speaks the current flat review line."""
+
+ self._reviewCurrentLine(inputEvent, 1)
+ self.lastReviewCurrentEvent = inputEvent
+
+ return True
+
+ def reviewSpellCurrentLine(self, inputEvent):
+ """Brailles and spells the current flat review line."""
+
+ self._reviewCurrentLine(inputEvent, 2)
+ self.lastReviewCurrentEvent = inputEvent
+
+ return True
+
+ def reviewPhoneticCurrentLine(self, inputEvent):
+ """Brailles and phonetically spells the current flat review line."""
+
+ self._reviewCurrentLine(inputEvent, 3)
+ self.lastReviewCurrentEvent = inputEvent
+
+ return True
+
+ def _reviewCurrentLine(self, inputEvent, speechType=1):
+ """Presents the current flat review line via braille and speech.
+
+ Arguments:
+ - inputEvent - the current input event.
+ - speechType - the desired presentation: speak (1), spell (2), or
+ phonetic (3)
+ """
+
+ context = self.getFlatReviewContext()
+
+ [lineString, x, y, width, height] = \
+ context.getCurrent(flat_review.Context.LINE)
+ self.drawOutline(x, y, width, height)
+
+ # Don't announce anything from speech if the user used
+ # the Braille display as an input device.
+ #
+ if not isinstance(inputEvent, input_event.BrailleEvent):
+ if (not lineString) \
+ or (not len(lineString)) \
+ or (lineString == "\n"):
+ # Translators: "blank" is a short word to mean the
+ # user has navigated to an empty line.
+ #
+ speech.speak(_("blank"))
+ elif lineString.isspace():
+ # Translators: "white space" is a short phrase to mean the
+ # user has navigated to a line with only whitespace on it.
+ #
+ speech.speak(_("white space"))
+ elif lineString.decode("UTF-8").isupper() \
+ and (speechType < 2 or speechType > 3):
+ speech.speak(lineString, self.voices[settings.UPPERCASE_VOICE])
+ elif speechType == 2:
+ self.spellCurrentItem(lineString)
+ elif speechType == 3:
+ self.phoneticSpellCurrentItem(lineString)
+ else:
+ lineString = self.utilities.adjustForRepeats(lineString)
+ speech.speak(lineString)
+
+ self.updateBrailleReview()
+
+ return True
+
+ def reviewPreviousLine(self, inputEvent):
+ """Moves the flat review context to the beginning of the
+ previous line."""
+
+ context = self.getFlatReviewContext()
+
+ moved = context.goPrevious(flat_review.Context.LINE,
+ flat_review.Context.WRAP_LINE)
+
+ if moved:
+ self._reviewCurrentLine(inputEvent)
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ return True
+
+ def reviewHome(self, inputEvent):
+ """Moves the flat review context to the top left of the current
+ window."""
+
+ context = self.getFlatReviewContext()
+
+ context.goBegin()
+
+ self._reviewCurrentLine(inputEvent)
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ return True
+
+ def reviewNextLine(self, inputEvent):
+ """Moves the flat review context to the beginning of the
+ next line. Places the flat review cursor at the beginning
+ of the line."""
+
+ context = self.getFlatReviewContext()
+
+ moved = context.goNext(flat_review.Context.LINE,
+ flat_review.Context.WRAP_LINE)
+
+ if moved:
+ self._reviewCurrentLine(inputEvent)
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ return True
+
+ def reviewBottomLeft(self, inputEvent):
+ """Moves the flat review context to the beginning of the
+ last line in the window. Places the flat review cursor at
+ the beginning of the line."""
+
+ context = self.getFlatReviewContext()
+
+ context.goEnd(flat_review.Context.WINDOW)
+ context.goBegin(flat_review.Context.LINE)
+ self._reviewCurrentLine(inputEvent)
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ return True
+
+ def reviewEnd(self, inputEvent):
+ """Moves the flat review context to the end of the
+ last line in the window. Places the flat review cursor
+ at the end of the line."""
+
+ context = self.getFlatReviewContext()
+ context.goEnd()
+
+ self._reviewCurrentLine(inputEvent)
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ return True
+
+ def reviewCurrentItem(self, inputEvent, targetCursorCell=0):
+ """Brailles and speaks the current item to the user."""
+
+ self._reviewCurrentItem(inputEvent, targetCursorCell, 1)
+ self.lastReviewCurrentEvent = inputEvent
+
+ return True
+
+ def reviewSpellCurrentItem(self, inputEvent, targetCursorCell=0):
+ """Brailles and spells the current item to the user."""
+
+ self._reviewCurrentItem(inputEvent, targetCursorCell, 2)
+ self.lastReviewCurrentEvent = inputEvent
+
+ return True
+
+ def reviewPhoneticCurrentItem(self, inputEvent, targetCursorCell=0):
+ """Brailles and phonetically spells the current item to the user."""
+
+ self._reviewCurrentItem(inputEvent, targetCursorCell, 3)
+ self.lastReviewCurrentEvent = inputEvent
+
+ return True
+
+ def showZones(self, inputEvent):
+ """Debug routine to paint rectangles around the discrete
+ interesting (e.g., text) zones in the active window for
+ this application.
+ """
+
+ flatReviewContext = self.getFlatReviewContext()
+ lines = flatReviewContext.lines
+ for line in lines:
+ lineString = ""
+ for zone in line.zones:
+ lineString += " '%s' [%s]" % \
+ (zone.string, zone.accessible.getRoleName())
+ debug.println(debug.LEVEL_OFF, lineString)
+ self.flatReviewContext = None
+
+ def sayAll(self, inputEvent):
+ clickCount = self.getClickCount()
+ doubleClick = clickCount == 2
+ self.lastSayAllEvent = inputEvent
+
+ if doubleClick:
+ # Try to "say all" for the current dialog/window by flat
+ # reviewing everything. See bug #354462 for more details.
+ #
+ context = self.getFlatReviewContext()
+
+ utterances = []
+ context.goBegin()
+ while True:
+ [wordString, x, y, width, height] = \
+ context.getCurrent(flat_review.Context.ZONE)
+
+ utterances.append(wordString)
+
+ moved = context.goNext(flat_review.Context.ZONE,
+ flat_review.Context.WRAP_LINE)
+
+ if not moved:
+ break
+
+ speech.speak(utterances)
+
+ elif self.utilities.isTextArea(orca_state.locusOfFocus):
+ try:
+ orca_state.locusOfFocus.queryText()
+ except NotImplementedError:
+ utterances = self.speechGenerator.generateSpeech(
+ orca_state.locusOfFocus)
+ utterances.extend(self.tutorialGenerator.getTutorial(
+ orca_state.locusOfFocus, False))
+ speech.speak(utterances)
+ except AttributeError:
+ pass
+ else:
+ speech.sayAll(self.textLines(orca_state.locusOfFocus),
+ self.__sayAllProgressCallback)
+
+ return True
+
+ def toggleFlatReviewMode(self, inputEvent=None):
+ """Toggles between flat review mode and focus tracking mode."""
+
+ verbosity = _settingsManager.getSetting('speechVerbosityLevel')
+ if self.flatReviewContext:
+ if inputEvent and verbosity != settings.VERBOSITY_LEVEL_BRIEF:
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. This message lets the user know
+ # they have left the flat review feature.
+ #
+ self.presentMessage(_("Leaving flat review."))
+ self.drawOutline(-1, 0, 0, 0)
+ self.flatReviewContext = None
+ self.updateBraille(orca_state.locusOfFocus)
+ else:
+ if inputEvent and verbosity != settings.VERBOSITY_LEVEL_BRIEF:
+ # Translators: the 'flat review' feature of Orca
+ # allows the blind user to explore the text in a
+ # window in a 2D fashion. That is, Orca treats all
+ # the text from all objects in a window (e.g.,
+ # buttons, labels, etc.) as a sequence of words in a
+ # sequence of lines. The flat review feature allows
+ # the user to explore this text by the {previous,next}
+ # {line,word,character}. This message lets the user know
+ # they have entered the flat review feature.
+ #
+ self.presentMessage(_("Entering flat review."))
+ context = self.getFlatReviewContext()
+ [wordString, x, y, width, height] = \
+ context.getCurrent(flat_review.Context.WORD)
+ self.drawOutline(x, y, width, height)
+ self._reviewCurrentItem(inputEvent, self.targetCursorCell)
+
+ return True
+
+ def toggleSpeakingIndentationJustification(self, inputEvent=None):
+ """Toggles the speaking of indentation and justification."""
+
+ value = _settingsManager.getSetting('enableSpeechIndentation')
+ _settingsManager.setSetting('enableSpeechIndentation', not value)
+ if _settingsManager.getSetting('enableSpeechIndentation'):
+ # Translators: This is a detailed message indicating that
+ # indentation and justification will be spoken.
+ #
+ full = _("Speaking of indentation and justification enabled.")
+ # Translators: This is a brief message that will be presented
+ # to the user who has just enabled/disabled the speaking of
+ # indentation and justification information.
+ #
+ brief = C_("indentation and justification", "Enabled")
+ else:
+ # Translators: This is a detailed message indicating that
+ # indentation and justification will not be spoken.
+ #
+ full = _("Speaking of indentation and justification disabled.")
+ # Translators: This is a brief message that will be presented
+ # to the user who has just enabled/disabled the speaking of
+ # indentation and justification information.
+ #
+ brief = C_("indentation and justification", "Disabled")
+
+ self.presentMessage(full, brief)
+
+ return True
+
+ def cycleSpeakingPunctuationLevel(self, inputEvent=None):
+ """ Cycle through the punctuation levels for speech. """
+
+ currentLevel = _settingsManager.getSetting('verbalizePunctuationStyle')
+ if currentLevel == settings.PUNCTUATION_STYLE_NONE:
+ newLevel = settings.PUNCTUATION_STYLE_SOME
+ # Translators: This detailed message will be presented as the
+ # user cycles through the different levels of spoken punctuation.
+ # The options are: All puntuation marks will be spoken, None
+ # will be spoken, Most will be spoken, or Some will be spoken.
+ #
+ full = _("Punctuation level set to some.")
+ # Translators: This brief message will be presented as the user
+ # cycles through the different levels of spoken punctuation.
+ # The options are: All puntuation marks will be spoken, None
+ # will be spoken, Most will be spoken, or Some will be spoken.
+ #
+ brief = C_("spoken punctuation", "Some")
+ elif currentLevel == settings.PUNCTUATION_STYLE_SOME:
+ newLevel = settings.PUNCTUATION_STYLE_MOST
+ # Translators: This detailed message will be presented as the
+ # user cycles through the different levels of spoken punctuation.
+ # The options are: All puntuation marks will be spoken, None
+ # will be spoken, Most will be spoken, or Some will be spoken.
+ #
+ full = _("Punctuation level set to most.")
+ # Translators: This brief message will be presented as the user
+ # cycles through the different levels of spoken punctuation.
+ # The options are: All puntuation marks will be spoken, None
+ # will be spoken, Most will be spoken, or Some will be spoken.
+ #
+ brief = C_("spoken punctuation", "Most")
+ elif currentLevel == settings.PUNCTUATION_STYLE_MOST:
+ newLevel = settings.PUNCTUATION_STYLE_ALL
+ # Translators: This detailed message will be presented as the
+ # user cycles through the different levels of spoken punctuation.
+ # The options are: All puntuation marks will be spoken, None
+ # will be spoken, Most will be spoken, or Some will be spoken.
+ #
+ full = _("Punctuation level set to all.")
+ # Translators: This brief message will be presented as the user
+ # cycles through the different levels of spoken punctuation.
+ # The options are: All puntuation marks will be spoken, None
+ # will be spoken, Most will be spoken, or Some will be spoken.
+ #
+ brief = C_("spoken punctuation", "All")
+ else:
+ # the all case, so cycle to none.
+ newLevel = settings.PUNCTUATION_STYLE_NONE
+ # Translators: This detailed message will be presented as the
+ # user cycles through the different levels of spoken punctuation.
+ # The options are: All puntuation marks will be spoken, None
+ # will be spoken, Most will be spoken, or Some will be spoken.
+ #
+ full = _("Punctuation level set to none.")
+ # Translators: This brief message will be presented as the user
+ # cycles through the different levels of spoken punctuation.
+ # The options are: All puntuation marks will be spoken, None
+ # will be spoken, Most will be spoken, or Some will be spoken.
+ #
+ brief = C_("spoken punctuation", "None")
+
+ _settingsManager.setSetting('verbalizePunctuationStyle', newLevel)
+ self.presentMessage(full, brief)
+ speech.updatePunctuationLevel()
+ return True
+
+ def cycleKeyEcho(self, inputEvent=None):
+ (newKey, newWord, newSentence) = (False, False, False)
+ key = _settingsManager.getSetting('enableKeyEcho')
+ word = _settingsManager.getSetting('enableEchoByWord')
+ sentence = _settingsManager.getSetting('enableEchoBySentence')
+
+ # check if we are in the none case.
+ if (key, word, sentence) == (False, False, False):
+ # cycle to key echo
+ (newKey, newWord, newSentence) = (True, False, False)
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command.
+ #
+ full = _("Key echo set to key.")
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command. The following string is a
+ # brief message which will be presented to the user who is
+ # cycling amongst the various echo options.
+ #
+ brief = C_("key echo", "key")
+
+ # The key echo only case
+ elif (key, word, sentence) == (True, False, False):
+ # cycle to word echo
+ (newKey, newWord, newSentence) = (False, True, False)
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command.
+ #
+ full = _("Key echo set to word.")
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command. The following string is a
+ # brief message which will be presented to the user who is
+ # cycling amongst the various echo options.
+ #
+ brief = C_("key echo", "word")
+
+ # the word only case
+ elif (key, word, sentence) == (False, True, False):
+ # cycle to sentence echo
+ (newKey, newWord, newSentence) = (False, False, True)
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command.
+ #
+ full = _("Key echo set to sentence.")
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command. The following string is a
+ # brief message which will be presented to the user who is
+ # cycling amongst the various echo options.
+ #
+ brief = C_("key echo", "sentence")
+
+ # the sentence only case
+ elif (key, word, sentence) == (False, False, True):
+ # cycle to word and key echo
+ (newKey, newWord, newSentence) = (True, True, False)
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command.
+ #
+ full = _("Key echo set to key and word.")
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command. The following string is a
+ # brief message which will be presented to the user who is
+ # cycling amongst the various echo options.
+ #
+ brief = C_("key echo", "key and word")
+
+ # the key and word case
+ elif (key, word, sentence) == (True, True, False):
+ # cycle to word and sentence echo
+ (newKey, newWord, newSentence) = (False, True, True)
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command.
+ #
+ full = _("Key echo set to word and sentence.")
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command. The following string is a
+ # brief message which will be presented to the user who is
+ # cycling amongst the various echo options.
+ #
+ brief = C_("key echo", "word and sentence")
+
+ # cycle round
+ else:
+ # cycle to none
+ (newKey, newWord, newSentence) = (False, False, False)
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command.
+ #
+ full = _("Key echo set to None.")
+ # Translators: Orca has an "echo" setting which allows
+ # the user to configure what is spoken in response to a
+ # key press. Given a user who typed "Hello world.":
+ # - key echo: "H e l l o space w o r l d period"
+ # - word echo: "Hello" spoken when the space is pressed;
+ # "world" spoken when the period is pressed.
+ # - sentence echo: "Hello world" spoken when the period
+ # is pressed.
+ # A user can choose to have no echo, one type of echo, or
+ # multiple types of echo and can cycle through the various
+ # levels quickly via a command. The following string is a
+ # brief message which will be presented to the user who is
+ # cycling amongst the various echo options.
+ #
+ brief = C_("key echo", "None")
+
+ _settingsManager.setSetting('enableKeyEcho', newKey)
+ _settingsManager.setSetting('enableEchoByWord', newWord)
+ _settingsManager.setSetting('enableEchoBySentence', newSentence)
+ self.presentMessage(full, brief)
+ return True
+
+
+ def toggleTableCellReadMode(self, inputEvent=None):
+ """Toggles an indicator for whether we should just read the current
+ table cell or read the whole row."""
+
+ speakRow = _settingsManager.getSetting('readTableCellRow')
+ _settingsManager.setSetting('readTableCellRow', not speakRow)
+ if not speakRow:
+ # Translators: when users are navigating a table, they
+ # sometimes want the entire row of a table read, or
+ # they just want the current cell to be presented to them.
+ #
+ line = _("Speak row")
+ else:
+ # Translators: when users are navigating a table, they
+ # sometimes want the entire row of a table read, or
+ # they just want the current cell to be presented to them.
+ #
+ line = _("Speak cell")
+
+ self.presentMessage(line)
+
+ return True
+
+ def doWhereAmI(self, inputEvent, basicOnly):
+ """Peforms the whereAmI operation.
+
+ Arguments:
+ - inputEvent: The original inputEvent
+ """
+
+ obj = orca_state.locusOfFocus
+ self.updateBraille(obj)
+
+ return self.whereAmI.whereAmI(obj, basicOnly)
+
+ def whereAmIBasic(self, inputEvent):
+ """Speaks basic information about the current object of interest.
+ """
+
+ self.doWhereAmI(inputEvent, True)
+
+ def whereAmIDetailed(self, inputEvent):
+ """Speaks detailed/custom information about the current object of
+ interest.
+ """
+
+ self.doWhereAmI(inputEvent, False)
+
+ def printMemoryUsageHandler(self, inputEvent):
+ """Prints memory usage information."""
+ print 'TODO: print something useful for memory debugging'
+
+ def printAppsHandler(self, inputEvent=None):
+ """Prints a list of all applications to stdout."""
+
+ self.utilities.printApps()
+ return True
+
+ def printAncestryHandler(self, inputEvent=None):
+ """Prints the ancestry for the current locusOfFocus"""
+
+ self.utilities.printAncestry(orca_state.locusOfFocus)
+ return True
+
+ def printHierarchyHandler(self, inputEvent=None):
+ """Prints the application for the current locusOfFocus"""
+
+ if orca_state.locusOfFocus:
+ self.utilities.printHierarchy(
+ orca_state.locusOfFocus.getApplication(),
+ orca_state.locusOfFocus)
+
+ return True
+
+ ########################################################################
+ # #
+ # AT-SPI OBJECT EVENT HANDLERS #
+ # #
+ ########################################################################
+
+ def noOp(self, event):
+ """Just here to capture events.
+
+ Arguments:
+ - event: the Event
+ """
+ pass
+
+ def onActiveDescendantChanged(self, event):
+ """Called when an object who manages its own descendants detects a
+ change in one of its children.
+
+ Arguments:
+ - event: the Event
+ """
+
+ if not event.source.getState().contains(pyatspi.STATE_FOCUSED):
+ return
+
+ # There can be cases when the object that fires an
+ # active-descendant-changed event has no children. In this case,
+ # use the object that fired the event, otherwise, use the child.
+ #
+ child = event.any_data
+ if child:
+ if self.stopSpeechOnActiveDescendantChanged(event):
+ speech.stop()
+ orca.setLocusOfFocus(event, child)
+ else:
+ orca.setLocusOfFocus(event, event.source)
+
+ # We'll tuck away the activeDescendant information for future
+ # reference since the AT-SPI gives us little help in finding
+ # this.
+ #
+ if orca_state.locusOfFocus \
+ and (orca_state.locusOfFocus != event.source):
+ self.pointOfReference['activeDescendantInfo'] = \
+ [orca_state.locusOfFocus.parent,
+ orca_state.locusOfFocus.getIndexInParent()]
+
+ def onCaretMoved(self, event):
+ """Called whenever the caret moves.
+
+ Arguments:
+ - event: the Event
+ """
+
+ if not orca_state.locusOfFocus:
+ return
+
+ # Should the event source be the locusOfFocus?
+ #
+ role = orca_state.locusOfFocus.getRole()
+ if role in [pyatspi.ROLE_FRAME, pyatspi.ROLE_DIALOG]:
+ frameApp = orca_state.locusOfFocus.getApplication()
+ eventApp = event.source.getApplication()
+ if frameApp == eventApp \
+ and event.source.getState().contains(pyatspi.STATE_FOCUSED):
+ orca.setLocusOfFocus(event, event.source, False)
+
+ # Ignore caret movements from non-focused objects, unless the
+ # currently focused object is the parent of the object which
+ # has the caret.
+ #
+ if (event.source != orca_state.locusOfFocus) \
+ and (event.source.parent != orca_state.locusOfFocus):
+ return
+
+ # We always automatically go back to focus tracking mode when
+ # the caret moves in the focused object.
+ #
+ if self.flatReviewContext:
+ self.toggleFlatReviewMode()
+
+ self._presentTextAtNewCaretPosition(event)
+
+ def onFocus(self, event):
+ """Called whenever an object gets focus.
+
+ Arguments:
+ - event: the Event
+ """
+
+ # [[[TODO: WDW - HACK to deal with quirky GTK+ menu behavior.
+ # The problem is that when moving to submenus in a menu, the
+ # menu gets focus first and then the submenu gets focus all
+ # with a single keystroke. So...focus in menus really means
+ # that the object has focus *and* it is selected. Now, this
+ # assumes the selected state will be set before focus is given,
+ # which appears to be the case from empirical analysis of the
+ # event stream. But of course, all menu items and menus in
+ # the complete menu path will have their selected state set,
+ # so, we really only care about the leaf menu or menu item
+ # that it selected.]]]
+ #
+ role = event.source.getRole()
+ if role in (pyatspi.ROLE_MENU,
+ pyatspi.ROLE_MENU_ITEM,
+ pyatspi.ROLE_CHECK_MENU_ITEM,
+ pyatspi.ROLE_RADIO_MENU_ITEM):
+ try:
+ if event.source.querySelection().nSelectedChildren > 0:
+ return
+ except:
+ pass
+
+ # [[[TODO: WDW - HACK to deal with the fact that active cells
+ # may or may not get focus. Their parents, however, do tend to
+ # get focus, but when the parent gets focus, it really means
+ # that the selected child in it has focus. Of course, this all
+ # breaks when more than one child is selected. Then, we really
+ # need to depend upon the model where focus really works.]]]
+ #
+ newFocus = event.source
+
+ if role in (pyatspi.ROLE_LAYERED_PANE,
+ pyatspi.ROLE_TABLE,
+ pyatspi.ROLE_TREE_TABLE,
+ pyatspi.ROLE_TREE):
+ if event.source.childCount:
+ # We might have tucked away some information for this
+ # thing in the onActiveDescendantChanged method.
+ #
+ if "activeDescendantInfo" in self.pointOfReference:
+ [parent, index] = \
+ self.pointOfReference['activeDescendantInfo']
+ newFocus = parent[index]
+
+ else:
+ # Well...we'll first see if there is a selection. If there
+ # is, we'll use it.
+ #
+ try:
+ selection = event.source.querySelection()
+ except NotImplementedError:
+ selection = None
+ if selection and selection.nSelectedChildren > 0:
+ newFocus = selection.getSelectedChild(0)
+
+ orca.setLocusOfFocus(event, newFocus)
+
+ def onLinkSelected(self, event):
+ """Called when a hyperlink is selected in a text area.
+
+ Arguments:
+ - event: the Event
+ """
+
+ # [[[TODO: WDW - HACK one might think we could expect an
+ # application to keep its name, but it appears as though
+ # yelp has an identity problem and likes to start calling
+ # itself "yelp," but then changes its name to "Mozilla"
+ # on Fedora Core 4 after the user selects a link. So, we'll
+ # just assume that link-selected events always come from the
+ # application with focus.]]]
+ #
+ #if orca_state.locusOfFocus \
+ # and (orca_state.locusOfFocus.app == event.source.app):
+ # orca.setLocusOfFocus(event, event.source)
+ orca.setLocusOfFocus(event, event.source)
+
+ def onMouseButton(self, event):
+ """Called whenever the user presses or releases a mouse button.
+
+ Arguments:
+ - event: the Event
+ """
+
+ # If we've received a mouse button released event, then check if
+ # there are and text selections for the locus of focus and speak
+ # them.
+ #
+ state = event.type[-1]
+ if state == "r":
+ obj = orca_state.locusOfFocus
+ try:
+ text = obj.queryText()
+ except:
+ pass
+ else:
+ [textContents, startOffset, endOffset] = \
+ self.utilities.allSelectedText(obj)
+ if textContents:
+ utterances = []
+ utterances.append(textContents)
+
+ # Translators: when the user selects (highlights) text in
+ # a document, Orca lets them know this.
+ #
+ utterances.append(C_("text", "selected"))
+ speech.speak(utterances)
+ self.updateBraille(orca_state.locusOfFocus)
+
+ def onNameChanged(self, event):
+ """Called whenever a property on an object changes.
+
+ Arguments:
+ - event: the Event
+ """
+
+ # [[[TODO: WDW - HACK because gnome-terminal issues a name changed
+ # event for the edit preferences dialog even though the name really
+ # didn't change. I'm guessing this is going to be a vagary in all
+ # of GTK+.]]]
+ #
+ # We are ignoring name changes in comboboxes that have focus
+ # see bgo#617204
+ ignoreList = [pyatspi.ROLE_DIALOG, pyatspi.ROLE_COMBO_BOX]
+ if event.source and (event.source.getRole() in ignoreList) \
+ and (event.source == orca_state.locusOfFocus):
+ return
+
+ # We do this because we can get name change events even if the
+ # name doesn't change. [[[TODO: WDW - I'm hesitant to rip the
+ # above TODO out, though, because it's been in here for so long.]]]
+ #
+ if self.pointOfReference.get('oldName', None) == event.source.name:
+ return
+
+ self.pointOfReference['oldName'] = event.source.name
+ self.visualAppearanceChanged(event, event.source)
+
+ def onSelectionChanged(self, event):
+ """Called when an object's selection changes.
+
+ Arguments:
+ - event: the Event
+ """
+
+ if not event or not event.source:
+ return
+
+ # Save the event source, if it is a menu or combo box. It will be
+ # useful for optimizing componentAtDesktopCoords in the case that
+ # the pointer is hovering over a menu item. The alternative is to
+ # traverse the application's tree looking for potential moused-over
+ # menu items.
+ if event.source.getRole() in (pyatspi.ROLE_COMBO_BOX,
+ pyatspi.ROLE_MENU):
+ self.lastSelectedMenu = event.source
+
+ # Avoid doing this with objects that manage their descendants
+ # because they'll issue a descendant changed event.
+ #
+ if event.source.getState().contains(pyatspi.STATE_MANAGES_DESCENDANTS):
+ return
+
+ if event.source.getRole() == pyatspi.ROLE_COMBO_BOX:
+ self.visualAppearanceChanged(event, event.source)
+
+ # We treat selected children as the locus of focus. When the
+ # selection changed we want to update the locus of focus. If
+ # there is no selection, we default the locus of focus to the
+ # containing object.
+ #
+ elif (event.source != orca_state.locusOfFocus) and \
+ event.source.getState().contains(pyatspi.STATE_FOCUSED):
+ newFocus = event.source
+ if event.source.childCount:
+ selection = event.source.querySelection()
+ if selection.nSelectedChildren > 0:
+ newFocus = selection.getSelectedChild(0)
+
+ orca.setLocusOfFocus(event, newFocus)
+
+ def onStateChanged(self, event):
+ """Called whenever an object's state changes.
+
+ Arguments:
+ - event: the Event
+ """
+
+ # Do we care?
+ #
+ if event.type.startswith("object:state-changed:active"):
+ if self.findCommandRun:
+ self.findCommandRun = False
+ self.find()
+ return
+
+ if event.type.startswith("object:state-changed:selected") \
+ and not _settingsManager.getSetting('onlySpeakDisplayedText') \
+ and orca_state.locusOfFocus:
+ # If this selection state change is for the object which
+ # currently has the locus of focus, and the last keyboard
+ # event was Space, or we are a focused table cell and we
+ # arrowed Down or Up and are now selected, then let the
+ # user know the selection state.
+ # See bugs #486908 and #519564 for more details.
+ #
+ announceState = False
+ keyString, mods = self.utilities.lastKeyAndModifiers()
+ state = orca_state.locusOfFocus.getState()
+ if state.contains(pyatspi.STATE_FOCUSED) \
+ and self.utilities.isSameObject(
+ event.source, orca_state.locusOfFocus):
+
+ if keyString == "space":
+ if mods & settings.CTRL_MODIFIER_MASK:
+ announceState = True
+ else:
+ # Weed out a bogus situation. If we are already
+ # selected and the user presses "space" again,
+ # we don't want to speak the intermediate
+ # "unselected" state.
+ #
+ eventState = event.source.getState()
+ selected = eventState.contains(pyatspi.STATE_SELECTED)
+ announceState = (selected and event.detail1)
+
+ elif keyString in ["Down", "Up"] \
+ and event.source.getRole() == pyatspi.ROLE_TABLE_CELL \
+ and state.contains(pyatspi.STATE_SELECTED):
+ announceState = True
+
+ if announceState:
+ voice = self.voices.get(settings.SYSTEM_VOICE)
+ if event.detail1:
+ # Translators: this object is now selected.
+ # Let the user know this.
+ #
+ #
+ speech.speak(C_("text", "selected"), voice, False)
+ else:
+ # Translators: this object is now unselected.
+ # Let the user know this.
+ #
+ #
+ speech.speak(C_("text", "unselected"), voice, False)
+ return
+
+ if event.type.startswith("object:state-changed:focused"):
+ iconified = False
+ try:
+ window = self.utilities.topLevelObject(event.source)
+ iconified = window.getState().contains(pyatspi.STATE_ICONIFIED)
+ except:
+ debug.println(debug.LEVEL_FINEST,
+ "onStateChanged: could not get frame of focused item")
+ if not iconified:
+ if event.detail1:
+ self.onFocus(event)
+ # We don't set locus of focus of None here because it
+ # wreaks havoc on the code that determines the context
+ # when you tab from widget to widget. For example,
+ # tabbing between panels in the gtk-demo buttons demo.
+ #
+ #else:
+ # orca.setLocusOfFocus(event, None)
+ return
+
+ # Handle tooltip popups.
+ #
+ if event.source.getRole() == pyatspi.ROLE_TOOL_TIP:
+ obj = event.source
+ if event.type.startswith("object:state-changed:showing"):
+ if event.detail1 == 1:
+ self.presentToolTip(obj)
+ elif orca_state.locusOfFocus:
+ keyString, mods = self.utilities.lastKeyAndModifiers()
+ if keyString == "F1":
+ self.updateBraille(orca_state.locusOfFocus)
+ utterances = self.speechGenerator.generateSpeech(
+ orca_state.locusOfFocus)
+ utterances.extend(self.tutorialGenerator.getTutorial(
+ orca_state.locusOfFocus, False))
+ speech.speak(utterances)
+ return
+
+ if event.source.getRole() in state_change_notifiers:
+ notifiers = state_change_notifiers[event.source.getRole()]
+ found = False
+ for state in notifiers:
+ if state and event.type.endswith(state):
+ found = True
+ break
+ if found:
+ self.visualAppearanceChanged(event, event.source)
+
+ def onTextAttributesChanged(self, event):
+ """Called when an object's text attributes change. Right now this
+ method is only to handle the presentation of spelling errors on
+ the fly. Also note that right now, the Gecko toolkit is the only
+ one to present this information to us.
+
+ Arguments:
+ - event: the Event
+ """
+
+ verbosity = _settingsManager.getSetting('speechVerbosityLevel')
+ if verbosity == settings.VERBOSITY_LEVEL_VERBOSE \
+ and self.utilities.isSameObject(
+ event.source, orca_state.locusOfFocus):
+ try:
+ text = event.source.queryText()
+ except:
+ return
+
+ # If the misspelled word indicator has just appeared, it's
+ # because the user typed a word boundary or navigated out
+ # of the word. We don't want to have to store a full set of
+ # each object's text attributes to compare, therefore, we'll
+ # check the previous word (most likely case) and the next
+ # word with respect to the current position.
+ #
+ prevWordAndOffsets = \
+ text.getTextAtOffset(text.caretOffset - 1,
+ pyatspi.TEXT_BOUNDARY_WORD_START)
+ nextWordAndOffsets = \
+ text.getTextAtOffset(text.caretOffset + 1,
+ pyatspi.TEXT_BOUNDARY_WORD_START)
+
+ if self.utilities.isWordMisspelled(
+ event.source, prevWordAndOffsets[1] ) \
+ or self.utilities.isWordMisspelled(
+ event.source, nextWordAndOffsets[1]):
+ # Translators: this is to inform the user of the presence
+ # of the red squiggly line which indicates that a given
+ # word is not spelled correctly.
+ #
+ self.speakMessage(_("misspelled"))
+
+ def onTextDeleted(self, event):
+ """Called whenever text is deleted from an object.
+
+ Arguments:
+ - event: the Event
+ """
+
+ # Ignore text deletions from non-focused objects, unless the
+ # currently focused object is the parent of the object from which
+ # text was deleted
+ #
+ if (event.source != orca_state.locusOfFocus) \
+ and (event.source.parent != orca_state.locusOfFocus):
+ return
+
+ # We'll also ignore sliders because we get their output via
+ # their values changing.
+ #
+ if event.source.getRole() == pyatspi.ROLE_SLIDER:
+ return
+
+ # [[[NOTE: WDW - if we handle events synchronously, we'll
+ # be looking at the text object *before* the text was
+ # actually removed from the object. If we handle events
+ # asynchronously, we'll be looking at the text object
+ # *after* the text was removed. The importance of knowing
+ # this is that the output will differ depending upon how
+ # orca.settings.asyncMode has been set. For example, the
+ # regression tests run in synchronous mode, so the output
+ # they see will not be the same as what the user normally
+ # experiences.]]]
+
+ self.updateBraille(event.source)
+
+ # The any_data member of the event object has the deleted text in
+ # it - If the last key pressed was a backspace or delete key,
+ # speak the deleted text. [[[TODO: WDW - again, need to think
+ # about the ramifications of this when it comes to editors such
+ # as vi or emacs.
+ #
+ keyString, mods = self.utilities.lastKeyAndModifiers()
+ if not keyString:
+ return
+
+ text = event.source.queryText()
+ if keyString == "BackSpace":
+ # Speak the character that has just been deleted.
+ #
+ character = event.any_data
+
+ elif keyString == "Delete" \
+ or (keyString == "D" and mods & settings.CTRL_MODIFIER_MASK):
+ # Speak the character to the right of the caret after
+ # the current right character has been deleted.
+ #
+ offset = text.caretOffset
+ [character, startOffset, endOffset] = \
+ text.getTextAtOffset(offset, pyatspi.TEXT_BOUNDARY_CHAR)
+
+ else:
+ return
+
+ if self.utilities.linkIndex(event.source, text.caretOffset) >= 0:
+ voice = self.voices[settings.HYPERLINK_VOICE]
+ elif character.decode("UTF-8").isupper():
+ voice = self.voices[settings.UPPERCASE_VOICE]
+ else:
+ voice = self.voices[settings.DEFAULT_VOICE]
+
+ # We won't interrupt what else might be being spoken
+ # right now because it is typically something else
+ # related to this event.
+ #
+ if len(character.decode('utf-8')) == 1:
+ speech.speakCharacter(character, voice)
+ else:
+ speech.speak(character, voice, False)
+
+ def onTextInserted(self, event):
+ """Called whenever text is inserted into an object.
+
+ Arguments:
+ - event: the Event
+ """
+
+ # Ignore text insertions from non-focused objects, unless the
+ # currently focused object is the parent of the object from which
+ # text was inserted.
+ #
+ if (event.source != orca_state.locusOfFocus) \
+ and (event.source.parent != orca_state.locusOfFocus):
+ return
+
+ # We'll also ignore sliders because we get their output via
+ # their values changing.
+ #
+ if event.source.getRole() == pyatspi.ROLE_SLIDER:
+ return
+
+ self.updateBraille(event.source)
+
+ if event.source.getRole() == pyatspi.ROLE_SPIN_BUTTON:
+ # We cannot use the event.any_data due to a problem with
+ # selected text in spin buttons. See bug #520395 for more
+ # details.
+ #
+ [value, caret, start] = self.getTextLineAtCaret(event.source)
+ speech.speak(value)
+ return
+
+ # If the last input event was a keyboard event, check to see if
+ # the text for this event matches what the user typed. If it does,
+ # then don't speak it.
+ #
+ # Note that the text widgets sometimes compress their events,
+ # thus we might get a longer string from a single text inserted
+ # event, while we also get individual keyboard events for the
+ # characters used to type the string. This is ugly. We attempt
+ # to handle it here by only echoing text if we think it was the
+ # result of a command (e.g., a paste operation).
+ #
+ # Note that we have to special case the space character as it
+ # comes across as "space" in the keyboard event and " " in the
+ # text event.
+ #
+ string = event.any_data
+ speakThis = False
+ if isinstance(orca_state.lastInputEvent, input_event.MouseButtonEvent) \
+ and orca_state.lastInputEvent.button == "2":
+ speakThis = True
+
+ else:
+ keyString, mods = self.utilities.lastKeyAndModifiers()
+ wasCommand = mods & settings.COMMAND_MODIFIER_MASK
+ wasAutoComplete = (event.source.getRole() == pyatspi.ROLE_TEXT \
+ and event.source.queryText().getNSelections())
+
+ if (string == " " and keyString == "space") or string == keyString:
+ pass
+ elif wasCommand or wasAutoComplete:
+ speakThis = True
+ elif event.source.getRole() == pyatspi.ROLE_PASSWORD_TEXT \
+ and _settingsManager.getSetting('enableKeyEcho') \
+ and _settingsManager.getSetting('enablePrintableKeys'):
+ # Echoing "star" is preferable to echoing the descriptive
+ # name of the bullet that has appeared (e.g. "black circle")
+ #
+ string = "*"
+ speakThis = True
+
+ # Auto-completed, auto-corrected, auto-inserted, etc.
+ #
+ speakThis = speakThis or self.utilities.isAutoTextEvent(event)
+
+ # We might need to echo this if it is a single character.
+ #
+ speakThis = speakThis \
+ or (_settingsManager.getSetting('enableEchoByCharacter') \
+ and string \
+ and event.source.getRole() \
+ != pyatspi.ROLE_PASSWORD_TEXT \
+ and len(string.decode("UTF-8")) == 1)
+
+ if speakThis:
+ if string.decode("UTF-8").isupper():
+ speech.speak(string, self.voices[settings.UPPERCASE_VOICE])
+ else:
+ speech.speak(string)
+
+ try:
+ text = event.source.queryText()
+ except NotImplementedError:
+ return
+
+ offset = min(event.detail1, text.caretOffset - 1)
+ previousOffset = offset - 1
+ if (offset < 0 or previousOffset < 0):
+ return
+
+ [currentChar, startOffset, endOffset] = \
+ text.getTextAtOffset(offset, pyatspi.TEXT_BOUNDARY_CHAR)
+ [previousChar, startOffset, endOffset] = \
+ text.getTextAtOffset(previousOffset, pyatspi.TEXT_BOUNDARY_CHAR)
+
+ if _settingsManager.getSetting('enableEchoBySentence') \
+ and self.utilities.isSentenceDelimiter(currentChar, previousChar):
+ self.echoPreviousSentence(event.source)
+
+ elif _settingsManager.getSetting('enableEchoByWord') \
+ and self.utilities.isWordDelimiter(currentChar):
+ self.echoPreviousWord(event.source)
+
+ def onTextSelectionChanged(self, event):
+ """Called when an object's text selection changes.
+
+ Arguments:
+ - event: the Event
+ """
+
+ obj = event.source
+ spokenRange = self.pointOfReference.get("spokenTextRange") or [0, 0]
+ startOffset, endOffset = spokenRange
+
+ if not obj.getState().contains(pyatspi.STATE_FOCUSED):
+ # We're selecting across paragraph (or other text object)
+ # boundaries. If we're here, the selection has changed in
+ # an object which does not have the caret. We need to try
+ # to sort this out.
+ #
+ lastPos = self.pointOfReference.get("lastCursorPosition")
+ if not lastPos:
+ # We have no point of reference. Bail.
+ #
+ return
+ elif endOffset - startOffset > 1:
+ # We're coming at the line from below. And didn't just
+ # land on a blank/empty line. We have other methods for
+ # dealing with this situation.
+ #
+ return
+ else:
+ # If we do a select all in a document in which each
+ # paragraph is a separate accessible object, we'll
+ # get an event for each of those objects. We don't
+ # want to repeat "(un)selected". See bug #583811.
+ #
+ diff = lastPos[0].getIndexInParent() - obj.getIndexInParent()
+ if abs(diff) > 1:
+ # We can skip this one because we'll do the
+ # announcement based on another one.
+ #
+ return
+ elif startOffset > 0 and startOffset == endOffset:
+ try:
+ text = lastPos[0].queryText()
+ except:
+ pass
+ else:
+ if startOffset == text.characterCount:
+ return
+
+ # We must be approaching from the top, left, or right. Or
+ # from below but we've found a blank line. Our stored point
+ # of reference tells us our caret location. Figure out how
+ # we got here by looking at our position with respect to
+ # the event under consideration.
+ #
+ relationType = None
+ for relation in lastPos[0].getRelationSet():
+ if relation.getRelationType() in [pyatspi.RELATION_FLOWS_FROM,
+ pyatspi.RELATION_FLOWS_TO] \
+ and self.utilities.isSameObject(obj, relation.getTarget(0)):
+ relationType = relation.getRelationType()
+ break
+
+ # If there's a completely blank line in between our previous
+ # and current locations, where we came from will lack any
+ # offically-selectable characters. As a result, we won't
+ # indicate when a blank line has been selected. Under these
+ # conditions, we'll try to backtrack further.
+ #
+ endOffset = 0
+ while obj and not endOffset:
+ try:
+ endOffset = obj.queryText().characterCount
+ startOffset = max(0, endOffset - 1)
+ except:
+ pass
+
+ if not endOffset:
+ for relation in obj.getRelationSet():
+ if relation.getRelationType() == relationType:
+ obj = relation.getTarget(0)
+ break
+ else:
+ break
+
+ self.speakTextSelectionState(obj, startOffset, endOffset)
+
+ def onValueChanged(self, event):
+ """Called whenever an object's value changes. Currently, the
+ value changes for non-focused objects are ignored.
+
+ Arguments:
+ - event: the Event
+ """
+
+ # We'll let caret moved and text inserted events be used to
+ # manage spin buttons, since they basically are text areas.
+ #
+ if event.source.getRole() == pyatspi.ROLE_SPIN_BUTTON:
+ return
+
+ # We'll also try to ignore those objects that keep telling
+ # us their value changed even though it hasn't.
+ #
+ value = event.source.queryValue()
+ if "oldValue" in self.pointOfReference \
+ and (value.currentValue == self.pointOfReference["oldValue"]):
+ return
+
+ self.visualAppearanceChanged(event, event.source)
+ if event.source.getState().contains(pyatspi.STATE_FOCUSED):
+ self.pointOfReference["oldValue"] = value.currentValue
+
+ def onWindowActivated(self, event):
+ """Called whenever a toplevel window is activated.
+
+ Arguments:
+ - event: the Event
+ """
+
+ self.windowActivateTime = time.time()
+ orca.setLocusOfFocus(event, event.source)
+
+ # We keep track of the active window to handle situations where
+ # we get window activated and window deactivated events out of
+ # order (see onWindowDeactivated).
+ #
+ # For example, events can be:
+ #
+ # window:activate (w1)
+ # window:activate (w2)
+ # window:deactivate (w1)
+ #
+ # as well as:
+ #
+ # window:activate (w1)
+ # window:deactivate (w1)
+ # window:activate (w2)
+ #
+ orca_state.activeWindow = event.source
+
+ def onWindowDeactivated(self, event):
+ """Called whenever a toplevel window is deactivated.
+
+ Arguments:
+ - event: the Event
+ """
+
+ # If we receive a "window:deactivate" event for the object that
+ # currently has focus, then stop the current speech output.
+ # This is very useful for terminating long speech output from
+ # commands running in gnome-terminal.
+ #
+ if orca_state.locusOfFocus and \
+ (orca_state.locusOfFocus.getApplication() == \
+ event.source.getApplication()):
+ speech.stop()
+
+ # Clear the braille display just in case we are about to give
+ # focus to an inaccessible application. See bug #519901 for
+ # more details.
+ #
+ self.clearBraille()
+
+ # Hide the flat review window and reset it so that it will be
+ # recreated.
+ #
+ if self.flatReviewContext:
+ self.drawOutline(-1, 0, 0, 0)
+ self.flatReviewContext = None
+ self.updateBraille(orca_state.locusOfFocus)
+
+ # Because window activated and deactivated events may be
+ # received in any order when switching from one application to
+ # another, locusOfFocus and activeWindow, we really only change
+ # the locusOfFocus and activeWindow when we are dealing with
+ # an event from the current activeWindow.
+ #
+ if event.source == orca_state.activeWindow:
+ orca.setLocusOfFocus(event, None)
+ orca_state.activeWindow = None
+
+ # disable list notification messages mode
+ notification_messages.listNotificationMessagesModeEnabled = False
+
+ # disable learn mode
+ _settingsManager.setSetting('learnModeEnabled', False)
+
+ # disable list shortcuts mode
+ _settingsManager.setSetting('listShortcutsModeEnabled', False)
+ orca_state.listOfShortcuts = []
+ orca_state.typeOfShortcuts = ""
+
+ ########################################################################
+ # #
+ # Methods for presenting content #
+ # #
+ ########################################################################
+
+ def _presentTextAtNewCaretPosition(self, event, otherObj=None):
+ """Updates braille, magnification, and outputs speech for the
+ event.source or the otherObj."""
+
+ obj = otherObj or event.source
+ text = obj.queryText()
+
+ if obj:
+ mag.magnifyAccessible(event, obj)
+
+ # Update the Braille display - if we can just reposition
+ # the cursor, then go for it.
+ #
+ brailleNeedsRepainting = True
+ line = braille.getShowingLine()
+ for region in line.regions:
+ if isinstance(region, braille.Text) \
+ and (region.accessible == obj):
+ if region.repositionCursor():
+ self.refreshBraille(True)
+ brailleNeedsRepainting = False
+ break
+
+ if brailleNeedsRepainting:
+ self.updateBraille(obj)
+
+ if not orca_state.lastInputEvent:
+ return
+
+ if isinstance(orca_state.lastInputEvent, input_event.MouseButtonEvent):
+ if not orca_state.lastInputEvent.pressed:
+ self.sayLine(obj)
+ return
+
+ # Guess why the caret moved and say something appropriate.
+ # [[[TODO: WDW - this motion assumes traditional GUI
+ # navigation gestures. In an editor such as vi, line up and
+ # down is done via other actions such as "i" or "j". We may
+ # need to think about this a little harder.]]]
+ #
+ keyString, mods = self.utilities.lastKeyAndModifiers()
+ if not keyString:
+ return
+ isControlKey = mods & settings.CTRL_MODIFIER_MASK
+ isShiftKey = mods & settings.SHIFT_MODIFIER_MASK
+ lastPos = self.pointOfReference.get("lastCursorPosition")
+ hasLastPos = (lastPos != None)
+
+ if keyString in ["Up", "Down"]:
+ # If the user has typed Shift-Up or Shift-Down, then we want
+ # to speak the text that has just been selected or unselected,
+ # otherwise we speak the new line where the text cursor is
+ # currently positioned.
+ #
+ if hasLastPos and isShiftKey and not isControlKey:
+ if keyString == "Up":
+ # If we have just crossed a paragraph boundary with
+ # Shift+Up, what we've selected in this object starts
+ # with the current offset and goes to the end of the
+ # paragraph.
+ #
+ if not self.utilities.isSameObject(lastPos[0], obj):
+ [startOffset, endOffset] = \
+ text.caretOffset, text.characterCount
+ else:
+ [startOffset, endOffset] = \
+ self.utilities.offsetsForPhrase(obj)
+ self.sayPhrase(obj, startOffset, endOffset)
+ selSpoken = self._speakContiguousSelection(obj,
+ pyatspi.RELATION_FLOWS_TO)
+ else:
+ selSpoken = self._speakContiguousSelection(obj,
+ pyatspi.RELATION_FLOWS_FROM)
+
+ # If we have just crossed a paragraph boundary with
+ # Shift+Down, what we've selected in this object starts
+ # with the beginning of the paragraph and goes to the
+ # current offset.
+ #
+ if not self.utilities.isSameObject(lastPos[0], obj):
+ [startOffset, endOffset] = 0, text.caretOffset
+ else:
+ [startOffset, endOffset] \
+ = self.utilities.offsetsForPhrase(obj)
+
+ if startOffset != endOffset:
+ self.sayPhrase(obj, startOffset, endOffset)
+
+ else:
+ [startOffset, endOffset] = self.utilities.offsetsForLine(obj)
+ self.sayLine(obj)
+
+ elif keyString in ["Left", "Right"]:
+ # If the user has typed Control-Shift-Up or Control-Shift-Dowm,
+ # then we want to speak the text that has just been selected
+ # or unselected, otherwise if the user has typed Control-Left
+ # or Control-Right, we speak the current word otherwise we speak
+ # the character at the text cursor position.
+ #
+ inNewObj = hasLastPos \
+ and not self.utilities.isSameObject(lastPos[0], obj)
+
+ if hasLastPos and not inNewObj and isShiftKey and isControlKey:
+ [startOffset, endOffset] = self.utilities.offsetsForPhrase(obj)
+ self.sayPhrase(obj, startOffset, endOffset)
+ elif isControlKey and not isShiftKey:
+ [startOffset, endOffset] = self.utilities.offsetsForWord(obj)
+ if startOffset == endOffset:
+ self.sayCharacter(obj)
+ else:
+ self.sayWord(obj)
+ else:
+ [startOffset, endOffset] = self.utilities.offsetsForChar(obj)
+ self.sayCharacter(obj)
+
+ elif keyString == "Page_Up":
+ # If the user has typed Control-Shift-Page_Up, then we want
+ # to speak the text that has just been selected or unselected,
+ # otherwise if the user has typed Control-Page_Up, then we
+ # speak the character to the right of the current text cursor
+ # position otherwise we speak the current line.
+ #
+ if hasLastPos and isShiftKey and isControlKey:
+ [startOffset, endOffset] = self.utilities.offsetsForPhrase(obj)
+ self.sayPhrase(obj, startOffset, endOffset)
+ elif isControlKey:
+ [startOffset, endOffset] = self.utilities.offsetsForChar(obj)
+ self.sayCharacter(obj)
+ else:
+ [startOffset, endOffset] = self.utilities.offsetsForLine(obj)
+ self.sayLine(obj)
+
+ elif keyString == "Page_Down":
+ # If the user has typed Control-Shift-Page_Down, then we want
+ # to speak the text that has just been selected or unselected,
+ # otherwise if the user has just typed Page_Down, then we speak
+ # the current line.
+ #
+ if hasLastPos and isShiftKey and isControlKey:
+ [startOffset, endOffset] = self.utilities.offsetsForPhrase(obj)
+ self.sayPhrase(obj, startOffset, endOffset)
+ else:
+ [startOffset, endOffset] = self.utilities.offsetsForLine(obj)
+ self.sayLine(obj)
+
+ elif keyString in ["Home", "End"]:
+ # If the user has typed Shift-Home or Shift-End, then we want
+ # to speak the text that has just been selected or unselected,
+ # otherwise if the user has typed Control-Home or Control-End,
+ # then we speak the current line otherwise we speak the character
+ # to the right of the current text cursor position.
+ #
+ if hasLastPos and isShiftKey and not isControlKey:
+ [startOffset, endOffset] = self.utilities.offsetsForPhrase(obj)
+ self.sayPhrase(obj, startOffset, endOffset)
+ elif isControlKey:
+ [startOffset, endOffset] = self.utilities.offsetsForLine(obj)
+ self.sayLine(obj)
+ else:
+ [startOffset, endOffset] = self.utilities.offsetsForChar(obj)
+ self.sayCharacter(obj)
+
+ else:
+ startOffset = text.caretOffset
+ endOffset = text.caretOffset
+
+ self._saveLastCursorPosition(obj, text.caretOffset)
+ self._saveSpokenTextRange(startOffset, endOffset)
+
+ def __sayAllProgressCallback(self, context, progressType):
+ # [[[TODO: WDW - this needs work. Need to be able to manage
+ # the monitoring of progress and couple that with both updating
+ # the visual progress of what is being spoken as well as
+ # positioning the cursor when speech has stopped.]]]
+ #
+ text = context.obj.queryText()
+ if progressType == speechserver.SayAllContext.PROGRESS:
+ #print "PROGRESS", context.utterance, context.currentOffset
+ #obj = context.obj
+ #[x, y, width, height] = obj.text.getCharacterExtents(
+ # context.currentOffset, 0)
+ #print context.currentOffset, x, y, width, height
+ #self.drawOutline(x, y, width, height)
+ return
+ elif progressType == speechserver.SayAllContext.INTERRUPTED:
+ #print "INTERRUPTED", context.utterance, context.currentOffset
+ text.setCaretOffset(context.currentOffset)
+ elif progressType == speechserver.SayAllContext.COMPLETED:
+ #print "COMPLETED", context.utterance, context.currentOffset
+ orca.setLocusOfFocus(None, context.obj, notifyScript=False)
+ text.setCaretOffset(context.currentOffset)
+
+ # If there is a selection, clear it. See bug #489504 for more details.
+ #
+ if text.getNSelections():
+ text.setSelection(0, context.currentOffset, context.currentOffset)
+
+ def _speakContiguousSelection(self, obj, relationship):
+ """Check if the contiguous object has a selection. If it does, then
+ speak it. If the user pressed Shift-Down, then look for an object
+ with a RELATION_FLOWS_FROM relationship. If they pressed Shift-Up,
+ then look for a RELATION_FLOWS_TO relationship.
+
+ Arguments:
+ - the current text object
+ - the flows relationship (RELATION_FLOWS_FROM or RELATION_FLOWS_TO).
+
+ Returns an indication of whether anything was spoken.
+ """
+
+ lastPos = self.pointOfReference.get("lastCursorPosition")
+
+ # Reasons to NOT speak contiguous selections:
+ #
+ # 1. The new cursor position is in the same object as the old
+ # cursor position. (The change in selection is all within
+ # the current object.)
+ # 2. If we are selecting up line by line from the beginning of
+ # the line and have just crossed into a new object, the change
+ # in selection is the previous line (which has just become
+ # selected). Nothing has changed on the line we came from.
+ #
+ if self.utilities.isSameObject(lastPos[0], obj) \
+ or relationship == pyatspi.RELATION_FLOWS_TO and lastPos[1] == 0:
+ return False
+
+ selSpoken = False
+ current = obj
+ for relation in current.getRelationSet():
+ if relation.getRelationType() == relationship:
+ obj = relation.getTarget(0)
+ objText = obj.queryText()
+
+ # When selecting down across paragraph boundaries, what
+ # we've (un)selected on (what is now) the previous line
+ # is from wherever the cursor used to be to the end of
+ # the line.
+ #
+ if relationship == pyatspi.RELATION_FLOWS_FROM:
+ start, end = lastPos[1], objText.characterCount
+
+ # When selecting up across paragraph boundaries, what
+ # we've (un)selected on (what is now) the next line is
+ # from the beginning of the line to wherever the cursor
+ # used to be.
+ #
+ else:
+ start, end = 0, lastPos[1]
+
+ if objText.getNSelections() > 0:
+ [textContents, startOffset, endOffset] = \
+ self.utilities.selectedText(obj)
+
+ # Now that we have the full selection, adjust based
+ # on the relation type. (see above comment)
+ #
+ startOffset = start or startOffset
+ endOffset = end or endOffset
+ self.sayPhrase(obj, startOffset, endOffset)
+ selSpoken = True
+ else:
+ # We don't have selections in this object. But we're
+ # here, which means that something is selected in a
+ # neighboring object and the text in this object must
+ # have just become unselected and needs to be spoken.
+ #
+ self.sayPhrase(obj, start, end)
+ selSpoken = True
+
+ return selSpoken
+
+ def echoPreviousSentence(self, obj):
+ """Speaks the sentence prior to the caret, as long as there is
+ a sentence prior to the caret and there is no intervening sentence
+ delimiter between the caret and the end of the sentence.
+
+ The entry condition for this method is that the character
+ prior to the current caret position is a sentence delimiter,
+ and it's what caused this method to be called in the first
+ place.
+
+ Arguments:
+ - obj: an Accessible object that implements the AccessibleText
+ interface.
+ """
+
+ try:
+ text = obj.queryText()
+ except NotImplementedError:
+ return
+
+ offset = text.caretOffset - 1
+ previousOffset = text.caretOffset - 2
+ if (offset < 0 or previousOffset < 0):
+ return
+
+ [currentChar, startOffset, endOffset] = \
+ text.getTextAtOffset(offset, pyatspi.TEXT_BOUNDARY_CHAR)
+ [previousChar, startOffset, endOffset] = \
+ text.getTextAtOffset(previousOffset, pyatspi.TEXT_BOUNDARY_CHAR)
+ if not self.utilities.isSentenceDelimiter(currentChar, previousChar):
+ return
+
+ # OK - we seem to be cool so far. So...starting with what
+ # should be the last character in the sentence (caretOffset - 2),
+ # work our way to the beginning of the sentence, stopping when
+ # we hit another sentence delimiter.
+ #
+ sentenceEndOffset = text.caretOffset - 2
+ sentenceStartOffset = sentenceEndOffset
+
+ while sentenceStartOffset >= 0:
+ [currentChar, startOffset, endOffset] = \
+ text.getTextAtOffset(sentenceStartOffset,
+ pyatspi.TEXT_BOUNDARY_CHAR)
+ [previousChar, startOffset, endOffset] = \
+ text.getTextAtOffset(sentenceStartOffset-1,
+ pyatspi.TEXT_BOUNDARY_CHAR)
+ if self.utilities.isSentenceDelimiter(currentChar, previousChar):
+ break
+ else:
+ sentenceStartOffset -= 1
+
+ # If we came across a sentence delimiter before hitting any
+ # text, we really don't have a previous sentence.
+ #
+ # Otherwise, get the sentence. Remember we stopped when we
+ # hit a sentence delimiter, so the sentence really starts at
+ # sentenceStartOffset + 1. getText also does not include
+ # the character at sentenceEndOffset, so we need to adjust
+ # for that, too.
+ #
+ if sentenceStartOffset == sentenceEndOffset:
+ return
+ else:
+ sentence = self.utilities.substring(obj, sentenceStartOffset + 1,
+ sentenceEndOffset + 1)
+
+ if self.utilities.linkIndex(obj, sentenceStartOffset + 1) >= 0:
+ voice = self.voices[settings.HYPERLINK_VOICE]
+ elif sentence.decode("UTF-8").isupper():
+ voice = self.voices[settings.UPPERCASE_VOICE]
+ else:
+ voice = self.voices[settings.DEFAULT_VOICE]
+
+ sentence = self.utilities.adjustForRepeats(sentence)
+ speech.speak(sentence, voice)
+
+ def echoPreviousWord(self, obj, offset=None):
+ """Speaks the word prior to the caret, as long as there is
+ a word prior to the caret and there is no intervening word
+ delimiter between the caret and the end of the word.
+
+ The entry condition for this method is that the character
+ prior to the current caret position is a word delimiter,
+ and it's what caused this method to be called in the first
+ place.
+
+ Arguments:
+ - obj: an Accessible object that implements the AccessibleText
+ interface.
+ - offset: if not None, the offset within the text to use as the
+ end of the word.
+ """
+
+ try:
+ text = obj.queryText()
+ except NotImplementedError:
+ return
+
+ if not offset:
+ offset = text.caretOffset - 1
+ if (offset < 0):
+ return
+
+ [char, startOffset, endOffset] = \
+ text.getTextAtOffset( \
+ offset,
+ pyatspi.TEXT_BOUNDARY_CHAR)
+ if not self.utilities.isWordDelimiter(char):
+ return
+
+ # OK - we seem to be cool so far. So...starting with what
+ # should be the last character in the word (caretOffset - 2),
+ # work our way to the beginning of the word, stopping when
+ # we hit another word delimiter.
+ #
+ wordEndOffset = offset - 1
+ wordStartOffset = wordEndOffset
+
+ while wordStartOffset >= 0:
+ [char, startOffset, endOffset] = \
+ text.getTextAtOffset( \
+ wordStartOffset,
+ pyatspi.TEXT_BOUNDARY_CHAR)
+ if self.utilities.isWordDelimiter(char):
+ break
+ else:
+ wordStartOffset -= 1
+
+ # If we came across a word delimiter before hitting any
+ # text, we really don't have a previous word.
+ #
+ # Otherwise, get the word. Remember we stopped when we
+ # hit a word delimiter, so the word really starts at
+ # wordStartOffset + 1. getText also does not include
+ # the character at wordEndOffset, so we need to adjust
+ # for that, too.
+ #
+ if wordStartOffset == wordEndOffset:
+ return
+ else:
+ word = self.utilities.\
+ substring(obj, wordStartOffset + 1, wordEndOffset + 1)
+
+ if self.utilities.linkIndex(obj, wordStartOffset + 1) >= 0:
+ voice = self.voices[settings.HYPERLINK_VOICE]
+ elif word.decode("UTF-8").isupper():
+ voice = self.voices[settings.UPPERCASE_VOICE]
+ else:
+ voice = self.voices[settings.DEFAULT_VOICE]
+
+ word = self.utilities.adjustForRepeats(word)
+ speech.speak(word, voice)
+
+ def handleProgressBarUpdate(self, event, obj):
+ """Determine whether this progress bar event should be spoken or not.
+ It should be spoken if:
+ 1/ settings.enableProgressBarUpdates is True.
+ 2/ settings.progressBarVerbosity matches the current location of the
+ progress bar.
+ 3/ The time of this event exceeds the
+ settings.progressBarUpdateInterval value. This value
+ indicates the time (in seconds) between potential spoken
+ progress bar updates.
+ 4/ The new value of the progress bar (converted to an integer),
+ is different from the last one or equals 100 (i.e complete).
+
+ Arguments:
+ - event: if not None, the Event that caused this to happen
+ - obj: the Accessible progress bar object.
+ """
+
+ if _settingsManager.getSetting('enableProgressBarUpdates'):
+ makeAnnouncement = False
+ verbosity = _settingsManager.getSetting('progressBarVerbosity')
+ if verbosity == settings.PROGRESS_BAR_ALL:
+ makeAnnouncement = True
+ elif verbosity == settings.PROGRESS_BAR_WINDOW:
+ makeAnnouncement = self.utilities.isSameObject(
+ self.utilities.topLevelObject(obj),
+ self.utilities.activeWindow())
+ elif orca_state.locusOfFocus:
+ makeAnnouncement = self.utilities.isSameObject( \
+ obj.getApplication(),
+ orca_state.locusOfFocus.getApplication())
+
+ if makeAnnouncement:
+ currentTime = time.time()
+
+ # Check for defunct progress bars. Get rid of them if they
+ # are all defunct. Also find out which progress bar was
+ # the most recently updated.
+ #
+ defunctBars = 0
+ mostRecentUpdate = [obj, 0]
+ for key, value in self.lastProgressBarTime.items():
+ if value > mostRecentUpdate[1]:
+ mostRecentUpdate = [key, value]
+ try:
+ isDefunct = \
+ key.getState().contains(pyatspi.STATE_DEFUNCT)
+ except:
+ isDefunct = True
+ if isDefunct:
+ defunctBars += 1
+
+ if defunctBars == len(self.lastProgressBarTime):
+ self.lastProgressBarTime = {}
+ self.lastProgressBarValue = {}
+
+ # If this progress bar is not already known, create initial
+ # values for it.
+ #
+ if obj not in self.lastProgressBarTime:
+ self.lastProgressBarTime[obj] = 0.0
+ if obj not in self.lastProgressBarValue:
+ self.lastProgressBarValue[obj] = None
+
+ lastProgressBarTime = self.lastProgressBarTime[obj]
+ lastProgressBarValue = self.lastProgressBarValue[obj]
+ value = obj.queryValue()
+ percentValue = int((value.currentValue / \
+ (value.maximumValue - value.minimumValue)) * 100.0)
+
+ if (currentTime - lastProgressBarTime) > \
+ _settingsManager.getSetting('progressBarUpdateInterval') \
+ or percentValue == 100:
+ if lastProgressBarValue != percentValue:
+ utterances = []
+
+ # There may be cases when more than one progress
+ # bar is updating at the same time in a window.
+ # If this is the case, then speak the index of this
+ # progress bar in the dictionary of known progress
+ # bars, as well as the value. But only speak the
+ # index if this progress bar was not the most
+ # recently updated to prevent chattiness.
+ #
+ if len(self.lastProgressBarTime) > 1:
+ index = 0
+ for key in self.lastProgressBarTime.keys():
+ if key == obj and key != mostRecentUpdate[0]:
+ # Translators: this is an index value
+ # so that we can tell which progress bar
+ # we are referring to.
+ #
+ label = _("Progress bar %d.") % (index + 1)
+ utterances.append(label)
+ else:
+ index += 1
+
+ utterances.extend(self.speechGenerator.generateSpeech(
+ obj, alreadyFocused=True))
+
+ speech.speak(utterances)
+
+ self.lastProgressBarTime[obj] = currentTime
+ self.lastProgressBarValue[obj] = percentValue
+
+ def outputCharAttributes(self, keys, attributes):
+ """Speak each of the text attributes given dictionary.
+
+ Arguments:
+ - attributes: a dictionary of text attributes to speak.
+ """
+
+ for key in keys:
+ localizedKey = text_attribute_names.getTextAttributeName(key)
+ if key in attributes:
+ line = ""
+ attribute = attributes[key]
+ localizedValue = \
+ text_attribute_names.getTextAttributeName(attribute)
+ if attribute:
+ key = self.getAtkNameForAttribute(key)
+ # If it's the 'weight' attribute and greater than 400, just
+ # speak it as bold, otherwise speak the weight.
+ #
+ if key == "weight" \
+ and (attribute == "bold" or int(attribute) > 400):
+ # Translators: bold as in the font sense.
+ #
+ line = _("bold")
+ elif key in ["left-margin", "right-margin"]:
+ # We need to test if we are getting a margin value
+ # that includes unit information (OOo now provides
+ # this). If not, then we will assume it's pixels.
+ #
+ numericPoint = locale.localeconv()["decimal_point"]
+ lastChar = attribute[len(attribute) - 1]
+ if lastChar == numericPoint or \
+ lastChar in self.digits:
+ # Translators: these represent the number of pixels
+ # for the left or right margins in a document. We
+ # are hesitant to interpret the values -- they are
+ # given to us in some unknown form by the
+ # application, so we leave things in plural form
+ # here.
+ #
+ line = ngettext("%(key)s %(value)s pixel",
+ "%(key)s %(value)s pixels",
+ int(attribute)) \
+ % {"key" : localizedKey,
+ "value": localizedValue}
+ elif key in ["indent", "size"]:
+ # In Gecko, we seem to get these values as a number
+ # immediately followed by "px". But we'll hedge our
+ # bet.
+ #
+ value = attribute.split("px")
+ if len(value) > 1:
+ line = ngettext("%(key)s %(value)s pixel",
+ "%(key)s %(value)s pixels",
+ float(value[0])) \
+ % {"key" : localizedKey,
+ "value" : value[0]}
+ elif key == "family-name":
+ # In Gecko, we get a huge list and we just want the
+ # first one. See:
+ # http://www.w3.org/TR/CSS2/fonts.html#font-family-prop
+ #
+ localizedValue = \
+ attribute.split(",")[0].strip().strip('"')
+
+ line = line or (localizedKey + " " + localizedValue)
+ self.speakMessage(line)
+
+ def presentToolTip(self, obj):
+ """
+ Speaks the tooltip for the current object of interest.
+ """
+
+ # The tooltip is generally the accessible description. If
+ # the description is not set, present the text that is
+ # spoken when the object receives keyboard focus.
+ #
+ speechResult = brailleResult = None
+ text = ""
+ if obj.description:
+ speechResult = brailleResult = obj.description
+ else:
+ speechResult = self.whereAmI.getWhereAmI(obj, True)
+ if speechResult:
+ brailleResult = speechResult[0]
+ debug.println(debug.LEVEL_FINEST,
+ "presentToolTip: text='%s'" % speechResult)
+ if speechResult:
+ speech.speak(speechResult)
+ if brailleResult:
+ self.displayBrailleMessage(brailleResult)
+
+ def sayCharacter(self, obj):
+ """Speak the character at the caret.
+
+ Arguments:
+ - obj: an Accessible object that implements the AccessibleText
+ interface
+ """
+
+ text = obj.queryText()
+ offset = text.caretOffset
+
+ # If we have selected text and the last event was a move to the
+ # right, then speak the character to the left of where the text
+ # caret is (i.e. the selected character).
+ #
+ eventString, mods = self.utilities.lastKeyAndModifiers()
+ if (mods & settings.SHIFT_MODIFIER_MASK) \
+ and eventString in ["Right", "Down"]:
+ offset -= 1
+
+ character, startOffset, endOffset = \
+ text.getTextAtOffset(offset, pyatspi.TEXT_BOUNDARY_CHAR)
+ if not character or character == '\r':
+ character = "\n"
+
+ if self.utilities.linkIndex(obj, offset) >= 0:
+ voice = self.voices[settings.HYPERLINK_VOICE]
+ elif character.decode("UTF-8").isupper():
+ voice = self.voices[settings.UPPERCASE_VOICE]
+ else:
+ voice = self.voices[settings.DEFAULT_VOICE]
+
+ speakBlankLines = _settingsManager.getSetting('speakBlankLines')
+ debug.println(debug.LEVEL_FINEST, \
+ "sayCharacter: char=<%s>, startOffset=%d, " % \
+ (character, startOffset))
+ debug.println(debug.LEVEL_FINEST, \
+ "caretOffset=%d, endOffset=%d, speakBlankLines=%s" % \
+ (offset, endOffset, speakBlankLines))
+
+ if character == "\n":
+ line = text.getTextAtOffset(max(0, offset),
+ pyatspi.TEXT_BOUNDARY_LINE_START)
+ if not line[0] or line[0] == "\n":
+ # This is a blank line. Announce it if the user requested
+ # that blank lines be spoken.
+ if speakBlankLines:
+ # Translators: "blank" is a short word to mean the
+ # user has navigated to an empty line.
+ #
+ self.speakMessage(_("blank"), interrupt=False)
+ return
+
+ if character in ["\n", "\r\n"]:
+ # This is a blank line. Announce it if the user requested
+ # that blank lines be spoken.
+ if speakBlankLines:
+ # Translators: "blank" is a short word to mean the
+ # user has navigated to an empty line.
+ #
+ self.speakMessage(_("blank"), interrupt=False)
+ return
+ else:
+ self.speakMisspelledIndicator(obj, offset)
+ speech.speakCharacter(character, voice)
+
+ def sayLine(self, obj):
+ """Speaks the line of an AccessibleText object that contains the
+ caret, unless the line is empty in which case it's ignored.
+
+ Arguments:
+ - obj: an Accessible object that implements the AccessibleText
+ interface
+ """
+
+ # Get the AccessibleText interface of the provided object
+ #
+ [line, caretOffset, startOffset] = self.getTextLineAtCaret(obj)
+ debug.println(debug.LEVEL_FINEST, \
+ "sayLine: line=<%s>, len=%d, start=%d, " % \
+ (line, len(line), startOffset))
+ debug.println(debug.LEVEL_FINEST, \
+ "caret=%d, speakBlankLines=%s" % \
+ (caretOffset, _settingsManager.getSetting('speakBlankLines')))
+
+ if len(line) and line != "\n":
+ if line.decode("UTF-8").isupper():
+ voice = self.voices[settings.UPPERCASE_VOICE]
+ else:
+ voice = self.voices[settings.DEFAULT_VOICE]
+
+ result = \
+ self.speechGenerator.generateTextIndentation(obj, line=line)
+ if result:
+ self.speakMessage(result[0])
+ line = self.utilities.adjustForLinks(obj, line, startOffset)
+ line = self.utilities.adjustForRepeats(line)
+ speech.speak(line, voice)
+ else:
+ # Speak blank line if appropriate.
+ #
+ self.sayCharacter(obj)
+
+ def sayPhrase(self, obj, startOffset, endOffset):
+ """Speaks the text of an Accessible object between the start and
+ end offsets, unless the phrase is empty in which case it's ignored.
+
+ Arguments:
+ - obj: an Accessible object that implements the AccessibleText
+ interface
+ - startOffset: the start text offset.
+ - endOffset: the end text offset.
+ """
+
+ phrase = self.utilities.substring(obj, startOffset, endOffset)
+
+ if len(phrase) and phrase != "\n":
+ if phrase.decode("UTF-8").isupper():
+ voice = self.voices[settings.UPPERCASE_VOICE]
+ else:
+ voice = self.voices[settings.DEFAULT_VOICE]
+
+ phrase = self.utilities.adjustForRepeats(phrase)
+ speech.speak(phrase, voice)
+ else:
+ # Speak blank line if appropriate.
+ #
+ self.sayCharacter(obj)
+
+ def sayWord(self, obj):
+ """Speaks the word at the caret. [[[TODO: WDW - what if there is no
+ word at the caret?]]]
+
+ Arguments:
+ - obj: an Accessible object that implements the AccessibleText
+ interface
+ """
+
+ text = obj.queryText()
+ offset = text.caretOffset
+ lastKey, mods = self.utilities.lastKeyAndModifiers()
+ lastWord = orca_state.lastWord
+
+ [word, startOffset, endOffset] = \
+ text.getTextAtOffset(offset,
+ pyatspi.TEXT_BOUNDARY_WORD_START)
+
+ # Speak a newline if a control-right-arrow or control-left-arrow
+ # was used to cross a line boundary. Handling is different for
+ # the two keys since control-right-arrow places the cursor after
+ # the last character in a word, but control-left-arrow places
+ # the cursor at the beginning of a word.
+ #
+ if lastKey == "Right" and len(lastWord) > 0:
+ lastChar = lastWord[len(lastWord) - 1]
+ if lastChar == "\n" and lastWord != word:
+ voice = self.voices[settings.DEFAULT_VOICE]
+ speech.speakCharacter("\n", voice)
+
+ if lastKey == "Left" and len(word) > 0:
+ lastChar = word[len(word) - 1]
+ if lastChar == "\n" and lastWord != word:
+ voice = self.voices[settings.DEFAULT_VOICE]
+ speech.speakCharacter("\n", voice)
+
+ if self.utilities.linkIndex(obj, offset) >= 0:
+ voice = self.voices[settings.HYPERLINK_VOICE]
+ elif word.decode("UTF-8").isupper():
+ voice = self.voices[settings.UPPERCASE_VOICE]
+ else:
+ voice = self.voices[settings.DEFAULT_VOICE]
+
+ self.speakMisspelledIndicator(obj, startOffset)
+
+ word = self.utilities.adjustForRepeats(word)
+ orca_state.lastWord = word
+ speech.speak(word, voice)
+
+ def stopSpeechOnActiveDescendantChanged(self, event):
+ """Whether or not speech should be stopped prior to setting the
+ locusOfFocus in onActiveDescendantChanged.
+
+ Arguments:
+ - event: the Event
+
+ Returns True if speech should be stopped; False otherwise.
+ """
+
+ return True
+
+ def getAtkNameForAttribute(self, attribName):
+ """Converts the given attribute name into the Atk equivalent. This
+ is necessary because an application or toolkit (e.g. Gecko) might
+ invent entirely new names for the same attributes.
+
+ Arguments:
+ - attribName: The name of the text attribute
+
+ Returns the Atk equivalent name if found or attribName otherwise.
+ """
+
+ return self.attributeNamesDict.get(attribName, attribName)
+
+ def getAppNameForAttribute(self, attribName):
+ """Converts the given Atk attribute name into the application's
+ equivalent. This is necessary because an application or toolkit
+ (e.g. Gecko) might invent entirely new names for the same text
+ attributes.
+
+ Arguments:
+ - attribName: The name of the text attribute
+
+ Returns the application's equivalent name if found or attribName
+ otherwise.
+ """
+
+ for key, value in self.attributeNamesDict.items():
+ if value == attribName:
+ return key
+
+ return attribName
+
+ def getFlatReviewContext(self):
+ """Returns the flat review context, creating one if necessary."""
+
+ if not self.flatReviewContext:
+ self.flatReviewContext = self.flatReviewContextClass(self)
+ self.justEnteredFlatReviewMode = True
+
+ # Remember where the cursor currently was
+ # when the user was in focus tracking mode. We'll try to
+ # keep the position the same as we move to characters above
+ # and below us.
+ #
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ return self.flatReviewContext
+
+ def drawOutline(self, x, y, width, height):
+ """Draws an outline around the accessible, erasing the last drawn
+ outline in the process."""
+
+ if (x == -1) and (y == 0) and (width == 0) and (height == 0):
+ outline.erase()
+ else:
+ outline.draw(x, y, width, height)
+
+ def outlineAccessible(self, accessible):
+ """Draws a rectangular outline around the accessible, erasing the
+ last drawn rectangle in the process."""
+
+ try:
+ component = accessible.queryComponent()
+ except AttributeError:
+ self.drawOutline(-1, 0, 0, 0)
+ except NotImplementedError:
+ pass
+ else:
+ visibleRectangle = \
+ component.getExtents(pyatspi.DESKTOP_COORDS)
+ self.drawOutline(visibleRectangle.x, visibleRectangle.y,
+ visibleRectangle.width, visibleRectangle.height)
+
+ def updateBrailleReview(self, targetCursorCell=0):
+ """Obtains the braille regions for the current flat review line
+ and displays them on the braille display. If the targetCursorCell
+ is non-0, then an attempt will be made to postion the review cursor
+ at that cell. Otherwise, we will pan in display-sized increments
+ to show the review cursor."""
+
+ context = self.getFlatReviewContext()
+
+ [regions, regionWithFocus] = context.getCurrentBrailleRegions()
+ if not regions:
+ regions = []
+ regionWithFocus = None
+
+ line = self.getNewBrailleLine()
+ self.addBrailleRegionsToLine(regions, line)
+ braille.setLines([line])
+ self.setBrailleFocus(regionWithFocus, False)
+ if regionWithFocus:
+ self.panBrailleToOffset(regionWithFocus.brailleOffset \
+ + regionWithFocus.cursorOffset)
+
+ if self.justEnteredFlatReviewMode:
+ self.refreshBraille(True, self.targetCursorCell)
+ self.justEnteredFlatReviewMode = False
+ else:
+ self.refreshBraille(True, targetCursorCell)
+
+ def _setFlatReviewContextToBeginningOfBrailleDisplay(self):
+ """Sets the character of interest to be the first character showing
+ at the beginning of the braille display."""
+
+ context = self.getFlatReviewContext()
+ [regions, regionWithFocus] = context.getCurrentBrailleRegions()
+ for region in regions:
+ if ((region.brailleOffset + len(region.string.decode("UTF-8"))) \
+ > braille.viewport[0]) \
+ and (isinstance(region, braille.ReviewText) \
+ or isinstance(region, braille.ReviewComponent)):
+ position = max(region.brailleOffset, braille.viewport[0])
+ offset = position - region.brailleOffset
+ self.targetCursorCell = region.brailleOffset \
+ - braille.viewport[0]
+ [word, charOffset] = region.zone.getWordAtOffset(offset)
+ if word:
+ self.flatReviewContext.setCurrent(
+ word.zone.line.index,
+ word.zone.index,
+ word.index,
+ charOffset)
+ else:
+ self.flatReviewContext.setCurrent(
+ region.zone.line.index,
+ region.zone.index,
+ 0, # word index
+ 0) # character index
+ break
+
+ def find(self, query=None):
+ """Searches for the specified query. If no query is specified,
+ it searches for the query specified in the Orca Find dialog.
+
+ Arguments:
+ - query: The search query to find.
+ """
+
+ if not query:
+ query = find.getLastQuery()
+ if query:
+ context = self.getFlatReviewContext()
+ location = query.findQuery(context, self.justEnteredFlatReviewMode)
+ if not location:
+ # Translators: the Orca "Find" dialog allows a user to
+ # search for text in a window and then move focus to
+ # that text. For example, they may want to find the
+ # "OK" button. This message lets them know a string
+ # they were searching for was not found.
+ #
+ message = _("string not found")
+ self.presentMessage(message)
+ else:
+ context.setCurrent(location.lineIndex, location.zoneIndex, \
+ location.wordIndex, location.charIndex)
+ self.reviewCurrentItem(None)
+ self.targetCursorCell = self.getBrailleCursorCell()
+
+ def getUnicodeCurrencySymbols(self):
+ """Return a list of the unicode currency symbols, populating the list
+ if this is the first time that this routine has been called.
+
+ Returns a list of unicode currency symbols.
+ """
+
+ if not self._unicodeCurrencySymbols:
+ self._unicodeCurrencySymbols = [ \
+ u'\u0024', # dollar sign
+ u'\u00A2', # cent sign
+ u'\u00A3', # pound sign
+ u'\u00A4', # currency sign
+ u'\u00A5', # yen sign
+ u'\u0192', # latin small letter f with hook
+ u'\u060B', # afghani sign
+ u'\u09F2', # bengali rupee mark
+ u'\u09F3', # bengali rupee sign
+ u'\u0AF1', # gujarati rupee sign
+ u'\u0BF9', # tamil rupee sign
+ u'\u0E3F', # thai currency symbol baht
+ u'\u17DB', # khmer currency symbol riel
+ u'\u2133', # script capital m
+ u'\u5143', # cjk unified ideograph-5143
+ u'\u5186', # cjk unified ideograph-5186
+ u'\u5706', # cjk unified ideograph-5706
+ u'\u5713', # cjk unified ideograph-5713
+ u'\uFDFC', # rial sign
+ ]
+
+ # Add 20A0 (EURO-CURRENCY SIGN) to 20B5 (CEDI SIGN)
+ #
+ for ordChar in range(ord(u'\u20A0'), ord(u'\u20B5') + 1):
+ self._unicodeCurrencySymbols.append(unichr(ordChar))
+
+ return self._unicodeCurrencySymbols
+
+ def speakMisspeltWord(self, allTokens, badWord):
+ """Called by various spell checking routine to speak the misspelt word,
+ plus the context that it is being used in.
+
+ Arguments:
+ - allTokens: a list of all the words.
+ - badWord: the misspelt word.
+ """
+
+ # Create an utterance to speak consisting of the misspelt
+ # word plus the context where it is used (upto five words
+ # to either side of it).
+ #
+ for i in range(0, len(allTokens)):
+ if allTokens[i].startswith(badWord):
+ minIndex = i - 5
+ if minIndex < 0:
+ minIndex = 0
+ maxIndex = i + 5
+ if maxIndex > (len(allTokens) - 1):
+ maxIndex = len(allTokens) - 1
+
+ # Translators: Orca will provide more compelling output of
+ # the spell checking dialog in some applications. The first
+ # thing it does is let them know what the misspelled word
+ # is.
+ #
+ utterances = [_("Misspelled word: %s") % badWord]
+
+ # Translators: Orca will provide more compelling output of
+ # the spell checking dialog in some applications. The second
+ # thing it does is give the phrase containing the misspelled
+ # word in the document. This is known as the context.
+ #
+ contextPhrase = " ".join(allTokens[minIndex:maxIndex+1])
+ utterances.append(_("Context is %s") % contextPhrase)
+
+ # Turn the list of utterances into a string.
+ text = " ".join(utterances)
+ speech.speak(text)
+
+ def textLines(self, obj):
+ """Creates a generator that can be used to iterate over each line
+ of a text object, starting at the caret offset.
+
+ Arguments:
+ - obj: an Accessible that has a text specialization
+
+ Returns an iterator that produces elements of the form:
+ [SayAllContext, acss], where SayAllContext has the text to be
+ spoken and acss is an ACSS instance for speaking the text.
+ """
+
+ try:
+ text = obj.queryText()
+ except:
+ return
+
+ length = text.characterCount
+ offset = text.caretOffset
+
+ # Determine the correct "say all by" mode to use.
+ #
+ sayAllStyle = _settingsManager.getSetting('sayAllStyle')
+ if sayAllStyle == settings.SAYALL_STYLE_SENTENCE:
+ mode = pyatspi.TEXT_BOUNDARY_SENTENCE_END
+ elif sayAllStyle == settings.SAYALL_STYLE_LINE:
+ mode = pyatspi.TEXT_BOUNDARY_LINE_START
+ else:
+ mode = pyatspi.TEXT_BOUNDARY_LINE_START
+
+ # Get the next line of text to read
+ #
+ done = False
+ while not done:
+ lastEndOffset = -1
+ while offset < length:
+ [lineString, startOffset, endOffset] = text.getTextAtOffset(
+ offset, mode)
+
+ # Some applications that don't support sentence boundaries
+ # will provide the line boundary results instead; others
+ # will return nothing.
+ #
+ if not lineString:
+ mode = pyatspi.TEXT_BOUNDARY_LINE_START
+ [lineString, startOffset, endOffset] = \
+ text.getTextAtOffset(offset, mode)
+
+ # [[[WDW - HACK: well...gnome-terminal sometimes wants to
+ # give us outrageous values back from getTextAtOffset
+ # (see http://bugzilla.gnome.org/show_bug.cgi?id=343133),
+ # so we try to handle it.]]]
+ #
+ if startOffset < 0:
+ break
+
+ # [[[WDW - HACK: this is here because getTextAtOffset
+ # tends not to be implemented consistently across toolkits.
+ # Sometimes it behaves properly (i.e., giving us an endOffset
+ # that is the beginning of the next line), sometimes it
+ # doesn't (e.g., giving us an endOffset that is the end of
+ # the current line). So...we hack. The whole 'max' deal
+ # is to account for lines that might be a brazillion lines
+ # long.]]]
+ #
+ if endOffset == lastEndOffset:
+ offset = max(offset + 1, lastEndOffset + 1)
+ lastEndOffset = endOffset
+ continue
+
+ lastEndOffset = endOffset
+ offset = endOffset
+
+ lineString = self.utilities.adjustForRepeats(lineString)
+ if lineString.decode("UTF-8").isupper():
+ voice = settings.voices[settings.UPPERCASE_VOICE]
+ else:
+ voice = settings.voices[settings.DEFAULT_VOICE]
+
+ yield [speechserver.SayAllContext(obj, lineString,
+ startOffset, endOffset),
+ voice]
+
+ moreLines = False
+ relations = obj.getRelationSet()
+ for relation in relations:
+ if relation.getRelationType() \
+ == pyatspi.RELATION_FLOWS_TO:
+ obj = relation.getTarget(0)
+
+ try:
+ text = obj.queryText()
+ except NotImplementedError:
+ return
+
+ length = text.characterCount
+ offset = 0
+ moreLines = True
+ break
+ if not moreLines:
+ done = True
+
+ def getTextEndOffset(self, textInterface):
+ """Returns the offset which should be used as the end offset.
+ By default, this is -1. However, this value triggers an assertion
+ in certain apps. See bug 598797.
+
+ Argument:
+ - textInterface: the accessible text interface for which the end
+ offset is desired.
+
+ """
+
+ return -1
+
+ def getTextLineAtCaret(self, obj, offset=None):
+ """Gets the line of text where the caret is.
+
+ Argument:
+ - obj: an Accessible object that implements the AccessibleText
+ interface
+ - offset: an optional caret offset to use. (Not used here at the
+ moment, but needed in the Gecko script)
+
+ Returns the [string, caretOffset, startOffset] for the line of text
+ where the caret is.
+ """
+
+ # Get the the AccessibleText interrface
+ #
+ try:
+ text = obj.queryText()
+ except NotImplementedError:
+ return ["", 0, 0]
+
+ # The caret might be positioned at the very end of the text area.
+ # In these cases, calling text.getTextAtOffset on an offset that's
+ # not positioned to a character can yield unexpected results. In
+ # particular, we'll see the Gecko toolkit return a start and end
+ # offset of (0, 0), and we'll see other implementations, such as
+ # gedit, return reasonable results (i.e., gedit will give us the
+ # last line).
+ #
+ # In order to accommodate the differing behavior of different
+ # AT-SPI implementations, we'll make sure we give getTextAtOffset
+ # the offset of an actual character. Then, we'll do a little check
+ # to see if that character is a newline - if it is, we'll treat it
+ # as the line.
+ #
+ if text.caretOffset == text.characterCount:
+ caretOffset = max(0, text.caretOffset - 1)
+ character = text.getText(caretOffset,
+ caretOffset + 1).decode("UTF-8")
+ else:
+ caretOffset = text.caretOffset
+ character = None
+
+ if (text.caretOffset == text.characterCount) \
+ and (character == "\n"):
+ content = ""
+ startOffset = caretOffset
+ else:
+ # Get the line containing the caret. [[[TODO: HACK WDW - If
+ # there's only 1 character in the string, well, we get it. We
+ # do this because Gecko's implementation of getTextAtOffset
+ # is broken if there is just one character in the string.]]]
+ #
+ if (text.characterCount == 1):
+ lineString = text.getText(caretOffset, caretOffset + 1)
+ startOffset = caretOffset
+ else:
+ [lineString, startOffset, endOffset] = text.getTextAtOffset(
+ caretOffset, pyatspi.TEXT_BOUNDARY_LINE_START)
+
+ # Sometimes we get the trailing line-feed-- remove it
+ #
+ content = lineString.decode("UTF-8")
+
+ # It is important that these are in order.
+ # In some circumstances we might get:
+ # word word\r\n
+ # so remove \n, and then remove \r.
+ # See bgo#619332.
+ #
+ content = content.rstrip('\n')
+ content = content.rstrip('\r')
+
+ return [content.encode("UTF-8"), text.caretOffset, startOffset]
+
+ def phoneticSpellCurrentItem(self, itemString):
+ """Phonetically spell the current flat review word or line.
+
+ Arguments:
+ - itemString: the string to phonetically spell.
+ """
+
+ for (charIndex, character) in enumerate(itemString.decode("UTF-8")):
+ if character.isupper():
+ voice = settings.voices[settings.UPPERCASE_VOICE]
+ character = character.lower()
+ else:
+ voice = settings.voices[settings.DEFAULT_VOICE]
+ phoneticString = phonnames.getPhoneticName(character)
+ speech.speak(phoneticString, voice)
+
+ def _saveSpokenTextRange(self, startOffset, endOffset):
+ """Save away the start and end offset of the range of text that
+ was spoken. It will be used by speakTextSelectionState, to try
+ to determine if the text was selected or unselected.
+
+ Arguments:
+ - startOffset: the start of the spoken text range.
+ - endOffset: the end of the spoken text range.
+ """
+
+ self.pointOfReference["spokenTextRange"] = [startOffset, endOffset]
+
+ def _saveLastCursorPosition(self, obj, caretOffset):
+ """Save away the current text cursor position for next time.
+
+ Arguments:
+ - obj: the current accessible
+ - caretOffset: the cursor position within this object
+ """
+
+ self.pointOfReference["lastCursorPosition"] = [obj, caretOffset]
+
+ def _saveLastTextSelections(self, text):
+ """Save away the list of text selections for next time.
+
+ Arguments:
+ - text: the text object.
+ """
+
+ self.pointOfReference["lastSelections"] = []
+ for i in xrange(text.getNSelections()):
+ self.pointOfReference["lastSelections"].append(
+ text.getSelection(i))
+
+ def _getCtrlShiftSelectionsStrings(self):
+ return [
+ # Translators: when the user selects (highlights) text in
+ # a document, Orca will speak information about what they
+ # have selected.
+ #
+ _("paragraph selected down from cursor position"),
+ _("paragraph unselected down from cursor position"),
+ _("paragraph selected up from cursor position"),
+ _("paragraph unselected up from cursor position"),
+ ]
+
+ def speakTextSelectionState(self, obj, startOffset, endOffset):
+ """Speak "selected" if the text was just selected, "unselected" if
+ it was just unselected.
+
+ Arguments:
+ - obj: the Accessible object.
+ - startOffset: text start offset.
+ - endOffset: text end offset.
+ """
+
+ if _settingsManager.getSetting('onlySpeakDisplayedText'):
+ return
+
+ try:
+ text = obj.queryText()
+ except:
+ return
+
+ # Handle special cases.
+ #
+ # Control-Shift-Page_Down:
+ # speak "line selected to end from previous cursor position".
+ # Control-Shift-Page_Up:
+ # speak "line selected from start to previous cursor position".
+ #
+ # Shift-Page_Down: speak "page <state> from cursor position".
+ # Shift-Page_Up: speak "page <state> to cursor position".
+ #
+ # Control-Shift-Down: speak "line <state> down from cursor position".
+ # Control-Shift-Up: speak "line <state> up from cursor position".
+ #
+ # Control-Shift-Home: speak "document <state> to cursor position".
+ # Control-Shift-End: speak "document <state> from cursor position".
+ #
+ # Control-a: speak "entire document selected".
+ #
+ # where <state> is either "selected" or "unselected" depending
+ # upon whether there are any text selections.
+ #
+ eventStr, mods = self.utilities.lastKeyAndModifiers()
+ isControlKey = mods & settings.CTRL_MODIFIER_MASK
+ isShiftKey = mods & settings.SHIFT_MODIFIER_MASK
+ selectedText = (text.getNSelections() != 0)
+
+ specialCaseFound = False
+ if (eventStr == "Page_Down") and isShiftKey and isControlKey:
+ specialCaseFound = True
+ # Translators: when the user selects (highlights) text in
+ # a document, Orca will speak information about what they
+ # have selected.
+ #
+ line = _("line selected to end from previous cursor position")
+
+ elif (eventStr == "Page_Up") and isShiftKey and isControlKey:
+ specialCaseFound = True
+ # Translators: when the user selects (highlights) text in
+ # a document, Orca will speak information about what they
+ # have selected.
+ #
+ line = _("line selected from start to previous cursor position")
+
+ elif (eventStr == "Page_Down") and isShiftKey and not isControlKey:
+ specialCaseFound = True
+ if selectedText:
+ # Translators: when the user selects (highlights) text in
+ # a document, Orca will speak information about what they
+ # have selected.
+ #
+ line = _("page selected from cursor position")
+ else:
+ # Translators: when the user unselects text in a document,
+ # Orca will speak information about what they have unselected.
+ #
+ line = _("page unselected from cursor position")
+
+ elif (eventStr == "Page_Up") and isShiftKey and not isControlKey:
+ specialCaseFound = True
+ if selectedText:
+ # Translators: when the user selects (highlights) text in
+ # a document, Orca will speak information about what they
+ # have selected.
+ #
+ line = _("page selected to cursor position")
+ else:
+ # Translators: when the user unselects text in a document,
+ # Orca will speak information about what they have unselected.
+ #
+ line = _("page unselected to cursor position")
+
+ elif (eventStr == "Down") and isShiftKey and isControlKey:
+ specialCaseFound = True
+ strings = self._getCtrlShiftSelectionsStrings()
+ if selectedText:
+ line = strings[0]
+ else:
+ line = strings[1]
+
+ elif (eventStr == "Up") and isShiftKey and isControlKey:
+ specialCaseFound = True
+ strings = self._getCtrlShiftSelectionsStrings()
+ if selectedText:
+ line = strings[2]
+ else:
+ line = strings[3]
+
+ elif (eventStr == "Home") and isShiftKey and isControlKey:
+ specialCaseFound = True
+ if selectedText:
+ # Translators: when the user selects (highlights) text in
+ # a document, Orca will speak information about what they
+ # have selected.
+ #
+ line = _("document selected to cursor position")
+ else:
+ # Translators: when the user unselects text in a document,
+ # Orca will speak information about what they have unselected.
+ #
+ line = _("document unselected to cursor position")
+
+ elif (eventStr == "End") and isShiftKey and isControlKey:
+ specialCaseFound = True
+ if selectedText:
+ # Translators: when the user selects (highlights) text in
+ # a document, Orca will speak information about what they
+ # have selected.
+ #
+ line = _("document selected from cursor position")
+ else:
+ # Translators: when the user unselects text in a document,
+ # Orca will speak information about what they have unselected.
+ #
+ line = _("document unselected from cursor position")
+
+ elif (eventStr == "A") and isControlKey:
+ # The user has typed Control-A. Check to see if the entire
+ # document has been selected, and if so, let the user know.
+ #
+ charCount = text.characterCount
+ for i in range(0, text.getNSelections()):
+ [startOffset, endOffset] = text.getSelection(i)
+ if text.caretOffset == 0 and \
+ startOffset == 0 and endOffset == charCount:
+ specialCaseFound = True
+ self.updateBraille(obj)
+
+ # Translators: this means the user has selected
+ # all the text in a document (e.g., Ctrl+a in gedit).
+ #
+ line = _("entire document selected")
+
+ if specialCaseFound:
+ speech.speak(line, None, False)
+ return
+ elif startOffset == endOffset:
+ return
+
+ try:
+ # If we are selecting by word, then there possibly will be
+ # whitespace characters on either end of the text. We adjust
+ # the startOffset and endOffset to exclude them.
+ #
+ try:
+ tmpStr = text.getText(startOffset,
+ endOffset).decode("UTF-8")
+ except:
+ tmpStr = u''
+ n = len(tmpStr)
+
+ # Don't strip whitespace if string length is one (might be a
+ # space).
+ #
+ if n > 1:
+ while endOffset > startOffset:
+ if self.utilities.isWordDelimiter(tmpStr[n-1]):
+ n -= 1
+ endOffset -= 1
+ else:
+ break
+ n = 0
+ while startOffset < endOffset:
+ if self.utilities.isWordDelimiter(tmpStr[n]):
+ n += 1
+ startOffset += 1
+ else:
+ break
+
+ except:
+ debug.printException(debug.LEVEL_FINEST)
+
+ if not _settingsManager.getSetting('onlySpeakDisplayedText'):
+ voice = self.voices.get(settings.SYSTEM_VOICE)
+ if self.utilities.isTextSelected(obj, startOffset, endOffset):
+ # Translators: when the user selects (highlights) text in
+ # a document, Orca lets them know this.
+ #
+ speech.speak(C_("text", "selected"), voice, False)
+ elif len(text.getText(startOffset, endOffset)):
+ # Translators: when the user unselects
+ # (unhighlights) text in a document, Orca lets
+ # them know this.
+ #
+ speech.speak(C_("text", "unselected"), voice, False)
+
+ self._saveLastTextSelections(text)
+
+ def systemBeep(self):
+ """Rings the system bell. This is really a hack. Ideally, we want
+ a method that will present an earcon (any sound designated for the
+ purpose of representing an error, event etc)
+ """
+
+ print "\a"
+
+ def speakWordUnderMouse(self, acc):
+ """Determine if the speak-word-under-mouse capability applies to
+ the given accessible.
+
+ Arguments:
+ - acc: Accessible to test.
+
+ Returns True if this accessible should provide the single word.
+ """
+ return acc and acc.getState().contains(pyatspi.STATE_EDITABLE)
+
+ def speakMisspelledIndicator(self, obj, offset):
+ """Speaks an announcement indicating that a given word is misspelled.
+
+ Arguments:
+ - obj: An accessible which implements the accessible text interface.
+ - offset: Offset in the accessible's text for which to retrieve the
+ attributes.
+ """
+
+ verbosity = _settingsManager.getSetting('speechVerbosityLevel')
+ if verbosity == settings.VERBOSITY_LEVEL_VERBOSE:
+ try:
+ text = obj.queryText()
+ except:
+ return
+ # If we're on whitespace, we cannot be on a misspelled word.
+ #
+ charAndOffsets = \
+ text.getTextAtOffset(offset, pyatspi.TEXT_BOUNDARY_CHAR)
+ if not charAndOffsets[0].strip() \
+ or self.utilities.isWordDelimiter(charAndOffsets[0]):
+ orca_state.lastWordCheckedForSpelling = charAndOffsets[0]
+ return
+
+ wordAndOffsets = \
+ text.getTextAtOffset(offset, pyatspi.TEXT_BOUNDARY_WORD_START)
+ if self.utilities.isWordMisspelled(obj, offset) \
+ and wordAndOffsets[0] != orca_state.lastWordCheckedForSpelling:
+ # Translators: this is to inform the user of the presence
+ # of the red squiggly line which indicates that a given
+ # word is not spelled correctly.
+ #
+ self.speakMessage(_("misspelled"))
+ # Store this word so that we do not continue to present the
+ # presence of the red squiggly as the user arrows amongst
+ # the characters.
+ #
+ orca_state.lastWordCheckedForSpelling = wordAndOffsets[0]
+
+ ############################################################################
+ # #
+ # Presentation methods #
+ # (scripts should not call methods in braille.py or speech.py directly) #
+ # #
+ ############################################################################
+
+ def presentMessage(self, fullMessage, briefMessage=None, voice=None):
+ """Convenience method to speak a message and 'flash' it in braille.
+
+ Arguments:
+ - fullMessage: This can be a string or a list. This will be presented
+ as the message for users whose flash or message verbosity level is
+ verbose.
+ - briefMessage: This can be a string or a list. This will be presented
+ as the message for users whose flash or message verbosity level is
+ brief. Note that providing no briefMessage will result in the full
+ message being used for either. Callers wishing to present nothing as
+ the briefMessage should set briefMessage to an empty string.
+ - voice: The voice to use when speaking this message. By default, the
+ "system" voice will be used.
+ """
+
+ if not fullMessage:
+ return
+
+ if briefMessage is None:
+ briefMessage = fullMessage
+
+ if _settingsManager.getSetting('enableSpeech'):
+ if _settingsManager.getSetting('messageVerbosityLevel') \
+ == settings.VERBOSITY_LEVEL_BRIEF:
+ message = briefMessage
+ else:
+ message = fullMessage
+ if message:
+ voice = voice or self.voices.get(settings.SYSTEM_VOICE)
+ speech.speak(message, voice)
+
+ if (_settingsManager.getSetting('enableBraille') \
+ or _settingsManager.getSetting('enableBrailleMonitor')) \
+ and _settingsManager.getSetting('enableFlashMessages'):
+ if _settingsManager.getSetting('flashVerbosityLevel') \
+ == settings.VERBOSITY_LEVEL_BRIEF:
+ message = briefMessage
+ else:
+ message = fullMessage
+ if not message:
+ return
+
+ if isinstance(message[0], list):
+ message = message[0]
+ if isinstance(message, list):
+ message = filter(lambda i: isinstance(i, str), message)
+ message = " ".join(message)
+
+ if _settingsManager.getSetting('flashIsPersistent'):
+ duration = -1
+ else:
+ duration = _settingsManager.getSetting('brailleFlashTime')
+
+ braille.displayMessage(message, flashTime=duration)
+
+ # [[[TODO - JD: Soon I'll add a check to only do the braille
+ # presentation if the user has braille or the braille monitor
+ # enabled. For now, the easiest way to regression test these
+ # changes is to always present braille.]]]
+
+ @staticmethod
+ def addBrailleRegionToLine(region, line):
+ """Adds the braille region to the line.
+
+ Arguments:
+ - region: a braille.Region (e.g. what is returned by the braille
+ generator's generateBraille() method.
+ - line: a braille.Line
+ """
+
+ line.addRegion(region)
+
+ @staticmethod
+ def addBrailleRegionsToLine(regions, line):
+ """Adds the braille region to the line.
+
+ Arguments:
+ - regions: a series of braille.Region instances (a single instance
+ being what is returned by the braille generator's generateBraille()
+ method.
+ - line: a braille.Line
+ """
+
+ line.addRegions(regions)
+
+ @staticmethod
+ def addToLineAsBrailleRegion(string, line):
+ """Creates a Braille Region out of string and adds it to the line.
+
+ Arguments:
+ - string: the string to be displayed
+ - line: a braille.Line
+ """
+
+ line.addRegion(braille.Region(string))
+
+ @staticmethod
+ def brailleRegionsFromStrings(strings):
+ """Creates a list of braille regions from the list of strings.
+
+ Arguments:
+ - strings: a list of strings from which to create the list of
+ braille Region instances
+
+ Returns the list of braille Region instances
+ """
+
+ brailleRegions = []
+ for string in strings:
+ brailleRegions.append(braille.Region(string))
+
+ return brailleRegions
+
+ @staticmethod
+ def clearBraille():
+ """Clears the logical structure, but keeps the Braille display as is
+ (until a refresh operation)."""
+
+ braille.clear()
+
+ @staticmethod
+ def displayBrailleMessage(message, cursor=-1, flashTime=0):
+ """Displays a single line, setting the cursor to the given position,
+ ensuring that the cursor is in view.
+
+ Arguments:
+ - message: the string to display
+ - cursor: the 0-based cursor position, where -1 (default) means no
+ cursor
+ - flashTime: if non-0, the number of milliseconds to display the
+ regions before reverting back to what was there before. A 0 means
+ to not do any flashing. A negative number means to display the
+ message until some other message comes along or the user presses
+ a cursor routing key.
+ """
+
+ braille.displayMessage(message, cursor, flashTime)
+
+ @staticmethod
+ def displayBrailleRegions(regionInfo, flashTime=0):
+ """Displays a list of regions on a single line, setting focus to the
+ specified region. The regionInfo parameter is something that is
+ typically returned by a call to braille_generator.generateBraille.
+
+ Arguments:
+ - regionInfo: a list where the first element is a list of regions
+ to display and the second element is the region with focus (must
+ be in the list from element 0)
+ - flashTime: if non-0, the number of milliseconds to display the
+ regions before reverting back to what was there before. A 0 means
+ to not do any flashing. A negative number means to display the
+ message until some other message comes along or the user presses
+ a cursor routing key.
+ """
+
+ braille.displayRegions(regionInfo, flashTime)
+
+ def displayBrailleForObject(self, obj):
+ """Convenience method for scripts combining the call to the braille
+ generator for the script with the call to displayBrailleRegions.
+
+ Arguments:
+ - obj: the accessible object to display in braille
+ """
+
+ regions = self.brailleGenerator.generateBraille(obj)
+ self.displayBrailleRegions(regions)
+
+ @staticmethod
+ def getBrailleCaretContext(event):
+ """Gets the accesible and caret offset associated with the given
+ event. The event should have a BrlAPI event that contains an
+ argument value that corresponds to a cell on the display.
+
+ Arguments:
+ - event: an instance of input_event.BrailleEvent. event.event is
+ the dictionary form of the expanded BrlAPI event.
+ """
+
+ return braille.getCaretContext(event)
+
+ @staticmethod
+ def getBrailleCursorCell():
+ """Returns the value of position of the braille cell which has the
+ cursor. A value of 0 means no cell has the cursor."""
+
+ return braille.cursorCell
+
+ @staticmethod
+ def getNewBrailleLine(clearBraille=False, addLine=False):
+ """Creates a new braille Line.
+
+ Arguments:
+ - clearBraille: Whether the display should be cleared.
+ - addLine: Whether the line should be added to the logical display
+ for painting.
+
+ Returns the new Line.
+ """
+
+ if clearBraille:
+ braille.clear()
+ line = braille.Line()
+ if addLine:
+ braille.addLine(line)
+
+ return line
+
+ @staticmethod
+ def getNewBrailleComponent(accessible, string, cursorOffset=0,
+ indicator='', expandOnCursor=False):
+ """Creates a new braille Component.
+
+ Arguments:
+ - accessible: the accessible associated with this region
+ - string: the string to be displayed
+ - cursorOffset: a 0-based index saying where to draw the cursor
+ for this Region if it gets focus
+
+ Returns the new Component.
+ """
+
+ return braille.Component(accessible, string, cursorOffset,
+ indicator, expandOnCursor)
+
+ @staticmethod
+ def getNewBrailleRegion(string, cursorOffset=0, expandOnCursor=False):
+ """Creates a new braille Region.
+
+ Arguments:
+ - string: the string to be displayed
+ - cursorOffset: a 0-based index saying where to draw the cursor
+ for this Region if it gets focus
+
+ Returns the new Region.
+ """
+
+ return braille.Region(string, cursorOffset, expandOnCursor)
+
+ @staticmethod
+ def getNewBrailleText(accessible, label="", eol="", startOffset=None,
+ endOffset=None):
+
+ """Creates a new braille Text region.
+
+ Arguments:
+ - accessible: the accessible associated with this region and which
+ implements AtkText
+ - label: an optional label to display
+ - eol: the endOfLine indicator
+
+ Returns the new Text region.
+ """
+
+ return braille.Text(accessible, label, eol, startOffset, endOffset)
+
+ @staticmethod
+ def isBrailleBeginningShowing():
+ """If True, the beginning of the line is showing on the braille
+ display."""
+
+ return braille.beginningIsShowing
+
+ @staticmethod
+ def isBrailleEndShowing():
+ """If True, the end of the line is showing on the braille display."""
+
+ return braille.endIsShowing
+
+ @staticmethod
+ def panBrailleInDirection(panAmount=0, panToLeft=True):
+ """Pans the display to the left, limiting the pan to the beginning
+ of the line being displayed.
+
+ Arguments:
+ - panAmount: the amount to pan. A value of 0 means the entire
+ width of the physical display.
+ - panToLeft: if True, pan to the left; otherwise to the right
+
+ Returns True if a pan actually happened.
+ """
+
+ if panToLeft:
+ return braille.panLeft(panAmount)
+ else:
+ return braille.panRight(panAmount)
+
+ @staticmethod
+ def panBrailleToOffset(offset):
+ """Automatically pan left or right to make sure the current offset
+ is showing."""
+
+ braille.panToOffset(offset)
+
+ @staticmethod
+ def presentItemsInBraille(items):
+ """Method to braille a list of items. Scripts should call this
+ method rather than handling the creation and displaying of a
+ braille line directly.
+
+ Arguments:
+ - items: a list of strings to be presented
+ """
+
+ line = braille.getShowingLine()
+ for item in items:
+ line.addRegion(braille.Region(" " + item))
+
+ braille.refresh()
+
+ @staticmethod
+ def refreshBraille(panToCursor=True, targetCursorCell=0, getLinkMask=True,
+ stopFlash=True):
+ """This is the method scripts should use to refresh braille rather
+ than calling self.refreshBraille() directly. The intent is to centralize
+ such calls into as few places as possible so that we can easily and
+ safely not perform braille-related functions for users who do not
+ have braille and/or the braille monitor enabled.
+
+ Arguments:
+
+ - panToCursor: if True, will adjust the viewport so the cursor is
+ showing.
+ - targetCursorCell: Only effective if panToCursor is True.
+ 0 means automatically place the cursor somewhere on the display so
+ as to minimize movement but show as much of the line as possible.
+ A positive value is a 1-based target cell from the left side of
+ the display and a negative value is a 1-based target cell from the
+ right side of the display.
+ - getLinkMask: Whether or not we should take the time to get the
+ attributeMask for links. Reasons we might not want to include
+ knowing that we will fail and/or it taking an unreasonable
+ amount of time (AKA Gecko).
+ - stopFlash: if True, kill any flashed message that may be showing.
+ """
+
+ braille.refresh(panToCursor, targetCursorCell, getLinkMask, stopFlash)
+
+ @staticmethod
+ def setBrailleFocus(region, panToFocus=True, getLinkMask=True):
+ """Specififes the region with focus. This region will be positioned
+ at the home position if panToFocus is True.
+
+ Arguments:
+ - region: the given region, which much be in a line that has been
+ added to the logical display
+ - panToFocus: whether or not to position the region at the home
+ position
+ - getLinkMask: Whether or not we should take the time to get the
+ attributeMask for links. Reasons we might not want to include
+ knowning that we will fail and/or it taking an unreasonable
+ amount of time (AKA Gecko).
+ """
+
+ braille.setFocus(region, panToFocus, getLinkMask)
+
+ @staticmethod
+ def _setContractedBraille(event):
+ """Turns contracted braille on or off based upon the event.
+
+ Arguments:
+ - event: an instance of input_event.BrailleEvent. event.event is
+ the dictionary form of the expanded BrlAPI event.
+ """
+
+ braille.setContractedBraille(event)
+
+ ########################################################################
+ # #
+ # Speech methods #
+ # (scripts should not call methods in speech.py directly) #
+ # #
+ ########################################################################
+
+ def speakMessage(self, string, voice=None, interrupt=True):
+ """Method to speak a single string. Scripts should use this
+ method rather than calling speech.speak directly.
+
+ - string: The string to be spoken.
+ - voice: The voice to use. By default, the "system" voice will
+ be used.
+ - interrupt: If True, any current speech should be interrupted
+ prior to speaking the new text.
+ """
+
+ if _settingsManager.getSetting('enableSpeech'):
+ voice = voice or self.voices.get(settings.SYSTEM_VOICE)
+ speech.speak(string, voice, interrupt)
+
+ @staticmethod
+ def presentItemsInSpeech(items):
+ """Method to speak a list of items. Scripts should call this
+ method rather than handling the creation and speaking of
+ utterances directly.
+
+ Arguments:
+ - items: a list of strings to be presented
+ """
+
+ utterances = []
+ for item in items:
+ utterances.append(item)
+
+ speech.speak(utterances)
+
+ def speakUnicodeCharacter(self, character):
+ """ Speaks some information about an unicode character.
+ At the Momment it just anounces the character unicode number but
+ this information may be changed in the future
+
+ Arguments:
+ - character: the character to speak information of
+ """
+ # Translators: this is information about a unicode character
+ # reported to the user. The value is the unicode number value
+ # of this character in hex.
+ #
+ speech.speak(_("Unicode %s") % \
+ self.utilities.unicodeValueString(character))
+
+ def presentTime(self, inputEvent):
+ """ Presents the current time. """
+ timeFormat = _settingsManager.getSetting('presentTimeFormat')
+ message = time.strftime(timeFormat, time.localtime())
+ self.presentMessage(message)
+ return True
+
+ def presentDate(self, inputEvent):
+ """ Presents the current date. """
+ dateFormat = _settingsManager.getSetting('presentDateFormat')
+ message = time.strftime(dateFormat, time.localtime())
+ self.presentMessage(message)
+ return True
+
+# Dictionary that defines the state changes we care about for various
+# objects. The key represents the role and the value represents a list
+# of states that we care about.
+#
+state_change_notifiers = {}
+
+state_change_notifiers[pyatspi.ROLE_CHECK_MENU_ITEM] = ("checked", None)
+state_change_notifiers[pyatspi.ROLE_CHECK_BOX] = ("checked",
+ "indeterminate",
+ None)
+state_change_notifiers[pyatspi.ROLE_PANEL] = ("showing", None)
+state_change_notifiers[pyatspi.ROLE_LABEL] = ("showing", None)
+state_change_notifiers[pyatspi.ROLE_RADIO_BUTTON] = ("checked", None)
+state_change_notifiers[pyatspi.ROLE_TOGGLE_BUTTON] = ("checked",
+ "pressed",
+ None)
+state_change_notifiers[pyatspi.ROLE_TABLE_CELL] = ("checked",
+ "expanded",
+ None)
+state_change_notifiers[pyatspi.ROLE_LIST_ITEM] = ("expanded", None)
+state_change_notifiers[pyatspi.ROLE_LABEL] = ("expanded", None)
diff --git a/src/orca/event_manager.py b/src/orca/event_manager.py
index db73fd7..272a8de 100644
--- a/src/orca/event_manager.py
+++ b/src/orca/event_manager.py
@@ -59,12 +59,7 @@ class EventManager:
"""Called when this presentation manager is activated."""
global _scriptManager
-
- if hasattr(orca, '_scriptManager'):
- _scriptManager = getattr(orca, '_scriptManager')
- else:
- from script_manager import ScriptManager
- _scriptManager = ScriptManager()
+ _scriptManager = getattr(orca, '_scriptManager')
# Tell BrlTTY which commands we care about.
#
@@ -204,7 +199,6 @@ class EventManager:
toolkitName = None
if toolkitName in settings.synchronousToolkits:
asyncMode = False
-
script = _scriptManager.getScript(app, e.source)
script.eventCache[e.type] = (e, time.time())
diff --git a/src/orca/interfaces.py b/src/orca/interfaces.py
index f721d77..b383d8e 100644
--- a/src/orca/interfaces.py
+++ b/src/orca/interfaces.py
@@ -1,31 +1,22 @@
-# Orca
-#
-# Copyright 2011 Consorcio Fernando de los Rios.
-# Author: J. Ignacio Alvarez <jialvarez emergya es>
-# Author: J. Felix Ontanon <fontanon emergya es>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2010, J. Félix Ontañón <felixonta gmail com>
+# Copyright (C) 2011, J. Ignacio Ã?lvarez <neonigma gmail com>
+
+# This file is part of Pluglib.
+
+# Pluglib is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Pluglib is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
-# Boston MA 02110-1301 USA.
-
-"""Definition of interfaces must be implemented in plugins."""
-
-__id__ = "$Id$"
-__version__ = "$Revision$"
-__date__ = "$Date$"
-__copyright__ = "Copyright (c) 2011 Consorcio Fernando de los Rios."
-__license__ = "LGPL"
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Pluglib. If not, see <http://www.gnu.org/licenses/>.
import exceptions
import abc
@@ -190,67 +181,6 @@ class ICommand(object):
def get_command(command_name):
"""Return a command in this environment"""
-#
-#class Messaging(script.Script):
-#
-# def presentMessage(self, fullMessage, briefMessage=None, voice=None):
-# """Convenience method to speak a message and 'flash' it in braille.
-#
-# Arguments:
-# - fullMessage: This can be a string or a list. This will be presented
-# as the message for users whose flash or message verbosity level is
-# verbose.
-# - briefMessage: This can be a string or a list. This will be presented
-# as the message for users whose flash or message verbosity level is
-# brief. Note that providing no briefMessage will result in the full
-# message being used for either. Callers wishing to present nothing as
-# the briefMessage should set briefMessage to an empty string.
-# - voice: The voice to use when speaking this message. By default, the
-# "system" voice will be used.
-# """
-#
-# print "Called presentMessage..."
-#
-# if not fullMessage:
-# return
-#
-# if briefMessage is None:
-# briefMessage = fullMessage
-#
-# if _settingsManager.getSetting('enableSpeech'):
-# if _settingsManager.getSetting('messageVerbosityLevel') \
-# == settings.VERBOSITY_LEVEL_BRIEF:
-# message = briefMessage
-# else:
-# message = fullMessage
-# if message:
-# voice = voice or self.voices.get(settings.SYSTEM_VOICE)
-# speech.speak(message, voice)
-#
-# if (_settingsManager.getSetting('enableBraille') \
-# or _settingsManager.getSetting('enableBrailleMonitor')) \
-# and _settingsManager.getSetting('enableFlashMessages'):
-# if _settingsManager.getSetting('flashVerbosityLevel') \
-# == settings.VERBOSITY_LEVEL_BRIEF:
-# message = briefMessage
-# else:
-# message = fullMessage
-# if not message:
-# return
-#
-# if isinstance(message[0], list):
-# message = message[0]
-# if isinstance(message, list):
-# message = filter(lambda i: isinstance(i, str), message)
-# message = " ".join(message)
-#
-# if _settingsManager.getSetting('flashIsPersistent'):
-# duration = -1
-# else:
-# duration = _settingsManager.getSetting('brailleFlashTime')
-#
-# braille.displayMessage(message, flashTime=duration)
-
class IPresenter(object):
"""Allows to operate with presentation plugins"""
@@ -259,8 +189,62 @@ class IPresenter(object):
############## METHODS #################
def presentMessage(self, fullMessage, briefMessage=None, voice=None):
- print "Calling Messaging with fullMessage: " + str(fullMessage)
-# msg = Messaging(fullMessage, briefMessage, voice)
+ """Convenience method to speak a message and 'flash' it in braille.
+
+ Arguments:
+ - fullMessage: This can be a string or a list. This will be presented
+ as the message for users whose flash or message verbosity level is
+ verbose.
+ - briefMessage: This can be a string or a list. This will be presented
+ as the message for users whose flash or message verbosity level is
+ brief. Note that providing no briefMessage will result in the full
+ message being used for either. Callers wishing to present nothing as
+ the briefMessage should set briefMessage to an empty string.
+ - voice: The voice to use when speaking this message. By default, the
+ "system" voice will be used.
+ """
+
+ print "Called presentMessage..."
+
+ if not fullMessage:
+ return
+
+ if briefMessage is None:
+ briefMessage = fullMessage
+
+ if _settingsManager.getSetting('enableSpeech'):
+ if _settingsManager.getSetting('messageVerbosityLevel') \
+ == settings.VERBOSITY_LEVEL_BRIEF:
+ message = briefMessage
+ else:
+ message = fullMessage
+ if message:
+ voice = voice or self.voices.get(settings.SYSTEM_VOICE)
+ speech.speak(message, voice)
+
+ if (_settingsManager.getSetting('enableBraille') \
+ or _settingsManager.getSetting('enableBrailleMonitor')) \
+ and _settingsManager.getSetting('enableFlashMessages'):
+ if _settingsManager.getSetting('flashVerbosityLevel') \
+ == settings.VERBOSITY_LEVEL_BRIEF:
+ message = briefMessage
+ else:
+ message = fullMessage
+ if not message:
+ return
+
+ if isinstance(message[0], list):
+ message = message[0]
+ if isinstance(message, list):
+ message = filter(lambda i: isinstance(i, str), message)
+ message = " ".join(message)
+
+ if _settingsManager.getSetting('flashIsPersistent'):
+ duration = -1
+ else:
+ duration = _settingsManager.getSetting('brailleFlashTime')
+
+ braille.displayMessage(message, flashTime=duration)
class IDependenciesChecker(object):
"""Allows to check for dependencies before run"""
diff --git a/src/orca/mag.py b/src/orca/mag.py
index 3ed4e5e..ca1991f 100644
--- a/src/orca/mag.py
+++ b/src/orca/mag.py
@@ -47,15 +47,7 @@ import orca_state
from orca_i18n import _ # for gettext support
_magnifierAvailable = False
-
-if hasattr(orca, '_settingsManager'):
- _settingsManager = getattr(orca, '_settingsManager')
-else:
- from settings_manager import SettingsManager
- _settingsManager = SettingsManager()
- if _settingsManager is None:
- print "Could not load the settings manager. Exiting."
- sys.exit(1)
+_settingsManager = getattr(orca, '_settingsManager')
try:
import bonobo
diff --git a/src/orca/manager.py b/src/orca/manager.py
index 9e3bcda..4b27d6c 100644
--- a/src/orca/manager.py
+++ b/src/orca/manager.py
@@ -1,31 +1,22 @@
-# Orca
-#
-# Copyright 2011 Consorcio Fernando de los Rios.
-# Author: J. Ignacio Alvarez <jialvarez emergya es>
-# Author: J. Felix Ontanon <fontanon emergya es>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2010, J. Félix Ontañón <felixonta gmail com>
+# Copyright (C) 2011, J. Ignacio Ã?lvarez <neonigma gmail com>
+
+# This file is part of Pluglib.
+
+# Pluglib is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Pluglib is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
-# Boston MA 02110-1301 USA.
-
-"""Superclass for managing the plugins."""
-
-__id__ = "$Id$"
-__version__ = "$Revision$"
-__date__ = "$Date$"
-__copyright__ = "Copyright (c) 2011 Consorcio Fernando de los Rios."
-__license__ = "LGPL"
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Pluglib. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
@@ -34,15 +25,14 @@ import glob
import imp
import inspect
import abc
-import store_config
-import settings_manager
+import orca.store_config as store_config
-from interfaces import *
+from orca.pluglib.interfaces import *
class ModulePluginManager(IPluginManager):
"""A plugin manager that handles with python modules"""
- def __init__(self, plugin_paths=[]):
+ def __init__(self, plugin_paths=['baseplugins']):
self.plugin_paths = plugin_paths
if not type(self.plugin_paths) is list:
@@ -206,16 +196,10 @@ class ModulePluginManager(IPluginManager):
del (plugin_name)
def get_plugins(self):
- return [(plugin_name, plugin['class'], plugin['type'],
- plugin['registered'], plugin['name'])
+ return [(plugin_name, plugin['class'],
+ plugin['type'], plugin['registered'], plugin['name'])
for (plugin_name, plugin) in self.plugins.items()]
- def get_plugin_object_by_name(self, plugin_name):
- if self.plugins.has_key(plugin_name):
- return self.plugins[plugin_name]['object']
- else:
- return None
-
def is_plugin_loaded(self, plugin_name):
if self.plugins.has_key(plugin_name):
return self.plugins[plugin_name]['object'] is not None
@@ -249,3 +233,4 @@ class ModulePluginManager(IPluginManager):
# Register implementation
IPluginManager.register(ModulePluginManager)
+plugmanager = ModulePluginManager()
diff --git a/src/orca/mouse_review.py b/src/orca/mouse_review.py
index b41d14c..62e52d7 100644
--- a/src/orca/mouse_review.py
+++ b/src/orca/mouse_review.py
@@ -44,11 +44,7 @@ import speech
import braille
import settings
-if hasattr(orca, '_scriptManager'):
- _scriptManager = getattr(orca, '_scriptManager')
-else:
- from script_manager import ScriptManager
- _scriptManager = ScriptManager()
+_scriptManager = getattr(orca, '_scriptManager')
class BoundingBox:
"""A bounding box, currently it is used to test if a given point is
diff --git a/src/orca/orca.py b/src/orca/orca.py
index 013b2a4..04f95de 100644
--- a/src/orca/orca.py
+++ b/src/orca/orca.py
@@ -64,6 +64,12 @@ import settings
from orca_i18n import _
from orca_i18n import ngettext
+#dirname, filename = os.path.split(os.path.abspath(__file__))
+#sys.path.insert(0, os.path.join(dirname, 'pluglib'))
+#sys.path.insert(1, dirname)
+
+import pluglib
+
class Options:
"""Class to handle getting run-time options."""
@@ -519,6 +525,7 @@ _eventManager = EventManager()
from script_manager import ScriptManager
_scriptManager = ScriptManager()
+
try:
# If we don't have an active desktop, we will get a RuntimeError.
import mouse_review
diff --git a/src/orca/orca_console_prefs.py b/src/orca/orca_console_prefs.py
index f3c2bcd..94325a7 100644
--- a/src/orca/orca_console_prefs.py
+++ b/src/orca/orca_console_prefs.py
@@ -50,14 +50,7 @@ workingFactories = []
speechServerChoice = None
speechVoiceChoice = None
-if hasattr(orca, '_settingsManager'):
- _settingsManager = getattr(orca, '_settingsManager')
-else:
- from settings_manager import SettingsManager
- _settingsManager = SettingsManager()
- if _settingsManager is None:
- print "Could not load the settings manager. Exiting."
- sys.exit(1)
+_settingsManager = getattr(orca, '_settingsManager')
# Translators: this is a regular expression that is intended to match
# a positive 'yes' response from a user at the command line. The expression
diff --git a/src/orca/orca_gui_prefs.py b/src/orca/orca_gui_prefs.py
index f5fe161..dc39119 100644
--- a/src/orca/orca_gui_prefs.py
+++ b/src/orca/orca_gui_prefs.py
@@ -51,25 +51,15 @@ import braille
import speech
import speechserver
import text_attribute_names
-from plugin_manager import plugmanager
-import pluglib
import orca_gui_profile
-if hasattr(orca, '_settingsManager'):
- _settingsManager = getattr(orca, '_settingsManager')
-else:
- from settings_manager import SettingsManager
- _settingsManager = SettingsManager()
- if _settingsManager is None:
- print "Could not load the settings manager. Exiting."
- sys.exit(1)
-
-if hasattr(orca, '_scriptManager'):
- _scriptManager = getattr(orca, '_scriptManager')
-else:
- from script_manager import ScriptManager
- _scriptManager = ScriptManager()
+_settingsManager = getattr(orca, '_settingsManager')
+_scriptManager = getattr(orca, '_scriptManager')
+
+# temp here - 3E
+from pluglib.manager import plugmanager
+plugmanager.scan_plugins()
try:
import louis
diff --git a/src/orca/orca_gui_profile.py b/src/orca/orca_gui_profile.py
index 3d62d18..3c65806 100644
--- a/src/orca/orca_gui_profile.py
+++ b/src/orca/orca_gui_profile.py
@@ -157,14 +157,7 @@ class OrcaProfileGUI(orca_gtkbuilder.GtkBuilderWrapper):
import orca
- if hasattr(orca, '_settingsManager'):
- _settingsManager = getattr(orca, '_settingsManager')
- else:
- from settings_manager import SettingsManager
- _settingsManager = SettingsManager()
- if _settingsManager is None:
- print "Could not load the settings manager. Exiting."
- sys.exit(1)
+ _settingsManager = getattr(orca, '_settingsManager')
return _settingsManager.availableProfiles()
diff --git a/src/orca/script.py b/src/orca/script.py
index 7d6822e..25b86f2 100644
--- a/src/orca/script.py
+++ b/src/orca/script.py
@@ -55,7 +55,6 @@ import where_am_I
import bookmarks
import tutorialgenerator
-
class Script:
"""The specific focus tracking scripts for applications.
"""
@@ -68,7 +67,6 @@ class Script:
Arguments:
- app: the Python Accessible application to create a script for
"""
-
self.app = app
if app:
@@ -332,23 +330,10 @@ class Script:
"""Returns the settings associated with this script, regardless of
whether or not the script is active.
"""
-
- import orca
- if hasattr(orca, '_scriptManager'):
- _scriptManager = getattr(orca, '_scriptManager')
- else:
- from script_manager import ScriptManager
- _scriptManager = ScriptManager()
-
- if hasattr(orca, '_settingsManager'):
- _settingsManager = getattr(orca, '_settingsManager')
- else:
- from settings_manager import SettingsManager
- _settingsManager = SettingsManager()
- if _settingsManager is None:
- print "Could not load the settings manager. Exiting."
- sys.exit(1)
+ import orca
+ _scriptManager = getattr(orca, '_scriptManager')
+ _settingsManager = getattr(orca, '_settingsManager')
scriptSettings = settings
if orca_state.activeScript != self:
diff --git a/src/orca/script_manager.py b/src/orca/script_manager.py
index 9c7f147..fc396b0 100644
--- a/src/orca/script_manager.py
+++ b/src/orca/script_manager.py
@@ -30,20 +30,8 @@ import orca_state
from scripts import apps, toolkits
-if hasattr(orca, '_settingsManager'):
- _settingsManager = getattr(orca, '_settingsManager')
-else:
- from settings_manager import SettingsManager
- _settingsManager = SettingsManager()
- if _settingsManager is None:
- print "Could not load the settings manager. Exiting."
- sys.exit(1)
-
-if hasattr(orca, '_eventManager'):
- _eventManager = getattr(orca, '_eventManager')
-else:
- from event_manager import EventManager
- _eventManager = EventManager()
+_settingsManager = getattr(orca, '_settingsManager')
+_eventManager = getattr(orca, '_eventManager')
class ScriptManager:
diff --git a/src/orca/scripts/default.py b/src/orca/scripts/default.py
index b2b2db4..3eecc9f 100644
--- a/src/orca/scripts/default.py
+++ b/src/orca/scripts/default.py
@@ -33,8 +33,6 @@ __license__ = "LGPL"
import locale
import time
-print "INTENTOOOOOO"
-
import orca.orca as orca
_settingsManager = getattr(orca, '_settingsManager')
@@ -93,7 +91,6 @@ class Script(script.Script):
"""
script.Script.__init__(self, app)
- self.app = app
self.flatReviewContext = None
self.windowActivateTime = None
self.lastReviewCurrentEvent = None
@@ -1070,40 +1067,23 @@ class Script(script.Script):
#
_("Toggle mouse review mode."))
- from plugin_manager import plugmanager
-
- plugmanager.scan_plugins()
- plugmanager.get_plugins()
-
- plugin_active = plugmanager.is_plugin_enabled("test")
-
- if plugin_active is True:
- testPluginObj = plugmanager.get_plugin_object_by_name("test")
-
- if testPluginObj:
- self.inputEventHandlers["presentTimeHandler"] = testPluginObj.getPresentTimeHandler(Script.presentTime)
- self.inputEventHandlers["presentDateHandler"] = testPluginObj.getPresentDateHandler(Script.presentDate)
-
- # my checks
- testPluginObj.registerEvent("event1", self.presentTime)
+ self.inputEventHandlers["presentTimeHandler"] = \
+ input_event.InputEventHandler(
+ Script.presentTime,
+ # Translators: Orca can present the current time to the
+ # user when the user presses
+ # a shortcut key.
+ #
+ _("Present current time."))
-# self.inputEventHandlers["presentTimeHandler"] = \
-# input_event.InputEventHandler(
-# Script.presentTime,
-# # Translators: Orca can present the current time to the
-# # user when the user presses
-# # a shortcut key.
-# #
-# _("Present current time."))
-#
-# self.inputEventHandlers["presentDateHandler"] = \
-# input_event.InputEventHandler(
-# Script.presentDate,
-# # Translators: Orca can present the current date to the
-# # user when the user presses
-# # a shortcut key.
-# #
-# _("Present current date."))
+ self.inputEventHandlers["presentDateHandler"] = \
+ input_event.InputEventHandler(
+ Script.presentDate,
+ # Translators: Orca can present the current date to the
+ # user when the user presses
+ # a shortcut key.
+ #
+ _("Present current date."))
self.inputEventHandlers["bypassNextCommandHandler"] = \
input_event.InputEventHandler(
@@ -1119,9 +1099,6 @@ class Script(script.Script):
self.inputEventHandlers.update(notification_messages.inputEventHandlers)
- def sayHello():
- print "Hello from default!"
-
def getInputEventHandlerKey(self, inputEventHandler):
"""Returns the name of the key that contains an inputEventHadler
passed as argument
diff --git a/src/orca/self_voicing.py b/src/orca/self_voicing.py
new file mode 100644
index 0000000..b75fc5c
--- /dev/null
+++ b/src/orca/self_voicing.py
@@ -0,0 +1,80 @@
+# Orca
+#
+# Copyright 2006-2008 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
+# Boston MA 02110-1301 USA.
+
+"""A script to do nothing. This is for self-voicing apps."""
+
+__id__ = "$Id$"
+__version__ = "$Revision$"
+__date__ = "$Date$"
+__copyright__ = "Copyright (c) 2005-2008 Sun Microsystems Inc."
+__license__ = "LGPL"
+
+import orca.scripts.default as default
+
+class Script(default.Script):
+ """A script to do nothing. This is for self-voicing apps."""
+
+ def __init__(self, app):
+ """Creates a script for the given application, if necessary.
+ This method should not be called by anyone except the
+ script manager.
+
+ Arguments:
+ - app: the Python Accessible application to create a script for
+ """
+
+ default.Script.__init__(self, app)
+
+ def getBrailleGenerator(self):
+ """Returns the braille generator for this script.
+ """
+ return None
+
+ def getSpeechGenerator(self):
+ """Returns the speech generator for this script.
+ """
+ return None
+
+ def processObjectEvent(self, event):
+ """Does nothing.
+
+ Arguments:
+ - event: the Event
+ """
+ pass
+
+ def processKeyboardEvent(self, keyboardEvent):
+ """Does nothing.
+
+ Arguments:
+ - keyboardEvent: an instance of input_event.KeyboardEvent
+
+ Returns False to indicate the event was not consumed.
+ """
+ return False
+
+ def processBrailleEvent(self, brailleEvent):
+ """Does nothing.
+
+ Arguments:
+ - brailleEvent: an instance of input_event.BrailleEvent
+
+ Returns False to indicate the event was not consumed.
+ """
+ return False
diff --git a/src/orca/settings.py b/src/orca/settings.py
index 9ce0348..aa3d8f1 100644
--- a/src/orca/settings.py
+++ b/src/orca/settings.py
@@ -1034,15 +1034,7 @@ def setGKSUGrabDisabled(disable):
#
def overrideKeyBindings(script, keyBindings):
import orca
-
- if hasattr(orca, '_settingsManager'):
- _settingsManager = getattr(orca, '_settingsManager')
- else:
- from settings_manager import SettingsManager
- _settingsManager = SettingsManager()
- if _settingsManager is None:
- print "Could not load the settings manager. Exiting."
- sys.exit(1)
+ _settingsManager = getattr(orca, '_settingsManager')
return _settingsManager.overrideKeyBindings(script, keyBindings)
diff --git a/src/orca/settings_manager.py b/src/orca/settings_manager.py
index 4231b0c..96d666b 100644
--- a/src/orca/settings_manager.py
+++ b/src/orca/settings_manager.py
@@ -487,11 +487,7 @@ class SettingsManager(object):
"""
import orca
- if hasattr(orca, '_scriptManager'):
- _scriptManager = getattr(orca, '_scriptManager')
- else:
- from script_manager import ScriptManager
- _scriptManager = ScriptManager()
+ _scriptManager = getattr(orca, '_scriptManager')
app = script.app
moduleName = _scriptManager.getModuleName(app)
@@ -596,6 +592,3 @@ def getRealValues(prefs):
# prefs[key] = getValueForKey(prefs, key)
return prefs
-from plugin_manager import plugmanager
-plugmanager.scan_plugins()
-
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index 55b7a30..7bcd677 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -80,14 +80,7 @@ voiceType = {
VALUE : settings.SYSTEM_VOICE, # Users may prefer DEFAULT_VOICE here
}
-if hasattr(orca, '_settingsManager'):
- _settingsManager = getattr(orca, '_settingsManager')
-else:
- from settings_manager import SettingsManager
- _settingsManager = SettingsManager()
- if _settingsManager is None:
- print "Could not load the settings manager. Exiting."
- sys.exit(1)
+_settingsManager = getattr(orca, '_settingsManager')
class SpeechGenerator(generator.Generator):
"""Takes accessible objects and produces a string to speak for
diff --git a/src/orca/store_config.py b/src/orca/store_config.py
index 58df6e5..3102b59 100644
--- a/src/orca/store_config.py
+++ b/src/orca/store_config.py
@@ -1,37 +1,29 @@
-# Orca
-#
-# Copyright 2011 Consorcio Fernando de los Rios.
-# Author: J. Ignacio Alvarez <jialvarez emergya es>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the
-# Free Software Foundation, Inc., Franklin Street, Fifth Floor,
-# Boston MA 02110-1301 USA.
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2011, J. Ignacio Ã?lvarez <neonigma gmail com>
+
+# This file is part of Pluglib ABC.
-"""Instance for managing the plugings."""
+# Pluglib is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Pluglib is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
-__id__ = "$Id$"
-__version__ = "$Revision$"
-__date__ = "$Date$"
-__copyright__ = "Copyright (c) 2011 Consorcio Fernando de los Rios."
-__license__ = "LGPL"
+# You should have received a copy of the GNU General Public License
+# along with Pluglib. If not, see <http://www.gnu.org/licenses/>.
-from settings_manager import SettingsManager
class StoreConfig:
def __init__(self):
# get settings_manager instance
- self.sm = SettingsManager()
+ import orca
+ _settingsManager = getattr(orca, '_settingsManager')
+ self.sm = _settingsManager
def addPlugin(self, name, registered, module_name, path):
# receives a dict in the following way
diff --git a/src/orca/test.py b/src/orca/test.py
new file mode 100644
index 0000000..39c5e8c
--- /dev/null
+++ b/src/orca/test.py
@@ -0,0 +1,85 @@
+# - coding: utf-8 -
+
+# Copyright (C) 2010, J. Félix Ontañón <felixonta gmail com>
+# Copyright (C) 2011, J. Ignacio Ã?lvarez <neonigma gmail com>
+
+# This file is part of Pluglib.
+
+# Pluglib is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# Pluglib is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with Pluglib. If not, see <http://www.gnu.org/licenses/>.
+
+from orca.pluglib.interfaces import *
+import orca.input_event as input_event
+
+from orca.orca_i18n import _ # for gettext support
+from orca.orca_i18n import ngettext # for ngettext support
+from orca.orca_i18n import C_ # to provide qualified translatable strings
+
+from orca.scripts.default import Script
+
+# test if I call any Orca code
+defaultObj = Script(None)
+print defaultObj.getListeners()
+
+class callPresenter(IPresenter):
+ inputEventHandlers = {}
+ def __init__(self):
+
+ print "Init call presenter..."
+ self.inputEventHandlers["presentTimeHandler"] = \
+ input_event.InputEventHandler(
+ callPresenter.presentTime,
+ # Translators: Orca can present the current time to the
+ # user when the user presses
+ # a shortcut key.
+ #
+ _("Present current time."))
+
+ self.inputEventHandlers["presentDateHandler"] = \
+ input_event.InputEventHandler(
+ callPresenter.presentDate,
+ # Translators: Orca can present the current date to the
+ # user when the user presses
+ # a shortcut key.
+ #
+ _("Present current date."))
+
+ def presentTime(self, inputEvent):
+ """ Presents the current time. """
+ timeFormat = self._settingsManager.getSetting('presentTimeFormat')
+ message = time.strftime(timeFormat, time.localtime())
+ super.presentMessage(message)
+ return True
+
+ def presentDate(self, inputEvent):
+ """ Presents the current date. """
+ dateFormat = self._settingsManager.getSetting('presentDateFormat')
+ message = time.strftime(dateFormat, time.localtime())
+ super.presentMessage(message)
+ return True
+
+class testPlugin(IPlugin, IPresenter):
+ name = 'Test Plugin'
+ description = 'A testing plugin for code tests'
+ version = '0.1pre'
+ authors = ['J. Félix Ontañón <felixonta gmail com>', 'J. Ignacio �lvarez <neonigma gmail com>']
+ website = 'http://fontanon.org'
+ icon = 'gtk-missing-image'
+
+ def __init__(self):
+ print 'Hello World (plugin started)!'
+ cp = callPresenter()
+
+
+
+IPlugin.register(testPlugin)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]