/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// right now, we're only handling the specific event necessary to fix this performance problem if (pSdrHint->GetKind() == SdrHintKind::ObjectChange)
{ auto pSdrObject = const_cast<SdrObject*>(pSdrHint->GetObject());
uno::Reference<drawing::XShape> xShape(pSdrObject->getUnoShape(), uno::UNO_QUERY);
std::unique_lock aGuard(maListenerMutex); auto [itBegin, itEnd] = maShapeListeners.equal_range(xShape); for (auto it = itBegin; it != itEnd; ++it)
it->second->notifyShapeEvent(aEvent);
}
}
private:
SwRect maOldBox; // the old bounds for CHILD_POS_CHANGED // and POS_CHANGED
unotools::WeakReference < SwAccessibleContext > mxAcc; // The object that fires the event
SwAccessibleChild maFrameOrObj; // the child for CHILD_POS_CHANGED and // the same as xAcc for any other // event type
EventType meType; // The event type
AccessibleStates mnStates; // check states or update caret pos
public: const SwFrame* mpParentFrame; // The object that fires the event bool IsNoXaccParentFrame() const
{ return CHILD_POS_CHANGED == meType && mpParentFrame != nullptr;
}
public:
SwAccessibleEvent_Impl( EventType eT,
SwAccessibleContext *pA,
SwAccessibleChild aFrameOrObj )
: mxAcc( pA ),
maFrameOrObj(std::move( aFrameOrObj )),
meType( eT ),
mnStates( AccessibleStates::NONE ),
mpParentFrame( nullptr )
{}
// helper class that stores preview data class SwAccPreviewData
{ typedef std::vector<tools::Rectangle> Rectangles;
Rectangles maPreviewRects;
Rectangles maLogicRects;
SwRect maVisArea;
Fraction maScale;
const SwPageFrame *mpSelPage;
/** adjust logic page rectangle to its visible part
@param _iorLogicPgSwRect input/output parameter - reference to the logic page rectangle, which has to be adjusted.
@param _rPreviewPgSwRect input parameter - constant reference to the corresponding preview page rectangle; needed to determine the visible part of the logic page rectangle.
@param _rPreviewWinSize input parameter - constant reference to the preview window size in TWIP; needed to determine the visible part of the logic page rectangle
*/ staticvoid AdjustLogicPgRectToVisibleArea( SwRect& _iorLogicPgSwRect, const SwRect& _rPreviewPgSwRect, const Size& _rPreviewWinSize );
/** Adjust the MapMode so that the preview page appears at the * proper position. rPoint identifies the page for which the * MapMode should be adjusted. If bFromPreview is true, rPoint is
* a preview coordinate; else it's a document coordinate. */ void AdjustMapMode( MapMode& rMapMode, const Point& rPoint ) const;
// loop on preview pages to calculate <maPreviewRects>, <maLogicRects> and // <maVisArea> for ( auto & rpPreviewPage : _rPreviewPages )
{
aPage = rpPreviewPage->pPage;
if( pFrame && pFrame->IsCellFrame() && rAcc.is() )
{ // Is it in the same table? We check that // by comparing the last table frame in the // follow chain, because that's cheaper than // searching the first one. if( rAcc->GetFrame()->IsCellFrame() )
{ const SwTabFrame *pTabFrame1 = rAcc->GetFrame()->FindTabFrame(); if (pTabFrame1)
{ while (pTabFrame1->GetFollow())
pTabFrame1 = pTabFrame1->GetFollow();
}
const SwTabFrame *pTabFrame2 = pFrame->FindTabFrame(); if (pTabFrame2)
{ while (pTabFrame2->GetFollow())
pTabFrame2 = pTabFrame2->GetFollow();
}
bRet = (pTabFrame1 == pTabFrame2);
}
}
return bRet;
}
void SwAccessibleMap::FireEvent( const SwAccessibleEvent_Impl& rEvent )
{
::rtl::Reference < SwAccessibleContext > xAccImpl( rEvent.GetContext() ); if (!xAccImpl.is() && rEvent.mpParentFrame != nullptr)
{
SwAccessibleContextMap::iterator aIter = maFrameMap.find(rEvent.mpParentFrame); if (aIter != maFrameMap.end())
{
rtl::Reference < SwAccessibleContext > xContext( (*aIter).second.get() ); if (xContext.is() && (xContext->getAccessibleRole() == AccessibleRole::PARAGRAPH
|| xContext->getAccessibleRole() == AccessibleRole::BLOCK_QUOTE))
{
xAccImpl = xContext.get();
}
}
} if( SwAccessibleEvent_Impl::SHAPE_SELECTION == rEvent.GetType() )
{
DoInvalidateShapeSelection();
} elseif( xAccImpl.is() && xAccImpl->GetFrame() )
{ if ( rEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE &&
rEvent.IsInvalidateTextAttrs() )
{
xAccImpl->InvalidateAttr();
} switch( rEvent.GetType() )
{ case SwAccessibleEvent_Impl::INVALID_CONTENT:
xAccImpl->InvalidateContent(); break; case SwAccessibleEvent_Impl::POS_CHANGED:
xAccImpl->InvalidatePosOrSize( rEvent.GetOldBox() ); break; case SwAccessibleEvent_Impl::CHILD_POS_CHANGED:
xAccImpl->InvalidateChildPosOrSize( rEvent.GetFrameOrObj(),
rEvent.GetOldBox() ); break; case SwAccessibleEvent_Impl::DISPOSE:
assert(!"dispose event has been stored"); break; case SwAccessibleEvent_Impl::INVALID_ATTR: // nothing to do here - handled above break; default: break;
} if( SwAccessibleEvent_Impl::DISPOSE != rEvent.GetType() )
{ if( rEvent.IsUpdateCursorPos() )
xAccImpl->InvalidateCursorPos(); if( rEvent.IsInvalidateStates() )
xAccImpl->InvalidateStates( rEvent.GetStates() ); if( rEvent.IsInvalidateRelation() )
{ // both events CONTENT_FLOWS_FROM_RELATION_CHANGED and // CONTENT_FLOWS_TO_RELATION_CHANGED are possible if ( rEvent.GetAllStates() & AccessibleStates::RELATION_FROM )
{
xAccImpl->InvalidateRelation(
AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED );
} if ( rEvent.GetAllStates() & AccessibleStates::RELATION_TO )
{
xAccImpl->InvalidateRelation(
AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED );
}
}
if ( rEvent.IsInvalidateTextSelection() )
{
xAccImpl->InvalidateTextSelection();
}
}
}
}
if( mpEvents->IsFiring() )
{ // While events are fired new ones are generated. They have to be fired // now. This does not work for DISPOSE events!
OSL_ENSURE( rEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE, "dispose event while firing events" );
FireEvent( rEvent );
} else
{
SwAccessibleEventMap_Impl::iterator aIter =
mpEventMap->find( rEvent.GetFrameOrObj() ); if( aIter != mpEventMap->end() )
{
SwAccessibleEvent_Impl aEvent( *(*aIter).second );
assert( aEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE && "dispose events should not be stored" ); bool bAppendEvent = true; switch( rEvent.GetType() )
{ case SwAccessibleEvent_Impl::CARET_OR_STATES: // A CARET_OR_STATES event is added to any other // event only. It is broadcasted after any other event, so the // event should be put to the back.
OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED, "invalid event combination" );
aEvent.SetStates( rEvent.GetAllStates() ); break; case SwAccessibleEvent_Impl::INVALID_CONTENT: // An INVALID_CONTENT event overwrites a CARET_OR_STATES // event (but keeps its flags) and it is contained in a // POS_CHANGED event. // Therefore, the event's type has to be adapted and the event // has to be put at the end. // // fdo#56031 An INVALID_CONTENT event overwrites a INVALID_ATTR // event and overwrites its flags
OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED, "invalid event combination" ); if( aEvent.GetType() == SwAccessibleEvent_Impl::CARET_OR_STATES )
aEvent.SetType( SwAccessibleEvent_Impl::INVALID_CONTENT ); elseif ( aEvent.GetType() == SwAccessibleEvent_Impl::INVALID_ATTR )
{
aEvent.SetType( SwAccessibleEvent_Impl::INVALID_CONTENT );
aEvent.SetStates( rEvent.GetAllStates() );
}
break; case SwAccessibleEvent_Impl::POS_CHANGED: // A pos changed event overwrites CARET_STATES (keeping its // flags) as well as INVALID_CONTENT. The old box position // has to be stored however if the old event is not a // POS_CHANGED itself.
OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED, "invalid event combination" ); if( aEvent.GetType() != SwAccessibleEvent_Impl::POS_CHANGED )
aEvent.SetOldBox( rEvent.GetOldBox() );
aEvent.SetType( SwAccessibleEvent_Impl::POS_CHANGED ); break; case SwAccessibleEvent_Impl::CHILD_POS_CHANGED: // CHILD_POS_CHANGED events can only follow CHILD_POS_CHANGED // events. The only action that needs to be done again is // to put the old event to the back. The new one cannot be used, // because we are interested in the old frame bounds.
OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::CHILD_POS_CHANGED, "invalid event combination" ); break; case SwAccessibleEvent_Impl::SHAPE_SELECTION:
OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::SHAPE_SELECTION, "invalid event combination" ); break; case SwAccessibleEvent_Impl::DISPOSE: // DISPOSE events overwrite all others. They are not stored // but executed immediately to avoid broadcasting of // nonfunctional objects. So what needs to be done here is to // remove all events for the frame in question.
bAppendEvent = false; break; case SwAccessibleEvent_Impl::INVALID_ATTR: // tdf#150708 if the old is CARET_OR_STATES then try updating it // with the additional states if (aEvent.GetType() == SwAccessibleEvent_Impl::CARET_OR_STATES)
aEvent.SetStates(rEvent.GetAllStates()); else
{
OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::INVALID_ATTR, "invalid event combination" );
} break;
} if( bAppendEvent )
{
mpEvents->erase( (*aIter).second );
(*aIter).second = mpEvents->insert( mpEvents->end(), aEvent );
} else
{
mpEvents->erase( (*aIter).second );
mpEventMap->erase( aIter );
}
} elseif( SwAccessibleEvent_Impl::DISPOSE != rEvent.GetType() )
{
mpEventMap->emplace( rEvent.GetFrameOrObj(),
mpEvents->insert( mpEvents->end(), rEvent ) );
}
}
}
void SwAccessibleMap::InvalidateCursorPosition(const rtl::Reference<SwAccessibleContext>& rxAcc)
{
assert(rxAcc.is());
assert(rxAcc->GetFrame()); if (GetShell().ActionPend())
{
SwAccessibleEvent_Impl aEvent(SwAccessibleEvent_Impl::CARET_OR_STATES, rxAcc.get(),
SwAccessibleChild(rxAcc->GetFrame()),
AccessibleStates::CARET);
AppendEvent( aEvent );
} else
{
FireEvents(); // While firing events the current frame might have // been disposed because it moved out of the visible area. // Setting the cursor for such frames is useless and even // causes asserts. if (rxAcc->GetFrame())
rxAcc->InvalidateCursorPos();
}
}
//This method should implement the following functions: //1.find the shape objects and set the selected state. //2.find the Swframe objects and set the selected state. //3.find the paragraph objects and set the selected state. void SwAccessibleMap::InvalidateShapeInParaSelection()
{
DBG_TESTSOLARMUTEX();
//when InvalidateFocus Call this function ,and the current selected shape count is not 1 , //return if (bInvalidateFocusMode && nSelShapes != 1)
{ return;
} if( mpShapeMap )
pShapes = mpShapeMap->Copy( nShapes, pFESh, &pSelShape );
assert(maFrameMap.empty() && "Frame map should be empty after disposing the root frame");
assert((!mpShapeMap || mpShapeMap->empty()) && "Object map should be empty after disposing the root frame");
mpShapeMap.reset();
mvShapes.clear();
mpSelectedParas.reset();
if (xAcc->HasCursor() && !AreInSameTable(mxCursorContext, pFrame))
{ // If the new context has the focus, and if we know // another context that had the focus, then the focus // just moves from the old context to the new one. We // then have to send a focus event and a caret event for // the old context. We have to do that now, // because after we have left this method, anyone might // call getStates for the new context and will get a // focused state then. Sending the focus changes event // after that seems to be strange. However, we cannot // send a focus event for the new context now, because
--> --------------------
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.