1
2 #include "studiox_includes.h"
3 #include "uiautomation.h"
4 #include "resource_view_provider.h"
5 #include "resource_item_provider.h"
6
7 ///////////////////////////////////////////////////////////////////////////////
resource_item_provider(resource_item * pControl)8 resource_item_provider::resource_item_provider(resource_item *pControl)
9 {
10 m_refCount = 1;
11 m_pResItemControl = pControl;
12
13 resource_tree *pTree = m_pResItemControl->GetResTree();
14 m_pResViewControl = pTree->GetParent();
15 }
16
17 ///////////////////////////////////////////////////////////////////////////////
~resource_item_provider()18 resource_item_provider::~resource_item_provider()
19 {
20 }
21
22 ///////////////////////////////////////////////////////////////////////////////
23 // IUnknown implementation.
24 //
25 ///////////////////////////////////////////////////////////////////////////////
IFACEMETHODIMP_(ULONG)26 IFACEMETHODIMP_(ULONG) resource_item_provider::AddRef()
27 {
28 return InterlockedIncrement(&m_refCount);
29 }
30
31 ///////////////////////////////////////////////////////////////////////////////
IFACEMETHODIMP_(ULONG)32 IFACEMETHODIMP_(ULONG) resource_item_provider::Release()
33 {
34 long val = InterlockedDecrement(&m_refCount);
35 if (val == 0)
36 {
37 delete this;
38 }
39 return val;
40 }
41
42 ///////////////////////////////////////////////////////////////////////////////
QueryInterface(REFIID riid,void ** ppInterface)43 IFACEMETHODIMP resource_item_provider::QueryInterface(REFIID riid, void** ppInterface)
44 {
45 if (riid == __uuidof(IUnknown)) *ppInterface = static_cast<IRawElementProviderSimple*>(this);
46 else if (riid == __uuidof(IRawElementProviderSimple)) *ppInterface = static_cast<IRawElementProviderSimple*>(this);
47 else if (riid == __uuidof(IRawElementProviderFragment)) *ppInterface = static_cast<IRawElementProviderFragment*>(this);
48 else if (riid == __uuidof(ISelectionItemProvider)) *ppInterface = static_cast<ISelectionItemProvider*>(this);
49 else if (riid == __uuidof(IExpandCollapseProvider)) *ppInterface = static_cast<IExpandCollapseProvider*>(this);
50 else if (riid == __uuidof(IScrollItemProvider)) *ppInterface = static_cast<IScrollItemProvider*>(this);
51 else
52 {
53 *ppInterface = NULL;
54 return E_NOINTERFACE;
55 }
56 (static_cast<IUnknown*>(*ppInterface))->AddRef();
57 return S_OK;
58 }
59
60 ///////////////////////////////////////////////////////////////////////////////
61 // IRawElementProviderSimple implementation
62 //
63 // Implementation of IRawElementProviderSimple::GetProviderOptions.
64 //
65 ///////////////////////////////////////////////////////////////////////////////
get_ProviderOptions(ProviderOptions * pRetVal)66 IFACEMETHODIMP resource_item_provider::get_ProviderOptions(ProviderOptions* pRetVal)
67 {
68
69 *pRetVal = ProviderOptions_ServerSideProvider;
70 return S_OK;
71 }
72
73 ///////////////////////////////////////////////////////////////////////////////
74 // Implementation of IRawElementProviderSimple::GetPatternProvider.
75 // Gets the object that supports the specified pattern.
76 //
77 ///////////////////////////////////////////////////////////////////////////////
GetPatternProvider(PATTERNID patternId,IUnknown ** pRetVal)78 IFACEMETHODIMP resource_item_provider::GetPatternProvider(PATTERNID patternId, IUnknown** pRetVal)
79 {
80 if ((patternId == UIA_SelectionItemPatternId) ||
81 (patternId == UIA_ExpandCollapsePatternId) ||
82 (patternId == UIA_ScrollItemPatternId))
83 {
84 *pRetVal = static_cast<IRawElementProviderSimple*>(this);
85 AddRef();
86 }
87 else
88 {
89 *pRetVal = NULL;
90 }
91 return S_OK;
92 }
93
94 ///////////////////////////////////////////////////////////////////////////////
95 // Implementation of IRawElementProviderSimple::GetPropertyValue.
96 // Gets custom properties.
97 //
98 ///////////////////////////////////////////////////////////////////////////////
GetPropertyValue(PROPERTYID propertyId,VARIANT * pRetVal)99 IFACEMETHODIMP resource_item_provider::GetPropertyValue(PROPERTYID propertyId, VARIANT* pRetVal)
100 {
101 switch (propertyId)
102 {
103 case UIA_SizeOfSetPropertyId:
104 pRetVal->vt = VT_I4;
105 pRetVal->lVal = GetCurrentSizeOfSet();
106 break;
107
108 case UIA_PositionInSetPropertyId:
109 pRetVal->vt = VT_I4;
110 pRetVal->lVal = GetCurrentPositionInSet();;
111 break;
112
113 case UIA_LevelPropertyId:
114 pRetVal->vt = VT_I4;
115 pRetVal->lVal = GetCurrentLevel();
116 break;
117
118 case UIA_AutomationIdPropertyId:
119 {
120 pRetVal->vt = VT_BSTR;
121
122 // Convert integer to string.
123 CString str;
124 str.Format(L"%d", m_pResItemControl->GetId());
125 pRetVal->bstrVal = SysAllocString(str);
126 break;
127 }
128
129 case UIA_NamePropertyId:
130 pRetVal->vt = VT_BSTR;
131 pRetVal->bstrVal = SysAllocString(m_pResItemControl->GetName());
132 break;
133
134 case UIA_ControlTypePropertyId:
135 pRetVal->vt = VT_I4;
136 pRetVal->lVal = UIA_TreeItemControlTypeId;
137 break;
138
139 case UIA_HasKeyboardFocusPropertyId:
140 {
141 // HasKeyboardFocus is true if the list has focus, and this item is selected.
142 resource_item* selected = m_pResViewControl->GetCurrentItem();
143 BOOL hasFocus = (selected == m_pResItemControl);
144 pRetVal->vt = VT_BOOL;
145 pRetVal->boolVal = hasFocus ? VARIANT_TRUE : VARIANT_FALSE;
146 }
147 break;
148
149 case UIA_IsExpandCollapsePatternAvailablePropertyId:
150 case UIA_IsControlElementPropertyId:
151 case UIA_IsContentElementPropertyId:
152 case UIA_IsKeyboardFocusablePropertyId:
153 pRetVal->vt = VT_BOOL;
154 pRetVal->boolVal = VARIANT_TRUE;
155 break;
156
157 case UIA_ExpandCollapseExpandCollapseStatePropertyId:
158 {
159 ExpandCollapseState state;
160 get_ExpandCollapseState(&state);
161 pRetVal->vt = VT_I4;
162 pRetVal->lVal = state;
163 }
164 break;
165
166 case UIA_IsOffscreenPropertyId:
167 pRetVal->vt = VT_BOOL;
168
169 if (m_pResItemControl->IsVisible())
170 {
171 pRetVal->boolVal = VARIANT_FALSE;
172 }
173 else
174 {
175 pRetVal->boolVal = VARIANT_TRUE;
176 }
177
178 if (m_pResItemControl->mpRes)
179 {
180 if (m_pResItemControl->mpRes->type == RES_TYPE_FOLDER)
181 {
182 switch (m_pResItemControl->mpRes->folder_id)
183 {
184 case DEFAULT_COLOR_FOLDER:
185 case CUSTOM_COLOR_FOLDER:
186 case DEFAULT_FONT_FOLDER:
187 case CUSTOM_FONT_FOLDER:
188 pRetVal->boolVal = VARIANT_TRUE;
189 break;
190 }
191 }
192 else if (!m_pResItemControl->Parent())
193 {
194 pRetVal->boolVal = VARIANT_TRUE;
195 }
196 }
197 break;
198
199 case UIA_FullDescriptionPropertyId:
200 case UIA_ProviderDescriptionPropertyId:
201 pRetVal->vt = VT_BSTR;
202 pRetVal->bstrVal = SysAllocString(m_pResItemControl->GetDescription());
203 break;
204
205 default:
206 pRetVal->vt = VT_EMPTY;
207 break;
208 }
209
210 return S_OK;
211 }
212
213 ///////////////////////////////////////////////////////////////////////////////
214 // Implementation of IRawElementProviderSimple::get_HostRawElementProvider.
215 // Gets the UI Automation provider for the host window.
216 // Return NULL. because the tree view items are not directly hosted in a window.
217 //
218 ///////////////////////////////////////////////////////////////////////////////
get_HostRawElementProvider(IRawElementProviderSimple ** pRetVal)219 IFACEMETHODIMP resource_item_provider::get_HostRawElementProvider(IRawElementProviderSimple** pRetVal)
220 {
221 *pRetVal = NULL;
222 return S_OK;
223 }
224
225 ///////////////////////////////////////////////////////////////////////////////
226 // IRawElementProviderFragment implementation.
227 //
228 // Implementation of IRawElementProviderFragment::Navigate.
229 // Enables UI Automation to locate the element in the tree.
230 //
231 ///////////////////////////////////////////////////////////////////////////////
Navigate(NavigateDirection direction,IRawElementProviderFragment ** pRetVal)232 IFACEMETHODIMP resource_item_provider::Navigate(NavigateDirection direction, IRawElementProviderFragment** pRetVal)
233 {
234 IRawElementProviderFragment* pFrag = NULL;
235 resource_item* pItem = NULL;
236
237 switch (direction)
238 {
239 case NavigateDirection_Parent:
240 pItem = m_pResItemControl->NavigateParent();
241
242 if (pItem)
243 {
244 pFrag = pItem->GetResItemProvider();
245 }
246 else
247 {
248 pFrag = m_pResViewControl->GetResViewProvider();
249 }
250 break;
251
252 case NavigateDirection_NextSibling:
253 pItem = m_pResItemControl->NavigateNext();
254
255 if (pItem)
256 {
257 pFrag = pItem->GetResItemProvider();
258 }
259 break;
260
261 case NavigateDirection_FirstChild:
262 pItem = m_pResItemControl->NavigateFirst();
263
264 if (pItem)
265 {
266 pFrag = pItem->GetResItemProvider();
267 }
268 break;
269
270 case NavigateDirection_LastChild:
271 pItem = m_pResItemControl->NavigateLast();
272
273 if (pItem)
274 {
275 pFrag = pItem->GetResItemProvider();
276 }
277 break;
278 }
279 *pRetVal = pFrag;
280 if (pFrag != NULL)
281 {
282 pFrag->AddRef();
283 }
284 return S_OK;
285 }
286
287 ///////////////////////////////////////////////////////////////////////////////
288 // Implementation of IRawElementProviderFragment::GetRuntimeId.
289 // Gets the runtime identifier. This is an array consisting of UiaAppendRuntimeId,
290 // which makes the ID unique among instances of the control, and the Automation Id.
291 //
292 ///////////////////////////////////////////////////////////////////////////////
GetRuntimeId(SAFEARRAY ** pRetVal)293 IFACEMETHODIMP resource_item_provider::GetRuntimeId(SAFEARRAY** pRetVal)
294 {
295 int id = m_pResItemControl->GetId();
296 int rId[] = { UiaAppendRuntimeId, id };
297
298 SAFEARRAY* psa = SafeArrayCreateVector(VT_I4, 0, 2);
299 for (LONG i = 0; i < 2; i++)
300 {
301 SafeArrayPutElement(psa, &i, &(rId[i]));
302 }
303 *pRetVal = psa;
304
305 return S_OK;
306 }
307
308 ///////////////////////////////////////////////////////////////////////////////
309 // Implementation of IRawElementProviderFragment::get_BoundingRectangle.
310 // Gets the bounding rectangle of the item, in screen coordinates.
311 //
312 ///////////////////////////////////////////////////////////////////////////////
get_BoundingRectangle(UiaRect * pRetVal)313 IFACEMETHODIMP resource_item_provider::get_BoundingRectangle(UiaRect* pRetVal)
314 {
315 CRect rect = m_pResItemControl->GetPos();
316
317 m_pResViewControl->ClientToScreen(&rect);
318 SCROLLINFO si;
319 si.cbSize = sizeof(SCROLLINFO);
320 si.fMask = SIF_POS;
321 SendMessage(m_pResViewControl->GetSafeHwnd(), SBM_GETSCROLLINFO, 0, (LPARAM)&si);
322
323 int height = rect.Height();
324 if ((m_pResItemControl->GetResType() == RES_TYPE_GROUP) && m_pResItemControl->IsOpen())
325 {
326 height -= m_pResItemControl->GetItemHeight();
327 }
328
329 pRetVal->left = rect.left;
330 pRetVal->top = rect.top - si.nPos;
331 pRetVal->width = rect.Width();
332 pRetVal->height = height;
333 return S_OK;
334 }
335
336 ///////////////////////////////////////////////////////////////////////////////
337 // Implementation of IRawElementProviderFragment::GetEmbeddedFragmentRoots.
338 // Retrieves any fragment roots that may be hosted in this element.
339 //
340 ///////////////////////////////////////////////////////////////////////////////
GetEmbeddedFragmentRoots(SAFEARRAY ** pRetVal)341 IFACEMETHODIMP resource_item_provider::GetEmbeddedFragmentRoots(SAFEARRAY** pRetVal)
342 {
343 *pRetVal = NULL;
344 return S_OK;
345 }
346
347 ///////////////////////////////////////////////////////////////////////////////
348 // Implementation of IRawElementProviderFragment::SetFocus.
349 // Responds to the control receiving focus through a UI Automation request.
350 //
351 ///////////////////////////////////////////////////////////////////////////////
SetFocus()352 IFACEMETHODIMP resource_item_provider::SetFocus()
353 {
354 Select();
355 return S_OK;
356 }
357
358 ///////////////////////////////////////////////////////////////////////////////
359 // Implementation of IRawElementProviderFragment::get_FragmentRoot.
360 // Retrieves the root element of this fragment.
361 //
362 ///////////////////////////////////////////////////////////////////////////////
get_FragmentRoot(IRawElementProviderFragmentRoot ** pRetVal)363 IFACEMETHODIMP resource_item_provider::get_FragmentRoot(IRawElementProviderFragmentRoot** pRetVal)
364 {
365 IRawElementProviderFragmentRoot* pRoot = this->m_pResViewControl->GetResViewProvider();
366 if (pRoot == NULL)
367 {
368 return E_FAIL;
369 }
370 pRoot->AddRef();
371 *pRetVal = pRoot;
372 return S_OK;
373 }
374
375
376 ///////////////////////////////////////////////////////////////////////////////
377 // ISelectionItemProvider implementation.
378 //
379 // Implementation of ISelectionItemProvider::Select.
380 // Responds to a request by UI Automation to select the item.
381 //
382 ///////////////////////////////////////////////////////////////////////////////
Select()383 IFACEMETHODIMP resource_item_provider::Select()
384 {
385 m_pResViewControl->SetCurrentItem(m_pResItemControl);
386
387 // Force refresh even when app doesn't have focus.
388 InvalidateRect(m_pResViewControl->GetSafeHwnd(), NULL, false);
389 return S_OK;
390 }
391
392 ///////////////////////////////////////////////////////////////////////////////
393 // Implementation of ISelectionItemProvider::AddToSelection.
394 // Responds to a request by UI Automation to add the item to the selection.
395 // Because this is a single-selection list box, the call is equivalent to Select().
396 //
397 ///////////////////////////////////////////////////////////////////////////////
AddToSelection()398 IFACEMETHODIMP resource_item_provider::AddToSelection()
399 {
400 Select();
401 return S_OK;
402 }
403
404 ///////////////////////////////////////////////////////////////////////////////
405 // Implementation of ISelectionItemProvider::RemoveFromSelection.
406 // Responds to a request by UI Automation to remove the item from the selection.
407 // One and only one item must always be selected, so this is not implemented.
408 //
409 ///////////////////////////////////////////////////////////////////////////////
RemoveFromSelection()410 IFACEMETHODIMP resource_item_provider::RemoveFromSelection()
411 {
412 return UIA_E_INVALIDOPERATION;
413 }
414
415 ///////////////////////////////////////////////////////////////////////////////
416 // Implementation of ISelectionItemProvider::get_IsSelected.
417 // Advises whether the item is selected.
418 //
419 ///////////////////////////////////////////////////////////////////////////////
get_IsSelected(BOOL * pRetVal)420 IFACEMETHODIMP resource_item_provider::get_IsSelected(BOOL* pRetVal)
421 {
422 *pRetVal = (m_pResItemControl == m_pResViewControl->GetCurrentItem());
423 return S_OK;
424 }
425
426 ///////////////////////////////////////////////////////////////////////////////
427 // Implementation of ISelectionItemProvider::get_SelectionContainer.
428 // Returns the UI Automation provider for the tree view control.
429 //
430 ///////////////////////////////////////////////////////////////////////////////
get_SelectionContainer(IRawElementProviderSimple ** pRetVal)431 IFACEMETHODIMP resource_item_provider::get_SelectionContainer(
432 IRawElementProviderSimple** pRetVal)
433 {
434 IRawElementProviderSimple* pParent =
435 static_cast<IRawElementProviderSimple*>(m_pResViewControl->GetResViewProvider());
436 pParent->AddRef();
437 *pRetVal = pParent;
438 return S_OK;
439 }
440
441 ///////////////////////////////////////////////////////////////////////////////
442 // Implementation of IExpandCollapseProvider::Expand.
443 // Hides all nodes, controls, or content that are descendants of the control.
444 //
445 ///////////////////////////////////////////////////////////////////////////////
Expand()446 IFACEMETHODIMP resource_item_provider::Expand()
447 {
448 switch (m_pResItemControl->GetResType())
449 {
450 case RES_TYPE_GROUP:
451 case RES_TYPE_FOLDER:
452 m_pResItemControl->Open();
453 break;
454 }
455
456 return S_OK;
457 }
458
459 ///////////////////////////////////////////////////////////////////////////////
460 // Implementation of IExpandCollapseProvider::Collapse.
461 // Displays all child nodes, controls, or content of the control.
462 //
463 ///////////////////////////////////////////////////////////////////////////////
Collapse()464 IFACEMETHODIMP resource_item_provider::Collapse()
465 {
466 switch (m_pResItemControl->GetResType())
467 {
468 case RES_TYPE_GROUP:
469 case RES_TYPE_FOLDER:
470 m_pResItemControl->Close();
471 break;
472 }
473
474 return S_OK;
475 }
476
477 ///////////////////////////////////////////////////////////////////////////////
478 // Implementation of IExpandCollapseProvider::get_ExpandCollapseState.
479 // Gets the state, expanded or collapsed, of the control.
480 //
481 ///////////////////////////////////////////////////////////////////////////////
get_ExpandCollapseState(ExpandCollapseState * pRetVal)482 IFACEMETHODIMP resource_item_provider::get_ExpandCollapseState(ExpandCollapseState* pRetVal)
483 {
484 switch (m_pResItemControl->GetResType())
485 {
486 case RES_TYPE_GROUP:
487 case RES_TYPE_FOLDER:
488 if (m_pResItemControl->IsOpen())
489 {
490 *pRetVal = ExpandCollapseState_Expanded;
491 }
492 else
493 {
494 *pRetVal = ExpandCollapseState_Collapsed;
495 }
496 break;
497
498 default:
499 *pRetVal = ExpandCollapseState_LeafNode;
500 break;
501 }
502
503 return S_OK;
504 }
505
506 ///////////////////////////////////////////////////////////////////////////////
507 // Implementation of IScrollItemProvider::ScrollIntoView.
508 // Scrolls the content area of a container object in order to display the
509 // control within the visible region of the container.
510 //
511 ///////////////////////////////////////////////////////////////////////////////
ScrollIntoView()512 IFACEMETHODIMP resource_item_provider::ScrollIntoView()
513 {
514 m_pResViewControl->ScrollIntoView(m_pResItemControl);
515
516 return S_OK;
517 }
518
519 ///////////////////////////////////////////////////////////////////////////////
520 // Raises an event when an element is selected.
521 //
522 ///////////////////////////////////////////////////////////////////////////////
RaiseSelectElementEvent()523 void resource_item_provider::RaiseSelectElementEvent()
524 {
525 if (UiaClientsAreListening())
526 {
527 UiaRaiseAutomationEvent(this, UIA_SelectionItem_ElementSelectedEventId);
528 }
529 }
530
531 ///////////////////////////////////////////////////////////////////////////////
532 // Raises an event when the focus has changed from one element to another.
533 //
534 ///////////////////////////////////////////////////////////////////////////////
RaiseChangeFocusEvent()535 void resource_item_provider::RaiseChangeFocusEvent()
536 {
537 if (UiaClientsAreListening())
538 {
539 UiaRaiseAutomationEvent(this, UIA_AutomationFocusChangedEventId);
540 }
541 }
542
543 ///////////////////////////////////////////////////////////////////////////////
544 // Raises an event when a property is changed.
545 //
546 ///////////////////////////////////////////////////////////////////////////////
RaiseExpandCollapseAutomationEvent(BOOL oldValue,BOOL newValue)547 void resource_item_provider::RaiseExpandCollapseAutomationEvent(BOOL oldValue, BOOL newValue)
548 {
549 if (UiaClientsAreListening())
550 {
551 VARIANT oldVar;
552 VARIANT newVar;
553 oldVar.vt = VT_I4;
554 oldVar.lVal = oldValue ? ExpandCollapseState_Expanded : ExpandCollapseState_Collapsed;
555
556 newVar.vt = VT_I4;
557 newVar.lVal = newValue ? ExpandCollapseState_Expanded : ExpandCollapseState_Collapsed;
558
559 UiaRaiseAutomationPropertyChangedEvent(this, UIA_ExpandCollapseExpandCollapseStatePropertyId, oldVar, newVar);
560 }
561 }
562
563 ///////////////////////////////////////////////////////////////////////////////
564 // Calcualte the position in the set for the element.
565 //
566 ///////////////////////////////////////////////////////////////////////////////
GetCurrentPositionInSet()567 int resource_item_provider::GetCurrentPositionInSet()
568 {
569 int pos = 1;
570 resource_item* parent;
571
572 parent = m_pResItemControl->NavigateParent();
573
574 if (parent)
575 {
576 resource_item* child;
577 child = parent->NavigateFirst();
578
579 while (child)
580 {
581 if (child == m_pResItemControl)
582 {
583 break;
584 }
585 child = child->NavigateNext();
586 pos++;
587 }
588 }
589
590 return pos;
591 }
592
593 ///////////////////////////////////////////////////////////////////////////////
594 // Calculate the size of the set where the element is located.
595 //
596 ///////////////////////////////////////////////////////////////////////////////
GetCurrentSizeOfSet()597 int resource_item_provider::GetCurrentSizeOfSet()
598 {
599 int size = 0;
600 resource_item* parent;
601
602 parent = m_pResItemControl->NavigateParent();
603
604 if (parent)
605 {
606 resource_item* child = parent->NavigateFirst();
607 while (child)
608 {
609 child = child->NavigateNext();
610 size++;
611 }
612 }
613
614 return size;
615 }
616
617 ///////////////////////////////////////////////////////////////////////////////
618 // Calculate current level for the element.
619 //
620 ///////////////////////////////////////////////////////////////////////////////
GetCurrentLevel()621 int resource_item_provider::GetCurrentLevel()
622 {
623 int level = 1;
624 resource_item* parent = m_pResItemControl->NavigateParent();
625
626 while (parent)
627 {
628 parent = parent->NavigateParent();
629 level++;
630 }
631
632 return level;
633 }
634
635