xref: /AOO41X/main/sc/source/core/tool/chartarr.cxx (revision b3f79822e811ac3493b185030a72c3c5a51f32d8)
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