update dev300-m57
[ooovba.git] / sc / source / core / tool / rangelst.cxx
blobd1bca458d5da8622129ae9d6ca95e88bab6a030e
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: rangelst.cxx,v $
10 * $Revision: 1.11.32.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
35 //------------------------------------------------------------------------
37 #define SC_RANGELST_CXX //fuer ICC
39 #include <tools/debug.hxx>
40 #include <stdlib.h> // qsort
41 #include <unotools/collatorwrapper.hxx>
43 #include "rangelst.hxx"
44 #include "document.hxx"
45 #include "refupdat.hxx"
46 #include "rechead.hxx"
49 // === ScRangeList ====================================================
51 ScRangeList::~ScRangeList()
53 for ( ScRangePtr pR = First(); pR; pR = Next() )
54 delete pR;
57 void ScRangeList::RemoveAll()
59 for ( ScRangePtr pR = First(); pR; pR = Next() )
60 delete pR;
61 Clear();
64 static void defaultDelimiter( char& cDelimiter, formula::FormulaGrammar::AddressConvention eConv)
66 if( cDelimiter == 0)
68 switch( eConv )
70 default :
71 case formula::FormulaGrammar::CONV_OOO :
72 cDelimiter = ';';
73 break;
75 case formula::FormulaGrammar::CONV_XL_A1 :
76 case formula::FormulaGrammar::CONV_XL_R1C1 :
77 cDelimiter = ',';
78 break;
83 USHORT ScRangeList::Parse( const String& rStr, ScDocument* pDoc, USHORT nMask,
84 formula::FormulaGrammar::AddressConvention eConv,
85 char cDelimiter )
87 if ( rStr.Len() )
89 defaultDelimiter( cDelimiter, eConv);
91 nMask |= SCA_VALID; // falls das jemand vergessen sollte
92 USHORT nResult = (USHORT)~0; // alle Bits setzen
93 ScRange aRange;
94 String aOne;
95 SCTAB nTab = 0;
96 if ( pDoc )
98 //! erste markierte Tabelle gibts nicht mehr am Dokument
99 //! -> uebergeben? oder spaeter an den Ranges setzen
101 else
102 nTab = 0;
103 USHORT nTCount = rStr.GetTokenCount( cDelimiter );
104 for ( USHORT i=0; i<nTCount; i++ )
106 aOne = rStr.GetToken( i, cDelimiter );
107 aRange.aStart.SetTab( nTab ); // Default Tab wenn nicht angegeben
108 USHORT nRes = aRange.ParseAny( aOne, pDoc, eConv );
109 USHORT nEndRangeBits = SCA_VALID_COL2 | SCA_VALID_ROW2 |
110 SCA_VALID_TAB2;
111 USHORT nTmp1 = ( nRes & SCA_BITS );
112 USHORT nTmp2 = ( nRes & nEndRangeBits );
113 // If we have a valid single range with
114 // any of the address bits we are interested in
115 // set - set the equiv end range bits
116 if ( (nRes & SCA_VALID ) && nTmp1 && ( nTmp2 != nEndRangeBits ) )
117 nRes |= ( nTmp1 << 4 );
119 if ( (nRes & nMask) == nMask )
120 Append( aRange );
121 nResult &= nRes; // alle gemeinsamen Bits bleiben erhalten
123 return nResult; // SCA_VALID gesetzt wenn alle ok
125 else
126 return 0;
130 void ScRangeList::Format( String& rStr, USHORT nFlags, ScDocument* pDoc,
131 formula::FormulaGrammar::AddressConvention eConv,
132 char cDelimiter ) const
134 rStr.Erase();
136 defaultDelimiter( cDelimiter, eConv);
138 ULONG nCnt = Count();
139 for ( ULONG nIdx = 0; nIdx < nCnt; nIdx++ )
141 String aStr;
142 GetObject( nIdx )->Format( aStr, nFlags, pDoc, eConv );
143 if ( nIdx )
144 rStr += cDelimiter;
145 rStr += aStr;
150 void ScRangeList::Join( const ScRange& r, BOOL bIsInList )
152 if ( !Count() )
154 Append( r );
155 return ;
157 SCCOL nCol1 = r.aStart.Col();
158 SCROW nRow1 = r.aStart.Row();
159 SCTAB nTab1 = r.aStart.Tab();
160 SCCOL nCol2 = r.aEnd.Col();
161 SCROW nRow2 = r.aEnd.Row();
162 SCTAB nTab2 = r.aEnd.Tab();
163 ScRangePtr pOver = (ScRangePtr) &r; // fies aber wahr wenn bInList
164 ULONG nOldPos = 0;
165 if ( bIsInList )
166 { // merken um ggbf. zu loeschen bzw. wiederherzustellen
167 nOldPos = GetPos( pOver );
169 BOOL bJoinedInput = FALSE;
170 for ( ScRangePtr p = First(); p && pOver; p = Next() )
172 if ( p == pOver )
173 continue; // derselbe, weiter mit dem naechsten
174 BOOL bJoined = FALSE;
175 if ( p->In( r ) )
176 { // Range r in Range p enthalten oder identisch
177 if ( bIsInList )
178 bJoined = TRUE; // weg mit Range r
179 else
180 { // das war's dann
181 bJoinedInput = TRUE; // nicht anhaengen
182 break; // for
185 else if ( r.In( *p ) )
186 { // Range p in Range r enthalten, r zum neuen Range machen
187 *p = r;
188 bJoined = TRUE;
190 if ( !bJoined && p->aStart.Tab() == nTab1 && p->aEnd.Tab() == nTab2 )
191 { // 2D
192 if ( p->aStart.Col() == nCol1 && p->aEnd.Col() == nCol2 )
194 if ( p->aStart.Row() == nRow2+1 )
195 { // oben
196 p->aStart.SetRow( nRow1 );
197 bJoined = TRUE;
199 else if ( p->aEnd.Row() == nRow1-1 )
200 { // unten
201 p->aEnd.SetRow( nRow2 );
202 bJoined = TRUE;
205 else if ( p->aStart.Row() == nRow1 && p->aEnd.Row() == nRow2 )
207 if ( p->aStart.Col() == nCol2+1 )
208 { // links
209 p->aStart.SetCol( nCol1 );
210 bJoined = TRUE;
212 else if ( p->aEnd.Col() == nCol1-1 )
213 { // rechts
214 p->aEnd.SetCol( nCol2 );
215 bJoined = TRUE;
219 if ( bJoined )
221 if ( bIsInList )
222 { // innerhalb der Liste Range loeschen
223 Remove( nOldPos );
224 delete pOver;
225 pOver = NULL;
226 if ( nOldPos )
227 nOldPos--; // Seek richtig aufsetzen
229 bJoinedInput = TRUE;
230 Join( *p, TRUE ); // rekursiv!
233 if ( bIsInList )
234 Seek( nOldPos );
235 else if ( !bJoinedInput )
236 Append( r );
240 BOOL ScRangeList::operator==( const ScRangeList& r ) const
242 if ( this == &r )
243 return TRUE; // identische Referenz
244 if ( Count() != r.Count() )
245 return FALSE;
246 ULONG nCnt = Count();
247 for ( ULONG nIdx = 0; nIdx < nCnt; nIdx++ )
249 if ( *GetObject( nIdx ) != *r.GetObject( nIdx ) )
250 return FALSE; // auch andere Reihenfolge ist ungleich
252 return TRUE;
255 BOOL ScRangeList::UpdateReference( UpdateRefMode eUpdateRefMode,
256 ScDocument* pDoc, const ScRange& rWhere,
257 SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
259 BOOL bChanged = FALSE;
260 if ( Count() )
262 SCCOL nCol1;
263 SCROW nRow1;
264 SCTAB nTab1;
265 SCCOL nCol2;
266 SCROW nRow2;
267 SCTAB nTab2;
268 rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
269 for ( ScRange* pR = First(); pR; pR = Next() )
271 SCCOL theCol1;
272 SCROW theRow1;
273 SCTAB theTab1;
274 SCCOL theCol2;
275 SCROW theRow2;
276 SCTAB theTab2;
277 pR->GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 );
278 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
279 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
280 nDx, nDy, nDz,
281 theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 )
282 != UR_NOTHING )
284 bChanged = TRUE;
285 pR->aStart.Set( theCol1, theRow1, theTab1 );
286 pR->aEnd.Set( theCol2, theRow2, theTab2 );
290 return bChanged;
294 ScRange* ScRangeList::Find( const ScAddress& rAdr ) const
296 ULONG nListCount = Count();
297 for ( ULONG j = 0; j < nListCount; j++ )
299 ScRange* pR = GetObject( j );
300 if ( pR->In( rAdr ) )
301 return pR;
303 return NULL;
307 ScRangeList::ScRangeList( const ScRangeList& rList ) :
308 ScRangeListBase(),
309 SvRefBase()
311 ULONG nListCount = rList.Count();
312 for ( ULONG j = 0; j < nListCount; j++ )
313 Append( *rList.GetObject( j ) );
317 ScRangeList& ScRangeList::operator=(const ScRangeList& rList)
319 RemoveAll();
321 ULONG nListCount = rList.Count();
322 for ( ULONG j = 0; j < nListCount; j++ )
323 Append( *rList.GetObject( j ) );
325 return *this;
329 BOOL ScRangeList::Intersects( const ScRange& rRange ) const
331 ULONG nListCount = Count();
332 for ( ULONG j = 0; j < nListCount; j++ )
333 if ( GetObject(j)->Intersects( rRange ) )
334 return TRUE;
336 return FALSE;
340 BOOL ScRangeList::In( const ScRange& rRange ) const
342 ULONG nListCount = Count();
343 for ( ULONG j = 0; j < nListCount; j++ )
344 if ( GetObject(j)->In( rRange ) )
345 return TRUE;
347 return FALSE;
351 ULONG ScRangeList::GetCellCount() const
353 ULONG nCellCount = 0;
354 ULONG nListCount = Count();
355 for ( ULONG j = 0; j < nListCount; j++ )
357 ScRange* pR = GetObject( j );
358 nCellCount += ULONG(pR->aEnd.Col() - pR->aStart.Col() + 1)
359 * ULONG(pR->aEnd.Row() - pR->aStart.Row() + 1)
360 * ULONG(pR->aEnd.Tab() - pR->aStart.Tab() + 1);
362 return nCellCount;
366 // === ScRangePairList ====================================================
368 ScRangePairList::~ScRangePairList()
370 for ( ScRangePair* pR = First(); pR; pR = Next() )
371 delete pR;
375 void ScRangePairList::Join( const ScRangePair& r, BOOL bIsInList )
377 if ( !Count() )
379 Append( r );
380 return ;
382 const ScRange& r1 = r.GetRange(0);
383 const ScRange& r2 = r.GetRange(1);
384 SCCOL nCol1 = r1.aStart.Col();
385 SCROW nRow1 = r1.aStart.Row();
386 SCTAB nTab1 = r1.aStart.Tab();
387 SCCOL nCol2 = r1.aEnd.Col();
388 SCROW nRow2 = r1.aEnd.Row();
389 SCTAB nTab2 = r1.aEnd.Tab();
390 ScRangePair* pOver = (ScRangePair*) &r; // fies aber wahr wenn bInList
391 ULONG nOldPos = 0;
392 if ( bIsInList )
393 { // merken um ggbf. zu loeschen bzw. wiederherzustellen
394 nOldPos = GetPos( pOver );
396 BOOL bJoinedInput = FALSE;
397 for ( ScRangePair* p = First(); p && pOver; p = Next() )
399 if ( p == pOver )
400 continue; // derselbe, weiter mit dem naechsten
401 BOOL bJoined = FALSE;
402 ScRange& rp1 = p->GetRange(0);
403 ScRange& rp2 = p->GetRange(1);
404 if ( rp2 == r2 )
405 { // nur wenn Range2 gleich ist
406 if ( rp1.In( r1 ) )
407 { // RangePair r in RangePair p enthalten oder identisch
408 if ( bIsInList )
409 bJoined = TRUE; // weg mit RangePair r
410 else
411 { // das war's dann
412 bJoinedInput = TRUE; // nicht anhaengen
413 break; // for
416 else if ( r1.In( rp1 ) )
417 { // RangePair p in RangePair r enthalten, r zum neuen RangePair machen
418 *p = r;
419 bJoined = TRUE;
422 if ( !bJoined && rp1.aStart.Tab() == nTab1 && rp1.aEnd.Tab() == nTab2
423 && rp2.aStart.Tab() == r2.aStart.Tab()
424 && rp2.aEnd.Tab() == r2.aEnd.Tab() )
425 { // 2D, Range2 muss genauso nebeneinander liegen wie Range1
426 if ( rp1.aStart.Col() == nCol1 && rp1.aEnd.Col() == nCol2
427 && rp2.aStart.Col() == r2.aStart.Col()
428 && rp2.aEnd.Col() == r2.aEnd.Col() )
430 if ( rp1.aStart.Row() == nRow2+1
431 && rp2.aStart.Row() == r2.aEnd.Row()+1 )
432 { // oben
433 rp1.aStart.SetRow( nRow1 );
434 rp2.aStart.SetRow( r2.aStart.Row() );
435 bJoined = TRUE;
437 else if ( rp1.aEnd.Row() == nRow1-1
438 && rp2.aEnd.Row() == r2.aStart.Row()-1 )
439 { // unten
440 rp1.aEnd.SetRow( nRow2 );
441 rp2.aEnd.SetRow( r2.aEnd.Row() );
442 bJoined = TRUE;
445 else if ( rp1.aStart.Row() == nRow1 && rp1.aEnd.Row() == nRow2
446 && rp2.aStart.Row() == r2.aStart.Row()
447 && rp2.aEnd.Row() == r2.aEnd.Row() )
449 if ( rp1.aStart.Col() == nCol2+1
450 && rp2.aStart.Col() == r2.aEnd.Col()+1 )
451 { // links
452 rp1.aStart.SetCol( nCol1 );
453 rp2.aStart.SetCol( r2.aStart.Col() );
454 bJoined = TRUE;
456 else if ( rp1.aEnd.Col() == nCol1-1
457 && rp2.aEnd.Col() == r2.aEnd.Col()-1 )
458 { // rechts
459 rp1.aEnd.SetCol( nCol2 );
460 rp2.aEnd.SetCol( r2.aEnd.Col() );
461 bJoined = TRUE;
465 if ( bJoined )
467 if ( bIsInList )
468 { // innerhalb der Liste RangePair loeschen
469 Remove( nOldPos );
470 delete pOver;
471 pOver = NULL;
472 if ( nOldPos )
473 nOldPos--; // Seek richtig aufsetzen
475 bJoinedInput = TRUE;
476 Join( *p, TRUE ); // rekursiv!
479 if ( bIsInList )
480 Seek( nOldPos );
481 else if ( !bJoinedInput )
482 Append( r );
486 BOOL ScRangePairList::operator==( const ScRangePairList& r ) const
488 if ( this == &r )
489 return TRUE; // identische Referenz
490 if ( Count() != r.Count() )
491 return FALSE;
492 ULONG nCnt = Count();
493 for ( ULONG nIdx = 0; nIdx < nCnt; nIdx++ )
495 if ( *GetObject( nIdx ) != *r.GetObject( nIdx ) )
496 return FALSE; // auch andere Reihenfolge ist ungleich
498 return TRUE;
502 BOOL ScRangePairList::UpdateReference( UpdateRefMode eUpdateRefMode,
503 ScDocument* pDoc, const ScRange& rWhere,
504 SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
506 BOOL bChanged = FALSE;
507 if ( Count() )
509 SCCOL nCol1;
510 SCROW nRow1;
511 SCTAB nTab1;
512 SCCOL nCol2;
513 SCROW nRow2;
514 SCTAB nTab2;
515 rWhere.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
516 for ( ScRangePair* pR = First(); pR; pR = Next() )
518 for ( USHORT j=0; j<2; j++ )
520 ScRange& rRange = pR->GetRange(j);
521 SCCOL theCol1;
522 SCROW theRow1;
523 SCTAB theTab1;
524 SCCOL theCol2;
525 SCROW theRow2;
526 SCTAB theTab2;
527 rRange.GetVars( theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 );
528 if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
529 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
530 nDx, nDy, nDz,
531 theCol1, theRow1, theTab1, theCol2, theRow2, theTab2 )
532 != UR_NOTHING )
534 bChanged = TRUE;
535 rRange.aStart.Set( theCol1, theRow1, theTab1 );
536 rRange.aEnd.Set( theCol2, theRow2, theTab2 );
541 return bChanged;
545 void ScRangePairList::DeleteOnTab( SCTAB nTab )
547 // Delete entries that have the labels (first range) on nTab
549 ULONG nListCount = Count();
550 ULONG nPos = 0;
551 while ( nPos < nListCount )
553 ScRangePair* pR = GetObject( nPos );
554 ScRange aRange = pR->GetRange(0);
555 if ( aRange.aStart.Tab() == nTab && aRange.aEnd.Tab() == nTab )
557 Remove( nPos );
558 delete pR;
559 nListCount = Count();
561 else
562 ++nPos;
567 ScRangePair* ScRangePairList::Find( const ScAddress& rAdr ) const
569 ULONG nListCount = Count();
570 for ( ULONG j = 0; j < nListCount; j++ )
572 ScRangePair* pR = GetObject( j );
573 if ( pR->GetRange(0).In( rAdr ) )
574 return pR;
576 return NULL;
580 ScRangePair* ScRangePairList::Find( const ScRange& rRange ) const
582 ULONG nListCount = Count();
583 for ( ULONG j = 0; j < nListCount; j++ )
585 ScRangePair* pR = GetObject( j );
586 if ( pR->GetRange(0) == rRange )
587 return pR;
589 return NULL;
593 ScRangePairList* ScRangePairList::Clone() const
595 ScRangePairList* pNew = new ScRangePairList;
596 ULONG nListCount = Count();
597 for ( ULONG j = 0; j < nListCount; j++ )
599 pNew->Append( *GetObject( j ) );
601 return pNew;
605 struct ScRangePairNameSort
607 ScRangePair* pPair;
608 ScDocument* pDoc;
612 extern "C" int
613 #ifdef WNT
614 __cdecl
615 #endif
616 ScRangePairList_QsortNameCompare( const void* p1, const void* p2 )
618 const ScRangePairNameSort* ps1 = (const ScRangePairNameSort*)p1;
619 const ScRangePairNameSort* ps2 = (const ScRangePairNameSort*)p2;
620 const ScAddress& rStartPos1 = ps1->pPair->GetRange(0).aStart;
621 const ScAddress& rStartPos2 = ps2->pPair->GetRange(0).aStart;
622 String aStr1, aStr2;
623 sal_Int32 nComp;
624 if ( rStartPos1.Tab() == rStartPos2.Tab() )
625 nComp = COMPARE_EQUAL;
626 else
628 ps1->pDoc->GetName( rStartPos1.Tab(), aStr1 );
629 ps2->pDoc->GetName( rStartPos2.Tab(), aStr2 );
630 nComp = ScGlobal::pCollator->compareString( aStr1, aStr2 );
632 switch ( nComp )
634 case COMPARE_LESS:
635 return -1;
636 //break;
637 case COMPARE_GREATER:
638 return 1;
639 //break;
640 default:
641 // gleiche Tabs
642 if ( rStartPos1.Col() < rStartPos2.Col() )
643 return -1;
644 if ( rStartPos1.Col() > rStartPos2.Col() )
645 return 1;
646 // gleiche Cols
647 if ( rStartPos1.Row() < rStartPos2.Row() )
648 return -1;
649 if ( rStartPos1.Row() > rStartPos2.Row() )
650 return 1;
651 // erste Ecke gleich, zweite Ecke
653 const ScAddress& rEndPos1 = ps1->pPair->GetRange(0).aEnd;
654 const ScAddress& rEndPos2 = ps2->pPair->GetRange(0).aEnd;
655 if ( rEndPos1.Tab() == rEndPos2.Tab() )
656 nComp = COMPARE_EQUAL;
657 else
659 ps1->pDoc->GetName( rEndPos1.Tab(), aStr1 );
660 ps2->pDoc->GetName( rEndPos2.Tab(), aStr2 );
661 nComp = ScGlobal::pCollator->compareString( aStr1, aStr2 );
663 switch ( nComp )
665 case COMPARE_LESS:
666 return -1;
667 //break;
668 case COMPARE_GREATER:
669 return 1;
670 //break;
671 default:
672 // gleiche Tabs
673 if ( rEndPos1.Col() < rEndPos2.Col() )
674 return -1;
675 if ( rEndPos1.Col() > rEndPos2.Col() )
676 return 1;
677 // gleiche Cols
678 if ( rEndPos1.Row() < rEndPos2.Row() )
679 return -1;
680 if ( rEndPos1.Row() > rEndPos2.Row() )
681 return 1;
682 return 0;
685 return 0;
687 return 0; // just in case
691 ScRangePair** ScRangePairList::CreateNameSortedArray( ULONG& nListCount,
692 ScDocument* pDoc ) const
694 nListCount = Count();
695 DBG_ASSERT( nListCount * sizeof(ScRangePairNameSort) <= (size_t)~0x1F,
696 "ScRangePairList::CreateNameSortedArray nListCount * sizeof(ScRangePairNameSort) > (size_t)~0x1F" );
697 ScRangePairNameSort* pSortArray = (ScRangePairNameSort*)
698 new BYTE [ nListCount * sizeof(ScRangePairNameSort) ];
699 ULONG j;
700 for ( j=0; j < nListCount; j++ )
702 pSortArray[j].pPair = GetObject( j );
703 pSortArray[j].pDoc = pDoc;
705 #if !(defined(ICC ) && defined(OS2))
706 qsort( (void*)pSortArray, nListCount, sizeof(ScRangePairNameSort), &ScRangePairList_QsortNameCompare );
707 #else
708 qsort( (void*)pSortArray, nListCount, sizeof(ScRangePairNameSort), ICCQsortRPairCompare );
709 #endif
710 // ScRangePair Pointer aufruecken
711 ScRangePair** ppSortArray = (ScRangePair**)pSortArray;
712 for ( j=0; j < nListCount; j++ )
714 ppSortArray[j] = pSortArray[j].pPair;
716 return ppSortArray;