Package NVDAObjects :: Package IAccessible :: Module sysTreeView32
[hide private]
[frames] | no frames]

Source Code for Module NVDAObjects.IAccessible.sysTreeView32

  1  #NVDAObjects/IAccessible/sysTreeView32.py 
  2  #A part of NonVisual Desktop Access (NVDA) 
  3  #This file is covered by the GNU General Public License. 
  4  #See the file COPYING for more details. 
  5  #Copyright (C) 2007-2010 Michael Curran <mick@kulgan.net>, James Teh <jamie@jantrid.net> 
  6   
  7  from ctypes import * 
  8  from ctypes.wintypes import * 
  9  import api 
 10  import winKernel 
 11  import controlTypes 
 12  import speech 
 13  import UIAHandler 
 14  from . import IAccessible 
 15  if UIAHandler.isUIAAvailable: from ..UIA import UIA 
 16  from .. import NVDAObject 
 17  from logHandler import log 
 18  import watchdog 
 19   
 20  TV_FIRST=0x1100 
 21  TVIS_STATEIMAGEMASK=0xf000 
 22   
 23  #Window messages 
 24  TVM_GETITEMSTATE=TV_FIRST+39 
 25  TVM_GETITEM=TV_FIRST+62 
 26  TVM_MAPACCIDTOHTREEITEM=TV_FIRST+42 
 27  TVM_MAPHTREEITEMTOACCID=TV_FIRST+43 
 28  TVM_GETNEXTITEM=TV_FIRST+10 
 29   
 30  #item mask flags 
 31  TVIF_CHILDREN=0x40 
 32   
 33  #Relation codes 
 34  TVGN_ROOT=0 
 35  TVGN_NEXT=1 
 36  TVGN_PREVIOUS=2 
 37  TVGN_PARENT=3 
 38  TVGN_CHILD=4 
39 40 -class TVItemStruct(Structure):
41 _fields_=[ 42 ('mask',c_uint), 43 ('hItem',c_void_p), 44 ('state',c_uint), 45 ('stateMask',c_uint), 46 ('pszText',LPWSTR), 47 ('cchTextMax',c_int), 48 ('iImage',c_int), 49 ('iSelectedImage',c_int), 50 ('cChildren',c_int), 51 ('lParam',LPARAM), 52 ]
53
54 -class TreeView(IAccessible):
55
56 - def _get_firstChild(self):
57 try: 58 return super(TreeView, self).firstChild 59 except: 60 # Broken commctrl 5 tree view. 61 return BrokenCommctrl5Item.getFirstItem(self)
62
63 -class TreeViewItem(IAccessible):
64
65 - def _get_role(self):
67
68 - def _get_treeview_hItem(self):
69 if not hasattr(self,'_treeview_hItem'): 70 self._treeview_hItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_MAPACCIDTOHTREEITEM,self.IAccessibleChildID,0) 71 if not self._treeview_hItem: 72 # Tree views from comctl < 6.0 use the hItem as the child ID. 73 self._treeview_hItem=self.IAccessibleChildID 74 return self._treeview_hItem
75
76 - def _get_treeview_level(self):
77 return int(self.IAccessibleObject.accValue(self.IAccessibleChildID))
78
79 - def _get_states(self):
80 states=super(TreeViewItem,self)._get_states() 81 hItem=self.treeview_hItem 82 itemStates=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETITEMSTATE,hItem,TVIS_STATEIMAGEMASK) 83 ch=(itemStates>>12)&3 84 if ch>0: 85 states.add(controlTypes.STATE_CHECKABLE) 86 if ch==2: 87 states.add(controlTypes.STATE_CHECKED) 88 elif ch==3: 89 states.add(controlTypes.STATE_HALFCHECKED) 90 return states
91
92 - def _get_value(self):
93 return None
94
95 - def _get_parent(self):
96 if self.IAccessibleChildID==0: 97 return super(TreeViewItem,self)._get_parent() 98 hItem=self.treeview_hItem 99 if not hItem: 100 return super(TreeViewItem,self)._get_parent() 101 parentItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_PARENT,hItem) 102 if parentItem<=0: 103 return super(TreeViewItem,self)._get_parent() 104 newID=watchdog.cancellableSendMessage(self.windowHandle,TVM_MAPHTREEITEMTOACCID,parentItem,0) 105 if not newID: 106 # Tree views from comctl < 6.0 use the hItem as the child ID. 107 newID=parentItem 108 return IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=newID)
109
110 - def _get_firstChild(self):
111 if self.IAccessibleChildID==0: 112 return super(TreeViewItem,self)._get_firstChild() 113 hItem=self.treeview_hItem 114 if not hItem: 115 return super(TreeViewItem,self)._get_firstChild() 116 childItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_CHILD,hItem) 117 if childItem<=0: 118 return super(TreeViewItem,self)._get_firstChild() 119 newID=watchdog.cancellableSendMessage(self.windowHandle,TVM_MAPHTREEITEMTOACCID,childItem,0) 120 if not newID: 121 # Tree views from comctl < 6.0 use the hItem as the child ID. 122 newID=childItem 123 return IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=newID)
124
125 - def _get_next(self):
126 if self.IAccessibleChildID==0: 127 return super(TreeViewItem,self)._get_next() 128 hItem=self.treeview_hItem 129 if not hItem: 130 return None 131 nextItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_NEXT,hItem) 132 if nextItem<=0: 133 return None 134 newID=watchdog.cancellableSendMessage(self.windowHandle,TVM_MAPHTREEITEMTOACCID,nextItem,0) 135 if not newID: 136 # Tree views from comctl < 6.0 use the hItem as the child ID. 137 newID=nextItem 138 return IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=newID)
139
140 - def _get_previous(self):
141 if self.IAccessibleChildID==0: 142 return super(TreeViewItem,self)._get_previous() 143 hItem=self.treeview_hItem 144 if not hItem: 145 return None 146 prevItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_PREVIOUS,hItem) 147 if prevItem<=0: 148 return None 149 newID=watchdog.cancellableSendMessage(self.windowHandle,TVM_MAPHTREEITEMTOACCID,prevItem,0) 150 if not newID: 151 # Tree views from comctl < 6.0 use the hItem as the child ID. 152 newID=prevItem 153 return IAccessible(windowHandle=self.windowHandle,IAccessibleObject=self.IAccessibleObject,IAccessibleChildID=newID)
154
155 - def _get_children(self):
156 children=[] 157 child=self.firstChild 158 while child: 159 children.append(child) 160 child=child.next 161 return children
162
163 - def _get_childCount(self):
164 hItem=self.treeview_hItem 165 if not hItem: 166 return 0 167 childItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_CHILD,hItem) 168 if childItem<=0: 169 return 0 170 numItems=0 171 while childItem>0: 172 numItems+=1 173 childItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_NEXT,childItem) 174 return numItems
175
176 - def _get_positionInfo(self):
177 if self.IAccessibleChildID==0: 178 return super(TreeViewItem,self)._get_positionInfo() 179 info={} 180 info['level']=self.treeview_level 181 hItem=self.treeview_hItem 182 if not hItem: 183 return info 184 newItem=hItem 185 index=0 186 while newItem>0: 187 index+=1 188 newItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_PREVIOUS,newItem) 189 newItem=hItem 190 numItems=index-1 191 while newItem>0: 192 numItems+=1 193 newItem=watchdog.cancellableSendMessage(self.windowHandle,TVM_GETNEXTITEM,TVGN_NEXT,newItem) 194 info['indexInGroup']=index 195 info['similarItemsInGroup']=numItems 196 return info
197
198 - def event_stateChange(self):
199 announceContains = self is api.getFocusObject() and controlTypes.STATE_EXPANDED in self.states and controlTypes.STATE_EXPANDED not in getattr(self,'_speakObjectPropertiesCache',{}).get('states',frozenset()) 200 super(TreeViewItem,self).event_stateChange() 201 if announceContains: 202 speech.speakMessage(_("%s items")%self.childCount)
203
204 -class BrokenCommctrl5Item(IAccessible):
205 """Handle broken CommCtrl v5 SysTreeView32 items in 64 bit applications. 206 In these controls, IAccessible fails to retrieve any info, so we must retrieve it using UIA. 207 We do this by obtaining a UIA NVDAObject and redirecting properties to it. 208 We can't simply use UIA objects alone for these controls because UIA events are also broken. 209 """ 210
211 - def __init__(self, _uiaObj=None, **kwargs):
212 # This class is being directly instantiated. 213 if not _uiaObj: 214 raise ValueError("Cannot instantiate directly without supplying _uiaObj") 215 self._uiaObj = _uiaObj 216 super(BrokenCommctrl5Item, self).__init__(**kwargs)
217
218 - def initOverlayClass(self):
219 self._uiaObj = None 220 if UIAHandler.handler: 221 parent=super(BrokenCommctrl5Item, self).parent 222 if parent and parent.hasFocus: 223 try: 224 kwargs = {} 225 UIA.kwargsFromSuper(kwargs, relation="focus") 226 self._uiaObj = UIA(**kwargs) 227 except: 228 log.debugWarning("Retrieving UIA focus failed", exc_info=True)
229
230 - def _get_role(self):
231 return self._uiaObj.role if self._uiaObj else controlTypes.ROLE_UNKNOWN
232
233 - def _get_name(self):
234 return self._uiaObj.name if self._uiaObj else None
235
236 - def _get_description(self):
237 return self._uiaObj.description if self._uiaObj else None
238
239 - def _get_value(self):
240 return self._uiaObj.value if self._uiaObj else None
241
242 - def _get_states(self):
243 return self._uiaObj.states if self._uiaObj else set()
244
245 - def _get_positionInfo(self):
246 return self._uiaObj.positionInfo if self._uiaObj else {}
247
248 - def _get_location(self):
249 return self._uiaObj.location if self._uiaObj else None
250
251 - def _makeRelatedObj(self, uiaObj):
252 # We need to wrap related UIA objects so that the ancestry will return to IAccessible for the tree view itself. 253 if not uiaObj: 254 return None 255 return BrokenCommctrl5Item(IAccessibleObject=self.IAccessibleObject, IAccessibleChildID=self.IAccessibleChildID, windowHandle=self.windowHandle, _uiaObj=uiaObj)
256
257 - def _get_parent(self):
258 if self._uiaObj: 259 uiaParent = self._uiaObj.parent 260 # If the parent is the tree view itself (root window object), just use super's parent. IAccessible isn't broken on the container itself. 261 if not uiaParent.UIAElement.cachedNativeWindowHandle: 262 return self._makeRelatedObj(uiaParent) 263 return super(BrokenCommctrl5Item, self).parent
264
265 - def _get_next(self):
266 return self._makeRelatedObj(self._uiaObj.next) if self._uiaObj else None
267
268 - def _get_previous(self):
269 return self._makeRelatedObj(self._uiaObj.previous) if self._uiaObj else None
270
271 - def _get_firstChild(self):
272 return self._makeRelatedObj(self._uiaObj.firstChild) if self._uiaObj else None
273
274 - def _get_lastChild(self):
275 return self._makeRelatedObj(self._uiaObj.lastChild) if self._uiaObj else None
276
277 - def _get_children(self):
278 # Use the base algorithm, which uses firstChild and next. 279 return NVDAObject._get_children(self)
280 281 @classmethod
282 - def getFirstItem(cls, treeObj):
283 """Get an instance for the first item in a given tree view. 284 """ 285 if not UIAHandler.handler: 286 return None 287 # Get a UIA object for the tree view by getting the root object for the window. 288 try: 289 kwargs = {"windowHandle": treeObj.windowHandle} 290 UIA.kwargsFromSuper(kwargs) 291 uiaObj = UIA(**kwargs) 292 except: 293 log.debugWarning("Error retrieving UIA object for tree view", exc_info=True) 294 return None 295 # Get the first tree item. 296 uiaObj = uiaObj.firstChild 297 if not uiaObj: 298 return None 299 # The IAccessibleChildID for this object isn't really used. 300 # However, it must not be 0, as 0 is the tree view itself. 301 return cls(IAccessibleObject=treeObj.IAccessibleObject, IAccessibleChildID=1, windowHandle=treeObj.windowHandle, _uiaObj=uiaObj)
302