32#include <com/sun/star/accessibility/AccessibleRole.hpp>
33#include <com/sun/star/accessibility/AccessibleStateType.hpp>
34#include <com/sun/star/accessibility/AccessibleEventId.hpp>
35#include <com/sun/star/beans/XPropertySet.hpp>
36#include <com/sun/star/document/XShapeEventBroadcaster.hpp>
37#include <com/sun/star/frame/XController.hpp>
38#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
39#include <com/sun/star/view/XSelectionSupplier.hpp>
40#include <com/sun/star/container/XChild.hpp>
43#include <rtl/ustring.hxx>
51using ::com::sun::star::uno::Reference;
60 for (
auto& rItem : _rList)
62 rItem.setIndexAtAccessibleShape(i);
70 uno::Reference<XAccessible> xParent,
71 uno::Reference<drawing::XShapes> xShapeList,
72 const AccessibleShapeTreeInfo& rShapeTreeInfo,
73 AccessibleContextBase& rContext)
74 : mxShapeList (
std::move(xShapeList)),
76 maShapeTreeInfo (rShapeTreeInfo),
78 mpFocusedShape(nullptr)
83ChildrenManagerImpl::~ChildrenManagerImpl()
89void ChildrenManagerImpl::Init()
92 Reference<frame::XController>
xController(maShapeTreeInfo.GetController());
93 Reference<view::XSelectionSupplier> xSelectionSupplier (
95 if (xSelectionSupplier.is())
98 static_cast<document::XEventListener*
>(
this));
100 xSelectionSupplier->addSelectionChangeListener (
101 static_cast<view::XSelectionChangeListener*
>(
this));
105 if (maShapeTreeInfo.GetModelBroadcaster().is())
106 maShapeTreeInfo.GetModelBroadcaster()->addEventListener (
107 static_cast<document::XEventListener*
>(
this));
111sal_Int64 ChildrenManagerImpl::GetChildCount() const noexcept
113 return maVisibleChildren.size();
117const css::uno::Reference<css::drawing::XShape>& ChildrenManagerImpl::GetChildShape(sal_Int64 nIndex)
121 throw lang::IndexOutOfBoundsException (
122 "no accessible child with index " + OUString::number(
nIndex),
124 return maVisibleChildren[
nIndex].mxShape;
130uno::Reference<XAccessible>
131 ChildrenManagerImpl::GetChild (sal_Int64 nIndex)
135 throw lang::IndexOutOfBoundsException (
136 "no accessible child with index " + OUString::number(
nIndex),
146uno::Reference<XAccessible>
163 ShapeTypeHandler::Instance().CreateAccessibleObject (
170 pShape->setIndexInParent(_nIndex);
189void ChildrenManagerImpl::Update (
bool bCreateNewObjectsOnDemand)
191 if (maShapeTreeInfo.GetViewForwarder() ==
nullptr)
193 tools::Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
197 CreateListOfVisibleShapes (aChildList);
205 maVisibleChildren.swap (aChildList);
210 std::vector<ChildDescriptor*> aUnusedChildList = MergeAccessibilityInformation (aChildList);
212 adjustIndexInParentOfShapes(maVisibleChildren);
235 RemoveNonVisibleChildren (aUnusedChildList);
237 aUnusedChildList.clear();
240 maVisibleArea = aVisibleArea;
246 if (maVisibleArea != aVisibleArea)
247 SendVisibleAreaEvents (maVisibleChildren);
251 if (bCreateNewObjectsOnDemand)
263 maVisibleChildren.swap(aChildList);
264 CreateAccessibilityObjects(aChildList);
265 maVisibleChildren.swap(aChildList);
268void ChildrenManagerImpl::CreateListOfVisibleShapes (
273 OSL_ASSERT (maShapeTreeInfo.GetViewForwarder() !=
nullptr);
275 tools::Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
278 for (
const auto& rpShape : maAccessibleShapes)
282 uno::Reference<XAccessibleComponent> xComponent (
283 rpShape->getAccessibleContext(), uno::UNO_QUERY);
289 awt::Rectangle aPixelBBox (xComponent->getBounds());
290 if ((aPixelBBox.Width > 0) && (aPixelBBox.Height > 0))
291 raDescriptorList.emplace_back(rpShape);
297 if (!mxShapeList.is() || !mxShapeList->hasElements())
300 sal_Int32 nShapeCount = mxShapeList->getCount();
301 raDescriptorList.reserve( nShapeCount );
305 uno::Reference<drawing::XShape> xShape;
306 for (sal_Int32
i=0;
i<nShapeCount; ++
i)
308 mxShapeList->getByIndex(
i) >>= xShape;
309 aPos = xShape->getPosition();
310 aSize = xShape->getSize();
312 aBoundingBox.
SetLeft( aPos.X );
313 aBoundingBox.
SetTop( aPos.Y );
314 aBoundingBox.
SetRight( aPos.X + aSize.Width );
315 aBoundingBox.
SetBottom( aPos.Y + aSize.Height );
319 if ( aBoundingBox.
Overlaps(aVisibleArea) )
320 raDescriptorList.emplace_back(xShape);
330 auto pLhsShape = lhs.
mxShape.get();
331 auto pRhsShape = rhs.
mxShape.get();
332 if (pLhsShape || pRhsShape)
333 return pLhsShape < pRhsShape;
337bool childDescriptorPtrLess(
const ChildDescriptor* lhs,
const ChildDescriptor* rhs)
339 return childDescriptorLess(*lhs, *rhs);
344void ChildrenManagerImpl::RemoveNonVisibleChildren (
345 const std::vector<ChildDescriptor*>& rNonVisibleChildren)
353 if (pChild->mxShape.is())
355 UnregisterAsDisposeListener (pChild->mxShape);
356 pChild->disposeAccessibleObject (
mrContext);
361 pAccessibleShape->
ResetState (AccessibleStateType::VISIBLE);
362 pChild->mxAccessibleShape =
nullptr;
367std::vector<ChildDescriptor*> ChildrenManagerImpl::MergeAccessibilityInformation (
375 std::vector<ChildDescriptor*> aSortedVisibleChildren(maVisibleChildren.size());
376 std::transform(maVisibleChildren.begin(), maVisibleChildren.end(),
377 aSortedVisibleChildren.begin(), [](
auto& e) {return &e;});
378 std::sort(aSortedVisibleChildren.begin(), aSortedVisibleChildren.end(), childDescriptorPtrLess);
381 std::sort(raOldChildList.begin(), raOldChildList.end(), childDescriptorLess);
383 ChildDescriptorListType::const_iterator aOldChildDescriptor = raOldChildList.begin();
384 ChildDescriptorListType::const_iterator aEndOldChildren = raOldChildList.end();
387 while (aOldChildDescriptor != aEndOldChildren && childDescriptorLess(*aOldChildDescriptor, *pChild))
389 aOldChildDescriptor++;
393 if (aOldChildDescriptor != aEndOldChildren && *aOldChildDescriptor == *pChild &&
394 aOldChildDescriptor->mxAccessibleShape.is())
396 pChild->mxAccessibleShape = aOldChildDescriptor->mxAccessibleShape;
397 pChild->mbCreateEventPending =
false;
400 RegisterAsDisposeListener (pChild->mxShape);
404 std::vector<ChildDescriptor*> aObsoleteChildren;
406 auto newIt = aSortedVisibleChildren.begin();
407 auto newEnd = aSortedVisibleChildren.end();
410 while (newIt != newEnd && childDescriptorLess(**newIt, rOldChild))
412 if (newIt == newEnd || !(**newIt == rOldChild) )
413 aObsoleteChildren.push_back(&rOldChild);
416 return aObsoleteChildren;
419void ChildrenManagerImpl::SendVisibleAreaEvents (
422 for (
const auto& rChild : raNewChildList)
428 if (pShape !=
nullptr)
434void ChildrenManagerImpl::CreateAccessibilityObjects (
438 for (
auto& rChild : raNewChildList)
442 if ( ! rChild.mxAccessibleShape.is() )
443 GetChild (rChild,
nPos);
444 if (rChild.mxAccessibleShape.is() && rChild.mbCreateEventPending)
446 rChild.mbCreateEventPending =
false;
448 AccessibleEventId::CHILD,
449 uno::Any(uno::Reference<XAccessible>(rChild.mxAccessibleShape)),
457void ChildrenManagerImpl::AddShape (
const Reference<drawing::XShape>& rxShape)
465 tools::Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
466 awt::Point aPos = rxShape->getPosition();
467 awt::Size aSize = rxShape->getSize();
472 aPos.X + aSize.Width,
473 aPos.Y + aSize.Height);
477 Reference<container::XChild> xChild (rxShape, uno::UNO_QUERY);
481 Reference<drawing::XShapes> xParent (xChild->getParent(), uno::UNO_QUERY);
482 if (xParent != mxShapeList)
485 if (!aBoundingBox.
Overlaps(aVisibleArea))
489 maVisibleChildren.emplace_back(rxShape);
493 GetChild (rDescriptor, maVisibleChildren.size()-1);
500 AccessibleEventId::CHILD,
503 maVisibleChildren.size() - 1);
504 RegisterAsDisposeListener(rxShape);
508void ChildrenManagerImpl::RemoveShape (
const Reference<drawing::XShape>& rxShape)
516 ChildDescriptorListType::iterator
I (
517 ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
519 if (
I == maVisibleChildren.end())
523 Reference<XAccessible> xHoldAlive(
I->mxAccessibleShape);
525 UnregisterAsDisposeListener (
I->mxShape);
531 maVisibleChildren.erase (
I);
533 adjustIndexInParentOfShapes(maVisibleChildren);
537void ChildrenManagerImpl::SetShapeList (
const css::uno::Reference<css::drawing::XShapes>& xShapeList)
539 mxShapeList = xShapeList;
546 maAccessibleShapes.push_back (shape);
550void ChildrenManagerImpl::ClearAccessibleShapeList()
555 aLocalVisibleChildren.swap(maVisibleChildren);
557 aLocalAccessibleShapes.swap(maAccessibleShapes);
561 AccessibleEventId::INVALIDATE_ALL_CHILDREN,
570 for (
auto& rChild : aLocalVisibleChildren)
571 if ( rChild.mxAccessibleShape.is() && rChild.mxShape.is() )
573 rChild.mxAccessibleShape->dispose();
574 rChild.mxAccessibleShape =
nullptr;
578 for (
auto& rpShape : aLocalAccessibleShapes)
594 Reference<document::XEventBroadcaster> xCurrentBroadcaster;
595 Reference<frame::XController> xCurrentController;
596 Reference<view::XSelectionSupplier> xCurrentSelectionSupplier;
599 xCurrentBroadcaster = maShapeTreeInfo.GetModelBroadcaster();
600 xCurrentController = maShapeTreeInfo.GetController();
601 xCurrentSelectionSupplier.set( xCurrentController, uno::UNO_QUERY);
602 maShapeTreeInfo = rShapeTreeInfo;
606 if (maShapeTreeInfo.GetModelBroadcaster() != xCurrentBroadcaster)
609 if (maShapeTreeInfo.GetModelBroadcaster().is())
611 static_cast<document::XEventListener*
>(
this));
614 if (xCurrentBroadcaster.is())
615 xCurrentBroadcaster->removeEventListener (
616 static_cast<document::XEventListener*
>(
this));
620 Reference<frame::XController> xNewController(maShapeTreeInfo.GetController());
621 Reference<view::XSelectionSupplier> xNewSelectionSupplier (
622 xNewController, uno::UNO_QUERY);
623 if (xNewSelectionSupplier == xCurrentSelectionSupplier)
627 if (xNewSelectionSupplier.is())
629 xNewController->addEventListener(
630 static_cast<document::XEventListener*
>(
this));
632 xNewSelectionSupplier->addSelectionChangeListener (
633 static_cast<view::XSelectionChangeListener*
>(
this));
637 if (xCurrentSelectionSupplier.is())
639 xCurrentSelectionSupplier->removeSelectionChangeListener (
640 static_cast<view::XSelectionChangeListener*
>(
this));
642 xCurrentController->removeEventListener(
643 static_cast<document::XEventListener*
>(
this));
649 ChildrenManagerImpl::disposing (
const lang::EventObject& rEventObject)
651 if (rEventObject.Source == maShapeTreeInfo.GetModelBroadcaster()
652 || rEventObject.Source == maShapeTreeInfo.GetController())
660 Reference<drawing::XShape> xShape (rEventObject.Source, uno::UNO_QUERY);
663 ChildDescriptorListType::iterator
I (
664 ::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
665 ChildDescriptor (xShape)));
666 if (I != maVisibleChildren.end())
669 I->disposeAccessibleObject (mrContext);
670 I->mxShape =
nullptr;
679 ChildrenManagerImpl::notifyEvent (
680 const document::EventObject& rEventObject)
682 if (rEventObject.EventName ==
"ShapeInserted")
683 AddShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
684 else if (rEventObject.EventName ==
"ShapeRemoved")
685 RemoveShape (Reference<drawing::XShape>(rEventObject.Source, uno::UNO_QUERY));
691 ChildrenManagerImpl::selectionChanged (
const lang::EventObject& )
697void ChildrenManagerImpl::impl_dispose()
699 Reference<frame::XController>
xController(maShapeTreeInfo.GetController());
703 Reference<view::XSelectionSupplier> xSelectionSupplier (
705 if (xSelectionSupplier.is())
707 xSelectionSupplier->removeSelectionChangeListener (
708 static_cast<view::XSelectionChangeListener*
>(
this));
711 catch( uno::RuntimeException&)
718 static_cast<document::XEventListener*
>(
this));
720 catch( uno::RuntimeException&)
723 maShapeTreeInfo.SetController (
nullptr);
728 if (maShapeTreeInfo.GetModelBroadcaster().is())
729 maShapeTreeInfo.GetModelBroadcaster()->removeEventListener (
730 static_cast<document::XEventListener*
>(
this));
731 maShapeTreeInfo.SetModelBroadcaster (
nullptr);
733 catch( uno::RuntimeException& )
736 ClearAccessibleShapeList ();
737 SetShapeList (
nullptr);
741void ChildrenManagerImpl::disposing(std::unique_lock<std::mutex>&)
747void ChildrenManagerImpl::ViewForwarderChanged()
753bool ChildrenManagerImpl::ReplaceChild (
755 const css::uno::Reference< css::drawing::XShape >& _rxShape,
764 auto I = std::find_if(maVisibleChildren.begin(), maVisibleChildren.end(),
765 [&pCurrentChild](
const ChildDescriptor& rChild) { return rChild.GetAccessibleShape() == pCurrentChild; });
767 if (
I != maVisibleChildren.end())
770 pCurrentChild->dispose();
772 AccessibleEventId::CHILD,
774 uno::Any (uno::Reference<XAccessible>(
I->mxAccessibleShape)), -1);
784 if ( pNewChild.is() )
787 I->mxAccessibleShape = pNewChild.get();
789 AccessibleEventId::CHILD,
790 uno::Any (uno::Reference<XAccessible>(
I->mxAccessibleShape)),
804 sal_Int64
count = GetChildCount();
811 if (pCtlAccShape->GetControlModel() == pSet)
817uno::Reference<XAccessible>
818 ChildrenManagerImpl::GetAccessibleCaption (
const uno::Reference<drawing::XShape>& xShape)
820 auto I = std::find_if(maVisibleChildren.begin(), maVisibleChildren.end(),
821 [&xShape](
const ChildDescriptor& rChild) { return rChild.mxShape.get() == xShape.get(); });
822 if (
I != maVisibleChildren.end())
823 return I->mxAccessibleShape;
824 return uno::Reference<XAccessible> ();
837void ChildrenManagerImpl::UpdateSelection()
842 typedef std::pair< AccessibleShape* , sal_Bool > PAIR_SHAPE;
843 typedef std::vector< PAIR_SHAPE > VEC_SHAPE;
846 bool bHasSelectedShape=
false;
847 if (!maVisibleChildren.empty())
849 Reference<frame::XController>
xController(maShapeTreeInfo.GetController());
850 Reference<view::XSelectionSupplier> xSelectionSupplier (
855 Reference<container::XIndexAccess> xSelectedShapeAccess;
856 Reference<drawing::XShape> xSelectedShape;
857 if (xSelectionSupplier.is())
859 xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
860 xSelectedShape.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
864 std::vector<css::uno::Reference<css::drawing::XShape>> aSortedSelectedShapes;
865 if (!xSelectedShape.is() && xSelectedShapeAccess.is())
867 sal_Int32
nCount = xSelectedShapeAccess->getCount();
868 aSortedSelectedShapes.reserve(
nCount);
871 pSvxShape->getAllShapes(aSortedSelectedShapes);
876 css::uno::Reference<css::drawing::XShape> xShape(xSelectedShapeAccess->getByIndex(
i), uno::UNO_QUERY);
877 aSortedSelectedShapes.push_back(xShape);
879 std::sort(aSortedSelectedShapes.begin(), aSortedSelectedShapes.end());
882 for (
const auto& rChild : maVisibleChildren)
885 if (rChild.mxAccessibleShape.is() && rChild.mxShape.is() && pAccessibleShape!=
nullptr)
889 nRole == AccessibleRole::GRAPHIC ||
890 nRole == AccessibleRole::EMBEDDED_OBJECT ||
891 nRole == AccessibleRole::SHAPE ||
892 nRole == AccessibleRole::IMAGE_MAP ||
893 nRole == AccessibleRole::TABLE_CELL ||
894 nRole == AccessibleRole::TABLE );
895 bool bShapeIsSelected =
false;
898 if (xSelectedShape.is())
900 if (rChild.mxShape == xSelectedShape)
902 bShapeIsSelected =
true;
903 pNewFocusedShape = pAccessibleShape;
906 else if (!aSortedSelectedShapes.empty())
908 if (std::binary_search(aSortedSelectedShapes.begin(), aSortedSelectedShapes.end(), rChild.mxShape))
910 bShapeIsSelected =
true;
912 if (aSortedSelectedShapes.size() == 1)
913 pNewFocusedShape = pAccessibleShape;
918 if (bShapeIsSelected)
920 if (pAccessibleShape->
SetState (AccessibleStateType::SELECTED))
924 vecSelect.emplace_back(pAccessibleShape,
true);
930 bHasSelectedShape=
true;
936 if(pAccessibleShape->
ResetState (AccessibleStateType::SELECTED))
940 vecSelect.emplace_back(pAccessibleShape,
false);
945 if (pAccessibleShape->
GetState (AccessibleStateType::FOCUSED))
946 pCurrentlyFocusedShape = pAccessibleShape;
951 vcl::Window *pParentWindow = maShapeTreeInfo.GetWindow();
952 bool bShapeActive=
false;
961 if (pCurrentlyFocusedShape != pNewFocusedShape)
963 if (pCurrentlyFocusedShape !=
nullptr)
964 pCurrentlyFocusedShape->
ResetState (AccessibleStateType::FOCUSED);
965 if (pNewFocusedShape !=
nullptr && bShapeActive)
966 pNewFocusedShape->
SetState (AccessibleStateType::FOCUSED);
969 if (nAddSelect >= 10 )
974 for (VEC_SHAPE::reverse_iterator vi = vecSelect.rbegin(), aEndVecSelect = vecSelect.rend(); vi != aEndVecSelect ;++vi)
976 PAIR_SHAPE &pairShape= *vi;
977 Reference< XAccessible > xShape(pairShape.first);
981 if (pairShape.second)
983 if (bHasSelectedShape)
985 if ( nAddSelect > 0 )
987 mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD,anyShape,
uno::Any(), -1);
995 mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED,anyShape,
uno::Any(), -1);
999 bHasSelectedShape=
true;
1005 mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE,anyShape,
uno::Any(), -1);
1010 mpFocusedShape = pNewFocusedShape;
1014bool ChildrenManagerImpl::HasFocus()
const
1016 return mpFocusedShape !=
nullptr;
1020void ChildrenManagerImpl::RemoveFocus()
1022 if (mpFocusedShape !=
nullptr)
1024 mpFocusedShape->
ResetState (AccessibleStateType::FOCUSED);
1025 mpFocusedShape =
nullptr;
1030void ChildrenManagerImpl::RegisterAsDisposeListener (
1031 const Reference<drawing::XShape>& xShape)
1033 Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
1034 if (xComponent.is())
1035 xComponent->addEventListener (
1036 static_cast<document::XEventListener*
>(
this));
1040void ChildrenManagerImpl::UnregisterAsDisposeListener (
1041 const Reference<drawing::XShape>& xShape)
1043 Reference<lang::XComponent> xComponent (xShape, uno::UNO_QUERY);
1044 if (xComponent.is())
1045 xComponent->removeEventListener (
1046 static_cast<document::XEventListener*
>(
this));
1050ChildDescriptor::ChildDescriptor (
const Reference<drawing::XShape>& xShape)
1052 mbCreateEventPending (true)
1059 : mxAccessibleShape (rxAccessibleShape),
1060 mbCreateEventPending (true)
1065 pAccessibleShape->
SetState (AccessibleStateType::VISIBLE);
1085 AccessibleEventId::CHILD,
const NodeContext & mrContext
unotools::WeakReference< AnimationNode > mxParent
virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override
void CommitChange(sal_Int16 aEventId, const css::uno::Any &rNewValue, const css::uno::Any &rOldValue, sal_Int32 nValueIndex)
@descr This class is a container for the information specific for a single shape that is passed to th...
This class bundles all information that is passed down the tree of accessible shapes so that each sha...
const css::uno::Reference< css::document::XShapeEventBroadcaster > & GetModelBroadcaster() const
Return the current model broadcaster.
This base class provides a base implementation for all shapes.
virtual bool ResetState(sal_Int64 aState) override
Reset the specified state.
bool GetState(sal_Int64 aState)
Return the state of the specified state.
const css::uno::Reference< css::drawing::XShape > & GetXShape() const
void setIndexInParent(sal_Int32 _nIndex)
set the index _nIndex at the accessible shape
virtual void ViewForwarderChanged() override
This method is called to indicate a change of the specified view forwarder, specifically,...
virtual bool SetState(sal_Int64 aState) override
Set the specified state.
virtual sal_Int16 SAL_CALL getAccessibleRole() override
Return this object's role.
A child descriptor holds a reference to a UNO shape and the corresponding accessible object.
AccessibleShape * GetAccessibleShape() const
Return a pointer to the implementation object of the accessible shape of this descriptor.
ChildDescriptor(const css::uno::Reference< css::drawing::XShape > &xShape)
Create a new descriptor for the specified shape with empty reference to accessible object.
css::uno::Reference< css::drawing::XShape > mxShape
Reference to a (partially) visible shape.
void disposeAccessibleObject(AccessibleContextBase &rParent)
Dispose the accessible object of this descriptor.
rtl::Reference< AccessibleShape > mxAccessibleShape
The corresponding accessible object.
void setIndexAtAccessibleShape(sal_Int32 _nIndex)
set the index _nIndex at the accessible shape
ChildrenManagerImpl(css::uno::Reference< css::accessibility::XAccessible > xParent, css::uno::Reference< css::drawing::XShapes > xShapeList, const AccessibleShapeTreeInfo &rShapeTreeInfo, AccessibleContextBase &rContext)
Create a children manager, which manages the children of the given parent.
std::vector< rtl::Reference< AccessibleShape > > AccessibleShapeList
This list of additional accessible shapes that can or shall not be created by the shape factory.
static ShapeTypeHandler & Instance()
This function returns a reference to the only instance of this class.
vcl::Window * GetParent() const
#define DBG_ASSERT(sCon, aError)
::std::vector< ChildDescriptor > ChildDescriptorListType
class SAL_NO_VTABLE XPropertySet
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
uno::Reference< drawing::XShape > const mxShape
Reference< XController > xController