| /************************************************************** |
| * |
| * 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 --------------------------------------------------------------- |
| |
| #include "scitems.hxx" |
| #include "collect.hxx" |
| #include "attrib.hxx" |
| #include "patattr.hxx" |
| #include "docpool.hxx" |
| #include "cell.hxx" |
| #include "table.hxx" |
| #include "column.hxx" |
| #include "document.hxx" |
| #include "drwlayer.hxx" |
| #include "olinetab.hxx" |
| #include "userlist.hxx" |
| #include "stlsheet.hxx" |
| #include "global.hxx" |
| #include "rechead.hxx" |
| #include "stlpool.hxx" |
| #include "stlsheet.hxx" |
| #include "brdcst.hxx" |
| #include "tabprotection.hxx" |
| #include "globstr.hrc" |
| #include "segmenttree.hxx" |
| #include <com/sun/star/sheet/TablePageBreakData.hpp> |
| |
| #include <algorithm> |
| #include <limits> |
| |
| using ::com::sun::star::uno::Sequence; |
| using ::com::sun::star::sheet::TablePageBreakData; |
| using ::std::set; |
| |
| // STATIC DATA ----------------------------------------------------------- |
| |
| #define GET_SCALEVALUE(set,id) ((const SfxUInt16Item&)(set.Get( id ))).GetValue() |
| |
| |
| void ScTable::UpdatePageBreaks( const ScRange* pUserArea ) |
| { |
| if ( pDocument->IsImportingXML() ) |
| return; |
| |
| // pUserArea != NULL -> print area is specified. We need to force-update |
| // the page breaks. |
| |
| if (!pUserArea) |
| { |
| if (!bPageSizeValid) |
| return; |
| |
| if (mbPageBreaksValid) |
| return; |
| } |
| |
| SfxStyleSheetBase* pStyle = pDocument->GetStyleSheetPool()-> |
| Find( aPageStyle, SFX_STYLE_FAMILY_PAGE ); |
| if ( !pStyle ) |
| { |
| DBG_ERROR("UpdatePageBreaks: Style nicht gefunden"); |
| return; |
| } |
| SfxItemSet* pStyleSet = &pStyle->GetItemSet(); |
| const SfxPoolItem* pItem; |
| |
| SCCOL nX; |
| SCCOL nStartCol = 0; |
| SCROW nStartRow = 0; |
| SCCOL nEndCol = MAXCOL; |
| SCROW nEndRow = MAXROW; |
| if (pUserArea) |
| { |
| nStartCol = pUserArea->aStart.Col(); |
| nStartRow = pUserArea->aStart.Row(); |
| nEndCol = pUserArea->aEnd.Col(); |
| nEndRow = pUserArea->aEnd.Row(); |
| } |
| else |
| { |
| sal_uInt16 nAreaCount = GetPrintRangeCount(); |
| if ( nAreaCount > 1 ) |
| { |
| // bei mehreren Bereichen nichts anzeigen: |
| |
| for (nX=0; nX<MAXCOL; nX++) |
| RemoveColBreak(nX, true, false); |
| |
| RemoveRowPageBreaks(0, MAXROW-1); |
| |
| return; |
| } |
| else if ( nAreaCount == 1 ) |
| { |
| const ScRange* pArea = GetPrintRange( 0 ); |
| if (pArea) |
| { |
| nStartCol = pArea->aStart.Col(); |
| nStartRow = pArea->aStart.Row(); |
| nEndCol = pArea->aEnd.Col(); |
| nEndRow = pArea->aEnd.Row(); |
| } |
| } // sonst alles |
| } |
| |
| // get bSkipColBreaks/bSkipRowBreaks flags: |
| |
| bool bSkipColBreaks = false; |
| bool bSkipRowBreaks = false; |
| |
| if ( pStyleSet->GetItemState( ATTR_PAGE_SCALETOPAGES, sal_False, &pItem ) == SFX_ITEM_SET ) |
| { |
| DBG_ASSERT( pItem->ISA(SfxUInt16Item), "falsches Item" ); |
| bSkipColBreaks = bSkipRowBreaks = ( ((const SfxUInt16Item*)pItem)->GetValue() > 0 ); |
| } |
| |
| if ( !bSkipColBreaks && pStyleSet->GetItemState(ATTR_PAGE_SCALETO, sal_False, &pItem) == SFX_ITEM_SET ) |
| { |
| // #i54993# when fitting to width or height, ignore only manual breaks in that direction |
| const ScPageScaleToItem* pScaleToItem = static_cast<const ScPageScaleToItem*>(pItem); |
| if ( pScaleToItem->GetWidth() > 0 ) |
| bSkipColBreaks = true; |
| if ( pScaleToItem->GetHeight() > 0 ) |
| bSkipRowBreaks = true; |
| } |
| |
| //-------------------------------------------------------------------------- |
| |
| long nPageSizeX = aPageSizeTwips.Width(); |
| long nPageSizeY = aPageSizeTwips.Height(); |
| |
| // Anfang: Breaks loeschen |
| |
| for (nX=0; nX<nStartCol; nX++) |
| RemoveColBreak(nX, true, false); |
| RemoveRowPageBreaks(0, nStartRow-1); |
| |
| if (nStartCol > 0) |
| SetColBreak(nStartCol, true, false); // AREABREAK |
| if (nStartRow > 0) |
| SetRowBreak(nStartRow, true, false); // AREABREAK |
| |
| // Mittelteil: Breaks verteilen |
| |
| sal_Bool bRepeatCol = ( nRepeatStartX != SCCOL_REPEAT_NONE ); |
| sal_Bool bColFound = sal_False; |
| long nSizeX = 0; |
| for (nX=nStartCol; nX<=nEndCol; nX++) |
| { |
| sal_Bool bStartOfPage = sal_False; |
| long nThisX = ColHidden(nX) ? 0 : pColWidth[nX]; |
| bool bManualBreak = HasColManualBreak(nX); |
| if ( (nSizeX+nThisX > nPageSizeX) || (bManualBreak && !bSkipColBreaks) ) |
| { |
| SetColBreak(nX, true, false); |
| nSizeX = 0; |
| bStartOfPage = sal_True; |
| } |
| else if (nX != nStartCol) |
| RemoveColBreak(nX, true, false); |
| else |
| bStartOfPage = sal_True; |
| |
| if ( bStartOfPage && bRepeatCol && nX>nRepeatStartX && !bColFound ) |
| { |
| // subtract size of repeat columns from page size |
| for (SCCOL i=nRepeatStartX; i<=nRepeatEndX; i++) |
| nPageSizeX -= ColHidden(i) ? 0 : pColWidth[i]; |
| while (nX<=nRepeatEndX) |
| RemoveColBreak(++nX, true, false); |
| bColFound = sal_True; |
| } |
| |
| nSizeX += nThisX; |
| } |
| |
| // Remove all page breaks in range. |
| RemoveRowPageBreaks(nStartRow+1, nEndRow); |
| |
| // And set new page breaks. |
| sal_Bool bRepeatRow = ( nRepeatStartY != SCROW_REPEAT_NONE ); |
| sal_Bool bRowFound = sal_False; |
| long nSizeY = 0; |
| ScFlatBoolRowSegments::ForwardIterator aIterHidden(*mpHiddenRows); |
| ScFlatUInt16RowSegments::ForwardIterator aIterHeights(*mpRowHeights); |
| SCROW nNextManualBreak = GetNextManualBreak(nStartRow); // -1 => no more manual breaks |
| for (SCROW nY = nStartRow; nY <= nEndRow; ++nY) |
| { |
| sal_Bool bStartOfPage = sal_False; |
| bool bThisRowHidden = false; |
| aIterHidden.getValue(nY, bThisRowHidden); |
| long nThisY = 0; |
| if (!bThisRowHidden) |
| { |
| sal_uInt16 nTmp; |
| aIterHeights.getValue(nY, nTmp); |
| nThisY = static_cast<long>(nTmp); |
| } |
| |
| bool bManualBreak = false; |
| if (nNextManualBreak >= 0) |
| { |
| bManualBreak = (nY == nNextManualBreak); |
| if (nY >= nNextManualBreak) |
| // Query the next menual break position. |
| nNextManualBreak = GetNextManualBreak(nY+1); |
| } |
| |
| if ( (nSizeY+nThisY > nPageSizeY) || (bManualBreak && !bSkipRowBreaks) ) |
| { |
| SetRowBreak(nY, true, false); |
| nSizeY = 0; |
| bStartOfPage = sal_True; |
| } |
| else if (nY != nStartRow) |
| ; // page break already removed |
| else |
| bStartOfPage = sal_True; |
| |
| if ( bStartOfPage && bRepeatRow && nY>nRepeatStartY && !bRowFound ) |
| { |
| // subtract size of repeat rows from page size |
| unsigned long nHeights = GetTotalRowHeight(nRepeatStartY, nRepeatEndY); |
| #ifdef DBG_UTIL |
| if (nHeights == ::std::numeric_limits<unsigned long>::max()) |
| DBG_ERRORFILE("ScTable::UpdatePageBreaks: row heights overflow"); |
| #endif |
| nPageSizeY -= nHeights; |
| if (nY <= nRepeatEndY) |
| RemoveRowPageBreaks(nY, nRepeatEndY); |
| bRowFound = sal_True; |
| } |
| |
| if (bThisRowHidden) |
| { |
| // Hidden row range. Skip them unless there is a manual break. |
| SCROW nLastCommon = aIterHidden.getLastPos(); |
| if (nNextManualBreak >= 0) |
| nLastCommon = ::std::min(nLastCommon, nNextManualBreak-1); |
| nY = nLastCommon; |
| } |
| else |
| { |
| // Visible row range. |
| |
| SCROW nLastHidden = aIterHidden.getLastPos(); |
| SCROW nLastHeight = aIterHeights.getLastPos(); |
| SCROW nLastCommon = ::std::min(nLastHidden, nLastHeight); |
| if (nNextManualBreak >= 0) |
| nLastCommon = ::std::min(nLastCommon, nNextManualBreak-1); |
| |
| if (nLastCommon > nY) |
| { |
| long nMaxMultiple = static_cast<long>(nLastCommon - nY); |
| long nMultiple = (nPageSizeY - nSizeY) / nThisY; |
| if (nMultiple > nMaxMultiple) |
| nMultiple = nMaxMultiple; |
| if (nMultiple > 1) |
| { |
| nSizeY += nThisY * (nMultiple - 1); |
| nY += nMultiple - 1; |
| } |
| } |
| } |
| |
| nSizeY += nThisY; |
| } |
| |
| // Ende: Breaks loeschen |
| |
| if (nEndCol < MAXCOL) |
| { |
| SetColBreak(nEndCol+1, true, false); // AREABREAK |
| for (nX=nEndCol+2; nX<=MAXCOL; nX++) |
| RemoveColBreak(nX, true, false); |
| } |
| if (nEndRow < MAXROW) |
| { |
| SetRowBreak(nEndRow+1, true, false); // AREABREAK |
| if (nEndRow+2 <= MAXROW) |
| RemoveRowPageBreaks(nEndRow+2, MAXROW); |
| } |
| mbPageBreaksValid = !pUserArea; // #i116881# the valid flag can only apply to the "no user area" case |
| } |
| |
| void ScTable::RemoveManualBreaks() |
| { |
| maRowManualBreaks.clear(); |
| maColManualBreaks.clear(); |
| InvalidatePageBreaks(); |
| |
| if (IsStreamValid()) |
| SetStreamValid(sal_False); |
| } |
| |
| sal_Bool ScTable::HasManualBreaks() const |
| { |
| return !maRowManualBreaks.empty() || !maColManualBreaks.empty(); |
| } |
| |
| void ScTable::SetRowManualBreaks( const ::std::set<SCROW>& rBreaks ) |
| { |
| maRowManualBreaks = rBreaks; |
| InvalidatePageBreaks(); |
| if (IsStreamValid()) |
| SetStreamValid(sal_False); |
| } |
| |
| void ScTable::SetColManualBreaks( const ::std::set<SCCOL>& rBreaks ) |
| { |
| maColManualBreaks = rBreaks; |
| InvalidatePageBreaks(); |
| if (IsStreamValid()) |
| SetStreamValid(sal_False); |
| } |
| |
| void ScTable::GetAllRowBreaks(set<SCROW>& rBreaks, bool bPage, bool bManual) const |
| { |
| if (bPage) |
| rBreaks = maRowPageBreaks; |
| |
| if (bManual) |
| { |
| using namespace std; |
| copy(maRowManualBreaks.begin(), maRowManualBreaks.end(), inserter(rBreaks, rBreaks.begin())); |
| } |
| } |
| |
| void ScTable::GetAllColBreaks(set<SCCOL>& rBreaks, bool bPage, bool bManual) const |
| { |
| if (bPage) |
| rBreaks = maColPageBreaks; |
| |
| if (bManual) |
| { |
| using namespace std; |
| copy(maColManualBreaks.begin(), maColManualBreaks.end(), inserter(rBreaks, rBreaks.begin())); |
| } |
| } |
| |
| bool ScTable::HasRowPageBreak(SCROW nRow) const |
| { |
| if (!ValidRow(nRow)) |
| return false; |
| |
| return maRowPageBreaks.find(nRow) != maRowPageBreaks.end(); |
| } |
| |
| bool ScTable::HasColPageBreak(SCCOL nCol) const |
| { |
| if (!ValidCol(nCol)) |
| return false; |
| |
| return maColPageBreaks.find(nCol) != maColPageBreaks.end(); |
| } |
| |
| bool ScTable::HasRowManualBreak(SCROW nRow) const |
| { |
| if (!ValidRow(nRow)) |
| return false; |
| |
| return maRowManualBreaks.find(nRow) != maRowManualBreaks.end(); |
| } |
| |
| bool ScTable::HasColManualBreak(SCCOL nCol) const |
| { |
| if (!ValidCol(nCol)) |
| return false; |
| |
| return maColManualBreaks.find(nCol) != maColManualBreaks.end(); |
| } |
| |
| SCROW ScTable::GetNextManualBreak(SCROW nRow) const |
| { |
| set<SCROW>::const_iterator itr = maRowManualBreaks.lower_bound(nRow); |
| return itr == maRowManualBreaks.end() ? -1 : *itr; |
| } |
| |
| void ScTable::RemoveRowPageBreaks(SCROW nStartRow, SCROW nEndRow) |
| { |
| using namespace std; |
| |
| if (!ValidRow(nStartRow) || !ValidRow(nEndRow)) |
| return; |
| |
| set<SCROW>::iterator low = maRowPageBreaks.lower_bound(nStartRow); |
| set<SCROW>::iterator high = maRowPageBreaks.upper_bound(nEndRow); |
| maRowPageBreaks.erase(low, high); |
| } |
| |
| void ScTable::RemoveRowBreak(SCROW nRow, bool bPage, bool bManual) |
| { |
| if (!ValidRow(nRow)) |
| return; |
| |
| if (bPage) |
| maRowPageBreaks.erase(nRow); |
| |
| if (bManual) |
| { |
| maRowManualBreaks.erase(nRow); |
| InvalidatePageBreaks(); |
| } |
| } |
| |
| void ScTable::RemoveColBreak(SCCOL nCol, bool bPage, bool bManual) |
| { |
| if (!ValidCol(nCol)) |
| return; |
| |
| if (bPage) |
| maColPageBreaks.erase(nCol); |
| |
| if (bManual) |
| { |
| maColManualBreaks.erase(nCol); |
| InvalidatePageBreaks(); |
| } |
| } |
| |
| void ScTable::SetRowBreak(SCROW nRow, bool bPage, bool bManual) |
| { |
| if (!ValidRow(nRow)) |
| return; |
| |
| if (bPage) |
| maRowPageBreaks.insert(nRow); |
| |
| if (bManual) |
| { |
| maRowManualBreaks.insert(nRow); |
| InvalidatePageBreaks(); |
| } |
| } |
| |
| void ScTable::SetColBreak(SCCOL nCol, bool bPage, bool bManual) |
| { |
| if (!ValidCol(nCol)) |
| return; |
| |
| if (bPage) |
| maColPageBreaks.insert(nCol); |
| |
| if (bManual) |
| { |
| maColManualBreaks.insert(nCol); |
| InvalidatePageBreaks(); |
| } |
| } |
| |
| Sequence<TablePageBreakData> ScTable::GetRowBreakData() const |
| { |
| using ::std::copy; |
| using ::std::inserter; |
| |
| set<SCROW> aRowBreaks = maRowPageBreaks; |
| copy(maRowManualBreaks.begin(), maRowManualBreaks.end(), inserter(aRowBreaks, aRowBreaks.begin())); |
| |
| set<SCROW>::const_iterator itr = aRowBreaks.begin(), itrEnd = aRowBreaks.end(); |
| Sequence<TablePageBreakData> aSeq(aRowBreaks.size()); |
| |
| for (sal_Int32 i = 0; itr != itrEnd; ++itr, ++i) |
| { |
| SCROW nRow = *itr; |
| TablePageBreakData aData; |
| aData.Position = nRow; |
| aData.ManualBreak = HasRowManualBreak(nRow); |
| aSeq[i] = aData; |
| } |
| |
| return aSeq; |
| } |
| |
| bool ScTable::RowHidden(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const |
| { |
| if (!ValidRow(nRow)) |
| { |
| if (pFirstRow) |
| *pFirstRow = nRow; |
| if (pLastRow) |
| *pLastRow = nRow; |
| return true; |
| } |
| |
| ScFlatBoolRowSegments::RangeData aData; |
| if (!mpHiddenRows->getRangeData(nRow, aData)) |
| { |
| // search failed. |
| if (pFirstRow) |
| *pFirstRow = nRow; |
| if (pLastRow) |
| *pLastRow = nRow; |
| return true; |
| } |
| |
| if (pFirstRow) |
| *pFirstRow = aData.mnRow1; |
| if (pLastRow) |
| *pLastRow = aData.mnRow2; |
| |
| return aData.mbValue; |
| } |
| |
| |
| bool ScTable::RowHidden(SCROW nRow, SCROW& rLastRow) const |
| { |
| rLastRow = nRow; |
| if (!ValidRow(nRow)) |
| return true; |
| |
| ScFlatBoolRowSegments::RangeData aData; |
| if (!mpHiddenRows->getRangeData(nRow, aData)) |
| // search failed. |
| return true; |
| |
| rLastRow = aData.mnRow2; |
| return aData.mbValue; |
| } |
| |
| bool ScTable::HasHiddenRows(SCROW nStartRow, SCROW nEndRow) const |
| { |
| SCROW nRow = nStartRow; |
| while (nRow <= nEndRow) |
| { |
| SCROW nLastRow = -1; |
| bool bHidden = RowHidden(nRow, nLastRow); |
| if (bHidden) |
| return true; |
| |
| nRow = nLastRow + 1; |
| } |
| return false; |
| } |
| |
| bool ScTable::ColHidden(SCCOL nCol, SCCOL& rLastCol) const |
| { |
| rLastCol = nCol; |
| if (!ValidCol(nCol)) |
| return true; |
| |
| ScFlatBoolColSegments::RangeData aData; |
| if (!mpHiddenCols->getRangeData(nCol, aData)) |
| return true; |
| |
| rLastCol = aData.mnCol2; |
| return aData.mbValue; |
| } |
| |
| bool ScTable::ColHidden(SCCOL nCol, SCCOL* pFirstCol, SCCOL* pLastCol) const |
| { |
| if (!ValidCol(nCol)) |
| return true; |
| |
| ScFlatBoolColSegments::RangeData aData; |
| if (!mpHiddenCols->getRangeData(nCol, aData)) |
| return true; |
| |
| if (pFirstCol) |
| *pFirstCol = aData.mnCol1; |
| if (pLastCol) |
| *pLastCol = aData.mnCol2; |
| |
| return aData.mbValue; |
| } |
| |
| void ScTable::SetRowHidden(SCROW nStartRow, SCROW nEndRow, bool bHidden) |
| { |
| if (bHidden) |
| mpHiddenRows->setTrue(nStartRow, nEndRow); |
| else |
| mpHiddenRows->setFalse(nStartRow, nEndRow); |
| } |
| |
| void ScTable::SetColHidden(SCCOL nStartCol, SCCOL nEndCol, bool bHidden) |
| { |
| if (bHidden) |
| mpHiddenCols->setTrue(nStartCol, nEndCol); |
| else |
| mpHiddenCols->setFalse(nStartCol, nEndCol); |
| } |
| |
| void ScTable::CopyColHidden(ScTable& rTable, SCCOL nStartCol, SCCOL nEndCol) |
| { |
| SCCOL nCol = nStartCol; |
| while (nCol <= nEndCol) |
| { |
| SCCOL nLastCol; |
| bool bHidden = rTable.ColHidden(nCol, NULL, &nLastCol); |
| if (nLastCol > nEndCol) |
| nLastCol = nEndCol; |
| |
| SetColHidden(nCol, nLastCol, bHidden); |
| nCol = nLastCol + 1; |
| } |
| } |
| |
| void ScTable::CopyRowHidden(ScTable& rTable, SCROW nStartRow, SCROW nEndRow) |
| { |
| SCROW nRow = nStartRow; |
| while (nRow <= nEndRow) |
| { |
| SCROW nLastRow = -1; |
| bool bHidden = rTable.RowHidden(nRow, nLastRow); |
| if (nLastRow > nEndRow) |
| nLastRow = nEndRow; |
| SetRowHidden(nRow, nLastRow, bHidden); |
| nRow = nLastRow + 1; |
| } |
| } |
| |
| void ScTable::CopyRowHeight(ScTable& rSrcTable, SCROW nStartRow, SCROW nEndRow, SCROW nSrcOffset) |
| { |
| SCROW nRow = nStartRow; |
| ScFlatUInt16RowSegments::RangeData aSrcData; |
| while (nRow <= nEndRow) |
| { |
| if (!rSrcTable.mpRowHeights->getRangeData(nRow + nSrcOffset, aSrcData)) |
| // Something is wrong ! |
| return; |
| |
| SCROW nLastRow = aSrcData.mnRow2 - nSrcOffset; |
| if (nLastRow > nEndRow) |
| nLastRow = nEndRow; |
| |
| mpRowHeights->setValue(nRow, nLastRow, aSrcData.mnValue); |
| nRow = nLastRow + 1; |
| } |
| } |
| |
| SCROW ScTable::FirstVisibleRow(SCROW nStartRow, SCROW nEndRow) const |
| { |
| SCROW nRow = nStartRow; |
| ScFlatBoolRowSegments::RangeData aData; |
| while (nRow <= nEndRow) |
| { |
| if (!ValidRow(nRow)) |
| break; |
| |
| if (!mpHiddenRows->getRangeData(nRow, aData)) |
| // failed to get range data. |
| break; |
| |
| if (!aData.mbValue) |
| // visible row found |
| return nRow; |
| |
| nRow = aData.mnRow2 + 1; |
| } |
| |
| return ::std::numeric_limits<SCROW>::max(); |
| } |
| |
| SCROW ScTable::LastVisibleRow(SCROW nStartRow, SCROW nEndRow) const |
| { |
| SCROW nRow = nEndRow; |
| ScFlatBoolRowSegments::RangeData aData; |
| while (nRow >= nStartRow) |
| { |
| if (!ValidRow(nRow)) |
| break; |
| |
| if (!mpHiddenRows->getRangeData(nRow, aData)) |
| // failed to get range data. |
| break; |
| |
| if (!aData.mbValue) |
| // visible row found |
| return nRow; |
| |
| nRow = aData.mnRow1 - 1; |
| } |
| |
| return ::std::numeric_limits<SCROW>::max(); |
| } |
| |
| SCROW ScTable::CountVisibleRows(SCROW nStartRow, SCROW nEndRow) const |
| { |
| SCROW nCount = 0; |
| SCROW nRow = nStartRow; |
| ScFlatBoolRowSegments::RangeData aData; |
| while (nRow <= nEndRow) |
| { |
| if (!mpHiddenRows->getRangeData(nRow, aData)) |
| break; |
| |
| if (aData.mnRow2 > nEndRow) |
| aData.mnRow2 = nEndRow; |
| |
| if (!aData.mbValue) |
| nCount += aData.mnRow2 - nRow + 1; |
| |
| nRow = aData.mnRow2 + 1; |
| } |
| return nCount; |
| } |
| |
| sal_uInt32 ScTable::GetTotalRowHeight(SCROW nStartRow, SCROW nEndRow) const |
| { |
| sal_uInt32 nHeight = 0; |
| SCROW nRow = nStartRow; |
| ScFlatBoolRowSegments::RangeData aData; |
| while (nRow <= nEndRow) |
| { |
| if (!mpHiddenRows->getRangeData(nRow, aData)) |
| break; |
| |
| if (aData.mnRow2 > nEndRow) |
| aData.mnRow2 = nEndRow; |
| |
| if (!aData.mbValue) |
| // visible row range. |
| nHeight += mpRowHeights->getSumValue(nRow, aData.mnRow2); |
| |
| nRow = aData.mnRow2 + 1; |
| } |
| |
| return nHeight; |
| } |
| |
| SCCOLROW ScTable::LastHiddenColRow(SCCOLROW nPos, bool bCol) const |
| { |
| if (bCol) |
| { |
| SCCOL nCol = static_cast<SCCOL>(nPos); |
| if (ColHidden(nCol)) |
| { |
| for (SCCOL i = nCol+1; i <= MAXCOL; ++i) |
| { |
| if (!ColHidden(nCol)) |
| return nCol - 1; |
| } |
| } |
| } |
| else |
| { |
| SCROW nRow = static_cast<SCROW>(nPos); |
| SCROW nLastRow; |
| if (RowHidden(nRow, NULL, &nLastRow)) |
| return static_cast<SCCOLROW>(nLastRow); |
| } |
| return ::std::numeric_limits<SCCOLROW>::max(); |
| } |
| |
| bool ScTable::RowFiltered(SCROW nRow, SCROW* pFirstRow, SCROW* pLastRow) const |
| { |
| if (!ValidRow(nRow)) |
| return false; |
| |
| ScFlatBoolRowSegments::RangeData aData; |
| if (!mpFilteredRows->getRangeData(nRow, aData)) |
| // search failed. |
| return false; |
| |
| if (pFirstRow) |
| *pFirstRow = aData.mnRow1; |
| if (pLastRow) |
| *pLastRow = aData.mnRow2; |
| |
| return aData.mbValue; |
| } |
| |
| bool ScTable::ColFiltered(SCCOL nCol, SCCOL* pFirstCol, SCCOL* pLastCol) const |
| { |
| if (!ValidCol(nCol)) |
| return false; |
| |
| ScFlatBoolColSegments::RangeData aData; |
| if (!mpFilteredCols->getRangeData(nCol, aData)) |
| // search failed. |
| return false; |
| |
| if (pFirstCol) |
| *pFirstCol = aData.mnCol1; |
| if (pLastCol) |
| *pLastCol = aData.mnCol2; |
| |
| return aData.mbValue; |
| } |
| |
| bool ScTable::HasFilteredRows(SCROW nStartRow, SCROW nEndRow) const |
| { |
| SCROW nRow = nStartRow; |
| while (nRow <= nEndRow) |
| { |
| SCROW nLastRow = nRow; |
| bool bFiltered = RowFiltered(nRow, NULL, &nLastRow); |
| if (bFiltered) |
| return true; |
| |
| nRow = nLastRow + 1; |
| } |
| return false; |
| } |
| |
| void ScTable::CopyColFiltered(ScTable& rTable, SCCOL nStartCol, SCCOL nEndCol) |
| { |
| SCCOL nCol = nStartCol; |
| while (nCol <= nEndCol) |
| { |
| SCCOL nLastCol; |
| bool bFiltered = rTable.ColFiltered(nCol, NULL, &nLastCol); |
| if (nLastCol > nEndCol) |
| nLastCol = nEndCol; |
| |
| SetColFiltered(nCol, nLastCol, bFiltered); |
| nCol = nLastCol + 1; |
| } |
| } |
| |
| void ScTable::CopyRowFiltered(ScTable& rTable, SCROW nStartRow, SCROW nEndRow) |
| { |
| SCROW nRow = nStartRow; |
| while (nRow <= nEndRow) |
| { |
| SCROW nLastRow = -1; |
| bool bFiltered = rTable.RowFiltered(nRow, NULL, &nLastRow); |
| if (nLastRow > nEndRow) |
| nLastRow = nEndRow; |
| SetRowFiltered(nRow, nLastRow, bFiltered); |
| nRow = nLastRow + 1; |
| } |
| } |
| |
| void ScTable::SetRowFiltered(SCROW nStartRow, SCROW nEndRow, bool bFiltered) |
| { |
| if (bFiltered) |
| mpFilteredRows->setTrue(nStartRow, nEndRow); |
| else |
| mpFilteredRows->setFalse(nStartRow, nEndRow); |
| } |
| |
| void ScTable::SetColFiltered(SCCOL nStartCol, SCCOL nEndCol, bool bFiltered) |
| { |
| if (bFiltered) |
| mpFilteredCols->setTrue(nStartCol, nEndCol); |
| else |
| mpFilteredCols->setFalse(nStartCol, nEndCol); |
| } |
| |
| SCROW ScTable::FirstNonFilteredRow(SCROW nStartRow, SCROW nEndRow) const |
| { |
| SCROW nRow = nStartRow; |
| ScFlatBoolRowSegments::RangeData aData; |
| while (nRow <= nEndRow) |
| { |
| if (!ValidRow(nRow)) |
| break; |
| |
| if (!mpFilteredRows->getRangeData(nRow, aData)) |
| // failed to get range data. |
| break; |
| |
| if (!aData.mbValue) |
| // non-filtered row found |
| return nRow; |
| |
| nRow = aData.mnRow2 + 1; |
| } |
| |
| return ::std::numeric_limits<SCROW>::max(); |
| } |
| |
| SCROW ScTable::LastNonFilteredRow(SCROW nStartRow, SCROW nEndRow) const |
| { |
| SCROW nRow = nEndRow; |
| ScFlatBoolRowSegments::RangeData aData; |
| while (nRow >= nStartRow) |
| { |
| if (!ValidRow(nRow)) |
| break; |
| |
| if (!mpFilteredRows->getRangeData(nRow, aData)) |
| // failed to get range data. |
| break; |
| |
| if (!aData.mbValue) |
| // non-filtered row found |
| return nRow; |
| |
| nRow = aData.mnRow1 - 1; |
| } |
| |
| return ::std::numeric_limits<SCROW>::max(); |
| } |
| |
| SCROW ScTable::CountNonFilteredRows(SCROW nStartRow, SCROW nEndRow) const |
| { |
| SCROW nCount = 0; |
| SCROW nRow = nStartRow; |
| ScFlatBoolRowSegments::RangeData aData; |
| while (nRow <= nEndRow) |
| { |
| if (!mpFilteredRows->getRangeData(nRow, aData)) |
| break; |
| |
| if (aData.mnRow2 > nEndRow) |
| aData.mnRow2 = nEndRow; |
| |
| if (!aData.mbValue) |
| nCount += aData.mnRow2 - nRow + 1; |
| |
| nRow = aData.mnRow2 + 1; |
| } |
| return nCount; |
| } |
| |
| namespace { |
| |
| void lcl_syncFlags(ScFlatBoolColSegments& rColSegments, ScFlatBoolRowSegments& rRowSegments, |
| sal_uInt8* pColFlags, ScBitMaskCompressedArray< SCROW, sal_uInt8>* pRowFlags, const sal_uInt8 nFlagMask) |
| { |
| using ::sal::static_int_cast; |
| |
| pRowFlags->AndValue(0, MAXROW, static_int_cast<sal_uInt8>(~nFlagMask)); |
| for (SCCOL i = 0; i <= MAXCOL; ++i) |
| pColFlags[i] &= static_int_cast<sal_uInt8>(~nFlagMask); |
| |
| { |
| // row hidden flags. |
| |
| SCROW nRow = 0; |
| ScFlatBoolRowSegments::RangeData aData; |
| while (nRow <= MAXROW) |
| { |
| if (!rRowSegments.getRangeData(nRow, aData)) |
| break; |
| |
| if (aData.mbValue) |
| pRowFlags->OrValue(nRow, aData.mnRow2, static_int_cast<sal_uInt8>(nFlagMask)); |
| |
| nRow = aData.mnRow2 + 1; |
| } |
| } |
| |
| { |
| // column hidden flags. |
| |
| SCCOL nCol = 0; |
| ScFlatBoolColSegments::RangeData aData; |
| while (nCol <= MAXCOL) |
| { |
| if (!rColSegments.getRangeData(nCol, aData)) |
| break; |
| |
| if (aData.mbValue) |
| { |
| for (SCCOL i = nCol; i <= aData.mnCol2; ++i) |
| pColFlags[i] |= nFlagMask; |
| } |
| |
| nCol = aData.mnCol2 + 1; |
| } |
| } |
| } |
| |
| } |
| |
| void ScTable::SyncColRowFlags() |
| { |
| using ::sal::static_int_cast; |
| |
| // Manual breaks. |
| pRowFlags->AndValue(0, MAXROW, static_int_cast<sal_uInt8>(~CR_MANUALBREAK)); |
| for (SCCOL i = 0; i <= MAXCOL; ++i) |
| pColFlags[i] &= static_int_cast<sal_uInt8>(~CR_MANUALBREAK); |
| |
| if (!maRowManualBreaks.empty()) |
| { |
| for (set<SCROW>::const_iterator itr = maRowManualBreaks.begin(), itrEnd = maRowManualBreaks.end(); |
| itr != itrEnd; ++itr) |
| pRowFlags->OrValue(*itr, static_int_cast<sal_uInt8>(CR_MANUALBREAK)); |
| } |
| |
| if (!maColManualBreaks.empty()) |
| { |
| for (set<SCCOL>::const_iterator itr = maColManualBreaks.begin(), itrEnd = maColManualBreaks.end(); |
| itr != itrEnd; ++itr) |
| pColFlags[*itr] |= CR_MANUALBREAK; |
| } |
| |
| // Hidden flags. |
| lcl_syncFlags(*mpHiddenCols, *mpHiddenRows, pColFlags, pRowFlags, CR_HIDDEN); |
| lcl_syncFlags(*mpFilteredCols, *mpFilteredRows, pColFlags, pRowFlags, CR_FILTERED); |
| } |
| |
| void ScTable::SetPageSize( const Size& rSize ) |
| { |
| if ( rSize.Width() != 0 && rSize.Height() != 0 ) |
| { |
| if (aPageSizeTwips != rSize) |
| InvalidatePageBreaks(); |
| |
| bPageSizeValid = sal_True; |
| aPageSizeTwips = rSize; |
| } |
| else |
| bPageSizeValid = sal_False; |
| } |
| |
| sal_Bool ScTable::IsProtected() const |
| { |
| return pTabProtection.get() && pTabProtection->isProtected(); |
| } |
| |
| void ScTable::SetProtection(const ScTableProtection* pProtect) |
| { |
| if (pProtect) |
| pTabProtection.reset(new ScTableProtection(*pProtect)); |
| else |
| pTabProtection.reset(); |
| |
| if (IsStreamValid()) |
| SetStreamValid(sal_False); |
| } |
| |
| ScTableProtection* ScTable::GetProtection() |
| { |
| return pTabProtection.get(); |
| } |
| |
| Size ScTable::GetPageSize() const |
| { |
| if ( bPageSizeValid ) |
| return aPageSizeTwips; |
| else |
| return Size(); // leer |
| } |
| |
| void ScTable::SetRepeatArea( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow ) |
| { |
| // #i117952# page break calculation uses these values (set from ScPrintFunc), not pRepeatColRange/pRepeatRowRange |
| if ( nStartCol != nRepeatStartX || nEndCol != nRepeatEndX || nStartRow != nRepeatStartY || nEndRow != nRepeatEndY ) |
| InvalidatePageBreaks(); |
| |
| nRepeatStartX = nStartCol; |
| nRepeatEndX = nEndCol; |
| nRepeatStartY = nStartRow; |
| nRepeatEndY = nEndRow; |
| } |
| |
| void ScTable::StartListening( const ScAddress& rAddress, SvtListener* pListener ) |
| { |
| aCol[rAddress.Col()].StartListening( *pListener, rAddress.Row() ); |
| } |
| |
| void ScTable::EndListening( const ScAddress& rAddress, SvtListener* pListener ) |
| { |
| aCol[rAddress.Col()].EndListening( *pListener, rAddress.Row() ); |
| } |
| |
| void ScTable::SetPageStyle( const String& rName ) |
| { |
| if ( aPageStyle != rName ) |
| { |
| String aStrNew = rName; |
| SfxStyleSheetBasePool* pStylePool = pDocument->GetStyleSheetPool(); |
| SfxStyleSheetBase* pNewStyle = pStylePool->Find( aStrNew, SFX_STYLE_FAMILY_PAGE ); |
| |
| if ( !pNewStyle ) |
| { |
| aStrNew = ScGlobal::GetRscString(STR_STYLENAME_STANDARD); |
| pNewStyle = pStylePool->Find( aStrNew, SFX_STYLE_FAMILY_PAGE ); |
| } |
| |
| if ( aPageStyle != aStrNew ) |
| { |
| SfxStyleSheetBase* pOldStyle = pStylePool->Find( aPageStyle, SFX_STYLE_FAMILY_PAGE ); |
| |
| if ( pOldStyle && pNewStyle ) |
| { |
| SfxItemSet& rOldSet = pOldStyle->GetItemSet(); |
| SfxItemSet& rNewSet = pNewStyle->GetItemSet(); |
| const sal_uInt16 nOldScale = GET_SCALEVALUE(rOldSet,ATTR_PAGE_SCALE); |
| const sal_uInt16 nOldScaleToPages = GET_SCALEVALUE(rOldSet,ATTR_PAGE_SCALETOPAGES); |
| const sal_uInt16 nNewScale = GET_SCALEVALUE(rNewSet,ATTR_PAGE_SCALE); |
| const sal_uInt16 nNewScaleToPages = GET_SCALEVALUE(rNewSet,ATTR_PAGE_SCALETOPAGES); |
| |
| if ( (nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages) ) |
| InvalidateTextWidth(NULL, NULL, sal_False, sal_False); |
| } |
| |
| if ( pNewStyle ) // auch ohne den alten (fuer UpdateStdNames) |
| aPageStyle = aStrNew; |
| |
| if (IsStreamValid()) |
| SetStreamValid(sal_False); |
| } |
| } |
| } |
| |
| void ScTable::PageStyleModified( const String& rNewName ) |
| { |
| aPageStyle = rNewName; |
| InvalidateTextWidth(NULL, NULL, sal_False, sal_False); // don't know what was in the style before |
| } |
| |
| void ScTable::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo, |
| sal_Bool bNumFormatChanged, sal_Bool bBroadcast ) |
| { |
| if ( pAdrFrom && !pAdrTo ) |
| { |
| ScBaseCell* pCell = aCol[pAdrFrom->Col()].GetCell( pAdrFrom->Row() ); |
| if ( pCell ) |
| { |
| pCell->SetTextWidth( TEXTWIDTH_DIRTY ); |
| if ( bNumFormatChanged ) |
| pCell->SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); |
| if ( bBroadcast ) |
| { // nur bei CalcAsShown |
| switch ( pCell->GetCellType() ) |
| { |
| case CELLTYPE_VALUE : |
| pDocument->Broadcast( SC_HINT_DATACHANGED, |
| ScAddress( pAdrFrom->Col(), pAdrFrom->Row(), nTab ), |
| pCell ); |
| break; |
| case CELLTYPE_FORMULA : |
| ((ScFormulaCell*)pCell)->SetDirty(); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| } |
| } |
| else |
| { |
| const SCCOL nColStart = pAdrFrom ? pAdrFrom->Col() : 0; |
| const SCROW nRowStart = pAdrFrom ? pAdrFrom->Row() : 0; |
| const SCCOL nColEnd = pAdrTo ? pAdrTo->Col() : MAXCOL; |
| const SCROW nRowEnd = pAdrTo ? pAdrTo->Row() : MAXROW; |
| |
| for ( SCCOL nCol=nColStart; nCol<=nColEnd; nCol++ ) |
| { |
| ScColumnIterator aIter( &aCol[nCol], nRowStart, nRowEnd ); |
| ScBaseCell* pCell = NULL; |
| SCROW nRow = nRowStart; |
| |
| while ( aIter.Next( nRow, pCell ) ) |
| { |
| pCell->SetTextWidth( TEXTWIDTH_DIRTY ); |
| if ( bNumFormatChanged ) |
| pCell->SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); |
| if ( bBroadcast ) |
| { // nur bei CalcAsShown |
| switch ( pCell->GetCellType() ) |
| { |
| case CELLTYPE_VALUE : |
| pDocument->Broadcast( SC_HINT_DATACHANGED, |
| ScAddress( nCol, nRow, nTab ), pCell ); |
| break; |
| case CELLTYPE_FORMULA : |
| ((ScFormulaCell*)pCell)->SetDirty(); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| |
| |
| |
| |