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