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