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
->Insert( cIns
, rPos
.nContent
);
109 aInsStr
.Insert( cIns
);
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
,
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 ))
136 // ist der Node ueberhaupt ein TextNode?
137 SwTxtNode
* pDelTxtNd
= rPos
.nNode
.GetNode().GetTxtNode();
139 ( pDelTxtNd
->GetTxt().Len() != rPos
.nContent
.GetIndex() &&
140 rPos
.nContent
.GetIndex() != ( nSttCntnt
+ aInsStr
.Len() )))
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 ) )
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() ));
167 pDoc
->DeleteRedline( aPam
, false, USHRT_MAX
);
170 // Ok, die beiden 'Overwrites' koennen zusammen gefasst werden, also
171 // 'verschiebe' das enstprechende Zeichen
174 if( rPos
.nContent
.GetIndex() < pDelTxtNd
->GetTxt().Len() )
176 aDelStr
.Insert( pDelTxtNd
->GetTxt().GetChar(rPos
.nContent
.GetIndex()) );
183 BOOL bOldExpFlg
= pDelTxtNd
->IsIgnoreDontExpand();
184 pDelTxtNd
->SetIgnoreDontExpand( TRUE
);
186 pDelTxtNd
->Insert( cIns
, rPos
.nContent
);
187 aInsStr
.Insert( cIns
);
191 const SwIndex
aTmpIndex( rPos
.nContent
, -2 );
192 pDelTxtNd
->Erase( aTmpIndex
, 1 );
194 pDelTxtNd
->SetIgnoreDontExpand( bOldExpFlg
);
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();
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
225 if( aInsStr
.Len() > aDelStr
.Len() )
227 rIdx
+= aDelStr
.Len();
228 pTxtNd
->Erase( rIdx
, aInsStr
.Len() - aDelStr
.Len() );
234 String
aTmpStr( '1' );
235 sal_Unicode
* pTmpStr
= aTmpStr
.GetBufferAccess();
237 BOOL bOldExpFlg
= pTxtNd
->IsIgnoreDontExpand();
238 pTxtNd
->SetIgnoreDontExpand( TRUE
);
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*/ );
247 pTxtNd
->Erase( rIdx
, 1 );
250 pTxtNd
->SetIgnoreDontExpand( bOldExpFlg
);
255 if( pTxtNd
->GetpSwpHints() )
256 pTxtNd
->ClearSwpHintsArr( false );
257 pHistory
->TmpRollback( pDoc
, 0, false );
260 if( pAktPam
->GetMark()->nContent
.GetIndex() != nSttCntnt
)
263 pAktPam
->GetMark()->nContent
= nSttCntnt
;
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() )
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
;
301 rIdx
.Assign( pTxtNd
, nSttCntnt
);
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() )
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
327 pHistory
->SetTmpEnd( pHistory
->Count() );
328 if( pAktPam
->GetMark()->nContent
.GetIndex() != nSttCntnt
)
331 pAktPam
->GetMark()->nContent
= nSttCntnt
;
335 SwRewriter
SwUndoOverwrite::GetRewriter() const
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
);
351 //------------------------------------------------------------
353 struct _UndoTransliterate_Data
356 _UndoTransliterate_Data
* pNext
;
358 Sequence
<sal_Int32
>* pOffsets
;
360 xub_StrLen nStart
, nLen
;
362 _UndoTransliterate_Data( ULONG nNd
, xub_StrLen nStt
, xub_StrLen nStrLen
,
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
;
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
);
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
));
432 pLastData
->pNext
= 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();
447 long nMyOff
, nNewVal
= nStart
;
448 for( n
= 0, nMyOff
= nStart
; n
< nOffsLen
; ++p
, ++n
, ++nMyOff
)
452 // something is deleted
454 *(pIdx
-1) = nNewVal
++;
456 else if( *p
> nMyOff
)
458 for( ; *p
> nMyOff
; ++nMyOff
)
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
;
473 if( pD
->nNdIdx
== pNew
->nNdIdx
&& pD
->pHistory
)
475 // same node and have a history?
476 pNew
->pHistory
= pD
->pHistory
;
478 break; // more can't exist
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 );
494 void _UndoTransliterate_Data::SetChangeAtNode( SwDoc
& rDoc
)
496 SwTxtNode
* pTNd
= rDoc
.GetNodes()[ nNdIdx
]->GetTxtNode();
499 Sequence
<sal_Int32
> aOffsets( pOffsets
? pOffsets
->getLength() : nLen
);
501 aOffsets
= *pOffsets
;
504 sal_Int32
* p
= aOffsets
.getArray();
505 for( xub_StrLen n
= 0; n
< nLen
; ++n
, ++p
)
508 pTNd
->ReplaceTextOnly( nStart
, nLen
, sText
, aOffsets
);
512 if( pTNd
->GetpSwpHints() )
513 pTNd
->ClearSwpHintsArr( false );
514 pHistory
->TmpRollback( &rDoc
, 0, false );
515 pHistory
->SetTmpEnd( pHistory
->Count() );