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