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