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