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 <scitems.hxx>
21 #include <svl/intitem.hxx>
22 #include <svl/zforlist.hxx>
23 #include <float.h>
24 
25 #include <chartarr.hxx>
26 #include <cellvalue.hxx>
27 #include <document.hxx>
28 #include <rechead.hxx>
29 #include <globstr.hrc>
30 #include <scresid.hxx>
31 #include <formulacell.hxx>
32 #include <docoptio.hxx>
33 
34 #include <formula/errorcodes.hxx>
35 
36 #include <memory>
37 #include <vector>
38 
39 using ::std::vector;
40 
42 {
43  nRowCnt = nRows;
44  nColCnt = nCols;
45  pData.reset( new double[nColCnt * nRowCnt] );
46 
47  memset( pData.get(), 0.0, nColCnt * nRowCnt );
48 
49  pColText.reset( new OUString[nColCnt] );
50  pRowText.reset( new OUString[nRowCnt] );
51 }
52 
54 {
55 }
56 
58  ScDocument* pDoc, const ScRangeListRef& rRangeList ) :
59  pDocument( pDoc ),
60  aPositioner(pDoc, rRangeList) {}
61 
62 std::unique_ptr<ScMemChart> ScChartArray::CreateMemChart()
63 {
64  ScRangeListRef aRangeListRef(GetRangeList());
65  size_t nCount = aRangeListRef->size();
66  if ( nCount > 1 )
67  return CreateMemChartMulti();
68  else if ( nCount == 1 )
69  {
70  const ScRange & rR = aRangeListRef->front();
71  if ( rR.aStart.Tab() != rR.aEnd.Tab() )
72  return CreateMemChartMulti();
73  else
74  return CreateMemChartSingle();
75  }
76  else
77  return CreateMemChartMulti(); // Can handle 0 range better than Single
78 }
79 
80 namespace {
81 
82 double getCellValue( ScDocument& rDoc, const ScAddress& rPos, double fDefault, bool bCalcAsShown )
83 {
84  double fRet = fDefault;
85 
86  ScRefCellValue aCell(rDoc, rPos);
87  switch (aCell.meType)
88  {
89  case CELLTYPE_VALUE:
90  {
91  fRet = aCell.getValue();
92  if (bCalcAsShown && fRet != 0.0)
93  {
94  sal_uInt32 nFormat = rDoc.GetNumberFormat(rPos);
95  fRet = rDoc.RoundValueAsShown(fRet, nFormat);
96  }
97  }
98  break;
99  case CELLTYPE_FORMULA:
100  {
101  ScFormulaCell* pFCell = aCell.mpFormula;
102  if (pFCell && pFCell->GetErrCode() == FormulaError::NONE && pFCell->IsValue())
103  fRet = pFCell->GetValue();
104  }
105  break;
106  default:
107  ;
108  }
109  return fRet;
110 }
111 
112 }
113 
114 std::unique_ptr<ScMemChart> ScChartArray::CreateMemChartSingle()
115 {
116  SCSIZE nCol;
117  SCSIZE nRow;
118 
119  // real size (without hidden rows/columns)
120 
121  SCCOL nColAdd = HasRowHeaders() ? 1 : 0;
122  SCROW nRowAdd = HasColHeaders() ? 1 : 0;
123 
124  SCCOL nCol1;
125  SCROW nRow1;
126  SCTAB nTab1;
127  SCCOL nCol2;
128  SCROW nRow2;
129  SCTAB nTab2;
130  ScRangeListRef aRangeListRef(GetRangeList());
131  aRangeListRef->front().GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
132 
133  SCCOL nStrCol = nCol1; // remember for labeling
134  SCROW nStrRow = nRow1;
135  // Skip hidden columns.
136  // TODO: make use of last column value once implemented.
137  SCCOL nLastCol = -1;
138  while (pDocument->ColHidden(nCol1, nTab1, nullptr, &nLastCol))
139  ++nCol1;
140 
141  // Skip hidden rows.
142  SCROW nLastRow = -1;
143  if (pDocument->RowHidden(nRow1, nTab1, nullptr, &nLastRow))
144  nRow1 = nLastRow + 1;
145 
146  // if everything is hidden then the label remains at the beginning
147  if ( nCol1 <= nCol2 )
148  {
149  nStrCol = nCol1;
150  nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nColAdd );
151  }
152  if ( nRow1 <= nRow2 )
153  {
154  nStrRow = nRow1;
155  nRow1 = sal::static_int_cast<SCROW>( nRow1 + nRowAdd );
156  }
157 
158  SCSIZE nTotalCols = ( nCol1 <= nCol2 ? nCol2 - nCol1 + 1 : 0 );
159  vector<SCCOL> aCols;
160  aCols.reserve(nTotalCols);
161  for (SCSIZE i=0; i<nTotalCols; i++)
162  {
163  SCCOL nThisCol = sal::static_int_cast<SCCOL>(nCol1+i);
164  if (!pDocument->ColHidden(nThisCol, nTab1, nullptr, &nLastCol))
165  aCols.push_back(nThisCol);
166  }
167  SCSIZE nColCount = aCols.size();
168 
169  SCSIZE nTotalRows = ( nRow1 <= nRow2 ? nRow2 - nRow1 + 1 : 0 );
170  vector<SCROW> aRows;
171  aRows.reserve(nTotalRows);
172  if (nRow1 <= nRow2)
173  {
174  // Get all visible rows between nRow1 and nRow2.
175  SCROW nThisRow = nRow1;
176  while (nThisRow <= nRow2)
177  {
178  if (pDocument->RowHidden(nThisRow, nTab1, nullptr, &nLastRow))
179  nThisRow = nLastRow;
180  else
181  aRows.push_back(nThisRow);
182  ++nThisRow;
183  }
184  }
185  SCSIZE nRowCount = aRows.size();
186 
187  // May happen at least with more than 32k rows.
188  if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
189  {
190  nColCount = 0;
191  nRowCount = 0;
192  }
193 
194  bool bValidData = true;
195  if ( !nColCount )
196  {
197  bValidData = false;
198  nColCount = 1;
199  aCols.push_back(nStrCol);
200  }
201  if ( !nRowCount )
202  {
203  bValidData = false;
204  nRowCount = 1;
205  aRows.push_back(nStrRow);
206  }
207 
208  // Data
209  std::unique_ptr<ScMemChart> pMemChart(new ScMemChart( nColCount, nRowCount ));
210 
211  if ( bValidData )
212  {
213  bool bCalcAsShown = pDocument->GetDocOptions().IsCalcAsShown();
214  for (nCol=0; nCol<nColCount; nCol++)
215  {
216  for (nRow=0; nRow<nRowCount; nRow++)
217  {
218  // DBL_MIN is a Hack for Chart to recognize empty cells.
219  ScAddress aPos(aCols[nCol], aRows[nRow], nTab1);
220  double nVal = getCellValue(*pDocument, aPos, DBL_MIN, bCalcAsShown);
221  pMemChart->SetData(nCol, nRow, nVal);
222  }
223  }
224  }
225  else
226  {
227  // Flag marking data as invalid?
228  for (nCol=0; nCol<nColCount; nCol++)
229  for (nRow=0; nRow<nRowCount; nRow++)
230  pMemChart->SetData( nCol, nRow, DBL_MIN );
231  }
232 
233  // Column Header
234 
235  for (nCol=0; nCol<nColCount; nCol++)
236  {
237  OUString aString;
238  if (HasColHeaders())
239  aString = pDocument->GetString(aCols[nCol], nStrRow, nTab1);
240  if (aString.isEmpty())
241  {
242  OUStringBuffer aBuf;
243  aBuf.append(ScResId(STR_COLUMN));
244  aBuf.append(' ');
245 
246  ScAddress aPos( aCols[ nCol ], 0, 0 );
247  aBuf.append(aPos.Format(ScRefFlags::COL_VALID));
248 
249  aString = aBuf.makeStringAndClear();
250  }
251  pMemChart->SetColText( nCol, aString);
252  }
253 
254  // Row Header
255 
256  for (nRow=0; nRow<nRowCount; nRow++)
257  {
258  OUString aString;
259  if (HasRowHeaders())
260  {
261  aString = pDocument->GetString(nStrCol, aRows[nRow], nTab1);
262  }
263  if (aString.isEmpty())
264  {
265  OUStringBuffer aBuf;
266  aBuf.append(ScResId(STR_ROW));
267  aBuf.append(' ');
268  aBuf.append(static_cast<sal_Int32>(aRows[nRow]+1));
269  aString = aBuf.makeStringAndClear();
270  }
271  pMemChart->SetRowText( nRow, aString);
272  }
273 
274  return pMemChart;
275 }
276 
277 std::unique_ptr<ScMemChart> ScChartArray::CreateMemChartMulti()
278 {
280  SCSIZE nRowCount = GetPositionMap()->GetRowCount();
281 
282  // May happen at least with more than 32k rows.
283  if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
284  {
285  nColCount = 0;
286  nRowCount = 0;
287  }
288 
289  bool bValidData = true;
290  if ( !nColCount )
291  {
292  bValidData = false;
293  nColCount = 1;
294  }
295  if ( !nRowCount )
296  {
297  bValidData = false;
298  nRowCount = 1;
299  }
300 
301  // Data
302  std::unique_ptr<ScMemChart> pMemChart(new ScMemChart( nColCount, nRowCount ));
303 
304  SCSIZE nCol = 0;
305  SCSIZE nRow = 0;
306  bool bCalcAsShown = pDocument->GetDocOptions().IsCalcAsShown();
307  sal_uLong nIndex = 0;
308  if (bValidData)
309  {
310  for ( nCol = 0; nCol < nColCount; nCol++ )
311  {
312  for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
313  {
314  double nVal = DBL_MIN; // Hack for Chart to recognize empty cells
315  const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
316  if (pPos)
317  // otherwise: Gap
318  nVal = getCellValue(*pDocument, *pPos, DBL_MIN, bCalcAsShown);
319 
320  pMemChart->SetData(nCol, nRow, nVal);
321  }
322  }
323  }
324  else
325  {
326  for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
327  {
328  double nVal = DBL_MIN; // Hack for Chart to recognize empty cells
329  const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
330  if (pPos)
331  // otherwise: Gap
332  nVal = getCellValue(*pDocument, *pPos, DBL_MIN, bCalcAsShown);
333 
334  pMemChart->SetData(nCol, nRow, nVal);
335  }
336  }
337 
338  //TODO: Label when gaps
339 
340  // Column header
341 
342  SCCOL nPosCol = 0;
343  for ( nCol = 0; nCol < nColCount; nCol++ )
344  {
345  OUString aString;
346  const ScAddress* pPos = GetPositionMap()->GetColHeaderPosition( static_cast<SCCOL>(nCol) );
347  if ( HasColHeaders() && pPos )
348  aString = pDocument->GetString(pPos->Col(), pPos->Row(), pPos->Tab());
349 
350  if (aString.isEmpty())
351  {
352  OUStringBuffer aBuf(ScResId(STR_COLUMN));
353  aBuf.append(' ');
354  if ( pPos )
355  nPosCol = pPos->Col() + 1;
356  else
357  nPosCol++;
358  ScAddress aPos( nPosCol - 1, 0, 0 );
359  aBuf.append(aPos.Format(ScRefFlags::COL_VALID));
360  aString = aBuf.makeStringAndClear();
361  }
362  pMemChart->SetColText( nCol, aString);
363  }
364 
365  // Row header
366 
367  SCROW nPosRow = 0;
368  for ( nRow = 0; nRow < nRowCount; nRow++ )
369  {
370  OUString aString;
371  const ScAddress* pPos = GetPositionMap()->GetRowHeaderPosition( nRow );
372  if ( HasRowHeaders() && pPos )
373  aString = pDocument->GetString(pPos->Col(), pPos->Row(), pPos->Tab());
374 
375  if (aString.isEmpty())
376  {
377  if ( pPos )
378  nPosRow = pPos->Row() + 1;
379  else
380  nPosRow++;
381  aString = ScResId(STR_ROW) + " " + OUString::number(static_cast<sal_Int32>(nPosRow));
382  }
383  pMemChart->SetRowText( nRow, aString);
384  }
385 
386  return pMemChart;
387 }
388 
389 /* 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:2111
sal_Int32 nIndex
ScAddress aStart
Definition: address.hxx:500
SCROW Row() const
Definition: address.hxx:262
sal_uIntPtr sal_uLong
ScChartArray(ScDocument *pDoc, const ScRangeListRef &rRangeList)
Definition: chartarr.cxx:57
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:3643
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:114
int nCount
SC_DLLPUBLIC OUString GetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext *pContext=nullptr) const
Definition: document.cxx:3488
std::unique_ptr< double[]> pData
Definition: chartarr.hxx:38
SCTAB Tab() const
Definition: address.hxx:271
ScDocument * pDocument
Definition: chartarr.hxx:60
SC_DLLPUBLIC const ScDocOptions & GetDocOptions() const
Definition: documen3.cxx:1904
bool HasRowHeaders() const
Definition: chartarr.hxx:74
SC_DLLPUBLIC bool ColHidden(SCCOL nCol, SCTAB nTab, SCCOL *pFirstCol=nullptr, SCCOL *pLastCol=nullptr) const
Definition: document.cxx:4447
std::unique_ptr< OUString[]> pRowText
Definition: chartarr.hxx:40
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:95
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:70
std::unique_ptr< ScMemChart > CreateMemChart()
Definition: chartarr.cxx:62
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:73
SC_DLLPUBLIC bool RowHidden(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4431
const ScRangeListRef & GetRangeList() const
Definition: chartarr.hxx:69
ScRange & front()
Definition: rangelst.hxx:93
std::unique_ptr< ScMemChart > CreateMemChartMulti()
Definition: chartarr.cxx:277
sal_Int16 SCTAB
Definition: types.hxx:23