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