/************************************************************** * * 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" //------------------------------------------------------------------------ #define SC_RANGELST_CXX //fuer ICC #include #include // qsort #include #include "rangelst.hxx" #include "document.hxx" #include "refupdat.hxx" #include "rechead.hxx" #include "compiler.hxx" // === ScRangeList ==================================================== ScRangeList::~ScRangeList() { for ( ScRangePtr pR = First(); pR; pR = Next() ) delete pR; } void ScRangeList::RemoveAll() { for ( ScRangePtr pR = First(); pR; pR = Next() ) delete pR; Clear(); } sal_uInt16 ScRangeList::Parse( const String& rStr, ScDocument* pDoc, sal_uInt16 nMask, formula::FormulaGrammar::AddressConvention eConv, sal_Unicode cDelimiter ) { if ( rStr.Len() ) { if (!cDelimiter) cDelimiter = ScCompiler::GetNativeSymbol(ocSep).GetChar(0); nMask |= SCA_VALID; // falls das jemand vergessen sollte sal_uInt16 nResult = (sal_uInt16)~0; // alle Bits setzen ScRange aRange; String aOne; SCTAB nTab = 0; if ( pDoc ) { //! erste markierte Tabelle gibts nicht mehr am Dokument //! -> uebergeben? oder spaeter an den Ranges setzen } else nTab = 0; sal_uInt16 nTCount = rStr.GetTokenCount( cDelimiter ); for ( sal_uInt16 i=0; iFormat( aStr, nFlags, pDoc, eConv ); if ( nIdx ) rStr += cDelimiter; rStr += aStr; } } void ScRangeList::Join( const ScRange& r, sal_Bool bIsInList ) { if ( !Count() ) { Append( r ); return ; } SCCOL nCol1 = r.aStart.Col(); SCROW nRow1 = r.aStart.Row(); SCTAB nTab1 = r.aStart.Tab(); SCCOL nCol2 = r.aEnd.Col(); SCROW nRow2 = r.aEnd.Row(); SCTAB nTab2 = r.aEnd.Tab(); ScRangePtr pOver = (ScRangePtr) &r; // fies aber wahr wenn bInList sal_uLong nOldPos = 0; if ( bIsInList ) { // merken um ggbf. zu loeschen bzw. wiederherzustellen nOldPos = GetPos( pOver ); } sal_Bool bJoinedInput = sal_False; for ( ScRangePtr p = First(); p && pOver; p = Next() ) { if ( p == pOver ) continue; // derselbe, weiter mit dem naechsten sal_Bool bJoined = sal_False; if ( p->In( r ) ) { // Range r in Range p enthalten oder identisch if ( bIsInList ) bJoined = sal_True; // weg mit Range r else { // das war's dann bJoinedInput = sal_True; // nicht anhaengen break; // for } } else if ( r.In( *p ) ) { // Range p in Range r enthalten, r zum neuen Range machen *p = r; bJoined = sal_True; } if ( !bJoined && p->aStart.Tab() == nTab1 && p->aEnd.Tab() == nTab2 ) { // 2D if ( p->aStart.Col() == nCol1 && p->aEnd.Col() == nCol2 ) { if ( p->aStart.Row() == nRow2+1 ) { // oben p->aStart.SetRow( nRow1 ); bJoined = sal_True; } else if ( p->aEnd.Row() == nRow1-1 ) { // unten p->aEnd.SetRow( nRow2 ); bJoined = sal_True; } } else if ( p->aStart.Row() == nRow1 && p->aEnd.Row() == nRow2 ) { if ( p->aStart.Col() == nCol2+1 ) { // links p->aStart.SetCol( nCol1 ); bJoined = sal_True; } else if ( p->aEnd.Col() == nCol1-1 ) { // rechts p->aEnd.SetCol( nCol2 ); bJoined = sal_True; } } } if ( bJoined ) { if ( bIsInList ) { // innerhalb der Liste Range loeschen Remove( nOldPos ); delete pOver; pOver = NULL; if ( nOldPos ) nOldPos--; // Seek richtig aufsetzen } bJoinedInput = sal_True; Join( *p, sal_True ); // rekursiv! } } if ( bIsInList ) Seek( nOldPos ); else if ( !bJoinedInput ) Append( r ); } sal_Bool ScRangeList::operator==( const ScRangeList& r ) const { if ( this == &r ) return sal_True; // identische Referenz if ( Count() != r.Count() ) return sal_False; sal_uLong nCnt = Count(); for ( sal_uLong nIdx = 0; nIdx < nCnt; nIdx++ ) { if ( *GetObject( nIdx ) != *r.GetObject( nIdx ) ) return sal_False; // auch andere Reihenfolge ist ungleich } return sal_True; } sal_Bool ScRangeList::operator!=( const ScRangeList& r ) const { return !operator==( r ); } sal_Bool ScRangeList::UpdateReference( UpdateRefMode eUpdateRefMode, ScDocument* pDoc, const ScRange& rWhere, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) { sal_Bool bChanged = sal_False; if ( Count() ) { SCCOL nCol1; SCROW nRow1; SCTAB nTab1; SCCOL nCol2; SCROW nRow2; SCTAB nTab2; rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); for ( ScRange* pR = First(); pR; pR = Next() ) { SCCOL theCol1; SCROW theRow1; SCTAB theTab1; SCCOL theCol2; SCROW theRow2; SCTAB theTab2; pR->GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 ); if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz, theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 ) != UR_NOTHING ) { bChanged = sal_True; pR->aStart.Set( theCol1, theRow1, theTab1 ); pR->aEnd.Set( theCol2, theRow2, theTab2 ); } } } return bChanged; } ScRange* ScRangeList::Find( const ScAddress& rAdr ) const { sal_uLong nListCount = Count(); for ( sal_uLong j = 0; j < nListCount; j++ ) { ScRange* pR = GetObject( j ); if ( pR->In( rAdr ) ) return pR; } return NULL; } ScRangeList::ScRangeList( const ScRangeList& rList ) : ScRangeListBase(), SvRefBase() { sal_uLong nListCount = rList.Count(); for ( sal_uLong j = 0; j < nListCount; j++ ) Append( *rList.GetObject( j ) ); } ScRangeList& ScRangeList::operator=(const ScRangeList& rList) { RemoveAll(); sal_uLong nListCount = rList.Count(); for ( sal_uLong j = 0; j < nListCount; j++ ) Append( *rList.GetObject( j ) ); return *this; } sal_Bool ScRangeList::Intersects( const ScRange& rRange ) const { sal_uLong nListCount = Count(); for ( sal_uLong j = 0; j < nListCount; j++ ) if ( GetObject(j)->Intersects( rRange ) ) return sal_True; return sal_False; } sal_Bool ScRangeList::In( const ScRange& rRange ) const { sal_uLong nListCount = Count(); for ( sal_uLong j = 0; j < nListCount; j++ ) if ( GetObject(j)->In( rRange ) ) return sal_True; return sal_False; } sal_uLong ScRangeList::GetCellCount() const { sal_uLong nCellCount = 0; sal_uLong nListCount = Count(); for ( sal_uLong j = 0; j < nListCount; j++ ) { ScRange* pR = GetObject( j ); nCellCount += sal_uLong(pR->aEnd.Col() - pR->aStart.Col() + 1) * sal_uLong(pR->aEnd.Row() - pR->aStart.Row() + 1) * sal_uLong(pR->aEnd.Tab() - pR->aStart.Tab() + 1); } return nCellCount; } // === ScRangePairList ==================================================== ScRangePairList::~ScRangePairList() { for ( ScRangePair* pR = First(); pR; pR = Next() ) delete pR; } void ScRangePairList::Join( const ScRangePair& r, sal_Bool bIsInList ) { if ( !Count() ) { Append( r ); return ; } const ScRange& r1 = r.GetRange(0); const ScRange& r2 = r.GetRange(1); SCCOL nCol1 = r1.aStart.Col(); SCROW nRow1 = r1.aStart.Row(); SCTAB nTab1 = r1.aStart.Tab(); SCCOL nCol2 = r1.aEnd.Col(); SCROW nRow2 = r1.aEnd.Row(); SCTAB nTab2 = r1.aEnd.Tab(); ScRangePair* pOver = (ScRangePair*) &r; // fies aber wahr wenn bInList sal_uLong nOldPos = 0; if ( bIsInList ) { // merken um ggbf. zu loeschen bzw. wiederherzustellen nOldPos = GetPos( pOver ); } sal_Bool bJoinedInput = sal_False; for ( ScRangePair* p = First(); p && pOver; p = Next() ) { if ( p == pOver ) continue; // derselbe, weiter mit dem naechsten sal_Bool bJoined = sal_False; ScRange& rp1 = p->GetRange(0); ScRange& rp2 = p->GetRange(1); if ( rp2 == r2 ) { // nur wenn Range2 gleich ist if ( rp1.In( r1 ) ) { // RangePair r in RangePair p enthalten oder identisch if ( bIsInList ) bJoined = sal_True; // weg mit RangePair r else { // das war's dann bJoinedInput = sal_True; // nicht anhaengen break; // for } } else if ( r1.In( rp1 ) ) { // RangePair p in RangePair r enthalten, r zum neuen RangePair machen *p = r; bJoined = sal_True; } } if ( !bJoined && rp1.aStart.Tab() == nTab1 && rp1.aEnd.Tab() == nTab2 && rp2.aStart.Tab() == r2.aStart.Tab() && rp2.aEnd.Tab() == r2.aEnd.Tab() ) { // 2D, Range2 muss genauso nebeneinander liegen wie Range1 if ( rp1.aStart.Col() == nCol1 && rp1.aEnd.Col() == nCol2 && rp2.aStart.Col() == r2.aStart.Col() && rp2.aEnd.Col() == r2.aEnd.Col() ) { if ( rp1.aStart.Row() == nRow2+1 && rp2.aStart.Row() == r2.aEnd.Row()+1 ) { // oben rp1.aStart.SetRow( nRow1 ); rp2.aStart.SetRow( r2.aStart.Row() ); bJoined = sal_True; } else if ( rp1.aEnd.Row() == nRow1-1 && rp2.aEnd.Row() == r2.aStart.Row()-1 ) { // unten rp1.aEnd.SetRow( nRow2 ); rp2.aEnd.SetRow( r2.aEnd.Row() ); bJoined = sal_True; } } else if ( rp1.aStart.Row() == nRow1 && rp1.aEnd.Row() == nRow2 && rp2.aStart.Row() == r2.aStart.Row() && rp2.aEnd.Row() == r2.aEnd.Row() ) { if ( rp1.aStart.Col() == nCol2+1 && rp2.aStart.Col() == r2.aEnd.Col()+1 ) { // links rp1.aStart.SetCol( nCol1 ); rp2.aStart.SetCol( r2.aStart.Col() ); bJoined = sal_True; } else if ( rp1.aEnd.Col() == nCol1-1 && rp2.aEnd.Col() == r2.aEnd.Col()-1 ) { // rechts rp1.aEnd.SetCol( nCol2 ); rp2.aEnd.SetCol( r2.aEnd.Col() ); bJoined = sal_True; } } } if ( bJoined ) { if ( bIsInList ) { // innerhalb der Liste RangePair loeschen Remove( nOldPos ); delete pOver; pOver = NULL; if ( nOldPos ) nOldPos--; // Seek richtig aufsetzen } bJoinedInput = sal_True; Join( *p, sal_True ); // rekursiv! } } if ( bIsInList ) Seek( nOldPos ); else if ( !bJoinedInput ) Append( r ); } sal_Bool ScRangePairList::operator==( const ScRangePairList& r ) const { if ( this == &r ) return sal_True; // identische Referenz if ( Count() != r.Count() ) return sal_False; sal_uLong nCnt = Count(); for ( sal_uLong nIdx = 0; nIdx < nCnt; nIdx++ ) { if ( *GetObject( nIdx ) != *r.GetObject( nIdx ) ) return sal_False; // auch andere Reihenfolge ist ungleich } return sal_True; } sal_Bool ScRangePairList::UpdateReference( UpdateRefMode eUpdateRefMode, ScDocument* pDoc, const ScRange& rWhere, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) { sal_Bool bChanged = sal_False; if ( Count() ) { SCCOL nCol1; SCROW nRow1; SCTAB nTab1; SCCOL nCol2; SCROW nRow2; SCTAB nTab2; rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); for ( ScRangePair* pR = First(); pR; pR = Next() ) { for ( sal_uInt16 j=0; j<2; j++ ) { ScRange& rRange = pR->GetRange(j); SCCOL theCol1; SCROW theRow1; SCTAB theTab1; SCCOL theCol2; SCROW theRow2; SCTAB theTab2; rRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 ); if ( ScRefUpdate::Update( pDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz, theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 ) != UR_NOTHING ) { bChanged = sal_True; rRange.aStart.Set( theCol1, theRow1, theTab1 ); rRange.aEnd.Set( theCol2, theRow2, theTab2 ); } } } } return bChanged; } void ScRangePairList::DeleteOnTab( SCTAB nTab ) { // Delete entries that have the labels (first range) on nTab sal_uLong nListCount = Count(); sal_uLong nPos = 0; while ( nPos < nListCount ) { ScRangePair* pR = GetObject( nPos ); ScRange aRange = pR->GetRange(0); if ( aRange.aStart.Tab() == nTab && aRange.aEnd.Tab() == nTab ) { Remove( nPos ); delete pR; nListCount = Count(); } else ++nPos; } } ScRangePair* ScRangePairList::Find( const ScAddress& rAdr ) const { sal_uLong nListCount = Count(); for ( sal_uLong j = 0; j < nListCount; j++ ) { ScRangePair* pR = GetObject( j ); if ( pR->GetRange(0).In( rAdr ) ) return pR; } return NULL; } ScRangePair* ScRangePairList::Find( const ScRange& rRange ) const { sal_uLong nListCount = Count(); for ( sal_uLong j = 0; j < nListCount; j++ ) { ScRangePair* pR = GetObject( j ); if ( pR->GetRange(0) == rRange ) return pR; } return NULL; } ScRangePairList* ScRangePairList::Clone() const { ScRangePairList* pNew = new ScRangePairList; sal_uLong nListCount = Count(); for ( sal_uLong j = 0; j < nListCount; j++ ) { pNew->Append( *GetObject( j ) ); } return pNew; } struct ScRangePairNameSort { ScRangePair* pPair; ScDocument* pDoc; }; extern "C" int #ifdef WNT __cdecl #endif ScRangePairList_QsortNameCompare( const void* p1, const void* p2 ) { const ScRangePairNameSort* ps1 = (const ScRangePairNameSort*)p1; const ScRangePairNameSort* ps2 = (const ScRangePairNameSort*)p2; const ScAddress& rStartPos1 = ps1->pPair->GetRange(0).aStart; const ScAddress& rStartPos2 = ps2->pPair->GetRange(0).aStart; String aStr1, aStr2; sal_Int32 nComp; if ( rStartPos1.Tab() == rStartPos2.Tab() ) nComp = COMPARE_EQUAL; else { ps1->pDoc->GetName( rStartPos1.Tab(), aStr1 ); ps2->pDoc->GetName( rStartPos2.Tab(), aStr2 ); nComp = ScGlobal::GetCollator()->compareString( aStr1, aStr2 ); } switch ( nComp ) { case COMPARE_LESS: return -1; case COMPARE_GREATER: return 1; default: // gleiche Tabs if ( rStartPos1.Col() < rStartPos2.Col() ) return -1; if ( rStartPos1.Col() > rStartPos2.Col() ) return 1; // gleiche Cols if ( rStartPos1.Row() < rStartPos2.Row() ) return -1; if ( rStartPos1.Row() > rStartPos2.Row() ) return 1; // erste Ecke gleich, zweite Ecke { const ScAddress& rEndPos1 = ps1->pPair->GetRange(0).aEnd; const ScAddress& rEndPos2 = ps2->pPair->GetRange(0).aEnd; if ( rEndPos1.Tab() == rEndPos2.Tab() ) nComp = COMPARE_EQUAL; else { ps1->pDoc->GetName( rEndPos1.Tab(), aStr1 ); ps2->pDoc->GetName( rEndPos2.Tab(), aStr2 ); nComp = ScGlobal::GetCollator()->compareString( aStr1, aStr2 ); } switch ( nComp ) { case COMPARE_LESS: return -1; case COMPARE_GREATER: return 1; default: // gleiche Tabs if ( rEndPos1.Col() < rEndPos2.Col() ) return -1; if ( rEndPos1.Col() > rEndPos2.Col() ) return 1; // gleiche Cols if ( rEndPos1.Row() < rEndPos2.Row() ) return -1; if ( rEndPos1.Row() > rEndPos2.Row() ) return 1; return 0; } } } } ScRangePair** ScRangePairList::CreateNameSortedArray( sal_uLong& nListCount, ScDocument* pDoc ) const { nListCount = Count(); DBG_ASSERT( nListCount * sizeof(ScRangePairNameSort) <= (size_t)~0x1F, "ScRangePairList::CreateNameSortedArray nListCount * sizeof(ScRangePairNameSort) > (size_t)~0x1F" ); ScRangePairNameSort* pSortArray = (ScRangePairNameSort*) new sal_uInt8 [ nListCount * sizeof(ScRangePairNameSort) ]; sal_uLong j; for ( j=0; j < nListCount; j++ ) { pSortArray[j].pPair = GetObject( j ); pSortArray[j].pDoc = pDoc; } #if !(defined(ICC ) && defined(OS2)) qsort( (void*)pSortArray, nListCount, sizeof(ScRangePairNameSort), &ScRangePairList_QsortNameCompare ); #else qsort( (void*)pSortArray, nListCount, sizeof(ScRangePairNameSort), ICCQsortRPairCompare ); #endif // ScRangePair Pointer aufruecken ScRangePair** ppSortArray = (ScRangePair**)pSortArray; for ( j=0; j < nListCount; j++ ) { ppSortArray[j] = pSortArray[j].pPair; } return ppSortArray; }