1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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() )
57 void ScRangeList::RemoveAll()
59 for ( ScRangePtr pR
= First(); pR
; pR
= Next() )
64 static void defaultDelimiter( char& cDelimiter
, formula::FormulaGrammar::AddressConvention eConv
)
71 case formula::FormulaGrammar::CONV_OOO
:
75 case formula::FormulaGrammar::CONV_XL_A1
:
76 case formula::FormulaGrammar::CONV_XL_R1C1
:
83 USHORT
ScRangeList::Parse( const String
& rStr
, ScDocument
* pDoc
, USHORT nMask
,
84 formula::FormulaGrammar::AddressConvention eConv
,
89 defaultDelimiter( cDelimiter
, eConv
);
91 nMask
|= SCA_VALID
; // falls das jemand vergessen sollte
92 USHORT nResult
= (USHORT
)~0; // alle Bits setzen
98 //! erste markierte Tabelle gibts nicht mehr am Dokument
99 //! -> uebergeben? oder spaeter an den Ranges setzen
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
|
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
)
121 nResult
&= nRes
; // alle gemeinsamen Bits bleiben erhalten
123 return nResult
; // SCA_VALID gesetzt wenn alle ok
130 void ScRangeList::Format( String
& rStr
, USHORT nFlags
, ScDocument
* pDoc
,
131 formula::FormulaGrammar::AddressConvention eConv
,
132 char cDelimiter
) const
136 defaultDelimiter( cDelimiter
, eConv
);
138 ULONG nCnt
= Count();
139 for ( ULONG nIdx
= 0; nIdx
< nCnt
; nIdx
++ )
142 GetObject( nIdx
)->Format( aStr
, nFlags
, pDoc
, eConv
);
150 void ScRangeList::Join( const ScRange
& r
, BOOL bIsInList
)
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
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() )
173 continue; // derselbe, weiter mit dem naechsten
174 BOOL bJoined
= FALSE
;
176 { // Range r in Range p enthalten oder identisch
178 bJoined
= TRUE
; // weg mit Range r
181 bJoinedInput
= TRUE
; // nicht anhaengen
185 else if ( r
.In( *p
) )
186 { // Range p in Range r enthalten, r zum neuen Range machen
190 if ( !bJoined
&& p
->aStart
.Tab() == nTab1
&& p
->aEnd
.Tab() == nTab2
)
192 if ( p
->aStart
.Col() == nCol1
&& p
->aEnd
.Col() == nCol2
)
194 if ( p
->aStart
.Row() == nRow2
+1 )
196 p
->aStart
.SetRow( nRow1
);
199 else if ( p
->aEnd
.Row() == nRow1
-1 )
201 p
->aEnd
.SetRow( nRow2
);
205 else if ( p
->aStart
.Row() == nRow1
&& p
->aEnd
.Row() == nRow2
)
207 if ( p
->aStart
.Col() == nCol2
+1 )
209 p
->aStart
.SetCol( nCol1
);
212 else if ( p
->aEnd
.Col() == nCol1
-1 )
214 p
->aEnd
.SetCol( nCol2
);
222 { // innerhalb der Liste Range loeschen
227 nOldPos
--; // Seek richtig aufsetzen
230 Join( *p
, TRUE
); // rekursiv!
235 else if ( !bJoinedInput
)
240 BOOL
ScRangeList::operator==( const ScRangeList
& r
) const
243 return TRUE
; // identische Referenz
244 if ( Count() != r
.Count() )
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
255 BOOL
ScRangeList::UpdateReference( UpdateRefMode eUpdateRefMode
,
256 ScDocument
* pDoc
, const ScRange
& rWhere
,
257 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
259 BOOL bChanged
= FALSE
;
268 rWhere
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
269 for ( ScRange
* pR
= First(); pR
; pR
= Next() )
277 pR
->GetVars( theCol1
, theRow1
, theTab1
, theCol2
, theRow2
, theTab2
);
278 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
,
279 nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
,
281 theCol1
, theRow1
, theTab1
, theCol2
, theRow2
, theTab2
)
285 pR
->aStart
.Set( theCol1
, theRow1
, theTab1
);
286 pR
->aEnd
.Set( theCol2
, theRow2
, theTab2
);
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
) )
307 ScRangeList::ScRangeList( const ScRangeList
& rList
) :
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
)
321 ULONG nListCount
= rList
.Count();
322 for ( ULONG j
= 0; j
< nListCount
; j
++ )
323 Append( *rList
.GetObject( j
) );
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
) )
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
) )
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);
366 // === ScRangePairList ====================================================
368 ScRangePairList::~ScRangePairList()
370 for ( ScRangePair
* pR
= First(); pR
; pR
= Next() )
375 void ScRangePairList::Join( const ScRangePair
& r
, BOOL bIsInList
)
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
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() )
400 continue; // derselbe, weiter mit dem naechsten
401 BOOL bJoined
= FALSE
;
402 ScRange
& rp1
= p
->GetRange(0);
403 ScRange
& rp2
= p
->GetRange(1);
405 { // nur wenn Range2 gleich ist
407 { // RangePair r in RangePair p enthalten oder identisch
409 bJoined
= TRUE
; // weg mit RangePair r
412 bJoinedInput
= TRUE
; // nicht anhaengen
416 else if ( r1
.In( rp1
) )
417 { // RangePair p in RangePair r enthalten, r zum neuen RangePair machen
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 )
433 rp1
.aStart
.SetRow( nRow1
);
434 rp2
.aStart
.SetRow( r2
.aStart
.Row() );
437 else if ( rp1
.aEnd
.Row() == nRow1
-1
438 && rp2
.aEnd
.Row() == r2
.aStart
.Row()-1 )
440 rp1
.aEnd
.SetRow( nRow2
);
441 rp2
.aEnd
.SetRow( r2
.aEnd
.Row() );
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 )
452 rp1
.aStart
.SetCol( nCol1
);
453 rp2
.aStart
.SetCol( r2
.aStart
.Col() );
456 else if ( rp1
.aEnd
.Col() == nCol1
-1
457 && rp2
.aEnd
.Col() == r2
.aEnd
.Col()-1 )
459 rp1
.aEnd
.SetCol( nCol2
);
460 rp2
.aEnd
.SetCol( r2
.aEnd
.Col() );
468 { // innerhalb der Liste RangePair loeschen
473 nOldPos
--; // Seek richtig aufsetzen
476 Join( *p
, TRUE
); // rekursiv!
481 else if ( !bJoinedInput
)
486 BOOL
ScRangePairList::operator==( const ScRangePairList
& r
) const
489 return TRUE
; // identische Referenz
490 if ( Count() != r
.Count() )
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
502 BOOL
ScRangePairList::UpdateReference( UpdateRefMode eUpdateRefMode
,
503 ScDocument
* pDoc
, const ScRange
& rWhere
,
504 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
506 BOOL bChanged
= FALSE
;
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
);
527 rRange
.GetVars( theCol1
, theRow1
, theTab1
, theCol2
, theRow2
, theTab2
);
528 if ( ScRefUpdate::Update( pDoc
, eUpdateRefMode
,
529 nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
,
531 theCol1
, theRow1
, theTab1
, theCol2
, theRow2
, theTab2
)
535 rRange
.aStart
.Set( theCol1
, theRow1
, theTab1
);
536 rRange
.aEnd
.Set( theCol2
, theRow2
, theTab2
);
545 void ScRangePairList::DeleteOnTab( SCTAB nTab
)
547 // Delete entries that have the labels (first range) on nTab
549 ULONG nListCount
= Count();
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
)
559 nListCount
= Count();
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
) )
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
)
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
) );
605 struct ScRangePairNameSort
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
;
624 if ( rStartPos1
.Tab() == rStartPos2
.Tab() )
625 nComp
= COMPARE_EQUAL
;
628 ps1
->pDoc
->GetName( rStartPos1
.Tab(), aStr1
);
629 ps2
->pDoc
->GetName( rStartPos2
.Tab(), aStr2
);
630 nComp
= ScGlobal::GetCollator()->compareString( aStr1
, aStr2
);
637 case COMPARE_GREATER
:
642 if ( rStartPos1
.Col() < rStartPos2
.Col() )
644 if ( rStartPos1
.Col() > rStartPos2
.Col() )
647 if ( rStartPos1
.Row() < rStartPos2
.Row() )
649 if ( rStartPos1
.Row() > rStartPos2
.Row() )
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
;
659 ps1
->pDoc
->GetName( rEndPos1
.Tab(), aStr1
);
660 ps2
->pDoc
->GetName( rEndPos2
.Tab(), aStr2
);
661 nComp
= ScGlobal::GetCollator()->compareString( aStr1
, aStr2
);
668 case COMPARE_GREATER
:
673 if ( rEndPos1
.Col() < rEndPos2
.Col() )
675 if ( rEndPos1
.Col() > rEndPos2
.Col() )
678 if ( rEndPos1
.Row() < rEndPos2
.Row() )
680 if ( rEndPos1
.Row() > rEndPos2
.Row() )
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
) ];
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
);
708 qsort( (void*)pSortArray
, nListCount
, sizeof(ScRangePairNameSort
), ICCQsortRPairCompare
);
710 // ScRangePair Pointer aufruecken
711 ScRangePair
** ppSortArray
= (ScRangePair
**)pSortArray
;
712 for ( j
=0; j
< nListCount
; j
++ )
714 ppSortArray
[j
] = pSortArray
[j
].pPair
;