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