Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  swcrsr.cxx   Sprache: 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 <hintids.hxx>
#include <editeng/protitem.hxx>
#include <com/sun/star/i18n/WordType.hpp>
#include <com/sun/star/i18n/XBreakIterator.hpp>
#include <unotools/charclass.hxx>
#include <svl/ctloptions.hxx>
#include <svl/srchitem.hxx>
#include <swmodule.hxx>
#include <fmtcntnt.hxx>
#include <swtblfmt.hxx>
#include <swcrsr.hxx>
#include <unocrsr.hxx>
#include <bookmark.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <docary.hxx>
#include <ndtxt.hxx>
#include <section.hxx>
#include <swtable.hxx>
#include <cntfrm.hxx>
#include <rootfrm.hxx>
#include <txtfrm.hxx>
#include <notxtfrm.hxx>
#include <scriptinfo.hxx>
#include <crstate.hxx>
#include <docsh.hxx>
#include <viewsh.hxx>
#include <frmatr.hxx>
#include <breakit.hxx>
#include <mdiexp.hxx>
#include <strings.hrc>
#include <redline.hxx>
#include <txatbase.hxx>
#include <IDocumentMarkAccess.hxx>
#include <memory>
#include <comphelper/lok.hxx>
#include <editsh.hxx>

#include <viewopt.hxx>
#include <annotationmark.hxx>

using namespace ::com::sun::star::i18n;

const sal_uInt16 coSrchRplcThreshold = 60000;

namespace {

struct PercentHdl
{
    SwDocShell* pDSh;
    sal_uLong nActPos;
    bool bBack, bNodeIdx;

    PercentHdl( sal_uLong nStt, sal_uLong nEnd, SwDocShell* pSh )
        : pDSh(pSh), nActPos(nStt), bBack(false), bNodeIdx(false)
    {
        bBack = (nStt > nEnd);
        if( bBack )
            std::swap( nStt, nEnd );
        ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd );
    }

    explicit PercentHdl( const SwPaM& rPam )
        : pDSh( rPam.GetDoc().GetDocShell() )
    {
        sal_Int32 nStt, nEnd;
        if( rPam.GetPoint()->GetNode() == rPam.GetMark()->GetNode() )
        {
            bNodeIdx = false;
            nStt = rPam.GetMark()->GetContentIndex();
            nEnd = rPam.GetPoint()->GetContentIndex();
        }
        else
        {
            bNodeIdx = true;
            nStt = sal_Int32(rPam.GetMark()->GetNodeIndex());
            nEnd = sal_Int32(rPam.GetPoint()->GetNodeIndex());
        }
        nActPos = nStt;
        bBack = (nStt > nEnd );
        if( bBack )
            std::swap( nStt, nEnd );
        ::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, pDSh );
    }

    ~PercentHdl()                      { ::EndProgress( pDSh ); }

    void NextPos( sal_uLong nPos ) const
        { ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh ); }

    void NextPos( SwPosition const & rPos ) const
        {
            sal_Int32 nPos;
            if( bNodeIdx )
                nPos = sal_Int32(rPos.GetNodeIndex());
            else
                nPos = rPos.GetContentIndex();
            ::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh );
        }
};

}

SwCursor::SwCursor( const SwPosition &rPos, SwPaM* pRing )
    : SwPaM( rPos, pRing )
    , m_nRowSpanOffset(0)
    , m_nCursorBidiLevel(0)
    , m_bColumnSelection(false)
{
}

// @@@ semantic: no copy ctor.
SwCursor::SwCursor(SwCursor const& rCpy, SwPaM *const pRing)
    : SwPaM( rCpy, pRing )
    , m_nRowSpanOffset(rCpy.m_nRowSpanOffset)
    , m_nCursorBidiLevel(rCpy.m_nCursorBidiLevel)
    , m_bColumnSelection(rCpy.m_bColumnSelection)
{
}

SwCursor::~SwCursor()
{
}

SwCursor* SwCursor::Create( SwPaM* pRing ) const
{
    return new SwCursor( *GetPoint(), pRing );
}

bool SwCursor::IsReadOnlyAvailable() const
{
    return false;
}

bool SwCursor::IsSkipOverHiddenSections() const
{
    return true;
}

bool SwCursor::IsSkipOverProtectSections() const
{
    return !IsReadOnlyAvailable();
}

// CreateNewSavePos is virtual so that derived classes of cursor can implement
// own SaveObjects if needed and validate them in the virtual check routines.
void SwCursor::SaveState()
{
    m_vSavePos.emplace_back( *this );
}

void SwCursor::RestoreState()
{
    if (!m_vSavePos.empty()) // Robust
    {
        m_vSavePos.pop_back();
    }
}

/// determine if point is outside of the node-array's content area
bool SwCursor::IsNoContent() const
{
    return GetPoint()->GetNodeIndex() <
            GetDoc().GetNodes().GetEndOfExtras().GetIndex();
}

bool SwCursor::IsSelOvrCheck(SwCursorSelOverFlags)
{
    return false;
}

// extracted from IsSelOvr()
bool SwTableCursor::IsSelOvrCheck(SwCursorSelOverFlags eFlags)
{
    SwNodes& rNds = GetDoc().GetNodes();
    // check sections of nodes array
    if( (SwCursorSelOverFlags::CheckNodeSection & eFlags)
        && HasMark() )
    {
        SwNodeIndex aOldPos( rNds, GetSavePos()->nNode );
        if( !CheckNodesRange( aOldPos.GetNode(), GetPoint()->GetNode(), true ))
        {
            GetPoint()->Assign( aOldPos );
            GetPoint()->SetContent( GetSavePos()->nContent );
            return true;
        }
    }
    return SwCursor::IsSelOvrCheck(eFlags);
}

namespace
{
    const SwTextAttr* InputFieldAtPos(SwPosition const *pPos)
    {
        SwTextNode* pTextNd = pPos->GetNode().GetTextNode();
        if (!pTextNd)
            return nullptr;
        return pTextNd->GetTextAttrAt(pPos->GetContentIndex(), RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent);
    }
}

bool SwCursor::IsSelOvr(SwCursorSelOverFlags const eFlags)
{
    SwDoc& rDoc = GetDoc();
    SwNodes& rNds = rDoc.GetNodes();

    bool bSkipOverHiddenSections = IsSkipOverHiddenSections();
    bool bSkipOverProtectSections = IsSkipOverProtectSections();

    if ( IsSelOvrCheck( eFlags ) )
    {
        return true;
    }

    if (m_vSavePos.back().nNode != GetPoint()->GetNodeIndex() &&
        // (1997) in UI-ReadOnly everything is allowed
        ( !rDoc.GetDocShell() || !rDoc.GetDocShell()->IsReadOnlyUI() ))
    {
        // check new sections
        SwPosition& rPtPos = *GetPoint();
        const SwSectionNode* pSectNd = rPtPos.GetNode().FindSectionNode();
        if( pSectNd &&
            ((bSkipOverHiddenSections && pSectNd->GetSection().IsHiddenFlag() ) ||
            (bSkipOverProtectSections && pSectNd->GetSection().IsProtectFlag() )))
        {
            if( !( SwCursorSelOverFlags::ChangePos & eFlags ) )
            {
                // then we're already done
                RestoreSavePos();
                return true;
            }

            // set cursor to new position:
            SwNodeIndex aIdx( rPtPos.GetNode() );
            sal_Int32 nContentPos = m_vSavePos.back().nContent;
            bool bGoNxt = m_vSavePos.back().nNode < rPtPos.GetNodeIndex();
            SwContentNode* pCNd = bGoNxt
                ? SwNodes::GoNextSection( &rPtPos, bSkipOverHiddenSections, bSkipOverProtectSections)
                : SwNodes::GoPrevSection( &rPtPos, bSkipOverHiddenSections, bSkipOverProtectSections);
            if( !pCNd && ( SwCursorSelOverFlags::EnableRevDirection & eFlags ))
            {
                bGoNxt = !bGoNxt;
                pCNd = bGoNxt ? SwNodes::GoNextSection( &rPtPos, bSkipOverHiddenSections, bSkipOverProtectSections)
                    : SwNodes::GoPrevSection( &rPtPos, bSkipOverHiddenSections, bSkipOverProtectSections);
            }

            bool bIsValidPos = nullptr != pCNd;
            const bool bValidNodesRange = bIsValidPos &&
                ::CheckNodesRange( rPtPos.GetNode(), aIdx.GetNode(), true );
            if( !bValidNodesRange )
            {
                rPtPos.Assign( m_vSavePos.back().nNode );
                pCNd = rPtPos.GetNode().GetContentNode();
                if( !pCNd )
                {
                    bIsValidPos = false;
                    nContentPos = 0;
                    rPtPos.Assign( aIdx );
                    pCNd = rPtPos.GetNode().GetContentNode();
                    if( !pCNd )
                    {
                        // then to the beginning of the document
                        rPtPos.Assign( rNds.GetEndOfExtras() );
                        pCNd = SwNodes::GoNext(&rPtPos);
                    }
                }
            }

            // register ContentIndex:
            const sal_Int32 nTmpPos = bIsValidPos ? (bGoNxt ? 0 : pCNd->Len()) : nContentPos;
            GetPoint()->SetContent( nTmpPos );
            if( !bIsValidPos || !bValidNodesRange ||
                IsInProtectTable( true ) )
                return true;
        }

        // is there a protected section in the section?
        if( HasMark() && bSkipOverProtectSections)
        {
            SwNodeOffset nSttIdx = GetMark()->GetNodeIndex(),
                nEndIdx = GetPoint()->GetNodeIndex();
            if( nEndIdx <= nSttIdx )
                std::swap( nSttIdx, nEndIdx );

            const SwSectionFormats& rFormats = rDoc.GetSections();
            for( SwSectionFormats::size_type n = 0; n < rFormats.size(); ++n )
            {
                const SwSectionFormat* pFormat = rFormats[n];
                const SvxProtectItem& rProtect = pFormat->GetProtect();
                if( rProtect.IsContentProtected() )
                {
                    const SwFormatContent& rContent = pFormat->GetContent(false);
                    OSL_ENSURE( rContent.GetContentIdx(), "No SectionNode?" );
                    SwNodeOffset nIdx = rContent.GetContentIdx()->GetIndex();
                    if( nSttIdx <= nIdx && nEndIdx >= nIdx )
                    {
                        // if it is no linked section then we cannot select it
                        const SwSection& rSect = *pFormat->GetSection();
                        if( SectionType::Content == rSect.GetType() )
                        {
                            RestoreSavePos();
                            return true;
                        }
                    }
                }
            }
        }
    }

    const SwNode* pNd = &GetPoint()->GetNode();
    if( pNd->IsContentNode() && !dynamic_cast<SwUnoCursor*>(this) )
    {
        const SwContentFrame* pFrame = static_cast<const SwContentNode*>(pNd)->getLayoutFrame( rDoc.getIDocumentLayoutAccess().GetCurrentLayout() );
        if ( (SwCursorSelOverFlags::ChangePos & eFlags)   //allowed to change position if it's a bad one
            && pFrame && pFrame->isFrameAreaDefinitionValid()
            && !pFrame->getFrameArea().Height()     //a bad zero height position
            && !InputFieldAtPos(GetPoint()) )                       //unless it's a (vertical) input field
        {
            // skip to the next/prev valid paragraph with a layout
            SwPosition& rPtPos = *GetPoint();
            bool bGoNxt = m_vSavePos.back().nNode < rPtPos.GetNodeIndex();
            for (;;)
            {
                pFrame = bGoNxt ? pFrame->FindNextCnt(true) : pFrame->FindPrevCnt();
                if (!pFrame || 0 != pFrame->getFrameArea().Height() )
                    break;
            }

            // #i72394# skip to prev/next valid paragraph with a layout in case
            // the first search did not succeed:
            if( !pFrame )
            {
                bGoNxt = !bGoNxt;
                pFrame = static_cast<const SwContentNode*>(pNd)->getLayoutFrame( rDoc.getIDocumentLayoutAccess().GetCurrentLayout() );
                while ( pFrame && 0 == pFrame->getFrameArea().Height() )
                {
                    pFrame = bGoNxt ? pFrame->FindNextCnt(true) : pFrame->FindPrevCnt();
                }
            }

            if (pFrame != nullptr)
            {
                if (pFrame->IsTextFrame())
                {
                    SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(pFrame));
                    *GetPoint() = pTextFrame->MapViewToModelPos(TextFrameIndex(
                            bGoNxt ? 0 : pTextFrame->GetText().getLength()));
                }
                else
                {
                    assert(pFrame->IsNoTextFrame());
                    SwContentNode *const pCNd = const_cast<SwContentNode*>(
                        static_cast<SwNoTextFrame const*>(pFrame)->GetNode());
                    assert(pCNd);

                    // set this ContentNode as new position
                    rPtPos.Assign( *pCNd );
                    // assign corresponding ContentIndex
                    const sal_Int32 nTmpPos = bGoNxt ? 0 : pCNd->Len();
                    GetPoint()->SetContent( nTmpPos );
                }


                if (rPtPos.GetNodeIndex() == m_vSavePos.back().nNode
                    && GetPoint()->GetContentIndex() == m_vSavePos.back().nContent)
                {
                    // new position equals saved one
                    // --> trigger restore of saved pos by setting <pFrame> to NULL - see below
                    pFrame = nullptr;
                }

                if ( IsInProtectTable( true ) )
                {
                    // new position in protected table
                    // --> trigger restore of saved pos by setting <pFrame> to NULL - see below
                    pFrame = nullptr;
                }
            }
        }

        if( !pFrame )
        {
            assert(!m_vSavePos.empty());
            SwContentNode const*const pSaveNode(rNds[m_vSavePos.back().nNode]->GetContentNode());
            // if the old position already didn't have a frame, allow moving
            // anyway, hope the caller can handle that
            if (pSaveNode && pSaveNode->getLayoutFrame(rDoc.getIDocumentLayoutAccess().GetCurrentLayout()))
            {
                DeleteMark();
                RestoreSavePos();
                return true// we need a frame
            }
        }
    }

    // is the cursor allowed to be in a protected node?
    if( !( SwCursorSelOverFlags::ChangePos & eFlags ) && !IsAtValidPos() )
    {
        DeleteMark();
        RestoreSavePos();
        return true;
    }

    if( !HasMark() )
        return false;

    // check for invalid sections
    if( !::CheckNodesRange( GetMark()->GetNode(), GetPoint()->GetNode(), true ))
    {
        DeleteMark();
        RestoreSavePos();
        return true// we need a frame
    }

    pNd = &GetMark()->GetNode();
    if( pNd->IsContentNode()
        && !static_cast<const SwContentNode*>(pNd)->getLayoutFrame( rDoc.getIDocumentLayoutAccess().GetCurrentLayout() )
        && !dynamic_cast<SwUnoCursor*>(this) )
    {
        DeleteMark();
        RestoreSavePos();
        return true// we need a frame
    }

    // ensure that selection is only inside an InputField or contains the InputField completely
    {
        const SwTextAttr* pInputFieldTextAttrAtPoint = InputFieldAtPos(GetPoint());
        const SwTextAttr* pInputFieldTextAttrAtMark = InputFieldAtPos(GetMark());

        if ( pInputFieldTextAttrAtPoint != pInputFieldTextAttrAtMark )
        {
            const SwNodeOffset nRefNodeIdx =
                ( SwCursorSelOverFlags::Toggle & eFlags )
                ? m_vSavePos.back().nNode
                : GetMark()->GetNodeIndex();
            const sal_Int32 nRefContentIdx =
                ( SwCursorSelOverFlags::Toggle & eFlags )
                ? m_vSavePos.back().nContent
                : GetMark()->GetContentIndex();
            const bool bIsForwardSelection =
                nRefNodeIdx < GetPoint()->GetNodeIndex()
                || ( nRefNodeIdx == GetPoint()->GetNodeIndex()
                     && nRefContentIdx < GetPoint()->GetContentIndex() );

            if ( pInputFieldTextAttrAtPoint != nullptr )
            {
                const sal_Int32 nNewPointPos =
                    bIsForwardSelection ? *(pInputFieldTextAttrAtPoint->End()) : pInputFieldTextAttrAtPoint->GetStart();
                GetPoint()->SetContent( nNewPointPos );
            }

            if ( pInputFieldTextAttrAtMark != nullptr )
            {
                const sal_Int32 nNewMarkPos =
                    bIsForwardSelection ? pInputFieldTextAttrAtMark->GetStart() : *(pInputFieldTextAttrAtMark->End());
                GetMark()->SetContent( nNewMarkPos );
            }
        }
    }

    const SwTableNode* pPtNd = GetPoint()->GetNode().FindTableNode();
    const SwTableNode* pMrkNd = GetMark()->GetNode().FindTableNode();
    // both in no or in same table node
    if( ( !pMrkNd && !pPtNd ) || pPtNd == pMrkNd )
        return false;

    // in different tables or only mark in table
    if( pMrkNd )
    {
        // not allowed, so go back to old position
        RestoreSavePos();
        // Cursor stays at old position
        return true;
    }

    // Note: this cannot happen in TableMode
    // Only Point in Table then go behind/in front of table
    if (SwCursorSelOverFlags::ChangePos & eFlags)
    {
        bool bSelTop = GetPoint()->GetNodeIndex() <
            ((SwCursorSelOverFlags::Toggle & eFlags)
                 ? m_vSavePos.back().nNode : GetMark()->GetNodeIndex());

        do { // loop for table after table
            SwNodeOffset nSEIdx = pPtNd->EndOfSectionIndex();
            SwNodeOffset nSttEndTable = nSEIdx + 1;

            if( bSelTop )
                nSttEndTable = rNds[ nSEIdx ]->StartOfSectionIndex() - 1;

            GetPoint()->Assign( nSttEndTable );
            const SwNode* pMyNd = &(GetPointNode());

            if( pMyNd->IsSectionNode() || ( pMyNd->IsEndNode() &&
                pMyNd->StartOfSectionNode()->IsSectionNode() ) )
            {
                pMyNd = bSelTop
                    ? SwNodes::GoPrevSection( GetPoint(),true,false )
                    : SwNodes::GoNextSection( GetPoint(),true,false );

                /* #i12312# Handle failure of Go{Prev|Next}Section */
                if ( nullptr == pMyNd)
                    break;

                pPtNd = pMyNd->FindTableNode();
                if( pPtNd )
                    continue;
            }

            // we permit these
            if( pMyNd->IsContentNode() &&
                ::CheckNodesRange( GetMark()->GetNode(),
                GetPoint()->GetNode(), true ))
            {
                // table in table
                const SwTableNode* pOuterTableNd = pMyNd->FindTableNode();
                if ( pOuterTableNd )
                    pMyNd = pOuterTableNd;
                else
                {
                    SwContentNode* pCNd = const_cast<SwContentNode*>(static_cast<const SwContentNode*>(pMyNd));
                    GetPoint()->SetContent( bSelTop ? pCNd->Len() : 0 );
                    return false;
                }
            }
            if( bSelTop )
            {
                if ( !pMyNd->IsEndNode() )
                    break;
                pPtNd = pMyNd->FindTableNode();
            }
            else
                pPtNd = pMyNd->GetTableNode();
            if (!pPtNd)
                break;
        } whiletrue );
    }

    // stay on old position
    RestoreSavePos();
    return true;
}

bool SwCursor::IsInProtectTable( bool bMove, bool bChgCursor )
{
    SwContentNode* pCNd = GetPointContentNode();
    if( !pCNd )
        return false;

    // No table, no protected cell:
    const SwTableNode* pTableNode = pCNd->FindTableNode();
    if ( !pTableNode )
        return false;

    // Current position == last save position?
    if (m_vSavePos.back().nNode == GetPoint()->GetNodeIndex())
        return false;

    // Check for covered cell:
    bool bInCoveredCell = false;
    const SwStartNode* pTmpSttNode = pCNd->FindTableBoxStartNode();
    OSL_ENSURE( pTmpSttNode, "In table, therefore I expect to get a SwTableBoxStartNode" );
    const SwTableBox* pBox = pTmpSttNode ? pTableNode->GetTable().GetTableBox( pTmpSttNode->GetIndex() ) : nullptr; //Robust #151355
    if ( pBox && pBox->getRowSpan() < 1 ) // Robust #151270
        bInCoveredCell = true;

    // Positions of covered cells are not acceptable:
    if ( !bInCoveredCell )
    {
        // Position not protected?
        if ( !pCNd->IsProtect() )
            return false;

        // Cursor in protected cells allowed?
        if ( IsReadOnlyAvailable() )
            return false;
    }

    // If we reach this point, we are in a protected or covered table cell!

    if( !bMove )
    {
        if( bChgCursor )
            // restore the last save position
            RestoreSavePos();

        return true// Cursor stays at old position
    }

    // We are in a protected table cell. Traverse top to bottom?
    if (m_vSavePos.back().nNode < GetPoint()->GetNodeIndex())
    {
        // search next valid box
        // if there is another StartNode after the EndNode of a cell then
        // there is another cell
        SwNodeIndex aCellStt( *GetPointNode().FindTableBoxStartNode()->EndOfSectionNode(), 1 );
        bool bProt = true;
GoNextCell:
        for (;;) {
            if( !aCellStt.GetNode().IsStartNode() )
                break;
            ++aCellStt;
            pCNd = aCellStt.GetNode().GetContentNode();
            if( !pCNd )
                pCNd = SwNodes::GoNext(&aCellStt);
            bProt = pCNd->IsProtect();
            if( !bProt )
                break;
            aCellStt.Assign( *pCNd->FindTableBoxStartNode()->EndOfSectionNode(), 1 );
        }

SetNextCursor:
        if( !bProt ) // found free cell
        {
            GetPoint()->Assign( aCellStt );
            SwContentNode* pTmpCNd = GetPointContentNode();
            if( pTmpCNd )
            {
                GetPoint()->SetContent( 0 );
                return false;
            }
            return IsSelOvr( SwCursorSelOverFlags::Toggle |
                             SwCursorSelOverFlags::ChangePos );
        }
        // end of table, so go to next node
        ++aCellStt;
        SwNode* pNd = &aCellStt.GetNode();
        if( pNd->IsEndNode() || HasMark())
        {
            // if only table in FlyFrame or SSelection then stay on old position
            if( bChgCursor )
                RestoreSavePos();
            return true;
        }
        else if( pNd->IsTableNode() )
        {
            ++aCellStt;
            goto GoNextCell;
        }

        bProt = false// index is now on a content node
        goto SetNextCursor;
    }

    // search for the previous valid box
    {
        // if there is another EndNode in front of the StartNode than there
        // exists a previous cell
        SwNodeIndex aCellStt( *GetPointNode().FindTableBoxStartNode(), -1 );
        SwNode* pNd;
        bool bProt = true;
GoPrevCell:
        for (;;) {
            pNd = &aCellStt.GetNode();
            if( !pNd->IsEndNode() )
                break;
            aCellStt.Assign( *pNd->StartOfSectionNode(), +1 );
            pCNd = aCellStt.GetNode().GetContentNode();
            if( !pCNd )
                pCNd = SwNodes::GoNext(&aCellStt);
            bProt = pCNd->IsProtect();
            if( !bProt )
                break;
            aCellStt.Assign( *pNd->FindTableBoxStartNode(), -1 );
        }

SetPrevCursor:
        if( !bProt ) // found free cell
        {
            GetPoint()->Assign( aCellStt );
            SwContentNode* pTmpCNd = GetPointContentNode();
            if( pTmpCNd )
            {
                GetPoint()->SetContent(  0 );
                return false;
            }
            return IsSelOvr( SwCursorSelOverFlags::Toggle |
                             SwCursorSelOverFlags::ChangePos );
        }
        // at the beginning of a table, so go to next node
        --aCellStt;
        pNd = &aCellStt.GetNode();
        if( pNd->IsStartNode() || HasMark() )
        {
            // if only table in FlyFrame or SSelection then stay on old position
            if( bChgCursor )
                RestoreSavePos();
            return true;
        }
        else if( pNd->StartOfSectionNode()->IsTableNode() )
        {
            --aCellStt;
            goto GoPrevCell;
        }

        bProt = false// index is now on a content node
        goto SetPrevCursor;
    }
}

/// Return <true> if cursor can be set to this position
bool SwCursor::IsAtValidPos( bool bPoint ) const
{
    const SwDoc& rDoc = GetDoc();
    const SwPosition* pPos = bPoint ? GetPoint() : GetMark();
    const SwNode* pNd = &pPos->GetNode();

    if( pNd->IsContentNode() && !static_cast<const SwContentNode*>(pNd)->getLayoutFrame( rDoc.getIDocumentLayoutAccess().GetCurrentLayout() ) &&
        !dynamic_cast<const SwUnoCursor*>(this) )
    {
        return false;
    }

    // #i45129# - in UI-ReadOnly everything is allowed
    const SwDocShell* pShell = rDoc.GetDocShell();
    if( !pShell || !pShell->IsReadOnlyUI() )
        return true;

    const bool bCursorInReadOnly = IsReadOnlyAvailable();
    if( !bCursorInReadOnly && pNd->IsProtect() )
        return false;

    const SwSectionNode* pSectNd = pNd->FindSectionNode();
    return !pSectNd
           || !(pSectNd->GetSection().IsHiddenFlag() ||
                ( !bCursorInReadOnly && pSectNd->GetSection().IsProtectFlag() ));
}

void SwCursor::SaveTableBoxContent( const SwPosition* ) {}

/// set range for search in document
SwMoveFnCollection const & SwCursor::MakeFindRange( SwDocPositions nStart,
                                SwDocPositions nEnd, SwPaM* pRange ) const
{
    pRange->SetMark();
    FillFindPos( nStart, *pRange->GetMark() );
    FillFindPos( nEnd, *pRange->GetPoint() );

    // determine direction of search
    return ( SwDocPositions::Start == nStart || SwDocPositions::OtherStart == nStart ||
              (SwDocPositions::Curr == nStart &&
                (SwDocPositions::End == nEnd || SwDocPositions::OtherEnd == nEnd ) ))
                ? fnMoveForward : fnMoveBackward;
}

static sal_Int32 lcl_FindSelection( SwFindParas& rParas, SwCursor* pCurrentCursor,
                        SwMoveFnCollection const & fnMove, SwCursor*& pFndRing,
                        SwPaM& aRegion, FindRanges eFndRngs,
                        bool bInReadOnly, bool& bCancel )
{
    SwDoc& rDoc = pCurrentCursor->GetDoc();
    bool const bDoesUndo = rDoc.GetIDocumentUndoRedo().DoesUndo();
    int nFndRet = 0;
    sal_Int32 nFound = 0;
    const bool bSrchBkwrd = &fnMove == &fnMoveBackward;
    SwPaM *pTmpCursor = pCurrentCursor, *pSaveCursor = pCurrentCursor;
    std::unique_ptr<SvxSearchItem> xSearchItem;

    // only create progress bar for ShellCursor
    bool bIsUnoCursor = dynamic_cast<SwUnoCursor*>(pCurrentCursor) !=  nullptr;
    std::unique_ptr<PercentHdl> pPHdl;
    sal_uInt16 nCursorCnt = 0;
    if( FindRanges::InSel & eFndRngs )
    {
        while( pCurrentCursor != ( pTmpCursor = pTmpCursor->GetNext() ))
            ++nCursorCnt;
        if( nCursorCnt && !bIsUnoCursor )
            pPHdl.reset(new PercentHdl( 0, nCursorCnt, rDoc.GetDocShell() ));
    }
    else
        pSaveCursor = pSaveCursor->GetPrev();

    bool bEnd = false;
    do {
        aRegion.SetMark();
        // independent from search direction: SPoint is always bigger than mark
        // if the search area is valid
        SwPosition *pSttPos = aRegion.GetMark(),
                        *pEndPos = aRegion.GetPoint();
        *pSttPos = *pTmpCursor->Start();
        *pEndPos = *pTmpCursor->End();
        if( bSrchBkwrd )
            aRegion.Exchange();

        if( !nCursorCnt && !pPHdl && !bIsUnoCursor )
            pPHdl.reset(new PercentHdl( aRegion ));

        // as long as found and not at same position
        while(  *pSttPos <= *pEndPos )
        {
            nFndRet = rParas.DoFind(*pCurrentCursor, fnMove, aRegion, bInReadOnly, xSearchItem);
            if( 0 == nFndRet ||
                ( pFndRing &&
                  *pFndRing->GetPoint() == *pCurrentCursor->GetPoint() &&
                  *pFndRing->GetMark() == *pCurrentCursor->GetMark() ))
                break;
            if( !( FIND_NO_RING & nFndRet ))
            {
                // #i24084# - create ring similar to the one in CreateCursor
                SwCursor* pNew = pCurrentCursor->Create( pFndRing );
                if( !pFndRing )
                    pFndRing = pNew;

                pNew->SetMark();
                *pNew->GetMark() = *pCurrentCursor->GetMark();
            }

            ++nFound;

            if( !( eFndRngs & FindRanges::InSelAll) )
            {
                bEnd = true;
                break;
            }

            if ((coSrchRplcThreshold == nFound)
                && rDoc.GetIDocumentUndoRedo().DoesUndo()
                && rParas.IsReplaceMode())
            {
                short nRet = pCurrentCursor->MaxReplaceArived();
                if( RET_YES == nRet )
                {
                    rDoc.GetIDocumentUndoRedo().DelAllUndoObj();
                    rDoc.GetIDocumentUndoRedo().DoUndo(false);
                }
                else
                {
                    bEnd = true;
                    if(RET_CANCEL == nRet)
                    {
                        bCancel = true;
                    }
                    break;
                }
            }

            if( bSrchBkwrd )
                // move pEndPos in front of the found area
                *pEndPos = *pCurrentCursor->Start();
            else
                // move pSttPos behind the found area
                *pSttPos = *pCurrentCursor->End();

            if( *pSttPos == *pEndPos )
                // in area but at the end => done
                break;

            if( !nCursorCnt && pPHdl )
            {
                pPHdl->NextPos( *aRegion.GetMark() );
            }
        }

        if( bEnd || !( eFndRngs & ( FindRanges::InSelAll | FindRanges::InSel )) )
            break;

        pTmpCursor = pTmpCursor->GetNext();
        if( nCursorCnt && pPHdl )
        {
            pPHdl->NextPos( ++pPHdl->nActPos );
        }

    } while( pTmpCursor != pSaveCursor && pTmpCursor->GetNext() != pTmpCursor);

    if( nFound && !pFndRing ) // if no ring should be created
        pFndRing = pCurrentCursor->Create();

    rDoc.GetIDocumentUndoRedo().DoUndo(bDoesUndo);
    return nFound;
}

static bool lcl_MakeSelFwrd( const SwNode& rSttNd, const SwNode& rEndNd,
                        SwPaM& rPam, bool bFirst )
{
    if( rSttNd.GetIndex() + 1 == rEndNd.GetIndex() )
        return false;

    rPam.DeleteMark();
    SwContentNode* pCNd;
    if( !bFirst )
    {
        rPam.GetPoint()->Assign(rSttNd);
        pCNd = SwNodes::GoNext(rPam.GetPoint());
        if( !pCNd )
            return false;
        rPam.GetPoint()->AssignStartIndex(*pCNd);
    }
    else if( rSttNd.GetIndex() > rPam.GetPoint()->GetNodeIndex() ||
             rPam.GetPoint()->GetNodeIndex() >= rEndNd.GetIndex() )
        // not in this section
        return false;

    rPam.SetMark();
    rPam.GetPoint()->Assign(rEndNd);
    pCNd = SwNodes::GoPrevious(rPam.GetPoint(), true);
    if( !pCNd )
        return false;
    rPam.GetPoint()->AssignEndIndex(*pCNd);

    return *rPam.GetMark() < *rPam.GetPoint();
}

static bool lcl_MakeSelBkwrd( const SwNode& rSttNd, const SwNode& rEndNd,
                        SwPaM& rPam, bool bFirst )
{
    if( rEndNd.GetIndex() + 1 == rSttNd.GetIndex() )
        return false;

    rPam.DeleteMark();
    SwContentNode* pCNd;
    if( !bFirst )
    {
        rPam.GetPoint()->Assign(rSttNd);
        pCNd = SwNodes::GoPrevious(rPam.GetPoint(), true);
        if( !pCNd )
            return false;
        rPam.GetPoint()->AssignEndIndex(*pCNd);
    }
    else if( rEndNd.GetIndex() > rPam.GetPoint()->GetNodeIndex() ||
             rPam.GetPoint()->GetNodeIndex() >= rSttNd.GetIndex() )
        return false;       // not in this section

    rPam.SetMark();
    rPam.GetPoint()->Assign(rEndNd);
    pCNd = SwNodes::GoNext(rPam.GetPoint());
    if( !pCNd )
        return false;
    rPam.GetPoint()->SetContent(0);

    return *rPam.GetPoint() < *rPam.GetMark();
}

// this method "searches" for all use cases because in SwFindParas is always the
// correct parameters and respective search method
sal_Int32 SwCursor::FindAll( SwFindParas& rParas,
                            SwDocPositions nStart, SwDocPositions nEnd,
                            FindRanges eFndRngs, bool& bCancel )
{
    bCancel = false;
    SwCursorSaveState aSaveState( *this );

    // create region without adding it to the ring
    SwPaM aRegion( *GetPoint() );
    SwMoveFnCollection const & fnMove = MakeFindRange( nStart, nEnd, &aRegion );

    sal_Int32 nFound = 0;
    const bool bMvBkwrd = &fnMove == &fnMoveBackward;
    bool bInReadOnly = IsReadOnlyAvailable();
    std::unique_ptr<SvxSearchItem> xSearchItem;

    SwCursor* pFndRing = nullptr;
    SwNodes& rNds = GetDoc().GetNodes();

    // search in sections?
    if( FindRanges::InSel & eFndRngs )
    {
        // if string was not found in region then get all sections (cursors
        // stays unchanged)
        nFound = lcl_FindSelection( rParas, this, fnMove,
                                    pFndRing, aRegion, eFndRngs,
                                    bInReadOnly, bCancel );
        if( 0 == nFound )
            return nFound;

        // found string at least once; it's all in new Cursor ring thus delete old one
        while( GetNext() != this )
            delete GetNext();

        *GetPoint() = *pFndRing->GetPoint();
        SetMark();
        *GetMark() = *pFndRing->GetMark();
        pFndRing->GetRingContainer().merge( GetRingContainer() );
        delete pFndRing;
    }
    else if( FindRanges::InOther & eFndRngs )
    {
        // put cursor as copy of current into ring
        // chaining points always to first created, so forward
        SwCursor* pSav = Create( this ); // save the current cursor

        // if already outside of body text search from this position or start at
        // 1. base section
        if( bMvBkwrd
            ? lcl_MakeSelBkwrd( rNds.GetEndOfExtras(),
                    *rNds.GetEndOfPostIts().StartOfSectionNode(),
                     *this, rNds.GetEndOfExtras().GetIndex() >=
                    GetPoint()->GetNodeIndex() )
            : lcl_MakeSelFwrd( *rNds.GetEndOfPostIts().StartOfSectionNode(),
                    rNds.GetEndOfExtras(), *this,
                    rNds.GetEndOfExtras().GetIndex() >=
                    GetPoint()->GetNodeIndex() ))
        {
            nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing,
                                        aRegion, eFndRngs, bInReadOnly, bCancel );
        }

        if( !nFound )
        {
            // put back the old one
            *GetPoint() = *pSav->GetPoint();
            if( pSav->HasMark() )
            {
                SetMark();
                *GetMark() = *pSav->GetMark();
            }
            else
                DeleteMark();
            return 0;
        }

        if( !( FindRanges::InSelAll & eFndRngs ))
        {
            // there should only be a single one, thus add it
            // independent from search direction: SPoint is always bigger than
            // mark if the search area is valid
            *GetPoint() = *pFndRing->GetPoint();
            SetMark();
            *GetMark() = *pFndRing->GetMark();
        }
        else
        {
            // found string at least once; it's all in new Cursor ring thus delete old one
            while( GetNext() != this )
                delete GetNext();

            *GetPoint() = *pFndRing->GetPoint();
            SetMark();
            *GetMark() = *pFndRing->GetMark();
            pFndRing->GetRingContainer().merge( GetRingContainer() );
        }
        delete pFndRing;
    }
    else if( FindRanges::InSelAll & eFndRngs )
    {
        SwCursor* pSav = Create( this );    // save the current cursor

        const SwNode* pSttNd = ( FindRanges::InBodyOnly & eFndRngs )
                            ? rNds.GetEndOfContent().StartOfSectionNode()
                            : rNds.GetEndOfPostIts().StartOfSectionNode();

        if( bMvBkwrd
            ? lcl_MakeSelBkwrd( rNds.GetEndOfContent(), *pSttNd, *thisfalse )
            : lcl_MakeSelFwrd( *pSttNd, rNds.GetEndOfContent(), *thisfalse ))
        {
            nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing,
                                        aRegion, eFndRngs, bInReadOnly, bCancel );
        }

        if( !nFound )
        {
            // put back the old one
            *GetPoint() = *pSav->GetPoint();
            if( pSav->HasMark() )
            {
                SetMark();
                *GetMark() = *pSav->GetMark();
            }
            else
                DeleteMark();
            return 0;
        }
        while( GetNext() != this )
            delete GetNext();

        *GetPoint() = *pFndRing->GetPoint();
        SetMark();
        *GetMark() = *pFndRing->GetMark();
        pFndRing->GetRingContainer().merge( GetRingContainer() );
        delete pFndRing;
    }
    else
    {
        // if a GetMark is set then keep the GetMark of the found object
        // This allows spanning an area with this search.
        SwPosition aMarkPos( *GetMark() );
        const bool bMarkPos = HasMark() && (eFndRngs == FindRanges::InBody);

        nFound = rParas.DoFind(*this, fnMove, aRegion, bInReadOnly, xSearchItem) ? 1 : 0;
        if (0 != nFound && bMarkPos)
            *GetMark() = std::move(aMarkPos);
    }

    if( nFound && SwCursor::IsSelOvr( SwCursorSelOverFlags::Toggle ) )
        nFound = 0;
    return nFound;
}

void SwCursor::FillFindPos( SwDocPositions ePos, SwPosition& rPos ) const
{
    bool bIsStart = true;
    SwContentNode* pCNd = nullptr;
    SwNodes& rNds = GetDoc().GetNodes();

    switch( ePos )
    {
    case SwDocPositions::Start:
        rPos.Assign(*rNds.GetEndOfContent().StartOfSectionNode());
        pCNd = SwNodes::GoNext(&rPos);
        break;
    case SwDocPositions::End:
        rPos.Assign(rNds.GetEndOfContent());
        pCNd = SwNodes::GoPrevious( &rPos );
        bIsStart = false;
        break;
    case SwDocPositions::OtherStart:
        rPos.Assign( *rNds[ SwNodeOffset(0) ] );
        pCNd = SwNodes::GoNext(&rPos);
        break;
    case SwDocPositions::OtherEnd:
        rPos.Assign( *rNds.GetEndOfContent().StartOfSectionNode() );
        pCNd = SwNodes::GoPrevious( &rPos );
        bIsStart = false;
        break;
    default:
        rPos = *GetPoint();
    }

    if( pCNd && !bIsStart )
    {
        rPos.AssignEndIndex( *pCNd );
    }
}

short SwCursor::MaxReplaceArived()
{
    return RET_YES;
}

namespace {

struct HideWrapper
{
    // either the frame's text or the node's text (possibly pre-filtered)
    OUString const* m_pText;
    // this is actually a TextFrameIndex but all of the i18n code uses sal_Int32
    sal_Int32 m_nPtIndex;
    // if mapping is needed, use this frame
    SwTextFrame * m_pFrame;
    // input in the constructor, output (via mapping) in the destructor
    SwTextNode *& m_rpTextNode;
    sal_Int32 & m_rPtPos;

    HideWrapper(SwRootFrame const*const pLayout,
            SwTextNode *& rpTextNode, sal_Int32 & rPtPos,
            OUString const*const pFilteredNodeText = nullptr)
        : m_pText(pFilteredNodeText)
        , m_pFrame(nullptr)
        , m_rpTextNode(rpTextNode)
        , m_rPtPos(rPtPos)
    {
        if (pLayout && pLayout->HasMergedParas())
        {
            m_pFrame = static_cast<SwTextFrame*>(rpTextNode->getLayoutFrame(pLayout));
            m_pText = &m_pFrame->GetText();
            m_nPtIndex = sal_Int32(m_pFrame->MapModelToView(rpTextNode, rPtPos));
        }
        else
        {
            if (!m_pText)
            {
                m_pText = &rpTextNode->GetText();
            }
            m_nPtIndex = rPtPos;
        }
    }
    ~HideWrapper()
    {
        AssignBack(m_rpTextNode, m_rPtPos);
    }
    void AssignBack(SwTextNode *& rpTextNode, sal_Int32 & rPtPos)
    {
        if (0 <= m_nPtIndex && m_pFrame)
        {
            std::pair<SwTextNode*, sal_Int32> const pos(
                    m_pFrame->MapViewToModel(TextFrameIndex(m_nPtIndex)));
            rpTextNode = pos.first;
            rPtPos = pos.second;
        }
        else
        {
            rPtPos = m_nPtIndex;
        }
    }
};

// namespace

bool SwCursor::SelectWord( SwViewShell const * pViewShell, const Point* pPt )
{
    return SelectWordWT( pViewShell, WordType::ANYWORD_IGNOREWHITESPACES, pPt );
}

bool SwCursor::IsStartWordWT(sal_Int16 nWordType, SwRootFrame const*const pLayout) const
{
    bool bRet = false;
    SwTextNode* pTextNd = GetPointNode().GetTextNode();
    if (pTextNd)
    {
        sal_Int32 nPtPos = GetPoint()->GetContentIndex();

        HideWrapper w(pLayout, pTextNd, nPtPos);

        bRet = g_pBreakIt->GetBreakIter()->isBeginWord(
                            *w.m_pText, w.m_nPtIndex,
                            g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos )),
                            nWordType );
    }
    return bRet;
}

bool SwCursor::IsEndWordWT(sal_Int16 nWordType, SwRootFrame const*const pLayout) const
{
    bool bRet = false;
    SwTextNode* pTextNd = GetPointNode().GetTextNode();
    if (pTextNd)
    {
        sal_Int32 nPtPos = GetPoint()->GetContentIndex();

        HideWrapper w(pLayout, pTextNd, nPtPos);

        bRet = g_pBreakIt->GetBreakIter()->isEndWord(
                            *w.m_pText, w.m_nPtIndex,
                            g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
                            nWordType );

    }
    return bRet;
}

bool SwCursor::IsInWordWT(sal_Int16 nWordType, SwRootFrame const*const pLayout) const
{
    bool bRet = false;
    SwTextNode* pTextNd = GetPointNode().GetTextNode();
    if (pTextNd)
    {
        sal_Int32 nPtPos = GetPoint()->GetContentIndex();

        {
            HideWrapper w(pLayout, pTextNd, nPtPos);

            Boundary aBoundary = g_pBreakIt->GetBreakIter()->getWordBoundary(
                                *w.m_pText, w.m_nPtIndex,
                                g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
                                nWordType,
                                true );

            bRet = aBoundary.startPos != aBoundary.endPos &&
                    aBoundary.startPos <= w.m_nPtIndex &&
                        w.m_nPtIndex <= aBoundary.endPos;
            w.m_nPtIndex = aBoundary.startPos; // hack: convert startPos back...
        }
        if(bRet)
        {
            const CharClass& rCC = GetAppCharClass();
            bRet = rCC.isLetterNumeric(pTextNd->GetText(), nPtPos);
        }
    }
    return bRet;
}

bool SwCursor::IsStartEndSentence(bool bEnd, SwRootFrame const*const pLayout) const
{
    bool bRet = bEnd ?
                    GetPointContentNode() && GetPoint()->GetContentIndex() == GetPointContentNode()->Len() :
                    GetPoint()->GetContentIndex() == 0;

    if ((pLayout != nullptr && pLayout->HasMergedParas()) || !bRet)
    {
        SwCursor aCursor(*GetPoint(), nullptr);
        SwPosition aOrigPos = *aCursor.GetPoint();
        aCursor.GoSentence(bEnd ? SwCursor::END_SENT : SwCursor::START_SENT, pLayout);
        bRet = aOrigPos == *aCursor.GetPoint();
    }
    return bRet;
}

bool SwCursor::GoStartWordWT(sal_Int16 nWordType, SwRootFrame const*const pLayout)
{
    bool bRet = false;
    SwTextNode* pTextNd = GetPointNode().GetTextNode();
    if (pTextNd)
    {
        SwCursorSaveState aSave( *this );
        sal_Int32 nPtPos = GetPoint()->GetContentIndex();

        {
            HideWrapper w(pLayout, pTextNd, nPtPos);

            w.m_nPtIndex = g_pBreakIt->GetBreakIter()->getWordBoundary(
                            *w.m_pText, w.m_nPtIndex,
                            g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
                            nWordType,
                            false ).startPos;
        }

        if (nPtPos < pTextNd->GetText().getLength() && nPtPos >= 0)
        {
            GetPoint()->Assign(*pTextNd, nPtPos);
            if( !IsSelOvr() )
                bRet = true;
        }
    }
    return bRet;
}

bool SwCursor::GoEndWordWT(sal_Int16 nWordType, SwRootFrame const*const pLayout)
{
    bool bRet = false;
    SwTextNode* pTextNd = GetPointNode().GetTextNode();
    if (pTextNd)
    {
        SwCursorSaveState aSave( *this );
        sal_Int32 nPtPos = GetPoint()->GetContentIndex();

        {
            HideWrapper w(pLayout, pTextNd, nPtPos);

            w.m_nPtIndex = g_pBreakIt->GetBreakIter()->getWordBoundary(
                            *w.m_pText, w.m_nPtIndex,
                            g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
                            nWordType,
                            true ).endPos;
        }

        if (nPtPos <= pTextNd->GetText().getLength() && nPtPos >= 0 &&
            GetPoint()->GetContentIndex() != nPtPos )
        {
            GetPoint()->Assign(*pTextNd, nPtPos);
            if( !IsSelOvr() )
                bRet = true;
        }
    }
    return bRet;
}

bool SwCursor::GoNextWordWT(sal_Int16 nWordType, SwRootFrame const*const pLayout)
{
    bool bRet = false;
    SwTextNode* pTextNd = GetPointNode().GetTextNode();
    if (pTextNd)
    {
        SwCursorSaveState aSave( *this );
        sal_Int32 nPtPos = GetPoint()->GetContentIndex();

        {
            HideWrapper w(pLayout, pTextNd, nPtPos);

            w.m_nPtIndex = g_pBreakIt->GetBreakIter()->nextWord(
                        *w.m_pText, w.m_nPtIndex,
                        g_pBreakIt->GetLocale( pTextNd->GetLang(nPtPos, 1) ),
                        nWordType ).startPos;
        }

        if (nPtPos <= pTextNd->GetText().getLength() && nPtPos >= 0)
        {
            GetPoint()->Assign(*pTextNd, nPtPos);
            if( !IsSelOvr() )
                bRet = true;
        }
    }
    return bRet;
}

bool SwCursor::GoPrevWordWT(sal_Int16 nWordType, SwRootFrame const*const pLayout)
{
    bool bRet = false;
    SwTextNode* pTextNd = GetPointNode().GetTextNode();
    if (pTextNd)
    {
        SwCursorSaveState aSave( *this );
        sal_Int32 nPtPos = GetPoint()->GetContentIndex();

        {
            HideWrapper w(pLayout, pTextNd, nPtPos);

            const sal_Int32 nPtStart = w.m_nPtIndex;
            if (w.m_nPtIndex)
            {
                --w.m_nPtIndex;
                w.AssignBack(pTextNd, nPtPos);
            }

            w.m_nPtIndex = g_pBreakIt->GetBreakIter()->previousWord(
                        *w.m_pText, nPtStart,
                        g_pBreakIt->GetLocale( pTextNd->GetLang(nPtPos, 1) ),
                                nWordType ).startPos;
        }

        if (nPtPos < pTextNd->GetText().getLength() && nPtPos >= 0)
        {
            GetPoint()->Assign(*pTextNd, nPtPos);
            if( !IsSelOvr() )
                bRet = true;
        }
    }
    return bRet;
}

bool SwCursor::SelectWordWT( SwViewShell const * pViewShell, sal_Int16 nWordType, const Point* pPt )
{
    SwCursorSaveState aSave( *this );

    bool bRet = false;
    DeleteMark();
    const SwRootFrame* pLayout = pViewShell->GetLayout();
    if( pPt && nullptr != pLayout )
    {
        // set the cursor to the layout position
        Point aPt( *pPt );
        pLayout->GetModelPositionForViewPoint( GetPoint(), aPt );
    }

    SwTextNode* pTextNd = GetPointNode().GetTextNode();
    if (pTextNd)
    {
        // Should we select the whole fieldmark?
        const IDocumentMarkAccess* pMarksAccess = GetDoc().getIDocumentMarkAccess( );
        sw::mark::Fieldmark const*const pMark(pMarksAccess->getInnerFieldmarkFor(*GetPoint()));
        if (pMark && (IDocumentMarkAccess::GetType(*pMark) == IDocumentMarkAccess::MarkType::TEXT_FIELDMARK
                      || IDocumentMarkAccess::GetType(*pMark) == IDocumentMarkAccess::MarkType::DATE_FIELDMARK))
        {
            *GetPoint() = sw::mark::FindFieldSep(*pMark);
            GetPoint()->AdjustContent(+1); // Don't select the separator

            const SwPosition& rEnd = pMark->GetMarkEnd();

            assert(pMark->GetMarkEnd() != *GetPoint());
            SetMark();
            *GetMark() = rEnd;
            GetMark()->AdjustContent(-1); // Don't select the end delimiter

            bRet = true;
        }
        else
        {
            sal_Int32 nPtPos = GetPoint()->GetContentIndex();

            HideWrapper w(pViewShell->GetLayout(), pTextNd, nPtPos);
            bool bForward = w.m_pText->getLength() == w.m_nPtIndex ? false : true;

            Boundary aBndry( g_pBreakIt->GetBreakIter()->getWordBoundary(
                                *w.m_pText, w.m_nPtIndex,
                                g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
                                nWordType,
                                bForward ));

            if (comphelper::LibreOfficeKit::isActive() && aBndry.startPos == aBndry.endPos && w.m_nPtIndex > 0)
            {
                // nPtPos is the end of the paragraph, select the last word then.
                --w.m_nPtIndex;
                w.AssignBack(pTextNd, nPtPos);

                aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
                                    *w.m_pText, w.m_nPtIndex,
                                    g_pBreakIt->GetLocale( pTextNd->GetLang( nPtPos ) ),
                                    nWordType,
                                    bForward );

            }

            SwTextNode * pStartNode(pTextNd);
            sal_Int32 nStartIndex;
            w.m_nPtIndex = aBndry.startPos;
            w.AssignBack(pStartNode, nStartIndex);

            SwTextNode * pEndNode(pTextNd);
            sal_Int32 nEndIndex;
            w.m_nPtIndex = aBndry.endPos;
            w.AssignBack(pEndNode, nEndIndex);

            if( aBndry.startPos != aBndry.endPos )
            {
                GetPoint()->Assign(*pEndNode, nEndIndex);
                if( !IsSelOvr() )
                {
                    SetMark();
                    GetMark()->Assign(*pStartNode, nStartIndex);
                    if (sw::mark::AnnotationMark* pAnnotationMark = pMarksAccess->getAnnotationMarkFor(*GetPoint()))
                    {
                        // An annotation mark covers the selected word. Check
                        // if it covers only the word: in that case we select
                        // the comment anchor as well.
                        bool bStartMatch = GetMark()->GetNode() == pAnnotationMark->GetMarkStart().GetNode() &&
                            GetMark()->GetContentIndex() == pAnnotationMark->GetMarkStart().GetContentIndex();
                        bool bEndMatch = GetPoint()->GetNode() == pAnnotationMark->GetMarkEnd().GetNode() &&
                            GetPoint()->GetContentIndex() + 1 == pAnnotationMark->GetMarkEnd().GetContentIndex();
                        if (bStartMatch && bEndMatch)
                            GetPoint()->AdjustContent(+1);
                    }
                    if( !IsSelOvr() )
                        bRet = true;
                }
            }
        }
    }

    if( !bRet )
    {
        DeleteMark();
        RestoreSavePos();
    }
    return bRet;
}

static OUString lcl_MaskDeletedRedlines( const SwTextNode* pTextNd )
{
    OUString aRes;
    if (pTextNd)
    {
        //mask deleted redlines
        OUString sNodeText(pTextNd->GetText());
        const SwDoc& rDoc = pTextNd->GetDoc();
        const bool bShowChg = IDocumentRedlineAccess::IsShowChanges( rDoc.getIDocumentRedlineAccess().GetRedlineFlags() );
        if ( bShowChg )
        {
            SwRedlineTable::size_type nAct = rDoc.getIDocumentRedlineAccess().GetRedlinePos( *pTextNd, RedlineType::Any );
            for ( ; nAct < rDoc.getIDocumentRedlineAccess().GetRedlineTable().size(); nAct++ )
            {
                const SwRangeRedline* pRed = rDoc.getIDocumentRedlineAccess().GetRedlineTable()[ nAct ];
                if ( pRed->Start()->GetNode() > *pTextNd )
                    break;

                if( RedlineType::Delete == pRed->GetType() )
                {
                    sal_Int32 nStart, nEnd;
                    pRed->CalcStartEnd( pTextNd->GetIndex(), nStart, nEnd );

                    while ( nStart < nEnd && nStart < sNodeText.getLength() )
                        sNodeText = sNodeText.replaceAt( nStart++, 1, rtl::OUStringChar(CH_TXTATR_INWORD) );
                }
            }
        }
        aRes = sNodeText;
    }
    return aRes;
}

bool SwCursor::GoSentence(SentenceMoveType eMoveType, SwRootFrame const*const pLayout)
{
    bool bRet = false;
    SwTextNode* pTextNd = GetPointNode().GetTextNode();
    if (pTextNd)
    {
        OUString const sNodeText(lcl_MaskDeletedRedlines(pTextNd));

        SwCursorSaveState aSave( *this );
        sal_Int32 nPtPos = GetPoint()->GetContentIndex();

        {
            HideWrapper w(pLayout, pTextNd, nPtPos, &sNodeText);

            switch ( eMoveType )
            {
            case START_SENT: /* when modifying: see also ExpandToSentenceBorders below! */
                w.m_nPtIndex = g_pBreakIt->GetBreakIter()->beginOfSentence(
                            *w.m_pText, w.m_nPtIndex,
                            g_pBreakIt->GetLocale(pTextNd->GetLang(nPtPos)));
                break;
            case END_SENT: /* when modifying: see also ExpandToSentenceBorders below! */
                w.m_nPtIndex = g_pBreakIt->GetBreakIter()->endOfSentence(
                            *w.m_pText, w.m_nPtIndex,
                            g_pBreakIt->GetLocale(pTextNd->GetLang(nPtPos)));
                break;
            case NEXT_SENT:
                {
                    w.m_nPtIndex = g_pBreakIt->GetBreakIter()->endOfSentence(
                            *w.m_pText, w.m_nPtIndex,
                            g_pBreakIt->GetLocale(pTextNd->GetLang(nPtPos)));
                    if (w.m_nPtIndex >= 0 && w.m_nPtIndex < w.m_pText->getLength())
                    {
                        do
                        {
                            ++w.m_nPtIndex;
                        }
                        while (w.m_nPtIndex < w.m_pText->getLength()
                               && (*w.m_pText)[w.m_nPtIndex] == ' ');
                    }
                    break;
                }
            case PREV_SENT:
                w.m_nPtIndex = g_pBreakIt->GetBreakIter()->beginOfSentence(
                            *w.m_pText, w.m_nPtIndex,
                            g_pBreakIt->GetLocale(pTextNd->GetLang(nPtPos)));

                if (w.m_nPtIndex == 0)
                    return false;   // the previous sentence is not in this paragraph
                if (w.m_nPtIndex > 0)
                {
                    w.m_nPtIndex = g_pBreakIt->GetBreakIter()->beginOfSentence(
                            *w.m_pText, w.m_nPtIndex - 1,
                            g_pBreakIt->GetLocale(pTextNd->GetLang(nPtPos)));
                }
                break;
            }
        }

        // it is allowed to place the PaM just behind the last
        // character in the text thus <= ...Len
        if (nPtPos <= pTextNd->GetText().getLength() && nPtPos >= 0)
        {
            GetPoint()->Assign(*pTextNd, nPtPos);
            if( !IsSelOvr() )
                bRet = true;
        }
    }
    return bRet;
}

void SwCursor::ExpandToSentenceBorders(SwRootFrame const*const pLayout)
{
    SwTextNode* pStartNd = Start()->GetNode().GetTextNode();
    SwTextNode* pEndNd   = End()->GetNode().GetTextNode();
    if (!pStartNd || !pEndNd)
        return;

    if (!HasMark())
        SetMark();

    OUString sStartText( lcl_MaskDeletedRedlines( pStartNd ) );
    OUString sEndText( pStartNd == pEndNd? sStartText : lcl_MaskDeletedRedlines( pEndNd ) );

    SwCursorSaveState aSave( *this );
    sal_Int32 nStartPos = Start()->GetContentIndex();
    sal_Int32 nEndPos   = End()->GetContentIndex();

    {
        HideWrapper w(pLayout, pStartNd, nStartPos, &sStartText);

        w.m_nPtIndex = g_pBreakIt->GetBreakIter()->beginOfSentence(
                            *w.m_pText, w.m_nPtIndex,
                            g_pBreakIt->GetLocale( pStartNd->GetLang( nStartPos ) ) );
    }
    {
        HideWrapper w(pLayout, pEndNd, nEndPos, &sEndText);

        w.m_nPtIndex = g_pBreakIt->GetBreakIter()->endOfSentence(
                            *w.m_pText, w.m_nPtIndex,
                            g_pBreakIt->GetLocale( pEndNd->GetLang( nEndPos ) ) );
    }

    // it is allowed to place the PaM just behind the last
    // character in the text thus <= ...Len
    if (nStartPos <= pStartNd->GetText().getLength() && nStartPos >= 0)
    {
        GetMark()->Assign(*pStartNd, nStartPos);
    }
    if (nEndPos <= pEndNd->GetText().getLength() && nEndPos >= 0)
    {
        GetPoint()->Assign(*pEndNd, nEndPos);
    }
}

bool SwTableCursor::LeftRight( bool bLeft, sal_uInt16 nCnt, SwCursorSkipMode /*nMode*/,
    bool /*bVisualAllowed*/, bool /*bSkipHidden*/, bool /*bInsertCursor*/,
    SwRootFrame const*, bool /*isFieldNames*/)
{
    return bLeft ? GoPrevCell( nCnt )
                 : GoNextCell( nCnt );
}

// calculate cursor bidi level: extracted from LeftRight()
const SwContentFrame*
SwCursor::DoSetBidiLevelLeftRight(
    bool & io_rbLeft, bool bVisualAllowed, bool bInsertCursor)
{
    // calculate cursor bidi level
    const SwContentFrame* pSttFrame = nullptr;
    SwNode& rNode = GetPoint()->GetNode();

    if( rNode.IsTextNode() )
    {
        const SwTextNode& rTNd = *rNode.GetTextNode();
        sal_Int32 nPos = GetPoint()->GetContentIndex();

        if ( bVisualAllowed && SvtCTLOptions::IsCTLFontEnabled() &&
             SvtCTLOptions::MOVEMENT_VISUAL == SvtCTLOptions::GetCTLCursorMovement() )
        {
            // for visual cursor travelling (used in bidi layout)
            // we first have to convert the logic to a visual position
            Point aPt;
            std::pair<Point, boolconst tmp(aPt, true);
            pSttFrame = rTNd.getLayoutFrame(
                    GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
                    GetPoint(), &tmp);
            if( pSttFrame )
            {
                sal_uInt8 nCursorLevel = GetCursorBidiLevel();
                bool bForward = ! io_rbLeft;
                SwTextFrame *const pTF(const_cast<SwTextFrame*>(
                            static_cast<const SwTextFrame*>(pSttFrame)));
                TextFrameIndex nTFIndex(pTF->MapModelToViewPos(*GetPoint()));
                pTF->PrepareVisualMove( nTFIndex, nCursorLevel,
                                                         bForward, bInsertCursor );
                *GetPoint() = pTF->MapViewToModelPos(nTFIndex);
                SetCursorBidiLevel( nCursorLevel );
                io_rbLeft = ! bForward;
            }
        }
        else
        {
            SwTextFrame const* pFrame;
            const SwScriptInfo* pSI = SwScriptInfo::GetScriptInfo(rTNd, &pFrame);
            if ( pSI )
            {
                const sal_Int32 nMoveOverPos = io_rbLeft ?
                                               ( nPos ? nPos - 1 : 0 ) :
                                                nPos;
                TextFrameIndex nIndex(pFrame->MapModelToView(&rTNd, nMoveOverPos));
                SetCursorBidiLevel( pSI->DirType(nIndex) );
            }
        }
    }
    return pSttFrame;
}

static const SwTextFrame* GetTextFrame(const SwNode& rNode, SwRootFrame const*const pLayout)
{
    if (!pLayout)
        return nullptr;

    SwContentFrame const* pFrame(rNode.GetContentNode()->getLayoutFrame(pLayout));
    if (!pFrame)
        return nullptr;

    while (pFrame->GetPrecede())
    {
        pFrame = static_cast<SwContentFrame const*>(pFrame->GetPrecede());
    }

    return pFrame->DynCastTextFrame();
}

bool SwCursor::LeftRight( bool bLeft, sal_uInt16 nCnt, SwCursorSkipMode nMode,
                          bool bVisualAllowed,bool bSkipHidden, bool bInsertCursor,
                          SwRootFrame const*const pLayout, bool isFieldNames)
{
    // calculate cursor bidi level
    SwNode& rNode = GetPoint()->GetNode();
    const SwContentFrame* pSttFrame = // may side-effect bLeft!
        DoSetBidiLevelLeftRight(bLeft, bVisualAllowed, bInsertCursor);

    // can the cursor be moved n times?
    SwCursorSaveState aSave( *this );
    SwMoveFnCollection const & fnMove = bLeft ? fnMoveBackward : fnMoveForward;

    SwGoInDoc fnGo;
    if ( bSkipHidden )
        fnGo = SwCursorSkipMode::Cells == nMode ? GoInContentCellsSkipHidden : GoInContentSkipHidden;
    else
        fnGo = SwCursorSkipMode::Cells == nMode ? GoInContentCells : GoInContent;

    SwTextFrame const* pFrame = GetTextFrame(rNode, pLayout);

    while( nCnt )
    {
        SwNodeIndex aOldNodeIdx( GetPoint()->GetNode() );

        TextFrameIndex beforeIndex(-1);
        if (pFrame)
        {
            beforeIndex = pFrame->MapModelToViewPos(*GetPoint());
        }

        if (!bLeft && pLayout && pLayout->GetFieldmarkMode() == sw::FieldmarkMode::ShowResult)
        {
            SwTextNode const*const pNode(GetPoint()->GetNode().GetTextNode());
            SAL_WARN_IF(!pNode, "sw.core""expected a SwTextNode");
            if (pNode && pNode->Len() != GetPoint()->GetContentIndex()
                && pNode->GetText()[GetPoint()->GetContentIndex()] == CH_TXT_ATR_FIELDSTART)
            {
                IDocumentMarkAccess const& rIDMA(*GetDoc().getIDocumentMarkAccess());
                sw::mark::Fieldmark const*const pMark(rIDMA.getFieldmarkAt(*GetPoint()));
                assert(pMark);
                *GetPoint() = sw::mark::FindFieldSep(*pMark);
            }
        }

        if ( !Move( fnMove, fnGo ) )
        {
            const SwEditShell* pSh = GetDoc().GetEditShell();
            const SwViewOption* pViewOptions = pSh ? pSh->GetViewOptions() : nullptr;
            if (pViewOptions && pViewOptions->IsShowOutlineContentVisibilityButton())
            {
                // Fixes crash that occurs in documents with outline content folded at the end of
                // the document. When the cursor is at the end of the visible document and
                // right arrow key is pressed Move fails after moving the cursor to the
                // end of the document model, which doesn't have a node frame and causes
                // weird numbers to be displayed in the statusbar page number count. Left
                // arrow, when in this state, causes a crash without RestoredSavePos() added here.
                RestoreSavePos();
            }
            break;
        }

        if (pFrame)
        {
            SwTextFrame const* pNewFrame = GetTextFrame(GetPoint()->GetNode(), pLayout);
            // sw_redlinehide: fully redline-deleted nodes don't have frames...
            if (pFrame == pNewFrame || !pNewFrame)
            {
                if (!pNewFrame || beforeIndex == pFrame->MapModelToViewPos(*GetPoint()))
                {
                    continue// moving inside delete redline, doesn't count...
                }
            }
            else
            {
                // assume iteration is stable & returns the same frame
                assert(!pFrame->IsAnFollow(pNewFrame) && !pNewFrame->IsAnFollow(pFrame));
                pFrame = pNewFrame;
            }
        }

        if (bLeft && pLayout && pLayout->GetFieldmarkMode() == sw::FieldmarkMode::ShowCommand)
        {
            SwTextNode const*const pNode(GetPoint()->GetNode().GetTextNode());
            assert(pNode);
            if (pNode->Len() != GetPoint()->GetContentIndex()
                && pNode->GetText()[GetPoint()->GetContentIndex()] == CH_TXT_ATR_FIELDEND)
            {
                IDocumentMarkAccess const& rIDMA(*GetDoc().getIDocumentMarkAccess());
                sw::mark::Fieldmark const*const pMark(rIDMA.getFieldmarkAt(*GetPoint()));
                assert(pMark);
                *GetPoint() = sw::mark::FindFieldSep(*pMark);
            }
        }

        if (isFieldNames)
        {
            SwTextNode const*const pNode(GetPoint()->GetNode().GetTextNode());
            assert(pNode);
            SwTextAttr const*const pInputField(pNode->GetTextAttrAt(
                GetPoint()->GetContentIndex(), RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent));
            if (pInputField)
            {
                continue// skip over input fields
            }
        }

        // If we were located inside a covered cell but our position has been
        // corrected, we check if the last move has moved the cursor to a
        // different table cell. In this case we set the cursor to the stored
        // covered position and redo the move:
        if (m_nRowSpanOffset)
        {
            const SwNode* pOldTabBoxSttNode = aOldNodeIdx.GetNode().FindTableBoxStartNode();
            const SwTableNode* pOldTabSttNode = pOldTabBoxSttNode ? pOldTabBoxSttNode->FindTableNode() : nullptr;
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=94 G=94

¤ Dauer der Verarbeitung: 0.32 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge