/* -*- 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 .
*/
/// go to next/previous point on the same level void SwCursorShell::GotoNextNum()
{ if (!SwDoc::GotoNextNum(*m_pCurrentCursor->GetPoint(), GetLayout())) return;
MoveCursorToNum();
}
void SwCursorShell::GotoPrevNum()
{ if (!SwDoc::GotoPrevNum(*m_pCurrentCursor->GetPoint(), GetLayout())) return;
MoveCursorToNum();
}
/// jump to index of TOXMark void SwCursorShell::GotoTOXMarkBase()
{
SwTOXMarks aMarks;
sal_uInt16 nCnt = SwDoc::GetCurTOXMark(*m_pCurrentCursor->GetPoint(), aMarks); if(!nCnt) return; // Take the 1. and get the index type. Ask it for the actual index. const SwTOXType* pType = aMarks[0]->GetTOXType(); auto pContentFrame = pType->FindContentFrame(*GetLayout()); if(!pContentFrame) return;
SwCallLink aLk(*this); // watch Cursor-Moves
SwCursorSaveState aSaveState(*m_pCurrentCursor);
assert(pContentFrame->IsTextFrame());
*m_pCurrentCursor->GetPoint() = static_cast<SwTextFrame const*>(pContentFrame)->MapViewToModelPos(TextFrameIndex(0)); if(!m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr())
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
}
/// Jump to next/previous table formula /// Optionally it is possible to also jump to broken formulas bool SwCursorShell::GotoNxtPrvTableFormula( bool bNext, bool bOnlyErrors )
{
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
if( rPos.GetNode() < GetDoc()->GetNodes().GetEndOfExtras() )
{ // also at collection use only the first frame
std::pair<Point, bool> const tmp(aPt, false);
aCurGEF.SetBodyPos( *rPos.GetNode().GetContentNode()->getLayoutFrame( GetLayout(),
&rPos, &tmp) );
}
if( rPos.GetNodeIndex() < GetDoc()->GetNodes().GetEndOfExtras().GetIndex() )
{ // also at collection use only the first frame
std::pair<Point, bool> const tmp(aPt, false);
aCurGEF.SetBodyPos( *rPos.GetNode().
GetContentNode()->getLayoutFrame(GetLayout(), &rPos, &tmp));
}
if (rPos.GetNodeIndex() < pTextNode->GetNodes().GetEndOfExtras().GetIndex())
{ // also at collection use only the first frame
Point aPt;
std::pair<Point, bool> const tmp(aPt, false);
oSrch->SetBodyPos(*pTextNode->getLayoutFrame(pLayout, &rPos, &tmp));
}
SetGetExpFields::const_iterator it = rSrtLst.lower_bound(&*oSrch);
// found Modify object, add all fields to array
::lcl_MakeFieldLst( aSrtLst, *pFieldType, IsReadOnlyAvailable() );
if( SwFieldIds::Input == pFieldType->Which() && bAddSetExpressionFieldsToInputFields )
{ // there are hidden input fields in the set exp. fields const SwFieldTypes& rFieldTypes = *mxDoc->getIDocumentFieldsAccess().GetFieldTypes(); const size_t nSize = rFieldTypes.size(); for( size_t i=0; i < nSize; ++i )
{
pFieldType = rFieldTypes[ i ].get(); if ( SwFieldIds::SetExp == pFieldType->Which() )
{
::lcl_MakeFieldLst( aSrtLst, *pFieldType, IsReadOnlyAvailable(), true );
}
}
}
} else
{ const SwFieldTypes& rFieldTypes = *mxDoc->getIDocumentFieldsAccess().GetFieldTypes(); const size_t nSize = rFieldTypes.size(); constbool bAllFieldTypes = nResType == SwFieldIds::Unknown; for( size_t i=0; i < nSize; ++i )
{
pFieldType = rFieldTypes[ i ].get(); if (bAllFieldTypes || nResType == pFieldType->Which())
{
::lcl_MakeFieldLst( aSrtLst, *pFieldType, IsReadOnlyAvailable() );
}
}
}
// found no fields? if( aSrtLst.empty() ) returnfalse;
SetGetExpFields::const_iterator it;
SwCursor* pCursor = getShellCursor( true );
{ // (1998): Always use field for search so that the right one is found as // well some are in frames that are anchored to a paragraph that has a // field const SwPosition& rPos = *pCursor->GetPoint();
SwTextNode* pTNd = rPos.GetNode().GetTextNode();
assert(pTNd && "No ContentNode");
if( bDelField )
{ // create dummy for the search // NOTE: with SfxPoolItemHolder in SwTextAttr the // SwFormatField will just be managed by it, when // wanted and handing over bPassingOwnership==true
pTextField = new SwTextField (
SfxPoolItemHolder(
mxDoc->GetAttrPool(), new SwFormatField(
SwDateTimeField( static_cast<SwDateTimeFieldType*>(mxDoc->getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::DateTime )))), true), // bPassingOwnership
rPos.GetContentIndex(),
mxDoc->IsClipBoard() );
pTextField->ChgTextNode( pTNd );
} else
{ // the cursor might be anywhere inside the input field, // but we will be searching for the field start if (pTextField->Which() == RES_TXTATR_INPUTFIELD
&& rPos.GetContentIndex() != pTextField->GetStart())
nContentOffset = pTextField->GetStart();
} bool isSrch;
it = lcl_FindField(isSrch, aSrtLst,
GetLayout(), pTNd, pTextField, rPos, nContentOffset);
if( bDelField )
{ // with using SfxPoolItemHolder in SwTextAttr there is no need anymore // to cleanup the contained SwFormatField self delete pTextField;
}
if( it != aSrtLst.end() && isSrch ) // found
{ if( bNext )
{ if( ++it == aSrtLst.end() ) returnfalse; // already at the end
} else
{ if( it == aSrtLst.begin() ) returnfalse; // no more steps backward possible
--it;
}
} else// not found
{ if( bNext )
{ if( it == aSrtLst.end() ) returnfalse;
} else
{ if( it == aSrtLst.begin() ) returnfalse; // no more steps backward possible
--it;
}
}
} const SetGetExpField& rFnd = **it;
SwTextNode* pTextNode = pContentControl->GetTextNode(); // Don't select the text attribute itself at the start.
sal_Int32 nStart = pTextContentControl->GetStart() + 1;
pCursor->GetPoint()->Assign(*pTextNode, nStart);
bool bRet = true; // select contents for certain controls or conditions if (pContentControl->GetShowingPlaceHolder() || pContentControl->GetCheckbox()
|| pContentControl->GetSelectedListItem() || pContentControl->GetSelectedDate())
{
pCursor->SetMark(); // Don't select the CH_TXTATR_BREAKWORD itself at the end.
sal_Int32 nEnd = *pTextContentControl->End() - 1;
pCursor->GetMark()->Assign(*pTextNode, nEnd);
bRet = !pCursor->IsSelOvr();
} else
ClearMark();
if (bRet)
{
UpdateCursor(SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE
| SwCursorShell::READONLY);
}
return bRet;
}
/** * Go to the next (or previous) form control, based first on tabIndex and then paragraph position, * where a tabIndex of 1 is first, 0 is last, and -1 is excluded.
*/ void SwCursorShell::GotoFormControl(bool bNext)
{ // (note: this only applies to modern content controls and legacy fieldmarks, // since activeX richText controls aren't exposed to SW keystrokes)
struct FormControlSort
{ booloperator()(std::pair<const SwPosition&, sal_uInt32> rLHS,
std::pair<const SwPosition&, sal_uInt32> rRHS) const
{
assert(rLHS.second && rRHS.second && "tabIndex zero must be changed to SAL_MAX_UINT32"); //first compare tabIndexes where 1 has the priority. if (rLHS.second < rRHS.second) returntrue; if (rLHS.second > rRHS.second) returnfalse;
// when tabIndexes are equal (and they usually are) then sort by paragraph position return rLHS.first < rRHS.first;
}
};
std::map<std::pair<SwPosition, sal_uInt32>,
std::pair<SwTextContentControl*, sw::mark::Fieldmark*>, FormControlSort> aFormMap;
// add all of the eligible modern Content Controls into a sorted map
SwContentControlManager& rManager = GetDoc()->GetContentControlManager(); for (size_t i = 0; i < rManager.GetCount(); ++i)
{
SwTextContentControl* pTCC = rManager.UnsortedGet(i); if (!pTCC || !pTCC->GetTextNode()) continue; auto pCC = pTCC->GetContentControl().GetContentControl();
// -1 indicates the control should not participate in keyboard tab navigation if (pCC && pCC->GetTabIndex() == SAL_MAX_UINT32) continue;
// since 0 is the lowest priority (1 is the highest), and -1 has already been excluded, // use SAL_MAX_UINT32 as zero's tabIndex so that automatic sorting is correct.
sal_uInt32 nTabIndex = pCC && pCC->GetTabIndex() ? pCC->GetTabIndex() : SAL_MAX_UINT32;
if (aFormMap.begin() == aFormMap.end())
{ // only legacy fields exist. Avoid reprocessing everything and use legacy code path.
GotoFieldmark(bNext ? GetFieldmarkAfter() : GetFieldmarkBefore()); return;
}
// add all of the legacy form field controls into the sorted map
IDocumentMarkAccess* pMarkAccess = GetDoc()->getIDocumentMarkAccess(); for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
{
sw::mark::Fieldmark* pFieldMark = *it;
assert(pFieldMark); // legacy form fields do not have (functional) tabIndexes - use lowest priority for them
aFormMap[std::make_pair((*it)->GetMarkStart(), SAL_MAX_UINT32)] =
std::pair<SwTextContentControl*, sw::mark::Fieldmark*>(nullptr, pFieldMark);
}
if (aFormMap.begin() == aFormMap.end()) return;
// Identify the current location in the document, and the current tab index priority
// A content control could contain a Fieldmark, so check for legacy fieldmarks first
sw::mark::Fieldmark* pFieldMark = GetCurrentFieldmark();
SwTextContentControl* pTCC = !pFieldMark ? CursorInsideContentControl() : nullptr;
// Find the previous (or next) tab control and navigate to it const std::pair<SwPosition, sal_uInt32> nOldPos(nCurPos, nCurTabIndex);
// lower_bound acts like find, and returns a pointer to nFindPos if it exists, // otherwise it will point to the previous entry. auto aNewPos = aFormMap.lower_bound(nOldPos); if (bNext && aNewPos != aFormMap.end())
++aNewPos; elseif (!bNext && aNewPos != aFormMap.end() && aNewPos->first == nOldPos)
{ // Found the current position - need to return previous if (aNewPos == aFormMap.begin())
aNewPos = aFormMap.end(); // prepare to loop around else
--aNewPos;
}
if (aNewPos == aFormMap.end())
{ // Loop around to the other side if (bNext)
aNewPos = aFormMap.begin(); else
--aNewPos;
}
// the entry contains a pointer to either a Content Control (first) or Fieldmark (second) if (aNewPos->second.first)
{ auto& rFCC = static_cast<SwFormatContentControl&>(aNewPos->second.first->GetAttr());
GotoFormatContentControl(rFCC);
} else
{
assert(aNewPos->second.second);
GotoFieldmark(aNewPos->second.second);
}
}
/// search "outline position" before previous outline node at given level
SwOutlineNodes::size_type SwCursorShell::GetOutlinePos(sal_uInt8 nLevel, SwPaM* pPaM)
{
SwPaM* pCursor = pPaM ? pPaM : getShellCursor(true); const SwNodes& rNds = GetDoc()->GetNodes();
SwNode* pNd = &(pCursor->GetPointNode());
SwOutlineNodes::size_type nPos; if( rNds.GetOutLineNds().Seek_Entry( pNd, &nPos ))
nPos++; // is at correct position; take next for while
while( nPos-- ) // check the one in front of the current
{
pNd = rNds.GetOutLineNds()[ nPos ];
if (sw::IsParaPropsNode(*GetLayout(), *pNd->GetTextNode())
&& pNd->GetTextNode()->GetAttrOutlineLevel()-1 <= nLevel)
{ if (pNd->GetIndex() < rNds.GetEndOfExtras().GetIndex()
&& pCursor->GetPointNode().GetIndex() > rNds.GetEndOfExtras().GetIndex())
{ // node found in extras but cursor position is not in extras return SwOutlineNodes::npos;
} return nPos;
}
} return SwOutlineNodes::npos; // no more left
}
if (pOutlNdsInline)
{
pSttNd = const_cast<SwNode*>(SwOutlineNodes::GetRootNode(pSttNd));
SwOutlineNodesInline::size_type nEndPosInline;
pOutlNdsInline->Seek_Entry( pEndNd, &nEndPosInline );
assert(nEndPosInline != SwOutlineNodesInline::npos && "always sets some number <= pOutlNdsInline->size()");
// headings in flys if (bWithChildren)
{ constint nLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel() - 1; for( ++nEndPosInline; nEndPosInline < pOutlNdsInline->size(); ++nEndPosInline )
{
pEndNd = (*pOutlNdsInline)[ nEndPosInline ]; constint nNxtLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel()-1; if( nNxtLevel <= nLevel ) break; // EndPos is now on the next one
} // set anchor node of the fly node if ( nEndPosInline < pOutlNdsInline->size() )
pEndNd = const_cast<SwNode*>(SwOutlineNodes::GetRootNode(pEndNd));
} elseif (++nEndPosInline < pOutlNdsInline->size())
pEndNd = const_cast<SwNode*>(SwOutlineNodes::GetRootNode((*pOutlNdsInline)[nEndPosInline]));
if (nEndPosInline == pOutlNdsInline->size()) // no end found
pEndNd = &rNds.GetEndOfContent();
} else
{ if (bWithChildren)
{ constint nLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel()-1; for( ++nEndPos; nEndPos < rOutlNds.size(); ++nEndPos )
{
pEndNd = rOutlNds[ nEndPos ]; constint nNxtLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel()-1; if( nNxtLevel <= nLevel ) break; // EndPos is now on the next one
}
} // if without children then set onto next one elseif (++nEndPos < rOutlNds.size())
pEndNd = rOutlNds[ nEndPos ];
if (nEndPos == rOutlNds.size()) // no end found
pEndNd = &rNds.GetEndOfContent();
}
// set end to the end of the previous content node
m_pCurrentCursor->GetPoint()->Assign(*pSttNd);
m_pCurrentCursor->SetMark();
m_pCurrentCursor->GetPoint()->Assign(*pEndNd);
m_pCurrentCursor->Move( fnMoveBackward, GoInNode ); // end of predecessor
// and everything is already selected bool bRet = !m_pCurrentCursor->IsSelOvr(); if( bRet )
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
}
const SwNodes& rNds = GetDoc()->GetNodes(); if( pTextNd
&& IsAttrAtPos::Outline & rContentAtPos.eContentAtPos
&& !rNds.GetOutLineNds().empty() )
{ // only for nodes in outline nodes
SwOutlineNodes::size_type nPos = 0; bool bFoundOutline = rNds.GetOutLineNds().Seek_Entry(pTextNd, &nPos); if (!bFoundOutline && nPos && (IsAttrAtPos::AllowContaining & rContentAtPos.eContentAtPos))
{ // nPos points to the first found outline node not before pTextNd, or to end(); // when bFoundOutline is false, and nPos is not 0, it means that there were // outline nodes before pTextNd, and nPos-1 points to the last of those.
pTextNd = rNds.GetOutLineNds()[nPos - 1]->GetTextNode();
bFoundOutline = true;
} if (bFoundOutline)
{
rContentAtPos.eContentAtPos = IsAttrAtPos::Outline;
rContentAtPos.sStr = sw::GetExpandTextMerged(GetLayout(), *pTextNd, true, false, ExpandMode::ExpandFootnote);
rContentAtPos.aFnd.pNode = pTextNd;
bRet = true;
}
} elseif ( IsAttrAtPos::ContentCheck & rContentAtPos.eContentAtPos
&& bCursorFoundExact )
{
bRet = true;
} elseif( pTextNd
&& IsAttrAtPos::NumLabel & rContentAtPos.eContentAtPos)
{
bRet = aTmpState.m_bInNumPortion;
rContentAtPos.aFnd.pNode = sw::GetParaPropsNode(*GetLayout(), aPos.GetNode());
if ( pField )
{ if (pFieldRect)
{
std::pair<Point, bool> tmp(aPt, true);
pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp); if (pFrame)
{ //tdf#116397 now that we looking for the bounds of the field drop the SmartTag //index within field setting so we don't the bounds of the char within the field
SwSpecialPos* pSpecialPos = aTmpState.m_pSpecialPos;
aTmpState.m_pSpecialPos = nullptr;
pFrame->GetCharRect( *pFieldRect, aPos, &aTmpState );
aTmpState.m_pSpecialPos = pSpecialPos;
}
}
if( bSetCursor )
{
SwCallLink aLk( *this ); // watch Cursor-Moves
SwCursorSaveState aSaveState( *m_pCurrentCursor );
m_pCurrentCursor->DeleteMark();
*m_pCurrentCursor->GetPoint() = aPos; if( m_pCurrentCursor->IsSelOvr() )
{ // allow click fields in protected sections // only placeholder is not possible if( IsAttrAtPos::Field & rContentAtPos.eContentAtPos
|| SwFieldIds::JumpEdit == pField->Which() )
pField = nullptr;
} else
UpdateCursor();
} elseif( SwFieldIds::Table == pField->Which() && static_cast<const SwTableField*>(pField)->IsIntrnlName() )
{ // create from internal (for CORE) the external // (for UI) formula const SwTableNode* pTableNd = pTextNd->FindTableNode(); if( pTableNd ) // is in a table const_cast<SwTableField*>(static_cast<const SwTableField*>(pField))->PtrToBoxNm( &pTableNd->GetTable() );
}
}
if( bRet )
{
OUStringBuffer aStringBuffer; if (RES_TXTATR_TOXMARK == pTextAttr->Which())
{ // tdf#143157 - include first and secondary keys in index fields constauto& aSwTOXMark = pTextAttr->GetTOXMark();
--> --------------------
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.