/* -*- 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 .
*/
bool SwPosition::operator<(const SwPosition &rPos) const
{ // cheaper to check for == first if( nNode == rPos.nNode )
{ // note that positions with text node but no SwContentIndex registered are // created for text frames anchored at para (see SwXFrame::getAnchor())
SwContentNode const*const pThisReg(GetContentNode());
SwContentNode const*const pOtherReg(rPos.GetContentNode()); if (pThisReg && pOtherReg)
{ return (nContent < rPos.nContent);
} else// by convention position with no index is smaller
{ return pOtherReg != nullptr;
}
} return nNode < rPos.nNode;
}
bool SwPosition::operator>(const SwPosition &rPos) const
{ // cheaper to check for == first if( nNode == rPos.nNode )
{ // note that positions with text node but no SwContentIndex registered are // created for text frames anchored at para (see SwXFrame::getAnchor())
SwContentNode const*const pThisReg(GetContentNode());
SwContentNode const*const pOtherReg(rPos.GetContentNode()); if (pThisReg && pOtherReg)
{ return (nContent > rPos.nContent);
} else// by convention position with no index is smaller
{ return pThisReg != nullptr;
}
} return nNode > rPos.nNode;
}
bool SwPosition::operator<=(const SwPosition &rPos) const
{ // cheaper to check for == first if( nNode == rPos.nNode )
{ // note that positions with text node but no SwContentIndex registered are // created for text frames anchored at para (see SwXFrame::getAnchor())
SwContentNode const*const pThisReg(GetContentNode());
SwContentNode const*const pOtherReg(rPos.GetContentNode()); if (pThisReg && pOtherReg)
{ return (nContent <= rPos.nContent);
} else// by convention position with no index is smaller
{ return pThisReg == nullptr;
}
} return nNode < rPos.nNode;
}
bool SwPosition::operator>=(const SwPosition &rPos) const
{ // cheaper to check for == first if( nNode == rPos.nNode )
{ // note that positions with text node but no SwContentIndex registered are // created for text frames anchored at para (see SwXFrame::getAnchor())
SwContentNode const*const pThisReg(GetContentNode());
SwContentNode const*const pOtherReg(rPos.GetContentNode()); if (pThisReg && pOtherReg)
{ return (nContent >= rPos.nContent);
} else// by convention position with no index is smaller
{ return pOtherReg == nullptr;
}
} return nNode > rPos.nNode;
}
/** Check if the given range is inside one of the defined top-level sections. * * The top-level sections are Content, AutoText, PostIts, Inserts, and Redlines. * * @param bChkSection if true, also check that the given range is inside * a single second-level section inside any of the * top-level sections, except for the Content section. * * @return <true> if valid range
*/ bool CheckNodesRange( const SwNode& rStt, const SwNode& rEnd, bool bChkSection )
{ const SwNodes& rNds = rStt.GetNodes();
SwNodeOffset nStt = rStt.GetIndex(), nEnd = rEnd.GetIndex();
CHKSECTION eSec = lcl_TstIdx( nStt, nEnd, rNds.GetEndOfContent() ); if( Chk_None != eSec ) return eSec == Chk_Both;
Sets the first SwPaM onto the given SwPaM, or to the beginning or end of a document. SPoint stays at its position, GetMark will be changed respectively.
@param fnMove Contains information if beginning or end of document. @param pOrigRg The given region. @param rPam returns newly created range, in Ring with parameter pOrigRg.
*/ void MakeRegion(SwMoveFnCollection const & fnMove, const SwPaM & rOrigRg, std::optional<SwPaM>& rPam)
{
rPam.emplace(rOrigRg, const_cast<SwPaM*>(&rOrigRg)); // given search range // make sure that SPoint is on the "real" start position // FORWARD: SPoint always smaller than GetMark // BACKWARD: SPoint always bigger than GetMark if( (rPam->GetMark()->*fnMove.fnCmpOp)( *rPam->GetPoint() ) )
rPam->Exchange();
}
// form view - see also SwCursorShell::IsCursorReadonly() staticconst SwFrame* lcl_FindEditInReadonlyFrame( const SwFrame& rFrame )
{ const SwFrame* pRet = nullptr;
if ( !bRet && bFormView )
{ // Check if start and end frame are inside the _same_ // edit-in-readonly-environment. Otherwise we better return 'true' if ( pPointEditInReadonlyFrame != pMarkEditInReadonlyFrame )
bRet = true;
}
// If a protected section should be between nodes, then the // selection needs to contain already x nodes. // (TextNd, SectNd, TextNd, EndNd, TextNd ) if( nSttIdx + SwNodeOffset(3) < nEndIdx )
{ const SwSectionFormats& rFormats = GetDoc().GetSections(); for( SwSectionFormats::size_type n = rFormats.size(); n; )
{ const SwSectionFormat* pFormat = rFormats[ --n ]; if( pFormat->GetProtect().IsContentProtected() )
{ const SwFormatContent& rContent = pFormat->GetContent(false);
OSL_ENSURE( rContent.GetContentIdx(), "where is the SectionNode?" );
SwNodeOffset nIdx = rContent.GetContentIdx()->GetIndex(); if( nSttIdx <= nIdx && nEndIdx >= nIdx &&
rContent.GetContentIdx()->GetNode().GetNodes().IsDocNodes() )
{
bRet = true; break;
}
}
}
}
}
}
const SwDoc& rDoc = GetDoc(); // Legacy text/combo/checkbox: never return read-only when inside these form fields. const IDocumentMarkAccess* pMarksAccess = rDoc.getIDocumentMarkAccess();
sw::mark::Fieldmark* pA = GetPoint() ? pMarksAccess->getInnerFieldmarkFor(*GetPoint()) : nullptr;
sw::mark::Fieldmark* pB = GetMark() ? pMarksAccess->getInnerFieldmarkFor(*GetMark()) : pA; // prevent the user from accidentally deleting the field itself when modifying the text. constbool bAtStartA = (pA != nullptr) && (pA->GetMarkStart() == *GetPoint()); constbool bAtStartB = (pB != nullptr) && (pB->GetMarkStart() == *GetMark());
if (officecfg::Office::Common::Filter::Microsoft::Import::ForceImportWWFieldsAsGenericFields::get())
{
; // allow editing all fields in generic mode
} elseif (!bRet)
{ bool bUnhandledMark = pA && pA->GetFieldname( ) == ODF_UNHANDLED; // Unhandled fieldmarks case shouldn't be edited manually to avoid breaking anything if ( ( pA == pB ) && bUnhandledMark )
bRet = true; else
{ if ((pA == pB) && (bAtStartA != bAtStartB))
bRet = true; elseif (pA != pB)
{ // If both points are either outside or at marks edges (i.e. selection either // touches fields, or fully encloses it), then don't disable editing
bRet = !( ( !pA || bAtStartA ) && ( !pB || bAtStartB ) );
} if( !bRet && rDoc.GetDocumentSettingManager().get( DocumentSettingId::PROTECT_FORM ) && (pA || pB) )
{ // Form protection case
bRet = ( pA == nullptr ) || ( pB == nullptr ) || bAtStartA || bAtStartB;
}
}
} else
{ // Allow editing when the cursor/selection is fully inside of a legacy form field.
bRet = !( pA != nullptr && !bAtStartA && !bAtStartB && pA == pB );
if (bRet)
{ // Also allow editing inside content controls in general, similar to form fields. // Specific types will be disabled below. if (const SwEditShell* pEditShell = rDoc.GetEditShell())
bRet = !pEditShell->CursorInsideContentControl();
}
}
if (!bRet)
{ // Paragraph Signatures and Classification fields are read-only. if (const SwEditShell* pEditShell = rDoc.GetEditShell())
bRet = pEditShell->IsCursorInParagraphMetadataField();
}
if (!bRet &&
rDoc.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
{ if (rDoc.getIDocumentMarkAccess()->isBookmarkDeleted(*this, isReplace))
{ returntrue;
}
} if (!bRet &&
rDoc.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FIELDS))
{
SwPosition const& rStart(*Start());
SwPosition const& rEnd(*End()); for (SwNodeIndex n(rStart.GetNode()); n <= rEnd.GetNode(); ++n)
{ if (SwTextNode const*const pNode = n.GetNode().GetTextNode())
{ if (SwpHints const*const pHints = pNode->GetpSwpHints())
{ for (size_t i = 0; i < pHints->Count(); ++i)
{
SwTextAttr const*const pHint(pHints->Get(i)); if (n == rStart.GetNode() && pHint->GetStart() < rStart.GetContentIndex())
{ continue; // before selection
} if (n == rEnd.GetNode() && rEnd.GetContentIndex() <= pHint->GetStart())
{ break; // after selection
} if (pHint->Which() == RES_TXTATR_FIELD // placeholders don't work if you can't delete them
&& pHint->GetFormatField().GetField()->GetTyp()->Which() != SwFieldIds::JumpEdit)
{ returntrue;
}
}
}
}
}
}
if (!bRet)
{ // See if we're inside a read-only content control. const SwPosition* pStart = Start();
SwTextNode* pTextNode = pStart->GetNode().GetTextNode(); if (pTextNode)
{
sal_Int32 nIndex = pStart->GetContentIndex();
SwTextAttr* pAttr
= pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent); auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr); if (pTextContentControl)
{ const SwFormatContentControl& rFormatContentControl
= pTextContentControl->GetContentControl();
std::shared_ptr<SwContentControl> pContentControl
= rFormatContentControl.GetContentControl(); if (pContentControl && !pContentControl->GetReadWrite())
{ switch (pContentControl->GetType())
{ case SwContentControlType::CHECKBOX: case SwContentControlType::PICTURE: case SwContentControlType::DROP_DOWN_LIST:
bRet = true; break; default: break;
}
}
}
}
}
if (HasMark() && GetPoint()->nNode != GetMark()->nNode)
{ // check for hidden section inside the selection
SwNodeOffset nSttIdx = Start()->GetNodeIndex(), nEndIdx = End()->GetNodeIndex();
if (nSttIdx + SwNodeOffset(3) < nEndIdx)
{ const SwSectionFormats& rFormats = GetDoc().GetSections(); for (SwSectionFormats::size_type n = rFormats.size(); n;)
{ const SwSectionFormat* pFormat = rFormats[--n]; if (pFormat->GetSection()->IsHidden())
{ const SwFormatContent& rContent = pFormat->GetContent(false);
OSL_ENSURE(rContent.GetContentIdx(), "where is the SectionNode?");
SwNodeOffset nIdx = rContent.GetContentIdx()->GetIndex(); if (nSttIdx <= nIdx && nEndIdx >= nIdx
&& rContent.GetContentIdx()->GetNode().GetNodes().IsDocNodes())
{
bRet = true; break;
}
}
}
}
}
return bRet;
}
/// This function returns the next node in direction of search. If there is no /// left or the next is out of the area, then a null-pointer is returned. /// @param rbFirst If <true> then first time request. If so than the position of /// the PaM must not be changed!
SwContentNode* GetNode( SwPaM & rPam, bool& rbFirst, SwMoveFnCollection const & fnMove, boolconst bInReadOnly, SwRootFrame const*const i_pLayout)
{
SwRootFrame const*const pLayout(i_pLayout ? i_pLayout :
rPam.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout());
SwContentNode * pNd = nullptr; if( ((*rPam.GetPoint()).*fnMove.fnCmpOp)( *rPam.GetMark() ) ||
( *rPam.GetPoint() == *rPam.GetMark() && rbFirst ) )
{ if( rbFirst )
{
rbFirst = false;
pNd = rPam.GetPointContentNode(); if( pNd )
{
SwContentFrame const*const pFrame(pNd->getLayoutFrame(pLayout)); if(
(
nullptr == pFrame ||
( !bInReadOnly && pFrame->IsProtected() ) ||
pFrame->IsHiddenNow()
) ||
( !bInReadOnly && pNd->FindSectionNode() &&
pNd->FindSectionNode()->GetSection().IsProtect()
)
)
{
pNd = nullptr;
}
}
}
if( !pNd ) // is the cursor not on a ContentNode?
{
SwPosition aPos( *rPam.GetPoint() ); bool bSrchForward = &fnMove == &fnMoveForward;
// go to next/previous ContentNode while( true )
{ if (i_pLayout && aPos.GetNode().IsTextNode())
{ autoconst fal(sw::GetFirstAndLastNode(*pLayout, aPos.GetNode()));
aPos.Assign( bSrchForward ? *fal.second : *fal.first );
}
pNd = bSrchForward
? SwNodes::GoNextSection( &aPos, true, !bInReadOnly )
: SwNodes::GoPrevSection( &aPos, true, !bInReadOnly ); if( pNd )
{ if (!bSrchForward)
aPos.AssignEndIndex( *pNd ); // is the position still in the area if( (aPos.*fnMove.fnCmpOp)( *rPam.GetMark() ) )
{ // only in AutoTextSection can be nodes that are hidden
SwContentFrame const*const pFrame(pNd->getLayoutFrame(pLayout)); if (nullptr == pFrame ||
( !bInReadOnly && pFrame->IsProtected() ) ||
pFrame->IsHiddenNow())
{ continue;
}
*rPam.GetPoint() = aPos;
} else
pNd = nullptr; // no valid node break;
} break;
}
}
} return pNd;
}
void GoStartDoc( SwPosition * pPos )
{
SwNodes& rNodes = pPos->GetNodes();
pPos->Assign( *rNodes.GetEndOfContent().StartOfSectionNode() ); // we always need to find a ContentNode!
SwNodes::GoNext(pPos);
}
/// go to the end of the current base section void GoEndSection( SwPosition * pPos )
{ // jump to section's beginning/end
SwNodes& rNodes = pPos->GetNodes(); int nLevel = SwNodes::GetSectionLevel( pPos->GetNode() ); if( pPos->GetNode() < *rNodes.GetEndOfContent().StartOfSectionNode() )
{
assert(nLevel > 0);
nLevel--;
} do { SwNodes::GoEndOfSection( &pPos->nNode ); } while( nLevel-- );
// now on an EndNode, thus to the previous ContentNode if( SwContentNode* pCNd = GoPreviousNds( &pPos->nNode ) )
pPos->AssignEndIndex(*pCNd);
}
// The first node can be already the end node. // Use a "forever" loop with an exit condition in the middle // of its body, in order to correctly handle all cases. bool bIsStartNode = true; for (;;)
{ constbool bIsEndNode = aNodeIndex == End()->nNode;
SwTextNode * pTextNode = aNodeIndex.GetNode().GetTextNode();
if (pTextNode != nullptr)
{ if (!bIsStartNode)
{
rResult.append(CH_TXTATR_NEWLINE); // use newline for para break
} const OUString& aTmpStr = pTextNode->GetText();
void SwPaM::InvalidatePaM()
{ for (SwNodeIndex index(Start()->GetNode()); index <= End()->GetNode(); ++index)
{ if (SwTextNode *const pTextNode = index.GetNode().GetTextNode())
{ // pretend that the PaM marks changed formatting to reformat...
sal_Int32 const nStart(
index == Start()->nNode ? Start()->GetContentIndex() : 0); // this should work even for length of 0
SwUpdateAttr const aHint(
nStart,
index == End()->nNode
? End()->GetContentIndex() - nStart
: pTextNode->Len() - nStart,
0);
pTextNode->TriggerNodeUpdate(sw::UpdateAttrHint(&aHint, &aHint));
} // other node types not invalidated
}
}
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.