xref: /trunk/main/sc/source/core/tool/chgtrack.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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