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