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