1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26
27 #include "ChildrenManagerImpl.hxx"
28 #include <svx/ShapeTypeHandler.hxx>
29 #include <svx/AccessibleShapeInfo.hxx>
30 #ifndef _COM_SUN_STAR_ACCESSIBLE_ACCESSIBLESTATETYPE_HPP_
31 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
32 #endif
33 #include <com/sun/star/view/XSelectionSupplier.hpp>
34 #include <com/sun/star/container/XChild.hpp>
35 #include <comphelper/uno3.hxx>
36 #include <com/sun/star/container/XChild.hpp>
37
38 #include <rtl/ustring.hxx>
39 #include <tools/debug.hxx>
40 #ifndef _SVX_ACCESSIBILITY_SVX_SHAPE_TYPES_HXX
41 #include <svx/SvxShapeTypes.hxx>
42 #endif
43 #include <toolkit/helper/vclunohelper.hxx>
44
45 #ifndef _SV_WINDOW_HXX
46 #include <vcl/window.hxx>
47 #endif
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::accessibility;
50 using ::com::sun::star::uno::Reference;
51
52
53 namespace accessibility {
54
55 namespace
56 {
adjustIndexInParentOfShapes(ChildDescriptorListType & _rList)57 void adjustIndexInParentOfShapes(ChildDescriptorListType& _rList)
58 {
59 ChildDescriptorListType::iterator aEnd = _rList.end();
60 sal_Int32 i=0;
61 for ( ChildDescriptorListType::iterator aIter = _rList.begin(); aIter != aEnd; ++aIter,++i)
62 aIter->setIndexAtAccessibleShape(i);
63 }
64 }
65
66 //===== AccessibleChildrenManager ===========================================
67
ChildrenManagerImpl(const uno::Reference<XAccessible> & rxParent,const uno::Reference<drawing::XShapes> & rxShapeList,const AccessibleShapeTreeInfo & rShapeTreeInfo,AccessibleContextBase & rContext)68 ChildrenManagerImpl::ChildrenManagerImpl (
69 const uno::Reference<XAccessible>& rxParent,
70 const uno::Reference<drawing::XShapes>& rxShapeList,
71 const AccessibleShapeTreeInfo& rShapeTreeInfo,
72 AccessibleContextBase& rContext)
73 : ::cppu::WeakComponentImplHelper2<
74 ::com::sun::star::document::XEventListener,
75 ::com::sun::star::view::XSelectionChangeListener>(maMutex),
76 mxShapeList (rxShapeList),
77 mxParent (rxParent),
78 maShapeTreeInfo (rShapeTreeInfo),
79 mrContext (rContext),
80 mnNewNameIndex(1),
81 mpFocusedShape(NULL)
82 {
83 }
84
85
86
87
~ChildrenManagerImpl(void)88 ChildrenManagerImpl::~ChildrenManagerImpl (void)
89 {
90 DBG_ASSERT (rBHelper.bDisposed || rBHelper.bInDispose,
91 "~AccessibleDrawDocumentView: object has not been disposed");
92 }
93
94
95
96
Init(void)97 void ChildrenManagerImpl::Init (void)
98 {
99 // Register as view::XSelectionChangeListener.
100 Reference<frame::XController> xController(maShapeTreeInfo.GetController());
101 Reference<view::XSelectionSupplier> xSelectionSupplier (
102 xController, uno::UNO_QUERY);
103 if (xSelectionSupplier.is())
104 {
105 xController->addEventListener(
106 static_cast<document::XEventListener*>(this));
107
108 xSelectionSupplier->addSelectionChangeListener (
109 static_cast<view::XSelectionChangeListener*>(this));
110 }
111
112 // Register at model as document::XEventListener.
113 if (maShapeTreeInfo.GetModelBroadcaster().is())
114 maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
115 static_cast<document::XEventListener*>(this));
116 }
117
118
119
120
GetChildCount(void) const121 long ChildrenManagerImpl::GetChildCount (void) const throw ()
122 {
123 return maVisibleChildren.size();
124 }
125
126
127 ::com::sun::star::uno::Reference<
GetChildShape(long nIndex)128 ::com::sun::star::drawing::XShape> ChildrenManagerImpl::GetChildShape(long nIndex)
129 {
130 uno::Reference<XAccessible> xAcc = GetChild(nIndex);
131 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
132 for (I = maVisibleChildren.begin(); I != aEnd; ++I)
133 {
134 if (I->mxAccessibleShape == xAcc)
135 return I->mxShape;
136 }
137 return uno::Reference< drawing::XShape > ();
138 }
139
140 /** Return the requested accessible child object. Create it if it is not
141 yet in the cache.
142 */
143 uno::Reference<XAccessible>
GetChild(long nIndex)144 ChildrenManagerImpl::GetChild (long nIndex)
145 {
146 // Check whether the given index is valid.
147 if (nIndex < 0 || (unsigned long)nIndex >= maVisibleChildren.size())
148 throw lang::IndexOutOfBoundsException (
149 ::rtl::OUString::createFromAscii( "no accessible child with index ")
150 + ::rtl::OUString::valueOf( nIndex, 10),
151 mxParent);
152
153 return GetChild (maVisibleChildren[nIndex],nIndex);
154 }
155
156
157
158
159 /** Return the requested accessible child object. Create it if it is not
160 yet in the cache.
161 */
162 uno::Reference<XAccessible>
GetChild(ChildDescriptor & rChildDescriptor,sal_Int32 _nIndex)163 ChildrenManagerImpl::GetChild (ChildDescriptor& rChildDescriptor,sal_Int32 _nIndex)
164 {
165 if ( ! rChildDescriptor.mxAccessibleShape.is())
166 {
167 ::osl::MutexGuard aGuard (maMutex);
168 // Make sure that the requested accessible object has not been
169 // created while locking the global mutex.
170 if ( ! rChildDescriptor.mxAccessibleShape.is())
171 {
172 AccessibleShapeInfo aShapeInfo(
173 rChildDescriptor.mxShape,
174 mxParent,
175 this,
176 mnNewNameIndex++);
177 // Create accessible object that corresponds to the descriptor's
178 // shape.
179 AccessibleShape* pShape =
180 ShapeTypeHandler::Instance().CreateAccessibleObject (
181 aShapeInfo,
182 maShapeTreeInfo);
183 rChildDescriptor.mxAccessibleShape = uno::Reference<XAccessible> (
184 static_cast<uno::XWeak*>(pShape),
185 uno::UNO_QUERY);
186 // Now that there is a reference to the new accessible shape we
187 // can safely call its Init() method.
188 if ( pShape != NULL )
189 {
190 pShape->Init();
191 pShape->setIndexInParent(_nIndex);
192 }
193 }
194 }
195
196 return rChildDescriptor.mxAccessibleShape;
197 }
198
199
200
201
202 uno::Reference<XAccessible>
GetChild(const uno::Reference<drawing::XShape> & xShape)203 ChildrenManagerImpl::GetChild (const uno::Reference<drawing::XShape>& xShape)
204 {
205 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
206 for (I = maVisibleChildren.begin(); I != aEnd; ++I)
207 {
208 if ( I->mxShape.get() == xShape.get() )
209 return I->mxAccessibleShape;
210 }
211 return uno::Reference<XAccessible> ();
212 }
213
214
215
216
217 /** Find all shapes among the specified shapes that lie fully or partially
218 inside the visible area. Put those shapes into the cleared cache. The
219 corresponding accessible objects will be created on demand.
220
221 At the moment, first all accessible objects are removed from the cache
222 and the appropriate listeners are informed of this. Next, the list is
223 created again. This should be optimized in the future to not remove and
224 create objects that will be in the list before and after the update
225 method.
226 */
Update(bool bCreateNewObjectsOnDemand)227 void ChildrenManagerImpl::Update (bool bCreateNewObjectsOnDemand)
228 {
229 if (maShapeTreeInfo.GetViewForwarder() == NULL)
230 return;
231 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
232
233 // 1. Create a local list of visible shapes.
234 ChildDescriptorListType aChildList;
235 CreateListOfVisibleShapes (aChildList);
236
237 // 2. Merge the information that is already known about the visible
238 // shapes from the current list into the new list.
239 MergeAccessibilityInformation (aChildList);
240
241 // 3. Replace the current list of visible shapes with the new one. Do
242 // the same with the visible area.
243 {
244 ::osl::MutexGuard aGuard (maMutex);
245 adjustIndexInParentOfShapes(aChildList);
246
247 // Use swap to copy the contents of the new list in constant time.
248 maVisibleChildren.swap (aChildList);
249
250 // aChildList now contains all the old children, while maVisibleChildren
251 // contains all the current children
252
253 // 4. Find all shapes in the old list that are not in the current list,
254 // send appropriate events and remove the accessible shape.
255 //
256 // Do this *after* we have set our new list of children, because
257 // removing a child may cause
258 //
259 // ChildDescriptor::disposeAccessibleObject -->
260 // AccessibleContextBase::CommitChange -->
261 // AtkListener::notifyEvent ->
262 // AtkListener::handleChildRemoved ->
263 // AtkListener::updateChildList
264 // AccessibleDrawDocumentView::getAccessibleChildCount ->
265 // ChildrenManagerImpl::GetChildCount ->
266 // maVisibleChildren.size()
267 //
268 // to be fired, and so the operations will take place on
269 // the list we are trying to replace
270 //
271 RemoveNonVisibleChildren (maVisibleChildren, aChildList);
272
273 aChildList.clear();
274
275 maVisibleArea = aVisibleArea;
276 }
277
278 // 5. If the visible area has changed then send events that signal a
279 // change of their bounding boxes for all shapes that are members of
280 // both the current and the new list of visible shapes.
281 if (maVisibleArea != aVisibleArea)
282 SendVisibleAreaEvents (maVisibleChildren);
283
284 // 6. If children have to be created immediately and not on demand then
285 // create the missing accessible objects now.
286 if ( ! bCreateNewObjectsOnDemand)
287 CreateAccessibilityObjects (maVisibleChildren);
288 }
289
290
291
292
CreateListOfVisibleShapes(ChildDescriptorListType & raDescriptorList)293 void ChildrenManagerImpl::CreateListOfVisibleShapes (
294 ChildDescriptorListType& raDescriptorList)
295 {
296 ::osl::MutexGuard aGuard (maMutex);
297
298 OSL_ASSERT (maShapeTreeInfo.GetViewForwarder() != NULL);
299
300 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
301
302 // Add the visible shapes for which the accessible objects already exist.
303 AccessibleShapeList::iterator I,aEnd = maAccessibleShapes.end();
304 for (I=maAccessibleShapes.begin(); I != aEnd; ++I)
305 {
306 if (I->is())
307 {
308 uno::Reference<XAccessibleComponent> xComponent (
309 (*I)->getAccessibleContext(), uno::UNO_QUERY);
310 if (xComponent.is())
311 {
312 // The bounding box of the object already is clipped to the
313 // visible area. The object is therefore visible if the
314 // bounding box has non-zero extensions.
315 awt::Rectangle aPixelBBox (xComponent->getBounds());
316 if ((aPixelBBox.Width > 0) && (aPixelBBox.Height > 0))
317 raDescriptorList.push_back (ChildDescriptor (*I));
318 }
319 }
320 }
321
322 // Add the visible shapes for which only the XShapes exist.
323 uno::Reference<container::XIndexAccess> xShapeAccess (mxShapeList, uno::UNO_QUERY);
324 if (xShapeAccess.is())
325 {
326 sal_Int32 nShapeCount = xShapeAccess->getCount();
327 raDescriptorList.reserve( nShapeCount );
328 awt::Point aPos;
329 awt::Size aSize;
330 Rectangle aBoundingBox;
331 uno::Reference<drawing::XShape> xShape;
332 for (sal_Int32 i=0; i<nShapeCount; ++i)
333 {
334 xShapeAccess->getByIndex(i) >>= xShape;
335 aPos = xShape->getPosition();
336 aSize = xShape->getSize();
337
338 aBoundingBox.nLeft = aPos.X;
339 aBoundingBox.nTop = aPos.Y;
340 aBoundingBox.nRight = aPos.X + aSize.Width;
341 aBoundingBox.nBottom = aPos.Y + aSize.Height;
342
343 // Insert shape if it is visible, i.e. its bounding box overlaps
344 // the visible area.
345 if ( aBoundingBox.IsOver (aVisibleArea) )
346 raDescriptorList.push_back (ChildDescriptor (xShape));
347 }
348 }
349 }
350
351
352
353
RemoveNonVisibleChildren(const ChildDescriptorListType & rNewChildList,ChildDescriptorListType & rOldChildList)354 void ChildrenManagerImpl::RemoveNonVisibleChildren (
355 const ChildDescriptorListType& rNewChildList,
356 ChildDescriptorListType& rOldChildList)
357 {
358 // Iterate over list of formerly visible children and remove those that
359 // are not visible anymore, i.e. member of the new list of visible
360 // children.
361 ChildDescriptorListType::iterator I, aEnd = rOldChildList.end();
362 for (I=rOldChildList.begin(); I != aEnd; ++I)
363 {
364 if (::std::find(rNewChildList.begin(), rNewChildList.end(), *I) == rNewChildList.end())
365 {
366 // The child is disposed when there is a UNO shape from which
367 // the accessible shape can be created when the shape becomes
368 // visible again. When there is no such UNO shape then simply
369 // reset the descriptor but keep the accessibility object.
370 if (I->mxShape.is())
371 {
372 UnregisterAsDisposeListener (I->mxShape);
373 I->disposeAccessibleObject (mrContext);
374 }
375 else
376 {
377 AccessibleShape* pAccessibleShape = I->GetAccessibleShape();
378 pAccessibleShape->ResetState (AccessibleStateType::VISIBLE);
379 I->mxAccessibleShape = NULL;
380 }
381 }
382 }
383 }
384
385
386
387
MergeAccessibilityInformation(ChildDescriptorListType & raNewChildList)388 void ChildrenManagerImpl::MergeAccessibilityInformation (
389 ChildDescriptorListType& raNewChildList)
390 {
391 ChildDescriptorListType::iterator aOldChildDescriptor;
392 ChildDescriptorListType::iterator I, aEnd = raNewChildList.end();
393 for (I=raNewChildList.begin(); I != aEnd; ++I)
394 {
395 aOldChildDescriptor = ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(), *I);
396
397 // Copy accessible shape if that exists in the old descriptor.
398 bool bRegistrationIsNecessary = true;
399 if (aOldChildDescriptor != maVisibleChildren.end())
400 if (aOldChildDescriptor->mxAccessibleShape.is())
401 {
402 I->mxAccessibleShape = aOldChildDescriptor->mxAccessibleShape;
403 I->mbCreateEventPending = false;
404 bRegistrationIsNecessary = false;
405 }
406 if (bRegistrationIsNecessary)
407 RegisterAsDisposeListener (I->mxShape);
408 }
409 }
410
411
412
413
SendVisibleAreaEvents(ChildDescriptorListType & raNewChildList)414 void ChildrenManagerImpl::SendVisibleAreaEvents (
415 ChildDescriptorListType& raNewChildList)
416 {
417 ChildDescriptorListType::iterator I,aEnd = raNewChildList.end();
418 for (I=raNewChildList.begin(); I != aEnd; ++I)
419 {
420 // Tell shape of changed visible area. To do this, fake a
421 // change of the view forwarder. (Actually we usually get here
422 // as a result of a change of the view forwarder).
423 AccessibleShape* pShape = I->GetAccessibleShape ();
424 if (pShape != NULL)
425 pShape->ViewForwarderChanged (
426 IAccessibleViewForwarderListener::VISIBLE_AREA,
427 maShapeTreeInfo.GetViewForwarder());
428 }
429 }
430
431
432
433
CreateAccessibilityObjects(ChildDescriptorListType & raNewChildList)434 void ChildrenManagerImpl::CreateAccessibilityObjects (
435 ChildDescriptorListType& raNewChildList)
436 {
437 ChildDescriptorListType::iterator I, aEnd = raNewChildList.end();
438 sal_Int32 nPos = 0;
439 for ( I = raNewChildList.begin(); I != aEnd; ++I,++nPos)
440 {
441 // Create the associated accessible object when the flag says so and
442 // it does not yet exist.
443 if ( ! I->mxAccessibleShape.is() )
444 GetChild (*I,nPos);
445 if (I->mxAccessibleShape.is() && I->mbCreateEventPending)
446 {
447 I->mbCreateEventPending = false;
448 mrContext.CommitChange (
449 AccessibleEventId::CHILD,
450 uno::makeAny(I->mxAccessibleShape),
451 uno::Any());
452 }
453 }
454 }
455
456
457
458
AddShape(const Reference<drawing::XShape> & rxShape)459 void ChildrenManagerImpl::AddShape (const Reference<drawing::XShape>& rxShape)
460 {
461 if (rxShape.is())
462 {
463 ::osl::ClearableMutexGuard aGuard (maMutex);
464
465 // Test visibility of the shape.
466 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
467 awt::Point aPos = rxShape->getPosition();
468 awt::Size aSize = rxShape->getSize();
469
470 Rectangle aBoundingBox (
471 aPos.X,
472 aPos.Y,
473 aPos.X + aSize.Width,
474 aPos.Y + aSize.Height);
475
476 // Add the shape only when it belongs to the list of shapes stored
477 // in mxShapeList (which is either a page or a group shape).
478 Reference<container::XChild> xChild (rxShape, uno::UNO_QUERY);
479 if (xChild.is())
480 {
481 Reference<drawing::XShapes> xParent (xChild->getParent(), uno::UNO_QUERY);
482 if (xParent == mxShapeList)
483 if (aBoundingBox.IsOver (aVisibleArea))
484 {
485 // Add shape to list of visible shapes.
486 maVisibleChildren.push_back (ChildDescriptor (rxShape));
487
488 // Create accessibility object.
489 ChildDescriptor& rDescriptor = maVisibleChildren.back();
490 GetChild (rDescriptor, maVisibleChildren.size()-1);
491
492 // Inform listeners about new child.
493 uno::Any aNewShape;
494 aNewShape <<= rDescriptor.mxAccessibleShape;
495 aGuard.clear();
496 mrContext.CommitChange (
497 AccessibleEventId::CHILD,
498 aNewShape,
499 uno::Any());
500 RegisterAsDisposeListener (rDescriptor.mxShape);
501 }
502 }
503 }
504 }
505
506
507
508
RemoveShape(const Reference<drawing::XShape> & rxShape)509 void ChildrenManagerImpl::RemoveShape (const Reference<drawing::XShape>& rxShape)
510 {
511 if (rxShape.is())
512 {
513 ::osl::ClearableMutexGuard aGuard (maMutex);
514
515 // Search shape in list of visible children.
516 ChildDescriptorListType::iterator I (
517 ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
518 ChildDescriptor (rxShape)));
519 if (I != maVisibleChildren.end())
520 {
521 // Remove descriptor from that list.
522 Reference<XAccessible> xAccessibleShape (I->mxAccessibleShape);
523
524 UnregisterAsDisposeListener (I->mxShape);
525 // Dispose the accessible object.
526 I->disposeAccessibleObject (mrContext);
527
528 // Now we can safely remove the child descriptor and thus
529 // invalidate the iterator.
530 maVisibleChildren.erase (I);
531
532 adjustIndexInParentOfShapes(maVisibleChildren);
533 }
534 }
535 }
536
537
538
539
SetShapeList(const::com::sun::star::uno::Reference<::com::sun::star::drawing::XShapes> & xShapeList)540 void ChildrenManagerImpl::SetShapeList (const ::com::sun::star::uno::Reference<
541 ::com::sun::star::drawing::XShapes>& xShapeList)
542 {
543 mxShapeList = xShapeList;
544 }
545
546
547
548
AddAccessibleShape(std::auto_ptr<AccessibleShape> pShape)549 void ChildrenManagerImpl::AddAccessibleShape (std::auto_ptr<AccessibleShape> pShape)
550 {
551 if (pShape.get() != NULL)
552 maAccessibleShapes.push_back (pShape.release());
553 }
554
555
556
557
ClearAccessibleShapeList(void)558 void ChildrenManagerImpl::ClearAccessibleShapeList (void)
559 {
560 // Copy the list of (visible) shapes to local lists and clear the
561 // originals.
562 ChildDescriptorListType aLocalVisibleChildren;
563 aLocalVisibleChildren.swap(maVisibleChildren);
564 AccessibleShapeList aLocalAccessibleShapes;
565 aLocalAccessibleShapes.swap(maAccessibleShapes);
566
567 // Tell the listeners that all children are gone.
568 mrContext.CommitChange (
569 AccessibleEventId::INVALIDATE_ALL_CHILDREN,
570 uno::Any(),
571 uno::Any());
572
573 // There are no accessible shapes left so the index assigned to new
574 // accessible shapes can be reset.
575 mnNewNameIndex = 1;
576
577 // Now the objects in the local lists can be safely disposed without
578 // having problems with callers that want to update their child lists.
579
580 // Clear the list of visible accessible objects. Objects not created on
581 // demand for XShapes are treated below.
582 ChildDescriptorListType::iterator I,aEnd = aLocalVisibleChildren.end();
583 for (I=aLocalVisibleChildren.begin(); I != aEnd; ++I)
584 if ( I->mxAccessibleShape.is() && I->mxShape.is() )
585 {
586 ::comphelper::disposeComponent(I->mxAccessibleShape);
587 I->mxAccessibleShape = NULL;
588 }
589
590 // Dispose all objects in the accessible shape list.
591 AccessibleShapeList::iterator J,aEnd2 = aLocalAccessibleShapes.end();
592 for (J=aLocalAccessibleShapes.begin(); J != aEnd2; ++J)
593 if (J->is())
594 {
595 // Dispose the object.
596 ::comphelper::disposeComponent(*J);
597 *J = NULL;
598 }
599 }
600
601
602
603
604 /** If the broadcasters change at which this object is registered then
605 unregister at old and register at new broadcasters.
606 */
SetInfo(const AccessibleShapeTreeInfo & rShapeTreeInfo)607 void ChildrenManagerImpl::SetInfo (const AccessibleShapeTreeInfo& rShapeTreeInfo)
608 {
609 // Remember the current broadcasters and exchange the shape tree info.
610 Reference<document::XEventBroadcaster> xCurrentBroadcaster;
611 Reference<frame::XController> xCurrentController;
612 Reference<view::XSelectionSupplier> xCurrentSelectionSupplier;
613 {
614 ::osl::MutexGuard aGuard (maMutex);
615 xCurrentBroadcaster = maShapeTreeInfo.GetModelBroadcaster();
616 xCurrentController = maShapeTreeInfo.GetController();
617 xCurrentSelectionSupplier = Reference<view::XSelectionSupplier> (
618 xCurrentController, uno::UNO_QUERY);
619 maShapeTreeInfo = rShapeTreeInfo;
620 }
621
622 // Move registration to new model.
623 if (maShapeTreeInfo.GetModelBroadcaster() != xCurrentBroadcaster)
624 {
625 // Register at new broadcaster.
626 if (maShapeTreeInfo.GetModelBroadcaster().is())
627 maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
628 static_cast<document::XEventListener*>(this));
629
630 // Unregister at old broadcaster.
631 if (xCurrentBroadcaster.is())
632 xCurrentBroadcaster->removeEventListener (
633 static_cast<document::XEventListener*>(this));
634 }
635
636 // Move registration to new selection supplier.
637 Reference<frame::XController> xNewController(maShapeTreeInfo.GetController());
638 Reference<view::XSelectionSupplier> xNewSelectionSupplier (
639 xNewController, uno::UNO_QUERY);
640 if (xNewSelectionSupplier != xCurrentSelectionSupplier)
641 {
642 // Register at new broadcaster.
643 if (xNewSelectionSupplier.is())
644 {
645 xNewController->addEventListener(
646 static_cast<document::XEventListener*>(this));
647
648 xNewSelectionSupplier->addSelectionChangeListener (
649 static_cast<view::XSelectionChangeListener*>(this));
650 }
651
652 // Unregister at old broadcaster.
653 if (xCurrentSelectionSupplier.is())
654 {
655 xCurrentSelectionSupplier->removeSelectionChangeListener (
656 static_cast<view::XSelectionChangeListener*>(this));
657
658 xCurrentController->removeEventListener(
659 static_cast<document::XEventListener*>(this));
660 }
661 }
662 }
663
664
665
666
667 //===== lang::XEventListener ================================================
668
669 void SAL_CALL
disposing(const lang::EventObject & rEventObject)670 ChildrenManagerImpl::disposing (const lang::EventObject& rEventObject)
671 {
672 if (rEventObject.Source == maShapeTreeInfo.GetModelBroadcaster()
673 || rEventObject.Source == maShapeTreeInfo.GetController())
674 {
675 impl_dispose();
676 }
677
678 // Handle disposing UNO shapes.
679 else
680 {
681 Reference<drawing::XShape> xShape (rEventObject.Source, uno::UNO_QUERY);
682
683 // Find the descriptor for the given shape.
684 ChildDescriptorListType::iterator I (
685 ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
686 ChildDescriptor (xShape)));
687 if (I != maVisibleChildren.end())
688 {
689 // Clear the descriptor.
690 I->disposeAccessibleObject (mrContext);
691 I->mxShape = NULL;
692 }
693 }
694 }
695
696
697
698
699 //===== document::XEventListener ============================================
700
701 /** Listen for new and removed shapes.
702 */
703 void SAL_CALL
notifyEvent(const document::EventObject & rEventObject)704 ChildrenManagerImpl::notifyEvent (
705 const document::EventObject& rEventObject)
706 {
707 static const ::rtl::OUString sShapeInserted (
708 RTL_CONSTASCII_USTRINGPARAM("ShapeInserted"));
709 static const ::rtl::OUString sShapeRemoved (
710 RTL_CONSTASCII_USTRINGPARAM("ShapeRemoved"));
711
712
713 if (rEventObject.EventName.equals (sShapeInserted))
714 AddShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
715 else if (rEventObject.EventName.equals (sShapeRemoved))
716 RemoveShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
717 // else ignore unknown event.
718 }
719
720
721
722
723 //===== view::XSelectionChangeListener ======================================
724
725 void SAL_CALL
selectionChanged(const lang::EventObject &)726 ChildrenManagerImpl::selectionChanged (const lang::EventObject& /*rEvent*/)
727 {
728 UpdateSelection ();
729 }
730
731
732
733
impl_dispose(void)734 void ChildrenManagerImpl::impl_dispose (void)
735 {
736 Reference<frame::XController> xController(maShapeTreeInfo.GetController());
737 // Remove from broadcasters.
738 try
739 {
740 Reference<view::XSelectionSupplier> xSelectionSupplier (
741 xController, uno::UNO_QUERY);
742 if (xSelectionSupplier.is())
743 {
744 xSelectionSupplier->removeSelectionChangeListener (
745 static_cast<view::XSelectionChangeListener*>(this));
746 }
747 }
748 catch( uno::RuntimeException&)
749 {}
750
751 try
752 {
753 if (xController.is())
754 xController->removeEventListener(
755 static_cast<document::XEventListener*>(this));
756 }
757 catch( uno::RuntimeException&)
758 {}
759
760 maShapeTreeInfo.SetController (NULL);
761
762 try
763 {
764 // Remove from broadcaster.
765 if (maShapeTreeInfo.GetModelBroadcaster().is())
766 maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
767 static_cast<document::XEventListener*>(this));
768 maShapeTreeInfo.SetModelBroadcaster (NULL);
769 }
770 catch( uno::RuntimeException& )
771 {}
772
773 ClearAccessibleShapeList ();
774 SetShapeList (NULL);
775 }
776
777
778
disposing(void)779 void SAL_CALL ChildrenManagerImpl::disposing (void)
780 {
781 impl_dispose();
782 }
783
784
785
786
787 // This method is experimental. Use with care.
GetChildIndex(const::com::sun::star::uno::Reference<::com::sun::star::accessibility::XAccessible> & xChild) const788 long int ChildrenManagerImpl::GetChildIndex (const ::com::sun::star::uno::Reference<
789 ::com::sun::star::accessibility::XAccessible>& xChild) const
790 {
791 ::osl::MutexGuard aGuard (maMutex);
792 sal_Int32 nCount = maVisibleChildren.size();
793 for (sal_Int32 i=0; i < nCount; ++i)
794 {
795 // Is this equality comparison valid?
796 if (maVisibleChildren[i].mxAccessibleShape == xChild)
797 return i;
798 }
799
800 return -1;
801 }
802
803
804
805
806 //===== IAccessibleViewForwarderListener ====================================
807
ViewForwarderChanged(ChangeType aChangeType,const IAccessibleViewForwarder * pViewForwarder)808 void ChildrenManagerImpl::ViewForwarderChanged (ChangeType aChangeType,
809 const IAccessibleViewForwarder* pViewForwarder)
810 {
811 if (aChangeType == IAccessibleViewForwarderListener::VISIBLE_AREA)
812 Update (false);
813 else
814 {
815 ::osl::MutexGuard aGuard (maMutex);
816 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
817 for (I=maVisibleChildren.begin(); I != aEnd; ++I)
818 {
819 AccessibleShape* pShape = I->GetAccessibleShape();
820 if (pShape != NULL)
821 pShape->ViewForwarderChanged (aChangeType, pViewForwarder);
822 }
823 }
824 }
825
826
827
828
829 //===== IAccessibleParent ===================================================
830
ReplaceChild(AccessibleShape * pCurrentChild,const::com::sun::star::uno::Reference<::com::sun::star::drawing::XShape> & _rxShape,const long _nIndex,const AccessibleShapeTreeInfo & _rShapeTreeInfo)831 sal_Bool ChildrenManagerImpl::ReplaceChild (
832 AccessibleShape* pCurrentChild,
833 const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& _rxShape,
834 const long _nIndex,
835 const AccessibleShapeTreeInfo& _rShapeTreeInfo)
836 {
837 AccessibleShapeInfo aShapeInfo( _rxShape, pCurrentChild->getAccessibleParent(), this, _nIndex );
838 // create the new child
839 AccessibleShape* pNewChild = ShapeTypeHandler::Instance().CreateAccessibleObject (
840 aShapeInfo,
841 _rShapeTreeInfo
842 );
843 Reference< XAccessible > xNewChild( pNewChild ); // keep this alive (do this before calling Init!)
844 if ( pNewChild )
845 pNewChild->Init();
846
847 sal_Bool bResult = sal_False;
848
849 // Iterate over the visible children. If one of them has an already
850 // created accessible object that matches pCurrentChild then replace
851 // it. Otherwise the child to replace is either not in the list or has
852 // not ye been created (and is therefore not in the list, too) and a
853 // replacement is not necessary.
854 ChildDescriptorListType::iterator I,aEnd = maVisibleChildren.end();
855 for (I=maVisibleChildren.begin(); I != aEnd; ++I)
856 {
857 if (I->GetAccessibleShape() == pCurrentChild)
858 {
859 // Dispose the current child and send an event about its deletion.
860 pCurrentChild->dispose();
861 mrContext.CommitChange (
862 AccessibleEventId::CHILD,
863 uno::Any(),
864 uno::makeAny (I->mxAccessibleShape));
865
866 // Replace with replacement and send an event about existence
867 // of the new child.
868 I->mxAccessibleShape = pNewChild;
869 mrContext.CommitChange (
870 AccessibleEventId::CHILD,
871 uno::makeAny (I->mxAccessibleShape),
872 uno::Any());
873 bResult = sal_True;
874 break;
875 }
876 }
877
878 // When not found among the visible children we have to search the list
879 // of accessible shapes. This is not yet implemented.
880
881 return bResult;
882 }
883 // Add the impl method for IAccessibleParent interface
GetAccControlShapeFromModel(::com::sun::star::beans::XPropertySet * pSet)884 AccessibleControlShape * ChildrenManagerImpl::GetAccControlShapeFromModel(::com::sun::star::beans::XPropertySet* pSet)
885 {
886 sal_Int32 count = GetChildCount();
887 for (sal_Int32 index=0;index<count;index++)
888 {
889 AccessibleShape* pAccShape = maVisibleChildren[index].GetAccessibleShape();
890 if (pAccShape && ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape->GetXShape()) == DRAWING_CONTROL)
891 {
892 ::accessibility::AccessibleControlShape *pCtlAccShape = static_cast < ::accessibility::AccessibleControlShape* >(pAccShape);
893 if (pCtlAccShape && pCtlAccShape->GetControlModel() == pSet)
894 return pCtlAccShape;
895 }
896 }
897 return NULL;
898 }
899 uno::Reference<XAccessible>
GetAccessibleCaption(const uno::Reference<drawing::XShape> & xShape)900 ChildrenManagerImpl::GetAccessibleCaption (const uno::Reference<drawing::XShape>& xShape)
901 {
902 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
903 for (I = maVisibleChildren.begin(); I != aEnd; ++I)
904 {
905 if ( I->mxShape.get() == xShape.get() )
906 return I->mxAccessibleShape;
907 }
908 return uno::Reference<XAccessible> ();
909 }
910
911 /** Update the <const>SELECTED</const> and the <const>FOCUSED</const> state
912 of all visible children. Maybe this should be changed to all children.
913
914 Iterate over all descriptors of visible accessible shapes and look them
915 up in the selection.
916
917 If there is no valid controller then all shapes are deselected and
918 unfocused. If the controller's frame is not active then all shapes are
919 unfocused.
920 */
UpdateSelection(void)921 void ChildrenManagerImpl::UpdateSelection (void)
922 {
923 Reference<frame::XController> xController(maShapeTreeInfo.GetController());
924 Reference<view::XSelectionSupplier> xSelectionSupplier (
925 xController, uno::UNO_QUERY);
926
927 // Try to cast the selection both to a multi selection and to a single
928 // selection.
929 Reference<container::XIndexAccess> xSelectedShapeAccess;
930 Reference<drawing::XShape> xSelectedShape;
931 if (xSelectionSupplier.is())
932 {
933 xSelectedShapeAccess = Reference<container::XIndexAccess> (
934 xSelectionSupplier->getSelection(), uno::UNO_QUERY);
935 xSelectedShape = Reference<drawing::XShape> (
936 xSelectionSupplier->getSelection(), uno::UNO_QUERY);
937 }
938
939 // Remember the current and new focused shape.
940 AccessibleShape* pCurrentlyFocusedShape = NULL;
941 AccessibleShape* pNewFocusedShape = NULL;
942 typedef std::pair< AccessibleShape* , sal_Bool > PAIR_SHAPE;//sal_Bool Selected,UnSelected.
943 typedef std::vector< PAIR_SHAPE > VEC_SHAPE;
944 VEC_SHAPE vecSelect;
945 int nAddSelect=0;
946 int nRemoveSelect=0;
947 sal_Bool bHasSelectedShape=sal_False;
948 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
949 for (I=maVisibleChildren.begin(); I != aEnd; ++I)
950 {
951 AccessibleShape* pAccessibleShape = I->GetAccessibleShape();
952 if (I->mxAccessibleShape.is() && I->mxShape.is() && pAccessibleShape!=NULL)
953 {
954 short nRole = pAccessibleShape->getAccessibleRole();
955 bool bDrawShape = (
956 nRole == AccessibleRole::GRAPHIC ||
957 nRole == AccessibleRole::EMBEDDED_OBJECT ||
958 nRole == AccessibleRole::SHAPE ||
959 nRole == AccessibleRole::IMAGE_MAP ||
960 nRole == AccessibleRole::TABLE_CELL ||
961 nRole == AccessibleRole::TABLE );
962 bool bShapeIsSelected = false;
963
964 // Look up the shape in the (single or multi-) selection.
965 if (xSelectedShape.is())
966 {
967 if (I->mxShape == xSelectedShape)
968 {
969 bShapeIsSelected = true;
970 pNewFocusedShape = pAccessibleShape;
971 }
972 }
973 else if (xSelectedShapeAccess.is())
974 {
975 sal_Int32 nCount=xSelectedShapeAccess->getCount();
976 for (sal_Int32 i=0; i<nCount&&!bShapeIsSelected; i++)
977 if (xSelectedShapeAccess->getByIndex(i) == I->mxShape)
978 {
979 bShapeIsSelected = true;
980 // In a multi-selection no shape has the focus.
981 if (nCount == 1)
982 pNewFocusedShape = pAccessibleShape;
983 }
984 }
985
986 // Set or reset the SELECTED state.
987 if (bShapeIsSelected)
988 {
989 if (pAccessibleShape->SetState (AccessibleStateType::SELECTED))
990 {
991 if (bDrawShape)
992 {
993 vecSelect.push_back(std::make_pair(pAccessibleShape,sal_True));
994 ++nAddSelect;
995 }
996 }
997 else
998 {//Selected not change,has selected shape before
999 bHasSelectedShape=sal_True;
1000 }
1001 }
1002 else
1003 {
1004 if(pAccessibleShape->ResetState (AccessibleStateType::SELECTED))
1005 {
1006 if(bDrawShape)
1007 {
1008 vecSelect.push_back(std::make_pair(pAccessibleShape,sal_False));
1009 ++nRemoveSelect;
1010 }
1011 }
1012 }
1013 // Does the shape have the current selection?
1014 if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
1015 pCurrentlyFocusedShape = pAccessibleShape;
1016 }
1017 }
1018 /*
1019 // Check if the frame we are in is currently active. If not then make
1020 // sure to not send a FOCUSED state change.
1021 if (xController.is())
1022 {
1023 Reference<frame::XFrame> xFrame (xController->getFrame());
1024 if (xFrame.is())
1025 if ( ! xFrame->isActive())
1026 pNewFocusedShape = NULL;
1027 }
1028 */
1029 Window *pParentWidow = maShapeTreeInfo.GetWindow();
1030 bool bShapeActive= false;
1031 // For table cell, the table's parent must be checked to make sure it has focus.
1032 Window *pPWindow = pParentWidow->GetParent();
1033 if (pParentWidow && ( pParentWidow->HasFocus() || (pPWindow && pPWindow->HasFocus())))
1034 {
1035 bShapeActive =true;
1036 }
1037 // Move focus from current to newly focused shape.
1038 if (pCurrentlyFocusedShape != pNewFocusedShape)
1039 {
1040 if (pCurrentlyFocusedShape != NULL)
1041 pCurrentlyFocusedShape->ResetState (AccessibleStateType::FOCUSED);
1042 if (pNewFocusedShape != NULL && bShapeActive)
1043 pNewFocusedShape->SetState (AccessibleStateType::FOCUSED);
1044 }
1045
1046 if (nAddSelect >= 10 )//fire selection within
1047 {
1048 mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN,uno::Any(),uno::Any());
1049 nAddSelect =0 ;//not fire selection event
1050 }
1051 //VEC_SHAPE::iterator vi = vecSelect.begin();
1052 //for (; vi != vecSelect.end() ;++vi)
1053 VEC_SHAPE::reverse_iterator vi = vecSelect.rbegin();
1054 for (; vi != vecSelect.rend() ;++vi)
1055
1056 {
1057 PAIR_SHAPE &pairShape= *vi;
1058 Reference< XAccessible > xShape(pairShape.first);
1059 uno::Any anyShape;
1060 anyShape <<= xShape;
1061
1062 if (pairShape.second)//Selection add
1063 {
1064 if (bHasSelectedShape)
1065 {
1066 if ( nAddSelect > 0 )
1067 {
1068 mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD,anyShape,uno::Any());
1069 }
1070 }
1071 else
1072 {
1073 //if has not selected shape ,first selected shape is fire selection event;
1074 if (nAddSelect > 0 )
1075 {
1076 mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED,anyShape,uno::Any());
1077 }
1078 if (nAddSelect > 1 )//check other selected shape fire selection add event
1079 {
1080 bHasSelectedShape=sal_True;
1081 }
1082 }
1083 }
1084 else //selection remove
1085 {
1086 mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE,anyShape,uno::Any());
1087 }
1088 }
1089
1090 // Remember whether there is a shape that now has the focus.
1091 mpFocusedShape = pNewFocusedShape;
1092 }
1093
1094
1095
1096
HasFocus(void)1097 bool ChildrenManagerImpl::HasFocus (void)
1098 {
1099 return mpFocusedShape != NULL;
1100 }
1101
1102
1103
1104
RemoveFocus(void)1105 void ChildrenManagerImpl::RemoveFocus (void)
1106 {
1107 if (mpFocusedShape != NULL)
1108 {
1109 mpFocusedShape->ResetState (AccessibleStateType::FOCUSED);
1110 mpFocusedShape = NULL;
1111 }
1112 }
1113
1114
1115
RegisterAsDisposeListener(const Reference<drawing::XShape> & xShape)1116 void ChildrenManagerImpl::RegisterAsDisposeListener (
1117 const Reference<drawing::XShape>& xShape)
1118 {
1119 Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
1120 if (xComponent.is())
1121 xComponent->addEventListener (
1122 static_cast<document::XEventListener*>(this));
1123 }
1124
1125
1126
1127
UnregisterAsDisposeListener(const Reference<drawing::XShape> & xShape)1128 void ChildrenManagerImpl::UnregisterAsDisposeListener (
1129 const Reference<drawing::XShape>& xShape)
1130 {
1131 Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
1132 if (xComponent.is())
1133 xComponent->removeEventListener (
1134 static_cast<document::XEventListener*>(this));
1135 }
1136
1137
1138
1139
1140 //===== AccessibleChildDescriptor ===========================================
1141
ChildDescriptor(const Reference<drawing::XShape> & xShape)1142 ChildDescriptor::ChildDescriptor (const Reference<drawing::XShape>& xShape)
1143 : mxShape (xShape),
1144 mxAccessibleShape (NULL),
1145 mbCreateEventPending (true)
1146 {
1147 // Empty.
1148 }
1149
1150
1151
1152
ChildDescriptor(const Reference<XAccessible> & rxAccessibleShape)1153 ChildDescriptor::ChildDescriptor (const Reference<XAccessible>& rxAccessibleShape)
1154 : mxShape (NULL),
1155 mxAccessibleShape (rxAccessibleShape),
1156 mbCreateEventPending (true)
1157 {
1158 // Make sure that the accessible object has the <const>VISIBLE</const>
1159 // state set.
1160 AccessibleShape* pAccessibleShape = GetAccessibleShape();
1161 pAccessibleShape->SetState (AccessibleStateType::VISIBLE);
1162 }
1163
1164
1165
1166
~ChildDescriptor(void)1167 ChildDescriptor::~ChildDescriptor (void)
1168 {
1169 }
1170
1171
1172
1173
GetAccessibleShape(void) const1174 AccessibleShape* ChildDescriptor::GetAccessibleShape (void) const
1175 {
1176 return static_cast<AccessibleShape*> (mxAccessibleShape.get());
1177 }
1178 // -----------------------------------------------------------------------------
setIndexAtAccessibleShape(sal_Int32 _nIndex)1179 void ChildDescriptor::setIndexAtAccessibleShape(sal_Int32 _nIndex)
1180 {
1181 AccessibleShape* pShape = GetAccessibleShape();
1182 if ( pShape )
1183 pShape->setIndexInParent(_nIndex);
1184 }
1185 // -----------------------------------------------------------------------------
1186
1187
1188
1189
disposeAccessibleObject(AccessibleContextBase & rParent)1190 void ChildDescriptor::disposeAccessibleObject (AccessibleContextBase& rParent)
1191 {
1192 if (mxAccessibleShape.is())
1193 {
1194 // Send event that the shape has been removed.
1195 uno::Any aOldValue;
1196 aOldValue <<= mxAccessibleShape;
1197 rParent.CommitChange (
1198 AccessibleEventId::CHILD,
1199 uno::Any(),
1200 aOldValue);
1201
1202 // Dispose and remove the object.
1203 Reference<lang::XComponent> xComponent (mxAccessibleShape, uno::UNO_QUERY);
1204 if (xComponent.is())
1205 xComponent->dispose ();
1206
1207 mxAccessibleShape = NULL;
1208 }
1209 }
1210
1211
1212 } // end of namespace accessibility
1213