Resolves: tdf#162093 TableRef item specifier may occur standalone
[LibreOffice.git] / sc / source / core / tool / chartarr.cxx
blob58f1b12215026451d39d8adf20f7a684312e448a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <float.h>
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>
30 #include <formula/errorcodes.hxx>
32 #include <memory>
33 #include <vector>
35 using ::std::vector;
37 ScMemChart::ScMemChart(SCCOL nCols, SCROW nRows)
39 nRowCnt = nRows;
40 nColCnt = nCols;
41 pData.reset( new double[nColCnt * nRowCnt] );
43 memset( pData.get(), 0.0, nColCnt * nRowCnt );
45 pColText.reset( new OUString[nColCnt] );
46 pRowText.reset( new OUString[nRowCnt] );
49 ScMemChart::~ScMemChart()
53 ScChartArray::ScChartArray(
54 ScDocument& rDoc, const ScRangeListRef& rRangeList ) :
55 rDocument( rDoc ),
56 aPositioner(rDoc, rRangeList) {}
58 std::unique_ptr<ScMemChart> ScChartArray::CreateMemChart()
60 ScRangeListRef aRangeListRef(GetRangeList());
61 size_t nCount = aRangeListRef->size();
62 if ( nCount > 1 )
63 return CreateMemChartMulti();
64 else if ( nCount == 1 )
66 const ScRange & rR = aRangeListRef->front();
67 if ( rR.aStart.Tab() != rR.aEnd.Tab() )
68 return CreateMemChartMulti();
69 else
70 return CreateMemChartSingle();
72 else
73 return CreateMemChartMulti(); // Can handle 0 range better than Single
76 namespace {
78 double getCellValue( ScDocument& rDoc, const ScAddress& rPos, double fDefault, bool bCalcAsShown )
80 double fRet = fDefault;
82 ScRefCellValue aCell(rDoc, rPos);
83 switch (aCell.getType())
85 case CELLTYPE_VALUE:
87 fRet = aCell.getValue();
88 if (bCalcAsShown && fRet != 0.0)
90 sal_uInt32 nFormat = rDoc.GetNumberFormat(rPos);
91 fRet = rDoc.RoundValueAsShown(fRet, nFormat);
94 break;
95 case CELLTYPE_FORMULA:
97 ScFormulaCell* pFCell = aCell.getFormula();
98 if (pFCell && pFCell->GetErrCode() == FormulaError::NONE && pFCell->IsValue())
99 fRet = pFCell->GetValue();
101 break;
102 default:
105 return fRet;
110 std::unique_ptr<ScMemChart> ScChartArray::CreateMemChartSingle()
112 SCSIZE nCol;
113 SCSIZE nRow;
115 // real size (without hidden rows/columns)
117 SCCOL nColAdd = HasRowHeaders() ? 1 : 0;
118 SCROW nRowAdd = HasColHeaders() ? 1 : 0;
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 );
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;
137 // Skip hidden rows.
138 SCROW nLastRow = -1;
139 if (rDocument.RowHidden(nRow1, nTab1, nullptr, &nLastRow))
140 nRow1 = nLastRow + 1;
142 // if everything is hidden then the label remains at the beginning
143 if ( nCol1 <= nCol2 )
145 nStrCol = nCol1;
146 nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nColAdd );
148 if ( nRow1 <= nRow2 )
150 nStrRow = nRow1;
151 nRow1 = sal::static_int_cast<SCROW>( nRow1 + nRowAdd );
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++)
159 SCCOL nThisCol = sal::static_int_cast<SCCOL>(nCol1+i);
160 if (!rDocument.ColHidden(nThisCol, nTab1, nullptr, &nLastCol))
161 aCols.push_back(nThisCol);
163 SCSIZE nColCount = aCols.size();
165 SCSIZE nTotalRows = ( nRow1 <= nRow2 ? nRow2 - nRow1 + 1 : 0 );
166 vector<SCROW> aRows;
167 aRows.reserve(nTotalRows);
168 if (nRow1 <= nRow2)
170 // Get all visible rows between nRow1 and nRow2.
171 SCROW nThisRow = nRow1;
172 while (nThisRow <= nRow2)
174 if (rDocument.RowHidden(nThisRow, nTab1, nullptr, &nLastRow))
175 nThisRow = nLastRow;
176 else
177 aRows.push_back(nThisRow);
178 ++nThisRow;
181 SCSIZE nRowCount = aRows.size();
183 // May happen at least with more than 32k rows.
184 if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
186 nColCount = 0;
187 nRowCount = 0;
190 bool bValidData = true;
191 if ( !nColCount )
193 bValidData = false;
194 nColCount = 1;
195 aCols.push_back(nStrCol);
197 if ( !nRowCount )
199 bValidData = false;
200 nRowCount = 1;
201 aRows.push_back(nStrRow);
204 // Data
205 std::unique_ptr<ScMemChart> pMemChart(new ScMemChart( nColCount, nRowCount ));
207 if ( bValidData )
209 bool bCalcAsShown = rDocument.GetDocOptions().IsCalcAsShown();
210 for (nCol=0; nCol<nColCount; nCol++)
212 for (nRow=0; nRow<nRowCount; nRow++)
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);
221 else
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 );
229 // Column Header
231 for (nCol=0; nCol<nColCount; nCol++)
233 OUString aString;
234 if (HasColHeaders())
235 aString = rDocument.GetString(aCols[nCol], nStrRow, nTab1);
236 if (aString.isEmpty())
238 ScAddress aPos( aCols[ nCol ], 0, 0 );
239 aString = ScResId(STR_COLUMN) + " " +
240 aPos.Format(ScRefFlags::COL_VALID);
242 pMemChart->SetColText( nCol, aString);
245 // Row Header
247 for (nRow=0; nRow<nRowCount; nRow++)
249 OUString aString;
250 if (HasRowHeaders())
252 aString = rDocument.GetString(nStrCol, aRows[nRow], nTab1);
254 if (aString.isEmpty())
256 aString = ScResId(STR_ROW) + " " +
257 OUString::number(static_cast<sal_Int32>(aRows[nRow]+1));
259 pMemChart->SetRowText( nRow, aString);
262 return pMemChart;
265 std::unique_ptr<ScMemChart> ScChartArray::CreateMemChartMulti()
267 SCSIZE nColCount = GetPositionMap()->GetColCount();
268 SCSIZE nRowCount = GetPositionMap()->GetRowCount();
270 // May happen at least with more than 32k rows.
271 if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
273 nColCount = 0;
274 nRowCount = 0;
277 bool bValidData = true;
278 if ( !nColCount )
280 bValidData = false;
281 nColCount = 1;
283 if ( !nRowCount )
285 bValidData = false;
286 nRowCount = 1;
289 // Data
290 std::unique_ptr<ScMemChart> pMemChart(new ScMemChart( nColCount, nRowCount ));
292 SCSIZE nCol = 0;
293 SCSIZE nRow = 0;
294 bool bCalcAsShown = rDocument.GetDocOptions().IsCalcAsShown();
295 sal_uLong nIndex = 0;
296 if (bValidData)
298 for ( nCol = 0; nCol < nColCount; nCol++ )
300 for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
302 double nVal = DBL_MIN; // Hack for Chart to recognize empty cells
303 const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
304 if (pPos)
305 // otherwise: Gap
306 nVal = getCellValue(rDocument, *pPos, DBL_MIN, bCalcAsShown);
308 pMemChart->SetData(nCol, nRow, nVal);
312 else
314 for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
316 double nVal = DBL_MIN; // Hack for Chart to recognize empty cells
317 const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
318 if (pPos)
319 // otherwise: Gap
320 nVal = getCellValue(rDocument, *pPos, DBL_MIN, bCalcAsShown);
322 pMemChart->SetData(nCol, nRow, nVal);
326 //TODO: Label when gaps
328 // Column header
330 SCCOL nPosCol = 0;
331 for ( nCol = 0; nCol < nColCount; nCol++ )
333 OUString aString;
334 const ScAddress* pPos = GetPositionMap()->GetColHeaderPosition( static_cast<SCCOL>(nCol) );
335 if ( HasColHeaders() && pPos )
336 aString = rDocument.GetString(pPos->Col(), pPos->Row(), pPos->Tab());
338 if (aString.isEmpty())
340 if ( pPos )
341 nPosCol = pPos->Col() + 1;
342 else
343 nPosCol++;
344 ScAddress aPos( nPosCol - 1, 0, 0 );
345 aString = ScResId(STR_COLUMN) + " " + aPos.Format(ScRefFlags::COL_VALID);
347 pMemChart->SetColText( nCol, aString);
350 // Row header
352 SCROW nPosRow = 0;
353 for ( nRow = 0; nRow < nRowCount; nRow++ )
355 OUString aString;
356 const ScAddress* pPos = GetPositionMap()->GetRowHeaderPosition( nRow );
357 if ( HasRowHeaders() && pPos )
358 aString = rDocument.GetString(pPos->Col(), pPos->Row(), pPos->Tab());
360 if (aString.isEmpty())
362 if ( pPos )
363 nPosRow = pPos->Row() + 1;
364 else
365 nPosRow++;
366 aString = ScResId(STR_ROW) + " " + OUString::number(static_cast<sal_Int32>(nPosRow));
368 pMemChart->SetRowText( nRow, aString);
371 return pMemChart;
374 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */