diff options
Diffstat (limited to 'sc/source/core/data/table1.cxx')
-rw-r--r-- | sc/source/core/data/table1.cxx | 1871 |
1 files changed, 1871 insertions, 0 deletions
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx new file mode 100644 index 000000000000..d4c194676471 --- /dev/null +++ b/sc/source/core/data/table1.cxx @@ -0,0 +1,1871 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +// INCLUDE --------------------------------------------------------------- + +#include "scitems.hxx" +#include <svx/algitem.hxx> +#include <editeng/justifyitem.hxx> +#include <unotools/textsearch.hxx> +#include <sfx2/objsh.hxx> + +#include "attrib.hxx" +#include "patattr.hxx" +#include "cell.hxx" +#include "table.hxx" +#include "document.hxx" +#include "drwlayer.hxx" +#include "olinetab.hxx" +#include "stlsheet.hxx" +#include "global.hxx" +#include "globstr.hrc" +#include "refupdat.hxx" +#include "markdata.hxx" +#include "progress.hxx" +#include "hints.hxx" // fuer Paint-Broadcast +#include "prnsave.hxx" +#include "tabprotection.hxx" +#include "sheetevents.hxx" +#include "segmenttree.hxx" + +#include <vector> + +using ::std::vector; + +namespace { + +ScProgress* GetProgressBar( + SCSIZE nCount, SCSIZE nTotalCount, ScProgress* pOuterProgress, ScDocument* pDoc) +{ + if (nTotalCount < 1000) + { + // if the total number of rows is less than 1000, don't even bother + // with the progress bar because drawing progress bar can be very + // expensive especially in GTK. + return NULL; + } + + if (pOuterProgress) + return pOuterProgress; + + if (nCount > 1) + return new ScProgress( + pDoc->GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nTotalCount); + + return NULL; +} + +void GetOptimalHeightsInColumn( + ScColumn* pCol, SCROW nStartRow, SCROW nEndRow, vector<sal_uInt16>& aHeights, + OutputDevice* pDev, double nPPTX, double nPPTY, const Fraction& rZoomX, const Fraction& rZoomY, bool bForce, + ScProgress* pProgress, sal_uInt32 nProgressStart) +{ + SCSIZE nCount = static_cast<SCSIZE>(nEndRow-nStartRow+1); + + // zuerst einmal ueber den ganzen Bereich + // (mit der letzten Spalte in der Hoffnung, dass die am ehesten noch auf + // Standard formatiert ist) + + pCol[MAXCOL].GetOptimalHeight( + nStartRow, nEndRow, &aHeights[0], pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce, 0, 0 ); + + // daraus Standardhoehe suchen, die im unteren Bereich gilt + + sal_uInt16 nMinHeight = aHeights[nCount-1]; + SCSIZE nPos = nCount-1; + while ( nPos && aHeights[nPos-1] >= nMinHeight ) + --nPos; + SCROW nMinStart = nStartRow + nPos; + + sal_uLong nWeightedCount = 0; + for (SCCOL nCol=0; nCol<MAXCOL; nCol++) // MAXCOL schon oben + { + pCol[nCol].GetOptimalHeight( + nStartRow, nEndRow, &aHeights[0], pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce, + nMinHeight, nMinStart ); + + if (pProgress) + { + sal_uLong nWeight = pCol[nCol].GetWeightedCount(); + if (nWeight) // nochmal denselben Status muss auch nicht sein + { + nWeightedCount += nWeight; + pProgress->SetState( nWeightedCount + nProgressStart ); + } + } + } +} + +struct OptimalHeightsFuncObjBase +{ + virtual ~OptimalHeightsFuncObjBase() {} + virtual bool operator() (SCROW nStartRow, SCROW nEndRow, sal_uInt16 nHeight) = 0; +}; + +struct SetRowHeightOnlyFunc : public OptimalHeightsFuncObjBase +{ + ScTable* mpTab; + SetRowHeightOnlyFunc(ScTable* pTab) : + mpTab(pTab) + {} + + virtual bool operator() (SCROW nStartRow, SCROW nEndRow, sal_uInt16 nHeight) + { + mpTab->SetRowHeightOnly(nStartRow, nEndRow, nHeight); + return false; + } +}; + +struct SetRowHeightRangeFunc : public OptimalHeightsFuncObjBase +{ + ScTable* mpTab; + double mnPPTX; + double mnPPTY; + + SetRowHeightRangeFunc(ScTable* pTab, double nPPTX, double nPPTY) : + mpTab(pTab), + mnPPTX(nPPTX), + mnPPTY(nPPTY) + {} + + virtual bool operator() (SCROW nStartRow, SCROW nEndRow, sal_uInt16 nHeight) + { + return mpTab->SetRowHeightRange(nStartRow, nEndRow, nHeight, mnPPTX, mnPPTY); + } +}; + +bool SetOptimalHeightsToRows(OptimalHeightsFuncObjBase& rFuncObj, + ScBitMaskCompressedArray<SCROW, sal_uInt8>* pRowFlags, SCROW nStartRow, SCROW nEndRow, sal_uInt16 nExtra, + const vector<sal_uInt16>& aHeights, bool bForce) +{ + SCSIZE nCount = static_cast<SCSIZE>(nEndRow-nStartRow+1); + bool bChanged = false; + SCROW nRngStart = 0; + SCROW nRngEnd = 0; + sal_uInt16 nLast = 0; + for (SCSIZE i=0; i<nCount; i++) + { + size_t nIndex; + SCROW nRegionEndRow; + sal_uInt8 nRowFlag = pRowFlags->GetValue( nStartRow+i, nIndex, nRegionEndRow ); + if ( nRegionEndRow > nEndRow ) + nRegionEndRow = nEndRow; + SCSIZE nMoreRows = nRegionEndRow - ( nStartRow+i ); // additional equal rows after first + + bool bAutoSize = ((nRowFlag & CR_MANUALSIZE) == 0); + if ( bAutoSize || bForce ) + { + if (nExtra) + { + if (bAutoSize) + pRowFlags->SetValue( nStartRow+i, nRegionEndRow, nRowFlag | CR_MANUALSIZE); + } + else if (!bAutoSize) + pRowFlags->SetValue( nStartRow+i, nRegionEndRow, nRowFlag & ~CR_MANUALSIZE); + + for (SCSIZE nInner = i; nInner <= i + nMoreRows; ++nInner) + { + if (nLast) + { + if (aHeights[nInner]+nExtra == nLast) + nRngEnd = nStartRow+nInner; + else + { + bChanged |= rFuncObj(nRngStart, nRngEnd, nLast); + nLast = 0; + } + } + if (!nLast) + { + nLast = aHeights[nInner]+nExtra; + nRngStart = nStartRow+nInner; + nRngEnd = nStartRow+nInner; + } + } + } + else + { + if (nLast) + bChanged |= rFuncObj(nRngStart, nRngEnd, nLast); + nLast = 0; + } + i += nMoreRows; // already handled - skip + } + if (nLast) + bChanged |= rFuncObj(nRngStart, nRngEnd, nLast); + + return bChanged; +} + +} + +// ----------------------------------------------------------------------- + +ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const String& rNewName, + sal_Bool bColInfo, sal_Bool bRowInfo ) : + aName( rNewName ), + aCodeName( rNewName ), + bScenario( false ), + bLayoutRTL( false ), + bLoadingRTL( false ), + nLinkMode( 0 ), + aPageStyle( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) ), + bPageSizeValid( false ), + nRepeatStartX( SCCOL_REPEAT_NONE ), + nRepeatStartY( SCROW_REPEAT_NONE ), + pTabProtection( NULL ), + pColWidth( NULL ), + mpRowHeights( static_cast<ScFlatUInt16RowSegments*>(NULL) ), + pColFlags( NULL ), + pRowFlags( NULL ), + mpHiddenCols(new ScFlatBoolColSegments), + mpHiddenRows(new ScFlatBoolRowSegments), + mpFilteredCols(new ScFlatBoolColSegments), + mpFilteredRows(new ScFlatBoolRowSegments), + pOutlineTable( NULL ), + pSheetEvents( NULL ), + bTableAreaValid( false ), + bVisible( sal_True ), + bStreamValid( false ), + bPendingRowHeights( false ), + bCalcNotification( false ), + nTab( nNewTab ), + nRecalcLvl( 0 ), + pDocument( pDoc ), + pSearchParam( NULL ), + pSearchText ( NULL ), + pSortCollator( NULL ), + bPrintEntireSheet(true), + pRepeatColRange( NULL ), + pRepeatRowRange( NULL ), + nLockCount( 0 ), + pScenarioRanges( NULL ), + aScenarioColor( COL_LIGHTGRAY ), + aTabBgColor( COL_AUTO ), + nScenarioFlags( 0 ), + bActiveScenario( false ), + pDBDataNoName(NULL), + mpRangeName(NULL), + mbPageBreaksValid(false) +{ + + if (bColInfo) + { + pColWidth = new sal_uInt16[ MAXCOL+1 ]; + pColFlags = new sal_uInt8[ MAXCOL+1 ]; + + for (SCCOL i=0; i<=MAXCOL; i++) + { + pColWidth[i] = STD_COL_WIDTH; + pColFlags[i] = 0; + } + } + + if (bRowInfo) + { + mpRowHeights.reset(new ScFlatUInt16RowSegments(ScGlobal::nStdRowHeight)); + pRowFlags = new ScBitMaskCompressedArray< SCROW, sal_uInt8>( MAXROW, 0); + } + + if ( pDocument->IsDocVisible() ) + { + // when a sheet is added to a visible document, + // initialize its RTL flag from the system locale + bLayoutRTL = ScGlobal::IsSystemRTL(); + } + + ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer(); + if (pDrawLayer) + { + if ( pDrawLayer->ScAddPage( nTab ) ) // sal_False (not inserted) during Undo + { + pDrawLayer->ScRenamePage( nTab, aName ); + sal_uLong nx = (sal_uLong) ((double) (MAXCOL+1) * STD_COL_WIDTH * HMM_PER_TWIPS ); + sal_uLong ny = (sal_uLong) ((double) (MAXROW+1) * ScGlobal::nStdRowHeight * HMM_PER_TWIPS ); + pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( nx, ny ), false ); + } + } + + for (SCCOL k=0; k<=MAXCOL; k++) + aCol[k].Init( k, nTab, pDocument ); +} + +ScTable::~ScTable() +{ + if (!pDocument->IsInDtorClear()) + { + // nicht im dtor die Pages in der falschen Reihenfolge loeschen + // (nTab stimmt dann als Page-Number nicht!) + // In ScDocument::Clear wird hinterher per Clear am Draw Layer alles geloescht. + + ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer(); + if (pDrawLayer) + pDrawLayer->ScRemovePage( nTab ); + } + + delete[] pColWidth; + delete[] pColFlags; + delete pRowFlags; + delete pSheetEvents; + delete pOutlineTable; + delete pSearchParam; + delete pSearchText; + delete pRepeatColRange; + delete pRepeatRowRange; + delete pScenarioRanges; + delete mpRangeName; + delete pDBDataNoName; + DestroySortCollator(); +} + +void ScTable::GetName( String& rName ) const +{ + rName = aName; +} + +void ScTable::SetName( const String& rNewName ) +{ + aName = rNewName; + aUpperName.Erase(); // invalidated if the name is changed + + // SetStreamValid is handled in ScDocument::RenameTab +} + +const String& ScTable::GetUpperName() const +{ + if ( !aUpperName.Len() && aName.Len() ) + aUpperName = ScGlobal::pCharClass->upper( aName ); + return aUpperName; +} + +void ScTable::SetVisible( sal_Bool bVis ) +{ + if (bVisible != bVis && IsStreamValid()) + SetStreamValid(false); + + bVisible = bVis; +} + +void ScTable::SetStreamValid( sal_Bool bSet, sal_Bool bIgnoreLock ) +{ + if ( bIgnoreLock || !pDocument->IsStreamValidLocked() ) + bStreamValid = bSet; +} + +void ScTable::SetPendingRowHeights( sal_Bool bSet ) +{ + bPendingRowHeights = bSet; +} + +void ScTable::SetLayoutRTL( sal_Bool bSet ) +{ + bLayoutRTL = bSet; +} + +void ScTable::SetLoadingRTL( sal_Bool bSet ) +{ + bLoadingRTL = bSet; +} + +const Color& ScTable::GetTabBgColor() const +{ + return aTabBgColor; +} + +void ScTable::SetTabBgColor(const Color& rColor) +{ + if (aTabBgColor != rColor) + { + // The tab color has changed. Set this table 'modified'. + aTabBgColor = rColor; + if (IsStreamValid()) + SetStreamValid(false); + } +} + +void ScTable::SetScenario( sal_Bool bFlag ) +{ + bScenario = bFlag; +} + +void ScTable::SetLink( sal_uInt8 nMode, + const String& rDoc, const String& rFlt, const String& rOpt, + const String& rTab, sal_uLong nRefreshDelay ) +{ + nLinkMode = nMode; + aLinkDoc = rDoc; // Datei + aLinkFlt = rFlt; // Filter + aLinkOpt = rOpt; // Filter-Optionen + aLinkTab = rTab; // Tabellenname in Quelldatei + nLinkRefreshDelay = nRefreshDelay; // refresh delay in seconds, 0==off + + if (IsStreamValid()) + SetStreamValid(false); +} + +sal_uInt16 ScTable::GetOptimalColWidth( SCCOL nCol, OutputDevice* pDev, + double nPPTX, double nPPTY, + const Fraction& rZoomX, const Fraction& rZoomY, + sal_Bool bFormula, const ScMarkData* pMarkData, + const ScColWidthParam* pParam ) +{ + return aCol[nCol].GetOptimalColWidth( pDev, nPPTX, nPPTY, rZoomX, rZoomY, + bFormula, STD_COL_WIDTH - STD_EXTRA_WIDTH, pMarkData, pParam ); +} + +long ScTable::GetNeededSize( SCCOL nCol, SCROW nRow, + OutputDevice* pDev, + double nPPTX, double nPPTY, + const Fraction& rZoomX, const Fraction& rZoomY, + sal_Bool bWidth, sal_Bool bTotalSize ) +{ + ScNeededSizeOptions aOptions; + aOptions.bSkipMerged = false; // zusammengefasste mitzaehlen + aOptions.bTotalSize = bTotalSize; + + return aCol[nCol].GetNeededSize + ( nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, aOptions ); +} + +sal_Bool ScTable::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nExtra, + OutputDevice* pDev, + double nPPTX, double nPPTY, + const Fraction& rZoomX, const Fraction& rZoomY, + sal_Bool bForce, ScProgress* pOuterProgress, sal_uLong nProgressStart ) +{ + DBG_ASSERT( nExtra==0 || bForce, "autom. OptimalHeight mit Extra" ); + + if ( !pDocument->IsAdjustHeightEnabled() ) + { + return false; + } + + SCSIZE nCount = static_cast<SCSIZE>(nEndRow-nStartRow+1); + + ScProgress* pProgress = GetProgressBar(nCount, GetWeightedCount(), pOuterProgress, pDocument); + + vector<sal_uInt16> aHeights(nCount, 0); + + GetOptimalHeightsInColumn( + aCol, nStartRow, nEndRow, aHeights, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce, + pProgress, nProgressStart); + + SetRowHeightRangeFunc aFunc(this, nPPTX, nPPTY); + bool bChanged = SetOptimalHeightsToRows( + aFunc, pRowFlags, nStartRow, nEndRow, nExtra, aHeights, bForce); + + if ( pProgress != pOuterProgress ) + delete pProgress; + + return bChanged; +} + +void ScTable::SetOptimalHeightOnly( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nExtra, + OutputDevice* pDev, + double nPPTX, double nPPTY, + const Fraction& rZoomX, const Fraction& rZoomY, + sal_Bool bForce, ScProgress* pOuterProgress, sal_uLong nProgressStart ) +{ + DBG_ASSERT( nExtra==0 || bForce, "autom. OptimalHeight mit Extra" ); + + if ( !pDocument->IsAdjustHeightEnabled() ) + return; + + SCSIZE nCount = static_cast<SCSIZE>(nEndRow-nStartRow+1); + + ScProgress* pProgress = GetProgressBar(nCount, GetWeightedCount(), pOuterProgress, pDocument); + + vector<sal_uInt16> aHeights(nCount, 0); + + GetOptimalHeightsInColumn( + aCol, nStartRow, nEndRow, aHeights, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce, + pProgress, nProgressStart); + + SetRowHeightOnlyFunc aFunc(this); + SetOptimalHeightsToRows( + aFunc, pRowFlags, nStartRow, nEndRow, nExtra, aHeights, bForce); + + if ( pProgress != pOuterProgress ) + delete pProgress; +} + +sal_Bool ScTable::GetCellArea( SCCOL& rEndCol, SCROW& rEndRow ) const +{ + sal_Bool bFound = false; + SCCOL nMaxX = 0; + SCROW nMaxY = 0; + for (SCCOL i=0; i<=MAXCOL; i++) + if (!aCol[i].IsEmptyVisData(sal_True)) // sal_True = Notizen zaehlen auch + { + bFound = sal_True; + nMaxX = i; + SCROW nColY = aCol[i].GetLastVisDataPos(sal_True); + if (nColY > nMaxY) + nMaxY = nColY; + } + + rEndCol = nMaxX; + rEndRow = nMaxY; + return bFound; +} + +sal_Bool ScTable::GetTableArea( SCCOL& rEndCol, SCROW& rEndRow ) const +{ + sal_Bool bRet = sal_True; //! merken? + if (!bTableAreaValid) + { + bRet = GetPrintArea( ((ScTable*)this)->nTableAreaX, + ((ScTable*)this)->nTableAreaY, sal_True ); + ((ScTable*)this)->bTableAreaValid = sal_True; + } + rEndCol = nTableAreaX; + rEndRow = nTableAreaY; + return bRet; +} + +const SCCOL SC_COLUMNS_STOP = 30; + +sal_Bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, sal_Bool bNotes ) const +{ + sal_Bool bFound = false; + SCCOL nMaxX = 0; + SCROW nMaxY = 0; + SCCOL i; + + for (i=0; i<=MAXCOL; i++) // Daten testen + if (!aCol[i].IsEmptyVisData(bNotes)) + { + bFound = sal_True; + if (i>nMaxX) + nMaxX = i; + SCROW nColY = aCol[i].GetLastVisDataPos(bNotes); + if (nColY > nMaxY) + nMaxY = nColY; + } + + SCCOL nMaxDataX = nMaxX; + + for (i=0; i<=MAXCOL; i++) // Attribute testen + { + SCROW nLastRow; + if (aCol[i].GetLastVisibleAttr( nLastRow )) + { + bFound = sal_True; + nMaxX = i; + if (nLastRow > nMaxY) + nMaxY = nLastRow; + } + } + + if (nMaxX == MAXCOL) // Attribute rechts weglassen + { + --nMaxX; + while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1]) ) + --nMaxX; + } + + if ( nMaxX < nMaxDataX ) + { + nMaxX = nMaxDataX; + } + else if ( nMaxX > nMaxDataX ) + { + SCCOL nAttrStartX = nMaxDataX + 1; + while ( nAttrStartX < MAXCOL ) + { + SCCOL nAttrEndX = nAttrStartX; + while ( nAttrEndX < MAXCOL && aCol[nAttrStartX].IsVisibleAttrEqual(aCol[nAttrEndX+1]) ) + ++nAttrEndX; + if ( nAttrEndX + 1 - nAttrStartX >= SC_COLUMNS_STOP ) + { + // found equally-formatted columns behind data -> stop before these columns + nMaxX = nAttrStartX - 1; + + // also don't include default-formatted columns before that + SCROW nDummyRow; + while ( nMaxX > nMaxDataX && !aCol[nMaxX].GetLastVisibleAttr( nDummyRow ) ) + --nMaxX; + break; + } + nAttrStartX = nAttrEndX + 1; + } + } + + rEndCol = nMaxX; + rEndRow = nMaxY; + return bFound; +} + +sal_Bool ScTable::GetPrintAreaHor( SCROW nStartRow, SCROW nEndRow, + SCCOL& rEndCol, sal_Bool /* bNotes */ ) const +{ + sal_Bool bFound = false; + SCCOL nMaxX = 0; + SCCOL i; + + for (i=0; i<=MAXCOL; i++) // Attribute testen + { + if (aCol[i].HasVisibleAttrIn( nStartRow, nEndRow )) + { + bFound = sal_True; + nMaxX = i; + } + } + + if (nMaxX == MAXCOL) // Attribute rechts weglassen + { + --nMaxX; + while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1], nStartRow, nEndRow) ) + --nMaxX; + } + + for (i=0; i<=MAXCOL; i++) // Daten testen + { + if (!aCol[i].IsEmptyBlock( nStartRow, nEndRow )) //! bNotes ?????? + { + bFound = sal_True; + if (i>nMaxX) + nMaxX = i; + } + } + + rEndCol = nMaxX; + return bFound; +} + +sal_Bool ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol, + SCROW& rEndRow, sal_Bool bNotes ) const +{ + sal_Bool bFound = false; + SCROW nMaxY = 0; + SCCOL i; + + for (i=nStartCol; i<=nEndCol; i++) // Attribute testen + { + SCROW nLastRow; + if (aCol[i].GetLastVisibleAttr( nLastRow )) + { + bFound = sal_True; + if (nLastRow > nMaxY) + nMaxY = nLastRow; + } + } + + for (i=nStartCol; i<=nEndCol; i++) // Daten testen + if (!aCol[i].IsEmptyVisData(bNotes)) + { + bFound = sal_True; + SCROW nColY = aCol[i].GetLastVisDataPos(bNotes); + if (nColY > nMaxY) + nMaxY = nColY; + } + + rEndRow = nMaxY; + return bFound; +} + +sal_Bool ScTable::GetDataStart( SCCOL& rStartCol, SCROW& rStartRow ) const +{ + sal_Bool bFound = false; + SCCOL nMinX = MAXCOL; + SCROW nMinY = MAXROW; + SCCOL i; + + for (i=0; i<=MAXCOL; i++) // Attribute testen + { + SCROW nFirstRow; + if (aCol[i].GetFirstVisibleAttr( nFirstRow )) + { + if (!bFound) + nMinX = i; + bFound = sal_True; + if (nFirstRow < nMinY) + nMinY = nFirstRow; + } + } + + if (nMinX == 0) // Attribute links weglassen + { + if ( aCol[0].IsVisibleAttrEqual(aCol[1]) ) // keine einzelnen + { + ++nMinX; + while ( nMinX<MAXCOL && aCol[nMinX].IsVisibleAttrEqual(aCol[nMinX-1]) ) + ++nMinX; + } + } + + sal_Bool bDatFound = false; + for (i=0; i<=MAXCOL; i++) // Daten testen + if (!aCol[i].IsEmptyVisData(sal_True)) + { + if (!bDatFound && i<nMinX) + nMinX = i; + bFound = bDatFound = sal_True; + SCROW nColY = aCol[i].GetFirstVisDataPos(sal_True); + if (nColY < nMinY) + nMinY = nColY; + } + + rStartCol = nMinX; + rStartRow = nMinY; + return bFound; +} + +void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, + sal_Bool bIncludeOld, bool bOnlyDown ) const +{ + sal_Bool bLeft = false; + sal_Bool bRight = false; + sal_Bool bTop = false; + sal_Bool bBottom = false; + sal_Bool bChanged; + sal_Bool bFound; + SCCOL i; + SCROW nTest; + + do + { + bChanged = false; + + if (!bOnlyDown) + { + SCROW nStart = rStartRow; + SCROW nEnd = rEndRow; + if (nStart>0) --nStart; + if (nEnd<MAXROW) ++nEnd; + + if (rEndCol < MAXCOL) + if (!aCol[rEndCol+1].IsEmptyBlock(nStart,nEnd)) + { + ++rEndCol; + bChanged = sal_True; + bRight = sal_True; + } + + if (rStartCol > 0) + if (!aCol[rStartCol-1].IsEmptyBlock(nStart,nEnd)) + { + --rStartCol; + bChanged = sal_True; + bLeft = sal_True; + } + + if (rStartRow > 0) + { + nTest = rStartRow-1; + bFound = false; + for (i=rStartCol; i<=rEndCol && !bFound; i++) + if (aCol[i].HasDataAt(nTest)) + bFound = sal_True; + if (bFound) + { + --rStartRow; + bChanged = sal_True; + bTop = sal_True; + } + } + } + + if (rEndRow < MAXROW) + { + nTest = rEndRow+1; + bFound = false; + for (i=rStartCol; i<=rEndCol && !bFound; i++) + if (aCol[i].HasDataAt(nTest)) + bFound = sal_True; + if (bFound) + { + ++rEndRow; + bChanged = sal_True; + bBottom = sal_True; + } + } + } + while( bChanged ); + + if ( !bIncludeOld ) + { + if ( !bLeft && rStartCol < MAXCOL && rStartCol < rEndCol ) + if ( aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) ) + ++rStartCol; + if ( !bRight && rEndCol > 0 && rStartCol < rEndCol ) + if ( aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) ) + --rEndCol; + if ( !bTop && rStartRow < MAXROW && rStartRow < rEndRow ) + { + bFound = false; + for (i=rStartCol; i<=rEndCol && !bFound; i++) + if (aCol[i].HasDataAt(rStartRow)) + bFound = sal_True; + if (!bFound) + ++rStartRow; + } + if ( !bBottom && rEndRow > 0 && rStartRow < rEndRow ) + { + bFound = false; + for (i=rStartCol; i<=rEndCol && !bFound; i++) + if (aCol[i].HasDataAt(rEndRow)) + bFound = sal_True; + if (!bFound) + --rEndRow; + } + } +} + + +bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow, + SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const +{ + o_bShrunk = false; + + PutInOrder( rStartCol, rEndCol); + PutInOrder( rStartRow, rEndRow); + if (rStartCol < 0) + rStartCol = 0, o_bShrunk = true; + if (rStartRow < 0) + rStartRow = 0, o_bShrunk = true; + if (rEndCol > MAXCOL) + rEndCol = MAXCOL, o_bShrunk = true; + if (rEndRow > MAXROW) + rEndRow = MAXROW, o_bShrunk = true; + + bool bChanged; + do + { + bChanged = false; + + while (rStartCol < rEndCol) + { + if (aCol[rEndCol].IsEmptyBlock( rStartRow, rEndRow)) + { + --rEndCol; + bChanged = true; + } + else + break; // while + } + + while (rStartCol < rEndCol) + { + if (aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow)) + { + ++rStartCol; + bChanged = true; + } + else + break; // while + } + + if (!bColumnsOnly) + { + if (rStartRow < rEndRow) + { + bool bFound = false; + for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++) + if (aCol[i].HasDataAt( rStartRow)) + bFound = true; + if (!bFound) + { + ++rStartRow; + bChanged = true; + } + } + + if (rStartRow < rEndRow) + { + bool bFound = false; + for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++) + if (aCol[i].HasDataAt( rEndRow)) + bFound = true; + if (!bFound) + { + --rEndRow; + bChanged = true; + } + } + } + + if (bChanged) + o_bShrunk = true; + } while( bChanged ); + + return rStartCol != rEndCol || (bColumnsOnly ? + !aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow) : + (rStartRow != rEndRow || aCol[rStartCol].HasDataAt( rStartRow))); +} + + +SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, + SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) +{ + SCSIZE nCount = 0; + SCCOL nCol; + if ((eDir == DIR_BOTTOM) || (eDir == DIR_TOP)) + { + nCount = static_cast<SCSIZE>(nEndRow - nStartRow); + for (nCol = nStartCol; nCol <= nEndCol; nCol++) + nCount = Min(nCount, aCol[nCol].GetEmptyLinesInBlock(nStartRow, nEndRow, eDir)); + } + else if (eDir == DIR_RIGHT) + { + nCol = nEndCol; + while (((SCsCOL)nCol >= (SCsCOL)nStartCol) && + aCol[nCol].IsEmptyBlock(nStartRow, nEndRow)) + { + nCount++; + nCol--; + } + } + else + { + nCol = nStartCol; + while ((nCol <= nEndCol) && aCol[nCol].IsEmptyBlock(nStartRow, nEndRow)) + { + nCount++; + nCol++; + } + } + return nCount; +} + +sal_Bool ScTable::IsEmptyLine( SCROW nRow, SCCOL nStartCol, SCCOL nEndCol ) +{ + sal_Bool bFound = false; + for (SCCOL i=nStartCol; i<=nEndCol && !bFound; i++) + if (aCol[i].HasDataAt(nRow)) + bFound = sal_True; + return !bFound; +} + +void ScTable::LimitChartArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow ) +{ + while ( rStartCol<rEndCol && aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) ) + ++rStartCol; + + while ( rStartCol<rEndCol && aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) ) + --rEndCol; + + while ( rStartRow<rEndRow && IsEmptyLine(rStartRow, rStartCol, rEndCol) ) + ++rStartRow; + + while ( rStartRow<rEndRow && IsEmptyLine(rEndRow, rStartCol, rEndCol) ) + --rEndRow; +} + +void ScTable::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY ) +{ + if (nMovX) + { + SCsCOL nNewCol = (SCsCOL) rCol; + sal_Bool bThere = aCol[nNewCol].HasVisibleDataAt(rRow); + sal_Bool bFnd; + if (bThere) + { + do + { + nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX ); + bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : false; + } + while (bFnd); + nNewCol = sal::static_int_cast<SCsCOL>( nNewCol - nMovX ); + + if (nNewCol == (SCsCOL)rCol) + bThere = false; + } + + if (!bThere) + { + do + { + nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX ); + bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : sal_True; + } + while (!bFnd); + } + + if (nNewCol<0) nNewCol=0; + if (nNewCol>MAXCOL) nNewCol=MAXCOL; + rCol = (SCCOL) nNewCol; + } + + if (nMovY) + aCol[rCol].FindDataAreaPos(rRow,nMovY); +} + +sal_Bool ScTable::ValidNextPos( SCCOL nCol, SCROW nRow, const ScMarkData& rMark, + sal_Bool bMarked, sal_Bool bUnprotected ) +{ + if (!ValidCol(nCol) || !ValidRow(nRow)) + return false; + + if (pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) + // Skip an overlapped cell. + return false; + + if (bMarked && !rMark.IsCellMarked(nCol,nRow)) + return false; + + if (bUnprotected && ((const ScProtectionAttr*) + GetAttr(nCol,nRow,ATTR_PROTECTION))->GetProtection()) + return false; + + if (bMarked || bUnprotected) //! auch sonst ??? + { + // ausgeblendete muessen uebersprungen werden, weil der Cursor sonst + // auf der naechsten Zelle landet, auch wenn die geschuetzt/nicht markiert ist. + //! per Extra-Parameter steuern, nur fuer Cursor-Bewegung ??? + + if (RowHidden(nRow)) + return false; + + if (ColHidden(nCol)) + return false; + } + + return sal_True; +} + +void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY, + sal_Bool bMarked, sal_Bool bUnprotected, const ScMarkData& rMark ) +{ + if (bUnprotected && !IsProtected()) // Tabelle ueberhaupt geschuetzt? + bUnprotected = false; + + sal_uInt16 nWrap = 0; + SCsCOL nCol = rCol; + SCsROW nRow = rRow; + + nCol = sal::static_int_cast<SCsCOL>( nCol + nMovX ); + nRow = sal::static_int_cast<SCsROW>( nRow + nMovY ); + + DBG_ASSERT( !nMovY || !bUnprotected, + "GetNextPos mit bUnprotected horizontal nicht implementiert" ); + + if ( nMovY && bMarked ) + { + sal_Bool bUp = ( nMovY < 0 ); + nRow = rMark.GetNextMarked( nCol, nRow, bUp ); + while ( VALIDROW(nRow) && + (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) ) + { + // ausgeblendete ueberspringen (s.o.) + nRow += nMovY; + nRow = rMark.GetNextMarked( nCol, nRow, bUp ); + } + + while ( nRow < 0 || nRow > MAXROW ) + { + nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) ); + while ( VALIDCOL(nCol) && ColHidden(nCol) ) + nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) ); // skip hidden rows (see above) + if (nCol < 0) + { + nCol = MAXCOL; + if (++nWrap >= 2) + return; + } + else if (nCol > MAXCOL) + { + nCol = 0; + if (++nWrap >= 2) + return; + } + if (nRow < 0) + nRow = MAXROW; + else if (nRow > MAXROW) + nRow = 0; + nRow = rMark.GetNextMarked( nCol, nRow, bUp ); + while ( VALIDROW(nRow) && + (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) ) + { + // ausgeblendete ueberspringen (s.o.) + nRow += nMovY; + nRow = rMark.GetNextMarked( nCol, nRow, bUp ); + } + } + } + + if ( nMovX && ( bMarked || bUnprotected ) ) + { + // initiales Weiterzaehlen wrappen: + if (nCol<0) + { + nCol = MAXCOL; + --nRow; + if (nRow<0) + nRow = MAXROW; + } + if (nCol>MAXCOL) + { + nCol = 0; + ++nRow; + if (nRow>MAXROW) + nRow = 0; + } + + if ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) ) + { + SCsROW* pNextRows = new SCsROW[MAXCOL+1]; + SCCOL i; + + if ( nMovX > 0 ) // vorwaerts + { + for (i=0; i<=MAXCOL; i++) + pNextRows[i] = (i<nCol) ? (nRow+1) : nRow; + do + { + SCsROW nNextRow = pNextRows[nCol] + 1; + if ( bMarked ) + nNextRow = rMark.GetNextMarked( nCol, nNextRow, false ); + if ( bUnprotected ) + nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, false ); + pNextRows[nCol] = nNextRow; + + SCsROW nMinRow = MAXROW+1; + for (i=0; i<=MAXCOL; i++) + if (pNextRows[i] < nMinRow) // bei gleichen den linken + { + nMinRow = pNextRows[i]; + nCol = i; + } + nRow = nMinRow; + + if ( nRow > MAXROW ) + { + if (++nWrap >= 2) break; // ungueltigen Wert behalten + nCol = 0; + nRow = 0; + for (i=0; i<=MAXCOL; i++) + pNextRows[i] = 0; // alles ganz von vorne + } + } + while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) ); + } + else // rueckwaerts + { + for (i=0; i<=MAXCOL; i++) + pNextRows[i] = (i>nCol) ? (nRow-1) : nRow; + do + { + SCsROW nNextRow = pNextRows[nCol] - 1; + if ( bMarked ) + nNextRow = rMark.GetNextMarked( nCol, nNextRow, sal_True ); + if ( bUnprotected ) + nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, sal_True ); + pNextRows[nCol] = nNextRow; + + SCsROW nMaxRow = -1; + for (i=0; i<=MAXCOL; i++) + if (pNextRows[i] >= nMaxRow) // bei gleichen den rechten + { + nMaxRow = pNextRows[i]; + nCol = i; + } + nRow = nMaxRow; + + if ( nRow < 0 ) + { + if (++nWrap >= 2) break; // ungueltigen Wert behalten + nCol = MAXCOL; + nRow = MAXROW; + for (i=0; i<=MAXCOL; i++) + pNextRows[i] = MAXROW; // alles ganz von vorne + } + } + while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) ); + } + + delete[] pNextRows; + } + } + + // ungueltige Werte kommen z.b. bei Tab heraus, + // wenn nicht markiert und nicht geschuetzt ist (linker / rechter Rand), + // dann Werte unveraendert lassen + + if (VALIDCOLROW(nCol,nRow)) + { + rCol = nCol; + rRow = nRow; + } +} + +sal_Bool ScTable::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark ) +{ + const ScMarkArray* pMarkArray = rMark.GetArray(); + DBG_ASSERT(pMarkArray,"GetNextMarkedCell ohne MarkArray"); + if ( !pMarkArray ) + return false; + + ++rRow; // naechste Zelle ist gesucht + + while ( rCol <= MAXCOL ) + { + const ScMarkArray& rArray = pMarkArray[rCol]; + while ( rRow <= MAXROW ) + { + SCROW nStart = (SCROW) rArray.GetNextMarked( (SCsROW) rRow, false ); + if ( nStart <= MAXROW ) + { + SCROW nEnd = rArray.GetMarkEnd( nStart, false ); + ScColumnIterator aColIter( &aCol[rCol], nStart, nEnd ); + SCROW nCellRow; + ScBaseCell* pCell = NULL; + while ( aColIter.Next( nCellRow, pCell ) ) + { + if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE ) + { + rRow = nCellRow; + return sal_True; // Zelle gefunden + } + } + rRow = nEnd + 1; // naechsten markierten Bereich suchen + } + else + rRow = MAXROW + 1; // Ende der Spalte + } + rRow = 0; + ++rCol; // naechste Spalte testen + } + + return false; // alle Spalten durch +} + +void ScTable::UpdateDrawRef( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, + SCCOL nCol2, SCROW nRow2, SCTAB nTab2, + SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bUpdateNoteCaptionPos ) +{ + if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // only within the table + { + InitializeNoteCaptions(); + ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer(); + if ( eUpdateRefMode != URM_COPY && pDrawLayer ) + { + if ( eUpdateRefMode == URM_MOVE ) + { // source range + nCol1 = sal::static_int_cast<SCCOL>( nCol1 - nDx ); + nRow1 = sal::static_int_cast<SCROW>( nRow1 - nDy ); + nCol2 = sal::static_int_cast<SCCOL>( nCol2 - nDx ); + nRow2 = sal::static_int_cast<SCROW>( nRow2 - nDy ); + } + pDrawLayer->MoveArea( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy, + (eUpdateRefMode == URM_INSDEL), bUpdateNoteCaptionPos ); + } + } +} + +void ScTable::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, + SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz, + ScDocument* pUndoDoc, sal_Bool bIncludeDraw, bool bUpdateNoteCaptionPos ) +{ + bool bUpdated = false; + SCCOL i; + SCCOL iMax; + if ( eUpdateRefMode == URM_COPY ) + { + i = nCol1; + iMax = nCol2; + } + else + { + i = 0; + iMax = MAXCOL; + } + for ( ; i<=iMax; i++) + bUpdated |= aCol[i].UpdateReference( + eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz, pUndoDoc ); + + if ( bIncludeDraw ) + UpdateDrawRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz, bUpdateNoteCaptionPos ); + + if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // print ranges: only within the table + { + SCTAB nSTab = nTab; + SCTAB nETab = nTab; + SCCOL nSCol = 0; + SCROW nSRow = 0; + SCCOL nECol = 0; + SCROW nERow = 0; + sal_Bool bRecalcPages = false; + + for ( ScRangeVec::iterator aIt = aPrintRanges.begin(), aEnd = aPrintRanges.end(); aIt != aEnd; ++aIt ) + { + nSCol = aIt->aStart.Col(); + nSRow = aIt->aStart.Row(); + nECol = aIt->aEnd.Col(); + nERow = aIt->aEnd.Row(); + + // do not try to modify sheet index of print range + if ( ScRefUpdate::Update( pDocument, eUpdateRefMode, + nCol1,nRow1,nTab, nCol2,nRow2,nTab, + nDx,nDy,0, + nSCol,nSRow,nSTab, nECol,nERow,nETab ) ) + { + *aIt = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 ); + bRecalcPages = sal_True; + } + } + + if ( pRepeatColRange ) + { + nSCol = pRepeatColRange->aStart.Col(); + nSRow = pRepeatColRange->aStart.Row(); + nECol = pRepeatColRange->aEnd.Col(); + nERow = pRepeatColRange->aEnd.Row(); + + // do not try to modify sheet index of repeat range + if ( ScRefUpdate::Update( pDocument, eUpdateRefMode, + nCol1,nRow1,nTab, nCol2,nRow2,nTab, + nDx,nDy,0, + nSCol,nSRow,nSTab, nECol,nERow,nETab ) ) + { + *pRepeatColRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 ); + bRecalcPages = sal_True; + nRepeatStartX = nSCol; // fuer UpdatePageBreaks + nRepeatEndX = nECol; + } + } + + if ( pRepeatRowRange ) + { + nSCol = pRepeatRowRange->aStart.Col(); + nSRow = pRepeatRowRange->aStart.Row(); + nECol = pRepeatRowRange->aEnd.Col(); + nERow = pRepeatRowRange->aEnd.Row(); + + // do not try to modify sheet index of repeat range + if ( ScRefUpdate::Update( pDocument, eUpdateRefMode, + nCol1,nRow1,nTab, nCol2,nRow2,nTab, + nDx,nDy,0, + nSCol,nSRow,nSTab, nECol,nERow,nETab ) ) + { + *pRepeatRowRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 ); + bRecalcPages = sal_True; + nRepeatStartY = nSRow; // fuer UpdatePageBreaks + nRepeatEndY = nERow; + } + } + + // updating print ranges is not necessary with multiple print ranges + if ( bRecalcPages && GetPrintRangeCount() <= 1 ) + { + UpdatePageBreaks(NULL); + + pDocument->RepaintRange( ScRange(0,0,nTab,MAXCOL,MAXROW,nTab) ); + } + } + + if (bUpdated && IsStreamValid()) + SetStreamValid(false); +} + +void ScTable::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest, + ScDocument* pUndoDoc ) +{ + for ( SCCOL i=0; i<=MAXCOL; i++ ) + aCol[i].UpdateTranspose( rSource, rDest, pUndoDoc ); +} + +void ScTable::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ) +{ + for ( SCCOL i=0; i<=MAXCOL; i++ ) + aCol[i].UpdateGrow( rArea, nGrowX, nGrowY ); +} + +void ScTable::UpdateInsertTab(SCTAB nTable) +{ + if (nTab >= nTable) nTab++; + for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].UpdateInsertTab(nTable); + + if (IsStreamValid()) + SetStreamValid(false); +} + +void ScTable::UpdateDeleteTab( SCTAB nTable, sal_Bool bIsMove, ScTable* pRefUndo ) +{ + if (nTab > nTable) nTab--; + + SCCOL i; + if (pRefUndo) + for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, &pRefUndo->aCol[i]); + else + for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, NULL); + + if (IsStreamValid()) + SetStreamValid(false); +} + +void ScTable::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo, + ScProgress& rProgress ) +{ + nTab = nTabNo; + for ( SCCOL i=0; i <= MAXCOL; i++ ) + { + aCol[i].UpdateMoveTab( nOldPos, nNewPos, nTabNo ); + rProgress.SetState( rProgress.GetState() + aCol[i].GetCodeCount() ); + } + + if (IsStreamValid()) + SetStreamValid(false); + if (pDBDataNoName) + pDBDataNoName->UpdateMoveTab(nOldPos, nNewPos); +} + +void ScTable::UpdateCompile( sal_Bool bForceIfNameInUse ) +{ + for (SCCOL i=0; i <= MAXCOL; i++) + { + aCol[i].UpdateCompile( bForceIfNameInUse ); + } +} + +void ScTable::SetTabNo(SCTAB nNewTab) +{ + nTab = nNewTab; + for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].SetTabNo(nNewTab); +} + +sal_Bool ScTable::IsRangeNameInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, + sal_uInt16 nIndex) const +{ + sal_Bool bInUse = false; + for (SCCOL i = nCol1; !bInUse && (i <= nCol2) && (ValidCol(i)); i++) + bInUse = aCol[i].IsRangeNameInUse(nRow1, nRow2, nIndex); + return bInUse; +} + +void ScTable::FindRangeNamesInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, + std::set<sal_uInt16>& rIndexes) const +{ + for (SCCOL i = nCol1; i <= nCol2 && ValidCol(i); i++) + aCol[i].FindRangeNamesInUse(nRow1, nRow2, rIndexes); +} + +void ScTable::ReplaceRangeNamesInUse(SCCOL nCol1, SCROW nRow1, + SCCOL nCol2, SCROW nRow2, + const ScRangeData::IndexMap& rMap ) +{ + for (SCCOL i = nCol1; i <= nCol2 && (ValidCol(i)); i++) + { + aCol[i].ReplaceRangeNamesInUse( nRow1, nRow2, rMap ); + } +} + +void ScTable::ExtendPrintArea( OutputDevice* pDev, + SCCOL /* nStartCol */, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow ) +{ + if ( !pColFlags || !pRowFlags ) + { + OSL_FAIL("keine ColInfo oder RowInfo in ExtendPrintArea"); + return; + } + + Point aPix1000 = pDev->LogicToPixel( Point(1000,1000), MAP_TWIP ); + double nPPTX = aPix1000.X() / 1000.0; + double nPPTY = aPix1000.Y() / 1000.0; + + // First, mark those columns that we need to skip i.e. hidden and empty columns. + + ScFlatBoolColSegments aSkipCols; + aSkipCols.setFalse(0, MAXCOL); + for (SCCOL i = 0; i <= MAXCOL; ++i) + { + SCCOL nLastCol = i; + if (ColHidden(i, NULL, &nLastCol)) + { + // Columns are hidden in this range. + aSkipCols.setTrue(i, nLastCol); + } + else + { + // These columns are visible. Check for empty columns. + for (SCCOL j = i; j <= nLastCol; ++j) + { + if (aCol[j].GetCellCount() == 0) + // empty + aSkipCols.setTrue(j,j); + } + } + i = nLastCol; + } + + ScFlatBoolColSegments::RangeData aColData; + for (SCCOL nCol = rEndCol; nCol >= 0; --nCol) + { + if (!aSkipCols.getRangeData(nCol, aColData)) + // Failed to get the data. This should never happen! + return; + + if (aColData.mbValue) + { + // Skip these columns. + nCol = aColData.mnCol1; // move toward 0. + continue; + } + + // These are visible and non-empty columns. + for (SCCOL nDataCol = nCol; 0 <= nDataCol && nDataCol >= aColData.mnCol1; --nDataCol) + { + SCCOL nPrintCol = nDataCol; + VisibleDataCellIterator aIter(*mpHiddenRows, aCol[nDataCol]); + ScBaseCell* pCell = aIter.reset(nStartRow); + if (!pCell) + // No visible cells found in this column. Skip it. + continue; + + while (pCell) + { + SCCOL nNewCol = nDataCol; + SCROW nRow = aIter.getRow(); + if (nRow > nEndRow) + // Went past the last row position. Bail out. + break; + + MaybeAddExtraColumn(nNewCol, nRow, pDev, nPPTX, nPPTY); + if (nNewCol > nPrintCol) + nPrintCol = nNewCol; + pCell = aIter.next(); + } + + if (nPrintCol > rEndCol) + // Make sure we don't shrink the print area. + rEndCol = nPrintCol; + } + nCol = aColData.mnCol1; // move toward 0. + } +} + +void ScTable::MaybeAddExtraColumn(SCCOL& rCol, SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY) +{ + ScBaseCell* pCell = aCol[rCol].GetCell(nRow); + if (!pCell || !pCell->HasStringData()) + return; + + bool bFormula = false; //! ueberge + long nPixel = pCell->GetTextWidth(); + + // Breite bereits im Idle-Handler berechnet? + if ( TEXTWIDTH_DIRTY == nPixel ) + { + ScNeededSizeOptions aOptions; + aOptions.bTotalSize = sal_True; + aOptions.bFormula = bFormula; + aOptions.bSkipMerged = false; + + Fraction aZoom(1,1); + nPixel = aCol[rCol].GetNeededSize( + nRow, pDev, nPPTX, nPPTY, aZoom, aZoom, true, aOptions ); + pCell->SetTextWidth( (sal_uInt16)nPixel ); + } + + long nTwips = (long) (nPixel / nPPTX); + long nDocW = GetColWidth( rCol ); + + long nMissing = nTwips - nDocW; + if ( nMissing > 0 ) + { + // look at alignment + + const ScPatternAttr* pPattern = GetPattern( rCol, nRow ); + const SfxItemSet* pCondSet = NULL; + if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() ) + pCondSet = pDocument->GetCondResult( rCol, nRow, nTab ); + + SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&) + pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue(); + if ( eHorJust == SVX_HOR_JUSTIFY_CENTER ) + nMissing /= 2; // distributed into both directions + else + { + // STANDARD is LEFT (only text is handled here) + bool bRight = ( eHorJust == SVX_HOR_JUSTIFY_RIGHT ); + if ( IsLayoutRTL() ) + bRight = !bRight; + if ( bRight ) + nMissing = 0; // extended only to the left (logical) + } + } + + SCCOL nNewCol = rCol; + while (nMissing > 0 && nNewCol < MAXCOL) + { + ScBaseCell* pNextCell = aCol[nNewCol+1].GetCell(nRow); + if (pNextCell && pNextCell->GetCellType() != CELLTYPE_NOTE) + // Cell content in a next column ends display of this string. + nMissing = 0; + else + nMissing -= GetColWidth(++nNewCol); + } + rCol = nNewCol; +} + +namespace { + +class SetTableIndex : public ::std::unary_function<ScRange, void> +{ + SCTAB mnTab; +public: + SetTableIndex(SCTAB nTab) : mnTab(nTab) {} + + void operator() (ScRange& rRange) const + { + rRange.aStart.SetTab(mnTab); + rRange.aEnd.SetTab(mnTab); + } +}; + +} + +void ScTable::CopyPrintRange(const ScTable& rTable) +{ + // The table index shouldn't be used when the print range is used, but + // just in case set the correct table index. + + aPrintRanges = rTable.aPrintRanges; + ::std::for_each(aPrintRanges.begin(), aPrintRanges.end(), SetTableIndex(nTab)); + + bPrintEntireSheet = rTable.bPrintEntireSheet; + + delete pRepeatColRange; + pRepeatColRange = NULL; + if (rTable.pRepeatColRange) + { + pRepeatColRange = new ScRange(*rTable.pRepeatColRange); + pRepeatColRange->aStart.SetTab(nTab); + pRepeatColRange->aEnd.SetTab(nTab); + } + + delete pRepeatRowRange; + pRepeatRowRange = NULL; + if (rTable.pRepeatRowRange) + { + pRepeatRowRange = new ScRange(*rTable.pRepeatRowRange); + pRepeatRowRange->aStart.SetTab(nTab); + pRepeatRowRange->aEnd.SetTab(nTab); + } +} + +void ScTable::DoColResize( SCCOL nCol1, SCCOL nCol2, SCSIZE nAdd ) +{ + for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++) + aCol[nCol].Resize(aCol[nCol].GetCellCount() + nAdd); +} + +#define SET_PRINTRANGE( p1, p2 ) \ + if ( (p2) ) \ + { \ + if ( (p1) ) \ + *(p1) = *(p2); \ + else \ + (p1) = new ScRange( *(p2) ); \ + } \ + else \ + DELETEZ( (p1) ) + +void ScTable::SetRepeatColRange( const ScRange* pNew ) +{ + SET_PRINTRANGE( pRepeatColRange, pNew ); + + if (IsStreamValid()) + SetStreamValid(false); +} + +void ScTable::SetRepeatRowRange( const ScRange* pNew ) +{ + SET_PRINTRANGE( pRepeatRowRange, pNew ); + + if (IsStreamValid()) + SetStreamValid(false); +} + +void ScTable::ClearPrintRanges() +{ + aPrintRanges.clear(); + bPrintEntireSheet = false; + + if (IsStreamValid()) + SetStreamValid(false); +} + +void ScTable::AddPrintRange( const ScRange& rNew ) +{ + bPrintEntireSheet = false; + if( aPrintRanges.size() < 0xFFFF ) + aPrintRanges.push_back( rNew ); + + if (IsStreamValid()) + SetStreamValid(false); +} + + +void ScTable::SetPrintEntireSheet() +{ + if( !IsPrintEntireSheet() ) + { + ClearPrintRanges(); + bPrintEntireSheet = sal_True; + } +} + +const ScRange* ScTable::GetPrintRange(sal_uInt16 nPos) const +{ + return (nPos < GetPrintRangeCount()) ? &aPrintRanges[ nPos ] : NULL; +} + +void ScTable::FillPrintSaver( ScPrintSaverTab& rSaveTab ) const +{ + rSaveTab.SetAreas( aPrintRanges, bPrintEntireSheet ); + rSaveTab.SetRepeat( pRepeatColRange, pRepeatRowRange ); +} + +void ScTable::RestorePrintRanges( const ScPrintSaverTab& rSaveTab ) +{ + aPrintRanges = rSaveTab.GetPrintRanges(); + bPrintEntireSheet = rSaveTab.IsEntireSheet(); + SetRepeatColRange( rSaveTab.GetRepeatCol() ); + SetRepeatRowRange( rSaveTab.GetRepeatRow() ); + + UpdatePageBreaks(NULL); +} + +SCROW ScTable::VisibleDataCellIterator::ROW_NOT_FOUND = -1; + +ScTable::VisibleDataCellIterator::VisibleDataCellIterator(ScFlatBoolRowSegments& rRowSegs, ScColumn& rColumn) : + mrRowSegs(rRowSegs), + mrColumn(rColumn), + mpCell(NULL), + mnCurRow(ROW_NOT_FOUND), + mnUBound(ROW_NOT_FOUND) +{ +} + +ScTable::VisibleDataCellIterator::~VisibleDataCellIterator() +{ +} + +ScBaseCell* ScTable::VisibleDataCellIterator::reset(SCROW nRow) +{ + if (nRow > MAXROW) + { + mnCurRow = ROW_NOT_FOUND; + return NULL; + } + + ScFlatBoolRowSegments::RangeData aData; + if (!mrRowSegs.getRangeData(nRow, aData)) + { + mnCurRow = ROW_NOT_FOUND; + return NULL; + } + + if (!aData.mbValue) + { + // specified row is visible. Take it. + mnCurRow = nRow; + mnUBound = aData.mnRow2; + } + else + { + // specified row is not-visible. The first visible row is the start of + // the next segment. + mnCurRow = aData.mnRow2 + 1; + mnUBound = mnCurRow; // get range data on the next iteration. + if (mnCurRow > MAXROW) + { + // Make sure the row doesn't exceed our current limit. + mnCurRow = ROW_NOT_FOUND; + return NULL; + } + } + + mpCell = mrColumn.GetCell(mnCurRow); + if (mpCell) + // First visible cell found. + return mpCell; + + // Find a first visible cell below this row (if any). + return next(); +} + +ScBaseCell* ScTable::VisibleDataCellIterator::next() +{ + if (mnCurRow == ROW_NOT_FOUND) + return NULL; + + while (mrColumn.GetNextDataPos(mnCurRow)) + { + if (mnCurRow > mnUBound) + { + // We don't know the visibility of this row range. Query it. + ScFlatBoolRowSegments::RangeData aData; + if (!mrRowSegs.getRangeData(mnCurRow, aData)) + { + mnCurRow = ROW_NOT_FOUND; + return NULL; + } + + if (aData.mbValue) + { + // This row is invisible. Skip to the last invisible row and + // try again. + mnCurRow = mnUBound = aData.mnRow2; + continue; + } + + // This row is visible. + mnUBound = aData.mnRow2; + } + + mpCell = mrColumn.GetCell(mnCurRow); + if (mpCell) + return mpCell; + } + mnCurRow = ROW_NOT_FOUND; + return NULL; +} + +SCROW ScTable::VisibleDataCellIterator::getRow() const +{ + return mnCurRow; +} + +void ScTable::SetAnonymousDBData(ScDBData* pDBData) +{ + delete pDBDataNoName; + pDBDataNoName = pDBData; +} + +ScDBData* ScTable::GetAnonymousDBData() +{ + return pDBDataNoName; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |