Update ooo320-m1
[ooovba.git] / sw / source / core / undo / unovwr.cxx
blobd91db0515e837057025574d8b4d55078ee3f189d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: unovwr.cxx,v $
10 * $Revision: 1.20 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <unotools/charclass.hxx>
36 #include <unotools/transliterationwrapper.hxx>
37 #include <comphelper/processfactory.hxx>
38 #include <doc.hxx>
39 #include <swundo.hxx> // fuer die UndoIds
40 #include <pam.hxx>
41 #include <ndtxt.hxx>
42 #include <undobj.hxx>
43 #include <rolbck.hxx>
44 #include <acorrect.hxx>
45 #include <docary.hxx>
47 #include <tools/resid.hxx>
48 #include <comcore.hrc> // #111827#
49 #include <undo.hrc>
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::i18n;
53 using namespace ::com::sun::star::uno;
55 //------------------------------------------------------------------
57 // zwei Zugriffs-Funktionen
58 inline SwPosition* IterPt( SwUndoIter& rUIter )
59 { return rUIter.pAktPam->GetPoint(); }
60 inline SwPosition* IterMk( SwUndoIter& rUIter )
61 { return rUIter.pAktPam->GetMark(); }
63 inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); }
65 //------------------------------------------------------------
68 // OVERWRITE
71 SwUndoOverwrite::SwUndoOverwrite( SwDoc* pDoc, SwPosition& rPos,
72 sal_Unicode cIns )
73 : SwUndo(UNDO_OVERWRITE),
74 pRedlSaveData( 0 ), bGroup( FALSE )
76 if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() )
78 SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
79 rPos.nNode, rPos.nContent.GetIndex()+1 );
80 pRedlSaveData = new SwRedlineSaveDatas;
81 if( !FillSaveData( aPam, *pRedlSaveData, FALSE ))
82 delete pRedlSaveData, pRedlSaveData = 0;
85 nSttNode = rPos.nNode.GetIndex();
86 nSttCntnt = rPos.nContent.GetIndex();
88 SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
89 ASSERT( pTxtNd, "Overwrite nicht im TextNode?" );
91 bInsChar = TRUE;
92 xub_StrLen nTxtNdLen = pTxtNd->GetTxt().Len();
93 if( nSttCntnt < nTxtNdLen ) // kein reines Einfuegen ?
95 aDelStr.Insert( pTxtNd->GetTxt().GetChar( nSttCntnt ) );
96 if( !pHistory )
97 pHistory = new SwHistory;
98 SwRegHistory aRHst( *pTxtNd, pHistory );
99 pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nSttNode, 0,
100 nTxtNdLen, false );
101 rPos.nContent++;
102 bInsChar = FALSE;
105 BOOL bOldExpFlg = pTxtNd->IsIgnoreDontExpand();
106 pTxtNd->SetIgnoreDontExpand( TRUE );
108 pTxtNd->InsertText( cIns, rPos.nContent,
109 IDocumentContentOperations::INS_EMPTYEXPAND );
110 aInsStr.Insert( cIns );
112 if( !bInsChar )
114 const SwIndex aTmpIndex( rPos.nContent, -2 );
115 pTxtNd->EraseText( aTmpIndex, 1 );
117 pTxtNd->SetIgnoreDontExpand( bOldExpFlg );
119 bCacheComment = false;
122 SwUndoOverwrite::~SwUndoOverwrite()
124 delete pRedlSaveData;
127 BOOL SwUndoOverwrite::CanGrouping( SwDoc* pDoc, SwPosition& rPos,
128 sal_Unicode cIns )
130 /// ?? was ist mit nur eingefuegten Charaktern ???
132 // es kann nur das Loeschen von einzelnen char's zusammengefasst werden
133 if( rPos.nNode != nSttNode || !aInsStr.Len() ||
134 ( !bGroup && aInsStr.Len() != 1 ))
135 return FALSE;
137 // ist der Node ueberhaupt ein TextNode?
138 SwTxtNode * pDelTxtNd = rPos.nNode.GetNode().GetTxtNode();
139 if( !pDelTxtNd ||
140 ( pDelTxtNd->GetTxt().Len() != rPos.nContent.GetIndex() &&
141 rPos.nContent.GetIndex() != ( nSttCntnt + aInsStr.Len() )))
142 return FALSE;
144 CharClass& rCC = GetAppCharClass();
146 // befrage das einzufuegende Charakter
147 if (( CH_TXTATR_BREAKWORD == cIns || CH_TXTATR_INWORD == cIns ) ||
148 rCC.isLetterNumeric( String( cIns ), 0 ) !=
149 rCC.isLetterNumeric( aInsStr, aInsStr.Len()-1 ) )
150 return FALSE;
153 SwRedlineSaveDatas* pTmpSav = new SwRedlineSaveDatas;
154 SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
155 rPos.nNode, rPos.nContent.GetIndex()+1 );
157 if( !FillSaveData( aPam, *pTmpSav, FALSE ))
158 delete pTmpSav, pTmpSav = 0;
160 BOOL bOk = ( !pRedlSaveData && !pTmpSav ) ||
161 ( pRedlSaveData && pTmpSav &&
162 SwUndo::CanRedlineGroup( *pRedlSaveData, *pTmpSav,
163 nSttCntnt > rPos.nContent.GetIndex() ));
164 delete pTmpSav;
165 if( !bOk )
166 return FALSE;
168 pDoc->DeleteRedline( aPam, false, USHRT_MAX );
171 // Ok, die beiden 'Overwrites' koennen zusammen gefasst werden, also
172 // 'verschiebe' das enstprechende Zeichen
173 if( !bInsChar )
175 if( rPos.nContent.GetIndex() < pDelTxtNd->GetTxt().Len() )
177 aDelStr.Insert( pDelTxtNd->GetTxt().GetChar(rPos.nContent.GetIndex()) );
178 rPos.nContent++;
180 else
181 bInsChar = TRUE;
184 BOOL bOldExpFlg = pDelTxtNd->IsIgnoreDontExpand();
185 pDelTxtNd->SetIgnoreDontExpand( TRUE );
187 pDelTxtNd->InsertText( cIns, rPos.nContent,
188 IDocumentContentOperations::INS_EMPTYEXPAND );
189 aInsStr.Insert( cIns );
191 if( !bInsChar )
193 const SwIndex aTmpIndex( rPos.nContent, -2 );
194 pDelTxtNd->EraseText( aTmpIndex, 1 );
196 pDelTxtNd->SetIgnoreDontExpand( bOldExpFlg );
198 bGroup = TRUE;
199 return TRUE;
206 void SwUndoOverwrite::Undo( SwUndoIter& rUndoIter )
208 SwPaM* pAktPam = rUndoIter.pAktPam;
209 SwDoc* pDoc = pAktPam->GetDoc();
210 pAktPam->DeleteMark();
211 pAktPam->GetPoint()->nNode = nSttNode;
212 SwTxtNode* pTxtNd = pAktPam->GetNode()->GetTxtNode();
213 ASSERT( pTxtNd, "Overwrite nicht im TextNode?" );
214 SwIndex& rIdx = pAktPam->GetPoint()->nContent;
215 rIdx.Assign( pTxtNd, nSttCntnt );
217 SwAutoCorrExceptWord* pACEWord = pDoc->GetAutoCorrExceptWord();
218 if( pACEWord )
220 if( 1 == aInsStr.Len() && 1 == aDelStr.Len() )
221 pACEWord->CheckChar( *pAktPam->GetPoint(), aDelStr.GetChar( 0 ) );
222 pDoc->SetAutoCorrExceptWord( 0 );
225 // wurde nicht nur ueberschieben sondern auch geinsertet, so loesche
226 // den Ueberhang
227 if( aInsStr.Len() > aDelStr.Len() )
229 rIdx += aDelStr.Len();
230 pTxtNd->EraseText( rIdx, aInsStr.Len() - aDelStr.Len() );
231 rIdx = nSttCntnt;
234 if( aDelStr.Len() )
236 String aTmpStr( '1' );
237 sal_Unicode* pTmpStr = aTmpStr.GetBufferAccess();
239 BOOL bOldExpFlg = pTxtNd->IsIgnoreDontExpand();
240 pTxtNd->SetIgnoreDontExpand( TRUE );
242 rIdx++;
243 for( xub_StrLen n = 0; n < aDelStr.Len(); n++ )
245 // einzeln, damit die Attribute stehen bleiben !!!
246 *pTmpStr = aDelStr.GetChar( n );
247 pTxtNd->InsertText( aTmpStr, rIdx /*???, SETATTR_NOTXTATRCHR*/ );
248 rIdx -= 2;
249 pTxtNd->EraseText( rIdx, 1 );
250 rIdx += 2;
252 pTxtNd->SetIgnoreDontExpand( bOldExpFlg );
253 rIdx--;
255 if( pHistory )
257 if( pTxtNd->GetpSwpHints() )
258 pTxtNd->ClearSwpHintsArr( false );
259 pHistory->TmpRollback( pDoc, 0, false );
262 if( pAktPam->GetMark()->nContent.GetIndex() != nSttCntnt )
264 pAktPam->SetMark();
265 pAktPam->GetMark()->nContent = nSttCntnt;
268 if( pRedlSaveData )
269 SetSaveData( *pDoc, *pRedlSaveData );
272 void SwUndoOverwrite::Repeat( SwUndoIter& rUndoIter )
274 rUndoIter.pLastUndoObj = this;
275 SwPaM* pAktPam = rUndoIter.pAktPam;
276 if( !aInsStr.Len() || pAktPam->HasMark() )
277 return;
279 SwDoc& rDoc = *pAktPam->GetDoc();
281 BOOL bGroupUndo = rDoc.DoesGroupUndo();
282 rDoc.DoGroupUndo( FALSE );
283 rDoc.Overwrite( *pAktPam, aInsStr.GetChar( 0 ));
284 rDoc.DoGroupUndo( bGroupUndo );
285 for( xub_StrLen n = 1; n < aInsStr.Len(); ++n )
286 rDoc.Overwrite( *pAktPam, aInsStr.GetChar( n ) );
291 void SwUndoOverwrite::Redo( SwUndoIter& rUndoIter )
293 SwPaM* pAktPam = rUndoIter.pAktPam;
294 SwDoc* pDoc = pAktPam->GetDoc();
295 pAktPam->DeleteMark();
296 pAktPam->GetPoint()->nNode = nSttNode;
297 SwTxtNode* pTxtNd = pAktPam->GetNode()->GetTxtNode();
298 ASSERT( pTxtNd, "Overwrite nicht im TextNode?" );
299 SwIndex& rIdx = pAktPam->GetPoint()->nContent;
301 if( pRedlSaveData )
303 rIdx.Assign( pTxtNd, nSttCntnt );
304 pAktPam->SetMark();
305 pAktPam->GetMark()->nContent += aInsStr.Len();
306 pDoc->DeleteRedline( *pAktPam, false, USHRT_MAX );
307 pAktPam->DeleteMark();
309 rIdx.Assign( pTxtNd, aDelStr.Len() ? nSttCntnt+1 : nSttCntnt );
311 BOOL bOldExpFlg = pTxtNd->IsIgnoreDontExpand();
312 pTxtNd->SetIgnoreDontExpand( TRUE );
314 for( xub_StrLen n = 0; n < aInsStr.Len(); n++ )
316 // einzeln, damit die Attribute stehen bleiben !!!
317 pTxtNd->InsertText( aInsStr.GetChar( n ), rIdx,
318 IDocumentContentOperations::INS_EMPTYEXPAND );
319 if( n < aDelStr.Len() )
321 rIdx -= 2;
322 pTxtNd->EraseText( rIdx, 1 );
323 rIdx += n+1 < aDelStr.Len() ? 2 : 1;
326 pTxtNd->SetIgnoreDontExpand( bOldExpFlg );
328 // alte Anfangs-Position vom UndoNodes-Array zurueckholen
329 if( pHistory )
330 pHistory->SetTmpEnd( pHistory->Count() );
331 if( pAktPam->GetMark()->nContent.GetIndex() != nSttCntnt )
333 pAktPam->SetMark();
334 pAktPam->GetMark()->nContent = nSttCntnt;
338 SwRewriter SwUndoOverwrite::GetRewriter() const
340 SwRewriter aResult;
342 String aString;
344 aString += String(SW_RES(STR_START_QUOTE));
345 aString += ShortenString(aInsStr, nUndoStringLength,
346 String(SW_RES(STR_LDOTS)));
347 aString += String(SW_RES(STR_END_QUOTE));
349 aResult.AddRule(UNDO_ARG1, aString);
351 return aResult;
354 //------------------------------------------------------------
356 struct _UndoTransliterate_Data
358 String sText;
359 _UndoTransliterate_Data* pNext;
360 SwHistory* pHistory;
361 Sequence <sal_Int32>* pOffsets;
362 ULONG nNdIdx;
363 xub_StrLen nStart, nLen;
365 _UndoTransliterate_Data( ULONG nNd, xub_StrLen nStt, xub_StrLen nStrLen,
366 const String& rTxt )
367 : sText( rTxt ), pNext( 0 ), pHistory( 0 ), pOffsets( 0 ),
368 nNdIdx( nNd ), nStart( nStt ), nLen( nStrLen )
370 ~_UndoTransliterate_Data() { delete pOffsets; delete pHistory; }
372 void SetChangeAtNode( SwDoc& rDoc );
375 SwUndoTransliterate::SwUndoTransliterate( const SwPaM& rPam,
376 const utl::TransliterationWrapper& rTrans )
377 : SwUndo( UNDO_TRANSLITERATE ), SwUndRng( rPam ),
378 pData( 0 ), pLastData( 0 ), nType( rTrans.getType() )
382 SwUndoTransliterate::~SwUndoTransliterate()
384 _UndoTransliterate_Data* pD = pData;
385 while( pD )
387 pData = pD;
388 pD = pD->pNext;
389 delete pData;
393 void SwUndoTransliterate::Undo( SwUndoIter& rUndoIter )
395 SwDoc& rDoc = rUndoIter.GetDoc();
396 BOOL bUndo = rDoc.DoesUndo();
397 rDoc.DoUndo( FALSE );
399 for( _UndoTransliterate_Data* pD = pData; pD; pD = pD->pNext )
400 pD->SetChangeAtNode( rDoc );
402 rDoc.DoUndo( bUndo );
403 SetPaM( rUndoIter, TRUE );
406 void SwUndoTransliterate::Redo( SwUndoIter& rUndoIter )
408 /* ??? */ rUndoIter.SetUpdateAttr( TRUE );
410 SetPaM( *rUndoIter.pAktPam );
411 Repeat( rUndoIter );
414 void SwUndoTransliterate::Repeat( SwUndoIter& rUndoIter )
416 SwPaM& rPam = *rUndoIter.pAktPam;
417 SwDoc& rDoc = rUndoIter.GetDoc();
419 utl::TransliterationWrapper aTrans(
420 ::comphelper::getProcessServiceFactory(), nType );
421 rDoc.TransliterateText( rPam, aTrans );
423 rUndoIter.pLastUndoObj = this;
426 void SwUndoTransliterate::AddChanges( SwTxtNode& rTNd,
427 xub_StrLen nStart, xub_StrLen nLen,
428 uno::Sequence <sal_Int32>& rOffsets )
430 long nOffsLen = rOffsets.getLength();
431 _UndoTransliterate_Data* pNew = new _UndoTransliterate_Data(
432 rTNd.GetIndex(), nStart, (xub_StrLen)nOffsLen,
433 rTNd.GetTxt().Copy( nStart, nLen ));
434 if( pData )
435 pLastData->pNext = pNew;
436 else
437 pData = pNew;
438 pLastData = pNew;
440 const sal_Int32* pOffsets = rOffsets.getConstArray();
441 // where did we need less memory ?
442 const sal_Int32* p = pOffsets;
443 for( long n = 0; n < nOffsLen; ++n, ++p )
444 if( *p != ( nStart + n ))
446 // create the Offset array
447 pNew->pOffsets = new Sequence <sal_Int32> ( nLen );
448 sal_Int32* pIdx = pNew->pOffsets->getArray();
449 p = pOffsets;
450 long nMyOff, nNewVal = nStart;
451 for( n = 0, nMyOff = nStart; n < nOffsLen; ++p, ++n, ++nMyOff )
453 if( *p < nMyOff )
455 // something is deleted
456 nMyOff = *p;
457 *(pIdx-1) = nNewVal++;
459 else if( *p > nMyOff )
461 for( ; *p > nMyOff; ++nMyOff )
462 *pIdx++ = nNewVal;
463 --nMyOff;
464 --n;
465 --p;
467 else
468 *pIdx++ = nNewVal++;
471 // and then we need to save the attributes/bookmarks
472 // but this data must moved every time to the last in the chain!
473 _UndoTransliterate_Data* pD = pData;
474 while( pD != pNew )
476 if( pD->nNdIdx == pNew->nNdIdx && pD->pHistory )
478 // same node and have a history?
479 pNew->pHistory = pD->pHistory;
480 pD->pHistory = 0;
481 break; // more can't exist
483 pD = pD->pNext;
486 if( !pNew->pHistory )
488 pNew->pHistory = new SwHistory;
489 SwRegHistory aRHst( rTNd, pNew->pHistory );
490 pNew->pHistory->CopyAttr( rTNd.GetpSwpHints(),
491 pNew->nNdIdx, 0, rTNd.GetTxt().Len(), false );
493 break;
497 void _UndoTransliterate_Data::SetChangeAtNode( SwDoc& rDoc )
499 SwTxtNode* pTNd = rDoc.GetNodes()[ nNdIdx ]->GetTxtNode();
500 if( pTNd )
502 Sequence <sal_Int32> aOffsets( pOffsets ? pOffsets->getLength() : nLen );
503 if( pOffsets )
504 aOffsets = *pOffsets;
505 else
507 sal_Int32* p = aOffsets.getArray();
508 for( xub_StrLen n = 0; n < nLen; ++n, ++p )
509 *p = n + nStart;
511 pTNd->ReplaceTextOnly( nStart, nLen, sText, aOffsets );
513 if( pHistory )
515 if( pTNd->GetpSwpHints() )
516 pTNd->ClearSwpHintsArr( false );
517 pHistory->TmpRollback( &rDoc, 0, false );
518 pHistory->SetTmpEnd( pHistory->Count() );