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