LibreOffice Module sc (master) 1
chgtrack.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <chgtrack.hxx>
21#include <compiler.hxx>
22#include <formulacell.hxx>
23#include <document.hxx>
24#include <dociter.hxx>
25#include <global.hxx>
26#include <scmod.hxx>
27#include <inputopt.hxx>
28#include <patattr.hxx>
29#include <hints.hxx>
30#include <markdata.hxx>
31#include <globstr.hrc>
32#include <scresid.hxx>
33#include <editutil.hxx>
34#include <tokenarray.hxx>
35#include <refupdatecontext.hxx>
36#include <refupdat.hxx>
37
38#include <osl/diagnose.h>
39#include <svl/numformat.hxx>
40#include <sfx2/objsh.hxx>
42#include <unotools/datetime.hxx>
43#include <tools/json_writer.hxx>
44#include <algorithm>
45#include <memory>
46#include <utility>
47
49 :
50 aBigRange( rRange ),
51 aDateTime( DateTime::SYSTEM ),
52 pNext( nullptr ),
53 pPrev( nullptr ),
54 pLinkAny( nullptr ),
55 pLinkDeletedIn( nullptr ),
56 pLinkDeleted( nullptr ),
57 pLinkDependent( nullptr ),
58 nAction( 0 ),
59 nRejectAction( 0 ),
60 eType( eTypeP ),
61 eState( SC_CAS_VIRGIN )
62{
64}
65
67 ScChangeActionType eTypeP, ScBigRange aRange,
68 const sal_uLong nTempAction, const sal_uLong nTempRejectAction,
69 const ScChangeActionState eTempState, const DateTime& aTempDateTime,
70 OUString aTempUser, OUString aTempComment) :
71 aBigRange(std::move( aRange )),
72 aDateTime( aTempDateTime ),
73 aUser(std::move( aTempUser )),
74 aComment(std::move( aTempComment )),
75 pNext( nullptr ),
76 pPrev( nullptr ),
77 pLinkAny( nullptr ),
78 pLinkDeletedIn( nullptr ),
79 pLinkDeleted( nullptr ),
80 pLinkDependent( nullptr ),
81 nAction( nTempAction ),
82 nRejectAction( nTempRejectAction ),
83 eType( eTypeP ),
84 eState( eTempState )
85{
86}
87
89 const sal_uLong nTempAction)
90 :
91 aBigRange(std::move( aRange )),
92 aDateTime( DateTime::SYSTEM ),
93 pNext( nullptr ),
94 pPrev( nullptr ),
95 pLinkAny( nullptr ),
96 pLinkDeletedIn( nullptr ),
97 pLinkDeleted( nullptr ),
98 pLinkDependent( nullptr ),
99 nAction( nTempAction ),
100 nRejectAction( 0 ),
101 eType( eTypeP ),
102 eState( SC_CAS_VIRGIN )
103{
105}
106
108{
110}
111
113{
115}
116
118{
120}
121
123{
124 return eState == SC_CAS_VIRGIN;
125}
126
128{
129 return eState == SC_CAS_ACCEPTED;
130}
131
133{
134 return eState == SC_CAS_REJECTED;
135}
136
138{
139 return nRejectAction != 0;
140}
141
143{
144 // sequence order of execution is significant!
146 return false;
147 if ( GetType() == SC_CAT_CONTENT )
148 return static_cast<const ScChangeActionContent*>(this)->IsTopContent();
149 return true;
150}
151
153{
154 // sequence order of execution is significant!
155 if ( IsRejected() || GetType() == SC_CAT_REJECT || IsDeletedIn() )
156 return false;
157 // content may reject and be touchable if on top
158 if ( GetType() == SC_CAT_CONTENT )
159 return static_cast<const ScChangeActionContent*>(this)->IsTopContent();
160 if ( IsRejecting() )
161 return false;
162 return true;
163}
164
166{
167 // sequence order of execution is significant!
168 if ( !IsVirgin() )
169 return false;
170 if ( IsDeletedIn() )
171 return false;
172 if ( GetType() == SC_CAT_CONTENT )
173 {
176 static_cast<const ScChangeActionContent*>(this)->GetNewCell() );
177 if ( eCCT == SC_CACCT_MATREF )
178 return false;
179 if ( eCCT == SC_CACCT_MATORG )
180 { // no Accept-Select if one of the references is in a deleted col/row
181 const ScChangeActionLinkEntry* pL =
182 static_cast<const ScChangeActionContent*>(this)->GetFirstDependentEntry();
183 while ( pL )
184 {
185 ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction());
186 if ( p && p->IsDeletedIn() )
187 return false;
188 pL = pL->GetNext();
189 }
190 }
191 return true; // for Select() a content doesn't have to be touchable
192 }
193 return IsTouchable(); // Accept()/Reject() only on touchables
194}
195
197{
198 // sequence order of execution is significant!
199 if ( !IsClickable() )
200 return false;
201 if ( GetType() == SC_CAT_CONTENT )
202 {
203 if ( static_cast<const ScChangeActionContent*>(this)->IsOldMatrixReference() )
204 return false;
205 ScChangeActionContent* pNextContent =
206 static_cast<const ScChangeActionContent*>(this)->GetNextContent();
207 if ( pNextContent == nullptr )
208 return true; // *this is TopContent
209 return pNextContent->IsRejected(); // *this is next rejectable
210 }
211 return IsTouchable();
212}
213
215{
216 // sequence order of execution is significant!
217 if ( !IsVirgin() )
218 return false;
219 if ( IsDeletedIn() )
220 return false;
221 if ( GetType() == SC_CAT_CONTENT )
222 {
223 ScChangeActionContent* pNextContent =
224 static_cast<const ScChangeActionContent*>(this)->GetNextContent();
225 if ( pNextContent == nullptr )
226 return true; // *this is TopContent
227 return pNextContent->IsRejected(); // *this is next rejectable
228 }
229 return IsTouchable();
230}
231
233{
234 return IsInternalRejectable(); // only rejectables in root
235}
236
238{
239 // sequence order of execution is significant!
240 if ( GetType() == SC_CAT_CONTENT )
241 {
242 if ( !IsDialogRoot() )
243 return false;
244 if ( static_cast<const ScChangeActionContent*>(this)->IsMatrixOrigin() && HasDependent() )
245 return true;
246 ScChangeActionContent* pPrevContent =
247 static_cast<const ScChangeActionContent*>(this)->GetPrevContent();
248 return pPrevContent && pPrevContent->IsVirgin();
249 }
250 if ( HasDependent() )
251 return IsDeleteType() || !IsDeletedIn();
252 if ( HasDeleted() )
253 {
254 if ( IsDeleteType() )
255 {
256 if ( IsDialogRoot() )
257 return true;
259 while ( pL )
260 {
261 ScChangeAction* p = pL->GetAction();
262 if ( p && p->GetType() != eType )
263 return true;
264 pL = pL->GetNext();
265 }
266 }
267 else
268 return true;
269 }
270 return false;
271}
272
274{
275 if ( !IsDeleteType() )
276 return false;
277 const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(this);
278 return pDel->IsMultiDelete() && (pDel->IsTopDelete() || pDel->IsRejectable());
279}
280
282{
283 while (pLinkAny)
284 {
285 // coverity[use_after_free] - Moves up by itself
286 delete pLinkAny;
287 }
288
290
291 while (pLinkDeleted)
292 {
293 // coverity[use_after_free] - Moves up by itself
294 delete pLinkDeleted;
295 }
296
298}
299
301{
302 bool bRemoved = false;
304 while ( pL )
305 {
306 ScChangeActionLinkEntry* pNextLink = pL->GetNext();
307 if ( pL->GetAction() == p )
308 {
309 delete pL;
310 bRemoved = true;
311 }
312 pL = pNextLink;
313 }
314 return bRemoved;
315}
316
318{
319 return GetDeletedIn() != nullptr;
320}
321
323{
325 while ( pL )
326 {
327 if ( pL->GetAction() == p )
328 return true;
329 pL = pL->GetNext();
330 }
331 return false;
332}
333
335{
336 //TODO: Not from TopContent, but really this one
337 while (pLinkDeletedIn)
338 {
339 // coverity[use_after_free] - Moves up by itself
341 }
342}
343
345{
347 if ( pL )
348 {
349 // InsertType for MergePrepare/MergeOwn
350 ScChangeActionType eInsType;
351 switch ( eDelType )
352 {
353 case SC_CAT_DELETE_COLS :
354 eInsType = SC_CAT_INSERT_COLS;
355 break;
356 case SC_CAT_DELETE_ROWS :
357 eInsType = SC_CAT_INSERT_ROWS;
358 break;
359 case SC_CAT_DELETE_TABS :
360 eInsType = SC_CAT_INSERT_TABS;
361 break;
362 default:
363 eInsType = SC_CAT_NONE;
364 }
365 while ( pL )
366 {
367 ScChangeAction* p = pL->GetAction();
368 if ( p != nullptr && (p->GetType() == eDelType || p->GetType() == eInsType) )
369 return true;
370 pL = pL->GetNext();
371 }
372 }
373 return false;
374}
375
377{
378 return pLinkDependent != nullptr;
379}
380
382{
383 return pLinkDeleted != nullptr;
384}
385
387{
390 if ( GetType() == SC_CAT_CONTENT )
391 pLink2 = p->AddDeleted( static_cast<ScChangeActionContent*>(this)->GetTopContent() );
392 else
393 pLink2 = p->AddDeleted( this );
394 pLink1->SetLink( pLink2 );
395}
396
398{
399 while (pLinkDependent)
400 {
401 // coverity[use_after_free] - Moves up by itself
402 delete pLinkDependent;
403 }
404}
405
407{
408 DateTime aDT( aDateTime );
409 aDT.ConvertToLocalTime();
410 return aDT;
411}
412
414 UpdateRefMode eMode, const ScBigRange& rRange,
415 sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
416{
417 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() );
418}
419
421 ScDocument& /* rDoc */, bool /* bSplitRange */, bool bWarning ) const
422{
423 if (!IsRejecting() || !bWarning)
424 return OUString();
425
426 // Add comment if rejection may have resulted in references
427 // not properly restored in formulas. See specification at
428 // http://specs.openoffice.org/calc/ease-of-use/redlining_comment.sxw
429
430 if (GetType() == SC_CAT_MOVE)
431 {
432 return ScResId(STR_CHANGED_MOVE_REJECTION_WARNING) + " ";
433 }
434
435 if (IsInsertType())
436 {
437 return ScResId(STR_CHANGED_DELETE_REJECTION_WARNING) + " ";
438 }
439
440 const ScChangeTrack* pCT = GetChangeTrack();
441 if (!pCT)
442 return OUString();
443
445
446 if (!pReject)
447 return OUString();
448
449 if (pReject->GetType() == SC_CAT_MOVE)
450 {
451 return ScResId(STR_CHANGED_MOVE_REJECTION_WARNING) + " ";
452 }
453
454 if (pReject->IsDeleteType())
455 {
456 return ScResId(STR_CHANGED_DELETE_REJECTION_WARNING) + " ";
457 }
458
459 if (!pReject->HasDependent())
460 return OUString();
461
463 pCT->GetDependents( pReject, aMap, false, true );
464 ScChangeActionMap::iterator itChangeAction = std::find_if(aMap.begin(), aMap.end(),
465 [&pReject](const ScChangeActionMap::value_type& rEntry) {
466 return rEntry.second->GetType() == SC_CAT_MOVE || pReject->IsDeleteType(); });
467 if (itChangeAction == aMap.end())
468 return OUString();
469
470 if( itChangeAction->second->GetType() == SC_CAT_MOVE)
471 return ScResId(STR_CHANGED_MOVE_REJECTION_WARNING) + " ";
472 else
473 return ScResId(STR_CHANGED_DELETE_REJECTION_WARNING) + " ";
474}
475
477 const ScBigRange& rRange, const ScDocument& rDoc, bool bFlag3D ) const
478{
479 OUStringBuffer aBuf;
480 ScRefFlags nFlags = ( rRange.IsValid( rDoc ) ? ScRefFlags::VALID : ScRefFlags::ZERO );
481 if ( nFlags == ScRefFlags::ZERO )
483 else
484 {
485 ScRange aTmpRange( rRange.MakeRange( rDoc ) );
486 switch ( GetType() )
487 {
488 case SC_CAT_INSERT_COLS :
489 case SC_CAT_DELETE_COLS :
490 if ( bFlag3D )
491 {
492 OUString aTmp;
493 rDoc.GetName( aTmpRange.aStart.Tab(), aTmp );
494 aBuf.append(aTmp);
495 aBuf.append('.');
496 }
497 aBuf.append(ScColToAlpha(aTmpRange.aStart.Col()));
498 aBuf.append(':');
499 aBuf.append(ScColToAlpha(aTmpRange.aEnd.Col()));
500 break;
501 case SC_CAT_INSERT_ROWS :
502 case SC_CAT_DELETE_ROWS :
503 if ( bFlag3D )
504 {
505 OUString aTmp;
506 rDoc.GetName( aTmpRange.aStart.Tab(), aTmp );
507 aBuf.append(aTmp);
508 aBuf.append('.');
509 }
510 aBuf.append(static_cast<sal_Int64>(aTmpRange.aStart.Row()+1));
511 aBuf.append(':');
512 aBuf.append(static_cast<sal_Int64>(aTmpRange.aEnd.Row()+1));
513 break;
514 default:
515 {
516 if ( bFlag3D || GetType() == SC_CAT_INSERT_TABS )
517 nFlags |= ScRefFlags::TAB_3D;
518
519 aBuf.append(aTmpRange.Format(rDoc, nFlags, rDoc.GetAddressConvention()));
520 }
521 }
522 if ( (bFlag3D && IsDeleteType()) || IsDeletedIn() )
523 {
524 aBuf.insert(0, '(');
525 aBuf.append(')');
526 }
527 }
528 return aBuf.makeStringAndClear();
529}
530
531void ScChangeAction::SetUser( const OUString& r )
532{
533 aUser = r;
534}
535
536void ScChangeAction::SetComment( const OUString& rStr )
537{
538 aComment = rStr;
539}
540
541OUString ScChangeAction::GetRefString( ScDocument& rDoc, bool bFlag3D ) const
542{
543 return GetRefString( GetBigRange(), rDoc, bFlag3D );
544}
545
547{
548 if ( IsVirgin() )
549 {
552 }
553}
554
556{
557 if ( IsVirgin() )
558 {
562 }
563}
564
566 SCCOL nDx, SCROW nDy )
567{
568 // Construct list of Contents
569 std::vector<ScChangeActionContent*> aContentsList;
570 for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() )
571 {
572 ScChangeAction* p = pL->GetAction();
573 if ( p && p->GetType() == SC_CAT_CONTENT )
574 {
575 aContentsList.push_back(static_cast<ScChangeActionContent*>(p) );
576 }
577 }
578 SetState( SC_CAS_REJECTED ); // Before UpdateReference for Move
579 pTrack->UpdateReference( this, true ); // Free LinkDeleted
580 OSL_ENSURE( !pLinkDeleted, "ScChangeAction::RejectRestoreContents: pLinkDeleted != NULL" );
581
582 // Work through list of Contents and delete
583 ScDocument& rDoc = pTrack->GetDocument();
584 for (ScChangeActionContent* pContent : aContentsList)
585 {
586 if ( !pContent->IsDeletedIn() &&
587 pContent->GetBigRange().aStart.IsValid( rDoc ) )
588 pContent->PutNewValueToDoc( &rDoc, nDx, nDy );
589 }
590 DeleteCellEntries(); // Remove generated ones
591}
592
594 const ScChangeTrack* pTrack )
595{
596 if ( nActionNumber )
597 {
598 ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber );
599 OSL_ENSURE( pAct, "ScChangeAction::SetDeletedInThis: missing Action" );
600 if ( pAct )
601 pAct->SetDeletedIn( this );
602 }
603}
604
606 const ScChangeTrack* pTrack )
607{
608 if ( nActionNumber )
609 {
610 ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber );
611 OSL_ENSURE( pAct, "ScChangeAction::AddDependent: missing Action" );
612 if ( pAct )
613 {
615 pAct->AddLink( this, pLink );
616 }
617 }
618}
619
620// ScChangeActionIns
621ScChangeActionIns::ScChangeActionIns( const ScDocument* pDoc, const ScRange& rRange, bool bEndOfList ) :
623 mbEndOfList(bEndOfList)
624{
625 if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == pDoc->MaxCol() )
626 {
629 if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == pDoc->MaxRow() )
630 {
634 }
635 else
637 }
638 else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == pDoc->MaxRow() )
639 {
643 }
644 else
645 {
646 OSL_FAIL( "ScChangeActionIns: Block not supported!" );
647 }
648}
649
651 const sal_uLong nActionNumber, const ScChangeActionState eStateP,
652 const sal_uLong nRejectingNumber, const ScBigRange& aBigRangeP,
653 const OUString& aUserP, const DateTime& aDateTimeP,
654 const OUString& sComment, const ScChangeActionType eTypeP,
655 bool bEndOfList ) :
656 ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
657 mbEndOfList(bEndOfList)
658{
659}
660
662{
663}
664
665OUString ScChangeActionIns::GetDescription( ScDocument& rDoc, bool bSplitRange, bool bWarning ) const
666{
667 OUString str = ScChangeAction::GetDescription( rDoc, bSplitRange, bWarning );
668
669 TranslateId pWhatId;
670 switch ( GetType() )
671 {
672 case SC_CAT_INSERT_COLS :
673 pWhatId = STR_COLUMN;
674 break;
675 case SC_CAT_INSERT_ROWS :
676 pWhatId = STR_ROW;
677 break;
678 default:
679 pWhatId = STR_AREA;
680 }
681
682 OUString aRsc = ScResId(STR_CHANGED_INSERT);
683 sal_Int32 nPos = aRsc.indexOf("#1");
684 if (nPos < 0)
685 return str;
686
687 // Construct a range string to replace '#1' first.
688 OUString aRangeStr = ScResId(pWhatId) +
689 " " +
690 GetRefString(GetBigRange(), rDoc);
691
692 aRsc = aRsc.replaceAt(nPos, 2, aRangeStr); // replace '#1' with the range string.
693
694 return str + aRsc;
695}
696
698{
699 return mbEndOfList;
700}
701
703{
704 if ( !aBigRange.IsValid( rDoc ) )
705 return false;
706
707 ScRange aRange( aBigRange.MakeRange( rDoc ) );
708 if ( !rDoc.IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(),
709 aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) )
710 return false;
711
712 switch ( GetType() )
713 {
714 case SC_CAT_INSERT_COLS :
715 rDoc.DeleteCol( aRange );
716 break;
717 case SC_CAT_INSERT_ROWS :
718 rDoc.DeleteRow( aRange );
719 break;
720 case SC_CAT_INSERT_TABS :
721 rDoc.DeleteTab( aRange.aStart.Tab() );
722 break;
723 default:
724 {
725 // added to avoid warnings
726 }
727 }
730 return true;
731}
732
733// ScChangeActionDel
735 SCCOL nDxP, SCROW nDyP, ScChangeTrack* pTrackP )
736 :
737 ScChangeAction( SC_CAT_NONE, rRange ),
738 pTrack( pTrackP ),
739 pCutOff( nullptr ),
740 nCutOff( 0 ),
741 pLinkMove( nullptr ),
742 nDx( nDxP ),
743 nDy( nDyP )
744{
745 if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == pDoc->MaxCol() )
746 {
749 if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == pDoc->MaxRow() )
750 {
754 }
755 else
757 }
758 else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == pDoc->MaxRow() )
759 {
763 }
764 else
765 {
766 OSL_FAIL( "ScChangeActionDel: Block not supported!" );
767 }
768}
769
771 const sal_uLong nActionNumber, const ScChangeActionState eStateP,
772 const sal_uLong nRejectingNumber, const ScBigRange& aBigRangeP,
773 const OUString& aUserP, const DateTime& aDateTimeP, const OUString &sComment,
774 const ScChangeActionType eTypeP, const SCCOLROW nD, ScChangeTrack* pTrackP) : // which of nDx and nDy is set depends on the type
775 ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
776 pTrack( pTrackP ),
777 pCutOff( nullptr ),
778 nCutOff( 0 ),
779 pLinkMove( nullptr ),
780 nDx( 0 ),
781 nDy( 0 )
782{
784 nDx = static_cast<SCCOL>(nD);
785 else if (eType == SC_CAT_DELETE_ROWS)
786 nDy = static_cast<SCROW>(nD);
787}
788
790{
792 while (pLinkMove)
793 {
794 // coverity[use_after_free] - Moves up by itself
795 delete pLinkMove;
796 }
797}
798
800{
801 mvCells.push_back(pContent);
802}
803
805{
807}
808
810{
811 return !GetDx() && !GetDy();
812}
813
815{
816 const ScChangeAction* p = GetNext();
817 if ( !p || p->GetType() != GetType() )
818 return true;
819 return static_cast<const ScChangeActionDel*>(p)->IsBaseDelete();
820}
821
823{
824 if ( GetDx() || GetDy() )
825 return true;
826 const ScChangeAction* p = GetNext();
827 if ( !p || p->GetType() != GetType() )
828 return false;
829 const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(p);
830 return (pDel->GetDx() > GetDx() || pDel->GetDy() > GetDy()) &&
831 pDel->GetBigRange() == aBigRange;
832}
833
835{
836 if ( GetType() != SC_CAT_DELETE_COLS )
837 return false;
838 const ScChangeAction* p = this;
839 while ( p && p->GetType() == SC_CAT_DELETE_COLS &&
840 !static_cast<const ScChangeActionDel*>(p)->IsTopDelete() )
841 p = p->GetNext();
842 return p && p->GetType() == SC_CAT_DELETE_TABS;
843}
844
846 ScChangeActionMove* pMove, short nFrom, short nTo )
847{
848 return new ScChangeActionDelMoveEntry(&pLinkMove, pMove, nFrom, nTo);
849}
850
852 UpdateRefMode eMode, const ScBigRange& rRange,
853 sal_Int32 nDxP, sal_Int32 nDyP, sal_Int32 nDz )
854{
855 ScRefUpdate::Update( eMode, rRange, nDxP, nDyP, nDz, GetBigRange() );
856
857 if ( !IsDeletedIn() )
858 return ;
859
860 // Correct in the ones who slipped through
861 for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() )
862 {
863 ScChangeAction* p = pL->GetAction();
864 if ( p && p->GetType() == SC_CAT_CONTENT &&
865 !GetBigRange().Contains( p->GetBigRange() ) )
866 {
867 switch ( GetType() )
868 {
869 case SC_CAT_DELETE_COLS :
870 p->GetBigRange().aStart.SetCol( GetBigRange().aStart.Col() );
871 p->GetBigRange().aEnd.SetCol( GetBigRange().aStart.Col() );
872 break;
873 case SC_CAT_DELETE_ROWS :
874 p->GetBigRange().aStart.SetRow( GetBigRange().aStart.Row() );
875 p->GetBigRange().aEnd.SetRow( GetBigRange().aStart.Row() );
876 break;
877 case SC_CAT_DELETE_TABS :
878 p->GetBigRange().aStart.SetTab( GetBigRange().aStart.Tab() );
879 p->GetBigRange().aEnd.SetTab( GetBigRange().aStart.Tab() );
880 break;
881 default:
882 {
883 // added to avoid warnings
884 }
885 }
886 }
887 }
888}
889
891{
892 ScBigRange aTmpRange( GetBigRange() );
893 aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() );
894 aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() );
895 return aTmpRange;
896}
897
898OUString ScChangeActionDel::GetDescription( ScDocument& rDoc, bool bSplitRange, bool bWarning ) const
899{
900 OUString str = ScChangeAction::GetDescription( rDoc, bSplitRange, bWarning );
901
902 TranslateId pWhatId;
903 switch ( GetType() )
904 {
905 case SC_CAT_DELETE_COLS :
906 pWhatId = STR_COLUMN;
907 break;
908 case SC_CAT_DELETE_ROWS :
909 pWhatId = STR_ROW;
910 break;
911 default:
912 pWhatId = STR_AREA;
913 }
914
915 ScBigRange aTmpRange( GetBigRange() );
916 if ( !IsRejected() )
917 {
918 if ( bSplitRange )
919 {
920 aTmpRange.aStart.SetCol( aTmpRange.aStart.Col() + GetDx() );
921 aTmpRange.aStart.SetRow( aTmpRange.aStart.Row() + GetDy() );
922 }
923 aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() );
924 aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() );
925 }
926
927 OUString aRsc = ScResId(STR_CHANGED_DELETE);
928 sal_Int32 nPos = aRsc.indexOf("#1");
929 if (nPos < 0)
930 return str;
931
932 // Build a string to replace with.
933 OUString aRangeStr = ScResId(pWhatId) + " " +
934 GetRefString(aTmpRange, rDoc);
935 aRsc = aRsc.replaceAt(nPos, 2, aRangeStr); // replace '#1' with the string.
936
937 return str + aRsc; // append to the original.
938}
939
941{
942 if ( !aBigRange.IsValid( rDoc ) && GetType() != SC_CAT_DELETE_TABS )
943 return false;
944
945 if ( IsTopDelete() )
946 { // Restore whole section in one go
947 bool bOk = true;
948 ScBigRange aTmpRange( GetOverAllRange() );
949 if ( !aTmpRange.IsValid( rDoc ) )
950 {
951 if ( GetType() == SC_CAT_DELETE_TABS )
952 { // Do we attach a Tab?
953 if ( aTmpRange.aStart.Tab() > rDoc.GetMaxTableNumber() )
954 bOk = false;
955 }
956 else
957 bOk = false;
958 }
959 if ( bOk )
960 {
961 ScRange aRange( aTmpRange.MakeRange( rDoc ) );
962 // InDelete... for formula UpdateReference in Document
963 pTrack->SetInDeleteRange( aRange );
964 pTrack->SetInDeleteTop( true );
965 pTrack->SetInDeleteUndo( true );
966 pTrack->SetInDelete( true );
967 switch ( GetType() )
968 {
969 case SC_CAT_DELETE_COLS :
970 if ( aRange.aStart.Col() != 0 || aRange.aEnd.Col() != rDoc.MaxCol() )
971 { // Only if not TabDelete
972 bOk = rDoc.CanInsertCol( aRange ) && rDoc.InsertCol( aRange );
973 }
974 break;
975 case SC_CAT_DELETE_ROWS :
976 bOk = rDoc.CanInsertRow( aRange ) && rDoc.InsertRow( aRange );
977 break;
978 case SC_CAT_DELETE_TABS :
979 {
980 //TODO: Remember table names?
981 OUString aName;
983 bOk = rDoc.ValidNewTabName( aName ) && rDoc.InsertTab( aRange.aStart.Tab(), aName );
984 }
985 break;
986 default:
987 {
988 // added to avoid warnings
989 }
990 }
991 pTrack->SetInDelete( false );
992 pTrack->SetInDeleteUndo( false );
993 }
994 if ( !bOk )
995 {
996 pTrack->SetInDeleteTop( false );
997 return false;
998 }
999 // Keep InDeleteTop for UpdateReference Undo
1000 }
1001
1002 // Sets rejected and calls UpdateReference-Undo and DeleteCellEntries
1004
1005 pTrack->SetInDeleteTop( false );
1007 return true;
1008}
1009
1011{ // Restore cut off Moves; delete Entries/Links
1012 while ( pLinkMove )
1013 {
1014 // coverity[deref_arg] - the call on delete pLinkMove at the block end Moves a new entry into pLinkMode by itself
1016 short nFrom = pLinkMove->GetCutOffFrom();
1017 short nTo = pLinkMove->GetCutOffTo();
1018 switch ( GetType() )
1019 {
1020 case SC_CAT_DELETE_COLS :
1021 if ( nFrom > 0 )
1022 pMove->GetFromRange().aStart.IncCol( -nFrom );
1023 else if ( nFrom < 0 )
1024 pMove->GetFromRange().aEnd.IncCol( -nFrom );
1025 if ( nTo > 0 )
1026 pMove->GetBigRange().aStart.IncCol( -nTo );
1027 else if ( nTo < 0 )
1028 pMove->GetBigRange().aEnd.IncCol( -nTo );
1029 break;
1030 case SC_CAT_DELETE_ROWS :
1031 if ( nFrom > 0 )
1032 pMove->GetFromRange().aStart.IncRow( -nFrom );
1033 else if ( nFrom < 0 )
1034 pMove->GetFromRange().aEnd.IncRow( -nFrom );
1035 if ( nTo > 0 )
1036 pMove->GetBigRange().aStart.IncRow( -nTo );
1037 else if ( nTo < 0 )
1038 pMove->GetBigRange().aEnd.IncRow( -nTo );
1039 break;
1040 case SC_CAT_DELETE_TABS :
1041 if ( nFrom > 0 )
1042 pMove->GetFromRange().aStart.IncTab( -nFrom );
1043 else if ( nFrom < 0 )
1044 pMove->GetFromRange().aEnd.IncTab( -nFrom );
1045 if ( nTo > 0 )
1046 pMove->GetBigRange().aStart.IncTab( -nTo );
1047 else if ( nTo < 0 )
1048 pMove->GetBigRange().aEnd.IncTab( -nTo );
1049 break;
1050 default:
1051 {
1052 // added to avoid warnings
1053 }
1054 }
1055 delete pLinkMove; // Moves up by itself
1056 }
1057}
1058
1060{ //Restore cut off Insert
1061 if ( !pCutOff )
1062 return;
1063
1064 switch ( pCutOff->GetType() )
1065 {
1066 case SC_CAT_INSERT_COLS :
1067 if ( nCutOff < 0 )
1069 else
1071 break;
1072 case SC_CAT_INSERT_ROWS :
1073 if ( nCutOff < 0 )
1075 else
1077 break;
1078 case SC_CAT_INSERT_TABS :
1079 if ( nCutOff < 0 )
1081 else
1083 break;
1084 default:
1085 {
1086 // added to avoid warnings
1087 }
1088 }
1089 SetCutOffInsert( nullptr, 0 );
1090}
1091
1092// ScChangeActionMove
1094 const sal_uLong nActionNumber, const ScChangeActionState eStateP,
1095 const sal_uLong nRejectingNumber, const ScBigRange& aToBigRange,
1096 const OUString& aUserP, const DateTime& aDateTimeP,
1097 const OUString &sComment, ScBigRange aFromBigRange,
1098 ScChangeTrack* pTrackP) : // which of nDx and nDy is set depends on the type
1099 ScChangeAction(SC_CAT_MOVE, aToBigRange, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
1100 aFromRange(std::move(aFromBigRange)),
1101 pTrack( pTrackP ),
1102 nStartLastCut(0),
1103 nEndLastCut(0)
1104{
1105}
1106
1108{
1110}
1111
1113{
1114 mvCells.push_back(pContent);
1115}
1116
1118{
1120}
1121
1123 UpdateRefMode eMode, const ScBigRange& rRange,
1124 sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
1125{
1126 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aFromRange );
1127 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() );
1128}
1129
1130void ScChangeActionMove::GetDelta( sal_Int32& nDx, sal_Int32& nDy, sal_Int32& nDz ) const
1131{
1132 const ScBigAddress& rToPos = GetBigRange().aStart;
1133 const ScBigAddress& rFromPos = GetFromRange().aStart;
1134 nDx = rToPos.Col() - rFromPos.Col();
1135 nDy = rToPos.Row() - rFromPos.Row();
1136 nDz = rToPos.Tab() - rFromPos.Tab();
1137}
1138
1140 ScDocument& rDoc, bool bSplitRange, bool bWarning ) const
1141{
1142 OUString str = ScChangeAction::GetDescription( rDoc, bSplitRange, bWarning );
1143
1144 bool bFlag3D = GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab();
1145
1146 OUString aRsc = ScResId(STR_CHANGED_MOVE);
1147
1148 OUString aTmpStr = ScChangeAction::GetRefString(GetFromRange(), rDoc, bFlag3D);
1149 sal_Int32 nPos = aRsc.indexOf("#1");
1150 if (nPos >= 0)
1151 {
1152 aRsc = aRsc.replaceAt(nPos, 2, aTmpStr);
1153 nPos += aTmpStr.getLength();
1154 }
1155
1156 aTmpStr = ScChangeAction::GetRefString(GetBigRange(), rDoc, bFlag3D);
1157 nPos = nPos >= 0 ? aRsc.indexOf("#2", nPos) : -1;
1158 if (nPos >= 0)
1159 {
1160 aRsc = aRsc.replaceAt(nPos, 2, aTmpStr);
1161 }
1162
1163 return str + aRsc; // append to the original string.
1164}
1165
1166OUString ScChangeActionMove::GetRefString( ScDocument& rDoc, bool bFlag3D ) const
1167{
1168 if ( !bFlag3D )
1169 bFlag3D = ( GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab() );
1170
1171 return ScChangeAction::GetRefString(GetFromRange(), rDoc, bFlag3D)
1172 + ", "
1173 + ScChangeAction::GetRefString(GetBigRange(), rDoc, bFlag3D);
1174}
1175
1177{
1178 if ( !(aBigRange.IsValid( rDoc ) && aFromRange.IsValid( rDoc )) )
1179 return false;
1180
1181 ScRange aToRange( aBigRange.MakeRange( rDoc ) );
1182 ScRange aFrmRange( aFromRange.MakeRange( rDoc ) );
1183
1184 bool bOk = rDoc.IsBlockEditable( aToRange.aStart.Tab(),
1185 aToRange.aStart.Col(), aToRange.aStart.Row(),
1186 aToRange.aEnd.Col(), aToRange.aEnd.Row() );
1187 if ( bOk )
1188 bOk = rDoc.IsBlockEditable( aFrmRange.aStart.Tab(),
1189 aFrmRange.aStart.Col(), aFrmRange.aStart.Row(),
1190 aFrmRange.aEnd.Col(), aFrmRange.aEnd.Row() );
1191 if ( !bOk )
1192 return false;
1193
1194 pTrack->LookUpContents( aToRange, &rDoc, 0, 0, 0 ); // Contents to be moved
1195
1196 rDoc.DeleteAreaTab( aToRange, InsertDeleteFlags::ALL );
1197 rDoc.DeleteAreaTab( aFrmRange, InsertDeleteFlags::ALL );
1198 // Adjust formula in the Document
1199 sc::RefUpdateContext aCxt(rDoc);
1200 aCxt.meMode = URM_MOVE;
1201 aCxt.maRange = aFrmRange;
1202 aCxt.mnColDelta = aFrmRange.aStart.Col() - aToRange.aStart.Col();
1203 aCxt.mnRowDelta = aFrmRange.aStart.Row() - aToRange.aStart.Row();
1204 aCxt.mnTabDelta = aFrmRange.aStart.Tab() - aToRange.aStart.Tab();
1205 rDoc.UpdateReference(aCxt);
1206
1207 // Free LinkDependent, set succeeding UpdateReference Undo
1208 // ToRange->FromRange Dependents
1210
1211 // Sets rejected and calls UpdateReference Undo and DeleteCellEntries
1213
1214 while ( pLinkDependent )
1215 {
1217 if ( p && p->GetType() == SC_CAT_CONTENT )
1218 {
1219 ScChangeActionContent* pContent = static_cast<ScChangeActionContent*>(p);
1220 if ( !pContent->IsDeletedIn() &&
1221 pContent->GetBigRange().aStart.IsValid( rDoc ) )
1222 pContent->PutNewValueToDoc( &rDoc, 0, 0 );
1223 // Delete the ones created in LookUpContents
1224 if ( pTrack->IsGenerated( pContent->GetActionNumber() ) &&
1225 !pContent->IsDeletedIn() )
1226 {
1227 pLinkDependent->UnLink(); // Else this one is also deleted!
1228 pTrack->DeleteGeneratedDelContent( pContent );
1229 }
1230 }
1231 delete pLinkDependent;
1232 }
1233
1235 return true;
1236}
1237
1240 pNextContent(nullptr),
1241 pPrevContent(nullptr),
1242 pNextInSlot(nullptr),
1243 ppPrevInSlot(nullptr)
1244{}
1245
1247 const ScChangeActionState eStateP, const sal_uLong nRejectingNumber,
1248 const ScBigRange& aBigRangeP, const OUString& aUserP,
1249 const DateTime& aDateTimeP, const OUString& sComment,
1250 ScCellValue aOldCell, const ScDocument* pDoc, const OUString& sOldValue ) :
1251 ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment),
1252 maOldCell(std::move(aOldCell)),
1253 maOldValue(sOldValue),
1254 pNextContent(nullptr),
1255 pPrevContent(nullptr),
1256 pNextInSlot(nullptr),
1257 ppPrevInSlot(nullptr)
1258{
1259 if (!maOldCell.isEmpty())
1260 SetCell(maOldValue, maOldCell, 0, pDoc);
1261
1262 if (!sOldValue.isEmpty()) // #i40704# don't overwrite SetCell result with empty string
1263 maOldValue = sOldValue; // set again, because SetCell removes it
1264}
1265
1267 ScCellValue aNewCell, const ScBigRange& aBigRangeP,
1268 const ScDocument* pDoc, const OUString& sNewValue ) :
1269 ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber),
1270 maNewCell(std::move(aNewCell)),
1271 maNewValue(sNewValue),
1272 pNextContent(nullptr),
1273 pPrevContent(nullptr),
1274 pNextInSlot(nullptr),
1275 ppPrevInSlot(nullptr)
1276{
1277 if (!maNewCell.isEmpty())
1278 SetCell(maNewValue, maNewCell, 0, pDoc);
1279
1280 if (!sNewValue.isEmpty()) // #i40704# don't overwrite SetCell result with empty string
1281 maNewValue = sNewValue; // set again, because SetCell removes it
1282}
1283
1285{
1286 ClearTrack();
1287}
1288
1290{
1292 if ( pPrevContent )
1294 if ( pNextContent )
1296}
1297
1299{
1300 if ( pNextContent )
1301 {
1303 while ( pContent->pNextContent && pContent != pContent->pNextContent )
1304 pContent = pContent->pNextContent;
1305 return pContent;
1306 }
1307 return const_cast<ScChangeActionContent*>(this);
1308}
1309
1311{
1312 if ( pNextContent )
1313 return GetTopContent()->pLinkDeletedIn;
1314 return pLinkDeletedIn;
1315}
1316
1318{
1319 if ( pNextContent )
1321 return &pLinkDeletedIn;
1322}
1323
1325 const ScCellValue& rCell, const ScDocument* pFromDoc, ScDocument* pToDoc, sal_uLong nFormat )
1326{
1327 SetValue(maOldValue, maOldCell, nFormat, rCell, pFromDoc, pToDoc);
1328}
1329
1331 const ScCellValue& rCell, const ScDocument* pFromDoc, ScDocument* pToDoc )
1332{
1333 SetValue(maOldValue, maOldCell, aBigRange.aStart.MakeAddress(*pFromDoc), rCell, pFromDoc, pToDoc);
1334}
1335
1337{
1338 SetValue(maNewValue, maNewCell, aBigRange.aStart.MakeAddress(*pDoc), rCell, pDoc, pDoc);
1339}
1340
1342 const ScCellValue& rOldCell, sal_uLong nOldFormat, const ScCellValue& rNewCell,
1343 sal_uLong nNewFormat, const ScDocument* pDoc )
1344{
1345 maOldCell = rOldCell;
1346 maNewCell = rNewCell;
1347 SetCell(maOldValue, maOldCell, nOldFormat, pDoc);
1348 SetCell(maNewValue, maNewCell, nNewFormat, pDoc);
1349}
1350
1352 const ScCellValue& rCell, const ScDocument* pDoc, const OUString& rFormatted )
1353{
1354 maNewCell = rCell;
1355 SetCell(maNewValue, maNewCell, 0, pDoc);
1356
1357 // #i40704# allow to set formatted text here - don't call SetNewValue with string from XML filter
1358 if (!rFormatted.isEmpty())
1359 maNewValue = rFormatted;
1360}
1361
1363 OUString& rValue, ScCellValue& rCell, const OUString& rStr, ScDocument* pDoc )
1364{
1365 rCell.clear();
1366 if ( rStr.getLength() > 1 && rStr[0] == '=' )
1367 {
1368 rValue.clear();
1369 rCell.set(new ScFormulaCell(
1370 *pDoc, aBigRange.aStart.MakeAddress(*pDoc), rStr,
1371 pDoc->GetGrammar() ));
1372 rCell.getFormula()->SetInChangeTrack(true);
1373 }
1374 else
1375 rValue = rStr;
1376}
1377
1378void ScChangeActionContent::SetOldValue( const OUString& rOld, ScDocument* pDoc )
1379{
1380 SetValueString(maOldValue, maOldCell, rOld, pDoc);
1381}
1382
1384{
1385 return GetValueString(maOldValue, maOldCell, pDoc);
1386}
1387
1389{
1390 return GetValueString(maNewValue, maNewCell, pDoc);
1391}
1392
1394 ScDocument& rDoc, bool bSplitRange, bool bWarning ) const
1395{
1396 OUString str = ScChangeAction::GetDescription( rDoc, bSplitRange, bWarning );
1397
1398 OUString aRsc = ScResId(STR_CHANGED_CELL);
1399
1400 OUString aTmpStr = GetRefString(rDoc);
1401
1402 sal_Int32 nPos = aRsc.indexOf("#1", 0);
1403 if (nPos >= 0)
1404 {
1405 aRsc = aRsc.replaceAt(nPos, 2, aTmpStr);
1406 nPos += aTmpStr.getLength();
1407 }
1408
1409 aTmpStr = GetOldString( &rDoc );
1410 if (aTmpStr.isEmpty())
1411 aTmpStr = ScResId( STR_CHANGED_BLANK );
1412
1413 nPos = nPos >= 0 ? aRsc.indexOf("#2", nPos) : -1;
1414 if (nPos >= 0)
1415 {
1416 aRsc = aRsc.replaceAt(nPos, 2, aTmpStr);
1417 nPos += aTmpStr.getLength();
1418 }
1419
1420 aTmpStr = GetNewString( &rDoc );
1421 if (aTmpStr.isEmpty())
1422 aTmpStr = ScResId( STR_CHANGED_BLANK );
1423
1424 nPos = nPos >= 0 ? aRsc.indexOf("#3", nPos) : -1;
1425 if (nPos >= 0)
1426 {
1427 aRsc = aRsc.replaceAt(nPos, 2, aTmpStr);
1428 }
1429
1430 return str + aRsc; // append to the original string.
1431}
1432
1434 ScDocument& rDoc, bool bFlag3D ) const
1435{
1437 if ( nFlags != ScRefFlags::ZERO )
1438 {
1439 const ScCellValue& rCell = GetNewCell();
1440 if ( GetContentCellType(rCell) == SC_CACCT_MATORG )
1441 {
1442 ScBigRange aLocalBigRange( GetBigRange() );
1443 SCCOL nC;
1444 SCROW nR;
1445 rCell.getFormula()->GetMatColsRows( nC, nR );
1446 aLocalBigRange.aEnd.IncCol( nC-1 );
1447 aLocalBigRange.aEnd.IncRow( nR-1 );
1448 return ScChangeAction::GetRefString( aLocalBigRange, rDoc, bFlag3D );
1449 }
1450
1451 ScAddress aTmpAddress( GetBigRange().aStart.MakeAddress( rDoc ) );
1452 if ( bFlag3D )
1453 nFlags |= ScRefFlags::TAB_3D;
1454 OUString str = aTmpAddress.Format(nFlags, &rDoc, rDoc.GetAddressConvention());
1455 if ( IsDeletedIn() )
1456 {
1457 // Insert the parentheses.
1458 str = "(" + str + ")";
1459 }
1460 return str;
1461 }
1462 else
1464}
1465
1467{
1468 if ( !aBigRange.IsValid( rDoc ) )
1469 return false;
1470
1471 PutOldValueToDoc( &rDoc, 0, 0 );
1472
1475
1476 return true;
1477}
1478
1480 bool bOldest, ::std::stack<ScChangeActionContent*>* pRejectActions )
1481{
1482 if ( !aBigRange.IsValid( rDoc ) )
1483 return false;
1484
1485 ScChangeActionContent* pContent = this;
1486 // accept previous contents
1487 while ( ( pContent = pContent->pPrevContent ) != nullptr )
1488 {
1489 if ( pContent->IsVirgin() )
1490 pContent->SetState( SC_CAS_ACCEPTED );
1491 }
1492 ScChangeActionContent* pEnd = pContent = this;
1493 // reject subsequent contents
1494 while ( ( pContent = pContent->pNextContent ) != nullptr )
1495 {
1496 // MatrixOrigin may have dependents, no dependency recursion needed
1497 const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry();
1498 while ( pL )
1499 {
1500 ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction());
1501 if ( p )
1502 p->SetRejected();
1503 pL = pL->GetNext();
1504 }
1505 pContent->SetRejected();
1506 pEnd = pContent;
1507 }
1508
1509 // If not oldest: Is it anyone else than the last one?
1510 if ( bOldest || pEnd != this )
1511 { ScRange aRange( aBigRange.aStart.MakeAddress( rDoc ) );
1512 const ScAddress& rPos = aRange.aStart;
1513
1514 ScChangeActionContent* pNew = new ScChangeActionContent( aRange );
1515 ScCellValue aCell;
1516 aCell.assign(rDoc, rPos);
1517 pNew->SetOldValue(aCell, &rDoc, &rDoc);
1518
1519 if ( bOldest )
1520 PutOldValueToDoc( &rDoc, 0, 0 );
1521 else
1522 PutNewValueToDoc( &rDoc, 0, 0 );
1523
1524 pNew->SetRejectAction( bOldest ? GetActionNumber() : pEnd->GetActionNumber() );
1525 pNew->SetState( SC_CAS_ACCEPTED );
1526 if ( pRejectActions )
1527 pRejectActions->push( pNew );
1528 else
1529 {
1530 aCell.assign(rDoc, rPos);
1531 pNew->SetNewValue(aCell, &rDoc);
1532 pTrack->Append( pNew );
1533 }
1534 }
1535
1536 if ( bOldest )
1537 SetRejected();
1538 else
1540
1541 return true;
1542}
1543
1545 const ScCellValue& rCell, const ScDocument* pDoc, const ScAddress& rPos )
1546{
1547 if (NeedsNumberFormat(rCell))
1548 return GetStringOfCell(rCell, pDoc, pDoc->GetNumberFormat(rPos));
1549 else
1550 return GetStringOfCell(rCell, pDoc, 0);
1551}
1552
1554 const ScCellValue& rCell, const ScDocument* pDoc, sal_uLong nFormat )
1555{
1556 if (!GetContentCellType(rCell))
1557 return OUString();
1558
1559 switch (rCell.getType())
1560 {
1561 case CELLTYPE_VALUE:
1562 {
1563 OUString str;
1564 pDoc->GetFormatTable()->GetInputLineString(rCell.getDouble(), nFormat, str);
1565 return str;
1566 }
1567 case CELLTYPE_STRING:
1568 return rCell.getSharedString()->getString();
1569 case CELLTYPE_EDIT:
1570 if (rCell.getEditText())
1571 return ScEditUtil::GetString(*rCell.getEditText(), pDoc);
1572 return OUString();
1573 case CELLTYPE_FORMULA:
1574 return rCell.getFormula()->GetFormula();
1575 default:
1576 return OUString();
1577 }
1578}
1579
1581{
1582 switch (rCell.getType())
1583 {
1584 case CELLTYPE_VALUE :
1585 case CELLTYPE_STRING :
1586 case CELLTYPE_EDIT :
1587 return SC_CACCT_NORMAL;
1588 case CELLTYPE_FORMULA :
1589 switch (rCell.getFormula()->GetMatrixFlag())
1590 {
1591 case ScMatrixMode::NONE :
1592 return SC_CACCT_NORMAL;
1594 return SC_CACCT_MATORG;
1596 return SC_CACCT_MATREF;
1597 }
1598 return SC_CACCT_NORMAL;
1599 default:
1600 return SC_CACCT_NONE;
1601 }
1602}
1603
1605{
1606 switch (rCell.getType())
1607 {
1608 case CELLTYPE_VALUE:
1609 case CELLTYPE_STRING:
1610 case CELLTYPE_EDIT:
1611 return SC_CACCT_NORMAL;
1612 case CELLTYPE_FORMULA:
1613 {
1614 const ScFormulaCell* pCell = rCell.getFormula();
1615 switch (pCell->GetMatrixFlag())
1616 {
1617 case ScMatrixMode::NONE :
1618 return SC_CACCT_NORMAL;
1620 return SC_CACCT_MATORG;
1622 return SC_CACCT_MATREF;
1623 }
1624 return SC_CACCT_NORMAL;
1625 }
1626 default:
1627 ;
1628 }
1629
1630 return SC_CACCT_NONE;
1631}
1632
1634{
1635 return rVal.getType() == CELLTYPE_VALUE;
1636}
1637
1639 OUString& rStr, ScCellValue& rCell, const ScAddress& rPos, const ScCellValue& rOrgCell,
1640 const ScDocument* pFromDoc, ScDocument* pToDoc )
1641{
1642 sal_uInt32 nFormat = NeedsNumberFormat(rOrgCell) ? pFromDoc->GetNumberFormat(rPos) : 0;
1643 SetValue(rStr, rCell, nFormat, rOrgCell, pFromDoc, pToDoc);
1644}
1645
1647 OUString& rStr, ScCellValue& rCell, sal_uLong nFormat, const ScCellValue& rOrgCell,
1648 const ScDocument* pFromDoc, ScDocument* pToDoc )
1649{
1650 rStr.clear();
1651
1652 if (GetContentCellType(rOrgCell))
1653 {
1654 rCell.assign(rOrgCell, *pToDoc);
1655 switch (rOrgCell.getType())
1656 {
1657 case CELLTYPE_VALUE :
1658 { // E.g.: Remember date as such
1660 rOrgCell.getDouble(), nFormat, rStr);
1661 }
1662 break;
1663 case CELLTYPE_FORMULA :
1664 rCell.getFormula()->SetInChangeTrack(true);
1665 break;
1666 default:
1667 {
1668 // added to avoid warnings
1669 }
1670 }
1671 }
1672 else
1673 rCell.clear();
1674}
1675
1676void ScChangeActionContent::SetCell( OUString& rStr, ScCellValue& rCell, sal_uLong nFormat, const ScDocument* pDoc )
1677{
1678 rStr.clear();
1679 if (rCell.isEmpty())
1680 return;
1681
1682 switch (rCell.getType())
1683 {
1684 case CELLTYPE_VALUE :
1685 // e.g. remember date as date string
1686 pDoc->GetFormatTable()->GetInputLineString(rCell.getDouble(), nFormat, rStr);
1687 break;
1688 case CELLTYPE_FORMULA :
1689 rCell.getFormula()->SetInChangeTrack(true);
1690 break;
1691 default:
1692 {
1693 // added to avoid warnings
1694 }
1695 }
1696}
1697
1699 const OUString& rValue, const ScCellValue& rCell, const ScDocument* pDoc ) const
1700{
1701 if (!rValue.isEmpty())
1702 {
1703 return rValue;
1704 }
1705
1706 switch (rCell.getType())
1707 {
1708 case CELLTYPE_STRING :
1709 return rCell.getSharedString()->getString();
1710 case CELLTYPE_EDIT :
1711 if (rCell.getEditText())
1712 return ScEditUtil::GetString(*rCell.getEditText(), pDoc);
1713 return OUString();
1714 case CELLTYPE_VALUE : // Is always in rValue
1715 return rValue;
1716 case CELLTYPE_FORMULA :
1717 return GetFormulaString(rCell.getFormula());
1718 case CELLTYPE_NONE:
1719 default:
1720 return OUString();
1721 }
1722}
1723
1725 const ScFormulaCell* pCell ) const
1726{
1728 if ( aPos == pCell->aPos || IsDeletedIn() )
1729 return pCell->GetFormula();
1730 else
1731 {
1732 OSL_FAIL( "ScChangeActionContent::GetFormulaString: aPos != pCell->aPos" );
1733 ScFormulaCell aNew( *pCell, pCell->GetDocument(), aPos );
1734 return aNew.GetFormula();
1735 }
1736}
1737
1739 SCCOL nDx, SCROW nDy ) const
1740{
1741 PutValueToDoc(maOldCell, maOldValue, pDoc, nDx, nDy);
1742}
1743
1745 SCCOL nDx, SCROW nDy ) const
1746{
1747 PutValueToDoc(maNewCell, maNewValue, pDoc, nDx, nDy);
1748}
1749
1751 const ScCellValue& rCell, const OUString& rValue, ScDocument* pDoc,
1752 SCCOL nDx, SCROW nDy ) const
1753{
1754 ScAddress aPos( aBigRange.aStart.MakeAddress( *pDoc ) );
1755 if ( nDx )
1756 aPos.IncCol( nDx );
1757 if ( nDy )
1758 aPos.IncRow( nDy );
1759
1760 if (!rValue.isEmpty())
1761 {
1762 pDoc->SetString(aPos, rValue);
1763 return;
1764 }
1765
1766 if (rCell.isEmpty())
1767 {
1768 pDoc->SetEmptyCell(aPos);
1769 return;
1770 }
1771
1772 if (rCell.getType() == CELLTYPE_VALUE)
1773 {
1774 pDoc->SetString( aPos.Col(), aPos.Row(), aPos.Tab(), rValue );
1775 return;
1776 }
1777
1778 switch (GetContentCellType(rCell))
1779 {
1780 case SC_CACCT_MATORG :
1781 {
1782 SCCOL nC;
1783 SCROW nR;
1784 rCell.getFormula()->GetMatColsRows(nC, nR);
1785 OSL_ENSURE( nC>0 && nR>0, "ScChangeActionContent::PutValueToDoc: MatColsRows?" );
1786 ScRange aRange( aPos );
1787 if ( nC > 1 )
1788 aRange.aEnd.IncCol( nC-1 );
1789 if ( nR > 1 )
1790 aRange.aEnd.IncRow( nR-1 );
1791 ScMarkData aDestMark(pDoc->GetSheetLimits());
1792 aDestMark.SelectOneTable( aPos.Tab() );
1793 aDestMark.SetMarkArea( aRange );
1794 pDoc->InsertMatrixFormula( aPos.Col(), aPos.Row(),
1795 aRange.aEnd.Col(), aRange.aEnd.Row(),
1796 aDestMark, OUString(), rCell.getFormula()->GetCode());
1797 }
1798 break;
1799 case SC_CACCT_MATREF :
1800 // nothing
1801 break;
1802 default:
1803 rCell.commit(*pDoc, aPos);
1804 }
1805}
1806
1807static void lcl_InvalidateReference( const ScDocument& rDoc, formula::FormulaToken& rTok, const ScBigAddress& rPos )
1808{
1809 ScSingleRefData& rRef1 = *rTok.GetSingleRef();
1810 if ( rPos.Col() < 0 || rDoc.MaxCol() < rPos.Col() )
1811 {
1812 rRef1.SetColDeleted( true );
1813 }
1814 if ( rPos.Row() < 0 || rDoc.MaxRow() < rPos.Row() )
1815 {
1816 rRef1.SetRowDeleted( true );
1817 }
1818 if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() )
1819 {
1820 rRef1.SetTabDeleted( true );
1821 }
1822 if ( rTok.GetType() != formula::svDoubleRef )
1823 return;
1824
1825 ScSingleRefData& rRef2 = rTok.GetDoubleRef()->Ref2;
1826 if ( rPos.Col() < 0 || rDoc.MaxCol() < rPos.Col() )
1827 {
1828 rRef2.SetColDeleted( true );
1829 }
1830 if ( rPos.Row() < 0 || rDoc.MaxRow() < rPos.Row() )
1831 {
1832 rRef2.SetRowDeleted( true );
1833 }
1834 if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() )
1835 {
1836 rRef2.SetTabDeleted( true );
1837 }
1838}
1839
1841 UpdateRefMode eMode, const ScBigRange& rRange,
1842 sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz )
1843{
1844 SCSIZE nOldSlot = pTrack->ComputeContentSlot( aBigRange.aStart.Row() );
1845 ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aBigRange );
1846 SCSIZE nNewSlot = pTrack->ComputeContentSlot( aBigRange.aStart.Row() );
1847 if ( nNewSlot != nOldSlot )
1848 {
1850 InsertInSlot( &(pTrack->GetContentSlots()[nNewSlot]) );
1851 }
1852
1853 if ( pTrack->IsInDelete() && !pTrack->IsInDeleteTop() )
1854 return ; // Formula only update whole range
1855
1856 bool bOldFormula = maOldCell.getType() == CELLTYPE_FORMULA;
1857 bool bNewFormula = maNewCell.getType() == CELLTYPE_FORMULA;
1858 if ( !(bOldFormula || bNewFormula) )
1859 return;
1860
1861// Adjust UpdateReference via ScFormulaCell (there)
1862 if ( pTrack->IsInDelete() )
1863 {
1864 const ScRange& rDelRange = pTrack->GetInDeleteRange();
1865 if ( nDx > 0 )
1866 nDx = rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1;
1867 else if ( nDx < 0 )
1868 nDx = -(rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1);
1869 if ( nDy > 0 )
1870 nDy = rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1;
1871 else if ( nDy < 0 )
1872 nDy = -(rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1);
1873 if ( nDz > 0 )
1874 nDz = rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1;
1875 else if ( nDz < 0 )
1876 nDz = -(rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1);
1877 }
1878 ScBigRange aTmpRange( rRange );
1879 switch ( eMode )
1880 {
1881 case URM_INSDEL :
1882 if ( nDx < 0 || nDy < 0 || nDz < 0 )
1883 { // Delete starts there after removed range
1884 // Position is changed there
1885 if ( nDx )
1886 aTmpRange.aStart.IncCol( -nDx );
1887 if ( nDy )
1888 aTmpRange.aStart.IncRow( -nDy );
1889 if ( nDz )
1890 aTmpRange.aStart.IncTab( -nDz );
1891 }
1892 break;
1893 case URM_MOVE :
1894 // Move is Source here and Target there
1895 // Position needs to be adjusted before that
1896 if ( bOldFormula )
1898 if ( bNewFormula )
1900 if ( nDx )
1901 {
1902 aTmpRange.aStart.IncCol( nDx );
1903 aTmpRange.aEnd.IncCol( nDx );
1904 }
1905 if ( nDy )
1906 {
1907 aTmpRange.aStart.IncRow( nDy );
1908 aTmpRange.aEnd.IncRow( nDy );
1909 }
1910 if ( nDz )
1911 {
1912 aTmpRange.aStart.IncTab( nDz );
1913 aTmpRange.aEnd.IncTab( nDz );
1914 }
1915 break;
1916 default:
1917 {
1918 // added to avoid warnings
1919 }
1920 }
1921 ScRange aRange( aTmpRange.MakeRange(pTrack->GetDocument()) );
1922
1923 sc::RefUpdateContext aRefCxt(pTrack->GetDocument());
1924 aRefCxt.meMode = eMode;
1925 aRefCxt.maRange = aRange;
1926 aRefCxt.mnColDelta = nDx;
1927 aRefCxt.mnRowDelta = nDy;
1928 aRefCxt.mnTabDelta = nDz;
1929
1930 if ( bOldFormula )
1932 if ( bNewFormula )
1934
1935 if ( aBigRange.aStart.IsValid( pTrack->GetDocument() ) )
1936 return;
1937
1938//FIXME:
1939 // UpdateReference cannot handle positions outside of the Document.
1940 // Therefore set everything to #REF!
1941 //TODO: Remove the need for this hack! This means big changes to ScAddress etc.!
1942 const ScBigAddress& rPos = aBigRange.aStart;
1943 if ( bOldFormula )
1944 {
1948 while ( ( t = aIter.GetNextReference() ) != nullptr )
1949 lcl_InvalidateReference( pTrack->GetDocument(), *t, rPos );
1950 aIter.Reset();
1951 while ( ( t = aIter.GetNextReferenceRPN() ) != nullptr )
1952 lcl_InvalidateReference( pTrack->GetDocument(), *t, rPos );
1953 }
1954 if ( bNewFormula )
1955 {
1959 while ( ( t = aIter.GetNextReference() ) != nullptr )
1960 lcl_InvalidateReference( pTrack->GetDocument(), *t, rPos );
1961 aIter.Reset();
1962 while ( ( t = aIter.GetNextReferenceRPN() ) != nullptr )
1963 lcl_InvalidateReference( pTrack->GetDocument(), *t, rPos );
1964 }
1965}
1966
1968{
1970}
1971
1973{
1975}
1976
1977// ScChangeActionReject
1979 const sal_uLong nActionNumber, const ScChangeActionState eStateP,
1980 const sal_uLong nRejectingNumber,
1981 const ScBigRange& aBigRangeP, const OUString& aUserP,
1982 const DateTime& aDateTimeP, const OUString& sComment) :
1983 ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment)
1984{
1985}
1986
1988{
1989 return false;
1990}
1991
1993{
1994 if ( nRow < 0 || nRow > rDoc.GetSheetLimits().mnMaxRow )
1995 return mnContentSlots - 1;
1996 return static_cast< SCSIZE >( nRow / mnContentRowsPerSlot );
1997}
1998
2000{
2001 const SCSIZE nMaxSlots = 0xffe0 / sizeof( ScChangeActionContent* ) - 2;
2002 SCROW nRowsPerSlot = rDoc.GetMaxRowCount() / nMaxSlots;
2003 if ( nRowsPerSlot * nMaxSlots < sal::static_int_cast<SCSIZE>(rDoc.GetMaxRowCount()) )
2004 ++nRowsPerSlot;
2005 return nRowsPerSlot;
2006}
2007
2009 aFixDateTime( DateTime::SYSTEM ),
2010 rDoc( rDocP )
2011{
2012 Init();
2013 SC_MOD()->GetUserOptions().AddListener(this);
2014
2016 memset( ppContentSlots.get(), 0, mnContentSlots * sizeof( ScChangeActionContent* ) );
2017}
2018
2019ScChangeTrack::ScChangeTrack( ScDocument& rDocP, std::set<OUString>&& aTempUserCollection) :
2020 maUserCollection(std::move(aTempUserCollection)),
2021 aFixDateTime( DateTime::SYSTEM ),
2022 rDoc( rDocP )
2023{
2024 Init();
2025 SC_MOD()->GetUserOptions().AddListener(this);
2027 memset( ppContentSlots.get(), 0, mnContentSlots * sizeof( ScChangeActionContent* ) );
2028}
2029
2031{
2032 SC_MOD()->GetUserOptions().RemoveListener(this);
2033 DtorClear();
2034}
2035
2037{
2040
2041 pFirst = nullptr;
2042 pLast = nullptr;
2043 pFirstGeneratedDelContent = nullptr;
2044 pLastCutMove = nullptr;
2045 pLinkInsertCol = nullptr;
2046 pLinkInsertRow = nullptr;
2047 pLinkInsertTab = nullptr;
2048 pLinkMove = nullptr;
2049 xBlockModifyMsg.reset();
2050 nActionMax = 0;
2052 nMarkLastSaved = 0;
2053 nStartLastCut = 0;
2054 nEndLastCut = 0;
2055 nLastMerge = 0;
2057 bInDelete = false;
2058 bInDeleteTop = false;
2059 bInDeleteUndo = false;
2060 bInPasteCut = false;
2061 bUseFixDateTime = false;
2062 bTimeNanoSeconds = true;
2063
2064 const SvtUserOptions& rUserOpt = SC_MOD()->GetUserOptions();
2065 maUser = rUserOpt.GetFirstName() + " " + rUserOpt.GetLastName();
2066 maUserCollection.insert(maUser);
2067}
2068
2070{
2072 ScChangeAction* pNext;
2073 for ( p = GetFirst(); p; p = pNext )
2074 {
2075 pNext = p->GetNext();
2076 delete p;
2077 }
2078 for ( p = pFirstGeneratedDelContent; p; p = pNext )
2079 {
2080 pNext = p->GetNext();
2081 delete p;
2082 }
2083 for( const auto& rEntry : aPasteCutMap )
2084 {
2085 delete rEntry.second;
2086 }
2087 pLastCutMove.reset();
2088 ClearMsgQueue();
2089}
2090
2092{
2093 xBlockModifyMsg.reset();
2094 aMsgStackTmp.clear();
2095 aMsgStackFinal.clear();
2096 aMsgQueue.clear();
2097}
2098
2100{
2101 DtorClear();
2102 aMap.clear();
2103 aGeneratedMap.clear();
2104 aPasteCutMap.clear();
2105 maUserCollection.clear();
2106 maUser.clear();
2107 Init();
2108}
2109
2111{
2112 return nAction >= nGeneratedMin;
2113}
2114
2116{
2117 ScChangeActionMap::const_iterator it = aMap.find( nAction );
2118 if( it != aMap.end() )
2119 return it->second;
2120 else
2121 return nullptr;
2122}
2123
2125{
2126 ScChangeActionMap::const_iterator it = aGeneratedMap.find( nGenerated );
2127 if( it != aGeneratedMap.end() )
2128 return it->second;
2129 else
2130 return nullptr;
2131}
2132
2134{
2135 return IsGenerated( nAction ) ?
2136 GetGenerated( nAction ) :
2137 GetAction( nAction );
2138}
2140{
2141 return nMarkLastSaved;
2142}
2143
2145{
2146 nMarkLastSaved = nNew;
2147}
2148
2150{
2151 ScChangeActionMap::const_iterator it = aMap.find( nMarkLastSaved );
2152 if( it != aMap.end() )
2153 return it->second;
2154 else
2155 return nullptr;
2156}
2157
2159{
2160 if ( rDoc.IsInDtorClear() )
2161 return;
2162
2163 const SvtUserOptions& rUserOptions = SC_MOD()->GetUserOptions();
2164 size_t nOldCount = maUserCollection.size();
2165
2166 SetUser(rUserOptions.GetFirstName() + " " + rUserOptions.GetLastName());
2167
2168 if ( maUserCollection.size() != nOldCount )
2169 {
2170 // New user in collection -> have to repaint because
2171 // colors may be different now (#106697#).
2172 // (Has to be done in the Notify handler, to be sure
2173 // the user collection has already been updated)
2174
2176 if (pDocSh)
2177 pDocSh->Broadcast( ScPaintHint( ScRange(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB), PaintPartFlags::Grid ) );
2178 }
2179}
2180
2181void ScChangeTrack::SetUser( const OUString& rUser )
2182{
2183 maUser = rUser;
2184 maUserCollection.insert(maUser);
2185}
2186
2188 sal_uLong nStartAction )
2189{
2190 if ( aModifiedLink.IsSet() )
2191 {
2192 if ( xBlockModifyMsg )
2193 aMsgStackTmp.push_back( *xBlockModifyMsg ); // Block in Block
2195 xBlockModifyMsg->eMsgType = eMsgType;
2196 xBlockModifyMsg->nStartAction = nStartAction;
2197 xBlockModifyMsg->nEndAction = 0;
2198 }
2199}
2200
2202{
2203 if ( !aModifiedLink.IsSet() )
2204 return;
2205
2206 if ( xBlockModifyMsg )
2207 {
2208 if ( xBlockModifyMsg->nStartAction <= nEndAction )
2209 {
2210 xBlockModifyMsg->nEndAction = nEndAction;
2211 // Blocks dissolved in Blocks
2212 aMsgStackFinal.push_back( *xBlockModifyMsg );
2213 }
2214 else
2215 xBlockModifyMsg.reset();
2216 if (aMsgStackTmp.empty())
2217 xBlockModifyMsg.reset();
2218 else
2219 {
2220 xBlockModifyMsg = aMsgStackTmp.back(); // Maybe Block in Block
2221 aMsgStackTmp.pop_back();
2222 }
2223 }
2224 if ( !xBlockModifyMsg )
2225 {
2226 bool bNew = !aMsgStackFinal.empty();
2227 aMsgQueue.reserve(aMsgQueue.size() + aMsgStackFinal.size());
2228 aMsgQueue.insert(aMsgQueue.end(), aMsgStackFinal.rbegin(), aMsgStackFinal.rend());
2229 aMsgStackFinal.clear();
2230 if ( bNew )
2231 aModifiedLink.Call( *this );
2232 }
2233}
2234
2236{
2237 return aMsgQueue;
2238}
2239
2241 sal_uLong nStartAction, sal_uLong nEndAction )
2242{
2243 if ( aModifiedLink.IsSet() )
2244 {
2245 if ( !xBlockModifyMsg || xBlockModifyMsg->eMsgType != eMsgType ||
2246 (IsGenerated( nStartAction ) &&
2247 (eMsgType == ScChangeTrackMsgType::Append || eMsgType == ScChangeTrackMsgType::Remove)) )
2248 { // Append within Append e.g. not
2249 StartBlockModify( eMsgType, nStartAction );
2250 EndBlockModify( nEndAction );
2251 }
2252 }
2253}
2254
2256{
2257 ScChangeActionType eType = pAppend->GetType();
2258
2259 if ( eType == SC_CAT_CONTENT )
2260 {
2261 if ( !IsGenerated( pAppend->GetActionNumber() ) )
2262 {
2263 SCSIZE nSlot = ComputeContentSlot(
2264 pAppend->GetBigRange().aStart.Row() );
2265 static_cast<ScChangeActionContent*>(pAppend)->InsertInSlot(
2266 &ppContentSlots[nSlot] );
2267 }
2268 return ;
2269 }
2270
2271 if ( pAppend->IsRejecting() )
2272 return ; // Rejects do not have dependencies
2273
2274 switch ( eType )
2275 {
2276 case SC_CAT_INSERT_COLS :
2277 {
2279 &pLinkInsertCol, pAppend );
2280 pAppend->AddLink( nullptr, pLink );
2281 }
2282 break;
2283 case SC_CAT_INSERT_ROWS :
2284 {
2286 &pLinkInsertRow, pAppend );
2287 pAppend->AddLink( nullptr, pLink );
2288 }
2289 break;
2290 case SC_CAT_INSERT_TABS :
2291 {
2293 &pLinkInsertTab, pAppend );
2294 pAppend->AddLink( nullptr, pLink );
2295 }
2296 break;
2297 case SC_CAT_MOVE :
2298 {
2300 &pLinkMove, pAppend );
2301 pAppend->AddLink( nullptr, pLink );
2302 }
2303 break;
2304 default:
2305 {
2306 // added to avoid warnings
2307 }
2308 }
2309}
2310
2311void ScChangeTrack::AppendLoaded( std::unique_ptr<ScChangeAction> pActionParam )
2312{
2313 ScChangeAction* pAppend = pActionParam.release();
2314 aMap.insert( ::std::make_pair( pAppend->GetActionNumber(), pAppend ) );
2315 if ( !pLast )
2316 pFirst = pLast = pAppend;
2317 else
2318 {
2319 pLast->pNext = pAppend;
2320 pAppend->pPrev = pLast;
2321 pLast = pAppend;
2322 }
2323 MasterLinks( pAppend );
2324}
2325
2327{
2328 if ( nActionMax < nAction )
2329 nActionMax = nAction;
2330 pAppend->SetUser( maUser );
2331 if ( bUseFixDateTime )
2332 pAppend->SetDateTimeUTC( aFixDateTime );
2333 pAppend->SetActionNumber( nAction );
2334 aMap.insert( ::std::make_pair( nAction, pAppend ) );
2335 // UpdateReference Inserts before Dependencies.
2336 // Delete rejecting Insert which had UpdateReference with Delete Undo.
2337 // UpdateReference also with pLast==NULL, as pAppend can be a Delete,
2338 // which could have generated DelContents.
2339 if ( pAppend->IsInsertType() && !pAppend->IsRejecting() )
2340 UpdateReference( pAppend, false );
2341 if ( !pLast )
2342 pFirst = pLast = pAppend;
2343 else
2344 {
2345 pLast->pNext = pAppend;
2346 pAppend->pPrev = pLast;
2347 pLast = pAppend;
2348 Dependencies( pAppend );
2349 }
2350 // UpdateReference does not Insert() after Dependencies.
2351 // Move rejecting Move, which had UpdateReference with Move Undo.
2352 // Do not delete content in ToRange.
2353 if ( !pAppend->IsInsertType() &&
2354 !(pAppend->GetType() == SC_CAT_MOVE && pAppend->IsRejecting()) )
2355 UpdateReference( pAppend, false );
2356 MasterLinks( pAppend );
2357
2358 if ( !aModifiedLink.IsSet() )
2359 return;
2360
2361 NotifyModified( ScChangeTrackMsgType::Append, nAction, nAction );
2362 if ( pAppend->GetType() == SC_CAT_CONTENT )
2363 {
2364 ScChangeActionContent* pContent = static_cast<ScChangeActionContent*>(pAppend);
2365 if ( ( pContent = pContent->GetPrevContent() ) != nullptr )
2366 {
2367 sal_uLong nMod = pContent->GetActionNumber();
2369 }
2370 }
2371 else
2374}
2375
2377{
2378 Append( pAppend, ++nActionMax );
2379}
2380
2382 ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction, SCTAB nDz )
2383{
2384 nStartAction = GetActionMax() + 1;
2385 AppendDeleteRange( rRange, pRefDoc, nDz, 0 );
2386 nEndAction = GetActionMax();
2387}
2388
2390 ScDocument* pRefDoc, SCTAB nDz, sal_uLong nRejectingInsert )
2391{
2392 SetInDeleteRange( rRange );
2394 SCCOL nCol1;
2395 SCROW nRow1;
2396 SCTAB nTab1;
2397 SCCOL nCol2;
2398 SCROW nRow2;
2399 SCTAB nTab2;
2400 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
2401 for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
2402 {
2403 if ( !pRefDoc || nTab < pRefDoc->GetTableCount() )
2404 {
2405 if ( nCol1 == 0 && nCol2 == rDoc.MaxCol() )
2406 { // Whole Row and/or Tables
2407 if ( nRow1 == 0 && nRow2 == rDoc.MaxRow() )
2408 { // Whole Table
2409 // TODO: Can't we do the whole Table as a whole?
2410 ScRange aRange( 0, 0, nTab, 0, rDoc.MaxRow(), nTab );
2411 for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ )
2412 { // Column by column is less than row by row
2413 aRange.aStart.SetCol( nCol );
2414 aRange.aEnd.SetCol( nCol );
2415 if ( nCol == nCol2 )
2416 SetInDeleteTop( true );
2417 AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0,
2418 nTab-nTab1 + nDz, nRejectingInsert );
2419 }
2420 // Still InDeleteTop!
2421 AppendOneDeleteRange( rRange, pRefDoc, 0, 0,
2422 nTab-nTab1 + nDz, nRejectingInsert );
2423 }
2424 else
2425 { // Whole rows
2426 ScRange aRange( 0, 0, nTab, rDoc.MaxCol(), 0, nTab );
2427 for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
2428 {
2429 aRange.aStart.SetRow( nRow );
2430 aRange.aEnd.SetRow( nRow );
2431 if ( nRow == nRow2 )
2432 SetInDeleteTop( true );
2433 AppendOneDeleteRange( aRange, pRefDoc, 0, nRow-nRow1,
2434 0, nRejectingInsert );
2435 }
2436 }
2437 }
2438 else if ( nRow1 == 0 && nRow2 == rDoc.MaxRow() )
2439 { // Whole columns
2440 ScRange aRange( 0, 0, nTab, 0, rDoc.MaxRow(), nTab );
2441 for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ )
2442 {
2443 aRange.aStart.SetCol( nCol );
2444 aRange.aEnd.SetCol( nCol );
2445 if ( nCol == nCol2 )
2446 SetInDeleteTop( true );
2447 AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0,
2448 0, nRejectingInsert );
2449 }
2450 }
2451 else
2452 {
2453 OSL_FAIL( "ScChangeTrack::AppendDeleteRange: Block not supported!" );
2454 }
2455 SetInDeleteTop( false );
2456 }
2457 }
2459}
2460
2462 ScDocument* pRefDoc, SCCOL nDx, SCROW nDy, SCTAB nDz,
2463 sal_uLong nRejectingInsert )
2464{
2465 ScRange aTrackRange( rOrgRange );
2466 if ( nDx )
2467 {
2468 aTrackRange.aStart.IncCol( -nDx );
2469 aTrackRange.aEnd.IncCol( -nDx );
2470 }
2471 if ( nDy )
2472 {
2473 aTrackRange.aStart.IncRow( -nDy );
2474 aTrackRange.aEnd.IncRow( -nDy );
2475 }
2476 if ( nDz )
2477 {
2478 aTrackRange.aStart.IncTab( -nDz );
2479 aTrackRange.aEnd.IncTab( -nDz );
2480 }
2481 ScChangeActionDel* pAct = new ScChangeActionDel( &rDoc, aTrackRange, nDx, nDy,
2482 this );
2483 // TabDelete not Contents; they are in separate columns
2484 if ( !(rOrgRange.aStart.Col() == 0 && rOrgRange.aStart.Row() == 0 &&
2485 rOrgRange.aEnd.Col() == rDoc.MaxCol() && rOrgRange.aEnd.Row() == rDoc.MaxRow()) )
2486 LookUpContents( rOrgRange, pRefDoc, -nDx, -nDy, -nDz );
2487 if ( nRejectingInsert )
2488 {
2489 pAct->SetRejectAction( nRejectingInsert );
2490 pAct->SetState( SC_CAS_ACCEPTED );
2491 }
2492 Append( pAct );
2493}
2494
2496 ScDocument* pRefDoc, SCCOL nDx, SCROW nDy, SCTAB nDz )
2497{
2498 if (!pRefDoc)
2499 return;
2500
2501 ScAddress aPos;
2502 ScBigAddress aBigPos;
2503 ScCellIterator aIter( *pRefDoc, rOrgRange );
2504 for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
2505 {
2507 continue;
2508
2509 aBigPos.Set( aIter.GetPos().Col() + nDx, aIter.GetPos().Row() + nDy,
2510 aIter.GetPos().Tab() + nDz );
2511 ScChangeActionContent* pContent = SearchContentAt( aBigPos, nullptr );
2512 if (pContent)
2513 continue;
2514
2515 // Untracked Contents
2516 aPos.Set( aIter.GetPos().Col() + nDx, aIter.GetPos().Row() + nDy,
2517 aIter.GetPos().Tab() + nDz );
2518
2519 GenerateDelContent(aPos, aIter.getCellValue(), pRefDoc);
2520 // The Content is _not_ added with AddContent here, but in UpdateReference.
2521 // We do this in order to e.g. handle intersecting Deletes correctly
2522 }
2523}
2524
2525void ScChangeTrack::AppendMove( const ScRange& rFromRange,
2526 const ScRange& rToRange, ScDocument* pRefDoc )
2527{
2528 ScChangeActionMove* pAct = new ScChangeActionMove( rFromRange, rToRange, this );
2529 LookUpContents( rToRange, pRefDoc, 0, 0, 0 ); // Overwritten Contents
2530 Append( pAct );
2531}
2532
2534 const ScCellValue& rOldCell, const ScCellValue& rNewCell )
2535{
2536 SCCOL nC1, nC2;
2537 SCROW nR1, nR2;
2538 nC1 = nC2 = 0;
2539 nR1 = nR2 = 0;
2540
2541 if (rOldCell.getType() == CELLTYPE_FORMULA && rOldCell.getFormula()->GetMatrixFlag() == ScMatrixMode::Formula)
2542 rOldCell.getFormula()->GetMatColsRows(nC1, nR1);
2543
2544 if (rNewCell.getType() == CELLTYPE_FORMULA && rNewCell.getFormula()->GetMatrixFlag() == ScMatrixMode::Formula)
2545 rNewCell.getFormula()->GetMatColsRows(nC1, nR1);
2546
2547 return nC1 != nC2 || nR1 != nR2;
2548}
2549
2551 const ScAddress& rPos, const ScCellValue& rOldCell, sal_uLong nOldFormat, ScDocument* pRefDoc )
2552{
2553 if ( !pRefDoc )
2554 pRefDoc = &rDoc;
2555
2556 OUString aOldValue = ScChangeActionContent::GetStringOfCell(rOldCell, pRefDoc, nOldFormat);
2557
2558 ScCellValue aNewCell;
2559 aNewCell.assign(rDoc, rPos);
2560 OUString aNewValue = ScChangeActionContent::GetStringOfCell(aNewCell, &rDoc, rPos);
2561
2562 if (aOldValue != aNewValue || IsMatrixFormulaRangeDifferent(rOldCell, aNewCell))
2563 { // Only track real changes
2564 ScRange aRange( rPos );
2565 ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
2566 pAct->SetOldValue(rOldCell, pRefDoc, &rDoc, nOldFormat);
2567 pAct->SetNewValue(aNewCell, &rDoc);
2568 Append( pAct );
2569 }
2570}
2571
2573 const ScDocument* pRefDoc )
2574{
2575 ScCellValue aOldCell;
2576 aOldCell.assign(*pRefDoc, rPos);
2577 OUString aOldValue = ScChangeActionContent::GetStringOfCell(aOldCell, pRefDoc, rPos);
2578
2579 ScCellValue aNewCell;
2580 aNewCell.assign(rDoc, rPos);
2581 OUString aNewValue = ScChangeActionContent::GetStringOfCell(aNewCell, &rDoc, rPos);
2582
2583 if (aOldValue != aNewValue || IsMatrixFormulaRangeDifferent(aOldCell, aNewCell))
2584 { // Only track real changes
2585 ScRange aRange( rPos );
2586 ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
2587 pAct->SetOldValue(aOldCell, pRefDoc, &rDoc);
2588 pAct->SetNewValue(aNewCell, &rDoc);
2589 Append( pAct );
2590 }
2591}
2592
2593void ScChangeTrack::AppendContent( const ScAddress& rPos, const ScCellValue& rOldCell )
2594{
2596 AppendContent(rPos, rOldCell, rDoc.GetNumberFormat(rPos), &rDoc);
2597 else
2598 AppendContent(rPos, rOldCell, 0, &rDoc);
2599}
2600
2602 ScDocument* pRefDoc )
2603{
2604 if ( !pLastCutMove )
2605 return;
2606
2607 // Do not link ToRange with Deletes and don't change its size
2608 // This is actually unnecessary, as a delete triggers a ResetLastCut
2609 // in ScViewFunc::PasteFromClip before that
2610 ScBigRange& r = pLastCutMove->GetBigRange();
2611 r.aEnd.SetCol( -1 );
2612 r.aEnd.SetRow( -1 );
2613 r.aEnd.SetTab( -1 );
2614 r.aStart.SetCol( -1 - (rRange.aEnd.Col() - rRange.aStart.Col()) );
2615 r.aStart.SetRow( -1 - (rRange.aEnd.Row() - rRange.aStart.Row()) );
2616 r.aStart.SetTab( -1 - (rRange.aEnd.Tab() - rRange.aStart.Tab()) );
2617 // Contents in FromRange we should overwrite
2618 LookUpContents( rRange, pRefDoc, 0, 0, 0 );
2619}
2620
2622 ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction,
2623 ScChangeActionClipMode eClipMode )
2624{
2625 if ( eClipMode == SC_CACM_CUT )
2626 {
2627 ResetLastCut();
2628 pLastCutMove.reset(new ScChangeActionMove( rRange, rRange, this ));
2629 SetLastCutMoveRange( rRange, pRefDoc );
2630 }
2631 SCCOL nCol1;
2632 SCROW nRow1;
2633 SCTAB nTab1;
2634 SCCOL nCol2;
2635 SCROW nRow2;
2636 SCTAB nTab2;
2637 rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
2638 bool bDoContents;
2639 if ( eClipMode == SC_CACM_PASTE && HasLastCut() )
2640 {
2641 bDoContents = false;
2642 SetInPasteCut( true );
2643 // Adjust Paste and Cut; Paste can be larger a Range
2644 ScRange aRange( rRange );
2645 ScBigRange& r = pLastCutMove->GetBigRange();
2646 SCCOL nTmpCol;
2647 if ( (nTmpCol = static_cast<SCCOL>(r.aEnd.Col() - r.aStart.Col())) != (nCol2 - nCol1) )
2648 {
2649 aRange.aEnd.SetCol( aRange.aStart.Col() + nTmpCol );
2650 nCol1 += nTmpCol + 1;
2651 bDoContents = true;
2652 }
2653 SCROW nTmpRow;
2654 if ( (nTmpRow = static_cast<SCROW>(r.aEnd.Row() - r.aStart.Row())) != (nRow2 - nRow1) )
2655 {
2656 aRange.aEnd.SetRow( aRange.aStart.Row() + nTmpRow );
2657 nRow1 += nTmpRow + 1;
2658 bDoContents = true;
2659 }
2660 SCTAB nTmpTab;
2661 if ( (nTmpTab = static_cast<SCTAB>(r.aEnd.Tab() - r.aStart.Tab())) != (nTab2 - nTab1) )
2662 {
2663 aRange.aEnd.SetTab( aRange.aStart.Tab() + nTmpTab );
2664 nTab1 += nTmpTab + 1;
2665 bDoContents = true;
2666 }
2667 r = aRange;
2668 Undo( nStartLastCut, nEndLastCut ); // Remember Cuts here
2669 // StartAction only after Undo!
2670 nStartAction = GetActionMax() + 1;
2672 // Contents to overwrite in ToRange
2673 LookUpContents( aRange, pRefDoc, 0, 0, 0 );
2674 pLastCutMove->SetStartLastCut( nStartLastCut );
2675 pLastCutMove->SetEndLastCut( nEndLastCut );
2676 Append( pLastCutMove.release() );
2677 ResetLastCut();
2678 SetInPasteCut( false );
2679 }
2680 else
2681 {
2682 bDoContents = true;
2683 nStartAction = GetActionMax() + 1;
2685 }
2686 if ( bDoContents )
2687 {
2688 ScAddress aPos;
2689 for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
2690 {
2691 aPos.SetTab( nTab );
2692 // AppendContent() is a no-op if both cells are empty.
2693 SCCOL lastCol = std::max( pRefDoc->ClampToAllocatedColumns( nTab, nCol2 ),
2694 rDoc.ClampToAllocatedColumns( nTab, nCol2 ));
2695 for ( SCCOL nCol = nCol1; nCol <= lastCol; nCol++ )
2696 {
2697 aPos.SetCol( nCol );
2698 SCROW lastRow = std::max( pRefDoc->GetLastDataRow( nTab, nCol, nCol, nRow2 ),
2699 rDoc.GetLastDataRow( nTab, nCol, nCol, nRow2 ));
2700 for ( SCROW nRow = nRow1; nRow <= lastRow; nRow++ )
2701 {
2702 aPos.SetRow( nRow );
2703 AppendContent( aPos, pRefDoc );
2704 }
2705 }
2706 }
2707 }
2708 nEndAction = GetActionMax();
2709 EndBlockModify( nEndAction );
2710 if ( eClipMode == SC_CACM_CUT )
2711 {
2712 nStartLastCut = nStartAction;
2713 nEndLastCut = nEndAction;
2714 }
2715}
2716
2718 sal_uLong& nStartAction, sal_uLong& nEndAction )
2719{
2720 ScCellIterator aIter(rRefDoc, ScRange(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB));
2721 if (aIter.first())
2722 {
2723 nStartAction = GetActionMax() + 1;
2725 SvNumberFormatter* pFormatter = rRefDoc.GetFormatTable();
2726 do
2727 {
2728 const ScAddress& rPos = aIter.GetPos();
2729 const ScPatternAttr* pPat = rRefDoc.GetPattern(rPos);
2731 rPos, aIter.getCellValue(), pPat->GetNumberFormat(pFormatter), &rRefDoc);
2732 }
2733 while (aIter.next());
2734
2735 nEndAction = GetActionMax();
2736 EndBlockModify( nEndAction );
2737 }
2738 else
2739 nStartAction = nEndAction = 0;
2740}
2741
2743 const ScAddress& rPos, const ScCellValue& rOldCell, const ScCellValue& rNewCell,
2744 sal_uLong nOldFormat, sal_uLong nNewFormat )
2745{
2746 ScRange aRange( rPos );
2747 ScChangeActionContent* pAct = new ScChangeActionContent( aRange );
2748 pAct->SetOldNewCells(rOldCell, nOldFormat, rNewCell, nNewFormat, &rDoc);
2749 Append( pAct );
2750 return pAct;
2751}
2752
2753void ScChangeTrack::AppendInsert( const ScRange& rRange, bool bEndOfList )
2754{
2755 ScChangeActionIns* pAct = new ScChangeActionIns(&rDoc, rRange, bEndOfList);
2756 Append( pAct );
2757}
2758
2759void ScChangeTrack::DeleteCellEntries( std::vector<ScChangeActionContent*>& rCellList,
2760 const ScChangeAction* pDeletor )
2761{
2762 for (ScChangeActionContent* pContent : rCellList)
2763 {
2764 pContent->RemoveDeletedIn( pDeletor );
2765 if ( IsGenerated( pContent->GetActionNumber() ) &&
2766 !pContent->IsDeletedIn() )
2767 DeleteGeneratedDelContent( pContent );
2768 }
2769 rCellList.clear();
2770}
2771
2773 const ScAddress& rPos, const ScCellValue& rCell, const ScDocument* pFromDoc )
2774{
2776 ScRange( rPos ) );
2777 pContent->SetActionNumber( --nGeneratedMin );
2778 // Only NewValue
2780 rPos, rCell, pFromDoc, &rDoc );
2781 // pNextContent and pPrevContent are not set
2783 { // Insert at front
2784 pFirstGeneratedDelContent->pPrev = pContent;
2785 pContent->pNext = pFirstGeneratedDelContent;
2786 }
2787 pFirstGeneratedDelContent = pContent;
2788 aGeneratedMap.insert( std::make_pair( nGeneratedMin, pContent ) );
2790 return pContent;
2791}
2792
2794{
2795 sal_uLong nAct = pContent->GetActionNumber();
2796 aGeneratedMap.erase( nAct );
2797 if ( pFirstGeneratedDelContent == pContent )
2798 pFirstGeneratedDelContent = static_cast<ScChangeActionContent*>(pContent->pNext);
2799 if ( pContent->pNext )
2800 pContent->pNext->pPrev = pContent->pPrev;
2801 if ( pContent->pPrev )
2802 pContent->pPrev->pNext = pContent->pNext;
2803 delete pContent;
2805 if ( nAct == nGeneratedMin )
2806 ++nGeneratedMin; // Only after NotifyModified due to IsGenerated!
2807}
2808
2810 const ScBigAddress& rPos, const ScChangeAction* pButNotThis ) const
2811{
2812 SCSIZE nSlot = ComputeContentSlot( rPos.Row() );
2813 for ( ScChangeActionContent* p = ppContentSlots[nSlot]; p;
2814 p = p->GetNextInSlot() )
2815 {
2816 if ( p != pButNotThis && !p->IsDeletedIn() &&
2817 p->GetBigRange().aStart == rPos )
2818 {
2819 ScChangeActionContent* pContent = p->GetTopContent();
2820 if ( !pContent->IsDeletedIn() )
2821 return pContent;
2822 }
2823 }
2824 return nullptr;
2825}
2826
2828 ScChangeAction* pDependent )
2829{
2830 ScChangeActionLinkEntry* pLink = pParent->AddDependent( pDependent );
2831 pDependent->AddLink( pParent, pLink );
2832 if ( aModifiedLink.IsSet() )
2833 {
2834 sal_uLong nMod = pParent->GetActionNumber();
2836 }
2837}
2838
2840{
2841 // Find the last dependency for Col/Row/Tab each
2842 // Concatenate Content at the same position
2843 // Move dependencies
2844 ScChangeActionType eActType = pAct->GetType();
2845 if ( eActType == SC_CAT_REJECT ||
2846 (eActType == SC_CAT_MOVE && pAct->IsRejecting()) )
2847 return ; // These Rejects are not dependent
2848
2849 if ( eActType == SC_CAT_CONTENT )
2850 {
2851 if ( !(static_cast<ScChangeActionContent*>(pAct)->GetNextContent() ||
2852 static_cast<ScChangeActionContent*>(pAct)->GetPrevContent()) )
2853 { // Concatenate Contents at same position
2855 pAct->GetBigRange().aStart, pAct );
2856 if ( pContent )
2857 {
2858 pContent->SetNextContent( static_cast<ScChangeActionContent*>(pAct) );
2859 static_cast<ScChangeActionContent*>(pAct)->SetPrevContent( pContent );
2860 }
2861 }
2862 const ScCellValue& rCell = static_cast<ScChangeActionContent*>(pAct)->GetNewCell();
2864 {
2865 ScAddress aOrg;
2866 bool bOrgFound = rCell.getFormula()->GetMatrixOrigin(rDoc, aOrg);
2867 ScChangeActionContent* pContent = (bOrgFound ? SearchContentAt( aOrg, pAct ) : nullptr);
2868 if ( pContent && pContent->IsMatrixOrigin() )
2869 {
2870 AddDependentWithNotify( pContent, pAct );
2871 }
2872 else
2873 {
2874 OSL_FAIL( "ScChangeTrack::Dependencies: MatOrg not found" );
2875 }
2876 }
2877 }
2878
2880 return ; // No Dependencies
2881 if ( pAct->IsRejecting() )
2882 return ; // Except for Content no Dependencies
2883
2884 // Insert in a corresponding Insert depends on it or else we would need
2885 // to split the preceding one.
2886 // Intersecting Inserts and Deletes are not dependent, everything else
2887 // is dependent.
2888 // The Insert last linked in is at the beginning of a chain, just the way we need it
2889
2890 const ScBigRange& rRange = pAct->GetBigRange();
2891 bool bActNoInsert = !pAct->IsInsertType();
2892 bool bActColDel = ( eActType == SC_CAT_DELETE_COLS );
2893 bool bActRowDel = ( eActType == SC_CAT_DELETE_ROWS );
2894 bool bActTabDel = ( eActType == SC_CAT_DELETE_TABS );
2895
2896 if ( pLinkInsertCol && (eActType == SC_CAT_INSERT_COLS ||
2897 (bActNoInsert && !bActRowDel && !bActTabDel)) )
2898 {
2899 for ( ScChangeActionLinkEntry* pL = pLinkInsertCol; pL; pL = pL->GetNext() )
2900 {
2901 ScChangeActionIns* pTest = static_cast<ScChangeActionIns*>(pL->GetAction());
2902 if ( !pTest->IsRejected() &&
2903 pTest->GetBigRange().Intersects( rRange ) )
2904 {
2905 AddDependentWithNotify( pTest, pAct );
2906 break; // for
2907 }
2908 }
2909 }
2910 if ( pLinkInsertRow && (eActType == SC_CAT_INSERT_ROWS ||
2911 (bActNoInsert && !bActColDel && !bActTabDel)) )
2912 {
2913 for ( ScChangeActionLinkEntry* pL = pLinkInsertRow; pL; pL = pL->GetNext() )
2914 {
2915 ScChangeActionIns* pTest = static_cast<ScChangeActionIns*>(pL->GetAction());
2916 if ( !pTest->IsRejected() &&
2917 pTest->GetBigRange().Intersects( rRange ) )
2918 {
2919 AddDependentWithNotify( pTest, pAct );
2920 break; // for
2921 }
2922 }
2923 }
2924 if ( pLinkInsertTab && (eActType == SC_CAT_INSERT_TABS ||
2925 (bActNoInsert && !bActColDel && !bActRowDel)) )
2926 {
2927 for ( ScChangeActionLinkEntry* pL = pLinkInsertTab; pL; pL = pL->GetNext() )
2928 {
2929 ScChangeActionIns* pTest = static_cast<ScChangeActionIns*>(pL->GetAction());
2930 if ( !pTest->IsRejected() &&
2931 pTest->GetBigRange().Intersects( rRange ) )
2932 {
2933 AddDependentWithNotify( pTest, pAct );
2934 break; // for
2935 }
2936 }
2937 }
2938
2939 if ( !pLinkMove )
2940 return;
2941
2942 if ( eActType == SC_CAT_CONTENT )
2943 { // Content is depending on FromRange
2944 const ScBigAddress& rPos = rRange.aStart;
2945 for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
2946 {
2947 ScChangeActionMove* pTest = static_cast<ScChangeActionMove*>(pL->GetAction());
2948 if ( !pTest->IsRejected() &&
2949 pTest->GetFromRange().Contains( rPos ) )
2950 {
2951 AddDependentWithNotify( pTest, pAct );
2952 }
2953 }
2954 }
2955 else if ( eActType == SC_CAT_MOVE )
2956 { // Move FromRange is depending on ToRange
2957 const ScBigRange& rFromRange = static_cast<ScChangeActionMove*>(pAct)->GetFromRange();
2958 for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
2959 {
2960 ScChangeActionMove* pTest = static_cast<ScChangeActionMove*>(pL->GetAction());
2961 if ( !pTest->IsRejected() &&
2962 pTest->GetBigRange().Intersects( rFromRange ) )
2963 {
2964 AddDependentWithNotify( pTest, pAct );
2965 }
2966 }
2967 }
2968 else
2969 { // Inserts and Deletes are depending as soon as they cross FromRange or
2970 // ToRange
2971 for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() )
2972 {
2973 ScChangeActionMove* pTest = static_cast<ScChangeActionMove*>(pL->GetAction());
2974 if ( !pTest->IsRejected() &&
2975 (pTest->GetFromRange().Intersects( rRange ) ||
2976 pTest->GetBigRange().Intersects( rRange )) )
2977 {
2978 AddDependentWithNotify( pTest, pAct );
2979 }
2980 }
2981 }
2982}
2983
2985{
2986 // Remove from Track
2987 sal_uLong nAct = pRemove->GetActionNumber();
2988 aMap.erase( nAct );
2989 if ( nAct == nActionMax )
2990 --nActionMax;
2991 if ( pRemove == pLast )
2992 pLast = pRemove->pPrev;
2993 if ( pRemove == pFirst )
2994 pFirst = pRemove->pNext;
2995 if ( nAct == nMarkLastSaved )
2997 ( pRemove->pPrev ? pRemove->pPrev->GetActionNumber() : 0 );
2998
2999 // Remove from global chain
3000 if ( pRemove->pNext )
3001 pRemove->pNext->pPrev = pRemove->pPrev;
3002 if ( pRemove->pPrev )
3003 pRemove->pPrev->pNext = pRemove->pNext;
3004
3005 // Don't delete Dependencies
3006 // That happens automatically on delete by LinkEntry without traversing lists
3007 if ( aModifiedLink.IsSet() )
3008 {
3010 if ( pRemove->GetType() == SC_CAT_CONTENT )
3011 {
3012 ScChangeActionContent* pContent = static_cast<ScChangeActionContent*>(pRemove);
3013 if ( ( pContent = pContent->GetPrevContent() ) != nullptr )
3014 {
3015 sal_uLong nMod = pContent->GetActionNumber();
3017 }
3018 }
3019 else if ( pLast )
3022 }
3023
3024 if ( IsInPasteCut() && pRemove->GetType() == SC_CAT_CONTENT )
3025 { // Content is reused!
3026 ScChangeActionContent* pContent = static_cast<ScChangeActionContent*>(pRemove);
3027 pContent->RemoveAllLinks();
3028 pContent->ClearTrack();
3029 pContent->pNext = pContent->pPrev = nullptr;
3030 pContent->pNextContent = pContent->pPrevContent = nullptr;
3031 }
3032}
3033
3034void ScChangeTrack::Undo( sal_uLong nStartAction, sal_uLong nEndAction, bool bMerge )
3035{
3036 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3037 if ( bMerge )
3038 {
3040 }
3041
3042 if ( nStartAction == 0 )
3043 ++nStartAction;
3044 if ( nEndAction > nActionMax )
3045 nEndAction = nActionMax;
3046 if ( nEndAction && nStartAction <= nEndAction )
3047 {
3048 if ( nStartAction == nStartLastCut && nEndAction == nEndLastCut &&
3049 !IsInPasteCut() )
3050 ResetLastCut();
3052 for ( sal_uLong j = nEndAction; j >= nStartAction; --j )
3053 { // Traverse backwards to recycle nActionMax and for faster access via pLast
3054 // Deletes are in right order
3055 ScChangeAction* pAct = IsLastAction(j) ? pLast : GetAction(j);
3056
3057 if (!pAct)
3058 continue;
3059
3060 if ( pAct->IsDeleteType() )
3061 {
3062 if (j == nEndAction || (pAct != pLast && static_cast<ScChangeActionDel*>(pAct)->IsTopDelete()))
3063 {
3064 SetInDeleteTop( true );
3065 SetInDeleteRange( static_cast<ScChangeActionDel*>(pAct)->GetOverAllRange().MakeRange( rDoc ) );
3066 }
3067 }
3068 UpdateReference( pAct, true );
3069 SetInDeleteTop( false );
3070 Remove( pAct );
3071 if ( IsInPasteCut() )
3072 {
3073 aPasteCutMap.insert( ::std::make_pair( pAct->GetActionNumber(), pAct ) );
3074 continue;
3075 }
3076
3077 if ( j == nStartAction && pAct->GetType() == SC_CAT_MOVE )
3078 {
3079 ScChangeActionMove* pMove = static_cast<ScChangeActionMove*>(pAct);
3080 sal_uLong nStart = pMove->GetStartLastCut();
3081 sal_uLong nEnd = pMove->GetEndLastCut();
3082 if ( nStart && nStart <= nEnd )
3083 { // Recover LastCut
3084 // Break Links before Cut Append!
3085 pMove->RemoveAllLinks();
3087 for ( sal_uLong nCut = nStart; nCut <= nEnd; nCut++ )
3088 {
3089 ScChangeActionMap::iterator itCut = aPasteCutMap.find( nCut );
3090
3091 if ( itCut != aPasteCutMap.end() )
3092 {
3093 OSL_ENSURE( aMap.find( nCut ) == aMap.end(), "ScChangeTrack::Undo: nCut dup" );
3094 Append( itCut->second, nCut );
3095 aPasteCutMap.erase( itCut );
3096 }
3097 else
3098 {
3099 OSL_FAIL( "ScChangeTrack::Undo: nCut not found" );
3100 }
3101 }
3102 EndBlockModify( nEnd );
3103 ResetLastCut();
3104 nStartLastCut = nStart;
3105 nEndLastCut = nEnd;
3106 pLastCutMove.reset(pMove);
3108 pMove->GetFromRange().MakeRange( rDoc ), &rDoc );
3109 }
3110 else
3111 delete pMove;
3112 }
3113 else
3114 delete pAct;
3115 }
3116 EndBlockModify( nEndAction );
3117 }
3118
3119 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3120 if ( bMerge )
3121 {
3123 }
3124}
3125
3126bool ScChangeTrack::MergeIgnore( const ScChangeAction& rAction, sal_uLong nFirstMerge )
3127{
3128 if ( rAction.IsRejected() )
3129 return true; // There's still a suitable Reject Action coming
3130
3131 if ( rAction.IsRejecting() && rAction.GetRejectAction() >= nFirstMerge )
3132 return true; // There it is
3133
3134 return false; // Everything else
3135}
3136
3137void ScChangeTrack::MergePrepare( const ScChangeAction* pFirstMerge, bool bShared )
3138{
3140 sal_uLong nFirstMerge = pFirstMerge->GetActionNumber();
3141 ScChangeAction* pAct = GetLast();
3142 if ( pAct )
3143 {
3144 SetLastMerge( pAct->GetActionNumber() );
3145 while ( pAct )
3146 { // Traverse backwards; Deletes in right order
3147 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3148 if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) )
3149 {
3150 if ( pAct->IsDeleteType() )
3151 {
3152 if ( static_cast<ScChangeActionDel*>(pAct)->IsTopDelete() )
3153 {
3154 SetInDeleteTop( true );
3155 SetInDeleteRange( static_cast<ScChangeActionDel*>(pAct)->
3156 GetOverAllRange().MakeRange( rDoc ) );
3157 }
3158 }
3159 UpdateReference( pAct, true );
3160 SetInDeleteTop( false );
3161 pAct->DeleteCellEntries(); // Else segfault in Track Clear()
3162 }
3163 pAct = ( pAct == pFirstMerge ? nullptr : pAct->GetPrev() );
3164 }
3165 }
3166 SetMergeState( SC_CTMS_OTHER ); // Preceding by default MergeOther!
3167}
3168
3169void ScChangeTrack::MergeOwn( ScChangeAction* pAct, sal_uLong nFirstMerge, bool bShared )
3170{
3171 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3172 if ( !bShared && ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) )
3173 return;
3174
3176 if ( pAct->IsDeleteType() )
3177 {
3178 if ( static_cast<ScChangeActionDel*>(pAct)->IsTopDelete() )
3179 {
3180 SetInDeleteTop( true );
3181 SetInDeleteRange( static_cast<ScChangeActionDel*>(pAct)->
3182 GetOverAllRange().MakeRange( rDoc ) );
3183 }
3184 }
3185 UpdateReference( pAct, false );
3186 SetInDeleteTop( false );
3187 SetMergeState( SC_CTMS_OTHER ); // Preceding by default MergeOther!
3188}
3189
3191{
3192 ScChangeActionType eActType = pAct->GetType();
3193 if ( eActType == SC_CAT_CONTENT || eActType == SC_CAT_REJECT )
3194 return ;
3195
3196 // Formula cells are not in the Document!
3197 bool bOldAutoCalc = rDoc.GetAutoCalc();
3198 rDoc.SetAutoCalc( false );
3199 bool bOldNoListening = rDoc.GetNoListening();
3200 rDoc.SetNoListening( true );
3201
3202 // Formula cells ExpandRefs synchronized to the ones in the Document!
3203 bool bOldExpandRefs = rDoc.IsExpandRefs();
3204 if ( (!bUndo && pAct->IsInsertType()) || (bUndo && pAct->IsDeleteType()) )
3205 rDoc.SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
3206
3207 if ( pAct->IsDeleteType() )
3208 {
3209 SetInDeleteUndo( bUndo );
3210 SetInDelete( true );
3211 }
3212 else if ( GetMergeState() == SC_CTMS_OWN )
3213 {
3214 // Recover references of formula cells
3215 // Previous MergePrepare behaved like a Delete when Inserting
3216 if ( pAct->IsInsertType() )
3217 SetInDeleteUndo( true );
3218 }
3219
3220 // First the generated ones, as if they were tracked previously!
3222 UpdateReference( reinterpret_cast<ScChangeAction**>(&pFirstGeneratedDelContent), pAct,
3223 bUndo );
3224 UpdateReference( &pFirst, pAct, bUndo );
3225
3226 SetInDelete( false );
3227 SetInDeleteUndo( false );
3228
3229 rDoc.SetExpandRefs( bOldExpandRefs );
3230 rDoc.SetNoListening( bOldNoListening );
3231 rDoc.SetAutoCalc( bOldAutoCalc );
3232}
3233
3235 ScChangeAction* pAct, bool bUndo )
3236{
3237 ScChangeActionType eActType = pAct->GetType();
3238 bool bGeneratedDelContents =
3239 ( ppFirstAction == reinterpret_cast<ScChangeAction**>(&pFirstGeneratedDelContent) );
3240 const ScBigRange& rOrgRange = pAct->GetBigRange();
3241 ScBigRange aRange( rOrgRange );
3242 ScBigRange aDelRange( rOrgRange );
3243 sal_Int32 nDx, nDy, nDz;
3244 nDx = nDy = nDz = 0;
3246 bool bDel = false;
3247 switch ( eActType )
3248 {
3249 case SC_CAT_INSERT_COLS :
3251 nDx = rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1;
3252 break;
3253 case SC_CAT_INSERT_ROWS :
3255 nDy = rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1;
3256 break;
3257 case SC_CAT_INSERT_TABS :
3259 nDz = rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1;
3260 break;
3261 case SC_CAT_DELETE_COLS :
3263 nDx = -(rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1);
3264 aDelRange.aEnd.SetCol( aDelRange.aStart.Col() - nDx - 1 );
3265 bDel = true;
3266 break;
3267 case SC_CAT_DELETE_ROWS :
3269 nDy = -(rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1);
3270 aDelRange.aEnd.SetRow( aDelRange.aStart.Row() - nDy - 1 );
3271 bDel = true;
3272 break;
3273 case SC_CAT_DELETE_TABS :
3275 nDz = -(rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1);
3276 aDelRange.aEnd.SetTab( aDelRange.aStart.Tab() - nDz - 1 );
3277 bDel = true;
3278 break;
3279 case SC_CAT_MOVE :
3280 eMode = URM_MOVE;
3281 static_cast<ScChangeActionMove*>(pAct)->GetDelta( nDx, nDy, nDz );
3282 break;
3283 default:
3284 OSL_FAIL( "ScChangeTrack::UpdateReference: unknown Type" );
3285 }
3286 if ( bUndo )
3287 {
3288 nDx = -nDx;
3289 nDy = -nDy;
3290 nDz = -nDz;
3291 }
3292 if ( bDel )
3293 { // For this mechanism we assume:
3294 // There's only a whole, simple deleted row/column
3295 ScChangeActionDel* pActDel = static_cast<ScChangeActionDel*>(pAct);
3296 if ( !bUndo )
3297 { // Delete
3298 ScChangeActionType eInsType = SC_CAT_NONE; // for Insert Undo "Deletes"
3299 switch ( eActType )
3300 {
3301 case SC_CAT_DELETE_COLS :
3302 eInsType = SC_CAT_INSERT_COLS;
3303 break;
3304 case SC_CAT_DELETE_ROWS :
3305 eInsType = SC_CAT_INSERT_ROWS;
3306 break;
3307 case SC_CAT_DELETE_TABS :
3308 eInsType = SC_CAT_INSERT_TABS;
3309 break;
3310 default:
3311 {
3312 // added to avoid warnings
3313 }
3314 }
3315 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3316 {
3317 if ( p == pAct )
3318 continue; // for
3319 bool bUpdate = true;
3320 if ( GetMergeState() == SC_CTMS_OTHER &&
3321 p->GetActionNumber() <= GetLastMerge() )
3322 { // Delete in merged Document, Action in the one to be merged
3323 if ( p->IsInsertType() )
3324 {
3325 // On Insert only adjust references if the Delete does
3326 // not intersect the Insert
3327 if ( !aDelRange.Intersects( p->GetBigRange() ) )
3328 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3329 bUpdate = false;
3330 }
3331 else if ( p->GetType() == SC_CAT_CONTENT &&
3332 p->IsDeletedInDelType( eInsType ) )
3333 { // Content in Insert Undo "Delete"
3334 // Do not adjust if this Delete would be in the Insert "Delete" (was just moved)
3335 if ( aDelRange.Contains( p->GetBigRange().aStart ) )
3336 bUpdate = false;
3337 else
3338 {
3339 const ScChangeActionLinkEntry* pLink = p->GetDeletedIn();
3340 while ( pLink && bUpdate )
3341 {
3342 const ScChangeAction* pDel = pLink->GetAction();
3343 if ( pDel && pDel->GetType() == eInsType &&
3344 pDel->GetBigRange().Contains( aDelRange ) )
3345 bUpdate = false;
3346 pLink = pLink->GetNext();
3347 }
3348 }
3349 }
3350 if ( !bUpdate )
3351 continue; // for
3352 }
3353 if ( aDelRange.Contains( p->GetBigRange() ) )
3354 {
3355 // Do not adjust within a just deleted range,
3356 // instead assign the range.
3357 // Stack up ranges that have been deleted multiple times.
3358 // Intersecting Deletes cause "multiple delete" to be set.
3359 if ( !p->IsDeletedInDelType( eActType ) )
3360 {
3361 p->SetDeletedIn( pActDel );
3362 // Add GeneratedDelContent to the to-be-deleted list
3363 if ( bGeneratedDelContents )
3364 pActDel->AddContent( static_cast<ScChangeActionContent*>(p) );
3365 }
3366 bUpdate = false;
3367 }
3368 else
3369 {
3370 // Cut off inserted ranges, if Start/End is within the Delete,
3371 // but the Insert is not completely within the Delete or
3372 // the Delete is not completely within the Insert.
3373 // The Delete remembers which Insert it has cut off from;
3374 // it can also just be a single Insert (because Delete has
3375 // a single column/is a single row).
3376 // There can be a lot of cut-off Moves.
3377 //
3378 // ! A Delete is always a single column/a single row, therefore
3379 // ! 1 without calculating the intersection.
3380 switch ( p->GetType() )
3381 {
3382 case SC_CAT_INSERT_COLS :
3383 if ( eActType == SC_CAT_DELETE_COLS )
3384 {
3385 if ( aDelRange.Contains( p->GetBigRange().aStart ) )
3386 {
3387 pActDel->SetCutOffInsert(
3388 static_cast<ScChangeActionIns*>(p), 1 );
3389 p->GetBigRange().aStart.IncCol();
3390 }
3391 else if ( aDelRange.Contains( p->GetBigRange().aEnd ) )
3392 {
3393 pActDel->SetCutOffInsert(
3394 static_cast<ScChangeActionIns*>(p), -1 );
3395 p->GetBigRange().aEnd.IncCol( -1 );
3396 }
3397 }
3398 break;
3399 case SC_CAT_INSERT_ROWS :
3400 if ( eActType == SC_CAT_DELETE_ROWS )
3401 {
3402 if ( aDelRange.Contains( p->GetBigRange().aStart ) )
3403 {
3404 pActDel->SetCutOffInsert(
3405 static_cast<ScChangeActionIns*>(p), 1 );
3406 p->GetBigRange().aStart.IncRow();
3407 }
3408 else if ( aDelRange.Contains( p->GetBigRange().aEnd ) )
3409 {
3410 pActDel->SetCutOffInsert(
3411 static_cast<ScChangeActionIns*>(p), -1 );
3412 p->GetBigRange().aEnd.IncRow( -1 );
3413 }
3414 }
3415 break;
3416 case SC_CAT_INSERT_TABS :
3417 if ( eActType == SC_CAT_DELETE_TABS )
3418 {
3419 if ( aDelRange.Contains( p->GetBigRange().aStart ) )
3420 {
3421 pActDel->SetCutOffInsert(
3422 static_cast<ScChangeActionIns*>(p), 1 );
3423 p->GetBigRange().aStart.IncTab();
3424 }
3425 else if ( aDelRange.Contains( p->GetBigRange().aEnd ) )
3426 {
3427 pActDel->SetCutOffInsert(
3428 static_cast<ScChangeActionIns*>(p), -1 );
3429 p->GetBigRange().aEnd.IncTab( -1 );
3430 }
3431 }
3432 break;
3433 case SC_CAT_MOVE :
3434 {
3435 ScChangeActionMove* pMove = static_cast<ScChangeActionMove*>(p);
3436 short nFrom = 0;
3437 short nTo = 0;
3438 if ( aDelRange.Contains( pMove->GetBigRange().aStart ) )
3439 nTo = 1;
3440 else if ( aDelRange.Contains( pMove->GetBigRange().aEnd ) )
3441 nTo = -1;
3442 if ( aDelRange.Contains( pMove->GetFromRange().aStart ) )
3443 nFrom = 1;
3444 else if ( aDelRange.Contains( pMove->GetFromRange().aEnd ) )
3445 nFrom = -1;
3446 if ( nFrom )
3447 {
3448 switch ( eActType )
3449 {
3450 case SC_CAT_DELETE_COLS :
3451 if ( nFrom > 0 )
3452 pMove->GetFromRange().aStart.IncCol( nFrom );
3453 else
3454 pMove->GetFromRange().aEnd.IncCol( nFrom );
3455 break;
3456 case SC_CAT_DELETE_ROWS :
3457 if ( nFrom > 0 )
3458 pMove->GetFromRange().aStart.IncRow( nFrom );
3459 else
3460 pMove->GetFromRange().aEnd.IncRow( nFrom );
3461 break;
3462 case SC_CAT_DELETE_TABS :
3463 if ( nFrom > 0 )
3464 pMove->GetFromRange().aStart.IncTab( nFrom );
3465 else
3466 pMove->GetFromRange().aEnd.IncTab( nFrom );
3467 break;
3468 default:
3469 {
3470 // added to avoid warnings
3471 }
3472 }
3473 }
3474 if ( nTo )
3475 {
3476 switch ( eActType )
3477 {
3478 case SC_CAT_DELETE_COLS :
3479 if ( nTo > 0 )
3480 pMove->GetBigRange().aStart.IncCol( nTo );
3481 else
3482 pMove->GetBigRange().aEnd.IncCol( nTo );
3483 break;
3484 case SC_CAT_DELETE_ROWS :
3485 if ( nTo > 0 )
3486 pMove->GetBigRange().aStart.IncRow( nTo );
3487 else
3488 pMove->GetBigRange().aEnd.IncRow( nTo );
3489 break;
3490 case SC_CAT_DELETE_TABS :
3491 if ( nTo > 0 )
3492 pMove->GetBigRange().aStart.IncTab( nTo );
3493 else
3494 pMove->GetBigRange().aEnd.IncTab( nTo );
3495 break;
3496 default:
3497 {
3498 // added to avoid warnings
3499 }
3500 }
3501 }
3502 if ( nFrom || nTo )
3503 {
3505 pActDel->AddCutOffMove( pMove, nFrom, nTo );
3506 pMove->AddLink( pActDel, pLink );
3507 }
3508 }
3509 break;
3510 default:
3511 {
3512 // added to avoid warnings
3513 }
3514 }
3515 }
3516 if ( bUpdate )
3517 {
3518 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3519 if ( p->GetType() == eActType && !p->IsRejected() &&
3520 !pActDel->IsDeletedIn() &&
3521 p->GetBigRange().Contains( aDelRange ) )
3522 pActDel->SetDeletedIn( p ); // Slipped underneath it
3523 }
3524 }
3525 }
3526 else
3527 { // Undo Delete
3528 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3529 {
3530 if ( p == pAct )
3531 continue; // for
3532 bool bUpdate = true;
3533 if ( aDelRange.Contains( p->GetBigRange() ) )
3534 {
3535 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3536 if ( GetMergeState() == SC_CTMS_UNDO && !p->IsDeletedIn( pAct ) && pAct->IsDeleteType() &&
3537 ( p->GetType() == SC_CAT_CONTENT ||
3538 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
3539 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) )
3540 {
3541 p->SetDeletedIn( pAct );
3542 }
3543
3544 if ( p->IsDeletedInDelType( eActType ) )
3545 {
3546 if ( p->IsDeletedIn( pActDel ) )
3547 {
3548 if ( p->GetType() != SC_CAT_CONTENT ||
3549 static_cast<ScChangeActionContent*>(p)->IsTopContent() )
3550 { // First really remove the TopContent
3551 p->RemoveDeletedIn( pActDel );
3552 // Do NOT delete GeneratedDelContent from the list, we might need
3553 // it later on for Reject; we delete in DeleteCellEntries
3554 }
3555 }
3556 bUpdate = false;
3557 }
3558 else if ( eActType != SC_CAT_DELETE_TABS &&
3559 p->IsDeletedInDelType( SC_CAT_DELETE_TABS ) )
3560 { // Do not update in deleted Tables except for when moving Tables
3561 bUpdate = false;
3562 }
3563 if ( p->GetType() == eActType && pActDel->IsDeletedIn( p ) )
3564 {
3565 pActDel->RemoveDeletedIn( p );// Slipped underneath
3566 bUpdate = true;
3567 }
3568 }
3569 if ( bUpdate )
3570 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3571 }
3572 if ( !bGeneratedDelContents )
3573 { // These are else also needed for the real Undo
3574 pActDel->UndoCutOffInsert();
3575 pActDel->UndoCutOffMoves();
3576 }
3577 }
3578 }
3579 else if ( eActType == SC_CAT_MOVE )
3580 {
3581 ScChangeActionMove* pActMove = static_cast<ScChangeActionMove*>(pAct);
3582 bool bLastCutMove = ( pActMove == pLastCutMove.get() );
3583 const ScBigRange& rTo = pActMove->GetBigRange();
3584 const ScBigRange& rFrom = pActMove->GetFromRange();
3585 if ( !bUndo )
3586 { // Move
3587 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3588 {
3589 if ( p == pAct )
3590 continue; // for
3591 if ( p->GetType() == SC_CAT_CONTENT )
3592 {
3593 // Delete content in Target (Move Content to Source)
3594 if ( rTo.Contains( p->GetBigRange() ) )
3595 {
3596 if ( !p->IsDeletedIn( pActMove ) )
3597 {
3598 p->SetDeletedIn( pActMove );
3599 // Add GeneratedDelContent to the to-be-deleted list
3600 if ( bGeneratedDelContents )
3601 pActMove->AddContent( static_cast<ScChangeActionContent*>(p) );
3602 }
3603 }
3604 else if ( bLastCutMove &&
3605 p->GetActionNumber() > nEndLastCut &&
3606 rFrom.Contains( p->GetBigRange() ) )
3607 { // Paste Cut: insert new Content inserted after stays
3608 // Split up the ContentChain
3609 ScChangeActionContent *pHere, *pTmp;
3610 pHere = static_cast<ScChangeActionContent*>(p);
3611 for (;;)
3612 {
3613 pTmp = pHere->GetPrevContent();
3614 if (!pTmp || pTmp->GetActionNumber() <= nEndLastCut)
3615 break;
3616 pHere = pTmp;
3617 }
3618 if ( pTmp )
3619 { // Becomes TopContent of the Move
3620 pTmp->SetNextContent( nullptr );
3621 pHere->SetPrevContent( nullptr );
3622 }
3623 do
3624 { // Recover dependency from FromRange
3625 AddDependentWithNotify( pActMove, pHere );
3626 } while ( ( pHere = pHere->GetNextContent() ) != nullptr );
3627 }
3628 // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
3629 else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() )
3630 p->UpdateReference( this, eMode, rFrom, nDx, nDy, nDz );
3631 }
3632 }
3633 }
3634 else
3635 { // Undo Move
3636 bool bActRejected = pActMove->IsRejected();
3637 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3638 {
3639 if ( p == pAct )
3640 continue; // for
3641 if ( p->GetType() == SC_CAT_CONTENT )
3642 {
3643 // Move Content into Target if not deleted else to delete (FIXME: What?)
3644 if ( p->IsDeletedIn( pActMove ) )
3645 {
3646 if ( static_cast<ScChangeActionContent*>(p)->IsTopContent() )
3647 { // First really remove the TopContent
3648 p->RemoveDeletedIn( pActMove );
3649 // Do NOT delete GeneratedDelContent from the list, we might need
3650 // it later on for Reject; we delete in DeleteCellEntries
3651 }
3652 }
3653 // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
3654 else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() )
3655 p->UpdateReference( this, eMode, rTo, nDx, nDy, nDz );
3656 if ( bActRejected &&
3657 static_cast<ScChangeActionContent*>(p)->IsTopContent() &&
3658 rFrom.Contains( p->GetBigRange() ) )
3659 { // Recover dependency to write Content
3661 pActMove->AddDependent( p );
3662 p->AddLink( pActMove, pLink );
3663 }
3664 }
3665 }
3666 }
3667 }
3668 else
3669 { // Insert/Undo Insert
3670 switch ( GetMergeState() )
3671 {
3672 case SC_CTMS_NONE :
3673 case SC_CTMS_OTHER :
3674 {
3675 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3676 {
3677 if ( p == pAct )
3678 continue; // for
3679 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3680 }
3681 }
3682 break;
3683 case SC_CTMS_PREPARE :
3684 {
3685 // "Delete" in Insert-Undo
3687 while ( pLink )
3688 {
3689 ScChangeAction* p = const_cast<ScChangeAction*>(pLink->GetAction());
3690 if ( p )
3691 p->SetDeletedIn( pAct );
3692 pLink = pLink->GetNext();
3693 }
3694
3695 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
3696 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3697 {
3698 if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
3699 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3700 ( p->GetType() == SC_CAT_CONTENT ||
3701 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
3702 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
3703 pAct->GetBigRange().Intersects( p->GetBigRange() ) )
3704 {
3705 p->SetDeletedIn( pAct );
3706 }
3707 }
3708
3709 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3710 {
3711 if ( p == pAct )
3712 continue; // for
3713 if ( !p->IsDeletedIn( pAct )
3714 // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
3715 && p->GetActionNumber() <= pAct->GetActionNumber() )
3716 {
3717 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3718 }
3719 }
3720 }
3721 break;
3722 case SC_CTMS_OWN :
3723 {
3724 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3725 {
3726 if ( p == pAct )
3727 continue; // for
3728 if ( !p->IsDeletedIn( pAct )
3729 // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
3730 && p->GetActionNumber() <= pAct->GetActionNumber() )
3731 {
3732 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3733 }
3734 }
3735 // Undo "Delete" in Insert-Undo
3737 while ( pLink )
3738 {
3739 ScChangeAction* p = const_cast<ScChangeAction*>(pLink->GetAction());
3740 if ( p )
3741 p->RemoveDeletedIn( pAct );
3742 pLink = pLink->GetNext();
3743 }
3744
3745 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
3746 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3747 {
3748 if ( p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
3749 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3750 ( p->GetType() == SC_CAT_CONTENT ||
3751 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
3752 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
3753 pAct->GetBigRange().Intersects( p->GetBigRange() ) )
3754 {
3755 p->RemoveDeletedIn( pAct );
3756 }
3757 }
3758 }
3759 break;
3760 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3761 case SC_CTMS_UNDO :
3762 {
3763 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3764 {
3765 if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() &&
3766 ( p->GetType() == SC_CAT_CONTENT ||
3767 p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS ||
3768 p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) &&
3769 pAct->GetBigRange().Intersects( p->GetBigRange() ) )
3770 {
3771 p->SetDeletedIn( pAct );
3772 }
3773 }
3774
3775 for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() )
3776 {
3777 if ( p == pAct )
3778 {
3779 continue;
3780 }
3781 if ( !p->IsDeletedIn( pAct ) && p->GetActionNumber() <= pAct->GetActionNumber() )
3782 {
3783 p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz );
3784 }
3785 }
3786 }
3787 break;
3788 }
3789 }
3790}
3791
3793 ScChangeActionMap& rMap, bool bListMasterDelete, bool bAllFlat ) const
3794{
3795 //TODO: bAllFlat==TRUE: called internally from Accept or Reject
3796 //TODO: => Generated will not be added
3797 bool bIsDelete = pAct->IsDeleteType();
3798 bool bIsMasterDelete = ( bListMasterDelete && pAct->IsMasterDelete() );
3799
3800 const ScChangeAction* pCur = nullptr;
3801 ::std::stack<ScChangeAction*> cStack;
3802 cStack.push(pAct);
3803
3804 while ( !cStack.empty() )
3805 {
3806 pCur = cStack.top();
3807 cStack.pop();
3808
3809 if ( pCur->IsInsertType() )
3810 {
3812 while ( pL )
3813 {
3814 ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction());
3815 if ( p != pAct )
3816 {
3817 if ( bAllFlat )
3818 {
3819 sal_uLong n = p->GetActionNumber();
3820 if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second )
3821 if ( p->HasDependent() )
3822 cStack.push( p );
3823 }
3824 else
3825 {
3826 if ( p->GetType() == SC_CAT_CONTENT )
3827 {
3828 if ( static_cast<ScChangeActionContent*>(p)->IsTopContent() )
3829 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3830 }
3831 else
3832 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3833 }
3834 }
3835 pL = pL->GetNext();
3836 }
3837 }
3838 else if ( pCur->IsDeleteType() )
3839 {
3840 if ( bIsDelete )
3841 { // Contents of deleted Ranges are only of interest on Delete
3842 ScChangeActionDel* pDel = const_cast<ScChangeActionDel*>(static_cast<const ScChangeActionDel*>(pCur));
3843 if ( !bAllFlat && bIsMasterDelete && pCur == pAct )
3844 {
3845 // Corresponding Deletes to this Delete to the same level,
3846 // if this Delete is at the top of a Row
3848 ScChangeAction* p = pDel;
3849 for (;;)
3850 {
3851 p = p->GetPrev();
3852 if (!p || p->GetType() != eType ||
3853 static_cast<ScChangeActionDel*>(p)->IsTopDelete() )
3854 break;
3855 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3856 }
3857 // delete this in the map too
3858 rMap.insert( ::std::make_pair( pAct->GetActionNumber(), pAct ) );
3859 }
3860 else
3861 {
3863 while ( pL )
3864 {
3865 ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction());
3866 if ( p != pAct )
3867 {
3868 if ( bAllFlat )
3869 {
3870 // Only a TopContent of a chain is in LinkDeleted
3871 sal_uLong n = p->GetActionNumber();
3872 if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second )
3873 if ( p->HasDeleted() ||
3874 p->GetType() == SC_CAT_CONTENT )
3875 cStack.push( p );
3876 }
3877 else
3878 {
3879 if ( p->IsDeleteType() )
3880 { // Further TopDeletes to same level: it's not rejectable
3881 if ( static_cast<ScChangeActionDel*>(p)->IsTopDelete() )
3882 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3883 }
3884 else
3885 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3886 }
3887 }
3888 pL = pL->GetNext();
3889 }
3890 }
3891 }
3892 }
3893 else if ( pCur->GetType() == SC_CAT_MOVE )
3894 {
3895 // Deleted Contents in ToRange
3897 while ( pL )
3898 {
3899 ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction());
3900 if ( p != pAct && rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) ).second )
3901 {
3902 // Only one TopContent of a chain is in LinkDeleted
3903 if ( bAllFlat && (p->HasDeleted() ||
3904 p->GetType() == SC_CAT_CONTENT) )
3905 cStack.push( p );
3906 }
3907 pL = pL->GetNext();
3908 }
3909 // New Contents in FromRange or new FromRange in ToRange
3910 // or Inserts/Deletes in FromRange/ToRange
3911 pL = pCur->GetFirstDependentEntry();
3912 while ( pL )
3913 {
3914 ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction());
3915 if ( p != pAct )
3916 {
3917 if ( bAllFlat )
3918 {
3919 sal_uLong n = p->GetActionNumber();
3920 if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second )
3921 if ( p->HasDependent() || p->HasDeleted() )
3922 cStack.push( p );
3923 }
3924 else
3925 {
3926 if ( p->GetType() == SC_CAT_CONTENT )
3927 {
3928 if ( static_cast<ScChangeActionContent*>(p)->IsTopContent() )
3929 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3930 }
3931 else
3932 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3933 }
3934 }
3935 pL = pL->GetNext();
3936 }
3937 }
3938 else if ( pCur->GetType() == SC_CAT_CONTENT )
3939 { // All changes at same position
3940 ScChangeActionContent* pContent = const_cast<ScChangeActionContent*>(static_cast<const ScChangeActionContent*>(pCur));
3941 // All preceding ones
3942 while ( ( pContent = pContent->GetPrevContent() ) != nullptr )
3943 {
3944 if ( !pContent->IsRejected() )
3945 rMap.insert( ::std::make_pair( pContent->GetActionNumber(), pContent ) );
3946 }
3947 pContent = const_cast<ScChangeActionContent*>(static_cast<const ScChangeActionContent*>(pCur));
3948 // All succeeding ones
3949 while ( ( pContent = pContent->GetNextContent() ) != nullptr )
3950 {
3951 if ( !pContent->IsRejected() )
3952 rMap.insert( ::std::make_pair( pContent->GetActionNumber(), pContent ) );
3953 }
3954 // all MatrixReferences of a MatrixOrigin
3956 while ( pL )
3957 {
3958 ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction());
3959 if ( p != pAct )
3960 {
3961 if ( bAllFlat )
3962 {
3963 sal_uLong n = p->GetActionNumber();
3964 if ( !IsGenerated( n ) && rMap.insert( ::std::make_pair( n, p ) ).second )
3965 if ( p->HasDependent() )
3966 cStack.push( p );
3967 }
3968 else
3969 rMap.insert( ::std::make_pair( p->GetActionNumber(), p ) );
3970 }
3971 pL = pL->GetNext();
3972 }
3973 }
3974 else if ( pCur->GetType() == SC_CAT_REJECT )
3975 {
3976 if ( bAllFlat )
3977 {
3979 static_cast<const ScChangeActionReject*>(pCur)->GetRejectAction() );
3980 if (p != pAct && rMap.find( p->GetActionNumber() ) == rMap.end())
3981 cStack.push( p );
3982 }
3983 }
3984 }
3985}
3986
3988{
3989 if ( pAct->GetType() != SC_CAT_CONTENT )
3990 return false;
3991
3992 ScChangeActionContent* pContent = static_cast<ScChangeActionContent*>(pAct);
3993 if ( bOldest )
3994 {
3995 pContent = pContent->GetTopContent();
3996 for (;;)
3997 {
3998 ScChangeActionContent* pPrevContent = pContent->GetPrevContent();
3999 if ( !pPrevContent || !pPrevContent->IsVirgin() )
4000 break;
4001 pContent = pPrevContent;
4002 }
4003 }
4004
4005 if ( !pContent->IsClickable() )
4006 return false;
4007
4008 ScBigRange aBigRange( pContent->GetBigRange() );
4009 const ScCellValue& rCell = (bOldest ? pContent->GetOldCell() : pContent->GetNewCell());
4011 {
4012 SCCOL nC;
4013 SCROW nR;
4014 rCell.getFormula()->GetMatColsRows(nC, nR);
4015 aBigRange.aEnd.IncCol( nC-1 );
4016 aBigRange.aEnd.IncRow( nR-1 );
4017 }
4018
4019 if ( !aBigRange.IsValid( rDoc ) )
4020 return false;
4021
4022 ScRange aRange( aBigRange.MakeRange( rDoc ) );
4023 if ( !rDoc.IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(),
4024 aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) )
4025 return false;
4026
4027 if ( pContent->HasDependent() )
4028 {
4029 bool bOk = true;
4030 ::std::stack<ScChangeActionContent*> aRejectActions;
4031 const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry();
4032 while ( pL )
4033 {
4034 ScChangeAction* p = const_cast<ScChangeAction*>(pL->GetAction());
4035 if ( p != pContent )
4036 {
4037 if ( p->GetType() == SC_CAT_CONTENT )
4038 {
4039 // we don't need no recursion here, do we?
4040 bOk &= static_cast<ScChangeActionContent*>(p)->Select( rDoc, this,
4041 bOldest, &aRejectActions );
4042 }
4043 else
4044 {
4045 OSL_FAIL( "ScChangeTrack::SelectContent: content dependent no content" );
4046 }
4047 }
4048 pL = pL->GetNext();
4049 }
4050
4051 bOk &= pContent->Select( rDoc, this, bOldest, nullptr );
4052 // now the matrix is inserted and new content values are ready
4053
4054 while ( !aRejectActions.empty() )
4055 {
4056 ScChangeActionContent* pNew = aRejectActions.top();
4057 aRejectActions.pop();
4058 ScAddress aPos( pNew->GetBigRange().aStart.MakeAddress( rDoc ) );
4059 ScCellValue aCell;
4060 aCell.assign(rDoc, aPos);
4061 pNew->SetNewValue(aCell, &rDoc);
4062 Append( pNew );
4063 }
4064 return bOk;
4065 }
4066 else
4067 return pContent->Select( rDoc, this, bOldest, nullptr );
4068}
4069
4071{
4072 for ( ScChangeAction* p = GetFirst(); p; p = p->GetNext() )
4073 {
4074 p->Accept();
4075 }
4076}
4077
4079{
4080 if ( !pAct->IsClickable() )
4081 return false;
4082
4083 if ( pAct->IsDeleteType() || pAct->GetType() == SC_CAT_CONTENT )
4084 {
4085 ScChangeActionMap aActionMap;
4086
4087 GetDependents( pAct, aActionMap, false, true );
4088
4089 for( auto& rEntry : aActionMap )
4090 {
4091 rEntry.second->Accept();
4092 }
4093 }
4094 pAct->Accept();
4095 return true;
4096}
4097
4099{
4100 bool bOk = true;
4101 for ( ScChangeAction* p = GetLast(); p && bOk; p = p->GetPrev() )
4102 { //TODO: Traverse backwards as dependencies attached to RejectActions
4103 if ( p->IsInternalRejectable() )
4104 bOk = Reject( p );
4105 }
4106 return bOk;
4107}
4108
4109bool ScChangeTrack::Reject( ScChangeAction* pAct, bool bShared )
4110{
4111 // #i100895# When collaboration changes are reversed, it must be possible
4112 // to reject a deleted row above another deleted row.
4113 if ( bShared && pAct->IsDeletedIn() )
4114 pAct->RemoveAllDeletedIn();
4115
4116 if ( !pAct->IsRejectable() )
4117 return false;
4118
4119 std::unique_ptr<ScChangeActionMap> pMap;
4120 if ( pAct->HasDependent() )
4121 {
4122 pMap.reset(new ScChangeActionMap);
4123 GetDependents( pAct, *pMap, false, true );
4124 }
4125 bool bRejected = Reject( pAct, pMap.get(), false );
4126 return bRejected;
4127}
4128
4130 ScChangeAction* pAct, ScChangeActionMap* pMap, bool bRecursion )
4131{
4132 if ( !pAct->IsInternalRejectable() )
4133 return false;
4134
4135 bool bOk = true;
4136 bool bRejected = false;
4137 if ( pAct->IsInsertType() )
4138 {
4139 if ( pAct->HasDependent() && !bRecursion )
4140 {
4141 OSL_ENSURE( pMap, "ScChangeTrack::Reject: Insert without map" );
4142 ScChangeActionMap::reverse_iterator itChangeAction;
4143 for (itChangeAction = pMap->rbegin();
4144 itChangeAction != pMap->rend() && bOk; ++itChangeAction)
4145 {
4146 // Do not restore Contents which would end up being deleted anyways
4147 if ( itChangeAction->second->GetType() == SC_CAT_CONTENT )
4148 itChangeAction->second->SetRejected();
4149 else if ( itChangeAction->second->IsDeleteType() )
4150 itChangeAction->second->Accept(); // Deleted to Nirvana
4151 else
4152 bOk = Reject( itChangeAction->second, nullptr, true ); // Recursion!
4153 }
4154 }
4155 if ( bOk )
4156 {
4157 bRejected = pAct->Reject( rDoc );
4158 if ( bRejected )
4159 {
4160 // pRefDoc NULL := Do not save deleted Cells
4161 AppendDeleteRange( pAct->GetBigRange().MakeRange( rDoc ), nullptr, short(0),
4162 pAct->GetActionNumber() );
4163 }
4164 }
4165 }
4166 else if ( pAct->IsDeleteType() )
4167 {
4168 OSL_ENSURE( !pMap, "ScChangeTrack::Reject: Delete with map" );
4169 ScBigRange aDelRange;
4170 sal_uLong nRejectAction = pAct->GetActionNumber();
4171 bool bTabDel, bTabDelOk;
4172 if ( pAct->GetType() == SC_CAT_DELETE_TABS )
4173 {
4174 bTabDel = true;
4175 aDelRange = pAct->GetBigRange();
4176 bTabDelOk = pAct->Reject( rDoc );
4177 bOk = bTabDelOk;
4178 if ( bOk )
4179 {
4180 pAct = pAct->GetPrev();
4181 bOk = ( pAct && pAct->GetType() == SC_CAT_DELETE_COLS );
4182 }
4183 }
4184 else
4185 bTabDel = bTabDelOk = false;
4186 ScChangeActionDel* pDel = static_cast<ScChangeActionDel*>(pAct);
4187 if ( bOk )
4188 {
4189 aDelRange = pDel->GetOverAllRange();
4190 bOk = aDelRange.IsValid( rDoc );
4191 }
4192 bool bOneOk = false;
4193 if ( bOk )
4194 {
4195 ScChangeActionType eActType = pAct->GetType();
4196 switch ( eActType )
4197 {
4198 case SC_CAT_DELETE_COLS :
4199 aDelRange.aStart.SetCol( aDelRange.aEnd.Col() );
4200 break;
4201 case SC_CAT_DELETE_ROWS :
4202 aDelRange.aStart.SetRow( aDelRange.aEnd.Row() );
4203 break;
4204 case SC_CAT_DELETE_TABS :
4205 aDelRange.aStart.SetTab( aDelRange.aEnd.Tab() );
4206 break;
4207 default:
4208 {
4209 // added to avoid warnings
4210 }
4211 }
4212 ScChangeAction* p = pAct;
4213 bool bLoop = true;
4214 do
4215 {
4216 pDel = static_cast<ScChangeActionDel*>(p);
4217 bOk = pDel->Reject( rDoc );
4218 if ( bOk )
4219 {
4220 if ( bOneOk )
4221 {
4222 switch ( pDel->GetType() )
4223 {
4224 case SC_CAT_DELETE_COLS :
4225 aDelRange.aStart.IncCol( -1 );
4226 break;
4227 case SC_CAT_DELETE_ROWS :
4228 aDelRange.aStart.IncRow( -1 );
4229 break;
4230 case SC_CAT_DELETE_TABS :
4231 aDelRange.aStart.IncTab( -1 );
4232 break;
4233 default:
4234 {
4235 // added to avoid warnings
4236 }
4237 }
4238 }
4239 else
4240 bOneOk = true;
4241 }
4242 if ( pDel->IsBaseDelete() )
4243 bLoop = false;
4244 else
4245 p = p->GetPrev();
4246 } while ( bOk && bLoop && p && p->GetType() == eActType &&
4247 !static_cast<ScChangeActionDel*>(p)->IsTopDelete() );
4248 }
4249 bRejected = bOk;
4250 if ( bOneOk || (bTabDel && bTabDelOk) )
4251 {
4252 // Delete Reject made UpdateReference Undo
4253 ScChangeActionIns* pReject = new ScChangeActionIns( &rDoc,
4254 aDelRange.MakeRange( rDoc ) );
4255 pReject->SetRejectAction( nRejectAction );
4256 pReject->SetState( SC_CAS_ACCEPTED );
4257 Append( pReject );
4258 }
4259 }
4260 else if ( pAct->GetType() == SC_CAT_MOVE )
4261 {
4262 if ( pAct->HasDependent() && !bRecursion )
4263 {
4264 OSL_ENSURE( pMap, "ScChangeTrack::Reject: Move without Map" );
4265 ScChangeActionMap::reverse_iterator itChangeAction;
4266
4267 for( itChangeAction = pMap->rbegin(); itChangeAction != pMap->rend() && bOk; ++itChangeAction )
4268 {
4269 bOk = Reject( itChangeAction->second, nullptr, true ); // Recursion!
4270 }
4271 }
4272 if ( bOk )
4273 {
4274 bRejected = pAct->Reject( rDoc );
4275 if ( bRejected )
4276 {
4278 pAct->GetBigRange().MakeRange( rDoc ),
4279 static_cast<ScChangeActionMove*>(pAct)->GetFromRange().MakeRange( rDoc ), this );
4280 pReject->SetRejectAction( pAct->GetActionNumber() );
4281 pReject->SetState( SC_CAS_ACCEPTED );
4282 Append( pReject );
4283 }
4284 }
4285 }
4286 else if ( pAct->GetType() == SC_CAT_CONTENT )
4287 {
4288 ScRange aRange;
4289 ScChangeActionContent* pReject;
4290 if ( bRecursion )
4291 pReject = nullptr;
4292 else
4293 {
4294 aRange = pAct->GetBigRange().aStart.MakeAddress( rDoc );
4295 pReject = new ScChangeActionContent( aRange );
4296 ScCellValue aCell;
4297 aCell.assign(rDoc, aRange.aStart);
4298 pReject->SetOldValue(aCell, &rDoc, &rDoc);
4299 }
4300 bRejected = pAct->Reject( rDoc );
4301 if ( bRejected && !bRecursion )
4302 {
4303 ScCellValue aCell;
4304 aCell.assign(rDoc, aRange.aStart);
4305 pReject->SetNewValue(aCell, &rDoc);
4306 pReject->SetRejectAction( pAct->GetActionNumber() );
4307 pReject->SetState( SC_CAS_ACCEPTED );
4308 Append( pReject );
4309 }
4310 else
4311 delete pReject;
4312 }
4313 else
4314 {
4315 OSL_FAIL( "ScChangeTrack::Reject: say what?" );
4316 }
4317
4318 return bRejected;
4319}
4320
4322{
4323 return nNum == nActionMax && pLast && pLast->GetActionNumber() == nNum;
4324}
4325
4327 const ScCellValue& rNewCell, const ScBigRange& aBigRange, const OUString& sNewValue )
4328{
4329 ScChangeActionContent* pAct = new ScChangeActionContent( --nGeneratedMin, rNewCell, aBigRange, &rDoc, sNewValue );
4334 aGeneratedMap.insert( ::std::make_pair( pAct->GetActionNumber(), pAct ) );
4335 return pAct->GetActionNumber();
4336}
4337
4339{
4340 aMap.insert( ::std::make_pair( pAppend->GetActionNumber(), pAppend ) );
4341 if ( !pLast )
4342 pFirst = pLast = pAppend;
4343 else
4344 {
4345 pLast->pNext = pAppend;
4346 pAppend->pPrev = pLast;
4347 pLast = pAppend;
4348 }
4349}
4350
4352{
4353 if ( !pDocument )
4354 {
4355 return nullptr;
4356 }
4357
4358 std::unique_ptr<ScChangeTrack> pClonedTrack(new ScChangeTrack( *pDocument ));
4359 pClonedTrack->SetTimeNanoSeconds( IsTimeNanoSeconds() );
4360
4361 // clone generated actions
4362 ::std::stack< const ScChangeAction* > aGeneratedStack;
4363 const ScChangeAction* pGenerated = GetFirstGenerated();
4364 while ( pGenerated )
4365 {
4366 aGeneratedStack.push( pGenerated );
4367 pGenerated = pGenerated->GetNext();
4368 }
4369 while ( !aGeneratedStack.empty() )
4370 {
4371 pGenerated = aGeneratedStack.top();
4372 aGeneratedStack.pop();
4373 const ScChangeActionContent& rContent = dynamic_cast<const ScChangeActionContent&>(*pGenerated);
4374 const ScCellValue& rNewCell = rContent.GetNewCell();
4375 if (!rNewCell.isEmpty())
4376 {
4377 ScCellValue aClonedNewCell;
4378 aClonedNewCell.assign(rNewCell, *pDocument);
4379 OUString aNewValue = rContent.GetNewString( pDocument );
4380 pClonedTrack->nGeneratedMin = pGenerated->GetActionNumber() + 1;
4381 pClonedTrack->AddLoadedGenerated(aClonedNewCell, pGenerated->GetBigRange(), aNewValue);
4382 }
4383 }
4384
4385 // clone actions
4386 const ScChangeAction* pAction = GetFirst();
4387 while ( pAction )
4388 {
4389 ScChangeAction* pClonedAction = nullptr;
4390
4391 switch ( pAction->GetType() )
4392 {
4393 case SC_CAT_INSERT_COLS:
4394 case SC_CAT_INSERT_ROWS:
4395 case SC_CAT_INSERT_TABS:
4396 {
4397 bool bEndOfList = static_cast<const ScChangeActionIns*>(pAction)->IsEndOfList();
4398 pClonedAction = new ScChangeActionIns(
4399 pAction->GetActionNumber(),
4400 pAction->GetState(),
4401 pAction->GetRejectAction(),
4402 pAction->GetBigRange(),
4403 pAction->GetUser(),
4404 pAction->GetDateTimeUTC(),
4405 pAction->GetComment(),
4406 pAction->GetType(),
4407 bEndOfList );
4408 }
4409 break;
4410 case SC_CAT_DELETE_COLS:
4411 case SC_CAT_DELETE_ROWS:
4412 case SC_CAT_DELETE_TABS:
4413 {
4414 const ScChangeActionDel& rDelete = dynamic_cast<const ScChangeActionDel&>(*pAction);
4415
4416 SCCOLROW nD = 0;
4417 ScChangeActionType eType = pAction->GetType();
4418 if ( eType == SC_CAT_DELETE_COLS )
4419 {
4420 nD = static_cast< SCCOLROW >( rDelete.GetDx() );
4421 }
4422 else if ( eType == SC_CAT_DELETE_ROWS )
4423 {
4424 nD = static_cast< SCCOLROW >( rDelete.GetDy() );
4425 }
4426
4427 pClonedAction = new ScChangeActionDel(
4428 pAction->GetActionNumber(),
4429 pAction->GetState(),
4430 pAction->GetRejectAction(),
4431 pAction->GetBigRange(),
4432 pAction->GetUser(),
4433 pAction->GetDateTimeUTC(),
4434 pAction->GetComment(),
4435 eType,
4436 nD,
4437 pClonedTrack.get() );
4438 }
4439 break;
4440 case SC_CAT_MOVE:
4441 {
4442 auto pMove = dynamic_cast<const ScChangeActionMove*>(pAction);
4443 assert(pMove && "ScChangeTrack::Clone: pMove is null!");
4444
4445 pClonedAction = new ScChangeActionMove(
4446 pAction->GetActionNumber(),
4447 pAction->GetState(),
4448 pAction->GetRejectAction(),
4449 pAction->GetBigRange(),
4450 pAction->GetUser(),
4451 pAction->GetDateTimeUTC(),
4452 pAction->GetComment(),
4453 pMove->GetFromRange(),
4454 pClonedTrack.get() );
4455 }
4456 break;
4457 case SC_CAT_CONTENT:
4458 {
4459 const ScChangeActionContent& rContent = dynamic_cast<const ScChangeActionContent&>(*pAction);
4460 const ScCellValue& rOldCell = rContent.GetOldCell();
4461 ScCellValue aClonedOldCell;
4462 aClonedOldCell.assign(rOldCell, *pDocument);
4463 OUString aOldValue = rContent.GetOldString( pDocument );
4464
4465 ScChangeActionContent* pClonedContent = new ScChangeActionContent(
4466 pAction->GetActionNumber(),
4467 pAction->GetState(),
4468 pAction->GetRejectAction(),
4469 pAction->GetBigRange(),
4470 pAction->GetUser(),
4471 pAction->GetDateTimeUTC(),
4472 pAction->GetComment(),
4473 std::move(aClonedOldCell),
4474 pDocument,
4475 aOldValue );
4476
4477 const ScCellValue& rNewCell = rContent.GetNewCell();
4478 if (!rNewCell.isEmpty())
4479 {
4480 ScCellValue aClonedNewCell;
4481 aClonedNewCell.assign(rNewCell, *pDocument);
4482 pClonedContent->SetNewValue(aClonedNewCell, pDocument);
4483 }
4484
4485 pClonedAction = pClonedContent;
4486 }
4487 break;
4488 case SC_CAT_REJECT:
4489 {
4490 pClonedAction = new ScChangeActionReject(
4491 pAction->GetActionNumber(),
4492 pAction->GetState(),
4493 pAction->GetRejectAction(),
4494 pAction->GetBigRange(),
4495 pAction->GetUser(),
4496 pAction->GetDateTimeUTC(),
4497 pAction->GetComment() );
4498 }
4499 break;
4500 default:
4501 {
4502 }
4503 break;
4504 }
4505
4506 if ( pClonedAction )
4507 {
4508 pClonedTrack->AppendCloned( pClonedAction );
4509 }
4510
4511 pAction = pAction->GetNext();
4512 }
4513
4514 if ( pClonedTrack->GetLast() )
4515 {
4516 pClonedTrack->SetActionMax( pClonedTrack->GetLast()->GetActionNumber() );
4517 }
4518
4519 // set dependencies for Deleted/DeletedIn
4520 pAction = GetFirst();
4521 while ( pAction )
4522 {
4523 if ( pAction->HasDeleted() )
4524 {
4525 ::std::stack< sal_uLong > aStack;
4526 const ScChangeActionLinkEntry* pL = pAction->GetFirstDeletedEntry();
4527 while ( pL )
4528 {
4529 const ScChangeAction* pDeleted = pL->GetAction();
4530 if ( pDeleted )
4531 {
4532 aStack.push( pDeleted->GetActionNumber() );
4533 }
4534 pL = pL->GetNext();
4535 }
4536 ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() );
4537 if ( pClonedAction )
4538 {
4539 while ( !aStack.empty() )
4540 {
4541 ScChangeAction* pClonedDeleted = pClonedTrack->GetActionOrGenerated( aStack.top() );
4542 aStack.pop();
4543 if ( pClonedDeleted )
4544 {
4545 pClonedDeleted->SetDeletedIn( pClonedAction );
4546 }
4547 }
4548 }
4549 }
4550 pAction = pAction->GetNext();
4551 }
4552
4553 // set dependencies for Dependent/Any
4554 pAction = GetLast();
4555 while ( pAction )
4556 {
4557 if ( pAction->HasDependent() )
4558 {
4559 ::std::stack< sal_uLong > aStack;
4560 const ScChangeActionLinkEntry* pL = pAction->GetFirstDependentEntry();
4561 while ( pL )
4562 {
4563 const ScChangeAction* pDependent = pL->GetAction();
4564 if ( pDependent )
4565 {
4566 aStack.push( pDependent->GetActionNumber() );
4567 }
4568 pL = pL->GetNext();
4569 }
4570 ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() );
4571 if ( pClonedAction )
4572 {
4573 while ( !aStack.empty() )
4574 {
4575 ScChangeAction* pClonedDependent = pClonedTrack->GetActionOrGenerated( aStack.top() );
4576 aStack.pop();
4577 if ( pClonedDependent )
4578 {
4579 ScChangeActionLinkEntry* pLink = pClonedAction->AddDependent( pClonedDependent );
4580 p