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