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(tools::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() || !mxShapeList->hasElements())
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 
325  const ChildDescriptorListType& rNewChildList,
326  ChildDescriptorListType& rOldChildList)
327 {
328  // Iterate over list of formerly visible children and remove those that
329  // are not visible anymore, i.e. member of the new list of visible
330  // children.
331  for (auto& rChild : rOldChildList)
332  {
333  if (::std::find(rNewChildList.begin(), rNewChildList.end(), rChild) == rNewChildList.end())
334  {
335  // The child is disposed when there is a UNO shape from which
336  // the accessible shape can be created when the shape becomes
337  // visible again. When there is no such UNO shape then simply
338  // reset the descriptor but keep the accessibility object.
339  if (rChild.mxShape.is())
340  {
341  UnregisterAsDisposeListener (rChild.mxShape);
342  rChild.disposeAccessibleObject (mrContext);
343  }
344  else
345  {
346  AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
347  pAccessibleShape->ResetState (AccessibleStateType::VISIBLE);
348  rChild.mxAccessibleShape = nullptr;
349  }
350  }
351  }
352 }
353 
355  ChildDescriptorListType& raNewChildList)
356 {
357  ChildDescriptorListType::const_iterator aStartVisibleChildren = maVisibleChildren.begin();
358  ChildDescriptorListType::const_iterator aEndVisibleChildren = maVisibleChildren.end();
359 
360  for (auto& rChild : raNewChildList)
361  {
362  ChildDescriptorListType::const_iterator aOldChildDescriptor =
363  std::find(aStartVisibleChildren, aEndVisibleChildren, rChild);
364 
365  // Copy accessible shape if that exists in the old descriptor.
366  if (aOldChildDescriptor != aEndVisibleChildren &&
367  aOldChildDescriptor->mxAccessibleShape.is())
368  {
369  rChild.mxAccessibleShape = aOldChildDescriptor->mxAccessibleShape;
370  rChild.mbCreateEventPending = false;
371  }
372  else
373  RegisterAsDisposeListener (rChild.mxShape);
374  }
375 }
376 
378  ChildDescriptorListType& raNewChildList)
379 {
380  for (const auto& rChild : raNewChildList)
381  {
382  // Tell shape of changed visible area. To do this, fake a
383  // change of the view forwarder. (Actually we usually get here
384  // as a result of a change of the view forwarder).
385  AccessibleShape* pShape = rChild.GetAccessibleShape ();
386  if (pShape != nullptr)
387  pShape->ViewForwarderChanged();
388  }
389 }
390 
391 
393  ChildDescriptorListType& raNewChildList)
394 {
395  sal_Int32 nPos = 0;
396  for ( auto& rChild : raNewChildList)
397  {
398  // Create the associated accessible object when the flag says so and
399  // it does not yet exist.
400  if ( ! rChild.mxAccessibleShape.is() )
401  GetChild (rChild, nPos);
402  if (rChild.mxAccessibleShape.is() && rChild.mbCreateEventPending)
403  {
404  rChild.mbCreateEventPending = false;
406  AccessibleEventId::CHILD,
407  uno::makeAny(rChild.mxAccessibleShape),
408  uno::Any());
409  }
410  ++nPos;
411  }
412 }
413 
414 
415 void ChildrenManagerImpl::AddShape (const Reference<drawing::XShape>& rxShape)
416 {
417  if (!rxShape.is())
418  return;
419 
421 
422  // Test visibility of the shape.
424  awt::Point aPos = rxShape->getPosition();
425  awt::Size aSize = rxShape->getSize();
426 
427  tools::Rectangle aBoundingBox (
428  aPos.X,
429  aPos.Y,
430  aPos.X + aSize.Width,
431  aPos.Y + aSize.Height);
432 
433  // Add the shape only when it belongs to the list of shapes stored
434  // in mxShapeList (which is either a page or a group shape).
435  Reference<container::XChild> xChild (rxShape, uno::UNO_QUERY);
436  if (!xChild.is())
437  return;
438 
439  Reference<drawing::XShapes> xParent (xChild->getParent(), uno::UNO_QUERY);
440  if (xParent != mxShapeList)
441  return;
442 
443  if (!aBoundingBox.IsOver (aVisibleArea))
444  return;
445 
446  // Add shape to list of visible shapes.
447  maVisibleChildren.emplace_back(rxShape);
448 
449  // Create accessibility object.
450  ChildDescriptor& rDescriptor = maVisibleChildren.back();
451  GetChild (rDescriptor, maVisibleChildren.size()-1);
452 
453  // Inform listeners about new child.
454  uno::Any aNewShape;
455  aNewShape <<= rDescriptor.mxAccessibleShape;
456  aGuard.clear();
458  AccessibleEventId::CHILD,
459  aNewShape,
460  uno::Any());
461  RegisterAsDisposeListener(rxShape);
462 }
463 
464 
465 void ChildrenManagerImpl::RemoveShape (const Reference<drawing::XShape>& rxShape)
466 {
467  if (!rxShape.is())
468  return;
469 
470  SolarMutexGuard g;
471 
472  // Search shape in list of visible children.
473  ChildDescriptorListType::iterator I (
474  ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
475  ChildDescriptor (rxShape)));
476  if (I == maVisibleChildren.end())
477  return;
478 
479  // Remove descriptor from that list.
480  Reference<XAccessible> xHoldAlive(I->mxAccessibleShape);
481 
482  UnregisterAsDisposeListener (I->mxShape);
483  // Dispose the accessible object.
484  I->disposeAccessibleObject (mrContext);
485 
486  // Now we can safely remove the child descriptor and thus
487  // invalidate the iterator.
488  maVisibleChildren.erase (I);
489 
490  adjustIndexInParentOfShapes(maVisibleChildren);
491 }
492 
493 
494 void ChildrenManagerImpl::SetShapeList (const css::uno::Reference<css::drawing::XShapes>& xShapeList)
495 {
496  mxShapeList = xShapeList;
497 }
498 
499 
500 void ChildrenManagerImpl::AddAccessibleShape (css::uno::Reference<css::accessibility::XAccessible> const & shape)
501 {
502  assert(shape.is());
503  maAccessibleShapes.push_back (shape);
504 }
505 
506 
508 {
509  // Copy the list of (visible) shapes to local lists and clear the
510  // originals.
511  ChildDescriptorListType aLocalVisibleChildren;
512  aLocalVisibleChildren.swap(maVisibleChildren);
513  AccessibleShapeList aLocalAccessibleShapes;
514  aLocalAccessibleShapes.swap(maAccessibleShapes);
515 
516  // Tell the listeners that all children are gone.
518  AccessibleEventId::INVALIDATE_ALL_CHILDREN,
519  uno::Any(),
520  uno::Any());
521 
522  // Now the objects in the local lists can be safely disposed without
523  // having problems with callers that want to update their child lists.
524 
525  // Clear the list of visible accessible objects. Objects not created on
526  // demand for XShapes are treated below.
527  for (auto& rChild : aLocalVisibleChildren)
528  if ( rChild.mxAccessibleShape.is() && rChild.mxShape.is() )
529  {
530  ::comphelper::disposeComponent(rChild.mxAccessibleShape);
531  rChild.mxAccessibleShape = nullptr;
532  }
533 
534  // Dispose all objects in the accessible shape list.
535  for (auto& rpShape : aLocalAccessibleShapes)
536  if (rpShape.is())
537  {
538  // Dispose the object.
539  ::comphelper::disposeComponent(rpShape);
540  rpShape = nullptr;
541  }
542 }
543 
544 
549 {
550  // Remember the current broadcasters and exchange the shape tree info.
551  Reference<document::XEventBroadcaster> xCurrentBroadcaster;
552  Reference<frame::XController> xCurrentController;
553  Reference<view::XSelectionSupplier> xCurrentSelectionSupplier;
554  {
555  SolarMutexGuard g;
556  xCurrentBroadcaster = maShapeTreeInfo.GetModelBroadcaster();
557  xCurrentController = maShapeTreeInfo.GetController();
558  xCurrentSelectionSupplier.set( xCurrentController, uno::UNO_QUERY);
559  maShapeTreeInfo = rShapeTreeInfo;
560  }
561 
562  // Move registration to new model.
563  if (maShapeTreeInfo.GetModelBroadcaster() != xCurrentBroadcaster)
564  {
565  // Register at new broadcaster.
567  maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
568  static_cast<document::XEventListener*>(this));
569 
570  // Unregister at old broadcaster.
571  if (xCurrentBroadcaster.is())
572  xCurrentBroadcaster->removeEventListener (
573  static_cast<document::XEventListener*>(this));
574  }
575 
576  // Move registration to new selection supplier.
577  Reference<frame::XController> xNewController(maShapeTreeInfo.GetController());
578  Reference<view::XSelectionSupplier> xNewSelectionSupplier (
579  xNewController, uno::UNO_QUERY);
580  if (xNewSelectionSupplier == xCurrentSelectionSupplier)
581  return;
582 
583  // Register at new broadcaster.
584  if (xNewSelectionSupplier.is())
585  {
586  xNewController->addEventListener(
587  static_cast<document::XEventListener*>(this));
588 
589  xNewSelectionSupplier->addSelectionChangeListener (
590  static_cast<view::XSelectionChangeListener*>(this));
591  }
592 
593  // Unregister at old broadcaster.
594  if (xCurrentSelectionSupplier.is())
595  {
596  xCurrentSelectionSupplier->removeSelectionChangeListener (
597  static_cast<view::XSelectionChangeListener*>(this));
598 
599  xCurrentController->removeEventListener(
600  static_cast<document::XEventListener*>(this));
601  }
602 }
603 
604 // lang::XEventListener
605 void SAL_CALL
606  ChildrenManagerImpl::disposing (const lang::EventObject& rEventObject)
607 {
608  if (rEventObject.Source == maShapeTreeInfo.GetModelBroadcaster()
609  || rEventObject.Source == maShapeTreeInfo.GetController())
610  {
611  impl_dispose();
612  }
613 
614  // Handle disposing UNO shapes.
615  else
616  {
617  Reference<drawing::XShape> xShape (rEventObject.Source, uno::UNO_QUERY);
618 
619  // Find the descriptor for the given shape.
620  ChildDescriptorListType::iterator I (
621  ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
622  ChildDescriptor (xShape)));
623  if (I != maVisibleChildren.end())
624  {
625  // Clear the descriptor.
626  I->disposeAccessibleObject (mrContext);
627  I->mxShape = nullptr;
628  }
629  }
630 }
631 
632 // document::XEventListener
635 void SAL_CALL
637  const document::EventObject& rEventObject)
638 {
639  if (rEventObject.EventName == "ShapeInserted")
640  AddShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
641  else if (rEventObject.EventName == "ShapeRemoved")
642  RemoveShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
643  // else ignore unknown event.
644 }
645 
646 // view::XSelectionChangeListener
647 void SAL_CALL
648  ChildrenManagerImpl::selectionChanged (const lang::EventObject& /*rEvent*/)
649 {
650  UpdateSelection ();
651 }
652 
653 
655 {
656  Reference<frame::XController> xController(maShapeTreeInfo.GetController());
657  // Remove from broadcasters.
658  try
659  {
660  Reference<view::XSelectionSupplier> xSelectionSupplier (
661  xController, uno::UNO_QUERY);
662  if (xSelectionSupplier.is())
663  {
664  xSelectionSupplier->removeSelectionChangeListener (
665  static_cast<view::XSelectionChangeListener*>(this));
666  }
667  }
668  catch( uno::RuntimeException&)
669  {}
670 
671  try
672  {
673  if (xController.is())
674  xController->removeEventListener(
675  static_cast<document::XEventListener*>(this));
676  }
677  catch( uno::RuntimeException&)
678  {}
679 
680  maShapeTreeInfo.SetController (nullptr);
681 
682  try
683  {
684  // Remove from broadcaster.
686  maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
687  static_cast<document::XEventListener*>(this));
689  }
690  catch( uno::RuntimeException& )
691  {}
692 
694  SetShapeList (nullptr);
695 }
696 
697 
699 {
700  impl_dispose();
701 }
702 
703 // IAccessibleViewForwarderListener
705 {
706  Update(false);
707 }
708 
709 // IAccessibleParent
711  AccessibleShape* pCurrentChild,
712  const css::uno::Reference< css::drawing::XShape >& _rxShape,
713  const tools::Long /*_nIndex*/,
714  const AccessibleShapeTreeInfo& _rShapeTreeInfo)
715 {
716  // Iterate over the visible children. If one of them has an already
717  // created accessible object that matches pCurrentChild then replace
718  // it. Otherwise the child to replace is either not in the list or has
719  // not ye been created (and is therefore not in the list, too) and a
720  // replacement is not necessary.
721  auto I = std::find_if(maVisibleChildren.begin(), maVisibleChildren.end(),
722  [&pCurrentChild](const ChildDescriptor& rChild) { return rChild.GetAccessibleShape() == pCurrentChild; });
723 
724  if (I != maVisibleChildren.end())
725  {
726  // Dispose the current child and send an event about its deletion.
727  pCurrentChild->dispose();
729  AccessibleEventId::CHILD,
730  uno::Any(),
731  uno::makeAny (I->mxAccessibleShape));
732 
733  // Replace with replacement and send an event about existence
734  // of the new child.
735  AccessibleShapeInfo aShapeInfo( _rxShape, pCurrentChild->getAccessibleParent(), this );
736  // create the new child
737  rtl::Reference<AccessibleShape> pNewChild(ShapeTypeHandler::Instance().CreateAccessibleObject (
738  aShapeInfo,
739  _rShapeTreeInfo
740  ));
741  if ( pNewChild.is() )
742  pNewChild->Init();
743 
744  I->mxAccessibleShape = pNewChild.get();
746  AccessibleEventId::CHILD,
747  uno::makeAny (I->mxAccessibleShape),
748  uno::Any());
749 
750  return true;
751  }
752 
753  // When not found among the visible children we have to search the list
754  // of accessible shapes. This is not yet implemented.
755  return false;
756 }
757 
758 // Add the impl method for IAccessibleParent interface
760 {
761  sal_Int32 count = GetChildCount();
762  for (sal_Int32 index=0;index<count;index++)
763  {
764  AccessibleShape* pAccShape = maVisibleChildren[index].GetAccessibleShape();
765  if (pAccShape && ::accessibility::ShapeTypeHandler::Instance().GetTypeId(pAccShape->GetXShape()) == DRAWING_CONTROL)
766  {
767  auto* pCtlAccShape = static_cast<::accessibility::AccessibleControlShape*>(pAccShape);
768  if (pCtlAccShape->GetControlModel() == pSet)
769  return pCtlAccShape;
770  }
771  }
772  return nullptr;
773 }
774 uno::Reference<XAccessible>
775  ChildrenManagerImpl::GetAccessibleCaption (const uno::Reference<drawing::XShape>& xShape)
776 {
777  auto I = std::find_if(maVisibleChildren.begin(), maVisibleChildren.end(),
778  [&xShape](const ChildDescriptor& rChild) { return rChild.mxShape.get() == xShape.get(); });
779  if (I != maVisibleChildren.end())
780  return I->mxAccessibleShape;
781  return uno::Reference<XAccessible> ();
782 }
783 
795 {
796  Reference<frame::XController> xController(maShapeTreeInfo.GetController());
797  Reference<view::XSelectionSupplier> xSelectionSupplier (
798  xController, uno::UNO_QUERY);
799 
800  // Try to cast the selection both to a multi selection and to a single
801  // selection.
802  Reference<container::XIndexAccess> xSelectedShapeAccess;
803  Reference<drawing::XShape> xSelectedShape;
804  if (xSelectionSupplier.is())
805  {
806  xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
807  xSelectedShape.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
808  }
809 
810  // Remember the current and new focused shape.
811  AccessibleShape* pCurrentlyFocusedShape = nullptr;
812  AccessibleShape* pNewFocusedShape = nullptr;
813  typedef std::pair< AccessibleShape* , sal_Bool > PAIR_SHAPE;//sal_Bool Selected,UnSelected.
814  typedef std::vector< PAIR_SHAPE > VEC_SHAPE;
815  VEC_SHAPE vecSelect;
816  int nAddSelect=0;
817  bool bHasSelectedShape=false;
818  for (const auto& rChild : maVisibleChildren)
819  {
820  AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
821  if (rChild.mxAccessibleShape.is() && rChild.mxShape.is() && pAccessibleShape!=nullptr)
822  {
823  short nRole = pAccessibleShape->getAccessibleRole();
824  bool bDrawShape = (
825  nRole == AccessibleRole::GRAPHIC ||
826  nRole == AccessibleRole::EMBEDDED_OBJECT ||
827  nRole == AccessibleRole::SHAPE ||
828  nRole == AccessibleRole::IMAGE_MAP ||
829  nRole == AccessibleRole::TABLE_CELL ||
830  nRole == AccessibleRole::TABLE );
831  bool bShapeIsSelected = false;
832 
833  // Look up the shape in the (single or multi-) selection.
834  if (xSelectedShape.is())
835  {
836  if (rChild.mxShape == xSelectedShape)
837  {
838  bShapeIsSelected = true;
839  pNewFocusedShape = pAccessibleShape;
840  }
841  }
842  else if (xSelectedShapeAccess.is())
843  {
844  sal_Int32 nCount=xSelectedShapeAccess->getCount();
845  for (sal_Int32 i=0; i<nCount&&!bShapeIsSelected; i++)
846  if (xSelectedShapeAccess->getByIndex(i) == rChild.mxShape)
847  {
848  bShapeIsSelected = true;
849  // In a multi-selection no shape has the focus.
850  if (nCount == 1)
851  pNewFocusedShape = pAccessibleShape;
852  }
853  }
854 
855  // Set or reset the SELECTED state.
856  if (bShapeIsSelected)
857  {
858  if (pAccessibleShape->SetState (AccessibleStateType::SELECTED))
859  {
860  if (bDrawShape)
861  {
862  vecSelect.emplace_back(pAccessibleShape,true);
863  ++nAddSelect;
864  }
865  }
866  else
867  {//Selected not change,has selected shape before
868  bHasSelectedShape=true;
869  }
870  }
871  else
872  //pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
873  {
874  if(pAccessibleShape->ResetState (AccessibleStateType::SELECTED))
875  {
876  if(bDrawShape)
877  {
878  vecSelect.emplace_back(pAccessibleShape,false);
879  }
880  }
881  }
882  // Does the shape have the current selection?
883  if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
884  pCurrentlyFocusedShape = pAccessibleShape;
885  }
886  }
887 
888  vcl::Window *pParentWindow = maShapeTreeInfo.GetWindow();
889  bool bShapeActive= false;
890  // For table cell, the table's parent must be checked to make sure it has focus.
891  if (pParentWindow)
892  {
893  vcl::Window *pPWindow = pParentWindow->GetParent();
894  if (pParentWindow->HasFocus() || (pPWindow && pPWindow->HasFocus()))
895  bShapeActive =true;
896  }
897  // Move focus from current to newly focused shape.
898  if (pCurrentlyFocusedShape != pNewFocusedShape)
899  {
900  if (pCurrentlyFocusedShape != nullptr)
901  pCurrentlyFocusedShape->ResetState (AccessibleStateType::FOCUSED);
902  if (pNewFocusedShape != nullptr && bShapeActive)
903  pNewFocusedShape->SetState (AccessibleStateType::FOCUSED);
904  }
905 
906  if (nAddSelect >= 10 )//fire selection within
907  {
908  mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN,uno::Any(),uno::Any());
909  nAddSelect =0 ;//not fire selection event
910  }
911  for (VEC_SHAPE::reverse_iterator vi = vecSelect.rbegin(), aEndVecSelect = vecSelect.rend(); vi != aEndVecSelect ;++vi)
912  {
913  PAIR_SHAPE &pairShape= *vi;
914  Reference< XAccessible > xShape(pairShape.first);
915  uno::Any anyShape;
916  anyShape <<= xShape;
917 
918  if (pairShape.second)//Selection add
919  {
920  if (bHasSelectedShape)
921  {
922  if ( nAddSelect > 0 )
923  {
924  mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD,anyShape,uno::Any());
925  }
926  }
927  else
928  {
929  //if has not selected shape ,first selected shape is fire selection event;
930  if (nAddSelect > 0 )
931  {
932  mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED,anyShape,uno::Any());
933  }
934  if (nAddSelect > 1 )//check other selected shape fire selection add event
935  {
936  bHasSelectedShape=true;
937  }
938  }
939  }
940  else //selection remove
941  {
942  mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE,anyShape,uno::Any());
943  }
944  }
945 
946  // Remember whether there is a shape that now has the focus.
947  mpFocusedShape = pNewFocusedShape;
948 }
949 
950 
952 {
953  return mpFocusedShape != nullptr;
954 }
955 
956 
958 {
959  if (mpFocusedShape != nullptr)
960  {
961  mpFocusedShape->ResetState (AccessibleStateType::FOCUSED);
962  mpFocusedShape = nullptr;
963  }
964 }
965 
966 
968  const Reference<drawing::XShape>& xShape)
969 {
970  Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
971  if (xComponent.is())
972  xComponent->addEventListener (
973  static_cast<document::XEventListener*>(this));
974 }
975 
976 
978  const Reference<drawing::XShape>& xShape)
979 {
980  Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
981  if (xComponent.is())
982  xComponent->removeEventListener (
983  static_cast<document::XEventListener*>(this));
984 }
985 
986 // AccessibleChildDescriptor
987 ChildDescriptor::ChildDescriptor (const Reference<drawing::XShape>& xShape)
988  : mxShape (xShape),
989  mbCreateEventPending (true)
990 {
991  // Empty.
992 }
993 
994 
995 ChildDescriptor::ChildDescriptor (const Reference<XAccessible>& rxAccessibleShape)
996  : mxAccessibleShape (rxAccessibleShape),
997  mbCreateEventPending (true)
998 {
999  // Make sure that the accessible object has the <const>VISIBLE</const>
1000  // state set.
1001  AccessibleShape* pAccessibleShape = GetAccessibleShape();
1002  pAccessibleShape->SetState (AccessibleStateType::VISIBLE);
1003 }
1004 
1006 {
1007  return static_cast<AccessibleShape*> (mxAccessibleShape.get());
1008 }
1009 
1011 {
1012  AccessibleShape* pShape = GetAccessibleShape();
1013  if ( pShape )
1014  pShape->setIndexInParent(_nIndex);
1015 }
1016 
1017 
1019 {
1020  if (!mxAccessibleShape.is())
1021  return;
1022 
1023  // Send event that the shape has been removed.
1024  uno::Any aOldValue;
1025  aOldValue <<= mxAccessibleShape;
1026  rParent.CommitChange (
1027  AccessibleEventId::CHILD,
1028  uno::Any(),
1029  aOldValue);
1030 
1031  // Dispose and remove the object.
1032  Reference<lang::XComponent> xComponent (mxAccessibleShape, uno::UNO_QUERY);
1033  if (xComponent.is())
1034  xComponent->dispose ();
1035 
1036  mxAccessibleShape = nullptr;
1037 }
1038 
1039 
1040 } // end of namespace accessibility
1041 
1042 /* 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())
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.
long Long
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.
void SetRight(tools::Long v)
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.
void SetLeft(tools::Long v)
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
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.
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.
tools::Long GetChildCount() const
Return the number of currently visible accessible children.
virtual void SAL_CALL notifyEvent(const css::document::EventObject &rEventObject) override
Listen for new and removed shapes.
void SetTop(tools::Long v)
void SetBottom(tools::Long v)
bool HasFocus() const
Return whether one of the shapes managed by this object has currently the focus.
tuple index
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.
css::uno::Reference< css::drawing::XShape > GetChildShape(tools::Long nIndex)
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 bool ReplaceChild(AccessibleShape *pCurrentChild, const css::uno::Reference< css::drawing::XShape > &_rxShape, const tools::Long _nIndex, const AccessibleShapeTreeInfo &_rShapeTreeInfo) override
Replace the specified child with a replacement.
virtual void ViewForwarderChanged() override
This method is called to indicate a change of the specified view forwarder, specifically, a change in visible area.
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.
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
css::uno::Reference< css::accessibility::XAccessible > GetChild(tools::Long nIndex)
Return the requested accessible child or throw and IndexOutOfBoundsException if the given index is in...
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.