/**************************************************************
 * 
 * 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
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"


#include <hintids.hxx>
#include <editeng/protitem.hxx>
#include <com/sun/star/i18n/WordType.hdl>
#include <com/sun/star/i18n/CharType.hdl>
#include <unotools/charclass.hxx>
#include <svl/ctloptions.hxx>
#include <swmodule.hxx>
#include <fmtcntnt.hxx>
#include <swtblfmt.hxx>
#include <swcrsr.hxx>
#include <unocrsr.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <docary.hxx>
#include <ndtxt.hxx>
#include <section.hxx>
#include <swtable.hxx>
#include <cntfrm.hxx>
#include <rootfrm.hxx>
#include <txtfrm.hxx>
#include <scriptinfo.hxx>
#include <crstate.hxx>
#include <docsh.hxx>
#include <viewsh.hxx>
#include <frmatr.hxx>
#include <breakit.hxx>
#include <crsskip.hxx>
#include <vcl/msgbox.hxx>
#include <mdiexp.hxx>			// ...Percent()
#include <statstr.hrc>			// ResId fuer Statusleiste
#include <redline.hxx>      // SwRedline
#include <txatbase.hxx>


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


static const sal_uInt16 coSrchRplcThreshold = 60000;

struct _PercentHdl
{
	SwDocShell* pDSh;
	sal_uLong nActPos;
	sal_Bool bBack, bNodeIdx;

	_PercentHdl( sal_uLong nStt, sal_uLong nEnd, SwDocShell* pSh )
		: pDSh( pSh )
	{
		nActPos = nStt;
		if( 0 != ( bBack = (nStt > nEnd )) )
		{
			sal_uLong n = nStt; nStt = nEnd; nEnd = n;
		}
		::StartProgress( STR_STATSTR_SEARCH, nStt, nEnd, 0 );
	}

	_PercentHdl( const SwPaM& rPam )
		: pDSh( (SwDocShell*)rPam.GetDoc()->GetDocShell() )
	{
		sal_uLong nStt, nEnd;
		if( rPam.GetPoint()->nNode == rPam.GetMark()->nNode )
		{
			bNodeIdx = sal_False;
			nStt = rPam.GetMark()->nContent.GetIndex();
			nEnd = rPam.GetPoint()->nContent.GetIndex();
		}
		else
		{
            bNodeIdx = sal_True;
            nStt = rPam.GetMark()->nNode.GetIndex();
			nEnd = rPam.GetPoint()->nNode.GetIndex();
		}
		nActPos = nStt;
		if( 0 != ( bBack = (nStt > nEnd )) )
		{
			sal_uLong n = nStt; nStt = nEnd; nEnd = n;
		}
		::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& rPos ) const
		{
			sal_uLong nPos;
			if( bNodeIdx )
				nPos = rPos.nNode.GetIndex();
			else
				nPos = rPos.nContent.GetIndex();
			::SetProgressState( bBack ? nActPos - nPos : nPos, pDSh );
		}
};

SwCursor::SwCursor( const SwPosition &rPos, SwPaM* pRing, bool bColumnSel )
    : SwPaM( rPos, pRing ), pSavePos( 0 ), mnRowSpanOffset( 0 ), nCursorBidiLevel( 0 ),
    mbColumnSelection( bColumnSel )
{
}

// @@@ semantic: no copy ctor.
SwCursor::SwCursor( SwCursor& rCpy )
    : SwPaM( rCpy ), pSavePos( 0 ), mnRowSpanOffset( rCpy.mnRowSpanOffset ), 
    nCursorBidiLevel( rCpy.nCursorBidiLevel ), mbColumnSelection( rCpy.mbColumnSelection )
{
}

SwCursor::~SwCursor()
{
	while( pSavePos )
	{
        _SwCursor_SavePos* pNxt = pSavePos->pNext;
		delete pSavePos;
        pSavePos = pNxt;
	}
}

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

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

sal_Bool SwCursor::IsSkipOverHiddenSections() const
{
    return sal_True;
}

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


// Sicher die aktuelle Position, damit ggfs. auf diese zurueck
// gefallen werden kann. Die SavePos Objekte werden als Stack verwaltet,
// damit das auch alles bei verschachtelten Aufrufen funktioniert.
// Das CreateNewSavePos ist virtual, damit abgeleitete Klassen vom Cursor
// gegebenenfalls eigene SaveObjecte anlegen und in den virtuellen
// Check-Routinen verwenden koennen.

void SwCursor::SaveState()
{
	_SwCursor_SavePos* pNew = CreateNewSavePos();
	pNew->pNext = pSavePos;
	pSavePos = pNew;
}

void SwCursor::RestoreState()
{
    if( pSavePos ) // Robust
    {
        _SwCursor_SavePos* pDel = pSavePos;
        pSavePos = pSavePos->pNext;
        delete pDel;
    }
}

_SwCursor_SavePos* SwCursor::CreateNewSavePos() const
{
	return new _SwCursor_SavePos( *this );
}

// stelle fest, ob sich der Point ausserhalb des Content-Bereichs
// vom Nodes-Array befindet
sal_Bool SwCursor::IsNoCntnt() const
{
	return GetPoint()->nNode.GetIndex() <
			GetDoc()->GetNodes().GetEndOfExtras().GetIndex();
}

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

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

sal_Bool SwCursor::IsSelOvr( int eFlags )
{
	SwDoc* pDoc = GetDoc();
	SwNodes& rNds = pDoc->GetNodes();

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

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

    if( pSavePos->nNode != GetPoint()->nNode.GetIndex()
        && ( !pDoc->GetDocShell()
             || !pDoc->GetDocShell()->IsReadOnlyUI() ) )
    {
        // teste doch mal die neuen Sections:
        SwNodeIndex& rPtIdx = GetPoint()->nNode;
        const SwSectionNode* pSectNd = rPtIdx.GetNode().FindSectionNode();
        if( pSectNd &&
            ((bSkipOverHiddenSections && pSectNd->GetSection().IsHiddenFlag() ) ||
            (bSkipOverProtectSections && pSectNd->GetSection().IsProtectFlag() )))
        {
            if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) )
            {
                // dann wars das schon
                RestoreSavePos();
                return sal_True;
            }

            // dann setze den Cursor auf die neue Position:
            SwNodeIndex aIdx( rPtIdx );
            xub_StrLen nCntntPos = pSavePos->nCntnt;
            int bGoNxt = pSavePos->nNode < rPtIdx.GetIndex();
            SwCntntNode* pCNd = bGoNxt
                ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections)
                : rNds.GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections);
            if( !pCNd && ( nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION & eFlags ))
            {
                bGoNxt = !bGoNxt;
                pCNd = bGoNxt ? rNds.GoNextSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections)
                    : rNds.GoPrevSection( &rPtIdx, bSkipOverHiddenSections, bSkipOverProtectSections);
            }

            int bIsValidPos = 0 != pCNd;
            sal_Bool bValidNodesRange = bIsValidPos &&
                ::CheckNodesRange( rPtIdx, aIdx, sal_True );
            if( !bValidNodesRange )
            {
                rPtIdx = pSavePos->nNode;
                if( 0 == ( pCNd = rPtIdx.GetNode().GetCntntNode() ) )
                {
                    bIsValidPos = sal_False;
                    nCntntPos = 0;
                    rPtIdx = aIdx;
                    if( 0 == ( pCNd = rPtIdx.GetNode().GetCntntNode() ) )
                    {
                        // dann auf den Anfang vom Doc
                        rPtIdx = rNds.GetEndOfExtras();
                        pCNd = rNds.GoNext( &rPtIdx );
                    }
                }
            }

            // ContentIndex noch anmelden:
            xub_StrLen nTmpPos = bIsValidPos ? (bGoNxt ? 0 : pCNd->Len()) : nCntntPos;
            GetPoint()->nContent.Assign( pCNd, nTmpPos );
            if( !bIsValidPos || !bValidNodesRange ||
                // sollten wir in einer Tabelle gelandet sein?
                    IsInProtectTable( sal_True ) )
                    return sal_True;
        }

        // oder sollte eine geschuetzte Section innerhalb der Selektion liegen?
        if( HasMark() && bSkipOverProtectSections)
        {
            sal_uLong nSttIdx = GetMark()->nNode.GetIndex(),
                nEndIdx = GetPoint()->nNode.GetIndex();
            if( nEndIdx <= nSttIdx )
            {
                sal_uLong nTmp = nSttIdx;
                nSttIdx = nEndIdx;
                nEndIdx = nTmp;
            }

            const SwSectionFmts& rFmts = pDoc->GetSections();
            for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
            {
                const SwSectionFmt* pFmt = rFmts[n];
                const SvxProtectItem& rProtect = pFmt->GetProtect();
                if( rProtect.IsCntntProtected() )
                {
                    const SwFmtCntnt& rCntnt = pFmt->GetCntnt(sal_False);
                    ASSERT( rCntnt.GetCntntIdx(), "wo ist der SectionNode?" );
                    sal_uLong nIdx = rCntnt.GetCntntIdx()->GetIndex();
                    if( nSttIdx <= nIdx && nEndIdx >= nIdx )
                    {
                        // ist es keine gelinkte Section, dann kann sie auch
                        // nicht mitselektiert werden
                        const SwSection& rSect = *pFmt->GetSection();
                        if( CONTENT_SECTION == rSect.GetType() )
                        {
                            RestoreSavePos();
                            return sal_True;
                        }
                    }
                }
            }
        }

    }

    const SwNode* pNd = &GetPoint()->nNode.GetNode();
    if( pNd->IsCntntNode() && !dynamic_cast<SwUnoCrsr*>(this) )
    {
        const SwCntntFrm* pFrm = ((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() );
        if( pFrm && pFrm->IsValid()
            && 0 == pFrm->Frm().Height()
            && 0 != ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) )
        {
            // skip to the next / prev valid paragraph with a layout
            SwNodeIndex& rPtIdx = GetPoint()->nNode;
            int bGoNxt = pSavePos->nNode < rPtIdx.GetIndex();
            while( 0 != ( pFrm = ( bGoNxt ? pFrm->GetNextCntntFrm() : pFrm->GetPrevCntntFrm() ))
                   && 0 == pFrm->Frm().Height() )
                ;

            // --> LIJIAN/FME 2007-11-27 #i72394# skip to prev /next valid paragraph
            // with a layout in case the first search did not succeed:
            if( !pFrm )
            {
                bGoNxt = !bGoNxt;
                pFrm = ((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() );
                while ( pFrm && 0 == pFrm->Frm().Height() ) 
                {
                    pFrm = bGoNxt ? pFrm->GetNextCntntFrm()
                        :   pFrm->GetPrevCntntFrm();
                }
            }
            // <--

            SwCntntNode* pCNd;
            if( pFrm && 0 != (pCNd = (SwCntntNode*)pFrm->GetNode()) )
            {
                // set this cntntNode as new position
                rPtIdx = *pCNd;
                pNd = pCNd;

                // ContentIndex noch anmelden:
                xub_StrLen nTmpPos = bGoNxt ? 0 : pCNd->Len();
                GetPoint()->nContent.Assign( pCNd, nTmpPos );

                // sollten wir in einer Tabelle gelandet sein?
                if( IsInProtectTable( sal_True ) )
                    pFrm = 0;
            }
        }

        if( !pFrm )
        {
            DeleteMark();
            RestoreSavePos();
            return sal_True;		// ohne Frames geht gar nichts!
        }
    }

    // darf der Cursor in geschuetzen "Nodes" stehen?
    if( 0 == ( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags ) && !IsAtValidPos() )
    {
        DeleteMark();
        RestoreSavePos();
        return sal_True;
    }

    if( !HasMark() )
        return sal_False;

    //JP 19.08.98: teste mal auf ungueltige Selektion - sprich ueber
    // 				GrundSections:
    if( !::CheckNodesRange( GetMark()->nNode, GetPoint()->nNode, sal_True ))
    {
        DeleteMark();
        RestoreSavePos();
        return sal_True;		// ohne Frames geht gar nichts!
    }

    if( (pNd = &GetMark()->nNode.GetNode())->IsCntntNode()
        && !((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() )
        && !dynamic_cast<SwUnoCrsr*>(this) )
    {
        DeleteMark();
        RestoreSavePos();
        return sal_True;		// ohne Frames geht gar nichts!
    }

    // assure that selection is only inside an InputField or contains the InputField completely
    {
        const SwTxtAttr* pInputFldTxtAttrAtPoint = NULL;
        SwTxtNode* pTxtNdAtPoint = GetPoint()->nNode.GetNode().GetTxtNode();
        if ( pTxtNdAtPoint != NULL )
        {
            pInputFldTxtAttrAtPoint =
                pTxtNdAtPoint->GetTxtAttrAt( GetPoint()->nContent.GetIndex(), RES_TXTATR_INPUTFIELD, SwTxtNode::PARENT );
        }

        const SwTxtAttr* pInputFldTxtAttrAtMark = NULL;
        SwTxtNode* pTxtNdAtMark = GetMark()->nNode.GetNode().GetTxtNode();
        if ( pTxtNdAtMark != NULL )
        {
            pInputFldTxtAttrAtMark =
                pTxtNdAtMark->GetTxtAttrAt( GetMark()->nContent.GetIndex(), RES_TXTATR_INPUTFIELD, SwTxtNode::PARENT );
        }

        if ( pInputFldTxtAttrAtPoint != pInputFldTxtAttrAtMark )
        {
            const sal_uLong nRefNodeIdx =
                ( nsSwCursorSelOverFlags::SELOVER_TOGGLE & eFlags )
                ? pSavePos->nNode
                : GetMark()->nNode.GetIndex();
            const xub_StrLen nRefContentIdx =
                ( nsSwCursorSelOverFlags::SELOVER_TOGGLE & eFlags )
                ? pSavePos->nCntnt
                : GetMark()->nContent.GetIndex();
            const bool bIsForwardSelection =
                nRefNodeIdx < GetPoint()->nNode.GetIndex()
                || ( nRefNodeIdx == GetPoint()->nNode.GetIndex()
                     && nRefContentIdx < GetPoint()->nContent.GetIndex() );

            if ( pInputFldTxtAttrAtPoint != NULL )
            {
                const xub_StrLen nNewPointPos =
                    bIsForwardSelection ? *(pInputFldTxtAttrAtPoint->End()) : *(pInputFldTxtAttrAtPoint->GetStart());
                GetPoint()->nContent.Assign( pTxtNdAtPoint, nNewPointPos );
            }

            if ( pInputFldTxtAttrAtMark != NULL )
            {
                const xub_StrLen nNewMarkPos =
                    bIsForwardSelection ? *(pInputFldTxtAttrAtMark->GetStart()) : *(pInputFldTxtAttrAtMark->End());
                GetMark()->nContent.Assign( pTxtNdAtMark, nNewMarkPos );
            }
        }
    }

    const SwTableNode* pPtNd = GetPoint()->nNode.GetNode().FindTableNode();
    const SwTableNode* pMrkNd = GetMark()->nNode.GetNode().FindTableNode();
    // beide in keinem oder beide im gleichen TableNode
    if( ( !pMrkNd && !pPtNd ) || pPtNd == pMrkNd )
        return sal_False;

    // in unterschiedlichen Tabellen oder nur Mark in der Tabelle
    if( ( pPtNd && pMrkNd ) || pMrkNd )
    {
        // dann lasse das nicht zu, alte Pos zurueck
        RestoreSavePos();
        // Crsr bleibt an der alten Position
        return sal_True;
    }

    // ACHTUNG: dieses kann nicht im TableMode geschehen !!
    if( pPtNd )		// nur Point in Tabelle, dann gehe hinter/vor diese
    {
        if( nsSwCursorSelOverFlags::SELOVER_CHANGEPOS & eFlags )
        {
            sal_Bool bSelTop = GetPoint()->nNode.GetIndex() <
                (( nsSwCursorSelOverFlags::SELOVER_TOGGLE & eFlags ) ? pSavePos->nNode
                : GetMark()->nNode.GetIndex());

            do {
                // in Schleife fuer Tabelle hinter Tabelle
                sal_uLong nSEIdx = pPtNd->EndOfSectionIndex();
                sal_uLong nSttEndTbl = nSEIdx + 1; // dflt. Sel. nach unten

                if( bSelTop )								// Sel. nach oben
                    nSttEndTbl = rNds[ nSEIdx ]->StartOfSectionIndex() - 1;

                GetPoint()->nNode = nSttEndTbl;
                const SwNode* pMyNd = GetNode();

                if( pMyNd->IsSectionNode() || ( pMyNd->IsEndNode() &&
                    pMyNd->StartOfSectionNode()->IsSectionNode() ) )
                {
                    // die lassen wir zu:
                    pMyNd = bSelTop
                        ? rNds.GoPrevSection( &GetPoint()->nNode,sal_True,sal_False )
                        : rNds.GoNextSection( &GetPoint()->nNode,sal_True,sal_False );

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

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

                if( pMyNd->IsCntntNode() &&      // ist es ein ContentNode ??
                    ::CheckNodesRange( GetMark()->nNode,
                    GetPoint()->nNode, sal_True ))
                {
                    // TABLE IN TABLE
                    const SwTableNode* pOuterTableNd = pMyNd->FindTableNode();
                    if ( pOuterTableNd )
                        pMyNd = pOuterTableNd;
                    else
                    {
                        SwCntntNode* pCNd = (SwCntntNode*)pMyNd;
                        xub_StrLen nTmpPos = bSelTop ? pCNd->Len() : 0;
                        GetPoint()->nContent.Assign( pCNd, nTmpPos );
                        return sal_False;
                    }
                }
                if( bSelTop
                    ? ( !pMyNd->IsEndNode() || 0 == ( pPtNd = pMyNd->FindTableNode() ))
                    : 0 == ( pPtNd = pMyNd->GetTableNode() ))
                    break;
            } while( sal_True );
        }

        // dann verbleibe auf der alten Position
        RestoreSavePos();
        return sal_True;		// Crsr bleibt an der alten Position
    }

    return sal_False;
}

#if defined( UNX )
#define IDX     (*pCellStt)
#else
#define IDX     aCellStt
#endif


sal_Bool SwCursor::IsInProtectTable( sal_Bool bMove, sal_Bool bChgCrsr )
{
	SwCntntNode* pCNd = GetCntntNode();
	if( !pCNd )
        return sal_False;

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

    // Current position == last save position?
    if ( pSavePos->nNode == GetPoint()->nNode.GetIndex() )
        return sal_False;

    // Check for convered cell:
    bool bInCoveredCell = false;
    const SwStartNode* pTmpSttNode = pCNd->FindTableBoxStartNode();
    ASSERT( pTmpSttNode, "In table, therefore I expect to get a SwTableBoxStartNode" )
    const SwTableBox* pBox = pTmpSttNode ? pTableNode->GetTable().GetTblBox( pTmpSttNode->GetIndex() ) : 0; //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 sal_False;

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

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

	if( !bMove )
	{
		if( bChgCrsr )
			// restore the last save position
			RestoreSavePos();
		return sal_True;		// Crsr bleibt an der alten Position
	}

	// wir stehen in einer geschuetzten TabellenZelle
	// von Oben nach Unten Traveln ?
	if( pSavePos->nNode < GetPoint()->nNode.GetIndex() )
	{
		// suche die naechste "gueltige" Box

		// folgt nach dem EndNode der Zelle ein weiterer StartNode, dann
		// gibt es auch eine naechste Zelle
#if defined( UNX )
		SwNodeIndex* pCellStt = new SwNodeIndex( *GetNode()->
						FindTableBoxStartNode()->EndOfSectionNode(), 1 );
#else
		SwNodeIndex aCellStt( *GetNode()->FindTableBoxStartNode()->EndOfSectionNode(), 1 );
#endif
		sal_Bool bProt = sal_True;
GoNextCell:
		do {
			if( !IDX.GetNode().IsStartNode() )
				break;
			IDX++;
			if( 0 == ( pCNd = IDX.GetNode().GetCntntNode() ))
				pCNd = IDX.GetNodes().GoNext( &IDX );
			if( 0 == ( bProt = pCNd->IsProtect() ))
				break;
			IDX.Assign( *pCNd->FindTableBoxStartNode()->EndOfSectionNode(), 1 );
		} while( bProt );

SetNextCrsr:
		if( !bProt )		// eine freie Zelle gefunden
		{
			GetPoint()->nNode = IDX;
#if defined( UNX )
			delete pCellStt;
#endif
            SwCntntNode* pTmpCNd = GetCntntNode();
            if( pTmpCNd )
			{
                GetPoint()->nContent.Assign( pTmpCNd, 0 );
				return sal_False;
			}
            return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
                             nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
		}
		// am Ende der Tabelle, also setze hinter diese
		IDX++;     // auf den naechsten Node
		SwNode* pNd;
		if( ( pNd = &IDX.GetNode())->IsEndNode() || HasMark())
		{
			// Tabelle allein in einem FlyFrame oder SSelection,
			// dann verbleibe auf der alten Position
			if( bChgCrsr )
				RestoreSavePos();
#if defined( UNX )
			delete pCellStt;
#endif
			return sal_True;        // Crsr bleibt an der alten Position
		}
		else if( pNd->IsTableNode() && IDX++ )
			goto GoNextCell;

		bProt = sal_False;		// Index steht jetzt auf einem ContentNode
		goto SetNextCrsr;
	}

	// suche die vorherige "gueltige" Box
	{
		// liegt vor dem StartNode der Zelle ein weiterer EndNode, dann
		// gibt es auch eine vorherige Zelle
#if defined( UNX )
		SwNodeIndex* pCellStt = new SwNodeIndex(
					*GetNode()->FindTableBoxStartNode(), -1 );
#else
		SwNodeIndex aCellStt( *GetNode()->FindTableBoxStartNode(), -1 );
#endif
		SwNode* pNd;
		sal_Bool bProt = sal_True;
GoPrevCell:
		do {
			if( !( pNd = &IDX.GetNode())->IsEndNode() )
				break;
			IDX.Assign( *pNd->StartOfSectionNode(), +1 );
			if( 0 == ( pCNd = IDX.GetNode().GetCntntNode() ))
				pCNd = pNd->GetNodes().GoNext( &IDX );
			if( 0 == ( bProt = pCNd->IsProtect() ))
				break;
			IDX.Assign( *pNd->FindTableBoxStartNode(), -1 );
		} while( bProt );

SetPrevCrsr:
		if( !bProt )		// eine freie Zelle gefunden
		{
			GetPoint()->nNode = IDX;
#if defined( UNX )
			delete pCellStt;
#endif
            SwCntntNode* pTmpCNd = GetCntntNode();
            if( pTmpCNd )
			{
                GetPoint()->nContent.Assign( pTmpCNd, 0 );
				return sal_False;
			}
            return IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
                             nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
		}
		// am Start der Tabelle, also setze vor diese
		IDX--;     // auf den naechsten Node
		if( ( pNd = &IDX.GetNode())->IsStartNode() || HasMark() )
		{
			// Tabelle allein in einem FlyFrame oder Selektion,
			// dann verbleibe auf der alten Position
			if( bChgCrsr )
				RestoreSavePos();
#if defined( UNX )
			delete pCellStt;
#endif
			return sal_True;        // Crsr bleibt an der alten Position
		}
		else if( pNd->StartOfSectionNode()->IsTableNode() && IDX-- )
			goto GoPrevCell;

		bProt = sal_False;		// Index steht jetzt auf einem ContentNode
		goto SetPrevCrsr;
	}
}

// sal_True: an die Position kann der Cursor gesetzt werden
sal_Bool SwCursor::IsAtValidPos( sal_Bool bPoint ) const
{
	const SwDoc* pDoc = GetDoc();
	const SwPosition* pPos = bPoint ? GetPoint() : GetMark();
	const SwNode* pNd = &pPos->nNode.GetNode();

	if( pNd->IsCntntNode() && !((SwCntntNode*)pNd)->getLayoutFrm( pDoc->GetCurrentLayout() ) &&
        !dynamic_cast<const SwUnoCrsr*>(this) )
    {
		return sal_False;
    }

		//JP 28.10.97: Bug 45129 - im UI-ReadOnly ist alles erlaubt
	if( !pDoc->GetDocShell() || !pDoc->GetDocShell()->IsReadOnlyUI() )
		return sal_True;

	sal_Bool bCrsrInReadOnly = IsReadOnlyAvailable();
	if( !bCrsrInReadOnly && pNd->IsProtect() )
		return sal_False;

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

	return sal_True;
}

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

// setze den SRange fuer das Suchen im Dokument
SwMoveFnCollection* SwCursor::MakeFindRange( SwDocPositions nStart,
								SwDocPositions nEnd, SwPaM* pRange ) const
{
	pRange->SetMark();
	FillFindPos( nStart, *pRange->GetMark() );
	FillFindPos( nEnd, *pRange->GetPoint() );

	// bestimme die Richtung, in der zu suchen ist
	// ( GetPoint > GetMark -> vorwaerts, sonst rueckwaerts )
	return ( DOCPOS_START == nStart || DOCPOS_OTHERSTART == nStart ||
			  (DOCPOS_CURR == nStart &&
				(DOCPOS_END == nEnd || DOCPOS_OTHEREND == nEnd ) ))
				? fnMoveForward : fnMoveBackward;
}


sal_uLong lcl_FindSelection( SwFindParas& rParas, SwCursor* pCurCrsr,
						SwMoveFn fnMove, SwCursor*& pFndRing,
						SwPaM& aRegion, FindRanges eFndRngs,
                        sal_Bool bInReadOnly, sal_Bool& bCancel )
{
	SwDoc* pDoc = pCurCrsr->GetDoc();
    bool const bDoesUndo = pDoc->GetIDocumentUndoRedo().DoesUndo();
	int nFndRet = 0;
	sal_uLong nFound = 0;
	int bSrchBkwrd = fnMove == fnMoveBackward, bEnde = sal_False;
	SwPaM *pTmpCrsr = pCurCrsr, *pSaveCrsr = pCurCrsr;

    // only create progress-bar for ShellCrsr
    bool bIsUnoCrsr = 0 != dynamic_cast<SwUnoCrsr*>(pCurCrsr);
	_PercentHdl* pPHdl = 0;
	sal_uInt16 nCrsrCnt = 0;
	if( FND_IN_SEL & eFndRngs )
	{
		while( pCurCrsr != ( pTmpCrsr = (SwPaM*)pTmpCrsr->GetNext() ))
			++nCrsrCnt;
		if( nCrsrCnt && !bIsUnoCrsr )
			pPHdl = new _PercentHdl( 0, nCrsrCnt, pDoc->GetDocShell() );
	}
    else
        pSaveCrsr = (SwPaM*)pSaveCrsr->GetPrev();

	do {
		aRegion.SetMark();
		// egal in welche Richtung, SPoint ist immer groesser als Mark,
		// wenn der Suchbereich gueltig ist !!
		SwPosition *pSttPos = aRegion.GetMark(),
						*pEndPos = aRegion.GetPoint();
		*pSttPos = *pTmpCrsr->Start();
		*pEndPos = *pTmpCrsr->End();
		if( bSrchBkwrd )
			aRegion.Exchange();

		if( !nCrsrCnt && !pPHdl && !bIsUnoCrsr )
			pPHdl = new _PercentHdl( aRegion );

		// solange gefunden und nicht auf gleicher Position haengen bleibt
		while(  *pSttPos <= *pEndPos &&
				0 != ( nFndRet = rParas.Find( pCurCrsr, fnMove,
											&aRegion, bInReadOnly )) &&
				( !pFndRing ||
					*pFndRing->GetPoint() != *pCurCrsr->GetPoint() ||
					*pFndRing->GetMark() != *pCurCrsr->GetMark() ))
		{
			if( !( FIND_NO_RING & nFndRet ))
			{
				// Bug 24084: Ring richtig herum aufbauen -> gleiche Mimik
				//			  wie beim CreateCrsr !!!!

				SwCursor* pNew = pCurCrsr->Create( pFndRing );
				if( !pFndRing )
					pFndRing = pNew;

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

			++nFound;

			if( !( eFndRngs & FND_IN_SELALL) )
			{
				bEnde = sal_True;
				break;
			}

            if ((coSrchRplcThreshold == nFound)
                && pDoc->GetIDocumentUndoRedo().DoesUndo()
                && rParas.IsReplaceMode())
            {
                short nRet = pCurCrsr->MaxReplaceArived();
                if( RET_YES == nRet )
                {
                    pDoc->GetIDocumentUndoRedo().DelAllUndoObj();
                    pDoc->GetIDocumentUndoRedo().DoUndo(false);
                }
                else
                {
                    bEnde = sal_True;
                    if(RET_CANCEL == nRet)
                    {
                        bCancel = sal_True;
                        //unwind() ??
                    }
                    break;
                }
            }

			if( bSrchBkwrd )
				// bewege pEndPos vor den gefundenen Bereich
				*pEndPos = *pCurCrsr->Start();
			else
				// bewege pSttPos hinter den gefundenen Bereich
				*pSttPos = *pCurCrsr->End();

			if( *pSttPos == *pEndPos )		// im Bereich, aber am Ende
				break;						// fertig

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

		if( bEnde || !( eFndRngs & ( FND_IN_SELALL | FND_IN_SEL )) )
			break;

		pTmpCrsr = ((SwPaM*)pTmpCrsr->GetNext());
        if( nCrsrCnt && pPHdl )
        {
			pPHdl->NextPos( ++pPHdl->nActPos );
        }

	} while( pTmpCrsr != pSaveCrsr );

	if( nFound && !pFndRing )		// falls kein Ring aufgebaut werden soll
		pFndRing = pCurCrsr->Create();

	delete pPHdl;
    pDoc->GetIDocumentUndoRedo().DoUndo(bDoesUndo);
	return nFound;
}


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

	SwNodes& rNds = rPam.GetDoc()->GetNodes();
	rPam.DeleteMark();
	SwCntntNode* pCNd;
	if( !bFirst )
	{
		rPam.GetPoint()->nNode = rSttNd;
		pCNd = rNds.GoNext( &rPam.GetPoint()->nNode );
		if( !pCNd )
			return sal_False;
		pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
	}
	else if( rSttNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() ||
			 rPam.GetPoint()->nNode.GetIndex() >= rEndNd.GetIndex() )
		return sal_False;		// steht nicht in dieser Section

	rPam.SetMark();
	rPam.GetPoint()->nNode = rEndNd;
	pCNd = rNds.GoPrevious( &rPam.GetPoint()->nNode );
	if( !pCNd )
		return sal_False;
	pCNd->MakeEndIndex( &rPam.GetPoint()->nContent );

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


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

	SwNodes& rNds = rPam.GetDoc()->GetNodes();
	rPam.DeleteMark();
	SwCntntNode* pCNd;
	if( !bFirst )
	{
		rPam.GetPoint()->nNode = rSttNd;
		pCNd = rNds.GoPrevious( &rPam.GetPoint()->nNode );
		if( !pCNd )
			return sal_False;
		pCNd->MakeEndIndex( &rPam.GetPoint()->nContent );
	}
	else if( rEndNd.GetIndex() > rPam.GetPoint()->nNode.GetIndex() ||
			 rPam.GetPoint()->nNode.GetIndex() >= rSttNd.GetIndex() )
		return sal_False;		// steht nicht in dieser Section

	rPam.SetMark();
	rPam.GetPoint()->nNode = rEndNd;
	pCNd = rNds.GoNext( &rPam.GetPoint()->nNode );
	if( !pCNd )
		return sal_False;
	pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );

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


// diese Methode "sucht" fuer alle Anwendungsfaelle, denn in SwFindParas
// steht immer die richtigen Parameter und die entsprechende Find-Methode

sal_uLong SwCursor::FindAll( SwFindParas& rParas,
							SwDocPositions nStart, SwDocPositions nEnde,
                            FindRanges eFndRngs, sal_Bool& bCancel )
{
    bCancel = sal_False;
    SwCrsrSaveState aSaveState( *this );

	// Region erzeugen, ohne das diese in den Ring aufgenommen wird !
	SwPaM aRegion( *GetPoint() );
	SwMoveFn fnMove = MakeFindRange( nStart, nEnde, &aRegion );

	sal_uLong nFound = 0;
	int bMvBkwrd = fnMove == fnMoveBackward;
	sal_Bool bInReadOnly = IsReadOnlyAvailable();

	SwCursor* pFndRing = 0;
	SwNodes& rNds = GetDoc()->GetNodes();

	// suche in Bereichen ?
	if( FND_IN_SEL & eFndRngs )
	{
		// String nicht im Bereich gefunden, dann erhalte alle Bereiche,
		// der Cursor beleibt unveraendert
		if( 0 == ( nFound = lcl_FindSelection( rParas, this, fnMove,
												pFndRing, aRegion, eFndRngs,
                                                bInReadOnly, bCancel ) ))
			return nFound;

		// der String wurde ein- bis mehrmals gefunden. Das steht alles
		// im neuen Crsr-Ring. Darum hebe erstmal den alten Ring auf
		while( GetNext() != this )
			delete GetNext();

		*GetPoint() = *pFndRing->GetPoint();
		SetMark();
		*GetMark() = *pFndRing->GetMark();
		pFndRing->MoveRingTo( this );
		delete pFndRing;
	}
	else if( FND_IN_OTHER & eFndRngs )
	{
		// Cursor als Kopie vom akt. und in den Ring aufnehmen
		// Verkettung zeigt immer auf den zuerst erzeugten, also vorwaerts
		std::auto_ptr< SwCursor > pSav( Create( this ) ); 	// save the current cursor

		// wenn schon ausserhalb vom Bodytext, suche von der Position,
		// ansonsten beginne mit der 1. GrundSection
		if( bMvBkwrd
			? lcl_MakeSelBkwrd( rNds.GetEndOfExtras(),
					*rNds.GetEndOfPostIts().StartOfSectionNode(),
					 *this, rNds.GetEndOfExtras().GetIndex() >=
					GetPoint()->nNode.GetIndex() )
			: lcl_MakeSelFwrd( *rNds.GetEndOfPostIts().StartOfSectionNode(),
					rNds.GetEndOfExtras(), *this,
					rNds.GetEndOfExtras().GetIndex() >=
					GetPoint()->nNode.GetIndex() ))
		{
			nFound = lcl_FindSelection( rParas, this, fnMove, pFndRing,
                                        aRegion, eFndRngs, bInReadOnly, bCancel );
		}

		if( !nFound )
		{
			// den alten wieder zurueck
			*GetPoint() = *pSav->GetPoint();
			if( pSav->HasMark() )
			{
				SetMark();
				*GetMark() = *pSav->GetMark();
			}
			else
				DeleteMark();
			return 0;
		}
        pSav.release();

		if( !( FND_IN_SELALL & eFndRngs ))
		{
			// es sollte nur einer gesucht werden, also fuege in dazu
			// egal in welche Richtung, SPoint ist immer groesser als Mark,
			// wenn der Suchbereich gueltig ist !!
			*GetPoint() = *pFndRing->GetPoint();
			SetMark();
			*GetMark() = *pFndRing->GetMark();
		}
		else
		{
			// es  wurde ein- bis mehrmals gefunden. Das steht alles
			// im neuen Crsr-Ring. Darum hebe erstmal den alten Ring auf
			while( GetNext() != this )
				delete GetNext();

			*GetPoint() = *pFndRing->GetPoint();
			SetMark();
			*GetMark() = *pFndRing->GetMark();
			pFndRing->MoveRingTo( this );
		}
		delete pFndRing;
	}
	else if( FND_IN_SELALL & eFndRngs )
	{
		::std::auto_ptr< SwCursor> pSav( Create( this ) ); 	// save the current cursor

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

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

		if( !nFound )
		{
			// den alten wieder zurueck
			*GetPoint() = *pSav->GetPoint();
			if( pSav->HasMark() )
			{
				SetMark();
				*GetMark() = *pSav->GetMark();
			}
			else
				DeleteMark();
			return 0;
		}
        pSav.release();
		while( GetNext() != this )
			delete GetNext();

		*GetPoint() = *pFndRing->GetPoint();
		SetMark();
		*GetMark() = *pFndRing->GetMark();
		pFndRing->MoveRingTo( this );
		delete pFndRing;
	}
	else
	{
		// ist ein GetMark gesetzt, dann wird bei gefundenem Object
		// der GetMark beibehalten !! Dadurch kann ein Bereich mit der Suche
		// aufgespannt werden.
		SwPosition aMarkPos( *GetMark() );
		int bMarkPos = HasMark() && !eFndRngs;

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

    if( nFound && SwCursor::IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE ) )
        nFound = 0;
	return nFound;
}


void SwCursor::FillFindPos( SwDocPositions ePos, SwPosition& rPos ) const
{
	sal_Bool bIsStart = sal_True;
	SwCntntNode* pCNd = 0;
	SwNodes& rNds = GetDoc()->GetNodes();

	switch( ePos )
	{
	case DOCPOS_START:
		rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode();
		pCNd = rNds.GoNext( &rPos.nNode );
		break;

	case DOCPOS_END:
		rPos.nNode = rNds.GetEndOfContent();
		pCNd = rNds.GoPrevious( &rPos.nNode );
		bIsStart = sal_False;
		break;

	case DOCPOS_OTHERSTART:
		rPos.nNode = *rNds[ sal_uLong(0) ];
		pCNd = rNds.GoNext( &rPos.nNode );
		break;

	case DOCPOS_OTHEREND:
		rPos.nNode = *rNds.GetEndOfContent().StartOfSectionNode();
		pCNd = rNds.GoPrevious( &rPos.nNode );
		bIsStart = sal_False;
		break;

//	case DOCPOS_CURR:
	default:
		rPos = *GetPoint();
	}

	if( pCNd )
	{
		xub_StrLen nCPos = 0;
		if( !bIsStart )
			nCPos = pCNd->Len();
		rPos.nContent.Assign( pCNd, nCPos );
	}
}

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


sal_Bool SwCursor::IsStartWord( sal_Int16 nWordType ) const
{
    return IsStartWordWT( nWordType );
}

sal_Bool SwCursor::IsEndWord( sal_Int16 nWordType ) const
{
    return IsEndWordWT( nWordType );
}

sal_Bool SwCursor::IsInWord( sal_Int16 nWordType ) const
{
    return IsInWordWT( nWordType );
}

sal_Bool SwCursor::GoStartWord()
{
    return GoStartWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
}

sal_Bool SwCursor::GoEndWord()
{
    return GoEndWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
}

sal_Bool SwCursor::GoNextWord()
{
    return GoNextWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
}

sal_Bool SwCursor::GoPrevWord()
{
    return GoPrevWordWT( WordType::ANYWORD_IGNOREWHITESPACES );
}

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

sal_Bool SwCursor::IsStartWordWT( sal_Int16 nWordType ) const
{
	sal_Bool bRet = sal_False;
	const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
	if( pTxtNd && pBreakIt->GetBreakIter().is() )
	{
		xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
		bRet = pBreakIt->GetBreakIter()->isBeginWord(
							pTxtNd->GetTxt(), nPtPos,
							pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos )),
                            nWordType );
	}
	return bRet;
}

sal_Bool SwCursor::IsEndWordWT( sal_Int16 nWordType ) const
{
	sal_Bool bRet = sal_False;
	const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
	if( pTxtNd && pBreakIt->GetBreakIter().is() )
	{
		xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
		bRet = pBreakIt->GetBreakIter()->isEndWord(
							pTxtNd->GetTxt(), nPtPos,
							pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
                            nWordType );

	}
	return bRet;
}

sal_Bool SwCursor::IsInWordWT( sal_Int16 nWordType ) const
{
    sal_Bool bRet = sal_False;
	const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
	if( pTxtNd && pBreakIt->GetBreakIter().is() )
	{
		xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
        Boundary aBoundary = pBreakIt->GetBreakIter()->getWordBoundary(
							pTxtNd->GetTxt(), nPtPos,
							pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
                            nWordType,
                            sal_True );

        bRet = aBoundary.startPos != aBoundary.endPos &&
                aBoundary.startPos <= nPtPos &&
                    nPtPos <= aBoundary.endPos;
        if(bRet)
        {
            const CharClass& rCC = GetAppCharClass();
            bRet = rCC.isLetterNumeric( pTxtNd->GetTxt(), static_cast<xub_StrLen>(aBoundary.startPos) );
        }
	}
	return bRet;
}

sal_Bool SwCursor::IsStartEndSentence( bool bEnd ) const
{
    sal_Bool bRet = bEnd ?
                    GetCntntNode() && GetPoint()->nContent == GetCntntNode()->Len() :
                    GetPoint()->nContent.GetIndex() == 0;

    if( !bRet )
    {
        SwCursor aCrsr(*GetPoint(), 0, false);
        SwPosition aOrigPos = *aCrsr.GetPoint();
        aCrsr.GoSentence( bEnd ? SwCursor::END_SENT : SwCursor::START_SENT );
        bRet = aOrigPos == *aCrsr.GetPoint();
    }

    return bRet;
}

sal_Bool SwCursor::GoStartWordWT( sal_Int16 nWordType )
{
	sal_Bool bRet = sal_False;
	const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
	if( pTxtNd && pBreakIt->GetBreakIter().is() )
	{
		SwCrsrSaveState aSave( *this );
		xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
		nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->getWordBoundary(
							pTxtNd->GetTxt(), nPtPos,
							pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
                            nWordType,
							sal_False ).startPos;

        if( nPtPos < pTxtNd->GetTxt().Len() )
		{
			GetPoint()->nContent = nPtPos;
			if( !IsSelOvr() )
				bRet = sal_True;
		}
	}
	return bRet;
}

sal_Bool SwCursor::GoEndWordWT( sal_Int16 nWordType )
{
	sal_Bool bRet = sal_False;
	const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
	if( pTxtNd && pBreakIt->GetBreakIter().is() )
	{
		SwCrsrSaveState aSave( *this );
		xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
		nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->getWordBoundary(
							pTxtNd->GetTxt(), nPtPos,
							pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
                            nWordType,
							sal_True ).endPos;

        if( nPtPos <= pTxtNd->GetTxt().Len() &&
			GetPoint()->nContent.GetIndex() != nPtPos )
		{
			GetPoint()->nContent = nPtPos;
			if( !IsSelOvr() )
				bRet = sal_True;
		}
	}
	return bRet;
}

sal_Bool SwCursor::GoNextWordWT( sal_Int16 nWordType )
{
	sal_Bool bRet = sal_False;
	const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
	if( pTxtNd && pBreakIt->GetBreakIter().is() )
	{
		SwCrsrSaveState aSave( *this );
		xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();

		nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->nextWord(
								pTxtNd->GetTxt(), nPtPos,
            pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos, 1 ) ),
                    nWordType ).startPos;

        if( nPtPos < pTxtNd->GetTxt().Len() )
		{
			GetPoint()->nContent = nPtPos;
			if( !IsSelOvr() )
				bRet = sal_True;
		}
	}
	return bRet;
}

sal_Bool SwCursor::GoPrevWordWT( sal_Int16 nWordType )
{
	sal_Bool bRet = sal_False;
	const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
	if( pTxtNd && pBreakIt->GetBreakIter().is() )
	{
		SwCrsrSaveState aSave( *this );
		xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
        const xub_StrLen nPtStart = nPtPos;

        if( nPtPos )
            --nPtPos;
		nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->previousWord(
                                pTxtNd->GetTxt(), nPtStart,
            pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos, 1 ) ),
                    nWordType ).startPos;

        if( nPtPos < pTxtNd->GetTxt().Len() )
		{
			GetPoint()->nContent = nPtPos;
			if( !IsSelOvr() )
				bRet = sal_True;
		}
	}
	return bRet;
}

sal_Bool SwCursor::SelectWordWT( ViewShell* pViewShell, sal_Int16 nWordType, const Point* pPt )
{
	SwCrsrSaveState aSave( *this );

	sal_Bool bRet = sal_False;
	sal_Bool bForward = sal_True;
	DeleteMark();
	const SwRootFrm* pLayout = pViewShell->GetLayout();
	if( pPt && 0 != pLayout )
	{
		// set the cursor to the layout position
		Point aPt( *pPt );
		pLayout->GetCrsrOfst( GetPoint(), aPt );
	}	//swmod 071107//swmod 071225

	const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
	if( pTxtNd && pBreakIt->GetBreakIter().is() )
	{
		xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
		Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary(
							pTxtNd->GetTxt(), nPtPos,
							pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ),
                            nWordType,
							bForward ));

		if( aBndry.startPos != aBndry.endPos )
		{
			GetPoint()->nContent = (xub_StrLen)aBndry.endPos;
			if( !IsSelOvr() )
			{
				SetMark();
				GetMark()->nContent = (xub_StrLen)aBndry.startPos;
				if( !IsSelOvr() )
					bRet = sal_True;
			}
		}
	}

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

//-----------------------------------------------------------------------------

static String lcl_MaskDeletedRedlines( const SwTxtNode* pTxtNd )
{
    String aRes;
	if (pTxtNd)
	{
        //mask deleted redlines
        String sNodeText(pTxtNd->GetTxt());
        const SwDoc& rDoc = *pTxtNd->GetDoc();
        const bool nShowChg = IDocumentRedlineAccess::IsShowChanges( rDoc.GetRedlineMode() );
        if ( nShowChg )
        {
            sal_uInt16 nAct = rDoc.GetRedlinePos( *pTxtNd, USHRT_MAX );
            for ( ; nAct < rDoc.GetRedlineTbl().Count(); nAct++ )
            {
                const SwRedline* pRed = rDoc.GetRedlineTbl()[ nAct ];
                if ( pRed->Start()->nNode > pTxtNd->GetIndex() )
                    break;

                if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
                {
                    xub_StrLen nStart, nEnd;
                    pRed->CalcStartEnd( pTxtNd->GetIndex(), nStart, nEnd );

                    while ( nStart < nEnd && nStart < sNodeText.Len() )
                        sNodeText.SetChar( nStart++, CH_TXTATR_INWORD );
                }
            }
        }
        aRes = sNodeText;
    }
    return aRes;
}

sal_Bool SwCursor::GoSentence( SentenceMoveType eMoveType )
{
	sal_Bool bRet = sal_False;
	const SwTxtNode* pTxtNd = GetNode()->GetTxtNode();
	if( pTxtNd && pBreakIt->GetBreakIter().is() )
	{
        String sNodeText( lcl_MaskDeletedRedlines( pTxtNd ) );

        SwCrsrSaveState aSave( *this );
		xub_StrLen nPtPos = GetPoint()->nContent.GetIndex();
		switch ( eMoveType )
		{
		case START_SENT: /* when modifying: see also ExpandToSentenceBorders below! */
			nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
                                    sNodeText,
									nPtPos, pBreakIt->GetLocale(
											pTxtNd->GetLang( nPtPos ) ));
			break;
		case END_SENT: /* when modifying: see also ExpandToSentenceBorders below! */
            nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence(
                                    sNodeText,
                                    nPtPos, pBreakIt->GetLocale(
                                                pTxtNd->GetLang( nPtPos ) ));
			break;
		case NEXT_SENT:
			{
				nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence(
                                        sNodeText,
										nPtPos, pBreakIt->GetLocale(
													pTxtNd->GetLang( nPtPos ) ));
                while (nPtPos != (sal_uInt16) -1 && ++nPtPos < sNodeText.Len()
                       && sNodeText.GetChar(nPtPos)== ' ' /*isWhiteSpace( aTxt.GetChar(nPtPos)*/ )
					;
				break;
			}
		case PREV_SENT:
			nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
                                    sNodeText,
                                    nPtPos, pBreakIt->GetLocale(
                                                pTxtNd->GetLang( nPtPos ) ));
			if (nPtPos == 0)
				return sal_False;	// the previous sentence is not in this paragraph
			if (nPtPos > 0)
				nPtPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
                                    sNodeText,
                                    nPtPos - 1, pBreakIt->GetLocale(
                                                pTxtNd->GetLang( nPtPos ) ));
			break;
		}

		// it is allowed to place the PaM just behind the last
		// character in the text thus <= ...Len
        if( nPtPos <= pTxtNd->GetTxt().Len() )
		{
			GetPoint()->nContent = nPtPos;
			if( !IsSelOvr() )
				bRet = sal_True;
		}
	}
	return bRet;
}


sal_Bool SwCursor::ExpandToSentenceBorders()
{
    sal_Bool bRes = sal_False;
	const SwTxtNode* pStartNd = Start()->nNode.GetNode().GetTxtNode();
	const SwTxtNode* pEndNd   = End()->nNode.GetNode().GetTxtNode();
	if (pStartNd && pEndNd && pBreakIt->GetBreakIter().is())
	{
        if (!HasMark())
            SetMark();

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

        SwCrsrSaveState aSave( *this );
		xub_StrLen nStartPos = Start()->nContent.GetIndex();
		xub_StrLen nEndPos   = End()->nContent.GetIndex();

        nStartPos = (xub_StrLen)pBreakIt->GetBreakIter()->beginOfSentence(
                                sStartText, nStartPos, 
                                pBreakIt->GetLocale( pStartNd->GetLang( nStartPos ) ) );
		nEndPos   = (xub_StrLen)pBreakIt->GetBreakIter()->endOfSentence(
                                sEndText, nEndPos, 
                                pBreakIt->GetLocale( pEndNd->GetLang( nEndPos ) ) );

		// it is allowed to place the PaM just behind the last
		// character in the text thus <= ...Len
        bool bChanged = false;
        if (nStartPos <= pStartNd->GetTxt().Len())
		{
			GetMark()->nContent = nStartPos;
            bChanged = true;
		}
        if (nEndPos <= pEndNd->GetTxt().Len())
		{
			GetPoint()->nContent = nEndPos;
            bChanged = true;
		}
		if (bChanged && !IsSelOvr())
            bRes = sal_True;
    }
    return bRes;
}


sal_Bool SwTableCursor::LeftRight( sal_Bool bLeft, sal_uInt16 nCnt, sal_uInt16 /*nMode*/,
    sal_Bool /*bVisualAllowed*/, sal_Bool /*bSkipHidden*/, sal_Bool /*bInsertCrsr*/ )
{
    return bLeft ? GoPrevCell( nCnt )
                 : GoNextCell( nCnt );
}


// calculate cursor bidi level: extracted from LeftRight()
const SwCntntFrm*
SwCursor::DoSetBidiLevelLeftRight(
    sal_Bool & io_rbLeft, sal_Bool bVisualAllowed, sal_Bool bInsertCrsr)
{
    // calculate cursor bidi level
    const SwCntntFrm* pSttFrm = NULL;
    SwNode& rNode = GetPoint()->nNode.GetNode();

    if( rNode.IsTxtNode() )
    {
        const SwTxtNode& rTNd = *rNode.GetTxtNode();
        SwIndex& rIdx = GetPoint()->nContent;
        xub_StrLen nPos = rIdx.GetIndex();

        const SvtCTLOptions& rCTLOptions = SW_MOD()->GetCTLOptions();
        if ( bVisualAllowed && rCTLOptions.IsCTLFontEnabled() &&
             SvtCTLOptions::MOVEMENT_VISUAL ==
             rCTLOptions.GetCTLCursorMovement() )
        {
            // for visual cursor travelling (used in bidi layout)
            // we first have to convert the logic to a visual position
            Point aPt;
            pSttFrm = rTNd.getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
            if( pSttFrm )
            {
                sal_uInt8 nCrsrLevel = GetCrsrBidiLevel();
                sal_Bool bForward = ! io_rbLeft;
                ((SwTxtFrm*)pSttFrm)->PrepareVisualMove( nPos, nCrsrLevel,
                                                         bForward, bInsertCrsr );
                rIdx = nPos;
                SetCrsrBidiLevel( nCrsrLevel );
                io_rbLeft = ! bForward;
            }
        }
        else
        {
            const SwScriptInfo* pSI = SwScriptInfo::GetScriptInfo( rTNd );
            if ( pSI )
            {
                const xub_StrLen nMoveOverPos = io_rbLeft ?
                                               ( nPos ? nPos - 1 : 0 ) :
                                                nPos;
                SetCrsrBidiLevel( pSI->DirType( nMoveOverPos ) );
            }
        }
    }
    return pSttFrm;
}

sal_Bool SwCursor::LeftRight( sal_Bool bLeft, sal_uInt16 nCnt, sal_uInt16 nMode,
                          sal_Bool bVisualAllowed,sal_Bool bSkipHidden, sal_Bool bInsertCrsr )
{
    // calculate cursor bidi level
    SwNode& rNode = GetPoint()->nNode.GetNode();
    const SwCntntFrm* pSttFrm = // may side-effect bLeft!
        DoSetBidiLevelLeftRight(bLeft, bVisualAllowed, bInsertCrsr);

	// kann der Cursor n-mal weiterverschoben werden ?
    SwCrsrSaveState aSave( *this );
    SwMoveFn fnMove = bLeft ? fnMoveBackward : fnMoveForward;

    SwGoInDoc fnGo;
    if ( bSkipHidden )
        fnGo = CRSR_SKIP_CELLS == nMode ? fnGoCntntCellsSkipHidden : fnGoCntntSkipHidden;
    else
        fnGo = CRSR_SKIP_CELLS == nMode ? fnGoCntntCells : fnGoCntnt;

    // ASSERT( not in covered cell )

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

        bool bSuccess = Move( fnMove, fnGo );
        if ( !bSuccess )
            break;

        // 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 ( mnRowSpanOffset )
        {
            const SwNode* pOldTabBoxSttNode = aOldNodeIdx.GetNode().FindTableBoxStartNode();
            const SwTableNode* pOldTabSttNode = pOldTabBoxSttNode ? pOldTabBoxSttNode->FindTableNode() : 0;
            const SwNode* pNewTabBoxSttNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode();
            const SwTableNode* pNewTabSttNode = pNewTabBoxSttNode ? pNewTabBoxSttNode->FindTableNode() : 0;

            const bool bCellChanged = pOldTabSttNode && pNewTabSttNode &&
                                      pOldTabSttNode == pNewTabSttNode &&
                                      pOldTabBoxSttNode && pNewTabBoxSttNode &&
                                      pOldTabBoxSttNode != pNewTabBoxSttNode;

            if ( bCellChanged )
            {
                // Set cursor to start/end of covered cell:
                SwTableBox* pTableBox = pOldTabBoxSttNode->GetTblBox();
                const long nRowSpan = pTableBox->getRowSpan();
                if ( nRowSpan > 1 )
                {
                    pTableBox = & pTableBox->FindEndOfRowSpan( pOldTabSttNode->GetTable(), (sal_uInt16)(pTableBox->getRowSpan() + mnRowSpanOffset ) );
            	    SwNodeIndex& rPtIdx = GetPoint()->nNode;
                    SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
                    rPtIdx = aNewIdx;

                    GetDoc()->GetNodes().GoNextSection( &rPtIdx, sal_False, sal_False );
                    SwCntntNode* pCntntNode = GetCntntNode();
                    if ( pCntntNode )
                    {
                        const xub_StrLen nTmpPos = bLeft ? pCntntNode->Len() : 0;
		        		GetPoint()->nContent.Assign( pCntntNode, nTmpPos );

                        // Redo the move:
                        bSuccess = Move( fnMove, fnGo );
                        if ( !bSuccess )
                            break;
                    }
                }

                mnRowSpanOffset = 0;
            }
        }

        // Check if I'm inside a covered cell. Correct cursor if necessary and
        // store covered cell:
        const SwNode* pTableBoxStartNode = GetPoint()->nNode.GetNode().FindTableBoxStartNode();
        if ( pTableBoxStartNode )
        {
            const SwTableBox* pTableBox = pTableBoxStartNode->GetTblBox();
            if ( pTableBox->getRowSpan() < 1 )
            {
                // Store the row span offset:
                mnRowSpanOffset = pTableBox->getRowSpan();

                // Move cursor to non-covered cell:
                const SwTableNode* pTblNd = pTableBoxStartNode->FindTableNode();
                pTableBox = & pTableBox->FindStartOfRowSpan( pTblNd->GetTable(), USHRT_MAX );
         	    SwNodeIndex& rPtIdx = GetPoint()->nNode;
                SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
                rPtIdx = aNewIdx;

                GetDoc()->GetNodes().GoNextSection( &rPtIdx, sal_False, sal_False );
                SwCntntNode* pCntntNode = GetCntntNode();
                if ( pCntntNode )
                {
                    const xub_StrLen nTmpPos = bLeft ? pCntntNode->Len() : 0;
               		GetPoint()->nContent.Assign( pCntntNode, nTmpPos );
                }
            }
        }

        --nCnt;
    }

    // here come some special rules for visual cursor travelling
    if ( pSttFrm )
    {
        SwNode& rTmpNode = GetPoint()->nNode.GetNode();
        if ( &rTmpNode != &rNode && rTmpNode.IsTxtNode() )
        {
            Point aPt;
            const SwCntntFrm* pEndFrm = ((SwTxtNode&)rTmpNode).getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
            if ( pEndFrm )
            {
                if ( ! pEndFrm->IsRightToLeft() != ! pSttFrm->IsRightToLeft() )
                {
                    if ( ! bLeft )
                        pEndFrm->RightMargin( this );
                    else
                        pEndFrm->LeftMargin( this );
                }
            }
        }
    }

	return 0 == nCnt && !IsInProtectTable( sal_True ) &&
            !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
                       nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
}

// calculate cursor bidi level: extracted from UpDown()
void SwCursor::DoSetBidiLevelUpDown()
{
    SwNode& rNode = GetPoint()->nNode.GetNode();
    if ( rNode.IsTxtNode() )
    {
        const SwScriptInfo* pSI =
            SwScriptInfo::GetScriptInfo( (SwTxtNode&)rNode );
        if ( pSI )
        {
            SwIndex& rIdx = GetPoint()->nContent;
            xub_StrLen nPos = rIdx.GetIndex();

            if( nPos && nPos < ((SwTxtNode&)rNode).GetTxt().Len() )
            {
                const sal_uInt8 nCurrLevel = pSI->DirType( nPos );
                const sal_uInt8 nPrevLevel = pSI->DirType( nPos - 1 );

                if ( nCurrLevel % 2 != nPrevLevel % 2 )
                {
                    // set cursor level to the lower of the two levels
                    SetCrsrBidiLevel( Min( nCurrLevel, nPrevLevel ) );
                }
                else
                    SetCrsrBidiLevel( nCurrLevel );
            }
        }
    }
}

sal_Bool SwCursor::UpDown( sal_Bool bUp, sal_uInt16 nCnt,
							Point* pPt, long nUpDownX )
{
    SwTableCursor* pTblCrsr = dynamic_cast<SwTableCursor*>(this);
    sal_Bool bAdjustTableCrsr = sal_False;

	// vom Tabellen Crsr Point/Mark in der gleichen Box ??
	// dann stelle den Point an den Anfang der Box
    if( pTblCrsr && GetNode( sal_True )->StartOfSectionNode() ==
                    GetNode( sal_False )->StartOfSectionNode() )
    {
        if ( End() != GetPoint() )
            Exchange();
        bAdjustTableCrsr = sal_True;
    }

	sal_Bool bRet = sal_False;
	Point aPt;
	if( pPt )
		aPt = *pPt;
	SwCntntFrm* pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );

	if( pFrm )
	{
		SwCrsrSaveState aSave( *this );

		if( !pPt )
		{
			SwRect aTmpRect;
			pFrm->GetCharRect( aTmpRect, *GetPoint() );
			aPt = aTmpRect.Pos();

            nUpDownX = pFrm->IsVertical() ?
                aPt.Y() - pFrm->Frm().Top() :
                aPt.X() - pFrm->Frm().Left();
		}

		// Bei Fussnoten ist auch die Bewegung in eine andere Fussnote erlaubt.
		// aber keine Selection!!
		const sal_Bool bChkRange = pFrm->IsInFtn() && !HasMark()
									? sal_False : sal_True;
		const SwPosition aOldPos( *GetPoint() );
		sal_Bool bInReadOnly = IsReadOnlyAvailable();

        if ( bAdjustTableCrsr && !bUp )
        {
            // Special case: We have a table cursor but the start box
            // has more than one paragraph. If we want to go down, we have to
            // set the point to the last frame in the table box. This is
            // only necessary if we do not already have a table selection
            const SwStartNode* pTblNd = GetNode( sal_True )->FindTableBoxStartNode();
            ASSERT( pTblNd, "pTblCrsr without SwTableNode?" )

            if ( pTblNd ) // safety first
            {
                const SwNode* pEndNd = pTblNd->EndOfSectionNode();
                GetPoint()->nNode = *pEndNd;
                pTblCrsr->Move( fnMoveBackward, fnGoNode );
   			    pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
            }
        }

        while( nCnt &&
               (bUp ? pFrm->UnitUp( this, nUpDownX, bInReadOnly )
		            : pFrm->UnitDown( this, nUpDownX, bInReadOnly ) ) &&
    		    CheckNodesRange( aOldPos.nNode, GetPoint()->nNode, bChkRange ))
	    {
   			pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
		    --nCnt;
	    }

        if( !nCnt && !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
                                nsSwCursorSelOverFlags::SELOVER_CHANGEPOS ) )  // die gesamte Anzahl durchlaufen ?
		{
			if( !pTblCrsr )
			{
				// dann versuche den Cursor auf die Position zu setzen,
				// auf halber Heohe vom Char-Rectangle
				pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
				SwCrsrMoveState eTmpState( MV_UPDOWN );
				eTmpState.bSetInReadOnly = bInReadOnly;
				SwRect aTmpRect;
				pFrm->GetCharRect( aTmpRect, *GetPoint(), &eTmpState );
                if ( pFrm->IsVertical() )
                {
                    aPt.X() = aTmpRect.Center().X();
                    pFrm->Calc();
                    aPt.Y() = pFrm->Frm().Top() + nUpDownX;
                }
                else
                {
                    aPt.Y() = aTmpRect.Center().Y();
                    pFrm->Calc();
                    aPt.X() = pFrm->Frm().Left() + nUpDownX;
                }
                pFrm->GetCrsrOfst( GetPoint(), aPt, &eTmpState );
            }
            bRet = !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
        }
        else
            *GetPoint() = aOldPos;

        DoSetBidiLevelUpDown(); // calculate cursor bidi level
    }

	return bRet;
}

sal_Bool SwCursor::LeftRightMargin( sal_Bool bLeft, sal_Bool bAPI )
{
    Point aPt;
    SwCntntFrm * pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );

    // calculate cursor bidi level
    if ( pFrm )
        SetCrsrBidiLevel( pFrm->IsRightToLeft() ? 1 : 0 );

    SwCrsrSaveState aSave( *this );
    return pFrm
           && (bLeft ? pFrm->LeftMargin( this ) : pFrm->RightMargin( this, bAPI ) )
           && !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE | nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
}

sal_Bool SwCursor::IsAtLeftRightMargin( sal_Bool bLeft, sal_Bool bAPI ) const
{
	sal_Bool bRet = sal_False;
	Point aPt;
	SwCntntFrm * pFrm = GetCntntNode()->getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, GetPoint() );
	if( pFrm )
	{
		SwPaM aPam( *GetPoint() );
		if( !bLeft && aPam.GetPoint()->nContent.GetIndex() )
			aPam.GetPoint()->nContent--;
		bRet = (bLeft ? pFrm->LeftMargin( &aPam )
					  : pFrm->RightMargin( &aPam, bAPI ))
				&& *aPam.GetPoint() == *GetPoint();
	}
	return bRet;
}

sal_Bool SwCursor::SttEndDoc( sal_Bool bStt )
{
	SwCrsrSaveState aSave( *this );

	// Springe beim Selektieren nie ueber Section-Grenzen !!
	// kann der Cursor weiterverschoben werden ?
	SwMoveFn fnMove = bStt ? fnMoveBackward : fnMoveForward;
	sal_Bool bRet = (!HasMark() || !IsNoCntnt() ) &&
					Move( fnMove, fnGoDoc ) &&
					!IsInProtectTable( sal_True ) &&
                    !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
                               nsSwCursorSelOverFlags::SELOVER_CHANGEPOS |
                               nsSwCursorSelOverFlags::SELOVER_ENABLEREVDIREKTION );

	return bRet;
}

sal_Bool SwCursor::GoPrevNextCell( sal_Bool bNext, sal_uInt16 nCnt )
{
	const SwTableNode* pTblNd = GetPoint()->nNode.GetNode().FindTableNode();
	if( !pTblNd )
		return sal_False;

	// liegt vor dem StartNode der Cell ein weiterer EndNode, dann
	// gibt es auch eine vorherige Celle
	SwCrsrSaveState aSave( *this );
	SwNodeIndex& rPtIdx = GetPoint()->nNode;

    while( nCnt-- )
	{
        const SwNode* pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
        const SwTableBox* pTableBox = pTableBoxStartNode->GetTblBox();

        // Check if we have to move the cursor to a covered cell before
        // proceeding:
        if ( mnRowSpanOffset )
        {
            if ( pTableBox->getRowSpan() > 1 )
            {
                pTableBox = & pTableBox->FindEndOfRowSpan( pTblNd->GetTable(), (sal_uInt16)(pTableBox->getRowSpan() + mnRowSpanOffset) );
                SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
                rPtIdx = aNewIdx;
                pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
            }
            mnRowSpanOffset = 0;
        }

        const SwNode* pTmpNode = bNext ?
                                 pTableBoxStartNode->EndOfSectionNode() :
                                 pTableBoxStartNode;

        SwNodeIndex aCellIdx( *pTmpNode, bNext ? 1 : -1 );
		if(  (bNext && !aCellIdx.GetNode().IsStartNode()) ||
            (!bNext && !aCellIdx.GetNode().IsEndNode()) )
			return sal_False;

        rPtIdx = bNext ? aCellIdx : SwNodeIndex(*aCellIdx.GetNode().StartOfSectionNode());

        pTableBoxStartNode = rPtIdx.GetNode().FindTableBoxStartNode();
        pTableBox = pTableBoxStartNode->GetTblBox();
        if ( pTableBox->getRowSpan() < 1 )
        {
            mnRowSpanOffset = pTableBox->getRowSpan();
            // move cursor to non-covered cell:
            pTableBox = & pTableBox->FindStartOfRowSpan( pTblNd->GetTable(), USHRT_MAX );
            SwNodeIndex aNewIdx( *pTableBox->GetSttNd() );
            rPtIdx = aNewIdx;
        }
    }

	rPtIdx++;
	if( !rPtIdx.GetNode().IsCntntNode() )
		GetDoc()->GetNodes().GoNextSection( &rPtIdx, sal_True, sal_False );
	GetPoint()->nContent.Assign( GetCntntNode(), 0 );

	return !IsInProtectTable( sal_True );
}

sal_Bool SwTableCursor::GotoTable( const String& /*rName*/ )
{
    return sal_False; // invalid action
}

sal_Bool SwCursor::GotoTable( const String& rName )
{
	sal_Bool bRet = sal_False;
    if ( !HasMark() )
	{
		SwTable* pTmpTbl = SwTable::FindTable( GetDoc()->FindTblFmtByName( rName ) );
		if( pTmpTbl )
		{
			// eine Tabelle im normalen NodesArr
			SwCrsrSaveState aSave( *this );
			GetPoint()->nNode = *pTmpTbl->GetTabSortBoxes()[ 0 ]->
								GetSttNd()->FindTableNode();
			Move( fnMoveForward, fnGoCntnt );
			bRet = !IsSelOvr();
		}
	}
	return bRet;
}

sal_Bool SwCursor::GotoTblBox( const String& rName )
{
	sal_Bool bRet = sal_False;
	const SwTableNode* pTblNd = GetPoint()->nNode.GetNode().FindTableNode();
	if( pTblNd )
	{
		// erfrage die Box, mit dem Nanen
		const SwTableBox* pTblBox = pTblNd->GetTable().GetTblBox( rName );
		if( pTblBox && pTblBox->GetSttNd() &&
			( !pTblBox->GetFrmFmt()->GetProtect().IsCntntProtected() ||
			  IsReadOnlyAvailable() ) )
		{
			SwCrsrSaveState aSave( *this );
			GetPoint()->nNode = *pTblBox->GetSttNd();
			Move( fnMoveForward, fnGoCntnt );
			bRet = !IsSelOvr();
		}
	}
	return bRet;
}

sal_Bool SwCursor::MovePara(SwWhichPara fnWhichPara, SwPosPara fnPosPara )
{
	//JP 28.8.2001: for optimization test something before
    const SwNode* pNd = &GetPoint()->nNode.GetNode();
    bool bShortCut = false;
    if ( fnWhichPara == fnParaCurr )
    {
        // --> FME 2005-02-21 #i41048#
        // If fnWhichPara == fnParaCurr, (*fnWhichPara)( *this, fnPosPara )
        // can already move the cursor to a different text node. In this case
        // we better check if IsSelOvr().
        const SwCntntNode* pCntntNd = pNd->GetCntntNode();
        if ( pCntntNd )
        {
            const xub_StrLen nSttEnd = fnPosPara == fnMoveForward ? 0 : pCntntNd->Len();
            if ( GetPoint()->nContent.GetIndex() != nSttEnd )
                bShortCut = true;
        }
        // <--
    }
    else
    {
        if ( pNd->IsTxtNode() &&
             pNd->GetNodes()[ pNd->GetIndex() +
                    (fnWhichPara == fnParaNext ? 1 : -1 ) ]->IsTxtNode() )
            bShortCut = true;
    }

    if ( bShortCut )
        return (*fnWhichPara)( *this, fnPosPara );

    // else we must use the SaveStructure, because the next/prev is not
	// a same node type.
	SwCrsrSaveState aSave( *this );
	return (*fnWhichPara)( *this, fnPosPara ) &&
			!IsInProtectTable( sal_True ) &&
            !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
                       nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
}


sal_Bool SwCursor::MoveSection( SwWhichSection fnWhichSect,
								SwPosSection fnPosSect)
{
	SwCrsrSaveState aSave( *this );
	return (*fnWhichSect)( *this, fnPosSect ) &&
			!IsInProtectTable( sal_True ) &&
            !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_TOGGLE |
                       nsSwCursorSelOverFlags::SELOVER_CHANGEPOS );
}

/*
	sal_Bool MoveTable( SwWhichTable, SwPosTable );
	sal_Bool MoveColumn( SwWhichColumn, SwPosColumn );
	sal_Bool MoveRegion( SwWhichRegion, SwPosRegion );
*/

void SwCursor::RestoreSavePos()		// Point auf die SavePos setzen
{
	if( pSavePos )
	{
		GetPoint()->nNode = pSavePos->nNode;
		GetPoint()->nContent.Assign( GetCntntNode(), pSavePos->nCntnt );
	}
}


/*  */

SwTableCursor::SwTableCursor( const SwPosition &rPos, SwPaM* pRing )
	: SwCursor( rPos, pRing, false )
{
	bParked = sal_False;
	bChg = sal_False;
	nTblPtNd = 0, nTblMkNd = 0;
	nTblPtCnt = 0, nTblMkCnt = 0;
}

SwTableCursor::~SwTableCursor() {}


sal_Bool lcl_SeekEntry( const SwSelBoxes& rTmp, const SwStartNode* pSrch, sal_uInt16& rFndPos )
{
	sal_uLong nIdx = pSrch->GetIndex();

	sal_uInt16 nO = rTmp.Count(), nM, nU = 0;
	if( nO > 0 )
	{
		nO--;
		while( nU <= nO )
		{
			nM = nU + ( nO - nU ) / 2;
			if( rTmp[ nM ]->GetSttNd() == pSrch )
			{
				rFndPos = nM;
				return sal_True;
			}
			else if( rTmp[ nM ]->GetSttIdx() < nIdx )
				nU = nM + 1;
			else if( nM == 0 )
				return sal_False;
			else
				nO = nM - 1;
		}
	}
	return sal_False;
}


SwCursor* SwTableCursor::MakeBoxSels( SwCursor* pAktCrsr )
{
	if( bChg )		// ???
	{
		if( bParked )
		{
			// wieder in den Inhalt schieben
			Exchange();
			Move( fnMoveForward );
			Exchange();
			Move( fnMoveForward );
			bParked = sal_False;
		}

		bChg = sal_False;

		// temp Kopie anlegen, damit alle Boxen, fuer die schon Cursor
		// existieren, entfernt werden koennen.
		SwSelBoxes aTmp;
		aTmp.Insert( &aSelBoxes );

		//Jetzt die Alten und die neuen abgleichen.
		SwNodes& rNds = pAktCrsr->GetDoc()->GetNodes();
		sal_uInt16 nPos;
		const SwStartNode* pSttNd;
		SwPaM* pCur = pAktCrsr;
		do {
			sal_Bool bDel = sal_False;
			pSttNd = pCur->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
			if( !pCur->HasMark() || !pSttNd ||
				pSttNd != pCur->GetMark()->nNode.GetNode().FindTableBoxStartNode() )
				bDel = sal_True;

			else if( lcl_SeekEntry( aTmp, pSttNd, nPos ))
			{
				SwNodeIndex aIdx( *pSttNd, 1 );
				const SwNode* pNd = &aIdx.GetNode();
				if( !pNd->IsCntntNode() )
					pNd = rNds.GoNextSection( &aIdx, sal_True, sal_False );

				SwPosition* pPos = pCur->GetMark();
				if( pNd != &pPos->nNode.GetNode() )
					pPos->nNode = *pNd;
				pPos->nContent.Assign( (SwCntntNode*)pNd, 0 );

				aIdx.Assign( *pSttNd->EndOfSectionNode(), - 1 );
				if( !( pNd = &aIdx.GetNode())->IsCntntNode() )
					pNd = rNds.GoPrevSection( &aIdx, sal_True, sal_False );

				pPos = pCur->GetPoint();
				if( pNd != &pPos->nNode.GetNode() )
					pPos->nNode = *pNd;
				pPos->nContent.Assign( (SwCntntNode*)pNd, ((SwCntntNode*)pNd)->Len() );

				aTmp.Remove( nPos );
			}
			else
				bDel = sal_True;

			pCur = (SwPaM*)pCur->GetNext();
			if( bDel )
			{
				SwPaM* pDel = (SwPaM*)pCur->GetPrev();
/*
JP 20.07.98: der alte Code geht mit dem UNO-TableCrsr nicht
				if( pDel == pAktCrsr )
				{
					if( pAktCrsr->GetNext() == pAktCrsr )
					{
						pAktCrsr->DeleteMark();
						break;		// es gibt nichts mehr zu loeschen!
					}
					pAktCrsr = (SwCursor*)pDel->GetPrev();
				}
				delete pDel;
*/

				if( pDel == pAktCrsr )
					pAktCrsr->DeleteMark();
				else
					delete pDel;
			}
		} while ( pAktCrsr != pCur );

		for( nPos = 0; nPos < aTmp.Count(); ++nPos )
		{
			pSttNd = aTmp[ nPos ]->GetSttNd();

			SwNodeIndex aIdx( *pSttNd, 1 );
            if( &aIdx.GetNodes() != &rNds )
                break;
			const SwNode* pNd = &aIdx.GetNode();
			if( !pNd->IsCntntNode() )
				pNd = rNds.GoNextSection( &aIdx, sal_True, sal_False );

			SwPaM* pNew;
			if( pAktCrsr->GetNext() == pAktCrsr && !pAktCrsr->HasMark() )
			{
				pNew = pAktCrsr;
				pNew->GetPoint()->nNode = *pNd;
				pNew->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
			}
			else
			{
				pNew = pAktCrsr->Create( pAktCrsr );
				pNew->GetPoint()->nNode = *pNd;
				pNew->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
			}
			pNew->SetMark();

			SwPosition* pPos = pNew->GetPoint();
			pPos->nNode.Assign( *pSttNd->EndOfSectionNode(), - 1 );
			if( !( pNd = &pPos->nNode.GetNode())->IsCntntNode() )
				pNd = rNds.GoPrevSection( &pPos->nNode, sal_True, sal_False );

			pPos->nContent.Assign( (SwCntntNode*)pNd, ((SwCntntNode*)pNd)->Len() );
		}
	}
	return pAktCrsr;
}


void SwTableCursor::InsertBox( const SwTableBox& rTblBox )
{
	SwTableBox* pBox = (SwTableBox*)&rTblBox;
	aSelBoxes.Insert( pBox );
	bChg = sal_True;
}

bool SwTableCursor::NewTableSelection()
{
    bool bRet = false;
	const SwNode *pStart = GetCntntNode()->FindTableBoxStartNode();
	const SwNode *pEnd = GetCntntNode(sal_False)->FindTableBoxStartNode();
    if( pStart && pEnd )
    {
        const SwTableNode *pTableNode = pStart->FindTableNode();
        if( pTableNode == pEnd->FindTableNode() &&
            pTableNode->GetTable().IsNewModel() )
        {
            bRet = true;
            SwSelBoxes aNew;
            aNew.Insert( &aSelBoxes );
            pTableNode->GetTable().CreateSelection( pStart, pEnd, aNew,
                SwTable::SEARCH_NONE, false );
            ActualizeSelection( aNew );
        }
    }
    return bRet;
}

void SwTableCursor::ActualizeSelection( const SwSelBoxes &rNew )
{
    sal_uInt16 nOld = 0, nNew = 0;
    while ( nOld < aSelBoxes.Count() && nNew < rNew.Count() )
    {
        const SwTableBox* pPOld = *( aSelBoxes.GetData() + nOld );
        const SwTableBox* pPNew = *( rNew.GetData() + nNew );
        if( pPOld == pPNew )
        {   // this box will stay
            ++nOld;
            ++nNew;
        }
        else if( pPOld->GetSttIdx() < pPNew->GetSttIdx() )
            DeleteBox( nOld ); // this box has to go
        else
        {
            InsertBox( *pPNew ); // this is a new one
            ++nOld;
            ++nNew;
        }
    }

    while( nOld < aSelBoxes.Count() )
        DeleteBox( nOld ); // some more to delete

    for( ; nNew < rNew.Count(); ++nNew ) // some more to insert
        InsertBox( **( rNew.GetData() + nNew ) );
}

sal_Bool SwTableCursor::IsCrsrMovedUpdt()
{
	if( !IsCrsrMoved() )
		return sal_False;

	nTblMkNd = GetMark()->nNode.GetIndex();
	nTblPtNd = GetPoint()->nNode.GetIndex();
	nTblMkCnt = GetMark()->nContent.GetIndex();
	nTblPtCnt = GetPoint()->nContent.GetIndex();
	return sal_True;
}


// Parke den Tabellen-Cursor auf dem StartNode der Boxen.
void SwTableCursor::ParkCrsr()
{
	// Index aus dem TextNode abmelden
	SwNode* pNd = &GetPoint()->nNode.GetNode();
	if( !pNd->IsStartNode() )
		pNd = pNd->StartOfSectionNode();
	GetPoint()->nNode = *pNd;
	GetPoint()->nContent.Assign( 0, 0 );

	pNd = &GetMark()->nNode.GetNode();
	if( !pNd->IsStartNode() )
		pNd = pNd->StartOfSectionNode();
	GetMark()->nNode = *pNd;
	GetMark()->nContent.Assign( 0, 0 );

	bChg = sal_True;
	bParked = sal_True;
}


sal_Bool SwTableCursor::HasReadOnlyBoxSel() const
{
	sal_Bool bRet = sal_False;
	for( sal_uInt16 n = aSelBoxes.Count(); n;  )
		if( aSelBoxes[ --n ]->GetFrmFmt()->GetProtect().IsCntntProtected() )
		{
			bRet = sal_True;
			break;
		}
	return bRet;
}