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