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