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