| /************************************************************** |
| * |
| * 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 ); |
| } |
| } |
| } |