xref: /trunk/main/sc/source/core/tool/chgtrack.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 #include <tools/debug.hxx>
33 #include <tools/shl.hxx>		// SHL_CALC
34 #include <tools/stack.hxx>
35 #include <tools/rtti.hxx>
36 #include <svl/zforlist.hxx>
37 #include <svl/itemset.hxx>
38 #include <svl/isethint.hxx>
39 #include <svl/itempool.hxx>
40 #include <sfx2/app.hxx>
41 #include <unotools/useroptions.hxx>
42 #include <sfx2/sfxsids.hrc>
43 
44 #include "cell.hxx"
45 #include "document.hxx"
46 #include "dociter.hxx"
47 #include "global.hxx"
48 #include "rechead.hxx"
49 #include "scerrors.hxx"
50 #include "scmod.hxx"   		// SC_MOD
51 #include "inputopt.hxx" 	// GetExpandRefs
52 #include "patattr.hxx"
53 #include "hints.hxx"
54 
55 #include "globstr.hrc"
56 
57 #include <stack>
58 
59 #define SC_CHGTRACK_CXX
60 #include "chgtrack.hxx"
61 
62 DECLARE_STACK( ScChangeActionStack, ScChangeAction* )
63 
64 const sal_uInt16 nMemPoolChangeActionCellListEntry = (0x2000 - 64) / sizeof(ScChangeActionCellListEntry);
65 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionCellListEntry, nMemPoolChangeActionCellListEntry, nMemPoolChangeActionCellListEntry )
66 
67 const sal_uInt16 nMemPoolChangeActionLinkEntry = (0x8000 - 64) / sizeof(ScChangeActionLinkEntry);
68 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionLinkEntry, nMemPoolChangeActionLinkEntry, nMemPoolChangeActionLinkEntry )
69 
70 // loaded MSB > eigenes => inkompatibel
71 #define SC_CHGTRACK_FILEFORMAT_FIRST	0x0001
72 #define SC_CHGTRACK_FILEFORMAT	0x0001
73 
74 // --- ScChangeActionLinkEntry ---------------------------------------------
75 
76 #if DEBUG_CHANGETRACK
77 String ScChangeActionLinkEntry::ToString() const
78 {
79     String aReturn;
80     if ( pAction )
81     {
82         aReturn = String::CreateFromInt64( static_cast< sal_Int64 >( pAction->GetActionNumber() ) );
83     }
84     else if ( pLink && pLink->pAction )
85     {
86         aReturn = String::CreateFromAscii( "*" );
87         aReturn += String::CreateFromInt64( static_cast< sal_Int64 >( pLink->pAction->GetActionNumber() ) );
88     }
89     else
90     {
91         aReturn = String::CreateFromAscii( "-" );
92     }
93 
94     return aReturn;
95 }
96 #endif // DEBUG_CHANGETRACK
97 
98 // --- ScChangeAction ------------------------------------------------------
99 
100 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScRange& rRange )
101 		:
102 		aBigRange( rRange ),
103 		pNext( NULL ),
104 		pPrev( NULL ),
105 		pLinkAny( NULL ),
106 		pLinkDeletedIn( NULL ),
107 		pLinkDeleted( NULL ),
108 		pLinkDependent( NULL ),
109 		nAction( 0 ),
110 		nRejectAction( 0 ),
111 		eType( eTypeP ),
112 		eState( SC_CAS_VIRGIN )
113 {
114 	aDateTime.ConvertToUTC();
115 }
116 
117 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScBigRange& rRange,
118 						const sal_uLong nTempAction, const sal_uLong nTempRejectAction,
119 						const ScChangeActionState eTempState, const DateTime& aTempDateTime,
120 						const String& aTempUser,  const String& aTempComment)
121 		:
122 		aBigRange( rRange ),
123 		aDateTime( aTempDateTime ),
124 		aUser( aTempUser ),
125 		aComment( aTempComment ),
126 		pNext( NULL ),
127 		pPrev( NULL ),
128 		pLinkAny( NULL ),
129 		pLinkDeletedIn( NULL ),
130 		pLinkDeleted( NULL ),
131 		pLinkDependent( NULL ),
132 		nAction( nTempAction ),
133 		nRejectAction( nTempRejectAction ),
134 		eType( eTypeP ),
135 		eState( eTempState )
136 {
137 }
138 
139 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScBigRange& rRange,
140 						const sal_uLong nTempAction)
141 		:
142 		aBigRange( rRange ),
143 		pNext( NULL ),
144 		pPrev( NULL ),
145 		pLinkAny( NULL ),
146 		pLinkDeletedIn( NULL ),
147 		pLinkDeleted( NULL ),
148 		pLinkDependent( NULL ),
149 		nAction( nTempAction ),
150 		nRejectAction( 0 ),
151 		eType( eTypeP ),
152 		eState( SC_CAS_VIRGIN )
153 {
154 	aDateTime.ConvertToUTC();
155 }
156 
157 
158 ScChangeAction::~ScChangeAction()
159 {
160 	RemoveAllLinks();
161 }
162 
163 
164 sal_Bool ScChangeAction::IsVisible() const
165 {
166 	//! sequence order of execution is significant
167 	if ( IsRejected() || GetType() == SC_CAT_DELETE_TABS || IsDeletedIn() )
168 		return sal_False;
169 	if ( GetType() == SC_CAT_CONTENT )
170 		return ((ScChangeActionContent*)this)->IsTopContent();
171 	return sal_True;
172 }
173 
174 
175 sal_Bool ScChangeAction::IsTouchable() const
176 {
177 	//! sequence order of execution is significant
178 	if ( IsRejected() || GetType() == SC_CAT_REJECT || IsDeletedIn() )
179 		return sal_False;
180 	// content may reject and be touchable if on top
181 	if ( GetType() == SC_CAT_CONTENT )
182 		return ((ScChangeActionContent*)this)->IsTopContent();
183 	if ( IsRejecting() )
184 		return sal_False;
185 	return sal_True;
186 }
187 
188 
189 sal_Bool ScChangeAction::IsClickable() const
190 {
191 	//! sequence order of execution is significant
192 	if ( !IsVirgin() )
193 		return sal_False;
194 	if ( IsDeletedIn() )
195 		return sal_False;
196 	if ( GetType() == SC_CAT_CONTENT )
197 	{
198 		ScChangeActionContentCellType eCCT =
199 			ScChangeActionContent::GetContentCellType(
200 			((ScChangeActionContent*)this)->GetNewCell() );
201 		if ( eCCT == SC_CACCT_MATREF )
202 			return sal_False;
203 		if ( eCCT == SC_CACCT_MATORG )
204 		{	// no Accept-Select if one of the references is in a deleted col/row
205 			const ScChangeActionLinkEntry* pL =
206 				((ScChangeActionContent*)this)->GetFirstDependentEntry();
207 			while ( pL )
208 			{
209 				ScChangeAction* p = (ScChangeAction*) pL->GetAction();
210 				if ( p && p->IsDeletedIn() )
211 					return sal_False;
212 				pL = pL->GetNext();
213 			}
214 		}
215 		return sal_True;	// for Select() a content doesn't have to be touchable
216 	}
217 	return IsTouchable();	// Accept()/Reject() only on touchables
218 }
219 
220 
221 sal_Bool ScChangeAction::IsRejectable() const
222 {
223 	//! sequence order of execution is significant
224 	if ( !IsClickable() )
225 		return sal_False;
226 	if ( GetType() == SC_CAT_CONTENT )
227 	{
228 		if ( ((ScChangeActionContent*)this)->IsOldMatrixReference() )
229 			return sal_False;
230 		ScChangeActionContent* pNextContent =
231 			((ScChangeActionContent*)this)->GetNextContent();
232 		if ( pNextContent == NULL )
233 			return sal_True;		// *this is TopContent
234 		return pNextContent->IsRejected();		// *this is next rejectable
235 	}
236 	return IsTouchable();
237 }
238 
239 
240 sal_Bool ScChangeAction::IsInternalRejectable() const
241 {
242 	//! sequence order of execution is significant
243 	if ( !IsVirgin() )
244 		return sal_False;
245 	if ( IsDeletedIn() )
246 		return sal_False;
247 	if ( GetType() == SC_CAT_CONTENT )
248 	{
249 		ScChangeActionContent* pNextContent =
250 			((ScChangeActionContent*)this)->GetNextContent();
251 		if ( pNextContent == NULL )
252 			return sal_True;		// *this is TopContent
253 		return pNextContent->IsRejected();		// *this is next rejectable
254 	}
255 	return IsTouchable();
256 }
257 
258 
259 sal_Bool ScChangeAction::IsDialogRoot() const
260 {
261 	return IsInternalRejectable();		// only rejectables in root
262 }
263 
264 
265 sal_Bool ScChangeAction::IsDialogParent() const
266 {
267 	//! sequence order of execution is significant
268 	if ( GetType() == SC_CAT_CONTENT )
269 	{
270 		if ( !IsDialogRoot() )
271 			return sal_False;
272 		if ( ((ScChangeActionContent*)this)->IsMatrixOrigin() && HasDependent() )
273 			return sal_True;
274 		ScChangeActionContent* pPrevContent =
275 			((ScChangeActionContent*)this)->GetPrevContent();
276 		return pPrevContent && pPrevContent->IsVirgin();
277 	}
278 	if ( HasDependent() )
279 		return IsDeleteType() ? sal_True : !IsDeletedIn();
280 	if ( HasDeleted() )
281 	{
282 		if ( IsDeleteType() )
283 		{
284 			if ( IsDialogRoot() )
285 				return sal_True;
286 			ScChangeActionLinkEntry* pL = pLinkDeleted;
287 			while ( pL )
288 			{
289 				ScChangeAction* p = pL->GetAction();
290 				if ( p && p->GetType() != eType )
291 					return sal_True;
292 				pL = pL->GetNext();
293 			}
294 		}
295 		else
296 			return sal_True;
297 	}
298 	return sal_False;
299 }
300 
301 
302 sal_Bool ScChangeAction::IsMasterDelete() const
303 {
304 	if ( !IsDeleteType() )
305 		return sal_False;
306 	ScChangeActionDel* pDel = (ScChangeActionDel*) this;
307 	return pDel->IsMultiDelete() && (pDel->IsTopDelete() || pDel->IsRejectable());
308 }
309 
310 
311 void ScChangeAction::RemoveAllLinks()
312 {
313 	RemoveAllAnyLinks();
314 	RemoveAllDeletedIn();
315 	RemoveAllDeleted();
316 	RemoveAllDependent();
317 }
318 
319 
320 void ScChangeAction::RemoveAllAnyLinks()
321 {
322 	while ( pLinkAny )
323 		delete pLinkAny;		// rueckt sich selbst hoch
324 }
325 
326 
327 sal_Bool ScChangeAction::RemoveDeletedIn( const ScChangeAction* p )
328 {
329 	sal_Bool bRemoved = sal_False;
330 	ScChangeActionLinkEntry* pL = GetDeletedIn();
331 	while ( pL )
332 	{
333 		ScChangeActionLinkEntry* pNextLink = pL->GetNext();
334 		if ( pL->GetAction() == p )
335 		{
336 			delete pL;
337 			bRemoved = sal_True;
338 		}
339 		pL = pNextLink;
340 	}
341 	return bRemoved;
342 }
343 
344 
345 sal_Bool ScChangeAction::IsDeletedIn( const ScChangeAction* p ) const
346 {
347 	ScChangeActionLinkEntry* pL = GetDeletedIn();
348 	while ( pL )
349 	{
350 		if ( pL->GetAction() == p )
351 			return sal_True;
352 		pL = pL->GetNext();
353 	}
354 	return sal_False;
355 }
356 
357 
358 void ScChangeAction::RemoveAllDeletedIn()
359 {
360 	//! nicht vom evtl. TopContent sondern wirklich dieser
361 	while ( pLinkDeletedIn )
362 		delete pLinkDeletedIn;		// rueckt sich selbst hoch
363 }
364 
365 
366 sal_Bool ScChangeAction::IsDeletedInDelType( ScChangeActionType eDelType ) const
367 {
368 	ScChangeAction* p;
369 	ScChangeActionLinkEntry* pL = GetDeletedIn();
370 	if ( pL )
371 	{
372 		// InsertType fuer MergePrepare/MergeOwn
373 		ScChangeActionType eInsType;
374 		switch ( eDelType )
375 		{
376 			case SC_CAT_DELETE_COLS :
377 				eInsType = SC_CAT_INSERT_COLS;
378 			break;
379 			case SC_CAT_DELETE_ROWS :
380 				eInsType = SC_CAT_INSERT_ROWS;
381 			break;
382 			case SC_CAT_DELETE_TABS :
383 				eInsType = SC_CAT_INSERT_TABS;
384 			break;
385 			default:
386 				eInsType = SC_CAT_NONE;
387 		}
388 		while ( pL )
389 		{
390             if ( (p = pL->GetAction()) != NULL &&
391 					(p->GetType() == eDelType || p->GetType() == eInsType) )
392 				return sal_True;
393 			pL = pL->GetNext();
394 		}
395 	}
396 	return sal_False;
397 }
398 
399 
400 void ScChangeAction::SetDeletedIn( ScChangeAction* p )
401 {
402 	ScChangeActionLinkEntry* pLink1 = AddDeletedIn( p );
403 	ScChangeActionLinkEntry* pLink2;
404 	if ( GetType() == SC_CAT_CONTENT )
405 		pLink2 = p->AddDeleted( ((ScChangeActionContent*)this)->GetTopContent() );
406 	else
407 		pLink2 = p->AddDeleted( this );
408 	pLink1->SetLink( pLink2 );
409 }
410 
411 
412 void ScChangeAction::RemoveAllDeleted()
413 {
414 	while ( pLinkDeleted )
415 		delete pLinkDeleted;		// rueckt sich selbst hoch
416 }
417 
418 
419 void ScChangeAction::RemoveAllDependent()
420 {
421 	while ( pLinkDependent )
422 		delete pLinkDependent;		// rueckt sich selbst hoch
423 }
424 
425 
426 DateTime ScChangeAction::GetDateTime() const
427 {
428 	DateTime aDT( aDateTime );
429 	aDT.ConvertToLocalTime();
430 	return aDT;
431 }
432 
433 
434 void ScChangeAction::UpdateReference( const ScChangeTrack* /* pTrack */,
435 		UpdateRefMode eMode, const ScBigRange& rRange,
436 		sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
437 {
438 	ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() );
439 }
440 
441 
442 void ScChangeAction::GetDescription( String& rStr, ScDocument* /* pDoc */,
443         sal_Bool /* bSplitRange */, bool bWarning ) const
444 {
445     if ( IsRejecting() && bWarning )
446     {
447         // #112261# Add comment if rejection may have resulted in references
448         // not properly restored in formulas. See specification at
449         // http://specs.openoffice.org/calc/ease-of-use/redlining_comment.sxw
450         if (GetType() == SC_CAT_MOVE)
451         {
452             rStr += ScGlobal::GetRscString(
453                     STR_CHANGED_MOVE_REJECTION_WARNING);
454             rStr += ' ';
455         }
456         else if (IsInsertType())
457         {
458             rStr += ScGlobal::GetRscString(
459                     STR_CHANGED_DELETE_REJECTION_WARNING);
460             rStr += ' ';
461         }
462         else
463         {
464             const ScChangeTrack* pCT = GetChangeTrack();
465             if (pCT)
466             {
467                 ScChangeAction* pReject = pCT->GetActionOrGenerated(
468                         GetRejectAction());
469                 if (pReject)
470                 {
471                     if (pReject->GetType() == SC_CAT_MOVE)
472                     {
473                         rStr += ScGlobal::GetRscString(
474                                 STR_CHANGED_MOVE_REJECTION_WARNING);
475                         rStr += ' ';
476                     }
477                     else if (pReject->IsDeleteType())
478                     {
479                         rStr += ScGlobal::GetRscString(
480                                 STR_CHANGED_DELETE_REJECTION_WARNING);
481                         rStr += ' ';
482                     }
483                     else if (pReject->HasDependent())
484                     {
485                         ScChangeActionTable aTable;
486                         pCT->GetDependents( pReject, aTable, sal_False, sal_True );
487                         for ( const ScChangeAction* p = aTable.First(); p;
488                                 p = aTable.Next() )
489                         {
490                             if (p->GetType() == SC_CAT_MOVE)
491                             {
492                                 rStr += ScGlobal::GetRscString(
493                                         STR_CHANGED_MOVE_REJECTION_WARNING);
494                                 rStr += ' ';
495                                 break;  // for
496                             }
497                             else if (pReject->IsDeleteType())
498                             {
499                                 rStr += ScGlobal::GetRscString(
500                                         STR_CHANGED_DELETE_REJECTION_WARNING);
501                                 rStr += ' ';
502                                 break;  // for
503                             }
504                         }
505                     }
506                 }
507             }
508         }
509     }
510 }
511 
512 
513 String ScChangeAction::GetRefString( const ScBigRange& rRange,
514 		ScDocument* pDoc, sal_Bool bFlag3D ) const
515 {
516 	String aStr;
517 	sal_uInt16 nFlags = ( rRange.IsValid( pDoc ) ? SCA_VALID : 0 );
518 	if ( !nFlags )
519 		aStr = ScGlobal::GetRscString( STR_NOREF_STR );
520 	else
521 	{
522 		ScRange aTmpRange( rRange.MakeRange() );
523 		switch ( GetType() )
524 		{
525 			case SC_CAT_INSERT_COLS :
526 			case SC_CAT_DELETE_COLS :
527 				if ( bFlag3D )
528 				{
529 					pDoc->GetName( aTmpRange.aStart.Tab(), aStr );
530 					aStr += '.';
531 				}
532 				aStr += ::ScColToAlpha( aTmpRange.aStart.Col() );
533 				aStr += ':';
534 				aStr += ::ScColToAlpha( aTmpRange.aEnd.Col() );
535 			break;
536 			case SC_CAT_INSERT_ROWS :
537 			case SC_CAT_DELETE_ROWS :
538 				if ( bFlag3D )
539 				{
540 					pDoc->GetName( aTmpRange.aStart.Tab(), aStr );
541 					aStr += '.';
542 				}
543 				aStr += String::CreateFromInt32( aTmpRange.aStart.Row() + 1 );
544 				aStr += ':';
545 				aStr += String::CreateFromInt32( aTmpRange.aEnd.Row() + 1 );
546 			break;
547 			default:
548 				if ( bFlag3D || GetType() == SC_CAT_INSERT_TABS )
549 					nFlags |= SCA_TAB_3D;
550 				aTmpRange.Format( aStr, nFlags, pDoc, pDoc->GetAddressConvention() );
551 		}
552 		if ( (bFlag3D && IsDeleteType()) || IsDeletedIn() )
553 		{
554 			aStr.Insert( '(', 0 );
555 			aStr += ')';
556 		}
557 	}
558 	return aStr;
559 }
560 
561 
562 void ScChangeAction::GetRefString( String& rStr, ScDocument* pDoc,
563 		sal_Bool bFlag3D ) const
564 {
565 	rStr = GetRefString( GetBigRange(), pDoc, bFlag3D );
566 }
567 
568 
569 void ScChangeAction::Accept()
570 {
571 	if ( IsVirgin() )
572 	{
573 		SetState( SC_CAS_ACCEPTED );
574 		DeleteCellEntries();
575 	}
576 }
577 
578 
579 void ScChangeAction::SetRejected()
580 {
581 	if ( IsVirgin() )
582 	{
583 		SetState( SC_CAS_REJECTED );
584 		RemoveAllLinks();
585 		DeleteCellEntries();
586 	}
587 }
588 
589 
590 void ScChangeAction::RejectRestoreContents( ScChangeTrack* pTrack,
591 		SCsCOL nDx, SCsROW nDy )
592 {
593 	// Liste der Contents aufbauen
594 	ScChangeActionCellListEntry* pListContents = NULL;
595 	for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() )
596 	{
597 		ScChangeAction* p = pL->GetAction();
598 		if ( p && p->GetType() == SC_CAT_CONTENT )
599 		{
600 			ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry(
601 				(ScChangeActionContent*) p, pListContents );
602 			pListContents = pE;
603 		}
604 	}
605 	SetState( SC_CAS_REJECTED );		// vor UpdateReference fuer Move
606 	pTrack->UpdateReference( this, sal_True );		// LinkDeleted freigeben
607 	DBG_ASSERT( !pLinkDeleted, "ScChangeAction::RejectRestoreContents: pLinkDeleted != NULL" );
608 	// Liste der Contents abarbeiten und loeschen
609 	ScDocument* pDoc = pTrack->GetDocument();
610 	ScChangeActionCellListEntry* pE = pListContents;
611 	while ( pE )
612 	{
613 		if ( !pE->pContent->IsDeletedIn() &&
614 				pE->pContent->GetBigRange().aStart.IsValid( pDoc ) )
615 			pE->pContent->PutNewValueToDoc( pDoc, nDx, nDy );
616         ScChangeActionCellListEntry* pNextEntry;
617         pNextEntry = pE->pNext;
618 		delete pE;
619         pE = pNextEntry;
620 	}
621 	DeleteCellEntries();		// weg mit den generierten
622 }
623 
624 
625 void ScChangeAction::SetDeletedInThis( sal_uLong nActionNumber,
626 		const ScChangeTrack* pTrack )
627 {
628 	if ( nActionNumber )
629 	{
630 		ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber );
631 		DBG_ASSERT( pAct, "ScChangeAction::SetDeletedInThis: missing Action" );
632 		if ( pAct )
633 			pAct->SetDeletedIn( this );
634 	}
635 }
636 
637 
638 void ScChangeAction::AddDependent( sal_uLong nActionNumber,
639 		const ScChangeTrack* pTrack )
640 {
641 	if ( nActionNumber )
642 	{
643 		ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber );
644 		DBG_ASSERT( pAct, "ScChangeAction::AddDependent: missing Action" );
645 		if ( pAct )
646 		{
647 			ScChangeActionLinkEntry* pLink = AddDependent( pAct );
648 			pAct->AddLink( this, pLink );
649 		}
650 	}
651 }
652 
653 
654 #if DEBUG_CHANGETRACK
655 String ScChangeAction::ToString( ScDocument* pDoc ) const
656 {
657     String aReturn;
658 
659     String aNumber = String::CreateFromInt64( static_cast< sal_Int64 >( GetActionNumber() ) );
660 
661     String aActionState;
662     ScChangeActionState eActionState = GetState();
663     switch ( eActionState )
664     {
665         case SC_CAS_VIRGIN:
666             {
667                 aActionState = String::CreateFromAscii( " " );
668             }
669             break;
670         case SC_CAS_ACCEPTED:
671             {
672                 aActionState = String::CreateFromAscii( "+" );
673             }
674             break;
675         case SC_CAS_REJECTED:
676             {
677                 aActionState = String::CreateFromAscii( "-" );
678             }
679             break;
680     }
681 
682     String aRejectAction;
683     if ( IsRejecting() )
684     {
685         aRejectAction += 'r';
686         aRejectAction += String::CreateFromInt64( static_cast< sal_Int64 >( GetRejectAction() ) );
687     }
688 
689     String aReference;
690     GetRefString( aReference, pDoc, sal_True );
691 
692     String aAuthor = GetUser();
693 
694     DateTime aDT = GetDateTime();
695     String aDate = ScGlobal::pLocaleData->getDate( aDT );
696     aDate += ' ';
697     aDate += ScGlobal::pLocaleData->getTime( aDT, sal_False, sal_False );
698 
699     String aDescription;
700     GetDescription( aDescription, pDoc );
701 
702     String aLinkAny;
703     const ScChangeActionLinkEntry* pLinkA = pLinkAny;
704     while ( pLinkA )
705     {
706         if ( !aLinkAny.Len() )
707         {
708             aLinkAny = String::CreateFromAscii( "(Any:" );
709         }
710         aLinkAny += String::CreateFromAscii( " ->" );
711         aLinkAny += pLinkA->ToString();
712         pLinkA = pLinkA->GetNext();
713     }
714     if ( aLinkAny.Len() )
715     {
716         aLinkAny += ')';
717     }
718 
719     String aLinkDeletedIn;
720     const ScChangeActionLinkEntry* pLinkDI = pLinkDeletedIn;
721     while ( pLinkDI )
722     {
723         if ( !aLinkDeletedIn.Len() )
724         {
725             aLinkDeletedIn = String::CreateFromAscii( "(DeletedIn:" );
726         }
727         aLinkDeletedIn += String::CreateFromAscii( " ->" );
728         aLinkDeletedIn += pLinkDI->ToString();
729         pLinkDI = pLinkDI->GetNext();
730     }
731     if ( aLinkDeletedIn.Len() )
732     {
733         aLinkDeletedIn += ')';
734     }
735 
736     String aLinkDeleted;
737     const ScChangeActionLinkEntry* pLinkD = pLinkDeleted;
738     while ( pLinkD )
739     {
740         if ( !aLinkDeleted.Len() )
741         {
742             aLinkDeleted = String::CreateFromAscii( "(Deleted:" );
743         }
744         aLinkDeleted += String::CreateFromAscii( " ->" );
745         aLinkDeleted += pLinkD->ToString();
746         pLinkD = pLinkD->GetNext();
747     }
748     if ( aLinkDeleted.Len() )
749     {
750         aLinkDeleted += ')';
751     }
752 
753     String aLinkDependent;
754     const ScChangeActionLinkEntry* pLinkDp = pLinkDependent;
755     while ( pLinkDp )
756     {
757         if ( !aLinkDependent.Len() )
758         {
759             aLinkDependent = String::CreateFromAscii( "(Dependent:" );
760         }
761         aLinkDependent += String::CreateFromAscii( " ->" );
762         aLinkDependent += pLinkDp->ToString();
763         pLinkDp = pLinkDp->GetNext();
764     }
765     if ( aLinkDependent.Len() )
766     {
767         aLinkDependent += ')';
768     }
769 
770     aReturn += aNumber;
771     aReturn += aActionState;
772     aReturn += aRejectAction;
773     aReturn += String::CreateFromAscii( ": " );
774     aReturn += aReference;
775     aReturn += ' ';
776     aReturn += aAuthor;
777     aReturn += ' ';
778     aReturn += aDate;
779     aReturn += ' ';
780     aReturn += aDescription;
781     aReturn += ' ';
782     aReturn += aLinkAny;
783     aReturn += ' ';
784     aReturn += aLinkDeletedIn;
785     aReturn += ' ';
786     aReturn += aLinkDeleted;
787     aReturn += ' ';
788     aReturn += aLinkDependent;
789 
790     return aReturn;
791 }
792 #endif // DEBUG_CHANGETRACK
793 
794 
795 // --- ScChangeActionIns ---------------------------------------------------
796 
797 ScChangeActionIns::ScChangeActionIns( const ScRange& rRange )
798 		: ScChangeAction( SC_CAT_NONE, rRange )
799 {
800 	if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == MAXCOL )
801 	{
802 		aBigRange.aStart.SetCol( nInt32Min );
803 		aBigRange.aEnd.SetCol( nInt32Max );
804 		if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
805 		{
806 			SetType( SC_CAT_INSERT_TABS );
807 			aBigRange.aStart.SetRow( nInt32Min );
808 			aBigRange.aEnd.SetRow( nInt32Max );
809 		}
810 		else
811 			SetType( SC_CAT_INSERT_ROWS );
812 	}
813 	else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
814 	{
815 		SetType( SC_CAT_INSERT_COLS );
816 		aBigRange.aStart.SetRow( nInt32Min );
817 		aBigRange.aEnd.SetRow( nInt32Max );
818 	}
819 	else
820 	{
821 		DBG_ERROR( "ScChangeActionIns: Block not supported!" );
822 	}
823 }
824 
825 
826 ScChangeActionIns::ScChangeActionIns(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
827                                                 const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String& sComment,
828                                                 const ScChangeActionType eTypeP)
829 		:
830         ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment)
831 {
832 }
833 
834 ScChangeActionIns::~ScChangeActionIns()
835 {
836 }
837 
838 
839 void ScChangeActionIns::GetDescription( String& rStr, ScDocument* pDoc,
840 		sal_Bool bSplitRange, bool bWarning ) const
841 {
842     ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
843 
844 	sal_uInt16 nWhatId;
845 	switch ( GetType() )
846 	{
847 		case SC_CAT_INSERT_COLS :
848 			nWhatId = STR_COLUMN;
849 		break;
850 		case SC_CAT_INSERT_ROWS :
851 			nWhatId = STR_ROW;
852 		break;
853 		default:
854 			nWhatId = STR_AREA;
855 	}
856 
857 	String aRsc( ScGlobal::GetRscString( STR_CHANGED_INSERT ) );
858 	xub_StrLen nPos = aRsc.SearchAscii( "#1" );
859 	rStr += aRsc.Copy( 0, nPos );
860 	rStr += ScGlobal::GetRscString( nWhatId );
861 	rStr += ' ';
862 	rStr += GetRefString( GetBigRange(), pDoc );
863 	rStr += aRsc.Copy( nPos+2 );
864 }
865 
866 
867 sal_Bool ScChangeActionIns::Reject( ScDocument* pDoc )
868 {
869 	if ( !aBigRange.IsValid( pDoc ) )
870 		return sal_False;
871 
872 	ScRange aRange( aBigRange.MakeRange() );
873 	if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(),
874 			aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) )
875 		return sal_False;
876 
877 	switch ( GetType() )
878 	{
879 		case SC_CAT_INSERT_COLS :
880 			pDoc->DeleteCol( aRange );
881 		break;
882 		case SC_CAT_INSERT_ROWS :
883 			pDoc->DeleteRow( aRange );
884 		break;
885 		case SC_CAT_INSERT_TABS :
886 			pDoc->DeleteTab( aRange.aStart.Tab() );
887 		break;
888         default:
889         {
890             // added to avoid warnings
891         }
892 	}
893 	SetState( SC_CAS_REJECTED );
894 	RemoveAllLinks();
895 	return sal_True;
896 }
897 
898 
899 // --- ScChangeActionDel ---------------------------------------------------
900 
901 ScChangeActionDel::ScChangeActionDel( const ScRange& rRange,
902 			SCsCOL nDxP, SCsROW nDyP, ScChangeTrack* pTrackP )
903 		:
904 		ScChangeAction( SC_CAT_NONE, rRange ),
905 		pTrack( pTrackP ),
906 		pFirstCell( NULL ),
907 		pCutOff( NULL ),
908 		nCutOff( 0 ),
909 		pLinkMove( NULL ),
910 		nDx( nDxP ),
911 		nDy( nDyP )
912 {
913 	if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == MAXCOL )
914 	{
915 		aBigRange.aStart.SetCol( nInt32Min );
916 		aBigRange.aEnd.SetCol( nInt32Max );
917 		if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
918 		{
919 			SetType( SC_CAT_DELETE_TABS );
920 			aBigRange.aStart.SetRow( nInt32Min );
921 			aBigRange.aEnd.SetRow( nInt32Max );
922 		}
923 		else
924 			SetType( SC_CAT_DELETE_ROWS );
925 	}
926 	else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW )
927 	{
928 		SetType( SC_CAT_DELETE_COLS );
929 		aBigRange.aStart.SetRow( nInt32Min );
930 		aBigRange.aEnd.SetRow( nInt32Max );
931 	}
932 	else
933 	{
934 		DBG_ERROR( "ScChangeActionDel: Block not supported!" );
935 	}
936 }
937 
938 
939 ScChangeActionDel::ScChangeActionDel(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
940                                     const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String &sComment,
941                                     const ScChangeActionType eTypeP, const SCsCOLROW nD, ScChangeTrack* pTrackP) // wich of nDx and nDy is set is depend on the type
942 		:
943         ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
944 		pTrack( pTrackP ),
945 		pFirstCell( NULL ),
946 		pCutOff( NULL ),
947 		nCutOff( 0 ),
948 		pLinkMove( NULL ),
949 		nDx( 0 ),
950 		nDy( 0 )
951 {
952 	if (eType == SC_CAT_DELETE_COLS)
953 		nDx = static_cast<SCsCOL>(nD);
954 	else if (eType == SC_CAT_DELETE_ROWS)
955 		nDy = static_cast<SCsROW>(nD);
956 }
957 
958 ScChangeActionDel::~ScChangeActionDel()
959 {
960 	DeleteCellEntries();
961 	while ( pLinkMove )
962 		delete pLinkMove;
963 }
964 
965 void ScChangeActionDel::AddContent( ScChangeActionContent* pContent )
966 {
967 	ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry(
968 		pContent, pFirstCell );
969 	pFirstCell = pE;
970 }
971 
972 
973 void ScChangeActionDel::DeleteCellEntries()
974 {
975 	pTrack->DeleteCellEntries( pFirstCell, this );
976 }
977 
978 
979 sal_Bool ScChangeActionDel::IsBaseDelete() const
980 {
981 	return !GetDx() && !GetDy();
982 }
983 
984 
985 sal_Bool ScChangeActionDel::IsTopDelete() const
986 {
987 	const ScChangeAction* p = GetNext();
988 	if ( !p || p->GetType() != GetType() )
989 		return sal_True;
990 	return ((ScChangeActionDel*)p)->IsBaseDelete();
991 }
992 
993 
994 sal_Bool ScChangeActionDel::IsMultiDelete() const
995 {
996 	if ( GetDx() || GetDy() )
997 		return sal_True;
998 	const ScChangeAction* p = GetNext();
999 	if ( !p || p->GetType() != GetType() )
1000 		return sal_False;
1001 	const ScChangeActionDel* pDel = (const ScChangeActionDel*) p;
1002 	if ( (pDel->GetDx() > GetDx() || pDel->GetDy() > GetDy()) &&
1003 			pDel->GetBigRange() == aBigRange )
1004 		return sal_True;
1005 	return sal_False;
1006 }
1007 
1008 
1009 sal_Bool ScChangeActionDel::IsTabDeleteCol() const
1010 {
1011 	if ( GetType() != SC_CAT_DELETE_COLS )
1012 		return sal_False;
1013 	const ScChangeAction* p = this;
1014 	while ( p && p->GetType() == SC_CAT_DELETE_COLS &&
1015 			!((const ScChangeActionDel*)p)->IsTopDelete() )
1016 		p = p->GetNext();
1017 	return p && p->GetType() == SC_CAT_DELETE_TABS;
1018 }
1019 
1020 
1021 void ScChangeActionDel::UpdateReference( const ScChangeTrack* /* pTrack */,
1022 		UpdateRefMode eMode, const ScBigRange& rRange,
1023         sal_Int32 nDxP, sal_Int32 nDyP, sal_Int32 nDz )
1024 {
1025     ScRefUpdate::Update( eMode, rRange, nDxP, nDyP, nDz, GetBigRange() );
1026 	if ( !IsDeletedIn() )
1027 		return ;
1028 	// evtl. in "druntergerutschten" anpassen
1029 	for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() )
1030 	{
1031 		ScChangeAction* p = pL->GetAction();
1032 		if ( p && p->GetType() == SC_CAT_CONTENT &&
1033 				!GetBigRange().In( p->GetBigRange() ) )
1034 		{
1035 			switch ( GetType() )
1036 			{
1037 				case SC_CAT_DELETE_COLS :
1038 					p->GetBigRange().aStart.SetCol( GetBigRange().aStart.Col() );
1039 					p->GetBigRange().aEnd.SetCol( GetBigRange().aStart.Col() );
1040 				break;
1041 				case SC_CAT_DELETE_ROWS :
1042 					p->GetBigRange().aStart.SetRow( GetBigRange().aStart.Row() );
1043 					p->GetBigRange().aEnd.SetRow( GetBigRange().aStart.Row() );
1044 				break;
1045 				case SC_CAT_DELETE_TABS :
1046 					p->GetBigRange().aStart.SetTab( GetBigRange().aStart.Tab() );
1047 					p->GetBigRange().aEnd.SetTab( GetBigRange().aStart.Tab() );
1048 				break;
1049                 default:
1050                 {
1051                     // added to avoid warnings
1052                 }
1053 			}
1054 		}
1055 	}
1056 }
1057 
1058 
1059 ScBigRange ScChangeActionDel::GetOverAllRange() const
1060 {
1061 	ScBigRange aTmpRange( GetBigRange() );
1062 	aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() );
1063 	aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() );
1064 	return aTmpRange;
1065 }
1066 
1067 
1068 void ScChangeActionDel::GetDescription( String& rStr, ScDocument* pDoc,
1069 		sal_Bool bSplitRange, bool bWarning ) const
1070 {
1071     ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
1072 
1073 	sal_uInt16 nWhatId;
1074 	switch ( GetType() )
1075 	{
1076 		case SC_CAT_DELETE_COLS :
1077 			nWhatId = STR_COLUMN;
1078 		break;
1079 		case SC_CAT_DELETE_ROWS :
1080 			nWhatId = STR_ROW;
1081 		break;
1082 		default:
1083 			nWhatId = STR_AREA;
1084 	}
1085 
1086 	ScBigRange aTmpRange( GetBigRange() );
1087 	if ( !IsRejected() )
1088 	{
1089 		if ( bSplitRange )
1090 		{
1091 			aTmpRange.aStart.SetCol( aTmpRange.aStart.Col() + GetDx() );
1092 			aTmpRange.aStart.SetRow( aTmpRange.aStart.Row() + GetDy() );
1093 		}
1094 		aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() );
1095 		aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() );
1096 	}
1097 
1098 	String aRsc( ScGlobal::GetRscString( STR_CHANGED_DELETE ) );
1099 	xub_StrLen nPos = aRsc.SearchAscii( "#1" );
1100 	rStr += aRsc.Copy( 0, nPos );
1101 	rStr += ScGlobal::GetRscString( nWhatId );
1102 	rStr += ' ';
1103 	rStr += GetRefString( aTmpRange, pDoc );
1104 	rStr += aRsc.Copy( nPos+2 );
1105 }
1106 
1107 
1108 sal_Bool ScChangeActionDel::Reject( ScDocument* pDoc )
1109 {
1110 	if ( !aBigRange.IsValid( pDoc ) && GetType() != SC_CAT_DELETE_TABS )
1111 		return sal_False;
1112 
1113 	sal_Bool bOk = sal_True;
1114 
1115 	if ( IsTopDelete() )
1116 	{	// den kompletten Bereich in einem Rutsch restaurieren
1117 		ScBigRange aTmpRange( GetOverAllRange() );
1118 		if ( !aTmpRange.IsValid( pDoc ) )
1119 		{
1120 			if ( GetType() == SC_CAT_DELETE_TABS )
1121 			{	// wird Tab angehaengt?
1122 				if ( aTmpRange.aStart.Tab() > pDoc->GetMaxTableNumber() )
1123 					bOk = sal_False;
1124 			}
1125 			else
1126 				bOk = sal_False;
1127 		}
1128 		if ( bOk )
1129 		{
1130 			ScRange aRange( aTmpRange.MakeRange() );
1131 			// InDelete... fuer Formel UpdateReference in Document
1132 			pTrack->SetInDeleteRange( aRange );
1133 			pTrack->SetInDeleteTop( sal_True );
1134 			pTrack->SetInDeleteUndo( sal_True );
1135 			pTrack->SetInDelete( sal_True );
1136 			switch ( GetType() )
1137 			{
1138 				case SC_CAT_DELETE_COLS :
1139 					if ( !(aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL) )
1140 					{	// nur wenn nicht TabDelete
1141                         if ( ( bOk = pDoc->CanInsertCol( aRange ) ) != sal_False )
1142 							bOk = pDoc->InsertCol( aRange );
1143 					}
1144 				break;
1145 				case SC_CAT_DELETE_ROWS :
1146                     if ( ( bOk = pDoc->CanInsertRow( aRange ) ) != sal_False )
1147 						bOk = pDoc->InsertRow( aRange );
1148 				break;
1149 				case SC_CAT_DELETE_TABS :
1150 				{
1151 //2do: Tabellennamen merken?
1152 					String aName;
1153 					pDoc->CreateValidTabName( aName );
1154                     if ( ( bOk = pDoc->ValidNewTabName( aName ) ) != sal_False )
1155 						bOk = pDoc->InsertTab( aRange.aStart.Tab(), aName );
1156 				}
1157 				break;
1158                 default:
1159                 {
1160                     // added to avoid warnings
1161                 }
1162 			}
1163 			pTrack->SetInDelete( sal_False );
1164 			pTrack->SetInDeleteUndo( sal_False );
1165 		}
1166 		if ( !bOk )
1167 		{
1168 			pTrack->SetInDeleteTop( sal_False );
1169 			return sal_False;
1170 		}
1171 		// InDeleteTop fuer UpdateReference-Undo behalten
1172 	}
1173 
1174 	// setzt rejected und ruft UpdateReference-Undo und DeleteCellEntries
1175 	RejectRestoreContents( pTrack, GetDx(), GetDy() );
1176 
1177 	pTrack->SetInDeleteTop( sal_False );
1178 	RemoveAllLinks();
1179 	return sal_True;
1180 }
1181 
1182 
1183 void ScChangeActionDel::UndoCutOffMoves()
1184 {	// abgeschnittene Moves wiederherstellen, Entries/Links deleten
1185 	while ( pLinkMove )
1186 	{
1187 		ScChangeActionMove* pMove = pLinkMove->GetMove();
1188 		short nFrom = pLinkMove->GetCutOffFrom();
1189 		short nTo = pLinkMove->GetCutOffTo();
1190 		switch ( GetType() )
1191 		{
1192 			case SC_CAT_DELETE_COLS :
1193 				if ( nFrom > 0 )
1194 					pMove->GetFromRange().aStart.IncCol( -nFrom );
1195 				else if ( nFrom < 0 )
1196 					pMove->GetFromRange().aEnd.IncCol( -nFrom );
1197 				if ( nTo > 0 )
1198 					pMove->GetBigRange().aStart.IncCol( -nTo );
1199 				else if ( nTo < 0 )
1200 					pMove->GetBigRange().aEnd.IncCol( -nTo );
1201 			break;
1202 			case SC_CAT_DELETE_ROWS :
1203 				if ( nFrom > 0 )
1204 					pMove->GetFromRange().aStart.IncRow( -nFrom );
1205 				else if ( nFrom < 0 )
1206 					pMove->GetFromRange().aEnd.IncRow( -nFrom );
1207 				if ( nTo > 0 )
1208 					pMove->GetBigRange().aStart.IncRow( -nTo );
1209 				else if ( nTo < 0 )
1210 					pMove->GetBigRange().aEnd.IncRow( -nTo );
1211 			break;
1212 			case SC_CAT_DELETE_TABS :
1213 				if ( nFrom > 0 )
1214 					pMove->GetFromRange().aStart.IncTab( -nFrom );
1215 				else if ( nFrom < 0 )
1216 					pMove->GetFromRange().aEnd.IncTab( -nFrom );
1217 				if ( nTo > 0 )
1218 					pMove->GetBigRange().aStart.IncTab( -nTo );
1219 				else if ( nTo < 0 )
1220 					pMove->GetBigRange().aEnd.IncTab( -nTo );
1221 			break;
1222             default:
1223             {
1224                 // added to avoid warnings
1225             }
1226 		}
1227 		delete pLinkMove;		// rueckt sich selbst hoch
1228 	}
1229 }
1230 
1231 void ScChangeActionDel::UndoCutOffInsert()
1232 {	// abgeschnittenes Insert wiederherstellen
1233 	if ( pCutOff )
1234 	{
1235 		switch ( pCutOff->GetType() )
1236 		{
1237 			case SC_CAT_INSERT_COLS :
1238 				if ( nCutOff < 0 )
1239 					pCutOff->GetBigRange().aEnd.IncCol( -nCutOff );
1240 				else
1241 					pCutOff->GetBigRange().aStart.IncCol( -nCutOff );
1242 			break;
1243 			case SC_CAT_INSERT_ROWS :
1244 				if ( nCutOff < 0 )
1245 					pCutOff->GetBigRange().aEnd.IncRow( -nCutOff );
1246 				else
1247 					pCutOff->GetBigRange().aStart.IncRow( -nCutOff );
1248 			break;
1249 			case SC_CAT_INSERT_TABS :
1250 				if ( nCutOff < 0 )
1251 					pCutOff->GetBigRange().aEnd.IncTab( -nCutOff );
1252 				else
1253 					pCutOff->GetBigRange().aStart.IncTab( -nCutOff );
1254 			break;
1255             default:
1256             {
1257                 // added to avoid warnings
1258             }
1259 		}
1260 		SetCutOffInsert( NULL, 0 );
1261 	}
1262 }
1263 
1264 
1265 // --- ScChangeActionMove --------------------------------------------------
1266 
1267 ScChangeActionMove::ScChangeActionMove(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
1268                                     const ScBigRange& aToBigRange, const String& aUserP, const DateTime& aDateTimeP, const String &sComment,
1269 									const ScBigRange& aFromBigRange, ScChangeTrack* pTrackP) // wich of nDx and nDy is set is depend on the type
1270 		:
1271         ScChangeAction(SC_CAT_MOVE, aToBigRange, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
1272 		aFromRange(aFromBigRange),
1273 		pTrack( pTrackP ),
1274 		pFirstCell( NULL ),
1275 		nStartLastCut(0),
1276 		nEndLastCut(0)
1277 {
1278 }
1279 
1280 ScChangeActionMove::~ScChangeActionMove()
1281 {
1282 	DeleteCellEntries();
1283 }
1284 
1285 
1286 void ScChangeActionMove::AddContent( ScChangeActionContent* pContent )
1287 {
1288 	ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry(
1289 		pContent, pFirstCell );
1290 	pFirstCell = pE;
1291 }
1292 
1293 
1294 void ScChangeActionMove::DeleteCellEntries()
1295 {
1296 	pTrack->DeleteCellEntries( pFirstCell, this );
1297 }
1298 
1299 
1300 void ScChangeActionMove::UpdateReference( const ScChangeTrack* /* pTrack */,
1301 		UpdateRefMode eMode, const ScBigRange& rRange,
1302 		sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
1303 {
1304 	ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aFromRange );
1305 	ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() );
1306 }
1307 
1308 
1309 void ScChangeActionMove::GetDelta( sal_Int32& nDx, sal_Int32& nDy, sal_Int32& nDz ) const
1310 {
1311 	const ScBigAddress& rToPos = GetBigRange().aStart;
1312 	const ScBigAddress& rFromPos = GetFromRange().aStart;
1313 	nDx = rToPos.Col() - rFromPos.Col();
1314 	nDy = rToPos.Row() - rFromPos.Row();
1315 	nDz = rToPos.Tab() - rFromPos.Tab();
1316 }
1317 
1318 
1319 void ScChangeActionMove::GetDescription( String& rStr, ScDocument* pDoc,
1320 		sal_Bool bSplitRange, bool bWarning ) const
1321 {
1322     ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
1323 
1324 	sal_Bool bFlag3D = ( GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab() );
1325 
1326 	String aRsc( ScGlobal::GetRscString( STR_CHANGED_MOVE ) );
1327 
1328 	xub_StrLen nPos = 0;
1329 	String aTmpStr = ScChangeAction::GetRefString( GetFromRange(), pDoc, bFlag3D );
1330 	nPos = aRsc.SearchAscii( "#1", nPos );
1331 	aRsc.Erase( nPos, 2 );
1332 	aRsc.Insert( aTmpStr, nPos );
1333     nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() );
1334 
1335 	aTmpStr = ScChangeAction::GetRefString( GetBigRange(), pDoc, bFlag3D );
1336 	nPos = aRsc.SearchAscii( "#2", nPos );
1337 	aRsc.Erase( nPos, 2 );
1338 	aRsc.Insert( aTmpStr, nPos );
1339 	nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() );
1340 
1341 	rStr += aRsc;
1342 }
1343 
1344 
1345 void ScChangeActionMove::GetRefString( String& rStr, ScDocument* pDoc,
1346 		sal_Bool bFlag3D ) const
1347 {
1348 	if ( !bFlag3D )
1349 		bFlag3D = ( GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab() );
1350 	rStr = ScChangeAction::GetRefString( GetFromRange(), pDoc, bFlag3D );
1351 	rStr += ',';
1352 	rStr += ' ';
1353 	rStr += ScChangeAction::GetRefString( GetBigRange(), pDoc, bFlag3D );
1354 }
1355 
1356 
1357 sal_Bool ScChangeActionMove::Reject( ScDocument* pDoc )
1358 {
1359 	if ( !(aBigRange.IsValid( pDoc ) && aFromRange.IsValid( pDoc )) )
1360 		return sal_False;
1361 
1362 	ScRange aToRange( aBigRange.MakeRange() );
1363 	ScRange aFrmRange( aFromRange.MakeRange() );
1364 
1365 	sal_Bool bOk = pDoc->IsBlockEditable( aToRange.aStart.Tab(),
1366 		aToRange.aStart.Col(), aToRange.aStart.Row(),
1367 		aToRange.aEnd.Col(), aToRange.aEnd.Row() );
1368 	if ( bOk )
1369 		bOk = pDoc->IsBlockEditable( aFrmRange.aStart.Tab(),
1370 			aFrmRange.aStart.Col(), aFrmRange.aStart.Row(),
1371 			aFrmRange.aEnd.Col(), aFrmRange.aEnd.Row() );
1372 	if ( !bOk )
1373 		return sal_False;
1374 
1375 	pTrack->LookUpContents( aToRange, pDoc, 0, 0, 0 );	// zu movende Contents
1376 
1377 	pDoc->DeleteAreaTab( aToRange, IDF_ALL );
1378 	pDoc->DeleteAreaTab( aFrmRange, IDF_ALL );
1379 	// Formeln im Dokument anpassen
1380 	pDoc->UpdateReference( URM_MOVE,
1381 		aFrmRange.aStart.Col(), aFrmRange.aStart.Row(), aFrmRange.aStart.Tab(),
1382 		aFrmRange.aEnd.Col(), aFrmRange.aEnd.Row(), aFrmRange.aEnd.Tab(),
1383 		(SCsCOL) aFrmRange.aStart.Col() - aToRange.aStart.Col(),
1384 		(SCsROW) aFrmRange.aStart.Row() - aToRange.aStart.Row(),
1385 		(SCsTAB) aFrmRange.aStart.Tab() - aToRange.aStart.Tab(), NULL );
1386 
1387 	// LinkDependent freigeben, nachfolgendes UpdateReference-Undo setzt
1388 	// ToRange->FromRange Dependents
1389 	RemoveAllDependent();
1390 
1391 	// setzt rejected und ruft UpdateReference-Undo und DeleteCellEntries
1392 	RejectRestoreContents( pTrack, 0, 0 );
1393 
1394 	while ( pLinkDependent )
1395 	{
1396 		ScChangeAction* p = pLinkDependent->GetAction();
1397 		if ( p && p->GetType() == SC_CAT_CONTENT )
1398 		{
1399 			ScChangeActionContent* pContent = (ScChangeActionContent*) p;
1400 			if ( !pContent->IsDeletedIn() &&
1401 					pContent->GetBigRange().aStart.IsValid( pDoc ) )
1402 				pContent->PutNewValueToDoc( pDoc, 0, 0 );
1403 			// in LookUpContents generierte loeschen
1404 			if ( pTrack->IsGenerated( pContent->GetActionNumber() ) &&
1405 					!pContent->IsDeletedIn() )
1406 			{
1407 				pLinkDependent->UnLink();		//! sonst wird der mitgeloescht
1408 				pTrack->DeleteGeneratedDelContent( pContent );
1409 			}
1410 		}
1411 		delete pLinkDependent;
1412 	}
1413 
1414 	RemoveAllLinks();
1415 	return sal_True;
1416 }
1417 
1418 
1419 // --- ScChangeActionContent -----------------------------------------------
1420 
1421 const sal_uInt16 nMemPoolChangeActionContent = (0x8000 - 64) / sizeof(ScChangeActionContent);
1422 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionContent, nMemPoolChangeActionContent, nMemPoolChangeActionContent )
1423 
1424 ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber,
1425             const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
1426             const ScBigRange& aBigRangeP, const String& aUserP,
1427             const DateTime& aDateTimeP, const String& sComment,
1428 			ScBaseCell* pTempOldCell, ScDocument* pDoc, const String& sOldValue )
1429 		:
1430         ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
1431 		aOldValue(sOldValue),
1432 		pOldCell(pTempOldCell),
1433 		pNewCell(NULL),
1434 		pNextContent(NULL),
1435 		pPrevContent(NULL),
1436 		pNextInSlot(NULL),
1437 		ppPrevInSlot(NULL)
1438 
1439 {
1440 	if (pOldCell)
1441 		ScChangeActionContent::SetCell( aOldValue, pOldCell, 0, pDoc );
1442     if ( sOldValue.Len() )     // #i40704# don't overwrite SetCell result with empty string
1443         aOldValue = sOldValue; // set again, because SetCell removes it
1444 }
1445 
1446 ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber,
1447             ScBaseCell* pTempNewCell, const ScBigRange& aBigRangeP,
1448 			ScDocument* pDoc, const String& sNewValue )
1449 		:
1450         ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber),
1451         aNewValue(sNewValue),
1452 		pOldCell(NULL),
1453 		pNewCell(pTempNewCell),
1454 		pNextContent(NULL),
1455 		pPrevContent(NULL),
1456 		pNextInSlot(NULL),
1457 		ppPrevInSlot(NULL)
1458 {
1459 	if (pNewCell)
1460 		ScChangeActionContent::SetCell( aNewValue, pNewCell, 0, pDoc );
1461     if ( sNewValue.Len() )     // #i40704# don't overwrite SetCell result with empty string
1462         aNewValue = sNewValue; // set again, because SetCell removes it
1463 }
1464 
1465 ScChangeActionContent::~ScChangeActionContent()
1466 {
1467 	ClearTrack();
1468 }
1469 
1470 
1471 void ScChangeActionContent::ClearTrack()
1472 {
1473 	RemoveFromSlot();
1474 	if ( pPrevContent )
1475 		pPrevContent->pNextContent = pNextContent;
1476 	if ( pNextContent )
1477 		pNextContent->pPrevContent = pPrevContent;
1478 }
1479 
1480 
1481 ScChangeActionContent* ScChangeActionContent::GetTopContent() const
1482 {
1483 	if ( pNextContent )
1484 	{
1485 		ScChangeActionContent* pContent = pNextContent;
1486 		while ( pContent->pNextContent && pContent != pContent->pNextContent )
1487 			pContent = pContent->pNextContent;
1488 		return pContent;
1489 	}
1490 	return (ScChangeActionContent*) this;
1491 }
1492 
1493 
1494 ScChangeActionLinkEntry* ScChangeActionContent::GetDeletedIn() const
1495 {
1496 	if ( pNextContent )
1497 		return GetTopContent()->pLinkDeletedIn;
1498 	return pLinkDeletedIn;
1499 }
1500 
1501 
1502 ScChangeActionLinkEntry** ScChangeActionContent::GetDeletedInAddress()
1503 {
1504 	if ( pNextContent )
1505 		return GetTopContent()->GetDeletedInAddress();
1506 	return &pLinkDeletedIn;
1507 }
1508 
1509 
1510 void ScChangeActionContent::SetOldValue( const ScBaseCell* pCell,
1511 		const ScDocument* pFromDoc, ScDocument* pToDoc, sal_uLong nFormat )
1512 {
1513 	ScChangeActionContent::SetValue( aOldValue, pOldCell,
1514 		nFormat, pCell, pFromDoc, pToDoc );
1515 }
1516 
1517 
1518 void ScChangeActionContent::SetOldValue( const ScBaseCell* pCell,
1519 		const ScDocument* pFromDoc, ScDocument* pToDoc )
1520 {
1521 	ScChangeActionContent::SetValue( aOldValue, pOldCell,
1522 		aBigRange.aStart.MakeAddress(), pCell, pFromDoc, pToDoc );
1523 }
1524 
1525 
1526 void ScChangeActionContent::SetNewValue( const ScBaseCell* pCell,
1527 		ScDocument* pDoc )
1528 {
1529 	ScChangeActionContent::SetValue( aNewValue, pNewCell,
1530 		aBigRange.aStart.MakeAddress(), pCell, pDoc, pDoc );
1531 }
1532 
1533 
1534 void ScChangeActionContent::SetOldNewCells( ScBaseCell* pOldCellP,
1535 						sal_uLong nOldFormat, ScBaseCell* pNewCellP,
1536 						sal_uLong nNewFormat, ScDocument* pDoc )
1537 {
1538 	pOldCell = pOldCellP;
1539 	pNewCell = pNewCellP;
1540 	ScChangeActionContent::SetCell( aOldValue, pOldCell, nOldFormat, pDoc );
1541 	ScChangeActionContent::SetCell( aNewValue, pNewCell, nNewFormat, pDoc );
1542 }
1543 
1544 void ScChangeActionContent::SetNewCell( ScBaseCell* pCell, ScDocument* pDoc, const String& rFormatted )
1545 {
1546 	DBG_ASSERT( !pNewCell, "ScChangeActionContent::SetNewCell: overwriting existing cell" );
1547 	pNewCell = pCell;
1548 	ScChangeActionContent::SetCell( aNewValue, pNewCell, 0, pDoc );
1549 
1550     // #i40704# allow to set formatted text here - don't call SetNewValue with String from XML filter
1551     if ( rFormatted.Len() )
1552         aNewValue = rFormatted;
1553 }
1554 
1555 void ScChangeActionContent::SetValueString( String& rValue, ScBaseCell*& pCell,
1556 		const String& rStr, ScDocument* pDoc )
1557 {
1558 	if ( pCell )
1559 	{
1560 		pCell->Delete();
1561 		pCell = NULL;
1562 	}
1563 	if ( rStr.Len() > 1 && rStr.GetChar(0) == '=' )
1564 	{
1565 		rValue.Erase();
1566 		pCell = new ScFormulaCell(
1567             pDoc, aBigRange.aStart.MakeAddress(), rStr, formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::CONV_OOO );
1568 		((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True );
1569 	}
1570 	else
1571 		rValue = rStr;
1572 }
1573 
1574 
1575 void ScChangeActionContent::SetOldValue( const String& rOld, ScDocument* pDoc )
1576 {
1577 	SetValueString( aOldValue, pOldCell, rOld, pDoc );
1578 }
1579 
1580 
1581 void ScChangeActionContent::SetNewValue( const String& rNew, ScDocument* pDoc )
1582 {
1583 	SetValueString( aNewValue, pNewCell, rNew, pDoc );
1584 }
1585 
1586 
1587 void ScChangeActionContent::GetOldString( String& rStr ) const
1588 {
1589 	GetValueString( rStr, aOldValue, pOldCell );
1590 }
1591 
1592 
1593 void ScChangeActionContent::GetNewString( String& rStr ) const
1594 {
1595 	GetValueString( rStr, aNewValue, pNewCell );
1596 }
1597 
1598 
1599 void ScChangeActionContent::GetDescription( String& rStr, ScDocument* pDoc,
1600 		sal_Bool bSplitRange, bool bWarning ) const
1601 {
1602     ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning );
1603 
1604 	String aRsc( ScGlobal::GetRscString( STR_CHANGED_CELL ) );
1605 
1606 	String aTmpStr;
1607 	GetRefString( aTmpStr, pDoc );
1608 
1609 	xub_StrLen nPos = 0;
1610 	nPos = aRsc.SearchAscii( "#1", nPos );
1611 	aRsc.Erase( nPos, 2 );
1612 	aRsc.Insert( aTmpStr, nPos );
1613     nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() );
1614 
1615 	GetOldString( aTmpStr );
1616 	if ( !aTmpStr.Len() )
1617 		aTmpStr = ScGlobal::GetRscString( STR_CHANGED_BLANK );
1618 	nPos = aRsc.SearchAscii( "#2", nPos );
1619 	aRsc.Erase( nPos, 2 );
1620 	aRsc.Insert( aTmpStr, nPos );
1621 	nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() );
1622 
1623 	GetNewString( aTmpStr );
1624 	if ( !aTmpStr.Len() )
1625 		aTmpStr = ScGlobal::GetRscString( STR_CHANGED_BLANK );
1626 	nPos = aRsc.SearchAscii( "#3", nPos );
1627 	aRsc.Erase( nPos, 2 );
1628 	aRsc.Insert( aTmpStr, nPos );
1629 
1630 	rStr += aRsc;
1631 }
1632 
1633 
1634 void ScChangeActionContent::GetRefString( String& rStr, ScDocument* pDoc,
1635 		sal_Bool bFlag3D ) const
1636 {
1637 	sal_uInt16 nFlags = ( GetBigRange().IsValid( pDoc ) ? SCA_VALID : 0 );
1638 	if ( nFlags )
1639 	{
1640 		const ScBaseCell* pCell = GetNewCell();
1641 		if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATORG )
1642 		{
1643             ScBigRange aLocalBigRange( GetBigRange() );
1644             SCCOL nC;
1645             SCROW nR;
1646             ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR );
1647             aLocalBigRange.aEnd.IncCol( nC-1 );
1648             aLocalBigRange.aEnd.IncRow( nR-1 );
1649             rStr = ScChangeAction::GetRefString( aLocalBigRange, pDoc, bFlag3D );
1650 
1651 			return ;
1652 		}
1653 
1654 		ScAddress aTmpAddress( GetBigRange().aStart.MakeAddress() );
1655 		if ( bFlag3D )
1656 			nFlags |= SCA_TAB_3D;
1657 		aTmpAddress.Format( rStr, nFlags, pDoc, pDoc->GetAddressConvention() );
1658 		if ( IsDeletedIn() )
1659 		{
1660 			rStr.Insert( '(', 0 );
1661 			rStr += ')';
1662 		}
1663 	}
1664 	else
1665 		rStr = ScGlobal::GetRscString( STR_NOREF_STR );
1666 }
1667 
1668 
1669 sal_Bool ScChangeActionContent::Reject( ScDocument* pDoc )
1670 {
1671 	if ( !aBigRange.IsValid( pDoc ) )
1672 		return sal_False;
1673 
1674 	PutOldValueToDoc( pDoc, 0, 0 );
1675 
1676 	SetState( SC_CAS_REJECTED );
1677 	RemoveAllLinks();
1678 
1679 	return sal_True;
1680 }
1681 
1682 
1683 sal_Bool ScChangeActionContent::Select( ScDocument* pDoc, ScChangeTrack* pTrack,
1684 		sal_Bool bOldest, Stack* pRejectActions )
1685 {
1686 	if ( !aBigRange.IsValid( pDoc ) )
1687 		return sal_False;
1688 
1689 	ScChangeActionContent* pContent = this;
1690 	// accept previous contents
1691     while ( ( pContent = pContent->pPrevContent ) != NULL )
1692 	{
1693 		if ( pContent->IsVirgin() )
1694 			pContent->SetState( SC_CAS_ACCEPTED );
1695 	}
1696 	ScChangeActionContent* pEnd = pContent = this;
1697 	// reject subsequent contents
1698     while ( ( pContent = pContent->pNextContent ) != NULL )
1699 	{
1700 		// MatrixOrigin may have dependents, no dependency recursion needed
1701 		const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry();
1702 		while ( pL )
1703 		{
1704 			ScChangeAction* p = (ScChangeAction*) pL->GetAction();
1705 			if ( p )
1706 				p->SetRejected();
1707 			pL = pL->GetNext();
1708 		}
1709 		pContent->SetRejected();
1710 		pEnd = pContent;
1711 	}
1712 
1713 	if ( bOldest || pEnd != this )
1714 	{	// wenn nicht aeltester: ist es ueberhaupt ein anderer als der letzte?
1715 		ScRange aRange( aBigRange.aStart.MakeAddress() );
1716 		const ScAddress& rPos = aRange.aStart;
1717 
1718 		ScChangeActionContent* pNew = new ScChangeActionContent( aRange );
1719 		pNew->SetOldValue( pDoc->GetCell( rPos ), pDoc, pDoc );
1720 
1721 		if ( bOldest )
1722 			PutOldValueToDoc( pDoc, 0, 0 );
1723 		else
1724 			PutNewValueToDoc( pDoc, 0, 0 );
1725 
1726 		pNew->SetRejectAction( bOldest ? GetActionNumber() : pEnd->GetActionNumber() );
1727 		pNew->SetState( SC_CAS_ACCEPTED );
1728 		if ( pRejectActions )
1729 			pRejectActions->Push( pNew );
1730 		else
1731 		{
1732 			pNew->SetNewValue( pDoc->GetCell( rPos ), pDoc );
1733 			pTrack->Append( pNew );
1734 		}
1735 	}
1736 
1737 	if ( bOldest )
1738 		SetRejected();
1739 	else
1740 		SetState( SC_CAS_ACCEPTED );
1741 
1742 	return sal_True;
1743 }
1744 
1745 
1746 // static
1747 void ScChangeActionContent::GetStringOfCell( String& rStr,
1748 		const ScBaseCell* pCell, const ScDocument* pDoc, const ScAddress& rPos )
1749 {
1750 	if ( pCell )
1751 	{
1752 		if ( ScChangeActionContent::NeedsNumberFormat( pCell ) )
1753 			GetStringOfCell( rStr, pCell, pDoc, pDoc->GetNumberFormat( rPos ) );
1754 		else
1755 			GetStringOfCell( rStr, pCell, pDoc, 0 );
1756 	}
1757 	else
1758 		rStr.Erase();
1759 }
1760 
1761 
1762 // static
1763 void ScChangeActionContent::GetStringOfCell( String& rStr,
1764 		const ScBaseCell* pCell, const ScDocument* pDoc, sal_uLong nFormat )
1765 {
1766 	if ( ScChangeActionContent::GetContentCellType( pCell ) )
1767 	{
1768 		switch ( pCell->GetCellType() )
1769 		{
1770 			case CELLTYPE_VALUE :
1771 			{
1772 				double nValue = ((ScValueCell*)pCell)->GetValue();
1773 				pDoc->GetFormatTable()->GetInputLineString( nValue,	nFormat,
1774 					rStr );
1775 			}
1776 			break;
1777 			case CELLTYPE_STRING :
1778 				((ScStringCell*)pCell)->GetString( rStr );
1779 			break;
1780 			case CELLTYPE_EDIT :
1781 				((ScEditCell*)pCell)->GetString( rStr );
1782 			break;
1783 			case CELLTYPE_FORMULA :
1784 				((ScFormulaCell*)pCell)->GetFormula( rStr );
1785 			break;
1786 			default:
1787 				rStr.Erase();
1788 		}
1789 	}
1790 	else
1791 		rStr.Erase();
1792 }
1793 
1794 
1795 // static
1796 ScChangeActionContentCellType ScChangeActionContent::GetContentCellType( const ScBaseCell* pCell )
1797 {
1798 	if ( pCell )
1799 	{
1800 		switch ( pCell->GetCellType() )
1801 		{
1802 			case CELLTYPE_VALUE :
1803 			case CELLTYPE_STRING :
1804 			case CELLTYPE_EDIT :
1805 				return SC_CACCT_NORMAL;
1806             //break;
1807 			case CELLTYPE_FORMULA :
1808 				switch ( ((const ScFormulaCell*)pCell)->GetMatrixFlag() )
1809 				{
1810 					case MM_NONE :
1811 						return SC_CACCT_NORMAL;
1812                     //break;
1813 					case MM_FORMULA :
1814 					case MM_FAKE :
1815 						return SC_CACCT_MATORG;
1816                     //break;
1817 					case MM_REFERENCE :
1818 						return SC_CACCT_MATREF;
1819                     //break;
1820 				}
1821 				return SC_CACCT_NORMAL;
1822             //break;
1823 			default:
1824 				return SC_CACCT_NONE;
1825 		}
1826 	}
1827 	return SC_CACCT_NONE;
1828 }
1829 
1830 
1831 // static
1832 sal_Bool ScChangeActionContent::NeedsNumberFormat( const ScBaseCell* pCell )
1833 {
1834 	return pCell && pCell->GetCellType() == CELLTYPE_VALUE;
1835 }
1836 
1837 
1838 // static
1839 void ScChangeActionContent::SetValue( String& rStr, ScBaseCell*& pCell,
1840 		const ScAddress& rPos, const ScBaseCell* pOrgCell,
1841 		const ScDocument* pFromDoc, ScDocument* pToDoc )
1842 {
1843 	sal_uLong nFormat = NeedsNumberFormat( pOrgCell ) ? pFromDoc->GetNumberFormat( rPos ) : 0;
1844     SetValue( rStr, pCell, nFormat, pOrgCell, pFromDoc, pToDoc );
1845 }
1846 
1847 
1848 // static
1849 void ScChangeActionContent::SetValue( String& rStr, ScBaseCell*& pCell,
1850 		sal_uLong nFormat, const ScBaseCell* pOrgCell,
1851 		const ScDocument* pFromDoc, ScDocument* pToDoc )
1852 {
1853 	rStr.Erase();
1854 	if ( pCell )
1855 		pCell->Delete();
1856 	if ( ScChangeActionContent::GetContentCellType( pOrgCell ) )
1857 	{
1858         pCell = pOrgCell->CloneWithoutNote( *pToDoc );
1859 		switch ( pOrgCell->GetCellType() )
1860 		{
1861 			case CELLTYPE_VALUE :
1862 			{	// z.B. Datum auch als solches merken
1863 				double nValue = ((ScValueCell*)pOrgCell)->GetValue();
1864 				pFromDoc->GetFormatTable()->GetInputLineString( nValue,
1865 					nFormat, rStr );
1866 			}
1867 			break;
1868 			case CELLTYPE_FORMULA :
1869 				((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True );
1870 			break;
1871             default:
1872             {
1873                 // added to avoid warnings
1874             }
1875 		}
1876 	}
1877 	else
1878 		pCell = NULL;
1879 }
1880 
1881 
1882 // static
1883 void ScChangeActionContent::SetCell( String& rStr, ScBaseCell* pCell,
1884 		sal_uLong nFormat, const ScDocument* pDoc )
1885 {
1886 	rStr.Erase();
1887 	if ( pCell )
1888 	{
1889 		switch ( pCell->GetCellType() )
1890 		{
1891 			case CELLTYPE_VALUE :
1892 			{	// e.g. remember date as date string
1893 				double nValue = ((ScValueCell*)pCell)->GetValue();
1894 				pDoc->GetFormatTable()->GetInputLineString( nValue,
1895 					nFormat, rStr );
1896 			}
1897 			break;
1898 			case CELLTYPE_FORMULA :
1899 				((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True );
1900 			break;
1901             default:
1902             {
1903                 // added to avoid warnings
1904             }
1905 		}
1906 	}
1907 }
1908 
1909 
1910 void ScChangeActionContent::GetValueString( String& rStr,
1911 		const String& rValue, const ScBaseCell* pCell ) const
1912 {
1913 	if ( !rValue.Len() )
1914 	{
1915 		if ( pCell )
1916 		{
1917 			switch ( pCell->GetCellType() )
1918 			{
1919 				case CELLTYPE_STRING :
1920 					((ScStringCell*)pCell)->GetString( rStr );
1921 				break;
1922 				case CELLTYPE_EDIT :
1923 					((ScEditCell*)pCell)->GetString( rStr );
1924 				break;
1925 				case CELLTYPE_VALUE :	// ist immer in rValue
1926 					rStr = rValue;
1927 				break;
1928 				case CELLTYPE_FORMULA :
1929 					GetFormulaString( rStr, (ScFormulaCell*) pCell );
1930 				break;
1931                 default:
1932                 {
1933                     // added to avoid warnings
1934                 }
1935 			}
1936 		}
1937 		else
1938 			rStr.Erase();
1939 	}
1940 	else
1941 		rStr = rValue;
1942 }
1943 
1944 
1945 void ScChangeActionContent::GetFormulaString( String& rStr,
1946 		const ScFormulaCell* pCell ) const
1947 {
1948 	ScAddress aPos( aBigRange.aStart.MakeAddress() );
1949 	if ( aPos == pCell->aPos || IsDeletedIn() )
1950 		pCell->GetFormula( rStr );
1951 	else
1952 	{
1953 		DBG_ERROR( "ScChangeActionContent::GetFormulaString: aPos != pCell->aPos" );
1954         ScFormulaCell* pNew = new ScFormulaCell( *pCell, *pCell->GetDocument(), aPos );
1955 		pNew->GetFormula( rStr );
1956 		delete pNew;
1957 	}
1958 }
1959 
1960 
1961 void ScChangeActionContent::PutOldValueToDoc( ScDocument* pDoc,
1962 		SCsCOL nDx, SCsROW nDy ) const
1963 {
1964 	PutValueToDoc( pOldCell, aOldValue, pDoc, nDx, nDy );
1965 }
1966 
1967 
1968 void ScChangeActionContent::PutNewValueToDoc( ScDocument* pDoc,
1969 		SCsCOL nDx, SCsROW nDy ) const
1970 {
1971 	PutValueToDoc( pNewCell, aNewValue, pDoc, nDx, nDy );
1972 }
1973 
1974 
1975 void ScChangeActionContent::PutValueToDoc( ScBaseCell* pCell,
1976 		const String& rValue, ScDocument* pDoc, SCsCOL nDx, SCsROW nDy ) const
1977 {
1978 	ScAddress aPos( aBigRange.aStart.MakeAddress() );
1979 	if ( nDx )
1980 		aPos.IncCol( nDx );
1981 	if ( nDy )
1982 		aPos.IncRow( nDy );
1983 	if ( !rValue.Len() )
1984 	{
1985 		if ( pCell )
1986 		{
1987 			switch ( pCell->GetCellType() )
1988 			{
1989 				case CELLTYPE_VALUE :	// ist immer in rValue
1990 					pDoc->SetString( aPos.Col(), aPos.Row(), aPos.Tab(), rValue );
1991 				break;
1992 				default:
1993 					switch ( ScChangeActionContent::GetContentCellType( pCell ) )
1994 					{
1995 						case SC_CACCT_MATORG :
1996 						{
1997                             SCCOL nC;
1998                             SCROW nR;
1999                             ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR );
2000 							DBG_ASSERT( nC>0 && nR>0, "ScChangeActionContent::PutValueToDoc: MatColsRows?" );
2001 							ScRange aRange( aPos );
2002 							if ( nC > 1 )
2003 								aRange.aEnd.IncCol( nC-1 );
2004 							if ( nR > 1 )
2005 								aRange.aEnd.IncRow( nR-1 );
2006 							ScMarkData aDestMark;
2007 							aDestMark.SelectOneTable( aPos.Tab() );
2008 							aDestMark.SetMarkArea( aRange );
2009 							pDoc->InsertMatrixFormula( aPos.Col(), aPos.Row(),
2010 								aRange.aEnd.Col(), aRange.aEnd.Row(),
2011 								aDestMark, EMPTY_STRING,
2012 								((const ScFormulaCell*)pCell)->GetCode() );
2013 						}
2014 						break;
2015 						case SC_CACCT_MATREF :
2016 							// nothing
2017 						break;
2018 						default:
2019                             pDoc->PutCell( aPos, pCell->CloneWithoutNote( *pDoc ) );
2020 					}
2021 			}
2022 		}
2023 		else
2024 			pDoc->PutCell( aPos, NULL );
2025 	}
2026 	else
2027 		pDoc->SetString( aPos.Col(), aPos.Row(), aPos.Tab(), rValue );
2028 }
2029 
2030 
2031 void lcl_InvalidateReference( ScToken& rTok, const ScBigAddress& rPos )
2032 {
2033 	ScSingleRefData& rRef1 = rTok.GetSingleRef();
2034 	if ( rPos.Col() < 0 || MAXCOL < rPos.Col() )
2035 	{
2036 		rRef1.nCol = SCCOL_MAX;
2037 		rRef1.nRelCol = SCCOL_MAX;
2038 		rRef1.SetColDeleted( sal_True );
2039 	}
2040 	if ( rPos.Row() < 0 || MAXROW < rPos.Row() )
2041 	{
2042 		rRef1.nRow = SCROW_MAX;
2043 		rRef1.nRelRow = SCROW_MAX;
2044 		rRef1.SetRowDeleted( sal_True );
2045 	}
2046 	if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() )
2047 	{
2048 		rRef1.nTab = SCTAB_MAX;
2049 		rRef1.nRelTab = SCTAB_MAX;
2050 		rRef1.SetTabDeleted( sal_True );
2051 	}
2052 	if ( rTok.GetType() == formula::svDoubleRef )
2053 	{
2054 		ScSingleRefData& rRef2 = rTok.GetDoubleRef().Ref2;
2055 		if ( rPos.Col() < 0 || MAXCOL < rPos.Col() )
2056 		{
2057 			rRef2.nCol = SCCOL_MAX;
2058 			rRef2.nRelCol = SCCOL_MAX;
2059 			rRef2.SetColDeleted( sal_True );
2060 		}
2061 		if ( rPos.Row() < 0 || MAXROW < rPos.Row() )
2062 		{
2063 			rRef2.nRow = SCROW_MAX;
2064 			rRef2.nRelRow = SCROW_MAX;
2065 			rRef2.SetRowDeleted( sal_True );
2066 		}
2067 		if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() )
2068 		{
2069 			rRef2.nTab = SCTAB_MAX;
2070 			rRef2.nRelTab = SCTAB_MAX;
2071 			rRef2.SetTabDeleted( sal_True );
2072 		}
2073 	}
2074 }
2075 
2076 
2077 void ScChangeActionContent::UpdateReference( const ScChangeTrack* pTrack,
2078 		UpdateRefMode eMode, const ScBigRange& rRange,
2079 		sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
2080 {
2081 	SCSIZE nOldSlot = ScChangeTrack::ComputeContentSlot( aBigRange.aStart.Row() );
2082 	ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aBigRange );
2083 	SCSIZE nNewSlot = ScChangeTrack::ComputeContentSlot( aBigRange.aStart.Row() );
2084 	if ( nNewSlot != nOldSlot )
2085 	{
2086 		RemoveFromSlot();
2087 		InsertInSlot( &(pTrack->GetContentSlots()[nNewSlot]) );
2088 	}
2089 
2090 	if ( pTrack->IsInDelete() && !pTrack->IsInDeleteTop() )
2091 		return ;		// Formeln nur kompletten Bereich updaten
2092 
2093 	sal_Bool bOldFormula = ( pOldCell && pOldCell->GetCellType() == CELLTYPE_FORMULA );
2094 	sal_Bool bNewFormula = ( pNewCell && pNewCell->GetCellType() == CELLTYPE_FORMULA );
2095 	if ( bOldFormula || bNewFormula )
2096 	{	// via ScFormulaCell UpdateReference anpassen (dort)
2097 		if ( pTrack->IsInDelete() )
2098 		{
2099 			const ScRange& rDelRange = pTrack->GetInDeleteRange();
2100 			if ( nDx > 0 )
2101 				nDx = rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1;
2102 			else if ( nDx < 0 )
2103 				nDx = -(rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1);
2104 			if ( nDy > 0 )
2105 				nDy = rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1;
2106 			else if ( nDy < 0 )
2107 				nDy = -(rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1);
2108 			if ( nDz > 0 )
2109 				nDz = rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1;
2110 			else if ( nDz < 0 )
2111 				nDz = -(rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1);
2112 		}
2113 		ScBigRange aTmpRange( rRange );
2114 		switch ( eMode )
2115 		{
2116 			case URM_INSDEL :
2117 				if ( nDx < 0 || nDy < 0 || nDz < 0 )
2118 				{	// Delete startet dort hinter geloeschtem Bereich,
2119 					// Position wird dort angepasst.
2120 					if ( nDx )
2121 						aTmpRange.aStart.IncCol( -nDx );
2122 					if ( nDy )
2123 						aTmpRange.aStart.IncRow( -nDy );
2124 					if ( nDz )
2125 						aTmpRange.aStart.IncTab( -nDz );
2126 				}
2127 			break;
2128 			case URM_MOVE :
2129 				// Move ist hier Quelle, dort Ziel,
2130 				// Position muss vorher angepasst sein.
2131 				if ( bOldFormula )
2132 					((ScFormulaCell*)pOldCell)->aPos = aBigRange.aStart.MakeAddress();
2133 				if ( bNewFormula )
2134 					((ScFormulaCell*)pNewCell)->aPos = aBigRange.aStart.MakeAddress();
2135 				if ( nDx )
2136 				{
2137 					aTmpRange.aStart.IncCol( nDx );
2138 					aTmpRange.aEnd.IncCol( nDx );
2139 				}
2140 				if ( nDy )
2141 				{
2142 					aTmpRange.aStart.IncRow( nDy );
2143 					aTmpRange.aEnd.IncRow( nDy );
2144 				}
2145 				if ( nDz )
2146 				{
2147 					aTmpRange.aStart.IncTab( nDz );
2148 					aTmpRange.aEnd.IncTab( nDz );
2149 				}
2150 			break;
2151             default:
2152             {
2153                 // added to avoid warnings
2154             }
2155 		}
2156 		ScRange aRange( aTmpRange.MakeRange() );
2157 		if ( bOldFormula )
2158 			((ScFormulaCell*)pOldCell)->UpdateReference( eMode, aRange,
2159 				(SCsCOL) nDx, (SCsROW) nDy, (SCsTAB) nDz, NULL );
2160 		if ( bNewFormula )
2161 			((ScFormulaCell*)pNewCell)->UpdateReference( eMode, aRange,
2162 				(SCsCOL) nDx, (SCsROW) nDy, (SCsTAB) nDz, NULL );
2163 		if ( !aBigRange.aStart.IsValid( pTrack->GetDocument() ) )
2164 		{	//! HACK!
2165 			//! UpdateReference kann nicht mit Positionen ausserhalb des
2166 			//! Dokuments umgehen, deswegen alles auf #REF! setzen
2167 //2do: make it possible! das bedeutet grossen Umbau von ScAddress etc.!
2168 			const ScBigAddress& rPos = aBigRange.aStart;
2169 			if ( bOldFormula )
2170 			{
2171 				ScToken* t;
2172 				ScTokenArray* pArr = ((ScFormulaCell*)pOldCell)->GetCode();
2173 				pArr->Reset();
2174                 while ( ( t = static_cast<ScToken*>(pArr->GetNextReference()) ) != NULL )
2175 					lcl_InvalidateReference( *t, rPos );
2176 				pArr->Reset();
2177                 while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
2178 					lcl_InvalidateReference( *t, rPos );
2179 			}
2180 			if ( bNewFormula )
2181 			{
2182 				ScToken* t;
2183 				ScTokenArray* pArr = ((ScFormulaCell*)pNewCell)->GetCode();
2184 				pArr->Reset();
2185                 while ( ( t = static_cast<ScToken*>(pArr->GetNextReference()) ) != NULL )
2186 					lcl_InvalidateReference( *t, rPos );
2187 				pArr->Reset();
2188                 while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
2189 					lcl_InvalidateReference( *t, rPos );
2190 			}
2191 		}
2192 	}
2193 }
2194 
2195 
2196 // --- ScChangeActionReject ------------------------------------------------
2197 
2198 ScChangeActionReject::ScChangeActionReject(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
2199                                                 const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String& sComment)
2200 		:
2201         ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment)
2202 {
2203 }
2204 
2205 
2206 // --- ScChangeTrack -------------------------------------------------------
2207 
2208 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeTrackMsgInfo, 16, 16 )
2209 
2210 const SCROW ScChangeTrack::nContentRowsPerSlot = InitContentRowsPerSlot();
2211 const SCSIZE ScChangeTrack::nContentSlots =
2212 	(MAXROWCOUNT) / InitContentRowsPerSlot() + 2;
2213 
2214 // static
2215 SCROW ScChangeTrack::InitContentRowsPerSlot()
2216 {
2217 	const SCSIZE nMaxSlots = 0xffe0 / sizeof( ScChangeActionContent* ) - 2;
2218 	SCROW nRowsPerSlot = (MAXROWCOUNT) / nMaxSlots;
2219     if ( nRowsPerSlot * nMaxSlots < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
2220 		++nRowsPerSlot;
2221 	return nRowsPerSlot;
2222 }
2223 
2224 
2225 ScChangeTrack::ScChangeTrack( ScDocument* pDocP ) :
2226 		pDoc( pDocP )
2227 {
2228 	Init();
2229     SC_MOD()->GetUserOptions().AddListener(this);
2230 
2231 	ppContentSlots = new ScChangeActionContent* [ nContentSlots ];
2232 	memset( ppContentSlots, 0, nContentSlots * sizeof( ScChangeActionContent* ) );
2233 }
2234 
2235 ScChangeTrack::ScChangeTrack( ScDocument* pDocP, const ScStrCollection& aTempUserCollection) :
2236 		aUserCollection(aTempUserCollection),
2237 		pDoc( pDocP )
2238 {
2239 	Init();
2240     SC_MOD()->GetUserOptions().AddListener(this);
2241     ppContentSlots = new ScChangeActionContent* [ nContentSlots ];
2242 	memset( ppContentSlots, 0, nContentSlots * sizeof( ScChangeActionContent* ) );
2243 }
2244 
2245 ScChangeTrack::~ScChangeTrack()
2246 {
2247     SC_MOD()->GetUserOptions().RemoveListener(this);
2248 	DtorClear();
2249 	delete [] ppContentSlots;
2250 }
2251 
2252 
2253 void ScChangeTrack::Init()
2254 {
2255 	pFirst = NULL;
2256 	pLast = NULL;
2257 	pFirstGeneratedDelContent = NULL;
2258 	pLastCutMove = NULL;
2259 	pLinkInsertCol = NULL;
2260 	pLinkInsertRow = NULL;
2261 	pLinkInsertTab = NULL;
2262 	pLinkMove = NULL;
2263 	pBlockModifyMsg = NULL;
2264 	nActionMax = 0;
2265 	nGeneratedMin = SC_CHGTRACK_GENERATED_START;
2266 	nMarkLastSaved = 0;
2267 	nStartLastCut = 0;
2268 	nEndLastCut = 0;
2269 	nLastMerge = 0;
2270 	eMergeState = SC_CTMS_NONE;
2271 	nLoadedFileFormatVersion = SC_CHGTRACK_FILEFORMAT;
2272 	bLoadSave = sal_False;
2273 	bInDelete = sal_False;
2274 	bInDeleteTop = sal_False;
2275 	bInDeleteUndo = sal_False;
2276 	bInPasteCut = sal_False;
2277 	bUseFixDateTime = sal_False;
2278     bTime100thSeconds = sal_True;
2279 
2280     const SvtUserOptions& rUserOpt = SC_MOD()->GetUserOptions();
2281     aUser = rUserOpt.GetFirstName();
2282 	aUser += ' ';
2283     aUser += (String)rUserOpt.GetLastName();
2284 	aUserCollection.Insert( new StrData( aUser ) );
2285 }
2286 
2287 
2288 void ScChangeTrack::DtorClear()
2289 {
2290 	ScChangeAction* p;
2291 	ScChangeAction* pNext;
2292 	for ( p = GetFirst(); p; p = pNext )
2293 	{
2294 		pNext = p->GetNext();
2295 		delete p;
2296 	}
2297 	for ( p = pFirstGeneratedDelContent; p; p = pNext )
2298 	{
2299 		pNext = p->GetNext();
2300 		delete p;
2301 	}
2302 	for ( p = aPasteCutTable.First(); p; p = aPasteCutTable.Next() )
2303 	{
2304 		delete p;
2305 	}
2306 	delete pLastCutMove;
2307 	ClearMsgQueue();
2308 }
2309 
2310 
2311 void ScChangeTrack::ClearMsgQueue()
2312 {
2313 	if ( pBlockModifyMsg )
2314 	{
2315 		delete pBlockModifyMsg;
2316 		pBlockModifyMsg = NULL;
2317 	}
2318 	ScChangeTrackMsgInfo* pMsgInfo;
2319     while ( ( pMsgInfo = aMsgStackTmp.Pop() ) != NULL )
2320 		delete pMsgInfo;
2321     while ( ( pMsgInfo = aMsgStackFinal.Pop() ) != NULL )
2322 		delete pMsgInfo;
2323     while ( ( pMsgInfo = aMsgQueue.Get() ) != NULL )
2324 		delete pMsgInfo;
2325 }
2326 
2327 
2328 void ScChangeTrack::Clear()
2329 {
2330 	DtorClear();
2331 	aTable.Clear();
2332 	aGeneratedTable.Clear();
2333 	aPasteCutTable.Clear();
2334 	aUserCollection.FreeAll();
2335 	aUser.Erase();
2336 	Init();
2337 }
2338 
2339 
2340 void __EXPORT ScChangeTrack::ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 )
2341 {
2342     if ( !pDoc->IsInDtorClear() )
2343 	{
2344         const SvtUserOptions& rUserOptions = SC_MOD()->GetUserOptions();
2345         sal_uInt16 nOldCount = aUserCollection.GetCount();
2346 
2347         String aStr( rUserOptions.GetFirstName() );
2348         aStr += ' ';
2349         aStr += (String)rUserOptions.GetLastName();
2350         SetUser( aStr );
2351 
2352         if ( aUserCollection.GetCount() != nOldCount )
2353         {
2354             //  New user in collection -> have to repaint because
2355             //  colors may be different now (#106697#).
2356             //  (Has to be done in the Notify handler, to be sure
2357             //  the user collection has already been updated)
2358 
2359             SfxObjectShell* pDocSh = pDoc->GetDocumentShell();
2360             if (pDocSh)
2361                 pDocSh->Broadcast( ScPaintHint( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB), PAINT_GRID ) );
2362         }
2363 	}
2364 }
2365 
2366 
2367 void ScChangeTrack::SetUser( const String& rUser )
2368 {
2369 	if ( IsLoadSave() )
2370 		return ;		// nicht die Collection zerschiessen
2371 
2372 	aUser = rUser;
2373 	StrData* pStrData = new StrData( aUser );
2374 	if ( !aUserCollection.Insert( pStrData ) )
2375 		delete pStrData;
2376 }
2377 
2378 
2379 void ScChangeTrack::StartBlockModify( ScChangeTrackMsgType eMsgType,
2380 		sal_uLong nStartAction )
2381 {
2382 	if ( aModifiedLink.IsSet() )
2383 	{
2384 		if ( pBlockModifyMsg )
2385 			aMsgStackTmp.Push( pBlockModifyMsg );	// Block im Block
2386 		pBlockModifyMsg = new ScChangeTrackMsgInfo;
2387 		pBlockModifyMsg->eMsgType = eMsgType;
2388 		pBlockModifyMsg->nStartAction = nStartAction;
2389 	}
2390 }
2391 
2392 
2393 void ScChangeTrack::EndBlockModify( sal_uLong nEndAction )
2394 {
2395 	if ( aModifiedLink.IsSet() )
2396 	{
2397 		if ( pBlockModifyMsg )
2398 		{
2399 			if ( pBlockModifyMsg->nStartAction <= nEndAction )
2400 			{
2401 				pBlockModifyMsg->nEndAction = nEndAction;
2402 				// Blocks in Blocks aufgeloest
2403 				aMsgStackFinal.Push( pBlockModifyMsg );
2404 			}
2405 			else
2406 				delete pBlockModifyMsg;
2407 			pBlockModifyMsg = aMsgStackTmp.Pop();	// evtl. Block im Block
2408 		}
2409 		if ( !pBlockModifyMsg )
2410 		{
2411 			sal_Bool bNew = sal_False;
2412 			ScChangeTrackMsgInfo* pMsg;
2413             while ( ( pMsg = aMsgStackFinal.Pop() ) != NULL )
2414 			{
2415 				aMsgQueue.Put( pMsg );
2416 				bNew = sal_True;
2417 			}
2418 			if ( bNew )
2419 				aModifiedLink.Call( this );
2420 		}
2421 	}
2422 }
2423 
2424 
2425 void ScChangeTrack::NotifyModified( ScChangeTrackMsgType eMsgType,
2426 		sal_uLong nStartAction, sal_uLong nEndAction )
2427 {
2428 	if ( aModifiedLink.IsSet() )
2429 	{
2430 		if ( !pBlockModifyMsg || pBlockModifyMsg->eMsgType != eMsgType ||
2431 				(IsGenerated( nStartAction ) &&
2432 				(eMsgType == SC_CTM_APPEND || eMsgType == SC_CTM_REMOVE)) )
2433 		{	// Append innerhalb von Append z.B. nicht
2434 			StartBlockModify( eMsgType, nStartAction );
2435 			EndBlockModify( nEndAction );
2436 		}
2437 	}
2438 }
2439 
2440 
2441 void ScChangeTrack::MasterLinks( ScChangeAction* pAppend )
2442 {
2443 	ScChangeActionType eType = pAppend->GetType();
2444 
2445 	if ( eType == SC_CAT_CONTENT )
2446 	{
2447 		if ( !IsGenerated( pAppend->GetActionNumber() ) )
2448 		{
2449 			SCSIZE nSlot = ComputeContentSlot(
2450 				pAppend->GetBigRange().aStart.Row() );
2451 			((ScChangeActionContent*)pAppend)->InsertInSlot(
2452 				&ppContentSlots[nSlot] );
2453 		}
2454 		return ;
2455 	}
2456 
2457 	if ( pAppend->IsRejecting() )
2458 		return ;		// Rejects haben keine Abhaengigkeiten
2459 
2460 	switch ( eType )
2461 	{
2462 		case SC_CAT_INSERT_COLS :
2463 		{
2464 			ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
2465 				&pLinkInsertCol, pAppend );
2466 			pAppend->AddLink( NULL, pLink );
2467 		}
2468 		break;
2469 		case SC_CAT_INSERT_ROWS :
2470 		{
2471 			ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
2472 				&pLinkInsertRow, pAppend );
2473 			pAppend->AddLink( NULL, pLink );
2474 		}
2475 		break;
2476 		case SC_CAT_INSERT_TABS :
2477 		{
2478 			ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
2479 				&pLinkInsertTab, pAppend );
2480 			pAppend->AddLink( NULL, pLink );
2481 		}
2482 		break;
2483 		case SC_CAT_MOVE :
2484 		{
2485 			ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry(
2486 				&pLinkMove, pAppend );
2487 			pAppend->AddLink( NULL, pLink );
2488 		}
2489 		break;
2490         default:
2491         {
2492             // added to avoid warnings
2493         }
2494 	}
2495 }
2496 
2497 
2498 void ScChangeTrack::AppendLoaded( ScChangeAction* pAppend )
2499 {
2500 	aTable.Insert( pAppend->GetActionNumber(), pAppend );
2501 	if ( !pLast )
2502 		pFirst = pLast = pAppend;
2503 	else
2504 	{
2505 		pLast->pNext = pAppend;
2506 		pAppend->pPrev = pLast;
2507 		pLast = pAppend;
2508 	}
2509 	MasterLinks( pAppend );
2510 }
2511 
2512 
2513 void ScChangeTrack::Append( ScChangeAction* pAppend, sal_uLong nAction )
2514 {
2515 	if ( nActionMax < nAction )
2516 		nActionMax = nAction;
2517 	pAppend->SetUser( aUser );
2518 	if ( bUseFixDateTime )
2519 		pAppend->SetDateTimeUTC( aFixDateTime );
2520 	pAppend->SetActionNumber( nAction );
2521 	aTable.Insert( nAction, pAppend );
2522 	// UpdateReference Inserts vor Dependencies.
2523 	// Delete rejectendes Insert hatte UpdateReference mit Delete-Undo.
2524 	// UpdateReference auch wenn pLast==NULL, weil pAppend ein Delete sein
2525 	// kann, dass DelContents generiert haben kann
2526 	if ( pAppend->IsInsertType() && !pAppend->IsRejecting() )
2527 		UpdateReference( pAppend, sal_False );
2528 	if ( !pLast )
2529 		pFirst = pLast = pAppend;
2530 	else
2531 	{
2532 		pLast->pNext = pAppend;
2533 		pAppend->pPrev = pLast;
2534 		pLast = pAppend;
2535 		Dependencies( pAppend );
2536 	}
2537 	// UpdateReference Inserts nicht nach Dependencies.
2538 	// Move rejectendes Move hatte UpdateReference mit Move-Undo, Inhalt in
2539 	// ToRange nicht deleten.
2540 	if ( !pAppend->IsInsertType() &&
2541 			!(pAppend->GetType() == SC_CAT_MOVE && pAppend->IsRejecting()) )
2542 		UpdateReference( pAppend, sal_False );
2543 	MasterLinks( pAppend );
2544 
2545 	if ( aModifiedLink.IsSet() )
2546 	{
2547 		NotifyModified( SC_CTM_APPEND, nAction, nAction );
2548 		if ( pAppend->GetType() == SC_CAT_CONTENT )
2549 		{
2550 			ScChangeActionContent* pContent = (ScChangeActionContent*) pAppend;
2551             if ( ( pContent = pContent->GetPrevContent() ) != NULL )
2552 			{
2553 				sal_uLong nMod = pContent->GetActionNumber();
2554 				NotifyModified( SC_CTM_CHANGE, nMod, nMod );
2555 			}
2556 		}
2557 		else
2558 			NotifyModified( SC_CTM_CHANGE, pFirst->GetActionNumber(),
2559 				pLast->GetActionNumber() );
2560 	}
2561 }
2562 
2563 
2564 void ScChangeTrack::Append( ScChangeAction* pAppend )
2565 {
2566 	Append( pAppend, ++nActionMax );
2567 }
2568 
2569 
2570 void ScChangeTrack::AppendDeleteRange( const ScRange& rRange,
2571 		ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction, SCsTAB nDz )
2572 {
2573 	nStartAction = GetActionMax() + 1;
2574 	AppendDeleteRange( rRange, pRefDoc, nDz, 0 );
2575 	nEndAction = GetActionMax();
2576 }
2577 
2578 
2579 void ScChangeTrack::AppendDeleteRange( const ScRange& rRange,
2580 		ScDocument* pRefDoc, SCsTAB nDz, sal_uLong nRejectingInsert )
2581 {
2582 	SetInDeleteRange( rRange );
2583 	StartBlockModify( SC_CTM_APPEND, GetActionMax() + 1 );
2584 	SCCOL nCol1;
2585 	SCROW nRow1;
2586 	SCTAB nTab1;
2587 	SCCOL nCol2;
2588 	SCROW nRow2;
2589 	SCTAB nTab2;
2590 	rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
2591 	for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
2592 	{
2593 		if ( !pRefDoc || nTab < pRefDoc->GetTableCount() )
2594 		{
2595 			if ( nCol1 == 0 && nCol2 == MAXCOL )
2596 			{	// ganze Zeilen und/oder Tabellen
2597 				if ( nRow1 == 0 && nRow2 == MAXROW )
2598 				{	// ganze Tabellen
2599 //2do: geht nicht auch komplette Tabelle als ganzes?
2600 					ScRange aRange( 0, 0, nTab, 0, MAXROW, nTab );
2601 					for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ )
2602 					{	// spaltenweise ist weniger als zeilenweise
2603 						aRange.aStart.SetCol( nCol );
2604 						aRange.aEnd.SetCol( nCol );
2605 						if ( nCol == nCol2 )
2606 							SetInDeleteTop( sal_True );
2607 						AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0,
2608 							nTab-nTab1 + nDz, nRejectingInsert );
2609 					}
2610 					//! immer noch InDeleteTop
2611 					AppendOneDeleteRange( rRange, pRefDoc, 0, 0,
2612 						nTab-nTab1 + nDz, nRejectingInsert );
2613 				}
2614 				else
2615 				{	// ganze Zeilen
2616 					ScRange aRange( 0, 0, nTab, MAXCOL, 0, nTab );
2617 					for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
2618 					{
2619 						aRange.aStart.SetRow( nRow );
2620 						aRange.aEnd.SetRow( nRow );
2621 						if ( nRow == nRow2 )
2622 							SetInDeleteTop( sal_True );
2623 						AppendOneDeleteRange( aRange, pRefDoc, 0, nRow-nRow1,
2624 							0, nRejectingInsert );
2625 					}
2626 				}
2627 			}
2628 			else if ( nRow1 == 0 && nRow2 == MAXROW )
2629 			{	// ganze Spalten
2630 				ScRange aRange( 0, 0, nTab, 0, MAXROW, nTab );
2631 				for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ )
2632 				{
2633 					aRange.aStart.SetCol( nCol );
2634 					aRange.aEnd.SetCol( nCol );
2635 					if ( nCol == nCol2 )
2636 						SetInDeleteTop( sal_True );
2637 					AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0,
2638 						0, nRejectingInsert );
2639 				}
2640 			}
2641 			else
2642 			{
2643 				DBG_ERROR( "ScChangeTrack::AppendDeleteRange: Block not supported!" );
2644 			}
2645 			SetInDeleteTop( sal_False );
2646 		}
2647 	}
2648 	EndBlockModify( GetActionMax() );
2649 }
2650 
2651 
2652 void ScChangeTrack::AppendOneDeleteRange( const ScRange& rOrgRange,
2653 		ScDocument* pRefDoc, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
2654 		sal_uLong nRejectingInsert )
2655 {
2656 	ScRange aTrackRange( rOrgRange );
2657 	if ( nDx )
2658 	{
2659 		aTrackRange.aStart.IncCol( -nDx );
2660 		aTrackRange.aEnd.IncCol( -nDx );
2661 	}
2662 	if ( nDy )
2663 	{
2664 		aTrackRange.aStart.IncRow( -nDy );
2665 		aTrackRange.aEnd.IncRow( -nDy );
2666 	}
2667 	if ( nDz )
2668 	{
2669 		aTrackRange.aStart.IncTab( -nDz );
2670 		aTrackRange.aEnd.IncTab( -nDz );
2671 	}
2672 	ScChangeActionDel* pAct = new ScChangeActionDel( aTrackRange, nDx, nDy,
2673 		this );
2674 	// TabDelete keine Contents, sind in einzelnen Spalten
2675 	if ( !(rOrgRange.aStart.Col() == 0 && rOrgRange.aStart.Row() == 0 &&
2676 			rOrgRange.aEnd.Col() == MAXCOL && rOrgRange.aEnd.Row() == MAXROW) )
2677 		LookUpContents( rOrgRange, pRefDoc, -nDx, -nDy, -nDz );
2678 	if ( nRejectingInsert )
2679 	{
2680 		pAct->SetRejectAction( nRejectingInsert );
2681 		pAct->SetState( SC_CAS_ACCEPTED );
2682 	}
2683 	Append( pAct );
2684 }
2685 
2686 
2687 void ScChangeTrack::LookUpContents( const ScRange& rOrgRange,
2688 		ScDocument* pRefDoc, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
2689 {
2690 	if ( pRefDoc )
2691 	{
2692 		ScAddress aPos;
2693 		ScBigAddress aBigPos;
2694 		ScCellIterator aIter( pRefDoc, rOrgRange );
2695 		ScBaseCell* pCell = aIter.GetFirst();
2696 		while ( pCell )
2697 		{
2698 			if ( ScChangeActionContent::GetContentCellType( pCell ) )
2699 			{
2700 				aBigPos.Set( aIter.GetCol() + nDx, aIter.GetRow() + nDy,
2701 					aIter.GetTab() + nDz );
2702 				ScChangeActionContent* pContent = SearchContentAt( aBigPos, NULL );
2703 				if ( !pContent )
2704 				{	// nicht getrackte Contents
2705 					aPos.Set( aIter.GetCol() + nDx, aIter.GetRow() + nDy,
2706 						aIter.GetTab() + nDz );
2707 					GenerateDelContent( aPos, pCell, pRefDoc );
2708 					//! der Content wird hier _nicht_ per AddContent hinzugefuegt,
2709 					//! sondern in UpdateReference, um z.B. auch kreuzende Deletes
2710 					//! korrekt zu erfassen
2711 				}
2712 			}
2713 			pCell = aIter.GetNext();
2714 		}
2715 	}
2716 }
2717 
2718 
2719 void ScChangeTrack::AppendMove( const ScRange& rFromRange,
2720 		const ScRange& rToRange, ScDocument* pRefDoc )
2721 {
2722 	ScChangeActionMove* pAct = new ScChangeActionMove( rFromRange, rToRange, this );
2723 	LookUpContents( rToRange, pRefDoc, 0, 0, 0 );	// ueberschriebene Contents
2724 	Append( pAct );
2725 }
2726 
2727 
2728 // static
2729 sal_Bool ScChangeTrack::IsMatrixFormulaRangeDifferent( const ScBaseCell* pOldCell,
2730 		const ScBaseCell* pNewCell )
2731 {
2732 	SCCOL nC1, nC2;
2733 	SCROW nR1, nR2;
2734 	nC1 = nC2 = 0;
2735     nR1 = nR2 = 0;
2736 	if ( pOldCell && (pOldCell->GetCellType() == CELLTYPE_FORMULA) &&
2737 			((const ScFormulaCell*)pOldCell)->GetMatrixFlag() == MM_FORMULA )
2738 		((const ScFormulaCell*)pOldCell)->GetMatColsRows( nC1, nR1 );
2739 	if ( pNewCell && (pNewCell->GetCellType() == CELLTYPE_FORMULA) &&
2740 			((const ScFormulaCell*)pNewCell)->GetMatrixFlag() == MM_FORMULA )
2741 		((const ScFormulaCell*)pNewCell)->GetMatColsRows( nC1, nR1 );
2742 	return nC1 != nC2 || nR1 != nR2;
2743 }
2744 
2745 
2746 void ScChangeTrack::AppendContent( const ScAddress& rPos,
2747 		const String& rNewValue, ScBaseCell* pOldCell )
2748 {
2749 	String aOldValue;
2750 	ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pDoc, rPos );
2751 	if ( aOldValue != rNewValue ||
2752 			IsMatrixFormulaRangeDifferent( pOldCell, NULL ) )
2753 	{	// nur wirkliche Aenderung tracken
2754 		ScRange aRange( rPos );
2755 		ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
2756 		pAct->SetOldValue( pOldCell, pDoc, pDoc );
2757 		pAct->SetNewValue( rNewValue, pDoc );
2758 		Append( pAct );
2759 	}
2760 }
2761 
2762 
2763 void ScChangeTrack::AppendContent( const ScAddress& rPos,
2764 		const ScBaseCell* pOldCell, sal_uLong nOldFormat, ScDocument* pRefDoc )
2765 {
2766 	if ( !pRefDoc )
2767 		pRefDoc = pDoc;
2768 	String aOldValue;
2769 	ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pRefDoc, nOldFormat );
2770 	String aNewValue;
2771 	ScBaseCell* pNewCell = pDoc->GetCell( rPos );
2772 	ScChangeActionContent::GetStringOfCell( aNewValue, pNewCell, pDoc, rPos );
2773 	if ( aOldValue != aNewValue ||
2774 			IsMatrixFormulaRangeDifferent( pOldCell, pNewCell ) )
2775 	{	// nur wirkliche Aenderung tracken
2776 		ScRange aRange( rPos );
2777 		ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
2778 		pAct->SetOldValue( pOldCell, pRefDoc, pDoc, nOldFormat );
2779 		pAct->SetNewValue( pNewCell, pDoc );
2780 		Append( pAct );
2781 	}
2782 }
2783 
2784 
2785 void ScChangeTrack::AppendContent( const ScAddress& rPos,
2786 		ScDocument* pRefDoc )
2787 {
2788 	String aOldValue;
2789 	ScBaseCell* pOldCell = pRefDoc->GetCell( rPos );
2790 	ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pRefDoc, rPos );
2791 	String aNewValue;
2792 	ScBaseCell* pNewCell = pDoc->GetCell( rPos );
2793 	ScChangeActionContent::GetStringOfCell( aNewValue, pNewCell, pDoc, rPos );
2794 	if ( aOldValue != aNewValue ||
2795 			IsMatrixFormulaRangeDifferent( pOldCell, pNewCell ) )
2796 	{	// nur wirkliche Aenderung tracken
2797 		ScRange aRange( rPos );
2798 		ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
2799 		pAct->SetOldValue( pOldCell, pRefDoc, pDoc );
2800 		pAct->SetNewValue( pNewCell, pDoc );
2801 		Append( pAct );
2802 	}
2803 }
2804 
2805 
2806 void ScChangeTrack::AppendContent( const ScAddress& rPos,
2807 		const ScBaseCell* pOldCell )
2808 {
2809 	if ( ScChangeActionContent::NeedsNumberFormat( pOldCell ) )
2810 		AppendContent( rPos, pOldCell, pDoc->GetNumberFormat( rPos ), pDoc );
2811 	else
2812 		AppendContent( rPos, pOldCell, 0, pDoc );
2813 }
2814 
2815 
2816 void ScChangeTrack::SetLastCutMoveRange( const ScRange& rRange,
2817 		ScDocument* pRefDoc )
2818 {
2819 	if ( pLastCutMove )
2820 	{
2821 		// ToRange nicht mit Deletes linken und nicht in der Groesse aendern,
2822 		// eigentlich unnoetig, da ein Delete vorher in
2823 		// ScViewFunc::PasteFromClip ein ResetLastCut ausloest
2824 		ScBigRange& r = pLastCutMove->GetBigRange();
2825 		r.aEnd.SetCol( -1 );
2826 		r.aEnd.SetRow( -1 );
2827 		r.aEnd.SetTab( -1 );
2828 		r.aStart.SetCol( -1 - (rRange.aEnd.Col() - rRange.aStart.Col()) );
2829 		r.aStart.SetRow( -1 - (rRange.aEnd.Row() - rRange.aStart.Row()) );
2830 		r.aStart.SetTab( -1 - (rRange.aEnd.Tab() - rRange.aStart.Tab()) );
2831 		// zu ueberschreibende Contents im FromRange
2832 		LookUpContents( rRange, pRefDoc, 0, 0, 0 );
2833 	}
2834 }
2835 
2836 
2837 void ScChangeTrack::AppendContentRange( const ScRange& rRange,
2838 		ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction,
2839 		ScChangeActionClipMode eClipMode )
2840 {
2841 	if ( eClipMode == SC_CACM_CUT )
2842 	{
2843 		ResetLastCut();
2844 		pLastCutMove = new ScChangeActionMove( rRange, rRange, this );
2845 		SetLastCutMoveRange( rRange, pRefDoc );
2846 	}
2847 	SCCOL nCol1;
2848 	SCROW nRow1;
2849 	SCTAB nTab1;
2850 	SCCOL nCol2;
2851 	SCROW nRow2;
2852 	SCTAB nTab2;
2853 	rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
2854 	sal_Bool bDoContents;
2855 	if ( eClipMode == SC_CACM_PASTE && HasLastCut() )
2856 	{
2857 		bDoContents = sal_False;
2858 		SetInPasteCut( sal_True );
2859 		// Paste und Cut abstimmen, Paste kann groesserer Range sein
2860 		ScRange aRange( rRange );
2861 		ScBigRange& r = pLastCutMove->GetBigRange();
2862         SCCOL nTmpCol;
2863 		if ( (nTmpCol = (SCCOL) (r.aEnd.Col() - r.aStart.Col())) != (nCol2 - nCol1) )
2864 		{
2865 			aRange.aEnd.SetCol( aRange.aStart.Col() + nTmpCol );
2866 			nCol1 += nTmpCol + 1;
2867 			bDoContents = sal_True;
2868 		}
2869         SCROW nTmpRow;
2870 		if ( (nTmpRow = (SCROW) (r.aEnd.Row() - r.aStart.Row())) != (nRow2 - nRow1) )
2871 		{
2872 			aRange.aEnd.SetRow( aRange.aStart.Row() + nTmpRow );
2873 			nRow1 += nTmpRow + 1;
2874 			bDoContents = sal_True;
2875 		}
2876         SCTAB nTmpTab;
2877 		if ( (nTmpTab = (SCTAB) (r.aEnd.Tab() - r.aStart.Tab())) != (nTab2 - nTab1) )
2878 		{
2879 			aRange.aEnd.SetTab( aRange.aStart.Tab() + nTmpTab );
2880 			nTab1 += nTmpTab + 1;
2881 			bDoContents = sal_True;
2882 		}
2883 		r = aRange;
2884 		Undo( nStartLastCut, nEndLastCut );	// hier werden sich die Cuts gemerkt
2885 		//! StartAction erst nach Undo
2886 		nStartAction = GetActionMax() + 1;
2887 		StartBlockModify( SC_CTM_APPEND, nStartAction );
2888 		// zu ueberschreibende Contents im ToRange
2889 		LookUpContents( aRange, pRefDoc, 0, 0, 0 );
2890 		pLastCutMove->SetStartLastCut( nStartLastCut );
2891 		pLastCutMove->SetEndLastCut( nEndLastCut );
2892 		Append( pLastCutMove );
2893 		pLastCutMove = NULL;
2894 		ResetLastCut();
2895 		SetInPasteCut( sal_False );
2896 	}
2897 	else
2898 	{
2899 		bDoContents = sal_True;
2900 		nStartAction = GetActionMax() + 1;
2901 		StartBlockModify( SC_CTM_APPEND, nStartAction );
2902 	}
2903 	if ( bDoContents )
2904 	{
2905 		ScAddress aPos;
2906 		for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
2907 		{
2908 			aPos.SetTab( nTab );
2909 			for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ )
2910 			{
2911 				aPos.SetCol( nCol );
2912 				for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
2913 				{
2914 					aPos.SetRow( nRow );
2915 					AppendContent( aPos, pRefDoc );
2916 				}
2917 			}
2918 		}
2919 	}
2920 	nEndAction = GetActionMax();
2921 	EndBlockModify( nEndAction );
2922 	if ( eClipMode == SC_CACM_CUT )
2923 	{
2924 		nStartLastCut = nStartAction;
2925 		nEndLastCut = nEndAction;
2926 	}
2927 }
2928 
2929 
2930 void ScChangeTrack::AppendContentsIfInRefDoc( ScDocument* pRefDoc,
2931 			sal_uLong& nStartAction, sal_uLong& nEndAction )
2932 {
2933 	ScDocumentIterator aIter( pRefDoc, 0, MAXTAB );
2934 	if ( aIter.GetFirst() )
2935 	{
2936 		nStartAction = GetActionMax() + 1;
2937 		StartBlockModify( SC_CTM_APPEND, nStartAction );
2938 		SvNumberFormatter* pFormatter = pRefDoc->GetFormatTable();
2939 		do
2940 		{
2941             SCCOL nCol;
2942             SCROW nRow;
2943             SCTAB nTab;
2944 			aIter.GetPos( nCol, nRow, nTab );
2945 			ScAddress aPos( nCol, nRow, nTab );
2946 			AppendContent( aPos, aIter.GetCell(),
2947 				aIter.GetPattern()->GetNumberFormat( pFormatter ), pRefDoc );
2948 		} while ( aIter.GetNext() );
2949 		nEndAction = GetActionMax();
2950 		EndBlockModify( nEndAction );
2951 	}
2952 	else
2953 		nStartAction = nEndAction = 0;
2954 }
2955 
2956 
2957 ScChangeActionContent* ScChangeTrack::AppendContentOnTheFly(
2958 		const ScAddress& rPos, ScBaseCell* pOldCell, ScBaseCell* pNewCell,
2959 		sal_uLong nOldFormat, sal_uLong nNewFormat )
2960 {
2961 	ScRange aRange( rPos );
2962 	ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
2963 	pAct->SetOldNewCells( pOldCell, nOldFormat, pNewCell, nNewFormat, pDoc );
2964 	Append( pAct );
2965 	return pAct;
2966 }
2967 
2968 
2969 void ScChangeTrack::AppendInsert( const ScRange& rRange )
2970 {
2971 	ScChangeActionIns* pAct = new ScChangeActionIns( rRange );
2972 	Append( pAct );
2973 }
2974 
2975 
2976 void ScChangeTrack::DeleteCellEntries( ScChangeActionCellListEntry*& pCellList,
2977 		ScChangeAction* pDeletor )
2978 {
2979 	ScChangeActionCellListEntry* pE = pCellList;
2980 	while ( pE )
2981 	{
2982 		ScChangeActionCellListEntry* pNext = pE->pNext;
2983 		pE->pContent->RemoveDeletedIn( pDeletor );
2984 		if ( IsGenerated( pE->pContent->GetActionNumber() ) &&
2985 				!pE->pContent->IsDeletedIn() )
2986 			DeleteGeneratedDelContent( pE->pContent );
2987 		delete pE;
2988 		pE = pNext;
2989 	}
2990 	pCellList = NULL;
2991 }
2992 
2993 
2994 ScChangeActionContent* ScChangeTrack::GenerateDelContent(
2995 		const ScAddress& rPos, const ScBaseCell* pCell,
2996 		const ScDocument* pFromDoc )
2997 {
2998 	ScChangeActionContent* pContent = new ScChangeActionContent(
2999 		ScRange( rPos ) );
3000 	pContent->SetActionNumber( --nGeneratedMin );
3001 	// nur NewValue
3002 	ScChangeActionContent::SetValue( pContent->aNewValue, pContent->pNewCell,
3003 		rPos, pCell, pFromDoc, pDoc );
3004 	// pNextContent und pPrevContent werden nicht gesetzt
3005 	if ( pFirstGeneratedDelContent )
3006 	{	// vorne reinhaengen
3007 		pFirstGeneratedDelContent->pPrev = pContent;
3008 		pContent->pNext = pFirstGeneratedDelContent;
3009 	}
3010 	pFirstGeneratedDelContent = pContent;
3011 	aGeneratedTable.Insert( nGeneratedMin, pContent );
3012 	NotifyModified( SC_CTM_APPEND, nGeneratedMin, nGeneratedMin );
3013 	return pContent;
3014 }
3015 
3016 
3017 void ScChangeTrack::DeleteGeneratedDelContent( ScChangeActionContent* pContent )
3018 {
3019 	sal_uLong nAct = pContent->GetActionNumber();
3020 	aGeneratedTable.Remove( nAct );
3021 	if ( pFirstGeneratedDelContent == pContent )
3022 		pFirstGeneratedDelContent = (ScChangeActionContent*) pContent->pNext;
3023 	if ( pContent->pNext )
3024 		pContent->pNext->pPrev = pContent->pPrev;
3025 	if ( pContent->pPrev )
3026 		pContent->pPrev->pNext = pContent->pNext;
3027 	delete pContent;
3028 	NotifyModified( SC_CTM_REMOVE, nAct, nAct );
3029 	if ( nAct == nGeneratedMin )
3030 		++nGeneratedMin;		//! erst nach NotifyModified wg. IsGenerated
3031 }
3032 
3033 
3034 ScChangeActionContent* ScChangeTrack::SearchContentAt(
3035 		const ScBigAddress& rPos, ScChangeAction* pButNotThis ) const
3036 {
3037 	SCSIZE nSlot = ComputeContentSlot( rPos.Row() );
3038 	for ( ScChangeActionContent* p = ppContentSlots[nSlot]; p;
3039 			p = p->GetNextInSlot() )
3040 	{
3041 		if ( p != pButNotThis && !p->IsDeletedIn() &&
3042 				p->GetBigRange().aStart == rPos )
3043 		{
3044 			ScChangeActionContent* pContent = p->GetTopContent();
3045 			if ( !pContent->IsDeletedIn() )
3046 				return pContent;
3047 		}
3048 	}
3049 	return NULL;
3050 }
3051 
3052 
3053 void ScChangeTrack::AddDependentWithNotify( ScChangeAction* pParent,
3054 		ScChangeAction* pDependent )
3055 {
3056 	ScChangeActionLinkEntry* pLink = pParent->AddDependent( pDependent );
3057 	pDependent->AddLink( pParent, pLink );
3058 	if ( aModifiedLink.IsSet() )
3059 	{
3060 		sal_uLong nMod = pParent->GetActionNumber();
3061 		NotifyModified( SC_CTM_PARENT, nMod, nMod );
3062 	}
3063 }
3064 
3065 
3066 void ScChangeTrack::Dependencies( ScChangeAction* pAct )
3067 {
3068 	// Finde die letzte Abhaengigkeit fuer jeweils Col/Row/Tab.
3069 	// Content an gleicher Position verketten.
3070 	// Move Abhaengigkeiten.
3071 	ScChangeActionType eActType = pAct->GetType();
3072 	if ( eActType == SC_CAT_REJECT ||
3073 			(eActType == SC_CAT_MOVE && pAct->IsRejecting()) )
3074 		return ;		// diese Rejects sind nicht abhaengig
3075 
3076 	if ( eActType == SC_CAT_CONTENT )
3077 	{
3078 		if ( !(((ScChangeActionContent*)pAct)->GetNextContent() ||
3079 			((ScChangeActionContent*)pAct)->GetPrevContent()) )
3080 		{	// Contents an gleicher Position verketten
3081 			ScChangeActionContent* pContent = SearchContentAt(
3082 				pAct->GetBigRange().aStart, pAct );
3083 			if ( pContent )
3084 			{
3085 				pContent->SetNextContent( (ScChangeActionContent*) pAct );
3086 				((ScChangeActionContent*)pAct)->SetPrevContent( pContent );
3087 			}
3088 		}
3089 		const ScBaseCell* pCell = ((ScChangeActionContent*)pAct)->GetNewCell();
3090 		if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATREF )
3091 		{
3092 			ScAddress aOrg;
3093 			((const ScFormulaCell*)pCell)->GetMatrixOrigin( aOrg );
3094 			ScChangeActionContent* pContent = SearchContentAt( aOrg, pAct );
3095 			if ( pContent && pContent->IsMatrixOrigin() )
3096 			{
3097 				AddDependentWithNotify( pContent, pAct );
3098 			}
3099 			else
3100 			{
3101 				DBG_ERRORFILE( "ScChangeTrack::Dependencies: MatOrg not found" );
3102 			}
3103 		}
3104 	}
3105 
3106 	if ( !(pLinkInsertCol || pLinkInsertRow || pLinkInsertTab || pLinkMove) )
3107 		return ;		// keine Dependencies
3108 	if ( pAct->IsRejecting() )
3109 		return ;		// ausser Content keine Dependencies
3110 
3111 	// Insert in einem entsprechenden Insert haengt davon ab, sonst muesste
3112 	// der vorherige Insert gesplittet werden.
3113 	// Sich kreuzende Inserts und Deletes sind nicht abhaengig.
3114 	// Alles andere ist abhaengig.
3115 
3116 	// Der zuletzt eingelinkte Insert steht am Anfang einer Kette,
3117 	// also genau richtig
3118 
3119 	const ScBigRange& rRange = pAct->GetBigRange();
3120 	sal_Bool bActNoInsert = !pAct->IsInsertType();
3121 	sal_Bool bActColDel = ( eActType == SC_CAT_DELETE_COLS );
3122 	sal_Bool bActRowDel = ( eActType == SC_CAT_DELETE_ROWS );
3123 	sal_Bool bActTabDel = ( eActType == SC_CAT_DELETE_TABS );
3124 
3125 	if ( pLinkInsertCol && (eActType == SC_CAT_INSERT_COLS ||
3126 			(bActNoInsert && !bActRowDel && !bActTabDel)) )
3127 	{
3128 		for ( ScChangeActionLinkEntry* pL = pLinkInsertCol; pL; pL = pL->GetNext() )
3129 		{
3130 			ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction();
3131 			if ( !pTest->IsRejected() &&
3132 					pTest->GetBigRange().Intersects( rRange ) )
3133 			{
3134 				AddDependentWithNotify( pTest, pAct );
3135 				break;	// for
3136 			}
3137 		}
3138 	}
3139 	if ( pLinkInsertRow && (eActType == SC_CAT_INSERT_ROWS ||
3140 			(bActNoInsert && !bActColDel && !bActTabDel)) )
3141 	{
3142 		for ( ScChangeActionLinkEntry* pL = pLinkInsertRow; pL; pL = pL->GetNext() )
3143 		{
3144 			ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction();
3145 			if ( !pTest->IsRejected() &&
3146 					pTest->GetBigRange().Intersects( rRange ) )
3147 			{
3148 				AddDependentWithNotify( pTest, pAct );
3149 				break;	// for
3150 			}
3151 		}
3152 	}
3153 	if ( pLinkInsertTab && (eActType == SC_CAT_INSERT_TABS ||
3154 			(bActNoInsert && !bActColDel &&  !bActRowDel)) )
3155 	{
3156 		for ( ScChangeActionLinkEntry* pL = pLinkInsertTab; pL; pL = pL->GetNext() )
3157 		{
3158 			ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction();
3159 			if ( !pTest->IsRejected() &&
3160 					pTest->GetBigRange().Intersects( rRange ) )
3161 			{
3162 				AddDependentWithNotify( pTest, pAct );
3163 				break;	// for
3164 			}
3165 		}
3166 	}
3167 
3168 	if ( pLinkMove )
3169 	{
3170 		if ( eActType == SC_CAT_CONTENT )
3171 		{	// Content ist von FromRange abhaengig
3172 			const ScBigAddress& rPos = rRange.aStart;
3173 			for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
3174 			{
3175 				ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction();
3176 				if ( !pTest->IsRejected() &&
3177 						pTest->GetFromRange().In( rPos ) )
3178 				{
3179 					AddDependentWithNotify( pTest, pAct );
3180 				}
3181 			}
3182 		}
3183 		else if ( eActType == SC_CAT_MOVE )
3184 		{	// Move FromRange ist von ToRange abhaengig
3185 			const ScBigRange& rFromRange = ((ScChangeActionMove*)pAct)->GetFromRange();
3186 			for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
3187 			{
3188 				ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction();
3189 				if ( !pTest->IsRejected() &&
3190 						pTest->GetBigRange().Intersects( rFromRange ) )
3191 				{
3192 					AddDependentWithNotify( pTest, pAct );
3193 				}
3194 			}
3195 		}
3196 		else
3197 		{	// Inserts und Deletes sind abhaengig, sobald sie FromRange oder
3198 			// ToRange kreuzen
3199 			for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
3200 			{
3201 				ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction();
3202 				if ( !pTest->IsRejected() &&
3203 						(pTest->GetFromRange().Intersects( rRange ) ||
3204 						pTest->GetBigRange().Intersects( rRange )) )
3205 				{
3206 					AddDependentWithNotify( pTest, pAct );
3207 				}
3208 			}
3209 		}
3210 	}
3211 }
3212 
3213 
3214 void ScChangeTrack::Remove( ScChangeAction* pRemove )
3215 {
3216 	// aus Track ausklinken
3217 	sal_uLong nAct = pRemove->GetActionNumber();
3218 	aTable.Remove( nAct );
3219 	if ( nAct == nActionMax )
3220 		--nActionMax;
3221 	if ( pRemove == pLast )
3222 		pLast = pRemove->pPrev;
3223 	if ( pRemove == pFirst )
3224 		pFirst = pRemove->pNext;
3225 	if ( nAct == nMarkLastSaved )
3226 		nMarkLastSaved =
3227 			( pRemove->pPrev ? pRemove->pPrev->GetActionNumber() : 0 );
3228 
3229 	// aus der globalen Kette ausklinken
3230 	if ( pRemove->pNext )
3231 		pRemove->pNext->pPrev = pRemove->pPrev;
3232 	if ( pRemove->pPrev )
3233 		pRemove->pPrev->pNext = pRemove->pNext;
3234 
3235 	// Dependencies nicht loeschen, passiert on delete automatisch durch
3236 	// LinkEntry, ohne Listen abzuklappern
3237 
3238 	if ( aModifiedLink.IsSet() )
3239 	{
3240 		NotifyModified( SC_CTM_REMOVE, nAct, nAct );
3241 		if ( pRemove->GetType() == SC_CAT_CONTENT )
3242 		{
3243 			ScChangeActionContent* pContent = (ScChangeActionContent*) pRemove;
3244             if ( ( pContent = pContent->GetPrevContent() ) != NULL )
3245 			{
3246 				sal_uLong nMod = pContent->GetActionNumber();
3247 				NotifyModified( SC_CTM_CHANGE, nMod, nMod );
3248 			}
3249 		}
3250 		else if ( pLast )
3251 			NotifyModified( SC_CTM_CHANGE, pFirst->GetActionNumber(),
3252 				pLast->GetActionNumber() );
3253 	}
3254 
3255 	if ( IsInPasteCut() && pRemove->GetType() == SC_CAT_CONTENT )
3256 	{	//! Content wird wiederverwertet
3257 		ScChangeActionContent* pContent = (ScChangeActionContent*) pRemove;
3258 		pContent->RemoveAllLinks();
3259 		pContent->ClearTrack();
3260 		pContent->pNext = pContent->pPrev = NULL;
3261 		pContent->pNextContent = pContent->pPrevContent = NULL;
3262 	}
3263 }
3264 
3265 
3266 void ScChangeTrack::Undo( sal_uLong nStartAction, sal_uLong nEndAction, bool bMerge )
3267 {
3268     // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3269     if ( bMerge )
3270     {
3271         SetMergeState( SC_CTMS_UNDO );
3272     }
3273 
3274 	if ( nStartAction == 0 )
3275 		++nStartAction;
3276 	if ( nEndAction > nActionMax )
3277 		nEndAction = nActionMax;
3278 	if ( nEndAction && nStartAction <= nEndAction )
3279 	{
3280 		if ( nStartAction == nStartLastCut && nEndAction == nEndLastCut &&
3281 				!IsInPasteCut() )
3282 			ResetLastCut();
3283 		StartBlockModify( SC_CTM_REMOVE, nStartAction );
3284 		for ( sal_uLong j = nEndAction; j >= nStartAction; --j )
3285 		{	// rueckwaerts um evtl. nActionMax zu recyclen und schnelleren
3286 			// Zugriff via pLast, Deletes in richtiger Reihenfolge
3287 			ScChangeAction* pAct = ( (j == nActionMax && pLast &&
3288 				pLast->GetActionNumber() == j) ? pLast : GetAction( j ) );
3289 			if ( pAct )
3290 			{
3291 				if ( pAct->IsDeleteType() )
3292 				{
3293 					if ( j == nEndAction || (pAct != pLast &&
3294 							((ScChangeActionDel*)pAct)->IsTopDelete()) )
3295 					{
3296 						SetInDeleteTop( sal_True );
3297 						SetInDeleteRange( ((ScChangeActionDel*)pAct)->
3298 							GetOverAllRange().MakeRange() );
3299 					}
3300 				}
3301 				UpdateReference( pAct, sal_True );
3302 				SetInDeleteTop( sal_False );
3303 				Remove( pAct );
3304 				if ( IsInPasteCut() )
3305 					aPasteCutTable.Insert( pAct->GetActionNumber(), pAct );
3306 				else
3307 				{
3308 					if ( j == nStartAction && pAct->GetType() == SC_CAT_MOVE )
3309 					{
3310 						ScChangeActionMove* pMove = (ScChangeActionMove*) pAct;
3311 						sal_uLong nStart = pMove->GetStartLastCut();
3312 						sal_uLong nEnd = pMove->GetEndLastCut();
3313 						if ( nStart && nStart <= nEnd )
3314 						{	// LastCut wiederherstellen
3315 							//! Links vor Cut-Append aufloesen
3316 							pMove->RemoveAllLinks();
3317 							StartBlockModify( SC_CTM_APPEND, nStart );
3318 							for ( sal_uLong nCut = nStart; nCut <= nEnd; nCut++ )
3319 							{
3320 								ScChangeAction* pCut = aPasteCutTable.Remove( nCut );
3321 								if ( pCut )
3322 								{
3323 									DBG_ASSERT( !aTable.Get( nCut ), "ScChangeTrack::Undo: nCut dup" );
3324 									Append( pCut, nCut );
3325 								}
3326 								else
3327 								{
3328 									DBG_ERROR( "ScChangeTrack::Undo: nCut not found" );
3329 								}
3330 							}
3331 							EndBlockModify( nEnd );
3332 							ResetLastCut();
3333 							nStartLastCut = nStart;
3334 							nEndLastCut = nEnd;
3335 							pLastCutMove = pMove;
3336 							SetLastCutMoveRange(
3337 								pMove->GetFromRange().MakeRange(), pDoc );
3338 						}
3339 						else
3340 							delete pMove;
3341 					}
3342 					else
3343 						delete pAct;
3344 				}
3345 			}
3346 		}
3347 		EndBlockModify( nEndAction );
3348 	}
3349 
3350     // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3351     if ( bMerge )
3352     {
3353         SetMergeState( SC_CTMS_OTHER );
3354     }
3355 }
3356 
3357 
3358 // static
3359 sal_Bool ScChangeTrack::MergeIgnore( const ScChangeAction& rAction, sal_uLong nFirstMerge )
3360 {
3361 	if ( rAction.IsRejected() )
3362 		return sal_True;				// da kommt noch eine passende Reject-Action
3363 
3364 	if ( rAction.IsRejecting() && rAction.GetRejectAction() >= nFirstMerge )
3365 		return sal_True;				// da ist sie
3366 
3367 	return sal_False;					// alles andere
3368 }
3369 
3370 
3371 void ScChangeTrack::MergePrepare( ScChangeAction* pFirstMerge, bool bShared )
3372 {
3373 	SetMergeState( SC_CTMS_PREPARE );
3374 	sal_uLong nFirstMerge = pFirstMerge->GetActionNumber();
3375 	ScChangeAction* pAct = GetLast();
3376 	if ( pAct )
3377 	{
3378 		SetLastMerge( pAct->GetActionNumber() );
3379 		while ( pAct )
3380 		{	// rueckwaerts, Deletes in richtiger Reihenfolge
3381             // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3382             if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) )
3383 			{
3384 				if ( pAct->IsDeleteType() )
3385 				{
3386 					if ( ((ScChangeActionDel*)pAct)->IsTopDelete() )
3387 					{
3388 						SetInDeleteTop( sal_True );
3389 						SetInDeleteRange( ((ScChangeActionDel*)pAct)->
3390 							GetOverAllRange().MakeRange() );
3391 					}
3392 				}
3393 				UpdateReference( pAct, sal_True );
3394 				SetInDeleteTop( sal_False );
3395 				pAct->DeleteCellEntries();		// sonst GPF bei Track Clear()
3396 			}
3397 			pAct = ( pAct == pFirstMerge ? NULL : pAct->GetPrev() );
3398 		}
3399 	}
3400 	SetMergeState( SC_CTMS_OTHER );		//! nachfolgende per default MergeOther
3401 }
3402 
3403 
3404 void ScChangeTrack::MergeOwn( ScChangeAction* pAct, sal_uLong nFirstMerge, bool bShared )
3405 {
3406     // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3407     if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) )
3408 	{
3409 		SetMergeState( SC_CTMS_OWN );
3410 		if ( pAct->IsDeleteType() )
3411 		{
3412 			if ( ((ScChangeActionDel*)pAct)->IsTopDelete() )
3413 			{
3414 				SetInDeleteTop( sal_True );
3415 				SetInDeleteRange( ((ScChangeActionDel*)pAct)->
3416 					GetOverAllRange().MakeRange() );
3417 			}
3418 		}
3419 		UpdateReference( pAct, sal_False );
3420 		SetInDeleteTop( sal_False );
3421 		SetMergeState( SC_CTMS_OTHER );		//! nachfolgende per default MergeOther
3422 	}
3423 }
3424 
3425 
3426 void ScChangeTrack::UpdateReference( ScChangeAction* pAct, sal_Bool bUndo )
3427 {
3428 	ScChangeActionType eActType = pAct->GetType();
3429 	if ( eActType == SC_CAT_CONTENT || eActType == SC_CAT_REJECT )
3430 		return ;
3431 
3432 	//! Formelzellen haengen nicht im Dokument
3433 	sal_Bool bOldAutoCalc = pDoc->GetAutoCalc();
3434 	pDoc->SetAutoCalc( sal_False );
3435 	sal_Bool bOldNoListening = pDoc->GetNoListening();
3436 	pDoc->SetNoListening( sal_True );
3437 	//! Formelzellen ExpandRefs synchronisiert zu denen im Dokument
3438 	sal_Bool bOldExpandRefs = pDoc->IsExpandRefs();
3439 	if ( (!bUndo && pAct->IsInsertType()) || (bUndo && pAct->IsDeleteType()) )
3440 		pDoc->SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
3441 
3442 	if ( pAct->IsDeleteType() )
3443 	{
3444 		SetInDeleteUndo( bUndo );
3445 		SetInDelete( sal_True );
3446 	}
3447 	else if ( GetMergeState() == SC_CTMS_OWN )
3448 	{
3449 		// Referenzen von Formelzellen wiederherstellen,
3450 		// vorheriges MergePrepare war bei einem Insert wie ein Delete
3451 		if ( pAct->IsInsertType() )
3452 			SetInDeleteUndo( sal_True );
3453 	}
3454 
3455 	//! erst die generated, als waeren sie vorher getrackt worden
3456 	if ( pFirstGeneratedDelContent )
3457 		UpdateReference( (ScChangeAction**)&pFirstGeneratedDelContent, pAct,
3458 			bUndo );
3459 	UpdateReference( &pFirst, pAct, bUndo );
3460 
3461 	SetInDelete( sal_False );
3462 	SetInDeleteUndo( sal_False );
3463 
3464 	pDoc->SetExpandRefs( bOldExpandRefs );
3465 	pDoc->SetNoListening( bOldNoListening );
3466 	pDoc->SetAutoCalc( bOldAutoCalc );
3467 }
3468 
3469 
3470 void ScChangeTrack::UpdateReference( ScChangeAction** ppFirstAction,
3471 		ScChangeAction* pAct, sal_Bool bUndo )
3472 {
3473 	ScChangeActionType eActType = pAct->GetType();
3474 	sal_Bool bGeneratedDelContents =
3475 		( ppFirstAction == (ScChangeAction**)&pFirstGeneratedDelContent );
3476 	const ScBigRange& rOrgRange = pAct->GetBigRange();
3477 	ScBigRange aRange( rOrgRange );
3478 	ScBigRange aDelRange( rOrgRange );
3479 	sal_Int32 nDx, nDy, nDz;
3480 	nDx = nDy = nDz = 0;
3481 	UpdateRefMode eMode = URM_INSDEL;
3482 	sal_Bool bDel = sal_False;
3483 	switch ( eActType )
3484 	{
3485 		case SC_CAT_INSERT_COLS :
3486 			aRange.aEnd.SetCol( nInt32Max );
3487 			nDx = rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1;
3488 		break;
3489 		case SC_CAT_INSERT_ROWS :
3490 			aRange.aEnd.SetRow( nInt32Max );
3491 			nDy = rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1;
3492 		break;
3493 		case SC_CAT_INSERT_TABS :
3494 			aRange.aEnd.SetTab( nInt32Max );
3495 			nDz = rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1;
3496 		break;
3497 		case SC_CAT_DELETE_COLS :
3498 			aRange.aEnd.SetCol( nInt32Max );
3499 			nDx = -(rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1);
3500 			aDelRange.aEnd.SetCol( aDelRange.aStart.Col() - nDx - 1 );
3501 			bDel = sal_True;
3502 		break;
3503 		case SC_CAT_DELETE_ROWS :
3504 			aRange.aEnd.SetRow( nInt32Max );
3505 			nDy = -(rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1);
3506 			aDelRange.aEnd.SetRow( aDelRange.aStart.Row() - nDy - 1 );
3507 			bDel = sal_True;
3508 		break;
3509 		case SC_CAT_DELETE_TABS :
3510 			aRange.aEnd.SetTab( nInt32Max );
3511 			nDz = -(rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1);
3512 			aDelRange.aEnd.SetTab( aDelRange.aStart.Tab() - nDz - 1 );
3513 			bDel = sal_True;
3514 		break;
3515 		case SC_CAT_MOVE :
3516 			eMode = URM_MOVE;
3517 			((ScChangeActionMove*)pAct)->GetDelta( nDx, nDy, nDz );
3518 		break;
3519 		default:
3520 			DBG_ERROR( "ScChangeTrack::UpdateReference: unknown Type" );
3521 	}
3522 	if ( bUndo )
3523 	{
3524 		nDx = -nDx;
3525 		nDy = -nDy;
3526 		nDz = -nDz;
3527 	}
3528 	if ( bDel )
3529 	{	//! fuer diesen Mechanismus gilt:
3530 		//! es gibt nur ganze, einfache geloeschte Spalten/Zeilen
3531 		ScChangeActionDel* pActDel = (ScChangeActionDel*) pAct;
3532 		if ( !bUndo )
3533 		{	// Delete
3534             ScChangeActionType eInsType = SC_CAT_NONE;      // for Insert-Undo-"Deletes"
3535 			switch ( eActType )
3536 			{
3537 				case SC_CAT_DELETE_COLS :
3538 					eInsType = SC_CAT_INSERT_COLS;
3539 				break;
3540 				case SC_CAT_DELETE_ROWS :
3541 					eInsType = SC_CAT_INSERT_ROWS;
3542 				break;
3543 				case SC_CAT_DELETE_TABS :
3544 					eInsType = SC_CAT_INSERT_TABS;
3545 				break;
3546                 default:
3547                 {
3548                     // added to avoid warnings
3549                 }
3550 			}
3551 			for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3552 			{
3553 				if ( p == pAct )
3554 					continue;	// for
3555 				sal_Bool bUpdate = sal_True;
3556 				if ( GetMergeState() == SC_CTMS_OTHER &&
3557 						p->GetActionNumber() <= GetLastMerge() )
3558 				{	// Delete in mergendem Dokument, Action im zu mergenden
3559 					if ( p->IsInsertType() )
3560 					{
3561 						// Bei Insert Referenzen nur anpassen, wenn das Delete
3562 						// das Insert nicht schneidet.
3563 						if ( !aDelRange.Intersects( p->GetBigRange() ) )
3564 							p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3565 						bUpdate = sal_False;
3566 					}
3567 					else if ( p->GetType() == SC_CAT_CONTENT &&
3568 							p->IsDeletedInDelType( eInsType ) )
3569 					{	// Content in Insert-Undo-"Delete"
3570 						// Nicht anpassen, wenn dieses Delete in dem
3571 						// Insert-"Delete" sein wuerde (ist nur verschoben).
3572 						if ( aDelRange.In( p->GetBigRange().aStart ) )
3573 							bUpdate = sal_False;
3574 						else
3575 						{
3576 							const ScChangeActionLinkEntry* pLink = p->GetDeletedIn();
3577 							while ( pLink && bUpdate )
3578 							{
3579 								const ScChangeAction* pDel = pLink->GetAction();
3580 								if ( pDel && pDel->GetType() == eInsType &&
3581 										pDel->GetBigRange().In( aDelRange ) )
3582 									bUpdate = sal_False;
3583 								pLink = pLink->GetNext();
3584 							}
3585 						}
3586 					}
3587 					if ( !bUpdate )
3588 						continue;	// for
3589 				}
3590 				if ( aDelRange.In( p->GetBigRange() ) )
3591 				{
3592 					// Innerhalb eines gerade geloeschten Bereiches nicht
3593 					// anpassen, stattdessen dem Bereich zuordnen.
3594 					// Mehrfache geloeschte Bereiche "stapeln".
3595 					// Kreuzende Deletes setzen mehrfach geloescht.
3596 					if ( !p->IsDeletedInDelType( eActType ) )
3597 					{
3598 						p->SetDeletedIn( pActDel );
3599 						// GeneratedDelContent in zu loeschende Liste aufnehmen
3600 						if ( bGeneratedDelContents )
3601 							pActDel->AddContent( (ScChangeActionContent*) p );
3602 					}
3603 					bUpdate = sal_False;
3604 				}
3605 				else
3606 				{
3607 					// Eingefuegte Bereiche abschneiden, wenn Start/End im
3608 					// Delete liegt, aber das Insert nicht komplett innerhalb
3609 					// des Delete liegt bzw. das Delete nicht komplett im
3610 					// Insert. Das Delete merkt sich, welchem Insert es was
3611 					// abgeschnitten hat, es kann auch nur ein einziges Insert
3612 					// sein (weil Delete einspaltig/einzeilig ist).
3613 					// Abgeschnittene Moves kann es viele geben.
3614 					//! Ein Delete ist immer einspaltig/einzeilig, deswegen 1
3615 					//! ohne die Ueberlappung auszurechnen.
3616 					switch ( p->GetType() )
3617 					{
3618 						case SC_CAT_INSERT_COLS :
3619 							if ( eActType == SC_CAT_DELETE_COLS )
3620 							{
3621 								if ( aDelRange.In( p->GetBigRange().aStart ) )
3622 								{
3623 									pActDel->SetCutOffInsert(
3624 										(ScChangeActionIns*) p, 1 );
3625 									p->GetBigRange().aStart.IncCol( 1 );
3626 								}
3627 								else if ( aDelRange.In( p->GetBigRange().aEnd ) )
3628 								{
3629 									pActDel->SetCutOffInsert(
3630 										(ScChangeActionIns*) p, -1 );
3631 									p->GetBigRange().aEnd.IncCol( -1 );
3632 								}
3633 							}
3634 						break;
3635 						case SC_CAT_INSERT_ROWS :
3636 							if ( eActType == SC_CAT_DELETE_ROWS )
3637 							{
3638 								if ( aDelRange.In( p->GetBigRange().aStart ) )
3639 								{
3640 									pActDel->SetCutOffInsert(
3641 										(ScChangeActionIns*) p, 1 );
3642 									p->GetBigRange().aStart.IncRow( 1 );
3643 								}
3644 								else if ( aDelRange.In( p->GetBigRange().aEnd ) )
3645 								{
3646 									pActDel->SetCutOffInsert(
3647 										(ScChangeActionIns*) p, -1 );
3648 									p->GetBigRange().aEnd.IncRow( -1 );
3649 								}
3650 							}
3651 						break;
3652 						case SC_CAT_INSERT_TABS :
3653 							if ( eActType == SC_CAT_DELETE_TABS )
3654 							{
3655 								if ( aDelRange.In( p->GetBigRange().aStart ) )
3656 								{
3657 									pActDel->SetCutOffInsert(
3658 										(ScChangeActionIns*) p, 1 );
3659 									p->GetBigRange().aStart.IncTab( 1 );
3660 								}
3661 								else if ( aDelRange.In( p->GetBigRange().aEnd ) )
3662 								{
3663 									pActDel->SetCutOffInsert(
3664 										(ScChangeActionIns*) p, -1 );
3665 									p->GetBigRange().aEnd.IncTab( -1 );
3666 								}
3667 							}
3668 						break;
3669 						case SC_CAT_MOVE :
3670 						{
3671 							ScChangeActionMove* pMove = (ScChangeActionMove*) p;
3672 							short nFrom = 0;
3673 							short nTo = 0;
3674 							if ( aDelRange.In( pMove->GetBigRange().aStart ) )
3675 								nTo = 1;
3676 							else if ( aDelRange.In( pMove->GetBigRange().aEnd ) )
3677 								nTo = -1;
3678 							if ( aDelRange.In( pMove->GetFromRange().aStart ) )
3679 								nFrom = 1;
3680 							else if ( aDelRange.In( pMove->GetFromRange().aEnd ) )
3681 								nFrom = -1;
3682 							if ( nFrom )
3683 							{
3684 								switch ( eActType )
3685 								{
3686 									case SC_CAT_DELETE_COLS :
3687 										if ( nFrom > 0 )
3688 											pMove->GetFromRange().aStart.IncCol( nFrom );
3689 										else
3690 											pMove->GetFromRange().aEnd.IncCol( nFrom );
3691 									break;
3692 									case SC_CAT_DELETE_ROWS :
3693 										if ( nFrom > 0 )
3694 											pMove->GetFromRange().aStart.IncRow( nFrom );
3695 										else
3696 											pMove->GetFromRange().aEnd.IncRow( nFrom );
3697 									break;
3698 									case SC_CAT_DELETE_TABS :
3699 										if ( nFrom > 0 )
3700 											pMove->GetFromRange().aStart.IncTab( nFrom );
3701 										else
3702 											pMove->GetFromRange().aEnd.IncTab( nFrom );
3703 									break;
3704                                     default:
3705                                     {
3706                                         // added to avoid warnings
3707                                     }
3708 								}
3709 							}
3710 							if ( nTo )
3711 							{
3712 								switch ( eActType )
3713 								{
3714 									case SC_CAT_DELETE_COLS :
3715 										if ( nTo > 0 )
3716 											pMove->GetBigRange().aStart.IncCol( nTo );
3717 										else
3718 											pMove->GetBigRange().aEnd.IncCol( nTo );
3719 									break;
3720 									case SC_CAT_DELETE_ROWS :
3721 										if ( nTo > 0 )
3722 											pMove->GetBigRange().aStart.IncRow( nTo );
3723 										else
3724 											pMove->GetBigRange().aEnd.IncRow( nTo );
3725 									break;
3726 									case SC_CAT_DELETE_TABS :
3727 										if ( nTo > 0 )
3728 											pMove->GetBigRange().aStart.IncTab( nTo );
3729 										else
3730 											pMove->GetBigRange().aEnd.IncTab( nTo );
3731 									break;
3732                                     default:
3733                                     {
3734                                         // added to avoid warnings
3735                                     }
3736 								}
3737 							}
3738 							if ( nFrom || nTo )
3739 							{
3740 								ScChangeActionDelMoveEntry* pLink =
3741 									pActDel->AddCutOffMove( pMove, nFrom, nTo );
3742 								pMove->AddLink( pActDel, pLink );
3743 							}
3744 						}
3745 						break;
3746                         default:
3747                         {
3748                             // added to avoid warnings
3749                         }
3750 					}
3751 				}
3752 				if ( bUpdate )
3753 				{
3754 					p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3755 					if ( p->GetType() == eActType && !p->IsRejected() &&
3756 							!pActDel->IsDeletedIn() &&
3757 							p->GetBigRange().In( aDelRange ) )
3758 						pActDel->SetDeletedIn( p );		// "druntergerutscht"
3759 				}
3760 			}
3761 		}
3762 		else
3763 		{	// Undo Delete
3764 			for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3765 			{
3766 				if ( p == pAct )
3767 					continue;	// for
3768 				sal_Bool bUpdate = sal_True;
3769 				if ( aDelRange.In( p->GetBigRange() ) )
3770 				{
3771                     // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3772                     if ( GetMergeState() == SC_CTMS_UNDO && !p->IsDeletedIn( pAct ) && pAct->IsDeleteType() &&
3773                          ( p->GetType() == SC_CAT_CONTENT ||
3774                            p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
3775                            p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) )
3776                     {
3777                         p->SetDeletedIn( pAct );
3778                     }
3779 
3780 					if ( p->IsDeletedInDelType( eActType ) )
3781 					{
3782 						if ( p->IsDeletedIn( pActDel ) )
3783 						{
3784 							if ( p->GetType() != SC_CAT_CONTENT ||
3785 									((ScChangeActionContent*)p)->IsTopContent() )
3786 							{	// erst der TopContent wird wirklich entfernt
3787 								p->RemoveDeletedIn( pActDel );
3788 								// GeneratedDelContent _nicht_ aus Liste loeschen,
3789 								// wir brauchen ihn evtl. noch fuer Reject,
3790 								// geloescht wird in DeleteCellEntries
3791 							}
3792 						}
3793 						bUpdate = sal_False;
3794 					}
3795 					else if ( eActType != SC_CAT_DELETE_TABS &&
3796 							p->IsDeletedInDelType( SC_CAT_DELETE_TABS ) )
3797 					{	// in geloeschten Tabellen nicht updaten,
3798 						// ausser wenn Tabelle verschoben wird
3799 						bUpdate = sal_False;
3800 					}
3801 					if ( p->GetType() == eActType && pActDel->IsDeletedIn( p ) )
3802 					{
3803 						pActDel->RemoveDeletedIn( p );	// "druntergerutscht"
3804 						bUpdate = sal_True;
3805 					}
3806 				}
3807 				if ( bUpdate )
3808 					p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3809 			}
3810 			if ( !bGeneratedDelContents )
3811 			{	// die werden sonst noch fuer das echte Undo gebraucht
3812 				pActDel->UndoCutOffInsert();
3813 				pActDel->UndoCutOffMoves();
3814 			}
3815 		}
3816 	}
3817 	else if ( eActType == SC_CAT_MOVE )
3818 	{
3819 		ScChangeActionMove* pActMove = (ScChangeActionMove*) pAct;
3820 		sal_Bool bLastCutMove = ( pActMove == pLastCutMove );
3821 		const ScBigRange& rTo = pActMove->GetBigRange();
3822 		const ScBigRange& rFrom = pActMove->GetFromRange();
3823 		if ( !bUndo )
3824 		{	// Move
3825 			for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3826 			{
3827 				if ( p == pAct )
3828 					continue;	// for
3829 				if ( p->GetType() == SC_CAT_CONTENT )
3830 				{
3831 					// Inhalt in Ziel deleten (Inhalt in Quelle moven)
3832 					if ( rTo.In( p->GetBigRange() ) )
3833 					{
3834 						if ( !p->IsDeletedIn( pActMove ) )
3835 						{
3836 							p->SetDeletedIn( pActMove );
3837 							// GeneratedDelContent in zu loeschende Liste aufnehmen
3838 							if ( bGeneratedDelContents )
3839 								pActMove->AddContent( (ScChangeActionContent*) p );
3840 						}
3841 					}
3842 					else if ( bLastCutMove &&
3843 							p->GetActionNumber() > nEndLastCut &&
3844 							rFrom.In( p->GetBigRange() ) )
3845 					{	// Paste Cut: neuer Content nach Cut eingefuegt, bleibt.
3846 						// Aufsplitten der ContentChain
3847 						ScChangeActionContent *pHere, *pTmp;
3848 						pHere = (ScChangeActionContent*) p;
3849                         while ( (pTmp = pHere->GetPrevContent()) != NULL &&
3850 								pTmp->GetActionNumber() > nEndLastCut )
3851 							pHere = pTmp;
3852 						if ( pTmp )
3853 						{	// wird TopContent des Move
3854 							pTmp->SetNextContent( NULL );
3855 							pHere->SetPrevContent( NULL );
3856 						}
3857 						do
3858 						{	// Abhaengigkeit vom FromRange herstellen
3859 							AddDependentWithNotify( pActMove, pHere );
3860                         } while ( ( pHere = pHere->GetNextContent() ) != NULL );
3861 					}
3862                     // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
3863                     else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() )
3864 						p->UpdateReference( this, eMode, rFrom, nDx, nDy, nDz );
3865 				}
3866 			}
3867 		}
3868 		else
3869 		{	// Undo Move
3870 			sal_Bool bActRejected = pActMove->IsRejected();
3871 			for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3872 			{
3873 				if ( p == pAct )
3874 					continue;	// for
3875 				if ( p->GetType() == SC_CAT_CONTENT )
3876 				{
3877 					// Inhalt in Ziel moven, wenn nicht deleted, sonst undelete
3878 					if ( p->IsDeletedIn( pActMove ) )
3879 					{
3880 						if ( ((ScChangeActionContent*)p)->IsTopContent() )
3881 						{	// erst der TopContent wird wirklich entfernt
3882 							p->RemoveDeletedIn( pActMove );
3883 							// GeneratedDelContent _nicht_ aus Liste loeschen,
3884 							// wir brauchen ihn evtl. noch fuer Reject,
3885 							// geloescht wird in DeleteCellEntries
3886 						}
3887 					}
3888                     // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
3889                     else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() )
3890 						p->UpdateReference( this, eMode, rTo, nDx, nDy, nDz );
3891 					if ( bActRejected &&
3892 							((ScChangeActionContent*)p)->IsTopContent() &&
3893 							rFrom.In( p->GetBigRange() ) )
3894 					{	// Abhaengigkeit herstellen, um Content zu schreiben
3895 						ScChangeActionLinkEntry* pLink =
3896 							pActMove->AddDependent( p );
3897 						p->AddLink( pActMove, pLink );
3898 					}
3899 				}
3900 			}
3901 		}
3902 	}
3903 	else
3904 	{	// Insert / Undo Insert
3905 		switch ( GetMergeState() )
3906 		{
3907 			case SC_CTMS_NONE :
3908 			case SC_CTMS_OTHER :
3909 			{
3910 				for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3911 				{
3912 					if ( p == pAct )
3913 						continue;	// for
3914 					p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3915 				}
3916 			}
3917 			break;
3918 			case SC_CTMS_PREPARE :
3919 			{
3920 				// in Insert-Undo "Deleten"
3921 				const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry();
3922 				while ( pLink )
3923 				{
3924 					ScChangeAction* p = (ScChangeAction*) pLink->GetAction();
3925 					if ( p )
3926 						p->SetDeletedIn( pAct );
3927 					pLink = pLink->GetNext();
3928 				}
3929 
3930                 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
3931                 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3932                 {
3933                     if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
3934                          // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3935                          ( p->GetType() == SC_CAT_CONTENT ||
3936                            p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
3937                            p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
3938                          pAct->GetBigRange().Intersects( p->GetBigRange() ) )
3939                     {
3940                         p->SetDeletedIn( pAct );
3941                     }
3942                 }
3943 
3944                 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3945 				{
3946 					if ( p == pAct )
3947 						continue;	// for
3948                     if ( !p->IsDeletedIn( pAct )
3949                          // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
3950                          && p->GetActionNumber() <= pAct->GetActionNumber() )
3951                     {
3952 						p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3953                     }
3954 				}
3955 			}
3956 			break;
3957 			case SC_CTMS_OWN :
3958 			{
3959 				for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3960 				{
3961 					if ( p == pAct )
3962 						continue;	// for
3963                     if ( !p->IsDeletedIn( pAct )
3964                          // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
3965                          && p->GetActionNumber() <= pAct->GetActionNumber() )
3966                     {
3967 						p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3968                     }
3969 				}
3970 				// in Insert-Undo "Delete" rueckgaengig
3971 				const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry();
3972 				while ( pLink )
3973 				{
3974 					ScChangeAction* p = (ScChangeAction*) pLink->GetAction();
3975 					if ( p )
3976 						p->RemoveDeletedIn( pAct );
3977 					pLink = pLink->GetNext();
3978 				}
3979 
3980                 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
3981                 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3982                 {
3983                     if ( p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
3984                          // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3985                          ( p->GetType() == SC_CAT_CONTENT ||
3986                            p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
3987                            p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
3988                          pAct->GetBigRange().Intersects( p->GetBigRange() ) )
3989                     {
3990                         p->RemoveDeletedIn( pAct );
3991                     }
3992                 }
3993 			}
3994 			break;
3995             // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3996             case SC_CTMS_UNDO :
3997             {
3998                 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3999                 {
4000                     if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
4001                          ( p->GetType() == SC_CAT_CONTENT ||
4002                            p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
4003                            p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
4004                          pAct->GetBigRange().Intersects( p->GetBigRange() ) )
4005                     {
4006                         p->SetDeletedIn( pAct );
4007                     }
4008                 }
4009 
4010                 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
4011                 {
4012                     if ( p == pAct )
4013                     {
4014                         continue;
4015                     }
4016                     if ( !p->IsDeletedIn( pAct ) && p->GetActionNumber() <= pAct->GetActionNumber() )
4017                     {
4018                         p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
4019                     }
4020                 }
4021             }
4022             break;
4023 		}
4024 	}
4025 }
4026 
4027 
4028 void ScChangeTrack::GetDependents( ScChangeAction* pAct,
4029 		ScChangeActionTable& rTable, sal_Bool bListMasterDelete, sal_Bool bAllFlat ) const
4030 {
4031 	//! bAllFlat==TRUE: intern aus Accept oder Reject gerufen,
4032 	//! => Generated werden nicht aufgenommen
4033 
4034 	sal_Bool bIsDelete = pAct->IsDeleteType();
4035 	sal_Bool bIsMasterDelete = ( bListMasterDelete && pAct->IsMasterDelete() );
4036 
4037 	const ScChangeAction* pCur = pAct;
4038 	ScChangeActionStack* pStack = new ScChangeActionStack;
4039 	do
4040 	{
4041 		if ( pCur->IsInsertType() )
4042 		{
4043 			const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry();
4044 			while ( pL )
4045 			{
4046 				ScChangeAction* p = (ScChangeAction*) pL->GetAction();
4047 				if ( p != pAct )
4048 				{
4049 					if ( bAllFlat )
4050 					{
4051 						sal_uLong n = p->GetActionNumber();
4052 						if ( !IsGenerated( n ) && rTable.Insert( n, p ) )
4053 							if ( p->HasDependent() )
4054 								pStack->Push( p );
4055 					}
4056 					else
4057 					{
4058 						if ( p->GetType() == SC_CAT_CONTENT )
4059 						{
4060 							if ( ((ScChangeActionContent*)p)->IsTopContent() )
4061 								rTable.Insert( p->GetActionNumber(), p );
4062 						}
4063 						else
4064 							rTable.Insert( p->GetActionNumber(), p );
4065 					}
4066 				}
4067 				pL = pL->GetNext();
4068 			}
4069 		}
4070 		else if ( pCur->IsDeleteType() )
4071 		{
4072 			if ( bIsDelete )
4073 			{	// Inhalte geloeschter Bereiche interessieren nur bei Delete
4074 				ScChangeActionDel* pDel = (ScChangeActionDel*) pCur;
4075 				if ( !bAllFlat && bIsMasterDelete && pCur == pAct )
4076 				{
4077 					// zu diesem Delete gehoerende Deletes in gleiche Ebene,
4078 					// wenn dieses Delete das momentan oberste einer Reihe ist,
4079 					ScChangeActionType eType = pDel->GetType();
4080 					ScChangeAction* p = pDel;
4081                     while ( (p = p->GetPrev()) != NULL && p->GetType() == eType &&
4082 							!((ScChangeActionDel*)p)->IsTopDelete() )
4083 						rTable.Insert( p->GetActionNumber(), p );
4084 					// dieses Delete auch in Table!
4085 					rTable.Insert( pAct->GetActionNumber(), pAct );
4086 				}
4087 				else
4088 				{
4089 					const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry();
4090 					while ( pL )
4091 					{
4092 						ScChangeAction* p = (ScChangeAction*) pL->GetAction();
4093 						if ( p != pAct )
4094 						{
4095 							if ( bAllFlat )
4096 							{
4097 								// nur ein TopContent einer Kette ist in LinkDeleted
4098 								sal_uLong n = p->GetActionNumber();
4099 								if ( !IsGenerated( n ) && rTable.Insert( n, p ) )
4100 									if ( p->HasDeleted() ||
4101 											p->GetType() == SC_CAT_CONTENT )
4102 										pStack->Push( p );
4103 							}
4104 							else
4105 							{
4106 								if ( p->IsDeleteType() )
4107 								{	// weiteres TopDelete in gleiche Ebene,
4108 									// es ist nicht rejectable
4109 									if ( ((ScChangeActionDel*)p)->IsTopDelete() )
4110 										rTable.Insert( p->GetActionNumber(), p );
4111 								}
4112 								else
4113 									rTable.Insert( p->GetActionNumber(), p );
4114 							}
4115 						}
4116 						pL = pL->GetNext();
4117 					}
4118 				}
4119 			}
4120 		}
4121 		else if ( pCur->GetType() == SC_CAT_MOVE )
4122 		{
4123 			// geloeschte Contents im ToRange
4124 			const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry();
4125 			while ( pL )
4126 			{
4127 				ScChangeAction* p = (ScChangeAction*) pL->GetAction();
4128 				if ( p != pAct && rTable.Insert( p->GetActionNumber(), p ) )
4129 				{
4130 					// nur ein TopContent einer Kette ist in LinkDeleted
4131 					if ( bAllFlat && (p->HasDeleted() ||
4132 							p->GetType() == SC_CAT_CONTENT) )
4133 						pStack->Push( p );
4134 				}
4135 				pL = pL->GetNext();
4136 			}
4137 			// neue Contents im FromRange oder neuer FromRange im ToRange
4138 			// oder Inserts/Deletes in FromRange/ToRange
4139 			pL = pCur->GetFirstDependentEntry();
4140 			while ( pL )
4141 			{
4142 				ScChangeAction* p = (ScChangeAction*) pL->GetAction();
4143 				if ( p != pAct )
4144 				{
4145 					if ( bAllFlat )
4146 					{
4147 						sal_uLong n = p->GetActionNumber();
4148 						if ( !IsGenerated( n ) && rTable.Insert( n, p ) )
4149 							if ( p->HasDependent() || p->HasDeleted() )
4150 								pStack->Push( p );
4151 					}
4152 					else
4153 					{
4154 						if ( p->GetType() == SC_CAT_CONTENT )
4155 						{
4156 							if ( ((ScChangeActionContent*)p)->IsTopContent() )
4157 								rTable.Insert( p->GetActionNumber(), p );
4158 						}
4159 						else
4160 							rTable.Insert( p->GetActionNumber(), p );
4161 					}
4162 				}
4163 				pL = pL->GetNext();
4164 			}
4165 		}
4166 		else if ( pCur->GetType() == SC_CAT_CONTENT )
4167 		{	// alle Aenderungen an gleicher Position
4168 			ScChangeActionContent* pContent = (ScChangeActionContent*) pCur;
4169 			// alle vorherigen
4170             while ( ( pContent = pContent->GetPrevContent() ) != NULL )
4171 			{
4172 				if ( !pContent->IsRejected() )
4173 					rTable.Insert( pContent->GetActionNumber(), pContent );
4174 			}
4175 			pContent = (ScChangeActionContent*) pCur;
4176 			// alle nachfolgenden
4177             while ( ( pContent = pContent->GetNextContent() ) != NULL )
4178 			{
4179 				if ( !pContent->IsRejected() )
4180 					rTable.Insert( pContent->GetActionNumber(), pContent );
4181 			}
4182 			// all MatrixReferences of a MatrixOrigin
4183 			const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry();
4184 			while ( pL )
4185 			{
4186 				ScChangeAction* p = (ScChangeAction*) pL->GetAction();
4187 				if ( p != pAct )
4188 				{
4189 					if ( bAllFlat )
4190 					{
4191 						sal_uLong n = p->GetActionNumber();
4192 						if ( !IsGenerated( n ) && rTable.Insert( n, p ) )
4193 							if ( p->HasDependent() )
4194 								pStack->Push( p );
4195 					}
4196 					else
4197 						rTable.Insert( p->GetActionNumber(), p );
4198 				}
4199 				pL = pL->GetNext();
4200 			}
4201 		}
4202 		else if ( pCur->GetType() == SC_CAT_REJECT )
4203 		{
4204 			if ( bAllFlat )
4205 			{
4206 				ScChangeAction* p = GetAction(
4207 						((ScChangeActionReject*)pCur)->GetRejectAction() );
4208 				if ( p != pAct && !rTable.Get( p->GetActionNumber() ) )
4209 					pStack->Push( p );
4210 			}
4211 		}
4212     } while ( ( pCur = pStack->Pop() ) != NULL );
4213 	delete pStack;
4214 }
4215 
4216 
4217 sal_Bool ScChangeTrack::SelectContent( ScChangeAction* pAct, sal_Bool bOldest )
4218 {
4219 	if ( pAct->GetType() != SC_CAT_CONTENT )
4220 		return sal_False;
4221 
4222 	ScChangeActionContent* pContent = (ScChangeActionContent*) pAct;
4223 	if ( bOldest )
4224 	{
4225 		pContent = pContent->GetTopContent();
4226 		ScChangeActionContent* pPrevContent;
4227         while ( (pPrevContent = pContent->GetPrevContent()) != NULL &&
4228 				pPrevContent->IsVirgin() )
4229 			pContent = pPrevContent;
4230 	}
4231 
4232 	if ( !pContent->IsClickable() )
4233 		return sal_False;
4234 
4235 	ScBigRange aBigRange( pContent->GetBigRange() );
4236 	const ScBaseCell* pCell = (bOldest ? pContent->GetOldCell() :
4237 		pContent->GetNewCell());
4238 	if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATORG )
4239 	{
4240         SCCOL nC;
4241         SCROW nR;
4242         ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR );
4243 		aBigRange.aEnd.IncCol( nC-1 );
4244 		aBigRange.aEnd.IncRow( nR-1 );
4245 	}
4246 
4247 	if ( !aBigRange.IsValid( pDoc ) )
4248 		return sal_False;
4249 
4250 	ScRange aRange( aBigRange.MakeRange() );
4251 	if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(),
4252 			aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) )
4253 		return sal_False;
4254 
4255 	if ( pContent->HasDependent() )
4256 	{
4257 		sal_Bool bOk = sal_True;
4258 		Stack aRejectActions;
4259 		const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry();
4260 		while ( pL )
4261 		{
4262 			ScChangeAction* p = (ScChangeAction*) pL->GetAction();
4263 			if ( p != pContent )
4264 			{
4265 				if ( p->GetType() == SC_CAT_CONTENT )
4266 				{
4267 					// we don't need no recursion here, do we?
4268 					bOk &= ((ScChangeActionContent*)p)->Select( pDoc, this,
4269 						bOldest, &aRejectActions );
4270 				}
4271 				else
4272 				{
4273 					DBG_ERRORFILE( "ScChangeTrack::SelectContent: content dependent no content" );
4274 				}
4275 			}
4276 			pL = pL->GetNext();
4277 		}
4278 
4279 		bOk &= pContent->Select( pDoc, this, bOldest, NULL );
4280 		// now the matrix is inserted and new content values are ready
4281 
4282 		ScChangeActionContent* pNew;
4283         while ( ( pNew = (ScChangeActionContent*) aRejectActions.Pop() ) != NULL )
4284 		{
4285 			ScAddress aPos( pNew->GetBigRange().aStart.MakeAddress() );
4286 			pNew->SetNewValue( pDoc->GetCell( aPos ), pDoc );
4287 			Append( pNew );
4288 		}
4289 		return bOk;
4290 	}
4291 	else
4292 		return pContent->Select( pDoc, this, bOldest, NULL );
4293 }
4294 
4295 
4296 void ScChangeTrack::AcceptAll()
4297 {
4298 	for ( ScChangeAction* p = GetFirst(); p; p = p->GetNext() )
4299 	{
4300 		p->Accept();
4301 	}
4302 }
4303 
4304 
4305 sal_Bool ScChangeTrack::Accept( ScChangeAction* pAct )
4306 {
4307 	if ( !pAct->IsClickable() )
4308 		return sal_False;
4309 
4310 	if ( pAct->IsDeleteType() || pAct->GetType() == SC_CAT_CONTENT )
4311 	{
4312         ScChangeActionTable aActionTable;
4313         GetDependents( pAct, aActionTable, sal_False, sal_True );
4314         for ( ScChangeAction* p = aActionTable.First(); p; p = aActionTable.Next() )
4315 		{
4316 			p->Accept();
4317 		}
4318 	}
4319 	pAct->Accept();
4320 	return sal_True;
4321 }
4322 
4323 
4324 sal_Bool ScChangeTrack::RejectAll()
4325 {
4326 	sal_Bool bOk = sal_True;
4327 	for ( ScChangeAction* p = GetLast(); p && bOk; p = p->GetPrev() )
4328 	{	//! rueckwaerts, weil abhaengige hinten und RejectActions angehaengt
4329 		if ( p->IsInternalRejectable() )
4330 			bOk = Reject( p );
4331 	}
4332 	return bOk;
4333 }
4334 
4335 
4336 sal_Bool ScChangeTrack::Reject( ScChangeAction* pAct, bool bShared )
4337 {
4338     // #i100895# When collaboration changes are reversed, it must be possible
4339     // to reject a deleted row above another deleted row.
4340     if ( bShared && pAct->IsDeletedIn() )
4341         pAct->RemoveAllDeletedIn();
4342 
4343 	if ( !pAct->IsRejectable() )
4344 		return sal_False;
4345 
4346 	ScChangeActionTable* pTable = NULL;
4347 	if ( pAct->HasDependent() )
4348 	{
4349 		pTable = new ScChangeActionTable;
4350 		GetDependents( pAct, *pTable, sal_False, sal_True );
4351 	}
4352 	sal_Bool bRejected = Reject( pAct, pTable, sal_False );
4353 	if ( pTable )
4354 		delete pTable;
4355 	return bRejected;
4356 }
4357 
4358 
4359 sal_Bool ScChangeTrack::Reject( ScChangeAction* pAct, ScChangeActionTable* pTable,
4360 		sal_Bool bRecursion )
4361 {
4362 	if ( !pAct->IsInternalRejectable() )
4363 		return sal_False;
4364 
4365 	sal_Bool bOk = sal_True;
4366 	sal_Bool bRejected = sal_False;
4367 	if ( pAct->IsInsertType() )
4368 	{
4369 		if ( pAct->HasDependent() && !bRecursion )
4370 		{
4371 			DBG_ASSERT( pTable, "ScChangeTrack::Reject: Insert ohne Table" );
4372 			for ( ScChangeAction* p = pTable->Last(); p && bOk; p = pTable->Prev() )
4373 			{
4374 				// keine Contents restoren, die eh geloescht werden wuerden
4375 				if ( p->GetType() == SC_CAT_CONTENT )
4376 					p->SetRejected();
4377 				else if ( p->IsDeleteType() )
4378 					p->Accept();		// geloeschtes ins Nirvana
4379 				else
4380 					bOk = Reject( p, NULL, sal_True );		//! rekursiv
4381 			}
4382 		}
4383         if ( bOk && (bRejected = pAct->Reject( pDoc )) != sal_False )
4384 		{
4385 			// pRefDoc NULL := geloeschte Zellen nicht speichern
4386 			AppendDeleteRange( pAct->GetBigRange().MakeRange(), NULL, (short) 0,
4387 				pAct->GetActionNumber() );
4388 		}
4389 	}
4390 	else if ( pAct->IsDeleteType() )
4391 	{
4392 		DBG_ASSERT( !pTable, "ScChangeTrack::Reject: Delete mit Table" );
4393 		ScBigRange aDelRange;
4394 		sal_uLong nRejectAction = pAct->GetActionNumber();
4395 		sal_Bool bTabDel, bTabDelOk;
4396 		if ( pAct->GetType() == SC_CAT_DELETE_TABS )
4397 		{
4398 			bTabDel = sal_True;
4399 			aDelRange = pAct->GetBigRange();
4400 			bOk = bTabDelOk = pAct->Reject( pDoc );
4401 			if ( bOk )
4402 			{
4403 				pAct = pAct->GetPrev();
4404 				bOk = ( pAct && pAct->GetType() == SC_CAT_DELETE_COLS );
4405 			}
4406 		}
4407 		else
4408 			bTabDel = bTabDelOk = sal_False;
4409 		ScChangeActionDel* pDel = (ScChangeActionDel*) pAct;
4410 		if ( bOk )
4411 		{
4412 			aDelRange = pDel->GetOverAllRange();
4413 			bOk = aDelRange.IsValid( pDoc );
4414 		}
4415 		sal_Bool bOneOk = sal_False;
4416 		if ( bOk )
4417 		{
4418 			ScChangeActionType eActType = pAct->GetType();
4419 			switch ( eActType )
4420 			{
4421 				case SC_CAT_DELETE_COLS :
4422 					aDelRange.aStart.SetCol( aDelRange.aEnd.Col() );
4423 				break;
4424 				case SC_CAT_DELETE_ROWS :
4425 					aDelRange.aStart.SetRow( aDelRange.aEnd.Row() );
4426 				break;
4427 				case SC_CAT_DELETE_TABS :
4428 					aDelRange.aStart.SetTab( aDelRange.aEnd.Tab() );
4429 				break;
4430                 default:
4431                 {
4432                     // added to avoid warnings
4433                 }
4434 			}
4435 			ScChangeAction* p = pAct;
4436 			sal_Bool bLoop = sal_True;
4437 			do
4438 			{
4439 				pDel = (ScChangeActionDel*) p;
4440 				bOk = pDel->Reject( pDoc );
4441 				if ( bOk )
4442 				{
4443 					if ( bOneOk )
4444 					{
4445 						switch ( pDel->GetType() )
4446 						{
4447 							case SC_CAT_DELETE_COLS :
4448 								aDelRange.aStart.IncCol( -1 );
4449 							break;
4450 							case SC_CAT_DELETE_ROWS :
4451 								aDelRange.aStart.IncRow( -1 );
4452 							break;
4453 							case SC_CAT_DELETE_TABS :
4454 								aDelRange.aStart.IncTab( -1 );
4455 							break;
4456                             default:
4457                             {
4458                                 // added to avoid warnings
4459                             }
4460 						}
4461 					}
4462 					else
4463 						bOneOk = sal_True;
4464 				}
4465 				if ( pDel->IsBaseDelete() )
4466 					bLoop = sal_False;
4467 				else
4468 					p = p->GetPrev();
4469 			} while ( bOk && bLoop && p && p->GetType() == eActType &&
4470 				!((ScChangeActionDel*)p)->IsTopDelete() );
4471 		}
4472 		bRejected = bOk;
4473 		if ( bOneOk || (bTabDel && bTabDelOk) )
4474 		{
4475 			// Delete-Reject machte UpdateReference Undo
4476 			ScChangeActionIns* pReject = new ScChangeActionIns(
4477 				aDelRange.MakeRange() );
4478 			pReject->SetRejectAction( nRejectAction );
4479 			pReject->SetState( SC_CAS_ACCEPTED );
4480 			Append( pReject );
4481 		}
4482 	}
4483 	else if ( pAct->GetType() == SC_CAT_MOVE )
4484 	{
4485 		if ( pAct->HasDependent() && !bRecursion )
4486 		{
4487 			DBG_ASSERT( pTable, "ScChangeTrack::Reject: Move ohne Table" );
4488 			for ( ScChangeAction* p = pTable->Last(); p && bOk; p = pTable->Prev() )
4489 			{
4490 				bOk = Reject( p, NULL, sal_True );		//! rekursiv
4491 			}
4492 		}
4493         if ( bOk && (bRejected = pAct->Reject( pDoc )) != sal_False )
4494 		{
4495 			ScChangeActionMove* pReject = new ScChangeActionMove(
4496 				pAct->GetBigRange().MakeRange(),
4497 				((ScChangeActionMove*)pAct)->GetFromRange().MakeRange(), this );
4498 			pReject->SetRejectAction( pAct->GetActionNumber() );
4499 			pReject->SetState( SC_CAS_ACCEPTED );
4500 			Append( pReject );
4501 		}
4502 	}
4503 	else if ( pAct->GetType() == SC_CAT_CONTENT )
4504 	{
4505 		ScRange aRange;
4506 		ScChangeActionContent* pReject;
4507 		if ( bRecursion )
4508 			pReject = NULL;
4509 		else
4510 		{
4511 			aRange = pAct->GetBigRange().aStart.MakeAddress();
4512 			pReject = new ScChangeActionContent( aRange );
4513 			pReject->SetOldValue( pDoc->GetCell( aRange.aStart ), pDoc, pDoc );
4514 		}
4515         if ( (bRejected = pAct->Reject( pDoc )) != sal_False && !bRecursion )
4516 		{
4517 			pReject->SetNewValue( pDoc->GetCell( aRange.aStart ), pDoc );
4518 			pReject->SetRejectAction( pAct->GetActionNumber() );
4519 			pReject->SetState( SC_CAS_ACCEPTED );
4520 			Append( pReject );
4521 		}
4522 		else if ( pReject )
4523 			delete pReject;
4524 	}
4525 	else
4526 	{
4527 		DBG_ERROR( "ScChangeTrack::Reject: say what?" );
4528 	}
4529 
4530 	return bRejected;
4531 }
4532 
4533 
4534 sal_uLong ScChangeTrack::AddLoadedGenerated(ScBaseCell* pNewCell, const ScBigRange& aBigRange, const String& sNewValue )
4535 {
4536 	ScChangeActionContent* pAct = new ScChangeActionContent( --nGeneratedMin, pNewCell, aBigRange, pDoc, sNewValue );
4537 	if ( pAct )
4538 	{
4539 		if ( pFirstGeneratedDelContent )
4540 			pFirstGeneratedDelContent->pPrev = pAct;
4541 		pAct->pNext = pFirstGeneratedDelContent;
4542 		pFirstGeneratedDelContent = pAct;
4543 		aGeneratedTable.Insert( pAct->GetActionNumber(), pAct );
4544 		return pAct->GetActionNumber();
4545 	}
4546 	return 0;
4547 }
4548 
4549 void ScChangeTrack::AppendCloned( ScChangeAction* pAppend )
4550 {
4551     aTable.Insert( pAppend->GetActionNumber(), pAppend );
4552     if ( !pLast )
4553         pFirst = pLast = pAppend;
4554     else
4555     {
4556         pLast->pNext = pAppend;
4557         pAppend->pPrev = pLast;
4558         pLast = pAppend;
4559     }
4560 }
4561 
4562 ScChangeTrack* ScChangeTrack::Clone( ScDocument* pDocument ) const
4563 {
4564     if ( !pDocument )
4565     {
4566         return NULL;
4567     }
4568 
4569     ScChangeTrack* pClonedTrack = new ScChangeTrack( pDocument );
4570     pClonedTrack->SetTime100thSeconds( IsTime100thSeconds() );
4571 
4572     // clone generated actions
4573     ::std::stack< const ScChangeAction* > aGeneratedStack;
4574     const ScChangeAction* pGenerated = GetFirstGenerated();
4575     while ( pGenerated )
4576     {
4577         aGeneratedStack.push( pGenerated );
4578         pGenerated = pGenerated->GetNext();
4579     }
4580     while ( !aGeneratedStack.empty() )
4581     {
4582         pGenerated = aGeneratedStack.top();
4583         aGeneratedStack.pop();
4584         const ScChangeActionContent* pContent = dynamic_cast< const ScChangeActionContent* >( pGenerated );
4585         DBG_ASSERT( pContent, "ScChangeTrack::Clone: pContent is null!" );
4586         const ScBaseCell* pNewCell = pContent->GetNewCell();
4587         if ( pNewCell )
4588         {
4589             ScBaseCell* pClonedNewCell = pNewCell->CloneWithoutNote( *pDocument );
4590             String aNewValue;
4591             pContent->GetNewString( aNewValue );
4592             pClonedTrack->nGeneratedMin = pGenerated->GetActionNumber() + 1;
4593             pClonedTrack->AddLoadedGenerated( pClonedNewCell, pGenerated->GetBigRange(), aNewValue );
4594         }
4595     }
4596 
4597     // clone actions
4598     const ScChangeAction* pAction = GetFirst();
4599     while ( pAction )
4600     {
4601         ScChangeAction* pClonedAction = NULL;
4602 
4603         switch ( pAction->GetType() )
4604         {
4605             case SC_CAT_INSERT_COLS:
4606             case SC_CAT_INSERT_ROWS:
4607             case SC_CAT_INSERT_TABS:
4608                 {
4609                     pClonedAction = new ScChangeActionIns(
4610                         pAction->GetActionNumber(),
4611                         pAction->GetState(),
4612                         pAction->GetRejectAction(),
4613 		                pAction->GetBigRange(),
4614                         pAction->GetUser(),
4615                         pAction->GetDateTimeUTC(),
4616                         pAction->GetComment(),
4617                         pAction->GetType() );
4618                 }
4619                 break;
4620             case SC_CAT_DELETE_COLS:
4621             case SC_CAT_DELETE_ROWS:
4622             case SC_CAT_DELETE_TABS:
4623                 {
4624                     const ScChangeActionDel* pDelete = dynamic_cast< const ScChangeActionDel* >( pAction );
4625                     DBG_ASSERT( pDelete, "ScChangeTrack::Clone: pDelete is null!" );
4626 
4627                     SCsCOLROW nD = 0;
4628                     ScChangeActionType eType = pAction->GetType();
4629                     if ( eType == SC_CAT_DELETE_COLS )
4630                     {
4631                         nD = static_cast< SCsCOLROW >( pDelete->GetDx() );
4632                     }
4633                     else if ( eType == SC_CAT_DELETE_ROWS )
4634                     {
4635                         nD = static_cast< SCsCOLROW >( pDelete->GetDy() );
4636                     }
4637 
4638                     pClonedAction = new ScChangeActionDel(
4639                         pAction->GetActionNumber(),
4640                         pAction->GetState(),
4641                         pAction->GetRejectAction(),
4642 		                pAction->GetBigRange(),
4643                         pAction->GetUser(),
4644                         pAction->GetDateTimeUTC(),
4645                         pAction->GetComment(),
4646                         eType,
4647                         nD,
4648                         pClonedTrack );
4649                 }
4650                 break;
4651             case SC_CAT_MOVE:
4652                 {
4653                     const ScChangeActionMove* pMove = dynamic_cast< const ScChangeActionMove* >( pAction );
4654                     DBG_ASSERT( pMove, "ScChangeTrack::Clone: pMove is null!" );
4655 
4656                     pClonedAction = new ScChangeActionMove(
4657                         pAction->GetActionNumber(),
4658                         pAction->GetState(),
4659                         pAction->GetRejectAction(),
4660 		                pAction->GetBigRange(),
4661                         pAction->GetUser(),
4662                         pAction->GetDateTimeUTC(),
4663                         pAction->GetComment(),
4664                         pMove->GetFromRange(),
4665                         pClonedTrack );
4666                 }
4667                 break;
4668             case SC_CAT_CONTENT:
4669                 {
4670                     const ScChangeActionContent* pContent = dynamic_cast< const ScChangeActionContent* >( pAction );
4671                     DBG_ASSERT( pContent, "ScChangeTrack::Clone: pContent is null!" );
4672                     const ScBaseCell* pOldCell = pContent->GetOldCell();
4673                     ScBaseCell* pClonedOldCell = pOldCell ? pOldCell->CloneWithoutNote( *pDocument ) : 0;
4674                     String aOldValue;
4675                     pContent->GetOldString( aOldValue );
4676 
4677                     ScChangeActionContent* pClonedContent = new ScChangeActionContent(
4678                         pAction->GetActionNumber(),
4679                         pAction->GetState(),
4680                         pAction->GetRejectAction(),
4681 		                pAction->GetBigRange(),
4682                         pAction->GetUser(),
4683                         pAction->GetDateTimeUTC(),
4684                         pAction->GetComment(),
4685                         pClonedOldCell,
4686                         pDocument,
4687                         aOldValue );
4688 
4689                     const ScBaseCell* pNewCell = pContent->GetNewCell();
4690                     if ( pNewCell )
4691                     {
4692                         ScBaseCell* pClonedNewCell = pNewCell->CloneWithoutNote( *pDocument );
4693                         pClonedContent->SetNewValue( pClonedNewCell, pDocument );
4694                     }
4695 
4696                     pClonedAction = pClonedContent;
4697                 }
4698                 break;
4699             case SC_CAT_REJECT:
4700                 {
4701                     pClonedAction = new ScChangeActionReject(
4702                         pAction->GetActionNumber(),
4703                         pAction->GetState(),
4704                         pAction->GetRejectAction(),
4705 		                pAction->GetBigRange(),
4706                         pAction->GetUser(),
4707                         pAction->GetDateTimeUTC(),
4708                         pAction->GetComment() );
4709                 }
4710                 break;
4711             default:
4712                 {
4713                 }
4714                 break;
4715         }
4716 
4717         if ( pClonedAction )
4718         {
4719             pClonedTrack->AppendCloned( pClonedAction );
4720         }
4721 
4722         pAction = pAction->GetNext();
4723     }
4724 
4725     if ( pClonedTrack->GetLast() )
4726     {
4727         pClonedTrack->SetActionMax( pClonedTrack->GetLast()->GetActionNumber() );
4728     }
4729 
4730     // set dependencies for Deleted/DeletedIn
4731     pAction = GetFirst();
4732     while ( pAction )
4733     {
4734         if ( pAction->HasDeleted() )
4735         {
4736             ::std::stack< sal_uLong > aStack;
4737             const ScChangeActionLinkEntry* pL = pAction->GetFirstDeletedEntry();
4738             while ( pL )
4739             {
4740                 const ScChangeAction* pDeleted = pL->GetAction();
4741                 if ( pDeleted )
4742                 {
4743                     aStack.push( pDeleted->GetActionNumber() );
4744                 }
4745                 pL = pL->GetNext();
4746             }
4747             ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() );
4748             if ( pClonedAction )
4749             {
4750                 while ( !aStack.empty() )
4751                 {
4752                     ScChangeAction* pClonedDeleted = pClonedTrack->GetActionOrGenerated( aStack.top() );
4753                     aStack.pop();
4754                     if ( pClonedDeleted )
4755                     {
4756                         pClonedDeleted->SetDeletedIn( pClonedAction );
4757                     }
4758                 }
4759             }
4760         }
4761         pAction = pAction->GetNext();
4762     }
4763 
4764     // set dependencies for Dependent/Any
4765     pAction = GetLast();
4766     while ( pAction )
4767     {
4768         if ( pAction->HasDependent() )
4769         {
4770             ::std::stack< sal_uLong > aStack;
4771             const ScChangeActionLinkEntry* pL = pAction->GetFirstDependentEntry();
4772             while ( pL )
4773             {
4774                 const ScChangeAction* pDependent = pL->GetAction();
4775                 if ( pDependent )
4776                 {
4777                     aStack.push( pDependent->GetActionNumber() );
4778                 }
4779                 pL = pL->GetNext();
4780             }
4781             ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() );
4782             if ( pClonedAction )
4783             {
4784                 while ( !aStack.empty() )
4785                 {
4786                     ScChangeAction* pClonedDependent = pClonedTrack->GetActionOrGenerated( aStack.top() );
4787                     aStack.pop();
4788                     if ( pClonedDependent )
4789                     {
4790                         ScChangeActionLinkEntry* pLink = pClonedAction->AddDependent( pClonedDependent );
4791                         pClonedDependent->AddLink( pClonedAction, pLink );
4792                     }
4793                 }
4794             }
4795         }
4796         pAction = pAction->GetPrev();
4797     }
4798 
4799     // masterlinks
4800     ScChangeAction* pClonedAction = pClonedTrack->GetFirst();
4801     while ( pClonedAction )
4802     {
4803         pClonedTrack->MasterLinks( pClonedAction );
4804         pClonedAction = pClonedAction->GetNext();
4805     }
4806 
4807     if ( IsProtected() )
4808     {
4809         pClonedTrack->SetProtection( GetProtection() );
4810     }
4811 
4812     if ( pClonedTrack->GetLast() )
4813     {
4814         pClonedTrack->SetLastSavedActionNumber( pClonedTrack->GetLast()->GetActionNumber() );
4815     }
4816 
4817     pDocument->SetChangeTrack( pClonedTrack );
4818 
4819     return pClonedTrack;
4820 }
4821 
4822 void ScChangeTrack::MergeActionState( ScChangeAction* pAct, const ScChangeAction* pOtherAct )
4823 {
4824     if ( pAct->IsVirgin() )
4825     {
4826         if ( pOtherAct->IsAccepted() )
4827         {
4828             pAct->Accept();
4829             if ( pOtherAct->IsRejecting() )
4830             {
4831                 pAct->SetRejectAction( pOtherAct->GetRejectAction() );
4832             }
4833         }
4834         else if ( pOtherAct->IsRejected() )
4835         {
4836             pAct->SetRejected();
4837         }
4838     }
4839 }
4840 
4841 #if DEBUG_CHANGETRACK
4842 String ScChangeTrack::ToString() const
4843 {
4844     String aReturn;
4845 
4846     aReturn += String::CreateFromAscii( "============================================================\n" );
4847 
4848     const ScChangeAction* pGenerated = GetFirstGenerated();
4849     while ( pGenerated )
4850     {
4851         aReturn += pGenerated->ToString( pDoc );
4852         aReturn += '\n';
4853         pGenerated = pGenerated->GetNext();
4854     }
4855 
4856     aReturn += String::CreateFromAscii( "------------------------------------------------------------\n" );
4857 
4858     const ScChangeAction* pAction = GetFirst();
4859     while ( pAction )
4860     {
4861         aReturn += pAction->ToString( pDoc );
4862         aReturn += '\n';
4863         pAction = pAction->GetNext();
4864     }
4865     aReturn += String::CreateFromAscii( "============================================================\n" );
4866 
4867     return aReturn;
4868 }
4869 #endif // DEBUG_CHANGETRACK
4870