1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: chgtrack.cxx,v $
10 * $Revision: 1.32.100.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
35 #include <tools/debug.hxx>
36 #include <tools/shl.hxx> // SHL_CALC
37 #include <tools/stack.hxx>
38 #include <tools/rtti.hxx>
39 #include <svtools/zforlist.hxx>
40 #include <svtools/itemset.hxx>
41 #include <svtools/isethint.hxx>
42 #include <svtools/itempool.hxx>
43 #include <sfx2/app.hxx>
44 #include <svtools/useroptions.hxx>
45 #include <sfx2/sfxsids.hrc>
48 #include "document.hxx"
49 #include "dociter.hxx"
51 #include "rechead.hxx"
52 #include "scerrors.hxx"
53 #include "scmod.hxx" // SC_MOD
54 #include "inputopt.hxx" // GetExpandRefs
55 #include "patattr.hxx"
58 #include "globstr.hrc"
62 #define SC_CHGTRACK_CXX
63 #include "chgtrack.hxx"
65 DECLARE_STACK( ScChangeActionStack
, ScChangeAction
* )
67 const USHORT nMemPoolChangeActionCellListEntry
= (0x2000 - 64) / sizeof(ScChangeActionCellListEntry
);
68 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionCellListEntry
, nMemPoolChangeActionCellListEntry
, nMemPoolChangeActionCellListEntry
)
70 const USHORT nMemPoolChangeActionLinkEntry
= (0x8000 - 64) / sizeof(ScChangeActionLinkEntry
);
71 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionLinkEntry
, nMemPoolChangeActionLinkEntry
, nMemPoolChangeActionLinkEntry
)
73 // loaded MSB > eigenes => inkompatibel
74 #define SC_CHGTRACK_FILEFORMAT_FIRST 0x0001
75 #define SC_CHGTRACK_FILEFORMAT 0x0001
77 // --- ScChangeActionLinkEntry ---------------------------------------------
80 String
ScChangeActionLinkEntry::ToString() const
85 aReturn
= String::CreateFromInt64( static_cast< sal_Int64
>( pAction
->GetActionNumber() ) );
87 else if ( pLink
&& pLink
->pAction
)
89 aReturn
= String::CreateFromAscii( "*" );
90 aReturn
+= String::CreateFromInt64( static_cast< sal_Int64
>( pLink
->pAction
->GetActionNumber() ) );
94 aReturn
= String::CreateFromAscii( "-" );
99 #endif // DEBUG_CHANGETRACK
101 // --- ScChangeAction ------------------------------------------------------
103 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP
, const ScRange
& rRange
)
109 pLinkDeletedIn( NULL
),
110 pLinkDeleted( NULL
),
111 pLinkDependent( NULL
),
115 eState( SC_CAS_VIRGIN
)
117 aDateTime
.ConvertToUTC();
120 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP
, const ScBigRange
& rRange
,
121 const ULONG nTempAction
, const ULONG nTempRejectAction
,
122 const ScChangeActionState eTempState
, const DateTime
& aTempDateTime
,
123 const String
& aTempUser
, const String
& aTempComment
)
126 aDateTime( aTempDateTime
),
128 aComment( aTempComment
),
132 pLinkDeletedIn( NULL
),
133 pLinkDeleted( NULL
),
134 pLinkDependent( NULL
),
135 nAction( nTempAction
),
136 nRejectAction( nTempRejectAction
),
142 ScChangeAction::ScChangeAction( ScChangeActionType eTypeP
, const ScBigRange
& rRange
,
143 const ULONG nTempAction
)
149 pLinkDeletedIn( NULL
),
150 pLinkDeleted( NULL
),
151 pLinkDependent( NULL
),
152 nAction( nTempAction
),
155 eState( SC_CAS_VIRGIN
)
157 aDateTime
.ConvertToUTC();
161 ScChangeAction::~ScChangeAction()
167 BOOL
ScChangeAction::IsVisible() const
169 //! sequence order of execution is significant
170 if ( IsRejected() || GetType() == SC_CAT_DELETE_TABS
|| IsDeletedIn() )
172 if ( GetType() == SC_CAT_CONTENT
)
173 return ((ScChangeActionContent
*)this)->IsTopContent();
178 BOOL
ScChangeAction::IsTouchable() const
180 //! sequence order of execution is significant
181 if ( IsRejected() || GetType() == SC_CAT_REJECT
|| IsDeletedIn() )
183 // content may reject and be touchable if on top
184 if ( GetType() == SC_CAT_CONTENT
)
185 return ((ScChangeActionContent
*)this)->IsTopContent();
192 BOOL
ScChangeAction::IsClickable() const
194 //! sequence order of execution is significant
199 if ( GetType() == SC_CAT_CONTENT
)
201 ScChangeActionContentCellType eCCT
=
202 ScChangeActionContent::GetContentCellType(
203 ((ScChangeActionContent
*)this)->GetNewCell() );
204 if ( eCCT
== SC_CACCT_MATREF
)
206 if ( eCCT
== SC_CACCT_MATORG
)
207 { // no Accept-Select if one of the references is in a deleted col/row
208 const ScChangeActionLinkEntry
* pL
=
209 ((ScChangeActionContent
*)this)->GetFirstDependentEntry();
212 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
213 if ( p
&& p
->IsDeletedIn() )
218 return TRUE
; // for Select() a content doesn't have to be touchable
220 return IsTouchable(); // Accept()/Reject() only on touchables
224 BOOL
ScChangeAction::IsRejectable() const
226 //! sequence order of execution is significant
227 if ( !IsClickable() )
229 if ( GetType() == SC_CAT_CONTENT
)
231 if ( ((ScChangeActionContent
*)this)->IsOldMatrixReference() )
233 ScChangeActionContent
* pNextContent
=
234 ((ScChangeActionContent
*)this)->GetNextContent();
235 if ( pNextContent
== NULL
)
236 return TRUE
; // *this is TopContent
237 return pNextContent
->IsRejected(); // *this is next rejectable
239 return IsTouchable();
243 BOOL
ScChangeAction::IsInternalRejectable() const
245 //! sequence order of execution is significant
250 if ( GetType() == SC_CAT_CONTENT
)
252 ScChangeActionContent
* pNextContent
=
253 ((ScChangeActionContent
*)this)->GetNextContent();
254 if ( pNextContent
== NULL
)
255 return TRUE
; // *this is TopContent
256 return pNextContent
->IsRejected(); // *this is next rejectable
258 return IsTouchable();
262 BOOL
ScChangeAction::IsDialogRoot() const
264 return IsInternalRejectable(); // only rejectables in root
268 BOOL
ScChangeAction::IsDialogParent() const
270 //! sequence order of execution is significant
271 if ( GetType() == SC_CAT_CONTENT
)
273 if ( !IsDialogRoot() )
275 if ( ((ScChangeActionContent
*)this)->IsMatrixOrigin() && HasDependent() )
277 ScChangeActionContent
* pPrevContent
=
278 ((ScChangeActionContent
*)this)->GetPrevContent();
279 return pPrevContent
&& pPrevContent
->IsVirgin();
281 if ( HasDependent() )
282 return IsDeleteType() ? TRUE
: !IsDeletedIn();
285 if ( IsDeleteType() )
287 if ( IsDialogRoot() )
289 ScChangeActionLinkEntry
* pL
= pLinkDeleted
;
292 ScChangeAction
* p
= pL
->GetAction();
293 if ( p
&& p
->GetType() != eType
)
305 BOOL
ScChangeAction::IsMasterDelete() const
307 if ( !IsDeleteType() )
309 ScChangeActionDel
* pDel
= (ScChangeActionDel
*) this;
310 return pDel
->IsMultiDelete() && (pDel
->IsTopDelete() || pDel
->IsRejectable());
314 void ScChangeAction::RemoveAllLinks()
317 RemoveAllDeletedIn();
319 RemoveAllDependent();
323 void ScChangeAction::RemoveAllAnyLinks()
326 delete pLinkAny
; // rueckt sich selbst hoch
330 BOOL
ScChangeAction::RemoveDeletedIn( const ScChangeAction
* p
)
332 BOOL bRemoved
= FALSE
;
333 ScChangeActionLinkEntry
* pL
= GetDeletedIn();
336 ScChangeActionLinkEntry
* pNextLink
= pL
->GetNext();
337 if ( pL
->GetAction() == p
)
348 BOOL
ScChangeAction::IsDeletedIn( const ScChangeAction
* p
) const
350 ScChangeActionLinkEntry
* pL
= GetDeletedIn();
353 if ( pL
->GetAction() == p
)
361 void ScChangeAction::RemoveAllDeletedIn()
363 //! nicht vom evtl. TopContent sondern wirklich dieser
364 while ( pLinkDeletedIn
)
365 delete pLinkDeletedIn
; // rueckt sich selbst hoch
369 BOOL
ScChangeAction::IsDeletedInDelType( ScChangeActionType eDelType
) const
372 ScChangeActionLinkEntry
* pL
= GetDeletedIn();
375 // InsertType fuer MergePrepare/MergeOwn
376 ScChangeActionType eInsType
;
379 case SC_CAT_DELETE_COLS
:
380 eInsType
= SC_CAT_INSERT_COLS
;
382 case SC_CAT_DELETE_ROWS
:
383 eInsType
= SC_CAT_INSERT_ROWS
;
385 case SC_CAT_DELETE_TABS
:
386 eInsType
= SC_CAT_INSERT_TABS
;
389 eInsType
= SC_CAT_NONE
;
393 if ( (p
= pL
->GetAction()) != NULL
&&
394 (p
->GetType() == eDelType
|| p
->GetType() == eInsType
) )
403 void ScChangeAction::SetDeletedIn( ScChangeAction
* p
)
405 ScChangeActionLinkEntry
* pLink1
= AddDeletedIn( p
);
406 ScChangeActionLinkEntry
* pLink2
;
407 if ( GetType() == SC_CAT_CONTENT
)
408 pLink2
= p
->AddDeleted( ((ScChangeActionContent
*)this)->GetTopContent() );
410 pLink2
= p
->AddDeleted( this );
411 pLink1
->SetLink( pLink2
);
415 void ScChangeAction::RemoveAllDeleted()
417 while ( pLinkDeleted
)
418 delete pLinkDeleted
; // rueckt sich selbst hoch
422 void ScChangeAction::RemoveAllDependent()
424 while ( pLinkDependent
)
425 delete pLinkDependent
; // rueckt sich selbst hoch
429 DateTime
ScChangeAction::GetDateTime() const
431 DateTime
aDT( aDateTime
);
432 aDT
.ConvertToLocalTime();
437 void ScChangeAction::UpdateReference( const ScChangeTrack
* /* pTrack */,
438 UpdateRefMode eMode
, const ScBigRange
& rRange
,
439 INT32 nDx
, INT32 nDy
, INT32 nDz
)
441 ScRefUpdate::Update( eMode
, rRange
, nDx
, nDy
, nDz
, GetBigRange() );
445 void ScChangeAction::GetDescription( String
& rStr
, ScDocument
* /* pDoc */,
446 BOOL
/* bSplitRange */, bool bWarning
) const
448 if ( IsRejecting() && bWarning
)
450 // #112261# Add comment if rejection may have resulted in references
451 // not properly restored in formulas. See specification at
452 // http://specs.openoffice.org/calc/ease-of-use/redlining_comment.sxw
453 if (GetType() == SC_CAT_MOVE
)
455 rStr
+= ScGlobal::GetRscString(
456 STR_CHANGED_MOVE_REJECTION_WARNING
);
459 else if (IsInsertType())
461 rStr
+= ScGlobal::GetRscString(
462 STR_CHANGED_DELETE_REJECTION_WARNING
);
467 const ScChangeTrack
* pCT
= GetChangeTrack();
470 ScChangeAction
* pReject
= pCT
->GetActionOrGenerated(
474 if (pReject
->GetType() == SC_CAT_MOVE
)
476 rStr
+= ScGlobal::GetRscString(
477 STR_CHANGED_MOVE_REJECTION_WARNING
);
480 else if (pReject
->IsDeleteType())
482 rStr
+= ScGlobal::GetRscString(
483 STR_CHANGED_DELETE_REJECTION_WARNING
);
486 else if (pReject
->HasDependent())
488 ScChangeActionTable aTable
;
489 pCT
->GetDependents( pReject
, aTable
, FALSE
, TRUE
);
490 for ( const ScChangeAction
* p
= aTable
.First(); p
;
493 if (p
->GetType() == SC_CAT_MOVE
)
495 rStr
+= ScGlobal::GetRscString(
496 STR_CHANGED_MOVE_REJECTION_WARNING
);
500 else if (pReject
->IsDeleteType())
502 rStr
+= ScGlobal::GetRscString(
503 STR_CHANGED_DELETE_REJECTION_WARNING
);
516 String
ScChangeAction::GetRefString( const ScBigRange
& rRange
,
517 ScDocument
* pDoc
, BOOL bFlag3D
) const
520 USHORT nFlags
= ( rRange
.IsValid( pDoc
) ? SCA_VALID
: 0 );
522 aStr
= ScGlobal::GetRscString( STR_NOREF_STR
);
525 ScRange
aTmpRange( rRange
.MakeRange() );
528 case SC_CAT_INSERT_COLS
:
529 case SC_CAT_DELETE_COLS
:
532 pDoc
->GetName( aTmpRange
.aStart
.Tab(), aStr
);
535 aStr
+= ::ScColToAlpha( aTmpRange
.aStart
.Col() );
537 aStr
+= ::ScColToAlpha( aTmpRange
.aEnd
.Col() );
539 case SC_CAT_INSERT_ROWS
:
540 case SC_CAT_DELETE_ROWS
:
543 pDoc
->GetName( aTmpRange
.aStart
.Tab(), aStr
);
546 aStr
+= String::CreateFromInt32( aTmpRange
.aStart
.Row() + 1 );
548 aStr
+= String::CreateFromInt32( aTmpRange
.aEnd
.Row() + 1 );
551 if ( bFlag3D
|| GetType() == SC_CAT_INSERT_TABS
)
552 nFlags
|= SCA_TAB_3D
;
553 aTmpRange
.Format( aStr
, nFlags
, pDoc
, pDoc
->GetAddressConvention() );
555 if ( (bFlag3D
&& IsDeleteType()) || IsDeletedIn() )
557 aStr
.Insert( '(', 0 );
565 void ScChangeAction::GetRefString( String
& rStr
, ScDocument
* pDoc
,
568 rStr
= GetRefString( GetBigRange(), pDoc
, bFlag3D
);
572 void ScChangeAction::Accept()
576 SetState( SC_CAS_ACCEPTED
);
582 void ScChangeAction::SetRejected()
586 SetState( SC_CAS_REJECTED
);
593 void ScChangeAction::RejectRestoreContents( ScChangeTrack
* pTrack
,
594 SCsCOL nDx
, SCsROW nDy
)
596 // Liste der Contents aufbauen
597 ScChangeActionCellListEntry
* pListContents
= NULL
;
598 for ( ScChangeActionLinkEntry
* pL
= pLinkDeleted
; pL
; pL
= pL
->GetNext() )
600 ScChangeAction
* p
= pL
->GetAction();
601 if ( p
&& p
->GetType() == SC_CAT_CONTENT
)
603 ScChangeActionCellListEntry
* pE
= new ScChangeActionCellListEntry(
604 (ScChangeActionContent
*) p
, pListContents
);
608 SetState( SC_CAS_REJECTED
); // vor UpdateReference fuer Move
609 pTrack
->UpdateReference( this, TRUE
); // LinkDeleted freigeben
610 DBG_ASSERT( !pLinkDeleted
, "ScChangeAction::RejectRestoreContents: pLinkDeleted != NULL" );
611 // Liste der Contents abarbeiten und loeschen
612 ScDocument
* pDoc
= pTrack
->GetDocument();
613 ScChangeActionCellListEntry
* pE
= pListContents
;
616 if ( !pE
->pContent
->IsDeletedIn() &&
617 pE
->pContent
->GetBigRange().aStart
.IsValid( pDoc
) )
618 pE
->pContent
->PutNewValueToDoc( pDoc
, nDx
, nDy
);
619 ScChangeActionCellListEntry
* pNextEntry
;
620 pNextEntry
= pE
->pNext
;
624 DeleteCellEntries(); // weg mit den generierten
628 void ScChangeAction::SetDeletedInThis( ULONG nActionNumber
,
629 const ScChangeTrack
* pTrack
)
633 ScChangeAction
* pAct
= pTrack
->GetActionOrGenerated( nActionNumber
);
634 DBG_ASSERT( pAct
, "ScChangeAction::SetDeletedInThis: missing Action" );
636 pAct
->SetDeletedIn( this );
641 void ScChangeAction::AddDependent( ULONG nActionNumber
,
642 const ScChangeTrack
* pTrack
)
646 ScChangeAction
* pAct
= pTrack
->GetActionOrGenerated( nActionNumber
);
647 DBG_ASSERT( pAct
, "ScChangeAction::AddDependent: missing Action" );
650 ScChangeActionLinkEntry
* pLink
= AddDependent( pAct
);
651 pAct
->AddLink( this, pLink
);
657 #if DEBUG_CHANGETRACK
658 String
ScChangeAction::ToString( ScDocument
* pDoc
) const
662 String aNumber
= String::CreateFromInt64( static_cast< sal_Int64
>( GetActionNumber() ) );
665 ScChangeActionState eActionState
= GetState();
666 switch ( eActionState
)
670 aActionState
= String::CreateFromAscii( " " );
673 case SC_CAS_ACCEPTED
:
675 aActionState
= String::CreateFromAscii( "+" );
678 case SC_CAS_REJECTED
:
680 aActionState
= String::CreateFromAscii( "-" );
685 String aRejectAction
;
688 aRejectAction
+= 'r';
689 aRejectAction
+= String::CreateFromInt64( static_cast< sal_Int64
>( GetRejectAction() ) );
693 GetRefString( aReference
, pDoc
, TRUE
);
695 String aAuthor
= GetUser();
697 DateTime aDT
= GetDateTime();
698 String aDate
= ScGlobal::pLocaleData
->getDate( aDT
);
700 aDate
+= ScGlobal::pLocaleData
->getTime( aDT
, FALSE
, FALSE
);
703 GetDescription( aDescription
, pDoc
);
706 const ScChangeActionLinkEntry
* pLinkA
= pLinkAny
;
709 if ( !aLinkAny
.Len() )
711 aLinkAny
= String::CreateFromAscii( "(Any:" );
713 aLinkAny
+= String::CreateFromAscii( " ->" );
714 aLinkAny
+= pLinkA
->ToString();
715 pLinkA
= pLinkA
->GetNext();
717 if ( aLinkAny
.Len() )
722 String aLinkDeletedIn
;
723 const ScChangeActionLinkEntry
* pLinkDI
= pLinkDeletedIn
;
726 if ( !aLinkDeletedIn
.Len() )
728 aLinkDeletedIn
= String::CreateFromAscii( "(DeletedIn:" );
730 aLinkDeletedIn
+= String::CreateFromAscii( " ->" );
731 aLinkDeletedIn
+= pLinkDI
->ToString();
732 pLinkDI
= pLinkDI
->GetNext();
734 if ( aLinkDeletedIn
.Len() )
736 aLinkDeletedIn
+= ')';
740 const ScChangeActionLinkEntry
* pLinkD
= pLinkDeleted
;
743 if ( !aLinkDeleted
.Len() )
745 aLinkDeleted
= String::CreateFromAscii( "(Deleted:" );
747 aLinkDeleted
+= String::CreateFromAscii( " ->" );
748 aLinkDeleted
+= pLinkD
->ToString();
749 pLinkD
= pLinkD
->GetNext();
751 if ( aLinkDeleted
.Len() )
756 String aLinkDependent
;
757 const ScChangeActionLinkEntry
* pLinkDp
= pLinkDependent
;
760 if ( !aLinkDependent
.Len() )
762 aLinkDependent
= String::CreateFromAscii( "(Dependent:" );
764 aLinkDependent
+= String::CreateFromAscii( " ->" );
765 aLinkDependent
+= pLinkDp
->ToString();
766 pLinkDp
= pLinkDp
->GetNext();
768 if ( aLinkDependent
.Len() )
770 aLinkDependent
+= ')';
774 aReturn
+= aActionState
;
775 aReturn
+= aRejectAction
;
776 aReturn
+= String::CreateFromAscii( ": " );
777 aReturn
+= aReference
;
783 aReturn
+= aDescription
;
787 aReturn
+= aLinkDeletedIn
;
789 aReturn
+= aLinkDeleted
;
791 aReturn
+= aLinkDependent
;
795 #endif // DEBUG_CHANGETRACK
798 // --- ScChangeActionIns ---------------------------------------------------
800 ScChangeActionIns::ScChangeActionIns( const ScRange
& rRange
)
801 : ScChangeAction( SC_CAT_NONE
, rRange
)
803 if ( rRange
.aStart
.Col() == 0 && rRange
.aEnd
.Col() == MAXCOL
)
805 aBigRange
.aStart
.SetCol( nInt32Min
);
806 aBigRange
.aEnd
.SetCol( nInt32Max
);
807 if ( rRange
.aStart
.Row() == 0 && rRange
.aEnd
.Row() == MAXROW
)
809 SetType( SC_CAT_INSERT_TABS
);
810 aBigRange
.aStart
.SetRow( nInt32Min
);
811 aBigRange
.aEnd
.SetRow( nInt32Max
);
814 SetType( SC_CAT_INSERT_ROWS
);
816 else if ( rRange
.aStart
.Row() == 0 && rRange
.aEnd
.Row() == MAXROW
)
818 SetType( SC_CAT_INSERT_COLS
);
819 aBigRange
.aStart
.SetRow( nInt32Min
);
820 aBigRange
.aEnd
.SetRow( nInt32Max
);
824 DBG_ERROR( "ScChangeActionIns: Block not supported!" );
829 ScChangeActionIns::ScChangeActionIns(const ULONG nActionNumber
, const ScChangeActionState eStateP
, const ULONG nRejectingNumber
,
830 const ScBigRange
& aBigRangeP
, const String
& aUserP
, const DateTime
& aDateTimeP
, const String
& sComment
,
831 const ScChangeActionType eTypeP
)
833 ScChangeAction(eTypeP
, aBigRangeP
, nActionNumber
, nRejectingNumber
, eStateP
, aDateTimeP
, aUserP
, sComment
)
837 ScChangeActionIns::~ScChangeActionIns()
842 void ScChangeActionIns::GetDescription( String
& rStr
, ScDocument
* pDoc
,
843 BOOL bSplitRange
, bool bWarning
) const
845 ScChangeAction::GetDescription( rStr
, pDoc
, bSplitRange
, bWarning
);
850 case SC_CAT_INSERT_COLS
:
851 nWhatId
= STR_COLUMN
;
853 case SC_CAT_INSERT_ROWS
:
860 String
aRsc( ScGlobal::GetRscString( STR_CHANGED_INSERT
) );
861 xub_StrLen nPos
= aRsc
.SearchAscii( "#1" );
862 rStr
+= aRsc
.Copy( 0, nPos
);
863 rStr
+= ScGlobal::GetRscString( nWhatId
);
865 rStr
+= GetRefString( GetBigRange(), pDoc
);
866 rStr
+= aRsc
.Copy( nPos
+2 );
870 BOOL
ScChangeActionIns::Reject( ScDocument
* pDoc
)
872 if ( !aBigRange
.IsValid( pDoc
) )
875 ScRange
aRange( aBigRange
.MakeRange() );
876 if ( !pDoc
->IsBlockEditable( aRange
.aStart
.Tab(), aRange
.aStart
.Col(),
877 aRange
.aStart
.Row(), aRange
.aEnd
.Col(), aRange
.aEnd
.Row() ) )
882 case SC_CAT_INSERT_COLS
:
883 pDoc
->DeleteCol( aRange
);
885 case SC_CAT_INSERT_ROWS
:
886 pDoc
->DeleteRow( aRange
);
888 case SC_CAT_INSERT_TABS
:
889 pDoc
->DeleteTab( aRange
.aStart
.Tab() );
893 // added to avoid warnings
896 SetState( SC_CAS_REJECTED
);
902 // --- ScChangeActionDel ---------------------------------------------------
904 ScChangeActionDel::ScChangeActionDel( const ScRange
& rRange
,
905 SCsCOL nDxP
, SCsROW nDyP
, ScChangeTrack
* pTrackP
)
907 ScChangeAction( SC_CAT_NONE
, rRange
),
916 if ( rRange
.aStart
.Col() == 0 && rRange
.aEnd
.Col() == MAXCOL
)
918 aBigRange
.aStart
.SetCol( nInt32Min
);
919 aBigRange
.aEnd
.SetCol( nInt32Max
);
920 if ( rRange
.aStart
.Row() == 0 && rRange
.aEnd
.Row() == MAXROW
)
922 SetType( SC_CAT_DELETE_TABS
);
923 aBigRange
.aStart
.SetRow( nInt32Min
);
924 aBigRange
.aEnd
.SetRow( nInt32Max
);
927 SetType( SC_CAT_DELETE_ROWS
);
929 else if ( rRange
.aStart
.Row() == 0 && rRange
.aEnd
.Row() == MAXROW
)
931 SetType( SC_CAT_DELETE_COLS
);
932 aBigRange
.aStart
.SetRow( nInt32Min
);
933 aBigRange
.aEnd
.SetRow( nInt32Max
);
937 DBG_ERROR( "ScChangeActionDel: Block not supported!" );
942 ScChangeActionDel::ScChangeActionDel(const ULONG nActionNumber
, const ScChangeActionState eStateP
, const ULONG nRejectingNumber
,
943 const ScBigRange
& aBigRangeP
, const String
& aUserP
, const DateTime
& aDateTimeP
, const String
&sComment
,
944 const ScChangeActionType eTypeP
, const SCsCOLROW nD
, ScChangeTrack
* pTrackP
) // wich of nDx and nDy is set is depend on the type
946 ScChangeAction(eTypeP
, aBigRangeP
, nActionNumber
, nRejectingNumber
, eStateP
, aDateTimeP
, aUserP
, sComment
),
955 if (eType
== SC_CAT_DELETE_COLS
)
956 nDx
= static_cast<SCsCOL
>(nD
);
957 else if (eType
== SC_CAT_DELETE_ROWS
)
958 nDy
= static_cast<SCsROW
>(nD
);
961 ScChangeActionDel::~ScChangeActionDel()
968 void ScChangeActionDel::AddContent( ScChangeActionContent
* pContent
)
970 ScChangeActionCellListEntry
* pE
= new ScChangeActionCellListEntry(
971 pContent
, pFirstCell
);
976 void ScChangeActionDel::DeleteCellEntries()
978 pTrack
->DeleteCellEntries( pFirstCell
, this );
982 BOOL
ScChangeActionDel::IsBaseDelete() const
984 return !GetDx() && !GetDy();
988 BOOL
ScChangeActionDel::IsTopDelete() const
990 const ScChangeAction
* p
= GetNext();
991 if ( !p
|| p
->GetType() != GetType() )
993 return ((ScChangeActionDel
*)p
)->IsBaseDelete();
997 BOOL
ScChangeActionDel::IsMultiDelete() const
999 if ( GetDx() || GetDy() )
1001 const ScChangeAction
* p
= GetNext();
1002 if ( !p
|| p
->GetType() != GetType() )
1004 const ScChangeActionDel
* pDel
= (const ScChangeActionDel
*) p
;
1005 if ( (pDel
->GetDx() > GetDx() || pDel
->GetDy() > GetDy()) &&
1006 pDel
->GetBigRange() == aBigRange
)
1012 BOOL
ScChangeActionDel::IsTabDeleteCol() const
1014 if ( GetType() != SC_CAT_DELETE_COLS
)
1016 const ScChangeAction
* p
= this;
1017 while ( p
&& p
->GetType() == SC_CAT_DELETE_COLS
&&
1018 !((const ScChangeActionDel
*)p
)->IsTopDelete() )
1020 return p
&& p
->GetType() == SC_CAT_DELETE_TABS
;
1024 void ScChangeActionDel::UpdateReference( const ScChangeTrack
* /* pTrack */,
1025 UpdateRefMode eMode
, const ScBigRange
& rRange
,
1026 INT32 nDxP
, INT32 nDyP
, INT32 nDz
)
1028 ScRefUpdate::Update( eMode
, rRange
, nDxP
, nDyP
, nDz
, GetBigRange() );
1029 if ( !IsDeletedIn() )
1031 // evtl. in "druntergerutschten" anpassen
1032 for ( ScChangeActionLinkEntry
* pL
= pLinkDeleted
; pL
; pL
= pL
->GetNext() )
1034 ScChangeAction
* p
= pL
->GetAction();
1035 if ( p
&& p
->GetType() == SC_CAT_CONTENT
&&
1036 !GetBigRange().In( p
->GetBigRange() ) )
1038 switch ( GetType() )
1040 case SC_CAT_DELETE_COLS
:
1041 p
->GetBigRange().aStart
.SetCol( GetBigRange().aStart
.Col() );
1042 p
->GetBigRange().aEnd
.SetCol( GetBigRange().aStart
.Col() );
1044 case SC_CAT_DELETE_ROWS
:
1045 p
->GetBigRange().aStart
.SetRow( GetBigRange().aStart
.Row() );
1046 p
->GetBigRange().aEnd
.SetRow( GetBigRange().aStart
.Row() );
1048 case SC_CAT_DELETE_TABS
:
1049 p
->GetBigRange().aStart
.SetTab( GetBigRange().aStart
.Tab() );
1050 p
->GetBigRange().aEnd
.SetTab( GetBigRange().aStart
.Tab() );
1054 // added to avoid warnings
1062 ScBigRange
ScChangeActionDel::GetOverAllRange() const
1064 ScBigRange
aTmpRange( GetBigRange() );
1065 aTmpRange
.aEnd
.SetCol( aTmpRange
.aEnd
.Col() + GetDx() );
1066 aTmpRange
.aEnd
.SetRow( aTmpRange
.aEnd
.Row() + GetDy() );
1071 void ScChangeActionDel::GetDescription( String
& rStr
, ScDocument
* pDoc
,
1072 BOOL bSplitRange
, bool bWarning
) const
1074 ScChangeAction::GetDescription( rStr
, pDoc
, bSplitRange
, bWarning
);
1077 switch ( GetType() )
1079 case SC_CAT_DELETE_COLS
:
1080 nWhatId
= STR_COLUMN
;
1082 case SC_CAT_DELETE_ROWS
:
1089 ScBigRange
aTmpRange( GetBigRange() );
1090 if ( !IsRejected() )
1094 aTmpRange
.aStart
.SetCol( aTmpRange
.aStart
.Col() + GetDx() );
1095 aTmpRange
.aStart
.SetRow( aTmpRange
.aStart
.Row() + GetDy() );
1097 aTmpRange
.aEnd
.SetCol( aTmpRange
.aEnd
.Col() + GetDx() );
1098 aTmpRange
.aEnd
.SetRow( aTmpRange
.aEnd
.Row() + GetDy() );
1101 String
aRsc( ScGlobal::GetRscString( STR_CHANGED_DELETE
) );
1102 xub_StrLen nPos
= aRsc
.SearchAscii( "#1" );
1103 rStr
+= aRsc
.Copy( 0, nPos
);
1104 rStr
+= ScGlobal::GetRscString( nWhatId
);
1106 rStr
+= GetRefString( aTmpRange
, pDoc
);
1107 rStr
+= aRsc
.Copy( nPos
+2 );
1111 BOOL
ScChangeActionDel::Reject( ScDocument
* pDoc
)
1113 if ( !aBigRange
.IsValid( pDoc
) && GetType() != SC_CAT_DELETE_TABS
)
1118 if ( IsTopDelete() )
1119 { // den kompletten Bereich in einem Rutsch restaurieren
1120 ScBigRange
aTmpRange( GetOverAllRange() );
1121 if ( !aTmpRange
.IsValid( pDoc
) )
1123 if ( GetType() == SC_CAT_DELETE_TABS
)
1124 { // wird Tab angehaengt?
1125 if ( aTmpRange
.aStart
.Tab() > pDoc
->GetMaxTableNumber() )
1133 ScRange
aRange( aTmpRange
.MakeRange() );
1134 // InDelete... fuer Formel UpdateReference in Document
1135 pTrack
->SetInDeleteRange( aRange
);
1136 pTrack
->SetInDeleteTop( TRUE
);
1137 pTrack
->SetInDeleteUndo( TRUE
);
1138 pTrack
->SetInDelete( TRUE
);
1139 switch ( GetType() )
1141 case SC_CAT_DELETE_COLS
:
1142 if ( !(aRange
.aStart
.Col() == 0 && aRange
.aEnd
.Col() == MAXCOL
) )
1143 { // nur wenn nicht TabDelete
1144 if ( ( bOk
= pDoc
->CanInsertCol( aRange
) ) != FALSE
)
1145 bOk
= pDoc
->InsertCol( aRange
);
1148 case SC_CAT_DELETE_ROWS
:
1149 if ( ( bOk
= pDoc
->CanInsertRow( aRange
) ) != FALSE
)
1150 bOk
= pDoc
->InsertRow( aRange
);
1152 case SC_CAT_DELETE_TABS
:
1154 //2do: Tabellennamen merken?
1156 pDoc
->CreateValidTabName( aName
);
1157 if ( ( bOk
= pDoc
->ValidNewTabName( aName
) ) != FALSE
)
1158 bOk
= pDoc
->InsertTab( aRange
.aStart
.Tab(), aName
);
1163 // added to avoid warnings
1166 pTrack
->SetInDelete( FALSE
);
1167 pTrack
->SetInDeleteUndo( FALSE
);
1171 pTrack
->SetInDeleteTop( FALSE
);
1174 // InDeleteTop fuer UpdateReference-Undo behalten
1177 // setzt rejected und ruft UpdateReference-Undo und DeleteCellEntries
1178 RejectRestoreContents( pTrack
, GetDx(), GetDy() );
1180 pTrack
->SetInDeleteTop( FALSE
);
1186 void ScChangeActionDel::UndoCutOffMoves()
1187 { // abgeschnittene Moves wiederherstellen, Entries/Links deleten
1190 ScChangeActionMove
* pMove
= pLinkMove
->GetMove();
1191 short nFrom
= pLinkMove
->GetCutOffFrom();
1192 short nTo
= pLinkMove
->GetCutOffTo();
1193 switch ( GetType() )
1195 case SC_CAT_DELETE_COLS
:
1197 pMove
->GetFromRange().aStart
.IncCol( -nFrom
);
1198 else if ( nFrom
< 0 )
1199 pMove
->GetFromRange().aEnd
.IncCol( -nFrom
);
1201 pMove
->GetBigRange().aStart
.IncCol( -nTo
);
1203 pMove
->GetBigRange().aEnd
.IncCol( -nTo
);
1205 case SC_CAT_DELETE_ROWS
:
1207 pMove
->GetFromRange().aStart
.IncRow( -nFrom
);
1208 else if ( nFrom
< 0 )
1209 pMove
->GetFromRange().aEnd
.IncRow( -nFrom
);
1211 pMove
->GetBigRange().aStart
.IncRow( -nTo
);
1213 pMove
->GetBigRange().aEnd
.IncRow( -nTo
);
1215 case SC_CAT_DELETE_TABS
:
1217 pMove
->GetFromRange().aStart
.IncTab( -nFrom
);
1218 else if ( nFrom
< 0 )
1219 pMove
->GetFromRange().aEnd
.IncTab( -nFrom
);
1221 pMove
->GetBigRange().aStart
.IncTab( -nTo
);
1223 pMove
->GetBigRange().aEnd
.IncTab( -nTo
);
1227 // added to avoid warnings
1230 delete pLinkMove
; // rueckt sich selbst hoch
1234 void ScChangeActionDel::UndoCutOffInsert()
1235 { // abgeschnittenes Insert wiederherstellen
1238 switch ( pCutOff
->GetType() )
1240 case SC_CAT_INSERT_COLS
:
1242 pCutOff
->GetBigRange().aEnd
.IncCol( -nCutOff
);
1244 pCutOff
->GetBigRange().aStart
.IncCol( -nCutOff
);
1246 case SC_CAT_INSERT_ROWS
:
1248 pCutOff
->GetBigRange().aEnd
.IncRow( -nCutOff
);
1250 pCutOff
->GetBigRange().aStart
.IncRow( -nCutOff
);
1252 case SC_CAT_INSERT_TABS
:
1254 pCutOff
->GetBigRange().aEnd
.IncTab( -nCutOff
);
1256 pCutOff
->GetBigRange().aStart
.IncTab( -nCutOff
);
1260 // added to avoid warnings
1263 SetCutOffInsert( NULL
, 0 );
1268 // --- ScChangeActionMove --------------------------------------------------
1270 ScChangeActionMove::ScChangeActionMove(const ULONG nActionNumber
, const ScChangeActionState eStateP
, const ULONG nRejectingNumber
,
1271 const ScBigRange
& aToBigRange
, const String
& aUserP
, const DateTime
& aDateTimeP
, const String
&sComment
,
1272 const ScBigRange
& aFromBigRange
, ScChangeTrack
* pTrackP
) // wich of nDx and nDy is set is depend on the type
1274 ScChangeAction(SC_CAT_MOVE
, aToBigRange
, nActionNumber
, nRejectingNumber
, eStateP
, aDateTimeP
, aUserP
, sComment
),
1275 aFromRange(aFromBigRange
),
1283 ScChangeActionMove::~ScChangeActionMove()
1285 DeleteCellEntries();
1289 void ScChangeActionMove::AddContent( ScChangeActionContent
* pContent
)
1291 ScChangeActionCellListEntry
* pE
= new ScChangeActionCellListEntry(
1292 pContent
, pFirstCell
);
1297 void ScChangeActionMove::DeleteCellEntries()
1299 pTrack
->DeleteCellEntries( pFirstCell
, this );
1303 void ScChangeActionMove::UpdateReference( const ScChangeTrack
* /* pTrack */,
1304 UpdateRefMode eMode
, const ScBigRange
& rRange
,
1305 INT32 nDx
, INT32 nDy
, INT32 nDz
)
1307 ScRefUpdate::Update( eMode
, rRange
, nDx
, nDy
, nDz
, aFromRange
);
1308 ScRefUpdate::Update( eMode
, rRange
, nDx
, nDy
, nDz
, GetBigRange() );
1312 void ScChangeActionMove::GetDelta( INT32
& nDx
, INT32
& nDy
, INT32
& nDz
) const
1314 const ScBigAddress
& rToPos
= GetBigRange().aStart
;
1315 const ScBigAddress
& rFromPos
= GetFromRange().aStart
;
1316 nDx
= rToPos
.Col() - rFromPos
.Col();
1317 nDy
= rToPos
.Row() - rFromPos
.Row();
1318 nDz
= rToPos
.Tab() - rFromPos
.Tab();
1322 void ScChangeActionMove::GetDescription( String
& rStr
, ScDocument
* pDoc
,
1323 BOOL bSplitRange
, bool bWarning
) const
1325 ScChangeAction::GetDescription( rStr
, pDoc
, bSplitRange
, bWarning
);
1327 BOOL bFlag3D
= ( GetFromRange().aStart
.Tab() != GetBigRange().aStart
.Tab() );
1329 String
aRsc( ScGlobal::GetRscString( STR_CHANGED_MOVE
) );
1331 xub_StrLen nPos
= 0;
1332 String aTmpStr
= ScChangeAction::GetRefString( GetFromRange(), pDoc
, bFlag3D
);
1333 nPos
= aRsc
.SearchAscii( "#1", nPos
);
1334 aRsc
.Erase( nPos
, 2 );
1335 aRsc
.Insert( aTmpStr
, nPos
);
1336 nPos
= sal::static_int_cast
<xub_StrLen
>( nPos
+ aTmpStr
.Len() );
1338 aTmpStr
= ScChangeAction::GetRefString( GetBigRange(), pDoc
, bFlag3D
);
1339 nPos
= aRsc
.SearchAscii( "#2", nPos
);
1340 aRsc
.Erase( nPos
, 2 );
1341 aRsc
.Insert( aTmpStr
, nPos
);
1342 nPos
= sal::static_int_cast
<xub_StrLen
>( nPos
+ aTmpStr
.Len() );
1348 void ScChangeActionMove::GetRefString( String
& rStr
, ScDocument
* pDoc
,
1349 BOOL bFlag3D
) const
1352 bFlag3D
= ( GetFromRange().aStart
.Tab() != GetBigRange().aStart
.Tab() );
1353 rStr
= ScChangeAction::GetRefString( GetFromRange(), pDoc
, bFlag3D
);
1356 rStr
+= ScChangeAction::GetRefString( GetBigRange(), pDoc
, bFlag3D
);
1360 BOOL
ScChangeActionMove::Reject( ScDocument
* pDoc
)
1362 if ( !(aBigRange
.IsValid( pDoc
) && aFromRange
.IsValid( pDoc
)) )
1365 ScRange
aToRange( aBigRange
.MakeRange() );
1366 ScRange
aFrmRange( aFromRange
.MakeRange() );
1368 BOOL bOk
= pDoc
->IsBlockEditable( aToRange
.aStart
.Tab(),
1369 aToRange
.aStart
.Col(), aToRange
.aStart
.Row(),
1370 aToRange
.aEnd
.Col(), aToRange
.aEnd
.Row() );
1372 bOk
= pDoc
->IsBlockEditable( aFrmRange
.aStart
.Tab(),
1373 aFrmRange
.aStart
.Col(), aFrmRange
.aStart
.Row(),
1374 aFrmRange
.aEnd
.Col(), aFrmRange
.aEnd
.Row() );
1378 pTrack
->LookUpContents( aToRange
, pDoc
, 0, 0, 0 ); // zu movende Contents
1380 pDoc
->DeleteAreaTab( aToRange
, IDF_ALL
);
1381 pDoc
->DeleteAreaTab( aFrmRange
, IDF_ALL
);
1382 // Formeln im Dokument anpassen
1383 pDoc
->UpdateReference( URM_MOVE
,
1384 aFrmRange
.aStart
.Col(), aFrmRange
.aStart
.Row(), aFrmRange
.aStart
.Tab(),
1385 aFrmRange
.aEnd
.Col(), aFrmRange
.aEnd
.Row(), aFrmRange
.aEnd
.Tab(),
1386 (SCsCOL
) aFrmRange
.aStart
.Col() - aToRange
.aStart
.Col(),
1387 (SCsROW
) aFrmRange
.aStart
.Row() - aToRange
.aStart
.Row(),
1388 (SCsTAB
) aFrmRange
.aStart
.Tab() - aToRange
.aStart
.Tab(), NULL
);
1390 // LinkDependent freigeben, nachfolgendes UpdateReference-Undo setzt
1391 // ToRange->FromRange Dependents
1392 RemoveAllDependent();
1394 // setzt rejected und ruft UpdateReference-Undo und DeleteCellEntries
1395 RejectRestoreContents( pTrack
, 0, 0 );
1397 while ( pLinkDependent
)
1399 ScChangeAction
* p
= pLinkDependent
->GetAction();
1400 if ( p
&& p
->GetType() == SC_CAT_CONTENT
)
1402 ScChangeActionContent
* pContent
= (ScChangeActionContent
*) p
;
1403 if ( !pContent
->IsDeletedIn() &&
1404 pContent
->GetBigRange().aStart
.IsValid( pDoc
) )
1405 pContent
->PutNewValueToDoc( pDoc
, 0, 0 );
1406 // in LookUpContents generierte loeschen
1407 if ( pTrack
->IsGenerated( pContent
->GetActionNumber() ) &&
1408 !pContent
->IsDeletedIn() )
1410 pLinkDependent
->UnLink(); //! sonst wird der mitgeloescht
1411 pTrack
->DeleteGeneratedDelContent( pContent
);
1414 delete pLinkDependent
;
1422 // --- ScChangeActionContent -----------------------------------------------
1424 const USHORT nMemPoolChangeActionContent
= (0x8000 - 64) / sizeof(ScChangeActionContent
);
1425 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionContent
, nMemPoolChangeActionContent
, nMemPoolChangeActionContent
)
1427 ScChangeActionContent::ScChangeActionContent( const ULONG nActionNumber
,
1428 const ScChangeActionState eStateP
, const ULONG nRejectingNumber
,
1429 const ScBigRange
& aBigRangeP
, const String
& aUserP
,
1430 const DateTime
& aDateTimeP
, const String
& sComment
,
1431 ScBaseCell
* pTempOldCell
, ScDocument
* pDoc
, const String
& sOldValue
)
1433 ScChangeAction(SC_CAT_CONTENT
, aBigRangeP
, nActionNumber
, nRejectingNumber
, eStateP
, aDateTimeP
, aUserP
, sComment
),
1434 aOldValue(sOldValue
),
1435 pOldCell(pTempOldCell
),
1444 ScChangeActionContent::SetCell( aOldValue
, pOldCell
, 0, pDoc
);
1445 if ( sOldValue
.Len() ) // #i40704# don't overwrite SetCell result with empty string
1446 aOldValue
= sOldValue
; // set again, because SetCell removes it
1449 ScChangeActionContent::ScChangeActionContent( const ULONG nActionNumber
,
1450 ScBaseCell
* pTempNewCell
, const ScBigRange
& aBigRangeP
,
1451 ScDocument
* pDoc
, const String
& sNewValue
)
1453 ScChangeAction(SC_CAT_CONTENT
, aBigRangeP
, nActionNumber
),
1454 aNewValue(sNewValue
),
1456 pNewCell(pTempNewCell
),
1463 ScChangeActionContent::SetCell( aNewValue
, pNewCell
, 0, pDoc
);
1464 if ( sNewValue
.Len() ) // #i40704# don't overwrite SetCell result with empty string
1465 aNewValue
= sNewValue
; // set again, because SetCell removes it
1468 ScChangeActionContent::~ScChangeActionContent()
1474 void ScChangeActionContent::ClearTrack()
1478 pPrevContent
->pNextContent
= pNextContent
;
1480 pNextContent
->pPrevContent
= pPrevContent
;
1484 ScChangeActionContent
* ScChangeActionContent::GetTopContent() const
1488 ScChangeActionContent
* pContent
= pNextContent
;
1489 while ( pContent
->pNextContent
&& pContent
!= pContent
->pNextContent
)
1490 pContent
= pContent
->pNextContent
;
1493 return (ScChangeActionContent
*) this;
1497 ScChangeActionLinkEntry
* ScChangeActionContent::GetDeletedIn() const
1500 return GetTopContent()->pLinkDeletedIn
;
1501 return pLinkDeletedIn
;
1505 ScChangeActionLinkEntry
** ScChangeActionContent::GetDeletedInAddress()
1508 return GetTopContent()->GetDeletedInAddress();
1509 return &pLinkDeletedIn
;
1513 void ScChangeActionContent::SetOldValue( const ScBaseCell
* pCell
,
1514 const ScDocument
* pFromDoc
, ScDocument
* pToDoc
, ULONG nFormat
)
1516 ScChangeActionContent::SetValue( aOldValue
, pOldCell
,
1517 nFormat
, pCell
, pFromDoc
, pToDoc
);
1521 void ScChangeActionContent::SetOldValue( const ScBaseCell
* pCell
,
1522 const ScDocument
* pFromDoc
, ScDocument
* pToDoc
)
1524 ScChangeActionContent::SetValue( aOldValue
, pOldCell
,
1525 aBigRange
.aStart
.MakeAddress(), pCell
, pFromDoc
, pToDoc
);
1529 void ScChangeActionContent::SetNewValue( const ScBaseCell
* pCell
,
1532 ScChangeActionContent::SetValue( aNewValue
, pNewCell
,
1533 aBigRange
.aStart
.MakeAddress(), pCell
, pDoc
, pDoc
);
1537 void ScChangeActionContent::SetOldNewCells( ScBaseCell
* pOldCellP
,
1538 ULONG nOldFormat
, ScBaseCell
* pNewCellP
,
1539 ULONG nNewFormat
, ScDocument
* pDoc
)
1541 pOldCell
= pOldCellP
;
1542 pNewCell
= pNewCellP
;
1543 ScChangeActionContent::SetCell( aOldValue
, pOldCell
, nOldFormat
, pDoc
);
1544 ScChangeActionContent::SetCell( aNewValue
, pNewCell
, nNewFormat
, pDoc
);
1547 void ScChangeActionContent::SetNewCell( ScBaseCell
* pCell
, ScDocument
* pDoc
, const String
& rFormatted
)
1549 DBG_ASSERT( !pNewCell
, "ScChangeActionContent::SetNewCell: overwriting existing cell" );
1551 ScChangeActionContent::SetCell( aNewValue
, pNewCell
, 0, pDoc
);
1553 // #i40704# allow to set formatted text here - don't call SetNewValue with String from XML filter
1554 if ( rFormatted
.Len() )
1555 aNewValue
= rFormatted
;
1558 void ScChangeActionContent::SetValueString( String
& rValue
, ScBaseCell
*& pCell
,
1559 const String
& rStr
, ScDocument
* pDoc
)
1566 if ( rStr
.Len() > 1 && rStr
.GetChar(0) == '=' )
1569 pCell
= new ScFormulaCell(
1570 pDoc
, aBigRange
.aStart
.MakeAddress(), rStr
, formula::FormulaGrammar::GRAM_DEFAULT
, formula::FormulaGrammar::CONV_OOO
);
1571 ((ScFormulaCell
*)pCell
)->SetInChangeTrack( TRUE
);
1578 void ScChangeActionContent::SetOldValue( const String
& rOld
, ScDocument
* pDoc
)
1580 SetValueString( aOldValue
, pOldCell
, rOld
, pDoc
);
1584 void ScChangeActionContent::SetNewValue( const String
& rNew
, ScDocument
* pDoc
)
1586 SetValueString( aNewValue
, pNewCell
, rNew
, pDoc
);
1590 void ScChangeActionContent::GetOldString( String
& rStr
) const
1592 GetValueString( rStr
, aOldValue
, pOldCell
);
1596 void ScChangeActionContent::GetNewString( String
& rStr
) const
1598 GetValueString( rStr
, aNewValue
, pNewCell
);
1602 void ScChangeActionContent::GetDescription( String
& rStr
, ScDocument
* pDoc
,
1603 BOOL bSplitRange
, bool bWarning
) const
1605 ScChangeAction::GetDescription( rStr
, pDoc
, bSplitRange
, bWarning
);
1607 String
aRsc( ScGlobal::GetRscString( STR_CHANGED_CELL
) );
1610 GetRefString( aTmpStr
, pDoc
);
1612 xub_StrLen nPos
= 0;
1613 nPos
= aRsc
.SearchAscii( "#1", nPos
);
1614 aRsc
.Erase( nPos
, 2 );
1615 aRsc
.Insert( aTmpStr
, nPos
);
1616 nPos
= sal::static_int_cast
<xub_StrLen
>( nPos
+ aTmpStr
.Len() );
1618 GetOldString( aTmpStr
);
1619 if ( !aTmpStr
.Len() )
1620 aTmpStr
= ScGlobal::GetRscString( STR_CHANGED_BLANK
);
1621 nPos
= aRsc
.SearchAscii( "#2", nPos
);
1622 aRsc
.Erase( nPos
, 2 );
1623 aRsc
.Insert( aTmpStr
, nPos
);
1624 nPos
= sal::static_int_cast
<xub_StrLen
>( nPos
+ aTmpStr
.Len() );
1626 GetNewString( aTmpStr
);
1627 if ( !aTmpStr
.Len() )
1628 aTmpStr
= ScGlobal::GetRscString( STR_CHANGED_BLANK
);
1629 nPos
= aRsc
.SearchAscii( "#3", nPos
);
1630 aRsc
.Erase( nPos
, 2 );
1631 aRsc
.Insert( aTmpStr
, nPos
);
1637 void ScChangeActionContent::GetRefString( String
& rStr
, ScDocument
* pDoc
,
1638 BOOL bFlag3D
) const
1640 USHORT nFlags
= ( GetBigRange().IsValid( pDoc
) ? SCA_VALID
: 0 );
1643 const ScBaseCell
* pCell
= GetNewCell();
1644 if ( ScChangeActionContent::GetContentCellType( pCell
) == SC_CACCT_MATORG
)
1646 ScBigRange
aLocalBigRange( GetBigRange() );
1649 ((const ScFormulaCell
*)pCell
)->GetMatColsRows( nC
, nR
);
1650 aLocalBigRange
.aEnd
.IncCol( nC
-1 );
1651 aLocalBigRange
.aEnd
.IncRow( nR
-1 );
1652 rStr
= ScChangeAction::GetRefString( aLocalBigRange
, pDoc
, bFlag3D
);
1657 ScAddress
aTmpAddress( GetBigRange().aStart
.MakeAddress() );
1659 nFlags
|= SCA_TAB_3D
;
1660 aTmpAddress
.Format( rStr
, nFlags
, pDoc
, pDoc
->GetAddressConvention() );
1661 if ( IsDeletedIn() )
1663 rStr
.Insert( '(', 0 );
1668 rStr
= ScGlobal::GetRscString( STR_NOREF_STR
);
1672 BOOL
ScChangeActionContent::Reject( ScDocument
* pDoc
)
1674 if ( !aBigRange
.IsValid( pDoc
) )
1677 PutOldValueToDoc( pDoc
, 0, 0 );
1679 SetState( SC_CAS_REJECTED
);
1686 BOOL
ScChangeActionContent::Select( ScDocument
* pDoc
, ScChangeTrack
* pTrack
,
1687 BOOL bOldest
, Stack
* pRejectActions
)
1689 if ( !aBigRange
.IsValid( pDoc
) )
1692 ScChangeActionContent
* pContent
= this;
1693 // accept previous contents
1694 while ( ( pContent
= pContent
->pPrevContent
) != NULL
)
1696 if ( pContent
->IsVirgin() )
1697 pContent
->SetState( SC_CAS_ACCEPTED
);
1699 ScChangeActionContent
* pEnd
= pContent
= this;
1700 // reject subsequent contents
1701 while ( ( pContent
= pContent
->pNextContent
) != NULL
)
1703 // MatrixOrigin may have dependents, no dependency recursion needed
1704 const ScChangeActionLinkEntry
* pL
= pContent
->GetFirstDependentEntry();
1707 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
1712 pContent
->SetRejected();
1716 if ( bOldest
|| pEnd
!= this )
1717 { // wenn nicht aeltester: ist es ueberhaupt ein anderer als der letzte?
1718 ScRange
aRange( aBigRange
.aStart
.MakeAddress() );
1719 const ScAddress
& rPos
= aRange
.aStart
;
1721 ScChangeActionContent
* pNew
= new ScChangeActionContent( aRange
);
1722 pNew
->SetOldValue( pDoc
->GetCell( rPos
), pDoc
, pDoc
);
1725 PutOldValueToDoc( pDoc
, 0, 0 );
1727 PutNewValueToDoc( pDoc
, 0, 0 );
1729 pNew
->SetRejectAction( bOldest
? GetActionNumber() : pEnd
->GetActionNumber() );
1730 pNew
->SetState( SC_CAS_ACCEPTED
);
1731 if ( pRejectActions
)
1732 pRejectActions
->Push( pNew
);
1735 pNew
->SetNewValue( pDoc
->GetCell( rPos
), pDoc
);
1736 pTrack
->Append( pNew
);
1743 SetState( SC_CAS_ACCEPTED
);
1750 void ScChangeActionContent::GetStringOfCell( String
& rStr
,
1751 const ScBaseCell
* pCell
, const ScDocument
* pDoc
, const ScAddress
& rPos
)
1755 if ( ScChangeActionContent::NeedsNumberFormat( pCell
) )
1756 GetStringOfCell( rStr
, pCell
, pDoc
, pDoc
->GetNumberFormat( rPos
) );
1758 GetStringOfCell( rStr
, pCell
, pDoc
, 0 );
1766 void ScChangeActionContent::GetStringOfCell( String
& rStr
,
1767 const ScBaseCell
* pCell
, const ScDocument
* pDoc
, ULONG nFormat
)
1769 if ( ScChangeActionContent::GetContentCellType( pCell
) )
1771 switch ( pCell
->GetCellType() )
1773 case CELLTYPE_VALUE
:
1775 double nValue
= ((ScValueCell
*)pCell
)->GetValue();
1776 pDoc
->GetFormatTable()->GetInputLineString( nValue
, nFormat
,
1780 case CELLTYPE_STRING
:
1781 ((ScStringCell
*)pCell
)->GetString( rStr
);
1783 case CELLTYPE_EDIT
:
1784 ((ScEditCell
*)pCell
)->GetString( rStr
);
1786 case CELLTYPE_FORMULA
:
1787 ((ScFormulaCell
*)pCell
)->GetFormula( rStr
);
1799 ScChangeActionContentCellType
ScChangeActionContent::GetContentCellType( const ScBaseCell
* pCell
)
1803 switch ( pCell
->GetCellType() )
1805 case CELLTYPE_VALUE
:
1806 case CELLTYPE_STRING
:
1807 case CELLTYPE_EDIT
:
1808 return SC_CACCT_NORMAL
;
1810 case CELLTYPE_FORMULA
:
1811 switch ( ((const ScFormulaCell
*)pCell
)->GetMatrixFlag() )
1814 return SC_CACCT_NORMAL
;
1818 return SC_CACCT_MATORG
;
1821 return SC_CACCT_MATREF
;
1824 return SC_CACCT_NORMAL
;
1827 return SC_CACCT_NONE
;
1830 return SC_CACCT_NONE
;
1835 BOOL
ScChangeActionContent::NeedsNumberFormat( const ScBaseCell
* pCell
)
1837 return pCell
&& pCell
->GetCellType() == CELLTYPE_VALUE
;
1842 void ScChangeActionContent::SetValue( String
& rStr
, ScBaseCell
*& pCell
,
1843 const ScAddress
& rPos
, const ScBaseCell
* pOrgCell
,
1844 const ScDocument
* pFromDoc
, ScDocument
* pToDoc
)
1846 ULONG nFormat
= NeedsNumberFormat( pOrgCell
) ? pFromDoc
->GetNumberFormat( rPos
) : 0;
1847 SetValue( rStr
, pCell
, nFormat
, pOrgCell
, pFromDoc
, pToDoc
);
1852 void ScChangeActionContent::SetValue( String
& rStr
, ScBaseCell
*& pCell
,
1853 ULONG nFormat
, const ScBaseCell
* pOrgCell
,
1854 const ScDocument
* pFromDoc
, ScDocument
* pToDoc
)
1859 if ( ScChangeActionContent::GetContentCellType( pOrgCell
) )
1861 pCell
= pOrgCell
->CloneWithoutNote( *pToDoc
);
1862 switch ( pOrgCell
->GetCellType() )
1864 case CELLTYPE_VALUE
:
1865 { // z.B. Datum auch als solches merken
1866 double nValue
= ((ScValueCell
*)pOrgCell
)->GetValue();
1867 pFromDoc
->GetFormatTable()->GetInputLineString( nValue
,
1871 case CELLTYPE_FORMULA
:
1872 ((ScFormulaCell
*)pCell
)->SetInChangeTrack( TRUE
);
1876 // added to avoid warnings
1886 void ScChangeActionContent::SetCell( String
& rStr
, ScBaseCell
* pCell
,
1887 ULONG nFormat
, const ScDocument
* pDoc
)
1892 switch ( pCell
->GetCellType() )
1894 case CELLTYPE_VALUE
:
1895 { // e.g. remember date as date string
1896 double nValue
= ((ScValueCell
*)pCell
)->GetValue();
1897 pDoc
->GetFormatTable()->GetInputLineString( nValue
,
1901 case CELLTYPE_FORMULA
:
1902 ((ScFormulaCell
*)pCell
)->SetInChangeTrack( TRUE
);
1906 // added to avoid warnings
1913 void ScChangeActionContent::GetValueString( String
& rStr
,
1914 const String
& rValue
, const ScBaseCell
* pCell
) const
1916 if ( !rValue
.Len() )
1920 switch ( pCell
->GetCellType() )
1922 case CELLTYPE_STRING
:
1923 ((ScStringCell
*)pCell
)->GetString( rStr
);
1925 case CELLTYPE_EDIT
:
1926 ((ScEditCell
*)pCell
)->GetString( rStr
);
1928 case CELLTYPE_VALUE
: // ist immer in rValue
1931 case CELLTYPE_FORMULA
:
1932 GetFormulaString( rStr
, (ScFormulaCell
*) pCell
);
1936 // added to avoid warnings
1948 void ScChangeActionContent::GetFormulaString( String
& rStr
,
1949 const ScFormulaCell
* pCell
) const
1951 ScAddress
aPos( aBigRange
.aStart
.MakeAddress() );
1952 if ( aPos
== pCell
->aPos
|| IsDeletedIn() )
1953 pCell
->GetFormula( rStr
);
1956 DBG_ERROR( "ScChangeActionContent::GetFormulaString: aPos != pCell->aPos" );
1957 ScFormulaCell
* pNew
= new ScFormulaCell( *pCell
, *pCell
->GetDocument(), aPos
);
1958 pNew
->GetFormula( rStr
);
1964 void ScChangeActionContent::PutOldValueToDoc( ScDocument
* pDoc
,
1965 SCsCOL nDx
, SCsROW nDy
) const
1967 PutValueToDoc( pOldCell
, aOldValue
, pDoc
, nDx
, nDy
);
1971 void ScChangeActionContent::PutNewValueToDoc( ScDocument
* pDoc
,
1972 SCsCOL nDx
, SCsROW nDy
) const
1974 PutValueToDoc( pNewCell
, aNewValue
, pDoc
, nDx
, nDy
);
1978 void ScChangeActionContent::PutValueToDoc( ScBaseCell
* pCell
,
1979 const String
& rValue
, ScDocument
* pDoc
, SCsCOL nDx
, SCsROW nDy
) const
1981 ScAddress
aPos( aBigRange
.aStart
.MakeAddress() );
1986 if ( !rValue
.Len() )
1990 switch ( pCell
->GetCellType() )
1992 case CELLTYPE_VALUE
: // ist immer in rValue
1993 pDoc
->SetString( aPos
.Col(), aPos
.Row(), aPos
.Tab(), rValue
);
1996 switch ( ScChangeActionContent::GetContentCellType( pCell
) )
1998 case SC_CACCT_MATORG
:
2002 ((const ScFormulaCell
*)pCell
)->GetMatColsRows( nC
, nR
);
2003 DBG_ASSERT( nC
>0 && nR
>0, "ScChangeActionContent::PutValueToDoc: MatColsRows?" );
2004 ScRange
aRange( aPos
);
2006 aRange
.aEnd
.IncCol( nC
-1 );
2008 aRange
.aEnd
.IncRow( nR
-1 );
2009 ScMarkData aDestMark
;
2010 aDestMark
.SelectOneTable( aPos
.Tab() );
2011 aDestMark
.SetMarkArea( aRange
);
2012 pDoc
->InsertMatrixFormula( aPos
.Col(), aPos
.Row(),
2013 aRange
.aEnd
.Col(), aRange
.aEnd
.Row(),
2014 aDestMark
, EMPTY_STRING
,
2015 ((const ScFormulaCell
*)pCell
)->GetCode() );
2018 case SC_CACCT_MATREF
:
2022 pDoc
->PutCell( aPos
, pCell
->CloneWithoutNote( *pDoc
) );
2027 pDoc
->PutCell( aPos
, NULL
);
2030 pDoc
->SetString( aPos
.Col(), aPos
.Row(), aPos
.Tab(), rValue
);
2034 void lcl_InvalidateReference( ScToken
& rTok
, const ScBigAddress
& rPos
)
2036 ScSingleRefData
& rRef1
= rTok
.GetSingleRef();
2037 if ( rPos
.Col() < 0 || MAXCOL
< rPos
.Col() )
2039 rRef1
.nCol
= SCCOL_MAX
;
2040 rRef1
.nRelCol
= SCCOL_MAX
;
2041 rRef1
.SetColDeleted( TRUE
);
2043 if ( rPos
.Row() < 0 || MAXROW
< rPos
.Row() )
2045 rRef1
.nRow
= SCROW_MAX
;
2046 rRef1
.nRelRow
= SCROW_MAX
;
2047 rRef1
.SetRowDeleted( TRUE
);
2049 if ( rPos
.Tab() < 0 || MAXTAB
< rPos
.Tab() )
2051 rRef1
.nTab
= SCTAB_MAX
;
2052 rRef1
.nRelTab
= SCTAB_MAX
;
2053 rRef1
.SetTabDeleted( TRUE
);
2055 if ( rTok
.GetType() == formula::svDoubleRef
)
2057 ScSingleRefData
& rRef2
= rTok
.GetDoubleRef().Ref2
;
2058 if ( rPos
.Col() < 0 || MAXCOL
< rPos
.Col() )
2060 rRef2
.nCol
= SCCOL_MAX
;
2061 rRef2
.nRelCol
= SCCOL_MAX
;
2062 rRef2
.SetColDeleted( TRUE
);
2064 if ( rPos
.Row() < 0 || MAXROW
< rPos
.Row() )
2066 rRef2
.nRow
= SCROW_MAX
;
2067 rRef2
.nRelRow
= SCROW_MAX
;
2068 rRef2
.SetRowDeleted( TRUE
);
2070 if ( rPos
.Tab() < 0 || MAXTAB
< rPos
.Tab() )
2072 rRef2
.nTab
= SCTAB_MAX
;
2073 rRef2
.nRelTab
= SCTAB_MAX
;
2074 rRef2
.SetTabDeleted( TRUE
);
2080 void ScChangeActionContent::UpdateReference( const ScChangeTrack
* pTrack
,
2081 UpdateRefMode eMode
, const ScBigRange
& rRange
,
2082 INT32 nDx
, INT32 nDy
, INT32 nDz
)
2084 SCSIZE nOldSlot
= ScChangeTrack::ComputeContentSlot( aBigRange
.aStart
.Row() );
2085 ScRefUpdate::Update( eMode
, rRange
, nDx
, nDy
, nDz
, aBigRange
);
2086 SCSIZE nNewSlot
= ScChangeTrack::ComputeContentSlot( aBigRange
.aStart
.Row() );
2087 if ( nNewSlot
!= nOldSlot
)
2090 InsertInSlot( &(pTrack
->GetContentSlots()[nNewSlot
]) );
2093 if ( pTrack
->IsInDelete() && !pTrack
->IsInDeleteTop() )
2094 return ; // Formeln nur kompletten Bereich updaten
2096 BOOL bOldFormula
= ( pOldCell
&& pOldCell
->GetCellType() == CELLTYPE_FORMULA
);
2097 BOOL bNewFormula
= ( pNewCell
&& pNewCell
->GetCellType() == CELLTYPE_FORMULA
);
2098 if ( bOldFormula
|| bNewFormula
)
2099 { // via ScFormulaCell UpdateReference anpassen (dort)
2100 if ( pTrack
->IsInDelete() )
2102 const ScRange
& rDelRange
= pTrack
->GetInDeleteRange();
2104 nDx
= rDelRange
.aEnd
.Col() - rDelRange
.aStart
.Col() + 1;
2106 nDx
= -(rDelRange
.aEnd
.Col() - rDelRange
.aStart
.Col() + 1);
2108 nDy
= rDelRange
.aEnd
.Row() - rDelRange
.aStart
.Row() + 1;
2110 nDy
= -(rDelRange
.aEnd
.Row() - rDelRange
.aStart
.Row() + 1);
2112 nDz
= rDelRange
.aEnd
.Tab() - rDelRange
.aStart
.Tab() + 1;
2114 nDz
= -(rDelRange
.aEnd
.Tab() - rDelRange
.aStart
.Tab() + 1);
2116 ScBigRange
aTmpRange( rRange
);
2120 if ( nDx
< 0 || nDy
< 0 || nDz
< 0 )
2121 { // Delete startet dort hinter geloeschtem Bereich,
2122 // Position wird dort angepasst.
2124 aTmpRange
.aStart
.IncCol( -nDx
);
2126 aTmpRange
.aStart
.IncRow( -nDy
);
2128 aTmpRange
.aStart
.IncTab( -nDz
);
2132 // Move ist hier Quelle, dort Ziel,
2133 // Position muss vorher angepasst sein.
2135 ((ScFormulaCell
*)pOldCell
)->aPos
= aBigRange
.aStart
.MakeAddress();
2137 ((ScFormulaCell
*)pNewCell
)->aPos
= aBigRange
.aStart
.MakeAddress();
2140 aTmpRange
.aStart
.IncCol( nDx
);
2141 aTmpRange
.aEnd
.IncCol( nDx
);
2145 aTmpRange
.aStart
.IncRow( nDy
);
2146 aTmpRange
.aEnd
.IncRow( nDy
);
2150 aTmpRange
.aStart
.IncTab( nDz
);
2151 aTmpRange
.aEnd
.IncTab( nDz
);
2156 // added to avoid warnings
2159 ScRange
aRange( aTmpRange
.MakeRange() );
2161 ((ScFormulaCell
*)pOldCell
)->UpdateReference( eMode
, aRange
,
2162 (SCsCOL
) nDx
, (SCsROW
) nDy
, (SCsTAB
) nDz
, NULL
);
2164 ((ScFormulaCell
*)pNewCell
)->UpdateReference( eMode
, aRange
,
2165 (SCsCOL
) nDx
, (SCsROW
) nDy
, (SCsTAB
) nDz
, NULL
);
2166 if ( !aBigRange
.aStart
.IsValid( pTrack
->GetDocument() ) )
2168 //! UpdateReference kann nicht mit Positionen ausserhalb des
2169 //! Dokuments umgehen, deswegen alles auf #REF! setzen
2170 //2do: make it possible! das bedeutet grossen Umbau von ScAddress etc.!
2171 const ScBigAddress
& rPos
= aBigRange
.aStart
;
2175 ScTokenArray
* pArr
= ((ScFormulaCell
*)pOldCell
)->GetCode();
2177 while ( ( t
= static_cast<ScToken
*>(pArr
->GetNextReference()) ) != NULL
)
2178 lcl_InvalidateReference( *t
, rPos
);
2180 while ( ( t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN()) ) != NULL
)
2181 lcl_InvalidateReference( *t
, rPos
);
2186 ScTokenArray
* pArr
= ((ScFormulaCell
*)pNewCell
)->GetCode();
2188 while ( ( t
= static_cast<ScToken
*>(pArr
->GetNextReference()) ) != NULL
)
2189 lcl_InvalidateReference( *t
, rPos
);
2191 while ( ( t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN()) ) != NULL
)
2192 lcl_InvalidateReference( *t
, rPos
);
2199 // --- ScChangeActionReject ------------------------------------------------
2201 ScChangeActionReject::ScChangeActionReject(const ULONG nActionNumber
, const ScChangeActionState eStateP
, const ULONG nRejectingNumber
,
2202 const ScBigRange
& aBigRangeP
, const String
& aUserP
, const DateTime
& aDateTimeP
, const String
& sComment
)
2204 ScChangeAction(SC_CAT_CONTENT
, aBigRangeP
, nActionNumber
, nRejectingNumber
, eStateP
, aDateTimeP
, aUserP
, sComment
)
2209 // --- ScChangeTrack -------------------------------------------------------
2211 IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeTrackMsgInfo
, 16, 16 )
2213 const SCROW
ScChangeTrack::nContentRowsPerSlot
= InitContentRowsPerSlot();
2214 const SCSIZE
ScChangeTrack::nContentSlots
=
2215 (MAXROWCOUNT
) / InitContentRowsPerSlot() + 2;
2218 SCROW
ScChangeTrack::InitContentRowsPerSlot()
2220 const SCSIZE nMaxSlots
= 0xffe0 / sizeof( ScChangeActionContent
* ) - 2;
2221 SCROW nRowsPerSlot
= (MAXROWCOUNT
) / nMaxSlots
;
2222 if ( nRowsPerSlot
* nMaxSlots
< sal::static_int_cast
<SCSIZE
>(MAXROWCOUNT
) )
2224 return nRowsPerSlot
;
2228 ScChangeTrack::ScChangeTrack( ScDocument
* pDocP
) :
2232 StartListening(SC_MOD()->GetUserOptions());
2234 ppContentSlots
= new ScChangeActionContent
* [ nContentSlots
];
2235 memset( ppContentSlots
, 0, nContentSlots
* sizeof( ScChangeActionContent
* ) );
2238 ScChangeTrack::ScChangeTrack( ScDocument
* pDocP
, const ScStrCollection
& aTempUserCollection
) :
2239 aUserCollection(aTempUserCollection
),
2243 StartListening(SC_MOD()->GetUserOptions());
2244 ppContentSlots
= new ScChangeActionContent
* [ nContentSlots
];
2245 memset( ppContentSlots
, 0, nContentSlots
* sizeof( ScChangeActionContent
* ) );
2248 ScChangeTrack::~ScChangeTrack()
2251 delete [] ppContentSlots
;
2255 void ScChangeTrack::Init()
2259 pFirstGeneratedDelContent
= NULL
;
2260 pLastCutMove
= NULL
;
2261 pLinkInsertCol
= NULL
;
2262 pLinkInsertRow
= NULL
;
2263 pLinkInsertTab
= NULL
;
2265 pBlockModifyMsg
= NULL
;
2267 nGeneratedMin
= SC_CHGTRACK_GENERATED_START
;
2272 eMergeState
= SC_CTMS_NONE
;
2273 nLoadedFileFormatVersion
= SC_CHGTRACK_FILEFORMAT
;
2276 bInDeleteTop
= FALSE
;
2277 bInDeleteUndo
= FALSE
;
2278 bInPasteCut
= FALSE
;
2279 bUseFixDateTime
= FALSE
;
2280 bTime100thSeconds
= TRUE
;
2282 const SvtUserOptions
& rUserOpt
= SC_MOD()->GetUserOptions();
2283 aUser
= rUserOpt
.GetFirstName();
2285 aUser
+= (String
)rUserOpt
.GetLastName();
2286 aUserCollection
.Insert( new StrData( aUser
) );
2290 void ScChangeTrack::DtorClear()
2293 ScChangeAction
* pNext
;
2294 for ( p
= GetFirst(); p
; p
= pNext
)
2296 pNext
= p
->GetNext();
2299 for ( p
= pFirstGeneratedDelContent
; p
; p
= pNext
)
2301 pNext
= p
->GetNext();
2304 for ( p
= aPasteCutTable
.First(); p
; p
= aPasteCutTable
.Next() )
2308 delete pLastCutMove
;
2313 void ScChangeTrack::ClearMsgQueue()
2315 if ( pBlockModifyMsg
)
2317 delete pBlockModifyMsg
;
2318 pBlockModifyMsg
= NULL
;
2320 ScChangeTrackMsgInfo
* pMsgInfo
;
2321 while ( ( pMsgInfo
= aMsgStackTmp
.Pop() ) != NULL
)
2323 while ( ( pMsgInfo
= aMsgStackFinal
.Pop() ) != NULL
)
2325 while ( ( pMsgInfo
= aMsgQueue
.Get() ) != NULL
)
2330 void ScChangeTrack::Clear()
2334 aGeneratedTable
.Clear();
2335 aPasteCutTable
.Clear();
2336 aUserCollection
.FreeAll();
2342 void __EXPORT
ScChangeTrack::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
2344 if ( !pDoc
->IsInDtorClear() &&
2345 rHint
.ISA(SfxSimpleHint
) &&
2346 ((SfxSimpleHint
&)rHint
).GetId() == SFX_HINT_USER_OPTIONS_CHANGED
)
2348 const SvtUserOptions
& rUserOptions
= SC_MOD()->GetUserOptions();
2349 USHORT nOldCount
= aUserCollection
.GetCount();
2351 String
aStr( rUserOptions
.GetFirstName() );
2353 aStr
+= (String
)rUserOptions
.GetLastName();
2356 if ( aUserCollection
.GetCount() != nOldCount
)
2358 // New user in collection -> have to repaint because
2359 // colors may be different now (#106697#).
2360 // (Has to be done in the Notify handler, to be sure
2361 // the user collection has already been updated)
2363 SfxObjectShell
* pDocSh
= pDoc
->GetDocumentShell();
2365 pDocSh
->Broadcast( ScPaintHint( ScRange(0,0,0,MAXCOL
,MAXROW
,MAXTAB
), PAINT_GRID
) );
2371 void ScChangeTrack::SetUser( const String
& rUser
)
2374 return ; // nicht die Collection zerschiessen
2377 StrData
* pStrData
= new StrData( aUser
);
2378 if ( !aUserCollection
.Insert( pStrData
) )
2383 void ScChangeTrack::StartBlockModify( ScChangeTrackMsgType eMsgType
,
2384 ULONG nStartAction
)
2386 if ( aModifiedLink
.IsSet() )
2388 if ( pBlockModifyMsg
)
2389 aMsgStackTmp
.Push( pBlockModifyMsg
); // Block im Block
2390 pBlockModifyMsg
= new ScChangeTrackMsgInfo
;
2391 pBlockModifyMsg
->eMsgType
= eMsgType
;
2392 pBlockModifyMsg
->nStartAction
= nStartAction
;
2397 void ScChangeTrack::EndBlockModify( ULONG nEndAction
)
2399 if ( aModifiedLink
.IsSet() )
2401 if ( pBlockModifyMsg
)
2403 if ( pBlockModifyMsg
->nStartAction
<= nEndAction
)
2405 pBlockModifyMsg
->nEndAction
= nEndAction
;
2406 // Blocks in Blocks aufgeloest
2407 aMsgStackFinal
.Push( pBlockModifyMsg
);
2410 delete pBlockModifyMsg
;
2411 pBlockModifyMsg
= aMsgStackTmp
.Pop(); // evtl. Block im Block
2413 if ( !pBlockModifyMsg
)
2416 ScChangeTrackMsgInfo
* pMsg
;
2417 while ( ( pMsg
= aMsgStackFinal
.Pop() ) != NULL
)
2419 aMsgQueue
.Put( pMsg
);
2423 aModifiedLink
.Call( this );
2429 void ScChangeTrack::NotifyModified( ScChangeTrackMsgType eMsgType
,
2430 ULONG nStartAction
, ULONG nEndAction
)
2432 if ( aModifiedLink
.IsSet() )
2434 if ( !pBlockModifyMsg
|| pBlockModifyMsg
->eMsgType
!= eMsgType
||
2435 (IsGenerated( nStartAction
) &&
2436 (eMsgType
== SC_CTM_APPEND
|| eMsgType
== SC_CTM_REMOVE
)) )
2437 { // Append innerhalb von Append z.B. nicht
2438 StartBlockModify( eMsgType
, nStartAction
);
2439 EndBlockModify( nEndAction
);
2445 void ScChangeTrack::MasterLinks( ScChangeAction
* pAppend
)
2447 ScChangeActionType eType
= pAppend
->GetType();
2449 if ( eType
== SC_CAT_CONTENT
)
2451 if ( !IsGenerated( pAppend
->GetActionNumber() ) )
2453 SCSIZE nSlot
= ComputeContentSlot(
2454 pAppend
->GetBigRange().aStart
.Row() );
2455 ((ScChangeActionContent
*)pAppend
)->InsertInSlot(
2456 &ppContentSlots
[nSlot
] );
2461 if ( pAppend
->IsRejecting() )
2462 return ; // Rejects haben keine Abhaengigkeiten
2466 case SC_CAT_INSERT_COLS
:
2468 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2469 &pLinkInsertCol
, pAppend
);
2470 pAppend
->AddLink( NULL
, pLink
);
2473 case SC_CAT_INSERT_ROWS
:
2475 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2476 &pLinkInsertRow
, pAppend
);
2477 pAppend
->AddLink( NULL
, pLink
);
2480 case SC_CAT_INSERT_TABS
:
2482 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2483 &pLinkInsertTab
, pAppend
);
2484 pAppend
->AddLink( NULL
, pLink
);
2489 ScChangeActionLinkEntry
* pLink
= new ScChangeActionLinkEntry(
2490 &pLinkMove
, pAppend
);
2491 pAppend
->AddLink( NULL
, pLink
);
2496 // added to avoid warnings
2502 void ScChangeTrack::AppendLoaded( ScChangeAction
* pAppend
)
2504 aTable
.Insert( pAppend
->GetActionNumber(), pAppend
);
2506 pFirst
= pLast
= pAppend
;
2509 pLast
->pNext
= pAppend
;
2510 pAppend
->pPrev
= pLast
;
2513 MasterLinks( pAppend
);
2517 void ScChangeTrack::Append( ScChangeAction
* pAppend
, ULONG nAction
)
2519 if ( nActionMax
< nAction
)
2520 nActionMax
= nAction
;
2521 pAppend
->SetUser( aUser
);
2522 if ( bUseFixDateTime
)
2523 pAppend
->SetDateTimeUTC( aFixDateTime
);
2524 pAppend
->SetActionNumber( nAction
);
2525 aTable
.Insert( nAction
, pAppend
);
2526 // UpdateReference Inserts vor Dependencies.
2527 // Delete rejectendes Insert hatte UpdateReference mit Delete-Undo.
2528 // UpdateReference auch wenn pLast==NULL, weil pAppend ein Delete sein
2529 // kann, dass DelContents generiert haben kann
2530 if ( pAppend
->IsInsertType() && !pAppend
->IsRejecting() )
2531 UpdateReference( pAppend
, FALSE
);
2533 pFirst
= pLast
= pAppend
;
2536 pLast
->pNext
= pAppend
;
2537 pAppend
->pPrev
= pLast
;
2539 Dependencies( pAppend
);
2541 // UpdateReference Inserts nicht nach Dependencies.
2542 // Move rejectendes Move hatte UpdateReference mit Move-Undo, Inhalt in
2543 // ToRange nicht deleten.
2544 if ( !pAppend
->IsInsertType() &&
2545 !(pAppend
->GetType() == SC_CAT_MOVE
&& pAppend
->IsRejecting()) )
2546 UpdateReference( pAppend
, FALSE
);
2547 MasterLinks( pAppend
);
2549 if ( aModifiedLink
.IsSet() )
2551 NotifyModified( SC_CTM_APPEND
, nAction
, nAction
);
2552 if ( pAppend
->GetType() == SC_CAT_CONTENT
)
2554 ScChangeActionContent
* pContent
= (ScChangeActionContent
*) pAppend
;
2555 if ( ( pContent
= pContent
->GetPrevContent() ) != NULL
)
2557 ULONG nMod
= pContent
->GetActionNumber();
2558 NotifyModified( SC_CTM_CHANGE
, nMod
, nMod
);
2562 NotifyModified( SC_CTM_CHANGE
, pFirst
->GetActionNumber(),
2563 pLast
->GetActionNumber() );
2568 void ScChangeTrack::Append( ScChangeAction
* pAppend
)
2570 Append( pAppend
, ++nActionMax
);
2574 void ScChangeTrack::AppendDeleteRange( const ScRange
& rRange
,
2575 ScDocument
* pRefDoc
, ULONG
& nStartAction
, ULONG
& nEndAction
, SCsTAB nDz
)
2577 nStartAction
= GetActionMax() + 1;
2578 AppendDeleteRange( rRange
, pRefDoc
, nDz
, 0 );
2579 nEndAction
= GetActionMax();
2583 void ScChangeTrack::AppendDeleteRange( const ScRange
& rRange
,
2584 ScDocument
* pRefDoc
, SCsTAB nDz
, ULONG nRejectingInsert
)
2586 SetInDeleteRange( rRange
);
2587 StartBlockModify( SC_CTM_APPEND
, GetActionMax() + 1 );
2594 rRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
2595 for ( SCTAB nTab
= nTab1
; nTab
<= nTab2
; nTab
++ )
2597 if ( !pRefDoc
|| nTab
< pRefDoc
->GetTableCount() )
2599 if ( nCol1
== 0 && nCol2
== MAXCOL
)
2600 { // ganze Zeilen und/oder Tabellen
2601 if ( nRow1
== 0 && nRow2
== MAXROW
)
2603 //2do: geht nicht auch komplette Tabelle als ganzes?
2604 ScRange
aRange( 0, 0, nTab
, 0, MAXROW
, nTab
);
2605 for ( SCCOL nCol
= nCol1
; nCol
<= nCol2
; nCol
++ )
2606 { // spaltenweise ist weniger als zeilenweise
2607 aRange
.aStart
.SetCol( nCol
);
2608 aRange
.aEnd
.SetCol( nCol
);
2609 if ( nCol
== nCol2
)
2610 SetInDeleteTop( TRUE
);
2611 AppendOneDeleteRange( aRange
, pRefDoc
, nCol
-nCol1
, 0,
2612 nTab
-nTab1
+ nDz
, nRejectingInsert
);
2614 //! immer noch InDeleteTop
2615 AppendOneDeleteRange( rRange
, pRefDoc
, 0, 0,
2616 nTab
-nTab1
+ nDz
, nRejectingInsert
);
2620 ScRange
aRange( 0, 0, nTab
, MAXCOL
, 0, nTab
);
2621 for ( SCROW nRow
= nRow1
; nRow
<= nRow2
; nRow
++ )
2623 aRange
.aStart
.SetRow( nRow
);
2624 aRange
.aEnd
.SetRow( nRow
);
2625 if ( nRow
== nRow2
)
2626 SetInDeleteTop( TRUE
);
2627 AppendOneDeleteRange( aRange
, pRefDoc
, 0, nRow
-nRow1
,
2628 0, nRejectingInsert
);
2632 else if ( nRow1
== 0 && nRow2
== MAXROW
)
2634 ScRange
aRange( 0, 0, nTab
, 0, MAXROW
, nTab
);
2635 for ( SCCOL nCol
= nCol1
; nCol
<= nCol2
; nCol
++ )
2637 aRange
.aStart
.SetCol( nCol
);
2638 aRange
.aEnd
.SetCol( nCol
);
2639 if ( nCol
== nCol2
)
2640 SetInDeleteTop( TRUE
);
2641 AppendOneDeleteRange( aRange
, pRefDoc
, nCol
-nCol1
, 0,
2642 0, nRejectingInsert
);
2647 DBG_ERROR( "ScChangeTrack::AppendDeleteRange: Block not supported!" );
2649 SetInDeleteTop( FALSE
);
2652 EndBlockModify( GetActionMax() );
2656 void ScChangeTrack::AppendOneDeleteRange( const ScRange
& rOrgRange
,
2657 ScDocument
* pRefDoc
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
2658 ULONG nRejectingInsert
)
2660 ScRange
aTrackRange( rOrgRange
);
2663 aTrackRange
.aStart
.IncCol( -nDx
);
2664 aTrackRange
.aEnd
.IncCol( -nDx
);
2668 aTrackRange
.aStart
.IncRow( -nDy
);
2669 aTrackRange
.aEnd
.IncRow( -nDy
);
2673 aTrackRange
.aStart
.IncTab( -nDz
);
2674 aTrackRange
.aEnd
.IncTab( -nDz
);
2676 ScChangeActionDel
* pAct
= new ScChangeActionDel( aTrackRange
, nDx
, nDy
,
2678 // TabDelete keine Contents, sind in einzelnen Spalten
2679 if ( !(rOrgRange
.aStart
.Col() == 0 && rOrgRange
.aStart
.Row() == 0 &&
2680 rOrgRange
.aEnd
.Col() == MAXCOL
&& rOrgRange
.aEnd
.Row() == MAXROW
) )
2681 LookUpContents( rOrgRange
, pRefDoc
, -nDx
, -nDy
, -nDz
);
2682 if ( nRejectingInsert
)
2684 pAct
->SetRejectAction( nRejectingInsert
);
2685 pAct
->SetState( SC_CAS_ACCEPTED
);
2691 void ScChangeTrack::LookUpContents( const ScRange
& rOrgRange
,
2692 ScDocument
* pRefDoc
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
2697 ScBigAddress aBigPos
;
2698 ScCellIterator
aIter( pRefDoc
, rOrgRange
);
2699 ScBaseCell
* pCell
= aIter
.GetFirst();
2702 if ( ScChangeActionContent::GetContentCellType( pCell
) )
2704 aBigPos
.Set( aIter
.GetCol() + nDx
, aIter
.GetRow() + nDy
,
2705 aIter
.GetTab() + nDz
);
2706 ScChangeActionContent
* pContent
= SearchContentAt( aBigPos
, NULL
);
2708 { // nicht getrackte Contents
2709 aPos
.Set( aIter
.GetCol() + nDx
, aIter
.GetRow() + nDy
,
2710 aIter
.GetTab() + nDz
);
2711 GenerateDelContent( aPos
, pCell
, pRefDoc
);
2712 //! der Content wird hier _nicht_ per AddContent hinzugefuegt,
2713 //! sondern in UpdateReference, um z.B. auch kreuzende Deletes
2714 //! korrekt zu erfassen
2717 pCell
= aIter
.GetNext();
2723 void ScChangeTrack::AppendMove( const ScRange
& rFromRange
,
2724 const ScRange
& rToRange
, ScDocument
* pRefDoc
)
2726 ScChangeActionMove
* pAct
= new ScChangeActionMove( rFromRange
, rToRange
, this );
2727 LookUpContents( rToRange
, pRefDoc
, 0, 0, 0 ); // ueberschriebene Contents
2733 BOOL
ScChangeTrack::IsMatrixFormulaRangeDifferent( const ScBaseCell
* pOldCell
,
2734 const ScBaseCell
* pNewCell
)
2740 if ( pOldCell
&& (pOldCell
->GetCellType() == CELLTYPE_FORMULA
) &&
2741 ((const ScFormulaCell
*)pOldCell
)->GetMatrixFlag() == MM_FORMULA
)
2742 ((const ScFormulaCell
*)pOldCell
)->GetMatColsRows( nC1
, nR1
);
2743 if ( pNewCell
&& (pNewCell
->GetCellType() == CELLTYPE_FORMULA
) &&
2744 ((const ScFormulaCell
*)pNewCell
)->GetMatrixFlag() == MM_FORMULA
)
2745 ((const ScFormulaCell
*)pNewCell
)->GetMatColsRows( nC1
, nR1
);
2746 return nC1
!= nC2
|| nR1
!= nR2
;
2750 void ScChangeTrack::AppendContent( const ScAddress
& rPos
,
2751 const String
& rNewValue
, ScBaseCell
* pOldCell
)
2754 ScChangeActionContent::GetStringOfCell( aOldValue
, pOldCell
, pDoc
, rPos
);
2755 if ( aOldValue
!= rNewValue
||
2756 IsMatrixFormulaRangeDifferent( pOldCell
, NULL
) )
2757 { // nur wirkliche Aenderung tracken
2758 ScRange
aRange( rPos
);
2759 ScChangeActionContent
* pAct
= new ScChangeActionContent( aRange
);
2760 pAct
->SetOldValue( pOldCell
, pDoc
, pDoc
);
2761 pAct
->SetNewValue( rNewValue
, pDoc
);
2767 void ScChangeTrack::AppendContent( const ScAddress
& rPos
,
2768 const ScBaseCell
* pOldCell
, ULONG nOldFormat
, ScDocument
* pRefDoc
)
2773 ScChangeActionContent::GetStringOfCell( aOldValue
, pOldCell
, pRefDoc
, nOldFormat
);
2775 ScBaseCell
* pNewCell
= pDoc
->GetCell( rPos
);
2776 ScChangeActionContent::GetStringOfCell( aNewValue
, pNewCell
, pDoc
, rPos
);
2777 if ( aOldValue
!= aNewValue
||
2778 IsMatrixFormulaRangeDifferent( pOldCell
, pNewCell
) )
2779 { // nur wirkliche Aenderung tracken
2780 ScRange
aRange( rPos
);
2781 ScChangeActionContent
* pAct
= new ScChangeActionContent( aRange
);
2782 pAct
->SetOldValue( pOldCell
, pRefDoc
, pDoc
, nOldFormat
);
2783 pAct
->SetNewValue( pNewCell
, pDoc
);
2789 void ScChangeTrack::AppendContent( const ScAddress
& rPos
,
2790 ScDocument
* pRefDoc
)
2793 ScBaseCell
* pOldCell
= pRefDoc
->GetCell( rPos
);
2794 ScChangeActionContent::GetStringOfCell( aOldValue
, pOldCell
, pRefDoc
, rPos
);
2796 ScBaseCell
* pNewCell
= pDoc
->GetCell( rPos
);
2797 ScChangeActionContent::GetStringOfCell( aNewValue
, pNewCell
, pDoc
, rPos
);
2798 if ( aOldValue
!= aNewValue
||
2799 IsMatrixFormulaRangeDifferent( pOldCell
, pNewCell
) )
2800 { // nur wirkliche Aenderung tracken
2801 ScRange
aRange( rPos
);
2802 ScChangeActionContent
* pAct
= new ScChangeActionContent( aRange
);
2803 pAct
->SetOldValue( pOldCell
, pRefDoc
, pDoc
);
2804 pAct
->SetNewValue( pNewCell
, pDoc
);
2810 void ScChangeTrack::AppendContent( const ScAddress
& rPos
,
2811 const ScBaseCell
* pOldCell
)
2813 if ( ScChangeActionContent::NeedsNumberFormat( pOldCell
) )
2814 AppendContent( rPos
, pOldCell
, pDoc
->GetNumberFormat( rPos
), pDoc
);
2816 AppendContent( rPos
, pOldCell
, 0, pDoc
);
2820 void ScChangeTrack::SetLastCutMoveRange( const ScRange
& rRange
,
2821 ScDocument
* pRefDoc
)
2825 // ToRange nicht mit Deletes linken und nicht in der Groesse aendern,
2826 // eigentlich unnoetig, da ein Delete vorher in
2827 // ScViewFunc::PasteFromClip ein ResetLastCut ausloest
2828 ScBigRange
& r
= pLastCutMove
->GetBigRange();
2829 r
.aEnd
.SetCol( -1 );
2830 r
.aEnd
.SetRow( -1 );
2831 r
.aEnd
.SetTab( -1 );
2832 r
.aStart
.SetCol( -1 - (rRange
.aEnd
.Col() - rRange
.aStart
.Col()) );
2833 r
.aStart
.SetRow( -1 - (rRange
.aEnd
.Row() - rRange
.aStart
.Row()) );
2834 r
.aStart
.SetTab( -1 - (rRange
.aEnd
.Tab() - rRange
.aStart
.Tab()) );
2835 // zu ueberschreibende Contents im FromRange
2836 LookUpContents( rRange
, pRefDoc
, 0, 0, 0 );
2841 void ScChangeTrack::AppendContentRange( const ScRange
& rRange
,
2842 ScDocument
* pRefDoc
, ULONG
& nStartAction
, ULONG
& nEndAction
,
2843 ScChangeActionClipMode eClipMode
)
2845 if ( eClipMode
== SC_CACM_CUT
)
2848 pLastCutMove
= new ScChangeActionMove( rRange
, rRange
, this );
2849 SetLastCutMoveRange( rRange
, pRefDoc
);
2857 rRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
2859 if ( eClipMode
== SC_CACM_PASTE
&& HasLastCut() )
2861 bDoContents
= FALSE
;
2862 SetInPasteCut( TRUE
);
2863 // Paste und Cut abstimmen, Paste kann groesserer Range sein
2864 ScRange
aRange( rRange
);
2865 ScBigRange
& r
= pLastCutMove
->GetBigRange();
2867 if ( (nTmpCol
= (SCCOL
) (r
.aEnd
.Col() - r
.aStart
.Col())) != (nCol2
- nCol1
) )
2869 aRange
.aEnd
.SetCol( aRange
.aStart
.Col() + nTmpCol
);
2870 nCol1
+= nTmpCol
+ 1;
2874 if ( (nTmpRow
= (SCROW
) (r
.aEnd
.Row() - r
.aStart
.Row())) != (nRow2
- nRow1
) )
2876 aRange
.aEnd
.SetRow( aRange
.aStart
.Row() + nTmpRow
);
2877 nRow1
+= nTmpRow
+ 1;
2881 if ( (nTmpTab
= (SCTAB
) (r
.aEnd
.Tab() - r
.aStart
.Tab())) != (nTab2
- nTab1
) )
2883 aRange
.aEnd
.SetTab( aRange
.aStart
.Tab() + nTmpTab
);
2884 nTab1
+= nTmpTab
+ 1;
2888 Undo( nStartLastCut
, nEndLastCut
); // hier werden sich die Cuts gemerkt
2889 //! StartAction erst nach Undo
2890 nStartAction
= GetActionMax() + 1;
2891 StartBlockModify( SC_CTM_APPEND
, nStartAction
);
2892 // zu ueberschreibende Contents im ToRange
2893 LookUpContents( aRange
, pRefDoc
, 0, 0, 0 );
2894 pLastCutMove
->SetStartLastCut( nStartLastCut
);
2895 pLastCutMove
->SetEndLastCut( nEndLastCut
);
2896 Append( pLastCutMove
);
2897 pLastCutMove
= NULL
;
2899 SetInPasteCut( FALSE
);
2904 nStartAction
= GetActionMax() + 1;
2905 StartBlockModify( SC_CTM_APPEND
, nStartAction
);
2910 for ( SCTAB nTab
= nTab1
; nTab
<= nTab2
; nTab
++ )
2912 aPos
.SetTab( nTab
);
2913 for ( SCCOL nCol
= nCol1
; nCol
<= nCol2
; nCol
++ )
2915 aPos
.SetCol( nCol
);
2916 for ( SCROW nRow
= nRow1
; nRow
<= nRow2
; nRow
++ )
2918 aPos
.SetRow( nRow
);
2919 AppendContent( aPos
, pRefDoc
);
2924 nEndAction
= GetActionMax();
2925 EndBlockModify( nEndAction
);
2926 if ( eClipMode
== SC_CACM_CUT
)
2928 nStartLastCut
= nStartAction
;
2929 nEndLastCut
= nEndAction
;
2934 void ScChangeTrack::AppendContentsIfInRefDoc( ScDocument
* pRefDoc
,
2935 ULONG
& nStartAction
, ULONG
& nEndAction
)
2937 ScDocumentIterator
aIter( pRefDoc
, 0, MAXTAB
);
2938 if ( aIter
.GetFirst() )
2940 nStartAction
= GetActionMax() + 1;
2941 StartBlockModify( SC_CTM_APPEND
, nStartAction
);
2942 SvNumberFormatter
* pFormatter
= pRefDoc
->GetFormatTable();
2948 aIter
.GetPos( nCol
, nRow
, nTab
);
2949 ScAddress
aPos( nCol
, nRow
, nTab
);
2950 AppendContent( aPos
, aIter
.GetCell(),
2951 aIter
.GetPattern()->GetNumberFormat( pFormatter
), pRefDoc
);
2952 } while ( aIter
.GetNext() );
2953 nEndAction
= GetActionMax();
2954 EndBlockModify( nEndAction
);
2957 nStartAction
= nEndAction
= 0;
2961 ScChangeActionContent
* ScChangeTrack::AppendContentOnTheFly(
2962 const ScAddress
& rPos
, ScBaseCell
* pOldCell
, ScBaseCell
* pNewCell
,
2963 ULONG nOldFormat
, ULONG nNewFormat
)
2965 ScRange
aRange( rPos
);
2966 ScChangeActionContent
* pAct
= new ScChangeActionContent( aRange
);
2967 pAct
->SetOldNewCells( pOldCell
, nOldFormat
, pNewCell
, nNewFormat
, pDoc
);
2973 void ScChangeTrack::AppendInsert( const ScRange
& rRange
)
2975 ScChangeActionIns
* pAct
= new ScChangeActionIns( rRange
);
2980 void ScChangeTrack::DeleteCellEntries( ScChangeActionCellListEntry
*& pCellList
,
2981 ScChangeAction
* pDeletor
)
2983 ScChangeActionCellListEntry
* pE
= pCellList
;
2986 ScChangeActionCellListEntry
* pNext
= pE
->pNext
;
2987 pE
->pContent
->RemoveDeletedIn( pDeletor
);
2988 if ( IsGenerated( pE
->pContent
->GetActionNumber() ) &&
2989 !pE
->pContent
->IsDeletedIn() )
2990 DeleteGeneratedDelContent( pE
->pContent
);
2998 ScChangeActionContent
* ScChangeTrack::GenerateDelContent(
2999 const ScAddress
& rPos
, const ScBaseCell
* pCell
,
3000 const ScDocument
* pFromDoc
)
3002 ScChangeActionContent
* pContent
= new ScChangeActionContent(
3004 pContent
->SetActionNumber( --nGeneratedMin
);
3006 ScChangeActionContent::SetValue( pContent
->aNewValue
, pContent
->pNewCell
,
3007 rPos
, pCell
, pFromDoc
, pDoc
);
3008 // pNextContent und pPrevContent werden nicht gesetzt
3009 if ( pFirstGeneratedDelContent
)
3010 { // vorne reinhaengen
3011 pFirstGeneratedDelContent
->pPrev
= pContent
;
3012 pContent
->pNext
= pFirstGeneratedDelContent
;
3014 pFirstGeneratedDelContent
= pContent
;
3015 aGeneratedTable
.Insert( nGeneratedMin
, pContent
);
3016 NotifyModified( SC_CTM_APPEND
, nGeneratedMin
, nGeneratedMin
);
3021 void ScChangeTrack::DeleteGeneratedDelContent( ScChangeActionContent
* pContent
)
3023 ULONG nAct
= pContent
->GetActionNumber();
3024 aGeneratedTable
.Remove( nAct
);
3025 if ( pFirstGeneratedDelContent
== pContent
)
3026 pFirstGeneratedDelContent
= (ScChangeActionContent
*) pContent
->pNext
;
3027 if ( pContent
->pNext
)
3028 pContent
->pNext
->pPrev
= pContent
->pPrev
;
3029 if ( pContent
->pPrev
)
3030 pContent
->pPrev
->pNext
= pContent
->pNext
;
3032 NotifyModified( SC_CTM_REMOVE
, nAct
, nAct
);
3033 if ( nAct
== nGeneratedMin
)
3034 ++nGeneratedMin
; //! erst nach NotifyModified wg. IsGenerated
3038 ScChangeActionContent
* ScChangeTrack::SearchContentAt(
3039 const ScBigAddress
& rPos
, ScChangeAction
* pButNotThis
) const
3041 SCSIZE nSlot
= ComputeContentSlot( rPos
.Row() );
3042 for ( ScChangeActionContent
* p
= ppContentSlots
[nSlot
]; p
;
3043 p
= p
->GetNextInSlot() )
3045 if ( p
!= pButNotThis
&& !p
->IsDeletedIn() &&
3046 p
->GetBigRange().aStart
== rPos
)
3048 ScChangeActionContent
* pContent
= p
->GetTopContent();
3049 if ( !pContent
->IsDeletedIn() )
3057 void ScChangeTrack::AddDependentWithNotify( ScChangeAction
* pParent
,
3058 ScChangeAction
* pDependent
)
3060 ScChangeActionLinkEntry
* pLink
= pParent
->AddDependent( pDependent
);
3061 pDependent
->AddLink( pParent
, pLink
);
3062 if ( aModifiedLink
.IsSet() )
3064 ULONG nMod
= pParent
->GetActionNumber();
3065 NotifyModified( SC_CTM_PARENT
, nMod
, nMod
);
3070 void ScChangeTrack::Dependencies( ScChangeAction
* pAct
)
3072 // Finde die letzte Abhaengigkeit fuer jeweils Col/Row/Tab.
3073 // Content an gleicher Position verketten.
3074 // Move Abhaengigkeiten.
3075 ScChangeActionType eActType
= pAct
->GetType();
3076 if ( eActType
== SC_CAT_REJECT
||
3077 (eActType
== SC_CAT_MOVE
&& pAct
->IsRejecting()) )
3078 return ; // diese Rejects sind nicht abhaengig
3080 if ( eActType
== SC_CAT_CONTENT
)
3082 if ( !(((ScChangeActionContent
*)pAct
)->GetNextContent() ||
3083 ((ScChangeActionContent
*)pAct
)->GetPrevContent()) )
3084 { // Contents an gleicher Position verketten
3085 ScChangeActionContent
* pContent
= SearchContentAt(
3086 pAct
->GetBigRange().aStart
, pAct
);
3089 pContent
->SetNextContent( (ScChangeActionContent
*) pAct
);
3090 ((ScChangeActionContent
*)pAct
)->SetPrevContent( pContent
);
3093 const ScBaseCell
* pCell
= ((ScChangeActionContent
*)pAct
)->GetNewCell();
3094 if ( ScChangeActionContent::GetContentCellType( pCell
) == SC_CACCT_MATREF
)
3097 ((const ScFormulaCell
*)pCell
)->GetMatrixOrigin( aOrg
);
3098 ScChangeActionContent
* pContent
= SearchContentAt( aOrg
, pAct
);
3099 if ( pContent
&& pContent
->IsMatrixOrigin() )
3101 AddDependentWithNotify( pContent
, pAct
);
3105 DBG_ERRORFILE( "ScChangeTrack::Dependencies: MatOrg not found" );
3110 if ( !(pLinkInsertCol
|| pLinkInsertRow
|| pLinkInsertTab
|| pLinkMove
) )
3111 return ; // keine Dependencies
3112 if ( pAct
->IsRejecting() )
3113 return ; // ausser Content keine Dependencies
3115 // Insert in einem entsprechenden Insert haengt davon ab, sonst muesste
3116 // der vorherige Insert gesplittet werden.
3117 // Sich kreuzende Inserts und Deletes sind nicht abhaengig.
3118 // Alles andere ist abhaengig.
3120 // Der zuletzt eingelinkte Insert steht am Anfang einer Kette,
3121 // also genau richtig
3123 const ScBigRange
& rRange
= pAct
->GetBigRange();
3124 BOOL bActNoInsert
= !pAct
->IsInsertType();
3125 BOOL bActColDel
= ( eActType
== SC_CAT_DELETE_COLS
);
3126 BOOL bActRowDel
= ( eActType
== SC_CAT_DELETE_ROWS
);
3127 BOOL bActTabDel
= ( eActType
== SC_CAT_DELETE_TABS
);
3129 if ( pLinkInsertCol
&& (eActType
== SC_CAT_INSERT_COLS
||
3130 (bActNoInsert
&& !bActRowDel
&& !bActTabDel
)) )
3132 for ( ScChangeActionLinkEntry
* pL
= pLinkInsertCol
; pL
; pL
= pL
->GetNext() )
3134 ScChangeActionIns
* pTest
= (ScChangeActionIns
*) pL
->GetAction();
3135 if ( !pTest
->IsRejected() &&
3136 pTest
->GetBigRange().Intersects( rRange
) )
3138 AddDependentWithNotify( pTest
, pAct
);
3143 if ( pLinkInsertRow
&& (eActType
== SC_CAT_INSERT_ROWS
||
3144 (bActNoInsert
&& !bActColDel
&& !bActTabDel
)) )
3146 for ( ScChangeActionLinkEntry
* pL
= pLinkInsertRow
; pL
; pL
= pL
->GetNext() )
3148 ScChangeActionIns
* pTest
= (ScChangeActionIns
*) pL
->GetAction();
3149 if ( !pTest
->IsRejected() &&
3150 pTest
->GetBigRange().Intersects( rRange
) )
3152 AddDependentWithNotify( pTest
, pAct
);
3157 if ( pLinkInsertTab
&& (eActType
== SC_CAT_INSERT_TABS
||
3158 (bActNoInsert
&& !bActColDel
&& !bActRowDel
)) )
3160 for ( ScChangeActionLinkEntry
* pL
= pLinkInsertTab
; pL
; pL
= pL
->GetNext() )
3162 ScChangeActionIns
* pTest
= (ScChangeActionIns
*) pL
->GetAction();
3163 if ( !pTest
->IsRejected() &&
3164 pTest
->GetBigRange().Intersects( rRange
) )
3166 AddDependentWithNotify( pTest
, pAct
);
3174 if ( eActType
== SC_CAT_CONTENT
)
3175 { // Content ist von FromRange abhaengig
3176 const ScBigAddress
& rPos
= rRange
.aStart
;
3177 for ( ScChangeActionLinkEntry
* pL
= pLinkMove
; pL
; pL
= pL
->GetNext() )
3179 ScChangeActionMove
* pTest
= (ScChangeActionMove
*) pL
->GetAction();
3180 if ( !pTest
->IsRejected() &&
3181 pTest
->GetFromRange().In( rPos
) )
3183 AddDependentWithNotify( pTest
, pAct
);
3187 else if ( eActType
== SC_CAT_MOVE
)
3188 { // Move FromRange ist von ToRange abhaengig
3189 const ScBigRange
& rFromRange
= ((ScChangeActionMove
*)pAct
)->GetFromRange();
3190 for ( ScChangeActionLinkEntry
* pL
= pLinkMove
; pL
; pL
= pL
->GetNext() )
3192 ScChangeActionMove
* pTest
= (ScChangeActionMove
*) pL
->GetAction();
3193 if ( !pTest
->IsRejected() &&
3194 pTest
->GetBigRange().Intersects( rFromRange
) )
3196 AddDependentWithNotify( pTest
, pAct
);
3201 { // Inserts und Deletes sind abhaengig, sobald sie FromRange oder
3203 for ( ScChangeActionLinkEntry
* pL
= pLinkMove
; pL
; pL
= pL
->GetNext() )
3205 ScChangeActionMove
* pTest
= (ScChangeActionMove
*) pL
->GetAction();
3206 if ( !pTest
->IsRejected() &&
3207 (pTest
->GetFromRange().Intersects( rRange
) ||
3208 pTest
->GetBigRange().Intersects( rRange
)) )
3210 AddDependentWithNotify( pTest
, pAct
);
3218 void ScChangeTrack::Remove( ScChangeAction
* pRemove
)
3220 // aus Track ausklinken
3221 ULONG nAct
= pRemove
->GetActionNumber();
3222 aTable
.Remove( nAct
);
3223 if ( nAct
== nActionMax
)
3225 if ( pRemove
== pLast
)
3226 pLast
= pRemove
->pPrev
;
3227 if ( pRemove
== pFirst
)
3228 pFirst
= pRemove
->pNext
;
3229 if ( nAct
== nMarkLastSaved
)
3231 ( pRemove
->pPrev
? pRemove
->pPrev
->GetActionNumber() : 0 );
3233 // aus der globalen Kette ausklinken
3234 if ( pRemove
->pNext
)
3235 pRemove
->pNext
->pPrev
= pRemove
->pPrev
;
3236 if ( pRemove
->pPrev
)
3237 pRemove
->pPrev
->pNext
= pRemove
->pNext
;
3239 // Dependencies nicht loeschen, passiert on delete automatisch durch
3240 // LinkEntry, ohne Listen abzuklappern
3242 if ( aModifiedLink
.IsSet() )
3244 NotifyModified( SC_CTM_REMOVE
, nAct
, nAct
);
3245 if ( pRemove
->GetType() == SC_CAT_CONTENT
)
3247 ScChangeActionContent
* pContent
= (ScChangeActionContent
*) pRemove
;
3248 if ( ( pContent
= pContent
->GetPrevContent() ) != NULL
)
3250 ULONG nMod
= pContent
->GetActionNumber();
3251 NotifyModified( SC_CTM_CHANGE
, nMod
, nMod
);
3255 NotifyModified( SC_CTM_CHANGE
, pFirst
->GetActionNumber(),
3256 pLast
->GetActionNumber() );
3259 if ( IsInPasteCut() && pRemove
->GetType() == SC_CAT_CONTENT
)
3260 { //! Content wird wiederverwertet
3261 ScChangeActionContent
* pContent
= (ScChangeActionContent
*) pRemove
;
3262 pContent
->RemoveAllLinks();
3263 pContent
->ClearTrack();
3264 pContent
->pNext
= pContent
->pPrev
= NULL
;
3265 pContent
->pNextContent
= pContent
->pPrevContent
= NULL
;
3270 void ScChangeTrack::Undo( ULONG nStartAction
, ULONG nEndAction
, bool bMerge
)
3272 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3275 SetMergeState( SC_CTMS_UNDO
);
3278 if ( nStartAction
== 0 )
3280 if ( nEndAction
> nActionMax
)
3281 nEndAction
= nActionMax
;
3282 if ( nEndAction
&& nStartAction
<= nEndAction
)
3284 if ( nStartAction
== nStartLastCut
&& nEndAction
== nEndLastCut
&&
3287 StartBlockModify( SC_CTM_REMOVE
, nStartAction
);
3288 for ( ULONG j
= nEndAction
; j
>= nStartAction
; --j
)
3289 { // rueckwaerts um evtl. nActionMax zu recyclen und schnelleren
3290 // Zugriff via pLast, Deletes in richtiger Reihenfolge
3291 ScChangeAction
* pAct
= ( (j
== nActionMax
&& pLast
&&
3292 pLast
->GetActionNumber() == j
) ? pLast
: GetAction( j
) );
3295 if ( pAct
->IsDeleteType() )
3297 if ( j
== nEndAction
|| (pAct
!= pLast
&&
3298 ((ScChangeActionDel
*)pAct
)->IsTopDelete()) )
3300 SetInDeleteTop( TRUE
);
3301 SetInDeleteRange( ((ScChangeActionDel
*)pAct
)->
3302 GetOverAllRange().MakeRange() );
3305 UpdateReference( pAct
, TRUE
);
3306 SetInDeleteTop( FALSE
);
3308 if ( IsInPasteCut() )
3309 aPasteCutTable
.Insert( pAct
->GetActionNumber(), pAct
);
3312 if ( j
== nStartAction
&& pAct
->GetType() == SC_CAT_MOVE
)
3314 ScChangeActionMove
* pMove
= (ScChangeActionMove
*) pAct
;
3315 ULONG nStart
= pMove
->GetStartLastCut();
3316 ULONG nEnd
= pMove
->GetEndLastCut();
3317 if ( nStart
&& nStart
<= nEnd
)
3318 { // LastCut wiederherstellen
3319 //! Links vor Cut-Append aufloesen
3320 pMove
->RemoveAllLinks();
3321 StartBlockModify( SC_CTM_APPEND
, nStart
);
3322 for ( ULONG nCut
= nStart
; nCut
<= nEnd
; nCut
++ )
3324 ScChangeAction
* pCut
= aPasteCutTable
.Remove( nCut
);
3327 DBG_ASSERT( !aTable
.Get( nCut
), "ScChangeTrack::Undo: nCut dup" );
3328 Append( pCut
, nCut
);
3332 DBG_ERROR( "ScChangeTrack::Undo: nCut not found" );
3335 EndBlockModify( nEnd
);
3337 nStartLastCut
= nStart
;
3339 pLastCutMove
= pMove
;
3340 SetLastCutMoveRange(
3341 pMove
->GetFromRange().MakeRange(), pDoc
);
3351 EndBlockModify( nEndAction
);
3354 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3357 SetMergeState( SC_CTMS_OTHER
);
3363 BOOL
ScChangeTrack::MergeIgnore( const ScChangeAction
& rAction
, ULONG nFirstMerge
)
3365 if ( rAction
.IsRejected() )
3366 return TRUE
; // da kommt noch eine passende Reject-Action
3368 if ( rAction
.IsRejecting() && rAction
.GetRejectAction() >= nFirstMerge
)
3369 return TRUE
; // da ist sie
3371 return FALSE
; // alles andere
3375 void ScChangeTrack::MergePrepare( ScChangeAction
* pFirstMerge
, bool bShared
)
3377 SetMergeState( SC_CTMS_PREPARE
);
3378 ULONG nFirstMerge
= pFirstMerge
->GetActionNumber();
3379 ScChangeAction
* pAct
= GetLast();
3382 SetLastMerge( pAct
->GetActionNumber() );
3384 { // rueckwaerts, Deletes in richtiger Reihenfolge
3385 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3386 if ( bShared
|| !ScChangeTrack::MergeIgnore( *pAct
, nFirstMerge
) )
3388 if ( pAct
->IsDeleteType() )
3390 if ( ((ScChangeActionDel
*)pAct
)->IsTopDelete() )
3392 SetInDeleteTop( TRUE
);
3393 SetInDeleteRange( ((ScChangeActionDel
*)pAct
)->
3394 GetOverAllRange().MakeRange() );
3397 UpdateReference( pAct
, TRUE
);
3398 SetInDeleteTop( FALSE
);
3399 pAct
->DeleteCellEntries(); // sonst GPF bei Track Clear()
3401 pAct
= ( pAct
== pFirstMerge
? NULL
: pAct
->GetPrev() );
3404 SetMergeState( SC_CTMS_OTHER
); //! nachfolgende per default MergeOther
3408 void ScChangeTrack::MergeOwn( ScChangeAction
* pAct
, ULONG nFirstMerge
, bool bShared
)
3410 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3411 if ( bShared
|| !ScChangeTrack::MergeIgnore( *pAct
, nFirstMerge
) )
3413 SetMergeState( SC_CTMS_OWN
);
3414 if ( pAct
->IsDeleteType() )
3416 if ( ((ScChangeActionDel
*)pAct
)->IsTopDelete() )
3418 SetInDeleteTop( TRUE
);
3419 SetInDeleteRange( ((ScChangeActionDel
*)pAct
)->
3420 GetOverAllRange().MakeRange() );
3423 UpdateReference( pAct
, FALSE
);
3424 SetInDeleteTop( FALSE
);
3425 SetMergeState( SC_CTMS_OTHER
); //! nachfolgende per default MergeOther
3430 void ScChangeTrack::UpdateReference( ScChangeAction
* pAct
, BOOL bUndo
)
3432 ScChangeActionType eActType
= pAct
->GetType();
3433 if ( eActType
== SC_CAT_CONTENT
|| eActType
== SC_CAT_REJECT
)
3436 //! Formelzellen haengen nicht im Dokument
3437 BOOL bOldAutoCalc
= pDoc
->GetAutoCalc();
3438 pDoc
->SetAutoCalc( FALSE
);
3439 BOOL bOldNoListening
= pDoc
->GetNoListening();
3440 pDoc
->SetNoListening( TRUE
);
3441 //! Formelzellen ExpandRefs synchronisiert zu denen im Dokument
3442 BOOL bOldExpandRefs
= pDoc
->IsExpandRefs();
3443 if ( (!bUndo
&& pAct
->IsInsertType()) || (bUndo
&& pAct
->IsDeleteType()) )
3444 pDoc
->SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
3446 if ( pAct
->IsDeleteType() )
3448 SetInDeleteUndo( bUndo
);
3449 SetInDelete( TRUE
);
3451 else if ( GetMergeState() == SC_CTMS_OWN
)
3453 // Referenzen von Formelzellen wiederherstellen,
3454 // vorheriges MergePrepare war bei einem Insert wie ein Delete
3455 if ( pAct
->IsInsertType() )
3456 SetInDeleteUndo( TRUE
);
3459 //! erst die generated, als waeren sie vorher getrackt worden
3460 if ( pFirstGeneratedDelContent
)
3461 UpdateReference( (ScChangeAction
**)&pFirstGeneratedDelContent
, pAct
,
3463 UpdateReference( &pFirst
, pAct
, bUndo
);
3465 SetInDelete( FALSE
);
3466 SetInDeleteUndo( FALSE
);
3468 pDoc
->SetExpandRefs( bOldExpandRefs
);
3469 pDoc
->SetNoListening( bOldNoListening
);
3470 pDoc
->SetAutoCalc( bOldAutoCalc
);
3474 void ScChangeTrack::UpdateReference( ScChangeAction
** ppFirstAction
,
3475 ScChangeAction
* pAct
, BOOL bUndo
)
3477 ScChangeActionType eActType
= pAct
->GetType();
3478 BOOL bGeneratedDelContents
=
3479 ( ppFirstAction
== (ScChangeAction
**)&pFirstGeneratedDelContent
);
3480 const ScBigRange
& rOrgRange
= pAct
->GetBigRange();
3481 ScBigRange
aRange( rOrgRange
);
3482 ScBigRange
aDelRange( rOrgRange
);
3483 INT32 nDx
, nDy
, nDz
;
3484 nDx
= nDy
= nDz
= 0;
3485 UpdateRefMode eMode
= URM_INSDEL
;
3489 case SC_CAT_INSERT_COLS
:
3490 aRange
.aEnd
.SetCol( nInt32Max
);
3491 nDx
= rOrgRange
.aEnd
.Col() - rOrgRange
.aStart
.Col() + 1;
3493 case SC_CAT_INSERT_ROWS
:
3494 aRange
.aEnd
.SetRow( nInt32Max
);
3495 nDy
= rOrgRange
.aEnd
.Row() - rOrgRange
.aStart
.Row() + 1;
3497 case SC_CAT_INSERT_TABS
:
3498 aRange
.aEnd
.SetTab( nInt32Max
);
3499 nDz
= rOrgRange
.aEnd
.Tab() - rOrgRange
.aStart
.Tab() + 1;
3501 case SC_CAT_DELETE_COLS
:
3502 aRange
.aEnd
.SetCol( nInt32Max
);
3503 nDx
= -(rOrgRange
.aEnd
.Col() - rOrgRange
.aStart
.Col() + 1);
3504 aDelRange
.aEnd
.SetCol( aDelRange
.aStart
.Col() - nDx
- 1 );
3507 case SC_CAT_DELETE_ROWS
:
3508 aRange
.aEnd
.SetRow( nInt32Max
);
3509 nDy
= -(rOrgRange
.aEnd
.Row() - rOrgRange
.aStart
.Row() + 1);
3510 aDelRange
.aEnd
.SetRow( aDelRange
.aStart
.Row() - nDy
- 1 );
3513 case SC_CAT_DELETE_TABS
:
3514 aRange
.aEnd
.SetTab( nInt32Max
);
3515 nDz
= -(rOrgRange
.aEnd
.Tab() - rOrgRange
.aStart
.Tab() + 1);
3516 aDelRange
.aEnd
.SetTab( aDelRange
.aStart
.Tab() - nDz
- 1 );
3521 ((ScChangeActionMove
*)pAct
)->GetDelta( nDx
, nDy
, nDz
);
3524 DBG_ERROR( "ScChangeTrack::UpdateReference: unknown Type" );
3533 { //! fuer diesen Mechanismus gilt:
3534 //! es gibt nur ganze, einfache geloeschte Spalten/Zeilen
3535 ScChangeActionDel
* pActDel
= (ScChangeActionDel
*) pAct
;
3538 ScChangeActionType eInsType
= SC_CAT_NONE
; // for Insert-Undo-"Deletes"
3541 case SC_CAT_DELETE_COLS
:
3542 eInsType
= SC_CAT_INSERT_COLS
;
3544 case SC_CAT_DELETE_ROWS
:
3545 eInsType
= SC_CAT_INSERT_ROWS
;
3547 case SC_CAT_DELETE_TABS
:
3548 eInsType
= SC_CAT_INSERT_TABS
;
3552 // added to avoid warnings
3555 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3559 BOOL bUpdate
= TRUE
;
3560 if ( GetMergeState() == SC_CTMS_OTHER
&&
3561 p
->GetActionNumber() <= GetLastMerge() )
3562 { // Delete in mergendem Dokument, Action im zu mergenden
3563 if ( p
->IsInsertType() )
3565 // Bei Insert Referenzen nur anpassen, wenn das Delete
3566 // das Insert nicht schneidet.
3567 if ( !aDelRange
.Intersects( p
->GetBigRange() ) )
3568 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3571 else if ( p
->GetType() == SC_CAT_CONTENT
&&
3572 p
->IsDeletedInDelType( eInsType
) )
3573 { // Content in Insert-Undo-"Delete"
3574 // Nicht anpassen, wenn dieses Delete in dem
3575 // Insert-"Delete" sein wuerde (ist nur verschoben).
3576 if ( aDelRange
.In( p
->GetBigRange().aStart
) )
3580 const ScChangeActionLinkEntry
* pLink
= p
->GetDeletedIn();
3581 while ( pLink
&& bUpdate
)
3583 const ScChangeAction
* pDel
= pLink
->GetAction();
3584 if ( pDel
&& pDel
->GetType() == eInsType
&&
3585 pDel
->GetBigRange().In( aDelRange
) )
3587 pLink
= pLink
->GetNext();
3594 if ( aDelRange
.In( p
->GetBigRange() ) )
3596 // Innerhalb eines gerade geloeschten Bereiches nicht
3597 // anpassen, stattdessen dem Bereich zuordnen.
3598 // Mehrfache geloeschte Bereiche "stapeln".
3599 // Kreuzende Deletes setzen mehrfach geloescht.
3600 if ( !p
->IsDeletedInDelType( eActType
) )
3602 p
->SetDeletedIn( pActDel
);
3603 // GeneratedDelContent in zu loeschende Liste aufnehmen
3604 if ( bGeneratedDelContents
)
3605 pActDel
->AddContent( (ScChangeActionContent
*) p
);
3611 // Eingefuegte Bereiche abschneiden, wenn Start/End im
3612 // Delete liegt, aber das Insert nicht komplett innerhalb
3613 // des Delete liegt bzw. das Delete nicht komplett im
3614 // Insert. Das Delete merkt sich, welchem Insert es was
3615 // abgeschnitten hat, es kann auch nur ein einziges Insert
3616 // sein (weil Delete einspaltig/einzeilig ist).
3617 // Abgeschnittene Moves kann es viele geben.
3618 //! Ein Delete ist immer einspaltig/einzeilig, deswegen 1
3619 //! ohne die Ueberlappung auszurechnen.
3620 switch ( p
->GetType() )
3622 case SC_CAT_INSERT_COLS
:
3623 if ( eActType
== SC_CAT_DELETE_COLS
)
3625 if ( aDelRange
.In( p
->GetBigRange().aStart
) )
3627 pActDel
->SetCutOffInsert(
3628 (ScChangeActionIns
*) p
, 1 );
3629 p
->GetBigRange().aStart
.IncCol( 1 );
3631 else if ( aDelRange
.In( p
->GetBigRange().aEnd
) )
3633 pActDel
->SetCutOffInsert(
3634 (ScChangeActionIns
*) p
, -1 );
3635 p
->GetBigRange().aEnd
.IncCol( -1 );
3639 case SC_CAT_INSERT_ROWS
:
3640 if ( eActType
== SC_CAT_DELETE_ROWS
)
3642 if ( aDelRange
.In( p
->GetBigRange().aStart
) )
3644 pActDel
->SetCutOffInsert(
3645 (ScChangeActionIns
*) p
, 1 );
3646 p
->GetBigRange().aStart
.IncRow( 1 );
3648 else if ( aDelRange
.In( p
->GetBigRange().aEnd
) )
3650 pActDel
->SetCutOffInsert(
3651 (ScChangeActionIns
*) p
, -1 );
3652 p
->GetBigRange().aEnd
.IncRow( -1 );
3656 case SC_CAT_INSERT_TABS
:
3657 if ( eActType
== SC_CAT_DELETE_TABS
)
3659 if ( aDelRange
.In( p
->GetBigRange().aStart
) )
3661 pActDel
->SetCutOffInsert(
3662 (ScChangeActionIns
*) p
, 1 );
3663 p
->GetBigRange().aStart
.IncTab( 1 );
3665 else if ( aDelRange
.In( p
->GetBigRange().aEnd
) )
3667 pActDel
->SetCutOffInsert(
3668 (ScChangeActionIns
*) p
, -1 );
3669 p
->GetBigRange().aEnd
.IncTab( -1 );
3675 ScChangeActionMove
* pMove
= (ScChangeActionMove
*) p
;
3678 if ( aDelRange
.In( pMove
->GetBigRange().aStart
) )
3680 else if ( aDelRange
.In( pMove
->GetBigRange().aEnd
) )
3682 if ( aDelRange
.In( pMove
->GetFromRange().aStart
) )
3684 else if ( aDelRange
.In( pMove
->GetFromRange().aEnd
) )
3690 case SC_CAT_DELETE_COLS
:
3692 pMove
->GetFromRange().aStart
.IncCol( nFrom
);
3694 pMove
->GetFromRange().aEnd
.IncCol( nFrom
);
3696 case SC_CAT_DELETE_ROWS
:
3698 pMove
->GetFromRange().aStart
.IncRow( nFrom
);
3700 pMove
->GetFromRange().aEnd
.IncRow( nFrom
);
3702 case SC_CAT_DELETE_TABS
:
3704 pMove
->GetFromRange().aStart
.IncTab( nFrom
);
3706 pMove
->GetFromRange().aEnd
.IncTab( nFrom
);
3710 // added to avoid warnings
3718 case SC_CAT_DELETE_COLS
:
3720 pMove
->GetBigRange().aStart
.IncCol( nTo
);
3722 pMove
->GetBigRange().aEnd
.IncCol( nTo
);
3724 case SC_CAT_DELETE_ROWS
:
3726 pMove
->GetBigRange().aStart
.IncRow( nTo
);
3728 pMove
->GetBigRange().aEnd
.IncRow( nTo
);
3730 case SC_CAT_DELETE_TABS
:
3732 pMove
->GetBigRange().aStart
.IncTab( nTo
);
3734 pMove
->GetBigRange().aEnd
.IncTab( nTo
);
3738 // added to avoid warnings
3744 ScChangeActionDelMoveEntry
* pLink
=
3745 pActDel
->AddCutOffMove( pMove
, nFrom
, nTo
);
3746 pMove
->AddLink( pActDel
, pLink
);
3752 // added to avoid warnings
3758 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3759 if ( p
->GetType() == eActType
&& !p
->IsRejected() &&
3760 !pActDel
->IsDeletedIn() &&
3761 p
->GetBigRange().In( aDelRange
) )
3762 pActDel
->SetDeletedIn( p
); // "druntergerutscht"
3768 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3772 BOOL bUpdate
= TRUE
;
3773 if ( aDelRange
.In( p
->GetBigRange() ) )
3775 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3776 if ( GetMergeState() == SC_CTMS_UNDO
&& !p
->IsDeletedIn( pAct
) && pAct
->IsDeleteType() &&
3777 ( p
->GetType() == SC_CAT_CONTENT
||
3778 p
->GetType() == SC_CAT_DELETE_ROWS
|| p
->GetType() == SC_CAT_DELETE_COLS
||
3779 p
->GetType() == SC_CAT_INSERT_ROWS
|| p
->GetType() == SC_CAT_INSERT_COLS
) )
3781 p
->SetDeletedIn( pAct
);
3784 if ( p
->IsDeletedInDelType( eActType
) )
3786 if ( p
->IsDeletedIn( pActDel
) )
3788 if ( p
->GetType() != SC_CAT_CONTENT
||
3789 ((ScChangeActionContent
*)p
)->IsTopContent() )
3790 { // erst der TopContent wird wirklich entfernt
3791 p
->RemoveDeletedIn( pActDel
);
3792 // GeneratedDelContent _nicht_ aus Liste loeschen,
3793 // wir brauchen ihn evtl. noch fuer Reject,
3794 // geloescht wird in DeleteCellEntries
3799 else if ( eActType
!= SC_CAT_DELETE_TABS
&&
3800 p
->IsDeletedInDelType( SC_CAT_DELETE_TABS
) )
3801 { // in geloeschten Tabellen nicht updaten,
3802 // ausser wenn Tabelle verschoben wird
3805 if ( p
->GetType() == eActType
&& pActDel
->IsDeletedIn( p
) )
3807 pActDel
->RemoveDeletedIn( p
); // "druntergerutscht"
3812 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3814 if ( !bGeneratedDelContents
)
3815 { // die werden sonst noch fuer das echte Undo gebraucht
3816 pActDel
->UndoCutOffInsert();
3817 pActDel
->UndoCutOffMoves();
3821 else if ( eActType
== SC_CAT_MOVE
)
3823 ScChangeActionMove
* pActMove
= (ScChangeActionMove
*) pAct
;
3824 BOOL bLastCutMove
= ( pActMove
== pLastCutMove
);
3825 const ScBigRange
& rTo
= pActMove
->GetBigRange();
3826 const ScBigRange
& rFrom
= pActMove
->GetFromRange();
3829 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3833 if ( p
->GetType() == SC_CAT_CONTENT
)
3835 // Inhalt in Ziel deleten (Inhalt in Quelle moven)
3836 if ( rTo
.In( p
->GetBigRange() ) )
3838 if ( !p
->IsDeletedIn( pActMove
) )
3840 p
->SetDeletedIn( pActMove
);
3841 // GeneratedDelContent in zu loeschende Liste aufnehmen
3842 if ( bGeneratedDelContents
)
3843 pActMove
->AddContent( (ScChangeActionContent
*) p
);
3846 else if ( bLastCutMove
&&
3847 p
->GetActionNumber() > nEndLastCut
&&
3848 rFrom
.In( p
->GetBigRange() ) )
3849 { // Paste Cut: neuer Content nach Cut eingefuegt, bleibt.
3850 // Aufsplitten der ContentChain
3851 ScChangeActionContent
*pHere
, *pTmp
;
3852 pHere
= (ScChangeActionContent
*) p
;
3853 while ( (pTmp
= pHere
->GetPrevContent()) != NULL
&&
3854 pTmp
->GetActionNumber() > nEndLastCut
)
3857 { // wird TopContent des Move
3858 pTmp
->SetNextContent( NULL
);
3859 pHere
->SetPrevContent( NULL
);
3862 { // Abhaengigkeit vom FromRange herstellen
3863 AddDependentWithNotify( pActMove
, pHere
);
3864 } while ( ( pHere
= pHere
->GetNextContent() ) != NULL
);
3866 // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
3867 else if ( ( GetMergeState() != SC_CTMS_PREPARE
&& GetMergeState() != SC_CTMS_OWN
) || p
->GetActionNumber() <= pAct
->GetActionNumber() )
3868 p
->UpdateReference( this, eMode
, rFrom
, nDx
, nDy
, nDz
);
3874 BOOL bActRejected
= pActMove
->IsRejected();
3875 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3879 if ( p
->GetType() == SC_CAT_CONTENT
)
3881 // Inhalt in Ziel moven, wenn nicht deleted, sonst undelete
3882 if ( p
->IsDeletedIn( pActMove
) )
3884 if ( ((ScChangeActionContent
*)p
)->IsTopContent() )
3885 { // erst der TopContent wird wirklich entfernt
3886 p
->RemoveDeletedIn( pActMove
);
3887 // GeneratedDelContent _nicht_ aus Liste loeschen,
3888 // wir brauchen ihn evtl. noch fuer Reject,
3889 // geloescht wird in DeleteCellEntries
3892 // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly
3893 else if ( ( GetMergeState() != SC_CTMS_PREPARE
&& GetMergeState() != SC_CTMS_OWN
) || p
->GetActionNumber() <= pAct
->GetActionNumber() )
3894 p
->UpdateReference( this, eMode
, rTo
, nDx
, nDy
, nDz
);
3895 if ( bActRejected
&&
3896 ((ScChangeActionContent
*)p
)->IsTopContent() &&
3897 rFrom
.In( p
->GetBigRange() ) )
3898 { // Abhaengigkeit herstellen, um Content zu schreiben
3899 ScChangeActionLinkEntry
* pLink
=
3900 pActMove
->AddDependent( p
);
3901 p
->AddLink( pActMove
, pLink
);
3908 { // Insert / Undo Insert
3909 switch ( GetMergeState() )
3912 case SC_CTMS_OTHER
:
3914 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3918 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3922 case SC_CTMS_PREPARE
:
3924 // in Insert-Undo "Deleten"
3925 const ScChangeActionLinkEntry
* pLink
= pAct
->GetFirstDependentEntry();
3928 ScChangeAction
* p
= (ScChangeAction
*) pLink
->GetAction();
3930 p
->SetDeletedIn( pAct
);
3931 pLink
= pLink
->GetNext();
3934 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
3935 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3937 if ( !p
->IsDeletedIn( pAct
) && pAct
->IsInsertType() &&
3938 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3939 ( p
->GetType() == SC_CAT_CONTENT
||
3940 p
->GetType() == SC_CAT_DELETE_ROWS
|| p
->GetType() == SC_CAT_DELETE_COLS
||
3941 p
->GetType() == SC_CAT_INSERT_ROWS
|| p
->GetType() == SC_CAT_INSERT_COLS
) &&
3942 pAct
->GetBigRange().Intersects( p
->GetBigRange() ) )
3944 p
->SetDeletedIn( pAct
);
3948 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3952 if ( !p
->IsDeletedIn( pAct
)
3953 // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
3954 && p
->GetActionNumber() <= pAct
->GetActionNumber() )
3956 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3963 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3967 if ( !p
->IsDeletedIn( pAct
)
3968 // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet
3969 && p
->GetActionNumber() <= pAct
->GetActionNumber() )
3971 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
3974 // in Insert-Undo "Delete" rueckgaengig
3975 const ScChangeActionLinkEntry
* pLink
= pAct
->GetFirstDependentEntry();
3978 ScChangeAction
* p
= (ScChangeAction
*) pLink
->GetAction();
3980 p
->RemoveDeletedIn( pAct
);
3981 pLink
= pLink
->GetNext();
3984 // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
3985 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
3987 if ( p
->IsDeletedIn( pAct
) && pAct
->IsInsertType() &&
3988 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
3989 ( p
->GetType() == SC_CAT_CONTENT
||
3990 p
->GetType() == SC_CAT_DELETE_ROWS
|| p
->GetType() == SC_CAT_DELETE_COLS
||
3991 p
->GetType() == SC_CAT_INSERT_ROWS
|| p
->GetType() == SC_CAT_INSERT_COLS
) &&
3992 pAct
->GetBigRange().Intersects( p
->GetBigRange() ) )
3994 p
->RemoveDeletedIn( pAct
);
3999 // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
4002 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
4004 if ( !p
->IsDeletedIn( pAct
) && pAct
->IsInsertType() &&
4005 ( p
->GetType() == SC_CAT_CONTENT
||
4006 p
->GetType() == SC_CAT_DELETE_ROWS
|| p
->GetType() == SC_CAT_DELETE_COLS
||
4007 p
->GetType() == SC_CAT_INSERT_ROWS
|| p
->GetType() == SC_CAT_INSERT_COLS
) &&
4008 pAct
->GetBigRange().Intersects( p
->GetBigRange() ) )
4010 p
->SetDeletedIn( pAct
);
4014 for ( ScChangeAction
* p
= *ppFirstAction
; p
; p
= p
->GetNext() )
4020 if ( !p
->IsDeletedIn( pAct
) && p
->GetActionNumber() <= pAct
->GetActionNumber() )
4022 p
->UpdateReference( this, eMode
, aRange
, nDx
, nDy
, nDz
);
4032 void ScChangeTrack::GetDependents( ScChangeAction
* pAct
,
4033 ScChangeActionTable
& rTable
, BOOL bListMasterDelete
, BOOL bAllFlat
) const
4035 //! bAllFlat==TRUE: intern aus Accept oder Reject gerufen,
4036 //! => Generated werden nicht aufgenommen
4038 BOOL bIsDelete
= pAct
->IsDeleteType();
4039 BOOL bIsMasterDelete
= ( bListMasterDelete
&& pAct
->IsMasterDelete() );
4041 const ScChangeAction
* pCur
= pAct
;
4042 ScChangeActionStack
* pStack
= new ScChangeActionStack
;
4045 if ( pCur
->IsInsertType() )
4047 const ScChangeActionLinkEntry
* pL
= pCur
->GetFirstDependentEntry();
4050 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
4055 ULONG n
= p
->GetActionNumber();
4056 if ( !IsGenerated( n
) && rTable
.Insert( n
, p
) )
4057 if ( p
->HasDependent() )
4062 if ( p
->GetType() == SC_CAT_CONTENT
)
4064 if ( ((ScChangeActionContent
*)p
)->IsTopContent() )
4065 rTable
.Insert( p
->GetActionNumber(), p
);
4068 rTable
.Insert( p
->GetActionNumber(), p
);
4074 else if ( pCur
->IsDeleteType() )
4077 { // Inhalte geloeschter Bereiche interessieren nur bei Delete
4078 ScChangeActionDel
* pDel
= (ScChangeActionDel
*) pCur
;
4079 if ( !bAllFlat
&& bIsMasterDelete
&& pCur
== pAct
)
4081 // zu diesem Delete gehoerende Deletes in gleiche Ebene,
4082 // wenn dieses Delete das momentan oberste einer Reihe ist,
4083 ScChangeActionType eType
= pDel
->GetType();
4084 ScChangeAction
* p
= pDel
;
4085 while ( (p
= p
->GetPrev()) != NULL
&& p
->GetType() == eType
&&
4086 !((ScChangeActionDel
*)p
)->IsTopDelete() )
4087 rTable
.Insert( p
->GetActionNumber(), p
);
4088 // dieses Delete auch in Table!
4089 rTable
.Insert( pAct
->GetActionNumber(), pAct
);
4093 const ScChangeActionLinkEntry
* pL
= pCur
->GetFirstDeletedEntry();
4096 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
4101 // nur ein TopContent einer Kette ist in LinkDeleted
4102 ULONG n
= p
->GetActionNumber();
4103 if ( !IsGenerated( n
) && rTable
.Insert( n
, p
) )
4104 if ( p
->HasDeleted() ||
4105 p
->GetType() == SC_CAT_CONTENT
)
4110 if ( p
->IsDeleteType() )
4111 { // weiteres TopDelete in gleiche Ebene,
4112 // es ist nicht rejectable
4113 if ( ((ScChangeActionDel
*)p
)->IsTopDelete() )
4114 rTable
.Insert( p
->GetActionNumber(), p
);
4117 rTable
.Insert( p
->GetActionNumber(), p
);
4125 else if ( pCur
->GetType() == SC_CAT_MOVE
)
4127 // geloeschte Contents im ToRange
4128 const ScChangeActionLinkEntry
* pL
= pCur
->GetFirstDeletedEntry();
4131 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
4132 if ( p
!= pAct
&& rTable
.Insert( p
->GetActionNumber(), p
) )
4134 // nur ein TopContent einer Kette ist in LinkDeleted
4135 if ( bAllFlat
&& (p
->HasDeleted() ||
4136 p
->GetType() == SC_CAT_CONTENT
) )
4141 // neue Contents im FromRange oder neuer FromRange im ToRange
4142 // oder Inserts/Deletes in FromRange/ToRange
4143 pL
= pCur
->GetFirstDependentEntry();
4146 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
4151 ULONG n
= p
->GetActionNumber();
4152 if ( !IsGenerated( n
) && rTable
.Insert( n
, p
) )
4153 if ( p
->HasDependent() || p
->HasDeleted() )
4158 if ( p
->GetType() == SC_CAT_CONTENT
)
4160 if ( ((ScChangeActionContent
*)p
)->IsTopContent() )
4161 rTable
.Insert( p
->GetActionNumber(), p
);
4164 rTable
.Insert( p
->GetActionNumber(), p
);
4170 else if ( pCur
->GetType() == SC_CAT_CONTENT
)
4171 { // alle Aenderungen an gleicher Position
4172 ScChangeActionContent
* pContent
= (ScChangeActionContent
*) pCur
;
4174 while ( ( pContent
= pContent
->GetPrevContent() ) != NULL
)
4176 if ( !pContent
->IsRejected() )
4177 rTable
.Insert( pContent
->GetActionNumber(), pContent
);
4179 pContent
= (ScChangeActionContent
*) pCur
;
4180 // alle nachfolgenden
4181 while ( ( pContent
= pContent
->GetNextContent() ) != NULL
)
4183 if ( !pContent
->IsRejected() )
4184 rTable
.Insert( pContent
->GetActionNumber(), pContent
);
4186 // all MatrixReferences of a MatrixOrigin
4187 const ScChangeActionLinkEntry
* pL
= pCur
->GetFirstDependentEntry();
4190 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
4195 ULONG n
= p
->GetActionNumber();
4196 if ( !IsGenerated( n
) && rTable
.Insert( n
, p
) )
4197 if ( p
->HasDependent() )
4201 rTable
.Insert( p
->GetActionNumber(), p
);
4206 else if ( pCur
->GetType() == SC_CAT_REJECT
)
4210 ScChangeAction
* p
= GetAction(
4211 ((ScChangeActionReject
*)pCur
)->GetRejectAction() );
4212 if ( p
!= pAct
&& !rTable
.Get( p
->GetActionNumber() ) )
4216 } while ( ( pCur
= pStack
->Pop() ) != NULL
);
4221 BOOL
ScChangeTrack::SelectContent( ScChangeAction
* pAct
, BOOL bOldest
)
4223 if ( pAct
->GetType() != SC_CAT_CONTENT
)
4226 ScChangeActionContent
* pContent
= (ScChangeActionContent
*) pAct
;
4229 pContent
= pContent
->GetTopContent();
4230 ScChangeActionContent
* pPrevContent
;
4231 while ( (pPrevContent
= pContent
->GetPrevContent()) != NULL
&&
4232 pPrevContent
->IsVirgin() )
4233 pContent
= pPrevContent
;
4236 if ( !pContent
->IsClickable() )
4239 ScBigRange
aBigRange( pContent
->GetBigRange() );
4240 const ScBaseCell
* pCell
= (bOldest
? pContent
->GetOldCell() :
4241 pContent
->GetNewCell());
4242 if ( ScChangeActionContent::GetContentCellType( pCell
) == SC_CACCT_MATORG
)
4246 ((const ScFormulaCell
*)pCell
)->GetMatColsRows( nC
, nR
);
4247 aBigRange
.aEnd
.IncCol( nC
-1 );
4248 aBigRange
.aEnd
.IncRow( nR
-1 );
4251 if ( !aBigRange
.IsValid( pDoc
) )
4254 ScRange
aRange( aBigRange
.MakeRange() );
4255 if ( !pDoc
->IsBlockEditable( aRange
.aStart
.Tab(), aRange
.aStart
.Col(),
4256 aRange
.aStart
.Row(), aRange
.aEnd
.Col(), aRange
.aEnd
.Row() ) )
4259 if ( pContent
->HasDependent() )
4262 Stack aRejectActions
;
4263 const ScChangeActionLinkEntry
* pL
= pContent
->GetFirstDependentEntry();
4266 ScChangeAction
* p
= (ScChangeAction
*) pL
->GetAction();
4267 if ( p
!= pContent
)
4269 if ( p
->GetType() == SC_CAT_CONTENT
)
4271 // we don't need no recursion here, do we?
4272 bOk
&= ((ScChangeActionContent
*)p
)->Select( pDoc
, this,
4273 bOldest
, &aRejectActions
);
4277 DBG_ERRORFILE( "ScChangeTrack::SelectContent: content dependent no content" );
4283 bOk
&= pContent
->Select( pDoc
, this, bOldest
, NULL
);
4284 // now the matrix is inserted and new content values are ready
4286 ScChangeActionContent
* pNew
;
4287 while ( ( pNew
= (ScChangeActionContent
*) aRejectActions
.Pop() ) != NULL
)
4289 ScAddress
aPos( pNew
->GetBigRange().aStart
.MakeAddress() );
4290 pNew
->SetNewValue( pDoc
->GetCell( aPos
), pDoc
);
4296 return pContent
->Select( pDoc
, this, bOldest
, NULL
);
4300 void ScChangeTrack::AcceptAll()
4302 for ( ScChangeAction
* p
= GetFirst(); p
; p
= p
->GetNext() )
4309 BOOL
ScChangeTrack::Accept( ScChangeAction
* pAct
)
4311 if ( !pAct
->IsClickable() )
4314 if ( pAct
->IsDeleteType() || pAct
->GetType() == SC_CAT_CONTENT
)
4316 ScChangeActionTable aActionTable
;
4317 GetDependents( pAct
, aActionTable
, FALSE
, TRUE
);
4318 for ( ScChangeAction
* p
= aActionTable
.First(); p
; p
= aActionTable
.Next() )
4328 BOOL
ScChangeTrack::RejectAll()
4331 for ( ScChangeAction
* p
= GetLast(); p
&& bOk
; p
= p
->GetPrev() )
4332 { //! rueckwaerts, weil abhaengige hinten und RejectActions angehaengt
4333 if ( p
->IsInternalRejectable() )
4340 BOOL
ScChangeTrack::Reject( ScChangeAction
* pAct
, bool bShared
)
4342 // #i100895# When collaboration changes are reversed, it must be possible
4343 // to reject a deleted row above another deleted row.
4344 if ( bShared
&& pAct
->IsDeletedIn() )
4345 pAct
->RemoveAllDeletedIn();
4347 if ( !pAct
->IsRejectable() )
4350 ScChangeActionTable
* pTable
= NULL
;
4351 if ( pAct
->HasDependent() )
4353 pTable
= new ScChangeActionTable
;
4354 GetDependents( pAct
, *pTable
, FALSE
, TRUE
);
4356 BOOL bRejected
= Reject( pAct
, pTable
, FALSE
);
4363 BOOL
ScChangeTrack::Reject( ScChangeAction
* pAct
, ScChangeActionTable
* pTable
,
4366 if ( !pAct
->IsInternalRejectable() )
4370 BOOL bRejected
= FALSE
;
4371 if ( pAct
->IsInsertType() )
4373 if ( pAct
->HasDependent() && !bRecursion
)
4375 DBG_ASSERT( pTable
, "ScChangeTrack::Reject: Insert ohne Table" );
4376 for ( ScChangeAction
* p
= pTable
->Last(); p
&& bOk
; p
= pTable
->Prev() )
4378 // keine Contents restoren, die eh geloescht werden wuerden
4379 if ( p
->GetType() == SC_CAT_CONTENT
)
4381 else if ( p
->IsDeleteType() )
4382 p
->Accept(); // geloeschtes ins Nirvana
4384 bOk
= Reject( p
, NULL
, TRUE
); //! rekursiv
4387 if ( bOk
&& (bRejected
= pAct
->Reject( pDoc
)) != FALSE
)
4389 // pRefDoc NULL := geloeschte Zellen nicht speichern
4390 AppendDeleteRange( pAct
->GetBigRange().MakeRange(), NULL
, (short) 0,
4391 pAct
->GetActionNumber() );
4394 else if ( pAct
->IsDeleteType() )
4396 DBG_ASSERT( !pTable
, "ScChangeTrack::Reject: Delete mit Table" );
4397 ScBigRange aDelRange
;
4398 ULONG nRejectAction
= pAct
->GetActionNumber();
4399 BOOL bTabDel
, bTabDelOk
;
4400 if ( pAct
->GetType() == SC_CAT_DELETE_TABS
)
4403 aDelRange
= pAct
->GetBigRange();
4404 bOk
= bTabDelOk
= pAct
->Reject( pDoc
);
4407 pAct
= pAct
->GetPrev();
4408 bOk
= ( pAct
&& pAct
->GetType() == SC_CAT_DELETE_COLS
);
4412 bTabDel
= bTabDelOk
= FALSE
;
4413 ScChangeActionDel
* pDel
= (ScChangeActionDel
*) pAct
;
4416 aDelRange
= pDel
->GetOverAllRange();
4417 bOk
= aDelRange
.IsValid( pDoc
);
4419 BOOL bOneOk
= FALSE
;
4422 ScChangeActionType eActType
= pAct
->GetType();
4425 case SC_CAT_DELETE_COLS
:
4426 aDelRange
.aStart
.SetCol( aDelRange
.aEnd
.Col() );
4428 case SC_CAT_DELETE_ROWS
:
4429 aDelRange
.aStart
.SetRow( aDelRange
.aEnd
.Row() );
4431 case SC_CAT_DELETE_TABS
:
4432 aDelRange
.aStart
.SetTab( aDelRange
.aEnd
.Tab() );
4436 // added to avoid warnings
4439 ScChangeAction
* p
= pAct
;
4443 pDel
= (ScChangeActionDel
*) p
;
4444 bOk
= pDel
->Reject( pDoc
);
4449 switch ( pDel
->GetType() )
4451 case SC_CAT_DELETE_COLS
:
4452 aDelRange
.aStart
.IncCol( -1 );
4454 case SC_CAT_DELETE_ROWS
:
4455 aDelRange
.aStart
.IncRow( -1 );
4457 case SC_CAT_DELETE_TABS
:
4458 aDelRange
.aStart
.IncTab( -1 );
4462 // added to avoid warnings
4469 if ( pDel
->IsBaseDelete() )
4473 } while ( bOk
&& bLoop
&& p
&& p
->GetType() == eActType
&&
4474 !((ScChangeActionDel
*)p
)->IsTopDelete() );
4477 if ( bOneOk
|| (bTabDel
&& bTabDelOk
) )
4479 // Delete-Reject machte UpdateReference Undo
4480 ScChangeActionIns
* pReject
= new ScChangeActionIns(
4481 aDelRange
.MakeRange() );
4482 pReject
->SetRejectAction( nRejectAction
);
4483 pReject
->SetState( SC_CAS_ACCEPTED
);
4487 else if ( pAct
->GetType() == SC_CAT_MOVE
)
4489 if ( pAct
->HasDependent() && !bRecursion
)
4491 DBG_ASSERT( pTable
, "ScChangeTrack::Reject: Move ohne Table" );
4492 for ( ScChangeAction
* p
= pTable
->Last(); p
&& bOk
; p
= pTable
->Prev() )
4494 bOk
= Reject( p
, NULL
, TRUE
); //! rekursiv
4497 if ( bOk
&& (bRejected
= pAct
->Reject( pDoc
)) != FALSE
)
4499 ScChangeActionMove
* pReject
= new ScChangeActionMove(
4500 pAct
->GetBigRange().MakeRange(),
4501 ((ScChangeActionMove
*)pAct
)->GetFromRange().MakeRange(), this );
4502 pReject
->SetRejectAction( pAct
->GetActionNumber() );
4503 pReject
->SetState( SC_CAS_ACCEPTED
);
4507 else if ( pAct
->GetType() == SC_CAT_CONTENT
)
4510 ScChangeActionContent
* pReject
;
4515 aRange
= pAct
->GetBigRange().aStart
.MakeAddress();
4516 pReject
= new ScChangeActionContent( aRange
);
4517 pReject
->SetOldValue( pDoc
->GetCell( aRange
.aStart
), pDoc
, pDoc
);
4519 if ( (bRejected
= pAct
->Reject( pDoc
)) != FALSE
&& !bRecursion
)
4521 pReject
->SetNewValue( pDoc
->GetCell( aRange
.aStart
), pDoc
);
4522 pReject
->SetRejectAction( pAct
->GetActionNumber() );
4523 pReject
->SetState( SC_CAS_ACCEPTED
);
4531 DBG_ERROR( "ScChangeTrack::Reject: say what?" );
4538 ULONG
ScChangeTrack::AddLoadedGenerated(ScBaseCell
* pNewCell
, const ScBigRange
& aBigRange
, const String
& sNewValue
)
4540 ScChangeActionContent
* pAct
= new ScChangeActionContent( --nGeneratedMin
, pNewCell
, aBigRange
, pDoc
, sNewValue
);
4543 if ( pFirstGeneratedDelContent
)
4544 pFirstGeneratedDelContent
->pPrev
= pAct
;
4545 pAct
->pNext
= pFirstGeneratedDelContent
;
4546 pFirstGeneratedDelContent
= pAct
;
4547 aGeneratedTable
.Insert( pAct
->GetActionNumber(), pAct
);
4548 return pAct
->GetActionNumber();
4553 void ScChangeTrack::AppendCloned( ScChangeAction
* pAppend
)
4555 aTable
.Insert( pAppend
->GetActionNumber(), pAppend
);
4557 pFirst
= pLast
= pAppend
;
4560 pLast
->pNext
= pAppend
;
4561 pAppend
->pPrev
= pLast
;
4566 ScChangeTrack
* ScChangeTrack::Clone( ScDocument
* pDocument
) const
4573 ScChangeTrack
* pClonedTrack
= new ScChangeTrack( pDocument
);
4574 pClonedTrack
->SetTime100thSeconds( IsTime100thSeconds() );
4576 // clone generated actions
4577 ::std::stack
< const ScChangeAction
* > aGeneratedStack
;
4578 const ScChangeAction
* pGenerated
= GetFirstGenerated();
4579 while ( pGenerated
)
4581 aGeneratedStack
.push( pGenerated
);
4582 pGenerated
= pGenerated
->GetNext();
4584 while ( !aGeneratedStack
.empty() )
4586 pGenerated
= aGeneratedStack
.top();
4587 aGeneratedStack
.pop();
4588 const ScChangeActionContent
* pContent
= dynamic_cast< const ScChangeActionContent
* >( pGenerated
);
4589 DBG_ASSERT( pContent
, "ScChangeTrack::Clone: pContent is null!" );
4590 const ScBaseCell
* pNewCell
= pContent
->GetNewCell();
4593 ScBaseCell
* pClonedNewCell
= pNewCell
->CloneWithoutNote( *pDocument
);
4595 pContent
->GetNewString( aNewValue
);
4596 pClonedTrack
->nGeneratedMin
= pGenerated
->GetActionNumber() + 1;
4597 pClonedTrack
->AddLoadedGenerated( pClonedNewCell
, pGenerated
->GetBigRange(), aNewValue
);
4602 const ScChangeAction
* pAction
= GetFirst();
4605 ScChangeAction
* pClonedAction
= NULL
;
4607 switch ( pAction
->GetType() )
4609 case SC_CAT_INSERT_COLS
:
4610 case SC_CAT_INSERT_ROWS
:
4611 case SC_CAT_INSERT_TABS
:
4613 pClonedAction
= new ScChangeActionIns(
4614 pAction
->GetActionNumber(),
4615 pAction
->GetState(),
4616 pAction
->GetRejectAction(),
4617 pAction
->GetBigRange(),
4619 pAction
->GetDateTimeUTC(),
4620 pAction
->GetComment(),
4621 pAction
->GetType() );
4624 case SC_CAT_DELETE_COLS
:
4625 case SC_CAT_DELETE_ROWS
:
4626 case SC_CAT_DELETE_TABS
:
4628 const ScChangeActionDel
* pDelete
= dynamic_cast< const ScChangeActionDel
* >( pAction
);
4629 DBG_ASSERT( pDelete
, "ScChangeTrack::Clone: pDelete is null!" );
4632 ScChangeActionType eType
= pAction
->GetType();
4633 if ( eType
== SC_CAT_DELETE_COLS
)
4635 nD
= static_cast< SCsCOLROW
>( pDelete
->GetDx() );
4637 else if ( eType
== SC_CAT_DELETE_ROWS
)
4639 nD
= static_cast< SCsCOLROW
>( pDelete
->GetDy() );
4642 pClonedAction
= new ScChangeActionDel(
4643 pAction
->GetActionNumber(),
4644 pAction
->GetState(),
4645 pAction
->GetRejectAction(),
4646 pAction
->GetBigRange(),
4648 pAction
->GetDateTimeUTC(),
4649 pAction
->GetComment(),
4657 const ScChangeActionMove
* pMove
= dynamic_cast< const ScChangeActionMove
* >( pAction
);
4658 DBG_ASSERT( pMove
, "ScChangeTrack::Clone: pMove is null!" );
4660 pClonedAction
= new ScChangeActionMove(
4661 pAction
->GetActionNumber(),
4662 pAction
->GetState(),
4663 pAction
->GetRejectAction(),
4664 pAction
->GetBigRange(),
4666 pAction
->GetDateTimeUTC(),
4667 pAction
->GetComment(),
4668 pMove
->GetFromRange(),
4672 case SC_CAT_CONTENT
:
4674 const ScChangeActionContent
* pContent
= dynamic_cast< const ScChangeActionContent
* >( pAction
);
4675 DBG_ASSERT( pContent
, "ScChangeTrack::Clone: pContent is null!" );
4676 const ScBaseCell
* pOldCell
= pContent
->GetOldCell();
4677 ScBaseCell
* pClonedOldCell
= pOldCell
? pOldCell
->CloneWithoutNote( *pDocument
) : 0;
4679 pContent
->GetOldString( aOldValue
);
4681 ScChangeActionContent
* pClonedContent
= new ScChangeActionContent(
4682 pAction
->GetActionNumber(),
4683 pAction
->GetState(),
4684 pAction
->GetRejectAction(),
4685 pAction
->GetBigRange(),
4687 pAction
->GetDateTimeUTC(),
4688 pAction
->GetComment(),
4693 const ScBaseCell
* pNewCell
= pContent
->GetNewCell();
4696 ScBaseCell
* pClonedNewCell
= pNewCell
->CloneWithoutNote( *pDocument
);
4697 pClonedContent
->SetNewValue( pClonedNewCell
, pDocument
);
4700 pClonedAction
= pClonedContent
;
4705 pClonedAction
= new ScChangeActionReject(
4706 pAction
->GetActionNumber(),
4707 pAction
->GetState(),
4708 pAction
->GetRejectAction(),
4709 pAction
->GetBigRange(),
4711 pAction
->GetDateTimeUTC(),
4712 pAction
->GetComment() );
4721 if ( pClonedAction
)
4723 pClonedTrack
->AppendCloned( pClonedAction
);
4726 pAction
= pAction
->GetNext();
4729 if ( pClonedTrack
->GetLast() )
4731 pClonedTrack
->SetActionMax( pClonedTrack
->GetLast()->GetActionNumber() );
4734 // set dependencies for Deleted/DeletedIn
4735 pAction
= GetFirst();
4738 if ( pAction
->HasDeleted() )
4740 ::std::stack
< ULONG
> aStack
;
4741 const ScChangeActionLinkEntry
* pL
= pAction
->GetFirstDeletedEntry();
4744 const ScChangeAction
* pDeleted
= pL
->GetAction();
4747 aStack
.push( pDeleted
->GetActionNumber() );
4751 ScChangeAction
* pClonedAction
= pClonedTrack
->GetAction( pAction
->GetActionNumber() );
4752 if ( pClonedAction
)
4754 while ( !aStack
.empty() )
4756 ScChangeAction
* pClonedDeleted
= pClonedTrack
->GetActionOrGenerated( aStack
.top() );
4758 if ( pClonedDeleted
)
4760 pClonedDeleted
->SetDeletedIn( pClonedAction
);
4765 pAction
= pAction
->GetNext();
4768 // set dependencies for Dependent/Any
4769 pAction
= GetLast();
4772 if ( pAction
->HasDependent() )
4774 ::std::stack
< ULONG
> aStack
;
4775 const ScChangeActionLinkEntry
* pL
= pAction
->GetFirstDependentEntry();
4778 const ScChangeAction
* pDependent
= pL
->GetAction();
4781 aStack
.push( pDependent
->GetActionNumber() );
4785 ScChangeAction
* pClonedAction
= pClonedTrack
->GetAction( pAction
->GetActionNumber() );
4786 if ( pClonedAction
)
4788 while ( !aStack
.empty() )
4790 ScChangeAction
* pClonedDependent
= pClonedTrack
->GetActionOrGenerated( aStack
.top() );
4792 if ( pClonedDependent
)
4794 ScChangeActionLinkEntry
* pLink
= pClonedAction
->AddDependent( pClonedDependent
);
4795 pClonedDependent
->AddLink( pClonedAction
, pLink
);
4800 pAction
= pAction
->GetPrev();
4804 ScChangeAction
* pClonedAction
= pClonedTrack
->GetFirst();
4805 while ( pClonedAction
)
4807 pClonedTrack
->MasterLinks( pClonedAction
);
4808 pClonedAction
= pClonedAction
->GetNext();
4811 if ( IsProtected() )
4813 pClonedTrack
->SetProtection( GetProtection() );
4816 if ( pClonedTrack
->GetLast() )
4818 pClonedTrack
->SetLastSavedActionNumber( pClonedTrack
->GetLast()->GetActionNumber() );
4821 pDocument
->SetChangeTrack( pClonedTrack
);
4823 return pClonedTrack
;
4826 void ScChangeTrack::MergeActionState( ScChangeAction
* pAct
, const ScChangeAction
* pOtherAct
)
4828 if ( pAct
->IsVirgin() )
4830 if ( pOtherAct
->IsAccepted() )
4833 if ( pOtherAct
->IsRejecting() )
4835 pAct
->SetRejectAction( pOtherAct
->GetRejectAction() );
4838 else if ( pOtherAct
->IsRejected() )
4840 pAct
->SetRejected();
4845 #if DEBUG_CHANGETRACK
4846 String
ScChangeTrack::ToString() const
4850 aReturn
+= String::CreateFromAscii( "============================================================\n" );
4852 const ScChangeAction
* pGenerated
= GetFirstGenerated();
4853 while ( pGenerated
)
4855 aReturn
+= pGenerated
->ToString( pDoc
);
4857 pGenerated
= pGenerated
->GetNext();
4860 aReturn
+= String::CreateFromAscii( "------------------------------------------------------------\n" );
4862 const ScChangeAction
* pAction
= GetFirst();
4865 aReturn
+= pAction
->ToString( pDoc
);
4867 pAction
= pAction
->GetNext();
4869 aReturn
+= String::CreateFromAscii( "============================================================\n" );
4873 #endif // DEBUG_CHANGETRACK