update dev300-m58
[ooovba.git] / sw / source / core / undo / unovwr.cxx
blobd4456125395f5030e2ea9823b2c054138a0065e7
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->Insert( cIns, rPos.nContent );
109 aInsStr.Insert( cIns );
111 if( !bInsChar )
113 const SwIndex aTmpIndex( rPos.nContent, -2 );
114 pTxtNd->Erase( aTmpIndex, 1 );
116 pTxtNd->SetIgnoreDontExpand( bOldExpFlg );
118 bCacheComment = false;
121 SwUndoOverwrite::~SwUndoOverwrite()
123 delete pRedlSaveData;
126 BOOL SwUndoOverwrite::CanGrouping( SwDoc* pDoc, SwPosition& rPos,
127 sal_Unicode cIns )
129 /// ?? was ist mit nur eingefuegten Charaktern ???
131 // es kann nur das Loeschen von einzelnen char's zusammengefasst werden
132 if( rPos.nNode != nSttNode || !aInsStr.Len() ||
133 ( !bGroup && aInsStr.Len() != 1 ))
134 return FALSE;
136 // ist der Node ueberhaupt ein TextNode?
137 SwTxtNode * pDelTxtNd = rPos.nNode.GetNode().GetTxtNode();
138 if( !pDelTxtNd ||
139 ( pDelTxtNd->GetTxt().Len() != rPos.nContent.GetIndex() &&
140 rPos.nContent.GetIndex() != ( nSttCntnt + aInsStr.Len() )))
141 return FALSE;
143 CharClass& rCC = GetAppCharClass();
145 // befrage das einzufuegende Charakter
146 if( ( CH_TXTATR_BREAKWORD == cIns && CH_TXTATR_INWORD == cIns ) ||
147 rCC.isLetterNumeric( String( cIns ), 0 ) !=
148 rCC.isLetterNumeric( aInsStr, aInsStr.Len()-1 ) )
149 return FALSE;
152 SwRedlineSaveDatas* pTmpSav = new SwRedlineSaveDatas;
153 SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
154 rPos.nNode, rPos.nContent.GetIndex()+1 );
156 if( !FillSaveData( aPam, *pTmpSav, FALSE ))
157 delete pTmpSav, pTmpSav = 0;
159 BOOL bOk = ( !pRedlSaveData && !pTmpSav ) ||
160 ( pRedlSaveData && pTmpSav &&
161 SwUndo::CanRedlineGroup( *pRedlSaveData, *pTmpSav,
162 nSttCntnt > rPos.nContent.GetIndex() ));
163 delete pTmpSav;
164 if( !bOk )
165 return FALSE;
167 pDoc->DeleteRedline( aPam, false, USHRT_MAX );
170 // Ok, die beiden 'Overwrites' koennen zusammen gefasst werden, also
171 // 'verschiebe' das enstprechende Zeichen
172 if( !bInsChar )
174 if( rPos.nContent.GetIndex() < pDelTxtNd->GetTxt().Len() )
176 aDelStr.Insert( pDelTxtNd->GetTxt().GetChar(rPos.nContent.GetIndex()) );
177 rPos.nContent++;
179 else
180 bInsChar = TRUE;
183 BOOL bOldExpFlg = pDelTxtNd->IsIgnoreDontExpand();
184 pDelTxtNd->SetIgnoreDontExpand( TRUE );
186 pDelTxtNd->Insert( cIns, rPos.nContent );
187 aInsStr.Insert( cIns );
189 if( !bInsChar )
191 const SwIndex aTmpIndex( rPos.nContent, -2 );
192 pDelTxtNd->Erase( aTmpIndex, 1 );
194 pDelTxtNd->SetIgnoreDontExpand( bOldExpFlg );
196 bGroup = TRUE;
197 return TRUE;
204 void SwUndoOverwrite::Undo( SwUndoIter& rUndoIter )
206 SwPaM* pAktPam = rUndoIter.pAktPam;
207 SwDoc* pDoc = pAktPam->GetDoc();
208 pAktPam->DeleteMark();
209 pAktPam->GetPoint()->nNode = nSttNode;
210 SwTxtNode* pTxtNd = pAktPam->GetNode()->GetTxtNode();
211 ASSERT( pTxtNd, "Overwrite nicht im TextNode?" );
212 SwIndex& rIdx = pAktPam->GetPoint()->nContent;
213 rIdx.Assign( pTxtNd, nSttCntnt );
215 SwAutoCorrExceptWord* pACEWord = pDoc->GetAutoCorrExceptWord();
216 if( pACEWord )
218 if( 1 == aInsStr.Len() && 1 == aDelStr.Len() )
219 pACEWord->CheckChar( *pAktPam->GetPoint(), aDelStr.GetChar( 0 ) );
220 pDoc->SetAutoCorrExceptWord( 0 );
223 // wurde nicht nur ueberschieben sondern auch geinsertet, so loesche
224 // den Ueberhang
225 if( aInsStr.Len() > aDelStr.Len() )
227 rIdx += aDelStr.Len();
228 pTxtNd->Erase( rIdx, aInsStr.Len() - aDelStr.Len() );
229 rIdx = nSttCntnt;
232 if( aDelStr.Len() )
234 String aTmpStr( '1' );
235 sal_Unicode* pTmpStr = aTmpStr.GetBufferAccess();
237 BOOL bOldExpFlg = pTxtNd->IsIgnoreDontExpand();
238 pTxtNd->SetIgnoreDontExpand( TRUE );
240 rIdx++;
241 for( xub_StrLen n = 0; n < aDelStr.Len(); n++ )
243 // einzeln, damit die Attribute stehen bleiben !!!
244 *pTmpStr = aDelStr.GetChar( n );
245 pTxtNd->Insert( aTmpStr, rIdx /*???, SETATTR_NOTXTATRCHR*/ );
246 rIdx -= 2;
247 pTxtNd->Erase( rIdx, 1 );
248 rIdx += 2;
250 pTxtNd->SetIgnoreDontExpand( bOldExpFlg );
251 rIdx--;
253 if( pHistory )
255 if( pTxtNd->GetpSwpHints() )
256 pTxtNd->ClearSwpHintsArr( false );
257 pHistory->TmpRollback( pDoc, 0, false );
260 if( pAktPam->GetMark()->nContent.GetIndex() != nSttCntnt )
262 pAktPam->SetMark();
263 pAktPam->GetMark()->nContent = nSttCntnt;
266 if( pRedlSaveData )
267 SetSaveData( *pDoc, *pRedlSaveData );
270 void SwUndoOverwrite::Repeat( SwUndoIter& rUndoIter )
272 rUndoIter.pLastUndoObj = this;
273 SwPaM* pAktPam = rUndoIter.pAktPam;
274 if( !aInsStr.Len() || pAktPam->HasMark() )
275 return;
277 SwDoc& rDoc = *pAktPam->GetDoc();
279 BOOL bGroupUndo = rDoc.DoesGroupUndo();
280 rDoc.DoGroupUndo( FALSE );
281 rDoc.Overwrite( *pAktPam, aInsStr.GetChar( 0 ));
282 rDoc.DoGroupUndo( bGroupUndo );
283 for( xub_StrLen n = 1; n < aInsStr.Len(); ++n )
284 rDoc.Overwrite( *pAktPam, aInsStr.GetChar( n ) );
289 void SwUndoOverwrite::Redo( SwUndoIter& rUndoIter )
291 SwPaM* pAktPam = rUndoIter.pAktPam;
292 SwDoc* pDoc = pAktPam->GetDoc();
293 pAktPam->DeleteMark();
294 pAktPam->GetPoint()->nNode = nSttNode;
295 SwTxtNode* pTxtNd = pAktPam->GetNode()->GetTxtNode();
296 ASSERT( pTxtNd, "Overwrite nicht im TextNode?" );
297 SwIndex& rIdx = pAktPam->GetPoint()->nContent;
299 if( pRedlSaveData )
301 rIdx.Assign( pTxtNd, nSttCntnt );
302 pAktPam->SetMark();
303 pAktPam->GetMark()->nContent += aInsStr.Len();
304 pDoc->DeleteRedline( *pAktPam, false, USHRT_MAX );
305 pAktPam->DeleteMark();
307 rIdx.Assign( pTxtNd, aDelStr.Len() ? nSttCntnt+1 : nSttCntnt );
309 BOOL bOldExpFlg = pTxtNd->IsIgnoreDontExpand();
310 pTxtNd->SetIgnoreDontExpand( TRUE );
312 for( xub_StrLen n = 0; n < aInsStr.Len(); n++ )
314 // einzeln, damit die Attribute stehen bleiben !!!
315 pTxtNd->Insert( aInsStr.GetChar( n ), rIdx );
316 if( n < aDelStr.Len() )
318 rIdx -= 2;
319 pTxtNd->Erase( rIdx, 1 );
320 rIdx += n+1 < aDelStr.Len() ? 2 : 1;
323 pTxtNd->SetIgnoreDontExpand( bOldExpFlg );
325 // alte Anfangs-Position vom UndoNodes-Array zurueckholen
326 if( pHistory )
327 pHistory->SetTmpEnd( pHistory->Count() );
328 if( pAktPam->GetMark()->nContent.GetIndex() != nSttCntnt )
330 pAktPam->SetMark();
331 pAktPam->GetMark()->nContent = nSttCntnt;
335 SwRewriter SwUndoOverwrite::GetRewriter() const
337 SwRewriter aResult;
339 String aString;
341 aString += String(SW_RES(STR_START_QUOTE));
342 aString += ShortenString(aInsStr, nUndoStringLength,
343 String(SW_RES(STR_LDOTS)));
344 aString += String(SW_RES(STR_END_QUOTE));
346 aResult.AddRule(UNDO_ARG1, aString);
348 return aResult;
351 //------------------------------------------------------------
353 struct _UndoTransliterate_Data
355 String sText;
356 _UndoTransliterate_Data* pNext;
357 SwHistory* pHistory;
358 Sequence <sal_Int32>* pOffsets;
359 ULONG nNdIdx;
360 xub_StrLen nStart, nLen;
362 _UndoTransliterate_Data( ULONG nNd, xub_StrLen nStt, xub_StrLen nStrLen,
363 const String& rTxt )
364 : sText( rTxt ), pNext( 0 ), pHistory( 0 ), pOffsets( 0 ),
365 nNdIdx( nNd ), nStart( nStt ), nLen( nStrLen )
367 ~_UndoTransliterate_Data() { delete pOffsets; delete pHistory; }
369 void SetChangeAtNode( SwDoc& rDoc );
372 SwUndoTransliterate::SwUndoTransliterate( const SwPaM& rPam,
373 const utl::TransliterationWrapper& rTrans )
374 : SwUndo( UNDO_TRANSLITERATE ), SwUndRng( rPam ),
375 pData( 0 ), pLastData( 0 ), nType( rTrans.getType() )
379 SwUndoTransliterate::~SwUndoTransliterate()
381 _UndoTransliterate_Data* pD = pData;
382 while( pD )
384 pData = pD;
385 pD = pD->pNext;
386 delete pData;
390 void SwUndoTransliterate::Undo( SwUndoIter& rUndoIter )
392 SwDoc& rDoc = rUndoIter.GetDoc();
393 BOOL bUndo = rDoc.DoesUndo();
394 rDoc.DoUndo( FALSE );
396 for( _UndoTransliterate_Data* pD = pData; pD; pD = pD->pNext )
397 pD->SetChangeAtNode( rDoc );
399 rDoc.DoUndo( bUndo );
400 SetPaM( rUndoIter, TRUE );
403 void SwUndoTransliterate::Redo( SwUndoIter& rUndoIter )
405 /* ??? */ rUndoIter.SetUpdateAttr( TRUE );
407 SetPaM( *rUndoIter.pAktPam );
408 Repeat( rUndoIter );
411 void SwUndoTransliterate::Repeat( SwUndoIter& rUndoIter )
413 SwPaM& rPam = *rUndoIter.pAktPam;
414 SwDoc& rDoc = rUndoIter.GetDoc();
416 utl::TransliterationWrapper aTrans(
417 ::comphelper::getProcessServiceFactory(), nType );
418 rDoc.TransliterateText( rPam, aTrans );
420 rUndoIter.pLastUndoObj = this;
423 void SwUndoTransliterate::AddChanges( SwTxtNode& rTNd,
424 xub_StrLen nStart, xub_StrLen nLen,
425 uno::Sequence <sal_Int32>& rOffsets )
427 long nOffsLen = rOffsets.getLength();
428 _UndoTransliterate_Data* pNew = new _UndoTransliterate_Data(
429 rTNd.GetIndex(), nStart, (xub_StrLen)nOffsLen,
430 rTNd.GetTxt().Copy( nStart, nLen ));
431 if( pData )
432 pLastData->pNext = pNew;
433 else
434 pData = pNew;
435 pLastData = pNew;
437 const sal_Int32* pOffsets = rOffsets.getConstArray();
438 // where did we need less memory ?
439 const sal_Int32* p = pOffsets;
440 for( long n = 0; n < nOffsLen; ++n, ++p )
441 if( *p != ( nStart + n ))
443 // create the Offset array
444 pNew->pOffsets = new Sequence <sal_Int32> ( nLen );
445 sal_Int32* pIdx = pNew->pOffsets->getArray();
446 p = pOffsets;
447 long nMyOff, nNewVal = nStart;
448 for( n = 0, nMyOff = nStart; n < nOffsLen; ++p, ++n, ++nMyOff )
450 if( *p < nMyOff )
452 // something is deleted
453 nMyOff = *p;
454 *(pIdx-1) = nNewVal++;
456 else if( *p > nMyOff )
458 for( ; *p > nMyOff; ++nMyOff )
459 *pIdx++ = nNewVal;
460 --nMyOff;
461 --n;
462 --p;
464 else
465 *pIdx++ = nNewVal++;
468 // and then we need to save the attributes/bookmarks
469 // but this data must moved every time to the last in the chain!
470 _UndoTransliterate_Data* pD = pData;
471 while( pD != pNew )
473 if( pD->nNdIdx == pNew->nNdIdx && pD->pHistory )
475 // same node and have a history?
476 pNew->pHistory = pD->pHistory;
477 pD->pHistory = 0;
478 break; // more can't exist
480 pD = pD->pNext;
483 if( !pNew->pHistory )
485 pNew->pHistory = new SwHistory;
486 SwRegHistory aRHst( rTNd, pNew->pHistory );
487 pNew->pHistory->CopyAttr( rTNd.GetpSwpHints(),
488 pNew->nNdIdx, 0, rTNd.GetTxt().Len(), false );
490 break;
494 void _UndoTransliterate_Data::SetChangeAtNode( SwDoc& rDoc )
496 SwTxtNode* pTNd = rDoc.GetNodes()[ nNdIdx ]->GetTxtNode();
497 if( pTNd )
499 Sequence <sal_Int32> aOffsets( pOffsets ? pOffsets->getLength() : nLen );
500 if( pOffsets )
501 aOffsets = *pOffsets;
502 else
504 sal_Int32* p = aOffsets.getArray();
505 for( xub_StrLen n = 0; n < nLen; ++n, ++p )
506 *p = n + nStart;
508 pTNd->ReplaceTextOnly( nStart, nLen, sText, aOffsets );
510 if( pHistory )
512 if( pTNd->GetpSwpHints() )
513 pTNd->ClearSwpHintsArr( false );
514 pHistory->TmpRollback( &rDoc, 0, false );
515 pHistory->SetTmpEnd( pHistory->Count() );