bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / accessibility / ChildrenManagerImpl.cxx
blob4cea26f20bf613f9c1c8cfc44a89b32708c8c651
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <cassert>
24 #include "ChildrenManagerImpl.hxx"
25 #include <svx/ShapeTypeHandler.hxx>
26 #include <svx/AccessibleShapeInfo.hxx>
27 #include <vcl/svapp.hxx>
28 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
29 #include <com/sun/star/view/XSelectionSupplier.hpp>
30 #include <com/sun/star/container/XChild.hpp>
31 #include <comphelper/uno3.hxx>
33 #include <rtl/ustring.hxx>
34 #include <tools/debug.hxx>
35 #include <svx/SvxShapeTypes.hxx>
36 #include <vcl/window.hxx>
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::accessibility;
40 using ::com::sun::star::uno::Reference;
42 namespace accessibility {
44 namespace
46 void adjustIndexInParentOfShapes(ChildDescriptorListType& _rList)
48 ChildDescriptorListType::iterator aEnd = _rList.end();
49 sal_Int32 i=0;
50 for ( ChildDescriptorListType::iterator aIter = _rList.begin(); aIter != aEnd; ++aIter,++i)
51 aIter->setIndexAtAccessibleShape(i);
55 // AccessibleChildrenManager
56 ChildrenManagerImpl::ChildrenManagerImpl (
57 const uno::Reference<XAccessible>& rxParent,
58 const uno::Reference<drawing::XShapes>& rxShapeList,
59 const AccessibleShapeTreeInfo& rShapeTreeInfo,
60 AccessibleContextBase& rContext)
61 : ::cppu::WeakComponentImplHelper2<
62 ::com::sun::star::document::XEventListener,
63 ::com::sun::star::view::XSelectionChangeListener>(maMutex),
64 mxShapeList (rxShapeList),
65 mxParent (rxParent),
66 maShapeTreeInfo (rShapeTreeInfo),
67 mrContext (rContext),
68 mnNewNameIndex(1),
69 mpFocusedShape(NULL)
76 ChildrenManagerImpl::~ChildrenManagerImpl()
78 DBG_ASSERT (rBHelper.bDisposed || rBHelper.bInDispose,
79 "~AccessibleDrawDocumentView: object has not been disposed");
85 void ChildrenManagerImpl::Init()
87 // Register as view::XSelectionChangeListener.
88 Reference<frame::XController> xController(maShapeTreeInfo.GetController());
89 Reference<view::XSelectionSupplier> xSelectionSupplier (
90 xController, uno::UNO_QUERY);
91 if (xSelectionSupplier.is())
93 xController->addEventListener(
94 static_cast<document::XEventListener*>(this));
96 xSelectionSupplier->addSelectionChangeListener (
97 static_cast<view::XSelectionChangeListener*>(this));
100 // Register at model as document::XEventListener.
101 if (maShapeTreeInfo.GetModelBroadcaster().is())
102 maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
103 static_cast<document::XEventListener*>(this));
109 long ChildrenManagerImpl::GetChildCount() const throw ()
111 return maVisibleChildren.size();
115 ::com::sun::star::uno::Reference<
116 ::com::sun::star::drawing::XShape> ChildrenManagerImpl::GetChildShape(long nIndex)
117 throw (::com::sun::star::uno::RuntimeException,
118 ::com::sun::star::lang::IndexOutOfBoundsException)
120 uno::Reference<XAccessible> xAcc = GetChild(nIndex);
121 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
122 for (I = maVisibleChildren.begin(); I != aEnd; ++I)
124 if (I->mxAccessibleShape == xAcc)
125 return I->mxShape;
127 return uno::Reference< drawing::XShape > ();
130 /** Return the requested accessible child object. Create it if it is not
131 yet in the cache.
133 uno::Reference<XAccessible>
134 ChildrenManagerImpl::GetChild (long nIndex)
135 throw (::com::sun::star::uno::RuntimeException,
136 ::com::sun::star::lang::IndexOutOfBoundsException)
138 // Check whether the given index is valid.
139 if (nIndex < 0 || (unsigned long)nIndex >= maVisibleChildren.size())
140 throw lang::IndexOutOfBoundsException (
141 "no accessible child with index " + OUString::number(nIndex),
142 mxParent);
144 return GetChild (maVisibleChildren[nIndex],nIndex);
150 /** Return the requested accessible child object. Create it if it is not
151 yet in the cache.
153 uno::Reference<XAccessible>
154 ChildrenManagerImpl::GetChild (ChildDescriptor& rChildDescriptor,sal_Int32 _nIndex)
155 throw (::com::sun::star::uno::RuntimeException)
157 if ( ! rChildDescriptor.mxAccessibleShape.is())
159 SolarMutexGuard g;
160 // Make sure that the requested accessible object has not been
161 // created while locking the global mutex.
162 if ( ! rChildDescriptor.mxAccessibleShape.is())
164 AccessibleShapeInfo aShapeInfo(
165 rChildDescriptor.mxShape,
166 mxParent,
167 this,
168 mnNewNameIndex++);
169 // Create accessible object that corresponds to the descriptor's
170 // shape.
171 AccessibleShape* pShape =
172 ShapeTypeHandler::Instance().CreateAccessibleObject (
173 aShapeInfo,
174 maShapeTreeInfo);
175 rChildDescriptor.mxAccessibleShape = uno::Reference<XAccessible> (
176 static_cast<uno::XWeak*>(pShape),
177 uno::UNO_QUERY);
178 // Now that there is a reference to the new accessible shape we
179 // can safely call its Init() method.
180 if ( pShape != NULL )
182 pShape->Init();
183 pShape->setIndexInParent(_nIndex);
188 return rChildDescriptor.mxAccessibleShape;
194 uno::Reference<XAccessible>
195 ChildrenManagerImpl::GetChild (const uno::Reference<drawing::XShape>& xShape)
196 throw (uno::RuntimeException)
198 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
199 for (I = maVisibleChildren.begin(); I != aEnd; ++I)
201 if ( I->mxShape.get() == xShape.get() )
202 return I->mxAccessibleShape;
204 return uno::Reference<XAccessible> ();
210 /** Find all shapes among the specified shapes that lie fully or partially
211 inside the visible area. Put those shapes into the cleared cache. The
212 corresponding accessible objects will be created on demand.
214 At the moment, first all accessible objects are removed from the cache
215 and the appropriate listeners are informed of this. Next, the list is
216 created again. This should be optimized in the future to not remove and
217 create objects that will be in the list before and after the update
218 method.
220 void ChildrenManagerImpl::Update (bool bCreateNewObjectsOnDemand)
222 if (maShapeTreeInfo.GetViewForwarder() == NULL)
223 return;
224 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
226 // 1. Create a local list of visible shapes.
227 ChildDescriptorListType aChildList;
228 CreateListOfVisibleShapes (aChildList);
230 // 2. Merge the information that is already known about the visible
231 // shapes from the current list into the new list.
232 MergeAccessibilityInformation (aChildList);
234 // 3. Replace the current list of visible shapes with the new one. Do
235 // the same with the visible area.
237 SolarMutexGuard g;
238 adjustIndexInParentOfShapes(aChildList);
240 // Use swap to copy the contents of the new list in constant time.
241 maVisibleChildren.swap (aChildList);
243 // aChildList now contains all the old children, while maVisibleChildren
244 // contains all the current children
246 // 4. Find all shapes in the old list that are not in the current list,
247 // send appropriate events and remove the accessible shape.
249 // Do this *after* we have set our new list of children, because
250 // removing a child may cause
252 // ChildDescriptor::disposeAccessibleObject -->
253 // AccessibleContextBase::CommitChange -->
254 // AtkListener::notifyEvent ->
255 // AtkListener::handleChildRemoved ->
256 // AtkListener::updateChildList
257 // AccessibleDrawDocumentView::getAccessibleChildCount ->
258 // ChildrenManagerImpl::GetChildCount ->
259 // maVisibleChildren.size()
261 // to be fired, and so the operations will take place on
262 // the list we are trying to replace
264 RemoveNonVisibleChildren (maVisibleChildren, aChildList);
266 aChildList.clear();
268 maVisibleArea = aVisibleArea;
271 // 5. If the visible area has changed then send events that signal a
272 // change of their bounding boxes for all shapes that are members of
273 // both the current and the new list of visible shapes.
274 if (maVisibleArea != aVisibleArea)
275 SendVisibleAreaEvents (maVisibleChildren);
277 // 6. If children have to be created immediately and not on demand then
278 // create the missing accessible objects now.
279 if (!bCreateNewObjectsOnDemand)
281 //operate on a copy of the list and restore it afterwards to guard
282 //against the pathological case where maVisibleChildren gets modified
283 //by other calls to this object while CreateAccessibilityObjects
284 //executes which can happen when java is disabled and the "enable-java"
285 //dialog appears during the instantiation of the linguistic components
286 //triggered by the creation of shapes belonging to the a11y objects
288 //i.e. launch start-center, launch impress with java disabled and
289 //a java-using linguistic component installed
290 maVisibleChildren.swap(aChildList);
291 CreateAccessibilityObjects(aChildList);
292 maVisibleChildren.swap(aChildList);
296 void ChildrenManagerImpl::CreateListOfVisibleShapes (
297 ChildDescriptorListType& raDescriptorList)
299 SolarMutexGuard g;
301 OSL_ASSERT (maShapeTreeInfo.GetViewForwarder() != NULL);
303 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
305 // Add the visible shapes for which the accessible objects already exist.
306 AccessibleShapeList::iterator I,aEnd = maAccessibleShapes.end();
307 for (I=maAccessibleShapes.begin(); I != aEnd; ++I)
309 if (I->is())
311 uno::Reference<XAccessibleComponent> xComponent (
312 (*I)->getAccessibleContext(), uno::UNO_QUERY);
313 if (xComponent.is())
315 // The bounding box of the object already is clipped to the
316 // visible area. The object is therefore visible if the
317 // bounding box has non-zero extensions.
318 awt::Rectangle aPixelBBox (xComponent->getBounds());
319 if ((aPixelBBox.Width > 0) && (aPixelBBox.Height > 0))
320 raDescriptorList.push_back (ChildDescriptor (*I));
325 // Add the visible shapes for which only the XShapes exist.
326 uno::Reference<container::XIndexAccess> xShapeAccess (mxShapeList, uno::UNO_QUERY);
327 if (xShapeAccess.is())
329 sal_Int32 nShapeCount = xShapeAccess->getCount();
330 raDescriptorList.reserve( nShapeCount );
331 awt::Point aPos;
332 awt::Size aSize;
333 Rectangle aBoundingBox;
334 uno::Reference<drawing::XShape> xShape;
335 for (sal_Int32 i=0; i<nShapeCount; ++i)
337 xShapeAccess->getByIndex(i) >>= xShape;
338 aPos = xShape->getPosition();
339 aSize = xShape->getSize();
341 aBoundingBox.Left() = aPos.X;
342 aBoundingBox.Top() = aPos.Y;
343 aBoundingBox.Right() = aPos.X + aSize.Width;
344 aBoundingBox.Bottom() = aPos.Y + aSize.Height;
346 // Insert shape if it is visible, i.e. its bounding box overlaps
347 // the visible area.
348 if ( aBoundingBox.IsOver (aVisibleArea) )
349 raDescriptorList.push_back (ChildDescriptor (xShape));
357 void ChildrenManagerImpl::RemoveNonVisibleChildren (
358 const ChildDescriptorListType& rNewChildList,
359 ChildDescriptorListType& rOldChildList)
361 // Iterate over list of formerly visible children and remove those that
362 // are not visible anymore, i.e. member of the new list of visible
363 // children.
364 ChildDescriptorListType::iterator I, aEnd = rOldChildList.end();
365 for (I=rOldChildList.begin(); I != aEnd; ++I)
367 if (::std::find(rNewChildList.begin(), rNewChildList.end(), *I) == rNewChildList.end())
369 // The child is disposed when there is a UNO shape from which
370 // the accessible shape can be created when the shape becomes
371 // visible again. When there is no such UNO shape then simply
372 // reset the descriptor but keep the accessibility object.
373 if (I->mxShape.is())
375 UnregisterAsDisposeListener (I->mxShape);
376 I->disposeAccessibleObject (mrContext);
378 else
380 AccessibleShape* pAccessibleShape = I->GetAccessibleShape();
381 pAccessibleShape->ResetState (AccessibleStateType::VISIBLE);
382 I->mxAccessibleShape = NULL;
391 void ChildrenManagerImpl::MergeAccessibilityInformation (
392 ChildDescriptorListType& raNewChildList)
394 ChildDescriptorListType::iterator aOldChildDescriptor;
395 ChildDescriptorListType::iterator I, aEnd = raNewChildList.end();
396 for (I=raNewChildList.begin(); I != aEnd; ++I)
398 aOldChildDescriptor = ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(), *I);
400 // Copy accessible shape if that exists in the old descriptor.
401 bool bRegistrationIsNecessary = true;
402 if (aOldChildDescriptor != maVisibleChildren.end())
403 if (aOldChildDescriptor->mxAccessibleShape.is())
405 I->mxAccessibleShape = aOldChildDescriptor->mxAccessibleShape;
406 I->mbCreateEventPending = false;
407 bRegistrationIsNecessary = false;
409 if (bRegistrationIsNecessary)
410 RegisterAsDisposeListener (I->mxShape);
417 void ChildrenManagerImpl::SendVisibleAreaEvents (
418 ChildDescriptorListType& raNewChildList)
420 ChildDescriptorListType::iterator I,aEnd = raNewChildList.end();
421 for (I=raNewChildList.begin(); I != aEnd; ++I)
423 // Tell shape of changed visible area. To do this, fake a
424 // change of the view forwarder. (Actually we usually get here
425 // as a result of a change of the view forwarder).
426 AccessibleShape* pShape = I->GetAccessibleShape ();
427 if (pShape != NULL)
428 pShape->ViewForwarderChanged (
429 IAccessibleViewForwarderListener::VISIBLE_AREA,
430 maShapeTreeInfo.GetViewForwarder());
437 void ChildrenManagerImpl::CreateAccessibilityObjects (
438 ChildDescriptorListType& raNewChildList)
440 ChildDescriptorListType::iterator I, aEnd = raNewChildList.end();
441 sal_Int32 nPos = 0;
442 for ( I = raNewChildList.begin(); I != aEnd; ++I,++nPos)
444 // Create the associated accessible object when the flag says so and
445 // it does not yet exist.
446 if ( ! I->mxAccessibleShape.is() )
447 GetChild (*I,nPos);
448 if (I->mxAccessibleShape.is() && I->mbCreateEventPending)
450 I->mbCreateEventPending = false;
451 mrContext.CommitChange (
452 AccessibleEventId::CHILD,
453 uno::makeAny(I->mxAccessibleShape),
454 uno::Any());
462 void ChildrenManagerImpl::AddShape (const Reference<drawing::XShape>& rxShape)
464 if (rxShape.is())
466 SolarMutexClearableGuard aGuard;
468 // Test visibility of the shape.
469 Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
470 awt::Point aPos = rxShape->getPosition();
471 awt::Size aSize = rxShape->getSize();
473 Rectangle aBoundingBox (
474 aPos.X,
475 aPos.Y,
476 aPos.X + aSize.Width,
477 aPos.Y + aSize.Height);
479 // Add the shape only when it belongs to the list of shapes stored
480 // in mxShapeList (which is either a page or a group shape).
481 Reference<container::XChild> xChild (rxShape, uno::UNO_QUERY);
482 if (xChild.is())
484 Reference<drawing::XShapes> xParent (xChild->getParent(), uno::UNO_QUERY);
485 if (xParent == mxShapeList)
486 if (aBoundingBox.IsOver (aVisibleArea))
488 // Add shape to list of visible shapes.
489 maVisibleChildren.push_back (ChildDescriptor (rxShape));
491 // Create accessibility object.
492 ChildDescriptor& rDescriptor = maVisibleChildren.back();
493 GetChild (rDescriptor, maVisibleChildren.size()-1);
495 // Inform listeners about new child.
496 uno::Any aNewShape;
497 aNewShape <<= rDescriptor.mxAccessibleShape;
498 aGuard.clear();
499 mrContext.CommitChange (
500 AccessibleEventId::CHILD,
501 aNewShape,
502 uno::Any());
503 RegisterAsDisposeListener(rxShape);
512 void ChildrenManagerImpl::RemoveShape (const Reference<drawing::XShape>& rxShape)
514 if (rxShape.is())
516 SolarMutexGuard g;
518 // Search shape in list of visible children.
519 ChildDescriptorListType::iterator I (
520 ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
521 ChildDescriptor (rxShape)));
522 if (I != maVisibleChildren.end())
524 // Remove descriptor from that list.
525 Reference<XAccessible> xAccessibleShape (I->mxAccessibleShape);
527 UnregisterAsDisposeListener (I->mxShape);
528 // Dispose the accessible object.
529 I->disposeAccessibleObject (mrContext);
531 // Now we can safely remove the child descriptor and thus
532 // invalidate the iterator.
533 maVisibleChildren.erase (I);
535 adjustIndexInParentOfShapes(maVisibleChildren);
543 void ChildrenManagerImpl::SetShapeList (const ::com::sun::star::uno::Reference<
544 ::com::sun::star::drawing::XShapes>& xShapeList)
546 mxShapeList = xShapeList;
552 void ChildrenManagerImpl::AddAccessibleShape (css::uno::Reference<css::accessibility::XAccessible> const & shape)
554 assert(shape.is());
555 maAccessibleShapes.push_back (shape);
561 void ChildrenManagerImpl::ClearAccessibleShapeList()
563 // Copy the list of (visible) shapes to local lists and clear the
564 // originals.
565 ChildDescriptorListType aLocalVisibleChildren;
566 aLocalVisibleChildren.swap(maVisibleChildren);
567 AccessibleShapeList aLocalAccessibleShapes;
568 aLocalAccessibleShapes.swap(maAccessibleShapes);
570 // Tell the listeners that all children are gone.
571 mrContext.CommitChange (
572 AccessibleEventId::INVALIDATE_ALL_CHILDREN,
573 uno::Any(),
574 uno::Any());
576 // There are no accessible shapes left so the index assigned to new
577 // accessible shapes can be reset.
578 mnNewNameIndex = 1;
580 // Now the objects in the local lists can be safely disposed without
581 // having problems with callers that want to update their child lists.
583 // Clear the list of visible accessible objects. Objects not created on
584 // demand for XShapes are treated below.
585 ChildDescriptorListType::iterator I,aEnd = aLocalVisibleChildren.end();
586 for (I=aLocalVisibleChildren.begin(); I != aEnd; ++I)
587 if ( I->mxAccessibleShape.is() && I->mxShape.is() )
589 ::comphelper::disposeComponent(I->mxAccessibleShape);
590 I->mxAccessibleShape = NULL;
593 // Dispose all objects in the accessible shape list.
594 AccessibleShapeList::iterator J,aEnd2 = aLocalAccessibleShapes.end();
595 for (J=aLocalAccessibleShapes.begin(); J != aEnd2; ++J)
596 if (J->is())
598 // Dispose the object.
599 ::comphelper::disposeComponent(*J);
600 *J = NULL;
607 /** If the broadcasters change at which this object is registered then
608 unregister at old and register at new broadcasters.
610 void ChildrenManagerImpl::SetInfo (const AccessibleShapeTreeInfo& rShapeTreeInfo)
612 // Remember the current broadcasters and exchange the shape tree info.
613 Reference<document::XEventBroadcaster> xCurrentBroadcaster;
614 Reference<frame::XController> xCurrentController;
615 Reference<view::XSelectionSupplier> xCurrentSelectionSupplier;
617 SolarMutexGuard g;
618 xCurrentBroadcaster = maShapeTreeInfo.GetModelBroadcaster();
619 xCurrentController = maShapeTreeInfo.GetController();
620 xCurrentSelectionSupplier = Reference<view::XSelectionSupplier> (
621 xCurrentController, uno::UNO_QUERY);
622 maShapeTreeInfo = rShapeTreeInfo;
625 // Move registration to new model.
626 if (maShapeTreeInfo.GetModelBroadcaster() != xCurrentBroadcaster)
628 // Register at new broadcaster.
629 if (maShapeTreeInfo.GetModelBroadcaster().is())
630 maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
631 static_cast<document::XEventListener*>(this));
633 // Unregister at old broadcaster.
634 if (xCurrentBroadcaster.is())
635 xCurrentBroadcaster->removeEventListener (
636 static_cast<document::XEventListener*>(this));
639 // Move registration to new selection supplier.
640 Reference<frame::XController> xNewController(maShapeTreeInfo.GetController());
641 Reference<view::XSelectionSupplier> xNewSelectionSupplier (
642 xNewController, uno::UNO_QUERY);
643 if (xNewSelectionSupplier != xCurrentSelectionSupplier)
645 // Register at new broadcaster.
646 if (xNewSelectionSupplier.is())
648 xNewController->addEventListener(
649 static_cast<document::XEventListener*>(this));
651 xNewSelectionSupplier->addSelectionChangeListener (
652 static_cast<view::XSelectionChangeListener*>(this));
655 // Unregister at old broadcaster.
656 if (xCurrentSelectionSupplier.is())
658 xCurrentSelectionSupplier->removeSelectionChangeListener (
659 static_cast<view::XSelectionChangeListener*>(this));
661 xCurrentController->removeEventListener(
662 static_cast<document::XEventListener*>(this));
667 // lang::XEventListener
668 void SAL_CALL
669 ChildrenManagerImpl::disposing (const lang::EventObject& rEventObject)
670 throw (uno::RuntimeException, std::exception)
672 if (rEventObject.Source == maShapeTreeInfo.GetModelBroadcaster()
673 || rEventObject.Source == maShapeTreeInfo.GetController())
675 impl_dispose();
678 // Handle disposing UNO shapes.
679 else
681 Reference<drawing::XShape> xShape (rEventObject.Source, uno::UNO_QUERY);
683 // Find the descriptor for the given shape.
684 ChildDescriptorListType::iterator I (
685 ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
686 ChildDescriptor (xShape)));
687 if (I != maVisibleChildren.end())
689 // Clear the descriptor.
690 I->disposeAccessibleObject (mrContext);
691 I->mxShape = NULL;
696 // document::XEventListener
697 /** Listen for new and removed shapes.
699 void SAL_CALL
700 ChildrenManagerImpl::notifyEvent (
701 const document::EventObject& rEventObject)
702 throw (uno::RuntimeException, std::exception)
704 static const char sShapeInserted[] = "ShapeInserted";
705 static const char sShapeRemoved[] = "ShapeRemoved";
708 if (rEventObject.EventName == sShapeInserted)
709 AddShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
710 else if (rEventObject.EventName == sShapeRemoved)
711 RemoveShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
712 // else ignore unknown event.
715 // view::XSelectionChangeListener
716 void SAL_CALL
717 ChildrenManagerImpl::selectionChanged (const lang::EventObject& /*rEvent*/)
718 throw (uno::RuntimeException, std::exception)
720 UpdateSelection ();
726 void ChildrenManagerImpl::impl_dispose()
728 Reference<frame::XController> xController(maShapeTreeInfo.GetController());
729 // Remove from broadcasters.
732 Reference<view::XSelectionSupplier> xSelectionSupplier (
733 xController, uno::UNO_QUERY);
734 if (xSelectionSupplier.is())
736 xSelectionSupplier->removeSelectionChangeListener (
737 static_cast<view::XSelectionChangeListener*>(this));
740 catch( uno::RuntimeException&)
745 if (xController.is())
746 xController->removeEventListener(
747 static_cast<document::XEventListener*>(this));
749 catch( uno::RuntimeException&)
752 maShapeTreeInfo.SetController (NULL);
756 // Remove from broadcaster.
757 if (maShapeTreeInfo.GetModelBroadcaster().is())
758 maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
759 static_cast<document::XEventListener*>(this));
760 maShapeTreeInfo.SetModelBroadcaster (NULL);
762 catch( uno::RuntimeException& )
765 ClearAccessibleShapeList ();
766 SetShapeList (NULL);
771 void SAL_CALL ChildrenManagerImpl::disposing()
773 impl_dispose();
776 // IAccessibleViewForwarderListener
777 void ChildrenManagerImpl::ViewForwarderChanged (ChangeType aChangeType,
778 const IAccessibleViewForwarder* pViewForwarder)
780 if (aChangeType == IAccessibleViewForwarderListener::VISIBLE_AREA)
781 Update (false);
782 else
784 SolarMutexGuard g;
785 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
786 for (I=maVisibleChildren.begin(); I != aEnd; ++I)
788 AccessibleShape* pShape = I->GetAccessibleShape();
789 if (pShape != NULL)
790 pShape->ViewForwarderChanged (aChangeType, pViewForwarder);
795 // IAccessibleParent
796 bool ChildrenManagerImpl::ReplaceChild (
797 AccessibleShape* pCurrentChild,
798 const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& _rxShape,
799 const long _nIndex,
800 const AccessibleShapeTreeInfo& _rShapeTreeInfo)
801 throw (uno::RuntimeException)
803 AccessibleShapeInfo aShapeInfo( _rxShape, pCurrentChild->getAccessibleParent(), this, _nIndex );
804 // create the new child
805 AccessibleShape* pNewChild = ShapeTypeHandler::Instance().CreateAccessibleObject (
806 aShapeInfo,
807 _rShapeTreeInfo
809 Reference< XAccessible > xNewChild( pNewChild ); // keep this alive (do this before calling Init!)
810 if ( pNewChild )
811 pNewChild->Init();
813 bool bResult = false;
815 // Iterate over the visible children. If one of them has an already
816 // created accessible object that matches pCurrentChild then replace
817 // it. Otherwise the child to replace is either not in the list or has
818 // not ye been created (and is therefore not in the list, too) and a
819 // replacement is not necessary.
820 ChildDescriptorListType::iterator I,aEnd = maVisibleChildren.end();
821 for (I=maVisibleChildren.begin(); I != aEnd; ++I)
823 if (I->GetAccessibleShape() == pCurrentChild)
825 // Dispose the current child and send an event about its deletion.
826 pCurrentChild->dispose();
827 mrContext.CommitChange (
828 AccessibleEventId::CHILD,
829 uno::Any(),
830 uno::makeAny (I->mxAccessibleShape));
832 // Replace with replacement and send an event about existence
833 // of the new child.
834 I->mxAccessibleShape = pNewChild;
835 mrContext.CommitChange (
836 AccessibleEventId::CHILD,
837 uno::makeAny (I->mxAccessibleShape),
838 uno::Any());
839 bResult = true;
840 break;
844 // When not found among the visible children we have to search the list
845 // of accessible shapes. This is not yet implemented.
847 return bResult;
850 // Add the impl method for IAccessibleParent interface
851 AccessibleControlShape * ChildrenManagerImpl::GetAccControlShapeFromModel(::com::sun::star::beans::XPropertySet* pSet) throw (::com::sun::star::uno::RuntimeException)
853 sal_Int32 count = GetChildCount();
854 for (sal_Int32 index=0;index<count;index++)
856 AccessibleShape* pAccShape = maVisibleChildren[index].GetAccessibleShape();
857 if (pAccShape && ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape->GetXShape()) == DRAWING_CONTROL)
859 ::accessibility::AccessibleControlShape *pCtlAccShape = static_cast < ::accessibility::AccessibleControlShape* >(pAccShape);
860 if (pCtlAccShape && pCtlAccShape->GetControlModel() == pSet)
861 return pCtlAccShape;
864 return NULL;
866 uno::Reference<XAccessible>
867 ChildrenManagerImpl::GetAccessibleCaption (const uno::Reference<drawing::XShape>& xShape)
868 throw (uno::RuntimeException)
870 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
871 for (I = maVisibleChildren.begin(); I != aEnd; ++I)
873 if ( I->mxShape.get() == xShape.get() )
874 return I->mxAccessibleShape;
876 return uno::Reference<XAccessible> ();
879 /** Update the <const>SELECTED</const> and the <const>FOCUSED</const> state
880 of all visible children. Maybe this should be changed to all children.
882 Iterate over all descriptors of visible accessible shapes and look them
883 up in the selection.
885 If there is no valid controller then all shapes are deselected and
886 unfocused. If the controller's frame is not active then all shapes are
887 unfocused.
889 void ChildrenManagerImpl::UpdateSelection()
891 Reference<frame::XController> xController(maShapeTreeInfo.GetController());
892 Reference<view::XSelectionSupplier> xSelectionSupplier (
893 xController, uno::UNO_QUERY);
895 // Try to cast the selection both to a multi selection and to a single
896 // selection.
897 Reference<container::XIndexAccess> xSelectedShapeAccess;
898 Reference<drawing::XShape> xSelectedShape;
899 if (xSelectionSupplier.is())
901 xSelectedShapeAccess = Reference<container::XIndexAccess> (
902 xSelectionSupplier->getSelection(), uno::UNO_QUERY);
903 xSelectedShape = Reference<drawing::XShape> (
904 xSelectionSupplier->getSelection(), uno::UNO_QUERY);
907 // Remember the current and new focused shape.
908 AccessibleShape* pCurrentlyFocusedShape = NULL;
909 AccessibleShape* pNewFocusedShape = NULL;
910 typedef std::pair< AccessibleShape* , sal_Bool > PAIR_SHAPE;//sal_Bool Selected,UnSelected.
911 typedef std::vector< PAIR_SHAPE > VEC_SHAPE;
912 VEC_SHAPE vecSelect;
913 int nAddSelect=0;
914 int nRemoveSelect=0;
915 bool bHasSelectedShape=false;
916 ChildDescriptorListType::iterator I, aEnd = maVisibleChildren.end();
917 for (I=maVisibleChildren.begin(); I != aEnd; ++I)
919 AccessibleShape* pAccessibleShape = I->GetAccessibleShape();
920 if (I->mxAccessibleShape.is() && I->mxShape.is() && pAccessibleShape!=NULL)
922 short nRole = pAccessibleShape->getAccessibleRole();
923 bool bDrawShape = (
924 nRole == AccessibleRole::GRAPHIC ||
925 nRole == AccessibleRole::EMBEDDED_OBJECT ||
926 nRole == AccessibleRole::SHAPE ||
927 nRole == AccessibleRole::IMAGE_MAP ||
928 nRole == AccessibleRole::TABLE_CELL ||
929 nRole == AccessibleRole::TABLE );
930 bool bShapeIsSelected = false;
932 // Look up the shape in the (single or multi-) selection.
933 if (xSelectedShape.is())
935 if (I->mxShape == xSelectedShape)
937 bShapeIsSelected = true;
938 pNewFocusedShape = pAccessibleShape;
941 else if (xSelectedShapeAccess.is())
943 sal_Int32 nCount=xSelectedShapeAccess->getCount();
944 for (sal_Int32 i=0; i<nCount&&!bShapeIsSelected; i++)
945 if (xSelectedShapeAccess->getByIndex(i) == I->mxShape)
947 bShapeIsSelected = true;
948 // In a multi-selection no shape has the focus.
949 if (nCount == 1)
950 pNewFocusedShape = pAccessibleShape;
954 // Set or reset the SELECTED state.
955 if (bShapeIsSelected)
957 if (pAccessibleShape->SetState (AccessibleStateType::SELECTED))
959 if (bDrawShape)
961 vecSelect.push_back(std::make_pair(pAccessibleShape,sal_True));
962 ++nAddSelect;
965 else
966 {//Selected not change,has selected shape before
967 bHasSelectedShape=true;
970 else
971 //pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
973 if(pAccessibleShape->ResetState (AccessibleStateType::SELECTED))
975 if(bDrawShape)
977 vecSelect.push_back(std::make_pair(pAccessibleShape,sal_False));
978 ++nRemoveSelect;
982 // Does the shape have the current selection?
983 if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
984 pCurrentlyFocusedShape = pAccessibleShape;
988 vcl::Window *pParentWindow = maShapeTreeInfo.GetWindow();
989 bool bShapeActive= false;
990 // For table cell, the table's parent must be checked to make sure it has focus.
991 if (pParentWindow)
993 vcl::Window *pPWindow = pParentWindow->GetParent();
994 if (pParentWindow->HasFocus() || (pPWindow && pPWindow->HasFocus()))
995 bShapeActive =true;
997 // Move focus from current to newly focused shape.
998 if (pCurrentlyFocusedShape != pNewFocusedShape)
1000 if (pCurrentlyFocusedShape != NULL)
1001 pCurrentlyFocusedShape->ResetState (AccessibleStateType::FOCUSED);
1002 if (pNewFocusedShape != NULL && bShapeActive)
1003 pNewFocusedShape->SetState (AccessibleStateType::FOCUSED);
1006 if (nAddSelect >= 10 )//fire selection within
1008 mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN,uno::Any(),uno::Any());
1009 nAddSelect =0 ;//not fire selection event
1011 //VEC_SHAPE::iterator vi = vecSelect.begin();
1012 //for (; vi != vecSelect.end() ;++vi)
1013 VEC_SHAPE::reverse_iterator vi = vecSelect.rbegin();
1014 for (; vi != vecSelect.rend() ;++vi)
1017 PAIR_SHAPE &pairShape= *vi;
1018 Reference< XAccessible > xShape(pairShape.first);
1019 uno::Any anyShape;
1020 anyShape <<= xShape;
1022 if (pairShape.second)//Selection add
1024 if (bHasSelectedShape)
1026 if ( nAddSelect > 0 )
1028 mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD,anyShape,uno::Any());
1031 else
1033 //if has not selected shape ,first selected shape is fire selection event;
1034 if (nAddSelect > 0 )
1036 mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED,anyShape,uno::Any());
1038 if (nAddSelect > 1 )//check other selected shape fire selection add event
1040 bHasSelectedShape=true;
1044 else //selection remove
1046 mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE,anyShape,uno::Any());
1050 // Remember whether there is a shape that now has the focus.
1051 mpFocusedShape = pNewFocusedShape;
1057 bool ChildrenManagerImpl::HasFocus()
1059 return mpFocusedShape != NULL;
1065 void ChildrenManagerImpl::RemoveFocus()
1067 if (mpFocusedShape != NULL)
1069 mpFocusedShape->ResetState (AccessibleStateType::FOCUSED);
1070 mpFocusedShape = NULL;
1076 void ChildrenManagerImpl::RegisterAsDisposeListener (
1077 const Reference<drawing::XShape>& xShape)
1079 Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
1080 if (xComponent.is())
1081 xComponent->addEventListener (
1082 static_cast<document::XEventListener*>(this));
1088 void ChildrenManagerImpl::UnregisterAsDisposeListener (
1089 const Reference<drawing::XShape>& xShape)
1091 Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
1092 if (xComponent.is())
1093 xComponent->removeEventListener (
1094 static_cast<document::XEventListener*>(this));
1097 // AccessibleChildDescriptor
1098 ChildDescriptor::ChildDescriptor (const Reference<drawing::XShape>& xShape)
1099 : mxShape (xShape),
1100 mxAccessibleShape (NULL),
1101 mbCreateEventPending (true)
1103 // Empty.
1109 ChildDescriptor::ChildDescriptor (const Reference<XAccessible>& rxAccessibleShape)
1110 : mxShape (NULL),
1111 mxAccessibleShape (rxAccessibleShape),
1112 mbCreateEventPending (true)
1114 // Make sure that the accessible object has the <const>VISIBLE</const>
1115 // state set.
1116 AccessibleShape* pAccessibleShape = GetAccessibleShape();
1117 pAccessibleShape->SetState (AccessibleStateType::VISIBLE);
1123 ChildDescriptor::~ChildDescriptor()
1130 AccessibleShape* ChildDescriptor::GetAccessibleShape() const
1132 return static_cast<AccessibleShape*> (mxAccessibleShape.get());
1135 void ChildDescriptor::setIndexAtAccessibleShape(sal_Int32 _nIndex)
1137 AccessibleShape* pShape = GetAccessibleShape();
1138 if ( pShape )
1139 pShape->setIndexInParent(_nIndex);
1146 void ChildDescriptor::disposeAccessibleObject (AccessibleContextBase& rParent)
1148 if (mxAccessibleShape.is())
1150 // Send event that the shape has been removed.
1151 uno::Any aOldValue;
1152 aOldValue <<= mxAccessibleShape;
1153 rParent.CommitChange (
1154 AccessibleEventId::CHILD,
1155 uno::Any(),
1156 aOldValue);
1158 // Dispose and remove the object.
1159 Reference<lang::XComponent> xComponent (mxAccessibleShape, uno::UNO_QUERY);
1160 if (xComponent.is())
1161 xComponent->dispose ();
1163 mxAccessibleShape = NULL;
1168 } // end of namespace accessibility
1170 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */