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