xref: /aoo41x/main/sc/source/core/tool/chartpos.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 // INCLUDE ---------------------------------------------------------------
32 
33 #include <tools/table.hxx>
34 
35 #include "chartpos.hxx"
36 #include "document.hxx"
37 #include "rechead.hxx"
38 
39 namespace
40 {
41     bool lcl_hasValueDataButNoDates( ScDocument* pDocument, SCCOL nCol, SCROW nRow, SCTAB nTab )
42     {
43         bool bReturn = false;
44         if (pDocument->HasValueData( nCol, nRow, nTab ))
45         {
46             //treat dates like text #i25706#
47             sal_uInt32 nNumberFormat = pDocument->GetNumberFormat( ScAddress( nCol, nRow, nTab ) );
48             short nType = pDocument->GetFormatTable()->GetType(nNumberFormat);
49 			bool bIsDate = (nType & NUMBERFORMAT_DATE);
50 			bReturn = !bIsDate;
51         }
52         return bReturn;
53     }
54 }
55 
56 ScChartPositioner::ScChartPositioner( ScDocument* pDoc, SCTAB nTab,
57 					SCCOL nStartColP, SCROW nStartRowP, SCCOL nEndColP, SCROW nEndRowP) :
58 		pDocument( pDoc ),
59 		pPositionMap( NULL ),
60 		eGlue( SC_CHARTGLUE_NA ),
61 		nStartCol(0),
62 		nStartRow(0),
63 		bColHeaders( sal_False ),
64 		bRowHeaders( sal_False ),
65 		bDummyUpperLeft( sal_False )
66 {
67 	SetRangeList( ScRange( nStartColP, nStartRowP, nTab, nEndColP, nEndRowP, nTab ) );
68 	CheckColRowHeaders();
69 }
70 
71 ScChartPositioner::ScChartPositioner( ScDocument* pDoc, const ScRangeListRef& rRangeList ) :
72 		aRangeListRef( rRangeList ),
73 		pDocument( pDoc ),
74 		pPositionMap( NULL ),
75 		eGlue( SC_CHARTGLUE_NA ),
76 		nStartCol(0),
77 		nStartRow(0),
78 		bColHeaders( sal_False ),
79 		bRowHeaders( sal_False ),
80 		bDummyUpperLeft( sal_False )
81 {
82 	if ( aRangeListRef.Is() )
83 		CheckColRowHeaders();
84 }
85 
86 ScChartPositioner::ScChartPositioner( const ScChartPositioner& rPositioner ) :
87 		aRangeListRef( rPositioner.aRangeListRef ),
88 		pDocument(rPositioner.pDocument),
89 		pPositionMap( NULL ),
90 		eGlue(rPositioner.eGlue),
91 		nStartCol(rPositioner.nStartCol),
92 		nStartRow(rPositioner.nStartRow),
93 		bColHeaders(rPositioner.bColHeaders),
94 		bRowHeaders(rPositioner.bRowHeaders),
95 		bDummyUpperLeft( rPositioner.bDummyUpperLeft )
96 {
97 }
98 
99 ScChartPositioner::~ScChartPositioner()
100 {
101 	delete pPositionMap;
102 }
103 
104 sal_Bool ScChartPositioner::operator==(const ScChartPositioner& rCmp) const
105 {
106 	return bColHeaders == rCmp.bColHeaders
107 		&& bRowHeaders == rCmp.bRowHeaders
108 		&& *aRangeListRef == *rCmp.aRangeListRef;
109 }
110 
111 void ScChartPositioner::SetRangeList( const ScRange& rRange )
112 {
113 	aRangeListRef = new ScRangeList;
114 	aRangeListRef->Append( rRange );
115 	InvalidateGlue();
116 }
117 
118 void ScChartPositioner::GlueState()
119 {
120 	if ( eGlue != SC_CHARTGLUE_NA )
121 		return;
122 	bDummyUpperLeft = sal_False;
123 	ScRangePtr pR;
124 	if ( aRangeListRef->Count() <= 1 )
125 	{
126 		if ( (pR = aRangeListRef->First())!=NULL )
127 		{
128 			if ( pR->aStart.Tab() == pR->aEnd.Tab() )
129 				eGlue = SC_CHARTGLUE_NONE;
130 			else
131 				eGlue = SC_CHARTGLUE_COLS;	// mehrere Tabellen spaltenweise
132 			nStartCol = pR->aStart.Col();
133 			nStartRow = pR->aStart.Row();
134 		}
135 		else
136 		{
137 			InvalidateGlue();
138 			nStartCol = 0;
139 			nStartRow = 0;
140 		}
141 		return;
142 	}
143 // 	sal_uLong nOldPos = aRangeListRef->GetCurPos();
144 
145 	pR = aRangeListRef->First();
146 	nStartCol = pR->aStart.Col();
147 	nStartRow = pR->aStart.Row();
148 	SCCOL nMaxCols, nEndCol;
149 	SCROW nMaxRows, nEndRow;
150 	nMaxCols = nEndCol = 0;
151 	nMaxRows = nEndRow = 0;
152 	do
153 	{	// umspannenden Bereich etc. feststellen
154 		SCCOLROW nTmp, n1, n2;
155 		if ( (n1 = pR->aStart.Col()) < nStartCol )
156 			nStartCol = static_cast<SCCOL>(n1);
157 		if ( (n2 = pR->aEnd.Col()) > nEndCol )
158 			nEndCol = static_cast<SCCOL>(n2);
159 		if ( (nTmp = n2 - n1 + 1) > nMaxCols )
160 			nMaxCols = static_cast<SCCOL>(nTmp);
161 		if ( (n1 = pR->aStart.Row()) < nStartRow )
162 			nStartRow = static_cast<SCROW>(n1);
163 		if ( (n2 = pR->aEnd.Row()) > nEndRow )
164 			nEndRow = static_cast<SCROW>(n2);
165 		if ( (nTmp = n2 - n1 + 1) > nMaxRows )
166 			nMaxRows = static_cast<SCROW>(nTmp);
167 	} while ( (pR = aRangeListRef->Next())!=NULL );
168 	SCCOL nC = nEndCol - nStartCol + 1;
169 	if ( nC == 1 )
170 	{
171 		eGlue = SC_CHARTGLUE_ROWS;
172 		return;
173 	}
174 	SCROW nR = nEndRow - nStartRow + 1;
175 	if ( nR == 1 )
176 	{
177 		eGlue = SC_CHARTGLUE_COLS;
178 		return;
179 	}
180 	sal_uLong nCR = (sal_uLong)nC * nR;
181 //2do:
182 /*
183 	Erstmal simpel ohne Bitmaskiererei, maximal koennten so 8MB alloziert
184 	werden (256 Cols mal 32000 Rows), das liesse sich mit 2 Bit je Eintrag
185 	auf 2MB reduzieren, andererseits ist es so schneller.
186 	Weitere Platz-Optimierung waere, in dem Array nur die wirklich benutzten
187 	Zeilen/Spalten abzulegen, wuerde aber ein weiteres durchlaufen der
188 	RangeList und indirekten Zugriff auf das Array bedeuten.
189  */
190 	const sal_uInt8 nHole = 0;
191 	const sal_uInt8 nOccu = 1;
192 	const sal_uInt8 nFree = 2;
193 	const sal_uInt8 nGlue = 3;
194 	sal_uInt8* p;
195 	sal_uInt8* pA = new sal_uInt8[ nCR ];
196 	memset( pA, 0, nCR * sizeof(sal_uInt8) );
197 
198 	SCCOL nCol, nCol1, nCol2;
199 	SCROW nRow, nRow1, nRow2;
200 	for ( pR = aRangeListRef->First(); pR; pR = aRangeListRef->Next() )
201 	{	// Selektionen 2D als belegt markieren
202 		nCol1 = pR->aStart.Col() - nStartCol;
203 		nCol2 = pR->aEnd.Col() - nStartCol;
204 		nRow1 = pR->aStart.Row() - nStartRow;
205 		nRow2 = pR->aEnd.Row() - nStartRow;
206 		for ( nCol = nCol1; nCol <= nCol2; nCol++ )
207 		{
208 			p = pA + (sal_uLong)nCol * nR + nRow1;
209 			for ( nRow = nRow1; nRow <= nRow2; nRow++, p++ )
210 				*p = nOccu;
211 		}
212 	}
213 	sal_Bool bGlue = sal_True;
214 
215 	sal_Bool bGlueCols = sal_False;
216 	for ( nCol = 0; bGlue && nCol < nC; nCol++ )
217 	{	// Spalten probieren durchzugehen und als frei markieren
218 		p = pA + (sal_uLong)nCol * nR;
219 		for ( nRow = 0; bGlue && nRow < nR; nRow++, p++ )
220 		{
221 			if ( *p == nOccu )
222 			{	// Wenn einer mittendrin liegt ist keine Zusammenfassung
223 				// moeglich. Am Rand koennte ok sein, wenn in dieser Spalte
224 				// in jeder belegten Zeile einer belegt ist.
225 				if ( nRow > 0 && nCol > 0 )
226 					bGlue = sal_False;		// nCol==0 kann DummyUpperLeft sein
227 				else
228 					nRow = nR;
229 			}
230 			else
231 				*p = nFree;
232 		}
233 		if ( bGlue && *(p = (pA + ((((sal_uLong)nCol+1) * nR) - 1))) == nFree )
234 		{	// Spalte als komplett frei markieren
235 			*p = nGlue;
236 			bGlueCols = sal_True;		// mindestens eine freie Spalte
237 		}
238 	}
239 
240 	sal_Bool bGlueRows = sal_False;
241 	for ( nRow = 0; bGlue && nRow < nR; nRow++ )
242 	{	// Zeilen probieren durchzugehen und als frei markieren
243 		p = pA + nRow;
244 		for ( nCol = 0; bGlue && nCol < nC; nCol++, p+=nR )
245 		{
246 			if ( *p == nOccu )
247 			{
248 				if ( nCol > 0 && nRow > 0 )
249 					bGlue = sal_False;		// nRow==0 kann DummyUpperLeft sein
250 				else
251 					nCol = nC;
252 			}
253 			else
254 				*p = nFree;
255 		}
256 		if ( bGlue && *(p = (pA + ((((sal_uLong)nC-1) * nR) + nRow))) == nFree )
257 		{	// Zeile als komplett frei markieren
258 			*p = nGlue;
259 			bGlueRows = sal_True;		// mindestens eine freie Zeile
260 		}
261 	}
262 
263 	// n=1: die linke obere Ecke koennte bei Beschriftung automagisch
264 	// hinzugezogen werden
265 	p = pA + 1;
266 	for ( sal_uLong n = 1; bGlue && n < nCR; n++, p++ )
267 	{	// ein unberuehrtes Feld heisst, dass es weder spaltenweise noch
268 		// zeilenweise zu erreichen war, also nichts zusamenzufassen
269 		if ( *p == nHole )
270 			bGlue = sal_False;
271 	}
272 	if ( bGlue )
273 	{
274 		if ( bGlueCols && bGlueRows )
275 			eGlue = SC_CHARTGLUE_BOTH;
276 		else if ( bGlueRows )
277 			eGlue = SC_CHARTGLUE_ROWS;
278 		else
279 			eGlue = SC_CHARTGLUE_COLS;
280 		if ( *pA != nOccu )
281 			bDummyUpperLeft = sal_True;
282 	}
283 	else
284 	{
285 		eGlue = SC_CHARTGLUE_NONE;
286 	}
287 
288 	delete [] pA;
289 }
290 
291 void ScChartPositioner::CheckColRowHeaders()
292 {
293 	SCCOL nCol1, nCol2, iCol;
294 	SCROW nRow1, nRow2, iRow;
295 	SCTAB nTab1, nTab2;
296 
297 	sal_Bool bColStrings = sal_True;
298 	sal_Bool bRowStrings = sal_True;
299 	GlueState();
300 	if ( aRangeListRef->Count() == 1 )
301 	{
302 		aRangeListRef->First()->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
303 		if ( nCol1 > nCol2 || nRow1 > nRow2 )
304 			bColStrings = bRowStrings = sal_False;
305 		else
306 		{
307 			for (iCol=nCol1; iCol<=nCol2 && bColStrings; iCol++)
308 			{
309 				if (lcl_hasValueDataButNoDates( pDocument, iCol, nRow1, nTab1 ))
310 						bColStrings = sal_False;
311 			}
312 			for (iRow=nRow1; iRow<=nRow2 && bRowStrings; iRow++)
313 			{
314 				if (lcl_hasValueDataButNoDates( pDocument, nCol1, iRow, nTab1 ))
315 						bRowStrings = sal_False;
316 			}
317 		}
318 	}
319 	else
320 	{
321 		sal_Bool bVert = (eGlue == SC_CHARTGLUE_NONE || eGlue == SC_CHARTGLUE_ROWS);
322 		for ( ScRangePtr pR = aRangeListRef->First();
323 				pR && (bColStrings || bRowStrings);
324 				pR = aRangeListRef->Next() )
325 		{
326 			pR->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
327 			sal_Bool bTopRow = (nRow1 == nStartRow);
328 			if ( bRowStrings && (bVert || nCol1 == nStartCol) )
329 			{	// NONE oder ROWS: RowStrings in jeder Selektion moeglich
330 				// COLS oder BOTH: nur aus der ersten Spalte
331 				if ( nCol1 <= nCol2 )
332 					for (iRow=nRow1; iRow<=nRow2 && bRowStrings; iRow++)
333 					{
334 						if (lcl_hasValueDataButNoDates( pDocument, nCol1, iRow, nTab1 ))
335 								bRowStrings = sal_False;
336 					}
337 			}
338 			if ( bColStrings && bTopRow )
339 			{	// ColStrings nur aus der ersten Zeile
340 				if ( nRow1 <= nRow2 )
341 					for (iCol=nCol1; iCol<=nCol2 && bColStrings; iCol++)
342 					{
343 						if (lcl_hasValueDataButNoDates( pDocument, iCol, nRow1, nTab1 ))
344 								bColStrings = sal_False;
345 					}
346 			}
347 		}
348 	}
349 	bColHeaders = bColStrings;
350 	bRowHeaders = bRowStrings;
351 }
352 
353 const ScChartPositionMap* ScChartPositioner::GetPositionMap()
354 {
355     CreatePositionMap();
356 	return pPositionMap;
357 }
358 
359 
360 void ScChartPositioner::CreatePositionMap()
361 {
362 	if ( eGlue == SC_CHARTGLUE_NA && pPositionMap )
363 	{
364 		delete pPositionMap;
365 		pPositionMap = NULL;
366 	}
367 
368 	if ( pPositionMap )
369 		return ;
370 
371 	SCSIZE nColAdd = bRowHeaders ? 1 : 0;
372 	SCSIZE nRowAdd = bColHeaders ? 1 : 0;
373 
374 	SCCOL nCol, nCol1, nCol2;
375 	SCROW nRow, nRow1, nRow2;
376 	SCTAB nTab, nTab1, nTab2;
377 
378 	//
379 	//	wirkliche Groesse (ohne versteckte Zeilen/Spalten)
380 	//
381 
382 	SCSIZE nColCount = 0;
383     SCSIZE nRowCount = 0;
384 
385 	GlueState();
386 
387 	sal_Bool bNoGlue = (eGlue == SC_CHARTGLUE_NONE);
388 	Table* pCols = new Table;
389 	Table* pNewRowTable = new Table;
390 	ScAddress* pNewAddress = new ScAddress;
391 	ScRangePtr pR;
392 	Table* pCol;
393 	ScAddress* pPos;
394 	SCROW nNoGlueRow = 0;
395 	for ( pR = aRangeListRef->First(); pR; pR = aRangeListRef->Next() )
396 	{
397 		pR->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
398 		for ( nTab = nTab1; nTab <= nTab2; nTab++ )
399 		{
400 			// nTab im ColKey, um gleiche Col/Row in anderer Table haben zu koennen
401             sal_uLong nInsCol = (static_cast<sal_uLong>(nTab) << 16) | (bNoGlue ? 0 :
402                     static_cast<sal_uLong>(nCol1));
403 			for ( nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol )
404 			{
405 				if ( bNoGlue || eGlue == SC_CHARTGLUE_ROWS )
406 				{	// meistens gleiche Cols
407 					if ( (pCol = (Table*) pCols->Get( nInsCol ))==NULL )
408 					{
409 						pCols->Insert( nInsCol, pNewRowTable );
410 						pCol = pNewRowTable;
411 						pNewRowTable = new Table;
412 					}
413 				}
414 				else
415 				{	// meistens neue Cols
416 					if ( pCols->Insert( nInsCol, pNewRowTable ) )
417 					{
418 						pCol = pNewRowTable;
419 						pNewRowTable = new Table;
420 					}
421 					else
422 						pCol = (Table*) pCols->Get( nInsCol );
423 				}
424 				// bei anderer Tabelle wurde bereits neuer ColKey erzeugt,
425 				// die Zeilen muessen fuer's Dummy fuellen gleich sein!
426 				sal_uLong nInsRow = (bNoGlue ? nNoGlueRow : nRow1);
427 				for ( nRow = nRow1; nRow <= nRow2; nRow++, nInsRow++ )
428 				{
429 					if ( pCol->Insert( nInsRow, pNewAddress ) )
430 					{
431 						pNewAddress->Set( nCol, nRow, nTab );
432 						pNewAddress = new ScAddress;
433 					}
434 				}
435 			}
436 		}
437 		// bei NoGlue werden zusammengehoerige Tabellen als ColGlue dargestellt
438 		nNoGlueRow += nRow2 - nRow1 + 1;
439 	}
440 	delete pNewAddress;
441 	delete pNewRowTable;
442 
443 	// Anzahl der Daten
444 	nColCount = static_cast< SCSIZE >( pCols->Count());
445 	if ( (pCol = (Table*) pCols->First())!=NULL )
446 	{
447 		if ( bDummyUpperLeft )
448 			pCol->Insert( 0, (void*)0 );		// Dummy fuer Beschriftung
449 		nRowCount = static_cast< SCSIZE >( pCol->Count());
450 	}
451 	else
452 		nRowCount = 0;
453 	if ( nColCount > 0 )
454 		nColCount -= nColAdd;
455 	if ( nRowCount > 0 )
456 		nRowCount -= nRowAdd;
457 
458 	if ( nColCount==0 || nRowCount==0 )
459 	{	// einen Eintrag ohne Daten erzeugen
460 		pR = aRangeListRef->First();
461 		if ( pCols->Count() > 0 )
462 			pCol = (Table*) pCols->First();
463 		else
464 		{
465 			pCol = new Table;
466 			pCols->Insert( 0, pCol );
467 		}
468 		nColCount = 1;
469 		if ( pCol->Count() > 0 )
470 		{	// kann ja eigentlich nicht sein, wenn nColCount==0 || nRowCount==0
471 			pPos = (ScAddress*) pCol->First();
472 			if ( pPos )
473 			{
474 				delete pPos;
475 				pCol->Replace( pCol->GetCurKey(), (void*)0 );
476 			}
477 		}
478 		else
479 			pCol->Insert( 0, (void*)0 );
480 		nRowCount = 1;
481 		nColAdd = 0;
482 		nRowAdd = 0;
483 	}
484 	else
485 	{
486 		if ( bNoGlue )
487 		{	// Luecken mit Dummies fuellen, erste Spalte ist Master
488 			Table* pFirstCol = (Table*) pCols->First();
489 			sal_uLong nCount = pFirstCol->Count();
490 			pFirstCol->First();
491 			for ( sal_uLong n = 0; n < nCount; n++, pFirstCol->Next() )
492 			{
493 				sal_uLong nKey = pFirstCol->GetCurKey();
494 				pCols->First();
495 				while ( (pCol = (Table*) pCols->Next())!=NULL )
496 					pCol->Insert( nKey, (void*)0 );		// keine Daten
497 			}
498 		}
499 	}
500 
501 	pPositionMap = new ScChartPositionMap( static_cast<SCCOL>(nColCount), static_cast<SCROW>(nRowCount),
502 		static_cast<SCCOL>(nColAdd), static_cast<SCROW>(nRowAdd), *pCols );
503 
504 	//	Aufraeumen
505 	for ( pCol = (Table*) pCols->First(); pCol; pCol = (Table*) pCols->Next() )
506 	{	//! nur Tables loeschen, nicht die ScAddress*
507 		delete pCol;
508 	}
509 	delete pCols;
510 }
511 
512 
513 ScChartPositionMap::ScChartPositionMap( SCCOL nChartCols, SCROW nChartRows,
514 			SCCOL nColAdd, SCROW nRowAdd, Table& rCols ) :
515 		ppData( new ScAddress* [ nChartCols * nChartRows ] ),
516 		ppColHeader( new ScAddress* [ nChartCols ] ),
517 		ppRowHeader( new ScAddress* [ nChartRows ] ),
518 		nCount( (sal_uLong) nChartCols * nChartRows ),
519 		nColCount( nChartCols ),
520 		nRowCount( nChartRows )
521 {
522 	DBG_ASSERT( nColCount && nRowCount, "ScChartPositionMap without dimension" );
523 
524 	ScAddress* pPos;
525 	SCCOL nCol;
526 	SCROW nRow;
527 
528 	Table* pCol = (Table*) rCols.First();
529 
530 	// Zeilen-Header
531 	pPos = (ScAddress*) pCol->First();
532 	if ( nRowAdd )
533 		pPos = (ScAddress*) pCol->Next();
534 	if ( nColAdd )
535 	{	// eigenstaendig
536 		for ( nRow = 0; nRow < nRowCount; nRow++ )
537 		{
538 			ppRowHeader[ nRow ] = pPos;
539 			pPos = (ScAddress*) pCol->Next();
540 		}
541 	}
542 	else
543 	{	// Kopie
544 		for ( nRow = 0; nRow < nRowCount; nRow++ )
545 		{
546 			ppRowHeader[ nRow ] = ( pPos ? new ScAddress( *pPos ) : NULL );
547 			pPos = (ScAddress*) pCol->Next();
548 		}
549 	}
550 	if ( nColAdd )
551 		pCol = (Table*) rCols.Next();
552 
553 	// Daten spaltenweise und Spalten-Header
554 	sal_uLong nIndex = 0;
555 	for ( nCol = 0; nCol < nColCount; nCol++ )
556 	{
557 		if ( pCol )
558 		{
559 			pPos = (ScAddress*) pCol->First();
560 			if ( nRowAdd )
561 			{
562 				ppColHeader[ nCol ] = pPos;		// eigenstaendig
563 				pPos = (ScAddress*) pCol->Next();
564 			}
565 			else
566 				ppColHeader[ nCol ] = ( pPos ? new ScAddress( *pPos ) : NULL );
567 			for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
568 			{
569 				ppData[ nIndex ] = pPos;
570 				pPos = (ScAddress*) pCol->Next();
571 			}
572 		}
573 		else
574 		{
575 			ppColHeader[ nCol ] = NULL;
576 			for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
577 			{
578 				ppData[ nIndex ] = NULL;
579 			}
580 		}
581 		pCol = (Table*) rCols.Next();
582 	}
583 }
584 
585 
586 ScChartPositionMap::~ScChartPositionMap()
587 {
588 	for ( sal_uLong nIndex=0; nIndex < nCount; nIndex++ )
589 	{
590 		delete ppData[nIndex];
591 	}
592 	delete [] ppData;
593 
594 	SCCOL j;
595 	for ( j=0; j < nColCount; j++ )
596 	{
597 		delete ppColHeader[j];
598 	}
599 	delete [] ppColHeader;
600 	SCROW i;
601 	for ( i=0; i < nRowCount; i++ )
602 	{
603 		delete ppRowHeader[i];
604 	}
605 	delete [] ppRowHeader;
606 }
607 
608 
609 //UNUSED2009-05 ScRangeListRef ScChartPositionMap::GetColRanges( SCCOL nChartCol ) const
610 //UNUSED2009-05 {
611 //UNUSED2009-05     ScRangeListRef xRangeList = new ScRangeList;
612 //UNUSED2009-05     if ( nChartCol < nColCount )
613 //UNUSED2009-05     {
614 //UNUSED2009-05         sal_uLong nStop = GetIndex( nChartCol, nRowCount );
615 //UNUSED2009-05         for ( sal_uLong nIndex = GetIndex( nChartCol, 0 ); nIndex < nStop; nIndex++ )
616 //UNUSED2009-05         {
617 //UNUSED2009-05             if ( ppData[ nIndex ] )
618 //UNUSED2009-05                 xRangeList->Join( *ppData[ nIndex ] );
619 //UNUSED2009-05         }
620 //UNUSED2009-05     }
621 //UNUSED2009-05     return xRangeList;
622 //UNUSED2009-05 }
623 
624 
625 //UNUSED2009-05 ScRangeListRef ScChartPositionMap::GetRowRanges( SCROW nChartRow ) const
626 //UNUSED2009-05 {
627 //UNUSED2009-05     ScRangeListRef xRangeList = new ScRangeList;
628 //UNUSED2009-05     if ( nChartRow < nRowCount )
629 //UNUSED2009-05     {
630 //UNUSED2009-05         sal_uLong nStop = GetIndex( nColCount, nChartRow );
631 //UNUSED2009-05         for ( sal_uLong nIndex = GetIndex( 0, nChartRow ); nIndex < nStop;
632 //UNUSED2009-05                 nIndex += nRowCount )
633 //UNUSED2009-05         {
634 //UNUSED2009-05             if ( ppData[ nIndex ] )
635 //UNUSED2009-05                 xRangeList->Join( *ppData[ nIndex ] );
636 //UNUSED2009-05         }
637 //UNUSED2009-05     }
638 //UNUSED2009-05     return xRangeList;
639 //UNUSED2009-05 }
640