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