xref: /aoo41x/main/sc/source/core/tool/chartarr.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 
32 
33 // INCLUDE ---------------------------------------------------------------
34 
35 #include "scitems.hxx"
36 #include <svl/intitem.hxx>
37 #include <svl/zforlist.hxx>
38 #include <float.h>				// DBL_MIN
39 
40 #include "chartarr.hxx"
41 #include "document.hxx"
42 #include "rechead.hxx"
43 #include "globstr.hrc"
44 #include "cell.hxx"
45 #include "docoptio.hxx"
46 
47 #include <vector>
48 
49 using ::std::vector;
50 
51 // -----------------------------------------------------------------------
52 
53 ScMemChart::ScMemChart(short nCols, short nRows)
54 {
55     nRowCnt = nRows;
56     nColCnt = nCols;
57     pData   = new double[nColCnt * nRowCnt];
58 
59     if (pData)
60     {
61         double *pFill = pData;
62 
63         for (short i = 0; i < nColCnt; i++)
64             for (short j = 0; j < nRowCnt; j++)
65                 *(pFill ++) = 0.0;
66     }
67 
68     pColText = new String[nColCnt];
69     pRowText = new String[nRowCnt];
70 }
71 
72 ScMemChart::~ScMemChart()
73 {
74     delete[] pRowText;
75     delete[] pColText;
76     delete[] pData;
77 }
78 
79 // -----------------------------------------------------------------------
80 
81 ScChartArray::ScChartArray( ScDocument* pDoc, SCTAB nTab,
82                     SCCOL nStartColP, SCROW nStartRowP, SCCOL nEndColP, SCROW nEndRowP,
83 					const String& rChartName ) :
84 		aName( rChartName ),
85 		pDocument( pDoc ),
86         aPositioner(pDoc, nTab, nStartColP, nStartRowP, nEndColP, nEndRowP),
87 		bValid( sal_True )
88 {
89 }
90 
91 ScChartArray::ScChartArray( ScDocument* pDoc, const ScRangeListRef& rRangeList,
92 					const String& rChartName ) :
93 		aName( rChartName ),
94 		pDocument( pDoc ),
95         aPositioner(pDoc, rRangeList),
96 		bValid( sal_True )
97 {
98 }
99 
100 ScChartArray::ScChartArray( const ScChartArray& rArr ) :
101         ScDataObject(),
102 		aName(rArr.aName),
103 		pDocument(rArr.pDocument),
104         aPositioner(rArr.aPositioner),
105 		bValid(rArr.bValid)
106 {
107 }
108 
109 ScChartArray::~ScChartArray()
110 {
111 }
112 
113 ScDataObject* ScChartArray::Clone() const
114 {
115 	return new ScChartArray(*this);
116 }
117 
118 sal_Bool ScChartArray::operator==(const ScChartArray& rCmp) const
119 {
120 	return aPositioner == rCmp.aPositioner
121 		&& aName == rCmp.aName;
122 }
123 
124 #ifdef _MSC_VER
125 #pragma optimize("",off)
126 #endif
127 
128 ScMemChart* ScChartArray::CreateMemChart()
129 {
130     ScRangeListRef aRangeListRef(GetRangeList());
131 	sal_uLong nCount = aRangeListRef->Count();
132 	if ( nCount > 1 )
133 		return CreateMemChartMulti();
134 	else if ( nCount == 1 )
135 	{
136 		ScRange* pR = aRangeListRef->First();
137 		if ( pR->aStart.Tab() != pR->aEnd.Tab() )
138 			return CreateMemChartMulti();
139 		else
140 			return CreateMemChartSingle();
141 	}
142 	else
143 		return CreateMemChartMulti();	// kann 0 Range besser ab als Single
144 }
145 
146 ScMemChart* ScChartArray::CreateMemChartSingle()
147 {
148 	SCSIZE nCol;
149 	SCSIZE nRow;
150 
151 		//
152 		//	wirkliche Groesse (ohne versteckte Zeilen/Spalten)
153 		//
154 
155 	SCCOL nColAdd = HasRowHeaders() ? 1 : 0;
156 	SCROW nRowAdd = HasColHeaders() ? 1 : 0;
157 
158 	SCCOL nCol1;
159 	SCROW nRow1;
160 	SCTAB nTab1;
161 	SCCOL nCol2;
162 	SCROW nRow2;
163 	SCTAB nTab2;
164 	ScRangeListRef aRangeListRef(GetRangeList());
165 	aRangeListRef->First()->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
166 
167 	SCCOL nStrCol = nCol1;		// fuer Beschriftung merken
168 	SCROW nStrRow = nRow1;
169 	// Skip hidden columns.
170 	// TODO: make use of last column value once implemented.
171 	SCCOL nLastCol = -1;
172 	while (pDocument->ColHidden(nCol1, nTab1, nLastCol))
173 		++nCol1;
174 
175 	// Skip hidden rows.
176 	SCROW nLastRow = -1;
177 	if (pDocument->RowHidden(nRow1, nTab1, nLastRow))
178 		nRow1 = nLastRow + 1;
179 
180 	// falls alles hidden ist, bleibt die Beschriftung am Anfang
181 	if ( nCol1 <= nCol2 )
182 	{
183 		nStrCol = nCol1;
184         nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nColAdd );
185 	}
186 	if ( nRow1 <= nRow2 )
187 	{
188 		nStrRow = nRow1;
189         nRow1 = sal::static_int_cast<SCROW>( nRow1 + nRowAdd );
190 	}
191 
192 	SCSIZE nTotalCols = ( nCol1 <= nCol2 ? nCol2 - nCol1 + 1 : 0 );
193 	vector<SCCOL> aCols;
194 	aCols.reserve(nTotalCols);
195 	for (SCSIZE i=0; i<nTotalCols; i++)
196 	{
197 		SCCOL nThisCol = sal::static_int_cast<SCCOL>(nCol1+i);
198 		if (!pDocument->ColHidden(nThisCol, nTab1, nLastCol))
199 			aCols.push_back(nThisCol);
200 	}
201 	SCSIZE nColCount = aCols.size();
202 
203 	SCSIZE nTotalRows = ( nRow1 <= nRow2 ? nRow2 - nRow1 + 1 : 0 );
204 	vector<SCROW> aRows;
205 	aRows.reserve(nTotalRows);
206 	if (nRow1 <= nRow2)
207 	{
208 		// Get all visible rows between nRow1 and nRow2.
209 		SCROW nThisRow = nRow1;
210 		while (nThisRow <= nRow2)
211 		{
212 			if (pDocument->RowHidden(nThisRow, nTab1, nLastRow))
213 				nThisRow = nLastRow;
214 			else
215 				aRows.push_back(nThisRow);
216 			++nThisRow;
217 		}
218 	}
219 	SCSIZE nRowCount = aRows.size();
220 
221     // May happen at least with more than 32k rows.
222     if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
223     {
224         nColCount = 0;
225         nRowCount = 0;
226     }
227 
228 	sal_Bool bValidData = sal_True;
229 	if ( !nColCount )
230 	{
231 		bValidData = sal_False;
232 		nColCount = 1;
233 		aCols.push_back(nStrCol);
234 	}
235 	if ( !nRowCount )
236 	{
237 		bValidData = sal_False;
238 		nRowCount = 1;
239 		aRows.push_back(nStrRow);
240 	}
241 
242 		//
243 		//	Daten
244 		//
245 
246     ScMemChart* pMemChart = new ScMemChart(
247             static_cast<short>(nColCount), static_cast<short>(nRowCount) );
248 	if (pMemChart)
249 	{
250 // 		SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
251 //		pMemChart->SetNumberFormatter( pFormatter );
252 		if ( bValidData )
253 		{
254 			sal_Bool bCalcAsShown = pDocument->GetDocOptions().IsCalcAsShown();
255 			ScBaseCell* pCell;
256 			for (nCol=0; nCol<nColCount; nCol++)
257 			{
258 				for (nRow=0; nRow<nRowCount; nRow++)
259 				{
260 					double nVal = DBL_MIN;		// Hack fuer Chart, um leere Zellen zu erkennen
261 
262 					pDocument->GetCell( aCols[nCol], aRows[nRow], nTab1, pCell );
263 					if (pCell)
264 					{
265 						CellType eType = pCell->GetCellType();
266 						if (eType == CELLTYPE_VALUE)
267 						{
268 							nVal = ((ScValueCell*)pCell)->GetValue();
269 							if ( bCalcAsShown && nVal != 0.0 )
270 							{
271 								sal_uInt32 nFormat;
272 								pDocument->GetNumberFormat( aCols[nCol],
273 									aRows[nRow], nTab1, nFormat );
274 								nVal = pDocument->RoundValueAsShown( nVal, nFormat );
275 							}
276 						}
277 						else if (eType == CELLTYPE_FORMULA)
278 						{
279 							ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
280 							if ( (pFCell->GetErrCode() == 0) && pFCell->IsValue() )
281 								nVal = pFCell->GetValue();
282 						}
283 					}
284 					pMemChart->SetData(static_cast<short>(nCol), static_cast<short>(nRow), nVal);
285 				}
286 			}
287 		}
288 		else
289 		{
290 			//!	Flag, dass Daten ungueltig ??
291 
292 			for (nCol=0; nCol<nColCount; nCol++)
293 				for (nRow=0; nRow<nRowCount; nRow++)
294 					pMemChart->SetData( static_cast<short>(nCol), static_cast<short>(nRow), DBL_MIN );
295 		}
296 
297 		//
298 		//	Spalten-Header
299 		//
300 
301 		for (nCol=0; nCol<nColCount; nCol++)
302 		{
303             String aString, aColStr;
304 			if (HasColHeaders())
305 				pDocument->GetString( aCols[nCol], nStrRow, nTab1, aString );
306 			if ( !aString.Len() )
307 			{
308 				aString = ScGlobal::GetRscString(STR_COLUMN);
309 				aString += ' ';
310 //                aString += String::CreateFromInt32( pCols[nCol]+1 );
311                 ScAddress aPos( aCols[ nCol ], 0, 0 );
312                 aPos.Format( aColStr, SCA_VALID_COL, NULL );
313                 aString += aColStr;
314 			}
315 			pMemChart->SetColText( static_cast<short>(nCol), aString);
316 
317 //            sal_uLong nNumberAttr = (nTotalRows ? pDocument->GetNumberFormat(
318 //                        ScAddress( pCols[nCol], nRow1, nTab1)) : 0);
319 //			pMemChart->SetNumFormatIdCol( static_cast<long>(nCol), nNumberAttr );
320 		}
321 
322 		//
323 		//	Zeilen-Header
324 		//
325 
326 		for (nRow=0; nRow<nRowCount; nRow++)
327 		{
328 			String aString;
329 			if (HasRowHeaders())
330 			{
331 				ScAddress aAddr( nStrCol, aRows[nRow], nTab1 );
332 				pDocument->GetString( nStrCol, aRows[nRow], nTab1, aString );
333 			}
334 			if ( !aString.Len() )
335 			{
336 				aString = ScGlobal::GetRscString(STR_ROW);
337 				aString += ' ';
338 				aString += String::CreateFromInt32( aRows[nRow]+1 );
339 			}
340 			pMemChart->SetRowText( static_cast<short>(nRow), aString);
341 
342 //            sal_uLong nNumberAttr = (nTotalCols ? pDocument->GetNumberFormat(
343 //                        ScAddress( nCol1, pRows[nRow], nTab1)) : 0);
344 //			pMemChart->SetNumFormatIdRow( static_cast<long>(nRow), nNumberAttr );
345 		}
346 
347 		//
348 		//  Titel
349 		//
350 
351 //		pMemChart->SetMainTitle(ScGlobal::GetRscString(STR_CHART_MAINTITLE));
352 //		pMemChart->SetSubTitle(ScGlobal::GetRscString(STR_CHART_SUBTITLE));
353 //		pMemChart->SetXAxisTitle(ScGlobal::GetRscString(STR_CHART_XTITLE));
354 //		pMemChart->SetYAxisTitle(ScGlobal::GetRscString(STR_CHART_YTITLE));
355 //		pMemChart->SetZAxisTitle(ScGlobal::GetRscString(STR_CHART_ZTITLE));
356 
357 		//
358 		//	Zahlen-Typ
359 		//
360 
361 //        sal_uLong nNumberAttr = (nTotalCols && nTotalRows ?
362 //                pDocument->GetNumberFormat( ScAddress( nCol1, nRow1, nTab1)) :
363 //                0);
364 //		if (pFormatter)
365 //			pMemChart->SetDataType(pFormatter->GetType( nNumberAttr ));
366 
367 		//
368 		//	Parameter-Strings
369 		//
370 
371 //        SetExtraStrings( *pMemChart );
372 	}
373 
374 	return pMemChart;
375 }
376 
377 ScMemChart* ScChartArray::CreateMemChartMulti()
378 {
379 	SCSIZE nColCount = GetPositionMap()->GetColCount();
380 	SCSIZE nRowCount = GetPositionMap()->GetRowCount();
381 
382 	SCSIZE nCol = 0;
383 	SCSIZE nRow = 0;
384 
385     // May happen at least with more than 32k rows.
386     if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
387     {
388         nColCount = 0;
389         nRowCount = 0;
390     }
391 
392 	sal_Bool bValidData = sal_True;
393 	if ( !nColCount )
394 	{
395 		bValidData = sal_False;
396 		nColCount = 1;
397 	}
398 	if ( !nRowCount )
399 	{
400 		bValidData = sal_False;
401 		nRowCount = 1;
402 	}
403 
404 	//
405 	//	Daten
406 	//
407 
408     ScMemChart* pMemChart = new ScMemChart(
409             static_cast<short>(nColCount), static_cast<short>(nRowCount) );
410 	if (pMemChart)
411 	{
412 //		pMemChart->SetNumberFormatter( pDocument->GetFormatTable() );
413         sal_Bool bCalcAsShown = pDocument->GetDocOptions().IsCalcAsShown();
414         sal_uLong nIndex = 0;
415         if (bValidData)
416         {
417             for ( nCol = 0; nCol < nColCount; nCol++ )
418             {
419                 for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
420                 {
421                     double nVal = DBL_MIN;		// Hack fuer Chart, um leere Zellen zu erkennen
422                     const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
423                     if ( pPos )
424                     {	// sonst: Luecke
425                         ScBaseCell* pCell = pDocument->GetCell( *pPos );
426                         if (pCell)
427                         {
428                             CellType eType = pCell->GetCellType();
429                             if (eType == CELLTYPE_VALUE)
430                             {
431                                 nVal = ((ScValueCell*)pCell)->GetValue();
432                                 if ( bCalcAsShown && nVal != 0.0 )
433                                 {
434                                     sal_uLong nFormat = pDocument->GetNumberFormat( *pPos );
435                                     nVal = pDocument->RoundValueAsShown( nVal, nFormat );
436                                 }
437                             }
438                             else if (eType == CELLTYPE_FORMULA)
439                             {
440                                 ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
441                                 if ( (pFCell->GetErrCode() == 0) && pFCell->IsValue() )
442                                     nVal = pFCell->GetValue();
443                             }
444                         }
445                     }
446                     pMemChart->SetData(static_cast<short>(nCol), static_cast<short>(nRow), nVal);
447                 }
448             }
449         }
450 		else
451 		{
452 			for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
453 			{
454 				double nVal = DBL_MIN;		// Hack fuer Chart, um leere Zellen zu erkennen
455 				const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
456 				if ( pPos )
457 				{	// sonst: Luecke
458 					ScBaseCell* pCell = pDocument->GetCell( *pPos );
459 					if (pCell)
460 					{
461 						CellType eType = pCell->GetCellType();
462 						if (eType == CELLTYPE_VALUE)
463 						{
464 							nVal = ((ScValueCell*)pCell)->GetValue();
465 							if ( bCalcAsShown && nVal != 0.0 )
466 							{
467 								sal_uLong nFormat = pDocument->GetNumberFormat( *pPos );
468 								nVal = pDocument->RoundValueAsShown( nVal, nFormat );
469 							}
470 						}
471 						else if (eType == CELLTYPE_FORMULA)
472 						{
473 							ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
474 							if ( (pFCell->GetErrCode() == 0) && pFCell->IsValue() )
475 								nVal = pFCell->GetValue();
476 						}
477 					}
478 				}
479 				pMemChart->SetData(static_cast<short>(nCol), static_cast<short>(nRow), nVal);
480 			}
481 		}
482 
483 //2do: Beschriftung bei Luecken
484 
485 		//
486 		//	Spalten-Header
487 		//
488 
489 		SCCOL nPosCol = 0;
490 		for ( nCol = 0; nCol < nColCount; nCol++ )
491 		{
492             String aString, aColStr;
493 			const ScAddress* pPos = GetPositionMap()->GetColHeaderPosition( static_cast<SCCOL>(nCol) );
494 			if ( HasColHeaders() && pPos )
495 				pDocument->GetString(
496 					pPos->Col(), pPos->Row(), pPos->Tab(), aString );
497 			if ( !aString.Len() )
498 			{
499 				aString = ScGlobal::GetRscString(STR_COLUMN);
500 				aString += ' ';
501 				if ( pPos )
502 					nPosCol = pPos->Col() + 1;
503 				else
504 					nPosCol++;
505                 ScAddress aPos( nPosCol - 1, 0, 0 );
506                 aPos.Format( aColStr, SCA_VALID_COL, NULL );
507 //                aString += String::CreateFromInt32( nPosCol );
508                 aString += aColStr;
509 			}
510 			pMemChart->SetColText( static_cast<short>(nCol), aString);
511 
512 //			sal_uLong nNumberAttr = 0;
513 //			pPos = GetPositionMap()->GetPosition( nCol, 0 );
514 //			if ( pPos )
515 //				nNumberAttr = pDocument->GetNumberFormat( *pPos );
516 //			pMemChart->SetNumFormatIdCol( static_cast<long>(nCol), nNumberAttr );
517 		}
518 
519 		//
520 		//	Zeilen-Header
521 		//
522 
523 		SCROW nPosRow = 0;
524 		for ( nRow = 0; nRow < nRowCount; nRow++ )
525 		{
526 			String aString;
527 			const ScAddress* pPos = GetPositionMap()->GetRowHeaderPosition( nRow );
528 			if ( HasRowHeaders() && pPos )
529 			{
530 				pDocument->GetString(
531 					pPos->Col(), pPos->Row(), pPos->Tab(), aString );
532 			}
533 			if ( !aString.Len() )
534 			{
535 				aString = ScGlobal::GetRscString(STR_ROW);
536 				aString += ' ';
537 				if ( pPos )
538 					nPosRow = pPos->Row() + 1;
539 				else
540 					nPosRow++;
541 				aString += String::CreateFromInt32( nPosRow );
542 			}
543 			pMemChart->SetRowText( static_cast<short>(nRow), aString);
544 
545 //			sal_uLong nNumberAttr = 0;
546 //			pPos = GetPositionMap()->GetPosition( 0, nRow );
547 //			if ( pPos )
548 //				nNumberAttr = pDocument->GetNumberFormat( *pPos );
549 //			pMemChart->SetNumFormatIdRow( static_cast<long>(nRow), nNumberAttr );
550 		}
551 
552 		//
553 		//  Titel
554 		//
555 
556 //		pMemChart->SetMainTitle(ScGlobal::GetRscString(STR_CHART_MAINTITLE));
557 //		pMemChart->SetSubTitle(ScGlobal::GetRscString(STR_CHART_SUBTITLE));
558 //		pMemChart->SetXAxisTitle(ScGlobal::GetRscString(STR_CHART_XTITLE));
559 //		pMemChart->SetYAxisTitle(ScGlobal::GetRscString(STR_CHART_YTITLE));
560 //		pMemChart->SetZAxisTitle(ScGlobal::GetRscString(STR_CHART_ZTITLE));
561 
562 		//
563 		//	Zahlen-Typ
564 		//
565 
566 //		SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
567 //		if (pFormatter)
568 //		{
569 //			sal_uLong nIndex = 0;
570 //			sal_uLong nCount = GetPositionMap()->GetCount();
571 //			const ScAddress* pPos;
572 //			do
573 //			{
574 //				pPos = GetPositionMap()->GetPosition( nIndex );
575 //			} while ( !pPos && ++nIndex < nCount );
576 //			sal_uLong nFormat = ( pPos ? pDocument->GetNumberFormat( *pPos ) : 0 );
577 //			pMemChart->SetDataType( pFormatter->GetType( nFormat ) );
578 //		}
579 
580 		//
581 		//	Parameter-Strings
582 		//
583 
584 //        SetExtraStrings( *pMemChart );
585 	}
586 
587 	return pMemChart;
588 }
589 
590 #ifdef _MSC_VER
591 #pragma optimize("",on)
592 #endif
593 
594 
595 //
596 //				Collection
597 //
598 
599 ScDataObject*	ScChartCollection::Clone() const
600 {
601 	return new ScChartCollection(*this);
602 }
603 
604 sal_Bool ScChartCollection::operator==(const ScChartCollection& rCmp) const
605 {
606 	if (nCount != rCmp.nCount)
607 		return sal_False;
608 
609 	for (sal_uInt16 i=0; i<nCount; i++)
610 		if (!((*(const ScChartArray*)pItems[i]) == (*(const ScChartArray*)rCmp.pItems[i])))
611 			return sal_False;
612 
613 	return sal_True;
614 }
615 
616