LibreOffice Module sc (master)  1
chartarr.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <float.h>
21 
22 #include <chartarr.hxx>
23 #include <cellvalue.hxx>
24 #include <document.hxx>
25 #include <globstr.hrc>
26 #include <scresid.hxx>
27 #include <formulacell.hxx>
28 #include <docoptio.hxx>
29 
30 #include <formula/errorcodes.hxx>
31 
32 #include <memory>
33 #include <vector>
34 
35 using ::std::vector;
36 
38 {
39  nRowCnt = nRows;
40  nColCnt = nCols;
41  pData.reset( new double[nColCnt * nRowCnt] );
42 
43  memset( pData.get(), 0.0, nColCnt * nRowCnt );
44 
45  pColText.reset( new OUString[nColCnt] );
46  pRowText.reset( new OUString[nRowCnt] );
47 }
48 
50 {
51 }
52 
54  ScDocument& rDoc, const ScRangeListRef& rRangeList ) :
55  rDocument( rDoc ),
56  aPositioner(rDoc, rRangeList) {}
57 
58 std::unique_ptr<ScMemChart> ScChartArray::CreateMemChart()
59 {
60  ScRangeListRef aRangeListRef(GetRangeList());
61  size_t nCount = aRangeListRef->size();
62  if ( nCount > 1 )
63  return CreateMemChartMulti();
64  else if ( nCount == 1 )
65  {
66  const ScRange & rR = aRangeListRef->front();
67  if ( rR.aStart.Tab() != rR.aEnd.Tab() )
68  return CreateMemChartMulti();
69  else
70  return CreateMemChartSingle();
71  }
72  else
73  return CreateMemChartMulti(); // Can handle 0 range better than Single
74 }
75 
76 namespace {
77 
78 double getCellValue( ScDocument& rDoc, const ScAddress& rPos, double fDefault, bool bCalcAsShown )
79 {
80  double fRet = fDefault;
81 
82  ScRefCellValue aCell(rDoc, rPos);
83  switch (aCell.meType)
84  {
85  case CELLTYPE_VALUE:
86  {
87  fRet = aCell.getValue();
88  if (bCalcAsShown && fRet != 0.0)
89  {
90  sal_uInt32 nFormat = rDoc.GetNumberFormat(rPos);
91  fRet = rDoc.RoundValueAsShown(fRet, nFormat);
92  }
93  }
94  break;
95  case CELLTYPE_FORMULA:
96  {
97  ScFormulaCell* pFCell = aCell.mpFormula;
98  if (pFCell && pFCell->GetErrCode() == FormulaError::NONE && pFCell->IsValue())
99  fRet = pFCell->GetValue();
100  }
101  break;
102  default:
103  ;
104  }
105  return fRet;
106 }
107 
108 }
109 
110 std::unique_ptr<ScMemChart> ScChartArray::CreateMemChartSingle()
111 {
112  SCSIZE nCol;
113  SCSIZE nRow;
114 
115  // real size (without hidden rows/columns)
116 
117  SCCOL nColAdd = HasRowHeaders() ? 1 : 0;
118  SCROW nRowAdd = HasColHeaders() ? 1 : 0;
119 
120  SCCOL nCol1;
121  SCROW nRow1;
122  SCTAB nTab1;
123  SCCOL nCol2;
124  SCROW nRow2;
125  SCTAB nTab2;
126  ScRangeListRef aRangeListRef(GetRangeList());
127  aRangeListRef->front().GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
128 
129  SCCOL nStrCol = nCol1; // remember for labeling
130  SCROW nStrRow = nRow1;
131  // Skip hidden columns.
132  // TODO: make use of last column value once implemented.
133  SCCOL nLastCol = -1;
134  while (rDocument.ColHidden(nCol1, nTab1, nullptr, &nLastCol))
135  ++nCol1;
136 
137  // Skip hidden rows.
138  SCROW nLastRow = -1;
139  if (rDocument.RowHidden(nRow1, nTab1, nullptr, &nLastRow))
140  nRow1 = nLastRow + 1;
141 
142  // if everything is hidden then the label remains at the beginning
143  if ( nCol1 <= nCol2 )
144  {
145  nStrCol = nCol1;
146  nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nColAdd );
147  }
148  if ( nRow1 <= nRow2 )
149  {
150  nStrRow = nRow1;
151  nRow1 = sal::static_int_cast<SCROW>( nRow1 + nRowAdd );
152  }
153 
154  SCSIZE nTotalCols = ( nCol1 <= nCol2 ? nCol2 - nCol1 + 1 : 0 );
155  vector<SCCOL> aCols;
156  aCols.reserve(nTotalCols);
157  for (SCSIZE i=0; i<nTotalCols; i++)
158  {
159  SCCOL nThisCol = sal::static_int_cast<SCCOL>(nCol1+i);
160  if (!rDocument.ColHidden(nThisCol, nTab1, nullptr, &nLastCol))
161  aCols.push_back(nThisCol);
162  }
163  SCSIZE nColCount = aCols.size();
164 
165  SCSIZE nTotalRows = ( nRow1 <= nRow2 ? nRow2 - nRow1 + 1 : 0 );
166  vector<SCROW> aRows;
167  aRows.reserve(nTotalRows);
168  if (nRow1 <= nRow2)
169  {
170  // Get all visible rows between nRow1 and nRow2.
171  SCROW nThisRow = nRow1;
172  while (nThisRow <= nRow2)
173  {
174  if (rDocument.RowHidden(nThisRow, nTab1, nullptr, &nLastRow))
175  nThisRow = nLastRow;
176  else
177  aRows.push_back(nThisRow);
178  ++nThisRow;
179  }
180  }
181  SCSIZE nRowCount = aRows.size();
182 
183  // May happen at least with more than 32k rows.
184  if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
185  {
186  nColCount = 0;
187  nRowCount = 0;
188  }
189 
190  bool bValidData = true;
191  if ( !nColCount )
192  {
193  bValidData = false;
194  nColCount = 1;
195  aCols.push_back(nStrCol);
196  }
197  if ( !nRowCount )
198  {
199  bValidData = false;
200  nRowCount = 1;
201  aRows.push_back(nStrRow);
202  }
203 
204  // Data
205  std::unique_ptr<ScMemChart> pMemChart(new ScMemChart( nColCount, nRowCount ));
206 
207  if ( bValidData )
208  {
209  bool bCalcAsShown = rDocument.GetDocOptions().IsCalcAsShown();
210  for (nCol=0; nCol<nColCount; nCol++)
211  {
212  for (nRow=0; nRow<nRowCount; nRow++)
213  {
214  // DBL_MIN is a Hack for Chart to recognize empty cells.
215  ScAddress aPos(aCols[nCol], aRows[nRow], nTab1);
216  double nVal = getCellValue(rDocument, aPos, DBL_MIN, bCalcAsShown);
217  pMemChart->SetData(nCol, nRow, nVal);
218  }
219  }
220  }
221  else
222  {
223  // Flag marking data as invalid?
224  for (nCol=0; nCol<nColCount; nCol++)
225  for (nRow=0; nRow<nRowCount; nRow++)
226  pMemChart->SetData( nCol, nRow, DBL_MIN );
227  }
228 
229  // Column Header
230 
231  for (nCol=0; nCol<nColCount; nCol++)
232  {
233  OUString aString;
234  if (HasColHeaders())
235  aString = rDocument.GetString(aCols[nCol], nStrRow, nTab1);
236  if (aString.isEmpty())
237  {
238  OUStringBuffer aBuf;
239  aBuf.append(ScResId(STR_COLUMN));
240  aBuf.append(' ');
241 
242  ScAddress aPos( aCols[ nCol ], 0, 0 );
243  aBuf.append(aPos.Format(ScRefFlags::COL_VALID));
244 
245  aString = aBuf.makeStringAndClear();
246  }
247  pMemChart->SetColText( nCol, aString);
248  }
249 
250  // Row Header
251 
252  for (nRow=0; nRow<nRowCount; nRow++)
253  {
254  OUString aString;
255  if (HasRowHeaders())
256  {
257  aString = rDocument.GetString(nStrCol, aRows[nRow], nTab1);
258  }
259  if (aString.isEmpty())
260  {
261  OUStringBuffer aBuf;
262  aBuf.append(ScResId(STR_ROW));
263  aBuf.append(' ');
264  aBuf.append(static_cast<sal_Int32>(aRows[nRow]+1));
265  aString = aBuf.makeStringAndClear();
266  }
267  pMemChart->SetRowText( nRow, aString);
268  }
269 
270  return pMemChart;
271 }
272 
273 std::unique_ptr<ScMemChart> ScChartArray::CreateMemChartMulti()
274 {
276  SCSIZE nRowCount = GetPositionMap()->GetRowCount();
277 
278  // May happen at least with more than 32k rows.
279  if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
280  {
281  nColCount = 0;
282  nRowCount = 0;
283  }
284 
285  bool bValidData = true;
286  if ( !nColCount )
287  {
288  bValidData = false;
289  nColCount = 1;
290  }
291  if ( !nRowCount )
292  {
293  bValidData = false;
294  nRowCount = 1;
295  }
296 
297  // Data
298  std::unique_ptr<ScMemChart> pMemChart(new ScMemChart( nColCount, nRowCount ));
299 
300  SCSIZE nCol = 0;
301  SCSIZE nRow = 0;
302  bool bCalcAsShown = rDocument.GetDocOptions().IsCalcAsShown();
303  sal_uLong nIndex = 0;
304  if (bValidData)
305  {
306  for ( nCol = 0; nCol < nColCount; nCol++ )
307  {
308  for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
309  {
310  double nVal = DBL_MIN; // Hack for Chart to recognize empty cells
311  const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
312  if (pPos)
313  // otherwise: Gap
314  nVal = getCellValue(rDocument, *pPos, DBL_MIN, bCalcAsShown);
315 
316  pMemChart->SetData(nCol, nRow, nVal);
317  }
318  }
319  }
320  else
321  {
322  for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
323  {
324  double nVal = DBL_MIN; // Hack for Chart to recognize empty cells
325  const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
326  if (pPos)
327  // otherwise: Gap
328  nVal = getCellValue(rDocument, *pPos, DBL_MIN, bCalcAsShown);
329 
330  pMemChart->SetData(nCol, nRow, nVal);
331  }
332  }
333 
334  //TODO: Label when gaps
335 
336  // Column header
337 
338  SCCOL nPosCol = 0;
339  for ( nCol = 0; nCol < nColCount; nCol++ )
340  {
341  OUString aString;
342  const ScAddress* pPos = GetPositionMap()->GetColHeaderPosition( static_cast<SCCOL>(nCol) );
343  if ( HasColHeaders() && pPos )
344  aString = rDocument.GetString(pPos->Col(), pPos->Row(), pPos->Tab());
345 
346  if (aString.isEmpty())
347  {
348  OUStringBuffer aBuf(ScResId(STR_COLUMN));
349  aBuf.append(' ');
350  if ( pPos )
351  nPosCol = pPos->Col() + 1;
352  else
353  nPosCol++;
354  ScAddress aPos( nPosCol - 1, 0, 0 );
355  aBuf.append(aPos.Format(ScRefFlags::COL_VALID));
356  aString = aBuf.makeStringAndClear();
357  }
358  pMemChart->SetColText( nCol, aString);
359  }
360 
361  // Row header
362 
363  SCROW nPosRow = 0;
364  for ( nRow = 0; nRow < nRowCount; nRow++ )
365  {
366  OUString aString;
367  const ScAddress* pPos = GetPositionMap()->GetRowHeaderPosition( nRow );
368  if ( HasRowHeaders() && pPos )
369  aString = rDocument.GetString(pPos->Col(), pPos->Row(), pPos->Tab());
370 
371  if (aString.isEmpty())
372  {
373  if ( pPos )
374  nPosRow = pPos->Row() + 1;
375  else
376  nPosRow++;
377  aString = ScResId(STR_ROW) + " " + OUString::number(static_cast<sal_Int32>(nPosRow));
378  }
379  pMemChart->SetRowText( nRow, aString);
380  }
381 
382  return pMemChart;
383 }
384 
385 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const int nColCount
const ScAddress * GetRowHeaderPosition(SCROW nChartRow) const
Definition: chartpos.hxx:85
SC_DLLPUBLIC void Format(OStringBuffer &r, ScRefFlags nFlags, const ScDocument *pDocument=nullptr, const Details &rDetails=detailsOOOa1) const
Definition: address.cxx:2116
sal_Int32 nIndex
ScAddress aStart
Definition: address.hxx:500
SCROW Row() const
Definition: address.hxx:262
sal_uIntPtr sal_uLong
const ScAddress * GetPosition(sal_uLong nIndex) const
Definition: chartpos.hxx:65
aBuf
SC_DLLPUBLIC void GetNumberFormat(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt32 &rFormat) const
Definition: document.cxx:3639
ScAddress aEnd
Definition: address.hxx:501
SCCOL GetColCount() const
deletes all ScAddress*
Definition: chartpos.hxx:56
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:104
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:45
double GetValue()
SCROW nRowCnt
Definition: chartarr.hxx:36
FormulaError GetErrCode()
std::unique_ptr< ScMemChart > CreateMemChartSingle()
Definition: chartarr.cxx:110
int nCount
SC_DLLPUBLIC OUString GetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext *pContext=nullptr) const
Definition: document.cxx:3484
std::unique_ptr< double[]> pData
Definition: chartarr.hxx:38
SCTAB Tab() const
Definition: address.hxx:271
SC_DLLPUBLIC const ScDocOptions & GetDocOptions() const
Definition: documen3.cxx:1922
bool HasRowHeaders() const
Definition: chartarr.hxx:78
SC_DLLPUBLIC bool ColHidden(SCCOL nCol, SCTAB nTab, SCCOL *pFirstCol=nullptr, SCCOL *pLastCol=nullptr) const
Definition: document.cxx:4443
std::unique_ptr< OUString[]> pRowText
Definition: chartarr.hxx:40
ScDocument & rDocument
Definition: chartarr.hxx:63
int i
sal_Int16 SCCOL
Definition: types.hxx:22
ScMemChart(const ScMemChart &rMemChart)=delete
const ScAddress * GetColHeaderPosition(SCCOL nChartCol) const
Definition: chartpos.hxx:79
size_t size() const
Definition: rangelst.hxx:90
OUString ScResId(const char *pId)
Definition: scdll.cxx:89
ScChartArray(ScDocument &rDoc, const ScRangeListRef &rRangeList)
Definition: chartarr.cxx:53
SCROW GetRowCount() const
Definition: chartpos.hxx:57
void GetVars(SCCOL &nCol1, SCROW &nRow1, SCTAB &nTab1, SCCOL &nCol2, SCROW &nRow2, SCTAB &nTab2) const
Definition: address.hxx:693
SCCOL Col() const
Definition: address.hxx:267
SC_DLLPUBLIC double RoundValueAsShown(double fVal, sal_uInt32 nFormat, const ScInterpreterContext *pContext=nullptr) const
Definition: documen4.cxx:633
sal_Int32 SCROW
Definition: types.hxx:18
const ScChartPositionMap * GetPositionMap()
Definition: chartarr.hxx:74
std::unique_ptr< ScMemChart > CreateMemChart()
Definition: chartarr.cxx:58
bool IsCalcAsShown() const
Definition: docoptio.hxx:82
std::unique_ptr< OUString[]> pColText
Definition: chartarr.hxx:39
SCCOL nColCnt
Definition: chartarr.hxx:37
bool HasColHeaders() const
Definition: chartarr.hxx:77
SC_DLLPUBLIC bool RowHidden(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4427
const ScRangeListRef & GetRangeList() const
Definition: chartarr.hxx:73
ScRange & front()
Definition: rangelst.hxx:93
std::unique_ptr< ScMemChart > CreateMemChartMulti()
Definition: chartarr.cxx:273
sal_Int16 SCTAB
Definition: types.hxx:23