1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: unovwr.cxx,v $
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>
39 #include <swundo.hxx> // fuer die UndoIds
44 #include <acorrect.hxx>
47 #include <tools/resid.hxx>
48 #include <comcore.hrc> // #111827#
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 //------------------------------------------------------------
71 SwUndoOverwrite::SwUndoOverwrite( SwDoc
* pDoc
, SwPosition
& rPos
,
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?" );
92 xub_StrLen nTxtNdLen
= pTxtNd
->GetTxt().Len();
93 if( nSttCntnt
< nTxtNdLen
) // kein reines Einfuegen ?
95 aDelStr
.Insert( pTxtNd
->GetTxt().GetChar( nSttCntnt
) );
97 pHistory
= new SwHistory
;
98 SwRegHistory
aRHst( *pTxtNd
, pHistory
);
99 pHistory
->CopyAttr( pTxtNd
->GetpSwpHints(), nSttNode
, 0,
105 BOOL bOldExpFlg
= pTxtNd
->IsIgnoreDontExpand();
106 pTxtNd
->SetIgnoreDontExpand( TRUE
);
108 pTxtNd
->InsertText( cIns
, rPos
.nContent
,
109 IDocumentContentOperations::INS_EMPTYEXPAND
);
110 aInsStr
.Insert( cIns
);
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
,
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 ))
137 // ist der Node ueberhaupt ein TextNode?
138 SwTxtNode
* pDelTxtNd
= rPos
.nNode
.GetNode().GetTxtNode();
140 ( pDelTxtNd
->GetTxt().Len() != rPos
.nContent
.GetIndex() &&
141 rPos
.nContent
.GetIndex() != ( nSttCntnt
+ aInsStr
.Len() )))
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 ) )
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() ));
168 pDoc
->DeleteRedline( aPam
, false, USHRT_MAX
);
171 // Ok, die beiden 'Overwrites' koennen zusammen gefasst werden, also
172 // 'verschiebe' das enstprechende Zeichen
175 if( rPos
.nContent
.GetIndex() < pDelTxtNd
->GetTxt().Len() )
177 aDelStr
.Insert( pDelTxtNd
->GetTxt().GetChar(rPos
.nContent
.GetIndex()) );
184 BOOL bOldExpFlg
= pDelTxtNd
->IsIgnoreDontExpand();
185 pDelTxtNd
->SetIgnoreDontExpand( TRUE
);
187 pDelTxtNd
->InsertText( cIns
, rPos
.nContent
,
188 IDocumentContentOperations::INS_EMPTYEXPAND
);
189 aInsStr
.Insert( cIns
);
193 const SwIndex
aTmpIndex( rPos
.nContent
, -2 );
194 pDelTxtNd
->EraseText( aTmpIndex
, 1 );
196 pDelTxtNd
->SetIgnoreDontExpand( bOldExpFlg
);
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();
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
227 if( aInsStr
.Len() > aDelStr
.Len() )
229 rIdx
+= aDelStr
.Len();
230 pTxtNd
->EraseText( rIdx
, aInsStr
.Len() - aDelStr
.Len() );
236 String
aTmpStr( '1' );
237 sal_Unicode
* pTmpStr
= aTmpStr
.GetBufferAccess();
239 BOOL bOldExpFlg
= pTxtNd
->IsIgnoreDontExpand();
240 pTxtNd
->SetIgnoreDontExpand( TRUE
);
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*/ );
249 pTxtNd
->EraseText( rIdx
, 1 );
252 pTxtNd
->SetIgnoreDontExpand( bOldExpFlg
);
257 if( pTxtNd
->GetpSwpHints() )
258 pTxtNd
->ClearSwpHintsArr( false );
259 pHistory
->TmpRollback( pDoc
, 0, false );
262 if( pAktPam
->GetMark()->nContent
.GetIndex() != nSttCntnt
)
265 pAktPam
->GetMark()->nContent
= nSttCntnt
;
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() )
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
;
303 rIdx
.Assign( pTxtNd
, nSttCntnt
);
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() )
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
330 pHistory
->SetTmpEnd( pHistory
->Count() );
331 if( pAktPam
->GetMark()->nContent
.GetIndex() != nSttCntnt
)
334 pAktPam
->GetMark()->nContent
= nSttCntnt
;
338 SwRewriter
SwUndoOverwrite::GetRewriter() const
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
);
354 //------------------------------------------------------------
356 struct _UndoTransliterate_Data
359 _UndoTransliterate_Data
* pNext
;
361 Sequence
<sal_Int32
>* pOffsets
;
363 xub_StrLen nStart
, nLen
;
365 _UndoTransliterate_Data( ULONG nNd
, xub_StrLen nStt
, xub_StrLen nStrLen
,
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
;
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
);
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
));
435 pLastData
->pNext
= 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();
450 long nMyOff
, nNewVal
= nStart
;
451 for( n
= 0, nMyOff
= nStart
; n
< nOffsLen
; ++p
, ++n
, ++nMyOff
)
455 // something is deleted
457 *(pIdx
-1) = nNewVal
++;
459 else if( *p
> nMyOff
)
461 for( ; *p
> nMyOff
; ++nMyOff
)
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
;
476 if( pD
->nNdIdx
== pNew
->nNdIdx
&& pD
->pHistory
)
478 // same node and have a history?
479 pNew
->pHistory
= pD
->pHistory
;
481 break; // more can't exist
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 );
497 void _UndoTransliterate_Data::SetChangeAtNode( SwDoc
& rDoc
)
499 SwTxtNode
* pTNd
= rDoc
.GetNodes()[ nNdIdx
]->GetTxtNode();
502 Sequence
<sal_Int32
> aOffsets( pOffsets
? pOffsets
->getLength() : nLen
);
504 aOffsets
= *pOffsets
;
507 sal_Int32
* p
= aOffsets
.getArray();
508 for( xub_StrLen n
= 0; n
< nLen
; ++n
, ++p
)
511 pTNd
->ReplaceTextOnly( nStart
, nLen
, sText
, aOffsets
);
515 if( pTNd
->GetpSwpHints() )
516 pTNd
->ClearSwpHintsArr( false );
517 pHistory
->TmpRollback( &rDoc
, 0, false );
518 pHistory
->SetTmpEnd( pHistory
->Count() );