/* -*- 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 .
*/
// If the point is inside the rectangle, then distance is 0 // Otherwise, compute the distance to the center of the rectangle. if ( !rRect.Contains( rPoint ) )
{
tools::Line aLine( rPoint, rRect.Center( ) );
nDist = aLine.GetLength( );
}
return nDist;
}
}
namespace {
//For SwFlyFrame::GetModelPositionForViewPoint class SwCursorOszControl
{ public: // So the compiler can initialize the class already. No DTOR and member // as public members const SwFlyFrame* m_pEntry; const SwFlyFrame* m_pStack1; const SwFlyFrame* m_pStack2;
auto pTextFrame = pFrame->DynCastTextFrame(); bool bSplitFly = false; if (pTextFrame && pTextFrame->HasNonLastSplitFlyDrawObj())
{ // Don't consider a non-last anchor of the split fly, so the view point can be corrected // to go to the nearest fly, instead of the last anchor on a later page.
bSplitFly = true;
}
/** Searches for the page containing the searched point. */ bool SwPageFrame::GetModelPositionForViewPoint( SwPosition *pPos, Point &rPoint,
SwCursorMoveState* pCMS, bool bTestBackground ) const
{
Point aPoint(std::clamp(rPoint.X(), getFrameArea().Left(), getFrameArea().Right()),
std::clamp(rPoint.Y(), getFrameArea().Top(), getFrameArea().Bottom()));
bool bRet = false; //Could it be a free flying one? //If his content should be protected, we can't set the Cursor in it, thus //all changes should be impossible. if ( GetSortedObjs() )
{
bRet = lcl_GetModelPositionForViewPoint_Objects( this, false, pPos, rPoint, pCMS );
}
//We fix the StartPoint if no Content below the page 'answers' and then //start all over again one page before the current one. //However we can't use Flys in such a case. if (!SwLayoutFrame::GetModelPositionForViewPoint(&aTextPos, aPoint, pCMS))
{ if ( pCMS && (pCMS->m_bStop || pCMS->m_bExactOnly) )
{
pCMS->m_bStop = true; returnfalse;
}
if ( !bTextRet )
{ // Set point to pCnt, delete mark // this may happen, if pCnt is hidden if (pCnt->IsTextFrame())
{
aTextPos = static_cast<SwTextFrame const*>(pCnt)->MapViewToModelPos(TextFrameIndex(0));
} else
{
assert(pCnt->IsNoTextFrame());
aTextPos.Assign( *static_cast<SwNoTextFrame const*>(pCnt)->GetNode() );
}
}
}
SwContentNode* pContentNode = aTextPos.GetNode().GetContentNode(); bool bConsiderBackground = true; // If the text position is a clickable field, then that should have priority. if (pContentNode && pContentNode->IsTextNode())
{
SwTextNode* pTextNd = pContentNode->GetTextNode();
SwTextAttr* pTextAttr = pTextNd->GetTextAttrForCharAt(aTextPos.GetContentIndex(), RES_TXTATR_FIELD); if (pTextAttr)
{ const SwField* pField = pTextAttr->GetFormatField().GetField(); if (pField->IsClickable())
bConsiderBackground = false;
}
}
bool bBackRet = false; // Check objects in the background if nothing else matched if ( GetSortedObjs() )
{
bBackRet = lcl_GetModelPositionForViewPoint_Objects( this, true, &aBackPos, rPoint, pCMS );
}
if (bConsiderBackground && bTestBackground && bBackRet)
{
(*pPos) = std::move(aBackPos);
} elseif (!bBackRet)
{
(*pPos) = std::move(aTextPos);
} else// bBackRet && !(bConsiderBackground && bTestBackground)
{ /* In order to provide a selection as accurate as possible when we have both * text and background object, then we compute the distance between both * would-be positions and the click point. The shortest distance wins.
*/ double nTextDistance = 0; bool bValidTextDistance = false; if (pContentNode)
{
SwContentFrame* pTextFrame = pContentNode->getLayoutFrame( getRootFrame( ) );
// try this again but prefer the "previous" position
SwCursorMoveState aMoveState;
SwCursorMoveState *const pState(pCMS ? pCMS : &aMoveState);
comphelper::FlagRestorationGuard g(
pState->m_bPosMatchesBounds, true);
SwPosition prevTextPos(*pPos); if (SwLayoutFrame::GetModelPositionForViewPoint(&prevTextPos, aPoint, pState))
{
SwRect aTextRect;
pTextFrame->GetCharRect(aTextRect, prevTextPos);
if (prevTextPos.GetContentIndex() < pContentNode->Len())
{ // aRextRect is just a line on the left edge of the // previous character; to get a better measure from // lcl_getDistance, extend that to a rectangle over // the entire character.
SwPosition nextTextPos(std::move(prevTextPos));
nextTextPos.AdjustContent(+1);
SwRect nextTextRect;
pTextFrame->GetCharRect(nextTextRect, nextTextPos);
SwRectFnSet aRectFnSet(pTextFrame); if (aRectFnSet.GetTop(aTextRect) ==
aRectFnSet.GetTop(nextTextRect)) // same line?
{ // need to handle mixed RTL/LTR portions somehow if (aRectFnSet.GetLeft(aTextRect) <
aRectFnSet.GetLeft(nextTextRect))
{
aRectFnSet.SetRight( aTextRect,
aRectFnSet.GetLeft(nextTextRect));
} else// RTL
{
aRectFnSet.SetLeft( aTextRect,
aRectFnSet.GetLeft(nextTextRect));
}
}
}
/** * If this is about a Content-carrying cell the Cursor will be force inserted into one of the ContentFrames * if there are no other options. * * There is no entry for protected cells.
*/ bool SwCellFrame::GetModelPositionForViewPoint( SwPosition *pPos, Point &rPoint,
SwCursorMoveState* pCMS, bool ) const
{
vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut(); // cell frame does not necessarily have a lower (split table cell) if ( !Lower() ) returnfalse;
if ( !(pCMS && pCMS->m_bSetInReadOnly) &&
GetFormat()->GetProtect().IsContentProtected() ) returnfalse;
while (pFrame && !bRet)
{
pFrame->Calc(pRenderContext); if (pFrame->getFrameArea().Contains(rPoint))
{
bRet = pFrame->GetModelPositionForViewPoint(pPos, rPoint, pCMS); if (pCMS && pCMS->m_bStop) returnfalse;
}
pFrame = pFrame->GetNext();
} if (!bRet)
{ constbool bFill = pCMS && pCMS->m_pFill;
Point aPoint(rPoint); const SwContentFrame *pCnt = GetContentPos(rPoint, true); if (bFill && pCnt->IsTextFrame())
{
rPoint = aPoint;
}
pCnt->GetModelPositionForViewPoint(pPos, rPoint, pCMS);
} returntrue;
}
//Problem: If two Flys have the same size and share the same position then //they end inside each other. //Because we recursively check if a Point doesn't randomly lie inside another //fly which lies completely inside the current Fly we could trigger an endless //loop with the mentioned situation above. //Using the helper class SwCursorOszControl we prevent the recursion. During //a recursion GetModelPositionForViewPoint picks the one which lies on top. bool SwFlyFrame::GetModelPositionForViewPoint( SwPosition *pPos, Point &rPoint,
SwCursorMoveState* pCMS, bool ) const
{
vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut();
g_OszCtrl.Entry( this );
//If the Points lies inside the Fly, we try hard to set the Cursor inside it. //However if the Point sits inside a Fly which is completely located inside //the current one, we call GetModelPositionForViewPoint for it.
Calc(pRenderContext); bool bInside = getFrameArea().Contains( rPoint ) && Lower(); bool bRet = false;
//If a Frame contains a graphic, but only text was requested, it basically //won't accept the Cursor. if ( bInside && pCMS && pCMS->m_eState == CursorMoveState::SetOnlyText)
{ const SwFrame* pLower = Lower(); if (!pLower || pLower->IsNoTextFrame())
bInside = false;
}
//We have to cheat a little bit during a table selection: Go to the //beginning of the cell while going up and go to the end of the cell while //going down. bool bTableSel = false; if ( pStart->IsInTab() &&
pPam->GetPointNode().StartOfSectionNode() !=
pPam->GetMarkNode().StartOfSectionNode() )
{
bTableSel = true; const SwLayoutFrame *pCell = pStart->GetUpper(); while ( !pCell->IsCellFrame() )
pCell = pCell->GetUpper();
// Check, if cell has a Prev/Follow cell: constbool bFwd = ( fnNxtPrv == lcl_GetNxtCnt ); const SwLayoutFrame* pTmpCell = bFwd ? static_cast<const SwCellFrame*>(pCell)->GetFollowCell() : static_cast<const SwCellFrame*>(pCell)->GetPreviousCell();
SwTwips nX = 0; if ( bTab )
{ // pStart or pCnt is inside a table. nX will be used for travelling:
SwRect aRect( pStart->getFrameArea() );
pStart->GetCharRect( aRect, *pPam->GetPoint() );
Point aCenter = aRect.Center();
nX = aRectFnSet.IsVert() ? aCenter.Y() : aCenter.X();
if ( pStTab &&
!pStTab->GetUpper()->IsInTab() &&
!pTable->GetUpper()->IsInTab() )
{ const SwFrame *pCell = pStart->GetUpper(); while ( pCell && !pCell->IsCellFrame() )
pCell = pCell->GetUpper();
OSL_ENSURE( pCell, "could not find the cell" );
nX = aRectFnSet.XInc(aRectFnSet.GetLeft(pCell->getFrameArea()),
aRectFnSet.GetWidth(pCell->getFrameArea()) / 2);
//The flow leads from one table to the next. The X-value needs to be //corrected based on the middle of the starting cell by the amount //of the offset of the tables. if ( pStTab != pTable )
{
nX += aRectFnSet.GetLeft(pTable->getFrameArea()) -
aRectFnSet.GetLeft(pStTab->getFrameArea());
}
}
// Restrict nX to the left and right borders of pTab: // (is this really necessary?) if (pTable && !pTable->GetUpper()->IsInTab())
{ constbool bRTL = pTable->IsRightToLeft(); const tools::Long nPrtLeft = bRTL ?
aRectFnSet.GetPrtRight(*pTable) :
aRectFnSet.GetPrtLeft(*pTable); if (bRTL != (aRectFnSet.XDiff(nPrtLeft, nX) > 0))
nX = nPrtLeft; else
{ const tools::Long nPrtRight = bRTL ?
aRectFnSet.GetPrtLeft(*pTable) :
aRectFnSet.GetPrtRight(*pTable); if (bRTL != (aRectFnSet.XDiff(nX, nPrtRight) > 0))
nX = nPrtRight;
}
}
}
do
{ //If I'm in the DocumentBody, I want to stay there. if ( pStart->IsInDocBody() )
{ while (pCnt && (!pCnt->IsInDocBody() || pCnt->IsHiddenNow()))
{
pCnt = (*fnNxtPrv)( pCnt );
pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
}
}
//If I'm in the FootNoteArea, I try to reach the next FootNoteArea in //case of necessity. elseif ( pStart->IsInFootnote() )
{ while (pCnt && (!pCnt->IsInFootnote() || pCnt->IsHiddenNow()))
{
pCnt = (*fnNxtPrv)( pCnt );
pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
}
}
//In Flys we can go ahead blindly as long as we find a Content. elseif ( pStart->IsInFly() )
{ if (pCnt && pCnt->IsHiddenNow())
{
pCnt = (*fnNxtPrv)( pCnt );
pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel );
}
}
if ( bTab )
{ if ( !pCnt )
bEnd = true; else
{ const SwTabFrame *pTab = pCnt->FindTabFrame(); if( !pTab )
bEnd = true; else
{ if ( pTab != pTable )
{ //The flow leads from one table to the next. The X-value //needs to be corrected by the amount of the offset of //the tables if ( pTable &&
!pTab->GetUpper()->IsInTab() &&
!pTable->GetUpper()->IsInTab() )
nX += pTab->getFrameArea().Left() - pTable->getFrameArea().Left();
pTable = pTab;
} const SwLayoutFrame *pCell = pCnt->GetUpper(); while ( pCell && !pCell->IsCellFrame() )
pCell = pCell->GetUpper();
Point aInsideCell;
Point aInsideCnt; if ( pCell )
{
tools::Long nTmpTop = aRectFnSet.GetTop(pCell->getFrameArea()); if ( aRectFnSet.IsVert() )
{ if ( nTmpTop )
nTmpTop = aRectFnSet.XInc(nTmpTop, -1);
/** Returns the number of the current page. * * If the method gets a PaM then the current page is the one in which the PaM sits. Otherwise the * current page is the first one inside the VisibleArea. We only work on available pages!
*/
sal_uInt16 SwRootFrame::GetCurrPage( const SwPaM *pActualCursor ) const
{
assert(pActualCursor && "got no page cursor");
SwFrame const*const pActFrame = pActualCursor->GetPoint()->GetNode().
GetContentNode()->getLayoutFrame(this,
pActualCursor->GetPoint()); return pActFrame->FindPageFrame()->GetPhyPageNum();
}
/** Returns a PaM which sits at the beginning of the requested page. * * Formatting is done as far as necessary. * The PaM sits on the last page, if the page number was chosen too big. * * @return Null, if the operation was not possible.
*/
sal_uInt16 SwRootFrame::SetCurrPage( SwCursor* pToSet, sal_uInt16 nPageNum )
{
vcl::RenderContext* pRenderContext = GetCurrShell() ? GetCurrShell()->GetOut() : nullptr;
SwFrame* pLower = Lower();
assert( (pLower && pLower->IsPageFrame()) && "No page available." );
SwPageFrame *pPage = static_cast<SwPageFrame*>(pLower); bool bEnd =false; while ( !bEnd && pPage->GetPhyPageNum() != nPageNum )
{ if ( pPage->GetNext() )
pPage = static_cast<SwPageFrame*>(pPage->GetNext()); else
{ //Search the first ContentFrame and format until a new page is started //or until the ContentFrame are all done. const SwContentFrame *pContent = pPage->ContainsContent(); while ( pContent && pPage->IsAnLower( pContent ) )
{
pContent->Calc(pRenderContext);
pContent = pContent->GetNextContentFrame();
} //Either this is a new page or we found the last page. if ( pPage->GetNext() )
pPage = static_cast<SwPageFrame*>(pPage->GetNext()); else
bEnd = true;
}
} //pPage now points to the 'requested' page. Now we have to create the PaM //on the beginning of the first ContentFrame in the body-text. //If this is a footnote-page, the PaM will be set in the first footnote. const SwContentFrame *pContent = pPage->ContainsContent(); if ( pPage->IsFootnotePage() ) while ( pContent && !pContent->IsInFootnote() )
pContent = pContent->GetNextContentFrame(); else while ( pContent && !pContent->IsInDocBody() )
pContent = pContent->GetNextContentFrame(); if ( pContent )
{
assert(pContent->IsTextFrame());
SwTextFrame const*const pFrame(static_cast<const SwTextFrame*>(pContent));
*pToSet->GetPoint() = pFrame->MapViewToModelPos(pFrame->GetOffset());
/** * Returns the first/last Contentframe (controlled using the parameter fnPosPage) * of the current/previous/next page (controlled using the parameter fnWhichPage).
*/ bool GetFrameInPage( const SwContentFrame *pCnt, SwWhichPage fnWhichPage,
SwPosPage fnPosPage, SwPaM *pPam )
{ //First find the requested page, at first the current, then the one which //was requests through fnWichPage. const SwLayoutFrame *pLayoutFrame = pCnt->FindPageFrame(); if ( !pLayoutFrame || (nullptr == (pLayoutFrame = (*fnWhichPage)(pLayoutFrame))) ) returnfalse;
//Now the desired ContentFrame below the page
pCnt = (*fnPosPage)(pLayoutFrame); if( nullptr == pCnt ) returnfalse; else
{ // repeated headlines in tables if ( pCnt->IsInTab() && fnPosPage == GetFirstSub )
{ const SwTabFrame* pTab = pCnt->FindTabFrame(); if ( pTab->IsFollow() )
{ if ( pTab->IsInHeadline( *pCnt ) )
{
SwLayoutFrame* pRow = pTab->GetFirstNonHeadlineRow(); if ( pRow )
{ // We are in the first line of a follow table // with repeated headings. // To actually make a "real" move we take the first content // of the next row
pCnt = pRow->ContainsContent(); if ( ! pCnt ) returnfalse;
}
}
}
}
static sal_uInt64 CalcDiff(const Point &rPt1, const Point &rPt2)
{ //Calculate the distance between the two points. //'delta' X^2 + 'delta'Y^2 = 'distance'^2
sal_uInt64 dX = std::max( rPt1.X(), rPt2.X() ) -
std::min( rPt1.X(), rPt2.X() ),
dY = std::max( rPt1.Y(), rPt2.Y() ) -
std::min( rPt1.Y(), rPt2.Y() ); return (dX * dX) + (dY * dY);
}
/** Check if the point lies inside the page part in which also the ContentFrame lies. * * In this context header, page body, footer and footnote-container count as page part. * This will suit the purpose that the ContentFrame which lies in the "right" page part will be * accepted instead of one which doesn't lie there although his distance to the point is shorter.
*/ staticconst SwLayoutFrame* lcl_Inside( const SwContentFrame *pCnt, Point const & rPt )
{ const SwLayoutFrame* pUp = pCnt->GetUpper(); while( pUp )
{ if( pUp->IsPageBodyFrame() || pUp->IsFooterFrame() || pUp->IsHeaderFrame() )
{ if( rPt.Y() >= pUp->getFrameArea().Top() && rPt.Y() <= pUp->getFrameArea().Bottom() ) return pUp; return nullptr;
} if( pUp->IsFootnoteContFrame() ) return pUp->getFrameArea().Contains( rPt ) ? pUp : nullptr;
pUp = pUp->GetUpper();
} return nullptr;
}
/** Search for the nearest Content to pass. * * Considers the previous, the current and the next page. * If no content is found, the area gets expanded until one is found. * * @return The 'semantically correct' position inside the PrtArea of the found ContentFrame.
*/ const SwContentFrame *SwLayoutFrame::GetContentPos( Point& rPoint, constbool bDontLeave, constbool bBodyOnly,
SwCursorMoveState *pCMS, constbool bDefaultExpand ) const
{ //Determine the first ContentFrame. const SwLayoutFrame *pStart = (!bDontLeave && bDefaultExpand && GetPrev()) ? static_cast<const SwLayoutFrame*>(GetPrev()) : this; const SwContentFrame *pContent = pStart->ContainsContent();
while ( true ) //A loop to be sure we always find one.
{ while ( pContent &&
((!bDontLeave || IsAnLower( pContent )) &&
(pContent->GetPhyPageNum() <= nMaxPage)) )
{ if ( pContent->getFrameArea().Width() &&
( !bBodyOnly || pContent->IsInDocBody() ) )
{ //If the Content lies in a protected area (cell, Footnote, section), //we search the next Content which is not protected. const SwContentFrame *pComp = pContent;
pContent = ::lcl_MissProtectedFrames( pContent, lcl_GetNxtCnt, false,
pCMS && pCMS->m_bSetInReadOnly, false ); if ( pComp != pContent ) continue;
if (!pContent->IsHiddenNow())
{
SwRect aContentFrame( pContent->UnionFrame() ); if ( aContentFrame.Contains( rPoint ) )
{
pActual = pContent;
aPoint = rPoint; break;
} //The distance from rPoint to the nearest Point of pContent //will now be calculated.
Point aContentPoint( rPoint );
//First set the vertical position if ( aContentFrame.Top() > aContentPoint.Y() )
aContentPoint.setY( aContentFrame.Top() ); elseif ( aContentFrame.Bottom() < aContentPoint.Y() )
aContentPoint.setY( aContentFrame.Bottom() );
//Now the horizontal position if ( aContentFrame.Left() > aContentPoint.X() )
aContentPoint.setX( aContentFrame.Left() ); elseif ( aContentFrame.Right() < aContentPoint.X() )
aContentPoint.setX( aContentFrame.Right() );
// pInside is a page area in which the point lies. As soon // as pInside != 0 only frames are accepted which are // placed inside. if( !pInside || ( pInside->IsAnLower( pContent ) &&
( !pContent->IsInFootnote() || pInside->IsFootnoteContFrame() ) ) )
{ const sal_uInt64 nDiff = ::CalcDiff(aContentPoint, rPoint); bool bBetter = nDiff < nDistance; // This one is nearer if( !pInside )
{
pInside = lcl_Inside( pContent, rPoint ); if( pInside ) // In the "right" page area
bBetter = true;
} if( bBetter )
{
aPoint = aContentPoint;
nDistance = nDiff;
pActual = pContent;
}
}
}
}
pContent = pContent->GetNextContentFrame(); if ( bBodyOnly ) while ( pContent && !pContent->IsInDocBody() )
pContent = pContent->GetNextContentFrame();
} if ( !pActual )
{ //If we not yet found one we have to expand the searched //area, sometime we will find one! //MA 1997-01-09: Opt for many empty pages - if we only search inside //the body, we can expand the searched area sufficiently in one step. if ( bBodyOnly )
{ while ( !pContent && pStart->GetPrev() )
{
++nMaxPage; if( !pStart->GetPrev()->IsLayoutFrame() ) return nullptr;
pStart = static_cast<const SwLayoutFrame*>(pStart->GetPrev()); if( pStart->IsInDocBody() )
pContent = pStart->ContainsContent(); else
{ const SwPageFrame *pPage = pStart->FindPageFrame(); if( !pPage ) return nullptr;
pContent = pPage->FindFirstBodyContent();
}
} if ( !pContent ) // Somewhere down the road we have to start with one!
{ const SwPageFrame *pPage = pStart->FindPageFrame(); if( !pPage ) return nullptr;
pContent = pPage->GetUpper()->ContainsContent(); while ( pContent && !pContent->IsInDocBody() )
pContent = pContent->GetNextContentFrame(); if ( !pContent ) return nullptr; // There is no document content yet!
}
} else
{
++nMaxPage; if ( pStart->GetPrev() )
{ if( !pStart->GetPrev()->IsLayoutFrame() ) return nullptr;
pStart = static_cast<const SwLayoutFrame*>(pStart->GetPrev());
pContent = pStart->ContainsContent();
} else// Somewhere down the road we have to start with one!
{ const SwPageFrame *pPage = pStart->FindPageFrame(); if( !pPage ) return nullptr;
pContent = pPage->GetUpper()->ContainsContent();
}
}
pActual = pContent;
} else break;
}
OSL_ENSURE( pActual, "no Content found." );
OSL_ENSURE( !bBodyOnly || pActual->IsInDocBody(), "Content not in Body." );
//Special case for selecting tables not in repeated TableHeadlines. if ( pActual->IsInTab() && pCMS && pCMS->m_eState == CursorMoveState::TableSel )
{ const SwTabFrame *pTab = pActual->FindTabFrame(); if ( pTab->IsFollow() && pTab->IsInHeadline( *pActual ) )
{
pCMS->m_bStop = true; return nullptr;
}
}
//A small correction at the first/last
Size aActualSize( pActual->getFramePrintArea().SSize() ); if ( aActualSize.Height() > pActual->GetUpper()->getFramePrintArea().Height() )
aActualSize.setHeight( pActual->GetUpper()->getFramePrintArea().Height() );
//Bring the point into the PrtArea.
assert(pAct); const SwRect aRect( pAct->getFrameArea().Pos() + pAct->getFramePrintArea().Pos(), pAct->getFramePrintArea().SSize() ); if ( aAct.Y() < aRect.Top() )
aAct.setY( aRect.Top() ); elseif ( aAct.Y() > aRect.Bottom() )
aAct.setY( aRect.Bottom() ); if ( aAct.X() < aRect.Left() )
aAct.setX( aRect.Left() ); elseif ( aAct.X() > aRect.Right() )
aAct.setX( aRect.Right() );
if (!pAct->isFrameAreaDefinitionValid() ||
(pAct->IsTextFrame() && !static_cast<SwTextFrame const*>(pAct)->HasPara()))
{ // ContentFrame not formatted -> always on node-beginning // tdf#100635 also if the SwTextFrame would require reformatting, // which is unwanted in case this is called from text formatting code
rPos = static_cast<SwTextFrame const*>(pAct)->MapViewToModelPos(TextFrameIndex(0));
} else
{
SwCursorMoveState aTmpState( CursorMoveState::SetOnlyText );
pAct->GetModelPositionForViewPoint( &rPos, aAct, &aTmpState );
}
}
/** Search the nearest Content to the passed point. * * Only search inside the BodyText. * @note Only the nearest vertically one will be searched. * @note JP 11.10.2001: only in tables we try to find the right column - Bug 72294
*/
Point SwRootFrame::GetNextPrevContentPos( const Point& rPoint, bool bNext ) const
{
vcl::RenderContext* pRenderContext = GetCurrShell() ? GetCurrShell()->GetOut() : nullptr; // #123110# - disable creation of an action by a callback // event during processing of this method. Needed because formatting is // triggered by this method.
DisableCallbackAction aDisableCallbackAction(const_cast<SwRootFrame&>(*this)); //Search the first ContentFrame and his successor in the body area. //To be efficient (and not formatting too much) we'll start at the correct //page. const SwLayoutFrame *pPage = static_cast<const SwLayoutFrame*>(Lower()); if( pPage ) while( pPage->GetNext() && pPage->getFrameArea().Bottom() < rPoint.Y() )
pPage = static_cast<const SwLayoutFrame*>(pPage->GetNext());
pCnt->Calc(pRenderContext); if( !bNext )
{ // As long as the point lies before the first ContentFrame and there are // still precedent pages I'll go to the next page.
assert(pPage); while ( rPoint.Y() < pCnt->getFrameArea().Top() && pPage->GetPrev() )
{
pPage = static_cast<const SwLayoutFrame*>(pPage->GetPrev());
pCnt = pPage->ContainsContent(); while ( !pCnt )
{
pPage = static_cast<const SwLayoutFrame*>(pPage->GetPrev()); if ( pPage )
pCnt = pPage->ContainsContent(); else
{
pCnt = ContainsContent(); return pCnt ? pCnt->UnionFrame().Pos() : Point();
}
}
pCnt->Calc(pRenderContext);
}
}
//Does the point lie above the first ContentFrame? if ( rPoint.Y() < pCnt->getFrameArea().Top() && !lcl_IsInRepeatedHeadline( pCnt ) ) return pCnt->UnionFrame().Pos();
Point aRet(0, 0); do
{ //Does the point lie in the current ContentFrame?
SwRect aContentFrame( pCnt->UnionFrame() ); if ( aContentFrame.Contains( rPoint ) && !lcl_IsInRepeatedHeadline( pCnt ))
{
aRet = rPoint; break;
}
//Is the current one the last ContentFrame? //If the next ContentFrame lies behind the point, then the current on is the //one we searched. const SwContentFrame *pNxt = pCnt->GetNextContentFrame(); while ( pNxt && !pNxt->IsInDocBody() )
pNxt = pNxt->GetNextContentFrame();
//Does the point lie behind the last ContentFrame? if ( !pNxt )
{
aRet = Point( aContentFrame.Right(), aContentFrame.Bottom() ); break;
}
//If the next ContentFrame lies behind the point then it is the one we //searched. const SwTabFrame* pTFrame;
pNxt->Calc(pRenderContext); if( pNxt->getFrameArea().Top() > rPoint.Y() &&
!lcl_IsInRepeatedHeadline( pCnt, &pTFrame ) &&
( !pTFrame || pNxt->getFrameArea().Left() > rPoint.X() ))
{ if (bNext)
aRet = pNxt->getFrameArea().Pos(); else
aRet = Point( aContentFrame.Right(), aContentFrame.Bottom() ); break;
}
pCnt = pNxt;
} while (pCnt); return aRet;
}
/** Returns the absolute document position of the desired page. * * Formatting is done only as far as needed and only if bFormat=true. * Pos is set to the one of the last page, if the page number was chosen too big. * * @return Null, if the operation failed.
*/
Point SwRootFrame::GetPagePos( sal_uInt16 nPageNum ) const
{ const SwFrame* pLower = Lower();
assert( (pLower && pLower->IsPageFrame()) && "No page available." );
/** Is the Frame or rather the Section in which it lies protected? * * Also Fly in Fly in ... and Footnotes
*/ bool SwFrame::IsProtected() const
{ if (IsTextFrame())
{ const SwDoc *pDoc = &static_cast<const SwTextFrame*>(this)->GetDoc(); bool isFormProtected=pDoc->GetDocumentSettingManager().get(DocumentSettingId::PROTECT_FORM ); if (isFormProtected)
{ returnfalse; // TODO a hack for now, well deal with it later, I we return true here we have a "double" locking
}
} //The Frame can be protected in borders, cells or sections. //Also goes up FlyFrames recursive and from footnote to anchor. const SwFrame *pFrame = this; do
{ if (pFrame->IsTextFrame())
{ // sw_redlinehide: redlines can't overlap section nodes, so any node will do if (static_cast<SwTextFrame const*>(pFrame)->GetTextNodeFirst()->IsInProtectSect())
{ returntrue;
}
} elseif ( pFrame->IsContentFrame() )
{
assert(pFrame->IsNoTextFrame()); if (static_cast<const SwNoTextFrame*>(pFrame)->GetNode() && static_cast<const SwNoTextFrame*>(pFrame)->GetNode()->IsInProtectSect())
{ returntrue;
}
} else
{ if ( static_cast<const SwLayoutFrame*>(pFrame)->GetFormat() && static_cast<const SwLayoutFrame*>(pFrame)->GetFormat()->
GetProtect().IsContentProtected() ) returntrue; if ( pFrame->IsCoveredCell() ) returntrue;
} if ( pFrame->IsFlyFrame() )
{ //In a chain the protection of the content can be specified by the //master of the chain. if ( static_cast<const SwFlyFrame*>(pFrame)->GetPrevLink() )
{ const SwFlyFrame *pMaster = static_cast<const SwFlyFrame*>(pFrame); do
{ pMaster = pMaster->GetPrevLink();
} while ( pMaster->GetPrevLink() ); if ( pMaster->IsProtected() ) returntrue;
}
pFrame = static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame();
} elseif ( pFrame->IsFootnoteFrame() )
pFrame = static_cast<const SwFootnoteFrame*>(pFrame)->GetRef(); else
pFrame = pFrame->GetUpper();
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.