xref: /trunk/main/svx/source/accessibility/ChildrenManagerImpl.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956) !
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