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 if ( pClonedDependent )
4588 {
4589 ScChangeActionLinkEntry* pLink = pClonedAction->AddDependent( pClonedDependent );
4590 pClonedDependent->AddLink( pClonedAction, pLink );
4591 }
4592 }
4593 }
4594 }
4595 pAction = pAction->GetPrev();
4596 }
4597
4598 // masterlinks
4599 ScChangeAction* pClonedAction = pClonedTrack->GetFirst();
4600 while ( pClonedAction )
4601 {
4602 pClonedTrack->MasterLinks( pClonedAction );
4603 pClonedAction = pClonedAction->GetNext();
4604 }
4605
4606 if ( IsProtected() )
4607 {
4608 pClonedTrack->SetProtection( GetProtection() );
4609 }
4610
4611 if ( pClonedTrack->GetLast() )
4612 {
4613 pClonedTrack->SetLastSavedActionNumber( pClonedTrack->GetLast()->GetActionNumber() );
4614 }
4615
4616 auto tmp = pClonedTrack.get();
4617 pDocument->SetChangeTrack( std::move(pClonedTrack) );
4618
4619 return tmp;
4620}
4621
4623{
4624 if ( !pAct->IsVirgin() )
4625 return;
4626
4627 if ( pOtherAct->IsAccepted() )
4628 {
4629 pAct->Accept();
4630 if ( pOtherAct->IsRejecting() )
4631 {
4632 pAct->SetRejectAction( pOtherAct->GetRejectAction() );
4633 }
4634 }
4635 else if ( pOtherAct->IsRejected() )
4636 {
4637 pAct->SetRejected();
4638 }
4639}
4640
4642static void lcl_getTrackedChange(ScDocument& rDoc, int nIndex, const ScChangeAction* pAction, tools::JsonWriter& rRedlines)
4643{
4644 if (pAction->GetType() != SC_CAT_CONTENT)
4645 return;
4646
4647 auto redlinesNode = rRedlines.startStruct();
4648 rRedlines.put("index", static_cast<sal_Int64>(nIndex));
4649
4650 rRedlines.put("author", pAction->GetUser());
4651
4652 rRedlines.put("type", "Modify");
4653
4654 rRedlines.put("comment", pAction->GetComment());
4655
4656 OUString aDescription = pAction->GetDescription(rDoc, true);
4657 rRedlines.put("description", aDescription);
4658
4659 OUString sDateTime = utl::toISO8601(pAction->GetDateTimeUTC().GetUNODateTime());
4660 rRedlines.put("dateTime", sDateTime);
4661}
4662
4664{
4665 auto redlinesNode = aRedlines.startArray("redlines");
4666
4667 ScChangeAction* pAction = GetFirst();
4668 if (pAction)
4669 {
4670 int i = 0;
4671 lcl_getTrackedChange(rDoc, i++, pAction, aRedlines);
4672 ScChangeAction* pLastAction = GetLast();
4673 while (pAction != pLastAction)
4674 {
4675 pAction = pAction->GetNext();
4676 lcl_getTrackedChange(rDoc, i++, pAction, aRedlines);
4677 }
4678 }
4679}
4680
4681/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
void ScColToAlpha(OUStringBuffer &rBuf, SCCOL nCol)
append alpha representation of column to buffer
Definition: address.cxx:1884
ScRefFlags
Definition: address.hxx:158
const SCTAB MAXTAB
Definition: address.hxx:70
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
static void lcl_getTrackedChange(ScDocument &rDoc, int nIndex, const ScChangeAction *pAction, tools::JsonWriter &rRedlines)
Get info about a single ScChangeAction element.
Definition: chgtrack.cxx:4642
static void lcl_InvalidateReference(const ScDocument &rDoc, formula::FormulaToken &rTok, const ScBigAddress &rPos)
Definition: chgtrack.cxx:1804
ScChangeActionClipMode
Definition: chgtrack.hxx:84
@ SC_CACM_PASTE
Definition: chgtrack.hxx:87
@ SC_CACM_CUT
Definition: chgtrack.hxx:86
std::map< sal_uLong, ScChangeAction * > ScChangeActionMap
Definition: chgtrack.hxx:798
std::vector< ScChangeTrackMsgInfo > ScChangeTrackMsgQueue
Definition: chgtrack.hxx:796
ScChangeTrackMsgType
Definition: chgtrack.hxx:780
ScChangeActionType
Definition: chgtrack.hxx:63
@ SC_CAT_NONE
Definition: chgtrack.hxx:64
@ SC_CAT_MOVE
Definition: chgtrack.hxx:71
@ SC_CAT_DELETE_TABS
Definition: chgtrack.hxx:70
@ SC_CAT_INSERT_TABS
Definition: chgtrack.hxx:67
@ SC_CAT_DELETE_ROWS
Definition: chgtrack.hxx:69
@ SC_CAT_CONTENT
Definition: chgtrack.hxx:72
@ SC_CAT_REJECT
Definition: chgtrack.hxx:73
@ SC_CAT_DELETE_COLS
Definition: chgtrack.hxx:68
@ SC_CAT_INSERT_ROWS
Definition: chgtrack.hxx:66
@ SC_CAT_INSERT_COLS
Definition: chgtrack.hxx:65
class SAL_DLLPUBLIC_RTTI ScChangeActionMove
Definition: chgtrack.hxx:397
@ SC_CTMS_OTHER
Definition: chgtrack.hxx:806
@ SC_CTMS_UNDO
Definition: chgtrack.hxx:805
@ SC_CTMS_OWN
Definition: chgtrack.hxx:804
@ SC_CTMS_PREPARE
Definition: chgtrack.hxx:803
@ SC_CTMS_NONE
Definition: chgtrack.hxx:802
ScChangeActionState
Definition: chgtrack.hxx:77
@ SC_CAS_REJECTED
Definition: chgtrack.hxx:80
@ SC_CAS_VIRGIN
Definition: chgtrack.hxx:78
@ SC_CAS_ACCEPTED
Definition: chgtrack.hxx:79
#define SC_CHGTRACK_GENERATED_START
Definition: chgtrack.hxx:811
ScChangeActionContentCellType
Definition: chgtrack.hxx:587
@ SC_CACCT_MATORG
Definition: chgtrack.hxx:590
@ SC_CACCT_NONE
Definition: chgtrack.hxx:588
@ SC_CACCT_MATREF
Definition: chgtrack.hxx:591
@ SC_CACCT_NORMAL
Definition: chgtrack.hxx:589
void ConvertToUTC()
void ConvertToLocalTime()
css::util::DateTime GetUNODateTime() const
void IncTab(SCTAB nDelta=1)
Definition: address.hxx:320
SCTAB Tab() const
Definition: address.hxx:283
void Set(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: address.hxx:403
void SetCol(SCCOL nColP)
Definition: address.hxx:291
SC_DLLPUBLIC void Format(OStringBuffer &r, ScRefFlags nFlags, const ScDocument *pDocument=nullptr, const Details &rDetails=detailsOOOa1) const
Definition: address.cxx:2074
void IncCol(SCCOL nDelta=1)
Definition: address.hxx:316
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
void SetTab(SCTAB nTabP)
Definition: address.hxx:295
void IncRow(SCROW nDelta=1)
Definition: address.hxx:312
SCCOL Col() const
Definition: address.hxx:279
bool IsValid(const ScDocument &rDoc) const
Definition: bigrange.cxx:13
sal_Int64 Col() const
Definition: bigrange.hxx:44
void SetCol(sal_Int64 nColP)
Definition: bigrange.hxx:50
ScAddress MakeAddress(const ScDocument &rDoc) const
Definition: bigrange.hxx:74
void SetTab(sal_Int64 nTabP)
Definition: bigrange.hxx:52
void IncRow(sal_Int64 n=1)
Definition: bigrange.hxx:54
void IncCol(sal_Int64 n=1)
Definition: bigrange.hxx:53
void SetRow(sal_Int64 nRowP)
Definition: bigrange.hxx:51
sal_Int64 Row() const
Definition: bigrange.hxx:45
void IncTab(sal_Int64 n=1)
Definition: bigrange.hxx:55
void Set(sal_Int64 nColP, sal_Int64 nRowP, sal_Int64 nTabP)
Definition: bigrange.hxx:48
sal_Int64 Tab() const
Definition: bigrange.hxx:46
ScBigAddress aEnd
Definition: bigrange.hxx:109
bool Intersects(const ScBigRange &) const
do two ranges overlap?
Definition: bigrange.hxx:170
static constexpr sal_Int64 nRangeMin
Definition: bigrange.hxx:150
bool IsValid(const ScDocument &rDoc) const
Definition: bigrange.hxx:132
static constexpr sal_Int64 nRangeMax
Definition: bigrange.hxx:151
ScBigAddress aStart
Definition: bigrange.hxx:108
bool Contains(const ScBigAddress &) const
is Address& in range?
Definition: bigrange.hxx:154
ScRange MakeRange(const ScDocument &rDoc) const
Definition: bigrange.hxx:134
Walk through all cells in an area.
Definition: dociter.hxx:206
const ScAddress & GetPos() const
Definition: dociter.hxx:231
const ScRefCellValue & getRefCellValue() const
Definition: dociter.hxx:239
ScCellValue getCellValue() const
Definition: dociter.cxx:973
bool IsTopContent() const
Definition: chgtrack.hxx:700
void PutOldValueToDoc(ScDocument *, SCCOL nDx, SCROW nDy) const
Definition: chgtrack.cxx:1735
static bool NeedsNumberFormat(const ScCellValue &rVal)
Definition: chgtrack.cxx:1630
virtual ~ScChangeActionContent() override
Definition: chgtrack.cxx:1281
ScChangeActionContent * GetNextContent() const
Definition: chgtrack.hxx:697
OUString GetFormulaString(const ScFormulaCell *pCell) const
Definition: chgtrack.cxx:1721
void SetOldValue(const ScCellValue &rCell, const ScDocument *pFromDoc, ScDocument *pToDoc, sal_uLong nFormat)
Definition: chgtrack.cxx:1321
void InsertInSlot(ScChangeActionContent **pp)
Definition: chgtrack.hxx:608
ScChangeActionContent * GetPrevContent() const
Definition: chgtrack.hxx:698
virtual OUString GetRefString(ScDocument &rDoc, bool bFlag3D=false) const override
Definition: chgtrack.cxx:1430
ScChangeActionContent * pNextContent
Definition: chgtrack.hxx:603
bool IsMatrixOrigin() const
Definition: chgtrack.cxx:1964
virtual void UpdateReference(const ScChangeTrack *, UpdateRefMode, const ScBigRange &, sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz) override
Definition: chgtrack.cxx:1837
void PutValueToDoc(const ScCellValue &rCell, const OUString &rValue, ScDocument *pDoc, SCCOL nDx, SCROW nDy) const
Definition: chgtrack.cxx:1747
static void SetValue(OUString &rStr, ScCellValue &rCell, const ScAddress &rPos, const ScCellValue &rOrgCell, const ScDocument *pFromDoc, ScDocument *pToDoc)
Definition: chgtrack.cxx:1635
static ScChangeActionContentCellType GetContentCellType(const ScCellValue &rCell)
Definition: chgtrack.cxx:1577
void SetValueString(OUString &rValue, ScCellValue &rCell, const OUString &rStr, ScDocument *pDoc)
Definition: chgtrack.cxx:1359
void SetNewValue(const ScCellValue &rCell, ScDocument *pDoc)
Definition: chgtrack.cxx:1333
virtual ScChangeActionLinkEntry * GetDeletedIn() const override
Definition: chgtrack.cxx:1307
void SetPrevContent(ScChangeActionContent *p)
Definition: chgtrack.hxx:730
const ScCellValue & GetNewCell() const
Definition: chgtrack.hxx:740
virtual ScChangeActionLinkEntry ** GetDeletedInAddress() override
Definition: chgtrack.cxx:1314
void SetOldNewCells(const ScCellValue &rOldCell, sal_uLong nOldFormat, const ScCellValue &rNewCell, sal_uLong nNewFormat, const ScDocument *pDoc)
Definition: chgtrack.cxx:1338
virtual OUString GetDescription(ScDocument &rDoc, bool bSplitRange=false, bool bWarning=true) const override
Definition: chgtrack.cxx:1390
bool IsOldMatrixReference() const
Definition: chgtrack.cxx:1969
virtual bool Reject(ScDocument &rDoc) override
Definition: chgtrack.cxx:1463
void SetNextContent(ScChangeActionContent *p)
Definition: chgtrack.hxx:728
static void SetCell(OUString &rStr, ScCellValue &rCell, sal_uLong nFormat, const ScDocument *pDoc)
Definition: chgtrack.cxx:1673
void SetNewCell(const ScCellValue &rCell, const ScDocument *pDoc, const OUString &rFormatted)
Definition: chgtrack.cxx:1348
const ScCellValue & GetOldCell() const
Definition: chgtrack.hxx:739
ScCellValue maOldCell
Definition: chgtrack.hxx:598
OUString GetValueString(const OUString &rValue, const ScCellValue &rCell, const ScDocument *pDoc) const
Definition: chgtrack.cxx:1695
static OUString GetStringOfCell(const ScCellValue &rCell, const ScDocument *pDoc, const ScAddress &rPos)
Definition: chgtrack.cxx:1541
ScChangeActionContent * GetTopContent() const
Definition: chgtrack.cxx:1295
OUString GetOldString(const ScDocument *pDoc) const
Definition: chgtrack.cxx:1380
void PutNewValueToDoc(ScDocument *, SCCOL nDx, SCROW nDy) const
Definition: chgtrack.cxx:1741
ScCellValue maNewCell
Definition: chgtrack.hxx:599
OUString GetNewString(const ScDocument *pDoc) const
Definition: chgtrack.cxx:1385
bool Select(ScDocument &, ScChangeTrack *, bool bOldest, ::std::stack< ScChangeActionContent * > *pRejectActions)
Definition: chgtrack.cxx:1476
ScChangeActionContent * pPrevContent
Definition: chgtrack.hxx:604
short GetCutOffTo() const
Definition: chgtrack.hxx:422
short GetCutOffFrom() const
Definition: chgtrack.hxx:421
ScChangeActionMove * GetMove()
Definition: chgtrack.hxx:574
bool IsBaseDelete() const
Definition: chgtrack.cxx:806
bool IsMultiDelete() const
Definition: chgtrack.cxx:819
virtual void UpdateReference(const ScChangeTrack *, UpdateRefMode, const ScBigRange &, sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz) override
Definition: chgtrack.cxx:848
ScChangeTrack * pTrack
Definition: chgtrack.hxx:430
ScChangeActionDelMoveEntry * AddCutOffMove(ScChangeActionMove *pMove, short nFrom, short nTo)
Definition: chgtrack.cxx:842
SCROW GetDy() const
Definition: chgtrack.hxx:477
virtual void AddContent(ScChangeActionContent *) override
Definition: chgtrack.cxx:796
std::vector< ScChangeActionContent * > mvCells
Definition: chgtrack.hxx:431
void SetCutOffInsert(ScChangeActionIns *p, short n)
Definition: chgtrack.hxx:488
virtual void DeleteCellEntries() override
Definition: chgtrack.cxx:801
bool IsTabDeleteCol() const
Definition: chgtrack.cxx:831
ScChangeActionDelMoveEntry * pLinkMove
Definition: chgtrack.hxx:434
SCCOL GetDx() const
Definition: chgtrack.hxx:476
virtual ~ScChangeActionDel() override
Definition: chgtrack.cxx:786
void UndoCutOffInsert()
Definition: chgtrack.cxx:1056
ScBigRange GetOverAllRange() const
Definition: chgtrack.cxx:887
bool IsTopDelete() const
Definition: chgtrack.cxx:811
void UndoCutOffMoves()
Definition: chgtrack.cxx:1007
virtual bool Reject(ScDocument &rDoc) override
Definition: chgtrack.cxx:937
virtual OUString GetDescription(ScDocument &rDoc, bool bSplitRange=false, bool bWarning=true) const override
Definition: chgtrack.cxx:895
ScChangeActionIns * pCutOff
Definition: chgtrack.hxx:432
virtual bool Reject(ScDocument &rDoc) override
Definition: chgtrack.cxx:699
virtual ~ScChangeActionIns() override
Definition: chgtrack.cxx:658
virtual OUString GetDescription(ScDocument &rDoc, bool bSplitRange=false, bool bWarning=true) const override
Definition: chgtrack.cxx:662
SC_DLLPUBLIC bool IsEndOfList() const
Definition: chgtrack.cxx:694
A link/connection/dependency between change actions.
Definition: chgtrack.hxx:103
const ScChangeAction * GetAction() const
Definition: chgtrack.hxx:167
const ScChangeActionLinkEntry * GetNext() const
Definition: chgtrack.hxx:165
void SetLink(ScChangeActionLinkEntry *pLinkP)
Definition: chgtrack.hxx:136
virtual ~ScChangeActionMove() override
Definition: chgtrack.cxx:1104
virtual void UpdateReference(const ScChangeTrack *, UpdateRefMode, const ScBigRange &, sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz) override
Definition: chgtrack.cxx:1119
ScChangeTrack * pTrack
Definition: chgtrack.hxx:505
std::vector< ScChangeActionContent * > mvCells
Definition: chgtrack.hxx:506
virtual void AddContent(ScChangeActionContent *) override
Definition: chgtrack.cxx:1109
sal_uLong GetEndLastCut() const
Definition: chgtrack.hxx:529
ScBigRange & GetFromRange()
Definition: chgtrack.hxx:524
virtual bool Reject(ScDocument &rDoc) override
Definition: chgtrack.cxx:1173
virtual OUString GetDescription(ScDocument &rDoc, bool bSplitRange=false, bool bWarning=true) const override
Definition: chgtrack.cxx:1136
SC_DLLPUBLIC void GetDelta(sal_Int32 &nDx, sal_Int32 &nDy, sal_Int32 &nDz) const
Definition: chgtrack.cxx:1127
sal_uLong GetStartLastCut() const
Definition: chgtrack.hxx:527
ScBigRange aFromRange
Definition: chgtrack.hxx:504
virtual OUString GetRefString(ScDocument &rDoc, bool bFlag3D=false) const override
Definition: chgtrack.cxx:1163
virtual void DeleteCellEntries() override
Definition: chgtrack.cxx:1114
virtual bool Reject(ScDocument &rDoc) override
Definition: chgtrack.cxx:1984
ScChangeActionReject(const sal_uLong nActionNumber, const ScChangeActionState eState, const sal_uLong nRejectingNumber, const ScBigRange &aBigRange, const OUString &aUser, const DateTime &aDateTime, const OUString &sComment)
Definition: chgtrack.cxx:1975
DateTime aDateTime
Definition: chgtrack.hxx:189
ScChangeActionLinkEntry * pLinkDeleted
Definition: chgtrack.hxx:197
void SetDeletedInThis(sal_uLong nActionNumber, const ScChangeTrack *pTrack)
Definition: chgtrack.cxx:590
void SetDeletedIn(ScChangeAction *)
Definition: chgtrack.cxx:387
ScChangeActionLinkEntry * pLinkDependent
Definition: chgtrack.hxx:198
ScChangeAction * pPrev
Definition: chgtrack.hxx:193
sal_uLong nRejectAction
Definition: chgtrack.hxx:200
ScChangeAction(const ScChangeAction &)=delete
void SetRejectAction(sal_uLong n)
Definition: chgtrack.hxx:223
const OUString & GetComment() const
Definition: chgtrack.hxx:348
virtual ScChangeActionLinkEntry ** GetDeletedInAddress()
Definition: chgtrack.hxx:241
void SetComment(const OUString &rStr)
Definition: chgtrack.cxx:533
ScBigRange & GetBigRange()
Definition: chgtrack.hxx:229
friend class ScChangeActionMove
Definition: chgtrack.hxx:180
void SetUser(const OUString &r)
Definition: chgtrack.cxx:528
bool IsDeletedIn() const
Definition: chgtrack.cxx:318
bool IsRejected() const
Definition: chgtrack.cxx:133
virtual const ScChangeTrack * GetChangeTrack() const =0
bool IsClickable() const
Definition: chgtrack.cxx:166
bool IsVisible() const
Definition: chgtrack.cxx:143
bool IsMasterDelete() const
Definition: chgtrack.cxx:274
void RemoveAllLinks()
Definition: chgtrack.cxx:282
virtual void UpdateReference(const ScChangeTrack *, UpdateRefMode, const ScBigRange &, sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz)
Definition: chgtrack.cxx:414
void SetActionNumber(sal_uLong n)
Definition: chgtrack.hxx:222
bool IsDialogRoot() const
Definition: chgtrack.cxx:233
sal_uLong GetRejectAction() const
Definition: chgtrack.hxx:318
ScChangeAction * pNext
Definition: chgtrack.hxx:192
OUString aUser
UTC.
Definition: chgtrack.hxx:190
bool IsTouchable() const
Definition: chgtrack.cxx:153
ScBigRange aBigRange
Definition: chgtrack.hxx:188
bool IsDialogParent() const
Definition: chgtrack.cxx:238
friend class ScChangeActionContent
Definition: chgtrack.hxx:181
bool IsRejecting() const
Definition: chgtrack.cxx:138
sal_uLong GetActionNumber() const
Definition: chgtrack.hxx:317
void AddLink(ScChangeAction *p, ScChangeActionLinkEntry *pL)
Definition: chgtrack.hxx:231
const DateTime & GetDateTimeUTC() const
Definition: chgtrack.hxx:313
virtual ~ScChangeAction()
Definition: chgtrack.cxx:108
void SetDateTimeUTC(const DateTime &rDT)
Definition: chgtrack.hxx:344
void SetType(ScChangeActionType e)
Definition: chgtrack.hxx:225
ScChangeActionType GetType() const
Definition: chgtrack.hxx:315
ScChangeActionLinkEntry * pLinkAny
Definition: chgtrack.hxx:194
const ScChangeActionLinkEntry * GetFirstDependentEntry() const
Definition: chgtrack.hxx:330
bool HasDeleted() const
Definition: chgtrack.cxx:382
void SetRejected()
Definition: chgtrack.cxx:552
virtual ScChangeActionLinkEntry * GetDeletedIn() const
Definition: chgtrack.hxx:239
bool RemoveDeletedIn(const ScChangeAction *)
Definition: chgtrack.cxx:301
friend class ScChangeActionIns
Definition: chgtrack.hxx:178
friend class ScChangeActionDel
Definition: chgtrack.hxx:179
bool HasDependent() const
Definition: chgtrack.cxx:377
void RejectRestoreContents(ScChangeTrack *, SCCOL nDx, SCROW nDy)
Definition: chgtrack.cxx:562
bool IsDeleteType() const
Definition: chgtrack.cxx:118
void SetState(ScChangeActionState e)
Definition: chgtrack.hxx:226
const ScChangeActionLinkEntry * GetFirstDeletedEntry() const
Definition: chgtrack.hxx:328
bool IsRejectable() const
Definition: chgtrack.cxx:197
virtual OUString GetDescription(ScDocument &rDoc, bool bSplitRange=false, bool bWarning=true) const
Definition: chgtrack.cxx:421
bool IsDeletedInDelType(ScChangeActionType) const
Definition: chgtrack.cxx:345
bool IsInsertType() const
Definition: chgtrack.cxx:113
ScChangeAction * GetNext() const
Definition: chgtrack.hxx:320
ScChangeAction * GetPrev() const
Definition: chgtrack.hxx:321
bool IsInternalRejectable() const
Definition: chgtrack.cxx:215
void RemoveAllDependent()
Definition: chgtrack.cxx:398
bool IsVirgin() const
Definition: chgtrack.cxx:123
ScChangeActionState eState
Definition: chgtrack.hxx:202
ScChangeActionType eType
Definition: chgtrack.hxx:201
SC_DLLPUBLIC DateTime GetDateTime() const
Definition: chgtrack.cxx:407
virtual bool Reject(ScDocument &rDoc)=0
OUString GetRefString(const ScBigRange &rRange, const ScDocument &rDoc, bool bFlag3D=false) const
Definition: chgtrack.cxx:477
virtual void DeleteCellEntries()=0
ScChangeActionState GetState() const
Definition: chgtrack.hxx:316
ScChangeActionLinkEntry * pLinkDeletedIn
Definition: chgtrack.hxx:195
const OUString & GetUser() const
Definition: chgtrack.hxx:347
SC_DLLPUBLIC bool IsAccepted() const
Definition: chgtrack.cxx:128
void RemoveAllDeletedIn()
Definition: chgtrack.cxx:335
OUString aComment
Definition: chgtrack.hxx:191
ScChangeActionLinkEntry * AddDependent(ScChangeAction *p)
Definition: chgtrack.hxx:251
DateTime aFixDateTime
Definition: chgtrack.hxx:835
sal_uLong nEndLastCut
Definition: chgtrack.hxx:851
ScDocument & GetDocument() const
Definition: chgtrack.hxx:973
std::optional< ScChangeTrackMsgInfo > xBlockModifyMsg
Definition: chgtrack.hxx:845
ScChangeActionContent * SearchContentAt(const ScBigAddress &, const ScChangeAction *pButNotThis) const
Definition: chgtrack.cxx:2819
ScChangeTrackMsgStack aMsgStackFinal
Definition: chgtrack.hxx:830
bool SelectContent(ScChangeAction *, bool bOldest=false)
Definition: chgtrack.cxx:3997
void GetChangeTrackInfo(tools::JsonWriter &)
Get info about all ScChangeAction elements.
Definition: chgtrack.cxx:4663
void EndBlockModify(sal_uLong nEndAction)
Definition: chgtrack.cxx:2211
void AppendLoaded(std::unique_ptr< ScChangeAction > pAppend)
Definition: chgtrack.cxx:2321
ScChangeAction * GetLast() const
Definition: chgtrack.hxx:952
bool bUseFixDateTime
Definition: chgtrack.hxx:858
void AppendCloned(ScChangeAction *pAppend)
Definition: chgtrack.cxx:4348
SC_DLLPUBLIC void AppendInsert(const ScRange &rRange, bool bEndOfList=false)
Definition: chgtrack.cxx:2763
ScChangeActionMap aPasteCutMap
Definition: chgtrack.hxx:827
void AppendOneDeleteRange(const ScRange &rOrgRange, ScDocument *pRefDoc, SCCOL nDx, SCROW nDy, SCTAB nDz, sal_uLong nRejectingInsert)
Definition: chgtrack.cxx:2471
SCROW mnContentRowsPerSlot
Definition: chgtrack.hxx:821
SC_DLLPUBLIC ScChangeTrack * Clone(ScDocument *pDocument) const
Definition: chgtrack.cxx:4361
void SetLastSavedActionNumber(sal_uLong nNew)
Definition: chgtrack.cxx:2139
void MergePrepare(const ScChangeAction *pFirstMerge, bool bShared)
may only be used in a temporary opened document.
Definition: chgtrack.cxx:3147
SC_DLLPUBLIC ScChangeAction * GetAction(sal_uLong nAction) const
Definition: chgtrack.cxx:2110
void Append(ScChangeAction *pAppend, sal_uLong nAction)
Definition: chgtrack.cxx:2336
sal_uLong nActionMax
Definition: chgtrack.hxx:847
bool IsInDelete() const
Definition: chgtrack.hxx:965
ScChangeActionContent * GenerateDelContent(const ScAddress &rPos, const ScCellValue &rCell, const ScDocument *pFromDoc)
Definition: chgtrack.cxx:2782
bool IsLastAction(sal_uLong nNum) const
Definition: chgtrack.cxx:4331
void SetMergeState(ScChangeTrackMergeState eState)
Definition: chgtrack.hxx:883
ScChangeAction * pFirst
Definition: chgtrack.hxx:836
virtual void ConfigurationChanged(utl::ConfigurationBroadcaster *, ConfigurationHints) override
Definition: chgtrack.cxx:2153
void DeleteCellEntries(std::vector< ScChangeActionContent * > &, const ScChangeAction *pDeletor)
Definition: chgtrack.cxx:2769
ScChangeAction * pLast
Definition: chgtrack.hxx:837
SC_DLLPUBLIC ScChangeActionContent * AppendContentOnTheFly(const ScAddress &rPos, const ScCellValue &rOldCell, const ScCellValue &rNewCell, sal_uLong nOldFormat=0, sal_uLong nNewFormat=0)
Definition: chgtrack.cxx:2752
bool bTimeNanoSeconds
Definition: chgtrack.hxx:859
SC_DLLPUBLIC void SetUser(const OUString &rUser)
Definition: chgtrack.cxx:2191
ScChangeAction * GetActionOrGenerated(sal_uLong nAction) const
Definition: chgtrack.cxx:2128
ScChangeAction * GetLastSaved() const
Definition: chgtrack.cxx:2144
ScChangeAction * GetGenerated(sal_uLong nGenerated) const
Definition: chgtrack.cxx:2119
void AddDependentWithNotify(ScChangeAction *pParent, ScChangeAction *pDependent)
Definition: chgtrack.cxx:2837
std::set< OUString > maUserCollection
Definition: chgtrack.hxx:831
void LookUpContents(const ScRange &rOrgRange, ScDocument *pRefDoc, SCCOL nDx, SCROW nDy, SCTAB nDz)
Definition: chgtrack.cxx:2505
SC_DLLPUBLIC void AppendMove(const ScRange &rFromRange, const ScRange &rToRange, ScDocument *pRefDoc)
Definition: chgtrack.cxx:2535
ScChangeActionLinkEntry * pLinkInsertTab
Definition: chgtrack.hxx:843
OUString maUser
Definition: chgtrack.hxx:832
void SetInDeleteRange(const ScRange &rRange)
Definition: chgtrack.hxx:873
void AppendContentsIfInRefDoc(ScDocument &rRefDoc, sal_uLong &nStartAction, sal_uLong &nEndAction)
Definition: chgtrack.cxx:2727
void DtorClear()
Definition: chgtrack.cxx:2064
void SetInDeleteTop(bool bVal)
Definition: chgtrack.hxx:877
void AcceptAll()
Definition: chgtrack.cxx:4080
sal_uLong nLastMerge
Definition: chgtrack.hxx:852
void UpdateReference(ScChangeAction *, bool bUndo)
Definition: chgtrack.cxx:3200
void AppendContentRange(const ScRange &rRange, ScDocument *pRefDoc, sal_uLong &nStartAction, sal_uLong &nEndAction, ScChangeActionClipMode eMode=SC_CACM_NONE)
Definition: chgtrack.cxx:2631
bool RejectAll()
Definition: chgtrack.cxx:4108
sal_uLong GetActionMax() const
Definition: chgtrack.hxx:953
ScChangeActionContent ** GetContentSlots() const
Definition: chgtrack.hxx:961
bool IsProtected() const
Definition: chgtrack.hxx:1126
void MergeOwn(ScChangeAction *pAct, sal_uLong nFirstMerge, bool bShared)
Definition: chgtrack.cxx:3179
SCSIZE mnContentSlots
Definition: chgtrack.hxx:822
bool IsInPasteCut() const
Definition: chgtrack.hxx:968
void CreateAuthorName()
Definition: chgtrack.cxx:2175
SC_DLLPUBLIC void GetDependents(ScChangeAction *, ScChangeActionMap &, bool bListMasterDelete=false, bool bAllFlat=false) const
Definition: chgtrack.cxx:3802
ScChangeActionLinkEntry * pLinkInsertRow
Definition: chgtrack.hxx:842
void DeleteGeneratedDelContent(ScChangeActionContent *)
Definition: chgtrack.cxx:2803
void NotifyModified(ScChangeTrackMsgType eMsgType, sal_uLong nStartAction, sal_uLong nEndAction)
Definition: chgtrack.cxx:2250
static bool MergeIgnore(const ScChangeAction &, sal_uLong nFirstMerge)
Definition: chgtrack.cxx:3136
sal_uLong AddLoadedGenerated(const ScCellValue &rNewCell, const ScBigRange &aBigRange, const OUString &sNewValue)
Definition: chgtrack.cxx:4336
ScChangeTrackMsgQueue & GetMsgQueue()
Definition: chgtrack.cxx:2245
SC_DLLPUBLIC bool Accept(ScChangeAction *)
Definition: chgtrack.cxx:4088
SCSIZE ComputeContentSlot(sal_Int32 nRow) const
Definition: chgtrack.cxx:1989
ScChangeTrack(const ScChangeTrack &)=delete
bool bInDeleteUndo
Definition: chgtrack.hxx:855
ScChangeTrackMsgQueue aMsgQueue
Definition: chgtrack.hxx:828
void SetLastMerge(sal_uLong nVal)
Definition: chgtrack.hxx:886
void StartBlockModify(ScChangeTrackMsgType, sal_uLong nStartAction)
Definition: chgtrack.cxx:2197
ScDocument & rDoc
Definition: chgtrack.hxx:846
static bool IsMatrixFormulaRangeDifferent(const ScCellValue &rOldCell, const ScCellValue &rNewCell)
Definition: chgtrack.cxx:2543
SCROW InitContentRowsPerSlot()
Definition: chgtrack.cxx:1996
bool IsGenerated(sal_uLong nAction) const
Definition: chgtrack.cxx:2105
bool HasLastCut() const
Definition: chgtrack.hxx:1052
void ResetLastCut()
Definition: chgtrack.hxx:1047
sal_uLong GetLastMerge() const
Definition: chgtrack.hxx:887
bool bInPasteCut
Definition: chgtrack.hxx:857
ScChangeTrackMergeState GetMergeState() const
Definition: chgtrack.hxx:885
void SetLastCutMoveRange(const ScRange &, ScDocument *)
Definition: chgtrack.cxx:2611
SC_DLLPUBLIC void Undo(sal_uLong nStartAction, sal_uLong nEndAction, bool bMerge=false)
Definition: chgtrack.cxx:3044
void MasterLinks(ScChangeAction *)
Definition: chgtrack.cxx:2265
void SetInDelete(bool bVal)
Definition: chgtrack.hxx:875
sal_uLong nMarkLastSaved
Definition: chgtrack.hxx:849
ScChangeActionContent * pFirstGeneratedDelContent
Definition: chgtrack.hxx:838
void Remove(ScChangeAction *)
Definition: chgtrack.cxx:2994
const css::uno::Sequence< sal_Int8 > & GetProtection() const
Definition: chgtrack.hxx:1124
std::unique_ptr< ScChangeActionContent *[]> ppContentSlots
Definition: chgtrack.hxx:839
const ScRange & GetInDeleteRange() const
Definition: chgtrack.hxx:963
void ClearMsgQueue()
Definition: chgtrack.cxx:2086
void Dependencies(ScChangeAction *)
Definition: chgtrack.cxx:2849
ScChangeActionMap aGeneratedMap
Definition: chgtrack.hxx:826
bool Reject(ScChangeAction *, ScChangeActionMap *, bool bRecursion)
Definition: chgtrack.cxx:4139
bool IsTimeNanoSeconds() const
Definition: chgtrack.hxx:1132
SC_DLLPUBLIC void AppendDeleteRange(const ScRange &, ScDocument *pRefDoc, SCTAB nDz, sal_uLong nRejectingInsert)
Definition: chgtrack.cxx:2399
Link< ScChangeTrack &, void > aModifiedLink
Definition: chgtrack.hxx:833
void AppendContent(const ScAddress &rPos, const ScDocument *pRefDoc)
Definition: chgtrack.cxx:2582
sal_uLong GetLastSavedActionNumber() const
Definition: chgtrack.cxx:2134
static void MergeActionState(ScChangeAction *pAct, const ScChangeAction *pOtherAct)
Definition: chgtrack.cxx:4622
ScChangeActionContent * GetFirstGenerated() const
Definition: chgtrack.hxx:950
bool IsInDeleteTop() const
Definition: chgtrack.hxx:966
std::unique_ptr< ScChangeActionMove > pLastCutMove
Definition: chgtrack.hxx:840
ScChangeActionLinkEntry * pLinkMove
Definition: chgtrack.hxx:844
sal_uLong nStartLastCut
Definition: chgtrack.hxx:850
void SetInDeleteUndo(bool bVal)
Definition: chgtrack.hxx:879
ScChangeActionMap aMap
Definition: chgtrack.hxx:825
ScChangeActionLinkEntry * pLinkInsertCol
Definition: chgtrack.hxx:841
void SetInPasteCut(bool bVal)
Definition: chgtrack.hxx:881
bool bInDeleteTop
Definition: chgtrack.hxx:856
ScChangeTrackMergeState eMergeState
Definition: chgtrack.hxx:853
ScChangeAction * GetFirst() const
Definition: chgtrack.hxx:951
virtual SC_DLLPUBLIC ~ScChangeTrack() override
Definition: chgtrack.cxx:2027
ScChangeTrackMsgStack aMsgStackTmp
Definition: chgtrack.hxx:829
sal_uLong nGeneratedMin
Definition: chgtrack.hxx:848
SC_DLLPUBLIC bool InsertTab(SCTAB nPos, const OUString &rName, bool bExternalDocument=false, bool bUndoDeleteTab=false)
Definition: document.cxx:485
void SetEmptyCell(const ScAddress &rPos)
Definition: document.cxx:3471
ScSheetLimits & GetSheetLimits() const
Definition: document.hxx:898
SC_DLLPUBLIC sal_uInt32 GetNumberFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3640
SC_DLLPUBLIC void SetChangeTrack(std::unique_ptr< ScChangeTrack > pTrack)
only for import filter, deletes any existing ChangeTrack via EndChangeTracking() and takes ownership ...
Definition: documen2.cxx:294
bool CanInsertCol(const ScRange &rRange) const
Definition: document.cxx:1456
SC_DLLPUBLIC void InsertMatrixFormula(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData &rMark, const OUString &rFormula, const ScTokenArray *p=nullptr, const formula::FormulaGrammar::Grammar=formula::FormulaGrammar::GRAM_DEFAULT)
Definition: documen4.cxx:259
SC_DLLPUBLIC bool ValidNewTabName(const OUString &rName) const
Definition: document.cxx:357
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:892
SC_DLLPUBLIC SCROW GetMaxRowCount() const
Definition: document.hxx:895
void SetExpandRefs(bool bVal)
Definition: documen2.cxx:327
SC_DLLPUBLIC formula::FormulaGrammar::AddressConvention GetAddressConvention() const
Definition: documen3.cxx:492
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:893
void UpdateReference(sc::RefUpdateContext &rCxt, ScDocument *pUndoDoc=nullptr, bool bIncludeDraw=true, bool bUpdateNoteCaptionPos=true)
Definition: documen3.cxx:1008
SC_DLLPUBLIC SCROW GetLastDataRow(SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nLastRow) const
Return the last non-empty row position in given columns that's no greater than the initial last row p...
Definition: document.cxx:1063
bool GetNoListening() const
Definition: document.hxx:2230
SC_DLLPUBLIC bool GetAutoCalc() const
Definition: document.hxx:1413
SC_DLLPUBLIC bool SetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString &rString, const ScSetStringParam *pParam=nullptr)
Definition: document.cxx:3391
void DeleteRow(SCCOL nStartCol, SCTAB nStartTab, SCCOL nEndCol, SCTAB nEndTab, SCROW nStartRow, SCSIZE nSize, ScDocument *pRefUndoDoc=nullptr, bool *pUndoOutline=nullptr, const ScMarkData *pTabMark=nullptr)
Definition: document.cxx:1345
SC_DLLPUBLIC void CreateValidTabName(OUString &rName) const
Definition: document.cxx:375
SC_DLLPUBLIC formula::FormulaGrammar::Grammar GetGrammar() const
Definition: document.hxx:1010
bool IsBlockEditable(SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool *pOnlyNotBecauseOfMatrix=nullptr, bool bNoMatrixAtAll=false) const
Definition: document.cxx:5317
bool CanInsertRow(const ScRange &rRange) const
Definition: document.cxx:1167
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1083
SC_DLLPUBLIC SCCOL ClampToAllocatedColumns(SCTAB nTab, SCCOL nCol) const
Definition: documen3.cxx:2134
void DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab, SCCOL nStartCol, SCSIZE nSize, ScDocument *pRefUndoDoc=nullptr, bool *pUndoOutline=nullptr, const ScMarkData *pTabMark=nullptr)
Definition: document.cxx:1570
bool IsExpandRefs() const
Definition: document.hxx:2457
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:467
SC_DLLPUBLIC void SetAutoCalc(bool bNewAutoCalc)
Definition: documen7.cxx:602
bool IsInDtorClear() const
Definition: document.hxx:2455
SCTAB GetMaxTableNumber() const
Definition: document.hxx:817
SC_DLLPUBLIC void DeleteAreaTab(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab, InsertDeleteFlags nDelFlag)
Definition: document.cxx:1920
SC_DLLPUBLIC bool DeleteTab(SCTAB nTab)
Definition: document.cxx:654
SC_DLLPUBLIC bool GetName(SCTAB nTab, OUString &rName) const
Definition: document.cxx:204
void SetNoListening(bool bVal)
Definition: document.hxx:2229
SC_DLLPUBLIC const ScPatternAttr * GetPattern(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:4719
bool InsertCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab, SCCOL nStartCol, SCSIZE nSize, ScDocument *pRefUndoDoc=nullptr, const ScMarkData *pTabMark=nullptr)
Definition: document.cxx:1477
bool InsertRow(SCCOL nStartCol, SCTAB nStartTab, SCCOL nEndCol, SCTAB nEndTab, SCROW nStartRow, SCSIZE nSize, ScDocument *pRefUndoDoc=nullptr, const ScMarkData *pTabMark=nullptr)
Definition: document.cxx:1223
static SC_DLLPUBLIC OUString GetString(const EditTextObject &rEditText, const ScDocument *pDoc)
Retrieves string with paragraphs delimited by new lines (' ').
Definition: editutil.cxx:119
void SetInChangeTrack(bool bVal)
void GetMatColsRows(SCCOL &nCols, SCROW &nRows) const
ScMatrixMode GetMatrixFlag() const
bool UpdateReference(const sc::RefUpdateContext &rCxt, ScDocument *pUndoDoc=nullptr, const ScAddress *pUndoCellPos=nullptr)
bool GetMatrixOrigin(const ScDocument &rDoc, ScAddress &rPos) const
ScDocument & GetDocument() const
ScTokenArray * GetCode()
ScAddress aPos
OUString GetFormula(const formula::FormulaGrammar::Grammar=formula::FormulaGrammar::GRAM_DEFAULT, const ScInterpreterContext *pContext=nullptr) const
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:43
void SelectOneTable(SCTAB nTab)
Definition: markdata.cxx:174
void SetMarkArea(const ScRange &rRange)
Definition: markdata.cxx:92
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1398
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:690
OUString Format(const ScDocument &rDocument, ScRefFlags nFlags=ScRefFlags::ZERO, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1, bool bFullAddressNotation=false) const
Returns string with formatted cell range from aStart to aEnd, according to provided address conventio...
Definition: address.cxx:2170
ScAddress aEnd
Definition: address.hxx:498
ScAddress aStart
Definition: address.hxx:497
static ScRefUpdateRes Update(const ScDocument *pDoc, UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCCOL nDx, SCROW nDy, SCTAB nDz, SCCOL &theCol1, SCROW &theRow1, SCTAB &theTab1, SCCOL &theCol2, SCROW &theRow2, SCTAB &theTab2)
Definition: refupdat.cxx:188
void GetInputLineString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &rOutString, bool bFiltering=false, bool bForceSystemLocale=false)
OUString GetFirstName() const
OUString GetLastName() const
static const OUString & GetNativeSymbol(OpCode eOp)
virtual const ScSingleRefData * GetSingleRef() const
StackVar GetType() const
virtual const ScComplexRefData * GetDoubleRef() const
const OUString & getString() const
void put(std::u16string_view pPropName, const OUString &rPropValue)
ScopedJsonWriterStruct startStruct()
ScopedJsonWriterArray startArray(std::string_view)
DocumentType eType
@ CELLTYPE_EDIT
Definition: global.hxx:277
@ CELLTYPE_STRING
Definition: global.hxx:275
@ CELLTYPE_FORMULA
Definition: global.hxx:276
@ CELLTYPE_NONE
Definition: global.hxx:273
@ CELLTYPE_VALUE
Definition: global.hxx:274
UpdateRefMode
Definition: global.hxx:301
@ URM_MOVE
Definition: global.hxx:304
@ URM_INSDEL
Definition: global.hxx:302
sal_Int32 nIndex
OUString aName
Mode eMode
void * p
sal_Int64 n
sal_uInt16 nPos
SvBaseLink * pLink
aBuf
int i
OUString toISO8601(const css::util::DateTime &rDateTime)
HashMap_OWString_Interface aMap
ocErrRef
ConfigurationHints
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:90
#define SC_MOD()
Definition: scmod.hxx:247
sal_uIntPtr sal_uLong
Store arbitrary cell value of any kind.
Definition: cellvalue.hxx:32
void assign(const ScDocument &rDoc, const ScAddress &rPos)
Take cell value from specified position in specified document.
Definition: cellvalue.cxx:359
bool isEmpty() const
Definition: cellvalue.cxx:519
void set(double fValue)
Definition: cellvalue.cxx:329
const svl::SharedString * getSharedString() const
Definition: cellvalue.hxx:60
void clear() noexcept
Definition: cellvalue.cxx:311
CellType getType() const
Definition: cellvalue.cxx:296
ScFormulaCell * getFormula() const
Definition: cellvalue.hxx:59
EditTextObject * getEditText() const
Definition: cellvalue.hxx:61
double getDouble() const
Definition: cellvalue.hxx:58
void commit(ScDocument &rDoc, const ScAddress &rPos) const
Set cell value at specified position in specified document.
Definition: cellvalue.cxx:426
ScSingleRefData Ref2
Definition: refdata.hxx:125
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
ScFormulaCell * getFormula() const
Definition: cellvalue.hxx:137
CellType getType() const
Definition: cellvalue.hxx:133
const SCROW mnMaxRow
Maximum addressable column.
Definition: sheetlimits.hxx:30
Single reference (one address) into the sheet.
Definition: refdata.hxx:30
void SetColDeleted(bool bVal)
Definition: refdata.cxx:110
void SetRowDeleted(bool bVal)
Definition: refdata.cxx:115
void SetTabDeleted(bool bVal)
Definition: refdata.cxx:120
Context for reference update during shifting, moving or copying of cell ranges.
SCROW mnRowDelta
Amount and direction of movement in the row direction.
UpdateRefMode meMode
update mode - insert/delete, copy, or move.
SCCOL mnColDelta
Amount and direction of movement in the column direction.
SCTAB mnTabDelta
Amount and direction of movement in the sheet direction.
ScRange maRange
Range of cells that are about to be moved for insert/delete/move modes.
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:23
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17