/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" // System - Includes ----------------------------------------------------- #include #include // INCLUDE --------------------------------------------------------------- #include "olinetab.hxx" #include "global.hxx" #include "rechead.hxx" #include "address.hxx" //------------------------------------------------------------------------ ScOutlineEntry::ScOutlineEntry( SCCOLROW nNewStart, SCCOLROW nNewSize, BOOL bNewHidden ) : nStart ( nNewStart ), nSize ( nNewSize ), bHidden ( bNewHidden ), bVisible( TRUE ) { } ScOutlineEntry::ScOutlineEntry( const ScOutlineEntry& rEntry ) : ScDataObject(), nStart ( rEntry.nStart ), nSize ( rEntry.nSize ), bHidden ( rEntry.bHidden ), bVisible( rEntry.bVisible ) { } ScDataObject* ScOutlineEntry::Clone() const { return new ScOutlineEntry( *this ); } void ScOutlineEntry::Move( SCsCOLROW nDelta ) { SCCOLROW nNewPos = nStart + nDelta; if (nNewPos<0) { DBG_ERROR("OutlineEntry < 0"); nNewPos = 0; } nStart = nNewPos; } void ScOutlineEntry::SetSize( SCSIZE nNewSize ) { if (nNewSize>0) nSize = nNewSize; else { DBG_ERROR("ScOutlineEntry Size == 0"); } } void ScOutlineEntry::SetPosSize( SCCOLROW nNewPos, SCSIZE nNewSize ) { nStart = nNewPos; SetSize( nNewSize ); } void ScOutlineEntry::SetHidden( BOOL bNewHidden ) { bHidden = bNewHidden; } void ScOutlineEntry::SetVisible( BOOL bNewVisible ) { bVisible = bNewVisible; } //------------------------------------------------------------------------ ScOutlineCollection::ScOutlineCollection() : ScSortedCollection( 4,4,FALSE ) { } inline short IntCompare( SCCOLROW nX, SCCOLROW nY ) { if ( nX==nY ) return 0; else if ( nXGetStart(), ((ScOutlineEntry*)pKey2)->GetStart() ); } USHORT ScOutlineCollection::FindStart( SCCOLROW nMinStart ) { //! binaer suchen ? USHORT nPos = 0; USHORT nLocalCount = GetCount(); while ( (nPosGetStart() < nMinStart) : FALSE ) ++nPos; return nPos; } //------------------------------------------------------------------------ ScOutlineArray::ScOutlineArray() : nDepth( 0 ) { } ScOutlineArray::ScOutlineArray( const ScOutlineArray& rArray ) : nDepth( rArray.nDepth ) { for (USHORT nLevel=0; nLevel nDepth) nMaxLevel = nDepth; for (USHORT nLevel=0; nLevelGetCount(); for (USHORT i=0; iAt(i); if ( pEntry->GetStart() <= nSearchPos && pEntry->GetEnd() >= nSearchPos ) { rFindLevel = nLevel + 1; // naechster Level (zum Einfuegen) rFindIndex = i; } } } } BOOL ScOutlineArray::Insert( SCCOLROW nStartCol, SCCOLROW nEndCol, BOOL& rSizeChanged, BOOL bHidden, BOOL bVisible ) { rSizeChanged = FALSE; USHORT nStartLevel; USHORT nStartIndex; USHORT nEndLevel; USHORT nEndIndex; BOOL bFound = FALSE; BOOL bCont; USHORT nFindMax; FindEntry( nStartCol, nStartLevel, nStartIndex ); // nLevel = neuer Level (alter+1) !!! FindEntry( nEndCol, nEndLevel, nEndIndex ); nFindMax = Max(nStartLevel,nEndLevel); do { bCont = FALSE; if ( nStartLevel == nEndLevel && nStartIndex == nEndIndex && nStartLevel < SC_OL_MAXDEPTH ) bFound = TRUE; if (!bFound) { if (nFindMax>0) { --nFindMax; if (nStartLevel) if ( ((ScOutlineEntry*)aCollections[nStartLevel-1].At(nStartIndex))-> GetStart() == nStartCol ) FindEntry( nStartCol, nStartLevel, nStartIndex, nFindMax ); if (nEndLevel) if ( ((ScOutlineEntry*)aCollections[nEndLevel-1].At(nEndIndex))-> GetEnd() == nEndCol ) FindEntry( nEndCol, nEndLevel, nEndIndex, nFindMax ); bCont = TRUE; } } } while ( !bFound && bCont ); if (!bFound) return FALSE; USHORT nLevel = nStartLevel; // untere verschieben BOOL bNeedSize = FALSE; for ( short nMoveLevel = nDepth-1; nMoveLevel >= (short) nLevel; nMoveLevel-- ) { USHORT nCount = aCollections[nMoveLevel].GetCount(); BOOL bMoved = FALSE; for ( USHORT i=0; iGetStart(); if ( nEntryStart >= nStartCol && nEntryStart <= nEndCol ) { if (nMoveLevel >= SC_OL_MAXDEPTH - 1) { rSizeChanged = FALSE; // kein Platz return FALSE; } aCollections[nMoveLevel+1].Insert( new ScOutlineEntry( *pEntry ) ); aCollections[nMoveLevel].AtFree( i ); nCount = aCollections[nMoveLevel].GetCount(); bMoved = TRUE; if (nMoveLevel == (short) nDepth - 1) bNeedSize = TRUE; } else bMoved = FALSE; } } if (bNeedSize) { ++nDepth; rSizeChanged = TRUE; } if (nDepth <= nLevel) { nDepth = nLevel+1; rSizeChanged = TRUE; } /* nicht zusammenfassen! // zusammenfassen USHORT nCount = aCollections[nLevel].GetCount(); USHORT nIndex; bFound = FALSE; for ( nIndex=0; nIndexGetEnd() + 1 == nStartCol ) { nStartCol = ((ScOutlineEntry*) aCollections[nLevel].At(nIndex))->GetStart(); aCollections[nLevel].AtFree(nIndex); nCount = aCollections[nLevel].GetCount(); // Daten geaendert bFound = TRUE; } } bFound = FALSE; for ( nIndex=0; nIndexGetStart() == nEndCol + 1 ) { nEndCol = ((ScOutlineEntry*) aCollections[nLevel].At(nIndex))->GetEnd(); aCollections[nLevel].AtFree(nIndex); bFound = TRUE; } } */ ScOutlineEntry* pNewEntry = new ScOutlineEntry( nStartCol, nEndCol+1-nStartCol, bHidden ); pNewEntry->SetVisible( bVisible ); aCollections[nLevel].Insert( pNewEntry ); return TRUE; } BOOL ScOutlineArray::FindTouchedLevel( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, USHORT& rFindLevel ) const { BOOL bFound = FALSE; rFindLevel = 0; for (USHORT nLevel=0; nLevelGetCount(); for (USHORT i=0; iAt(i); SCCOLROW nStart = pEntry->GetStart(); SCCOLROW nEnd = pEntry->GetEnd(); if ( ( nBlockStart>=nStart && nBlockStart<=nEnd ) || ( nBlockEnd >=nStart && nBlockEnd <=nEnd ) ) { rFindLevel = nLevel; // wirklicher Level bFound = TRUE; } } } return bFound; } void ScOutlineArray::RemoveSub( SCCOLROW nStartPos, SCCOLROW nEndPos, USHORT nLevel ) { if ( nLevel >= nDepth ) return; ScOutlineCollection* pCollect = &aCollections[nLevel]; USHORT nCount = pCollect->GetCount(); BOOL bFound = FALSE; for ( USHORT i=0; iAt(i); SCCOLROW nStart = pEntry->GetStart(); SCCOLROW nEnd = pEntry->GetEnd(); if ( nStart>=nStartPos && nEnd<=nEndPos ) { RemoveSub( nStart, nEnd, nLevel+1 ); pCollect->AtFree(i); nCount = pCollect->GetCount(); bFound = TRUE; } } } void ScOutlineArray::PromoteSub( SCCOLROW nStartPos, SCCOLROW nEndPos, USHORT nStartLevel ) { if (nStartLevel==0) { DBG_ERROR("PromoteSub mit Level 0"); return; } for (USHORT nLevel = nStartLevel; nLevel < nDepth; nLevel++) { ScOutlineCollection* pCollect = &aCollections[nLevel]; USHORT nCount = pCollect->GetCount(); BOOL bFound = FALSE; for ( USHORT i=0; iAt(i); SCCOLROW nStart = pEntry->GetStart(); SCCOLROW nEnd = pEntry->GetEnd(); if ( nStart>=nStartPos && nEnd<=nEndPos ) { aCollections[nLevel-1].Insert( new ScOutlineEntry( *pEntry ) ); pCollect->AtFree(i); nCount = pCollect->GetCount(); bFound = TRUE; } } } } BOOL ScOutlineArray::DecDepth() // nDepth auf leere Levels anpassen { BOOL bChanged = FALSE; BOOL bCont; do { bCont = FALSE; if (nDepth) if (aCollections[nDepth-1].GetCount() == 0) { --nDepth; bChanged = TRUE; bCont = TRUE; } } while (bCont); return bChanged; } BOOL ScOutlineArray::Remove( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, BOOL& rSizeChanged ) { USHORT nLevel; FindTouchedLevel( nBlockStart, nBlockEnd, nLevel ); ScOutlineCollection* pCollect = &aCollections[nLevel]; USHORT nCount = pCollect->GetCount(); BOOL bFound = FALSE; BOOL bAny = FALSE; for ( USHORT i=0; iAt(i); SCCOLROW nStart = pEntry->GetStart(); SCCOLROW nEnd = pEntry->GetEnd(); if ( nBlockStart<=nEnd && nBlockEnd>=nStart ) { // RemoveSub( nStart, nEnd, nLevel+1 ); pCollect->AtFree(i); PromoteSub( nStart, nEnd, nLevel+1 ); nCount = pCollect->GetCount(); i = pCollect->FindStart( nEnd+1 ); bFound = TRUE; bAny = TRUE; } } if (bAny) // Depth anpassen if (DecDepth()) rSizeChanged = TRUE; return bAny; } ScOutlineEntry* ScOutlineArray::GetEntry( USHORT nLevel, USHORT nIndex ) const { return (ScOutlineEntry*)((nLevel < nDepth) ? aCollections[nLevel].At(nIndex) : NULL); } USHORT ScOutlineArray::GetCount( USHORT nLevel ) const { return (nLevel < nDepth) ? aCollections[nLevel].GetCount() : 0; } ScOutlineEntry* ScOutlineArray::GetEntryByPos( USHORT nLevel, SCCOLROW nPos ) const { USHORT nCount = GetCount( nLevel ); ScOutlineEntry* pEntry; for (USHORT nIndex = 0; nIndex < nCount; nIndex++) { pEntry = GetEntry( nLevel, nIndex ); if ((pEntry->GetStart() <= nPos) && (nPos <= pEntry->GetEnd())) return pEntry; } return NULL; } BOOL ScOutlineArray::GetEntryIndex( USHORT nLevel, SCCOLROW nPos, USHORT& rnIndex ) const { // found entry contains passed position USHORT nCount = GetCount( nLevel ); for ( rnIndex = 0; rnIndex < nCount; ++rnIndex ) { const ScOutlineEntry* pEntry = GetEntry( nLevel, rnIndex ); if ( (pEntry->GetStart() <= nPos) && (nPos <= pEntry->GetEnd()) ) return TRUE; } return FALSE; } BOOL ScOutlineArray::GetEntryIndexInRange( USHORT nLevel, SCCOLROW nBlockStart, SCCOLROW nBlockEnd, USHORT& rnIndex ) const { // found entry will be completely inside of passed range USHORT nCount = GetCount( nLevel ); for ( rnIndex = 0; rnIndex < nCount; ++rnIndex ) { const ScOutlineEntry* pEntry = GetEntry( nLevel, rnIndex ); if ( (nBlockStart <= pEntry->GetStart()) && (pEntry->GetEnd() <= nBlockEnd) ) return TRUE; } return FALSE; } void ScOutlineArray::SetVisibleBelow( USHORT nLevel, USHORT nEntry, BOOL bValue, BOOL bSkipHidden ) { ScOutlineEntry* pEntry = GetEntry( nLevel, nEntry ); if( pEntry ) { SCCOLROW nStart = pEntry->GetStart(); SCCOLROW nEnd = pEntry->GetEnd(); for (USHORT nSubLevel=nLevel+1; nSubLevelGetStart() >= nStart && pEntry->GetEnd() <= nEnd) { pEntry->SetVisible(bValue); if (bSkipHidden) if (!pEntry->IsHidden()) SetVisibleBelow( nSubLevel, i, bValue, TRUE ); } ++i; pEntry = (ScOutlineEntry*) aCollections[nSubLevel].At(i); } if (bSkipHidden) nSubLevel = nDepth; // Abbruch } } } void ScOutlineArray::GetRange( SCCOLROW& rStart, SCCOLROW& rEnd ) const { USHORT nCount = aCollections[0].GetCount(); if (nCount) { rStart = ((ScOutlineEntry*) aCollections[0].At(0))->GetStart(); rEnd = ((ScOutlineEntry*) aCollections[0].At(nCount-1))->GetEnd(); } else rStart = rEnd = 0; } void ScOutlineArray::ExtendBlock( USHORT nLevel, SCCOLROW& rBlkStart, SCCOLROW& rBlkEnd ) { USHORT nCount; SCCOLROW nStart; SCCOLROW nEnd; USHORT i; ScOutlineEntry* pEntry; nCount = GetCount(nLevel); for ( i=0; iGetStart(); nEnd = pEntry->GetEnd(); if ( rBlkStart<=nEnd && rBlkEnd>=nStart ) { if (nStartrBlkEnd) rBlkEnd = nEnd; } } } BOOL ScOutlineArray::TestInsertSpace( SCSIZE nSize, SCCOLROW nMaxVal ) const { USHORT nCount = aCollections[0].GetCount(); if (nCount) { SCCOLROW nEnd = ((ScOutlineEntry*) aCollections[0].At(nCount-1))->GetEnd(); return ( sal::static_int_cast(nEnd+nSize) <= nMaxVal ); } return TRUE; } void ScOutlineArray::InsertSpace( SCCOLROW nStartPos, SCSIZE nSize ) { ScSubOutlineIterator aIter( this ); ScOutlineEntry* pEntry; while((pEntry=aIter.GetNext())!=NULL) { if ( pEntry->GetStart() >= nStartPos ) pEntry->Move(static_cast(nSize)); else { SCCOLROW nEnd = pEntry->GetEnd(); // immer erweitern, wenn innerhalb der Gruppe eingefuegt // beim Einfuegen am Ende nur, wenn die Gruppe nicht ausgeblendet ist if ( nEnd >= nStartPos || ( nEnd+1 >= nStartPos && !pEntry->IsHidden() ) ) { SCSIZE nEntrySize = pEntry->GetSize(); nEntrySize += nSize; pEntry->SetSize( nEntrySize ); } } } } BOOL ScOutlineArray::DeleteSpace( SCCOLROW nStartPos, SCSIZE nSize ) { SCCOLROW nEndPos = nStartPos + nSize - 1; BOOL bNeedSave = FALSE; // Original fuer Undo benoetigt? BOOL bChanged = FALSE; // fuer Test auf Level ScSubOutlineIterator aIter( this ); ScOutlineEntry* pEntry; while((pEntry=aIter.GetNext())!=NULL) { SCCOLROW nEntryStart = pEntry->GetStart(); SCCOLROW nEntryEnd = pEntry->GetEnd(); SCSIZE nEntrySize = pEntry->GetSize(); if ( nEntryEnd >= nStartPos ) { if ( nEntryStart > nEndPos ) // rechts pEntry->Move(-(static_cast(nSize))); else if ( nEntryStart < nStartPos && nEntryEnd >= nEndPos ) // aussen pEntry->SetSize( nEntrySize-nSize ); else { bNeedSave = TRUE; if ( nEntryStart >= nStartPos && nEntryEnd <= nEndPos ) // innen { aIter.DeleteLast(); bChanged = TRUE; } else if ( nEntryStart >= nStartPos ) // rechts ueber pEntry->SetPosSize( nStartPos, static_cast(nEntryEnd-nEndPos) ); else // links ueber pEntry->SetSize( static_cast(nStartPos-nEntryStart) ); } } } if (bChanged) DecDepth(); return bNeedSave; } BOOL ScOutlineArray::ManualAction( SCCOLROW nStartPos, SCCOLROW nEndPos, BOOL bShow, const ScBitMaskCompressedArray< SCCOLROW, BYTE>& rHiddenFlags ) { BOOL bModified = FALSE; ScSubOutlineIterator aIter( this ); ScOutlineEntry* pEntry; while((pEntry=aIter.GetNext())!=NULL) { SCCOLROW nEntryStart = pEntry->GetStart(); SCCOLROW nEntryEnd = pEntry->GetEnd(); if (nEntryEnd>=nStartPos && nEntryStart<=nEndPos) { if ( pEntry->IsHidden() == bShow ) { // #i12341# hide if all columns/rows are hidden, show if at least one // is visible SCCOLROW nEnd = rHiddenFlags.GetBitStateEnd( nEntryStart, CR_HIDDEN, CR_HIDDEN); BOOL bAllHidden = (nEntryEnd <= nEnd && nEnd < ::std::numeric_limits::max()); BOOL bToggle = ( bShow != bAllHidden ); if ( bToggle ) { pEntry->SetHidden( !bShow ); SetVisibleBelow( aIter.LastLevel(), aIter.LastEntry(), bShow, bShow ); bModified = TRUE; } } } } return bModified; } void ScOutlineArray::RemoveAll() { for (USHORT nLevel=0; nLevelnDepth; } ScSubOutlineIterator::ScSubOutlineIterator( ScOutlineArray* pOutlineArray, USHORT nLevel, USHORT nEntry ) : pArray( pOutlineArray ) { ScOutlineEntry* pEntry = (ScOutlineEntry*) pArray->aCollections[nLevel].At(nEntry); nStart = pEntry->GetStart(); nEnd = pEntry->GetEnd(); nSubLevel = nLevel + 1; nSubEntry = 0; nDepth = pArray->nDepth; } ScOutlineEntry* ScSubOutlineIterator::GetNext() { ScOutlineEntry* pEntry; BOOL bFound = FALSE; do { if (nSubLevel >= nDepth) return NULL; pEntry = (ScOutlineEntry*) pArray->aCollections[nSubLevel].At(nSubEntry); if (!pEntry) { nSubEntry = 0; ++nSubLevel; } else { if ( pEntry->GetStart() >= nStart && pEntry->GetEnd() <= nEnd ) bFound = TRUE; ++nSubEntry; } } while (!bFound); return pEntry; // nSubLevel gueltig, wenn pEntry != 0 } USHORT ScSubOutlineIterator::LastLevel() const { return nSubLevel; } USHORT ScSubOutlineIterator::LastEntry() const { if (nSubEntry == 0) { DBG_ERROR("ScSubOutlineIterator::LastEntry vor GetNext"); return 0; } return nSubEntry-1; } void ScSubOutlineIterator::DeleteLast() { if (nSubLevel >= nDepth) { DBG_ERROR("ScSubOutlineIterator::DeleteLast nach Ende"); return; } if (nSubEntry == 0) { DBG_ERROR("ScSubOutlineIterator::DeleteLast vor GetNext"); return; } --nSubEntry; pArray->aCollections[nSubLevel].AtFree(nSubEntry); }