| /************************************************************** |
| * |
| * 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 "scitems.hxx" |
| #include <svx/algitem.hxx> |
| #include <editeng/boxitem.hxx> |
| #include <editeng/bolnitem.hxx> |
| #include <editeng/frmdiritem.hxx> |
| #include <editeng/shaditem.hxx> |
| #include <svl/poolcach.hxx> |
| #include <editeng/fontitem.hxx> |
| #include <unotools/fontcvt.hxx> |
| |
| #include "attarray.hxx" |
| #include "global.hxx" |
| #include "document.hxx" |
| #include "docpool.hxx" |
| #include "patattr.hxx" |
| #include "stlsheet.hxx" |
| #include "stlpool.hxx" |
| #include "markarr.hxx" |
| #include "rechead.hxx" |
| #include "globstr.hrc" |
| #include "segmenttree.hxx" |
| |
| #undef DBG_INVALIDATE |
| #define DBGOUTPUT(s) \ |
| DBG_ERROR( String("Invalidate ") + String(s) + String(": ") \ |
| + String(nCol) + String('/') + String(aAdrStart.Row()) + String('/') + String(nTab) \ |
| + String(" bis ") \ |
| + String(nCol) + String('/') + String(aAdrEnd.Row()) + String('/') + String(nTab) \ |
| ); |
| |
| // STATIC DATA ----------------------------------------------------------- |
| |
| |
| //------------------------------------------------------------------------ |
| |
| ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc ) : |
| nCol( nNewCol ), |
| nTab( nNewTab ), |
| pDocument( pDoc ) |
| { |
| nCount = nLimit = 1; |
| pData = new ScAttrEntry[1]; |
| if (pData) |
| { |
| pData[0].nRow = MAXROW; |
| pData[0].pPattern = pDocument->GetDefPattern(); // ohne Put !!! |
| } |
| } |
| |
| //------------------------------------------------------------------------ |
| |
| ScAttrArray::~ScAttrArray() |
| { |
| #ifdef DBG_UTIL |
| TestData(); |
| #endif |
| |
| if (pData) |
| { |
| ScDocumentPool* pDocPool = pDocument->GetPool(); |
| for (SCSIZE i=0; i<nCount; i++) |
| pDocPool->Remove(*pData[i].pPattern); |
| |
| delete[] pData; |
| } |
| } |
| |
| //------------------------------------------------------------------------ |
| #ifdef DBG_UTIL |
| void ScAttrArray::TestData() const |
| { |
| |
| sal_uInt16 nErr = 0; |
| if (pData) |
| { |
| SCSIZE nPos; |
| for (nPos=0; nPos<nCount; nPos++) |
| { |
| if (nPos > 0) |
| if (pData[nPos].pPattern == pData[nPos-1].pPattern || pData[nPos].nRow <= pData[nPos-1].nRow) |
| ++nErr; |
| if (pData[nPos].pPattern->Which() != ATTR_PATTERN) |
| ++nErr; |
| } |
| if ( nPos && pData[nPos-1].nRow != MAXROW ) |
| ++nErr; |
| } |
| if (nErr) |
| { |
| ByteString aMsg = ByteString::CreateFromInt32(nErr); |
| aMsg += " errors in attribute array, column "; |
| aMsg += ByteString::CreateFromInt32(nCol); |
| DBG_ERROR( aMsg.GetBuffer() ); |
| } |
| } |
| #endif |
| |
| //------------------------------------------------------------------------ |
| |
| void ScAttrArray::Reset( const ScPatternAttr* pPattern, sal_Bool bAlloc ) |
| { |
| if (pData) |
| { |
| ScDocumentPool* pDocPool = pDocument->GetPool(); |
| const ScPatternAttr* pOldPattern; |
| ScAddress aAdrStart( nCol, 0, nTab ); |
| ScAddress aAdrEnd ( nCol, 0, nTab ); |
| |
| for (SCSIZE i=0; i<nCount; i++) |
| { |
| // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert |
| pOldPattern = pData[i].pPattern; |
| sal_Bool bNumFormatChanged; |
| if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, |
| pPattern->GetItemSet(), pOldPattern->GetItemSet() ) ) |
| { |
| aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 ); |
| aAdrEnd .SetRow( pData[i].nRow ); |
| pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); |
| #ifdef DBG_INVALIDATE |
| DBGOUTPUT("Reset"); |
| #endif |
| } |
| // bedingtes Format gesetzt oder geloescht? |
| if ( &pPattern->GetItem(ATTR_CONDITIONAL) != &pOldPattern->GetItem(ATTR_CONDITIONAL) ) |
| { |
| pDocument->ConditionalChanged( ((const SfxUInt32Item&) |
| pOldPattern->GetItem(ATTR_CONDITIONAL)).GetValue() ); |
| pDocument->ConditionalChanged( ((const SfxUInt32Item&) |
| pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() ); |
| } |
| pDocPool->Remove(*pOldPattern); |
| } |
| delete[] pData; |
| |
| if (pDocument->IsStreamValid(nTab)) |
| pDocument->SetStreamValid(nTab, sal_False); |
| |
| if (bAlloc) |
| { |
| nCount = nLimit = 1; |
| pData = new ScAttrEntry[1]; |
| if (pData) |
| { |
| ScPatternAttr* pNewPattern = (ScPatternAttr*) &pDocPool->Put(*pPattern); |
| pData[0].nRow = MAXROW; |
| pData[0].pPattern = pNewPattern; |
| } |
| } |
| else |
| { |
| nCount = nLimit = 0; |
| pData = NULL; // muss sofort wieder belegt werden ! |
| } |
| } |
| } |
| |
| |
| sal_Bool ScAttrArray::Concat(SCSIZE nPos) |
| { |
| sal_Bool bRet = sal_False; |
| if (pData && (nPos < nCount)) |
| { |
| if (nPos > 0) |
| { |
| if (pData[nPos - 1].pPattern == pData[nPos].pPattern) |
| { |
| pData[nPos - 1].nRow = pData[nPos].nRow; |
| pDocument->GetPool()->Remove(*pData[nPos].pPattern); |
| memmove(&pData[nPos], &pData[nPos + 1], (nCount - nPos - 1) * sizeof(ScAttrEntry)); |
| pData[nCount - 1].pPattern = NULL; |
| pData[nCount - 1].nRow = 0; |
| nCount--; |
| nPos--; |
| bRet = sal_True; |
| } |
| } |
| if (nPos + 1 < nCount) |
| { |
| if (pData[nPos + 1].pPattern == pData[nPos].pPattern) |
| { |
| pData[nPos].nRow = pData[nPos + 1].nRow; |
| pDocument->GetPool()->Remove(*pData[nPos].pPattern); |
| memmove(&pData[nPos + 1], &pData[nPos + 2], (nCount - nPos - 2) * sizeof(ScAttrEntry)); |
| pData[nCount - 1].pPattern = NULL; |
| pData[nCount - 1].nRow = 0; |
| nCount--; |
| bRet = sal_True; |
| } |
| } |
| } |
| return bRet; |
| } |
| |
| //------------------------------------------------------------------------ |
| |
| sal_Bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const |
| { |
| long nLo = 0; |
| long nHi = static_cast<long>(nCount) - 1; |
| long nStartRow = 0; |
| long nEndRow = 0; |
| long i = 0; |
| sal_Bool bFound = (nCount == 1); |
| if (pData) |
| { |
| while ( !bFound && nLo <= nHi ) |
| { |
| i = (nLo + nHi) / 2; |
| if (i > 0) |
| nStartRow = (long) pData[i - 1].nRow; |
| else |
| nStartRow = -1; |
| nEndRow = (long) pData[i].nRow; |
| if (nEndRow < (long) nRow) |
| nLo = ++i; |
| else |
| if (nStartRow >= (long) nRow) |
| nHi = --i; |
| else |
| bFound = sal_True; |
| } |
| } |
| else |
| bFound = sal_False; |
| |
| if (bFound) |
| nIndex=(SCSIZE)i; |
| else |
| nIndex=0; |
| return bFound; |
| } |
| |
| |
| const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const |
| { |
| SCSIZE i; |
| if (Search( nRow, i )) |
| return pData[i].pPattern; |
| else |
| return NULL; |
| } |
| |
| |
| const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow, |
| SCROW& rEndRow, SCROW nRow ) const |
| { |
| SCSIZE nIndex; |
| if ( Search( nRow, nIndex ) ) |
| { |
| if ( nIndex > 0 ) |
| rStartRow = pData[nIndex-1].nRow + 1; |
| else |
| rStartRow = 0; |
| rEndRow = pData[nIndex].nRow; |
| return pData[nIndex].pPattern; |
| } |
| return NULL; |
| } |
| |
| //------------------------------------------------------------------------ |
| |
| void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, sal_Bool bPutToPool ) |
| { |
| SetPatternArea( nRow, nRow, pPattern, bPutToPool ); |
| } |
| |
| bool ScAttrArray::Reserve( SCSIZE nReserve ) |
| { |
| if ( nCount <= nReserve ) |
| { |
| if( ScAttrEntry* pNewData = new (std::nothrow) ScAttrEntry[nReserve] ) |
| { |
| nLimit = nReserve; |
| memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) ); |
| delete[] pData; |
| pData = pNewData; |
| return true; |
| } |
| else |
| return false; |
| } |
| else |
| return false; |
| } |
| |
| void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern, sal_Bool bPutToPool ) |
| { |
| if (ValidRow(nStartRow) && ValidRow(nEndRow)) |
| { |
| if (bPutToPool) |
| pPattern = (const ScPatternAttr*) &pDocument->GetPool()->Put(*pPattern); |
| |
| if ((nStartRow == 0) && (nEndRow == MAXROW)) |
| Reset(pPattern); |
| else |
| { |
| SCSIZE nNeeded = nCount + 2; |
| if ( nLimit < nNeeded ) |
| { |
| nLimit += SC_ATTRARRAY_DELTA; |
| if ( nLimit < nNeeded ) |
| nLimit = nNeeded; |
| ScAttrEntry* pNewData = new ScAttrEntry[nLimit]; |
| memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) ); |
| delete[] pData; |
| pData = pNewData; |
| } |
| |
| ScAddress aAdrStart( nCol, 0, nTab ); |
| ScAddress aAdrEnd ( nCol, 0, nTab ); |
| |
| SCSIZE ni = 0; // number of entries in beginning |
| SCSIZE nx = 0; // track position |
| SCROW ns = 0; // start row of track position |
| if ( nStartRow > 0 ) |
| { |
| // skip beginning |
| SCSIZE nIndex; |
| Search( nStartRow, nIndex ); |
| ni = nIndex; |
| |
| if ( ni > 0 ) |
| { |
| nx = ni; |
| ns = pData[ni-1].nRow+1; |
| } |
| } |
| |
| // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert |
| // oder bedingte Formate neu gesetzt oder geloescht werden |
| while ( ns <= nEndRow ) |
| { |
| const SfxItemSet& rNewSet = pPattern->GetItemSet(); |
| const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet(); |
| |
| sal_Bool bNumFormatChanged; |
| if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, |
| rNewSet, rOldSet ) ) |
| { |
| aAdrStart.SetRow( Max(nStartRow,ns) ); |
| aAdrEnd .SetRow( Min(nEndRow,pData[nx].nRow) ); |
| pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); |
| #ifdef DBG_INVALIDATE |
| DBGOUTPUT("SetPatternArea"); |
| #endif |
| } |
| if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) ) |
| { |
| pDocument->ConditionalChanged( ((const SfxUInt32Item&) |
| rOldSet.Get(ATTR_CONDITIONAL)).GetValue() ); |
| pDocument->ConditionalChanged( ((const SfxUInt32Item&) |
| rNewSet.Get(ATTR_CONDITIONAL)).GetValue() ); |
| } |
| ns = pData[nx].nRow + 1; |
| nx++; |
| } |
| |
| // continue modifying data array |
| |
| SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert) |
| sal_Bool bCombined = sal_False; |
| sal_Bool bSplit = sal_False; |
| if ( nStartRow > 0 ) |
| { |
| nInsert = MAXROWCOUNT; |
| if ( pData[ni].pPattern != pPattern ) |
| { |
| if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) ) |
| { // may be a split or a simple insert or just a shrink, |
| // row adjustment is done further down |
| if ( pData[ni].nRow > nEndRow ) |
| bSplit = sal_True; |
| ni++; |
| nInsert = ni; |
| } |
| else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 ) |
| nInsert = ni; |
| } |
| if ( ni > 0 && pData[ni-1].pPattern == pPattern ) |
| { // combine |
| pData[ni-1].nRow = nEndRow; |
| nInsert = MAXROWCOUNT; |
| bCombined = sal_True; |
| } |
| } |
| else |
| nInsert = 0; |
| |
| SCSIZE nj = ni; // stop position of range to replace |
| while ( nj < nCount && pData[nj].nRow <= nEndRow ) |
| nj++; |
| if ( !bSplit ) |
| { |
| if ( nj < nCount && pData[nj].pPattern == pPattern ) |
| { // combine |
| if ( ni > 0 ) |
| { |
| if ( pData[ni-1].pPattern == pPattern ) |
| { // adjacent entries |
| pData[ni-1].nRow = pData[nj].nRow; |
| nj++; |
| } |
| else if ( ni == nInsert ) |
| pData[ni-1].nRow = nStartRow - 1; // shrink |
| } |
| nInsert = MAXROWCOUNT; |
| bCombined = sal_True; |
| } |
| else if ( ni > 0 && ni == nInsert ) |
| pData[ni-1].nRow = nStartRow - 1; // shrink |
| } |
| ScDocumentPool* pDocPool = pDocument->GetPool(); |
| if ( bSplit ) |
| { // duplicate splitted entry in pool |
| pDocPool->Put( *pData[ni-1].pPattern ); |
| } |
| if ( ni < nj ) |
| { // remove middle entries |
| for ( SCSIZE nk=ni; nk<nj; nk++) |
| { // remove entries from pool |
| pDocPool->Remove( *pData[nk].pPattern ); |
| } |
| if ( !bCombined ) |
| { // replace one entry |
| pData[ni].nRow = nEndRow; |
| pData[ni].pPattern = pPattern; |
| ni++; |
| nInsert = MAXROWCOUNT; |
| } |
| if ( ni < nj ) |
| { // remove entries |
| memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) ); |
| nCount -= nj - ni; |
| } |
| } |
| |
| if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) ) |
| { // insert or append new entry |
| if ( nInsert <= nCount ) |
| { |
| if ( !bSplit ) |
| memmove( pData + nInsert + 1, pData + nInsert, |
| (nCount - nInsert) * sizeof(ScAttrEntry) ); |
| else |
| { |
| memmove( pData + nInsert + 2, pData + nInsert, |
| (nCount - nInsert) * sizeof(ScAttrEntry) ); |
| pData[nInsert+1] = pData[nInsert-1]; |
| nCount++; |
| } |
| } |
| if ( nInsert ) |
| pData[nInsert-1].nRow = nStartRow - 1; |
| pData[nInsert].nRow = nEndRow; |
| pData[nInsert].pPattern = pPattern; |
| nCount++; |
| } |
| |
| if (pDocument->IsStreamValid(nTab)) |
| pDocument->SetStreamValid(nTab, sal_False); |
| } |
| } |
| // InfoBox(0, String(nCount) + String(" Eintraege") ).Execute(); |
| |
| #ifdef DBG_UTIL |
| TestData(); |
| #endif |
| } |
| |
| |
| void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle ) |
| { |
| if (ValidRow(nStartRow) && ValidRow(nEndRow)) |
| { |
| SCSIZE nPos; |
| SCROW nStart=0; |
| if (!Search( nStartRow, nPos )) |
| { |
| DBG_ERROR("Search-Fehler"); |
| return; |
| } |
| |
| ScAddress aAdrStart( nCol, 0, nTab ); |
| ScAddress aAdrEnd ( nCol, 0, nTab ); |
| |
| do |
| { |
| const ScPatternAttr* pOldPattern = pData[nPos].pPattern; |
| ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern); |
| pNewPattern->SetStyleSheet(pStyle); |
| SCROW nY1 = nStart; |
| SCROW nY2 = pData[nPos].nRow; |
| nStart = pData[nPos].nRow + 1; |
| |
| if ( *pNewPattern == *pOldPattern ) |
| { |
| // keep the original pattern (might be default) |
| // pNewPattern is deleted below |
| nPos++; |
| } |
| else if ( nY1 < nStartRow || nY2 > nEndRow ) |
| { |
| if (nY1 < nStartRow) nY1=nStartRow; |
| if (nY2 > nEndRow) nY2=nEndRow; |
| SetPatternArea( nY1, nY2, pNewPattern, sal_True ); |
| Search( nStart, nPos ); |
| } |
| else |
| { |
| // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert |
| // bedingte Formate in Vorlagen gibt es (noch) nicht |
| |
| const SfxItemSet& rNewSet = pNewPattern->GetItemSet(); |
| const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); |
| |
| sal_Bool bNumFormatChanged; |
| if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, |
| rNewSet, rOldSet ) ) |
| { |
| aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 ); |
| aAdrEnd .SetRow( pData[nPos].nRow ); |
| pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); |
| #ifdef DBG_INVALIDATE |
| DBGOUTPUT("ApplyStyleArea"); |
| #endif |
| } |
| |
| pDocument->GetPool()->Remove(*pData[nPos].pPattern); |
| pData[nPos].pPattern = (const ScPatternAttr*) |
| &pDocument->GetPool()->Put(*pNewPattern); |
| if (Concat(nPos)) |
| Search(nStart, nPos); |
| else |
| nPos++; |
| } |
| delete pNewPattern; |
| } |
| while ((nStart <= nEndRow) && (nPos < nCount)); |
| |
| if (pDocument->IsStreamValid(nTab)) |
| pDocument->SetStreamValid(nTab, sal_False); |
| } |
| |
| #ifdef DBG_UTIL |
| TestData(); |
| #endif |
| } |
| |
| |
| // const wird weggecastet, weil es sonst |
| // zu ineffizient/kompliziert wird! |
| #define SET_LINECOLOR(dest,c) \ |
| if ((dest)) \ |
| { \ |
| ((SvxBorderLine*)(dest))->SetColor((c)); \ |
| } |
| |
| #define SET_LINE(dest,src) \ |
| if ((dest)) \ |
| { \ |
| SvxBorderLine* pCast = (SvxBorderLine*)(dest); \ |
| pCast->SetOutWidth((src)->GetOutWidth()); \ |
| pCast->SetInWidth ((src)->GetInWidth()); \ |
| pCast->SetDistance((src)->GetDistance()); \ |
| } |
| |
| void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow, |
| const SvxBorderLine* pLine, sal_Bool bColorOnly ) |
| { |
| if ( bColorOnly && !pLine ) |
| return; |
| |
| if (ValidRow(nStartRow) && ValidRow(nEndRow)) |
| { |
| SCSIZE nPos; |
| SCROW nStart=0; |
| if (!Search( nStartRow, nPos )) |
| { |
| DBG_ERROR("Search-Fehler"); |
| return; |
| } |
| |
| do |
| { |
| const ScPatternAttr* pOldPattern = pData[nPos].pPattern; |
| const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); |
| const SfxPoolItem* pBoxItem = 0; |
| SfxItemState eState = rOldSet.GetItemState( ATTR_BORDER, sal_True, &pBoxItem ); |
| const SfxPoolItem* pTLBRItem = 0; |
| SfxItemState eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, sal_True, &pTLBRItem ); |
| const SfxPoolItem* pBLTRItem = 0; |
| SfxItemState eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, sal_True, &pBLTRItem ); |
| |
| if ( (SFX_ITEM_SET == eState) || (SFX_ITEM_SET == eTLBRState) || (SFX_ITEM_SET == eBLTRState) ) |
| { |
| ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern); |
| SfxItemSet& rNewSet = pNewPattern->GetItemSet(); |
| SCROW nY1 = nStart; |
| SCROW nY2 = pData[nPos].nRow; |
| |
| SvxBoxItem* pNewBoxItem = pBoxItem ? (SvxBoxItem*)pBoxItem->Clone() : 0; |
| SvxLineItem* pNewTLBRItem = pTLBRItem ? (SvxLineItem*)pTLBRItem->Clone() : 0; |
| SvxLineItem* pNewBLTRItem = pBLTRItem ? (SvxLineItem*)pBLTRItem->Clone() : 0; |
| |
| // Linienattribute holen und mit Parametern aktualisieren |
| |
| if ( !pLine ) |
| { |
| if( pNewBoxItem ) |
| { |
| if ( pNewBoxItem->GetTop() ) pNewBoxItem->SetLine( NULL, BOX_LINE_TOP ); |
| if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( NULL, BOX_LINE_BOTTOM ); |
| if ( pNewBoxItem->GetLeft() ) pNewBoxItem->SetLine( NULL, BOX_LINE_LEFT ); |
| if ( pNewBoxItem->GetRight() ) pNewBoxItem->SetLine( NULL, BOX_LINE_RIGHT ); |
| } |
| if( pNewTLBRItem && pNewTLBRItem->GetLine() ) |
| pNewTLBRItem->SetLine( 0 ); |
| if( pNewBLTRItem && pNewBLTRItem->GetLine() ) |
| pNewBLTRItem->SetLine( 0 ); |
| } |
| else |
| { |
| if ( bColorOnly ) |
| { |
| Color aColor( pLine->GetColor() ); |
| if( pNewBoxItem ) |
| { |
| SET_LINECOLOR( pNewBoxItem->GetTop(), aColor ); |
| SET_LINECOLOR( pNewBoxItem->GetBottom(), aColor ); |
| SET_LINECOLOR( pNewBoxItem->GetLeft(), aColor ); |
| SET_LINECOLOR( pNewBoxItem->GetRight(), aColor ); |
| } |
| if( pNewTLBRItem ) |
| SET_LINECOLOR( pNewTLBRItem->GetLine(), aColor ); |
| if( pNewBLTRItem ) |
| SET_LINECOLOR( pNewBLTRItem->GetLine(), aColor ); |
| } |
| else |
| { |
| if( pNewBoxItem ) |
| { |
| SET_LINE( pNewBoxItem->GetTop(), pLine ); |
| SET_LINE( pNewBoxItem->GetBottom(), pLine ); |
| SET_LINE( pNewBoxItem->GetLeft(), pLine ); |
| SET_LINE( pNewBoxItem->GetRight(), pLine ); |
| } |
| if( pNewTLBRItem ) |
| SET_LINE( pNewTLBRItem->GetLine(), pLine ); |
| if( pNewBLTRItem ) |
| SET_LINE( pNewBLTRItem->GetLine(), pLine ); |
| } |
| } |
| if( pNewBoxItem ) rNewSet.Put( *pNewBoxItem ); |
| if( pNewTLBRItem ) rNewSet.Put( *pNewTLBRItem ); |
| if( pNewBLTRItem ) rNewSet.Put( *pNewBLTRItem ); |
| |
| nStart = pData[nPos].nRow + 1; |
| |
| if ( nY1 < nStartRow || nY2 > nEndRow ) |
| { |
| if (nY1 < nStartRow) nY1=nStartRow; |
| if (nY2 > nEndRow) nY2=nEndRow; |
| SetPatternArea( nY1, nY2, pNewPattern, sal_True ); |
| Search( nStart, nPos ); |
| } |
| else |
| { |
| //! aus Pool loeschen? |
| pDocument->GetPool()->Remove(*pData[nPos].pPattern); |
| pData[nPos].pPattern = (const ScPatternAttr*) |
| &pDocument->GetPool()->Put(*pNewPattern); |
| |
| if (Concat(nPos)) |
| Search(nStart, nPos); |
| else |
| nPos++; |
| } |
| delete pNewBoxItem; |
| delete pNewTLBRItem; |
| delete pNewBLTRItem; |
| delete pNewPattern; |
| } |
| else |
| { |
| nStart = pData[nPos].nRow + 1; |
| nPos++; |
| } |
| } |
| while ((nStart <= nEndRow) && (nPos < nCount)); |
| } |
| } |
| |
| #undef SET_LINECOLOR |
| #undef SET_LINE |
| |
| |
| void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache ) |
| { |
| #ifdef DBG_UTIL |
| TestData(); |
| #endif |
| |
| if (ValidRow(nStartRow) && ValidRow(nEndRow)) |
| { |
| SCSIZE nPos; |
| SCROW nStart=0; |
| if (!Search( nStartRow, nPos )) |
| { |
| DBG_ERROR("Search-Fehler"); |
| return; |
| } |
| |
| ScAddress aAdrStart( nCol, 0, nTab ); |
| ScAddress aAdrEnd ( nCol, 0, nTab ); |
| |
| do |
| { |
| const ScPatternAttr* pOldPattern = pData[nPos].pPattern; |
| const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pCache->ApplyTo( *pOldPattern, sal_True ); |
| ScDocumentPool::CheckRef( *pOldPattern ); |
| ScDocumentPool::CheckRef( *pNewPattern ); |
| if (pNewPattern != pOldPattern) |
| { |
| SCROW nY1 = nStart; |
| SCROW nY2 = pData[nPos].nRow; |
| nStart = pData[nPos].nRow + 1; |
| |
| if ( nY1 < nStartRow || nY2 > nEndRow ) |
| { |
| if (nY1 < nStartRow) nY1=nStartRow; |
| if (nY2 > nEndRow) nY2=nEndRow; |
| SetPatternArea( nY1, nY2, pNewPattern ); |
| Search( nStart, nPos ); |
| } |
| else |
| { |
| // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert |
| |
| const SfxItemSet& rNewSet = pNewPattern->GetItemSet(); |
| const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); |
| |
| sal_Bool bNumFormatChanged; |
| if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, |
| rNewSet, rOldSet ) ) |
| { |
| aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 ); |
| aAdrEnd .SetRow( pData[nPos].nRow ); |
| pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); |
| #ifdef DBG_INVALIDATE |
| DBGOUTPUT("ApplyCacheArea"); |
| #endif |
| } |
| |
| // bedingte Formate neu gesetzt oder geloescht ? |
| |
| if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) ) |
| { |
| pDocument->ConditionalChanged( ((const SfxUInt32Item&) |
| rOldSet.Get(ATTR_CONDITIONAL)).GetValue() ); |
| pDocument->ConditionalChanged( ((const SfxUInt32Item&) |
| rNewSet.Get(ATTR_CONDITIONAL)).GetValue() ); |
| } |
| |
| pDocument->GetPool()->Remove(*pData[nPos].pPattern); |
| pData[nPos].pPattern = pNewPattern; |
| if (Concat(nPos)) |
| Search(nStart, nPos); |
| else |
| ++nPos; |
| } |
| } |
| else |
| { |
| //!!!!!!!!!!!!!!!!!! mit diesem Remove gibt es Abstuerze (Calc1 Import) |
| //! pDocument->GetPool()->Remove(*pNewPattern); |
| nStart = pData[nPos].nRow + 1; |
| ++nPos; |
| } |
| } |
| while (nStart <= nEndRow); |
| |
| if (pDocument->IsStreamValid(nTab)) |
| pDocument->SetStreamValid(nTab, sal_False); |
| } |
| |
| #ifdef DBG_UTIL |
| TestData(); |
| #endif |
| } |
| |
| |
| void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource ) |
| { |
| const SfxPoolItem* pNewItem; |
| const SfxPoolItem* pOldItem; |
| for (sal_uInt16 nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++) |
| { |
| // pMergeSet hat keinen Parent |
| SfxItemState eOldState = rMergeSet.GetItemState( nId, sal_False, &pOldItem ); |
| |
| if ( eOldState == SFX_ITEM_DEFAULT ) // Default |
| { |
| SfxItemState eNewState = rSource.GetItemState( nId, sal_True, &pNewItem ); |
| if ( eNewState == SFX_ITEM_SET ) |
| { |
| if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) ) |
| rMergeSet.InvalidateItem( nId ); |
| } |
| } |
| else if ( eOldState == SFX_ITEM_SET ) // Item gesetzt |
| { |
| SfxItemState eNewState = rSource.GetItemState( nId, sal_True, &pNewItem ); |
| if ( eNewState == SFX_ITEM_SET ) |
| { |
| if ( pNewItem != pOldItem ) // beide gepuhlt |
| rMergeSet.InvalidateItem( nId ); |
| } |
| else // Default |
| { |
| if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) ) |
| rMergeSet.InvalidateItem( nId ); |
| } |
| } |
| // Dontcare bleibt Dontcare |
| } |
| } |
| |
| |
| void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow, |
| ScMergePatternState& rState, sal_Bool bDeep ) const |
| { |
| if (ValidRow(nStartRow) && ValidRow(nEndRow)) |
| { |
| SCSIZE nPos; |
| SCROW nStart=0; |
| if (!Search( nStartRow, nPos )) |
| { |
| DBG_ERROR("Search-Fehler"); |
| return; |
| } |
| |
| do |
| { |
| // gleiche Patterns muessen nicht mehrfach angesehen werden |
| |
| const ScPatternAttr* pPattern = pData[nPos].pPattern; |
| if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 ) |
| { |
| const SfxItemSet& rThisSet = pPattern->GetItemSet(); |
| if (rState.pItemSet) |
| { |
| // (*ppSet)->MergeValues( rThisSet, sal_False ); |
| // geht nicht, weil die Vorlagen nicht beruecksichtigt werden |
| |
| if (bDeep) |
| lcl_MergeDeep( *rState.pItemSet, rThisSet ); |
| else |
| rState.pItemSet->MergeValues( rThisSet, sal_False ); |
| } |
| else |
| { |
| // erstes Pattern - in Set ohne Parent kopieren |
| rState.pItemSet = new SfxItemSet( *rThisSet.GetPool(), rThisSet.GetRanges() ); |
| rState.pItemSet->Set( rThisSet, bDeep ); |
| } |
| |
| rState.pOld2 = rState.pOld1; |
| rState.pOld1 = pPattern; |
| } |
| |
| nStart = pData[nPos].nRow + 1; |
| ++nPos; |
| } |
| while (nStart <= nEndRow); |
| } |
| } |
| |
| |
| |
| // Umrandung zusammenbauen |
| |
| sal_Bool lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine, |
| sal_uInt8& rModified, const SvxBorderLine*& rpNew ) |
| { |
| if (rModified == SC_LINE_DONTCARE) |
| return sal_False; // weiter geht's nicht |
| |
| if (rModified == SC_LINE_EMPTY) |
| { |
| rModified = SC_LINE_SET; |
| rpNew = pNewLine; |
| return sal_True; // zum ersten mal gesetzt |
| } |
| |
| if (pOldLine == pNewLine) |
| { |
| rpNew = pOldLine; |
| return sal_False; |
| } |
| |
| if (pOldLine && pNewLine) |
| if (*pOldLine == *pNewLine) |
| { |
| rpNew = pOldLine; |
| return sal_False; |
| } |
| |
| rModified = SC_LINE_DONTCARE; |
| rpNew = NULL; |
| return sal_True; // andere Linie -> dontcare |
| } |
| |
| |
| void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, |
| ScLineFlags& rFlags, const ScPatternAttr* pPattern, |
| sal_Bool bLeft, SCCOL nDistRight, sal_Bool bTop, SCROW nDistBottom ) |
| { |
| // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst: |
| const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE); |
| if ( rMerge.GetColMerge() == nDistRight + 1 ) |
| nDistRight = 0; |
| if ( rMerge.GetRowMerge() == nDistBottom + 1 ) |
| nDistBottom = 0; |
| |
| const SvxBoxItem* pCellFrame = (SvxBoxItem*) &pPattern->GetItemSet().Get( ATTR_BORDER ); |
| const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft(); |
| const SvxBorderLine* pRightAttr = pCellFrame->GetRight(); |
| const SvxBorderLine* pTopAttr = pCellFrame->GetTop(); |
| const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom(); |
| const SvxBorderLine* pNew; |
| |
| if (bTop) |
| { |
| if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew )) |
| pLineOuter->SetLine( pNew, BOX_LINE_TOP ); |
| } |
| else |
| { |
| if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew )) |
| pLineInner->SetLine( pNew, BOXINFO_LINE_HORI ); |
| } |
| |
| if (nDistBottom == 0) |
| { |
| if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew )) |
| pLineOuter->SetLine( pNew, BOX_LINE_BOTTOM ); |
| } |
| else |
| { |
| if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew )) |
| pLineInner->SetLine( pNew, BOXINFO_LINE_HORI ); |
| } |
| |
| if (bLeft) |
| { |
| if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew )) |
| pLineOuter->SetLine( pNew, BOX_LINE_LEFT ); |
| } |
| else |
| { |
| if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew )) |
| pLineInner->SetLine( pNew, BOXINFO_LINE_VERT ); |
| } |
| |
| if (nDistRight == 0) |
| { |
| if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew )) |
| pLineOuter->SetLine( pNew, BOX_LINE_RIGHT ); |
| } |
| else |
| { |
| if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew )) |
| pLineInner->SetLine( pNew, BOXINFO_LINE_VERT ); |
| } |
| } |
| |
| |
| void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, |
| ScLineFlags& rFlags, |
| SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight ) const |
| { |
| const ScPatternAttr* pPattern; |
| |
| if (nStartRow == nEndRow) |
| { |
| pPattern = GetPattern( nStartRow ); |
| lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_True, 0 ); |
| } |
| else |
| { |
| pPattern = GetPattern( nStartRow ); |
| lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_True, |
| nEndRow-nStartRow ); |
| |
| SCSIZE nStartIndex; |
| SCSIZE nEndIndex; |
| Search( nStartRow+1, nStartIndex ); |
| Search( nEndRow-1, nEndIndex ); |
| for (SCSIZE i=nStartIndex; i<=nEndIndex; i++) |
| { |
| pPattern = (ScPatternAttr*) pData[i].pPattern; |
| lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_False, |
| nEndRow - Min( pData[i].nRow, (SCROW)(nEndRow-1) ) ); |
| // nDistBottom hier immer > 0 |
| } |
| |
| pPattern = GetPattern( nEndRow ); |
| lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_False, 0 ); |
| } |
| } |
| |
| // |
| // Rahmen anwenden |
| // |
| |
| // ApplyFrame - auf einen Eintrag im Array |
| |
| |
| sal_Bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem, |
| const SvxBoxInfoItem* pBoxInfoItem, |
| SCROW nStartRow, SCROW nEndRow, |
| sal_Bool bLeft, SCCOL nDistRight, sal_Bool bTop, SCROW nDistBottom ) |
| { |
| DBG_ASSERT( pBoxItem && pBoxInfoItem, "Linienattribute fehlen!" ); |
| |
| const ScPatternAttr* pPattern = GetPattern( nStartRow ); |
| const SvxBoxItem* pOldFrame = (const SvxBoxItem*) |
| &pPattern->GetItemSet().Get( ATTR_BORDER ); |
| |
| // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst: |
| const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE); |
| if ( rMerge.GetColMerge() == nDistRight + 1 ) |
| nDistRight = 0; |
| if ( rMerge.GetRowMerge() == nDistBottom + 1 ) |
| nDistBottom = 0; |
| |
| SvxBoxItem aNewFrame( *pOldFrame ); |
| |
| if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) ) |
| aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(), |
| BOX_LINE_LEFT ); |
| if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) ) |
| aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(), |
| BOX_LINE_RIGHT ); |
| if ( bTop ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) ) |
| aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(), |
| BOX_LINE_TOP ); |
| if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) ) |
| aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(), |
| BOX_LINE_BOTTOM ); |
| |
| if (aNewFrame == *pOldFrame) |
| { |
| // nothing to do |
| return sal_False; |
| } |
| else |
| { |
| SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame ); |
| ApplyCacheArea( nStartRow, nEndRow, &aCache ); |
| |
| /* ScPatternAttr* pNewPattern = (ScPatternAttr*) pPattern->Clone(); |
| pNewPattern->GetItemSet().Put( aNewFrame ); |
| SetPatternArea( nStartRow, nEndRow, pNewPattern, sal_True ); |
| */ |
| return sal_True; |
| } |
| } |
| |
| |
| void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner, |
| SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight ) |
| { |
| if (nStartRow == nEndRow) |
| ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, sal_True, 0 ); |
| else |
| { |
| ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight, |
| sal_True, nEndRow-nStartRow ); |
| |
| if ( nEndRow > nStartRow+1 ) // innerer Teil vorhanden? |
| { |
| SCSIZE nStartIndex; |
| SCSIZE nEndIndex; |
| Search( nStartRow+1, nStartIndex ); |
| Search( nEndRow-1, nEndIndex ); |
| SCROW nTmpStart = nStartRow+1; |
| SCROW nTmpEnd; |
| for (SCSIZE i=nStartIndex; i<=nEndIndex;) |
| { |
| nTmpEnd = Min( (SCROW)(nEndRow-1), (SCROW)(pData[i].nRow) ); |
| sal_Bool bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd, |
| bLeft, nDistRight, sal_False, nEndRow-nTmpEnd ); |
| nTmpStart = nTmpEnd+1; |
| if (bChanged) |
| { |
| Search(nTmpStart, i); |
| Search(nEndRow-1, nEndIndex); |
| } |
| else |
| i++; |
| } |
| } |
| |
| ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, sal_False, 0 ); |
| } |
| } |
| |
| |
| long lcl_LineSize( const SvxBorderLine& rLine ) |
| { |
| // nur eine Linie -> halbe Breite, min. 20 |
| // doppelte Linie -> halber Abstand + eine Linie (je min. 20) |
| |
| long nTotal = 0; |
| sal_uInt16 nWidth = Max( rLine.GetOutWidth(), rLine.GetInWidth() ); |
| sal_uInt16 nDist = rLine.GetDistance(); |
| if (nDist) |
| { |
| DBG_ASSERT( rLine.GetOutWidth() && rLine.GetInWidth(), |
| "Linie hat Abstand, aber nur eine Breite ???" ); |
| |
| // nTotal += ( nDist > 40 ) ? ( nDist / 2 ) : 20; |
| nTotal += ( nDist > 20 ) ? nDist : 20; |
| nTotal += ( nWidth > 20 ) ? nWidth : 20; |
| } |
| else if (nWidth) |
| // nTotal += ( nWidth > 40 ) ? ( nWidth / 2 ) : 20; |
| nTotal += ( nWidth > 20 ) ? nWidth : 20; |
| |
| //! auch halbieren ??? |
| |
| return nTotal; |
| } |
| |
| |
| sal_Bool ScAttrArray::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes, |
| sal_Bool bLeft, sal_Bool bRight ) const |
| { |
| SCSIZE nStartIndex; |
| SCSIZE nEndIndex; |
| Search( nRow1, nStartIndex ); |
| Search( nRow2, nEndIndex ); |
| sal_Bool bFound = sal_False; |
| |
| const SvxBoxItem* pItem = 0; |
| const SvxBorderLine* pLine = 0; |
| long nCmp; |
| |
| // oben |
| |
| pItem = (const SvxBoxItem*) &pData[nStartIndex].pPattern->GetItem(ATTR_BORDER); |
| pLine = pItem->GetTop(); |
| if (pLine) |
| { |
| nCmp = lcl_LineSize(*pLine); |
| if ( nCmp > rSizes.Top() ) |
| rSizes.Top() = nCmp; |
| bFound = sal_True; |
| } |
| |
| // unten |
| |
| if ( nEndIndex != nStartIndex ) |
| pItem = (const SvxBoxItem*) &pData[nEndIndex].pPattern->GetItem(ATTR_BORDER); |
| pLine = pItem->GetBottom(); |
| if (pLine) |
| { |
| nCmp = lcl_LineSize(*pLine); |
| if ( nCmp > rSizes.Bottom() ) |
| rSizes.Bottom() = nCmp; |
| bFound = sal_True; |
| } |
| |
| if ( bLeft || bRight ) |
| for ( SCSIZE i=nStartIndex; i<=nEndIndex; i++) |
| { |
| pItem = (const SvxBoxItem*) &pData[i].pPattern->GetItem(ATTR_BORDER); |
| |
| // links |
| |
| if (bLeft) |
| { |
| pLine = pItem->GetLeft(); |
| if (pLine) |
| { |
| nCmp = lcl_LineSize(*pLine); |
| if ( nCmp > rSizes.Left() ) |
| rSizes.Left() = nCmp; |
| bFound = sal_True; |
| } |
| } |
| |
| // rechts |
| |
| if (bRight) |
| { |
| pLine = pItem->GetRight(); |
| if (pLine) |
| { |
| nCmp = lcl_LineSize(*pLine); |
| if ( nCmp > rSizes.Right() ) |
| rSizes.Right() = nCmp; |
| bFound = sal_True; |
| } |
| } |
| } |
| |
| return bFound; |
| } |
| |
| // Testen, ob Bereich bestimmtes Attribut enthaelt |
| |
| bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const |
| { |
| SCSIZE nStartIndex; |
| SCSIZE nEndIndex; |
| Search( nRow1, nStartIndex ); |
| Search( nRow2, nEndIndex ); |
| bool bFound = false; |
| |
| for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++) |
| { |
| const ScPatternAttr* pPattern = pData[i].pPattern; |
| if ( nMask & HASATTR_MERGED ) |
| { |
| const ScMergeAttr* pMerge = |
| (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE ); |
| if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 ) |
| bFound = true; |
| } |
| if ( nMask & ( HASATTR_OVERLAPPED | HASATTR_NOTOVERLAPPED | HASATTR_AUTOFILTER ) ) |
| { |
| const ScMergeFlagAttr* pMergeFlag = |
| (const ScMergeFlagAttr*) &pPattern->GetItem( ATTR_MERGE_FLAG ); |
| if ( (nMask & HASATTR_OVERLAPPED) && pMergeFlag->IsOverlapped() ) |
| bFound = true; |
| if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() ) |
| bFound = true; |
| if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() ) |
| bFound = true; |
| } |
| if ( nMask & HASATTR_LINES ) |
| { |
| const SvxBoxItem* pBox = |
| (const SvxBoxItem*) &pPattern->GetItem( ATTR_BORDER ); |
| if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() ) |
| bFound = true; |
| } |
| if ( nMask & HASATTR_SHADOW ) |
| { |
| const SvxShadowItem* pShadow = |
| (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW ); |
| if ( pShadow->GetLocation() != SVX_SHADOW_NONE ) |
| bFound = true; |
| } |
| if ( nMask & HASATTR_CONDITIONAL ) |
| { |
| const SfxUInt32Item* pConditional = |
| (const SfxUInt32Item*) &pPattern->GetItem( ATTR_CONDITIONAL ); |
| if ( pConditional->GetValue() != 0 ) |
| bFound = true; |
| } |
| if ( nMask & HASATTR_PROTECTED ) |
| { |
| const ScProtectionAttr* pProtect = |
| (const ScProtectionAttr*) &pPattern->GetItem( ATTR_PROTECTION ); |
| if ( pProtect->GetProtection() || pProtect->GetHideCell() ) |
| bFound = true; |
| } |
| if ( nMask & HASATTR_ROTATE ) |
| { |
| const SfxInt32Item* pRotate = |
| (const SfxInt32Item*) &pPattern->GetItem( ATTR_ROTATE_VALUE ); |
| // 90 or 270 degrees is former SvxOrientationItem - only look for other values |
| // (see ScPatternAttr::GetCellOrientation) |
| sal_Int32 nAngle = pRotate->GetValue(); |
| if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 ) |
| bFound = true; |
| } |
| if ( nMask & HASATTR_NEEDHEIGHT ) |
| { |
| if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD) |
| bFound = true; |
| else if (((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue()) |
| bFound = true; |
| else if ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern-> |
| GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK) |
| bFound = true; |
| else if (((const SfxUInt32Item&)pPattern->GetItem( ATTR_CONDITIONAL )).GetValue()) |
| bFound = true; |
| else if (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue()) |
| bFound = true; |
| } |
| if ( nMask & ( HASATTR_SHADOW_RIGHT | HASATTR_SHADOW_DOWN ) ) |
| { |
| const SvxShadowItem* pShadow = |
| (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW ); |
| SvxShadowLocation eLoc = pShadow->GetLocation(); |
| if ( nMask & HASATTR_SHADOW_RIGHT ) |
| if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT ) |
| bFound = true; |
| if ( nMask & HASATTR_SHADOW_DOWN ) |
| if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT ) |
| bFound = true; |
| } |
| if ( nMask & HASATTR_RTL ) |
| { |
| const SvxFrameDirectionItem& rDirection = |
| (const SvxFrameDirectionItem&) pPattern->GetItem( ATTR_WRITINGDIR ); |
| if ( rDirection.GetValue() == FRMDIR_HORI_RIGHT_TOP ) |
| bFound = true; |
| } |
| if ( nMask & HASATTR_RIGHTORCENTER ) |
| { |
| // called only if the sheet is LTR, so physical=logical alignment can be assumed |
| SvxCellHorJustify eHorJust = (SvxCellHorJustify) |
| ((const SvxHorJustifyItem&) pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue(); |
| if ( eHorJust == SVX_HOR_JUSTIFY_RIGHT || eHorJust == SVX_HOR_JUSTIFY_CENTER ) |
| bFound = true; |
| } |
| } |
| |
| return bFound; |
| } |
| |
| // Bereich um evtl. enthaltene Zusammenfassungen erweitern |
| // und evtl. MergeFlag anpassen (bRefresh) |
| |
| sal_Bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow, |
| SCCOL& rPaintCol, SCROW& rPaintRow, |
| sal_Bool bRefresh, sal_Bool bAttrs ) |
| { |
| const ScPatternAttr* pPattern; |
| const ScMergeAttr* pItem; |
| SCSIZE nStartIndex; |
| SCSIZE nEndIndex; |
| Search( nStartRow, nStartIndex ); |
| Search( nEndRow, nEndIndex ); |
| sal_Bool bFound = sal_False; |
| |
| for (SCSIZE i=nStartIndex; i<=nEndIndex; i++) |
| { |
| pPattern = pData[i].pPattern; |
| pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE ); |
| SCsCOL nCountX = pItem->GetColMerge(); |
| SCsROW nCountY = pItem->GetRowMerge(); |
| if (nCountX>1 || nCountY>1) |
| { |
| SCROW nThisRow = (i>0) ? pData[i-1].nRow+1 : 0; |
| SCCOL nMergeEndCol = nThisCol + nCountX - 1; |
| SCROW nMergeEndRow = nThisRow + nCountY - 1; |
| if (nMergeEndCol > rPaintCol && nMergeEndCol <= MAXCOL) |
| rPaintCol = nMergeEndCol; |
| if (nMergeEndRow > rPaintRow && nMergeEndRow <= MAXROW) |
| rPaintRow = nMergeEndRow; |
| bFound = sal_True; |
| |
| if (bAttrs) |
| { |
| const SvxShadowItem* pShadow = |
| (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW ); |
| SvxShadowLocation eLoc = pShadow->GetLocation(); |
| if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT ) |
| if ( nMergeEndCol+1 > rPaintCol && nMergeEndCol < MAXCOL ) |
| rPaintCol = nMergeEndCol+1; |
| if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT ) |
| if ( nMergeEndRow+1 > rPaintRow && nMergeEndRow < MAXROW ) |
| rPaintRow = nMergeEndRow+1; |
| } |
| |
| if (bRefresh) |
| { |
| if ( nMergeEndCol > nThisCol ) |
| pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow, |
| nTab, SC_MF_HOR ); |
| if ( nMergeEndRow > nThisRow ) |
| pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow, |
| nTab, SC_MF_VER ); |
| if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow ) |
| pDocument->ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow, |
| nTab, SC_MF_HOR | SC_MF_VER ); |
| |
| Search( nThisRow, i ); // Daten wurden veraendert |
| Search( nStartRow, nStartIndex ); |
| Search( nEndRow, nEndIndex ); |
| } |
| } |
| } |
| |
| return bFound; |
| } |
| |
| |
| sal_Bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow) |
| { |
| sal_Bool bFound = sal_False; |
| const ScPatternAttr* pPattern; |
| const ScMergeAttr* pItem; |
| SCSIZE nIndex; |
| |
| Search( nStartRow, nIndex ); |
| SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; |
| if (nThisStart < nStartRow) |
| nThisStart = nStartRow; |
| |
| while ( nThisStart <= nEndRow ) |
| { |
| SCROW nThisEnd = pData[nIndex].nRow; |
| if (nThisEnd > nEndRow) |
| nThisEnd = nEndRow; |
| |
| pPattern = pData[nIndex].pPattern; |
| pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE ); |
| SCsCOL nCountX = pItem->GetColMerge(); |
| SCsROW nCountY = pItem->GetRowMerge(); |
| if (nCountX>1 || nCountY>1) |
| { |
| const ScMergeAttr* pAttr = (const ScMergeAttr*) |
| &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE ); |
| const ScMergeFlagAttr* pFlagAttr = (const ScMergeFlagAttr*) |
| &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG ); |
| |
| DBG_ASSERT( nCountY==1 || nThisStart==nThisEnd, "was'n hier los?" ); |
| |
| SCCOL nThisCol = nCol; |
| SCCOL nMergeEndCol = nThisCol + nCountX - 1; |
| SCROW nMergeEndRow = nThisEnd + nCountY - 1; |
| |
| //! ApplyAttr fuer Bereiche !!! |
| |
| for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++) |
| pDocument->ApplyAttr( nThisCol, nThisRow, nTab, *pAttr ); |
| |
| ScPatternAttr* pNewPattern = new ScPatternAttr( pDocument->GetPool() ); |
| SfxItemSet* pSet = &pNewPattern->GetItemSet(); |
| pSet->Put( *pFlagAttr ); |
| pDocument->ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow, |
| nTab, *pNewPattern ); |
| delete pNewPattern; |
| |
| Search( nThisEnd, nIndex ); // Daten wurden veraendert !!! |
| } |
| |
| ++nIndex; |
| if ( nIndex < nCount ) |
| nThisStart = pData[nIndex-1].nRow+1; |
| else |
| nThisStart = MAXROW+1; // Ende |
| } |
| |
| return bFound; |
| } |
| |
| // Bereich loeschen, aber Merge-Flags stehenlassen |
| |
| void ScAttrArray::DeleteAreaSafe(SCROW nStartRow, SCROW nEndRow) |
| { |
| SetPatternAreaSafe( nStartRow, nEndRow, pDocument->GetDefPattern(), sal_True ); |
| } |
| |
| |
| void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow, |
| const ScPatternAttr* pWantedPattern, sal_Bool bDefault ) |
| { |
| const ScPatternAttr* pOldPattern; |
| const ScMergeFlagAttr* pItem; |
| |
| SCSIZE nIndex; |
| SCROW nRow; |
| SCROW nThisRow; |
| sal_Bool bFirstUse = sal_True; |
| |
| Search( nStartRow, nIndex ); |
| nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; |
| while ( nThisRow <= nEndRow ) |
| { |
| pOldPattern = pData[nIndex].pPattern; |
| if (pOldPattern != pWantedPattern) //! else-Zweig ? |
| { |
| if (nThisRow < nStartRow) nThisRow = nStartRow; |
| nRow = pData[nIndex].nRow; |
| SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow ); |
| pItem = (const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ); |
| |
| if (pItem->IsOverlapped() || pItem->HasAutoFilter()) |
| { |
| // #108045# default-constructing a ScPatternAttr for DeleteArea doesn't work |
| // because it would have no cell style information. |
| // Instead, the document's GetDefPattern is copied. Since it is passed as |
| // pWantedPattern, no special treatment of default is needed here anymore. |
| ScPatternAttr* pNewPattern = new ScPatternAttr( *pWantedPattern ); |
| SfxItemSet* pSet = &pNewPattern->GetItemSet(); |
| pSet->Put( *pItem ); |
| SetPatternArea( nThisRow, nAttrRow, pNewPattern, sal_True ); |
| delete pNewPattern; |
| } |
| else |
| { |
| if ( !bDefault ) |
| { |
| if (bFirstUse) |
| bFirstUse = sal_False; |
| else |
| pDocument->GetPool()->Put( *pWantedPattern ); // im Pool ist es schon! |
| } |
| SetPatternArea( nThisRow, nAttrRow, pWantedPattern ); |
| } |
| |
| Search( nThisRow, nIndex ); // Daten wurden veraendert !!! |
| } |
| |
| ++nIndex; |
| nThisRow = pData[nIndex-1].nRow+1; |
| } |
| } |
| |
| |
| sal_Bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags ) |
| { |
| const ScPatternAttr* pOldPattern; |
| |
| sal_Int16 nOldValue; |
| SCSIZE nIndex; |
| SCROW nRow; |
| SCROW nThisRow; |
| sal_Bool bChanged = sal_False; |
| |
| Search( nStartRow, nIndex ); |
| nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; |
| if (nThisRow < nStartRow) nThisRow = nStartRow; |
| |
| while ( nThisRow <= nEndRow ) |
| { |
| pOldPattern = pData[nIndex].pPattern; |
| nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue(); |
| if ( (nOldValue | nFlags) != nOldValue ) |
| { |
| nRow = pData[nIndex].nRow; |
| SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow ); |
| ScPatternAttr aNewPattern(*pOldPattern); |
| aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) ); |
| SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True ); |
| Search( nThisRow, nIndex ); // Daten wurden veraendert !!! |
| bChanged = sal_True; |
| } |
| |
| ++nIndex; |
| nThisRow = pData[nIndex-1].nRow+1; |
| } |
| |
| return bChanged; |
| } |
| |
| |
| sal_Bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags ) |
| { |
| const ScPatternAttr* pOldPattern; |
| |
| sal_Int16 nOldValue; |
| SCSIZE nIndex; |
| SCROW nRow; |
| SCROW nThisRow; |
| sal_Bool bChanged = sal_False; |
| |
| Search( nStartRow, nIndex ); |
| nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; |
| if (nThisRow < nStartRow) nThisRow = nStartRow; |
| |
| while ( nThisRow <= nEndRow ) |
| { |
| pOldPattern = pData[nIndex].pPattern; |
| nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue(); |
| if ( (nOldValue & ~nFlags) != nOldValue ) |
| { |
| nRow = pData[nIndex].nRow; |
| SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow ); |
| ScPatternAttr aNewPattern(*pOldPattern); |
| aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) ); |
| SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True ); |
| Search( nThisRow, nIndex ); // Daten wurden veraendert !!! |
| bChanged = sal_True; |
| } |
| |
| ++nIndex; |
| nThisRow = pData[nIndex-1].nRow+1; |
| } |
| |
| return bChanged; |
| } |
| |
| |
| void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich ) |
| { |
| const ScPatternAttr* pOldPattern; |
| |
| SCSIZE nIndex; |
| SCROW nRow; |
| SCROW nThisRow; |
| |
| Search( nStartRow, nIndex ); |
| nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; |
| if (nThisRow < nStartRow) nThisRow = nStartRow; |
| |
| while ( nThisRow <= nEndRow ) |
| { |
| pOldPattern = pData[nIndex].pPattern; |
| if ( pOldPattern->HasItemsSet( pWhich ) ) |
| { |
| ScPatternAttr aNewPattern(*pOldPattern); |
| aNewPattern.ClearItems( pWhich ); |
| |
| nRow = pData[nIndex].nRow; |
| SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow ); |
| SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True ); |
| Search( nThisRow, nIndex ); // Daten wurden veraendert !!! |
| } |
| |
| ++nIndex; |
| nThisRow = pData[nIndex-1].nRow+1; |
| } |
| } |
| |
| |
| void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, sal_Bool bIncrement ) |
| { |
| SCSIZE nIndex; |
| Search( nStartRow, nIndex ); |
| SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; |
| if (nThisStart < nStartRow) nThisStart = nStartRow; |
| |
| while ( nThisStart <= nEndRow ) |
| { |
| const ScPatternAttr* pOldPattern = pData[nIndex].pPattern; |
| const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); |
| const SfxPoolItem* pItem; |
| |
| sal_Bool bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, sal_False, &pItem ) != SFX_ITEM_SET |
| || ((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT ); |
| sal_uInt16 nOldValue = ((const SfxUInt16Item&)rOldSet.Get( ATTR_INDENT )).GetValue(); |
| sal_uInt16 nNewValue = nOldValue; |
| if ( bIncrement ) |
| { |
| if ( nNewValue < SC_MAX_INDENT ) |
| { |
| nNewValue += SC_INDENT_STEP; |
| if ( nNewValue > SC_MAX_INDENT ) nNewValue = SC_MAX_INDENT; |
| } |
| } |
| else |
| { |
| if ( nNewValue > 0 ) |
| { |
| if ( nNewValue > SC_INDENT_STEP ) |
| nNewValue -= SC_INDENT_STEP; |
| else |
| nNewValue = 0; |
| } |
| } |
| |
| if ( bNeedJust || nNewValue != nOldValue ) |
| { |
| SCROW nThisEnd = pData[nIndex].nRow; |
| SCROW nAttrRow = Min( nThisEnd, nEndRow ); |
| ScPatternAttr aNewPattern(*pOldPattern); |
| aNewPattern.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, nNewValue ) ); |
| if ( bNeedJust ) |
| aNewPattern.GetItemSet().Put( |
| SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) ); |
| SetPatternArea( nThisStart, nAttrRow, &aNewPattern, sal_True ); |
| |
| nThisStart = nThisEnd + 1; |
| Search( nThisStart, nIndex ); // Daten wurden veraendert !!! |
| } |
| else |
| { |
| nThisStart = pData[nIndex].nRow + 1; // weiterzaehlen... |
| ++nIndex; |
| } |
| } |
| } |
| |
| |
| SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, sal_Bool bUp ) const |
| { |
| long nRet = nRow; |
| if (VALIDROW(nRow)) |
| { |
| SCSIZE nIndex; |
| Search(nRow, nIndex); |
| while (((const ScProtectionAttr&)pData[nIndex].pPattern-> |
| GetItem(ATTR_PROTECTION)).GetProtection()) |
| { |
| if (bUp) |
| { |
| if (nIndex==0) |
| return -1; // nichts gefunden |
| --nIndex; |
| nRet = pData[nIndex].nRow; |
| } |
| else |
| { |
| nRet = pData[nIndex].nRow+1; |
| ++nIndex; |
| if (nIndex>=nCount) |
| return MAXROW+1; // nichts gefunden |
| } |
| } |
| } |
| return nRet; |
| } |
| |
| void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset ) |
| { |
| SCROW nStart = 0; |
| SCSIZE nPos = 0; |
| while (nPos < nCount) |
| { |
| SCROW nEnd = pData[nPos].nRow; |
| if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet) |
| { |
| // for (SCROW nRow = nStart; nRow <= nEnd; nRow++) |
| // pUsed[nRow] = sal_True; |
| |
| rUsedRows.setTrue(nStart, nEnd); |
| |
| if (bReset) |
| { |
| ScPatternAttr* pNewPattern = new ScPatternAttr(*pData[nPos].pPattern); |
| pDocument->GetPool()->Remove(*pData[nPos].pPattern); |
| pNewPattern->SetStyleSheet( (ScStyleSheet*) |
| pDocument->GetStyleSheetPool()-> |
| Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD), |
| SFX_STYLE_FAMILY_PARA, |
| SFXSTYLEBIT_AUTO | SCSTYLEBIT_STANDARD ) ); |
| pData[nPos].pPattern = (const ScPatternAttr*) |
| &pDocument->GetPool()->Put(*pNewPattern); |
| delete pNewPattern; |
| |
| if (Concat(nPos)) |
| { |
| Search(nStart, nPos); |
| --nPos; // wegen ++ am Ende |
| } |
| } |
| } |
| nStart = nEnd + 1; |
| ++nPos; |
| } |
| } |
| |
| |
| sal_Bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle, |
| sal_Bool bGatherAllStyles ) const |
| { |
| sal_Bool bIsUsed = sal_False; |
| SCSIZE nPos = 0; |
| |
| while ( nPos < nCount ) |
| { |
| const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet(); |
| if ( pStyle ) |
| { |
| pStyle->SetUsage( ScStyleSheet::USED ); |
| if ( pStyle == &rStyle ) |
| { |
| if ( !bGatherAllStyles ) |
| return sal_True; |
| bIsUsed = sal_True; |
| } |
| } |
| nPos++; |
| } |
| |
| return bIsUsed; |
| } |
| |
| |
| sal_Bool ScAttrArray::IsEmpty() const |
| { |
| if (nCount == 1) |
| { |
| if ( pData[0].pPattern != pDocument->GetDefPattern() ) |
| return sal_False; |
| else |
| return sal_True; |
| } |
| else |
| return sal_False; |
| } |
| |
| |
| //UNUSED2008-05 SCROW ScAttrArray::GetFirstEntryPos() const |
| //UNUSED2008-05 { |
| //UNUSED2008-05 DBG_ASSERT( nCount, "nCount = 0" ); |
| //UNUSED2008-05 |
| //UNUSED2008-05 if ( pData[0].pPattern != pDocument->GetDefPattern() ) |
| //UNUSED2008-05 return 0; |
| //UNUSED2008-05 else |
| //UNUSED2008-05 { |
| //UNUSED2008-05 if (nCount==1) |
| //UNUSED2008-05 return 0; // leer |
| //UNUSED2008-05 else |
| //UNUSED2008-05 return pData[0].nRow + 1; |
| //UNUSED2008-05 } |
| //UNUSED2008-05 } |
| //UNUSED2008-05 |
| //UNUSED2008-05 |
| //UNUSED2008-05 SCROW ScAttrArray::GetLastEntryPos( sal_Bool bIncludeBottom ) const |
| //UNUSED2008-05 { |
| //UNUSED2008-05 DBG_ASSERT( nCount, "nCount == 0" ); |
| //UNUSED2008-05 |
| //UNUSED2008-05 if (bIncludeBottom) |
| //UNUSED2008-05 bIncludeBottom = ( pData[nCount-1].pPattern != pDocument->GetDefPattern() ); |
| //UNUSED2008-05 |
| //UNUSED2008-05 if (bIncludeBottom) |
| //UNUSED2008-05 return MAXROW; |
| //UNUSED2008-05 else |
| //UNUSED2008-05 { |
| //UNUSED2008-05 if (nCount<=1) |
| //UNUSED2008-05 return 0; // leer |
| //UNUSED2008-05 else |
| //UNUSED2008-05 return pData[nCount-2].nRow; |
| //UNUSED2008-05 } |
| //UNUSED2008-05 } |
| |
| |
| sal_Bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const |
| { |
| DBG_ASSERT( nCount, "nCount == 0" ); |
| |
| sal_Bool bFound = sal_False; |
| SCSIZE nStart = 0; |
| |
| // Skip first entry if more than 1 row. |
| // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr. |
| |
| SCSIZE nVisStart = 1; |
| while ( nVisStart < nCount && pData[nVisStart].pPattern->IsVisibleEqual(*pData[nVisStart-1].pPattern) ) |
| ++nVisStart; |
| if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 ) // more than 1 row? |
| nStart = nVisStart; |
| |
| while ( nStart < nCount && !bFound ) |
| { |
| if ( pData[nStart].pPattern->IsVisible() ) |
| { |
| rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0; |
| bFound = sal_True; |
| } |
| else |
| ++nStart; |
| } |
| |
| return bFound; |
| } |
| |
| // size (rows) of a range of attributes after cell content where the search is stopped |
| // (more than a default page size, 2*42 because it's as good as any number) |
| |
| const SCROW SC_VISATTR_STOP = 84; |
| |
| sal_Bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const |
| { |
| // #i30830# changed behavior: |
| // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows |
| // below the last content cell |
| |
| if ( nLastData == MAXROW ) |
| { |
| rLastRow = MAXROW; // can't look for attributes below MAXROW |
| return sal_True; |
| } |
| |
| sal_Bool bFound = sal_False; |
| |
| // loop backwards from the end instead of using Search, assuming that |
| // there usually aren't many attributes below the last cell |
| |
| SCSIZE nPos = nCount; |
| while ( nPos > 0 && pData[nPos-1].nRow > nLastData ) |
| { |
| SCSIZE nEndPos = nPos - 1; |
| SCSIZE nStartPos = nEndPos; // find range of visually equal formats |
| while ( nStartPos > 0 && |
| pData[nStartPos-1].nRow > nLastData && |
| pData[nStartPos-1].pPattern->IsVisibleEqual(*pData[nStartPos].pPattern) ) |
| --nStartPos; |
| |
| SCROW nAttrStartRow = ( nStartPos > 0 ) ? ( pData[nStartPos-1].nRow + 1 ) : 0; |
| if ( nAttrStartRow <= nLastData ) |
| nAttrStartRow = nLastData + 1; |
| SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow; |
| if ( nAttrSize >= SC_VISATTR_STOP ) |
| { |
| bFound = sal_False; // ignore this range and below |
| } |
| else if ( !bFound && pData[nEndPos].pPattern->IsVisible() ) |
| { |
| rLastRow = pData[nEndPos].nRow; |
| bFound = sal_True; |
| } |
| |
| nPos = nStartPos; // look further from the top of the range |
| } |
| |
| return bFound; |
| } |
| |
| sal_Bool ScAttrArray::GetLastAttr( SCROW& rLastRow, SCROW nLastData ) const |
| { |
| if ( nLastData == MAXROW ) |
| { |
| rLastRow = MAXROW; |
| return sal_True; |
| } |
| |
| sal_Bool bFound = sal_False; |
| |
| // Loop backwards from the end instead of using Search, assuming that |
| // there usually aren't many attributes below the last cell. |
| SCSIZE nPos = nCount; |
| while ( nPos > 0 && pData[nPos - 1].nRow > nLastData ) |
| { |
| SCSIZE nEndPos = nPos - 1; |
| SCSIZE nStartPos = nEndPos; |
| while ( nStartPos > 0 && pData[nStartPos - 1].nRow > nLastData && |
| pData[nStartPos - 1].pPattern->IsEqual( *pData[nStartPos].pPattern ) ) |
| --nStartPos; |
| |
| SCROW nAttrStartRow = ( nStartPos > 0 ) ? ( pData[nStartPos - 1].nRow + 1 ) : 0; |
| if ( nAttrStartRow <= nLastData ) |
| nAttrStartRow = nLastData + 1; |
| SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow; |
| if ( nAttrSize >= SC_VISATTR_STOP ) |
| { |
| bFound = sal_False; |
| } |
| else if ( !bFound ) |
| { |
| rLastRow = pData[nEndPos].nRow; |
| bFound = sal_True; |
| } |
| |
| // look further from the top of the range. |
| nPos = nStartPos; |
| } |
| |
| return bFound; |
| } |
| |
| |
| sal_Bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const |
| { |
| SCSIZE nIndex; |
| Search( nStartRow, nIndex ); |
| SCROW nThisStart = nStartRow; |
| sal_Bool bFound = sal_False; |
| while ( nIndex < nCount && nThisStart <= nEndRow && !bFound ) |
| { |
| if ( pData[nIndex].pPattern->IsVisible() ) |
| bFound = sal_True; |
| |
| nThisStart = pData[nIndex].nRow + 1; |
| ++nIndex; |
| } |
| |
| return bFound; |
| } |
| |
| |
| sal_Bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther, |
| SCROW nStartRow, SCROW nEndRow ) const |
| { |
| sal_Bool bEqual = sal_True; |
| SCSIZE nThisPos = 0; |
| SCSIZE nOtherPos = 0; |
| if ( nStartRow > 0 ) |
| { |
| Search( nStartRow, nThisPos ); |
| rOther.Search( nStartRow, nOtherPos ); |
| } |
| |
| while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual ) |
| { |
| SCROW nThisRow = pData[nThisPos].nRow; |
| SCROW nOtherRow = rOther.pData[nOtherPos].nRow; |
| const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern; |
| const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern; |
| bEqual = ( pThisPattern == pOtherPattern || |
| pThisPattern->IsVisibleEqual(*pOtherPattern) ); |
| |
| if ( nThisRow >= nOtherRow ) |
| { |
| if ( nOtherRow >= nEndRow ) break; |
| ++nOtherPos; |
| } |
| if ( nThisRow <= nOtherRow ) |
| { |
| if ( nThisRow >= nEndRow ) break; |
| ++nThisPos; |
| } |
| } |
| |
| return bEqual; |
| } |
| |
| |
| sal_Bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const |
| { |
| //! mit IsVisibleEqual zusammenfassen? |
| |
| sal_Bool bEqual = sal_True; |
| SCSIZE nThisPos = 0; |
| SCSIZE nOtherPos = 0; |
| if ( nStartRow > 0 ) |
| { |
| Search( nStartRow, nThisPos ); |
| rOther.Search( nStartRow, nOtherPos ); |
| } |
| |
| while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual ) |
| { |
| SCROW nThisRow = pData[nThisPos].nRow; |
| SCROW nOtherRow = rOther.pData[nOtherPos].nRow; |
| const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern; |
| const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern; |
| bEqual = ( pThisPattern == pOtherPattern ); |
| |
| if ( nThisRow >= nOtherRow ) |
| { |
| if ( nOtherRow >= nEndRow ) break; |
| ++nOtherPos; |
| } |
| if ( nThisRow <= nOtherRow ) |
| { |
| if ( nThisRow >= nEndRow ) break; |
| ++nThisPos; |
| } |
| } |
| |
| return bEqual; |
| } |
| |
| |
| sal_Bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const |
| { |
| // horizontal zusammengefasste duerfen nicht herausgeschoben werden |
| // (ob die ganze Zusammenfassung betroffen ist, ist hier nicht zu erkennen) |
| |
| sal_Bool bTest = sal_True; |
| if (!IsEmpty()) |
| { |
| SCSIZE nIndex = 0; |
| if ( nStartRow > 0 ) |
| Search( nStartRow, nIndex ); |
| |
| for ( ; nIndex < nCount; nIndex++ ) |
| { |
| if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern-> |
| GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() ) |
| { |
| bTest = sal_False; // darf nicht herausgeschoben werden |
| break; |
| } |
| if ( pData[nIndex].nRow >= nEndRow ) // Ende des Bereichs |
| break; |
| } |
| } |
| return bTest; |
| } |
| |
| |
| sal_Bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const |
| { |
| // wenn die erste herausgeschobene Zeile vertikal ueberlappt ist, |
| // wuerde eine kaputte Zusammenfassung uebrigbleiben |
| |
| if (pData) |
| { |
| // MAXROW + 1 - nSize = erste herausgeschobene Zeile |
| |
| SCSIZE nFirstLost = nCount-1; |
| while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) ) |
| --nFirstLost; |
| |
| if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern-> |
| GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() ) |
| return sal_False; |
| } |
| |
| return sal_True; |
| } |
| |
| |
| void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize ) |
| { |
| if (!pData) |
| return; |
| |
| SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // Vorgaenger erweitern |
| SCSIZE nIndex; |
| Search( nSearch, nIndex ); |
| |
| // ein gesetztes ScMergeAttr darf nicht ausgedehnt werden |
| // (darum hinterher wieder loeschen) |
| |
| sal_Bool bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged(); |
| |
| SCSIZE nRemove = 0; |
| SCSIZE i; |
| for (i = nIndex; i < nCount-1; i++) |
| { |
| SCROW nNew = pData[i].nRow + nSize; |
| if ( nNew >= MAXROW ) // Ende erreicht ? |
| { |
| nNew = MAXROW; |
| if (!nRemove) |
| nRemove = i+1; // folgende loeschen |
| } |
| pData[i].nRow = nNew; |
| } |
| |
| // muessen Eintraege am Ende geloescht werden? |
| |
| if (nRemove && nRemove < nCount) |
| DeleteRange( nRemove, nCount-1 ); |
| |
| if (bDoMerge) // ausgedehntes ScMergeAttr wieder reparieren |
| { |
| //! ApplyAttr fuer Bereiche !!! |
| |
| const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE ); |
| for (SCSIZE nAdd=0; nAdd<nSize; nAdd++) |
| pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef ); |
| |
| // im eingefuegten Bereich ist nichts zusammengefasst |
| } |
| |
| // Don't duplicate the merge flags in the inserted row. |
| // #i108488# SC_MF_SCENARIO has to be allowed. |
| RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON ); |
| } |
| |
| |
| void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize ) |
| { |
| if (pData) |
| { |
| sal_Bool bFirst=sal_True; |
| SCSIZE nStartIndex = 0; |
| SCSIZE nEndIndex = 0; |
| SCSIZE i; |
| |
| for ( i = 0; i < nCount-1; i++) |
| if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1)) |
| { |
| if (bFirst) |
| { |
| nStartIndex = i; |
| bFirst = sal_False; |
| } |
| nEndIndex = i; |
| } |
| if (!bFirst) |
| { |
| SCROW nStart; |
| if (nStartIndex==0) |
| nStart = 0; |
| else |
| nStart = pData[nStartIndex-1].nRow + 1; |
| |
| if (nStart < nStartRow) |
| { |
| pData[nStartIndex].nRow = nStartRow - 1; |
| ++nStartIndex; |
| } |
| if (nEndIndex >= nStartIndex) |
| { |
| DeleteRange( nStartIndex, nEndIndex ); |
| if (nStartIndex > 0) |
| if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern ) |
| DeleteRange( nStartIndex-1, nStartIndex-1 ); |
| } |
| } |
| for (i = 0; i < nCount-1; i++) |
| if (pData[i].nRow >= nStartRow) |
| pData[i].nRow -= nSize; |
| |
| // unten nicht Default-Pattern nachschieben, um Druckbereiche erkennen zu koennen |
| // stattdessen nur Merge-Flags loeschen |
| |
| RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO ); |
| } |
| } |
| |
| |
| void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex ) |
| { |
| ScDocumentPool* pDocPool = pDocument->GetPool(); |
| for (SCSIZE i = nStartIndex; i <= nEndIndex; i++) |
| pDocPool->Remove(*pData[i].pPattern); |
| |
| memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) ); |
| nCount -= nEndIndex-nStartIndex+1; |
| } |
| |
| |
| void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow) |
| { |
| RemoveAreaMerge( nStartRow, nEndRow ); // von zusammengefassten auch die Flags loeschen |
| |
| if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) ) |
| SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() ); |
| else |
| DeleteAreaSafe( nStartRow, nEndRow ); // Merge-Flags stehenlassen |
| } |
| |
| |
| void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow) |
| { |
| const ScPatternAttr* pDefPattern = pDocument->GetDefPattern(); |
| const ScPatternAttr* pOldPattern; |
| |
| SCSIZE nIndex; |
| SCROW nRow; |
| SCROW nThisRow; |
| |
| Search( nStartRow, nIndex ); |
| nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; |
| if (nThisRow < nStartRow) nThisRow = nStartRow; |
| |
| while ( nThisRow <= nEndRow ) |
| { |
| pOldPattern = pData[nIndex].pPattern; |
| |
| if ( pOldPattern->GetItemSet().Count() ) // harte Attribute ? |
| { |
| nRow = pData[nIndex].nRow; |
| SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow ); |
| |
| ScPatternAttr aNewPattern(*pOldPattern); |
| SfxItemSet& rSet = aNewPattern.GetItemSet(); |
| for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++) |
| if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG) |
| rSet.ClearItem(nId); |
| |
| if ( aNewPattern == *pDefPattern ) |
| SetPatternArea( nThisRow, nAttrRow, pDefPattern, sal_False ); |
| else |
| SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True ); |
| |
| Search( nThisRow, nIndex ); // Daten wurden veraendert !!! |
| } |
| |
| ++nIndex; |
| nThisRow = pData[nIndex-1].nRow+1; |
| } |
| } |
| |
| // Verschieben innerhalb eines Dokuments |
| |
| void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray) |
| { |
| SCROW nStart = nStartRow; |
| for (SCSIZE i = 0; i < nCount; i++) |
| { |
| if ((pData[i].nRow >= nStartRow) && ((i==0) ? sal_True : pData[i-1].nRow < nEndRow)) |
| { |
| // Kopieren (bPutToPool=sal_True) |
| rAttrArray.SetPatternArea( nStart, Min( (SCROW)pData[i].nRow, (SCROW)nEndRow ), |
| pData[i].pPattern, sal_True ); |
| } |
| nStart = Max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) ); |
| } |
| DeleteArea(nStartRow, nEndRow); |
| } |
| |
| |
| // Kopieren zwischen Dokumenten (Clipboard) |
| |
| void ScAttrArray::CopyArea( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray, |
| sal_Int16 nStripFlags ) |
| { |
| nStartRow -= nDy; // Source |
| nEndRow -= nDy; |
| |
| SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0); |
| SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW); |
| |
| ScDocumentPool* pSourceDocPool = pDocument->GetPool(); |
| ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool(); |
| sal_Bool bSamePool = (pSourceDocPool==pDestDocPool); |
| |
| for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++) |
| { |
| if (pData[i].nRow >= nStartRow) |
| { |
| const ScPatternAttr* pOldPattern = pData[i].pPattern; |
| const ScPatternAttr* pNewPattern; |
| |
| if (IsDefaultItem( pOldPattern )) |
| { |
| // am Default muss nichts veraendert werden |
| |
| pNewPattern = (const ScPatternAttr*) |
| &pDestDocPool->GetDefaultItem( ATTR_PATTERN ); |
| } |
| else if ( nStripFlags ) |
| { |
| ScPatternAttr* pTmpPattern = new ScPatternAttr( *pOldPattern ); |
| sal_Int16 nNewFlags = 0; |
| if ( nStripFlags != SC_MF_ALL ) |
| nNewFlags = ((const ScMergeFlagAttr&)pTmpPattern->GetItem(ATTR_MERGE_FLAG)). |
| GetValue() & ~nStripFlags; |
| |
| if ( nNewFlags ) |
| pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) ); |
| else |
| pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG ); |
| |
| if (bSamePool) |
| pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pTmpPattern); |
| else |
| pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument ); |
| delete pTmpPattern; |
| } |
| else |
| { |
| if (bSamePool) |
| pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern); |
| else |
| pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument ); |
| } |
| |
| rAttrArray.SetPatternArea(nDestStart, |
| Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern); |
| } |
| |
| // when pasting from clipboard and skipping filtered rows, the adjusted end position |
| // can be negative |
| nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1)); |
| } |
| } |
| |
| // Flags stehenlassen |
| //! mit CopyArea zusammenfassen !!! |
| |
| void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray ) |
| { |
| nStartRow -= nDy; // Source |
| nEndRow -= nDy; |
| |
| SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0); |
| SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW); |
| |
| if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) ) |
| { |
| CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray ); |
| return; |
| } |
| |
| ScDocumentPool* pSourceDocPool = pDocument->GetPool(); |
| ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool(); |
| sal_Bool bSamePool = (pSourceDocPool==pDestDocPool); |
| |
| for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++) |
| { |
| if (pData[i].nRow >= nStartRow) |
| { |
| const ScPatternAttr* pOldPattern = pData[i].pPattern; |
| const ScPatternAttr* pNewPattern; |
| |
| if (bSamePool) |
| pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern); |
| else |
| pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument ); |
| |
| rAttrArray.SetPatternAreaSafe(nDestStart, |
| Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, sal_False); |
| } |
| |
| // when pasting from clipboard and skipping filtered rows, the adjusted end position |
| // can be negative |
| nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1)); |
| } |
| } |
| |
| |
| SCsROW ScAttrArray::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle, |
| sal_Bool bUp, ScMarkArray* pMarkArray ) |
| { |
| sal_Bool bFound = sal_False; |
| |
| if (pMarkArray) |
| { |
| nRow = pMarkArray->GetNextMarked( nRow, bUp ); |
| if (!VALIDROW(nRow)) |
| return nRow; |
| } |
| |
| SCSIZE nIndex; |
| Search(nRow, nIndex); |
| const ScPatternAttr* pPattern = pData[nIndex].pPattern; |
| |
| while (nIndex < nCount && !bFound) |
| { |
| if (pPattern->GetStyleSheet() == pSearchStyle) |
| { |
| if (pMarkArray) |
| { |
| nRow = pMarkArray->GetNextMarked( nRow, bUp ); |
| SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0; |
| if (nRow >= nStart && nRow <= pData[nIndex].nRow) |
| bFound = sal_True; |
| } |
| else |
| bFound = sal_True; |
| } |
| |
| if (!bFound) |
| { |
| if (bUp) |
| { |
| if (nIndex==0) |
| { |
| nIndex = nCount; |
| nRow = -1; |
| } |
| else |
| { |
| --nIndex; |
| nRow = pData[nIndex].nRow; |
| pPattern = pData[nIndex].pPattern; |
| } |
| } |
| else |
| { |
| nRow = pData[nIndex].nRow+1; |
| ++nIndex; |
| if (nIndex<nCount) |
| pPattern = pData[nIndex].pPattern; |
| } |
| } |
| } |
| |
| DBG_ASSERT( bFound || !ValidRow(nRow), "interner Fehler in ScAttrArray::SearchStyle" ); |
| |
| return nRow; |
| } |
| |
| |
| sal_Bool ScAttrArray::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow, |
| const ScStyleSheet* pSearchStyle, sal_Bool bUp, ScMarkArray* pMarkArray ) |
| { |
| SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray ); |
| if (VALIDROW(nStartRow)) |
| { |
| SCSIZE nIndex; |
| Search(nStartRow,nIndex); |
| |
| rRow = nStartRow; |
| if (bUp) |
| { |
| if (nIndex>0) |
| rEndRow = pData[nIndex-1].nRow + 1; |
| else |
| rEndRow = 0; |
| if (pMarkArray) |
| { |
| SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, sal_True ); |
| if (nMarkEnd>rEndRow) |
| rEndRow = nMarkEnd; |
| } |
| } |
| else |
| { |
| rEndRow = pData[nIndex].nRow; |
| if (pMarkArray) |
| { |
| SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, sal_False ); |
| if (nMarkEnd<rEndRow) |
| rEndRow = nMarkEnd; |
| } |
| } |
| |
| return sal_True; |
| } |
| else |
| return sal_False; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| // Laden / Speichern |
| // |
| |
| |
| #if 0 |
| void ScAttrArray::Save( SvStream& /* rStream */ ) const |
| { |
| #if SC_ROWLIMIT_STREAM_ACCESS |
| #error address types changed! |
| ScWriteHeader aHdr( rStream, 8 ); |
| |
| ScDocumentPool* pDocPool = pDocument->GetPool(); |
| |
| sal_uInt16 nSaveCount = nCount; |
| SCROW nSaveMaxRow = pDocument->GetSrcMaxRow(); |
| if ( nSaveMaxRow != MAXROW ) |
| { |
| if ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow ) |
| { |
| pDocument->SetLostData(); // Warnung ausgeben |
| do |
| --nSaveCount; |
| while ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow ); |
| } |
| } |
| |
| rStream << nSaveCount; |
| |
| const SfxPoolItem* pItem; |
| for (SCSIZE i=0; i<nSaveCount; i++) |
| { |
| rStream << Min( pData[i].nRow, nSaveMaxRow ); |
| |
| const ScPatternAttr* pPattern = pData[i].pPattern; |
| pDocPool->StoreSurrogate( rStream, pPattern ); |
| |
| // sal_False, weil ATTR_CONDITIONAL (noch) nicht in Vorlagen: |
| if (pPattern->GetItemSet().GetItemState(ATTR_CONDITIONAL,sal_False,&pItem) == SFX_ITEM_SET) |
| pDocument->SetConditionalUsed( ((const SfxUInt32Item*)pItem)->GetValue() ); |
| |
| if (pPattern->GetItemSet().GetItemState(ATTR_VALIDDATA,sal_False,&pItem) == SFX_ITEM_SET) |
| pDocument->SetValidationUsed( ((const SfxUInt32Item*)pItem)->GetValue() ); |
| } |
| #endif // SC_ROWLIMIT_STREAM_ACCESS |
| } |
| |
| |
| void ScAttrArray::Load( SvStream& /* rStream */ ) |
| { |
| #if SC_ROWLIMIT_STREAM_ACCESS |
| #error address types changed! |
| ScDocumentPool* pDocPool = pDocument->GetPool(); |
| |
| ScReadHeader aHdr( rStream ); |
| |
| sal_uInt16 nNewCount; |
| rStream >> nNewCount; |
| if ( nNewCount > MAXROW+1 ) // wuerde das Array zu gross? |
| { |
| pDocument->SetLostData(); |
| rStream.SetError( SVSTREAM_FILEFORMAT_ERROR ); |
| return; |
| } |
| |
| Reset( pDocument->GetDefPattern(), sal_False ); // loeschen |
| pData = new ScAttrEntry[nNewCount]; // neu anlegen |
| for (SCSIZE i=0; i<nNewCount; i++) |
| { |
| rStream >> pData[i].nRow; |
| |
| sal_uInt16 nWhich = ATTR_PATTERN; |
| const ScPatternAttr* pNewPattern = (const ScPatternAttr*) |
| pDocPool->LoadSurrogate( rStream, nWhich, ATTR_PATTERN ); |
| if (!pNewPattern) |
| { |
| // da is was schiefgelaufen |
| DBG_ERROR("ScAttrArray::Load: Surrogat nicht im Pool"); |
| pNewPattern = pDocument->GetDefPattern(); |
| } |
| ScDocumentPool::CheckRef( *pNewPattern ); |
| pData[i].pPattern = pNewPattern; |
| |
| // LoadSurrogate erhoeht auch die Ref |
| } |
| nCount = nLimit = nNewCount; |
| |
| if ( nCount > 1 && pData[nCount-2].nRow >= MAXROW ) // faengt ein Attribut hinter MAXROW an? |
| { |
| pDocument->SetLostData(); |
| rStream.SetError( SVSTREAM_FILEFORMAT_ERROR ); |
| return; |
| } |
| |
| if ( pDocument->GetSrcMaxRow() != MAXROW ) // Ende anpassen? |
| { |
| // Ende immer auf MAXROW umsetzen (nur auf 32 Bit) |
| |
| DBG_ASSERT( pData[nCount-1].nRow == pDocument->GetSrcMaxRow(), "Attribut-Ende ?!?" ); |
| pData[nCount-1].nRow = MAXROW; |
| } |
| #endif // SC_ROWLIMIT_STREAM_ACCESS |
| } |
| #endif |
| |
| |
| //UNUSED2008-05 void ScAttrArray::ConvertFontsAfterLoad() |
| //UNUSED2008-05 { |
| //UNUSED2008-05 ScFontToSubsFontConverter_AutoPtr xFontConverter; |
| //UNUSED2008-05 const sal_uLong nFlags = FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS; |
| //UNUSED2008-05 SCSIZE nIndex = 0; |
| //UNUSED2008-05 SCROW nThisRow = 0; |
| //UNUSED2008-05 |
| //UNUSED2008-05 while ( nThisRow <= MAXROW ) |
| //UNUSED2008-05 { |
| //UNUSED2008-05 const ScPatternAttr* pOldPattern = pData[nIndex].pPattern; |
| //UNUSED2008-05 const SfxPoolItem* pItem; |
| //UNUSED2008-05 if( pOldPattern->GetItemSet().GetItemState( ATTR_FONT, sal_False, &pItem ) == SFX_ITEM_SET ) |
| //UNUSED2008-05 { |
| //UNUSED2008-05 const SvxFontItem* pFontItem = (const SvxFontItem*) pItem; |
| //UNUSED2008-05 const String& rOldName = pFontItem->GetFamilyName(); |
| //UNUSED2008-05 xFontConverter = CreateFontToSubsFontConverter( rOldName, nFlags ); |
| //UNUSED2008-05 if ( xFontConverter ) |
| //UNUSED2008-05 { |
| //UNUSED2008-05 String aNewName( GetFontToSubsFontName( xFontConverter ) ); |
| //UNUSED2008-05 if ( aNewName != rOldName ) |
| //UNUSED2008-05 { |
| //UNUSED2008-05 SCROW nAttrRow = pData[nIndex].nRow; |
| //UNUSED2008-05 SvxFontItem aNewItem( pFontItem->GetFamily(), aNewName, |
| //UNUSED2008-05 pFontItem->GetStyleName(), pFontItem->GetPitch(), |
| //UNUSED2008-05 RTL_TEXTENCODING_DONTKNOW, ATTR_FONT ); |
| //UNUSED2008-05 ScPatternAttr aNewPattern( *pOldPattern ); |
| //UNUSED2008-05 aNewPattern.GetItemSet().Put( aNewItem ); |
| //UNUSED2008-05 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True ); |
| //UNUSED2008-05 Search( nThisRow, nIndex ); //! data changed |
| //UNUSED2008-05 } |
| //UNUSED2008-05 } |
| //UNUSED2008-05 } |
| //UNUSED2008-05 ++nIndex; |
| //UNUSED2008-05 nThisRow = pData[nIndex-1].nRow+1; |
| //UNUSED2008-05 } |
| //UNUSED2008-05 } |
| |
| SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW nEndRow ) |
| { |
| SCSIZE nIndex1, nIndex2; |
| |
| if( !Search( nStartRow, nIndex1 ) ) |
| return 0; |
| |
| if( !Search( nEndRow, nIndex2 ) ) |
| nIndex2 = this->nCount - 1; |
| |
| return nIndex2 - nIndex1 + 1; |
| } |