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