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: chartpos.cxx,v $
10 * $Revision: 1.4.32.2 $
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"
34 // INCLUDE ---------------------------------------------------------------
36 #include <tools/table.hxx>
38 #include "chartpos.hxx"
39 #include "document.hxx"
40 #include "rechead.hxx"
43 ScChartPositioner::ScChartPositioner( ScDocument
* pDoc
, SCTAB nTab
,
44 SCCOL nStartColP
, SCROW nStartRowP
, SCCOL nEndColP
, SCROW nEndRowP
) :
47 eGlue( SC_CHARTGLUE_NA
),
52 bDummyUpperLeft( FALSE
)
54 SetRangeList( ScRange( nStartColP
, nStartRowP
, nTab
, nEndColP
, nEndRowP
, nTab
) );
58 ScChartPositioner::ScChartPositioner( ScDocument
* pDoc
, const ScRangeListRef
& rRangeList
) :
59 aRangeListRef( rRangeList
),
62 eGlue( SC_CHARTGLUE_NA
),
67 bDummyUpperLeft( FALSE
)
69 if ( aRangeListRef
.Is() )
73 ScChartPositioner::ScChartPositioner( const ScChartPositioner
& rPositioner
) :
74 aRangeListRef( rPositioner
.aRangeListRef
),
75 pDocument(rPositioner
.pDocument
),
77 eGlue(rPositioner
.eGlue
),
78 nStartCol(rPositioner
.nStartCol
),
79 nStartRow(rPositioner
.nStartRow
),
80 bColHeaders(rPositioner
.bColHeaders
),
81 bRowHeaders(rPositioner
.bRowHeaders
),
82 bDummyUpperLeft( rPositioner
.bDummyUpperLeft
)
86 ScChartPositioner::~ScChartPositioner()
91 BOOL
ScChartPositioner::operator==(const ScChartPositioner
& rCmp
) const
93 return bColHeaders
== rCmp
.bColHeaders
94 && bRowHeaders
== rCmp
.bRowHeaders
95 && *aRangeListRef
== *rCmp
.aRangeListRef
;
98 void ScChartPositioner::SetRangeList( const ScRange
& rRange
)
100 aRangeListRef
= new ScRangeList
;
101 aRangeListRef
->Append( rRange
);
105 void ScChartPositioner::GlueState()
107 if ( eGlue
!= SC_CHARTGLUE_NA
)
109 bDummyUpperLeft
= FALSE
;
111 if ( aRangeListRef
->Count() <= 1 )
113 if ( (pR
= aRangeListRef
->First())!=NULL
)
115 if ( pR
->aStart
.Tab() == pR
->aEnd
.Tab() )
116 eGlue
= SC_CHARTGLUE_NONE
;
118 eGlue
= SC_CHARTGLUE_COLS
; // mehrere Tabellen spaltenweise
119 nStartCol
= pR
->aStart
.Col();
120 nStartRow
= pR
->aStart
.Row();
130 // ULONG nOldPos = aRangeListRef->GetCurPos();
132 pR
= aRangeListRef
->First();
133 nStartCol
= pR
->aStart
.Col();
134 nStartRow
= pR
->aStart
.Row();
135 SCCOL nMaxCols
, nEndCol
;
136 SCROW nMaxRows
, nEndRow
;
137 nMaxCols
= nEndCol
= 0;
138 nMaxRows
= nEndRow
= 0;
140 { // umspannenden Bereich etc. feststellen
141 SCCOLROW nTmp
, n1
, n2
;
142 if ( (n1
= pR
->aStart
.Col()) < nStartCol
)
143 nStartCol
= static_cast<SCCOL
>(n1
);
144 if ( (n2
= pR
->aEnd
.Col()) > nEndCol
)
145 nEndCol
= static_cast<SCCOL
>(n2
);
146 if ( (nTmp
= n2
- n1
+ 1) > nMaxCols
)
147 nMaxCols
= static_cast<SCCOL
>(nTmp
);
148 if ( (n1
= pR
->aStart
.Row()) < nStartRow
)
149 nStartRow
= static_cast<SCROW
>(n1
);
150 if ( (n2
= pR
->aEnd
.Row()) > nEndRow
)
151 nEndRow
= static_cast<SCROW
>(n2
);
152 if ( (nTmp
= n2
- n1
+ 1) > nMaxRows
)
153 nMaxRows
= static_cast<SCROW
>(nTmp
);
154 } while ( (pR
= aRangeListRef
->Next())!=NULL
);
155 SCCOL nC
= nEndCol
- nStartCol
+ 1;
158 eGlue
= SC_CHARTGLUE_ROWS
;
161 SCROW nR
= nEndRow
- nStartRow
+ 1;
164 eGlue
= SC_CHARTGLUE_COLS
;
167 ULONG nCR
= (ULONG
)nC
* nR
;
170 Erstmal simpel ohne Bitmaskiererei, maximal koennten so 8MB alloziert
171 werden (256 Cols mal 32000 Rows), das liesse sich mit 2 Bit je Eintrag
172 auf 2MB reduzieren, andererseits ist es so schneller.
173 Weitere Platz-Optimierung waere, in dem Array nur die wirklich benutzten
174 Zeilen/Spalten abzulegen, wuerde aber ein weiteres durchlaufen der
175 RangeList und indirekten Zugriff auf das Array bedeuten.
177 const BYTE nHole
= 0;
178 const BYTE nOccu
= 1;
179 const BYTE nFree
= 2;
180 const BYTE nGlue
= 3;
182 // we hate 16bit, don't we?
184 BYTE huge
* pA
= (BYTE huge
*) SvMemAlloc( nCR
);
185 if ( nCR
> (ULONG
)((USHORT
)~0) )
186 { // in 32k Bloecken initialisieren
188 for ( j
=0; j
<nCR
; j
+=0x8000 )
190 memset( pA
+j
, nHole
, Min( (ULONG
)0x8000, nCR
-j
) );
194 memset( pA
, nHole
, nCR
* sizeof(BYTE
) );
197 BYTE
* pA
= new BYTE
[ nCR
];
198 memset( pA
, 0, nCR
* sizeof(BYTE
) );
201 SCCOL nCol
, nCol1
, nCol2
;
202 SCROW nRow
, nRow1
, nRow2
;
203 for ( pR
= aRangeListRef
->First(); pR
; pR
= aRangeListRef
->Next() )
204 { // Selektionen 2D als belegt markieren
205 nCol1
= pR
->aStart
.Col() - nStartCol
;
206 nCol2
= pR
->aEnd
.Col() - nStartCol
;
207 nRow1
= pR
->aStart
.Row() - nStartRow
;
208 nRow2
= pR
->aEnd
.Row() - nStartRow
;
209 for ( nCol
= nCol1
; nCol
<= nCol2
; nCol
++ )
211 p
= pA
+ (ULONG
)nCol
* nR
+ nRow1
;
212 for ( nRow
= nRow1
; nRow
<= nRow2
; nRow
++, p
++ )
218 BOOL bGlueCols
= FALSE
;
219 for ( nCol
= 0; bGlue
&& nCol
< nC
; nCol
++ )
220 { // Spalten probieren durchzugehen und als frei markieren
221 p
= pA
+ (ULONG
)nCol
* nR
;
222 for ( nRow
= 0; bGlue
&& nRow
< nR
; nRow
++, p
++ )
225 { // Wenn einer mittendrin liegt ist keine Zusammenfassung
226 // moeglich. Am Rand koennte ok sein, wenn in dieser Spalte
227 // in jeder belegten Zeile einer belegt ist.
228 if ( nRow
> 0 && nCol
> 0 )
229 bGlue
= FALSE
; // nCol==0 kann DummyUpperLeft sein
236 if ( bGlue
&& *(p
= (pA
+ ((((ULONG
)nCol
+1) * nR
) - 1))) == nFree
)
237 { // Spalte als komplett frei markieren
239 bGlueCols
= TRUE
; // mindestens eine freie Spalte
243 BOOL bGlueRows
= FALSE
;
244 for ( nRow
= 0; bGlue
&& nRow
< nR
; nRow
++ )
245 { // Zeilen probieren durchzugehen und als frei markieren
247 for ( nCol
= 0; bGlue
&& nCol
< nC
; nCol
++, p
+=nR
)
251 if ( nCol
> 0 && nRow
> 0 )
252 bGlue
= FALSE
; // nRow==0 kann DummyUpperLeft sein
259 if ( bGlue
&& *(p
= (pA
+ ((((ULONG
)nC
-1) * nR
) + nRow
))) == nFree
)
260 { // Zeile als komplett frei markieren
262 bGlueRows
= TRUE
; // mindestens eine freie Zeile
266 // n=1: die linke obere Ecke koennte bei Beschriftung automagisch
267 // hinzugezogen werden
269 for ( ULONG n
= 1; bGlue
&& n
< nCR
; n
++, p
++ )
270 { // ein unberuehrtes Feld heisst, dass es weder spaltenweise noch
271 // zeilenweise zu erreichen war, also nichts zusamenzufassen
277 if ( bGlueCols
&& bGlueRows
)
278 eGlue
= SC_CHARTGLUE_BOTH
;
279 else if ( bGlueRows
)
280 eGlue
= SC_CHARTGLUE_ROWS
;
282 eGlue
= SC_CHARTGLUE_COLS
;
284 bDummyUpperLeft
= TRUE
;
288 eGlue
= SC_CHARTGLUE_NONE
;
298 void ScChartPositioner::CheckColRowHeaders()
300 SCCOL nCol1
, nCol2
, iCol
;
301 SCROW nRow1
, nRow2
, iRow
;
304 BOOL bColStrings
= TRUE
;
305 BOOL bRowStrings
= TRUE
;
307 if ( aRangeListRef
->Count() == 1 )
309 aRangeListRef
->First()->GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
310 if ( nCol1
> nCol2
|| nRow1
> nRow2
)
311 bColStrings
= bRowStrings
= FALSE
;
314 for (iCol
=nCol1
; iCol
<=nCol2
&& bColStrings
; iCol
++)
316 if (pDocument
->HasValueData( iCol
, nRow1
, nTab1
))
319 for (iRow
=nRow1
; iRow
<=nRow2
&& bRowStrings
; iRow
++)
321 if (pDocument
->HasValueData( nCol1
, iRow
, nTab1
))
328 BOOL bVert
= (eGlue
== SC_CHARTGLUE_NONE
|| eGlue
== SC_CHARTGLUE_ROWS
);
329 for ( ScRangePtr pR
= aRangeListRef
->First();
330 pR
&& (bColStrings
|| bRowStrings
);
331 pR
= aRangeListRef
->Next() )
333 pR
->GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
334 BOOL bTopRow
= (nRow1
== nStartRow
);
335 if ( bRowStrings
&& (bVert
|| nCol1
== nStartCol
) )
336 { // NONE oder ROWS: RowStrings in jeder Selektion moeglich
337 // COLS oder BOTH: nur aus der ersten Spalte
338 if ( nCol1
<= nCol2
)
339 for (iRow
=nRow1
; iRow
<=nRow2
&& bRowStrings
; iRow
++)
341 if (pDocument
->HasValueData( nCol1
, iRow
, nTab1
))
345 if ( bColStrings
&& bTopRow
)
346 { // ColStrings nur aus der ersten Zeile
347 if ( nRow1
<= nRow2
)
348 for (iCol
=nCol1
; iCol
<=nCol2
&& bColStrings
; iCol
++)
350 if (pDocument
->HasValueData( iCol
, nRow1
, nTab1
))
356 bColHeaders
= bColStrings
;
357 bRowHeaders
= bRowStrings
;
360 const ScChartPositionMap
* ScChartPositioner::GetPositionMap()
367 void ScChartPositioner::CreatePositionMap()
369 if ( eGlue
== SC_CHARTGLUE_NA
&& pPositionMap
)
378 SCSIZE nColAdd
= bRowHeaders
? 1 : 0;
379 SCSIZE nRowAdd
= bColHeaders
? 1 : 0;
381 SCCOL nCol
, nCol1
, nCol2
;
382 SCROW nRow
, nRow1
, nRow2
;
383 SCTAB nTab
, nTab1
, nTab2
;
386 // wirkliche Groesse (ohne versteckte Zeilen/Spalten)
389 SCSIZE nColCount
= 0;
390 SCSIZE nRowCount
= 0;
394 BOOL bNoGlue
= (eGlue
== SC_CHARTGLUE_NONE
);
395 Table
* pCols
= new Table
;
396 Table
* pNewRowTable
= new Table
;
397 ScAddress
* pNewAddress
= new ScAddress
;
401 SCROW nNoGlueRow
= 0;
402 for ( pR
= aRangeListRef
->First(); pR
; pR
= aRangeListRef
->Next() )
404 pR
->GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
405 for ( nTab
= nTab1
; nTab
<= nTab2
; nTab
++ )
407 // nTab im ColKey, um gleiche Col/Row in anderer Table haben zu koennen
408 ULONG nInsCol
= (static_cast<ULONG
>(nTab
) << 16) | (bNoGlue
? 0 :
409 static_cast<ULONG
>(nCol1
));
410 for ( nCol
= nCol1
; nCol
<= nCol2
; ++nCol
, ++nInsCol
)
412 if ( bNoGlue
|| eGlue
== SC_CHARTGLUE_ROWS
)
413 { // meistens gleiche Cols
414 if ( (pCol
= (Table
*) pCols
->Get( nInsCol
))==NULL
)
416 pCols
->Insert( nInsCol
, pNewRowTable
);
418 pNewRowTable
= new Table
;
422 { // meistens neue Cols
423 if ( pCols
->Insert( nInsCol
, pNewRowTable
) )
426 pNewRowTable
= new Table
;
429 pCol
= (Table
*) pCols
->Get( nInsCol
);
431 // bei anderer Tabelle wurde bereits neuer ColKey erzeugt,
432 // die Zeilen muessen fuer's Dummy fuellen gleich sein!
433 ULONG nInsRow
= (bNoGlue
? nNoGlueRow
: nRow1
);
434 for ( nRow
= nRow1
; nRow
<= nRow2
; nRow
++, nInsRow
++ )
436 if ( pCol
->Insert( nInsRow
, pNewAddress
) )
438 pNewAddress
->Set( nCol
, nRow
, nTab
);
439 pNewAddress
= new ScAddress
;
444 // bei NoGlue werden zusammengehoerige Tabellen als ColGlue dargestellt
445 nNoGlueRow
+= nRow2
- nRow1
+ 1;
451 nColCount
= static_cast< SCSIZE
>( pCols
->Count());
452 if ( (pCol
= (Table
*) pCols
->First())!=NULL
)
454 if ( bDummyUpperLeft
)
455 pCol
->Insert( 0, (void*)0 ); // Dummy fuer Beschriftung
456 nRowCount
= static_cast< SCSIZE
>( pCol
->Count());
461 nColCount
-= nColAdd
;
463 nRowCount
-= nRowAdd
;
465 if ( nColCount
==0 || nRowCount
==0 )
466 { // einen Eintrag ohne Daten erzeugen
467 pR
= aRangeListRef
->First();
468 if ( pCols
->Count() > 0 )
469 pCol
= (Table
*) pCols
->First();
473 pCols
->Insert( 0, pCol
);
476 if ( pCol
->Count() > 0 )
477 { // kann ja eigentlich nicht sein, wenn nColCount==0 || nRowCount==0
478 pPos
= (ScAddress
*) pCol
->First();
482 pCol
->Replace( pCol
->GetCurKey(), (void*)0 );
486 pCol
->Insert( 0, (void*)0 );
494 { // Luecken mit Dummies fuellen, erste Spalte ist Master
495 Table
* pFirstCol
= (Table
*) pCols
->First();
496 ULONG nCount
= pFirstCol
->Count();
498 for ( ULONG n
= 0; n
< nCount
; n
++, pFirstCol
->Next() )
500 ULONG nKey
= pFirstCol
->GetCurKey();
502 while ( (pCol
= (Table
*) pCols
->Next())!=NULL
)
503 pCol
->Insert( nKey
, (void*)0 ); // keine Daten
508 pPositionMap
= new ScChartPositionMap( static_cast<SCCOL
>(nColCount
), static_cast<SCROW
>(nRowCount
),
509 static_cast<SCCOL
>(nColAdd
), static_cast<SCROW
>(nRowAdd
), *pCols
);
512 for ( pCol
= (Table
*) pCols
->First(); pCol
; pCol
= (Table
*) pCols
->Next() )
513 { //! nur Tables loeschen, nicht die ScAddress*
520 ScChartPositionMap::ScChartPositionMap( SCCOL nChartCols
, SCROW nChartRows
,
521 SCCOL nColAdd
, SCROW nRowAdd
, Table
& rCols
) :
522 ppData( new ScAddress
* [ nChartCols
* nChartRows
] ),
523 ppColHeader( new ScAddress
* [ nChartCols
] ),
524 ppRowHeader( new ScAddress
* [ nChartRows
] ),
525 nCount( (ULONG
) nChartCols
* nChartRows
),
526 nColCount( nChartCols
),
527 nRowCount( nChartRows
)
529 DBG_ASSERT( nColCount
&& nRowCount
, "ScChartPositionMap without dimension" );
531 #error ScChartPositionMap not implemented for 16-bit dumdums
538 Table
* pCol
= (Table
*) rCols
.First();
541 pPos
= (ScAddress
*) pCol
->First();
543 pPos
= (ScAddress
*) pCol
->Next();
546 for ( nRow
= 0; nRow
< nRowCount
; nRow
++ )
548 ppRowHeader
[ nRow
] = pPos
;
549 pPos
= (ScAddress
*) pCol
->Next();
554 for ( nRow
= 0; nRow
< nRowCount
; nRow
++ )
556 ppRowHeader
[ nRow
] = ( pPos
? new ScAddress( *pPos
) : NULL
);
557 pPos
= (ScAddress
*) pCol
->Next();
561 pCol
= (Table
*) rCols
.Next();
563 // Daten spaltenweise und Spalten-Header
565 for ( nCol
= 0; nCol
< nColCount
; nCol
++ )
569 pPos
= (ScAddress
*) pCol
->First();
572 ppColHeader
[ nCol
] = pPos
; // eigenstaendig
573 pPos
= (ScAddress
*) pCol
->Next();
576 ppColHeader
[ nCol
] = ( pPos
? new ScAddress( *pPos
) : NULL
);
577 for ( nRow
= 0; nRow
< nRowCount
; nRow
++, nIndex
++ )
579 ppData
[ nIndex
] = pPos
;
580 pPos
= (ScAddress
*) pCol
->Next();
585 ppColHeader
[ nCol
] = NULL
;
586 for ( nRow
= 0; nRow
< nRowCount
; nRow
++, nIndex
++ )
588 ppData
[ nIndex
] = NULL
;
591 pCol
= (Table
*) rCols
.Next();
596 ScChartPositionMap::~ScChartPositionMap()
598 for ( ULONG nIndex
=0; nIndex
< nCount
; nIndex
++ )
600 delete ppData
[nIndex
];
605 for ( j
=0; j
< nColCount
; j
++ )
607 delete ppColHeader
[j
];
609 delete [] ppColHeader
;
611 for ( i
=0; i
< nRowCount
; i
++ )
613 delete ppRowHeader
[i
];
615 delete [] ppRowHeader
;
619 //UNUSED2009-05 ScRangeListRef ScChartPositionMap::GetColRanges( SCCOL nChartCol ) const
621 //UNUSED2009-05 ScRangeListRef xRangeList = new ScRangeList;
622 //UNUSED2009-05 if ( nChartCol < nColCount )
624 //UNUSED2009-05 ULONG nStop = GetIndex( nChartCol, nRowCount );
625 //UNUSED2009-05 for ( ULONG nIndex = GetIndex( nChartCol, 0 ); nIndex < nStop; nIndex++ )
627 //UNUSED2009-05 if ( ppData[ nIndex ] )
628 //UNUSED2009-05 xRangeList->Join( *ppData[ nIndex ] );
631 //UNUSED2009-05 return xRangeList;
635 //UNUSED2009-05 ScRangeListRef ScChartPositionMap::GetRowRanges( SCROW nChartRow ) const
637 //UNUSED2009-05 ScRangeListRef xRangeList = new ScRangeList;
638 //UNUSED2009-05 if ( nChartRow < nRowCount )
640 //UNUSED2009-05 ULONG nStop = GetIndex( nColCount, nChartRow );
641 //UNUSED2009-05 for ( ULONG nIndex = GetIndex( 0, nChartRow ); nIndex < nStop;
642 //UNUSED2009-05 nIndex += nRowCount )
644 //UNUSED2009-05 if ( ppData[ nIndex ] )
645 //UNUSED2009-05 xRangeList->Join( *ppData[ nIndex ] );
648 //UNUSED2009-05 return xRangeList;