| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sc.hxx" |
| |
| |
| #include <tools/debug.hxx> |
| #include <tools/shl.hxx> // SHL_CALC |
| #include <tools/stack.hxx> |
| #include <tools/rtti.hxx> |
| #include <svl/zforlist.hxx> |
| #include <svl/itemset.hxx> |
| #include <svl/isethint.hxx> |
| #include <svl/itempool.hxx> |
| #include <sfx2/app.hxx> |
| #include <unotools/useroptions.hxx> |
| #include <sfx2/sfxsids.hrc> |
| |
| #include "cell.hxx" |
| #include "document.hxx" |
| #include "dociter.hxx" |
| #include "global.hxx" |
| #include "rechead.hxx" |
| #include "scerrors.hxx" |
| #include "scmod.hxx" // SC_MOD |
| #include "inputopt.hxx" // GetExpandRefs |
| #include "patattr.hxx" |
| #include "hints.hxx" |
| |
| #include "globstr.hrc" |
| |
| #include <stack> |
| |
| #define SC_CHGTRACK_CXX |
| #include "chgtrack.hxx" |
| |
| DECLARE_STACK( ScChangeActionStack, ScChangeAction* ) |
| |
| const sal_uInt16 nMemPoolChangeActionCellListEntry = (0x2000 - 64) / sizeof(ScChangeActionCellListEntry); |
| IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionCellListEntry, nMemPoolChangeActionCellListEntry, nMemPoolChangeActionCellListEntry ) |
| |
| const sal_uInt16 nMemPoolChangeActionLinkEntry = (0x8000 - 64) / sizeof(ScChangeActionLinkEntry); |
| IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionLinkEntry, nMemPoolChangeActionLinkEntry, nMemPoolChangeActionLinkEntry ) |
| |
| // loaded MSB > eigenes => inkompatibel |
| #define SC_CHGTRACK_FILEFORMAT_FIRST 0x0001 |
| #define SC_CHGTRACK_FILEFORMAT 0x0001 |
| |
| // --- ScChangeActionLinkEntry --------------------------------------------- |
| |
| #if DEBUG_CHANGETRACK |
| String ScChangeActionLinkEntry::ToString() const |
| { |
| String aReturn; |
| if ( pAction ) |
| { |
| aReturn = String::CreateFromInt64( static_cast< sal_Int64 >( pAction->GetActionNumber() ) ); |
| } |
| else if ( pLink && pLink->pAction ) |
| { |
| aReturn = String::CreateFromAscii( "*" ); |
| aReturn += String::CreateFromInt64( static_cast< sal_Int64 >( pLink->pAction->GetActionNumber() ) ); |
| } |
| else |
| { |
| aReturn = String::CreateFromAscii( "-" ); |
| } |
| |
| return aReturn; |
| } |
| #endif // DEBUG_CHANGETRACK |
| |
| // --- ScChangeAction ------------------------------------------------------ |
| |
| ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScRange& rRange ) |
| : |
| aBigRange( rRange ), |
| pNext( NULL ), |
| pPrev( NULL ), |
| pLinkAny( NULL ), |
| pLinkDeletedIn( NULL ), |
| pLinkDeleted( NULL ), |
| pLinkDependent( NULL ), |
| nAction( 0 ), |
| nRejectAction( 0 ), |
| eType( eTypeP ), |
| eState( SC_CAS_VIRGIN ) |
| { |
| aDateTime.ConvertToUTC(); |
| } |
| |
| ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScBigRange& rRange, |
| const sal_uLong nTempAction, const sal_uLong nTempRejectAction, |
| const ScChangeActionState eTempState, const DateTime& aTempDateTime, |
| const String& aTempUser, const String& aTempComment) |
| : |
| aBigRange( rRange ), |
| aDateTime( aTempDateTime ), |
| aUser( aTempUser ), |
| aComment( aTempComment ), |
| pNext( NULL ), |
| pPrev( NULL ), |
| pLinkAny( NULL ), |
| pLinkDeletedIn( NULL ), |
| pLinkDeleted( NULL ), |
| pLinkDependent( NULL ), |
| nAction( nTempAction ), |
| nRejectAction( nTempRejectAction ), |
| eType( eTypeP ), |
| eState( eTempState ) |
| { |
| } |
| |
| ScChangeAction::ScChangeAction( ScChangeActionType eTypeP, const ScBigRange& rRange, |
| const sal_uLong nTempAction) |
| : |
| aBigRange( rRange ), |
| pNext( NULL ), |
| pPrev( NULL ), |
| pLinkAny( NULL ), |
| pLinkDeletedIn( NULL ), |
| pLinkDeleted( NULL ), |
| pLinkDependent( NULL ), |
| nAction( nTempAction ), |
| nRejectAction( 0 ), |
| eType( eTypeP ), |
| eState( SC_CAS_VIRGIN ) |
| { |
| aDateTime.ConvertToUTC(); |
| } |
| |
| |
| ScChangeAction::~ScChangeAction() |
| { |
| RemoveAllLinks(); |
| } |
| |
| |
| sal_Bool ScChangeAction::IsVisible() const |
| { |
| //! sequence order of execution is significant |
| if ( IsRejected() || GetType() == SC_CAT_DELETE_TABS || IsDeletedIn() ) |
| return sal_False; |
| if ( GetType() == SC_CAT_CONTENT ) |
| return ((ScChangeActionContent*)this)->IsTopContent(); |
| return sal_True; |
| } |
| |
| |
| sal_Bool ScChangeAction::IsTouchable() const |
| { |
| //! sequence order of execution is significant |
| if ( IsRejected() || GetType() == SC_CAT_REJECT || IsDeletedIn() ) |
| return sal_False; |
| // content may reject and be touchable if on top |
| if ( GetType() == SC_CAT_CONTENT ) |
| return ((ScChangeActionContent*)this)->IsTopContent(); |
| if ( IsRejecting() ) |
| return sal_False; |
| return sal_True; |
| } |
| |
| |
| sal_Bool ScChangeAction::IsClickable() const |
| { |
| //! sequence order of execution is significant |
| if ( !IsVirgin() ) |
| return sal_False; |
| if ( IsDeletedIn() ) |
| return sal_False; |
| if ( GetType() == SC_CAT_CONTENT ) |
| { |
| ScChangeActionContentCellType eCCT = |
| ScChangeActionContent::GetContentCellType( |
| ((ScChangeActionContent*)this)->GetNewCell() ); |
| if ( eCCT == SC_CACCT_MATREF ) |
| return sal_False; |
| if ( eCCT == SC_CACCT_MATORG ) |
| { // no Accept-Select if one of the references is in a deleted col/row |
| const ScChangeActionLinkEntry* pL = |
| ((ScChangeActionContent*)this)->GetFirstDependentEntry(); |
| while ( pL ) |
| { |
| ScChangeAction* p = (ScChangeAction*) pL->GetAction(); |
| if ( p && p->IsDeletedIn() ) |
| return sal_False; |
| pL = pL->GetNext(); |
| } |
| } |
| return sal_True; // for Select() a content doesn't have to be touchable |
| } |
| return IsTouchable(); // Accept()/Reject() only on touchables |
| } |
| |
| |
| sal_Bool ScChangeAction::IsRejectable() const |
| { |
| //! sequence order of execution is significant |
| if ( !IsClickable() ) |
| return sal_False; |
| if ( GetType() == SC_CAT_CONTENT ) |
| { |
| if ( ((ScChangeActionContent*)this)->IsOldMatrixReference() ) |
| return sal_False; |
| ScChangeActionContent* pNextContent = |
| ((ScChangeActionContent*)this)->GetNextContent(); |
| if ( pNextContent == NULL ) |
| return sal_True; // *this is TopContent |
| return pNextContent->IsRejected(); // *this is next rejectable |
| } |
| return IsTouchable(); |
| } |
| |
| |
| sal_Bool ScChangeAction::IsInternalRejectable() const |
| { |
| //! sequence order of execution is significant |
| if ( !IsVirgin() ) |
| return sal_False; |
| if ( IsDeletedIn() ) |
| return sal_False; |
| if ( GetType() == SC_CAT_CONTENT ) |
| { |
| ScChangeActionContent* pNextContent = |
| ((ScChangeActionContent*)this)->GetNextContent(); |
| if ( pNextContent == NULL ) |
| return sal_True; // *this is TopContent |
| return pNextContent->IsRejected(); // *this is next rejectable |
| } |
| return IsTouchable(); |
| } |
| |
| |
| sal_Bool ScChangeAction::IsDialogRoot() const |
| { |
| return IsInternalRejectable(); // only rejectables in root |
| } |
| |
| |
| sal_Bool ScChangeAction::IsDialogParent() const |
| { |
| //! sequence order of execution is significant |
| if ( GetType() == SC_CAT_CONTENT ) |
| { |
| if ( !IsDialogRoot() ) |
| return sal_False; |
| if ( ((ScChangeActionContent*)this)->IsMatrixOrigin() && HasDependent() ) |
| return sal_True; |
| ScChangeActionContent* pPrevContent = |
| ((ScChangeActionContent*)this)->GetPrevContent(); |
| return pPrevContent && pPrevContent->IsVirgin(); |
| } |
| if ( HasDependent() ) |
| return IsDeleteType() ? sal_True : !IsDeletedIn(); |
| if ( HasDeleted() ) |
| { |
| if ( IsDeleteType() ) |
| { |
| if ( IsDialogRoot() ) |
| return sal_True; |
| ScChangeActionLinkEntry* pL = pLinkDeleted; |
| while ( pL ) |
| { |
| ScChangeAction* p = pL->GetAction(); |
| if ( p && p->GetType() != eType ) |
| return sal_True; |
| pL = pL->GetNext(); |
| } |
| } |
| else |
| return sal_True; |
| } |
| return sal_False; |
| } |
| |
| |
| sal_Bool ScChangeAction::IsMasterDelete() const |
| { |
| if ( !IsDeleteType() ) |
| return sal_False; |
| ScChangeActionDel* pDel = (ScChangeActionDel*) this; |
| return pDel->IsMultiDelete() && (pDel->IsTopDelete() || pDel->IsRejectable()); |
| } |
| |
| |
| void ScChangeAction::RemoveAllLinks() |
| { |
| RemoveAllAnyLinks(); |
| RemoveAllDeletedIn(); |
| RemoveAllDeleted(); |
| RemoveAllDependent(); |
| } |
| |
| |
| void ScChangeAction::RemoveAllAnyLinks() |
| { |
| while ( pLinkAny ) |
| delete pLinkAny; // rueckt sich selbst hoch |
| } |
| |
| |
| sal_Bool ScChangeAction::RemoveDeletedIn( const ScChangeAction* p ) |
| { |
| sal_Bool bRemoved = sal_False; |
| ScChangeActionLinkEntry* pL = GetDeletedIn(); |
| while ( pL ) |
| { |
| ScChangeActionLinkEntry* pNextLink = pL->GetNext(); |
| if ( pL->GetAction() == p ) |
| { |
| delete pL; |
| bRemoved = sal_True; |
| } |
| pL = pNextLink; |
| } |
| return bRemoved; |
| } |
| |
| |
| sal_Bool ScChangeAction::IsDeletedIn( const ScChangeAction* p ) const |
| { |
| ScChangeActionLinkEntry* pL = GetDeletedIn(); |
| while ( pL ) |
| { |
| if ( pL->GetAction() == p ) |
| return sal_True; |
| pL = pL->GetNext(); |
| } |
| return sal_False; |
| } |
| |
| |
| void ScChangeAction::RemoveAllDeletedIn() |
| { |
| //! nicht vom evtl. TopContent sondern wirklich dieser |
| while ( pLinkDeletedIn ) |
| delete pLinkDeletedIn; // rueckt sich selbst hoch |
| } |
| |
| |
| sal_Bool ScChangeAction::IsDeletedInDelType( ScChangeActionType eDelType ) const |
| { |
| ScChangeAction* p; |
| ScChangeActionLinkEntry* pL = GetDeletedIn(); |
| if ( pL ) |
| { |
| // InsertType fuer MergePrepare/MergeOwn |
| ScChangeActionType eInsType; |
| switch ( eDelType ) |
| { |
| case SC_CAT_DELETE_COLS : |
| eInsType = SC_CAT_INSERT_COLS; |
| break; |
| case SC_CAT_DELETE_ROWS : |
| eInsType = SC_CAT_INSERT_ROWS; |
| break; |
| case SC_CAT_DELETE_TABS : |
| eInsType = SC_CAT_INSERT_TABS; |
| break; |
| default: |
| eInsType = SC_CAT_NONE; |
| } |
| while ( pL ) |
| { |
| if ( (p = pL->GetAction()) != NULL && |
| (p->GetType() == eDelType || p->GetType() == eInsType) ) |
| return sal_True; |
| pL = pL->GetNext(); |
| } |
| } |
| return sal_False; |
| } |
| |
| |
| void ScChangeAction::SetDeletedIn( ScChangeAction* p ) |
| { |
| ScChangeActionLinkEntry* pLink1 = AddDeletedIn( p ); |
| ScChangeActionLinkEntry* pLink2; |
| if ( GetType() == SC_CAT_CONTENT ) |
| pLink2 = p->AddDeleted( ((ScChangeActionContent*)this)->GetTopContent() ); |
| else |
| pLink2 = p->AddDeleted( this ); |
| pLink1->SetLink( pLink2 ); |
| } |
| |
| |
| void ScChangeAction::RemoveAllDeleted() |
| { |
| while ( pLinkDeleted ) |
| delete pLinkDeleted; // rueckt sich selbst hoch |
| } |
| |
| |
| void ScChangeAction::RemoveAllDependent() |
| { |
| while ( pLinkDependent ) |
| delete pLinkDependent; // rueckt sich selbst hoch |
| } |
| |
| |
| DateTime ScChangeAction::GetDateTime() const |
| { |
| DateTime aDT( aDateTime ); |
| aDT.ConvertToLocalTime(); |
| return aDT; |
| } |
| |
| |
| void ScChangeAction::UpdateReference( const ScChangeTrack* /* pTrack */, |
| UpdateRefMode eMode, const ScBigRange& rRange, |
| sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) |
| { |
| ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() ); |
| } |
| |
| |
| void ScChangeAction::GetDescription( String& rStr, ScDocument* /* pDoc */, |
| sal_Bool /* bSplitRange */, bool bWarning ) const |
| { |
| if ( IsRejecting() && bWarning ) |
| { |
| // #112261# Add comment if rejection may have resulted in references |
| // not properly restored in formulas. See specification at |
| // http://specs.openoffice.org/calc/ease-of-use/redlining_comment.sxw |
| if (GetType() == SC_CAT_MOVE) |
| { |
| rStr += ScGlobal::GetRscString( |
| STR_CHANGED_MOVE_REJECTION_WARNING); |
| rStr += ' '; |
| } |
| else if (IsInsertType()) |
| { |
| rStr += ScGlobal::GetRscString( |
| STR_CHANGED_DELETE_REJECTION_WARNING); |
| rStr += ' '; |
| } |
| else |
| { |
| const ScChangeTrack* pCT = GetChangeTrack(); |
| if (pCT) |
| { |
| ScChangeAction* pReject = pCT->GetActionOrGenerated( |
| GetRejectAction()); |
| if (pReject) |
| { |
| if (pReject->GetType() == SC_CAT_MOVE) |
| { |
| rStr += ScGlobal::GetRscString( |
| STR_CHANGED_MOVE_REJECTION_WARNING); |
| rStr += ' '; |
| } |
| else if (pReject->IsDeleteType()) |
| { |
| rStr += ScGlobal::GetRscString( |
| STR_CHANGED_DELETE_REJECTION_WARNING); |
| rStr += ' '; |
| } |
| else if (pReject->HasDependent()) |
| { |
| ScChangeActionTable aTable; |
| pCT->GetDependents( pReject, aTable, sal_False, sal_True ); |
| for ( const ScChangeAction* p = aTable.First(); p; |
| p = aTable.Next() ) |
| { |
| if (p->GetType() == SC_CAT_MOVE) |
| { |
| rStr += ScGlobal::GetRscString( |
| STR_CHANGED_MOVE_REJECTION_WARNING); |
| rStr += ' '; |
| break; // for |
| } |
| else if (pReject->IsDeleteType()) |
| { |
| rStr += ScGlobal::GetRscString( |
| STR_CHANGED_DELETE_REJECTION_WARNING); |
| rStr += ' '; |
| break; // for |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |
| String ScChangeAction::GetRefString( const ScBigRange& rRange, |
| ScDocument* pDoc, sal_Bool bFlag3D ) const |
| { |
| String aStr; |
| sal_uInt16 nFlags = ( rRange.IsValid( pDoc ) ? SCA_VALID : 0 ); |
| if ( !nFlags ) |
| aStr = ScGlobal::GetRscString( STR_NOREF_STR ); |
| else |
| { |
| ScRange aTmpRange( rRange.MakeRange() ); |
| switch ( GetType() ) |
| { |
| case SC_CAT_INSERT_COLS : |
| case SC_CAT_DELETE_COLS : |
| if ( bFlag3D ) |
| { |
| pDoc->GetName( aTmpRange.aStart.Tab(), aStr ); |
| aStr += '.'; |
| } |
| aStr += ::ScColToAlpha( aTmpRange.aStart.Col() ); |
| aStr += ':'; |
| aStr += ::ScColToAlpha( aTmpRange.aEnd.Col() ); |
| break; |
| case SC_CAT_INSERT_ROWS : |
| case SC_CAT_DELETE_ROWS : |
| if ( bFlag3D ) |
| { |
| pDoc->GetName( aTmpRange.aStart.Tab(), aStr ); |
| aStr += '.'; |
| } |
| aStr += String::CreateFromInt32( aTmpRange.aStart.Row() + 1 ); |
| aStr += ':'; |
| aStr += String::CreateFromInt32( aTmpRange.aEnd.Row() + 1 ); |
| break; |
| default: |
| if ( bFlag3D || GetType() == SC_CAT_INSERT_TABS ) |
| nFlags |= SCA_TAB_3D; |
| aTmpRange.Format( aStr, nFlags, pDoc, pDoc->GetAddressConvention() ); |
| } |
| if ( (bFlag3D && IsDeleteType()) || IsDeletedIn() ) |
| { |
| aStr.Insert( '(', 0 ); |
| aStr += ')'; |
| } |
| } |
| return aStr; |
| } |
| |
| |
| void ScChangeAction::GetRefString( String& rStr, ScDocument* pDoc, |
| sal_Bool bFlag3D ) const |
| { |
| rStr = GetRefString( GetBigRange(), pDoc, bFlag3D ); |
| } |
| |
| |
| void ScChangeAction::Accept() |
| { |
| if ( IsVirgin() ) |
| { |
| SetState( SC_CAS_ACCEPTED ); |
| DeleteCellEntries(); |
| } |
| } |
| |
| |
| void ScChangeAction::SetRejected() |
| { |
| if ( IsVirgin() ) |
| { |
| SetState( SC_CAS_REJECTED ); |
| RemoveAllLinks(); |
| DeleteCellEntries(); |
| } |
| } |
| |
| |
| void ScChangeAction::RejectRestoreContents( ScChangeTrack* pTrack, |
| SCsCOL nDx, SCsROW nDy ) |
| { |
| // Liste der Contents aufbauen |
| ScChangeActionCellListEntry* pListContents = NULL; |
| for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() ) |
| { |
| ScChangeAction* p = pL->GetAction(); |
| if ( p && p->GetType() == SC_CAT_CONTENT ) |
| { |
| ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry( |
| (ScChangeActionContent*) p, pListContents ); |
| pListContents = pE; |
| } |
| } |
| SetState( SC_CAS_REJECTED ); // vor UpdateReference fuer Move |
| pTrack->UpdateReference( this, sal_True ); // LinkDeleted freigeben |
| DBG_ASSERT( !pLinkDeleted, "ScChangeAction::RejectRestoreContents: pLinkDeleted != NULL" ); |
| // Liste der Contents abarbeiten und loeschen |
| ScDocument* pDoc = pTrack->GetDocument(); |
| ScChangeActionCellListEntry* pE = pListContents; |
| while ( pE ) |
| { |
| if ( !pE->pContent->IsDeletedIn() && |
| pE->pContent->GetBigRange().aStart.IsValid( pDoc ) ) |
| pE->pContent->PutNewValueToDoc( pDoc, nDx, nDy ); |
| ScChangeActionCellListEntry* pNextEntry; |
| pNextEntry = pE->pNext; |
| delete pE; |
| pE = pNextEntry; |
| } |
| DeleteCellEntries(); // weg mit den generierten |
| } |
| |
| |
| void ScChangeAction::SetDeletedInThis( sal_uLong nActionNumber, |
| const ScChangeTrack* pTrack ) |
| { |
| if ( nActionNumber ) |
| { |
| ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber ); |
| DBG_ASSERT( pAct, "ScChangeAction::SetDeletedInThis: missing Action" ); |
| if ( pAct ) |
| pAct->SetDeletedIn( this ); |
| } |
| } |
| |
| |
| void ScChangeAction::AddDependent( sal_uLong nActionNumber, |
| const ScChangeTrack* pTrack ) |
| { |
| if ( nActionNumber ) |
| { |
| ScChangeAction* pAct = pTrack->GetActionOrGenerated( nActionNumber ); |
| DBG_ASSERT( pAct, "ScChangeAction::AddDependent: missing Action" ); |
| if ( pAct ) |
| { |
| ScChangeActionLinkEntry* pLink = AddDependent( pAct ); |
| pAct->AddLink( this, pLink ); |
| } |
| } |
| } |
| |
| |
| #if DEBUG_CHANGETRACK |
| String ScChangeAction::ToString( ScDocument* pDoc ) const |
| { |
| String aReturn; |
| |
| String aNumber = String::CreateFromInt64( static_cast< sal_Int64 >( GetActionNumber() ) ); |
| |
| String aActionState; |
| ScChangeActionState eActionState = GetState(); |
| switch ( eActionState ) |
| { |
| case SC_CAS_VIRGIN: |
| { |
| aActionState = String::CreateFromAscii( " " ); |
| } |
| break; |
| case SC_CAS_ACCEPTED: |
| { |
| aActionState = String::CreateFromAscii( "+" ); |
| } |
| break; |
| case SC_CAS_REJECTED: |
| { |
| aActionState = String::CreateFromAscii( "-" ); |
| } |
| break; |
| } |
| |
| String aRejectAction; |
| if ( IsRejecting() ) |
| { |
| aRejectAction += 'r'; |
| aRejectAction += String::CreateFromInt64( static_cast< sal_Int64 >( GetRejectAction() ) ); |
| } |
| |
| String aReference; |
| GetRefString( aReference, pDoc, sal_True ); |
| |
| String aAuthor = GetUser(); |
| |
| DateTime aDT = GetDateTime(); |
| String aDate = ScGlobal::pLocaleData->getDate( aDT ); |
| aDate += ' '; |
| aDate += ScGlobal::pLocaleData->getTime( aDT, sal_False, sal_False ); |
| |
| String aDescription; |
| GetDescription( aDescription, pDoc ); |
| |
| String aLinkAny; |
| const ScChangeActionLinkEntry* pLinkA = pLinkAny; |
| while ( pLinkA ) |
| { |
| if ( !aLinkAny.Len() ) |
| { |
| aLinkAny = String::CreateFromAscii( "(Any:" ); |
| } |
| aLinkAny += String::CreateFromAscii( " ->" ); |
| aLinkAny += pLinkA->ToString(); |
| pLinkA = pLinkA->GetNext(); |
| } |
| if ( aLinkAny.Len() ) |
| { |
| aLinkAny += ')'; |
| } |
| |
| String aLinkDeletedIn; |
| const ScChangeActionLinkEntry* pLinkDI = pLinkDeletedIn; |
| while ( pLinkDI ) |
| { |
| if ( !aLinkDeletedIn.Len() ) |
| { |
| aLinkDeletedIn = String::CreateFromAscii( "(DeletedIn:" ); |
| } |
| aLinkDeletedIn += String::CreateFromAscii( " ->" ); |
| aLinkDeletedIn += pLinkDI->ToString(); |
| pLinkDI = pLinkDI->GetNext(); |
| } |
| if ( aLinkDeletedIn.Len() ) |
| { |
| aLinkDeletedIn += ')'; |
| } |
| |
| String aLinkDeleted; |
| const ScChangeActionLinkEntry* pLinkD = pLinkDeleted; |
| while ( pLinkD ) |
| { |
| if ( !aLinkDeleted.Len() ) |
| { |
| aLinkDeleted = String::CreateFromAscii( "(Deleted:" ); |
| } |
| aLinkDeleted += String::CreateFromAscii( " ->" ); |
| aLinkDeleted += pLinkD->ToString(); |
| pLinkD = pLinkD->GetNext(); |
| } |
| if ( aLinkDeleted.Len() ) |
| { |
| aLinkDeleted += ')'; |
| } |
| |
| String aLinkDependent; |
| const ScChangeActionLinkEntry* pLinkDp = pLinkDependent; |
| while ( pLinkDp ) |
| { |
| if ( !aLinkDependent.Len() ) |
| { |
| aLinkDependent = String::CreateFromAscii( "(Dependent:" ); |
| } |
| aLinkDependent += String::CreateFromAscii( " ->" ); |
| aLinkDependent += pLinkDp->ToString(); |
| pLinkDp = pLinkDp->GetNext(); |
| } |
| if ( aLinkDependent.Len() ) |
| { |
| aLinkDependent += ')'; |
| } |
| |
| aReturn += aNumber; |
| aReturn += aActionState; |
| aReturn += aRejectAction; |
| aReturn += String::CreateFromAscii( ": " ); |
| aReturn += aReference; |
| aReturn += ' '; |
| aReturn += aAuthor; |
| aReturn += ' '; |
| aReturn += aDate; |
| aReturn += ' '; |
| aReturn += aDescription; |
| aReturn += ' '; |
| aReturn += aLinkAny; |
| aReturn += ' '; |
| aReturn += aLinkDeletedIn; |
| aReturn += ' '; |
| aReturn += aLinkDeleted; |
| aReturn += ' '; |
| aReturn += aLinkDependent; |
| |
| return aReturn; |
| } |
| #endif // DEBUG_CHANGETRACK |
| |
| |
| // --- ScChangeActionIns --------------------------------------------------- |
| |
| ScChangeActionIns::ScChangeActionIns( const ScRange& rRange ) |
| : ScChangeAction( SC_CAT_NONE, rRange ) |
| { |
| if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == MAXCOL ) |
| { |
| aBigRange.aStart.SetCol( nInt32Min ); |
| aBigRange.aEnd.SetCol( nInt32Max ); |
| if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW ) |
| { |
| SetType( SC_CAT_INSERT_TABS ); |
| aBigRange.aStart.SetRow( nInt32Min ); |
| aBigRange.aEnd.SetRow( nInt32Max ); |
| } |
| else |
| SetType( SC_CAT_INSERT_ROWS ); |
| } |
| else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW ) |
| { |
| SetType( SC_CAT_INSERT_COLS ); |
| aBigRange.aStart.SetRow( nInt32Min ); |
| aBigRange.aEnd.SetRow( nInt32Max ); |
| } |
| else |
| { |
| DBG_ERROR( "ScChangeActionIns: Block not supported!" ); |
| } |
| } |
| |
| |
| ScChangeActionIns::ScChangeActionIns(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber, |
| const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String& sComment, |
| const ScChangeActionType eTypeP) |
| : |
| ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment) |
| { |
| } |
| |
| ScChangeActionIns::~ScChangeActionIns() |
| { |
| } |
| |
| |
| void ScChangeActionIns::GetDescription( String& rStr, ScDocument* pDoc, |
| sal_Bool bSplitRange, bool bWarning ) const |
| { |
| ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning ); |
| |
| sal_uInt16 nWhatId; |
| switch ( GetType() ) |
| { |
| case SC_CAT_INSERT_COLS : |
| nWhatId = STR_COLUMN; |
| break; |
| case SC_CAT_INSERT_ROWS : |
| nWhatId = STR_ROW; |
| break; |
| default: |
| nWhatId = STR_AREA; |
| } |
| |
| String aRsc( ScGlobal::GetRscString( STR_CHANGED_INSERT ) ); |
| xub_StrLen nPos = aRsc.SearchAscii( "#1" ); |
| rStr += aRsc.Copy( 0, nPos ); |
| rStr += ScGlobal::GetRscString( nWhatId ); |
| rStr += ' '; |
| rStr += GetRefString( GetBigRange(), pDoc ); |
| rStr += aRsc.Copy( nPos+2 ); |
| } |
| |
| |
| sal_Bool ScChangeActionIns::Reject( ScDocument* pDoc ) |
| { |
| if ( !aBigRange.IsValid( pDoc ) ) |
| return sal_False; |
| |
| ScRange aRange( aBigRange.MakeRange() ); |
| if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(), |
| aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) ) |
| return sal_False; |
| |
| switch ( GetType() ) |
| { |
| case SC_CAT_INSERT_COLS : |
| pDoc->DeleteCol( aRange ); |
| break; |
| case SC_CAT_INSERT_ROWS : |
| pDoc->DeleteRow( aRange ); |
| break; |
| case SC_CAT_INSERT_TABS : |
| pDoc->DeleteTab( aRange.aStart.Tab() ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| SetState( SC_CAS_REJECTED ); |
| RemoveAllLinks(); |
| return sal_True; |
| } |
| |
| |
| // --- ScChangeActionDel --------------------------------------------------- |
| |
| ScChangeActionDel::ScChangeActionDel( const ScRange& rRange, |
| SCsCOL nDxP, SCsROW nDyP, ScChangeTrack* pTrackP ) |
| : |
| ScChangeAction( SC_CAT_NONE, rRange ), |
| pTrack( pTrackP ), |
| pFirstCell( NULL ), |
| pCutOff( NULL ), |
| nCutOff( 0 ), |
| pLinkMove( NULL ), |
| nDx( nDxP ), |
| nDy( nDyP ) |
| { |
| if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == MAXCOL ) |
| { |
| aBigRange.aStart.SetCol( nInt32Min ); |
| aBigRange.aEnd.SetCol( nInt32Max ); |
| if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW ) |
| { |
| SetType( SC_CAT_DELETE_TABS ); |
| aBigRange.aStart.SetRow( nInt32Min ); |
| aBigRange.aEnd.SetRow( nInt32Max ); |
| } |
| else |
| SetType( SC_CAT_DELETE_ROWS ); |
| } |
| else if ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == MAXROW ) |
| { |
| SetType( SC_CAT_DELETE_COLS ); |
| aBigRange.aStart.SetRow( nInt32Min ); |
| aBigRange.aEnd.SetRow( nInt32Max ); |
| } |
| else |
| { |
| DBG_ERROR( "ScChangeActionDel: Block not supported!" ); |
| } |
| } |
| |
| |
| ScChangeActionDel::ScChangeActionDel(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber, |
| const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String &sComment, |
| const ScChangeActionType eTypeP, const SCsCOLROW nD, ScChangeTrack* pTrackP) // which of nDx and nDy is set is depend on the type |
| : |
| ScChangeAction(eTypeP, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment), |
| pTrack( pTrackP ), |
| pFirstCell( NULL ), |
| pCutOff( NULL ), |
| nCutOff( 0 ), |
| pLinkMove( NULL ), |
| nDx( 0 ), |
| nDy( 0 ) |
| { |
| if (eType == SC_CAT_DELETE_COLS) |
| nDx = static_cast<SCsCOL>(nD); |
| else if (eType == SC_CAT_DELETE_ROWS) |
| nDy = static_cast<SCsROW>(nD); |
| } |
| |
| ScChangeActionDel::~ScChangeActionDel() |
| { |
| DeleteCellEntries(); |
| while ( pLinkMove ) |
| delete pLinkMove; |
| } |
| |
| void ScChangeActionDel::AddContent( ScChangeActionContent* pContent ) |
| { |
| ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry( |
| pContent, pFirstCell ); |
| pFirstCell = pE; |
| } |
| |
| |
| void ScChangeActionDel::DeleteCellEntries() |
| { |
| pTrack->DeleteCellEntries( pFirstCell, this ); |
| } |
| |
| |
| sal_Bool ScChangeActionDel::IsBaseDelete() const |
| { |
| return !GetDx() && !GetDy(); |
| } |
| |
| |
| sal_Bool ScChangeActionDel::IsTopDelete() const |
| { |
| const ScChangeAction* p = GetNext(); |
| if ( !p || p->GetType() != GetType() ) |
| return sal_True; |
| return ((ScChangeActionDel*)p)->IsBaseDelete(); |
| } |
| |
| |
| sal_Bool ScChangeActionDel::IsMultiDelete() const |
| { |
| if ( GetDx() || GetDy() ) |
| return sal_True; |
| const ScChangeAction* p = GetNext(); |
| if ( !p || p->GetType() != GetType() ) |
| return sal_False; |
| const ScChangeActionDel* pDel = (const ScChangeActionDel*) p; |
| if ( (pDel->GetDx() > GetDx() || pDel->GetDy() > GetDy()) && |
| pDel->GetBigRange() == aBigRange ) |
| return sal_True; |
| return sal_False; |
| } |
| |
| |
| sal_Bool ScChangeActionDel::IsTabDeleteCol() const |
| { |
| if ( GetType() != SC_CAT_DELETE_COLS ) |
| return sal_False; |
| const ScChangeAction* p = this; |
| while ( p && p->GetType() == SC_CAT_DELETE_COLS && |
| !((const ScChangeActionDel*)p)->IsTopDelete() ) |
| p = p->GetNext(); |
| return p && p->GetType() == SC_CAT_DELETE_TABS; |
| } |
| |
| |
| void ScChangeActionDel::UpdateReference( const ScChangeTrack* /* pTrack */, |
| UpdateRefMode eMode, const ScBigRange& rRange, |
| sal_Int32 nDxP, sal_Int32 nDyP, sal_Int32 nDz ) |
| { |
| ScRefUpdate::Update( eMode, rRange, nDxP, nDyP, nDz, GetBigRange() ); |
| if ( !IsDeletedIn() ) |
| return ; |
| // evtl. in "druntergerutschten" anpassen |
| for ( ScChangeActionLinkEntry* pL = pLinkDeleted; pL; pL = pL->GetNext() ) |
| { |
| ScChangeAction* p = pL->GetAction(); |
| if ( p && p->GetType() == SC_CAT_CONTENT && |
| !GetBigRange().In( p->GetBigRange() ) ) |
| { |
| switch ( GetType() ) |
| { |
| case SC_CAT_DELETE_COLS : |
| p->GetBigRange().aStart.SetCol( GetBigRange().aStart.Col() ); |
| p->GetBigRange().aEnd.SetCol( GetBigRange().aStart.Col() ); |
| break; |
| case SC_CAT_DELETE_ROWS : |
| p->GetBigRange().aStart.SetRow( GetBigRange().aStart.Row() ); |
| p->GetBigRange().aEnd.SetRow( GetBigRange().aStart.Row() ); |
| break; |
| case SC_CAT_DELETE_TABS : |
| p->GetBigRange().aStart.SetTab( GetBigRange().aStart.Tab() ); |
| p->GetBigRange().aEnd.SetTab( GetBigRange().aStart.Tab() ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| } |
| } |
| |
| |
| ScBigRange ScChangeActionDel::GetOverAllRange() const |
| { |
| ScBigRange aTmpRange( GetBigRange() ); |
| aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() ); |
| aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() ); |
| return aTmpRange; |
| } |
| |
| |
| void ScChangeActionDel::GetDescription( String& rStr, ScDocument* pDoc, |
| sal_Bool bSplitRange, bool bWarning ) const |
| { |
| ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning ); |
| |
| sal_uInt16 nWhatId; |
| switch ( GetType() ) |
| { |
| case SC_CAT_DELETE_COLS : |
| nWhatId = STR_COLUMN; |
| break; |
| case SC_CAT_DELETE_ROWS : |
| nWhatId = STR_ROW; |
| break; |
| default: |
| nWhatId = STR_AREA; |
| } |
| |
| ScBigRange aTmpRange( GetBigRange() ); |
| if ( !IsRejected() ) |
| { |
| if ( bSplitRange ) |
| { |
| aTmpRange.aStart.SetCol( aTmpRange.aStart.Col() + GetDx() ); |
| aTmpRange.aStart.SetRow( aTmpRange.aStart.Row() + GetDy() ); |
| } |
| aTmpRange.aEnd.SetCol( aTmpRange.aEnd.Col() + GetDx() ); |
| aTmpRange.aEnd.SetRow( aTmpRange.aEnd.Row() + GetDy() ); |
| } |
| |
| String aRsc( ScGlobal::GetRscString( STR_CHANGED_DELETE ) ); |
| xub_StrLen nPos = aRsc.SearchAscii( "#1" ); |
| rStr += aRsc.Copy( 0, nPos ); |
| rStr += ScGlobal::GetRscString( nWhatId ); |
| rStr += ' '; |
| rStr += GetRefString( aTmpRange, pDoc ); |
| rStr += aRsc.Copy( nPos+2 ); |
| } |
| |
| |
| sal_Bool ScChangeActionDel::Reject( ScDocument* pDoc ) |
| { |
| if ( !aBigRange.IsValid( pDoc ) && GetType() != SC_CAT_DELETE_TABS ) |
| return sal_False; |
| |
| sal_Bool bOk = sal_True; |
| |
| if ( IsTopDelete() ) |
| { // den kompletten Bereich in einem Rutsch restaurieren |
| ScBigRange aTmpRange( GetOverAllRange() ); |
| if ( !aTmpRange.IsValid( pDoc ) ) |
| { |
| if ( GetType() == SC_CAT_DELETE_TABS ) |
| { // wird Tab angehaengt? |
| if ( aTmpRange.aStart.Tab() > pDoc->GetMaxTableNumber() ) |
| bOk = sal_False; |
| } |
| else |
| bOk = sal_False; |
| } |
| if ( bOk ) |
| { |
| ScRange aRange( aTmpRange.MakeRange() ); |
| // InDelete... fuer Formel UpdateReference in Document |
| pTrack->SetInDeleteRange( aRange ); |
| pTrack->SetInDeleteTop( sal_True ); |
| pTrack->SetInDeleteUndo( sal_True ); |
| pTrack->SetInDelete( sal_True ); |
| switch ( GetType() ) |
| { |
| case SC_CAT_DELETE_COLS : |
| if ( !(aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL) ) |
| { // nur wenn nicht TabDelete |
| if ( ( bOk = pDoc->CanInsertCol( aRange ) ) != sal_False ) |
| bOk = pDoc->InsertCol( aRange ); |
| } |
| break; |
| case SC_CAT_DELETE_ROWS : |
| if ( ( bOk = pDoc->CanInsertRow( aRange ) ) != sal_False ) |
| bOk = pDoc->InsertRow( aRange ); |
| break; |
| case SC_CAT_DELETE_TABS : |
| { |
| //2do: Tabellennamen merken? |
| String aName; |
| pDoc->CreateValidTabName( aName ); |
| if ( ( bOk = pDoc->ValidNewTabName( aName ) ) != sal_False ) |
| bOk = pDoc->InsertTab( aRange.aStart.Tab(), aName ); |
| } |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| pTrack->SetInDelete( sal_False ); |
| pTrack->SetInDeleteUndo( sal_False ); |
| } |
| if ( !bOk ) |
| { |
| pTrack->SetInDeleteTop( sal_False ); |
| return sal_False; |
| } |
| // InDeleteTop fuer UpdateReference-Undo behalten |
| } |
| |
| // setzt rejected und ruft UpdateReference-Undo und DeleteCellEntries |
| RejectRestoreContents( pTrack, GetDx(), GetDy() ); |
| |
| pTrack->SetInDeleteTop( sal_False ); |
| RemoveAllLinks(); |
| return sal_True; |
| } |
| |
| |
| void ScChangeActionDel::UndoCutOffMoves() |
| { // abgeschnittene Moves wiederherstellen, Entries/Links deleten |
| while ( pLinkMove ) |
| { |
| ScChangeActionMove* pMove = pLinkMove->GetMove(); |
| short nFrom = pLinkMove->GetCutOffFrom(); |
| short nTo = pLinkMove->GetCutOffTo(); |
| switch ( GetType() ) |
| { |
| case SC_CAT_DELETE_COLS : |
| if ( nFrom > 0 ) |
| pMove->GetFromRange().aStart.IncCol( -nFrom ); |
| else if ( nFrom < 0 ) |
| pMove->GetFromRange().aEnd.IncCol( -nFrom ); |
| if ( nTo > 0 ) |
| pMove->GetBigRange().aStart.IncCol( -nTo ); |
| else if ( nTo < 0 ) |
| pMove->GetBigRange().aEnd.IncCol( -nTo ); |
| break; |
| case SC_CAT_DELETE_ROWS : |
| if ( nFrom > 0 ) |
| pMove->GetFromRange().aStart.IncRow( -nFrom ); |
| else if ( nFrom < 0 ) |
| pMove->GetFromRange().aEnd.IncRow( -nFrom ); |
| if ( nTo > 0 ) |
| pMove->GetBigRange().aStart.IncRow( -nTo ); |
| else if ( nTo < 0 ) |
| pMove->GetBigRange().aEnd.IncRow( -nTo ); |
| break; |
| case SC_CAT_DELETE_TABS : |
| if ( nFrom > 0 ) |
| pMove->GetFromRange().aStart.IncTab( -nFrom ); |
| else if ( nFrom < 0 ) |
| pMove->GetFromRange().aEnd.IncTab( -nFrom ); |
| if ( nTo > 0 ) |
| pMove->GetBigRange().aStart.IncTab( -nTo ); |
| else if ( nTo < 0 ) |
| pMove->GetBigRange().aEnd.IncTab( -nTo ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| delete pLinkMove; // rueckt sich selbst hoch |
| } |
| } |
| |
| void ScChangeActionDel::UndoCutOffInsert() |
| { // abgeschnittenes Insert wiederherstellen |
| if ( pCutOff ) |
| { |
| switch ( pCutOff->GetType() ) |
| { |
| case SC_CAT_INSERT_COLS : |
| if ( nCutOff < 0 ) |
| pCutOff->GetBigRange().aEnd.IncCol( -nCutOff ); |
| else |
| pCutOff->GetBigRange().aStart.IncCol( -nCutOff ); |
| break; |
| case SC_CAT_INSERT_ROWS : |
| if ( nCutOff < 0 ) |
| pCutOff->GetBigRange().aEnd.IncRow( -nCutOff ); |
| else |
| pCutOff->GetBigRange().aStart.IncRow( -nCutOff ); |
| break; |
| case SC_CAT_INSERT_TABS : |
| if ( nCutOff < 0 ) |
| pCutOff->GetBigRange().aEnd.IncTab( -nCutOff ); |
| else |
| pCutOff->GetBigRange().aStart.IncTab( -nCutOff ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| SetCutOffInsert( NULL, 0 ); |
| } |
| } |
| |
| |
| // --- ScChangeActionMove -------------------------------------------------- |
| |
| ScChangeActionMove::ScChangeActionMove(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber, |
| const ScBigRange& aToBigRange, const String& aUserP, const DateTime& aDateTimeP, const String &sComment, |
| const ScBigRange& aFromBigRange, ScChangeTrack* pTrackP) // which of nDx and nDy is set is depend on the type |
| : |
| ScChangeAction(SC_CAT_MOVE, aToBigRange, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment), |
| aFromRange(aFromBigRange), |
| pTrack( pTrackP ), |
| pFirstCell( NULL ), |
| nStartLastCut(0), |
| nEndLastCut(0) |
| { |
| } |
| |
| ScChangeActionMove::~ScChangeActionMove() |
| { |
| DeleteCellEntries(); |
| } |
| |
| |
| void ScChangeActionMove::AddContent( ScChangeActionContent* pContent ) |
| { |
| ScChangeActionCellListEntry* pE = new ScChangeActionCellListEntry( |
| pContent, pFirstCell ); |
| pFirstCell = pE; |
| } |
| |
| |
| void ScChangeActionMove::DeleteCellEntries() |
| { |
| pTrack->DeleteCellEntries( pFirstCell, this ); |
| } |
| |
| |
| void ScChangeActionMove::UpdateReference( const ScChangeTrack* /* pTrack */, |
| UpdateRefMode eMode, const ScBigRange& rRange, |
| sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) |
| { |
| ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aFromRange ); |
| ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, GetBigRange() ); |
| } |
| |
| |
| void ScChangeActionMove::GetDelta( sal_Int32& nDx, sal_Int32& nDy, sal_Int32& nDz ) const |
| { |
| const ScBigAddress& rToPos = GetBigRange().aStart; |
| const ScBigAddress& rFromPos = GetFromRange().aStart; |
| nDx = rToPos.Col() - rFromPos.Col(); |
| nDy = rToPos.Row() - rFromPos.Row(); |
| nDz = rToPos.Tab() - rFromPos.Tab(); |
| } |
| |
| |
| void ScChangeActionMove::GetDescription( String& rStr, ScDocument* pDoc, |
| sal_Bool bSplitRange, bool bWarning ) const |
| { |
| ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning ); |
| |
| sal_Bool bFlag3D = ( GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab() ); |
| |
| String aRsc( ScGlobal::GetRscString( STR_CHANGED_MOVE ) ); |
| |
| xub_StrLen nPos = 0; |
| String aTmpStr = ScChangeAction::GetRefString( GetFromRange(), pDoc, bFlag3D ); |
| nPos = aRsc.SearchAscii( "#1", nPos ); |
| aRsc.Erase( nPos, 2 ); |
| aRsc.Insert( aTmpStr, nPos ); |
| nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() ); |
| |
| aTmpStr = ScChangeAction::GetRefString( GetBigRange(), pDoc, bFlag3D ); |
| nPos = aRsc.SearchAscii( "#2", nPos ); |
| aRsc.Erase( nPos, 2 ); |
| aRsc.Insert( aTmpStr, nPos ); |
| nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() ); |
| |
| rStr += aRsc; |
| } |
| |
| |
| void ScChangeActionMove::GetRefString( String& rStr, ScDocument* pDoc, |
| sal_Bool bFlag3D ) const |
| { |
| if ( !bFlag3D ) |
| bFlag3D = ( GetFromRange().aStart.Tab() != GetBigRange().aStart.Tab() ); |
| rStr = ScChangeAction::GetRefString( GetFromRange(), pDoc, bFlag3D ); |
| rStr += ','; |
| rStr += ' '; |
| rStr += ScChangeAction::GetRefString( GetBigRange(), pDoc, bFlag3D ); |
| } |
| |
| |
| sal_Bool ScChangeActionMove::Reject( ScDocument* pDoc ) |
| { |
| if ( !(aBigRange.IsValid( pDoc ) && aFromRange.IsValid( pDoc )) ) |
| return sal_False; |
| |
| ScRange aToRange( aBigRange.MakeRange() ); |
| ScRange aFrmRange( aFromRange.MakeRange() ); |
| |
| sal_Bool bOk = pDoc->IsBlockEditable( aToRange.aStart.Tab(), |
| aToRange.aStart.Col(), aToRange.aStart.Row(), |
| aToRange.aEnd.Col(), aToRange.aEnd.Row() ); |
| if ( bOk ) |
| bOk = pDoc->IsBlockEditable( aFrmRange.aStart.Tab(), |
| aFrmRange.aStart.Col(), aFrmRange.aStart.Row(), |
| aFrmRange.aEnd.Col(), aFrmRange.aEnd.Row() ); |
| if ( !bOk ) |
| return sal_False; |
| |
| pTrack->LookUpContents( aToRange, pDoc, 0, 0, 0 ); // zu movende Contents |
| |
| pDoc->DeleteAreaTab( aToRange, IDF_ALL ); |
| pDoc->DeleteAreaTab( aFrmRange, IDF_ALL ); |
| // Formeln im Dokument anpassen |
| pDoc->UpdateReference( URM_MOVE, |
| aFrmRange.aStart.Col(), aFrmRange.aStart.Row(), aFrmRange.aStart.Tab(), |
| aFrmRange.aEnd.Col(), aFrmRange.aEnd.Row(), aFrmRange.aEnd.Tab(), |
| (SCsCOL) aFrmRange.aStart.Col() - aToRange.aStart.Col(), |
| (SCsROW) aFrmRange.aStart.Row() - aToRange.aStart.Row(), |
| (SCsTAB) aFrmRange.aStart.Tab() - aToRange.aStart.Tab(), NULL ); |
| |
| // LinkDependent freigeben, nachfolgendes UpdateReference-Undo setzt |
| // ToRange->FromRange Dependents |
| RemoveAllDependent(); |
| |
| // setzt rejected und ruft UpdateReference-Undo und DeleteCellEntries |
| RejectRestoreContents( pTrack, 0, 0 ); |
| |
| while ( pLinkDependent ) |
| { |
| ScChangeAction* p = pLinkDependent->GetAction(); |
| if ( p && p->GetType() == SC_CAT_CONTENT ) |
| { |
| ScChangeActionContent* pContent = (ScChangeActionContent*) p; |
| if ( !pContent->IsDeletedIn() && |
| pContent->GetBigRange().aStart.IsValid( pDoc ) ) |
| pContent->PutNewValueToDoc( pDoc, 0, 0 ); |
| // in LookUpContents generierte loeschen |
| if ( pTrack->IsGenerated( pContent->GetActionNumber() ) && |
| !pContent->IsDeletedIn() ) |
| { |
| pLinkDependent->UnLink(); //! sonst wird der mitgeloescht |
| pTrack->DeleteGeneratedDelContent( pContent ); |
| } |
| } |
| delete pLinkDependent; |
| } |
| |
| RemoveAllLinks(); |
| return sal_True; |
| } |
| |
| |
| // --- ScChangeActionContent ----------------------------------------------- |
| |
| const sal_uInt16 nMemPoolChangeActionContent = (0x8000 - 64) / sizeof(ScChangeActionContent); |
| IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeActionContent, nMemPoolChangeActionContent, nMemPoolChangeActionContent ) |
| |
| ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber, |
| const ScChangeActionState eStateP, const sal_uLong nRejectingNumber, |
| const ScBigRange& aBigRangeP, const String& aUserP, |
| const DateTime& aDateTimeP, const String& sComment, |
| ScBaseCell* pTempOldCell, ScDocument* pDoc, const String& sOldValue ) |
| : |
| ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment), |
| aOldValue(sOldValue), |
| pOldCell(pTempOldCell), |
| pNewCell(NULL), |
| pNextContent(NULL), |
| pPrevContent(NULL), |
| pNextInSlot(NULL), |
| ppPrevInSlot(NULL) |
| |
| { |
| if (pOldCell) |
| ScChangeActionContent::SetCell( aOldValue, pOldCell, 0, pDoc ); |
| if ( sOldValue.Len() ) // #i40704# don't overwrite SetCell result with empty string |
| aOldValue = sOldValue; // set again, because SetCell removes it |
| } |
| |
| ScChangeActionContent::ScChangeActionContent( const sal_uLong nActionNumber, |
| ScBaseCell* pTempNewCell, const ScBigRange& aBigRangeP, |
| ScDocument* pDoc, const String& sNewValue ) |
| : |
| ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber), |
| aNewValue(sNewValue), |
| pOldCell(NULL), |
| pNewCell(pTempNewCell), |
| pNextContent(NULL), |
| pPrevContent(NULL), |
| pNextInSlot(NULL), |
| ppPrevInSlot(NULL) |
| { |
| if (pNewCell) |
| ScChangeActionContent::SetCell( aNewValue, pNewCell, 0, pDoc ); |
| if ( sNewValue.Len() ) // #i40704# don't overwrite SetCell result with empty string |
| aNewValue = sNewValue; // set again, because SetCell removes it |
| } |
| |
| ScChangeActionContent::~ScChangeActionContent() |
| { |
| ClearTrack(); |
| } |
| |
| |
| void ScChangeActionContent::ClearTrack() |
| { |
| RemoveFromSlot(); |
| if ( pPrevContent ) |
| pPrevContent->pNextContent = pNextContent; |
| if ( pNextContent ) |
| pNextContent->pPrevContent = pPrevContent; |
| } |
| |
| |
| ScChangeActionContent* ScChangeActionContent::GetTopContent() const |
| { |
| if ( pNextContent ) |
| { |
| ScChangeActionContent* pContent = pNextContent; |
| while ( pContent->pNextContent && pContent != pContent->pNextContent ) |
| pContent = pContent->pNextContent; |
| return pContent; |
| } |
| return (ScChangeActionContent*) this; |
| } |
| |
| |
| ScChangeActionLinkEntry* ScChangeActionContent::GetDeletedIn() const |
| { |
| if ( pNextContent ) |
| return GetTopContent()->pLinkDeletedIn; |
| return pLinkDeletedIn; |
| } |
| |
| |
| ScChangeActionLinkEntry** ScChangeActionContent::GetDeletedInAddress() |
| { |
| if ( pNextContent ) |
| return GetTopContent()->GetDeletedInAddress(); |
| return &pLinkDeletedIn; |
| } |
| |
| |
| void ScChangeActionContent::SetOldValue( const ScBaseCell* pCell, |
| const ScDocument* pFromDoc, ScDocument* pToDoc, sal_uLong nFormat ) |
| { |
| ScChangeActionContent::SetValue( aOldValue, pOldCell, |
| nFormat, pCell, pFromDoc, pToDoc ); |
| } |
| |
| |
| void ScChangeActionContent::SetOldValue( const ScBaseCell* pCell, |
| const ScDocument* pFromDoc, ScDocument* pToDoc ) |
| { |
| ScChangeActionContent::SetValue( aOldValue, pOldCell, |
| aBigRange.aStart.MakeAddress(), pCell, pFromDoc, pToDoc ); |
| } |
| |
| |
| void ScChangeActionContent::SetNewValue( const ScBaseCell* pCell, |
| ScDocument* pDoc ) |
| { |
| ScChangeActionContent::SetValue( aNewValue, pNewCell, |
| aBigRange.aStart.MakeAddress(), pCell, pDoc, pDoc ); |
| } |
| |
| |
| void ScChangeActionContent::SetOldNewCells( ScBaseCell* pOldCellP, |
| sal_uLong nOldFormat, ScBaseCell* pNewCellP, |
| sal_uLong nNewFormat, ScDocument* pDoc ) |
| { |
| pOldCell = pOldCellP; |
| pNewCell = pNewCellP; |
| ScChangeActionContent::SetCell( aOldValue, pOldCell, nOldFormat, pDoc ); |
| ScChangeActionContent::SetCell( aNewValue, pNewCell, nNewFormat, pDoc ); |
| } |
| |
| void ScChangeActionContent::SetNewCell( ScBaseCell* pCell, ScDocument* pDoc, const String& rFormatted ) |
| { |
| DBG_ASSERT( !pNewCell, "ScChangeActionContent::SetNewCell: overwriting existing cell" ); |
| pNewCell = pCell; |
| ScChangeActionContent::SetCell( aNewValue, pNewCell, 0, pDoc ); |
| |
| // #i40704# allow to set formatted text here - don't call SetNewValue with String from XML filter |
| if ( rFormatted.Len() ) |
| aNewValue = rFormatted; |
| } |
| |
| void ScChangeActionContent::SetValueString( String& rValue, ScBaseCell*& pCell, |
| const String& rStr, ScDocument* pDoc ) |
| { |
| if ( pCell ) |
| { |
| pCell->Delete(); |
| pCell = NULL; |
| } |
| if ( rStr.Len() > 1 && rStr.GetChar(0) == '=' ) |
| { |
| rValue.Erase(); |
| pCell = new ScFormulaCell( |
| pDoc, aBigRange.aStart.MakeAddress(), rStr, formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::CONV_OOO ); |
| ((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True ); |
| } |
| else |
| rValue = rStr; |
| } |
| |
| |
| void ScChangeActionContent::SetOldValue( const String& rOld, ScDocument* pDoc ) |
| { |
| SetValueString( aOldValue, pOldCell, rOld, pDoc ); |
| } |
| |
| |
| void ScChangeActionContent::SetNewValue( const String& rNew, ScDocument* pDoc ) |
| { |
| SetValueString( aNewValue, pNewCell, rNew, pDoc ); |
| } |
| |
| |
| void ScChangeActionContent::GetOldString( String& rStr ) const |
| { |
| GetValueString( rStr, aOldValue, pOldCell ); |
| } |
| |
| |
| void ScChangeActionContent::GetNewString( String& rStr ) const |
| { |
| GetValueString( rStr, aNewValue, pNewCell ); |
| } |
| |
| |
| void ScChangeActionContent::GetDescription( String& rStr, ScDocument* pDoc, |
| sal_Bool bSplitRange, bool bWarning ) const |
| { |
| ScChangeAction::GetDescription( rStr, pDoc, bSplitRange, bWarning ); |
| |
| String aRsc( ScGlobal::GetRscString( STR_CHANGED_CELL ) ); |
| |
| String aTmpStr; |
| GetRefString( aTmpStr, pDoc ); |
| |
| xub_StrLen nPos = 0; |
| nPos = aRsc.SearchAscii( "#1", nPos ); |
| aRsc.Erase( nPos, 2 ); |
| aRsc.Insert( aTmpStr, nPos ); |
| nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() ); |
| |
| GetOldString( aTmpStr ); |
| if ( !aTmpStr.Len() ) |
| aTmpStr = ScGlobal::GetRscString( STR_CHANGED_BLANK ); |
| nPos = aRsc.SearchAscii( "#2", nPos ); |
| aRsc.Erase( nPos, 2 ); |
| aRsc.Insert( aTmpStr, nPos ); |
| nPos = sal::static_int_cast<xub_StrLen>( nPos + aTmpStr.Len() ); |
| |
| GetNewString( aTmpStr ); |
| if ( !aTmpStr.Len() ) |
| aTmpStr = ScGlobal::GetRscString( STR_CHANGED_BLANK ); |
| nPos = aRsc.SearchAscii( "#3", nPos ); |
| aRsc.Erase( nPos, 2 ); |
| aRsc.Insert( aTmpStr, nPos ); |
| |
| rStr += aRsc; |
| } |
| |
| |
| void ScChangeActionContent::GetRefString( String& rStr, ScDocument* pDoc, |
| sal_Bool bFlag3D ) const |
| { |
| sal_uInt16 nFlags = ( GetBigRange().IsValid( pDoc ) ? SCA_VALID : 0 ); |
| if ( nFlags ) |
| { |
| const ScBaseCell* pCell = GetNewCell(); |
| if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATORG ) |
| { |
| ScBigRange aLocalBigRange( GetBigRange() ); |
| SCCOL nC; |
| SCROW nR; |
| ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR ); |
| aLocalBigRange.aEnd.IncCol( nC-1 ); |
| aLocalBigRange.aEnd.IncRow( nR-1 ); |
| rStr = ScChangeAction::GetRefString( aLocalBigRange, pDoc, bFlag3D ); |
| |
| return ; |
| } |
| |
| ScAddress aTmpAddress( GetBigRange().aStart.MakeAddress() ); |
| if ( bFlag3D ) |
| nFlags |= SCA_TAB_3D; |
| aTmpAddress.Format( rStr, nFlags, pDoc, pDoc->GetAddressConvention() ); |
| if ( IsDeletedIn() ) |
| { |
| rStr.Insert( '(', 0 ); |
| rStr += ')'; |
| } |
| } |
| else |
| rStr = ScGlobal::GetRscString( STR_NOREF_STR ); |
| } |
| |
| |
| sal_Bool ScChangeActionContent::Reject( ScDocument* pDoc ) |
| { |
| if ( !aBigRange.IsValid( pDoc ) ) |
| return sal_False; |
| |
| PutOldValueToDoc( pDoc, 0, 0 ); |
| |
| SetState( SC_CAS_REJECTED ); |
| RemoveAllLinks(); |
| |
| return sal_True; |
| } |
| |
| |
| sal_Bool ScChangeActionContent::Select( ScDocument* pDoc, ScChangeTrack* pTrack, |
| sal_Bool bOldest, Stack* pRejectActions ) |
| { |
| if ( !aBigRange.IsValid( pDoc ) ) |
| return sal_False; |
| |
| ScChangeActionContent* pContent = this; |
| // accept previous contents |
| while ( ( pContent = pContent->pPrevContent ) != NULL ) |
| { |
| if ( pContent->IsVirgin() ) |
| pContent->SetState( SC_CAS_ACCEPTED ); |
| } |
| ScChangeActionContent* pEnd = pContent = this; |
| // reject subsequent contents |
| while ( ( pContent = pContent->pNextContent ) != NULL ) |
| { |
| // MatrixOrigin may have dependents, no dependency recursion needed |
| const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry(); |
| while ( pL ) |
| { |
| ScChangeAction* p = (ScChangeAction*) pL->GetAction(); |
| if ( p ) |
| p->SetRejected(); |
| pL = pL->GetNext(); |
| } |
| pContent->SetRejected(); |
| pEnd = pContent; |
| } |
| |
| if ( bOldest || pEnd != this ) |
| { // wenn nicht aeltester: ist es ueberhaupt ein anderer als der letzte? |
| ScRange aRange( aBigRange.aStart.MakeAddress() ); |
| const ScAddress& rPos = aRange.aStart; |
| |
| ScChangeActionContent* pNew = new ScChangeActionContent( aRange ); |
| pNew->SetOldValue( pDoc->GetCell( rPos ), pDoc, pDoc ); |
| |
| if ( bOldest ) |
| PutOldValueToDoc( pDoc, 0, 0 ); |
| else |
| PutNewValueToDoc( pDoc, 0, 0 ); |
| |
| pNew->SetRejectAction( bOldest ? GetActionNumber() : pEnd->GetActionNumber() ); |
| pNew->SetState( SC_CAS_ACCEPTED ); |
| if ( pRejectActions ) |
| pRejectActions->Push( pNew ); |
| else |
| { |
| pNew->SetNewValue( pDoc->GetCell( rPos ), pDoc ); |
| pTrack->Append( pNew ); |
| } |
| } |
| |
| if ( bOldest ) |
| SetRejected(); |
| else |
| SetState( SC_CAS_ACCEPTED ); |
| |
| return sal_True; |
| } |
| |
| |
| // static |
| void ScChangeActionContent::GetStringOfCell( String& rStr, |
| const ScBaseCell* pCell, const ScDocument* pDoc, const ScAddress& rPos ) |
| { |
| if ( pCell ) |
| { |
| if ( ScChangeActionContent::NeedsNumberFormat( pCell ) ) |
| GetStringOfCell( rStr, pCell, pDoc, pDoc->GetNumberFormat( rPos ) ); |
| else |
| GetStringOfCell( rStr, pCell, pDoc, 0 ); |
| } |
| else |
| rStr.Erase(); |
| } |
| |
| |
| // static |
| void ScChangeActionContent::GetStringOfCell( String& rStr, |
| const ScBaseCell* pCell, const ScDocument* pDoc, sal_uLong nFormat ) |
| { |
| if ( ScChangeActionContent::GetContentCellType( pCell ) ) |
| { |
| switch ( pCell->GetCellType() ) |
| { |
| case CELLTYPE_VALUE : |
| { |
| double nValue = ((ScValueCell*)pCell)->GetValue(); |
| pDoc->GetFormatTable()->GetInputLineString( nValue, nFormat, |
| rStr ); |
| } |
| break; |
| case CELLTYPE_STRING : |
| ((ScStringCell*)pCell)->GetString( rStr ); |
| break; |
| case CELLTYPE_EDIT : |
| ((ScEditCell*)pCell)->GetString( rStr ); |
| break; |
| case CELLTYPE_FORMULA : |
| ((ScFormulaCell*)pCell)->GetFormula( rStr ); |
| break; |
| default: |
| rStr.Erase(); |
| } |
| } |
| else |
| rStr.Erase(); |
| } |
| |
| |
| // static |
| ScChangeActionContentCellType ScChangeActionContent::GetContentCellType( const ScBaseCell* pCell ) |
| { |
| if ( pCell ) |
| { |
| switch ( pCell->GetCellType() ) |
| { |
| case CELLTYPE_VALUE : |
| case CELLTYPE_STRING : |
| case CELLTYPE_EDIT : |
| return SC_CACCT_NORMAL; |
| //break; |
| case CELLTYPE_FORMULA : |
| switch ( ((const ScFormulaCell*)pCell)->GetMatrixFlag() ) |
| { |
| case MM_NONE : |
| return SC_CACCT_NORMAL; |
| //break; |
| case MM_FORMULA : |
| case MM_FAKE : |
| return SC_CACCT_MATORG; |
| //break; |
| case MM_REFERENCE : |
| return SC_CACCT_MATREF; |
| //break; |
| } |
| return SC_CACCT_NORMAL; |
| //break; |
| default: |
| return SC_CACCT_NONE; |
| } |
| } |
| return SC_CACCT_NONE; |
| } |
| |
| |
| // static |
| sal_Bool ScChangeActionContent::NeedsNumberFormat( const ScBaseCell* pCell ) |
| { |
| return pCell && pCell->GetCellType() == CELLTYPE_VALUE; |
| } |
| |
| |
| // static |
| void ScChangeActionContent::SetValue( String& rStr, ScBaseCell*& pCell, |
| const ScAddress& rPos, const ScBaseCell* pOrgCell, |
| const ScDocument* pFromDoc, ScDocument* pToDoc ) |
| { |
| sal_uLong nFormat = NeedsNumberFormat( pOrgCell ) ? pFromDoc->GetNumberFormat( rPos ) : 0; |
| SetValue( rStr, pCell, nFormat, pOrgCell, pFromDoc, pToDoc ); |
| } |
| |
| |
| // static |
| void ScChangeActionContent::SetValue( String& rStr, ScBaseCell*& pCell, |
| sal_uLong nFormat, const ScBaseCell* pOrgCell, |
| const ScDocument* pFromDoc, ScDocument* pToDoc ) |
| { |
| rStr.Erase(); |
| if ( pCell ) |
| pCell->Delete(); |
| if ( ScChangeActionContent::GetContentCellType( pOrgCell ) ) |
| { |
| pCell = pOrgCell->CloneWithoutNote( *pToDoc ); |
| switch ( pOrgCell->GetCellType() ) |
| { |
| case CELLTYPE_VALUE : |
| { // z.B. Datum auch als solches merken |
| double nValue = ((ScValueCell*)pOrgCell)->GetValue(); |
| pFromDoc->GetFormatTable()->GetInputLineString( nValue, |
| nFormat, rStr ); |
| } |
| break; |
| case CELLTYPE_FORMULA : |
| ((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| else |
| pCell = NULL; |
| } |
| |
| |
| // static |
| void ScChangeActionContent::SetCell( String& rStr, ScBaseCell* pCell, |
| sal_uLong nFormat, const ScDocument* pDoc ) |
| { |
| rStr.Erase(); |
| if ( pCell ) |
| { |
| switch ( pCell->GetCellType() ) |
| { |
| case CELLTYPE_VALUE : |
| { // e.g. remember date as date string |
| double nValue = ((ScValueCell*)pCell)->GetValue(); |
| pDoc->GetFormatTable()->GetInputLineString( nValue, |
| nFormat, rStr ); |
| } |
| break; |
| case CELLTYPE_FORMULA : |
| ((ScFormulaCell*)pCell)->SetInChangeTrack( sal_True ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| } |
| |
| |
| void ScChangeActionContent::GetValueString( String& rStr, |
| const String& rValue, const ScBaseCell* pCell ) const |
| { |
| if ( !rValue.Len() ) |
| { |
| if ( pCell ) |
| { |
| switch ( pCell->GetCellType() ) |
| { |
| case CELLTYPE_STRING : |
| ((ScStringCell*)pCell)->GetString( rStr ); |
| break; |
| case CELLTYPE_EDIT : |
| ((ScEditCell*)pCell)->GetString( rStr ); |
| break; |
| case CELLTYPE_VALUE : // ist immer in rValue |
| rStr = rValue; |
| break; |
| case CELLTYPE_FORMULA : |
| GetFormulaString( rStr, (ScFormulaCell*) pCell ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| else |
| rStr.Erase(); |
| } |
| else |
| rStr = rValue; |
| } |
| |
| |
| void ScChangeActionContent::GetFormulaString( String& rStr, |
| const ScFormulaCell* pCell ) const |
| { |
| ScAddress aPos( aBigRange.aStart.MakeAddress() ); |
| if ( aPos == pCell->aPos || IsDeletedIn() ) |
| pCell->GetFormula( rStr ); |
| else |
| { |
| DBG_ERROR( "ScChangeActionContent::GetFormulaString: aPos != pCell->aPos" ); |
| ScFormulaCell* pNew = new ScFormulaCell( *pCell, *pCell->GetDocument(), aPos ); |
| pNew->GetFormula( rStr ); |
| delete pNew; |
| } |
| } |
| |
| |
| void ScChangeActionContent::PutOldValueToDoc( ScDocument* pDoc, |
| SCsCOL nDx, SCsROW nDy ) const |
| { |
| PutValueToDoc( pOldCell, aOldValue, pDoc, nDx, nDy ); |
| } |
| |
| |
| void ScChangeActionContent::PutNewValueToDoc( ScDocument* pDoc, |
| SCsCOL nDx, SCsROW nDy ) const |
| { |
| PutValueToDoc( pNewCell, aNewValue, pDoc, nDx, nDy ); |
| } |
| |
| |
| void ScChangeActionContent::PutValueToDoc( ScBaseCell* pCell, |
| const String& rValue, ScDocument* pDoc, SCsCOL nDx, SCsROW nDy ) const |
| { |
| ScAddress aPos( aBigRange.aStart.MakeAddress() ); |
| if ( nDx ) |
| aPos.IncCol( nDx ); |
| if ( nDy ) |
| aPos.IncRow( nDy ); |
| if ( !rValue.Len() ) |
| { |
| if ( pCell ) |
| { |
| switch ( pCell->GetCellType() ) |
| { |
| case CELLTYPE_VALUE : // ist immer in rValue |
| pDoc->SetString( aPos.Col(), aPos.Row(), aPos.Tab(), rValue ); |
| break; |
| default: |
| switch ( ScChangeActionContent::GetContentCellType( pCell ) ) |
| { |
| case SC_CACCT_MATORG : |
| { |
| SCCOL nC; |
| SCROW nR; |
| ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR ); |
| DBG_ASSERT( nC>0 && nR>0, "ScChangeActionContent::PutValueToDoc: MatColsRows?" ); |
| ScRange aRange( aPos ); |
| if ( nC > 1 ) |
| aRange.aEnd.IncCol( nC-1 ); |
| if ( nR > 1 ) |
| aRange.aEnd.IncRow( nR-1 ); |
| ScMarkData aDestMark; |
| aDestMark.SelectOneTable( aPos.Tab() ); |
| aDestMark.SetMarkArea( aRange ); |
| pDoc->InsertMatrixFormula( aPos.Col(), aPos.Row(), |
| aRange.aEnd.Col(), aRange.aEnd.Row(), |
| aDestMark, EMPTY_STRING, |
| ((const ScFormulaCell*)pCell)->GetCode() ); |
| } |
| break; |
| case SC_CACCT_MATREF : |
| // nothing |
| break; |
| default: |
| pDoc->PutCell( aPos, pCell->CloneWithoutNote( *pDoc ) ); |
| } |
| } |
| } |
| else |
| pDoc->PutCell( aPos, NULL ); |
| } |
| else |
| pDoc->SetString( aPos.Col(), aPos.Row(), aPos.Tab(), rValue ); |
| } |
| |
| |
| void lcl_InvalidateReference( ScToken& rTok, const ScBigAddress& rPos ) |
| { |
| ScSingleRefData& rRef1 = rTok.GetSingleRef(); |
| if ( rPos.Col() < 0 || MAXCOL < rPos.Col() ) |
| { |
| rRef1.nCol = SCCOL_MAX; |
| rRef1.nRelCol = SCCOL_MAX; |
| rRef1.SetColDeleted( sal_True ); |
| } |
| if ( rPos.Row() < 0 || MAXROW < rPos.Row() ) |
| { |
| rRef1.nRow = SCROW_MAX; |
| rRef1.nRelRow = SCROW_MAX; |
| rRef1.SetRowDeleted( sal_True ); |
| } |
| if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() ) |
| { |
| rRef1.nTab = SCTAB_MAX; |
| rRef1.nRelTab = SCTAB_MAX; |
| rRef1.SetTabDeleted( sal_True ); |
| } |
| if ( rTok.GetType() == formula::svDoubleRef ) |
| { |
| ScSingleRefData& rRef2 = rTok.GetDoubleRef().Ref2; |
| if ( rPos.Col() < 0 || MAXCOL < rPos.Col() ) |
| { |
| rRef2.nCol = SCCOL_MAX; |
| rRef2.nRelCol = SCCOL_MAX; |
| rRef2.SetColDeleted( sal_True ); |
| } |
| if ( rPos.Row() < 0 || MAXROW < rPos.Row() ) |
| { |
| rRef2.nRow = SCROW_MAX; |
| rRef2.nRelRow = SCROW_MAX; |
| rRef2.SetRowDeleted( sal_True ); |
| } |
| if ( rPos.Tab() < 0 || MAXTAB < rPos.Tab() ) |
| { |
| rRef2.nTab = SCTAB_MAX; |
| rRef2.nRelTab = SCTAB_MAX; |
| rRef2.SetTabDeleted( sal_True ); |
| } |
| } |
| } |
| |
| |
| void ScChangeActionContent::UpdateReference( const ScChangeTrack* pTrack, |
| UpdateRefMode eMode, const ScBigRange& rRange, |
| sal_Int32 nDx, sal_Int32 nDy, sal_Int32 nDz ) |
| { |
| SCSIZE nOldSlot = ScChangeTrack::ComputeContentSlot( aBigRange.aStart.Row() ); |
| ScRefUpdate::Update( eMode, rRange, nDx, nDy, nDz, aBigRange ); |
| SCSIZE nNewSlot = ScChangeTrack::ComputeContentSlot( aBigRange.aStart.Row() ); |
| if ( nNewSlot != nOldSlot ) |
| { |
| RemoveFromSlot(); |
| InsertInSlot( &(pTrack->GetContentSlots()[nNewSlot]) ); |
| } |
| |
| if ( pTrack->IsInDelete() && !pTrack->IsInDeleteTop() ) |
| return ; // Formeln nur kompletten Bereich updaten |
| |
| sal_Bool bOldFormula = ( pOldCell && pOldCell->GetCellType() == CELLTYPE_FORMULA ); |
| sal_Bool bNewFormula = ( pNewCell && pNewCell->GetCellType() == CELLTYPE_FORMULA ); |
| if ( bOldFormula || bNewFormula ) |
| { // via ScFormulaCell UpdateReference anpassen (dort) |
| if ( pTrack->IsInDelete() ) |
| { |
| const ScRange& rDelRange = pTrack->GetInDeleteRange(); |
| if ( nDx > 0 ) |
| nDx = rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1; |
| else if ( nDx < 0 ) |
| nDx = -(rDelRange.aEnd.Col() - rDelRange.aStart.Col() + 1); |
| if ( nDy > 0 ) |
| nDy = rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1; |
| else if ( nDy < 0 ) |
| nDy = -(rDelRange.aEnd.Row() - rDelRange.aStart.Row() + 1); |
| if ( nDz > 0 ) |
| nDz = rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1; |
| else if ( nDz < 0 ) |
| nDz = -(rDelRange.aEnd.Tab() - rDelRange.aStart.Tab() + 1); |
| } |
| ScBigRange aTmpRange( rRange ); |
| switch ( eMode ) |
| { |
| case URM_INSDEL : |
| if ( nDx < 0 || nDy < 0 || nDz < 0 ) |
| { // Delete startet dort hinter geloeschtem Bereich, |
| // Position wird dort angepasst. |
| if ( nDx ) |
| aTmpRange.aStart.IncCol( -nDx ); |
| if ( nDy ) |
| aTmpRange.aStart.IncRow( -nDy ); |
| if ( nDz ) |
| aTmpRange.aStart.IncTab( -nDz ); |
| } |
| break; |
| case URM_MOVE : |
| // Move ist hier Quelle, dort Ziel, |
| // Position muss vorher angepasst sein. |
| if ( bOldFormula ) |
| ((ScFormulaCell*)pOldCell)->aPos = aBigRange.aStart.MakeAddress(); |
| if ( bNewFormula ) |
| ((ScFormulaCell*)pNewCell)->aPos = aBigRange.aStart.MakeAddress(); |
| if ( nDx ) |
| { |
| aTmpRange.aStart.IncCol( nDx ); |
| aTmpRange.aEnd.IncCol( nDx ); |
| } |
| if ( nDy ) |
| { |
| aTmpRange.aStart.IncRow( nDy ); |
| aTmpRange.aEnd.IncRow( nDy ); |
| } |
| if ( nDz ) |
| { |
| aTmpRange.aStart.IncTab( nDz ); |
| aTmpRange.aEnd.IncTab( nDz ); |
| } |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| ScRange aRange( aTmpRange.MakeRange() ); |
| if ( bOldFormula ) |
| ((ScFormulaCell*)pOldCell)->UpdateReference( eMode, aRange, |
| (SCsCOL) nDx, (SCsROW) nDy, (SCsTAB) nDz, NULL ); |
| if ( bNewFormula ) |
| ((ScFormulaCell*)pNewCell)->UpdateReference( eMode, aRange, |
| (SCsCOL) nDx, (SCsROW) nDy, (SCsTAB) nDz, NULL ); |
| if ( !aBigRange.aStart.IsValid( pTrack->GetDocument() ) ) |
| { //! HACK! |
| //! UpdateReference kann nicht mit Positionen ausserhalb des |
| //! Dokuments umgehen, deswegen alles auf #REF! setzen |
| //2do: make it possible! das bedeutet grossen Umbau von ScAddress etc.! |
| const ScBigAddress& rPos = aBigRange.aStart; |
| if ( bOldFormula ) |
| { |
| ScToken* t; |
| ScTokenArray* pArr = ((ScFormulaCell*)pOldCell)->GetCode(); |
| pArr->Reset(); |
| while ( ( t = static_cast<ScToken*>(pArr->GetNextReference()) ) != NULL ) |
| lcl_InvalidateReference( *t, rPos ); |
| pArr->Reset(); |
| while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL ) |
| lcl_InvalidateReference( *t, rPos ); |
| } |
| if ( bNewFormula ) |
| { |
| ScToken* t; |
| ScTokenArray* pArr = ((ScFormulaCell*)pNewCell)->GetCode(); |
| pArr->Reset(); |
| while ( ( t = static_cast<ScToken*>(pArr->GetNextReference()) ) != NULL ) |
| lcl_InvalidateReference( *t, rPos ); |
| pArr->Reset(); |
| while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL ) |
| lcl_InvalidateReference( *t, rPos ); |
| } |
| } |
| } |
| } |
| |
| |
| // --- ScChangeActionReject ------------------------------------------------ |
| |
| ScChangeActionReject::ScChangeActionReject(const sal_uLong nActionNumber, const ScChangeActionState eStateP, const sal_uLong nRejectingNumber, |
| const ScBigRange& aBigRangeP, const String& aUserP, const DateTime& aDateTimeP, const String& sComment) |
| : |
| ScChangeAction(SC_CAT_CONTENT, aBigRangeP, nActionNumber, nRejectingNumber, eStateP, aDateTimeP, aUserP, sComment) |
| { |
| } |
| |
| |
| // --- ScChangeTrack ------------------------------------------------------- |
| |
| IMPL_FIXEDMEMPOOL_NEWDEL( ScChangeTrackMsgInfo, 16, 16 ) |
| |
| const SCROW ScChangeTrack::nContentRowsPerSlot = InitContentRowsPerSlot(); |
| const SCSIZE ScChangeTrack::nContentSlots = |
| (MAXROWCOUNT) / InitContentRowsPerSlot() + 2; |
| |
| // static |
| SCROW ScChangeTrack::InitContentRowsPerSlot() |
| { |
| const SCSIZE nMaxSlots = 0xffe0 / sizeof( ScChangeActionContent* ) - 2; |
| SCROW nRowsPerSlot = (MAXROWCOUNT) / nMaxSlots; |
| if ( nRowsPerSlot * nMaxSlots < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) ) |
| ++nRowsPerSlot; |
| return nRowsPerSlot; |
| } |
| |
| |
| ScChangeTrack::ScChangeTrack( ScDocument* pDocP ) : |
| pDoc( pDocP ) |
| { |
| Init(); |
| SC_MOD()->GetUserOptions().AddListener(this); |
| |
| ppContentSlots = new ScChangeActionContent* [ nContentSlots ]; |
| memset( ppContentSlots, 0, nContentSlots * sizeof( ScChangeActionContent* ) ); |
| } |
| |
| ScChangeTrack::ScChangeTrack( ScDocument* pDocP, const ScStrCollection& aTempUserCollection) : |
| aUserCollection(aTempUserCollection), |
| pDoc( pDocP ) |
| { |
| Init(); |
| SC_MOD()->GetUserOptions().AddListener(this); |
| ppContentSlots = new ScChangeActionContent* [ nContentSlots ]; |
| memset( ppContentSlots, 0, nContentSlots * sizeof( ScChangeActionContent* ) ); |
| } |
| |
| ScChangeTrack::~ScChangeTrack() |
| { |
| SC_MOD()->GetUserOptions().RemoveListener(this); |
| DtorClear(); |
| delete [] ppContentSlots; |
| } |
| |
| |
| void ScChangeTrack::Init() |
| { |
| pFirst = NULL; |
| pLast = NULL; |
| pFirstGeneratedDelContent = NULL; |
| pLastCutMove = NULL; |
| pLinkInsertCol = NULL; |
| pLinkInsertRow = NULL; |
| pLinkInsertTab = NULL; |
| pLinkMove = NULL; |
| pBlockModifyMsg = NULL; |
| nActionMax = 0; |
| nGeneratedMin = SC_CHGTRACK_GENERATED_START; |
| nMarkLastSaved = 0; |
| nStartLastCut = 0; |
| nEndLastCut = 0; |
| nLastMerge = 0; |
| eMergeState = SC_CTMS_NONE; |
| nLoadedFileFormatVersion = SC_CHGTRACK_FILEFORMAT; |
| bLoadSave = sal_False; |
| bInDelete = sal_False; |
| bInDeleteTop = sal_False; |
| bInDeleteUndo = sal_False; |
| bInPasteCut = sal_False; |
| bUseFixDateTime = sal_False; |
| bTime100thSeconds = sal_True; |
| |
| const SvtUserOptions& rUserOpt = SC_MOD()->GetUserOptions(); |
| aUser = rUserOpt.GetFirstName(); |
| aUser += ' '; |
| aUser += (String)rUserOpt.GetLastName(); |
| aUserCollection.Insert( new StrData( aUser ) ); |
| } |
| |
| |
| void ScChangeTrack::DtorClear() |
| { |
| ScChangeAction* p; |
| ScChangeAction* pNext; |
| for ( p = GetFirst(); p; p = pNext ) |
| { |
| pNext = p->GetNext(); |
| delete p; |
| } |
| for ( p = pFirstGeneratedDelContent; p; p = pNext ) |
| { |
| pNext = p->GetNext(); |
| delete p; |
| } |
| for ( p = aPasteCutTable.First(); p; p = aPasteCutTable.Next() ) |
| { |
| delete p; |
| } |
| delete pLastCutMove; |
| ClearMsgQueue(); |
| } |
| |
| |
| void ScChangeTrack::ClearMsgQueue() |
| { |
| if ( pBlockModifyMsg ) |
| { |
| delete pBlockModifyMsg; |
| pBlockModifyMsg = NULL; |
| } |
| ScChangeTrackMsgInfo* pMsgInfo; |
| while ( ( pMsgInfo = aMsgStackTmp.Pop() ) != NULL ) |
| delete pMsgInfo; |
| while ( ( pMsgInfo = aMsgStackFinal.Pop() ) != NULL ) |
| delete pMsgInfo; |
| while ( ( pMsgInfo = aMsgQueue.Get() ) != NULL ) |
| delete pMsgInfo; |
| } |
| |
| |
| void ScChangeTrack::Clear() |
| { |
| DtorClear(); |
| aTable.Clear(); |
| aGeneratedTable.Clear(); |
| aPasteCutTable.Clear(); |
| aUserCollection.FreeAll(); |
| aUser.Erase(); |
| Init(); |
| } |
| |
| |
| void __EXPORT ScChangeTrack::ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 ) |
| { |
| if ( !pDoc->IsInDtorClear() ) |
| { |
| const SvtUserOptions& rUserOptions = SC_MOD()->GetUserOptions(); |
| sal_uInt16 nOldCount = aUserCollection.GetCount(); |
| |
| String aStr( rUserOptions.GetFirstName() ); |
| aStr += ' '; |
| aStr += (String)rUserOptions.GetLastName(); |
| SetUser( aStr ); |
| |
| if ( aUserCollection.GetCount() != nOldCount ) |
| { |
| // New user in collection -> have to repaint because |
| // colors may be different now (#106697#). |
| // (Has to be done in the Notify handler, to be sure |
| // the user collection has already been updated) |
| |
| SfxObjectShell* pDocSh = pDoc->GetDocumentShell(); |
| if (pDocSh) |
| pDocSh->Broadcast( ScPaintHint( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB), PAINT_GRID ) ); |
| } |
| } |
| } |
| |
| |
| void ScChangeTrack::SetUser( const String& rUser ) |
| { |
| if ( IsLoadSave() ) |
| return ; // nicht die Collection zerschiessen |
| |
| aUser = rUser; |
| StrData* pStrData = new StrData( aUser ); |
| if ( !aUserCollection.Insert( pStrData ) ) |
| delete pStrData; |
| } |
| |
| |
| void ScChangeTrack::StartBlockModify( ScChangeTrackMsgType eMsgType, |
| sal_uLong nStartAction ) |
| { |
| if ( aModifiedLink.IsSet() ) |
| { |
| if ( pBlockModifyMsg ) |
| aMsgStackTmp.Push( pBlockModifyMsg ); // Block im Block |
| pBlockModifyMsg = new ScChangeTrackMsgInfo; |
| pBlockModifyMsg->eMsgType = eMsgType; |
| pBlockModifyMsg->nStartAction = nStartAction; |
| } |
| } |
| |
| |
| void ScChangeTrack::EndBlockModify( sal_uLong nEndAction ) |
| { |
| if ( aModifiedLink.IsSet() ) |
| { |
| if ( pBlockModifyMsg ) |
| { |
| if ( pBlockModifyMsg->nStartAction <= nEndAction ) |
| { |
| pBlockModifyMsg->nEndAction = nEndAction; |
| // Blocks in Blocks aufgeloest |
| aMsgStackFinal.Push( pBlockModifyMsg ); |
| } |
| else |
| delete pBlockModifyMsg; |
| pBlockModifyMsg = aMsgStackTmp.Pop(); // evtl. Block im Block |
| } |
| if ( !pBlockModifyMsg ) |
| { |
| sal_Bool bNew = sal_False; |
| ScChangeTrackMsgInfo* pMsg; |
| while ( ( pMsg = aMsgStackFinal.Pop() ) != NULL ) |
| { |
| aMsgQueue.Put( pMsg ); |
| bNew = sal_True; |
| } |
| if ( bNew ) |
| aModifiedLink.Call( this ); |
| } |
| } |
| } |
| |
| |
| void ScChangeTrack::NotifyModified( ScChangeTrackMsgType eMsgType, |
| sal_uLong nStartAction, sal_uLong nEndAction ) |
| { |
| if ( aModifiedLink.IsSet() ) |
| { |
| if ( !pBlockModifyMsg || pBlockModifyMsg->eMsgType != eMsgType || |
| (IsGenerated( nStartAction ) && |
| (eMsgType == SC_CTM_APPEND || eMsgType == SC_CTM_REMOVE)) ) |
| { // Append innerhalb von Append z.B. nicht |
| StartBlockModify( eMsgType, nStartAction ); |
| EndBlockModify( nEndAction ); |
| } |
| } |
| } |
| |
| |
| void ScChangeTrack::MasterLinks( ScChangeAction* pAppend ) |
| { |
| ScChangeActionType eType = pAppend->GetType(); |
| |
| if ( eType == SC_CAT_CONTENT ) |
| { |
| if ( !IsGenerated( pAppend->GetActionNumber() ) ) |
| { |
| SCSIZE nSlot = ComputeContentSlot( |
| pAppend->GetBigRange().aStart.Row() ); |
| ((ScChangeActionContent*)pAppend)->InsertInSlot( |
| &ppContentSlots[nSlot] ); |
| } |
| return ; |
| } |
| |
| if ( pAppend->IsRejecting() ) |
| return ; // Rejects haben keine Abhaengigkeiten |
| |
| switch ( eType ) |
| { |
| case SC_CAT_INSERT_COLS : |
| { |
| ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( |
| &pLinkInsertCol, pAppend ); |
| pAppend->AddLink( NULL, pLink ); |
| } |
| break; |
| case SC_CAT_INSERT_ROWS : |
| { |
| ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( |
| &pLinkInsertRow, pAppend ); |
| pAppend->AddLink( NULL, pLink ); |
| } |
| break; |
| case SC_CAT_INSERT_TABS : |
| { |
| ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( |
| &pLinkInsertTab, pAppend ); |
| pAppend->AddLink( NULL, pLink ); |
| } |
| break; |
| case SC_CAT_MOVE : |
| { |
| ScChangeActionLinkEntry* pLink = new ScChangeActionLinkEntry( |
| &pLinkMove, pAppend ); |
| pAppend->AddLink( NULL, pLink ); |
| } |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| |
| |
| void ScChangeTrack::AppendLoaded( ScChangeAction* pAppend ) |
| { |
| aTable.Insert( pAppend->GetActionNumber(), pAppend ); |
| if ( !pLast ) |
| pFirst = pLast = pAppend; |
| else |
| { |
| pLast->pNext = pAppend; |
| pAppend->pPrev = pLast; |
| pLast = pAppend; |
| } |
| MasterLinks( pAppend ); |
| } |
| |
| |
| void ScChangeTrack::Append( ScChangeAction* pAppend, sal_uLong nAction ) |
| { |
| if ( nActionMax < nAction ) |
| nActionMax = nAction; |
| pAppend->SetUser( aUser ); |
| if ( bUseFixDateTime ) |
| pAppend->SetDateTimeUTC( aFixDateTime ); |
| pAppend->SetActionNumber( nAction ); |
| aTable.Insert( nAction, pAppend ); |
| // UpdateReference Inserts vor Dependencies. |
| // Delete rejectendes Insert hatte UpdateReference mit Delete-Undo. |
| // UpdateReference auch wenn pLast==NULL, weil pAppend ein Delete sein |
| // kann, dass DelContents generiert haben kann |
| if ( pAppend->IsInsertType() && !pAppend->IsRejecting() ) |
| UpdateReference( pAppend, sal_False ); |
| if ( !pLast ) |
| pFirst = pLast = pAppend; |
| else |
| { |
| pLast->pNext = pAppend; |
| pAppend->pPrev = pLast; |
| pLast = pAppend; |
| Dependencies( pAppend ); |
| } |
| // UpdateReference Inserts nicht nach Dependencies. |
| // Move rejectendes Move hatte UpdateReference mit Move-Undo, Inhalt in |
| // ToRange nicht deleten. |
| if ( !pAppend->IsInsertType() && |
| !(pAppend->GetType() == SC_CAT_MOVE && pAppend->IsRejecting()) ) |
| UpdateReference( pAppend, sal_False ); |
| MasterLinks( pAppend ); |
| |
| if ( aModifiedLink.IsSet() ) |
| { |
| NotifyModified( SC_CTM_APPEND, nAction, nAction ); |
| if ( pAppend->GetType() == SC_CAT_CONTENT ) |
| { |
| ScChangeActionContent* pContent = (ScChangeActionContent*) pAppend; |
| if ( ( pContent = pContent->GetPrevContent() ) != NULL ) |
| { |
| sal_uLong nMod = pContent->GetActionNumber(); |
| NotifyModified( SC_CTM_CHANGE, nMod, nMod ); |
| } |
| } |
| else |
| NotifyModified( SC_CTM_CHANGE, pFirst->GetActionNumber(), |
| pLast->GetActionNumber() ); |
| } |
| } |
| |
| |
| void ScChangeTrack::Append( ScChangeAction* pAppend ) |
| { |
| Append( pAppend, ++nActionMax ); |
| } |
| |
| |
| void ScChangeTrack::AppendDeleteRange( const ScRange& rRange, |
| ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction, SCsTAB nDz ) |
| { |
| nStartAction = GetActionMax() + 1; |
| AppendDeleteRange( rRange, pRefDoc, nDz, 0 ); |
| nEndAction = GetActionMax(); |
| } |
| |
| |
| void ScChangeTrack::AppendDeleteRange( const ScRange& rRange, |
| ScDocument* pRefDoc, SCsTAB nDz, sal_uLong nRejectingInsert ) |
| { |
| SetInDeleteRange( rRange ); |
| StartBlockModify( SC_CTM_APPEND, GetActionMax() + 1 ); |
| SCCOL nCol1; |
| SCROW nRow1; |
| SCTAB nTab1; |
| SCCOL nCol2; |
| SCROW nRow2; |
| SCTAB nTab2; |
| rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); |
| for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ ) |
| { |
| if ( !pRefDoc || nTab < pRefDoc->GetTableCount() ) |
| { |
| if ( nCol1 == 0 && nCol2 == MAXCOL ) |
| { // ganze Zeilen und/oder Tabellen |
| if ( nRow1 == 0 && nRow2 == MAXROW ) |
| { // ganze Tabellen |
| //2do: geht nicht auch komplette Tabelle als ganzes? |
| ScRange aRange( 0, 0, nTab, 0, MAXROW, nTab ); |
| for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ ) |
| { // spaltenweise ist weniger als zeilenweise |
| aRange.aStart.SetCol( nCol ); |
| aRange.aEnd.SetCol( nCol ); |
| if ( nCol == nCol2 ) |
| SetInDeleteTop( sal_True ); |
| AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0, |
| nTab-nTab1 + nDz, nRejectingInsert ); |
| } |
| //! immer noch InDeleteTop |
| AppendOneDeleteRange( rRange, pRefDoc, 0, 0, |
| nTab-nTab1 + nDz, nRejectingInsert ); |
| } |
| else |
| { // ganze Zeilen |
| ScRange aRange( 0, 0, nTab, MAXCOL, 0, nTab ); |
| for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ ) |
| { |
| aRange.aStart.SetRow( nRow ); |
| aRange.aEnd.SetRow( nRow ); |
| if ( nRow == nRow2 ) |
| SetInDeleteTop( sal_True ); |
| AppendOneDeleteRange( aRange, pRefDoc, 0, nRow-nRow1, |
| 0, nRejectingInsert ); |
| } |
| } |
| } |
| else if ( nRow1 == 0 && nRow2 == MAXROW ) |
| { // ganze Spalten |
| ScRange aRange( 0, 0, nTab, 0, MAXROW, nTab ); |
| for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ ) |
| { |
| aRange.aStart.SetCol( nCol ); |
| aRange.aEnd.SetCol( nCol ); |
| if ( nCol == nCol2 ) |
| SetInDeleteTop( sal_True ); |
| AppendOneDeleteRange( aRange, pRefDoc, nCol-nCol1, 0, |
| 0, nRejectingInsert ); |
| } |
| } |
| else |
| { |
| DBG_ERROR( "ScChangeTrack::AppendDeleteRange: Block not supported!" ); |
| } |
| SetInDeleteTop( sal_False ); |
| } |
| } |
| EndBlockModify( GetActionMax() ); |
| } |
| |
| |
| void ScChangeTrack::AppendOneDeleteRange( const ScRange& rOrgRange, |
| ScDocument* pRefDoc, SCsCOL nDx, SCsROW nDy, SCsTAB nDz, |
| sal_uLong nRejectingInsert ) |
| { |
| ScRange aTrackRange( rOrgRange ); |
| if ( nDx ) |
| { |
| aTrackRange.aStart.IncCol( -nDx ); |
| aTrackRange.aEnd.IncCol( -nDx ); |
| } |
| if ( nDy ) |
| { |
| aTrackRange.aStart.IncRow( -nDy ); |
| aTrackRange.aEnd.IncRow( -nDy ); |
| } |
| if ( nDz ) |
| { |
| aTrackRange.aStart.IncTab( -nDz ); |
| aTrackRange.aEnd.IncTab( -nDz ); |
| } |
| ScChangeActionDel* pAct = new ScChangeActionDel( aTrackRange, nDx, nDy, |
| this ); |
| // TabDelete keine Contents, sind in einzelnen Spalten |
| if ( !(rOrgRange.aStart.Col() == 0 && rOrgRange.aStart.Row() == 0 && |
| rOrgRange.aEnd.Col() == MAXCOL && rOrgRange.aEnd.Row() == MAXROW) ) |
| LookUpContents( rOrgRange, pRefDoc, -nDx, -nDy, -nDz ); |
| if ( nRejectingInsert ) |
| { |
| pAct->SetRejectAction( nRejectingInsert ); |
| pAct->SetState( SC_CAS_ACCEPTED ); |
| } |
| Append( pAct ); |
| } |
| |
| |
| void ScChangeTrack::LookUpContents( const ScRange& rOrgRange, |
| ScDocument* pRefDoc, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) |
| { |
| if ( pRefDoc ) |
| { |
| ScAddress aPos; |
| ScBigAddress aBigPos; |
| ScCellIterator aIter( pRefDoc, rOrgRange ); |
| ScBaseCell* pCell = aIter.GetFirst(); |
| while ( pCell ) |
| { |
| if ( ScChangeActionContent::GetContentCellType( pCell ) ) |
| { |
| aBigPos.Set( aIter.GetCol() + nDx, aIter.GetRow() + nDy, |
| aIter.GetTab() + nDz ); |
| ScChangeActionContent* pContent = SearchContentAt( aBigPos, NULL ); |
| if ( !pContent ) |
| { // nicht getrackte Contents |
| aPos.Set( aIter.GetCol() + nDx, aIter.GetRow() + nDy, |
| aIter.GetTab() + nDz ); |
| GenerateDelContent( aPos, pCell, pRefDoc ); |
| //! der Content wird hier _nicht_ per AddContent hinzugefuegt, |
| //! sondern in UpdateReference, um z.B. auch kreuzende Deletes |
| //! korrekt zu erfassen |
| } |
| } |
| pCell = aIter.GetNext(); |
| } |
| } |
| } |
| |
| |
| void ScChangeTrack::AppendMove( const ScRange& rFromRange, |
| const ScRange& rToRange, ScDocument* pRefDoc ) |
| { |
| ScChangeActionMove* pAct = new ScChangeActionMove( rFromRange, rToRange, this ); |
| LookUpContents( rToRange, pRefDoc, 0, 0, 0 ); // ueberschriebene Contents |
| Append( pAct ); |
| } |
| |
| |
| // static |
| sal_Bool ScChangeTrack::IsMatrixFormulaRangeDifferent( const ScBaseCell* pOldCell, |
| const ScBaseCell* pNewCell ) |
| { |
| SCCOL nC1, nC2; |
| SCROW nR1, nR2; |
| nC1 = nC2 = 0; |
| nR1 = nR2 = 0; |
| if ( pOldCell && (pOldCell->GetCellType() == CELLTYPE_FORMULA) && |
| ((const ScFormulaCell*)pOldCell)->GetMatrixFlag() == MM_FORMULA ) |
| ((const ScFormulaCell*)pOldCell)->GetMatColsRows( nC1, nR1 ); |
| if ( pNewCell && (pNewCell->GetCellType() == CELLTYPE_FORMULA) && |
| ((const ScFormulaCell*)pNewCell)->GetMatrixFlag() == MM_FORMULA ) |
| ((const ScFormulaCell*)pNewCell)->GetMatColsRows( nC1, nR1 ); |
| return nC1 != nC2 || nR1 != nR2; |
| } |
| |
| |
| void ScChangeTrack::AppendContent( const ScAddress& rPos, |
| const String& rNewValue, ScBaseCell* pOldCell ) |
| { |
| String aOldValue; |
| ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pDoc, rPos ); |
| if ( aOldValue != rNewValue || |
| IsMatrixFormulaRangeDifferent( pOldCell, NULL ) ) |
| { // nur wirkliche Aenderung tracken |
| ScRange aRange( rPos ); |
| ScChangeActionContent* pAct = new ScChangeActionContent( aRange ); |
| pAct->SetOldValue( pOldCell, pDoc, pDoc ); |
| pAct->SetNewValue( rNewValue, pDoc ); |
| Append( pAct ); |
| } |
| } |
| |
| |
| void ScChangeTrack::AppendContent( const ScAddress& rPos, |
| const ScBaseCell* pOldCell, sal_uLong nOldFormat, ScDocument* pRefDoc ) |
| { |
| if ( !pRefDoc ) |
| pRefDoc = pDoc; |
| String aOldValue; |
| ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pRefDoc, nOldFormat ); |
| String aNewValue; |
| ScBaseCell* pNewCell = pDoc->GetCell( rPos ); |
| ScChangeActionContent::GetStringOfCell( aNewValue, pNewCell, pDoc, rPos ); |
| if ( aOldValue != aNewValue || |
| IsMatrixFormulaRangeDifferent( pOldCell, pNewCell ) ) |
| { // nur wirkliche Aenderung tracken |
| ScRange aRange( rPos ); |
| ScChangeActionContent* pAct = new ScChangeActionContent( aRange ); |
| pAct->SetOldValue( pOldCell, pRefDoc, pDoc, nOldFormat ); |
| pAct->SetNewValue( pNewCell, pDoc ); |
| Append( pAct ); |
| } |
| } |
| |
| |
| void ScChangeTrack::AppendContent( const ScAddress& rPos, |
| ScDocument* pRefDoc ) |
| { |
| String aOldValue; |
| ScBaseCell* pOldCell = pRefDoc->GetCell( rPos ); |
| ScChangeActionContent::GetStringOfCell( aOldValue, pOldCell, pRefDoc, rPos ); |
| String aNewValue; |
| ScBaseCell* pNewCell = pDoc->GetCell( rPos ); |
| ScChangeActionContent::GetStringOfCell( aNewValue, pNewCell, pDoc, rPos ); |
| if ( aOldValue != aNewValue || |
| IsMatrixFormulaRangeDifferent( pOldCell, pNewCell ) ) |
| { // nur wirkliche Aenderung tracken |
| ScRange aRange( rPos ); |
| ScChangeActionContent* pAct = new ScChangeActionContent( aRange ); |
| pAct->SetOldValue( pOldCell, pRefDoc, pDoc ); |
| pAct->SetNewValue( pNewCell, pDoc ); |
| Append( pAct ); |
| } |
| } |
| |
| |
| void ScChangeTrack::AppendContent( const ScAddress& rPos, |
| const ScBaseCell* pOldCell ) |
| { |
| if ( ScChangeActionContent::NeedsNumberFormat( pOldCell ) ) |
| AppendContent( rPos, pOldCell, pDoc->GetNumberFormat( rPos ), pDoc ); |
| else |
| AppendContent( rPos, pOldCell, 0, pDoc ); |
| } |
| |
| |
| void ScChangeTrack::SetLastCutMoveRange( const ScRange& rRange, |
| ScDocument* pRefDoc ) |
| { |
| if ( pLastCutMove ) |
| { |
| // ToRange nicht mit Deletes linken und nicht in der Groesse aendern, |
| // eigentlich unnoetig, da ein Delete vorher in |
| // ScViewFunc::PasteFromClip ein ResetLastCut ausloest |
| ScBigRange& r = pLastCutMove->GetBigRange(); |
| r.aEnd.SetCol( -1 ); |
| r.aEnd.SetRow( -1 ); |
| r.aEnd.SetTab( -1 ); |
| r.aStart.SetCol( -1 - (rRange.aEnd.Col() - rRange.aStart.Col()) ); |
| r.aStart.SetRow( -1 - (rRange.aEnd.Row() - rRange.aStart.Row()) ); |
| r.aStart.SetTab( -1 - (rRange.aEnd.Tab() - rRange.aStart.Tab()) ); |
| // zu ueberschreibende Contents im FromRange |
| LookUpContents( rRange, pRefDoc, 0, 0, 0 ); |
| } |
| } |
| |
| |
| void ScChangeTrack::AppendContentRange( const ScRange& rRange, |
| ScDocument* pRefDoc, sal_uLong& nStartAction, sal_uLong& nEndAction, |
| ScChangeActionClipMode eClipMode ) |
| { |
| if ( eClipMode == SC_CACM_CUT ) |
| { |
| ResetLastCut(); |
| pLastCutMove = new ScChangeActionMove( rRange, rRange, this ); |
| SetLastCutMoveRange( rRange, pRefDoc ); |
| } |
| SCCOL nCol1; |
| SCROW nRow1; |
| SCTAB nTab1; |
| SCCOL nCol2; |
| SCROW nRow2; |
| SCTAB nTab2; |
| rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); |
| sal_Bool bDoContents; |
| if ( eClipMode == SC_CACM_PASTE && HasLastCut() ) |
| { |
| bDoContents = sal_False; |
| SetInPasteCut( sal_True ); |
| // Paste und Cut abstimmen, Paste kann groesserer Range sein |
| ScRange aRange( rRange ); |
| ScBigRange& r = pLastCutMove->GetBigRange(); |
| SCCOL nTmpCol; |
| if ( (nTmpCol = (SCCOL) (r.aEnd.Col() - r.aStart.Col())) != (nCol2 - nCol1) ) |
| { |
| aRange.aEnd.SetCol( aRange.aStart.Col() + nTmpCol ); |
| nCol1 += nTmpCol + 1; |
| bDoContents = sal_True; |
| } |
| SCROW nTmpRow; |
| if ( (nTmpRow = (SCROW) (r.aEnd.Row() - r.aStart.Row())) != (nRow2 - nRow1) ) |
| { |
| aRange.aEnd.SetRow( aRange.aStart.Row() + nTmpRow ); |
| nRow1 += nTmpRow + 1; |
| bDoContents = sal_True; |
| } |
| SCTAB nTmpTab; |
| if ( (nTmpTab = (SCTAB) (r.aEnd.Tab() - r.aStart.Tab())) != (nTab2 - nTab1) ) |
| { |
| aRange.aEnd.SetTab( aRange.aStart.Tab() + nTmpTab ); |
| nTab1 += nTmpTab + 1; |
| bDoContents = sal_True; |
| } |
| r = aRange; |
| Undo( nStartLastCut, nEndLastCut ); // hier werden sich die Cuts gemerkt |
| //! StartAction erst nach Undo |
| nStartAction = GetActionMax() + 1; |
| StartBlockModify( SC_CTM_APPEND, nStartAction ); |
| // zu ueberschreibende Contents im ToRange |
| LookUpContents( aRange, pRefDoc, 0, 0, 0 ); |
| pLastCutMove->SetStartLastCut( nStartLastCut ); |
| pLastCutMove->SetEndLastCut( nEndLastCut ); |
| Append( pLastCutMove ); |
| pLastCutMove = NULL; |
| ResetLastCut(); |
| SetInPasteCut( sal_False ); |
| } |
| else |
| { |
| bDoContents = sal_True; |
| nStartAction = GetActionMax() + 1; |
| StartBlockModify( SC_CTM_APPEND, nStartAction ); |
| } |
| if ( bDoContents ) |
| { |
| ScAddress aPos; |
| for ( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ ) |
| { |
| aPos.SetTab( nTab ); |
| for ( SCCOL nCol = nCol1; nCol <= nCol2; nCol++ ) |
| { |
| aPos.SetCol( nCol ); |
| for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ ) |
| { |
| aPos.SetRow( nRow ); |
| AppendContent( aPos, pRefDoc ); |
| } |
| } |
| } |
| } |
| nEndAction = GetActionMax(); |
| EndBlockModify( nEndAction ); |
| if ( eClipMode == SC_CACM_CUT ) |
| { |
| nStartLastCut = nStartAction; |
| nEndLastCut = nEndAction; |
| } |
| } |
| |
| |
| void ScChangeTrack::AppendContentsIfInRefDoc( ScDocument* pRefDoc, |
| sal_uLong& nStartAction, sal_uLong& nEndAction ) |
| { |
| ScDocumentIterator aIter( pRefDoc, 0, MAXTAB ); |
| if ( aIter.GetFirst() ) |
| { |
| nStartAction = GetActionMax() + 1; |
| StartBlockModify( SC_CTM_APPEND, nStartAction ); |
| SvNumberFormatter* pFormatter = pRefDoc->GetFormatTable(); |
| do |
| { |
| SCCOL nCol; |
| SCROW nRow; |
| SCTAB nTab; |
| aIter.GetPos( nCol, nRow, nTab ); |
| ScAddress aPos( nCol, nRow, nTab ); |
| AppendContent( aPos, aIter.GetCell(), |
| aIter.GetPattern()->GetNumberFormat( pFormatter ), pRefDoc ); |
| } while ( aIter.GetNext() ); |
| nEndAction = GetActionMax(); |
| EndBlockModify( nEndAction ); |
| } |
| else |
| nStartAction = nEndAction = 0; |
| } |
| |
| |
| ScChangeActionContent* ScChangeTrack::AppendContentOnTheFly( |
| const ScAddress& rPos, ScBaseCell* pOldCell, ScBaseCell* pNewCell, |
| sal_uLong nOldFormat, sal_uLong nNewFormat ) |
| { |
| ScRange aRange( rPos ); |
| ScChangeActionContent* pAct = new ScChangeActionContent( aRange ); |
| pAct->SetOldNewCells( pOldCell, nOldFormat, pNewCell, nNewFormat, pDoc ); |
| Append( pAct ); |
| return pAct; |
| } |
| |
| |
| void ScChangeTrack::AppendInsert( const ScRange& rRange ) |
| { |
| ScChangeActionIns* pAct = new ScChangeActionIns( rRange ); |
| Append( pAct ); |
| } |
| |
| |
| void ScChangeTrack::DeleteCellEntries( ScChangeActionCellListEntry*& pCellList, |
| ScChangeAction* pDeletor ) |
| { |
| ScChangeActionCellListEntry* pE = pCellList; |
| while ( pE ) |
| { |
| ScChangeActionCellListEntry* pNext = pE->pNext; |
| pE->pContent->RemoveDeletedIn( pDeletor ); |
| if ( IsGenerated( pE->pContent->GetActionNumber() ) && |
| !pE->pContent->IsDeletedIn() ) |
| DeleteGeneratedDelContent( pE->pContent ); |
| delete pE; |
| pE = pNext; |
| } |
| pCellList = NULL; |
| } |
| |
| |
| ScChangeActionContent* ScChangeTrack::GenerateDelContent( |
| const ScAddress& rPos, const ScBaseCell* pCell, |
| const ScDocument* pFromDoc ) |
| { |
| ScChangeActionContent* pContent = new ScChangeActionContent( |
| ScRange( rPos ) ); |
| pContent->SetActionNumber( --nGeneratedMin ); |
| // nur NewValue |
| ScChangeActionContent::SetValue( pContent->aNewValue, pContent->pNewCell, |
| rPos, pCell, pFromDoc, pDoc ); |
| // pNextContent und pPrevContent werden nicht gesetzt |
| if ( pFirstGeneratedDelContent ) |
| { // vorne reinhaengen |
| pFirstGeneratedDelContent->pPrev = pContent; |
| pContent->pNext = pFirstGeneratedDelContent; |
| } |
| pFirstGeneratedDelContent = pContent; |
| aGeneratedTable.Insert( nGeneratedMin, pContent ); |
| NotifyModified( SC_CTM_APPEND, nGeneratedMin, nGeneratedMin ); |
| return pContent; |
| } |
| |
| |
| void ScChangeTrack::DeleteGeneratedDelContent( ScChangeActionContent* pContent ) |
| { |
| sal_uLong nAct = pContent->GetActionNumber(); |
| aGeneratedTable.Remove( nAct ); |
| if ( pFirstGeneratedDelContent == pContent ) |
| pFirstGeneratedDelContent = (ScChangeActionContent*) pContent->pNext; |
| if ( pContent->pNext ) |
| pContent->pNext->pPrev = pContent->pPrev; |
| if ( pContent->pPrev ) |
| pContent->pPrev->pNext = pContent->pNext; |
| delete pContent; |
| NotifyModified( SC_CTM_REMOVE, nAct, nAct ); |
| if ( nAct == nGeneratedMin ) |
| ++nGeneratedMin; //! erst nach NotifyModified wg. IsGenerated |
| } |
| |
| |
| ScChangeActionContent* ScChangeTrack::SearchContentAt( |
| const ScBigAddress& rPos, ScChangeAction* pButNotThis ) const |
| { |
| SCSIZE nSlot = ComputeContentSlot( rPos.Row() ); |
| for ( ScChangeActionContent* p = ppContentSlots[nSlot]; p; |
| p = p->GetNextInSlot() ) |
| { |
| if ( p != pButNotThis && !p->IsDeletedIn() && |
| p->GetBigRange().aStart == rPos ) |
| { |
| ScChangeActionContent* pContent = p->GetTopContent(); |
| if ( !pContent->IsDeletedIn() ) |
| return pContent; |
| } |
| } |
| return NULL; |
| } |
| |
| |
| void ScChangeTrack::AddDependentWithNotify( ScChangeAction* pParent, |
| ScChangeAction* pDependent ) |
| { |
| ScChangeActionLinkEntry* pLink = pParent->AddDependent( pDependent ); |
| pDependent->AddLink( pParent, pLink ); |
| if ( aModifiedLink.IsSet() ) |
| { |
| sal_uLong nMod = pParent->GetActionNumber(); |
| NotifyModified( SC_CTM_PARENT, nMod, nMod ); |
| } |
| } |
| |
| |
| void ScChangeTrack::Dependencies( ScChangeAction* pAct ) |
| { |
| // Finde die letzte Abhaengigkeit fuer jeweils Col/Row/Tab. |
| // Content an gleicher Position verketten. |
| // Move Abhaengigkeiten. |
| ScChangeActionType eActType = pAct->GetType(); |
| if ( eActType == SC_CAT_REJECT || |
| (eActType == SC_CAT_MOVE && pAct->IsRejecting()) ) |
| return ; // diese Rejects sind nicht abhaengig |
| |
| if ( eActType == SC_CAT_CONTENT ) |
| { |
| if ( !(((ScChangeActionContent*)pAct)->GetNextContent() || |
| ((ScChangeActionContent*)pAct)->GetPrevContent()) ) |
| { // Contents an gleicher Position verketten |
| ScChangeActionContent* pContent = SearchContentAt( |
| pAct->GetBigRange().aStart, pAct ); |
| if ( pContent ) |
| { |
| pContent->SetNextContent( (ScChangeActionContent*) pAct ); |
| ((ScChangeActionContent*)pAct)->SetPrevContent( pContent ); |
| } |
| } |
| const ScBaseCell* pCell = ((ScChangeActionContent*)pAct)->GetNewCell(); |
| if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATREF ) |
| { |
| ScAddress aOrg; |
| ((const ScFormulaCell*)pCell)->GetMatrixOrigin( aOrg ); |
| ScChangeActionContent* pContent = SearchContentAt( aOrg, pAct ); |
| if ( pContent && pContent->IsMatrixOrigin() ) |
| { |
| AddDependentWithNotify( pContent, pAct ); |
| } |
| else |
| { |
| DBG_ERRORFILE( "ScChangeTrack::Dependencies: MatOrg not found" ); |
| } |
| } |
| } |
| |
| if ( !(pLinkInsertCol || pLinkInsertRow || pLinkInsertTab || pLinkMove) ) |
| return ; // keine Dependencies |
| if ( pAct->IsRejecting() ) |
| return ; // ausser Content keine Dependencies |
| |
| // Insert in einem entsprechenden Insert haengt davon ab, sonst muesste |
| // der vorherige Insert gesplittet werden. |
| // Sich kreuzende Inserts und Deletes sind nicht abhaengig. |
| // Alles andere ist abhaengig. |
| |
| // Der zuletzt eingelinkte Insert steht am Anfang einer Kette, |
| // also genau richtig |
| |
| const ScBigRange& rRange = pAct->GetBigRange(); |
| sal_Bool bActNoInsert = !pAct->IsInsertType(); |
| sal_Bool bActColDel = ( eActType == SC_CAT_DELETE_COLS ); |
| sal_Bool bActRowDel = ( eActType == SC_CAT_DELETE_ROWS ); |
| sal_Bool bActTabDel = ( eActType == SC_CAT_DELETE_TABS ); |
| |
| if ( pLinkInsertCol && (eActType == SC_CAT_INSERT_COLS || |
| (bActNoInsert && !bActRowDel && !bActTabDel)) ) |
| { |
| for ( ScChangeActionLinkEntry* pL = pLinkInsertCol; pL; pL = pL->GetNext() ) |
| { |
| ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction(); |
| if ( !pTest->IsRejected() && |
| pTest->GetBigRange().Intersects( rRange ) ) |
| { |
| AddDependentWithNotify( pTest, pAct ); |
| break; // for |
| } |
| } |
| } |
| if ( pLinkInsertRow && (eActType == SC_CAT_INSERT_ROWS || |
| (bActNoInsert && !bActColDel && !bActTabDel)) ) |
| { |
| for ( ScChangeActionLinkEntry* pL = pLinkInsertRow; pL; pL = pL->GetNext() ) |
| { |
| ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction(); |
| if ( !pTest->IsRejected() && |
| pTest->GetBigRange().Intersects( rRange ) ) |
| { |
| AddDependentWithNotify( pTest, pAct ); |
| break; // for |
| } |
| } |
| } |
| if ( pLinkInsertTab && (eActType == SC_CAT_INSERT_TABS || |
| (bActNoInsert && !bActColDel && !bActRowDel)) ) |
| { |
| for ( ScChangeActionLinkEntry* pL = pLinkInsertTab; pL; pL = pL->GetNext() ) |
| { |
| ScChangeActionIns* pTest = (ScChangeActionIns*) pL->GetAction(); |
| if ( !pTest->IsRejected() && |
| pTest->GetBigRange().Intersects( rRange ) ) |
| { |
| AddDependentWithNotify( pTest, pAct ); |
| break; // for |
| } |
| } |
| } |
| |
| if ( pLinkMove ) |
| { |
| if ( eActType == SC_CAT_CONTENT ) |
| { // Content ist von FromRange abhaengig |
| const ScBigAddress& rPos = rRange.aStart; |
| for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() ) |
| { |
| ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction(); |
| if ( !pTest->IsRejected() && |
| pTest->GetFromRange().In( rPos ) ) |
| { |
| AddDependentWithNotify( pTest, pAct ); |
| } |
| } |
| } |
| else if ( eActType == SC_CAT_MOVE ) |
| { // Move FromRange ist von ToRange abhaengig |
| const ScBigRange& rFromRange = ((ScChangeActionMove*)pAct)->GetFromRange(); |
| for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() ) |
| { |
| ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction(); |
| if ( !pTest->IsRejected() && |
| pTest->GetBigRange().Intersects( rFromRange ) ) |
| { |
| AddDependentWithNotify( pTest, pAct ); |
| } |
| } |
| } |
| else |
| { // Inserts und Deletes sind abhaengig, sobald sie FromRange oder |
| // ToRange kreuzen |
| for ( ScChangeActionLinkEntry* pL = pLinkMove; pL; pL = pL->GetNext() ) |
| { |
| ScChangeActionMove* pTest = (ScChangeActionMove*) pL->GetAction(); |
| if ( !pTest->IsRejected() && |
| (pTest->GetFromRange().Intersects( rRange ) || |
| pTest->GetBigRange().Intersects( rRange )) ) |
| { |
| AddDependentWithNotify( pTest, pAct ); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| void ScChangeTrack::Remove( ScChangeAction* pRemove ) |
| { |
| // aus Track ausklinken |
| sal_uLong nAct = pRemove->GetActionNumber(); |
| aTable.Remove( nAct ); |
| if ( nAct == nActionMax ) |
| --nActionMax; |
| if ( pRemove == pLast ) |
| pLast = pRemove->pPrev; |
| if ( pRemove == pFirst ) |
| pFirst = pRemove->pNext; |
| if ( nAct == nMarkLastSaved ) |
| nMarkLastSaved = |
| ( pRemove->pPrev ? pRemove->pPrev->GetActionNumber() : 0 ); |
| |
| // aus der globalen Kette ausklinken |
| if ( pRemove->pNext ) |
| pRemove->pNext->pPrev = pRemove->pPrev; |
| if ( pRemove->pPrev ) |
| pRemove->pPrev->pNext = pRemove->pNext; |
| |
| // Dependencies nicht loeschen, passiert on delete automatisch durch |
| // LinkEntry, ohne Listen abzuklappern |
| |
| if ( aModifiedLink.IsSet() ) |
| { |
| NotifyModified( SC_CTM_REMOVE, nAct, nAct ); |
| if ( pRemove->GetType() == SC_CAT_CONTENT ) |
| { |
| ScChangeActionContent* pContent = (ScChangeActionContent*) pRemove; |
| if ( ( pContent = pContent->GetPrevContent() ) != NULL ) |
| { |
| sal_uLong nMod = pContent->GetActionNumber(); |
| NotifyModified( SC_CTM_CHANGE, nMod, nMod ); |
| } |
| } |
| else if ( pLast ) |
| NotifyModified( SC_CTM_CHANGE, pFirst->GetActionNumber(), |
| pLast->GetActionNumber() ); |
| } |
| |
| if ( IsInPasteCut() && pRemove->GetType() == SC_CAT_CONTENT ) |
| { //! Content wird wiederverwertet |
| ScChangeActionContent* pContent = (ScChangeActionContent*) pRemove; |
| pContent->RemoveAllLinks(); |
| pContent->ClearTrack(); |
| pContent->pNext = pContent->pPrev = NULL; |
| pContent->pNextContent = pContent->pPrevContent = NULL; |
| } |
| } |
| |
| |
| void ScChangeTrack::Undo( sal_uLong nStartAction, sal_uLong nEndAction, bool bMerge ) |
| { |
| // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong |
| if ( bMerge ) |
| { |
| SetMergeState( SC_CTMS_UNDO ); |
| } |
| |
| if ( nStartAction == 0 ) |
| ++nStartAction; |
| if ( nEndAction > nActionMax ) |
| nEndAction = nActionMax; |
| if ( nEndAction && nStartAction <= nEndAction ) |
| { |
| if ( nStartAction == nStartLastCut && nEndAction == nEndLastCut && |
| !IsInPasteCut() ) |
| ResetLastCut(); |
| StartBlockModify( SC_CTM_REMOVE, nStartAction ); |
| for ( sal_uLong j = nEndAction; j >= nStartAction; --j ) |
| { // rueckwaerts um evtl. nActionMax zu recyclen und schnelleren |
| // Zugriff via pLast, Deletes in richtiger Reihenfolge |
| ScChangeAction* pAct = ( (j == nActionMax && pLast && |
| pLast->GetActionNumber() == j) ? pLast : GetAction( j ) ); |
| if ( pAct ) |
| { |
| if ( pAct->IsDeleteType() ) |
| { |
| if ( j == nEndAction || (pAct != pLast && |
| ((ScChangeActionDel*)pAct)->IsTopDelete()) ) |
| { |
| SetInDeleteTop( sal_True ); |
| SetInDeleteRange( ((ScChangeActionDel*)pAct)-> |
| GetOverAllRange().MakeRange() ); |
| } |
| } |
| UpdateReference( pAct, sal_True ); |
| SetInDeleteTop( sal_False ); |
| Remove( pAct ); |
| if ( IsInPasteCut() ) |
| aPasteCutTable.Insert( pAct->GetActionNumber(), pAct ); |
| else |
| { |
| if ( j == nStartAction && pAct->GetType() == SC_CAT_MOVE ) |
| { |
| ScChangeActionMove* pMove = (ScChangeActionMove*) pAct; |
| sal_uLong nStart = pMove->GetStartLastCut(); |
| sal_uLong nEnd = pMove->GetEndLastCut(); |
| if ( nStart && nStart <= nEnd ) |
| { // LastCut wiederherstellen |
| //! Links vor Cut-Append aufloesen |
| pMove->RemoveAllLinks(); |
| StartBlockModify( SC_CTM_APPEND, nStart ); |
| for ( sal_uLong nCut = nStart; nCut <= nEnd; nCut++ ) |
| { |
| ScChangeAction* pCut = aPasteCutTable.Remove( nCut ); |
| if ( pCut ) |
| { |
| DBG_ASSERT( !aTable.Get( nCut ), "ScChangeTrack::Undo: nCut dup" ); |
| Append( pCut, nCut ); |
| } |
| else |
| { |
| DBG_ERROR( "ScChangeTrack::Undo: nCut not found" ); |
| } |
| } |
| EndBlockModify( nEnd ); |
| ResetLastCut(); |
| nStartLastCut = nStart; |
| nEndLastCut = nEnd; |
| pLastCutMove = pMove; |
| SetLastCutMoveRange( |
| pMove->GetFromRange().MakeRange(), pDoc ); |
| } |
| else |
| delete pMove; |
| } |
| else |
| delete pAct; |
| } |
| } |
| } |
| EndBlockModify( nEndAction ); |
| } |
| |
| // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong |
| if ( bMerge ) |
| { |
| SetMergeState( SC_CTMS_OTHER ); |
| } |
| } |
| |
| |
| // static |
| sal_Bool ScChangeTrack::MergeIgnore( const ScChangeAction& rAction, sal_uLong nFirstMerge ) |
| { |
| if ( rAction.IsRejected() ) |
| return sal_True; // da kommt noch eine passende Reject-Action |
| |
| if ( rAction.IsRejecting() && rAction.GetRejectAction() >= nFirstMerge ) |
| return sal_True; // da ist sie |
| |
| return sal_False; // alles andere |
| } |
| |
| |
| void ScChangeTrack::MergePrepare( ScChangeAction* pFirstMerge, bool bShared ) |
| { |
| SetMergeState( SC_CTMS_PREPARE ); |
| sal_uLong nFirstMerge = pFirstMerge->GetActionNumber(); |
| ScChangeAction* pAct = GetLast(); |
| if ( pAct ) |
| { |
| SetLastMerge( pAct->GetActionNumber() ); |
| while ( pAct ) |
| { // rueckwaerts, Deletes in richtiger Reihenfolge |
| // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong |
| if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) ) |
| { |
| if ( pAct->IsDeleteType() ) |
| { |
| if ( ((ScChangeActionDel*)pAct)->IsTopDelete() ) |
| { |
| SetInDeleteTop( sal_True ); |
| SetInDeleteRange( ((ScChangeActionDel*)pAct)-> |
| GetOverAllRange().MakeRange() ); |
| } |
| } |
| UpdateReference( pAct, sal_True ); |
| SetInDeleteTop( sal_False ); |
| pAct->DeleteCellEntries(); // sonst GPF bei Track Clear() |
| } |
| pAct = ( pAct == pFirstMerge ? NULL : pAct->GetPrev() ); |
| } |
| } |
| SetMergeState( SC_CTMS_OTHER ); //! nachfolgende per default MergeOther |
| } |
| |
| |
| void ScChangeTrack::MergeOwn( ScChangeAction* pAct, sal_uLong nFirstMerge, bool bShared ) |
| { |
| // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong |
| if ( bShared || !ScChangeTrack::MergeIgnore( *pAct, nFirstMerge ) ) |
| { |
| SetMergeState( SC_CTMS_OWN ); |
| if ( pAct->IsDeleteType() ) |
| { |
| if ( ((ScChangeActionDel*)pAct)->IsTopDelete() ) |
| { |
| SetInDeleteTop( sal_True ); |
| SetInDeleteRange( ((ScChangeActionDel*)pAct)-> |
| GetOverAllRange().MakeRange() ); |
| } |
| } |
| UpdateReference( pAct, sal_False ); |
| SetInDeleteTop( sal_False ); |
| SetMergeState( SC_CTMS_OTHER ); //! nachfolgende per default MergeOther |
| } |
| } |
| |
| |
| void ScChangeTrack::UpdateReference( ScChangeAction* pAct, sal_Bool bUndo ) |
| { |
| ScChangeActionType eActType = pAct->GetType(); |
| if ( eActType == SC_CAT_CONTENT || eActType == SC_CAT_REJECT ) |
| return ; |
| |
| //! Formelzellen haengen nicht im Dokument |
| sal_Bool bOldAutoCalc = pDoc->GetAutoCalc(); |
| pDoc->SetAutoCalc( sal_False ); |
| sal_Bool bOldNoListening = pDoc->GetNoListening(); |
| pDoc->SetNoListening( sal_True ); |
| //! Formelzellen ExpandRefs synchronisiert zu denen im Dokument |
| sal_Bool bOldExpandRefs = pDoc->IsExpandRefs(); |
| if ( (!bUndo && pAct->IsInsertType()) || (bUndo && pAct->IsDeleteType()) ) |
| pDoc->SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() ); |
| |
| if ( pAct->IsDeleteType() ) |
| { |
| SetInDeleteUndo( bUndo ); |
| SetInDelete( sal_True ); |
| } |
| else if ( GetMergeState() == SC_CTMS_OWN ) |
| { |
| // Referenzen von Formelzellen wiederherstellen, |
| // vorheriges MergePrepare war bei einem Insert wie ein Delete |
| if ( pAct->IsInsertType() ) |
| SetInDeleteUndo( sal_True ); |
| } |
| |
| //! erst die generated, als waeren sie vorher getrackt worden |
| if ( pFirstGeneratedDelContent ) |
| UpdateReference( (ScChangeAction**)&pFirstGeneratedDelContent, pAct, |
| bUndo ); |
| UpdateReference( &pFirst, pAct, bUndo ); |
| |
| SetInDelete( sal_False ); |
| SetInDeleteUndo( sal_False ); |
| |
| pDoc->SetExpandRefs( bOldExpandRefs ); |
| pDoc->SetNoListening( bOldNoListening ); |
| pDoc->SetAutoCalc( bOldAutoCalc ); |
| } |
| |
| |
| void ScChangeTrack::UpdateReference( ScChangeAction** ppFirstAction, |
| ScChangeAction* pAct, sal_Bool bUndo ) |
| { |
| ScChangeActionType eActType = pAct->GetType(); |
| sal_Bool bGeneratedDelContents = |
| ( ppFirstAction == (ScChangeAction**)&pFirstGeneratedDelContent ); |
| const ScBigRange& rOrgRange = pAct->GetBigRange(); |
| ScBigRange aRange( rOrgRange ); |
| ScBigRange aDelRange( rOrgRange ); |
| sal_Int32 nDx, nDy, nDz; |
| nDx = nDy = nDz = 0; |
| UpdateRefMode eMode = URM_INSDEL; |
| sal_Bool bDel = sal_False; |
| switch ( eActType ) |
| { |
| case SC_CAT_INSERT_COLS : |
| aRange.aEnd.SetCol( nInt32Max ); |
| nDx = rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1; |
| break; |
| case SC_CAT_INSERT_ROWS : |
| aRange.aEnd.SetRow( nInt32Max ); |
| nDy = rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1; |
| break; |
| case SC_CAT_INSERT_TABS : |
| aRange.aEnd.SetTab( nInt32Max ); |
| nDz = rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1; |
| break; |
| case SC_CAT_DELETE_COLS : |
| aRange.aEnd.SetCol( nInt32Max ); |
| nDx = -(rOrgRange.aEnd.Col() - rOrgRange.aStart.Col() + 1); |
| aDelRange.aEnd.SetCol( aDelRange.aStart.Col() - nDx - 1 ); |
| bDel = sal_True; |
| break; |
| case SC_CAT_DELETE_ROWS : |
| aRange.aEnd.SetRow( nInt32Max ); |
| nDy = -(rOrgRange.aEnd.Row() - rOrgRange.aStart.Row() + 1); |
| aDelRange.aEnd.SetRow( aDelRange.aStart.Row() - nDy - 1 ); |
| bDel = sal_True; |
| break; |
| case SC_CAT_DELETE_TABS : |
| aRange.aEnd.SetTab( nInt32Max ); |
| nDz = -(rOrgRange.aEnd.Tab() - rOrgRange.aStart.Tab() + 1); |
| aDelRange.aEnd.SetTab( aDelRange.aStart.Tab() - nDz - 1 ); |
| bDel = sal_True; |
| break; |
| case SC_CAT_MOVE : |
| eMode = URM_MOVE; |
| ((ScChangeActionMove*)pAct)->GetDelta( nDx, nDy, nDz ); |
| break; |
| default: |
| DBG_ERROR( "ScChangeTrack::UpdateReference: unknown Type" ); |
| } |
| if ( bUndo ) |
| { |
| nDx = -nDx; |
| nDy = -nDy; |
| nDz = -nDz; |
| } |
| if ( bDel ) |
| { //! fuer diesen Mechanismus gilt: |
| //! es gibt nur ganze, einfache geloeschte Spalten/Zeilen |
| ScChangeActionDel* pActDel = (ScChangeActionDel*) pAct; |
| if ( !bUndo ) |
| { // Delete |
| ScChangeActionType eInsType = SC_CAT_NONE; // for Insert-Undo-"Deletes" |
| switch ( eActType ) |
| { |
| case SC_CAT_DELETE_COLS : |
| eInsType = SC_CAT_INSERT_COLS; |
| break; |
| case SC_CAT_DELETE_ROWS : |
| eInsType = SC_CAT_INSERT_ROWS; |
| break; |
| case SC_CAT_DELETE_TABS : |
| eInsType = SC_CAT_INSERT_TABS; |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) |
| { |
| if ( p == pAct ) |
| continue; // for |
| sal_Bool bUpdate = sal_True; |
| if ( GetMergeState() == SC_CTMS_OTHER && |
| p->GetActionNumber() <= GetLastMerge() ) |
| { // Delete in mergendem Dokument, Action im zu mergenden |
| if ( p->IsInsertType() ) |
| { |
| // Bei Insert Referenzen nur anpassen, wenn das Delete |
| // das Insert nicht schneidet. |
| if ( !aDelRange.Intersects( p->GetBigRange() ) ) |
| p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); |
| bUpdate = sal_False; |
| } |
| else if ( p->GetType() == SC_CAT_CONTENT && |
| p->IsDeletedInDelType( eInsType ) ) |
| { // Content in Insert-Undo-"Delete" |
| // Nicht anpassen, wenn dieses Delete in dem |
| // Insert-"Delete" sein wuerde (ist nur verschoben). |
| if ( aDelRange.In( p->GetBigRange().aStart ) ) |
| bUpdate = sal_False; |
| else |
| { |
| const ScChangeActionLinkEntry* pLink = p->GetDeletedIn(); |
| while ( pLink && bUpdate ) |
| { |
| const ScChangeAction* pDel = pLink->GetAction(); |
| if ( pDel && pDel->GetType() == eInsType && |
| pDel->GetBigRange().In( aDelRange ) ) |
| bUpdate = sal_False; |
| pLink = pLink->GetNext(); |
| } |
| } |
| } |
| if ( !bUpdate ) |
| continue; // for |
| } |
| if ( aDelRange.In( p->GetBigRange() ) ) |
| { |
| // Innerhalb eines gerade geloeschten Bereiches nicht |
| // anpassen, stattdessen dem Bereich zuordnen. |
| // Mehrfache geloeschte Bereiche "stapeln". |
| // Kreuzende Deletes setzen mehrfach geloescht. |
| if ( !p->IsDeletedInDelType( eActType ) ) |
| { |
| p->SetDeletedIn( pActDel ); |
| // GeneratedDelContent in zu loeschende Liste aufnehmen |
| if ( bGeneratedDelContents ) |
| pActDel->AddContent( (ScChangeActionContent*) p ); |
| } |
| bUpdate = sal_False; |
| } |
| else |
| { |
| // Eingefuegte Bereiche abschneiden, wenn Start/End im |
| // Delete liegt, aber das Insert nicht komplett innerhalb |
| // des Delete liegt bzw. das Delete nicht komplett im |
| // Insert. Das Delete merkt sich, welchem Insert es was |
| // abgeschnitten hat, es kann auch nur ein einziges Insert |
| // sein (weil Delete einspaltig/einzeilig ist). |
| // Abgeschnittene Moves kann es viele geben. |
| //! Ein Delete ist immer einspaltig/einzeilig, deswegen 1 |
| //! ohne die Ueberlappung auszurechnen. |
| switch ( p->GetType() ) |
| { |
| case SC_CAT_INSERT_COLS : |
| if ( eActType == SC_CAT_DELETE_COLS ) |
| { |
| if ( aDelRange.In( p->GetBigRange().aStart ) ) |
| { |
| pActDel->SetCutOffInsert( |
| (ScChangeActionIns*) p, 1 ); |
| p->GetBigRange().aStart.IncCol( 1 ); |
| } |
| else if ( aDelRange.In( p->GetBigRange().aEnd ) ) |
| { |
| pActDel->SetCutOffInsert( |
| (ScChangeActionIns*) p, -1 ); |
| p->GetBigRange().aEnd.IncCol( -1 ); |
| } |
| } |
| break; |
| case SC_CAT_INSERT_ROWS : |
| if ( eActType == SC_CAT_DELETE_ROWS ) |
| { |
| if ( aDelRange.In( p->GetBigRange().aStart ) ) |
| { |
| pActDel->SetCutOffInsert( |
| (ScChangeActionIns*) p, 1 ); |
| p->GetBigRange().aStart.IncRow( 1 ); |
| } |
| else if ( aDelRange.In( p->GetBigRange().aEnd ) ) |
| { |
| pActDel->SetCutOffInsert( |
| (ScChangeActionIns*) p, -1 ); |
| p->GetBigRange().aEnd.IncRow( -1 ); |
| } |
| } |
| break; |
| case SC_CAT_INSERT_TABS : |
| if ( eActType == SC_CAT_DELETE_TABS ) |
| { |
| if ( aDelRange.In( p->GetBigRange().aStart ) ) |
| { |
| pActDel->SetCutOffInsert( |
| (ScChangeActionIns*) p, 1 ); |
| p->GetBigRange().aStart.IncTab( 1 ); |
| } |
| else if ( aDelRange.In( p->GetBigRange().aEnd ) ) |
| { |
| pActDel->SetCutOffInsert( |
| (ScChangeActionIns*) p, -1 ); |
| p->GetBigRange().aEnd.IncTab( -1 ); |
| } |
| } |
| break; |
| case SC_CAT_MOVE : |
| { |
| ScChangeActionMove* pMove = (ScChangeActionMove*) p; |
| short nFrom = 0; |
| short nTo = 0; |
| if ( aDelRange.In( pMove->GetBigRange().aStart ) ) |
| nTo = 1; |
| else if ( aDelRange.In( pMove->GetBigRange().aEnd ) ) |
| nTo = -1; |
| if ( aDelRange.In( pMove->GetFromRange().aStart ) ) |
| nFrom = 1; |
| else if ( aDelRange.In( pMove->GetFromRange().aEnd ) ) |
| nFrom = -1; |
| if ( nFrom ) |
| { |
| switch ( eActType ) |
| { |
| case SC_CAT_DELETE_COLS : |
| if ( nFrom > 0 ) |
| pMove->GetFromRange().aStart.IncCol( nFrom ); |
| else |
| pMove->GetFromRange().aEnd.IncCol( nFrom ); |
| break; |
| case SC_CAT_DELETE_ROWS : |
| if ( nFrom > 0 ) |
| pMove->GetFromRange().aStart.IncRow( nFrom ); |
| else |
| pMove->GetFromRange().aEnd.IncRow( nFrom ); |
| break; |
| case SC_CAT_DELETE_TABS : |
| if ( nFrom > 0 ) |
| pMove->GetFromRange().aStart.IncTab( nFrom ); |
| else |
| pMove->GetFromRange().aEnd.IncTab( nFrom ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| if ( nTo ) |
| { |
| switch ( eActType ) |
| { |
| case SC_CAT_DELETE_COLS : |
| if ( nTo > 0 ) |
| pMove->GetBigRange().aStart.IncCol( nTo ); |
| else |
| pMove->GetBigRange().aEnd.IncCol( nTo ); |
| break; |
| case SC_CAT_DELETE_ROWS : |
| if ( nTo > 0 ) |
| pMove->GetBigRange().aStart.IncRow( nTo ); |
| else |
| pMove->GetBigRange().aEnd.IncRow( nTo ); |
| break; |
| case SC_CAT_DELETE_TABS : |
| if ( nTo > 0 ) |
| pMove->GetBigRange().aStart.IncTab( nTo ); |
| else |
| pMove->GetBigRange().aEnd.IncTab( nTo ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| if ( nFrom || nTo ) |
| { |
| ScChangeActionDelMoveEntry* pLink = |
| pActDel->AddCutOffMove( pMove, nFrom, nTo ); |
| pMove->AddLink( pActDel, pLink ); |
| } |
| } |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| if ( bUpdate ) |
| { |
| p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); |
| if ( p->GetType() == eActType && !p->IsRejected() && |
| !pActDel->IsDeletedIn() && |
| p->GetBigRange().In( aDelRange ) ) |
| pActDel->SetDeletedIn( p ); // "druntergerutscht" |
| } |
| } |
| } |
| else |
| { // Undo Delete |
| for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) |
| { |
| if ( p == pAct ) |
| continue; // for |
| sal_Bool bUpdate = sal_True; |
| if ( aDelRange.In( p->GetBigRange() ) ) |
| { |
| // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong |
| if ( GetMergeState() == SC_CTMS_UNDO && !p->IsDeletedIn( pAct ) && pAct->IsDeleteType() && |
| ( p->GetType() == SC_CAT_CONTENT || |
| p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || |
| p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) ) |
| { |
| p->SetDeletedIn( pAct ); |
| } |
| |
| if ( p->IsDeletedInDelType( eActType ) ) |
| { |
| if ( p->IsDeletedIn( pActDel ) ) |
| { |
| if ( p->GetType() != SC_CAT_CONTENT || |
| ((ScChangeActionContent*)p)->IsTopContent() ) |
| { // erst der TopContent wird wirklich entfernt |
| p->RemoveDeletedIn( pActDel ); |
| // GeneratedDelContent _nicht_ aus Liste loeschen, |
| // wir brauchen ihn evtl. noch fuer Reject, |
| // geloescht wird in DeleteCellEntries |
| } |
| } |
| bUpdate = sal_False; |
| } |
| else if ( eActType != SC_CAT_DELETE_TABS && |
| p->IsDeletedInDelType( SC_CAT_DELETE_TABS ) ) |
| { // in geloeschten Tabellen nicht updaten, |
| // ausser wenn Tabelle verschoben wird |
| bUpdate = sal_False; |
| } |
| if ( p->GetType() == eActType && pActDel->IsDeletedIn( p ) ) |
| { |
| pActDel->RemoveDeletedIn( p ); // "druntergerutscht" |
| bUpdate = sal_True; |
| } |
| } |
| if ( bUpdate ) |
| p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); |
| } |
| if ( !bGeneratedDelContents ) |
| { // die werden sonst noch fuer das echte Undo gebraucht |
| pActDel->UndoCutOffInsert(); |
| pActDel->UndoCutOffMoves(); |
| } |
| } |
| } |
| else if ( eActType == SC_CAT_MOVE ) |
| { |
| ScChangeActionMove* pActMove = (ScChangeActionMove*) pAct; |
| sal_Bool bLastCutMove = ( pActMove == pLastCutMove ); |
| const ScBigRange& rTo = pActMove->GetBigRange(); |
| const ScBigRange& rFrom = pActMove->GetFromRange(); |
| if ( !bUndo ) |
| { // Move |
| for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) |
| { |
| if ( p == pAct ) |
| continue; // for |
| if ( p->GetType() == SC_CAT_CONTENT ) |
| { |
| // Inhalt in Ziel deleten (Inhalt in Quelle moven) |
| if ( rTo.In( p->GetBigRange() ) ) |
| { |
| if ( !p->IsDeletedIn( pActMove ) ) |
| { |
| p->SetDeletedIn( pActMove ); |
| // GeneratedDelContent in zu loeschende Liste aufnehmen |
| if ( bGeneratedDelContents ) |
| pActMove->AddContent( (ScChangeActionContent*) p ); |
| } |
| } |
| else if ( bLastCutMove && |
| p->GetActionNumber() > nEndLastCut && |
| rFrom.In( p->GetBigRange() ) ) |
| { // Paste Cut: neuer Content nach Cut eingefuegt, bleibt. |
| // Aufsplitten der ContentChain |
| ScChangeActionContent *pHere, *pTmp; |
| pHere = (ScChangeActionContent*) p; |
| while ( (pTmp = pHere->GetPrevContent()) != NULL && |
| pTmp->GetActionNumber() > nEndLastCut ) |
| pHere = pTmp; |
| if ( pTmp ) |
| { // wird TopContent des Move |
| pTmp->SetNextContent( NULL ); |
| pHere->SetPrevContent( NULL ); |
| } |
| do |
| { // Abhaengigkeit vom FromRange herstellen |
| AddDependentWithNotify( pActMove, pHere ); |
| } while ( ( pHere = pHere->GetNextContent() ) != NULL ); |
| } |
| // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly |
| else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() ) |
| p->UpdateReference( this, eMode, rFrom, nDx, nDy, nDz ); |
| } |
| } |
| } |
| else |
| { // Undo Move |
| sal_Bool bActRejected = pActMove->IsRejected(); |
| for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) |
| { |
| if ( p == pAct ) |
| continue; // for |
| if ( p->GetType() == SC_CAT_CONTENT ) |
| { |
| // Inhalt in Ziel moven, wenn nicht deleted, sonst undelete |
| if ( p->IsDeletedIn( pActMove ) ) |
| { |
| if ( ((ScChangeActionContent*)p)->IsTopContent() ) |
| { // erst der TopContent wird wirklich entfernt |
| p->RemoveDeletedIn( pActMove ); |
| // GeneratedDelContent _nicht_ aus Liste loeschen, |
| // wir brauchen ihn evtl. noch fuer Reject, |
| // geloescht wird in DeleteCellEntries |
| } |
| } |
| // #i87003# [Collaboration] Move range and insert content in FromRange is not merged correctly |
| else if ( ( GetMergeState() != SC_CTMS_PREPARE && GetMergeState() != SC_CTMS_OWN ) || p->GetActionNumber() <= pAct->GetActionNumber() ) |
| p->UpdateReference( this, eMode, rTo, nDx, nDy, nDz ); |
| if ( bActRejected && |
| ((ScChangeActionContent*)p)->IsTopContent() && |
| rFrom.In( p->GetBigRange() ) ) |
| { // Abhaengigkeit herstellen, um Content zu schreiben |
| ScChangeActionLinkEntry* pLink = |
| pActMove->AddDependent( p ); |
| p->AddLink( pActMove, pLink ); |
| } |
| } |
| } |
| } |
| } |
| else |
| { // Insert / Undo Insert |
| switch ( GetMergeState() ) |
| { |
| case SC_CTMS_NONE : |
| case SC_CTMS_OTHER : |
| { |
| for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) |
| { |
| if ( p == pAct ) |
| continue; // for |
| p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); |
| } |
| } |
| break; |
| case SC_CTMS_PREPARE : |
| { |
| // in Insert-Undo "Deleten" |
| const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry(); |
| while ( pLink ) |
| { |
| ScChangeAction* p = (ScChangeAction*) pLink->GetAction(); |
| if ( p ) |
| p->SetDeletedIn( pAct ); |
| pLink = pLink->GetNext(); |
| } |
| |
| // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly |
| for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) |
| { |
| if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() && |
| // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong |
| ( p->GetType() == SC_CAT_CONTENT || |
| p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || |
| p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) && |
| pAct->GetBigRange().Intersects( p->GetBigRange() ) ) |
| { |
| p->SetDeletedIn( pAct ); |
| } |
| } |
| |
| for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) |
| { |
| if ( p == pAct ) |
| continue; // for |
| if ( !p->IsDeletedIn( pAct ) |
| // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet |
| && p->GetActionNumber() <= pAct->GetActionNumber() ) |
| { |
| p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); |
| } |
| } |
| } |
| break; |
| case SC_CTMS_OWN : |
| { |
| for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) |
| { |
| if ( p == pAct ) |
| continue; // for |
| if ( !p->IsDeletedIn( pAct ) |
| // #i95212# [Collaboration] Bad handling of row insertion in shared spreadsheet |
| && p->GetActionNumber() <= pAct->GetActionNumber() ) |
| { |
| p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); |
| } |
| } |
| // in Insert-Undo "Delete" rueckgaengig |
| const ScChangeActionLinkEntry* pLink = pAct->GetFirstDependentEntry(); |
| while ( pLink ) |
| { |
| ScChangeAction* p = (ScChangeAction*) pLink->GetAction(); |
| if ( p ) |
| p->RemoveDeletedIn( pAct ); |
| pLink = pLink->GetNext(); |
| } |
| |
| // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly |
| for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) |
| { |
| if ( p->IsDeletedIn( pAct ) && pAct->IsInsertType() && |
| // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong |
| ( p->GetType() == SC_CAT_CONTENT || |
| p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || |
| p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) && |
| pAct->GetBigRange().Intersects( p->GetBigRange() ) ) |
| { |
| p->RemoveDeletedIn( pAct ); |
| } |
| } |
| } |
| break; |
| // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong |
| case SC_CTMS_UNDO : |
| { |
| for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) |
| { |
| if ( !p->IsDeletedIn( pAct ) && pAct->IsInsertType() && |
| ( p->GetType() == SC_CAT_CONTENT || |
| p->GetType() == SC_CAT_DELETE_ROWS || p->GetType() == SC_CAT_DELETE_COLS || |
| p->GetType() == SC_CAT_INSERT_ROWS || p->GetType() == SC_CAT_INSERT_COLS ) && |
| pAct->GetBigRange().Intersects( p->GetBigRange() ) ) |
| { |
| p->SetDeletedIn( pAct ); |
| } |
| } |
| |
| for ( ScChangeAction* p = *ppFirstAction; p; p = p->GetNext() ) |
| { |
| if ( p == pAct ) |
| { |
| continue; |
| } |
| if ( !p->IsDeletedIn( pAct ) && p->GetActionNumber() <= pAct->GetActionNumber() ) |
| { |
| p->UpdateReference( this, eMode, aRange, nDx, nDy, nDz ); |
| } |
| } |
| } |
| break; |
| } |
| } |
| } |
| |
| |
| void ScChangeTrack::GetDependents( ScChangeAction* pAct, |
| ScChangeActionTable& rTable, sal_Bool bListMasterDelete, sal_Bool bAllFlat ) const |
| { |
| //! bAllFlat==TRUE: intern aus Accept oder Reject gerufen, |
| //! => Generated werden nicht aufgenommen |
| |
| sal_Bool bIsDelete = pAct->IsDeleteType(); |
| sal_Bool bIsMasterDelete = ( bListMasterDelete && pAct->IsMasterDelete() ); |
| |
| const ScChangeAction* pCur = pAct; |
| ScChangeActionStack* pStack = new ScChangeActionStack; |
| do |
| { |
| if ( pCur->IsInsertType() ) |
| { |
| const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry(); |
| while ( pL ) |
| { |
| ScChangeAction* p = (ScChangeAction*) pL->GetAction(); |
| if ( p != pAct ) |
| { |
| if ( bAllFlat ) |
| { |
| sal_uLong n = p->GetActionNumber(); |
| if ( !IsGenerated( n ) && rTable.Insert( n, p ) ) |
| if ( p->HasDependent() ) |
| pStack->Push( p ); |
| } |
| else |
| { |
| if ( p->GetType() == SC_CAT_CONTENT ) |
| { |
| if ( ((ScChangeActionContent*)p)->IsTopContent() ) |
| rTable.Insert( p->GetActionNumber(), p ); |
| } |
| else |
| rTable.Insert( p->GetActionNumber(), p ); |
| } |
| } |
| pL = pL->GetNext(); |
| } |
| } |
| else if ( pCur->IsDeleteType() ) |
| { |
| if ( bIsDelete ) |
| { // Inhalte geloeschter Bereiche interessieren nur bei Delete |
| ScChangeActionDel* pDel = (ScChangeActionDel*) pCur; |
| if ( !bAllFlat && bIsMasterDelete && pCur == pAct ) |
| { |
| // zu diesem Delete gehoerende Deletes in gleiche Ebene, |
| // wenn dieses Delete das momentan oberste einer Reihe ist, |
| ScChangeActionType eType = pDel->GetType(); |
| ScChangeAction* p = pDel; |
| while ( (p = p->GetPrev()) != NULL && p->GetType() == eType && |
| !((ScChangeActionDel*)p)->IsTopDelete() ) |
| rTable.Insert( p->GetActionNumber(), p ); |
| // dieses Delete auch in Table! |
| rTable.Insert( pAct->GetActionNumber(), pAct ); |
| } |
| else |
| { |
| const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry(); |
| while ( pL ) |
| { |
| ScChangeAction* p = (ScChangeAction*) pL->GetAction(); |
| if ( p != pAct ) |
| { |
| if ( bAllFlat ) |
| { |
| // nur ein TopContent einer Kette ist in LinkDeleted |
| sal_uLong n = p->GetActionNumber(); |
| if ( !IsGenerated( n ) && rTable.Insert( n, p ) ) |
| if ( p->HasDeleted() || |
| p->GetType() == SC_CAT_CONTENT ) |
| pStack->Push( p ); |
| } |
| else |
| { |
| if ( p->IsDeleteType() ) |
| { // weiteres TopDelete in gleiche Ebene, |
| // es ist nicht rejectable |
| if ( ((ScChangeActionDel*)p)->IsTopDelete() ) |
| rTable.Insert( p->GetActionNumber(), p ); |
| } |
| else |
| rTable.Insert( p->GetActionNumber(), p ); |
| } |
| } |
| pL = pL->GetNext(); |
| } |
| } |
| } |
| } |
| else if ( pCur->GetType() == SC_CAT_MOVE ) |
| { |
| // geloeschte Contents im ToRange |
| const ScChangeActionLinkEntry* pL = pCur->GetFirstDeletedEntry(); |
| while ( pL ) |
| { |
| ScChangeAction* p = (ScChangeAction*) pL->GetAction(); |
| if ( p != pAct && rTable.Insert( p->GetActionNumber(), p ) ) |
| { |
| // nur ein TopContent einer Kette ist in LinkDeleted |
| if ( bAllFlat && (p->HasDeleted() || |
| p->GetType() == SC_CAT_CONTENT) ) |
| pStack->Push( p ); |
| } |
| pL = pL->GetNext(); |
| } |
| // neue Contents im FromRange oder neuer FromRange im ToRange |
| // oder Inserts/Deletes in FromRange/ToRange |
| pL = pCur->GetFirstDependentEntry(); |
| while ( pL ) |
| { |
| ScChangeAction* p = (ScChangeAction*) pL->GetAction(); |
| if ( p != pAct ) |
| { |
| if ( bAllFlat ) |
| { |
| sal_uLong n = p->GetActionNumber(); |
| if ( !IsGenerated( n ) && rTable.Insert( n, p ) ) |
| if ( p->HasDependent() || p->HasDeleted() ) |
| pStack->Push( p ); |
| } |
| else |
| { |
| if ( p->GetType() == SC_CAT_CONTENT ) |
| { |
| if ( ((ScChangeActionContent*)p)->IsTopContent() ) |
| rTable.Insert( p->GetActionNumber(), p ); |
| } |
| else |
| rTable.Insert( p->GetActionNumber(), p ); |
| } |
| } |
| pL = pL->GetNext(); |
| } |
| } |
| else if ( pCur->GetType() == SC_CAT_CONTENT ) |
| { // alle Aenderungen an gleicher Position |
| ScChangeActionContent* pContent = (ScChangeActionContent*) pCur; |
| // alle vorherigen |
| while ( ( pContent = pContent->GetPrevContent() ) != NULL ) |
| { |
| if ( !pContent->IsRejected() ) |
| rTable.Insert( pContent->GetActionNumber(), pContent ); |
| } |
| pContent = (ScChangeActionContent*) pCur; |
| // alle nachfolgenden |
| while ( ( pContent = pContent->GetNextContent() ) != NULL ) |
| { |
| if ( !pContent->IsRejected() ) |
| rTable.Insert( pContent->GetActionNumber(), pContent ); |
| } |
| // all MatrixReferences of a MatrixOrigin |
| const ScChangeActionLinkEntry* pL = pCur->GetFirstDependentEntry(); |
| while ( pL ) |
| { |
| ScChangeAction* p = (ScChangeAction*) pL->GetAction(); |
| if ( p != pAct ) |
| { |
| if ( bAllFlat ) |
| { |
| sal_uLong n = p->GetActionNumber(); |
| if ( !IsGenerated( n ) && rTable.Insert( n, p ) ) |
| if ( p->HasDependent() ) |
| pStack->Push( p ); |
| } |
| else |
| rTable.Insert( p->GetActionNumber(), p ); |
| } |
| pL = pL->GetNext(); |
| } |
| } |
| else if ( pCur->GetType() == SC_CAT_REJECT ) |
| { |
| if ( bAllFlat ) |
| { |
| ScChangeAction* p = GetAction( |
| ((ScChangeActionReject*)pCur)->GetRejectAction() ); |
| if ( p != pAct && !rTable.Get( p->GetActionNumber() ) ) |
| pStack->Push( p ); |
| } |
| } |
| } while ( ( pCur = pStack->Pop() ) != NULL ); |
| delete pStack; |
| } |
| |
| |
| sal_Bool ScChangeTrack::SelectContent( ScChangeAction* pAct, sal_Bool bOldest ) |
| { |
| if ( pAct->GetType() != SC_CAT_CONTENT ) |
| return sal_False; |
| |
| ScChangeActionContent* pContent = (ScChangeActionContent*) pAct; |
| if ( bOldest ) |
| { |
| pContent = pContent->GetTopContent(); |
| ScChangeActionContent* pPrevContent; |
| while ( (pPrevContent = pContent->GetPrevContent()) != NULL && |
| pPrevContent->IsVirgin() ) |
| pContent = pPrevContent; |
| } |
| |
| if ( !pContent->IsClickable() ) |
| return sal_False; |
| |
| ScBigRange aBigRange( pContent->GetBigRange() ); |
| const ScBaseCell* pCell = (bOldest ? pContent->GetOldCell() : |
| pContent->GetNewCell()); |
| if ( ScChangeActionContent::GetContentCellType( pCell ) == SC_CACCT_MATORG ) |
| { |
| SCCOL nC; |
| SCROW nR; |
| ((const ScFormulaCell*)pCell)->GetMatColsRows( nC, nR ); |
| aBigRange.aEnd.IncCol( nC-1 ); |
| aBigRange.aEnd.IncRow( nR-1 ); |
| } |
| |
| if ( !aBigRange.IsValid( pDoc ) ) |
| return sal_False; |
| |
| ScRange aRange( aBigRange.MakeRange() ); |
| if ( !pDoc->IsBlockEditable( aRange.aStart.Tab(), aRange.aStart.Col(), |
| aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() ) ) |
| return sal_False; |
| |
| if ( pContent->HasDependent() ) |
| { |
| sal_Bool bOk = sal_True; |
| Stack aRejectActions; |
| const ScChangeActionLinkEntry* pL = pContent->GetFirstDependentEntry(); |
| while ( pL ) |
| { |
| ScChangeAction* p = (ScChangeAction*) pL->GetAction(); |
| if ( p != pContent ) |
| { |
| if ( p->GetType() == SC_CAT_CONTENT ) |
| { |
| // we don't need no recursion here, do we? |
| bOk &= ((ScChangeActionContent*)p)->Select( pDoc, this, |
| bOldest, &aRejectActions ); |
| } |
| else |
| { |
| DBG_ERRORFILE( "ScChangeTrack::SelectContent: content dependent no content" ); |
| } |
| } |
| pL = pL->GetNext(); |
| } |
| |
| bOk &= pContent->Select( pDoc, this, bOldest, NULL ); |
| // now the matrix is inserted and new content values are ready |
| |
| ScChangeActionContent* pNew; |
| while ( ( pNew = (ScChangeActionContent*) aRejectActions.Pop() ) != NULL ) |
| { |
| ScAddress aPos( pNew->GetBigRange().aStart.MakeAddress() ); |
| pNew->SetNewValue( pDoc->GetCell( aPos ), pDoc ); |
| Append( pNew ); |
| } |
| return bOk; |
| } |
| else |
| return pContent->Select( pDoc, this, bOldest, NULL ); |
| } |
| |
| |
| void ScChangeTrack::AcceptAll() |
| { |
| for ( ScChangeAction* p = GetFirst(); p; p = p->GetNext() ) |
| { |
| p->Accept(); |
| } |
| } |
| |
| |
| sal_Bool ScChangeTrack::Accept( ScChangeAction* pAct ) |
| { |
| if ( !pAct->IsClickable() ) |
| return sal_False; |
| |
| if ( pAct->IsDeleteType() || pAct->GetType() == SC_CAT_CONTENT ) |
| { |
| ScChangeActionTable aActionTable; |
| GetDependents( pAct, aActionTable, sal_False, sal_True ); |
| for ( ScChangeAction* p = aActionTable.First(); p; p = aActionTable.Next() ) |
| { |
| p->Accept(); |
| } |
| } |
| pAct->Accept(); |
| return sal_True; |
| } |
| |
| |
| sal_Bool ScChangeTrack::RejectAll() |
| { |
| sal_Bool bOk = sal_True; |
| for ( ScChangeAction* p = GetLast(); p && bOk; p = p->GetPrev() ) |
| { //! rueckwaerts, weil abhaengige hinten und RejectActions angehaengt |
| if ( p->IsInternalRejectable() ) |
| bOk = Reject( p ); |
| } |
| return bOk; |
| } |
| |
| |
| sal_Bool ScChangeTrack::Reject( ScChangeAction* pAct, bool bShared ) |
| { |
| // #i100895# When collaboration changes are reversed, it must be possible |
| // to reject a deleted row above another deleted row. |
| if ( bShared && pAct->IsDeletedIn() ) |
| pAct->RemoveAllDeletedIn(); |
| |
| if ( !pAct->IsRejectable() ) |
| return sal_False; |
| |
| ScChangeActionTable* pTable = NULL; |
| if ( pAct->HasDependent() ) |
| { |
| pTable = new ScChangeActionTable; |
| GetDependents( pAct, *pTable, sal_False, sal_True ); |
| } |
| sal_Bool bRejected = Reject( pAct, pTable, sal_False ); |
| if ( pTable ) |
| delete pTable; |
| return bRejected; |
| } |
| |
| |
| sal_Bool ScChangeTrack::Reject( ScChangeAction* pAct, ScChangeActionTable* pTable, |
| sal_Bool bRecursion ) |
| { |
| if ( !pAct->IsInternalRejectable() ) |
| return sal_False; |
| |
| sal_Bool bOk = sal_True; |
| sal_Bool bRejected = sal_False; |
| if ( pAct->IsInsertType() ) |
| { |
| if ( pAct->HasDependent() && !bRecursion ) |
| { |
| DBG_ASSERT( pTable, "ScChangeTrack::Reject: Insert ohne Table" ); |
| for ( ScChangeAction* p = pTable->Last(); p && bOk; p = pTable->Prev() ) |
| { |
| // keine Contents restoren, die eh geloescht werden wuerden |
| if ( p->GetType() == SC_CAT_CONTENT ) |
| p->SetRejected(); |
| else if ( p->IsDeleteType() ) |
| p->Accept(); // geloeschtes ins Nirvana |
| else |
| bOk = Reject( p, NULL, sal_True ); //! rekursiv |
| } |
| } |
| if ( bOk && (bRejected = pAct->Reject( pDoc )) != sal_False ) |
| { |
| // pRefDoc NULL := geloeschte Zellen nicht speichern |
| AppendDeleteRange( pAct->GetBigRange().MakeRange(), NULL, (short) 0, |
| pAct->GetActionNumber() ); |
| } |
| } |
| else if ( pAct->IsDeleteType() ) |
| { |
| DBG_ASSERT( !pTable, "ScChangeTrack::Reject: Delete mit Table" ); |
| ScBigRange aDelRange; |
| sal_uLong nRejectAction = pAct->GetActionNumber(); |
| sal_Bool bTabDel, bTabDelOk; |
| if ( pAct->GetType() == SC_CAT_DELETE_TABS ) |
| { |
| bTabDel = sal_True; |
| aDelRange = pAct->GetBigRange(); |
| bOk = bTabDelOk = pAct->Reject( pDoc ); |
| if ( bOk ) |
| { |
| pAct = pAct->GetPrev(); |
| bOk = ( pAct && pAct->GetType() == SC_CAT_DELETE_COLS ); |
| } |
| } |
| else |
| bTabDel = bTabDelOk = sal_False; |
| ScChangeActionDel* pDel = (ScChangeActionDel*) pAct; |
| if ( bOk ) |
| { |
| aDelRange = pDel->GetOverAllRange(); |
| bOk = aDelRange.IsValid( pDoc ); |
| } |
| sal_Bool bOneOk = sal_False; |
| if ( bOk ) |
| { |
| ScChangeActionType eActType = pAct->GetType(); |
| switch ( eActType ) |
| { |
| case SC_CAT_DELETE_COLS : |
| aDelRange.aStart.SetCol( aDelRange.aEnd.Col() ); |
| break; |
| case SC_CAT_DELETE_ROWS : |
| aDelRange.aStart.SetRow( aDelRange.aEnd.Row() ); |
| break; |
| case SC_CAT_DELETE_TABS : |
| aDelRange.aStart.SetTab( aDelRange.aEnd.Tab() ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| ScChangeAction* p = pAct; |
| sal_Bool bLoop = sal_True; |
| do |
| { |
| pDel = (ScChangeActionDel*) p; |
| bOk = pDel->Reject( pDoc ); |
| if ( bOk ) |
| { |
| if ( bOneOk ) |
| { |
| switch ( pDel->GetType() ) |
| { |
| case SC_CAT_DELETE_COLS : |
| aDelRange.aStart.IncCol( -1 ); |
| break; |
| case SC_CAT_DELETE_ROWS : |
| aDelRange.aStart.IncRow( -1 ); |
| break; |
| case SC_CAT_DELETE_TABS : |
| aDelRange.aStart.IncTab( -1 ); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| else |
| bOneOk = sal_True; |
| } |
| if ( pDel->IsBaseDelete() ) |
| bLoop = sal_False; |
| else |
| p = p->GetPrev(); |
| } while ( bOk && bLoop && p && p->GetType() == eActType && |
| !((ScChangeActionDel*)p)->IsTopDelete() ); |
| } |
| bRejected = bOk; |
| if ( bOneOk || (bTabDel && bTabDelOk) ) |
| { |
| // Delete-Reject machte UpdateReference Undo |
| ScChangeActionIns* pReject = new ScChangeActionIns( |
| aDelRange.MakeRange() ); |
| pReject->SetRejectAction( nRejectAction ); |
| pReject->SetState( SC_CAS_ACCEPTED ); |
| Append( pReject ); |
| } |
| } |
| else if ( pAct->GetType() == SC_CAT_MOVE ) |
| { |
| if ( pAct->HasDependent() && !bRecursion ) |
| { |
| DBG_ASSERT( pTable, "ScChangeTrack::Reject: Move ohne Table" ); |
| for ( ScChangeAction* p = pTable->Last(); p && bOk; p = pTable->Prev() ) |
| { |
| bOk = Reject( p, NULL, sal_True ); //! rekursiv |
| } |
| } |
| if ( bOk && (bRejected = pAct->Reject( pDoc )) != sal_False ) |
| { |
| ScChangeActionMove* pReject = new ScChangeActionMove( |
| pAct->GetBigRange().MakeRange(), |
| ((ScChangeActionMove*)pAct)->GetFromRange().MakeRange(), this ); |
| pReject->SetRejectAction( pAct->GetActionNumber() ); |
| pReject->SetState( SC_CAS_ACCEPTED ); |
| Append( pReject ); |
| } |
| } |
| else if ( pAct->GetType() == SC_CAT_CONTENT ) |
| { |
| ScRange aRange; |
| ScChangeActionContent* pReject; |
| if ( bRecursion ) |
| pReject = NULL; |
| else |
| { |
| aRange = pAct->GetBigRange().aStart.MakeAddress(); |
| pReject = new ScChangeActionContent( aRange ); |
| pReject->SetOldValue( pDoc->GetCell( aRange.aStart ), pDoc, pDoc ); |
| } |
| if ( (bRejected = pAct->Reject( pDoc )) != sal_False && !bRecursion ) |
| { |
| pReject->SetNewValue( pDoc->GetCell( aRange.aStart ), pDoc ); |
| pReject->SetRejectAction( pAct->GetActionNumber() ); |
| pReject->SetState( SC_CAS_ACCEPTED ); |
| Append( pReject ); |
| } |
| else if ( pReject ) |
| delete pReject; |
| } |
| else |
| { |
| DBG_ERROR( "ScChangeTrack::Reject: say what?" ); |
| } |
| |
| return bRejected; |
| } |
| |
| |
| sal_uLong ScChangeTrack::AddLoadedGenerated(ScBaseCell* pNewCell, const ScBigRange& aBigRange, const String& sNewValue ) |
| { |
| ScChangeActionContent* pAct = new ScChangeActionContent( --nGeneratedMin, pNewCell, aBigRange, pDoc, sNewValue ); |
| if ( pAct ) |
| { |
| if ( pFirstGeneratedDelContent ) |
| pFirstGeneratedDelContent->pPrev = pAct; |
| pAct->pNext = pFirstGeneratedDelContent; |
| pFirstGeneratedDelContent = pAct; |
| aGeneratedTable.Insert( pAct->GetActionNumber(), pAct ); |
| return pAct->GetActionNumber(); |
| } |
| return 0; |
| } |
| |
| void ScChangeTrack::AppendCloned( ScChangeAction* pAppend ) |
| { |
| aTable.Insert( pAppend->GetActionNumber(), pAppend ); |
| if ( !pLast ) |
| pFirst = pLast = pAppend; |
| else |
| { |
| pLast->pNext = pAppend; |
| pAppend->pPrev = pLast; |
| pLast = pAppend; |
| } |
| } |
| |
| ScChangeTrack* ScChangeTrack::Clone( ScDocument* pDocument ) const |
| { |
| if ( !pDocument ) |
| { |
| return NULL; |
| } |
| |
| ScChangeTrack* pClonedTrack = new ScChangeTrack( pDocument ); |
| pClonedTrack->SetTime100thSeconds( IsTime100thSeconds() ); |
| |
| // clone generated actions |
| ::std::stack< const ScChangeAction* > aGeneratedStack; |
| const ScChangeAction* pGenerated = GetFirstGenerated(); |
| while ( pGenerated ) |
| { |
| aGeneratedStack.push( pGenerated ); |
| pGenerated = pGenerated->GetNext(); |
| } |
| while ( !aGeneratedStack.empty() ) |
| { |
| pGenerated = aGeneratedStack.top(); |
| aGeneratedStack.pop(); |
| const ScChangeActionContent* pContent = dynamic_cast< const ScChangeActionContent* >( pGenerated ); |
| DBG_ASSERT( pContent, "ScChangeTrack::Clone: pContent is null!" ); |
| const ScBaseCell* pNewCell = pContent->GetNewCell(); |
| if ( pNewCell ) |
| { |
| ScBaseCell* pClonedNewCell = pNewCell->CloneWithoutNote( *pDocument ); |
| String aNewValue; |
| pContent->GetNewString( aNewValue ); |
| pClonedTrack->nGeneratedMin = pGenerated->GetActionNumber() + 1; |
| pClonedTrack->AddLoadedGenerated( pClonedNewCell, pGenerated->GetBigRange(), aNewValue ); |
| } |
| } |
| |
| // clone actions |
| const ScChangeAction* pAction = GetFirst(); |
| while ( pAction ) |
| { |
| ScChangeAction* pClonedAction = NULL; |
| |
| switch ( pAction->GetType() ) |
| { |
| case SC_CAT_INSERT_COLS: |
| case SC_CAT_INSERT_ROWS: |
| case SC_CAT_INSERT_TABS: |
| { |
| pClonedAction = new ScChangeActionIns( |
| pAction->GetActionNumber(), |
| pAction->GetState(), |
| pAction->GetRejectAction(), |
| pAction->GetBigRange(), |
| pAction->GetUser(), |
| pAction->GetDateTimeUTC(), |
| pAction->GetComment(), |
| pAction->GetType() ); |
| } |
| break; |
| case SC_CAT_DELETE_COLS: |
| case SC_CAT_DELETE_ROWS: |
| case SC_CAT_DELETE_TABS: |
| { |
| const ScChangeActionDel* pDelete = dynamic_cast< const ScChangeActionDel* >( pAction ); |
| DBG_ASSERT( pDelete, "ScChangeTrack::Clone: pDelete is null!" ); |
| |
| SCsCOLROW nD = 0; |
| ScChangeActionType eType = pAction->GetType(); |
| if ( eType == SC_CAT_DELETE_COLS ) |
| { |
| nD = static_cast< SCsCOLROW >( pDelete->GetDx() ); |
| } |
| else if ( eType == SC_CAT_DELETE_ROWS ) |
| { |
| nD = static_cast< SCsCOLROW >( pDelete->GetDy() ); |
| } |
| |
| pClonedAction = new ScChangeActionDel( |
| pAction->GetActionNumber(), |
| pAction->GetState(), |
| pAction->GetRejectAction(), |
| pAction->GetBigRange(), |
| pAction->GetUser(), |
| pAction->GetDateTimeUTC(), |
| pAction->GetComment(), |
| eType, |
| nD, |
| pClonedTrack ); |
| } |
| break; |
| case SC_CAT_MOVE: |
| { |
| const ScChangeActionMove* pMove = dynamic_cast< const ScChangeActionMove* >( pAction ); |
| DBG_ASSERT( pMove, "ScChangeTrack::Clone: pMove is null!" ); |
| |
| pClonedAction = new ScChangeActionMove( |
| pAction->GetActionNumber(), |
| pAction->GetState(), |
| pAction->GetRejectAction(), |
| pAction->GetBigRange(), |
| pAction->GetUser(), |
| pAction->GetDateTimeUTC(), |
| pAction->GetComment(), |
| pMove->GetFromRange(), |
| pClonedTrack ); |
| } |
| break; |
| case SC_CAT_CONTENT: |
| { |
| const ScChangeActionContent* pContent = dynamic_cast< const ScChangeActionContent* >( pAction ); |
| DBG_ASSERT( pContent, "ScChangeTrack::Clone: pContent is null!" ); |
| const ScBaseCell* pOldCell = pContent->GetOldCell(); |
| ScBaseCell* pClonedOldCell = pOldCell ? pOldCell->CloneWithoutNote( *pDocument ) : 0; |
| String aOldValue; |
| pContent->GetOldString( aOldValue ); |
| |
| ScChangeActionContent* pClonedContent = new ScChangeActionContent( |
| pAction->GetActionNumber(), |
| pAction->GetState(), |
| pAction->GetRejectAction(), |
| pAction->GetBigRange(), |
| pAction->GetUser(), |
| pAction->GetDateTimeUTC(), |
| pAction->GetComment(), |
| pClonedOldCell, |
| pDocument, |
| aOldValue ); |
| |
| const ScBaseCell* pNewCell = pContent->GetNewCell(); |
| if ( pNewCell ) |
| { |
| ScBaseCell* pClonedNewCell = pNewCell->CloneWithoutNote( *pDocument ); |
| pClonedContent->SetNewValue( pClonedNewCell, pDocument ); |
| } |
| |
| pClonedAction = pClonedContent; |
| } |
| break; |
| case SC_CAT_REJECT: |
| { |
| pClonedAction = new ScChangeActionReject( |
| pAction->GetActionNumber(), |
| pAction->GetState(), |
| pAction->GetRejectAction(), |
| pAction->GetBigRange(), |
| pAction->GetUser(), |
| pAction->GetDateTimeUTC(), |
| pAction->GetComment() ); |
| } |
| break; |
| default: |
| { |
| } |
| break; |
| } |
| |
| if ( pClonedAction ) |
| { |
| pClonedTrack->AppendCloned( pClonedAction ); |
| } |
| |
| pAction = pAction->GetNext(); |
| } |
| |
| if ( pClonedTrack->GetLast() ) |
| { |
| pClonedTrack->SetActionMax( pClonedTrack->GetLast()->GetActionNumber() ); |
| } |
| |
| // set dependencies for Deleted/DeletedIn |
| pAction = GetFirst(); |
| while ( pAction ) |
| { |
| if ( pAction->HasDeleted() ) |
| { |
| ::std::stack< sal_uLong > aStack; |
| const ScChangeActionLinkEntry* pL = pAction->GetFirstDeletedEntry(); |
| while ( pL ) |
| { |
| const ScChangeAction* pDeleted = pL->GetAction(); |
| if ( pDeleted ) |
| { |
| aStack.push( pDeleted->GetActionNumber() ); |
| } |
| pL = pL->GetNext(); |
| } |
| ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() ); |
| if ( pClonedAction ) |
| { |
| while ( !aStack.empty() ) |
| { |
| ScChangeAction* pClonedDeleted = pClonedTrack->GetActionOrGenerated( aStack.top() ); |
| aStack.pop(); |
| if ( pClonedDeleted ) |
| { |
| pClonedDeleted->SetDeletedIn( pClonedAction ); |
| } |
| } |
| } |
| } |
| pAction = pAction->GetNext(); |
| } |
| |
| // set dependencies for Dependent/Any |
| pAction = GetLast(); |
| while ( pAction ) |
| { |
| if ( pAction->HasDependent() ) |
| { |
| ::std::stack< sal_uLong > aStack; |
| const ScChangeActionLinkEntry* pL = pAction->GetFirstDependentEntry(); |
| while ( pL ) |
| { |
| const ScChangeAction* pDependent = pL->GetAction(); |
| if ( pDependent ) |
| { |
| aStack.push( pDependent->GetActionNumber() ); |
| } |
| pL = pL->GetNext(); |
| } |
| ScChangeAction* pClonedAction = pClonedTrack->GetAction( pAction->GetActionNumber() ); |
| if ( pClonedAction ) |
| { |
| while ( !aStack.empty() ) |
| { |
| ScChangeAction* pClonedDependent = pClonedTrack->GetActionOrGenerated( aStack.top() ); |
| aStack.pop(); |
| if ( pClonedDependent ) |
| { |
| ScChangeActionLinkEntry* pLink = pClonedAction->AddDependent( pClonedDependent ); |
| pClonedDependent->AddLink( pClonedAction, pLink ); |
| } |
| } |
| } |
| } |
| pAction = pAction->GetPrev(); |
| } |
| |
| // masterlinks |
| ScChangeAction* pClonedAction = pClonedTrack->GetFirst(); |
| while ( pClonedAction ) |
| { |
| pClonedTrack->MasterLinks( pClonedAction ); |
| pClonedAction = pClonedAction->GetNext(); |
| } |
| |
| if ( IsProtected() ) |
| { |
| pClonedTrack->SetProtection( GetProtection() ); |
| } |
| |
| if ( pClonedTrack->GetLast() ) |
| { |
| pClonedTrack->SetLastSavedActionNumber( pClonedTrack->GetLast()->GetActionNumber() ); |
| } |
| |
| pDocument->SetChangeTrack( pClonedTrack ); |
| |
| return pClonedTrack; |
| } |
| |
| void ScChangeTrack::MergeActionState( ScChangeAction* pAct, const ScChangeAction* pOtherAct ) |
| { |
| if ( pAct->IsVirgin() ) |
| { |
| if ( pOtherAct->IsAccepted() ) |
| { |
| pAct->Accept(); |
| if ( pOtherAct->IsRejecting() ) |
| { |
| pAct->SetRejectAction( pOtherAct->GetRejectAction() ); |
| } |
| } |
| else if ( pOtherAct->IsRejected() ) |
| { |
| pAct->SetRejected(); |
| } |
| } |
| } |
| |
| #if DEBUG_CHANGETRACK |
| String ScChangeTrack::ToString() const |
| { |
| String aReturn; |
| |
| aReturn += String::CreateFromAscii( "============================================================\n" ); |
| |
| const ScChangeAction* pGenerated = GetFirstGenerated(); |
| while ( pGenerated ) |
| { |
| aReturn += pGenerated->ToString( pDoc ); |
| aReturn += '\n'; |
| pGenerated = pGenerated->GetNext(); |
| } |
| |
| aReturn += String::CreateFromAscii( "------------------------------------------------------------\n" ); |
| |
| const ScChangeAction* pAction = GetFirst(); |
| while ( pAction ) |
| { |
| aReturn += pAction->ToString( pDoc ); |
| aReturn += '\n'; |
| pAction = pAction->GetNext(); |
| } |
| aReturn += String::CreateFromAscii( "============================================================\n" ); |
| |
| return aReturn; |
| } |
| #endif // DEBUG_CHANGETRACK |