2937 lines
104 KiB
C++
2937 lines
104 KiB
C++
/* -*- 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 .
|
|
*/
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
#include <hintids.hxx>
|
|
#include <comphelper/string.hxx>
|
|
#include <svl/itemiter.hxx>
|
|
#include <editeng/lrspitem.hxx>
|
|
#include <editeng/adjustitem.hxx>
|
|
#include <editeng/formatbreakitem.hxx>
|
|
#include <svx/svdobj.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <crsrsh.hxx>
|
|
#include <doc.hxx>
|
|
#include <IDocumentUndoRedo.hxx>
|
|
#include <IDocumentRedlineAccess.hxx>
|
|
#include <IDocumentFieldsAccess.hxx>
|
|
#include <IDocumentLayoutAccess.hxx>
|
|
#include <pagefrm.hxx>
|
|
#include <cntfrm.hxx>
|
|
#include <rootfrm.hxx>
|
|
#include <pam.hxx>
|
|
#include <ndtxt.hxx>
|
|
#include <fldbas.hxx>
|
|
#include <swtable.hxx>
|
|
#include <docary.hxx>
|
|
#include <txtfld.hxx>
|
|
#include <fmtfld.hxx>
|
|
#include <txtftn.hxx>
|
|
#include <txtinet.hxx>
|
|
#include <fmtinfmt.hxx>
|
|
#include <txttxmrk.hxx>
|
|
#include <frmfmt.hxx>
|
|
#include <flyfrm.hxx>
|
|
#include <viscrs.hxx>
|
|
#include "callnk.hxx"
|
|
#include <doctxm.hxx>
|
|
#include <docfld.hxx>
|
|
#include <expfld.hxx>
|
|
#include <reffld.hxx>
|
|
#include <flddat.hxx>
|
|
#include <cellatr.hxx>
|
|
#include <swundo.hxx>
|
|
#include <redline.hxx>
|
|
#include <fmtcntnt.hxx>
|
|
#include <fmthdft.hxx>
|
|
#include <pagedesc.hxx>
|
|
#include <fesh.hxx>
|
|
#include <charfmt.hxx>
|
|
#include <fmturl.hxx>
|
|
#include <txtfrm.hxx>
|
|
#include <wrong.hxx>
|
|
#include <calbck.hxx>
|
|
#include <unotools/intlwrapper.hxx>
|
|
#include <docufld.hxx>
|
|
#include <svx/srchdlg.hxx>
|
|
#include <frameformats.hxx>
|
|
#include <docsh.hxx>
|
|
#include <wrtsh.hxx>
|
|
#include <textcontentcontrol.hxx>
|
|
|
|
using namespace ::com::sun::star;
|
|
|
|
void SwCursorShell::MoveCursorToNum()
|
|
{
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
if( ActionPend() )
|
|
return;
|
|
CurrShell aCurr( this );
|
|
// try to set cursor onto this position, at half of the char-
|
|
// SRectangle's height
|
|
Point aPt( m_pCurrentCursor->GetPtPos() );
|
|
std::pair<Point, bool> const tmp(aPt, true);
|
|
SwContentFrame * pFrame = m_pCurrentCursor->GetPointContentNode()->getLayoutFrame(
|
|
GetLayout(), m_pCurrentCursor->GetPoint(), &tmp);
|
|
pFrame->GetCharRect( m_aCharRect, *m_pCurrentCursor->GetPoint() );
|
|
pFrame->Calc(GetOut());
|
|
if( pFrame->IsVertical() )
|
|
{
|
|
aPt.setX(m_aCharRect.Center().getX());
|
|
aPt.setY(pFrame->getFrameArea().Top() + GetUpDownX());
|
|
}
|
|
else
|
|
{
|
|
aPt.setY(m_aCharRect.Center().getY());
|
|
aPt.setX(pFrame->getFrameArea().Left() + GetUpDownX());
|
|
}
|
|
pFrame->GetModelPositionForViewPoint( m_pCurrentCursor->GetPoint(), aPt );
|
|
if ( !m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::Toggle |
|
|
SwCursorSelOverFlags::ChangePos ))
|
|
{
|
|
UpdateCursor(SwCursorShell::UPDOWN |
|
|
SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
|
|
SwCursorShell::READONLY );
|
|
}
|
|
}
|
|
|
|
/// 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 from content to header
|
|
bool SwCursorShell::GotoHeaderText()
|
|
{
|
|
const SwFrame* pFrame = GetCurrFrame()->FindPageFrame();
|
|
while( pFrame && !pFrame->IsHeaderFrame() )
|
|
pFrame = pFrame->GetLower();
|
|
// found header, search 1. content frame
|
|
while( pFrame && !pFrame->IsContentFrame() )
|
|
pFrame = pFrame->GetLower();
|
|
|
|
if( !pFrame )
|
|
return false;
|
|
|
|
CurrShell aCurr( this );
|
|
// get header frame
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursor *pTmpCursor = getShellCursor( true );
|
|
SwCursorSaveState aSaveState( *pTmpCursor );
|
|
pFrame->Calc(GetOut());
|
|
Point aPt( pFrame->getFrameArea().Pos() + pFrame->getFramePrintArea().Pos() );
|
|
pFrame->GetModelPositionForViewPoint( pTmpCursor->GetPoint(), aPt );
|
|
if( !pTmpCursor->IsSelOvr() )
|
|
UpdateCursor();
|
|
else
|
|
pFrame = nullptr;
|
|
return nullptr != pFrame;
|
|
}
|
|
|
|
/// jump from content to footer
|
|
bool SwCursorShell::GotoFooterText()
|
|
{
|
|
const SwPageFrame* pFrame = GetCurrFrame()->FindPageFrame();
|
|
if( !pFrame )
|
|
return false;
|
|
|
|
const SwFrame* pLower = pFrame->GetLastLower();
|
|
|
|
while( pLower && !pLower->IsFooterFrame() )
|
|
pLower = pLower->GetLower();
|
|
// found footer, search 1. content frame
|
|
while( pLower && !pLower->IsContentFrame() )
|
|
pLower = pLower->GetLower();
|
|
|
|
if( !pLower )
|
|
return false;
|
|
|
|
SwCursor *pTmpCursor = getShellCursor( true );
|
|
CurrShell aCurr( this );
|
|
// get position in footer
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *pTmpCursor );
|
|
pLower->Calc(GetOut());
|
|
Point aPt( pLower->getFrameArea().Pos() + pLower->getFramePrintArea().Pos() );
|
|
pLower->GetModelPositionForViewPoint( pTmpCursor->GetPoint(), aPt );
|
|
if( !pTmpCursor->IsSelOvr() )
|
|
UpdateCursor();
|
|
else
|
|
pFrame = nullptr;
|
|
return nullptr != pFrame;
|
|
}
|
|
|
|
bool SwCursorShell::SetCursorInHdFt(size_t nDescNo, bool bInHeader, bool bEven, bool bFirst)
|
|
{
|
|
SwDoc *pMyDoc = GetDoc();
|
|
const SwPageDesc* pDesc = nullptr;
|
|
|
|
CurrShell aCurr( this );
|
|
|
|
if( SIZE_MAX == nDescNo )
|
|
{
|
|
// take the current one
|
|
const SwContentFrame *pCurrFrame = GetCurrFrame();
|
|
const SwPageFrame* pPage = (pCurrFrame == nullptr) ? nullptr : pCurrFrame->FindPageFrame();
|
|
if( pPage && pMyDoc->ContainsPageDesc(
|
|
pPage->GetPageDesc(), &nDescNo) )
|
|
pDesc = pPage->GetPageDesc();
|
|
}
|
|
else
|
|
if (nDescNo < pMyDoc->GetPageDescCnt())
|
|
pDesc = &pMyDoc->GetPageDesc( nDescNo );
|
|
|
|
if( !pDesc )
|
|
return false;
|
|
|
|
// check if the attribute exists
|
|
const SwFormatContent* pCnt = nullptr;
|
|
if( bInHeader )
|
|
{
|
|
const SwFormatHeader& rHd
|
|
= bEven ? bFirst ? pDesc->GetFirstLeft().GetHeader() : pDesc->GetLeft().GetHeader()
|
|
: bFirst ? pDesc->GetFirstMaster().GetHeader() : pDesc->GetMaster().GetHeader();
|
|
if( rHd.GetHeaderFormat() )
|
|
pCnt = &rHd.GetHeaderFormat()->GetContent();
|
|
}
|
|
else
|
|
{
|
|
const SwFormatFooter& rFt
|
|
= bEven ? bFirst ? pDesc->GetFirstLeft().GetFooter() : pDesc->GetLeft().GetFooter()
|
|
: bFirst ? pDesc->GetFirstMaster().GetFooter() : pDesc->GetMaster().GetFooter();
|
|
if( rFt.GetFooterFormat() )
|
|
pCnt = &rFt.GetFooterFormat()->GetContent();
|
|
}
|
|
|
|
if( !pCnt || !pCnt->GetContentIdx() )
|
|
return false;
|
|
|
|
SwNodeIndex aIdx( *pCnt->GetContentIdx(), 1 );
|
|
SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
|
|
if( !pCNd )
|
|
pCNd = SwNodes::GoNext(&aIdx);
|
|
|
|
Point aPt( m_pCurrentCursor->GetPtPos() );
|
|
|
|
std::pair<Point, bool> const tmp(aPt, false);
|
|
if (!pCNd || nullptr == pCNd->getLayoutFrame(GetLayout(), nullptr, &tmp))
|
|
return false;
|
|
|
|
// then we can set the cursor in here
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
ClearMark();
|
|
|
|
SwPosition& rPos = *m_pCurrentCursor->GetPoint();
|
|
rPos.Assign( *pCNd );
|
|
|
|
if (m_pCurrentCursor->IsSelOvr())
|
|
return false;
|
|
|
|
UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
|
|
SwCursorShell::READONLY );
|
|
return true;
|
|
}
|
|
|
|
/// jump to the next index
|
|
bool SwCursorShell::GotoNextTOXBase( const OUString* pName )
|
|
{
|
|
const SwSectionFormats& rFormats = GetDoc()->GetSections();
|
|
SwContentNode* pFnd = nullptr;
|
|
for( SwSectionFormats::size_type n = rFormats.size(); n; )
|
|
{
|
|
const SwSection* pSect = rFormats[ --n ]->GetSection();
|
|
if (SectionType::ToxContent == pSect->GetType())
|
|
{
|
|
SwSectionNode const*const pSectNd(
|
|
pSect->GetFormat()->GetSectionNode());
|
|
if ( pSectNd
|
|
&& m_pCurrentCursor->GetPoint()->GetNode() < *pSectNd
|
|
&& (!pFnd || pFnd->GetIndex() > pSectNd->GetIndex())
|
|
&& (!pName || *pName ==
|
|
static_cast<SwTOXBaseSection const*>(pSect)->GetTOXName()))
|
|
{
|
|
SwNodeIndex aIdx(*pSectNd, 1);
|
|
SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
|
|
if (!pCNd)
|
|
pCNd = SwNodes::GoNext(&aIdx);
|
|
if (pCNd &&
|
|
pCNd->EndOfSectionIndex() <= pSectNd->EndOfSectionIndex())
|
|
{
|
|
SwContentFrame const*const pCFrame(
|
|
pCNd->getLayoutFrame(GetLayout()));
|
|
if (pCFrame &&
|
|
(IsReadOnlyAvailable() || !pCFrame->IsProtected()))
|
|
{
|
|
pFnd = pCNd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if( !pFnd )
|
|
return false;
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
m_pCurrentCursor->GetPoint()->Assign( *pFnd );
|
|
bool bRet = !m_pCurrentCursor->IsSelOvr();
|
|
if( bRet )
|
|
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
return bRet;
|
|
}
|
|
|
|
/// jump to previous index
|
|
bool SwCursorShell::GotoPrevTOXBase( const OUString* pName )
|
|
{
|
|
const SwSectionFormats& rFormats = GetDoc()->GetSections();
|
|
SwContentNode* pFnd = nullptr;
|
|
for( SwSectionFormats::size_type n = rFormats.size(); n; )
|
|
{
|
|
const SwSection* pSect = rFormats[ --n ]->GetSection();
|
|
if (SectionType::ToxContent == pSect->GetType())
|
|
{
|
|
SwSectionNode const*const pSectNd(
|
|
pSect->GetFormat()->GetSectionNode());
|
|
if ( pSectNd
|
|
&& m_pCurrentCursor->GetPoint()->GetNode() > *pSectNd->EndOfSectionNode()
|
|
&& (!pFnd || *pFnd < *pSectNd)
|
|
&& (!pName || *pName ==
|
|
static_cast<SwTOXBaseSection const*>(pSect)->GetTOXName()))
|
|
{
|
|
SwNodeIndex aIdx(*pSectNd, 1);
|
|
SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
|
|
if (!pCNd)
|
|
pCNd = SwNodes::GoNext(&aIdx);
|
|
if (pCNd &&
|
|
pCNd->EndOfSectionIndex() <= pSectNd->EndOfSectionIndex())
|
|
{
|
|
SwContentFrame const*const pCFrame(
|
|
pCNd->getLayoutFrame(GetLayout()));
|
|
if (pCFrame &&
|
|
(IsReadOnlyAvailable() || !pCFrame->IsProtected()))
|
|
{
|
|
pFnd = pCNd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !pFnd )
|
|
return false;
|
|
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
m_pCurrentCursor->GetPoint()->Assign(*pFnd);
|
|
bool bRet = !m_pCurrentCursor->IsSelOvr();
|
|
if( bRet )
|
|
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
return bRet;
|
|
}
|
|
|
|
/// 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( IsTableMode() )
|
|
return false;
|
|
|
|
bool bFnd = false;
|
|
SwPosition aOldPos = *m_pCurrentCursor->GetPoint();
|
|
SwPosition& rPos = *m_pCurrentCursor->GetPoint();
|
|
|
|
Point aPt;
|
|
SwPosition aFndPos( GetDoc()->GetNodes().GetEndOfContent() );
|
|
if( !bNext )
|
|
aFndPos.Assign(SwNodeOffset(0));
|
|
SetGetExpField aFndGEF( aFndPos ), aCurGEF( rPos );
|
|
|
|
{
|
|
const SwNode* pSttNd = rPos.GetNode().FindTableBoxStartNode();
|
|
if( pSttNd )
|
|
{
|
|
const SwTableBox* pTBox = pSttNd->FindTableNode()->GetTable().
|
|
GetTableBox( pSttNd->GetIndex() );
|
|
if( pTBox )
|
|
aCurGEF = SetGetExpField( *pTBox );
|
|
}
|
|
}
|
|
|
|
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) );
|
|
}
|
|
|
|
std::vector<SwTableBoxFormula*> aTableBoxFormulas;
|
|
SwTable::GatherFormulas(*GetDoc(), aTableBoxFormulas);
|
|
const sal_uInt32 nMaxItems(aTableBoxFormulas.size());
|
|
if( nMaxItems > 0 )
|
|
{
|
|
sal_uInt8 nMaxDo = 2;
|
|
do {
|
|
for (SwTableBoxFormula* pItem : aTableBoxFormulas)
|
|
{
|
|
const SwTableBox* pTBox;
|
|
auto & rFormulaItem = *pItem;
|
|
pTBox = rFormulaItem.GetTableBox();
|
|
if( pTBox &&
|
|
pTBox->GetSttNd() &&
|
|
pTBox->GetSttNd()->GetNodes().IsDocNodes() &&
|
|
( !bOnlyErrors ||
|
|
!rFormulaItem.HasValidBoxes() ) )
|
|
{
|
|
SwNodeIndex aIdx( *pTBox->GetSttNd() );
|
|
const SwContentNode* pCNd = SwNodes::GoNext(&aIdx);
|
|
std::pair<Point, bool> const tmp(aPt, false);
|
|
if (pCNd)
|
|
{
|
|
const SwContentFrame* pCFrame = pCNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
|
|
if (pCFrame && (IsReadOnlyAvailable() || !pCFrame->IsProtected() ))
|
|
{
|
|
SetGetExpField aCmp( *pTBox );
|
|
aCmp.SetBodyPos( *pCFrame );
|
|
|
|
if( bNext ? ( aCurGEF < aCmp && aCmp < aFndGEF )
|
|
: ( aCmp < aCurGEF && aFndGEF < aCmp ))
|
|
{
|
|
aFndGEF = aCmp;
|
|
bFnd = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if( !bFnd )
|
|
{
|
|
if( bNext )
|
|
{
|
|
rPos.Assign(SwNodeOffset(0), 0);
|
|
aCurGEF = SetGetExpField( rPos );
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::EndWrapped );
|
|
}
|
|
else
|
|
{
|
|
aCurGEF = SetGetExpField( SwPosition( GetDoc()->GetNodes().GetEndOfContent() ) );
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::StartWrapped );
|
|
}
|
|
}
|
|
} while( !bFnd && --nMaxDo );
|
|
}
|
|
|
|
if( !bFnd )
|
|
{
|
|
rPos = std::move(aOldPos);
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
|
|
return false;
|
|
}
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
aFndGEF.GetPosOfContent( rPos );
|
|
m_pCurrentCursor->DeleteMark();
|
|
|
|
bFnd = !m_pCurrentCursor->IsSelOvr();
|
|
if( bFnd )
|
|
UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
|
|
SwCursorShell::READONLY );
|
|
|
|
return bFnd;
|
|
}
|
|
|
|
/// jump to next/previous index marker
|
|
bool SwCursorShell::GotoNxtPrvTOXMark( bool bNext )
|
|
{
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
|
|
|
|
if( IsTableMode() )
|
|
return false;
|
|
|
|
bool bFnd = false;
|
|
SwPosition& rPos = *m_pCurrentCursor->GetPoint();
|
|
|
|
Point aPt;
|
|
SwPosition aFndPos( GetDoc()->GetNodes().GetEndOfContent() );
|
|
if( !bNext )
|
|
aFndPos.Assign(SwNodeOffset(0));
|
|
SetGetExpField aFndGEF( aFndPos ), aCurGEF( rPos );
|
|
|
|
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));
|
|
}
|
|
|
|
std::vector<const SwTOXMark*> aSurrogates;
|
|
GetDoc()->ForEachTOXMark(
|
|
[&aSurrogates] (const SwTOXMark& rItem) -> bool
|
|
{
|
|
aSurrogates.push_back(&rItem);
|
|
return true;
|
|
});
|
|
const sal_uInt32 nMaxItems(aSurrogates.size());
|
|
if( nMaxItems == 0 )
|
|
{
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
|
|
return false;
|
|
}
|
|
|
|
const SwTextNode* pTextNd;
|
|
const SwTextTOXMark* pTextTOX;
|
|
do {
|
|
for (const SwTOXMark* pItem : aSurrogates)
|
|
{
|
|
auto & rToxMarkItem = *pItem;
|
|
pTextTOX = rToxMarkItem.GetTextTOXMark();
|
|
if( !pTextTOX )
|
|
continue;
|
|
pTextNd = &pTextTOX->GetTextNode();
|
|
if( !pTextNd->GetNodes().IsDocNodes() )
|
|
continue;
|
|
std::pair<Point, bool> const tmp(aPt, false);
|
|
const SwContentFrame* pCFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
|
|
if( pCFrame && ( IsReadOnlyAvailable() || !pCFrame->IsProtected() ))
|
|
{
|
|
SetGetExpField aCmp( *pTextNd, *pTextTOX );
|
|
aCmp.SetBodyPos( *pCFrame );
|
|
|
|
if( bNext ? ( aCurGEF < aCmp && aCmp < aFndGEF )
|
|
: ( aCmp < aCurGEF && aFndGEF < aCmp ))
|
|
{
|
|
aFndGEF = aCmp;
|
|
bFnd = true;
|
|
}
|
|
}
|
|
}
|
|
if( !bFnd )
|
|
{
|
|
if ( bNext )
|
|
{
|
|
rPos.Assign(SwNodeOffset(0), 0);
|
|
aCurGEF = SetGetExpField( rPos );
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::EndWrapped );
|
|
}
|
|
else
|
|
{
|
|
aCurGEF = SetGetExpField( SwPosition( GetDoc()->GetNodes().GetEndOfContent() ) );
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::StartWrapped );
|
|
}
|
|
}
|
|
} while ( !bFnd );
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
aFndGEF.GetPosOfContent( rPos );
|
|
|
|
bFnd = !m_pCurrentCursor->IsSelOvr();
|
|
if( bFnd )
|
|
UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
|
|
SwCursorShell::READONLY );
|
|
return bFnd;
|
|
}
|
|
|
|
/// traveling between marks
|
|
const SwTOXMark& SwCursorShell::GotoTOXMark( const SwTOXMark& rStart,
|
|
SwTOXSearch eDir )
|
|
{
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
const SwTOXMark& rNewMark = GetDoc()->GotoTOXMark( rStart, eDir,
|
|
IsReadOnlyAvailable() );
|
|
// set position
|
|
SwPosition& rPos = *GetCursor()->GetPoint();
|
|
rPos.Assign(rNewMark.GetTextTOXMark()->GetTextNode(),
|
|
rNewMark.GetTextTOXMark()->GetStart() );
|
|
GetCursor()->DeleteMark(); // tdf#158783 prevent UpdateCursor resetting point
|
|
|
|
if( !m_pCurrentCursor->IsSelOvr() )
|
|
UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE |
|
|
SwCursorShell::READONLY );
|
|
|
|
return rNewMark;
|
|
}
|
|
|
|
/// jump to next/previous field type
|
|
static void lcl_MakeFieldLst(
|
|
SetGetExpFields& rLst,
|
|
const SwFieldType& rFieldType,
|
|
const bool bInReadOnly,
|
|
const bool bChkInpFlag = false )
|
|
{
|
|
// always search the 1. frame
|
|
Point aPt;
|
|
std::vector<SwFormatField*> vFields;
|
|
rFieldType.GatherFields(vFields, false);
|
|
for(SwFormatField* pFormatField: vFields)
|
|
{
|
|
SwTextField* pTextField = pFormatField->GetTextField();
|
|
if ( pTextField != nullptr
|
|
&& ( !bChkInpFlag
|
|
|| static_cast<const SwSetExpField*>(pTextField->GetFormatField().GetField())->GetInputFlag() ) )
|
|
{
|
|
const SwTextNode& rTextNode = pTextField->GetTextNode();
|
|
std::pair<Point, bool> const tmp(aPt, false);
|
|
const SwContentFrame* pCFrame =
|
|
rTextNode.getLayoutFrame(
|
|
rTextNode.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
|
|
nullptr, &tmp);
|
|
if ( pCFrame != nullptr
|
|
&& ( bInReadOnly || !pCFrame->IsProtected() ) )
|
|
{
|
|
std::unique_ptr<SetGetExpField> pNew(new SetGetExpField( rTextNode, pTextField ));
|
|
pNew->SetBodyPos( *pCFrame );
|
|
rLst.insert( std::move(pNew) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static SetGetExpFields::const_iterator
|
|
lcl_FindField(bool & o_rFound, SetGetExpFields const& rSrtLst,
|
|
SwRootFrame const *const pLayout, SwTextNode *const pTextNode,
|
|
SwTextField const *const pTextField, SwPosition const& rPos,
|
|
sal_Int32 const nContentOffset)
|
|
{
|
|
std::optional<SetGetExpField> oSrch;
|
|
if (-1 == nContentOffset)
|
|
{
|
|
oSrch.emplace(rPos.GetNode(), pTextField, rPos.GetContentIndex());
|
|
}
|
|
else
|
|
{
|
|
oSrch.emplace(rPos.GetNode(), pTextField, nContentOffset);
|
|
}
|
|
|
|
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);
|
|
|
|
o_rFound = (it != rSrtLst.end()) && (**it == *oSrch);
|
|
return it;
|
|
}
|
|
|
|
bool SwCursorShell::MoveFieldType(
|
|
const SwFieldType* pFieldType,
|
|
const bool bNext,
|
|
const SwFieldIds nResType,
|
|
const bool bAddSetExpressionFieldsToInputFields )
|
|
{
|
|
// sorted list of all fields
|
|
SetGetExpFields aSrtLst;
|
|
|
|
if ( pFieldType )
|
|
{
|
|
if( SwFieldIds::Input != pFieldType->Which() && !pFieldType->HasWriterListeners() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 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();
|
|
const bool 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() )
|
|
return false;
|
|
|
|
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");
|
|
|
|
SwTextField * pTextField = pTNd->GetFieldTextAttrAt(rPos.GetContentIndex(), ::sw::GetTextAttrMode::Default);
|
|
const bool bDelField = ( pTextField == nullptr );
|
|
sal_Int32 nContentOffset = -1;
|
|
|
|
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() )
|
|
return false; // already at the end
|
|
}
|
|
else
|
|
{
|
|
if( it == aSrtLst.begin() )
|
|
return false; // no more steps backward possible
|
|
--it;
|
|
}
|
|
}
|
|
else // not found
|
|
{
|
|
if( bNext )
|
|
{
|
|
if( it == aSrtLst.end() )
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if( it == aSrtLst.begin() )
|
|
return false; // no more steps backward possible
|
|
--it;
|
|
}
|
|
}
|
|
}
|
|
const SetGetExpField& rFnd = **it;
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *pCursor );
|
|
|
|
rFnd.GetPosOfContent( *pCursor->GetPoint() );
|
|
bool bRet = !m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
|
|
SwCursorSelOverFlags::Toggle );
|
|
if( bRet )
|
|
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
return bRet;
|
|
}
|
|
|
|
bool SwCursorShell::GotoFootnoteAnchor(const SwTextFootnote& rTextFootnote)
|
|
{
|
|
if (SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(this))
|
|
pWrtSh->addCurrentPosition();
|
|
|
|
bool bRet = false;
|
|
SwCursor* pCursor = getShellCursor(true);
|
|
|
|
CurrShell aCurr(this);
|
|
SwCallLink aLk(*this); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState(*pCursor);
|
|
|
|
pCursor->GetPoint()->Assign(rTextFootnote.GetTextNode(),
|
|
rTextFootnote.GetStart());
|
|
bRet = !pCursor->IsSelOvr();
|
|
if (bRet)
|
|
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
return bRet;
|
|
}
|
|
|
|
bool SwCursorShell::GotoFormatContentControl(const SwFormatContentControl& rContentControl)
|
|
{
|
|
const std::shared_ptr<SwContentControl>& pContentControl = rContentControl.GetContentControl();
|
|
const SwTextContentControl* pTextContentControl = pContentControl->GetTextAttr();
|
|
if (!pTextContentControl)
|
|
return false;
|
|
|
|
CurrShell aCurr(this);
|
|
SwCallLink aLink(*this);
|
|
|
|
SwCursor* pCursor = getShellCursor(true);
|
|
SwCursorSaveState aSaveState(*pCursor);
|
|
|
|
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
|
|
{
|
|
bool operator()(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)
|
|
return true;
|
|
if (rLHS.second > rRHS.second)
|
|
return false;
|
|
|
|
// 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;
|
|
|
|
const SwPosition nPos(*pTCC->GetTextNode(), pTCC->GetStart());
|
|
|
|
// 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;
|
|
|
|
const std::pair<SwTextContentControl*, sw::mark::Fieldmark*> pFormControl(pTCC, nullptr);
|
|
aFormMap[std::make_pair(nPos, nTabIndex)] = pFormControl;
|
|
}
|
|
|
|
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;
|
|
|
|
auto pCC = pTCC ? pTCC->GetContentControl().GetContentControl() : nullptr;
|
|
const sal_uInt32 nCurTabIndex = pCC && pCC->GetTabIndex() ? pCC->GetTabIndex() : SAL_MAX_UINT32;
|
|
|
|
SwPosition nCurPos(*GetCursor()->GetPoint());
|
|
if (pFieldMark)
|
|
nCurPos = pFieldMark->GetMarkStart();
|
|
else if (pTCC && pTCC->GetTextNode())
|
|
nCurPos = SwPosition(*pTCC->GetTextNode(), pTCC->GetStart());
|
|
|
|
// 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;
|
|
else if (!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);
|
|
}
|
|
}
|
|
|
|
bool SwCursorShell::GotoFormatField( const SwFormatField& rField )
|
|
{
|
|
SwTextField const*const pTextField(rField.GetTextField());
|
|
if (!pTextField
|
|
|| (GetLayout()->IsHideRedlines()
|
|
&& sw::IsFieldDeletedInModel(
|
|
GetDoc()->getIDocumentRedlineAccess(), *pTextField)))
|
|
return false;
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
|
|
SwCursor* pCursor = getShellCursor( true );
|
|
SwCursorSaveState aSaveState( *pCursor );
|
|
|
|
SwTextNode* pTNd = pTextField->GetpTextNode();
|
|
pCursor->GetPoint()->Assign(*pTNd, pTextField->GetStart() );
|
|
|
|
bool bRet = !pCursor->IsSelOvr();
|
|
if( bRet )
|
|
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
if (&pCursor->GetPoint()->GetNode() != pTNd)
|
|
{
|
|
// tdf#161346 failed to move to field
|
|
return false;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
SwTextField * SwCursorShell::GetTextFieldAtPos(
|
|
const SwPosition* pPos,
|
|
::sw::GetTextAttrMode const eMode)
|
|
{
|
|
SwTextField* pTextField = nullptr;
|
|
|
|
SwTextNode * const pNode = pPos->GetNode().GetTextNode();
|
|
if ( pNode != nullptr )
|
|
{
|
|
pTextField = pNode->GetFieldTextAttrAt(pPos->GetContentIndex(), eMode);
|
|
}
|
|
|
|
return pTextField;
|
|
}
|
|
|
|
SwTextField* SwCursorShell::GetTextFieldAtCursor(
|
|
const SwPaM* pCursor,
|
|
::sw::GetTextAttrMode const eMode)
|
|
{
|
|
SwTextField* pTextField = GetTextFieldAtPos(pCursor->Start(), eMode);
|
|
if ( !pTextField
|
|
|| pCursor->Start()->GetNode() != pCursor->End()->GetNode() )
|
|
return nullptr;
|
|
|
|
SwTextField* pFieldAtCursor = nullptr;
|
|
const sal_Int32 nTextFieldLength =
|
|
pTextField->End() != nullptr
|
|
? *(pTextField->End()) - pTextField->GetStart()
|
|
: 1;
|
|
if ( ( pCursor->End()->GetContentIndex() - pCursor->Start()->GetContentIndex() ) <= nTextFieldLength )
|
|
{
|
|
pFieldAtCursor = pTextField;
|
|
}
|
|
|
|
return pFieldAtCursor;
|
|
}
|
|
|
|
SwField* SwCursorShell::GetFieldAtCursor(
|
|
const SwPaM *const pCursor,
|
|
const bool bIncludeInputFieldAtStart)
|
|
{
|
|
SwTextField *const pField(GetTextFieldAtCursor(pCursor,
|
|
bIncludeInputFieldAtStart ? ::sw::GetTextAttrMode::Default : ::sw::GetTextAttrMode::Expand));
|
|
return pField
|
|
? const_cast<SwField*>(pField->GetFormatField().GetField())
|
|
: nullptr;
|
|
}
|
|
|
|
SwField* SwCursorShell::GetCurField( const bool bIncludeInputFieldAtStart ) const
|
|
{
|
|
SwPaM* pCursor = GetCursor();
|
|
if ( pCursor->IsMultiSelection() )
|
|
{
|
|
// multi selection not handled.
|
|
return nullptr;
|
|
}
|
|
|
|
SwField* pCurField = GetFieldAtCursor( pCursor, bIncludeInputFieldAtStart );
|
|
if ( pCurField != nullptr
|
|
&& SwFieldIds::Table == pCurField->GetTyp()->Which() )
|
|
{
|
|
// table formula? convert internal name into external
|
|
const SwTableNode* pTableNd = IsCursorInTable();
|
|
static_cast<SwTableField*>(pCurField)->PtrToBoxNm( pTableNd ? &pTableNd->GetTable() : nullptr );
|
|
}
|
|
|
|
return pCurField;
|
|
}
|
|
|
|
bool SwCursorShell::CursorInsideInputField() const
|
|
{
|
|
for(SwPaM& rCursor : GetCursor()->GetRingContainer())
|
|
{
|
|
if (dynamic_cast<const SwTextInputField*>(GetTextFieldAtCursor(&rCursor, ::sw::GetTextAttrMode::Parent)))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
SwTextContentControl* SwCursorShell::CursorInsideContentControl() const
|
|
{
|
|
for (SwPaM& rCursor : GetCursor()->GetRingContainer())
|
|
{
|
|
const SwPosition* pStart = rCursor.Start();
|
|
SwTextNode* pTextNode = pStart->GetNode().GetTextNode();
|
|
if (!pTextNode)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
sal_Int32 nIndex = pStart->GetContentIndex();
|
|
if (SwTextAttr* pAttr = pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent))
|
|
{
|
|
return static_txtattr_cast<SwTextContentControl*>(pAttr);
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool SwCursorShell::PosInsideInputField( const SwPosition& rPos )
|
|
{
|
|
return dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos(&rPos, ::sw::GetTextAttrMode::Parent)) != nullptr;
|
|
}
|
|
|
|
bool SwCursorShell::DocPtInsideInputField( const Point& rDocPt ) const
|
|
{
|
|
SwPosition aPos( *(GetCursor()->Start()) );
|
|
Point aDocPt( rDocPt );
|
|
if ( GetLayout()->GetModelPositionForViewPoint( &aPos, aDocPt ) )
|
|
{
|
|
return PosInsideInputField( aPos );
|
|
}
|
|
return false;
|
|
}
|
|
|
|
sal_Int32 SwCursorShell::StartOfInputFieldAtPos( const SwPosition& rPos )
|
|
{
|
|
const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos(&rPos, ::sw::GetTextAttrMode::Default));
|
|
assert(pTextInputField != nullptr
|
|
&& "<SwEditShell::StartOfInputFieldAtPos(..)> - no Input Field at given position");
|
|
return pTextInputField->GetStart();
|
|
}
|
|
|
|
sal_Int32 SwCursorShell::EndOfInputFieldAtPos( const SwPosition& rPos )
|
|
{
|
|
const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos(&rPos, ::sw::GetTextAttrMode::Default));
|
|
assert(pTextInputField != nullptr
|
|
&& "<SwEditShell::EndOfInputFieldAtPos(..)> - no Input Field at given position");
|
|
return *(pTextInputField->End());
|
|
}
|
|
|
|
void SwCursorShell::GotoOutline( SwOutlineNodes::size_type nIdx )
|
|
{
|
|
SwCursor* pCursor = getShellCursor( true );
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *pCursor );
|
|
|
|
const SwNodes& rNds = GetDoc()->GetNodes();
|
|
SwTextNode* pTextNd = rNds.GetOutLineNds()[ nIdx ]->GetTextNode();
|
|
pCursor->GetPoint()->Assign(*pTextNd);
|
|
|
|
if( !pCursor->IsSelOvr() )
|
|
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
}
|
|
|
|
bool SwCursorShell::GotoOutline( const OUString& rName )
|
|
{
|
|
SwCursor* pCursor = getShellCursor( true );
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *pCursor );
|
|
|
|
bool bRet = false;
|
|
if (mxDoc->GotoOutline(*pCursor->GetPoint(), rName, GetLayout())
|
|
&& !pCursor->IsSelOvr())
|
|
{
|
|
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
bRet = true;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
/// jump to next node with outline num.
|
|
bool SwCursorShell::GotoNextOutline()
|
|
{
|
|
const SwNodes& rNds = GetDoc()->GetNodes();
|
|
|
|
if ( rNds.GetOutLineNds().empty() )
|
|
{
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
|
|
return false;
|
|
}
|
|
|
|
SwCursor* pCursor = getShellCursor( true );
|
|
SwNode* pNd = &(pCursor->GetPointNode());
|
|
SwOutlineNodes::size_type nPos;
|
|
bool bUseFirst = !rNds.GetOutLineNds().Seek_Entry( pNd, &nPos );
|
|
SwOutlineNodes::size_type const nStartPos(nPos);
|
|
|
|
do
|
|
{
|
|
if (!bUseFirst)
|
|
{
|
|
++nPos;
|
|
}
|
|
if (rNds.GetOutLineNds().size() <= nPos)
|
|
{
|
|
nPos = 0;
|
|
}
|
|
|
|
if (bUseFirst)
|
|
{
|
|
bUseFirst = false;
|
|
}
|
|
else
|
|
{
|
|
if (nPos == nStartPos)
|
|
{
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
pNd = rNds.GetOutLineNds()[ nPos ];
|
|
}
|
|
while (!sw::IsParaPropsNode(*GetLayout(), *pNd->GetTextNode()));
|
|
|
|
if (nPos < nStartPos)
|
|
{
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::EndWrapped );
|
|
}
|
|
else
|
|
{
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
|
|
}
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *pCursor );
|
|
pCursor->GetPoint()->Assign(*pNd);
|
|
|
|
bool bRet = !pCursor->IsSelOvr();
|
|
if( bRet )
|
|
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
return bRet;
|
|
}
|
|
|
|
/// jump to previous node with outline num.
|
|
bool SwCursorShell::GotoPrevOutline()
|
|
{
|
|
const SwNodes& rNds = GetDoc()->GetNodes();
|
|
|
|
if ( rNds.GetOutLineNds().empty() )
|
|
{
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
|
|
return false;
|
|
}
|
|
|
|
SwCursor* pCursor = getShellCursor( true );
|
|
SwNode* pNd = &(pCursor->GetPointNode());
|
|
SwOutlineNodes::size_type nPos;
|
|
(void)rNds.GetOutLineNds().Seek_Entry(pNd, &nPos);
|
|
SwOutlineNodes::size_type const nStartPos(nPos);
|
|
|
|
do
|
|
{
|
|
if (nPos == 0)
|
|
{
|
|
nPos = rNds.GetOutLineNds().size() - 1;
|
|
}
|
|
else
|
|
{
|
|
--nPos; // before
|
|
}
|
|
if (nPos == nStartPos)
|
|
{
|
|
pNd = nullptr;
|
|
break;
|
|
}
|
|
|
|
pNd = rNds.GetOutLineNds()[ nPos ];
|
|
}
|
|
while (!sw::IsParaPropsNode(*GetLayout(), *pNd->GetTextNode()));
|
|
|
|
if (!pNd)
|
|
{
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
|
|
return false;
|
|
}
|
|
|
|
if (nStartPos < nPos)
|
|
{
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::StartWrapped );
|
|
}
|
|
else
|
|
{
|
|
SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
|
|
}
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *pCursor );
|
|
pCursor->GetPoint()->Assign(*pNd);
|
|
|
|
bool bRet = !pCursor->IsSelOvr();
|
|
if( bRet )
|
|
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
return bRet;
|
|
}
|
|
|
|
/// 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
|
|
}
|
|
|
|
void SwCursorShell::MakeOutlineSel(SwOutlineNodes::size_type nSttPos, SwOutlineNodes::size_type nEndPos,
|
|
bool bWithChildren , bool bKillPams, SwOutlineNodesInline* pOutlNdsInline)
|
|
{
|
|
SwOutlineNodesInline::size_type nEndPosInline = SwOutlineNodesInline::npos;
|
|
const SwNodes& rNds = GetDoc()->GetNodes();
|
|
const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds();
|
|
if( rOutlNds.empty() )
|
|
return;
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
|
|
if( nSttPos > nEndPos ) // parameters switched?
|
|
{
|
|
OSL_ENSURE( false, "Start > End for array access" );
|
|
std::swap(nSttPos, nEndPos);
|
|
}
|
|
|
|
SwNode* pSttNd = rOutlNds[ nSttPos ];
|
|
SwNode* pEndNd = rOutlNds[ nEndPos ];
|
|
|
|
if( pOutlNdsInline )
|
|
{
|
|
pSttNd = const_cast<SwNode*>(SwOutlineNodes::GetRootNode(pSttNd));
|
|
pOutlNdsInline->Seek_Entry( pEndNd, &nEndPosInline );
|
|
}
|
|
|
|
if( bWithChildren && !pOutlNdsInline )
|
|
{
|
|
const int nLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel()-1;
|
|
for( ++nEndPos; nEndPos < rOutlNds.size(); ++nEndPos )
|
|
{
|
|
pEndNd = rOutlNds[ nEndPos ];
|
|
const int nNxtLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel()-1;
|
|
if( nNxtLevel <= nLevel )
|
|
break; // EndPos is now on the next one
|
|
}
|
|
}
|
|
// headings in flys
|
|
else if( bWithChildren && pOutlNdsInline )
|
|
{
|
|
const int nLevel = pEndNd->GetTextNode()->GetAttrOutlineLevel() - 1;
|
|
for( ++nEndPosInline; nEndPosInline < pOutlNdsInline->size(); ++nEndPosInline )
|
|
{
|
|
pEndNd = (*pOutlNdsInline)[ nEndPosInline ];
|
|
const int 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));
|
|
}
|
|
// if without children then set onto next one
|
|
else if( !pOutlNdsInline && ++nEndPos < rOutlNds.size() )
|
|
pEndNd = rOutlNds[ nEndPos ];
|
|
else if( pOutlNdsInline && ++nEndPosInline < pOutlNdsInline->size() )
|
|
pEndNd = const_cast<SwNode*>(SwOutlineNodes::GetRootNode((*pOutlNdsInline)[nEndPosInline]));
|
|
|
|
if( ( pOutlNdsInline && nEndPosInline == pOutlNdsInline->size() ) ||
|
|
( !pOutlNdsInline && nEndPos == rOutlNds.size() ) ) // no end found
|
|
pEndNd = &rNds.GetEndOfContent();
|
|
|
|
if( bKillPams )
|
|
KillPams();
|
|
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
// 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);
|
|
}
|
|
|
|
/// jump to reference marker
|
|
bool SwCursorShell::GotoRefMark( const OUString& rRefMark, sal_uInt16 nSubType,
|
|
sal_uInt16 nSeqNo, sal_uInt16 nFlags )
|
|
{
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
sal_Int32 nPos = -1;
|
|
|
|
SwPaM* pCursor = GetCursor();
|
|
SwPosition* pPos = pCursor->GetPoint();
|
|
SwTextNode* pRefTextNd = pPos->GetNode().GetTextNode();
|
|
SwContentFrame* pRefFrame = GetCurrFrame();
|
|
|
|
SwTextNode* pTextNd = SwGetRefFieldType::FindAnchor(GetDoc(), rRefMark,
|
|
nSubType, nSeqNo, nFlags, &nPos, nullptr, GetLayout(), pRefTextNd, pRefFrame);
|
|
if( !pTextNd || !pTextNd->GetNodes().IsDocNodes() )
|
|
return false;
|
|
|
|
m_pCurrentCursor->GetPoint()->Assign(*pTextNd, nPos );
|
|
|
|
if( m_pCurrentCursor->IsSelOvr() )
|
|
return false;
|
|
|
|
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
return true;
|
|
}
|
|
|
|
bool SwCursorShell::IsPageAtPos( const Point &rPt ) const
|
|
{
|
|
if( GetLayout() )
|
|
return nullptr != GetLayout()->GetPageAtPos( rPt );
|
|
return false;
|
|
}
|
|
|
|
bool SwCursorShell::GetContentAtPos( const Point& rPt,
|
|
SwContentAtPos& rContentAtPos,
|
|
bool bSetCursor,
|
|
SwRect* pFieldRect )
|
|
{
|
|
CurrShell aCurr( this );
|
|
bool bRet = false;
|
|
|
|
if( IsTableMode() )
|
|
{
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::NONE;
|
|
rContentAtPos.aFnd.pField = nullptr;
|
|
return false;
|
|
}
|
|
|
|
Point aPt( rPt );
|
|
SwPosition aPos( *m_pCurrentCursor->GetPoint() );
|
|
|
|
SwTextNode* pTextNd;
|
|
SwCursorMoveState aTmpState;
|
|
aTmpState.m_bFieldInfo = true;
|
|
aTmpState.m_bExactOnly = !( IsAttrAtPos::Outline & rContentAtPos.eContentAtPos );
|
|
aTmpState.m_bContentCheck = bool(IsAttrAtPos::ContentCheck & rContentAtPos.eContentAtPos);
|
|
aTmpState.m_bSetInReadOnly = IsReadOnlyAvailable();
|
|
aTmpState.m_bPosMatchesBounds = true; // treat last half of character same as first half
|
|
|
|
SwSpecialPos aSpecialPos;
|
|
aTmpState.m_pSpecialPos = ( IsAttrAtPos::SmartTag & rContentAtPos.eContentAtPos ) ?
|
|
&aSpecialPos : nullptr;
|
|
|
|
const bool bCursorFoundExact = GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aTmpState );
|
|
pTextNd = aPos.GetNode().GetTextNode();
|
|
|
|
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;
|
|
}
|
|
}
|
|
else if ( IsAttrAtPos::ContentCheck & rContentAtPos.eContentAtPos
|
|
&& bCursorFoundExact )
|
|
{
|
|
bRet = true;
|
|
}
|
|
else if( pTextNd
|
|
&& IsAttrAtPos::NumLabel & rContentAtPos.eContentAtPos)
|
|
{
|
|
bRet = aTmpState.m_bInNumPortion;
|
|
rContentAtPos.aFnd.pNode = sw::GetParaPropsNode(*GetLayout(), aPos.GetNode());
|
|
|
|
Size aSizeLogic(aTmpState.m_nInNumPortionOffset, 0);
|
|
Size aSizePixel = GetWin()->LogicToPixel(aSizeLogic);
|
|
rContentAtPos.nDist = aSizePixel.Width();
|
|
}
|
|
else if( bCursorFoundExact && pTextNd )
|
|
{
|
|
SwContentFrame *pFrame(nullptr);
|
|
if( !aTmpState.m_bPosCorr )
|
|
{
|
|
SwTextAttr* pTextAttr;
|
|
if ( IsAttrAtPos::SmartTag & rContentAtPos.eContentAtPos
|
|
&& !aTmpState.m_bFootnoteNoInfo )
|
|
{
|
|
const SwWrongList* pSmartTagList = pTextNd->GetSmartTags();
|
|
sal_Int32 nCurrent = aPos.GetContentIndex();
|
|
const sal_Int32 nBegin = nCurrent;
|
|
sal_Int32 nLen = 1;
|
|
|
|
if (pSmartTagList && pSmartTagList->InWrongWord(nCurrent, nLen) && !pTextNd->IsSymbolAt(nBegin))
|
|
{
|
|
const sal_uInt16 nIndex = pSmartTagList->GetWrongPos( nBegin );
|
|
const SwWrongList* pSubList = pSmartTagList->SubList( nIndex );
|
|
if ( pSubList )
|
|
{
|
|
nCurrent = aTmpState.m_pSpecialPos->nCharOfst;
|
|
|
|
if ( pSubList->InWrongWord( nCurrent, nLen ) )
|
|
bRet = true;
|
|
}
|
|
else
|
|
bRet = true;
|
|
|
|
if( bRet && bSetCursor )
|
|
{
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
m_pCurrentCursor->DeleteMark();
|
|
*m_pCurrentCursor->GetPoint() = aPos;
|
|
if( m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection | SwCursorSelOverFlags::Toggle) )
|
|
bRet = false;
|
|
else
|
|
UpdateCursor();
|
|
}
|
|
if( bRet )
|
|
{
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::SmartTag;
|
|
|
|
std::pair<Point, bool> tmp(aPt, true);
|
|
if (pFieldRect)
|
|
{
|
|
pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
|
|
if (pFrame)
|
|
pFrame->GetCharRect( *pFieldRect, aPos, &aTmpState );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !bRet
|
|
&& ( IsAttrAtPos::Field | IsAttrAtPos::ClickField ) & rContentAtPos.eContentAtPos
|
|
&& !aTmpState.m_bFootnoteNoInfo )
|
|
{
|
|
pTextAttr = pTextNd->GetFieldTextAttrAt( aPos.GetContentIndex() );
|
|
const SwField* pField = pTextAttr != nullptr
|
|
? pTextAttr->GetFormatField().GetField()
|
|
: nullptr;
|
|
if ( IsAttrAtPos::ClickField & rContentAtPos.eContentAtPos
|
|
&& pField && !pField->HasClickHdl() )
|
|
{
|
|
pField = nullptr;
|
|
}
|
|
|
|
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();
|
|
}
|
|
else if( 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( pField )
|
|
{
|
|
rContentAtPos.aFnd.pField = pField;
|
|
rContentAtPos.pFndTextAttr = pTextAttr;
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::Field;
|
|
bRet = true;
|
|
}
|
|
}
|
|
|
|
if( !bRet && IsAttrAtPos::FormControl & rContentAtPos.eContentAtPos )
|
|
{
|
|
IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess( );
|
|
sw::mark::Fieldmark* pFieldBookmark = pMarksAccess->getInnerFieldmarkFor(aPos);
|
|
if (bCursorFoundExact && pFieldBookmark)
|
|
{
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::FormControl;
|
|
rContentAtPos.aFnd.pFieldmark = pFieldBookmark;
|
|
bRet=true;
|
|
}
|
|
}
|
|
|
|
if (!bRet && rContentAtPos.eContentAtPos & IsAttrAtPos::ContentControl)
|
|
{
|
|
SwTextAttr* pAttr = pTextNd->GetTextAttrAt(
|
|
aPos.GetContentIndex(), RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent);
|
|
if (pAttr)
|
|
{
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::ContentControl;
|
|
rContentAtPos.pFndTextAttr = pAttr;
|
|
bRet = true;
|
|
}
|
|
}
|
|
|
|
if( !bRet && IsAttrAtPos::Ftn & rContentAtPos.eContentAtPos )
|
|
{
|
|
if( aTmpState.m_bFootnoteNoInfo )
|
|
{
|
|
// over the footnote's char
|
|
bRet = true;
|
|
if( bSetCursor )
|
|
{
|
|
*m_pCurrentCursor->GetPoint() = aPos;
|
|
if( !GotoFootnoteAnchor() )
|
|
bRet = false;
|
|
}
|
|
if( bRet )
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::Ftn;
|
|
}
|
|
else if ( nullptr != ( pTextAttr = pTextNd->GetTextAttrForCharAt(
|
|
aPos.GetContentIndex(), RES_TXTATR_FTN )) )
|
|
{
|
|
bRet = true;
|
|
if( bSetCursor )
|
|
{
|
|
if (SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(this))
|
|
pWrtSh->addCurrentPosition();
|
|
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
m_pCurrentCursor->GetPoint()->Assign( *static_cast<SwTextFootnote*>(pTextAttr)->GetStartNode() );
|
|
SwContentNode* pCNd = SwNodes::GoNextSection(
|
|
m_pCurrentCursor->GetPoint(),
|
|
true, !IsReadOnlyAvailable() );
|
|
|
|
if( pCNd )
|
|
{
|
|
if( m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
|
|
SwCursorSelOverFlags::Toggle ))
|
|
bRet = false;
|
|
else
|
|
UpdateCursor();
|
|
}
|
|
else
|
|
bRet = false;
|
|
}
|
|
|
|
if( bRet )
|
|
{
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::Ftn;
|
|
rContentAtPos.pFndTextAttr = pTextAttr;
|
|
rContentAtPos.aFnd.pAttr = &pTextAttr->GetAttr();
|
|
|
|
if (pFieldRect)
|
|
{
|
|
std::pair<Point, bool> tmp(aPt, true);
|
|
pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
|
|
if (pFrame)
|
|
pFrame->GetCharRect( *pFieldRect, aPos, &aTmpState );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !bRet
|
|
&& ( IsAttrAtPos::ToxMark | IsAttrAtPos::RefMark ) & rContentAtPos.eContentAtPos
|
|
&& !aTmpState.m_bFootnoteNoInfo )
|
|
{
|
|
pTextAttr = nullptr;
|
|
if( IsAttrAtPos::ToxMark & rContentAtPos.eContentAtPos )
|
|
{
|
|
std::vector<SwTextAttr *> const marks(
|
|
pTextNd->GetTextAttrsAt(
|
|
aPos.GetContentIndex(), RES_TXTATR_TOXMARK));
|
|
if (!marks.empty())
|
|
{ // hmm... can only return 1 here
|
|
pTextAttr = *marks.begin();
|
|
}
|
|
}
|
|
|
|
if( !pTextAttr &&
|
|
IsAttrAtPos::RefMark & rContentAtPos.eContentAtPos )
|
|
{
|
|
std::vector<SwTextAttr *> const marks(
|
|
pTextNd->GetTextAttrsAt(
|
|
aPos.GetContentIndex(), RES_TXTATR_REFMARK));
|
|
if (!marks.empty())
|
|
{ // hmm... can only return 1 here
|
|
pTextAttr = *marks.begin();
|
|
}
|
|
}
|
|
|
|
if( pTextAttr )
|
|
{
|
|
bRet = true;
|
|
if( bSetCursor )
|
|
{
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
m_pCurrentCursor->DeleteMark();
|
|
*m_pCurrentCursor->GetPoint() = aPos;
|
|
if( m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection | SwCursorSelOverFlags::Toggle ) )
|
|
bRet = false;
|
|
else
|
|
UpdateCursor();
|
|
}
|
|
|
|
if( bRet )
|
|
{
|
|
const sal_Int32* pEnd = pTextAttr->GetEnd();
|
|
if( pEnd )
|
|
rContentAtPos.sStr =
|
|
pTextNd->GetExpandText(GetLayout(), pTextAttr->GetStart(), *pEnd - pTextAttr->GetStart());
|
|
else if( RES_TXTATR_TOXMARK == pTextAttr->Which())
|
|
rContentAtPos.sStr =
|
|
pTextAttr->GetTOXMark().GetAlternativeText();
|
|
|
|
rContentAtPos.eContentAtPos =
|
|
RES_TXTATR_TOXMARK == pTextAttr->Which()
|
|
? IsAttrAtPos::ToxMark
|
|
: IsAttrAtPos::RefMark;
|
|
rContentAtPos.pFndTextAttr = pTextAttr;
|
|
rContentAtPos.aFnd.pAttr = &pTextAttr->GetAttr();
|
|
|
|
std::pair<Point, bool> tmp(aPt, true);
|
|
if (pFieldRect)
|
|
{
|
|
pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
|
|
if (pFrame)
|
|
pFrame->GetCharRect( *pFieldRect, aPos, &aTmpState );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !bRet
|
|
&& IsAttrAtPos::InetAttr & rContentAtPos.eContentAtPos
|
|
&& !aTmpState.m_bFootnoteNoInfo )
|
|
{
|
|
sal_Int32 index = aPos.GetContentIndex();
|
|
pTextAttr = pTextNd->GetTextAttrAt(index, RES_TXTATR_INETFMT);
|
|
|
|
// "detect" only INetAttrs with URLs
|
|
if( pTextAttr && !pTextAttr->GetINetFormat().GetValue().isEmpty() )
|
|
{
|
|
bRet = true;
|
|
if( bSetCursor )
|
|
{
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
m_pCurrentCursor->DeleteMark();
|
|
*m_pCurrentCursor->GetPoint() = aPos;
|
|
if( m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
|
|
SwCursorSelOverFlags::Toggle) )
|
|
bRet = false;
|
|
else
|
|
UpdateCursor();
|
|
}
|
|
if( bRet )
|
|
{
|
|
const sal_Int32 nSt = pTextAttr->GetStart();
|
|
const sal_Int32 nEnd = *pTextAttr->End();
|
|
|
|
rContentAtPos.sStr = pTextNd->GetExpandText(GetLayout(), nSt, nEnd-nSt);
|
|
|
|
rContentAtPos.aFnd.pAttr = &pTextAttr->GetAttr();
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::InetAttr;
|
|
rContentAtPos.pFndTextAttr = pTextAttr;
|
|
|
|
if (pFieldRect)
|
|
{
|
|
std::pair<Point, bool> tmp(aPt, true);
|
|
pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
|
|
if (pFrame)
|
|
{
|
|
//get bounding box of range
|
|
SwRect aStart;
|
|
SwPosition aStartPos(*pTextNd, nSt);
|
|
pFrame->GetCharRect(aStart, aStartPos, &aTmpState);
|
|
SwRect aEnd;
|
|
SwPosition aEndPos(*pTextNd, nEnd);
|
|
pFrame->GetCharRect(aEnd, aEndPos, &aTmpState);
|
|
if (aStart.Top() != aEnd.Top() || aStart.Bottom() != aEnd.Bottom())
|
|
{
|
|
aStart.Left(pFrame->getFrameArea().Left());
|
|
aEnd.Right(pFrame->getFrameArea().Right());
|
|
}
|
|
*pFieldRect = aStart.Union(aEnd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !bRet && IsAttrAtPos::Redline & rContentAtPos.eContentAtPos )
|
|
{
|
|
SwRedlineTable::size_type index;
|
|
IDocumentRedlineAccess const& rIDRA{GetDoc()->getIDocumentRedlineAccess()};
|
|
const SwRangeRedline* pRedl{rIDRA.GetRedline(aPos, &index)};
|
|
|
|
if( pRedl )
|
|
{
|
|
// treat insert/delete as more important than formatting
|
|
for (; index < rIDRA.GetRedlineTable().size(); ++index)
|
|
{
|
|
SwRangeRedline const*const pTmp{rIDRA.GetRedlineTable()[index]};
|
|
if (aPos < *pTmp->Start())
|
|
{
|
|
break;
|
|
}
|
|
switch (pRedl->GetType())
|
|
{
|
|
case RedlineType::Format:
|
|
case RedlineType::FmtColl:
|
|
case RedlineType::ParagraphFormat:
|
|
switch (pTmp->GetType())
|
|
{
|
|
case RedlineType::Insert:
|
|
case RedlineType::Delete:
|
|
pRedl = pTmp;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
};
|
|
|
|
rContentAtPos.aFnd.pRedl = pRedl;
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::Redline;
|
|
rContentAtPos.pFndTextAttr = nullptr;
|
|
bRet = true;
|
|
|
|
if (pFieldRect)
|
|
{
|
|
std::pair<Point, bool> tmp(aPt, true);
|
|
pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
|
|
if( pFrame )
|
|
{
|
|
// not sure if this should be limited to one
|
|
// paragraph, or mark the entire redline; let's
|
|
// leave it limited to one for now...
|
|
sal_Int32 nStart;
|
|
sal_Int32 nEnd;
|
|
pRedl->CalcStartEnd(pTextNd->GetIndex(), nStart, nEnd);
|
|
if (nStart == COMPLETE_STRING)
|
|
{
|
|
// consistency: found pRedl, so there must be
|
|
// something in pTextNd
|
|
assert(nEnd != COMPLETE_STRING);
|
|
nStart = 0;
|
|
}
|
|
if (nEnd == COMPLETE_STRING)
|
|
{
|
|
nEnd = pTextNd->Len();
|
|
}
|
|
//get bounding box of range
|
|
SwRect aStart;
|
|
pFrame->GetCharRect(aStart, SwPosition(*pTextNd, nStart), &aTmpState);
|
|
SwRect aEnd;
|
|
pFrame->GetCharRect(aEnd, SwPosition(*pTextNd, nEnd), &aTmpState);
|
|
if (aStart.Top() != aEnd.Top() || aStart.Bottom() != aEnd.Bottom())
|
|
{
|
|
aStart.Left(pFrame->getFrameArea().Left());
|
|
aEnd.Right(pFrame->getFrameArea().Right());
|
|
}
|
|
*pFieldRect = aStart.Union(aEnd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !bRet && ( ( IsAttrAtPos::TableRedline & rContentAtPos.eContentAtPos ) ||
|
|
( IsAttrAtPos::TableColRedline & rContentAtPos.eContentAtPos ) ) )
|
|
{
|
|
const SwTableNode* pTableNd;
|
|
const SwTableBox* pBox;
|
|
const SwTableLine* pTableLine;
|
|
const SwStartNode* pSttNd = pTextNd->FindTableBoxStartNode();
|
|
if( pSttNd && nullptr != ( pTableNd = pTextNd->FindTableNode()) &&
|
|
nullptr != ( pBox = pTableNd->GetTable().GetTableBox(
|
|
pSttNd->GetIndex() )) &&
|
|
nullptr != ( pTableLine = pBox->GetUpper() ) &&
|
|
( RedlineType::None != pBox->GetRedlineType() ||
|
|
RedlineType::None != pTableLine->GetRedlineType() ) )
|
|
{
|
|
const SwRedlineTable& aRedlineTable = GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
|
|
if ( RedlineType::None != pTableLine->GetRedlineType() )
|
|
{
|
|
SwRedlineTable::size_type nPos = 0;
|
|
nPos = pTableLine->UpdateTextChangesOnly(nPos);
|
|
if ( nPos != SwRedlineTable::npos )
|
|
{
|
|
rContentAtPos.aFnd.pRedl = aRedlineTable[nPos];
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::TableRedline;
|
|
bRet = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SwRedlineTable::size_type n = 0;
|
|
SwNodeIndex aIdx( *pSttNd, 1 );
|
|
const SwPosition aBoxStart(aIdx);
|
|
const SwRangeRedline* pFnd = aRedlineTable.FindAtPosition( aBoxStart, n, /*next=*/true );
|
|
if( pFnd && RedlineType::Delete == pFnd->GetType() )
|
|
{
|
|
rContentAtPos.aFnd.pRedl = aRedlineTable[n];
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::TableColRedline;
|
|
bRet = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !bRet
|
|
&& ( IsAttrAtPos::TableBoxFml & rContentAtPos.eContentAtPos
|
|
#ifdef DBG_UTIL
|
|
|| IsAttrAtPos::TableBoxValue & rContentAtPos.eContentAtPos
|
|
#endif
|
|
) )
|
|
{
|
|
const SwTableNode* pTableNd;
|
|
const SwTableBox* pBox;
|
|
const SwStartNode* pSttNd = pTextNd->FindTableBoxStartNode();
|
|
const SwTableBoxFormula* pItem;
|
|
#ifdef DBG_UTIL
|
|
const SwTableBoxValue* pItem2 = nullptr;
|
|
#endif
|
|
if( pSttNd && nullptr != ( pTableNd = pTextNd->FindTableNode()) &&
|
|
nullptr != ( pBox = pTableNd->GetTable().GetTableBox(
|
|
pSttNd->GetIndex() )) &&
|
|
#ifdef DBG_UTIL
|
|
( (pItem = pBox->GetFrameFormat()->GetItemIfSet( RES_BOXATR_FORMULA, false )) ||
|
|
(pItem2 = pBox->GetFrameFormat()->GetItemIfSet( RES_BOXATR_VALUE, false )) )
|
|
#else
|
|
(pItem = pBox->GetFrameFormat()->GetItemIfSet( RES_BOXATR_FORMULA, false ))
|
|
#endif
|
|
)
|
|
{
|
|
std::pair<Point, bool> tmp(aPt, true);
|
|
SwFrame* pF = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
|
|
if( pF )
|
|
{
|
|
// then the CellFrame
|
|
pFrame = static_cast<SwContentFrame*>(pF);
|
|
while( pF && !pF->IsCellFrame() )
|
|
pF = pF->GetUpper();
|
|
}
|
|
|
|
if( aTmpState.m_bPosCorr )
|
|
{
|
|
if( pF && !pF->getFrameArea().Contains( aPt ))
|
|
pF = nullptr;
|
|
}
|
|
else if( !pF )
|
|
pF = pFrame;
|
|
|
|
if( pF ) // only then it is valid
|
|
{
|
|
// create from internal (for CORE) the external
|
|
// (for UI) formula
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::TableBoxFml;
|
|
#ifdef DBG_UTIL
|
|
if( pItem2 )
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::TableBoxValue;
|
|
else
|
|
#endif
|
|
const_cast<SwTableBoxFormula&>(*pItem).PtrToBoxNm( &pTableNd->GetTable() );
|
|
|
|
bRet = true;
|
|
if( bSetCursor )
|
|
{
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
*m_pCurrentCursor->GetPoint() = std::move(aPos);
|
|
if( m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::CheckNodeSection |
|
|
SwCursorSelOverFlags::Toggle) )
|
|
bRet = false;
|
|
else
|
|
UpdateCursor();
|
|
}
|
|
|
|
if( bRet )
|
|
{
|
|
if( pFieldRect )
|
|
{
|
|
*pFieldRect = pF->getFramePrintArea();
|
|
*pFieldRect += pF->getFrameArea().Pos();
|
|
}
|
|
rContentAtPos.pFndTextAttr = nullptr;
|
|
rContentAtPos.aFnd.pAttr = pItem;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DBG_UTIL
|
|
if( !bRet && IsAttrAtPos::CurrAttrs & rContentAtPos.eContentAtPos )
|
|
{
|
|
const sal_Int32 n = aPos.GetContentIndex();
|
|
SfxItemSetFixed<POOLATTR_BEGIN, POOLATTR_END - 1> aSet( GetDoc()->GetAttrPool() );
|
|
if( pTextNd->GetpSwpHints() )
|
|
{
|
|
for( size_t i = 0; i < pTextNd->GetSwpHints().Count(); ++i )
|
|
{
|
|
const SwTextAttr* pHt = pTextNd->GetSwpHints().Get(i);
|
|
const sal_Int32 nAttrStart = pHt->GetStart();
|
|
if( nAttrStart > n ) // over the section
|
|
break;
|
|
|
|
if( nullptr != pHt->End() && (
|
|
( nAttrStart < n &&
|
|
( pHt->DontExpand() ? n < *pHt->End()
|
|
: n <= *pHt->End() )) ||
|
|
( n == nAttrStart &&
|
|
( nAttrStart == *pHt->End() || !n ))) )
|
|
{
|
|
aSet.Put( pHt->GetAttr() );
|
|
}
|
|
}
|
|
if( pTextNd->HasSwAttrSet() &&
|
|
pTextNd->GetpSwAttrSet()->Count() )
|
|
{
|
|
SfxItemSet aFormatSet( pTextNd->GetSwAttrSet() );
|
|
// remove all from format set that are also in TextSet
|
|
aFormatSet.Differentiate( aSet );
|
|
// now merge all together
|
|
aSet.Put( aFormatSet );
|
|
}
|
|
}
|
|
else
|
|
pTextNd->SwContentNode::GetAttr( aSet );
|
|
|
|
rContentAtPos.sStr = "Pos: (";
|
|
rContentAtPos.sStr += OUString::number( sal_Int32(aPos.GetNodeIndex()));
|
|
rContentAtPos.sStr += ":";
|
|
rContentAtPos.sStr += OUString::number( aPos.GetContentIndex());
|
|
rContentAtPos.sStr += ")";
|
|
rContentAtPos.sStr += "\nParagraph Style: ";
|
|
rContentAtPos.sStr += pTextNd->GetFormatColl()->GetName();
|
|
if( pTextNd->GetCondFormatColl() )
|
|
{
|
|
rContentAtPos.sStr += "\nConditional Style: " + pTextNd->GetCondFormatColl()->GetName();
|
|
}
|
|
|
|
if( aSet.Count() )
|
|
{
|
|
OUStringBuffer sAttrs;
|
|
SfxItemIter aIter( aSet );
|
|
const SfxPoolItem* pItem = aIter.GetCurItem();
|
|
const IntlWrapper aInt(SvtSysLocale().GetUILanguageTag());
|
|
do
|
|
{
|
|
if( !IsInvalidItem( pItem ))
|
|
{
|
|
OUString aStr;
|
|
GetDoc()->GetAttrPool().GetPresentation(*pItem,
|
|
MapUnit::MapCM, aStr, aInt);
|
|
if (!sAttrs.isEmpty())
|
|
sAttrs.append(", ");
|
|
sAttrs.append(aStr);
|
|
}
|
|
pItem = aIter.NextItem();
|
|
} while (pItem);
|
|
if (!sAttrs.isEmpty())
|
|
{
|
|
if( !rContentAtPos.sStr.isEmpty() )
|
|
rContentAtPos.sStr += "\n";
|
|
rContentAtPos.sStr += "Attr: " + sAttrs;
|
|
}
|
|
}
|
|
bRet = true;
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::CurrAttrs;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if( !bRet )
|
|
{
|
|
rContentAtPos.eContentAtPos = IsAttrAtPos::NONE;
|
|
rContentAtPos.aFnd.pField = nullptr;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
// #i90516#
|
|
const SwPostItField* SwCursorShell::GetPostItFieldAtCursor() const
|
|
{
|
|
if ( IsTableMode() )
|
|
return nullptr;
|
|
|
|
const SwPosition* pCursorPos = GetCursor_()->GetPoint();
|
|
const SwTextNode* pTextNd = pCursorPos->GetNode().GetTextNode();
|
|
if ( !pTextNd )
|
|
return nullptr;
|
|
|
|
const SwPostItField* pPostItField = nullptr;
|
|
SwTextAttr* pTextAttr = pTextNd->GetFieldTextAttrAt( pCursorPos->GetContentIndex() );
|
|
const SwField* pField = pTextAttr != nullptr ? pTextAttr->GetFormatField().GetField() : nullptr;
|
|
if ( pField && pField->Which()== SwFieldIds::Postit )
|
|
{
|
|
pPostItField = static_cast<const SwPostItField*>(pField);
|
|
}
|
|
|
|
return pPostItField;
|
|
}
|
|
|
|
/// is the node in a protected section?
|
|
bool SwContentAtPos::IsInProtectSect() const
|
|
{
|
|
const SwTextNode* pNd = nullptr;
|
|
if( pFndTextAttr )
|
|
{
|
|
switch( eContentAtPos )
|
|
{
|
|
case IsAttrAtPos::Field:
|
|
case IsAttrAtPos::ClickField:
|
|
pNd = static_txtattr_cast<SwTextField const*>(pFndTextAttr)->GetpTextNode();
|
|
break;
|
|
|
|
case IsAttrAtPos::Ftn:
|
|
pNd = &static_cast<const SwTextFootnote*>(pFndTextAttr)->GetTextNode();
|
|
break;
|
|
|
|
case IsAttrAtPos::InetAttr:
|
|
pNd = static_txtattr_cast<SwTextINetFormat const*>(pFndTextAttr)->GetpTextNode();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !pNd )
|
|
return false;
|
|
if( pNd->IsInProtectSect() )
|
|
return true;
|
|
|
|
const SwContentFrame* pFrame = pNd->getLayoutFrame(pNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr);
|
|
return pFrame && pFrame->IsProtected() ;
|
|
}
|
|
|
|
bool SwContentAtPos::IsInRTLText()const
|
|
{
|
|
const SwTextNode* pNd = nullptr;
|
|
if (!pFndTextAttr || (eContentAtPos != IsAttrAtPos::Ftn))
|
|
return false;
|
|
|
|
const SwTextFootnote* pTextFootnote = static_cast<const SwTextFootnote*>(pFndTextAttr);
|
|
if(!pTextFootnote->GetStartNode())
|
|
return false;
|
|
|
|
SwStartNode* pSttNd = pTextFootnote->GetStartNode()->GetNode().GetStartNode();
|
|
SwPaM aTemp( *pSttNd );
|
|
aTemp.Move(fnMoveForward, GoInNode);
|
|
SwContentNode* pContentNode = aTemp.GetPointContentNode();
|
|
if(pContentNode && pContentNode->IsTextNode())
|
|
pNd = pContentNode->GetTextNode();
|
|
if(!pNd)
|
|
return false;
|
|
|
|
bool bRet = false;
|
|
SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
|
|
SwTextFrame* pTmpFrame = aIter.First();
|
|
while( pTmpFrame )
|
|
{
|
|
if ( !pTmpFrame->IsFollow())
|
|
{
|
|
bRet = pTmpFrame->IsRightToLeft();
|
|
break;
|
|
}
|
|
pTmpFrame = aIter.Next();
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
bool SwCursorShell::SelectTextModel( const sal_Int32 nStart,
|
|
const sal_Int32 nEnd )
|
|
{
|
|
CurrShell aCurr( this );
|
|
bool bRet = false;
|
|
|
|
SwCallLink aLk( *this );
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
SwPosition& rPos = *m_pCurrentCursor->GetPoint();
|
|
assert(nEnd <= rPos.GetNode().GetTextNode()->Len());
|
|
m_pCurrentCursor->DeleteMark();
|
|
rPos.SetContent(nStart);
|
|
m_pCurrentCursor->SetMark();
|
|
rPos.SetContent(nEnd);
|
|
|
|
if( !m_pCurrentCursor->IsSelOvr() )
|
|
{
|
|
UpdateCursor();
|
|
bRet = true;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
TextFrameIndex SwCursorShell::GetCursorPointAsViewIndex() const
|
|
{
|
|
SwPosition const*const pPos(GetCursor()->GetPoint());
|
|
SwTextNode const*const pTextNode(pPos->GetNode().GetTextNode());
|
|
assert(pTextNode);
|
|
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(pTextNode->getLayoutFrame(GetLayout())));
|
|
assert(pFrame);
|
|
return pFrame->MapModelToViewPos(*pPos);
|
|
}
|
|
|
|
bool SwCursorShell::SelectTextView(TextFrameIndex const nStart,
|
|
TextFrameIndex const nEnd)
|
|
{
|
|
CurrShell aCurr( this );
|
|
bool bRet = false;
|
|
|
|
SwCallLink aLk( *this );
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
SwPosition& rPos = *m_pCurrentCursor->GetPoint();
|
|
m_pCurrentCursor->DeleteMark();
|
|
// indexes must correspond to cursor point!
|
|
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(m_pCurrentCursor->GetPoint()->GetNode().GetTextNode()->getLayoutFrame(GetLayout())));
|
|
assert(pFrame);
|
|
rPos = pFrame->MapViewToModelPos(nStart);
|
|
m_pCurrentCursor->SetMark();
|
|
rPos = pFrame->MapViewToModelPos(nEnd);
|
|
|
|
if (!m_pCurrentCursor->IsSelOvr())
|
|
{
|
|
UpdateCursor();
|
|
bRet = true;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
bool SwCursorShell::SelectTextAttr( sal_uInt16 nWhich,
|
|
bool bExpand,
|
|
const SwTextAttr* pTextAttr )
|
|
{
|
|
CurrShell aCurr( this );
|
|
|
|
if( IsTableMode() )
|
|
return false;
|
|
|
|
if( !pTextAttr )
|
|
{
|
|
SwPosition& rPos = *m_pCurrentCursor->GetPoint();
|
|
SwTextNode* pTextNd = rPos.GetNode().GetTextNode();
|
|
pTextAttr = pTextNd
|
|
? pTextNd->GetTextAttrAt(rPos.GetContentIndex(),
|
|
nWhich,
|
|
bExpand ? ::sw::GetTextAttrMode::Expand : ::sw::GetTextAttrMode::Default)
|
|
: nullptr;
|
|
}
|
|
if( !pTextAttr )
|
|
return false;
|
|
|
|
const sal_Int32* pEnd = pTextAttr->End();
|
|
sal_Int32 const nEnd(pEnd ? *pEnd : pTextAttr->GetStart() + 1);
|
|
assert(nEnd <= m_pCurrentCursor->GetPoint()->GetNode().GetTextNode()->Len());
|
|
bool bRet = SelectTextModel(pTextAttr->GetStart(), nEnd);
|
|
return bRet;
|
|
}
|
|
|
|
bool SwCursorShell::GotoINetAttr( const SwTextINetFormat& rAttr )
|
|
{
|
|
if( !rAttr.GetpTextNode() )
|
|
return false;
|
|
SwCursor* pCursor = getShellCursor( true );
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *pCursor );
|
|
|
|
pCursor->GetPoint()->Assign(*rAttr.GetpTextNode(), rAttr.GetStart() );
|
|
bool bRet = !pCursor->IsSelOvr();
|
|
if( bRet )
|
|
UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
return bRet;
|
|
}
|
|
|
|
const SwFormatINetFormat* SwCursorShell::FindINetAttr( std::u16string_view rName ) const
|
|
{
|
|
return mxDoc->FindINetAttr( rName );
|
|
}
|
|
|
|
bool SwCursorShell::GetShadowCursorPos( const Point& rPt, SwFillMode eFillMode,
|
|
SwRect& rRect, sal_Int16& rOrient )
|
|
{
|
|
|
|
CurrShell aCurr( this );
|
|
|
|
if (IsTableMode() || HasSelection()
|
|
|| !GetDoc()->GetIDocumentUndoRedo().DoesUndo())
|
|
return false;
|
|
|
|
Point aPt( rPt );
|
|
SwPosition aPos( *m_pCurrentCursor->GetPoint() );
|
|
|
|
SwFillCursorPos aFPos( eFillMode );
|
|
SwCursorMoveState aTmpState( &aFPos );
|
|
|
|
bool bRet = false;
|
|
if( GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aTmpState ) &&
|
|
!aPos.GetNode().IsProtect())
|
|
{
|
|
// start position in protected section?
|
|
rRect = aFPos.aCursor;
|
|
rOrient = aFPos.eOrient;
|
|
bRet = true;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
bool SwCursorShell::SetShadowCursorPos( const Point& rPt, SwFillMode eFillMode )
|
|
{
|
|
CurrShell aCurr( this );
|
|
|
|
if (IsTableMode() || HasSelection()
|
|
|| !GetDoc()->GetIDocumentUndoRedo().DoesUndo())
|
|
return false;
|
|
|
|
Point aPt( rPt );
|
|
SwPosition aPos( *m_pCurrentCursor->GetPoint() );
|
|
|
|
SwFillCursorPos aFPos( eFillMode );
|
|
SwCursorMoveState aTmpState( &aFPos );
|
|
|
|
if( !GetLayout()->GetModelPositionForViewPoint( &aPos, aPt, &aTmpState ) )
|
|
return false;
|
|
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
StartAction();
|
|
|
|
SwContentNode* pCNd = aPos.GetNode().GetContentNode();
|
|
SwUndoId nUndoId = SwUndoId::INS_FROM_SHADOWCRSR;
|
|
// If only the paragraph attributes "Adjust" or "LRSpace" are set,
|
|
// then the following should not delete those again.
|
|
if( 0 == aFPos.nParaCnt + aFPos.nColumnCnt &&
|
|
( SwFillMode::Indent == aFPos.eMode ||
|
|
( text::HoriOrientation::NONE != aFPos.eOrient &&
|
|
0 == aFPos.nTabCnt + aFPos.nSpaceCnt )) &&
|
|
pCNd && pCNd->Len() )
|
|
nUndoId = SwUndoId::EMPTY;
|
|
|
|
GetDoc()->GetIDocumentUndoRedo().StartUndo( nUndoId, nullptr );
|
|
|
|
SwTextFormatColl* pNextFormat = nullptr;
|
|
SwTextNode* pTNd = pCNd ? pCNd->GetTextNode() : nullptr;
|
|
if( pTNd )
|
|
pNextFormat = &pTNd->GetTextColl()->GetNextTextFormatColl();
|
|
|
|
const SwSectionNode* pSectNd = pCNd ? pCNd->FindSectionNode() : nullptr;
|
|
if( pSectNd && aFPos.nParaCnt )
|
|
{
|
|
SwNodeIndex aEnd( aPos.GetNode(), 1 );
|
|
while( aEnd.GetNode().IsEndNode() &&
|
|
&aEnd.GetNode() !=
|
|
pSectNd->EndOfSectionNode() )
|
|
++aEnd;
|
|
|
|
if( aEnd.GetNode().IsEndNode() &&
|
|
pCNd->Len() == aPos.GetContentIndex() )
|
|
aPos.Assign( *pSectNd->EndOfSectionNode() );
|
|
}
|
|
|
|
for( sal_uInt16 n = 0; n < aFPos.nParaCnt + aFPos.nColumnCnt; ++n )
|
|
{
|
|
GetDoc()->getIDocumentContentOperations().AppendTextNode( aPos );
|
|
if( !n && pNextFormat )
|
|
{
|
|
*m_pCurrentCursor->GetPoint() = aPos;
|
|
GetDoc()->SetTextFormatColl( *m_pCurrentCursor, pNextFormat, false );
|
|
}
|
|
if( n < aFPos.nColumnCnt )
|
|
{
|
|
*m_pCurrentCursor->GetPoint() = aPos;
|
|
GetDoc()->getIDocumentContentOperations().InsertPoolItem( *m_pCurrentCursor,
|
|
SvxFormatBreakItem( SvxBreak::ColumnBefore, RES_BREAK ) );
|
|
}
|
|
}
|
|
|
|
*m_pCurrentCursor->GetPoint() = aPos;
|
|
switch( aFPos.eMode )
|
|
{
|
|
case SwFillMode::Indent:
|
|
if( nullptr != (pCNd = aPos.GetNode().GetContentNode() ))
|
|
{
|
|
assert(pCNd->IsTextNode()); // ???
|
|
SfxItemSetFixed<
|
|
RES_PARATR_ADJUST, RES_PARATR_ADJUST,
|
|
RES_MARGIN_FIRSTLINE, RES_MARGIN_TEXTLEFT> aSet(GetDoc()->GetAttrPool());
|
|
SvxFirstLineIndentItem firstLine(pCNd->GetAttr(RES_MARGIN_FIRSTLINE));
|
|
SvxTextLeftMarginItem leftMargin(pCNd->GetAttr(RES_MARGIN_TEXTLEFT));
|
|
firstLine.SetTextFirstLineOffset(SvxIndentValue::zero());
|
|
leftMargin.SetTextLeft(SvxIndentValue::twips(aFPos.nTabCnt));
|
|
aSet.Put(firstLine);
|
|
aSet.Put(leftMargin);
|
|
|
|
const SvxAdjustItem& rAdj = pCNd->GetAttr(RES_PARATR_ADJUST);
|
|
if( SvxAdjust::Left != rAdj.GetAdjust() )
|
|
aSet.Put( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
|
|
|
|
GetDoc()->getIDocumentContentOperations().InsertItemSet( *m_pCurrentCursor, aSet );
|
|
}
|
|
else {
|
|
OSL_ENSURE( false, "No ContentNode" );
|
|
}
|
|
break;
|
|
|
|
case SwFillMode::Tab:
|
|
case SwFillMode::TabSpace:
|
|
case SwFillMode::Space:
|
|
{
|
|
OUStringBuffer sInsert;
|
|
if (aFPos.eMode == SwFillMode::Space)
|
|
{
|
|
comphelper::string::padToLength(sInsert, sInsert.getLength() + aFPos.nSpaceOnlyCnt, ' ');
|
|
}
|
|
else
|
|
{
|
|
if (aFPos.nTabCnt)
|
|
comphelper::string::padToLength(sInsert, aFPos.nTabCnt, '\t');
|
|
if (aFPos.nSpaceCnt)
|
|
comphelper::string::padToLength(sInsert, sInsert.getLength() + aFPos.nSpaceCnt, ' ');
|
|
}
|
|
if (!sInsert.isEmpty())
|
|
GetDoc()->getIDocumentContentOperations().InsertString( *m_pCurrentCursor, sInsert.makeStringAndClear());
|
|
}
|
|
[[fallthrough]]; // still need to set orientation
|
|
case SwFillMode::Margin:
|
|
if( text::HoriOrientation::NONE != aFPos.eOrient )
|
|
{
|
|
SvxAdjustItem aAdj( SvxAdjust::Left, RES_PARATR_ADJUST );
|
|
switch( aFPos.eOrient )
|
|
{
|
|
case text::HoriOrientation::CENTER:
|
|
aAdj.SetAdjust( SvxAdjust::Center );
|
|
break;
|
|
case text::HoriOrientation::RIGHT:
|
|
aAdj.SetAdjust( SvxAdjust::Right );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
GetDoc()->getIDocumentContentOperations().InsertPoolItem( *m_pCurrentCursor, aAdj );
|
|
}
|
|
break;
|
|
}
|
|
|
|
GetDoc()->GetIDocumentUndoRedo().EndUndo( nUndoId, nullptr );
|
|
EndAction();
|
|
|
|
return true;
|
|
}
|
|
|
|
const SwRangeRedline* SwCursorShell::SelNextRedline()
|
|
{
|
|
if( IsTableMode() )
|
|
return nullptr;
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
// ensure point is at the end so alternating SelNext/SelPrev works
|
|
NormalizePam(false);
|
|
const SwRangeRedline* pFnd = GetDoc()->getIDocumentRedlineAccess().SelNextRedline( *m_pCurrentCursor );
|
|
|
|
// at the end of the document, go to the start of the document, and try again
|
|
if ( !pFnd )
|
|
{
|
|
GetDoc()->GetDocShell()->GetWrtShell()->StartOfSection();
|
|
pFnd = GetDoc()->getIDocumentRedlineAccess().SelNextRedline( *m_pCurrentCursor );
|
|
}
|
|
|
|
if( pFnd && !m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr() )
|
|
UpdateCursor( SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
else
|
|
pFnd = nullptr;
|
|
return pFnd;
|
|
}
|
|
|
|
const SwRangeRedline* SwCursorShell::SelPrevRedline()
|
|
{
|
|
if( IsTableMode() )
|
|
return nullptr;
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
// ensure point is at the start so alternating SelNext/SelPrev works
|
|
NormalizePam(true);
|
|
const SwRangeRedline* pFnd = GetDoc()->getIDocumentRedlineAccess().SelPrevRedline( *m_pCurrentCursor );
|
|
|
|
// at the start of the document, go to the end of the document, and try again
|
|
if ( !pFnd )
|
|
{
|
|
GetDoc()->GetDocShell()->GetWrtShell()->EndOfSection();
|
|
pFnd = GetDoc()->getIDocumentRedlineAccess().SelPrevRedline( *m_pCurrentCursor );
|
|
}
|
|
|
|
if( pFnd && !m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr() )
|
|
UpdateCursor( SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY);
|
|
else
|
|
pFnd = nullptr;
|
|
return pFnd;
|
|
}
|
|
|
|
const SwRangeRedline* SwCursorShell::GotoRedline_( SwRedlineTable::size_type nArrPos, bool bSelect )
|
|
{
|
|
const SwRangeRedline* pFnd = nullptr;
|
|
SwCallLink aLk( *this ); // watch Cursor-Moves
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
pFnd = GetDoc()->getIDocumentRedlineAccess().GetRedlineTable()[ nArrPos ];
|
|
if( !pFnd )
|
|
return nullptr;
|
|
|
|
*m_pCurrentCursor->GetPoint() = *pFnd->Start();
|
|
|
|
SwPosition* pPtPos = m_pCurrentCursor->GetPoint();
|
|
if( !pPtPos->GetNode().IsContentNode() )
|
|
{
|
|
SwContentNode* pCNd = SwNodes::GoNextSection(pPtPos,
|
|
true, IsReadOnlyAvailable() );
|
|
if( pCNd )
|
|
{
|
|
if( pPtPos->GetNode() <= pFnd->End()->GetNode() )
|
|
pPtPos->SetContent( 0 );
|
|
else
|
|
pFnd = nullptr;
|
|
}
|
|
}
|
|
|
|
if( pFnd && bSelect )
|
|
{
|
|
m_pCurrentCursor->SetMark();
|
|
if( RedlineType::FmtColl == pFnd->GetType() )
|
|
{
|
|
SwContentNode* pCNd = pPtPos->GetNode().GetContentNode();
|
|
m_pCurrentCursor->GetPoint()->SetContent( pCNd->Len() );
|
|
m_pCurrentCursor->GetMark()->Assign( *pCNd, 0 );
|
|
}
|
|
else
|
|
*m_pCurrentCursor->GetPoint() = *pFnd->End();
|
|
|
|
pPtPos = m_pCurrentCursor->GetPoint();
|
|
if( !pPtPos->GetNode().IsContentNode() )
|
|
{
|
|
SwContentNode* pCNd = SwNodes::GoPrevSection( pPtPos,
|
|
true, IsReadOnlyAvailable() );
|
|
if( pCNd )
|
|
{
|
|
if( pPtPos->GetNode() >= m_pCurrentCursor->GetMark()->GetNode() )
|
|
pPtPos->SetContent( pCNd->Len() );
|
|
else
|
|
pFnd = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !pFnd )
|
|
{
|
|
m_pCurrentCursor->DeleteMark();
|
|
m_pCurrentCursor->RestoreSavePos();
|
|
}
|
|
else if( bSelect && *m_pCurrentCursor->GetMark() == *m_pCurrentCursor->GetPoint() )
|
|
m_pCurrentCursor->DeleteMark();
|
|
|
|
if( pFnd && !m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr() )
|
|
UpdateCursor( SwCursorShell::SCROLLWIN | SwCursorShell::CHKRANGE
|
|
| SwCursorShell::READONLY );
|
|
else
|
|
{
|
|
pFnd = nullptr;
|
|
if( bSelect )
|
|
m_pCurrentCursor->DeleteMark();
|
|
}
|
|
return pFnd;
|
|
}
|
|
|
|
const SwRangeRedline* SwCursorShell::GotoRedline( SwRedlineTable::size_type nArrPos, bool bSelect )
|
|
{
|
|
const SwRangeRedline* pFnd = nullptr;
|
|
if( IsTableMode() )
|
|
return nullptr;
|
|
|
|
CurrShell aCurr( this );
|
|
|
|
const SwRedlineTable& rTable = GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
|
|
const SwRangeRedline* pTmp = rTable[ nArrPos ];
|
|
sal_uInt16 nSeqNo = pTmp->GetSeqNo();
|
|
if( !nSeqNo || !bSelect )
|
|
{
|
|
pFnd = GotoRedline_( nArrPos, bSelect );
|
|
return pFnd;
|
|
}
|
|
|
|
bool bCheck = false;
|
|
int nLoopCnt = 2;
|
|
SwRedlineTable::size_type nArrSavPos = nArrPos;
|
|
|
|
do {
|
|
pTmp = GotoRedline_( nArrPos, true );
|
|
|
|
if( !pFnd )
|
|
pFnd = pTmp;
|
|
|
|
if( pTmp && bCheck )
|
|
{
|
|
// Check for overlaps. These can happen when FormatColl-
|
|
// Redlines were stretched over a whole paragraph
|
|
SwPaM* pCur = m_pCurrentCursor;
|
|
SwPaM* pNextPam = pCur->GetNext();
|
|
auto [pCStt, pCEnd] = pCur->StartEnd(); // SwPosition*
|
|
while( pCur != pNextPam )
|
|
{
|
|
auto [pNStt, pNEnd] = pNextPam->StartEnd(); // SwPosition*
|
|
|
|
bool bDel = true;
|
|
switch( ::ComparePosition( *pCStt, *pCEnd,
|
|
*pNStt, *pNEnd ))
|
|
{
|
|
case SwComparePosition::Inside: // Pos1 is completely in Pos2
|
|
if( !pCur->HasMark() )
|
|
{
|
|
pCur->SetMark();
|
|
*pCur->GetMark() = *pNStt;
|
|
}
|
|
else
|
|
*pCStt = *pNStt;
|
|
*pCEnd = *pNEnd;
|
|
break;
|
|
|
|
case SwComparePosition::Outside: // Pos2 is completely in Pos1
|
|
case SwComparePosition::Equal: // Pos1 has same size as Pos2
|
|
break;
|
|
|
|
case SwComparePosition::OverlapBefore: // Pos1 overlaps Pos2 at beginning
|
|
if( !pCur->HasMark() )
|
|
pCur->SetMark();
|
|
*pCEnd = *pNEnd;
|
|
break;
|
|
case SwComparePosition::OverlapBehind: // Pos1 overlaps Pos2 at end
|
|
if( !pCur->HasMark() )
|
|
{
|
|
pCur->SetMark();
|
|
*pCur->GetMark() = *pNStt;
|
|
}
|
|
else
|
|
*pCStt = *pNStt;
|
|
break;
|
|
|
|
default:
|
|
bDel = false;
|
|
}
|
|
|
|
if( bDel )
|
|
{
|
|
// not needed anymore
|
|
SwPaM* pPrevPam = pNextPam->GetPrev();
|
|
delete pNextPam;
|
|
pNextPam = pPrevPam;
|
|
}
|
|
pNextPam = pNextPam->GetNext();
|
|
}
|
|
}
|
|
|
|
SwRedlineTable::size_type nFndPos = 2 == nLoopCnt
|
|
? rTable.FindNextOfSeqNo( nArrPos )
|
|
: rTable.FindPrevOfSeqNo( nArrPos );
|
|
if( SwRedlineTable::npos != nFndPos ||
|
|
( 0 != ( --nLoopCnt ) && SwRedlineTable::npos != (
|
|
nFndPos = rTable.FindPrevOfSeqNo( nArrSavPos ))) )
|
|
{
|
|
if( pTmp )
|
|
{
|
|
// create new cursor
|
|
CreateCursor();
|
|
bCheck = true;
|
|
}
|
|
nArrPos = nFndPos;
|
|
}
|
|
else
|
|
nLoopCnt = 0;
|
|
|
|
} while( nLoopCnt );
|
|
return pFnd;
|
|
}
|
|
|
|
bool SwCursorShell::SelectNxtPrvHyperlink( bool bNext )
|
|
{
|
|
SwNodes& rNds = GetDoc()->GetNodes();
|
|
const SwNode* pBodyEndNd = &rNds.GetEndOfContent();
|
|
const SwNode* pBodySttNd = pBodyEndNd->StartOfSectionNode();
|
|
SwNodeOffset nBodySttNdIdx = pBodySttNd->GetIndex();
|
|
Point aPt;
|
|
|
|
SetGetExpField aCmpPos( SwPosition( bNext ? *pBodyEndNd : *pBodySttNd ) );
|
|
SetGetExpField aCurPos( bNext ? *m_pCurrentCursor->End() : *m_pCurrentCursor->Start() );
|
|
if( aCurPos.GetNode() < nBodySttNdIdx )
|
|
{
|
|
const SwContentNode* pCNd = aCurPos.GetNodeFromContent()->GetContentNode();
|
|
std::pair<Point, bool> tmp(aPt, true);
|
|
if (pCNd)
|
|
{
|
|
SwContentFrame* pFrame = pCNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
|
|
if( pFrame )
|
|
aCurPos.SetBodyPos( *pFrame );
|
|
}
|
|
}
|
|
|
|
// check first all the hyperlink fields
|
|
{
|
|
const SwTextNode* pTextNd;
|
|
const SwCharFormats* pFormats = GetDoc()->GetCharFormats();
|
|
for( SwCharFormats::size_type n = pFormats->size(); 1 < n; )
|
|
{
|
|
SwIterator<SwTextINetFormat,SwCharFormat> aIter(*(*pFormats)[--n]);
|
|
|
|
for( SwTextINetFormat* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() )
|
|
{
|
|
pTextNd = pFnd->GetpTextNode();
|
|
if( pTextNd && pTextNd->GetNodes().IsDocNodes() )
|
|
{
|
|
SwTextINetFormat& rAttr = *pFnd;
|
|
SetGetExpField aPos( *pTextNd, rAttr );
|
|
if (pTextNd->GetIndex() < nBodySttNdIdx)
|
|
{
|
|
std::pair<Point, bool> tmp(aPt, true);
|
|
SwContentFrame* pFrame = pTextNd->getLayoutFrame(GetLayout(), nullptr, &tmp);
|
|
if (pFrame)
|
|
{
|
|
aPos.SetBodyPos( *pFrame );
|
|
}
|
|
}
|
|
|
|
if( bNext
|
|
? ( aPos < aCmpPos && aCurPos < aPos )
|
|
: ( aCmpPos < aPos && aPos < aCurPos ))
|
|
{
|
|
OUString sText(pTextNd->GetExpandText(GetLayout(),
|
|
rAttr.GetStart(),
|
|
*rAttr.GetEnd() - rAttr.GetStart() ) );
|
|
|
|
sText = sText.replaceAll("\x0a", "");
|
|
sText = comphelper::string::strip(sText, ' ');
|
|
|
|
if( !sText.isEmpty() )
|
|
aCmpPos = aPos;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// then check all the Flys with a URL or image map
|
|
{
|
|
for(sw::SpzFrameFormat* pSpz: *GetDoc()->GetSpzFrameFormats())
|
|
{
|
|
if (pSpz->Which() != RES_FLYFRMFMT)
|
|
continue;
|
|
auto pFormat = static_cast<SwFlyFrameFormat*>(pSpz);
|
|
const SwFormatURL& rURLItem = pFormat->GetURL();
|
|
if( rURLItem.GetMap() || !rURLItem.GetURL().isEmpty() )
|
|
{
|
|
SwFlyFrame* pFly = pFormat->GetFrame( &aPt );
|
|
SwPosition aTmpPos( *pBodySttNd );
|
|
if( pFly &&
|
|
GetBodyTextNode( *GetDoc(), aTmpPos, *pFly->GetLower() ) )
|
|
{
|
|
SetGetExpField aPos( *pFormat, &aTmpPos );
|
|
|
|
if( bNext
|
|
? ( aPos < aCmpPos && aCurPos < aPos )
|
|
: ( aCmpPos < aPos && aPos < aCurPos ))
|
|
aCmpPos = aPos;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// found any URL ?
|
|
const SwTextINetFormat* pFndAttr = aCmpPos.GetINetFormat();
|
|
const SwFlyFrameFormat* pFndFormat = aCmpPos.GetFlyFormat();
|
|
if( !pFndAttr && !pFndFormat )
|
|
return false;
|
|
|
|
CurrShell aCurr( this );
|
|
SwCallLink aLk( *this );
|
|
|
|
bool bRet = false;
|
|
// found a text attribute ?
|
|
if( pFndAttr )
|
|
{
|
|
SwCursorSaveState aSaveState( *m_pCurrentCursor );
|
|
|
|
aCmpPos.GetPosOfContent( *m_pCurrentCursor->GetPoint() );
|
|
m_pCurrentCursor->DeleteMark();
|
|
m_pCurrentCursor->SetMark();
|
|
m_pCurrentCursor->GetPoint()->SetContent( *pFndAttr->End() );
|
|
|
|
if( !m_pCurrentCursor->IsInProtectTable() && !m_pCurrentCursor->IsSelOvr() )
|
|
{
|
|
UpdateCursor( SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|
|
|
SwCursorShell::READONLY );
|
|
bRet = true;
|
|
}
|
|
}
|
|
// found a draw object ?
|
|
else if( RES_DRAWFRMFMT == pFndFormat->Which() )
|
|
{
|
|
const SdrObject* pSObj = pFndFormat->FindSdrObject();
|
|
if (pSObj)
|
|
{
|
|
static_cast<SwFEShell*>(this)->SelectObj( pSObj->GetCurrentBoundRect().Center() );
|
|
MakeSelVisible();
|
|
bRet = true;
|
|
}
|
|
}
|
|
else // then is it a fly
|
|
{
|
|
SwFlyFrame* pFly = pFndFormat->GetFrame(&aPt);
|
|
if( pFly )
|
|
{
|
|
static_cast<SwFEShell*>(this)->SelectFlyFrame( *pFly );
|
|
MakeSelVisible();
|
|
bRet = true;
|
|
}
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|