blob: d1e6ae4d737bec715dc9430988324d6b01e29e4b [file] [log] [blame]
/**************************************************************
*
* 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 <string.h> // fuer strchr()
#include <hintids.hxx>
#include <vcl/sound.hxx>
#include <editeng/cscoitem.hxx>
#include <editeng/brkitem.hxx>
#include <linguistic/lngprops.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/i18n/WordType.hdl>
#include <unotools/charclass.hxx>
#include <unotools/transliterationwrapper.hxx>
#include <fmtanchr.hxx>
#include <fmtcntnt.hxx>
#include <fmtpdsc.hxx>
#include <txtftn.hxx>
#include <acorrect.hxx> // Autokorrektur
#include <IMark.hxx> // fuer SwBookmark
#include <cntfrm.hxx> // fuers Spell
#include <crsrsh.hxx>
#include <doc.hxx>
#include <UndoManager.hxx>
#include <docsh.hxx>
#include <docary.hxx>
#include <doctxm.hxx> // beim Move: Verzeichnisse korrigieren
#include <ftnidx.hxx>
#include <ftninfo.hxx>
#include <mdiexp.hxx> // Statusanzeige
#include <mvsave.hxx> // Strukturen zum Sichern beim Move/Delete
#include <ndtxt.hxx>
#include <pam.hxx>
#include <redline.hxx>
#include <rootfrm.hxx> // fuers UpdateFtn
#include <splargs.hxx> // fuer Spell
#include <swtable.hxx>
#include <swundo.hxx> // fuer die UndoIds
#include <txtfrm.hxx>
#include <hints.hxx>
#include <UndoSplitMove.hxx>
#include <UndoRedline.hxx>
#include <UndoOverwrite.hxx>
#include <UndoInsert.hxx>
#include <UndoDelete.hxx>
#include <breakit.hxx>
#include <hhcwrp.hxx>
#include <breakit.hxx>
#include <vcl/msgbox.hxx>
#include "comcore.hrc"
#include "editsh.hxx"
#include <fldbas.hxx>
#include <fmtfld.hxx>
#include <docufld.hxx>
#include <unoflatpara.hxx>
#include <SwGrammarMarkUp.hxx>
#include <vector>
using ::rtl::OUString;
using namespace ::com::sun::star;
using namespace ::com::sun::star::linguistic2;
using namespace ::com::sun::star::i18n;
//using namespace ::utl;
#ifndef S2U
#define S2U(rString) OUString::createFromAscii(rString)
#endif
struct _SaveRedline
{
SwRedline* pRedl;
sal_uInt32 nStt, nEnd;
xub_StrLen nSttCnt, nEndCnt;
_SaveRedline( SwRedline* pR, const SwNodeIndex& rSttIdx )
: pRedl( pR )
{
const SwPosition* pStt = pR->Start(),
* pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
sal_uInt32 nSttIdx = rSttIdx.GetIndex();
nStt = pStt->nNode.GetIndex() - nSttIdx;
nSttCnt = pStt->nContent.GetIndex();
if( pR->HasMark() )
{
nEnd = pEnd->nNode.GetIndex() - nSttIdx;
nEndCnt = pEnd->nContent.GetIndex();
}
pRedl->GetPoint()->nNode = 0;
pRedl->GetPoint()->nContent.Assign( 0, 0 );
pRedl->GetMark()->nNode = 0;
pRedl->GetMark()->nContent.Assign( 0, 0 );
}
_SaveRedline( SwRedline* pR, const SwPosition& rPos )
: pRedl( pR )
{
const SwPosition* pStt = pR->Start(),
* pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
sal_uInt32 nSttIdx = rPos.nNode.GetIndex();
nStt = pStt->nNode.GetIndex() - nSttIdx;
nSttCnt = pStt->nContent.GetIndex();
if( nStt == 0 )
nSttCnt = nSttCnt - rPos.nContent.GetIndex();
if( pR->HasMark() )
{
nEnd = pEnd->nNode.GetIndex() - nSttIdx;
nEndCnt = pEnd->nContent.GetIndex();
if( nEnd == 0 )
nEndCnt = nEndCnt - rPos.nContent.GetIndex();
}
pRedl->GetPoint()->nNode = 0;
pRedl->GetPoint()->nContent.Assign( 0, 0 );
pRedl->GetMark()->nNode = 0;
pRedl->GetMark()->nContent.Assign( 0, 0 );
}
void SetPos( sal_uInt32 nInsPos )
{
pRedl->GetPoint()->nNode = nInsPos + nStt;
pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt );
if( pRedl->HasMark() )
{
pRedl->GetMark()->nNode = nInsPos + nEnd;
pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt );
}
}
void SetPos( const SwPosition& aPos )
{
pRedl->GetPoint()->nNode = aPos.nNode.GetIndex() + nStt;
pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt + ( nStt == 0 ? aPos.nContent.GetIndex() : 0 ) );
if( pRedl->HasMark() )
{
pRedl->GetMark()->nNode = aPos.nNode.GetIndex() + nEnd;
pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt + ( nEnd == 0 ? aPos.nContent.GetIndex() : 0 ) );
}
}
};
SV_DECL_PTRARR_DEL( _SaveRedlines, _SaveRedline*, 0, 4 )
SV_IMPL_VARARR( _SaveFlyArr, _SaveFly )
SV_IMPL_PTRARR( _SaveRedlines, _SaveRedline* )
bool lcl_MayOverwrite( const SwTxtNode *pNode, const xub_StrLen nPos )
{
sal_Unicode cChr = pNode->GetTxt().GetChar( nPos );
return !( ( CH_TXTATR_BREAKWORD == cChr || CH_TXTATR_INWORD == cChr ) &&
(0 != pNode->GetTxtAttrForCharAt( nPos ) ) );
}
void lcl_SkipAttr( const SwTxtNode *pNode, SwIndex &rIdx, xub_StrLen &rStart )
{
if( !lcl_MayOverwrite( pNode, rStart ) )
{
// ueberspringe alle SonderAttribute
do {
// "Beep" bei jedem ausgelassenen
Sound::Beep(SOUND_ERROR);
rIdx++;
} while( (rStart = rIdx.GetIndex()) < pNode->GetTxt().Len()
&& !lcl_MayOverwrite(pNode, rStart) );
}
}
// -----------------------------------------------------------------
void _RestFlyInRange( _SaveFlyArr & rArr, const SwNodeIndex& rSttIdx,
const SwNodeIndex* pInsertPos )
{
SwPosition aPos( rSttIdx );
for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
{
// neuen Anker anlegen
_SaveFly& rSave = rArr[n];
SwFrmFmt* pFmt = rSave.pFrmFmt;
if( rSave.bInsertPosition )
{
if( pInsertPos != NULL )
aPos.nNode = *pInsertPos;
else
aPos.nNode = rSttIdx.GetIndex();
}
else
aPos.nNode = rSttIdx.GetIndex() + rSave.nNdDiff;
aPos.nContent.Assign( 0, 0 );
SwFmtAnchor aAnchor( pFmt->GetAnchor() );
aAnchor.SetAnchor( &aPos );
pFmt->GetDoc()->GetSpzFrmFmts()->Insert(
pFmt, pFmt->GetDoc()->GetSpzFrmFmts()->Count() );
pFmt->SetFmtAttr( aAnchor );
SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode();
if( pCNd && pCNd->getLayoutFrm( pFmt->GetDoc()->GetCurrentLayout(), 0, 0, sal_False ) )
pFmt->MakeFrms();
}
}
void _SaveFlyInRange( const SwNodeRange& rRg, _SaveFlyArr& rArr )
{
SwSpzFrmFmts& rFmts = *rRg.aStart.GetNode().GetDoc()->GetSpzFrmFmts();
for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
{
SwFrmFmt *const pFmt = static_cast<SwFrmFmt*>(rFmts[n]);
SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
if (pAPos &&
((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
(FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
rRg.aStart <= pAPos->nNode && pAPos->nNode < rRg.aEnd )
{
_SaveFly aSave( pAPos->nNode.GetIndex() - rRg.aStart.GetIndex(),
pFmt, sal_False );
rArr.Insert( aSave, rArr.Count());
pFmt->DelFrms();
rFmts.Remove( n--, 1 );
}
}
}
void _SaveFlyInRange( const SwPaM& rPam, const SwNodeIndex& rInsPos,
_SaveFlyArr& rArr, bool bMoveAllFlys )
{
SwSpzFrmFmts& rFmts = *rPam.GetPoint()->nNode.GetNode().GetDoc()->GetSpzFrmFmts();
SwFrmFmt* pFmt;
const SwFmtAnchor* pAnchor;
const SwPosition* pPos = rPam.Start();
const SwNodeIndex& rSttNdIdx = pPos->nNode;
short nSttOff = (!bMoveAllFlys && rSttNdIdx.GetNode().IsCntntNode() &&
pPos->nContent.GetIndex()) ? 1 : 0;
pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
const SwNodeIndex& rEndNdIdx = pPos->nNode;
short nOff = ( bMoveAllFlys || ( rEndNdIdx.GetNode().IsCntntNode() &&
pPos->nContent == rEndNdIdx.GetNode().GetCntntNode()->Len() ))
? 0 : 1;
const SwNodeIndex* pCntntIdx;
for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
{
sal_Bool bInsPos = sal_False;
pFmt = (SwFrmFmt*)rFmts[n];
pAnchor = &pFmt->GetAnchor();
const SwPosition* pAPos = pAnchor->GetCntntAnchor();
if (pAPos &&
((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
(FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
// nicht verschieben, wenn die InsPos im CntntBereich vom Fly ist
( 0 == ( pCntntIdx = pFmt->GetCntnt().GetCntntIdx() ) ||
!( *pCntntIdx < rInsPos &&
rInsPos < pCntntIdx->GetNode().EndOfSectionIndex() )) )
{
if( !bMoveAllFlys && rEndNdIdx == pAPos->nNode )
{
// wenn nur teil vom EndNode oder der EndNode und SttNode
// identisch sind, chaos::Anchor nicht anfassen
if( rSttNdIdx != pAPos->nNode )
{
// Anker nur an Anfang/Ende haengen
SwPosition aPos( rSttNdIdx );
SwFmtAnchor aAnchor( *pAnchor );
aAnchor.SetAnchor( &aPos );
pFmt->SetFmtAttr( aAnchor );
// ((SwFmtAnchor*)pAnchor)->SetAnchor( &aPos );
}
}
else if( ( rSttNdIdx.GetIndex() + nSttOff <= pAPos->nNode.GetIndex()
&& pAPos->nNode.GetIndex() <= rEndNdIdx.GetIndex() - nOff ) ||
0 != ( bInsPos = rInsPos == pAPos->nNode ))
{
_SaveFly aSave( pAPos->nNode.GetIndex() - rSttNdIdx.GetIndex(),
pFmt, bInsPos );
rArr.Insert( aSave, rArr.Count());
pFmt->DelFrms();
rFmts.Remove( n--, 1 );
}
}
}
}
// -----------------------------------------------------------------
// loesche und verschiebe alle "Fly's am Absatz", die in der SSelection
// liegen. Steht am SPoint ein Fly, wird dieser auf den Mark verschoben.
void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
const SwNodeIndex& rPtNdIdx )
{
const sal_Bool bDelFwrd = rMkNdIdx.GetIndex() <= rPtNdIdx.GetIndex();
SwDoc* pDoc = rMkNdIdx.GetNode().GetDoc();
SwSpzFrmFmts& rTbl = *pDoc->GetSpzFrmFmts();
for ( sal_uInt16 i = rTbl.Count(); i; )
{
SwFrmFmt *pFmt = rTbl[--i];
const SwFmtAnchor &rAnch = pFmt->GetAnchor();
SwPosition const*const pAPos = rAnch.GetCntntAnchor();
if (pAPos &&
((rAnch.GetAnchorId() == FLY_AT_PARA) ||
(rAnch.GetAnchorId() == FLY_AT_CHAR)) &&
( bDelFwrd
? rMkNdIdx < pAPos->nNode && pAPos->nNode <= rPtNdIdx
: rPtNdIdx <= pAPos->nNode && pAPos->nNode < rMkNdIdx ))
{
// nur den Anker verschieben ??
if( rPtNdIdx == pAPos->nNode )
{
SwFmtAnchor aAnch( pFmt->GetAnchor() );
SwPosition aPos( rMkNdIdx );
aAnch.SetAnchor( &aPos );
pFmt->SetFmtAttr( aAnch );
}
else
{
// wird der Fly geloescht muss auch im seinem Inhalt alle
// Flys geloescht werden !!
const SwFmtCntnt &rCntnt = pFmt->GetCntnt();
if( rCntnt.GetCntntIdx() )
{
DelFlyInRange( *rCntnt.GetCntntIdx(),
SwNodeIndex( *rCntnt.GetCntntIdx()->
GetNode().EndOfSectionNode() ));
// Position kann sich verschoben haben !
if( i > rTbl.Count() )
i = rTbl.Count();
else if( pFmt != rTbl[i] )
i = rTbl.GetPos( pFmt );
}
pDoc->DelLayoutFmt( pFmt );
// --> FME 2004-10-06 #117913# DelLayoutFmt can also
// trigger the deletion of objects.
if( i > rTbl.Count() )
i = rTbl.Count();
// <--
}
}
}
}
bool lcl_SaveFtn( const SwNodeIndex& rSttNd, const SwNodeIndex& rEndNd,
const SwNodeIndex& rInsPos,
SwFtnIdxs& rFtnArr, SwFtnIdxs& rSaveArr,
const SwIndex* pSttCnt = 0, const SwIndex* pEndCnt = 0 )
{
bool bUpdateFtn = sal_False;
const SwNodes& rNds = rInsPos.GetNodes();
const bool bDelFtn = rInsPos.GetIndex() < rNds.GetEndOfAutotext().GetIndex() &&
rSttNd.GetIndex() >= rNds.GetEndOfAutotext().GetIndex();
const bool bSaveFtn = !bDelFtn &&
rInsPos.GetIndex() >= rNds.GetEndOfExtras().GetIndex();
if( rFtnArr.Count() )
{
sal_uInt16 nPos;
rFtnArr.SeekEntry( rSttNd, &nPos );
SwTxtFtn* pSrch;
const SwNode* pFtnNd;
// loesche/sicher erstmal alle, die dahinter stehen
while( nPos < rFtnArr.Count() && ( pFtnNd =
&( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex()
<= rEndNd.GetIndex() )
{
xub_StrLen nFtnSttIdx = *pSrch->GetStart();
if( ( pEndCnt && pSttCnt )
? (( &rSttNd.GetNode() == pFtnNd &&
pSttCnt->GetIndex() > nFtnSttIdx) ||
( &rEndNd.GetNode() == pFtnNd &&
nFtnSttIdx >= pEndCnt->GetIndex() ))
: ( &rEndNd.GetNode() == pFtnNd ))
{
++nPos; // weiter suchen
}
else
{
// dann weg damit
if( bDelFtn )
{
SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
SwIndex aIdx( &rTxtNd, nFtnSttIdx );
rTxtNd.EraseText( aIdx, 1 );
}
else
{
pSrch->DelFrms(0);
rFtnArr.Remove( nPos );
if( bSaveFtn )
rSaveArr.Insert( pSrch );
}
bUpdateFtn = sal_True;
}
}
while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )->
GetTxtNode())->GetIndex() >= rSttNd.GetIndex() )
{
xub_StrLen nFtnSttIdx = *pSrch->GetStart();
if( !pEndCnt || !pSttCnt ||
!( (( &rSttNd.GetNode() == pFtnNd &&
pSttCnt->GetIndex() > nFtnSttIdx ) ||
( &rEndNd.GetNode() == pFtnNd &&
nFtnSttIdx >= pEndCnt->GetIndex() )) ))
{
if( bDelFtn )
{
// dann weg damit
SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
SwIndex aIdx( &rTxtNd, nFtnSttIdx );
rTxtNd.EraseText( aIdx, 1 );
}
else
{
pSrch->DelFrms(0);
rFtnArr.Remove( nPos );
if( bSaveFtn )
rSaveArr.Insert( pSrch );
}
bUpdateFtn = sal_True;
}
}
}
// When moving from redline section into document content section, e.g.
// after loading a document with (delete-)redlines, the footnote array
// has to be adjusted... (#i70572)
if( bSaveFtn )
{
SwNodeIndex aIdx( rSttNd );
while( aIdx < rEndNd ) // Check the moved section
{
SwNode* pNode = &aIdx.GetNode();
if( pNode->IsTxtNode() ) // Looking for text nodes...
{
SwpHints *pHints =
static_cast<SwTxtNode*>(pNode)->GetpSwpHints();
if( pHints && pHints->HasFtn() ) //...with footnotes
{
bUpdateFtn = sal_True; // Heureka
sal_uInt16 nCount = pHints->Count();
for( sal_uInt16 i = 0; i < nCount; ++i )
{
SwTxtAttr *pAttr = pHints->GetTextHint( i );
if ( pAttr->Which() == RES_TXTATR_FTN )
{
rSaveArr.Insert( static_cast<SwTxtFtn*>(pAttr) );
}
}
}
}
++aIdx;
}
}
return bUpdateFtn;
}
void lcl_SaveRedlines( const SwPaM& aPam, _SaveRedlines& rArr )
{
SwDoc* pDoc = aPam.GetNode()->GetDoc();
const SwPosition* pStart = aPam.Start();
const SwPosition* pEnd = aPam.End();
// get first relevant redline
sal_uInt16 nCurrentRedline;
pDoc->GetRedline( *pStart, &nCurrentRedline );
if( nCurrentRedline > 0)
nCurrentRedline--;
// redline mode REDLINE_IGNORE|REDLINE_ON; save old mode
RedlineMode_t eOld = pDoc->GetRedlineMode();
pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
// iterate over relevant redlines and decide for each whether it should
// be saved, or split + saved
SwRedlineTbl& rRedlineTable = const_cast<SwRedlineTbl&>( pDoc->GetRedlineTbl() );
for( ; nCurrentRedline < rRedlineTable.Count(); nCurrentRedline++ )
{
SwRedline* pCurrent = rRedlineTable[ nCurrentRedline ];
SwComparePosition eCompare =
ComparePosition( *pCurrent->Start(), *pCurrent->End(),
*pStart, *pEnd);
// we must save this redline if it overlaps aPam
// (we may have to split it, too)
if( eCompare == POS_OVERLAP_BEHIND ||
eCompare == POS_OVERLAP_BEFORE ||
eCompare == POS_OUTSIDE ||
eCompare == POS_INSIDE ||
eCompare == POS_EQUAL )
{
rRedlineTable.Remove( nCurrentRedline-- );
// split beginning, if necessary
if( eCompare == POS_OVERLAP_BEFORE ||
eCompare == POS_OUTSIDE )
{
SwRedline* pNewRedline = new SwRedline( *pCurrent );
*pNewRedline->End() = *pStart;
*pCurrent->Start() = *pStart;
pDoc->AppendRedline( pNewRedline, true );
}
// split end, if necessary
if( eCompare == POS_OVERLAP_BEHIND ||
eCompare == POS_OUTSIDE )
{
SwRedline* pNewRedline = new SwRedline( *pCurrent );
*pNewRedline->Start() = *pEnd;
*pCurrent->End() = *pEnd;
pDoc->AppendRedline( pNewRedline, true );
}
// save the current redline
_SaveRedline* pSave = new _SaveRedline( pCurrent, *pStart );
rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
}
}
// restore old redline mode
pDoc->SetRedlineMode_intern( eOld );
}
void lcl_RestoreRedlines( SwDoc* pDoc, const SwPosition& rPos, _SaveRedlines& rArr )
{
RedlineMode_t eOld = pDoc->GetRedlineMode();
pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
{
_SaveRedline* pSave = rArr[ n ];
pSave->SetPos( rPos );
pDoc->AppendRedline( pSave->pRedl, true );
}
pDoc->SetRedlineMode_intern( eOld );
}
void lcl_SaveRedlines( const SwNodeRange& rRg, _SaveRedlines& rArr )
{
SwDoc* pDoc = rRg.aStart.GetNode().GetDoc();
sal_uInt16 nRedlPos;
SwPosition aSrchPos( rRg.aStart ); aSrchPos.nNode--;
aSrchPos.nContent.Assign( aSrchPos.nNode.GetNode().GetCntntNode(), 0 );
if( pDoc->GetRedline( aSrchPos, &nRedlPos ) && nRedlPos )
--nRedlPos;
else if( nRedlPos >= pDoc->GetRedlineTbl().Count() )
return ;
RedlineMode_t eOld = pDoc->GetRedlineMode();
pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
SwRedlineTbl& rRedlTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl();
do {
SwRedline* pTmp = rRedlTbl[ nRedlPos ];
const SwPosition* pRStt = pTmp->Start(),
* pREnd = pTmp->GetMark() == pRStt
? pTmp->GetPoint() : pTmp->GetMark();
if( pRStt->nNode < rRg.aStart )
{
if( pREnd->nNode > rRg.aStart && pREnd->nNode < rRg.aEnd )
{
// Kopie erzeugen und Ende vom Original ans Ende des
// MoveBereiches setzen. Die Kopie wird mit verschoben
SwRedline* pNewRedl = new SwRedline( *pTmp );
SwPosition* pTmpPos = pNewRedl->Start();
pTmpPos->nNode = rRg.aStart;
pTmpPos->nContent.Assign(
pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
_SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
// rArr.Insert( pSave, rArr.Count() );
rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
pTmpPos = pTmp->End();
pTmpPos->nNode = rRg.aEnd;
pTmpPos->nContent.Assign(
pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
}
else if( pREnd->nNode == rRg.aStart )
{
SwPosition* pTmpPos = pTmp->End();
pTmpPos->nNode = rRg.aEnd;
pTmpPos->nContent.Assign(
pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
}
}
else if( pRStt->nNode < rRg.aEnd )
{
rRedlTbl.Remove( nRedlPos-- );
if( pREnd->nNode < rRg.aEnd ||
( pREnd->nNode == rRg.aEnd && !pREnd->nContent.GetIndex()) )
{
// gesamt verschieben
_SaveRedline* pSave = new _SaveRedline( pTmp, rRg.aStart );
// rArr.Insert( pSave, rArr.Count() );
rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
}
else
{
// aufsplitten
SwRedline* pNewRedl = new SwRedline( *pTmp );
SwPosition* pTmpPos = pNewRedl->End();
pTmpPos->nNode = rRg.aEnd;
pTmpPos->nContent.Assign(
pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
_SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
// rArr.Insert( pSave, rArr.Count() );
rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
pTmpPos = pTmp->Start();
pTmpPos->nNode = rRg.aEnd;
pTmpPos->nContent.Assign(
pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
pDoc->AppendRedline( pTmp, true );
}
}
else
break;
} while( ++nRedlPos < pDoc->GetRedlineTbl().Count() );
pDoc->SetRedlineMode_intern( eOld );
}
void lcl_RestoreRedlines( SwDoc* pDoc, sal_uInt32 nInsPos, _SaveRedlines& rArr )
{
RedlineMode_t eOld = pDoc->GetRedlineMode();
pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
{
_SaveRedline* pSave = rArr[ n ];
pSave->SetPos( nInsPos );
pDoc->AppendRedline( pSave->pRedl, true );
}
pDoc->SetRedlineMode_intern( eOld );
}
// ------------------------------------------------------------------------
// #i59534: Redo of insertion of multiple text nodes runs into trouble
// because of unnecessary expanded redlines
// From now on this class saves the redline positions of all redlines which ends exact at the
// insert position (node _and_ content index)
_SaveRedlEndPosForRestore::_SaveRedlEndPosForRestore( const SwNodeIndex& rInsIdx, xub_StrLen nCnt )
: pSavArr( 0 ), pSavIdx( 0 ), nSavCntnt( nCnt )
{
SwNode& rNd = rInsIdx.GetNode();
SwDoc* pDest = rNd.GetDoc();
if( pDest->GetRedlineTbl().Count() )
{
sal_uInt16 nFndPos;
const SwPosition* pEnd;
SwPosition aSrcPos( rInsIdx, SwIndex( rNd.GetCntntNode(), nCnt ));
const SwRedline* pRedl = pDest->GetRedline( aSrcPos, &nFndPos );
while( nFndPos-- && *( pEnd = ( pRedl =
pDest->GetRedlineTbl()[ nFndPos ] )->End() ) == aSrcPos && *pRedl->Start() < aSrcPos )
{
if( !pSavArr )
{
pSavArr = new SvPtrarr( 2, 2 );
pSavIdx = new SwNodeIndex( rInsIdx, -1 );
}
void* p = (void*)pEnd;
pSavArr->Insert( p, pSavArr->Count() );
}
}
}
_SaveRedlEndPosForRestore::~_SaveRedlEndPosForRestore()
{
if( pSavArr )
{
delete pSavArr;
delete pSavIdx;
}
}
void _SaveRedlEndPosForRestore::_Restore()
{
(*pSavIdx)++;
SwCntntNode* pNode = pSavIdx->GetNode().GetCntntNode();
// If there's no content node at the remembered position, we will not restore the old position
// This may happen if a table (or section?) will be inserted.
if( pNode )
{
SwPosition aPos( *pSavIdx, SwIndex( pNode, nSavCntnt ));
for( sal_uInt16 n = pSavArr->Count(); n; )
*((SwPosition*)pSavArr->GetObject( --n )) = aPos;
}
}
// ------------------------------------------------------------------------
// Loeschen einer vollstaendigen Section des NodesArray.
// Der uebergebene Node steht irgendwo in der gewuenschten Section
void SwDoc::DeleteSection( SwNode *pNode )
{
ASSERT( pNode, "Kein Node uebergeben." );
SwStartNode* pSttNd = pNode->IsStartNode() ? (SwStartNode*)pNode
: pNode->StartOfSectionNode();
SwNodeIndex aSttIdx( *pSttNd ), aEndIdx( *pNode->EndOfSectionNode() );
// dann loesche mal alle Fly's, text::Bookmarks, ...
DelFlyInRange( aSttIdx, aEndIdx );
DeleteRedline( *pSttNd, true, USHRT_MAX );
_DelBookmarks(aSttIdx, aEndIdx);
{
// alle Crsr/StkCrsr/UnoCrsr aus dem Loeschbereich verschieben
SwNodeIndex aMvStt( aSttIdx, 1 );
CorrAbs( aMvStt, aEndIdx, SwPosition( aSttIdx ), sal_True );
}
GetNodes().DelNodes( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() + 1 );
}
void SwDoc::SetModified(SwPaM &rPaM)
{
SwDataChanged aTmp( rPaM, 0 );
SetModified();
}
/*************************************************************************
* SwDoc::Overwrite()
************************************************************************/
bool SwDoc::Overwrite( const SwPaM &rRg, const String &rStr )
{
SwPosition& rPt = *(SwPosition*)rRg.GetPoint();
if( pACEWord ) // Aufnahme in die Autokorrektur
{
if( 1 == rStr.Len() )
pACEWord->CheckChar( rPt, rStr.GetChar( 0 ) );
delete pACEWord, pACEWord = 0;
}
SwTxtNode *pNode = rPt.nNode.GetNode().GetTxtNode();
if(!pNode)
return sal_False;
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called
}
sal_uInt16 nOldAttrCnt = pNode->GetpSwpHints()
? pNode->GetpSwpHints()->Count() : 0;
SwDataChanged aTmp( rRg, 0 );
SwIndex& rIdx = rPt.nContent;
xub_StrLen nStart = 0;
sal_Unicode c;
String aStr;
sal_Bool bOldExpFlg = pNode->IsIgnoreDontExpand();
pNode->SetIgnoreDontExpand( sal_True );
for( xub_StrLen nCnt = 0; nCnt < rStr.Len(); ++nCnt )
{
// hinter das Zeichen (zum aufspannen der Attribute !!)
nStart = rIdx.GetIndex();
if ( nStart < pNode->GetTxt().Len() )
{
lcl_SkipAttr( pNode, rIdx, nStart );
}
c = rStr.GetChar( nCnt );
if (GetIDocumentUndoRedo().DoesUndo())
{
bool bMerged(false);
if (GetIDocumentUndoRedo().DoesGroupUndo())
{
SwUndo *const pUndo = GetUndoManager().GetLastUndo();
SwUndoOverwrite *const pUndoOW(
dynamic_cast<SwUndoOverwrite *>(pUndo) );
if (pUndoOW)
{
// if CanGrouping() returns true it's already merged
bMerged = pUndoOW->CanGrouping( this, rPt, c );
}
}
if (!bMerged)
{
SwUndo *const pUndoOW( new SwUndoOverwrite(this, rPt, c) );
GetIDocumentUndoRedo().AppendUndo(pUndoOW);
}
}
else
{
// hinter das Zeichen (zum Aufspannen der Attribute !!)
if( nStart < pNode->GetTxt().Len() )
rIdx++;
pNode->InsertText( c, rIdx, INS_EMPTYEXPAND );
if( nStart+1 < rIdx.GetIndex() )
{
rIdx = nStart;
pNode->EraseText( rIdx, 1 );
rIdx++;
}
}
}
pNode->SetIgnoreDontExpand( bOldExpFlg );
sal_uInt16 nNewAttrCnt = pNode->GetpSwpHints()
? pNode->GetpSwpHints()->Count() : 0;
if( nOldAttrCnt != nNewAttrCnt )
{
SwUpdateAttr aHint( 0, 0, 0 );
pNode->ModifyBroadcast( 0, &aHint, TYPE( SwCrsrShell ) );
}
if (!GetIDocumentUndoRedo().DoesUndo() &&
!IsIgnoreRedline() && GetRedlineTbl().Count())
{
SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
DeleteRedline( aPam, true, USHRT_MAX );
}
else if( IsRedlineOn() )
{
// FIXME: this redline is WRONG: there is no DELETE, and the skipped
// characters are also included in aPam
SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
}
SetModified();
return sal_True;
}
bool SwDoc::MoveAndJoin( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
{
SwNodeIndex aIdx( rPaM.Start()->nNode );
sal_Bool bJoinTxt = aIdx.GetNode().IsTxtNode();
sal_Bool bOneNode = rPaM.GetPoint()->nNode == rPaM.GetMark()->nNode;
aIdx--; // vor den Move Bereich !!
bool bRet = MoveRange( rPaM, rPos, eMvFlags );
if( bRet && !bOneNode )
{
if( bJoinTxt )
aIdx++;
SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode();
SwNodeIndex aNxtIdx( aIdx );
if( pTxtNd && pTxtNd->CanJoinNext( &aNxtIdx ) )
{
{ // Block wegen SwIndex in den Node !!
CorrRel( aNxtIdx, SwPosition( aIdx, SwIndex( pTxtNd,
pTxtNd->GetTxt().Len() ) ), 0, sal_True );
}
pTxtNd->JoinNext();
}
}
return bRet;
}
// mst: it seems that this is mostly used by SwDoc internals; the only
// way to call this from the outside seems to be the special case in
// SwDoc::CopyRange (but i have not managed to actually hit that case)
bool SwDoc::MoveRange( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
{
// keine Moves-Abfangen
const SwPosition *pStt = rPaM.Start(), *pEnd = rPaM.End();
if( !rPaM.HasMark() || *pStt >= *pEnd || (*pStt <= rPos && rPos < *pEnd))
return false;
// sicher die absatzgebundenen Flys, damit sie verschoben werden koennen.
_SaveFlyArr aSaveFlyArr;
_SaveFlyInRange( rPaM, rPos.nNode, aSaveFlyArr, 0 != ( DOC_MOVEALLFLYS & eMvFlags ) );
// save redlines (if DOC_MOVEREDLINES is used)
_SaveRedlines aSaveRedl( 0, 4 );
if( DOC_MOVEREDLINES & eMvFlags && GetRedlineTbl().Count() )
{
lcl_SaveRedlines( rPaM, aSaveRedl );
// #i17764# unfortunately, code below relies on undos being
// in a particular order, and presence of bookmarks
// will change this order. Hence, we delete bookmarks
// here without undo.
::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
_DelBookmarks(
pStt->nNode,
pEnd->nNode,
NULL,
&pStt->nContent,
&pEnd->nContent);
}
int bUpdateFtn = sal_False;
SwFtnIdxs aTmpFntIdx;
// falls Undo eingeschaltet, erzeuge das UndoMove-Objekt
SwUndoMove * pUndoMove = 0;
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().ClearRedo();
pUndoMove = new SwUndoMove( rPaM, rPos );
pUndoMove->SetMoveRedlines( eMvFlags == DOC_MOVEREDLINES );
}
else
{
bUpdateFtn = lcl_SaveFtn( pStt->nNode, pEnd->nNode, rPos.nNode,
GetFtnIdxs(), aTmpFntIdx,
&pStt->nContent, &pEnd->nContent );
}
sal_Bool bSplit = sal_False;
SwPaM aSavePam( rPos, rPos );
// stelle den SPoint an den Anfang vom Bereich (Definition)
if( rPaM.GetPoint() == pEnd )
rPaM.Exchange();
// in der EditShell wird nach dem Move ein JoinNext erzeugt, wenn
// vor und nach dem Move ein Text-Node steht.
SwTxtNode* pSrcNd = rPaM.GetPoint()->nNode.GetNode().GetTxtNode();
sal_Bool bCorrSavePam = pSrcNd && pStt->nNode != pEnd->nNode;
// werden ein oder mehr TextNodes bewegt, so wird
// im SwNodes::Move ein SplitNode erzeugt. Dieser Updated aber nicht
// den Cursor. Um das zu verhindern, wird hier ein TextNode angelegt,
// um die Updaterei der Indizies zu erhalten. Nach dem Move wird
// evt. der Node geloescht.
SwTxtNode * pTNd = rPos.nNode.GetNode().GetTxtNode();
if( pTNd && rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode &&
( rPos.nContent.GetIndex() || ( pTNd->Len() && bCorrSavePam )) )
{
bSplit = sal_True;
xub_StrLen nMkCntnt = rPaM.GetMark()->nContent.GetIndex();
SvULongs aBkmkArr( 15, 15 );
_SaveCntntIdx( this, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(),
aBkmkArr, SAVEFLY_SPLIT );
pTNd = static_cast<SwTxtNode*>(pTNd->SplitCntntNode( rPos ));
if( aBkmkArr.Count() )
_RestoreCntntIdx( this, aBkmkArr, rPos.nNode.GetIndex()-1, 0, sal_True );
// jetzt noch den Pam berichtigen !!
if( rPos.nNode == rPaM.GetMark()->nNode )
{
rPaM.GetMark()->nNode = rPos.nNode.GetIndex()-1;
rPaM.GetMark()->nContent.Assign( pTNd, nMkCntnt );
}
}
// setze den Pam um einen "Inhalt" zurueck; dadurch steht er immer
// ausserhalb des manipulierten Bereiches. Falls kein Inhalt mehr vor-
// handen, dann auf den StartNode (es ist immer einer vorhanden !!!)
sal_Bool bNullCntnt = !aSavePam.Move( fnMoveBackward, fnGoCntnt );
if( bNullCntnt )
{
aSavePam.GetPoint()->nNode--;
}
// kopiere alle Bookmarks, die im Move Bereich stehen in ein
// Array, das alle Angaben auf die Position als Offset speichert.
// Die neue Zuordung erfolgt nach dem Moven.
::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
_DelBookmarks(
pStt->nNode,
pEnd->nNode,
&aSaveBkmks,
&pStt->nContent,
&pEnd->nContent);
// falls durch die vorherigen Loeschungen (z.B. der Fussnoten) kein
// Bereich mehr existiert, ist das immernoch ein gueltiger Move!
if( *rPaM.GetPoint() != *rPaM.GetMark() )
{
// now do the actual move
GetNodes().MoveRange( rPaM, rPos, GetNodes() );
// after a MoveRange() the Mark is deleted
if ( rPaM.HasMark() ) // => no Move occurred!
{
delete pUndoMove;
return false;
}
}
else
rPaM.DeleteMark();
ASSERT( *aSavePam.GetMark() == rPos ||
( aSavePam.GetMark()->nNode.GetNode().GetCntntNode() == NULL ),
"PaM wurde nicht verschoben, am Anfang/Ende keine ContentNodes?" );
*aSavePam.GetMark() = rPos;
rPaM.SetMark(); // um den neuen Bereich eine Sel. aufspannen
pTNd = aSavePam.GetNode()->GetTxtNode();
if (GetIDocumentUndoRedo().DoesUndo())
{
// korrigiere erstmal den Content vom SavePam
if( bNullCntnt )
{
aSavePam.GetPoint()->nContent = 0;
}
// die Methode SwEditShell::Move() fuegt nach dem Move den Text-Node
// zusammen, in dem der rPaM steht. Wurde der Inhalt nach hinten
// geschoben und liegt der SPoint vom SavePam im naechsten Node, so
// muss beim Speichern vom Undo-Object das beachtet werden !!
SwTxtNode * pPamTxtNd = 0;
// wird ans SwUndoMove weitergegeben, das dann beim Undo JoinNext
// aufruft. (falls es hier nicht moeglich ist).
sal_Bool bJoin = bSplit && pTNd;
bCorrSavePam = bCorrSavePam &&
0 != ( pPamTxtNd = rPaM.GetNode()->GetTxtNode() )
&& pPamTxtNd->CanJoinNext()
&& (*rPaM.GetPoint() <= *aSavePam.GetPoint());
// muessen am SavePam 2 Nodes zusammengefasst werden ??
if( bJoin && pTNd->CanJoinNext() )
{
pTNd->JoinNext();
// kein temp. sdbcx::Index bei &&
// es sollten wohl nur die Indexwerte verglichen werden.
if( bCorrSavePam && rPaM.GetPoint()->nNode.GetIndex()+1 ==
aSavePam.GetPoint()->nNode.GetIndex() )
{
aSavePam.GetPoint()->nContent += pPamTxtNd->Len();
}
bJoin = sal_False;
}
// else if( !bCorrSavePam && !pSavePam->Move( fnMoveForward, fnGoCntnt ))
else if ( !aSavePam.Move( fnMoveForward, fnGoCntnt ) )
{
aSavePam.GetPoint()->nNode++;
}
// zwischen SPoint und GetMark steht jetzt der neu eingefuegte Bereich
pUndoMove->SetDestRange( aSavePam, *rPaM.GetPoint(),
bJoin, bCorrSavePam );
GetIDocumentUndoRedo().AppendUndo( pUndoMove );
}
else
{
bool bRemove = true;
// muessen am SavePam 2 Nodes zusammengefasst werden ??
if( bSplit && pTNd )
{
if( pTNd->CanJoinNext())
{
// --> OD 2009-08-20 #i100466#
// Always join next, because <pTNd> has to stay as it is.
// A join previous from its next would more or less delete <pTNd>
pTNd->JoinNext();
// <--
bRemove = false;
}
}
if( bNullCntnt )
{
aSavePam.GetPoint()->nNode++;
aSavePam.GetPoint()->nContent.Assign( aSavePam.GetCntntNode(), 0 );
}
else if( bRemove ) // No move forward after joining with next paragraph
{
aSavePam.Move( fnMoveForward, fnGoCntnt );
}
}
// setze jetzt wieder die text::Bookmarks in das Dokument
*rPaM.GetMark() = *aSavePam.Start();
for(
::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
pBkmk != aSaveBkmks.end();
++pBkmk)
pBkmk->SetInDoc(
this,
rPaM.GetMark()->nNode,
&rPaM.GetMark()->nContent);
*rPaM.GetPoint() = *aSavePam.End();
// verschiebe die Flys an die neue Position
_RestFlyInRange( aSaveFlyArr, rPaM.Start()->nNode, &(rPos.nNode) );
// restore redlines (if DOC_MOVEREDLINES is used)
if( aSaveRedl.Count() )
{
lcl_RestoreRedlines( this, *aSavePam.Start(), aSaveRedl );
}
if( bUpdateFtn )
{
if( aTmpFntIdx.Count() )
{
GetFtnIdxs().Insert( &aTmpFntIdx );
aTmpFntIdx.Remove( sal_uInt16( 0 ), aTmpFntIdx.Count() );
}
GetFtnIdxs().UpdateAllFtn();
}
SetModified();
return true;
}
bool SwDoc::MoveNodeRange( SwNodeRange& rRange, SwNodeIndex& rPos,
SwMoveFlags eMvFlags )
{
// bewegt alle Nodes an die neue Position. Dabei werden die
// text::Bookmarks mit verschoben !! (zur Zeit ohne Undo)
// falls durchs Move Fussnoten in den Sonderbereich kommen sollten,
// dann entferne sie jetzt.
//JP 13.07.95:
// ansonsten bei allen Fussnoten, die verschoben werden, die Frames
// loeschen und nach dem Move wieder aufbauen lassen (Fussnoten koennen
// die Seite wechseln). Zusaetzlich muss natuerlich die Sortierung
// der FtnIdx-Array wieder korrigiert werden.
int bUpdateFtn = sal_False;
SwFtnIdxs aTmpFntIdx;
SwUndoMove* pUndo = 0;
if ((DOC_CREATEUNDOOBJ & eMvFlags ) && GetIDocumentUndoRedo().DoesUndo())
{
pUndo = new SwUndoMove( this, rRange, rPos );
}
else
{
bUpdateFtn = lcl_SaveFtn( rRange.aStart, rRange.aEnd, rPos,
GetFtnIdxs(), aTmpFntIdx );
}
_SaveRedlines aSaveRedl( 0, 4 );
SvPtrarr aSavRedlInsPosArr( 0, 4 );
if( DOC_MOVEREDLINES & eMvFlags && GetRedlineTbl().Count() )
{
lcl_SaveRedlines( rRange, aSaveRedl );
// suche alle Redlines, die an der InsPos aufhoeren. Diese muessen
// nach dem Move wieder an die "alte" Position verschoben werden
sal_uInt16 nRedlPos = GetRedlinePos( rPos.GetNode(), USHRT_MAX );
if( USHRT_MAX != nRedlPos )
{
const SwPosition *pRStt, *pREnd;
do {
SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
pRStt = pTmp->Start();
pREnd = pTmp->End();
if( pREnd->nNode == rPos && pRStt->nNode < rPos )
{
void* p = pTmp;
aSavRedlInsPosArr.Insert( p, aSavRedlInsPosArr.Count() );
}
} while( pRStt->nNode < rPos && ++nRedlPos < GetRedlineTbl().Count());
}
}
// kopiere alle Bookmarks, die im Move Bereich stehen in ein
// Array, das alle Angaben auf die Position als Offset speichert.
// Die neue Zuordung erfolgt nach dem Moven.
::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
_DelBookmarks(rRange.aStart, rRange.aEnd, &aSaveBkmks);
// sicher die absatzgebundenen Flys, damit verschoben werden koennen.
_SaveFlyArr aSaveFlyArr;
if( GetSpzFrmFmts()->Count() )
_SaveFlyInRange( rRange, aSaveFlyArr );
// vor die Position setzen, damit er nicht weitergeschoben wird
SwNodeIndex aIdx( rPos, -1 );
SwNodeIndex* pSaveInsPos = 0;
if( pUndo )
pSaveInsPos = new SwNodeIndex( rRange.aStart, -1 );
// verschiebe die Nodes
sal_Bool bNoDelFrms = 0 != (DOC_NO_DELFRMS & eMvFlags);
if( GetNodes()._MoveNodes( rRange, GetNodes(), rPos, !bNoDelFrms ) )
{
aIdx++; // wieder auf alte Position
if( pSaveInsPos )
(*pSaveInsPos)++;
}
else
{
aIdx = rRange.aStart;
delete pUndo, pUndo = 0;
}
// verschiebe die Flys an die neue Position
if( aSaveFlyArr.Count() )
_RestFlyInRange( aSaveFlyArr, aIdx, NULL );
// setze jetzt wieder die text::Bookmarks in das Dokument
for(
::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
pBkmk != aSaveBkmks.end();
++pBkmk)
pBkmk->SetInDoc(this, aIdx);
if( aSavRedlInsPosArr.Count() )
{
SwNode* pNewNd = &aIdx.GetNode();
for( sal_uInt16 n = 0; n < aSavRedlInsPosArr.Count(); ++n )
{
SwRedline* pTmp = (SwRedline*)aSavRedlInsPosArr[ n ];
if( USHRT_MAX != GetRedlineTbl().GetPos( pTmp ) )
{
SwPosition* pEnd = pTmp->End();
pEnd->nNode = aIdx;
pEnd->nContent.Assign( pNewNd->GetCntntNode(), 0 );
}
}
}
if( aSaveRedl.Count() )
lcl_RestoreRedlines( this, aIdx.GetIndex(), aSaveRedl );
if( pUndo )
{
pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos );
GetIDocumentUndoRedo().AppendUndo(pUndo);
}
if( pSaveInsPos )
delete pSaveInsPos;
if( bUpdateFtn )
{
if( aTmpFntIdx.Count() )
{
GetFtnIdxs().Insert( &aTmpFntIdx );
aTmpFntIdx.Remove( sal_uInt16( 0 ), aTmpFntIdx.Count() );
}
GetFtnIdxs().UpdateAllFtn();
}
SetModified();
return sal_True;
}
/* #107318# Convert list of ranges of whichIds to a corresponding list
of whichIds*/
SvUShorts * lcl_RangesToUShorts(sal_uInt16 * pRanges)
{
SvUShorts * pResult = new SvUShorts();
int i = 0;
while (pRanges[i] != 0)
{
ASSERT(pRanges[i+1] != 0, "malformed ranges");
for (sal_uInt16 j = pRanges[i]; j < pRanges[i+1]; j++)
pResult->Insert(j, pResult->Count());
i += 2;
}
return pResult;
}
bool lcl_StrLenOverFlow( const SwPaM& rPam )
{
// If we try to merge two paragraph we have to test if afterwards
// the string doesn't exceed the allowed string length
bool bRet = false;
if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
{
const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode();
if( (0 != pEndNd) && pStt->nNode.GetNode().IsTxtNode() )
{
sal_uInt64 nSum = pStt->nContent.GetIndex() +
pEndNd->GetTxt().Len() - pEnd->nContent.GetIndex();
if( nSum > STRING_LEN )
bRet = true;
}
}
return bRet;
}
void lcl_GetJoinFlags( SwPaM& rPam, sal_Bool& rJoinTxt, sal_Bool& rJoinPrev )
{
rJoinTxt = sal_False;
rJoinPrev = sal_False;
if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
{
const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
SwTxtNode *pSttNd = pStt->nNode.GetNode().GetTxtNode();
if( pSttNd )
{
SwTxtNode *pEndNd = pEnd->nNode.GetNode().GetTxtNode();
rJoinTxt = 0 != pEndNd;
if( rJoinTxt )
{
bool bExchange = pStt == rPam.GetPoint();
if( !pStt->nContent.GetIndex() &&
pEndNd->GetTxt().Len() != pEnd->nContent.GetIndex() )
bExchange = !bExchange;
if( bExchange )
rPam.Exchange();
rJoinPrev = rPam.GetPoint() == pStt;
ASSERT( !pStt->nContent.GetIndex() &&
pEndNd->GetTxt().Len() != pEnd->nContent.GetIndex()
? rPam.GetPoint()->nNode < rPam.GetMark()->nNode
: rPam.GetPoint()->nNode > rPam.GetMark()->nNode,
"lcl_GetJoinFlags");
}
}
}
}
void lcl_JoinText( SwPaM& rPam, sal_Bool bJoinPrev )
{
SwNodeIndex aIdx( rPam.GetPoint()->nNode );
SwTxtNode *pTxtNd = aIdx.GetNode().GetTxtNode();
SwNodeIndex aOldIdx( aIdx );
SwTxtNode *pOldTxtNd = pTxtNd;
if( pTxtNd && pTxtNd->CanJoinNext( &aIdx ) )
{
SwDoc* pDoc = rPam.GetDoc();
if( bJoinPrev )
{
// N.B.: we do not need to handle xmlids in this case, because
// it is only invoked if one paragraph is completely empty
// (see lcl_GetJoinFlags)
{
// falls PageBreaks geloescht / gesetzt werden, darf das
// nicht in die Undo-History aufgenommen werden !!
// (das loeschen vom Node geht auch am Undo vorbei !!!)
::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
/* PageBreaks, PageDesc, ColumnBreaks */
// Sollte an der Logik zum Kopieren der PageBreak's ...
// etwas geaendert werden, muss es auch im SwUndoDelete
// geandert werden. Dort wird sich das AUTO-PageBreak
// aus dem GetMarkNode kopiert.!!!
/* Der GetMarkNode */
if( ( pTxtNd = aIdx.GetNode().GetTxtNode())->HasSwAttrSet() )
{
const SfxPoolItem* pItem;
if( SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
RES_BREAK, sal_False, &pItem ) )
pTxtNd->ResetAttr( RES_BREAK );
if( pTxtNd->HasSwAttrSet() &&
SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
RES_PAGEDESC, sal_False, &pItem ) )
pTxtNd->ResetAttr( RES_PAGEDESC );
}
/* Der PointNode */
if( pOldTxtNd->HasSwAttrSet() )
{
const SfxPoolItem* pItem;
SfxItemSet aSet( pDoc->GetAttrPool(), aBreakSetRange );
const SfxItemSet* pSet = pOldTxtNd->GetpSwAttrSet();
if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
sal_False, &pItem ) )
aSet.Put( *pItem );
if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
sal_False, &pItem ) )
aSet.Put( *pItem );
if( aSet.Count() )
pTxtNd->SetAttr( aSet );
}
pOldTxtNd->FmtToTxtAttr( pTxtNd );
SvULongs aBkmkArr( 15, 15 );
::_SaveCntntIdx( pDoc, aOldIdx.GetIndex(),
pOldTxtNd->Len(), aBkmkArr );
SwIndex aAlphaIdx(pTxtNd);
pOldTxtNd->CutText( pTxtNd, aAlphaIdx, SwIndex(pOldTxtNd),
pOldTxtNd->Len() );
SwPosition aAlphaPos( aIdx, aAlphaIdx );
pDoc->CorrRel( rPam.GetPoint()->nNode, aAlphaPos, 0, sal_True );
// verschiebe noch alle Bookmarks/TOXMarks
if( aBkmkArr.Count() )
::_RestoreCntntIdx( pDoc, aBkmkArr, aIdx.GetIndex() );
// falls der uebergebene PaM nicht im Crsr-Ring steht,
// gesondert behandeln (z.B. Aufruf aus dem Auto-Format)
if( pOldTxtNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() )
rPam.GetBound( sal_True ) = aAlphaPos;
if( pOldTxtNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() )
rPam.GetBound( sal_False ) = aAlphaPos;
}
// jetzt nur noch den Node loeschen
pDoc->GetNodes().Delete( aOldIdx, 1 );
}
else
{
SwTxtNode* pDelNd = aIdx.GetNode().GetTxtNode();
if( pTxtNd->Len() )
pDelNd->FmtToTxtAttr( pTxtNd );
else
{
/* #107318# This case was missed:
<something></something> <-- pTxtNd
<other>ccc</other> <-- pDelNd
<something> and <other> are paragraph
attributes. The attribute <something> stayed if not
overwritten by an attribute in "ccc". Fixed by
first resetting all character attributes in first
paragraph (pTxtNd).
*/
SvUShorts * pShorts =
lcl_RangesToUShorts(aCharFmtSetRange);
pTxtNd->ResetAttr(*pShorts);
delete pShorts;
if( pDelNd->HasSwAttrSet() )
{
// nur die Zeichenattribute kopieren
SfxItemSet aTmpSet( pDoc->GetAttrPool(), aCharFmtSetRange );
aTmpSet.Put( *pDelNd->GetpSwAttrSet() );
pTxtNd->SetAttr( aTmpSet );
}
}
pDoc->CorrRel( aIdx, *rPam.GetPoint(), 0, sal_True );
// --> OD 2009-08-20 #i100466#
// adjust given <rPam>, if it does not belong to the cursors
if ( pDelNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() )
{
rPam.GetBound( sal_True ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
}
if( pDelNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() )
{
rPam.GetBound( sal_False ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
}
// <--
pTxtNd->JoinNext();
}
}
}
static void
lcl_CalcBreaks( ::std::vector<xub_StrLen> & rBreaks, SwPaM const & rPam )
{
SwTxtNode const * const pTxtNode(
rPam.End()->nNode.GetNode().GetTxtNode() );
if (!pTxtNode)
return; // left-overlap only possible at end of selection...
const xub_StrLen nStart(rPam.Start()->nContent.GetIndex());
const xub_StrLen nEnd (rPam.End ()->nContent.GetIndex());
if (nEnd == pTxtNode->Len())
return; // paragraph selected until the end
for (xub_StrLen i = nStart; i < nEnd; ++i)
{
const sal_Unicode c(pTxtNode->GetTxt().GetChar(i));
if ((CH_TXTATR_INWORD == c) || (CH_TXTATR_BREAKWORD == c))
{
SwTxtAttr const * const pAttr( pTxtNode->GetTxtAttrForCharAt(i) );
if (pAttr && pAttr->End() && (*pAttr->End() > nEnd))
{
ASSERT(pAttr->HasDummyChar(), "GetTxtAttrForCharAt broken?");
rBreaks.push_back(i);
}
}
}
}
bool lcl_DoWithBreaks(SwDoc & rDoc, SwPaM & rPam,
bool (SwDoc::*pFunc)(SwPaM&, bool), const bool bForceJoinNext = false)
{
::std::vector<xub_StrLen> Breaks;
lcl_CalcBreaks(Breaks, rPam);
if (!Breaks.size())
{
return (rDoc.*pFunc)(rPam, bForceJoinNext);
}
// N.B.: deletion must be split into several parts if the text node
// contains a text attribute with end and with dummy character
// and the selection does not contain the text attribute completely,
// but overlaps its start (left), where the dummy character is.
SwPosition const & rSelectionEnd( *rPam.End() );
bool bRet( true );
// iterate from end to start, to avoid invalidating the offsets!
::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() );
SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node!
SwPosition & rEnd( *aPam.End() );
SwPosition & rStart( *aPam.Start() );
while (iter != Breaks.rend())
{
rStart.nContent = *iter + 1;
if (rEnd.nContent > rStart.nContent) // check if part is empty
{
bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
}
rEnd.nContent = *iter;
++iter;
}
rStart = *rPam.Start(); // set to original start
if (rEnd.nContent > rStart.nContent) // check if part is empty
{
bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
}
return bRet;
}
bool SwDoc::DeleteAndJoinWithRedlineImpl( SwPaM & rPam, const bool )
{
ASSERT( IsRedlineOn(), "DeleteAndJoinWithRedline: redline off" );
{
SwUndoRedlineDelete* pUndo = 0;
RedlineMode_t eOld = GetRedlineMode();
checkRedlining( eOld );
if (GetIDocumentUndoRedo().DoesUndo())
{
//JP 06.01.98: MUSS noch optimiert werden!!!
SetRedlineMode(
(RedlineMode_t) ( nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ) );
GetIDocumentUndoRedo().StartUndo( UNDO_DELETE, NULL );
pUndo = new SwUndoRedlineDelete( rPam, UNDO_DELETE );
GetIDocumentUndoRedo().AppendUndo( pUndo );
}
if ( *rPam.GetPoint() != *rPam.GetMark() )
AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, rPam ), true );
SetModified();
if ( pUndo )
{
GetIDocumentUndoRedo().EndUndo( UNDO_EMPTY, NULL );
// ??? why the hell is the AppendUndo not below the
// CanGrouping, so this hideous cleanup wouldn't be necessary?
// bah, this is redlining, probably changing this would break it...
if ( GetIDocumentUndoRedo().DoesGroupUndo() )
{
SwUndo * const pLastUndo( GetUndoManager().GetLastUndo() );
SwUndoRedlineDelete * const pUndoRedlineDel( dynamic_cast< SwUndoRedlineDelete* >( pLastUndo ) );
if ( pUndoRedlineDel )
{
bool const bMerged = pUndoRedlineDel->CanGrouping( *pUndo );
if ( bMerged )
{
::sw::UndoGuard const undoGuard( GetIDocumentUndoRedo() );
SwUndo const* const pDeleted = GetUndoManager().RemoveLastUndo();
OSL_ENSURE( pDeleted == pUndo, "DeleteAndJoinWithRedlineImpl: "
"undo removed is not undo inserted?" );
delete pDeleted;
}
}
}
//JP 06.01.98: MUSS noch optimiert werden!!!
SetRedlineMode( eOld );
}
return true;
}
}
bool SwDoc::DeleteAndJoinImpl( SwPaM & rPam,
const bool bForceJoinNext )
{
sal_Bool bJoinTxt, bJoinPrev;
lcl_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
// --> OD 2009-08-20 #i100466#
if ( bForceJoinNext )
{
bJoinPrev = sal_False;
}
// <--
{
bool const bSuccess( DeleteRangeImpl( rPam ) );
if (!bSuccess)
return false;
}
if( bJoinTxt )
{
lcl_JoinText( rPam, bJoinPrev );
}
return true;
}
bool SwDoc::DeleteRangeImpl(SwPaM & rPam, const bool)
{
// move all cursors out of the deleted range.
// but first copy the given PaM, because it could be a cursor that
// would be moved!
SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
bool const bSuccess( DeleteRangeImplImpl( aDelPam ) );
if (bSuccess)
{ // now copy position from temp copy to given PaM
*rPam.GetPoint() = *aDelPam.GetPoint();
}
return bSuccess;
}
bool SwDoc::DeleteRangeImplImpl(SwPaM & rPam)
{
SwPosition *pStt = (SwPosition*)rPam.Start(), *pEnd = (SwPosition*)rPam.End();
if( !rPam.HasMark() || *pStt >= *pEnd )
return false;
if( pACEWord )
{
// ggfs. das gesicherte Word fuer die Ausnahme
if( pACEWord->IsDeleted() || pStt->nNode != pEnd->nNode ||
pStt->nContent.GetIndex() + 1 != pEnd->nContent.GetIndex() ||
!pACEWord->CheckDelChar( *pStt ))
delete pACEWord, pACEWord = 0;
}
{
// loesche alle leeren TextHints an der Mark-Position
SwTxtNode* pTxtNd = rPam.GetMark()->nNode.GetNode().GetTxtNode();
SwpHints* pHts;
if( pTxtNd && 0 != ( pHts = pTxtNd->GetpSwpHints()) && pHts->Count() )
{
const xub_StrLen *pEndIdx;
xub_StrLen nMkCntPos = rPam.GetMark()->nContent.GetIndex();
for( sal_uInt16 n = pHts->Count(); n; )
{
const SwTxtAttr* pAttr = (*pHts)[ --n ];
if( nMkCntPos > *pAttr->GetStart() )
break;
if( nMkCntPos == *pAttr->GetStart() &&
0 != (pEndIdx = pAttr->End()) &&
*pEndIdx == *pAttr->GetStart() )
pTxtNd->DestroyAttr( pHts->Cut( n ) );
}
}
}
{
// Bug 26675: DataChanged vorm loeschen verschicken, dann bekommt
// man noch mit, welche Objecte sich im Bereich befinden.
// Danach koennen sie vor/hinter der Position befinden.
SwDataChanged aTmp( rPam, 0 );
}
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().ClearRedo();
bool bMerged(false);
if (GetIDocumentUndoRedo().DoesGroupUndo())
{
SwUndo *const pLastUndo( GetUndoManager().GetLastUndo() );
SwUndoDelete *const pUndoDelete(
dynamic_cast<SwUndoDelete *>(pLastUndo) );
if (pUndoDelete)
{
bMerged = pUndoDelete->CanGrouping( this, rPam );
// if CanGrouping() returns true it's already merged
}
}
if (!bMerged)
{
GetIDocumentUndoRedo().AppendUndo( new SwUndoDelete( rPam ) );
}
SetModified();
return true;
}
if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
DeleteRedline( rPam, true, USHRT_MAX );
// loesche und verschiebe erstmal alle "Fly's am Absatz", die in der
// Selection liegen
DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
_DelBookmarks(
pStt->nNode,
pEnd->nNode,
NULL,
&pStt->nContent,
&pEnd->nContent);
SwNodeIndex aSttIdx( pStt->nNode );
SwCntntNode * pCNd = aSttIdx.GetNode().GetCntntNode();
do { // middle checked loop!
if( pCNd )
{
SwTxtNode * pStartTxtNode( pCNd->GetTxtNode() );
if ( pStartTxtNode )
{
// verschiebe jetzt noch den Inhalt in den neuen Node
sal_Bool bOneNd = pStt->nNode == pEnd->nNode;
xub_StrLen nLen = ( bOneNd ? pEnd->nContent.GetIndex()
: pCNd->Len() )
- pStt->nContent.GetIndex();
// falls schon leer, dann nicht noch aufrufen
if( nLen )
{
pStartTxtNode->EraseText( pStt->nContent, nLen );
if( !pStartTxtNode->Len() )
{
// METADATA: remove reference if empty (consider node deleted)
pStartTxtNode->RemoveMetadataReference();
}
}
if( bOneNd ) // das wars schon
break;
aSttIdx++;
}
else
{
// damit beim loeschen keine Indizies mehr angemeldet sind,
// wird hier der SwPaM aus dem Content entfernt !!
pStt->nContent.Assign( 0, 0 );
}
}
pCNd = pEnd->nNode.GetNode().GetCntntNode();
if( pCNd )
{
SwTxtNode * pEndTxtNode( pCNd->GetTxtNode() );
if( pEndTxtNode )
{
// falls schon leer, dann nicht noch aufrufen
if( pEnd->nContent.GetIndex() )
{
SwIndex aIdx( pCNd, 0 );
pEndTxtNode->EraseText( aIdx, pEnd->nContent.GetIndex() );
if( !pEndTxtNode->Len() )
{
// METADATA: remove reference if empty (consider node deleted)
pEndTxtNode->RemoveMetadataReference();
}
}
}
else
{
// damit beim Loeschen keine Indizies mehr angemeldet sind,
// wird hier der SwPaM aus dem Content entfernt !!
pEnd->nContent.Assign( 0, 0 );
}
}
// if the end is not a content node, delete it as well
sal_uInt32 nEnde = pEnd->nNode.GetIndex();
if( pCNd == NULL )
nEnde++;
if( aSttIdx != nEnde )
{
// loesche jetzt die Nodes in das NodesArary
GetNodes().Delete( aSttIdx, nEnde - aSttIdx.GetIndex() );
}
// falls der Node geloescht wurde, in dem der Cursor stand, so
// muss der Content im akt. Content angemeldet werden !!!
pStt->nContent.Assign( pStt->nNode.GetNode().GetCntntNode(),
pStt->nContent.GetIndex() );
// der PaM wird korrigiert, denn falls ueber Nodegrenzen geloescht
// wurde, so stehen sie in unterschieden Nodes. Auch die Selektion
// wird aufgehoben !
*pEnd = *pStt;
rPam.DeleteMark();
} while( sal_False );
if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
CompressRedlines();
SetModified();
return true;
}
// OD 2009-08-20 #i100466#
// Add handling of new optional parameter <bForceJoinNext>
bool SwDoc::DeleteAndJoin( SwPaM & rPam,
const bool bForceJoinNext )
{
if ( lcl_StrLenOverFlow( rPam ) )
return false;
return lcl_DoWithBreaks( *this, rPam, (IsRedlineOn())
? &SwDoc::DeleteAndJoinWithRedlineImpl
: &SwDoc::DeleteAndJoinImpl,
bForceJoinNext );
}
bool SwDoc::DeleteRange( SwPaM & rPam )
{
return lcl_DoWithBreaks( *this, rPam, &SwDoc::DeleteRangeImpl );
}
void lcl_syncGrammarError( SwTxtNode &rTxtNode, linguistic2::ProofreadingResult& rResult,
xub_StrLen /*nBeginGrammarCheck*/, const ModelToViewHelper::ConversionMap* pConversionMap )
{
if( rTxtNode.IsGrammarCheckDirty() )
return;
SwGrammarMarkUp* pWrong = rTxtNode.GetGrammarCheck();
linguistic2::SingleProofreadingError* pArray = rResult.aErrors.getArray();
sal_uInt16 i, j = 0;
if( pWrong )
{
for( i = 0; i < rResult.aErrors.getLength(); ++i )
{
const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i];
xub_StrLen nStart = (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart ).mnPos;
xub_StrLen nEnd = (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart + rError.nErrorLength ).mnPos;
if( i != j )
pArray[j] = pArray[i];
if( pWrong->LookForEntry( nStart, nEnd ) )
++j;
}
}
if( rResult.aErrors.getLength() > j )
rResult.aErrors.realloc( j );
}
uno::Any SwDoc::Spell( SwPaM& rPaM,
uno::Reference< XSpellChecker1 > &xSpeller,
sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
bool bGrammarCheck,
SwConversionArgs *pConvArgs ) const
{
SwPosition* pSttPos = rPaM.Start(), *pEndPos = rPaM.End();
uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() );
SwSpellArgs *pSpellArgs = 0;
//SwConversionArgs *pConvArgs = 0;
if (pConvArgs)
{
pConvArgs->SetStart(pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent);
pConvArgs->SetEnd( pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent );
}
else
pSpellArgs = new SwSpellArgs( xSpeller,
pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent,
pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent,
bGrammarCheck );
sal_uLong nCurrNd = pSttPos->nNode.GetIndex();
sal_uLong nEndNd = pEndPos->nNode.GetIndex();
uno::Any aRet;
if( nCurrNd <= nEndNd )
{
SwCntntFrm* pCntFrm;
sal_Bool bGoOn = sal_True;
while( bGoOn )
{
SwNode* pNd = GetNodes()[ nCurrNd ];
switch( pNd->GetNodeType() )
{
case ND_TEXTNODE:
if( 0 != ( pCntFrm = ((SwTxtNode*)pNd)->getLayoutFrm( GetCurrentLayout() )) )
{
// geschutze Cellen/Flys ueberspringen, ausgeblendete
//ebenfalls
if( pCntFrm->IsProtected() )
{
nCurrNd = pNd->EndOfSectionIndex();
}
else if( !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
{
if( pPageCnt && *pPageCnt && pPageSt )
{
sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
if( !*pPageSt )
{
*pPageSt = nPageNr;
if( *pPageCnt < *pPageSt )
*pPageCnt = *pPageSt;
}
long nStat;
if( nPageNr >= *pPageSt )
nStat = nPageNr - *pPageSt + 1;
else
nStat = nPageNr + *pPageCnt - *pPageSt + 1;
::SetProgressState( nStat, (SwDocShell*)GetDocShell() );
}
//Spell() changes the pSpellArgs in case an error is found
xub_StrLen nBeginGrammarCheck = 0;
xub_StrLen nEndGrammarCheck = 0;
if( pSpellArgs && pSpellArgs->bIsGrammarCheck)
{
nBeginGrammarCheck = pSpellArgs->pStartNode == pNd ? pSpellArgs->pStartIdx->GetIndex() : 0;
// if grammar checking starts inside of a sentence the start position has to be adjusted
if( nBeginGrammarCheck )
{
SwIndex aStartIndex( dynamic_cast< SwTxtNode* >( pNd ), nBeginGrammarCheck );
SwPosition aStart( *pNd, aStartIndex );
SwCursor aCrsr(aStart, 0, false);
SwPosition aOrigPos = *aCrsr.GetPoint();
aCrsr.GoSentence( SwCursor::START_SENT );
if( aOrigPos != *aCrsr.GetPoint() )
{
nBeginGrammarCheck = aCrsr.GetPoint()->nContent.GetIndex();
}
}
nEndGrammarCheck = pSpellArgs->pEndNode == pNd ? pSpellArgs->pEndIdx->GetIndex() : ((SwTxtNode*)pNd)->GetTxt().Len();
}
xub_StrLen nSpellErrorPosition = ((SwTxtNode*)pNd)->GetTxt().Len();
if( (!pConvArgs &&
((SwTxtNode*)pNd)->Spell( pSpellArgs )) ||
( pConvArgs &&
((SwTxtNode*)pNd)->Convert( *pConvArgs )))
{
// Abbrechen und Position merken
pSttPos->nNode = nCurrNd;
pEndPos->nNode = nCurrNd;
nCurrNd = nEndNd;
if( pSpellArgs )
nSpellErrorPosition = pSpellArgs->pStartIdx->GetIndex() > pSpellArgs->pEndIdx->GetIndex() ?
pSpellArgs->pEndIdx->GetIndex() :
pSpellArgs->pStartIdx->GetIndex();
}
if( pSpellArgs && pSpellArgs->bIsGrammarCheck )
{
uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( GetGCIterator() );
if (xGCIterator.is())
{
String aText( ((SwTxtNode*)pNd)->GetTxt().Copy( nBeginGrammarCheck, nEndGrammarCheck - nBeginGrammarCheck ) );
uno::Reference< lang::XComponent > xDoc( ((SwDocShell*)GetDocShell())->GetBaseModel(), uno::UNO_QUERY );
// Expand the string:
rtl::OUString aExpandText;
const ModelToViewHelper::ConversionMap* pConversionMap =
((SwTxtNode*)pNd)->BuildConversionMap( aExpandText );
// get XFlatParagraph to use...
uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *((SwTxtNode*)pNd), aExpandText, pConversionMap );
// get error position of cursor in XFlatParagraph
sal_Int32 nGrammarErrorPosInText;
linguistic2::ProofreadingResult aResult;
sal_Int32 nGrammarErrors;
do
{
nGrammarErrorPosInText = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nBeginGrammarCheck );
aResult = xGCIterator->checkSentenceAtPosition(
xDoc, xFlatPara, aExpandText, lang::Locale(), nBeginGrammarCheck, -1, -1 );
lcl_syncGrammarError( *((SwTxtNode*)pNd), aResult, nBeginGrammarCheck, pConversionMap );
// get suggestions to use for the specific error position
nGrammarErrors = aResult.aErrors.getLength();
// if grammar checking doesn't have any progress then quit
if( aResult.nStartOfNextSentencePosition <= nBeginGrammarCheck )
break;
// prepare next iteration
nBeginGrammarCheck = (xub_StrLen)aResult.nStartOfNextSentencePosition;
}
while( nSpellErrorPosition > aResult.nBehindEndOfSentencePosition && !nGrammarErrors && aResult.nBehindEndOfSentencePosition < nEndGrammarCheck );
if( nGrammarErrors > 0 && nSpellErrorPosition >= aResult.nBehindEndOfSentencePosition )
{
aRet <<= aResult;
//put the cursor to the current error
const linguistic2::SingleProofreadingError &rError = aResult.aErrors[0];
nCurrNd = pNd->GetIndex();
pSttPos->nNode = nCurrNd;
pEndPos->nNode = nCurrNd;
pSpellArgs->pStartNode = ((SwTxtNode*)pNd);
pSpellArgs->pEndNode = ((SwTxtNode*)pNd);
pSpellArgs->pStartIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart ).mnPos );
pSpellArgs->pEndIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart + rError.nErrorLength ).mnPos );
nCurrNd = nEndNd;
}
}
}
}
}
break;
case ND_SECTIONNODE:
if( ( ((SwSectionNode*)pNd)->GetSection().IsProtect() ||
((SwSectionNode*)pNd)->GetSection().IsHidden() ) )
nCurrNd = pNd->EndOfSectionIndex();
break;
case ND_ENDNODE:
{
break;
}
}
bGoOn = nCurrNd < nEndNd;
++nCurrNd;
}
}
if( !aRet.hasValue() )
{
if (pConvArgs)
aRet <<= pConvArgs->aConvText;
else
aRet <<= pSpellArgs->xSpellAlt;
}
delete pSpellArgs;
return aRet;
}
class SwHyphArgs : public SwInterHyphInfo
{
const SwNode *pStart;
const SwNode *pEnd;
SwNode *pNode;
sal_uInt16 *pPageCnt;
sal_uInt16 *pPageSt;
sal_uInt32 nNode;
xub_StrLen nPamStart;
xub_StrLen nPamLen;
public:
SwHyphArgs( const SwPaM *pPam, const Point &rPoint,
sal_uInt16* pPageCount, sal_uInt16* pPageStart );
void SetPam( SwPaM *pPam ) const;
inline void SetNode( SwNode *pNew ) { pNode = pNew; }
inline const SwNode *GetNode() const { return pNode; }
inline void SetRange( const SwNode *pNew );
inline void NextNode() { ++nNode; }
inline sal_uInt16 *GetPageCnt() { return pPageCnt; }
inline sal_uInt16 *GetPageSt() { return pPageSt; }
};
SwHyphArgs::SwHyphArgs( const SwPaM *pPam, const Point &rCrsrPos,
sal_uInt16* pPageCount, sal_uInt16* pPageStart )
: SwInterHyphInfo( rCrsrPos ), pNode(0),
pPageCnt( pPageCount ), pPageSt( pPageStart )
{
// Folgende Bedingungen muessen eingehalten werden:
// 1) es gibt mindestens eine Selektion
// 2) SPoint() == Start()
ASSERT( pPam->HasMark(), "SwDoc::Hyphenate: blowing in the wind");
ASSERT( *pPam->GetPoint() <= *pPam->GetMark(),
"SwDoc::Hyphenate: New York, New York");
const SwPosition *pPoint = pPam->GetPoint();
nNode = pPoint->nNode.GetIndex();
// Start einstellen
pStart = pPoint->nNode.GetNode().GetTxtNode();
nPamStart = pPoint->nContent.GetIndex();
// Ende und Laenge einstellen.
const SwPosition *pMark = pPam->GetMark();
pEnd = pMark->nNode.GetNode().GetTxtNode();
nPamLen = pMark->nContent.GetIndex();
if( pPoint->nNode == pMark->nNode )
nPamLen = nPamLen - pPoint->nContent.GetIndex();
}
inline void SwHyphArgs::SetRange( const SwNode *pNew )
{
nStart = pStart == pNew ? nPamStart : 0;
nLen = pEnd == pNew ? nPamLen : STRING_NOTFOUND;
}
void SwHyphArgs::SetPam( SwPaM *pPam ) const
{
if( !pNode )
*pPam->GetPoint() = *pPam->GetMark();
else
{
pPam->GetPoint()->nNode = nNode;
pPam->GetPoint()->nContent.Assign( pNode->GetCntntNode(), nWordStart );
pPam->GetMark()->nNode = nNode;
pPam->GetMark()->nContent.Assign( pNode->GetCntntNode(),
nWordStart + nWordLen );
ASSERT( nNode == pNode->GetIndex(),
"SwHyphArgs::SetPam: Pam desaster" );
}
}
// liefert sal_True zurueck, wenn es weitergehen soll.
sal_Bool lcl_HyphenateNode( const SwNodePtr& rpNd, void* pArgs )
{
// Hyphenate liefert sal_True zurueck, wenn eine Trennstelle anliegt
// und stellt pPam ein.
SwTxtNode *pNode = rpNd->GetTxtNode();
SwHyphArgs *pHyphArgs = (SwHyphArgs*)pArgs;
if( pNode )
{
SwCntntFrm* pCntFrm = pNode->getLayoutFrm( pNode->GetDoc()->GetCurrentLayout() );
if( pCntFrm && !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
{
sal_uInt16 *pPageSt = pHyphArgs->GetPageSt();
sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt();
if( pPageCnt && *pPageCnt && pPageSt )
{
sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
if( !*pPageSt )
{
*pPageSt = nPageNr;
if( *pPageCnt < *pPageSt )
*pPageCnt = *pPageSt;
}
long nStat = nPageNr >= *pPageSt ? nPageNr - *pPageSt + 1
: nPageNr + *pPageCnt - *pPageSt + 1;
::SetProgressState( nStat, (SwDocShell*)pNode->GetDoc()->GetDocShell() );
}
pHyphArgs->SetRange( rpNd );
if( pNode->Hyphenate( *pHyphArgs ) )
{
pHyphArgs->SetNode( rpNd );
return sal_False;
}
}
}
pHyphArgs->NextNode();
return sal_True;
}
uno::Reference< XHyphenatedWord > SwDoc::Hyphenate(
SwPaM *pPam, const Point &rCrsrPos,
sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
{
ASSERT(this == pPam->GetDoc(), "SwDoc::Hyphenate: strangers in the night");
if( *pPam->GetPoint() > *pPam->GetMark() )
pPam->Exchange();
SwHyphArgs aHyphArg( pPam, rCrsrPos, pPageCnt, pPageSt );
SwNodeIndex aTmpIdx( pPam->GetMark()->nNode, 1 );
GetNodes().ForEach( pPam->GetPoint()->nNode, aTmpIdx,
lcl_HyphenateNode, &aHyphArg );
aHyphArg.SetPam( pPam );
return aHyphArg.GetHyphWord(); // will be set by lcl_HyphenateNode
}
sal_Bool lcl_GetTokenToParaBreak( String& rStr, String& rRet, sal_Bool bRegExpRplc )
{
sal_Bool bRet = sal_False;
if( bRegExpRplc )
{
xub_StrLen nPos = 0;
String sPara( String::CreateFromAscii(
RTL_CONSTASCII_STRINGPARAM( "\\n" )));
while( STRING_NOTFOUND != ( nPos = rStr.Search( sPara, nPos )) )
{
// wurde das escaped?
if( nPos && '\\' == rStr.GetChar( nPos-1 ))
{
if( ++nPos >= rStr.Len() )
break;
}
else
{
rRet = rStr.Copy( 0, nPos );
rStr.Erase( 0, nPos + sPara.Len() );
bRet = sal_True;
break;
}
}
}
if( !bRet )
{
rRet = rStr;
rStr.Erase();
}
return bRet;
}
bool SwDoc::ReplaceRange( SwPaM& rPam, const String& rStr,
const bool bRegExReplace )
{
// unfortunately replace works slightly differently from delete,
// so we cannot use lcl_DoWithBreaks here...
::std::vector<xub_StrLen> Breaks;
SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
aPam.Normalize(sal_False);
if (aPam.GetPoint()->nNode != aPam.GetMark()->nNode)
{
aPam.Move(fnMoveBackward);
}
ASSERT((aPam.GetPoint()->nNode == aPam.GetMark()->nNode), "invalid pam?");
lcl_CalcBreaks(Breaks, aPam);
while (!Breaks.empty() // skip over prefix of dummy chars
&& (aPam.GetMark()->nContent.GetIndex() == *Breaks.begin()) )
{
// skip!
++aPam.GetMark()->nContent; // always in bounds if Breaks valid
Breaks.erase(Breaks.begin());
}
*rPam.Start() = *aPam.GetMark(); // update start of original pam w/ prefix
if (!Breaks.size())
{
return ReplaceRangeImpl(rPam, rStr, bRegExReplace); // original pam!
}
// N.B.: deletion must be split into several parts if the text node
// contains a text attribute with end and with dummy character
// and the selection does not contain the text attribute completely,
// but overlaps its start (left), where the dummy character is.
bool bRet( true );
// iterate from end to start, to avoid invalidating the offsets!
::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() );
ASSERT(aPam.GetPoint() == aPam.End(), "wrong!");
SwPosition & rEnd( *aPam.End() );
SwPosition & rStart( *aPam.Start() );
// set end of temp pam to original end (undo Move backward above)
rEnd = *rPam.End();
// after first deletion, rEnd will point into the original text node again!
while (iter != Breaks.rend())
{
rStart.nContent = *iter + 1;
if (rEnd.nContent != rStart.nContent) // check if part is empty
{
bRet &= (IsRedlineOn())
? DeleteAndJoinWithRedlineImpl(aPam)
: DeleteAndJoinImpl(aPam, false);
}
rEnd.nContent = *iter;
++iter;
}
rStart = *rPam.Start(); // set to original start
ASSERT(rEnd.nContent > rStart.nContent, "replace part empty!");
if (rEnd.nContent > rStart.nContent) // check if part is empty
{
bRet &= ReplaceRangeImpl(aPam, rStr, bRegExReplace);
}
rPam = aPam; // update original pam (is this required?)
return bRet;
}
// N.B.: it is possible to call Replace with a PaM that spans 2 paragraphs:
// search with regex for "$", then replace _all_
bool SwDoc::ReplaceRangeImpl( SwPaM& rPam, const String& rStr,
const bool bRegExReplace )
{
if( !rPam.HasMark() || *rPam.GetPoint() == *rPam.GetMark() )
return false;
sal_Bool bJoinTxt, bJoinPrev;
lcl_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
{
// dann eine Kopie vom Cursor erzeugen um alle Pams aus den
// anderen Sichten aus dem Loeschbereich zu verschieben
// ABER NICHT SICH SELBST !!
SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
SwPosition *pStt = (SwPosition*)aDelPam.Start(),
*pEnd = (SwPosition*)aDelPam.End();
ASSERT( pStt->nNode == pEnd->nNode ||
( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() &&
!pEnd->nContent.GetIndex() ),
"invalid range: Point and Mark on different nodes" );
sal_Bool bOneNode = pStt->nNode == pEnd->nNode;
// eigenes Undo ????
String sRepl( rStr );
SwTxtNode* pTxtNd = pStt->nNode.GetNode().GetTxtNode();
xub_StrLen nStt = pStt->nContent.GetIndex(),
nEnd = bOneNode ? pEnd->nContent.GetIndex()
: pTxtNd->GetTxt().Len();
SwDataChanged aTmp( aDelPam, 0 );
if( IsRedlineOn() )
{
RedlineMode_t eOld = GetRedlineMode();
checkRedlining(eOld);
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
// Bug 68584 - if any Redline will change (split!) the node
const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, ::rtl::OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
//JP 06.01.98: MUSS noch optimiert werden!!!
SetRedlineMode(
(RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ));
*aDelPam.GetPoint() = pBkmk->GetMarkPos();
if(pBkmk->IsExpanded())
*aDelPam.GetMark() = pBkmk->GetOtherMarkPos();
getIDocumentMarkAccess()->deleteMark(pBkmk);
pStt = aDelPam.Start();
pTxtNd = pStt->nNode.GetNode().GetTxtNode();
nStt = pStt->nContent.GetIndex();
}
if( sRepl.Len() )
{
// Attribute des 1. Zeichens ueber den ReplaceText setzen
SfxItemSet aSet( GetAttrPool(),
RES_CHRATR_BEGIN, RES_TXTATR_WITHEND_END - 1,
RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
0 );
pTxtNd->GetAttr( aSet, nStt+1, nStt+1 );
aSet.ClearItem( RES_TXTATR_REFMARK );
aSet.ClearItem( RES_TXTATR_TOXMARK );
aSet.ClearItem( RES_TXTATR_CJK_RUBY );
aSet.ClearItem( RES_TXTATR_INETFMT );
aSet.ClearItem( RES_TXTATR_META );
aSet.ClearItem( RES_TXTATR_METAFIELD );
if( aDelPam.GetPoint() != aDelPam.End() )
aDelPam.Exchange();
// das Ende merken
SwNodeIndex aPtNd( aDelPam.GetPoint()->nNode, -1 );
xub_StrLen nPtCnt = aDelPam.GetPoint()->nContent.GetIndex();
sal_Bool bFirst = sal_True;
String sIns;
while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
{
InsertString( aDelPam, sIns );
if( bFirst )
{
SwNodeIndex aMkNd( aDelPam.GetMark()->nNode, -1 );
xub_StrLen nMkCnt = aDelPam.GetMark()->nContent.GetIndex();
SplitNode( *aDelPam.GetPoint(), false );
aMkNd++;
aDelPam.GetMark()->nNode = aMkNd;
aDelPam.GetMark()->nContent.Assign(
aMkNd.GetNode().GetCntntNode(), nMkCnt );
bFirst = sal_False;
}
else
SplitNode( *aDelPam.GetPoint(), false );
}
if( sIns.Len() )
{
InsertString( aDelPam, sIns );
}
SwPaM aTmpRange( *aDelPam.GetPoint() );
aTmpRange.SetMark();
aPtNd++;
aDelPam.GetPoint()->nNode = aPtNd;
aDelPam.GetPoint()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
nPtCnt);
*aTmpRange.GetMark() = *aDelPam.GetPoint();
RstTxtAttrs( aTmpRange );
InsertItemSet( aTmpRange, aSet, 0 );
}
if (GetIDocumentUndoRedo().DoesUndo())
{
SwUndo *const pUndoRD =
new SwUndoRedlineDelete( aDelPam, UNDO_REPLACE );
GetIDocumentUndoRedo().AppendUndo(pUndoRD);
}
AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDelPam ), true);
*rPam.GetMark() = *aDelPam.GetMark();
if (GetIDocumentUndoRedo().DoesUndo())
{
*aDelPam.GetPoint() = *rPam.GetPoint();
GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
// Bug 68584 - if any Redline will change (split!) the node
const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, ::rtl::OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
SwIndex& rIdx = aDelPam.GetPoint()->nContent;
rIdx.Assign( 0, 0 );
aDelPam.GetMark()->nContent = rIdx;
rPam.GetPoint()->nNode = 0;
rPam.GetPoint()->nContent = rIdx;
*rPam.GetMark() = *rPam.GetPoint();
//JP 06.01.98: MUSS noch optimiert werden!!!
SetRedlineMode( eOld );
*rPam.GetPoint() = pBkmk->GetMarkPos();
if(pBkmk->IsExpanded())
*rPam.GetMark() = pBkmk->GetOtherMarkPos();
getIDocumentMarkAccess()->deleteMark(pBkmk);
}
bJoinTxt = sal_False;
}
else
{
if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
DeleteRedline( aDelPam, true, USHRT_MAX );
SwUndoReplace* pUndoRpl = 0;
bool const bDoesUndo = GetIDocumentUndoRedo().DoesUndo();
if (bDoesUndo)
{
pUndoRpl = new SwUndoReplace(aDelPam, sRepl, bRegExReplace);
GetIDocumentUndoRedo().AppendUndo(pUndoRpl);
}
::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
if( aDelPam.GetPoint() != pStt )
aDelPam.Exchange();
SwNodeIndex aPtNd( pStt->nNode, -1 );
xub_StrLen nPtCnt = pStt->nContent.GetIndex();
// die Werte nochmal setzen, falls schohn Rahmen oder Fussnoten
// auf dem Text entfernt wurden!
nStt = nPtCnt;
nEnd = bOneNode ? pEnd->nContent.GetIndex()
: pTxtNd->GetTxt().Len();
sal_Bool bFirst = sal_True;
String sIns;
while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
{
if( !bFirst || nStt == pTxtNd->GetTxt().Len() )
{
InsertString( aDelPam, sIns );
}
else if( nStt < nEnd || sIns.Len() )
{
pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
}
SplitNode( *pStt, false);
bFirst = sal_False;
}
if( bFirst || sIns.Len() )
{
if( !bFirst || nStt == pTxtNd->GetTxt().Len() )
{
InsertString( aDelPam, sIns );
}
else if( nStt < nEnd || sIns.Len() )
{
pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
}
}
*rPam.GetMark() = *aDelPam.GetMark();
aPtNd++;
rPam.GetMark()->nNode = aPtNd;
rPam.GetMark()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
nPtCnt );
if ( bJoinTxt && !bJoinPrev )
{
rPam.Move( fnMoveBackward );
}
if( pUndoRpl )
{
pUndoRpl->SetEnd(rPam);
}
}
}
if( bJoinTxt )
lcl_JoinText( rPam, bJoinPrev );
SetModified();
return true;
}
// speicher die akt. Werte fuer die automatische Aufnahme von Ausnahmen
// in die Autokorrektur
void SwDoc::SetAutoCorrExceptWord( SwAutoCorrExceptWord* pNew )
{
if( pACEWord && pNew != pACEWord )
delete pACEWord;
pACEWord = pNew;
}
bool SwDoc::DelFullPara( SwPaM& rPam )
{
const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
const SwNode* pNd = &rStt.nNode.GetNode();
sal_uInt32 nSectDiff = pNd->StartOfSectionNode()->EndOfSectionIndex() -
pNd->StartOfSectionIndex();
sal_uInt32 nNodeDiff = rEnd.nNode.GetIndex() - rStt.nNode.GetIndex();
if ( nSectDiff-2 <= nNodeDiff || IsRedlineOn() ||
/* #i9185# Prevent getting the node after the end node (see below) */
rEnd.nNode.GetIndex() + 1 == GetNodes().Count() )
{
return sal_False;
}
// harte SeitenUmbrueche am nachfolgenden Node verschieben
sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False;
/* #i9185# This whould lead to a segmentation fault if not catched
above. */
sal_uLong nNextNd = rEnd.nNode.GetIndex() + 1;
SwTableNode *const pTblNd = GetNodes()[ nNextNd ]->GetTableNode();
if( pTblNd && pNd->IsCntntNode() )
{
SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
//JP 24.08.98: will man wirklich den PageDesc/Break vom
// nachfolgen Absatz ueberbuegeln?
// const SwAttrSet& rAttrSet = pTableFmt->GetAttrSet();
// if( SFX_ITEM_SET != rAttrSet.GetItemState( RES_PAGEDESC ) &&
// SFX_ITEM_SET != rAttrSet.GetItemState( RES_BREAK ))
{
const SfxPoolItem *pItem;
const SfxItemSet* pSet = ((SwCntntNode*)pNd)->GetpSwAttrSet();
if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
sal_False, &pItem ) )
{
pTableFmt->SetFmtAttr( *pItem );
bSavePageDesc = sal_True;
}
if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
sal_False, &pItem ) )
{
pTableFmt->SetFmtAttr( *pItem );
bSavePageBreak = sal_True;
}
}
}
bool const bDoesUndo = GetIDocumentUndoRedo().DoesUndo();
if( bDoesUndo )
{
if( !rPam.HasMark() )
rPam.SetMark();
else if( rPam.GetPoint() == &rStt )
rPam.Exchange();
rPam.GetPoint()->nNode++;
SwCntntNode *pTmpNode = rPam.GetPoint()->nNode.GetNode().GetCntntNode();
rPam.GetPoint()->nContent.Assign( pTmpNode, 0 );
bool bGoNext = (0 == pTmpNode);
pTmpNode = rPam.GetMark()->nNode.GetNode().GetCntntNode();
rPam.GetMark()->nContent.Assign( pTmpNode, 0 );
GetIDocumentUndoRedo().ClearRedo();
SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
{
SwPosition aTmpPos( *aDelPam.GetPoint() );
if( bGoNext )
{
pTmpNode = GetNodes().GoNext( &aTmpPos.nNode );
aTmpPos.nContent.Assign( pTmpNode, 0 );
}
::PaMCorrAbs( aDelPam, aTmpPos );
}
SwUndoDelete* pUndo = new SwUndoDelete( aDelPam, sal_True );
*rPam.GetPoint() = *aDelPam.GetPoint();
pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
GetIDocumentUndoRedo().AppendUndo(pUndo);
}
else
{
SwNodeRange aRg( rStt.nNode, rEnd.nNode );
if( rPam.GetPoint() != &rEnd )
rPam.Exchange();
// versuche hinters Ende zu verschieben
if( !rPam.Move( fnMoveForward, fnGoNode ) )
{
// na gut, dann an den Anfang
rPam.Exchange();
if( !rPam.Move( fnMoveBackward, fnGoNode ))
{
ASSERT( sal_False, "kein Node mehr vorhanden" );
return sal_False;
}
}
// move bookmarks, redlines etc.
if (aRg.aStart == aRg.aEnd) // only first CorrAbs variant handles this
{
CorrAbs( aRg.aStart, *rPam.GetPoint(), 0, sal_True );
}
else
{
CorrAbs( aRg.aStart, aRg.aEnd, *rPam.GetPoint(), sal_True );
}
// was ist mit Fly's ??
{
// stehen noch FlyFrames rum, loesche auch diese
for( sal_uInt16 n = 0; n < GetSpzFrmFmts()->Count(); ++n )
{
SwFrmFmt* pFly = (*GetSpzFrmFmts())[n];
const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
if (pAPos &&
((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
(FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd )
{
DelLayoutFmt( pFly );
--n;
}
}
}
SwCntntNode *pTmpNode = rPam.GetBound( sal_True ).nNode.GetNode().GetCntntNode();
rPam.GetBound( sal_True ).nContent.Assign( pTmpNode, 0 );
pTmpNode = rPam.GetBound( sal_False ).nNode.GetNode().GetCntntNode();
rPam.GetBound( sal_False ).nContent.Assign( pTmpNode, 0 );
GetNodes().Delete( aRg.aStart, nNodeDiff+1 );
}
rPam.DeleteMark();
SetModified();
return sal_True;
}
void SwDoc::TransliterateText(
const SwPaM& rPaM,
utl::TransliterationWrapper& rTrans )
{
SwUndoTransliterate *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
? new SwUndoTransliterate( rPaM, rTrans )
: 0;
const SwPosition* pStt = rPaM.Start(),
* pEnd = rPaM.End();
sal_uLong nSttNd = pStt->nNode.GetIndex(),
nEndNd = pEnd->nNode.GetIndex();
xub_StrLen nSttCnt = pStt->nContent.GetIndex(),
nEndCnt = pEnd->nContent.GetIndex();
SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
if( pStt == pEnd && pTNd ) // no selection?
{
// set current word as 'area of effect'
Boundary aBndry;
if( pBreakIt->GetBreakIter().is() )
aBndry = pBreakIt->GetBreakIter()->getWordBoundary(
pTNd->GetTxt(), nSttCnt,
pBreakIt->GetLocale( pTNd->GetLang( nSttCnt ) ),
WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
sal_True );
if( aBndry.startPos < nSttCnt && nSttCnt < aBndry.endPos )
{
nSttCnt = (xub_StrLen)aBndry.startPos;
nEndCnt = (xub_StrLen)aBndry.endPos;
}
}
if( nSttNd != nEndNd ) // is more than one text node involved?
{
// iterate over all effected text nodes, the first and the last one
// may be incomplete because the selection starts and/or ends there
SwNodeIndex aIdx( pStt->nNode );
if( nSttCnt )
{
aIdx++;
if( pTNd )
pTNd->TransliterateText( rTrans, nSttCnt, pTNd->GetTxt().Len(), pUndo );
}
for( ; aIdx.GetIndex() < nEndNd; aIdx++ )
{
if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() ))
pTNd->TransliterateText( rTrans, 0, pTNd->GetTxt().Len(), pUndo );
}
if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo );
}
else if( pTNd && nSttCnt < nEndCnt )
pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo );
if( pUndo )
{
if( pUndo->HasData() )
{
GetIDocumentUndoRedo().AppendUndo(pUndo);
}
else
delete pUndo;
}
SetModified();
}
#define MAX_REDLINE_COUNT 250
// -----------------------------------------------------------------------------
void SwDoc::checkRedlining(RedlineMode_t& _rReadlineMode)
{
const SwRedlineTbl& rRedlineTbl = GetRedlineTbl();
SwEditShell* pEditShell = GetEditShell();
Window* pParent = pEditShell ? pEditShell->GetWin() : NULL;
if ( pParent && !mbReadlineChecked && rRedlineTbl.Count() > MAX_REDLINE_COUNT
&& !((_rReadlineMode & nsRedlineMode_t::REDLINE_SHOW_DELETE) == nsRedlineMode_t::REDLINE_SHOW_DELETE) )
{
WarningBox aWarning( pParent,SW_RES(MSG_DISABLE_READLINE_QUESTION));
sal_uInt16 nResult = aWarning.Execute();
mbReadlineChecked = sal_True;
if ( nResult == RET_YES )
{
sal_Int32 nMode = (sal_Int32)_rReadlineMode;
nMode |= nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE;
_rReadlineMode = (RedlineMode_t)nMode;
}
}
}
// -----------------------------------------------------------------------------
void SwDoc::CountWords( const SwPaM& rPaM, SwDocStat& rStat ) const
{
// This is a modified version of SwDoc::TransliterateText
const SwPosition* pStt = rPaM.Start();
const SwPosition* pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
: rPaM.GetPoint();
const sal_uLong nSttNd = pStt->nNode.GetIndex();
const sal_uLong nEndNd = pEnd->nNode.GetIndex();
const xub_StrLen nSttCnt = pStt->nContent.GetIndex();
const xub_StrLen nEndCnt = pEnd->nContent.GetIndex();
const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
if( pStt == pEnd && pTNd ) // no region ?
{
// do nothing
return;
}
if( nSttNd != nEndNd )
{
SwNodeIndex aIdx( pStt->nNode );
if( nSttCnt )
{
aIdx++;
if( pTNd )
pTNd->CountWords( rStat, nSttCnt, pTNd->GetTxt().Len() );
}
for( ; aIdx.GetIndex() < nEndNd; aIdx++ )
if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() ))
pTNd->CountWords( rStat, 0, pTNd->GetTxt().Len() );
if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
pTNd->CountWords( rStat, 0, nEndCnt );
}
else if( pTNd && nSttCnt < nEndCnt )
pTNd->CountWords( rStat, nSttCnt, nEndCnt );
}
void SwDoc::RemoveLeadingWhiteSpace(const SwPosition & rPos )
{
const SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode();
if ( pTNd )
{
const String& rTxt = pTNd->GetTxt();
xub_StrLen nIdx = 0;
sal_Unicode cCh;
while( nIdx < rTxt.Len() &&
( '\t' == ( cCh = rTxt.GetChar( nIdx ) ) ||
( ' ' == cCh ) ) )
++nIdx;
if ( nIdx > 0 )
{
SwPaM aPam(rPos);
aPam.GetPoint()->nContent = 0;
aPam.SetMark();
aPam.GetMark()->nContent = nIdx;
DeleteRange( aPam );
}
}
}