LibreOffice Module svx (master)  1
ChildrenManagerImpl.cxx
Go to the documentation of this file.
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>
29 #include <vcl/svapp.hxx>
30 #include <com/sun/star/accessibility/AccessibleRole.hpp>
31 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
32 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/document/XShapeEventBroadcaster.hpp>
35 #include <com/sun/star/frame/XController.hpp>
36 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
37 #include <com/sun/star/view/XSelectionSupplier.hpp>
38 #include <com/sun/star/container/XChild.hpp>
39 #include <comphelper/types.hxx>
40 #include <o3tl/safeint.hxx>
41 #include <rtl/ustring.hxx>
42 #include <tools/debug.hxx>
43 #include <svx/SvxShapeTypes.hxx>
44 #include <vcl/window.hxx>
45 
46 using namespace ::com::sun::star;
47 using namespace ::com::sun::star::accessibility;
48 using ::com::sun::star::uno::Reference;
49 
50 namespace accessibility {
51 
52 namespace
53 {
54 void adjustIndexInParentOfShapes(ChildDescriptorListType& _rList)
55 {
56  sal_Int32 i=0;
57  for (auto& rItem : _rList)
58  {
59  rItem.setIndexAtAccessibleShape(i);
60  ++i;
61  }
62 }
63 }
64 
65 // AccessibleChildrenManager
67  const uno::Reference<XAccessible>& rxParent,
68  const uno::Reference<drawing::XShapes>& rxShapeList,
69  const AccessibleShapeTreeInfo& rShapeTreeInfo,
70  AccessibleContextBase& rContext)
71  : ::cppu::WeakComponentImplHelper<
72  css::document::XEventListener,
73  css::view::XSelectionChangeListener>(maMutex),
74  mxShapeList (rxShapeList),
75  mxParent (rxParent),
76  maShapeTreeInfo (rShapeTreeInfo),
77  mrContext (rContext),
78  mpFocusedShape(nullptr)
79 {
80 }
81 
82 
84 {
85  DBG_ASSERT (rBHelper.bDisposed || rBHelper.bInDispose,
86  "~AccessibleDrawDocumentView: object has not been disposed");
87 }
88 
89 
91 {
92  // Register as view::XSelectionChangeListener.
93  Reference<frame::XController> xController(maShapeTreeInfo.GetController());
94  Reference<view::XSelectionSupplier> xSelectionSupplier (
95  xController, uno::UNO_QUERY);
96  if (xSelectionSupplier.is())
97  {
98  xController->addEventListener(
99  static_cast<document::XEventListener*>(this));
100 
101  xSelectionSupplier->addSelectionChangeListener (
102  static_cast<view::XSelectionChangeListener*>(this));
103  }
104 
105  // Register at model as document::XEventListener.
107  maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
108  static_cast<document::XEventListener*>(this));
109 }
110 
111 
113 {
114  return maVisibleChildren.size();
115 }
116 
117 
118 css::uno::Reference<css::drawing::XShape> ChildrenManagerImpl::GetChildShape(long nIndex)
119 {
120  uno::Reference<XAccessible> xAcc = GetChild(nIndex);
121  auto I = std::find_if(maVisibleChildren.begin(), maVisibleChildren.end(),
122  [&xAcc](const ChildDescriptor& rChild) { return rChild.mxAccessibleShape == xAcc; });
123  if (I != maVisibleChildren.end())
124  return I->mxShape;
125  return uno::Reference< drawing::XShape > ();
126 }
127 
131 uno::Reference<XAccessible>
133 {
134  // Check whether the given index is valid.
135  if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= maVisibleChildren.size())
136  throw lang::IndexOutOfBoundsException (
137  "no accessible child with index " + OUString::number(nIndex),
138  mxParent);
139 
140  return GetChild (maVisibleChildren[nIndex],nIndex);
141 }
142 
143 
147 uno::Reference<XAccessible>
148  ChildrenManagerImpl::GetChild (ChildDescriptor& rChildDescriptor,sal_Int32 _nIndex)
149 {
150  if ( ! rChildDescriptor.mxAccessibleShape.is())
151  {
152  SolarMutexGuard g;
153  // Make sure that the requested accessible object has not been
154  // created while locking the global mutex.
155  if ( ! rChildDescriptor.mxAccessibleShape.is())
156  {
157  AccessibleShapeInfo aShapeInfo(
158  rChildDescriptor.mxShape,
159  mxParent,
160  this);
161  // Create accessible object that corresponds to the descriptor's
162  // shape.
164  ShapeTypeHandler::Instance().CreateAccessibleObject (
165  aShapeInfo,
166  maShapeTreeInfo));
167  rChildDescriptor.mxAccessibleShape.set(
168  static_cast<uno::XWeak*>(pShape.get()),
169  uno::UNO_QUERY);
170  if ( pShape.is() )
171  {
172  pShape->Init();
173  pShape->setIndexInParent(_nIndex);
174  }
175  }
176  }
177 
178  return rChildDescriptor.mxAccessibleShape;
179 }
180 
181 
192 void ChildrenManagerImpl::Update (bool bCreateNewObjectsOnDemand)
193 {
194  if (maShapeTreeInfo.GetViewForwarder() == nullptr)
195  return;
197 
198  // 1. Create a local list of visible shapes.
199  ChildDescriptorListType aChildList;
200  CreateListOfVisibleShapes (aChildList);
201 
202  // 2. Merge the information that is already known about the visible
203  // shapes from the current list into the new list.
204  MergeAccessibilityInformation (aChildList);
205 
206  // 3. Replace the current list of visible shapes with the new one. Do
207  // the same with the visible area.
208  {
209  SolarMutexGuard g;
210  adjustIndexInParentOfShapes(aChildList);
211 
212  // Use swap to copy the contents of the new list in constant time.
213  maVisibleChildren.swap (aChildList);
214 
215  // aChildList now contains all the old children, while maVisibleChildren
216  // contains all the current children
217 
218  // 4. Find all shapes in the old list that are not in the current list,
219  // send appropriate events and remove the accessible shape.
220 
221  // Do this *after* we have set our new list of children, because
222  // removing a child may cause
223 
224  // ChildDescriptor::disposeAccessibleObject -->
225  // AccessibleContextBase::CommitChange -->
226  // AtkListener::notifyEvent ->
227  // AtkListener::handleChildRemoved ->
228  // AtkListener::updateChildList
229  // AccessibleDrawDocumentView::getAccessibleChildCount ->
230  // ChildrenManagerImpl::GetChildCount ->
231  // maVisibleChildren.size()
232 
233  // to be fired, and so the operations will take place on
234  // the list we are trying to replace
235 
237 
238  aChildList.clear();
239 
240  maVisibleArea = aVisibleArea;
241  }
242 
243  // 5. If the visible area has changed then send events that signal a
244  // change of their bounding boxes for all shapes that are members of
245  // both the current and the new list of visible shapes.
246  if (maVisibleArea != aVisibleArea)
248 
249  // 6. If children have to be created immediately and not on demand then
250  // create the missing accessible objects now.
251  if (bCreateNewObjectsOnDemand)
252  return;
253 
254  //operate on a copy of the list and restore it afterwards to guard
255  //against the pathological case where maVisibleChildren gets modified
256  //by other calls to this object while CreateAccessibilityObjects
257  //executes which can happen when java is disabled and the "enable-java"
258  //dialog appears during the instantiation of the linguistic components
259  //triggered by the creation of shapes belonging to the a11y objects
260  //
261  //i.e. launch start-center, launch impress with java disabled and
262  //a java-using linguistic component installed
263  maVisibleChildren.swap(aChildList);
264  CreateAccessibilityObjects(aChildList);
265  maVisibleChildren.swap(aChildList);
266 }
267 
269  ChildDescriptorListType& raDescriptorList)
270 {
271  SolarMutexGuard g;
272 
273  OSL_ASSERT (maShapeTreeInfo.GetViewForwarder() != nullptr);
274 
276 
277  // Add the visible shapes for which the accessible objects already exist.
278  for (const auto& rpShape : maAccessibleShapes)
279  {
280  if (rpShape.is())
281  {
282  uno::Reference<XAccessibleComponent> xComponent (
283  rpShape->getAccessibleContext(), uno::UNO_QUERY);
284  if (xComponent.is())
285  {
286  // The bounding box of the object already is clipped to the
287  // visible area. The object is therefore visible if the
288  // bounding box has non-zero extensions.
289  awt::Rectangle aPixelBBox (xComponent->getBounds());
290  if ((aPixelBBox.Width > 0) && (aPixelBBox.Height > 0))
291  raDescriptorList.emplace_back(rpShape);
292  }
293  }
294  }
295 
296  // Add the visible shapes for which only the XShapes exist.
297  if (!mxShapeList.is())
298  return;
299 
300  sal_Int32 nShapeCount = mxShapeList->getCount();
301  raDescriptorList.reserve( nShapeCount );
302  awt::Point aPos;
303  awt::Size aSize;
304  tools::Rectangle aBoundingBox;
305  uno::Reference<drawing::XShape> xShape;
306  for (sal_Int32 i=0; i<nShapeCount; ++i)
307  {
308  mxShapeList->getByIndex(i) >>= xShape;
309  aPos = xShape->getPosition();
310  aSize = xShape->getSize();
311 
312  aBoundingBox.SetLeft( aPos.X );
313  aBoundingBox.SetTop( aPos.Y );
314  aBoundingBox.SetRight( aPos.X + aSize.Width );
315  aBoundingBox.SetBottom( aPos.Y + aSize.Height );
316 
317  // Insert shape if it is visible, i.e. its bounding box overlaps
318  // the visible area.
319  if ( aBoundingBox.IsOver (aVisibleArea) )
320  raDescriptorList.emplace_back(xShape);
321  }
322 }
323 
324 
326  const ChildDescriptorListType& rNewChildList,
327  ChildDescriptorListType& rOldChildList)
328 {
329  // Iterate over list of formerly visible children and remove those that
330  // are not visible anymore, i.e. member of the new list of visible
331  // children.
332  for (auto& rChild : rOldChildList)
333  {
334  if (::std::find(rNewChildList.begin(), rNewChildList.end(), rChild) == rNewChildList.end())
335  {
336  // The child is disposed when there is a UNO shape from which
337  // the accessible shape can be created when the shape becomes
338  // visible again. When there is no such UNO shape then simply
339  // reset the descriptor but keep the accessibility object.
340  if (rChild.mxShape.is())
341  {
342  UnregisterAsDisposeListener (rChild.mxShape);
343  rChild.disposeAccessibleObject (mrContext);
344  }
345  else
346  {
347  AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
348  pAccessibleShape->ResetState (AccessibleStateType::VISIBLE);
349  rChild.mxAccessibleShape = nullptr;
350  }
351  }
352  }
353 }
354 
356  ChildDescriptorListType& raNewChildList)
357 {
358  ChildDescriptorListType::const_iterator aStartVisibleChildren = maVisibleChildren.begin();
359  ChildDescriptorListType::const_iterator aEndVisibleChildren = maVisibleChildren.end();
360 
361  for (auto& rChild : raNewChildList)
362  {
363  ChildDescriptorListType::const_iterator aOldChildDescriptor =
364  std::find(aStartVisibleChildren, aEndVisibleChildren, rChild);
365 
366  // Copy accessible shape if that exists in the old descriptor.
367  if (aOldChildDescriptor != aEndVisibleChildren &&
368  aOldChildDescriptor->mxAccessibleShape.is())
369  {
370  rChild.mxAccessibleShape = aOldChildDescriptor->mxAccessibleShape;
371  rChild.mbCreateEventPending = false;
372  }
373  else
374  RegisterAsDisposeListener (rChild.mxShape);
375  }
376 }
377 
379  ChildDescriptorListType& raNewChildList)
380 {
381  for (const auto& rChild : raNewChildList)
382  {
383  // Tell shape of changed visible area. To do this, fake a
384  // change of the view forwarder. (Actually we usually get here
385  // as a result of a change of the view forwarder).
386  AccessibleShape* pShape = rChild.GetAccessibleShape ();
387  if (pShape != nullptr)
388  pShape->ViewForwarderChanged();
389  }
390 }
391 
392 
394  ChildDescriptorListType& raNewChildList)
395 {
396  sal_Int32 nPos = 0;
397  for ( auto& rChild : raNewChildList)
398  {
399  // Create the associated accessible object when the flag says so and
400  // it does not yet exist.
401  if ( ! rChild.mxAccessibleShape.is() )
402  GetChild (rChild, nPos);
403  if (rChild.mxAccessibleShape.is() && rChild.mbCreateEventPending)
404  {
405  rChild.mbCreateEventPending = false;
407  AccessibleEventId::CHILD,
408  uno::makeAny(rChild.mxAccessibleShape),
409  uno::Any());
410  }
411  ++nPos;
412  }
413 }
414 
415 
416 void ChildrenManagerImpl::AddShape (const Reference<drawing::XShape>& rxShape)
417 {
418  if (!rxShape.is())
419  return;
420 
422 
423  // Test visibility of the shape.
425  awt::Point aPos = rxShape->getPosition();
426  awt::Size aSize = rxShape->getSize();
427 
428  tools::Rectangle aBoundingBox (
429  aPos.X,
430  aPos.Y,
431  aPos.X + aSize.Width,
432  aPos.Y + aSize.Height);
433 
434  // Add the shape only when it belongs to the list of shapes stored
435  // in mxShapeList (which is either a page or a group shape).
436  Reference<container::XChild> xChild (rxShape, uno::UNO_QUERY);
437  if (!xChild.is())
438  return;
439 
440  Reference<drawing::XShapes> xParent (xChild->getParent(), uno::UNO_QUERY);
441  if (xParent != mxShapeList)
442  return;
443 
444  if (!aBoundingBox.IsOver (aVisibleArea))
445  return;
446 
447  // Add shape to list of visible shapes.
448  maVisibleChildren.emplace_back(rxShape);
449 
450  // Create accessibility object.
451  ChildDescriptor& rDescriptor = maVisibleChildren.back();
452  GetChild (rDescriptor, maVisibleChildren.size()-1);
453 
454  // Inform listeners about new child.
455  uno::Any aNewShape;
456  aNewShape <<= rDescriptor.mxAccessibleShape;
457  aGuard.clear();
459  AccessibleEventId::CHILD,
460  aNewShape,
461  uno::Any());
462  RegisterAsDisposeListener(rxShape);
463 }
464 
465 
466 void ChildrenManagerImpl::RemoveShape (const Reference<drawing::XShape>& rxShape)
467 {
468  if (!rxShape.is())
469  return;
470 
471  SolarMutexGuard g;
472 
473  // Search shape in list of visible children.
474  ChildDescriptorListType::iterator I (
475  ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
476  ChildDescriptor (rxShape)));
477  if (I == maVisibleChildren.end())
478  return;
479 
480  // Remove descriptor from that list.
481  Reference<XAccessible> xHoldAlive(I->mxAccessibleShape);
482 
483  UnregisterAsDisposeListener (I->mxShape);
484  // Dispose the accessible object.
485  I->disposeAccessibleObject (mrContext);
486 
487  // Now we can safely remove the child descriptor and thus
488  // invalidate the iterator.
489  maVisibleChildren.erase (I);
490 
491  adjustIndexInParentOfShapes(maVisibleChildren);
492 }
493 
494 
495 void ChildrenManagerImpl::SetShapeList (const css::uno::Reference<css::drawing::XShapes>& xShapeList)
496 {
497  mxShapeList = xShapeList;
498 }
499 
500 
501 void ChildrenManagerImpl::AddAccessibleShape (css::uno::Reference<css::accessibility::XAccessible> const & shape)
502 {
503  assert(shape.is());
504  maAccessibleShapes.push_back (shape);
505 }
506 
507 
509 {
510  // Copy the list of (visible) shapes to local lists and clear the
511  // originals.
512  ChildDescriptorListType aLocalVisibleChildren;
513  aLocalVisibleChildren.swap(maVisibleChildren);
514  AccessibleShapeList aLocalAccessibleShapes;
515  aLocalAccessibleShapes.swap(maAccessibleShapes);
516 
517  // Tell the listeners that all children are gone.
519  AccessibleEventId::INVALIDATE_ALL_CHILDREN,
520  uno::Any(),
521  uno::Any());
522 
523  // Now the objects in the local lists can be safely disposed without
524  // having problems with callers that want to update their child lists.
525 
526  // Clear the list of visible accessible objects. Objects not created on
527  // demand for XShapes are treated below.
528  for (auto& rChild : aLocalVisibleChildren)
529  if ( rChild.mxAccessibleShape.is() && rChild.mxShape.is() )
530  {
531  ::comphelper::disposeComponent(rChild.mxAccessibleShape);
532  rChild.mxAccessibleShape = nullptr;
533  }
534 
535  // Dispose all objects in the accessible shape list.
536  for (auto& rpShape : aLocalAccessibleShapes)
537  if (rpShape.is())
538  {
539  // Dispose the object.
540  ::comphelper::disposeComponent(rpShape);
541  rpShape = nullptr;
542  }
543 }
544 
545 
550 {
551  // Remember the current broadcasters and exchange the shape tree info.
552  Reference<document::XEventBroadcaster> xCurrentBroadcaster;
553  Reference<frame::XController> xCurrentController;
554  Reference<view::XSelectionSupplier> xCurrentSelectionSupplier;
555  {
556  SolarMutexGuard g;
557  xCurrentBroadcaster = maShapeTreeInfo.GetModelBroadcaster();
558  xCurrentController = maShapeTreeInfo.GetController();
559  xCurrentSelectionSupplier.set( xCurrentController, uno::UNO_QUERY);
560  maShapeTreeInfo = rShapeTreeInfo;
561  }
562 
563  // Move registration to new model.
564  if (maShapeTreeInfo.GetModelBroadcaster() != xCurrentBroadcaster)
565  {
566  // Register at new broadcaster.
568  maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
569  static_cast<document::XEventListener*>(this));
570 
571  // Unregister at old broadcaster.
572  if (xCurrentBroadcaster.is())
573  xCurrentBroadcaster->removeEventListener (
574  static_cast<document::XEventListener*>(this));
575  }
576 
577  // Move registration to new selection supplier.
578  Reference<frame::XController> xNewController(maShapeTreeInfo.GetController());
579  Reference<view::XSelectionSupplier> xNewSelectionSupplier (
580  xNewController, uno::UNO_QUERY);
581  if (xNewSelectionSupplier == xCurrentSelectionSupplier)
582  return;
583 
584  // Register at new broadcaster.
585  if (xNewSelectionSupplier.is())
586  {
587  xNewController->addEventListener(
588  static_cast<document::XEventListener*>(this));
589 
590  xNewSelectionSupplier->addSelectionChangeListener (
591  static_cast<view::XSelectionChangeListener*>(this));
592  }
593 
594  // Unregister at old broadcaster.
595  if (xCurrentSelectionSupplier.is())
596  {
597  xCurrentSelectionSupplier->removeSelectionChangeListener (
598  static_cast<view::XSelectionChangeListener*>(this));
599 
600  xCurrentController->removeEventListener(
601  static_cast<document::XEventListener*>(this));
602  }
603 }
604 
605 // lang::XEventListener
606 void SAL_CALL
607  ChildrenManagerImpl::disposing (const lang::EventObject& rEventObject)
608 {
609  if (rEventObject.Source == maShapeTreeInfo.GetModelBroadcaster()
610  || rEventObject.Source == maShapeTreeInfo.GetController())
611  {
612  impl_dispose();
613  }
614 
615  // Handle disposing UNO shapes.
616  else
617  {
618  Reference<drawing::XShape> xShape (rEventObject.Source, uno::UNO_QUERY);
619 
620  // Find the descriptor for the given shape.
621  ChildDescriptorListType::iterator I (
622  ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
623  ChildDescriptor (xShape)));
624  if (I != maVisibleChildren.end())
625  {
626  // Clear the descriptor.
627  I->disposeAccessibleObject (mrContext);
628  I->mxShape = nullptr;
629  }
630  }
631 }
632 
633 // document::XEventListener
636 void SAL_CALL
638  const document::EventObject& rEventObject)
639 {
640  if (rEventObject.EventName == "ShapeInserted")
641  AddShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
642  else if (rEventObject.EventName == "ShapeRemoved")
643  RemoveShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
644  // else ignore unknown event.
645 }
646 
647 // view::XSelectionChangeListener
648 void SAL_CALL
649  ChildrenManagerImpl::selectionChanged (const lang::EventObject& /*rEvent*/)
650 {
651  UpdateSelection ();
652 }
653 
654 
656 {
657  Reference<frame::XController> xController(maShapeTreeInfo.GetController());
658  // Remove from broadcasters.
659  try
660  {
661  Reference<view::XSelectionSupplier> xSelectionSupplier (
662  xController, uno::UNO_QUERY);
663  if (xSelectionSupplier.is())
664  {
665  xSelectionSupplier->removeSelectionChangeListener (
666  static_cast<view::XSelectionChangeListener*>(this));
667  }
668  }
669  catch( uno::RuntimeException&)
670  {}
671 
672  try
673  {
674  if (xController.is())
675  xController->removeEventListener(
676  static_cast<document::XEventListener*>(this));
677  }
678  catch( uno::RuntimeException&)
679  {}
680 
681  maShapeTreeInfo.SetController (nullptr);
682 
683  try
684  {
685  // Remove from broadcaster.
687  maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
688  static_cast<document::XEventListener*>(this));
690  }
691  catch( uno::RuntimeException& )
692  {}
693 
695  SetShapeList (nullptr);
696 }
697 
698 
700 {
701  impl_dispose();
702 }
703 
704 // IAccessibleViewForwarderListener
706 {
707  Update(false);
708 }
709 
710 // IAccessibleParent
712  AccessibleShape* pCurrentChild,
713  const css::uno::Reference< css::drawing::XShape >& _rxShape,
714  const long /*_nIndex*/,
715  const AccessibleShapeTreeInfo& _rShapeTreeInfo)
716 {
717  // Iterate over the visible children. If one of them has an already
718  // created accessible object that matches pCurrentChild then replace
719  // it. Otherwise the child to replace is either not in the list or has
720  // not ye been created (and is therefore not in the list, too) and a
721  // replacement is not necessary.
722  auto I = std::find_if(maVisibleChildren.begin(), maVisibleChildren.end(),
723  [&pCurrentChild](const ChildDescriptor& rChild) { return rChild.GetAccessibleShape() == pCurrentChild; });
724 
725  if (I != maVisibleChildren.end())
726  {
727  // Dispose the current child and send an event about its deletion.
728  pCurrentChild->dispose();
730  AccessibleEventId::CHILD,
731  uno::Any(),
732  uno::makeAny (I->mxAccessibleShape));
733 
734  // Replace with replacement and send an event about existence
735  // of the new child.
736  AccessibleShapeInfo aShapeInfo( _rxShape, pCurrentChild->getAccessibleParent(), this );
737  // create the new child
738  rtl::Reference<AccessibleShape> pNewChild(ShapeTypeHandler::Instance().CreateAccessibleObject (
739  aShapeInfo,
740  _rShapeTreeInfo
741  ));
742  if ( pNewChild.is() )
743  pNewChild->Init();
744 
745  I->mxAccessibleShape = pNewChild.get();
747  AccessibleEventId::CHILD,
748  uno::makeAny (I->mxAccessibleShape),
749  uno::Any());
750 
751  return true;
752  }
753 
754  // When not found among the visible children we have to search the list
755  // of accessible shapes. This is not yet implemented.
756  return false;
757 }
758 
759 // Add the impl method for IAccessibleParent interface
761 {
762  sal_Int32 count = GetChildCount();
763  for (sal_Int32 index=0;index<count;index++)
764  {
765  AccessibleShape* pAccShape = maVisibleChildren[index].GetAccessibleShape();
766  if (pAccShape && ::accessibility::ShapeTypeHandler::Instance().GetTypeId(pAccShape->GetXShape()) == DRAWING_CONTROL)
767  {
768  auto* pCtlAccShape = static_cast<::accessibility::AccessibleControlShape*>(pAccShape);
769  if (pCtlAccShape->GetControlModel() == pSet)
770  return pCtlAccShape;
771  }
772  }
773  return nullptr;
774 }
775 uno::Reference<XAccessible>
776  ChildrenManagerImpl::GetAccessibleCaption (const uno::Reference<drawing::XShape>& xShape)
777 {
778  auto I = std::find_if(maVisibleChildren.begin(), maVisibleChildren.end(),
779  [&xShape](const ChildDescriptor& rChild) { return rChild.mxShape.get() == xShape.get(); });
780  if (I != maVisibleChildren.end())
781  return I->mxAccessibleShape;
782  return uno::Reference<XAccessible> ();
783 }
784 
796 {
797  Reference<frame::XController> xController(maShapeTreeInfo.GetController());
798  Reference<view::XSelectionSupplier> xSelectionSupplier (
799  xController, uno::UNO_QUERY);
800 
801  // Try to cast the selection both to a multi selection and to a single
802  // selection.
803  Reference<container::XIndexAccess> xSelectedShapeAccess;
804  Reference<drawing::XShape> xSelectedShape;
805  if (xSelectionSupplier.is())
806  {
807  xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
808  xSelectedShape.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
809  }
810 
811  // Remember the current and new focused shape.
812  AccessibleShape* pCurrentlyFocusedShape = nullptr;
813  AccessibleShape* pNewFocusedShape = nullptr;
814  typedef std::pair< AccessibleShape* , sal_Bool > PAIR_SHAPE;//sal_Bool Selected,UnSelected.
815  typedef std::vector< PAIR_SHAPE > VEC_SHAPE;
816  VEC_SHAPE vecSelect;
817  int nAddSelect=0;
818  bool bHasSelectedShape=false;
819  for (const auto& rChild : maVisibleChildren)
820  {
821  AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
822  if (rChild.mxAccessibleShape.is() && rChild.mxShape.is() && pAccessibleShape!=nullptr)
823  {
824  short nRole = pAccessibleShape->getAccessibleRole();
825  bool bDrawShape = (
826  nRole == AccessibleRole::GRAPHIC ||
827  nRole == AccessibleRole::EMBEDDED_OBJECT ||
828  nRole == AccessibleRole::SHAPE ||
829  nRole == AccessibleRole::IMAGE_MAP ||
830  nRole == AccessibleRole::TABLE_CELL ||
831  nRole == AccessibleRole::TABLE );
832  bool bShapeIsSelected = false;
833 
834  // Look up the shape in the (single or multi-) selection.
835  if (xSelectedShape.is())
836  {
837  if (rChild.mxShape == xSelectedShape)
838  {
839  bShapeIsSelected = true;
840  pNewFocusedShape = pAccessibleShape;
841  }
842  }
843  else if (xSelectedShapeAccess.is())
844  {
845  sal_Int32 nCount=xSelectedShapeAccess->getCount();
846  for (sal_Int32 i=0; i<nCount&&!bShapeIsSelected; i++)
847  if (xSelectedShapeAccess->getByIndex(i) == rChild.mxShape)
848  {
849  bShapeIsSelected = true;
850  // In a multi-selection no shape has the focus.
851  if (nCount == 1)
852  pNewFocusedShape = pAccessibleShape;
853  }
854  }
855 
856  // Set or reset the SELECTED state.
857  if (bShapeIsSelected)
858  {
859  if (pAccessibleShape->SetState (AccessibleStateType::SELECTED))
860  {
861  if (bDrawShape)
862  {
863  vecSelect.emplace_back(pAccessibleShape,true);
864  ++nAddSelect;
865  }
866  }
867  else
868  {//Selected not change,has selected shape before
869  bHasSelectedShape=true;
870  }
871  }
872  else
873  //pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
874  {
875  if(pAccessibleShape->ResetState (AccessibleStateType::SELECTED))
876  {
877  if(bDrawShape)
878  {
879  vecSelect.emplace_back(pAccessibleShape,false);
880  }
881  }
882  }
883  // Does the shape have the current selection?
884  if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
885  pCurrentlyFocusedShape = pAccessibleShape;
886  }
887  }
888 
889  vcl::Window *pParentWindow = maShapeTreeInfo.GetWindow();
890  bool bShapeActive= false;
891  // For table cell, the table's parent must be checked to make sure it has focus.
892  if (pParentWindow)
893  {
894  vcl::Window *pPWindow = pParentWindow->GetParent();
895  if (pParentWindow->HasFocus() || (pPWindow && pPWindow->HasFocus()))
896  bShapeActive =true;
897  }
898  // Move focus from current to newly focused shape.
899  if (pCurrentlyFocusedShape != pNewFocusedShape)
900  {
901  if (pCurrentlyFocusedShape != nullptr)
902  pCurrentlyFocusedShape->ResetState (AccessibleStateType::FOCUSED);
903  if (pNewFocusedShape != nullptr && bShapeActive)
904  pNewFocusedShape->SetState (AccessibleStateType::FOCUSED);
905  }
906 
907  if (nAddSelect >= 10 )//fire selection within
908  {
909  mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN,uno::Any(),uno::Any());
910  nAddSelect =0 ;//not fire selection event
911  }
912  for (VEC_SHAPE::reverse_iterator vi = vecSelect.rbegin(), aEndVecSelect = vecSelect.rend(); vi != aEndVecSelect ;++vi)
913  {
914  PAIR_SHAPE &pairShape= *vi;
915  Reference< XAccessible > xShape(pairShape.first);
916  uno::Any anyShape;
917  anyShape <<= xShape;
918 
919  if (pairShape.second)//Selection add
920  {
921  if (bHasSelectedShape)
922  {
923  if ( nAddSelect > 0 )
924  {
925  mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD,anyShape,uno::Any());
926  }
927  }
928  else
929  {
930  //if has not selected shape ,first selected shape is fire selection event;
931  if (nAddSelect > 0 )
932  {
933  mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED,anyShape,uno::Any());
934  }
935  if (nAddSelect > 1 )//check other selected shape fire selection add event
936  {
937  bHasSelectedShape=true;
938  }
939  }
940  }
941  else //selection remove
942  {
943  mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE,anyShape,uno::Any());
944  }
945  }
946 
947  // Remember whether there is a shape that now has the focus.
948  mpFocusedShape = pNewFocusedShape;
949 }
950 
951 
953 {
954  return mpFocusedShape != nullptr;
955 }
956 
957 
959 {
960  if (mpFocusedShape != nullptr)
961  {
962  mpFocusedShape->ResetState (AccessibleStateType::FOCUSED);
963  mpFocusedShape = nullptr;
964  }
965 }
966 
967 
969  const Reference<drawing::XShape>& xShape)
970 {
971  Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
972  if (xComponent.is())
973  xComponent->addEventListener (
974  static_cast<document::XEventListener*>(this));
975 }
976 
977 
979  const Reference<drawing::XShape>& xShape)
980 {
981  Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
982  if (xComponent.is())
983  xComponent->removeEventListener (
984  static_cast<document::XEventListener*>(this));
985 }
986 
987 // AccessibleChildDescriptor
988 ChildDescriptor::ChildDescriptor (const Reference<drawing::XShape>& xShape)
989  : mxShape (xShape),
990  mbCreateEventPending (true)
991 {
992  // Empty.
993 }
994 
995 
996 ChildDescriptor::ChildDescriptor (const Reference<XAccessible>& rxAccessibleShape)
997  : mxAccessibleShape (rxAccessibleShape),
998  mbCreateEventPending (true)
999 {
1000  // Make sure that the accessible object has the <const>VISIBLE</const>
1001  // state set.
1002  AccessibleShape* pAccessibleShape = GetAccessibleShape();
1003  pAccessibleShape->SetState (AccessibleStateType::VISIBLE);
1004 }
1005 
1007 {
1008  return static_cast<AccessibleShape*> (mxAccessibleShape.get());
1009 }
1010 
1012 {
1013  AccessibleShape* pShape = GetAccessibleShape();
1014  if ( pShape )
1015  pShape->setIndexInParent(_nIndex);
1016 }
1017 
1018 
1020 {
1021  if (!mxAccessibleShape.is())
1022  return;
1023 
1024  // Send event that the shape has been removed.
1025  uno::Any aOldValue;
1026  aOldValue <<= mxAccessibleShape;
1027  rParent.CommitChange (
1028  AccessibleEventId::CHILD,
1029  uno::Any(),
1030  aOldValue);
1031 
1032  // Dispose and remove the object.
1033  Reference<lang::XComponent> xComponent (mxAccessibleShape, uno::UNO_QUERY);
1034  if (xComponent.is())
1035  xComponent->dispose ();
1036 
1037  mxAccessibleShape = nullptr;
1038 }
1039 
1040 
1041 } // end of namespace accessibility
1042 
1043 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
A child descriptor holds a reference to a UNO shape and the corresponding accessible object...
void CreateAccessibilityObjects(ChildDescriptorListType &raChildList)
If children have to be created immediately and not on demand the create the missing accessible object...
const size_t count(pCandidateA->getBorderLines().size())
css::uno::Reference< css::drawing::XShape > GetChildShape(long nIndex)
void RemoveFocus()
When there is a shape that currently has the focus, i.e.
AccessibleContextBase & mrContext
Reference to an accessible context object that is used to inform its listeners of new and removed chi...
virtual void ViewForwarderChanged() override
Informs this children manager and its children about a change of one (or more) aspect of the view for...
vcl::Window * GetWindow() const
Return the current Window.
css::uno::Reference< css::accessibility::XAccessible > mxParent
The parent of the shapes.
ChildDescriptorListType maVisibleChildren
This list holds the descriptors of all currently visible shapes and associated accessible object...
void RegisterAsDisposeListener(const css::uno::Reference< css::drawing::XShape > &xShape)
Add the children manager as dispose listener at the given shape so that the associated accessible obj...
tools::Rectangle maVisibleArea
Rectangle that describes the visible area in which a shape has to lie at least partly, to be accessible through this class.
WeakReference< XInterface > mxParent
const css::uno::Reference< css::drawing::XShape > & GetXShape() const
virtual AccessibleControlShape * GetAccControlShapeFromModel(css::beans::XPropertySet *pSet) override
void disposeAccessibleObject(AccessibleContextBase &rParent)
Dispose the accessible object of this descriptor.
css::uno::Reference< css::drawing::XShapes > mxShapeList
The original list of UNO shapes.
bool IsOver(const tools::Rectangle &rRect) const
void MergeAccessibilityInformation(ChildDescriptorListType &raChildList)
Merge the information that is already known about the visible shapes from the current list into the n...
static void SendVisibleAreaEvents(ChildDescriptorListType &raChildList)
If the visible area has changed then send events that signal a change of their bounding boxes for all...
ChildDescriptor(const css::uno::Reference< css::drawing::XShape > &xShape)
Create a new descriptor for the specified shape with empty reference to accessible object...
void CommitChange(sal_Int16 aEventId, const css::uno::Any &rNewValue, const css::uno::Any &rOldValue)
bool GetState(sal_Int16 aState)
Return the state of the specified state.
uno::Reference< drawing::XShape > const mxShape
void Init()
Do that part of the initialization that you can not or should not do in the constructor like register...
void UnregisterAsDisposeListener(const css::uno::Reference< css::drawing::XShape > &xShape)
Remove the children manager as dispose listener at the given shape.
Reference< XController > xController
AccessibleShape * GetAccessibleShape() const
Return a pointer to the implementation object of the accessible shape of this descriptor.
virtual tools::Rectangle GetVisibleArea() const =0
Returns the area of the underlying document that is visible in the corresponding window.
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
void SetModelBroadcaster(const css::uno::Reference< css::document::XShapeEventBroadcaster > &rxModelBroadcaster)
Set a new broadcaster that sends events indicating shape changes.
int nCount
void SetController(const css::uno::Reference< css::frame::XController > &rxController)
Set a new controller.
void UpdateSelection()
Update the SELECTED and FOCUSED states of all visible children according to the given selection...
virtual sal_Int16 SAL_CALL getAccessibleRole() override
Return this object's role.
void RemoveShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Remove a single shape.
::osl::Mutex maMutex
css::uno::Reference< css::drawing::XShape > mxShape
Reference to a (partially) visible shape.
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override
virtual bool ReplaceChild(AccessibleShape *pCurrentChild, const css::uno::Reference< css::drawing::XShape > &_rxShape, const long _nIndex, const AccessibleShapeTreeInfo &_rShapeTreeInfo) override
Replace the specified child with a replacement.
void SetTop(long v)
ChildrenManagerImpl(const css::uno::Reference< css::accessibility::XAccessible > &rxParent, const css::uno::Reference< css::drawing::XShapes > &rxShapeList, const AccessibleShapeTreeInfo &rShapeTreeInfo, AccessibleContextBase &rContext)
Create a children manager, which manages the children of the given parent.
#define DBG_ASSERT(sCon, aError)
int i
void SetInfo(const AccessibleShapeTreeInfo &rShapeTreeInfo)
Set a new event shape tree info.
class SAL_NO_VTABLE XPropertySet
Definition: xmlexchg.hxx:28
exports com.sun.star. view
AccessibleShapeTreeInfo maShapeTreeInfo
Bundle of information passed down the shape tree.
void SetRight(long v)
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
static ShapeTypeHandler & Instance()
This function returns a reference to the only instance of this class.
virtual void SAL_CALL notifyEvent(const css::document::EventObject &rEventObject) override
Listen for new and removed shapes.
bool HasFocus() const
Return whether one of the shapes managed by this object has currently the focus.
tuple index
css::uno::Reference< css::accessibility::XAccessible > GetChild(long nIndex)
Return the requested accessible child or throw and IndexOutOfBoundsException if the given index is in...
vcl::Window * GetParent() const
void ClearAccessibleShapeList()
Clear the lists of accessible shapes and that of visible accessible shapes.
const NodeContext & mrContext
virtual ~ChildrenManagerImpl() override
If there still are managed children these are disposed and released.
::std::vector< ChildDescriptor > ChildDescriptorListType
This base class provides a base implementation for all shapes.
long GetChildCount() const
Return the number of currently visible accessible children.
void AddAccessibleShape(css::uno::Reference< css::accessibility::XAccessible > const &shape)
Add an accessible shape.
std::vector< css::uno::Reference< css::accessibility::XAccessible > > AccessibleShapeList
This list of additional accessible shapes that can or shall not be created by the shape factory...
AccessibleShape * mpFocusedShape
This member points to the currently focused shape.
void SetShapeList(const css::uno::Reference< css::drawing::XShapes > &xShapeList)
Set the list of UNO shapes to the given list.
const css::uno::Reference< css::document::XShapeEventBroadcaster > & GetModelBroadcaster() const
Return the current model broadcaster.
exports com.sun.star. document
virtual void ViewForwarderChanged() override
This method is called to indicate a change of the specified view forwarder, specifically, a change in visible area.
void SetBottom(long v)
void RemoveNonVisibleChildren(const ChildDescriptorListType &raNewChildList, ChildDescriptorListType &raOldChildList)
From the old list of (former) visible shapes remove those that are not member of the new list...
const IAccessibleViewForwarder * GetViewForwarder() const
Return the current view forwarder.
css::uno::Reference< css::accessibility::XAccessible > mxAccessibleShape
The corresponding accessible object.
virtual void SAL_CALL selectionChanged(const css::lang::EventObject &rEvent) override
virtual bool ResetState(sal_Int16 aState) override
Reset the specified state.
void Update(bool bCreateNewObjectsOnDemand)
Update the child manager.
void setIndexAtAccessibleShape(sal_Int32 _nIndex)
set the index _nIndex at the accessible shape
virtual bool SetState(sal_Int16 aState) override
Set the specified state.
void SetLeft(long v)
This class is a container for the information specific for a single shape that is passed to the const...
void setIndexInParent(sal_Int32 _nIndex)
set the index _nIndex at the accessible shape
void AddShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Add a single shape.
virtual void SAL_CALL disposing() override
This method is called from the component helper base class while disposing.
bool HasFocus() const
void CreateListOfVisibleShapes(ChildDescriptorListType &raChildList)
Three helper functions for the Update method.
virtual css::uno::Reference< css::accessibility::XAccessible > GetAccessibleCaption(const css::uno::Reference< css::drawing::XShape > &xShape) override
This class bundles all information that is passed down the tree of accessible shapes so that each sha...
sal_uInt16 nPos
const css::uno::Reference< css::frame::XController > & GetController() const
Return the currently set controller.