// Register at model as document::XEventListener. if (maShapeTreeInfo.GetModelBroadcaster().is())
maShapeTreeInfo.GetModelBroadcaster()->addEventListener ( static_cast<document::XEventListener*>(this));
}
const css::uno::Reference<css::drawing::XShape>& ChildrenManagerImpl::GetChildShape(sal_Int64 nIndex)
{ // Check whether the given index is valid. if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= maVisibleChildren.size()) throw lang::IndexOutOfBoundsException ( "no accessible child with index " + OUString::number(nIndex),
mxParent); return maVisibleChildren[nIndex].mxShape;
}
/** Return the requested accessible child object. Create it if it is not yetinthecache.
*/
uno::Reference<XAccessible>
ChildrenManagerImpl::GetChild (sal_Int64 nIndex)
{ // Check whether the given index is valid. if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= maVisibleChildren.size()) throw lang::IndexOutOfBoundsException ( "no accessible child with index " + OUString::number(nIndex),
mxParent);
/** Return the requested accessible child object. Create it if it is not yetinthecache.
*/
uno::Reference<XAccessible>
ChildrenManagerImpl::GetChild (ChildDescriptor& rChildDescriptor,sal_Int32 _nIndex)
{ if ( ! rChildDescriptor.mxAccessibleShape.is())
{
SolarMutexGuard g; // Make sure that the requested accessible object has not been // created while locking the global mutex. if ( ! rChildDescriptor.mxAccessibleShape.is())
{
AccessibleShapeInfo aShapeInfo(
rChildDescriptor.mxShape,
mxParent, this); // Create accessible object that corresponds to the descriptor's // shape.
rtl::Reference<AccessibleShape> pShape(
ShapeTypeHandler::Instance().CreateAccessibleObject (
aShapeInfo,
maShapeTreeInfo));
rChildDescriptor.mxAccessibleShape = pShape; if ( pShape.is() )
{
pShape->Init();
pShape->setIndexInParent(_nIndex);
}
}
}
return rChildDescriptor.mxAccessibleShape;
}
/** Find all shapes among the specified shapes that lie fully or partially insidethevisiblearea.Putthoseshapesintotheclearedcache.The correspondingaccessibleobjectswillbecreatedondemand.
// 1. Create a local list of visible shapes.
ChildDescriptorListType aChildList;
CreateListOfVisibleShapes (aChildList);
// 2. Replace the current list of visible shapes with the new one. Do // the same with the visible area.
{
SolarMutexGuard g;
// Use swap to copy the contents of the new list in constant time.
maVisibleChildren.swap (aChildList);
// 3. Merge the information that is already known about the visible // shapes from the previous list into the new list and identify // old children that are now unused
std::vector<ChildDescriptor*> aUnusedChildList = MergeAccessibilityInformation (aChildList);
adjustIndexInParentOfShapes(maVisibleChildren);
// aChildList now contains all the old children, while maVisibleChildren // contains all the current children
// 4. Find all shapes in the old list that are not in the current list, // send appropriate events and remove the accessible shape.
// Do this *after* we have set our new list of children, because // removing a child may cause
// to be fired, and so the operations will take place on // the list we are trying to replace
RemoveNonVisibleChildren (aUnusedChildList);
aUnusedChildList.clear();
aChildList.clear();
maVisibleArea = aVisibleArea;
}
// 5. If the visible area has changed then send events that signal a // change of their bounding boxes for all shapes that are members of // both the current and the new list of visible shapes. if (maVisibleArea != aVisibleArea)
SendVisibleAreaEvents (maVisibleChildren);
// 6. If children have to be created immediately and not on demand then // create the missing accessible objects now. if (bCreateNewObjectsOnDemand) return;
//operate on a copy of the list and restore it afterwards to guard //against the pathological case where maVisibleChildren gets modified //by other calls to this object while CreateAccessibilityObjects //executes which can happen when java is disabled and the "enable-java" //dialog appears during the instantiation of the linguistic components //triggered by the creation of shapes belonging to the a11y objects // //i.e. launch start-center, launch impress with java disabled and //a java-using linguistic component installed
maVisibleChildren.swap(aChildList);
CreateAccessibilityObjects(aChildList);
maVisibleChildren.swap(aChildList);
}
// Add the visible shapes for which the accessible objects already exist. for (constauto& rpShape : maAccessibleShapes)
{ if (rpShape.is())
{
uno::Reference<XAccessibleComponent> xComponent (
rpShape->getAccessibleContext(), uno::UNO_QUERY); if (xComponent.is())
{ // The bounding box of the object already is clipped to the // visible area. The object is therefore visible if the // bounding box has non-zero extensions.
awt::Rectangle aPixelBBox (xComponent->getBounds()); if ((aPixelBBox.Width > 0) && (aPixelBBox.Height > 0))
raDescriptorList.emplace_back(rpShape);
}
}
}
// Add the visible shapes for which only the XShapes exist. if (!mxShapeList.is() || !mxShapeList->hasElements()) return;
// Insert shape if it is visible, i.e. its bounding box overlaps // the visible area. In the LOK case we skip the overlap check // since we could remove a shape that is visible on the client. if ( aBoundingBox.Overlaps(aVisibleArea) || comphelper::LibreOfficeKit::isActive())
raDescriptorList.emplace_back(xShape);
}
}
void ChildrenManagerImpl::RemoveNonVisibleChildren ( const std::vector<ChildDescriptor*>& rNonVisibleChildren)
{ for (ChildDescriptor* pChild : rNonVisibleChildren)
{ // The child is disposed when there is a UNO shape from which // the accessible shape can be created when the shape becomes // visible again. When there is no such UNO shape then simply // reset the descriptor but keep the accessibility object. if (pChild->mxShape.is())
{
UnregisterAsDisposeListener (pChild->mxShape);
pChild->disposeAccessibleObject (mrContext);
} else
{
AccessibleShape* pAccessibleShape = pChild->GetAccessibleShape();
pAccessibleShape->ResetState (AccessibleStateType::VISIBLE);
pChild->mxAccessibleShape = nullptr;
}
}
}
{ // create a working copy of the vector of current children with pointers to elements, // sort the old list and copy by mxShape, and then walk old/current lists in parallel, // which avoids an O(n^2) loop // (order of maVisibleChildren must remain unchanged to not randomly change a11y tree)
std::vector<ChildDescriptor*> aSortedVisibleChildren(maVisibleChildren.size());
std::transform(maVisibleChildren.begin(), maVisibleChildren.end(),
aSortedVisibleChildren.begin(), [](auto& e) {return &e;});
std::sort(aSortedVisibleChildren.begin(), aSortedVisibleChildren.end(), childDescriptorPtrLess);
// old list can be reordered without problems
std::sort(raOldChildList.begin(), raOldChildList.end(), childDescriptorLess);
// Copy accessible shape if that exists in the old descriptor. if (aOldChildDescriptor != aEndOldChildren && *aOldChildDescriptor == *pChild &&
aOldChildDescriptor->mxAccessibleShape.is())
{
pChild->mxAccessibleShape = aOldChildDescriptor->mxAccessibleShape;
pChild->mbCreateEventPending = false;
} else
RegisterAsDisposeListener (pChild->mxShape);
}
// collect list of children that are in the old, but not the new vector
std::vector<ChildDescriptor*> aObsoleteChildren;
auto newIt = aSortedVisibleChildren.begin(); auto newEnd = aSortedVisibleChildren.end(); for (ChildDescriptor& rOldChild : raOldChildList)
{ while (newIt != newEnd && childDescriptorLess(**newIt, rOldChild))
newIt++; if (newIt == newEnd || !(**newIt == rOldChild) )
aObsoleteChildren.push_back(&rOldChild);
}
return aObsoleteChildren;
}
void ChildrenManagerImpl::SendVisibleAreaEvents (
ChildDescriptorListType& raNewChildList)
{ for (constauto& rChild : raNewChildList)
{ // Tell shape of changed visible area. To do this, fake a // change of the view forwarder. (Actually we usually get here // as a result of a change of the view forwarder).
AccessibleShape* pShape = rChild.GetAccessibleShape (); if (pShape != nullptr)
pShape->ViewForwarderChanged();
}
}
void ChildrenManagerImpl::CreateAccessibilityObjects (
ChildDescriptorListType& raNewChildList)
{
sal_Int32 nPos = 0; for ( auto& rChild : raNewChildList)
{ // Create the associated accessible object when the flag says so and // it does not yet exist. if ( ! rChild.mxAccessibleShape.is() )
GetChild (rChild, nPos); if (rChild.mxAccessibleShape.is() && rChild.mbCreateEventPending)
{
rChild.mbCreateEventPending = false;
mrContext.CommitChange (
AccessibleEventId::CHILD,
uno::Any(uno::Reference<XAccessible>(rChild.mxAccessibleShape)),
uno::Any(), -1);
}
++nPos;
}
}
void ChildrenManagerImpl::AddShape (const Reference<drawing::XShape>& rxShape)
{ if (!rxShape.is()) return;
SolarMutexClearableGuard aGuard;
// Test visibility of the shape.
tools::Rectangle aVisibleArea = maShapeTreeInfo.GetViewForwarder()->GetVisibleArea();
awt::Point aPos = rxShape->getPosition();
awt::Size aSize = rxShape->getSize();
// Add the shape only when it belongs to the list of shapes stored // in mxShapeList (which is either a page or a group shape).
Reference<container::XChild> xChild (rxShape, uno::UNO_QUERY); if (!xChild.is()) return;
Reference<drawing::XShapes> xParent (xChild->getParent(), uno::UNO_QUERY); if (xParent != mxShapeList) return;
if (!aBoundingBox.Overlaps(aVisibleArea) && !comphelper::LibreOfficeKit::isActive()) return;
// Add shape to list of visible shapes.
maVisibleChildren.emplace_back(rxShape);
void ChildrenManagerImpl::RemoveShape (const Reference<drawing::XShape>& rxShape)
{ if (!rxShape.is()) return;
SolarMutexGuard g;
// Search shape in list of visible children.
ChildDescriptorListType::iterator I (
::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
ChildDescriptor (rxShape))); if (I == maVisibleChildren.end()) return;
// Remove descriptor from that list.
rtl::Reference<AccessibleShape> xHoldAlive(I->mxAccessibleShape);
UnregisterAsDisposeListener (I->mxShape); // Dispose the accessible object.
I->disposeAccessibleObject (mrContext);
// Now we can safely remove the child descriptor and thus // invalidate the iterator.
maVisibleChildren.erase (I);
void ChildrenManagerImpl::ClearAccessibleShapeList()
{ // Copy the list of (visible) shapes to local lists and clear the // originals.
ChildDescriptorListType aLocalVisibleChildren;
aLocalVisibleChildren.swap(maVisibleChildren);
AccessibleShapeList aLocalAccessibleShapes;
aLocalAccessibleShapes.swap(maAccessibleShapes);
// Tell the listeners that all children are gone.
mrContext.CommitChange (
AccessibleEventId::INVALIDATE_ALL_CHILDREN,
uno::Any(),
uno::Any(), -1);
// Now the objects in the local lists can be safely disposed without // having problems with callers that want to update their child lists.
// Clear the list of visible accessible objects. Objects not created on // demand for XShapes are treated below. for (auto& rChild : aLocalVisibleChildren) if ( rChild.mxAccessibleShape.is() && rChild.mxShape.is() )
{
rChild.mxAccessibleShape->dispose();
rChild.mxAccessibleShape = nullptr;
}
// Dispose all objects in the accessible shape list. for (auto& rpShape : aLocalAccessibleShapes) if (rpShape.is())
{ // Dispose the object.
rpShape->dispose();
rpShape = nullptr;
}
}
/** If the broadcasters change at which this object is registered then unregisteratoldandregisteratnewbroadcasters.
*/ void ChildrenManagerImpl::SetInfo (const AccessibleShapeTreeInfo& rShapeTreeInfo)
{ // Remember the current broadcasters and exchange the shape tree info.
Reference<document::XEventBroadcaster> xCurrentBroadcaster;
Reference<frame::XController> xCurrentController;
Reference<view::XSelectionSupplier> xCurrentSelectionSupplier;
{
SolarMutexGuard g;
xCurrentBroadcaster = maShapeTreeInfo.GetModelBroadcaster();
xCurrentController = maShapeTreeInfo.GetController();
xCurrentSelectionSupplier.set( xCurrentController, uno::UNO_QUERY);
maShapeTreeInfo = rShapeTreeInfo;
}
// Move registration to new model. if (maShapeTreeInfo.GetModelBroadcaster() != xCurrentBroadcaster)
{ // Register at new broadcaster. if (maShapeTreeInfo.GetModelBroadcaster().is())
maShapeTreeInfo.GetModelBroadcaster()->addEventListener ( static_cast<document::XEventListener*>(this));
// Unregister at old broadcaster. if (xCurrentBroadcaster.is())
xCurrentBroadcaster->removeEventListener ( static_cast<document::XEventListener*>(this));
}
// Move registration to new selection supplier.
Reference<frame::XController> xNewController(maShapeTreeInfo.GetController());
Reference<view::XSelectionSupplier> xNewSelectionSupplier (
xNewController, uno::UNO_QUERY); if (xNewSelectionSupplier == xCurrentSelectionSupplier) return;
// Register at new broadcaster. if (xNewSelectionSupplier.is())
{
xNewController->addEventListener( static_cast<document::XEventListener*>(this));
// Unregister at old broadcaster. if (xCurrentSelectionSupplier.is())
{
xCurrentSelectionSupplier->removeSelectionChangeListener ( static_cast<view::XSelectionChangeListener*>(this));
// Find the descriptor for the given shape.
ChildDescriptorListType::iterator I (
::std::find (maVisibleChildren.begin(), maVisibleChildren.end(),
ChildDescriptor (xShape))); if (I != maVisibleChildren.end())
{ // Clear the descriptor.
I->disposeAccessibleObject (mrContext);
I->mxShape = nullptr;
}
}
}
// document::XEventListener /** Listen for new and removed shapes.
*/ void SAL_CALL
ChildrenManagerImpl::notifyEvent ( const document::EventObject& rEventObject)
{ // tdf#158169 if we are already disposed, execute no actions, but inform the // caller that we are disposed if ( m_bDisposed ) throw lang::DisposedException();
// IAccessibleParent bool ChildrenManagerImpl::ReplaceChild (
AccessibleShape* pCurrentChild, const css::uno::Reference< css::drawing::XShape >& _rxShape, const tools::Long/*_nIndex*/, const AccessibleShapeTreeInfo& _rShapeTreeInfo)
{ // Iterate over the visible children. If one of them has an already // created accessible object that matches pCurrentChild then replace // it. Otherwise the child to replace is either not in the list or has // not ye been created (and is therefore not in the list, too) and a // replacement is not necessary. auto I = std::find_if(maVisibleChildren.begin(), maVisibleChildren.end(),
[&pCurrentChild](const ChildDescriptor& rChild) { return rChild.GetAccessibleShape() == pCurrentChild; });
if (I != maVisibleChildren.end())
{ // Dispose the current child and send an event about its deletion.
pCurrentChild->dispose();
mrContext.CommitChange (
AccessibleEventId::CHILD,
uno::Any(),
uno::Any (uno::Reference<XAccessible>(I->mxAccessibleShape)), -1);
// Replace with replacement and send an event about existence // of the new child.
AccessibleShapeInfo aShapeInfo( _rxShape, pCurrentChild->getAccessibleParent(), this ); // create the new child
rtl::Reference<AccessibleShape> pNewChild(ShapeTypeHandler::Instance().CreateAccessibleObject (
aShapeInfo,
_rShapeTreeInfo
)); if ( pNewChild.is() )
pNewChild->Init();
Ifthereisnovalidcontrollerthenallshapesaredeselectedand unfocused.Ifthecontroller'sframeisnotactivethenallshapesare unfocused.
*/ void ChildrenManagerImpl::UpdateSelection()
{ // Remember the current and new focused shape.
AccessibleShape* pCurrentlyFocusedShape = nullptr;
AccessibleShape* pNewFocusedShape = nullptr; typedef std::pair< AccessibleShape* , sal_Bool > PAIR_SHAPE;//sal_Bool Selected,UnSelected. typedef std::vector< PAIR_SHAPE > VEC_SHAPE;
VEC_SHAPE vecSelect; int nAddSelect=0; bool bHasSelectedShape=false; if (!maVisibleChildren.empty())
{
Reference<frame::XController> xController(maShapeTreeInfo.GetController());
Reference<view::XSelectionSupplier> xSelectionSupplier (
xController, uno::UNO_QUERY);
// Try to cast the selection both to a multi selection and to a single // selection.
Reference<container::XIndexAccess> xSelectedShapeAccess;
Reference<drawing::XShape> xSelectedShape; if (xSelectionSupplier.is())
{
xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
xSelectedShape.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
}
// tdf#139220 to quickly find if a given drawing::XShape is selected
std::vector<css::uno::Reference<css::drawing::XShape>> aSortedSelectedShapes; if (!xSelectedShape.is() && xSelectedShapeAccess.is())
{
sal_Int32 nCount = xSelectedShapeAccess->getCount(); if (auto pSvxShape = dynamic_cast<SvxShapeCollection*>(xSelectedShapeAccess.get()))
{
aSortedSelectedShapes = pSvxShape->getAllShapes();
} else
{
aSortedSelectedShapes.reserve(nCount); for (sal_Int32 i = 0; i < nCount; ++i)
{
css::uno::Reference<css::drawing::XShape> xShape(xSelectedShapeAccess->getByIndex(i), uno::UNO_QUERY);
aSortedSelectedShapes.push_back(xShape);
}
}
std::sort(aSortedSelectedShapes.begin(), aSortedSelectedShapes.end());
}
// Look up the shape in the (single or multi-) selection. if (xSelectedShape.is())
{ if (rChild.mxShape == xSelectedShape)
{
bShapeIsSelected = true;
pNewFocusedShape = pAccessibleShape;
}
} elseif (!aSortedSelectedShapes.empty())
{ if (std::binary_search(aSortedSelectedShapes.begin(), aSortedSelectedShapes.end(), rChild.mxShape))
{
bShapeIsSelected = true; // In a multi-selection no shape has the focus. if (aSortedSelectedShapes.size() == 1)
pNewFocusedShape = pAccessibleShape;
}
}
// Set or reset the SELECTED state. if (bShapeIsSelected)
{ if (pAccessibleShape->SetState (AccessibleStateType::SELECTED))
{ if (bDrawShape)
{
vecSelect.emplace_back(pAccessibleShape,true);
++nAddSelect;
}
} else
{//Selected not change,has selected shape before
bHasSelectedShape=true;
}
} else //pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
{ if(pAccessibleShape->ResetState (AccessibleStateType::SELECTED))
{ if(bDrawShape)
{
vecSelect.emplace_back(pAccessibleShape,false);
}
}
} // Does the shape have the current selection? if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
pCurrentlyFocusedShape = pAccessibleShape;
}
}
}
vcl::Window *pParentWindow = maShapeTreeInfo.GetWindow(); bool bShapeActive= false; // For table cell, the table's parent must be checked to make sure it has focus. if (pParentWindow)
{
vcl::Window *pPWindow = pParentWindow->GetParent(); if (pParentWindow->HasFocus() || (pPWindow && pPWindow->HasFocus()))
bShapeActive =true;
} // Move focus from current to newly focused shape. if (pCurrentlyFocusedShape != pNewFocusedShape)
{ if (pCurrentlyFocusedShape != nullptr)
pCurrentlyFocusedShape->ResetState (AccessibleStateType::FOCUSED); if (pNewFocusedShape != nullptr && bShapeActive)
pNewFocusedShape->SetState (AccessibleStateType::FOCUSED);
}
if (nAddSelect >= 10 )//fire selection within
{
mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_WITHIN,uno::Any(),uno::Any(), -1);
nAddSelect =0 ;//not fire selection event
} for (VEC_SHAPE::reverse_iterator vi = vecSelect.rbegin(), aEndVecSelect = vecSelect.rend(); vi != aEndVecSelect ;++vi)
{
PAIR_SHAPE &pairShape= *vi;
Reference< XAccessible > xShape(pairShape.first);
uno::Any anyShape;
anyShape <<= xShape;
if (pairShape.second)//Selection add
{ if (bHasSelectedShape)
{ if ( nAddSelect > 0 )
{
mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_ADD,anyShape,uno::Any(), -1);
}
} else
{ //if has not selected shape ,first selected shape is fire selection event; if (nAddSelect > 0 )
{
mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED,anyShape,uno::Any(), -1);
} if (nAddSelect > 1 )//check other selected shape fire selection add event
{
bHasSelectedShape=true;
}
}
} else//selection remove
{
mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE,anyShape,uno::Any(), -1);
}
}
// We need to know when text content is no more edited but shape is still selected. // For instance when ESC is pressed. // The only difference is provided by nSelectedChildCount: on editing is equal to 1. // In the following a shape get selected, but it was already selected, anyway editing is no more active. if (comphelper::LibreOfficeKit::isActive() && pNewFocusedShape && nAddSelect == 0)
{
sal_Int64 nChildCount = pNewFocusedShape->getAccessibleChildCount();
sal_Int64 nSelectedChildCount = pNewFocusedShape->getSelectedAccessibleChildCount(); if (nChildCount > 0 && nSelectedChildCount == 0)
{
Reference< XAccessible > xShape(pNewFocusedShape);
uno::Any anyShape;
anyShape <<= xShape;
mrContext.CommitChange(AccessibleEventId::SELECTION_CHANGED,anyShape,uno::Any(), -1);
}
}
// Remember whether there is a shape that now has the focus.
mpFocusedShape = pNewFocusedShape;
}
ChildDescriptor::ChildDescriptor (const rtl::Reference<AccessibleShape>& rxAccessibleShape)
: mxAccessibleShape (rxAccessibleShape),
mbCreateEventPending (true)
{ // Make sure that the accessible object has the <const>VISIBLE</const> // state set.
AccessibleShape* pAccessibleShape = GetAccessibleShape();
pAccessibleShape->SetState (AccessibleStateType::VISIBLE);
}
void ChildDescriptor::disposeAccessibleObject (AccessibleContextBase& rParent)
{ if (!mxAccessibleShape.is()) return;
// Send event that the shape has been removed.
uno::Any aOldValue;
aOldValue <<= uno::Reference<XAccessible>(mxAccessibleShape);
rParent.CommitChange (
AccessibleEventId::CHILD,
uno::Any(),
aOldValue, -1);
// Dispose and remove the object. if (mxAccessibleShape.is())
mxAccessibleShape->dispose();
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.19Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-29)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.