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