diff --git a/source/NVDAObjects/IAccessible/__init__.py b/source/NVDAObjects/IAccessible/__init__.py index 8e0bc8bb8cb..5e9d952eee6 100644 --- a/source/NVDAObjects/IAccessible/__init__.py +++ b/source/NVDAObjects/IAccessible/__init__.py @@ -377,8 +377,8 @@ def findOverlayClasses(self,clsList): from . import adobeFlash adobeFlash.findExtraOverlayClasses(self, clsList) elif windowClassName.startswith('Mozilla'): - from .mozilla import Mozilla - clsList.append( Mozilla) + from . import mozilla + mozilla.findExtraOverlayClasses(self, clsList) elif windowClassName.startswith('bosa_sdm'): from .msOffice import SDM clsList.append(SDM) @@ -1450,17 +1450,6 @@ def _get_lastChild(self): ("TrayClockWClass",oleacc.ROLE_SYSTEM_CLIENT):"TrayClockWClass", ("TRxRichEdit",oleacc.ROLE_SYSTEM_CLIENT):"delphi.TRxRichEdit", (None,oleacc.ROLE_SYSTEM_OUTLINEITEM):"OutlineItem", - ("MozillaDialogClass",oleacc.ROLE_SYSTEM_ALERT):"Dialog", - ("MozillaContentWindowClass",oleacc.ROLE_SYSTEM_COMBOBOX):"mozilla.ComboBox", - ("MozillaContentWindowClass",oleacc.ROLE_SYSTEM_LIST):"mozilla.List", - ("MozillaWindowClass",oleacc.ROLE_SYSTEM_LISTITEM):"mozilla.ListItem", - ("MozillaContentWindowClass",oleacc.ROLE_SYSTEM_LISTITEM):"mozilla.ListItem", - ("MozillaContentWindowClass",oleacc.ROLE_SYSTEM_DOCUMENT):"mozilla.Document", - ("MozillaWindowClass",oleacc.ROLE_SYSTEM_DOCUMENT):"mozilla.Document", - ("MozillaUIWindowClass",oleacc.ROLE_SYSTEM_TABLE):"mozilla.Table", - ("MozillaUIWindowClass",oleacc.ROLE_SYSTEM_OUTLINE):"mozilla.Tree", - ("MozillaContentWindowClass",IAccessibleHandler.IA2_ROLE_EMBEDDED_OBJECT):"mozilla.EmbeddedObject", - ("MozillaContentWindowClass","embed"):"mozilla.EmbeddedObject", ("ConsoleWindowClass",oleacc.ROLE_SYSTEM_WINDOW):"ConsoleWindowClass", (None,oleacc.ROLE_SYSTEM_LIST):"List", (None,oleacc.ROLE_SYSTEM_COMBOBOX):"ComboBox", diff --git a/source/NVDAObjects/IAccessible/mozilla.py b/source/NVDAObjects/IAccessible/mozilla.py index 7fb5d771071..283dd744ff1 100755 --- a/source/NVDAObjects/IAccessible/mozilla.py +++ b/source/NVDAObjects/IAccessible/mozilla.py @@ -1,16 +1,16 @@ #NVDAObjects/IAccessible/mozilla.py #A part of NonVisual Desktop Access (NVDA) -#Copyright (C) 2006-2007 NVDA Contributors #This file is covered by the GNU General Public License. #See the file COPYING for more details. +#Copyright (C) 2006-2010 Michael Curran , James Teh import IAccessibleHandler import oleacc import winUser +from comtypes import IServiceProvider, COMError import eventHandler import controlTypes -from . import IAccessible -import textInfos +from . import IAccessible, Dialog from logHandler import log class Mozilla(IAccessible): @@ -22,13 +22,6 @@ def _get_beTransparentToMouse(self): return True return super(Mozilla,self).beTransparentToMouse - def _get_description(self): - rawDescription=super(Mozilla,self).description - if isinstance(rawDescription,basestring) and rawDescription.startswith('Description: '): - return rawDescription[13:] - else: - return "" - def _get_parent(self): #Special code to support Mozilla node_child_of relation (for comboboxes) res=IAccessibleHandler.accNavigate(self.IAccessibleObject,self.IAccessibleChildID,IAccessibleHandler.NAVRELATION_NODE_CHILD_OF) @@ -38,36 +31,54 @@ def _get_parent(self): return newObj return super(Mozilla,self).parent + def _get_states(self): + states = super(Mozilla, self).states + if self.IAccessibleStates & oleacc.STATE_SYSTEM_MARQUEED: + states.add(controlTypes.STATE_CHECKABLE) + return states + +class Gecko1_9(Mozilla): + + def _get_description(self): + rawDescription=super(Mozilla,self).description + if isinstance(rawDescription,basestring) and rawDescription.startswith('Description: '): + return rawDescription[13:] + else: + return "" + def event_scrollingStart(self): #Firefox 3.6 fires scrollingStart on leaf nodes which is not useful to us. #Bounce the event up to the node's parent so that any possible virtualBuffers will detect it. if self.role==controlTypes.ROLE_EDITABLETEXT and controlTypes.STATE_READONLY in self.states: eventHandler.queueEvent("scrollingStart",self.parent) - def _get_states(self): - states = super(Mozilla, self).states - if self.IAccessibleStates & oleacc.STATE_SYSTEM_MARQUEED: - states.add(controlTypes.STATE_CHECKABLE) - return states +class BrokenFocusedState(Mozilla): + shouldAllowIAccessibleFocusEvent=True + +class RootApplication(Mozilla): + """Mozilla exposes a root application accessible as the parent of all top level frames. + See MozillaBug:555861. + This is non-standard; the top level accessible should be the top level window. + NVDA expects the standard behaviour, so we never want to see this object. + """ + + def __nonzero__(self): + # As far as NVDA is concerned, this is a useless object. + return False class Document(Mozilla): - shouldAllowIAccessibleFocusEvent=True + value=None def _get_treeInterceptorClass(self): states=self.states - if isinstance(self.IAccessibleObject,IAccessibleHandler.IAccessible2) and controlTypes.STATE_READONLY in states and controlTypes.STATE_BUSY not in states and self.windowClassName=="MozillaContentWindowClass": + if controlTypes.STATE_READONLY in states and controlTypes.STATE_BUSY not in states and self.windowClassName=="MozillaContentWindowClass": import virtualBuffers.gecko_ia2 return virtualBuffers.gecko_ia2.Gecko_ia2 return super(Document,self).treeInterceptorClass - def _get_value(self): - return - class ListItem(Mozilla): - shouldAllowIAccessibleFocusEvent=True - def _get_name(self): name=super(ListItem,self)._get_name() if self.IAccessibleStates&oleacc.STATE_SYSTEM_READONLY: @@ -82,20 +93,6 @@ def _get_children(self): del children[0] return children -class ComboBox(Mozilla): - - shouldAllowIAccessibleFocusEvent=True - -class List(Mozilla): - - shouldAllowIAccessibleFocusEvent=True - -class Table(Mozilla): - shouldAllowIAccessibleFocusEvent=True - -class Tree(Mozilla): - shouldAllowIAccessibleFocusEvent=True - class EmbeddedObject(Mozilla): def _get_shouldAllowIAccessibleFocusEvent(self): @@ -105,3 +102,64 @@ def _get_shouldAllowIAccessibleFocusEvent(self): # We don't want to override the focus event fired by the embedded object. return False return super(EmbeddedObject, self).shouldAllowIAccessibleFocusEvent + +def _getGeckoVersion(obj): + appMod = obj.appModule + try: + return appMod._geckoVersion + except AttributeError: + pass + try: + ver = obj.IAccessibleObject.QueryInterface(IServiceProvider).QueryService(IAccessibleHandler.IAccessibleApplication._iid_, IAccessibleHandler.IAccessibleApplication).toolkitVersion + except COMError: + return None + appMod._geckoVersion = ver + return ver + +def findExtraOverlayClasses(obj, clsList): + """Determine the most appropriate class if this is a Mozilla object. + This works similarly to L{NVDAObjects.NVDAObject.findOverlayClasses} except that it never calls any other findOverlayClasses method. + """ + if not isinstance(obj.IAccessibleObject, IAccessibleHandler.IAccessible2): + # We require IAccessible2; i.e. Gecko >= 1.9. + return + + iaRole = obj.IAccessibleRole + cls = None + if iaRole == oleacc.ROLE_SYSTEM_APPLICATION: + try: + if not obj.IAccessibleObject.windowHandle: + cls = RootApplication + except COMError: + pass + if not cls: + cls = _IAccessibleRolesToOverlayClasses.get(iaRole) + if cls: + clsList.append(cls) + if iaRole in _IAccessibleRolesWithBrokenFocusedState: + clsList.append(BrokenFocusedState) + + if _getGeckoVersion(obj).startswith("1.9"): + clsList.append(Gecko1_9) + + clsList.append(Mozilla) + +#: Maps IAccessible roles to NVDAObject overlay classes. +_IAccessibleRolesToOverlayClasses = { + oleacc.ROLE_SYSTEM_ALERT: Dialog, + oleacc.ROLE_SYSTEM_LISTITEM: ListItem, + oleacc.ROLE_SYSTEM_DOCUMENT: Document, + IAccessibleHandler.IA2_ROLE_EMBEDDED_OBJECT: EmbeddedObject, + "embed": EmbeddedObject, +} + +#: Roles that mightn't set the focused state when they are focused. +_IAccessibleRolesWithBrokenFocusedState = frozenset(( + oleacc.ROLE_SYSTEM_COMBOBOX, + oleacc.ROLE_SYSTEM_LIST, + oleacc.ROLE_SYSTEM_LISTITEM, + oleacc.ROLE_SYSTEM_DOCUMENT, + oleacc.ROLE_SYSTEM_APPLICATION, + oleacc.ROLE_SYSTEM_TABLE, + oleacc.ROLE_SYSTEM_OUTLINE, +)) diff --git a/source/speech.py b/source/speech.py index b59011e120c..2329c54b59c 100755 --- a/source/speech.py +++ b/source/speech.py @@ -431,6 +431,7 @@ def speakTypedCharacters(ch): controlTypes.ROLE_RADIOBUTTON, controlTypes.ROLE_LINK, controlTypes.ROLE_MENUITEM, + controlTypes.ROLE_APPLICATION, ]) def processPositiveStates(role, states, reason, positiveStates):