/************************************************************** * * 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" // System - Includes ----------------------------------------------------- #include #include // INCLUDE --------------------------------------------------------------- #include "olinetab.hxx" #include "global.hxx" #include "rechead.hxx" #include "address.hxx" #include "table.hxx" //------------------------------------------------------------------------ ScOutlineEntry::ScOutlineEntry( SCCOLROW nNewStart, SCCOLROW nNewSize, bool bNewHidden ) : nStart ( nNewStart ), nSize ( nNewSize ), bHidden ( bNewHidden ), bVisible( sal_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,sal_False ) { } inline short IntCompare( SCCOLROW nX, SCCOLROW nY ) { if ( nX==nY ) return 0; else if ( nXGetStart(), ((ScOutlineEntry*)pKey2)->GetStart() ); } sal_uInt16 ScOutlineCollection::FindStart( SCCOLROW nMinStart ) { //! binaer suchen ? sal_uInt16 nPos = 0; sal_uInt16 nLocalCount = GetCount(); while ( (nPosGetStart() < nMinStart) : sal_False ) ++nPos; return nPos; } //------------------------------------------------------------------------ ScOutlineArray::ScOutlineArray() : nDepth( 0 ) { } ScOutlineArray::ScOutlineArray( const ScOutlineArray& rArray ) : nDepth( rArray.nDepth ) { for (sal_uInt16 nLevel=0; nLevel nDepth) nMaxLevel = nDepth; for (sal_uInt16 nLevel=0; nLevelGetCount(); for (sal_uInt16 i=0; iAt(i); if ( pEntry->GetStart() <= nSearchPos && pEntry->GetEnd() >= nSearchPos ) { rFindLevel = nLevel + 1; // naechster Level (zum Einfuegen) rFindIndex = i; } } } } sal_Bool ScOutlineArray::Insert( SCCOLROW nStartCol, SCCOLROW nEndCol, sal_Bool& rSizeChanged, sal_Bool bHidden, sal_Bool bVisible ) { rSizeChanged = sal_False; sal_uInt16 nStartLevel; sal_uInt16 nStartIndex; sal_uInt16 nEndLevel; sal_uInt16 nEndIndex; sal_Bool bFound = sal_False; sal_Bool bCont; sal_uInt16 nFindMax; FindEntry( nStartCol, nStartLevel, nStartIndex ); // nLevel = neuer Level (alter+1) !!! FindEntry( nEndCol, nEndLevel, nEndIndex ); nFindMax = Max(nStartLevel,nEndLevel); do { bCont = sal_False; if ( nStartLevel == nEndLevel && nStartIndex == nEndIndex && nStartLevel < SC_OL_MAXDEPTH ) bFound = sal_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 = sal_True; } } } while ( !bFound && bCont ); if (!bFound) return sal_False; sal_uInt16 nLevel = nStartLevel; // untere verschieben sal_Bool bNeedSize = sal_False; for ( short nMoveLevel = nDepth-1; nMoveLevel >= (short) nLevel; nMoveLevel-- ) { sal_uInt16 nCount = aCollections[nMoveLevel].GetCount(); sal_Bool bMoved = sal_False; for ( sal_uInt16 i=0; iGetStart(); if ( nEntryStart >= nStartCol && nEntryStart <= nEndCol ) { if (nMoveLevel >= SC_OL_MAXDEPTH - 1) { rSizeChanged = sal_False; // kein Platz return sal_False; } aCollections[nMoveLevel+1].Insert( new ScOutlineEntry( *pEntry ) ); aCollections[nMoveLevel].AtFree( i ); nCount = aCollections[nMoveLevel].GetCount(); bMoved = sal_True; if (nMoveLevel == (short) nDepth - 1) bNeedSize = sal_True; } else bMoved = sal_False; } } if (bNeedSize) { ++nDepth; rSizeChanged = sal_True; } if (nDepth <= nLevel) { nDepth = nLevel+1; rSizeChanged = sal_True; } /* nicht zusammenfassen! // zusammenfassen sal_uInt16 nCount = aCollections[nLevel].GetCount(); sal_uInt16 nIndex; bFound = sal_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 = sal_True; } } bFound = sal_False; for ( nIndex=0; nIndexGetStart() == nEndCol + 1 ) { nEndCol = ((ScOutlineEntry*) aCollections[nLevel].At(nIndex))->GetEnd(); aCollections[nLevel].AtFree(nIndex); bFound = sal_True; } } */ ScOutlineEntry* pNewEntry = new ScOutlineEntry( nStartCol, nEndCol+1-nStartCol, bHidden ); pNewEntry->SetVisible( bVisible ); aCollections[nLevel].Insert( pNewEntry ); return sal_True; } sal_Bool ScOutlineArray::FindTouchedLevel( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, sal_uInt16& rFindLevel ) const { sal_Bool bFound = sal_False; rFindLevel = 0; for (sal_uInt16 nLevel=0; nLevelGetCount(); for (sal_uInt16 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 = sal_True; } } } return bFound; } void ScOutlineArray::RemoveSub( SCCOLROW nStartPos, SCCOLROW nEndPos, sal_uInt16 nLevel ) { if ( nLevel >= nDepth ) return; ScOutlineCollection* pCollect = &aCollections[nLevel]; sal_uInt16 nCount = pCollect->GetCount(); sal_Bool bFound = sal_False; for ( sal_uInt16 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 = sal_True; } } } void ScOutlineArray::PromoteSub( SCCOLROW nStartPos, SCCOLROW nEndPos, sal_uInt16 nStartLevel ) { if (nStartLevel==0) { DBG_ERROR("PromoteSub mit Level 0"); return; } for (sal_uInt16 nLevel = nStartLevel; nLevel < nDepth; nLevel++) { ScOutlineCollection* pCollect = &aCollections[nLevel]; sal_uInt16 nCount = pCollect->GetCount(); sal_Bool bFound = sal_False; for ( sal_uInt16 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 = sal_True; } } } } sal_Bool ScOutlineArray::DecDepth() // nDepth auf leere Levels anpassen { sal_Bool bChanged = sal_False; sal_Bool bCont; do { bCont = sal_False; if (nDepth) if (aCollections[nDepth-1].GetCount() == 0) { --nDepth; bChanged = sal_True; bCont = sal_True; } } while (bCont); return bChanged; } sal_Bool ScOutlineArray::Remove( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, sal_Bool& rSizeChanged ) { sal_uInt16 nLevel; FindTouchedLevel( nBlockStart, nBlockEnd, nLevel ); ScOutlineCollection* pCollect = &aCollections[nLevel]; sal_uInt16 nCount = pCollect->GetCount(); sal_Bool bFound = sal_False; sal_Bool bAny = sal_False; for ( sal_uInt16 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 = sal_True; bAny = sal_True; } } if (bAny) // Depth anpassen if (DecDepth()) rSizeChanged = sal_True; return bAny; } ScOutlineEntry* ScOutlineArray::GetEntry( sal_uInt16 nLevel, sal_uInt16 nIndex ) const { return (ScOutlineEntry*)((nLevel < nDepth) ? aCollections[nLevel].At(nIndex) : NULL); } sal_uInt16 ScOutlineArray::GetCount( sal_uInt16 nLevel ) const { return (nLevel < nDepth) ? aCollections[nLevel].GetCount() : 0; } ScOutlineEntry* ScOutlineArray::GetEntryByPos( sal_uInt16 nLevel, SCCOLROW nPos ) const { sal_uInt16 nCount = GetCount( nLevel ); ScOutlineEntry* pEntry; for (sal_uInt16 nIndex = 0; nIndex < nCount; nIndex++) { pEntry = GetEntry( nLevel, nIndex ); if ((pEntry->GetStart() <= nPos) && (nPos <= pEntry->GetEnd())) return pEntry; } return NULL; } sal_Bool ScOutlineArray::GetEntryIndex( sal_uInt16 nLevel, SCCOLROW nPos, sal_uInt16& rnIndex ) const { // found entry contains passed position sal_uInt16 nCount = GetCount( nLevel ); for ( rnIndex = 0; rnIndex < nCount; ++rnIndex ) { const ScOutlineEntry* pEntry = GetEntry( nLevel, rnIndex ); if ( (pEntry->GetStart() <= nPos) && (nPos <= pEntry->GetEnd()) ) return sal_True; } return sal_False; } sal_Bool ScOutlineArray::GetEntryIndexInRange( sal_uInt16 nLevel, SCCOLROW nBlockStart, SCCOLROW nBlockEnd, sal_uInt16& rnIndex ) const { // found entry will be completely inside of passed range sal_uInt16 nCount = GetCount( nLevel ); for ( rnIndex = 0; rnIndex < nCount; ++rnIndex ) { const ScOutlineEntry* pEntry = GetEntry( nLevel, rnIndex ); if ( (nBlockStart <= pEntry->GetStart()) && (pEntry->GetEnd() <= nBlockEnd) ) return sal_True; } return sal_False; } void ScOutlineArray::SetVisibleBelow( sal_uInt16 nLevel, sal_uInt16 nEntry, sal_Bool bValue, sal_Bool bSkipHidden ) { ScOutlineEntry* pEntry = GetEntry( nLevel, nEntry ); if( pEntry ) { SCCOLROW nStart = pEntry->GetStart(); SCCOLROW nEnd = pEntry->GetEnd(); for (sal_uInt16 nSubLevel=nLevel+1; nSubLevelGetStart() >= nStart && pEntry->GetEnd() <= nEnd) { pEntry->SetVisible(bValue); if (bSkipHidden) if (!pEntry->IsHidden()) SetVisibleBelow( nSubLevel, i, bValue, sal_True ); } ++i; pEntry = (ScOutlineEntry*) aCollections[nSubLevel].At(i); } if (bSkipHidden) nSubLevel = nDepth; // Abbruch } } } void ScOutlineArray::GetRange( SCCOLROW& rStart, SCCOLROW& rEnd ) const { sal_uInt16 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( sal_uInt16 nLevel, SCCOLROW& rBlkStart, SCCOLROW& rBlkEnd ) { sal_uInt16 nCount; SCCOLROW nStart; SCCOLROW nEnd; sal_uInt16 i; ScOutlineEntry* pEntry; nCount = GetCount(nLevel); for ( i=0; iGetStart(); nEnd = pEntry->GetEnd(); if ( rBlkStart<=nEnd && rBlkEnd>=nStart ) { if (nStartrBlkEnd) rBlkEnd = nEnd; } } } sal_Bool ScOutlineArray::TestInsertSpace( SCSIZE nSize, SCCOLROW nMaxVal ) const { sal_uInt16 nCount = aCollections[0].GetCount(); if (nCount) { SCCOLROW nEnd = ((ScOutlineEntry*) aCollections[0].At(nCount-1))->GetEnd(); return ( sal::static_int_cast(nEnd+nSize) <= nMaxVal ); } return sal_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 ); } } } } sal_Bool ScOutlineArray::DeleteSpace( SCCOLROW nStartPos, SCSIZE nSize ) { SCCOLROW nEndPos = nStartPos + nSize - 1; sal_Bool bNeedSave = sal_False; // Original fuer Undo benoetigt? sal_Bool bChanged = sal_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 = sal_True; if ( nEntryStart >= nStartPos && nEntryEnd <= nEndPos ) // innen { aIter.DeleteLast(); bChanged = sal_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, ScTable& rTable, bool bCol ) { 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 = rTable.LastHiddenColRow(nEntryStart, bCol); 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 (sal_uInt16 nLevel=0; nLevelnDepth; } ScSubOutlineIterator::ScSubOutlineIterator( ScOutlineArray* pOutlineArray, sal_uInt16 nLevel, sal_uInt16 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; sal_Bool bFound = sal_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 = sal_True; ++nSubEntry; } } while (!bFound); return pEntry; // nSubLevel gueltig, wenn pEntry != 0 } sal_uInt16 ScSubOutlineIterator::LastLevel() const { return nSubLevel; } sal_uInt16 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); }