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