Line data Source code
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 "document.hxx"
27 : #include "rechead.hxx"
28 : #include "globstr.hrc"
29 : #include "formulacell.hxx"
30 : #include "docoptio.hxx"
31 :
32 : #include <vector>
33 :
34 : using ::std::vector;
35 :
36 18 : ScMemChart::ScMemChart(SCCOL nCols, SCROW nRows)
37 : {
38 18 : nRowCnt = nRows;
39 18 : nColCnt = nCols;
40 18 : pData = new double[nColCnt * nRowCnt];
41 :
42 18 : double *pFill = pData;
43 :
44 54 : for (SCCOL i = 0; i < nColCnt; i++)
45 268 : for (SCROW j = 0; j < nRowCnt; j++)
46 232 : *(pFill ++) = 0.0;
47 :
48 18 : pColText = new OUString[nColCnt];
49 18 : pRowText = new OUString[nRowCnt];
50 18 : }
51 :
52 18 : ScMemChart::~ScMemChart()
53 : {
54 18 : delete[] pRowText;
55 18 : delete[] pColText;
56 18 : delete[] pData;
57 18 : }
58 :
59 0 : ScChartArray::ScChartArray( ScDocument* pDoc, SCTAB nTab,
60 : SCCOL nStartColP, SCROW nStartRowP, SCCOL nEndColP, SCROW nEndRowP,
61 : const OUString& rChartName ) :
62 : aName( rChartName ),
63 : pDocument( pDoc ),
64 : aPositioner(pDoc, nTab, nStartColP, nStartRowP, nEndColP, nEndRowP),
65 0 : bValid( true )
66 : {
67 0 : }
68 :
69 26 : ScChartArray::ScChartArray(
70 : ScDocument* pDoc, const ScRangeListRef& rRangeList, const OUString& rChartName ) :
71 : aName( rChartName ),
72 : pDocument( pDoc ),
73 : aPositioner(pDoc, rRangeList),
74 26 : bValid( true ) {}
75 :
76 0 : ScChartArray::ScChartArray( const ScChartArray& rArr ) :
77 : aName(rArr.aName),
78 : pDocument(rArr.pDocument),
79 : aPositioner(rArr.aPositioner),
80 0 : bValid(rArr.bValid) {}
81 :
82 26 : ScChartArray::~ScChartArray() {}
83 :
84 0 : bool ScChartArray::operator==(const ScChartArray& rCmp) const
85 : {
86 0 : return aPositioner == rCmp.aPositioner
87 0 : && aName == rCmp.aName;
88 : }
89 :
90 18 : ScMemChart* ScChartArray::CreateMemChart()
91 : {
92 18 : ScRangeListRef aRangeListRef(GetRangeList());
93 18 : size_t nCount = aRangeListRef->size();
94 18 : if ( nCount > 1 )
95 10 : return CreateMemChartMulti();
96 8 : else if ( nCount == 1 )
97 : {
98 8 : ScRange* pR = aRangeListRef->front();
99 8 : if ( pR->aStart.Tab() != pR->aEnd.Tab() )
100 0 : return CreateMemChartMulti();
101 : else
102 8 : return CreateMemChartSingle();
103 : }
104 : else
105 0 : return CreateMemChartMulti(); // Can handle 0 range better than Single
106 : }
107 :
108 : namespace {
109 :
110 232 : double getCellValue( ScDocument& rDoc, const ScAddress& rPos, double fDefault, bool bCalcAsShown )
111 : {
112 232 : double fRet = fDefault;
113 :
114 232 : CellType eType = rDoc.GetCellType(rPos);
115 232 : switch (eType)
116 : {
117 : case CELLTYPE_VALUE:
118 : {
119 130 : fRet = rDoc.GetValue(rPos);
120 130 : if (bCalcAsShown && fRet != 0.0)
121 : {
122 0 : sal_uInt32 nFormat = rDoc.GetNumberFormat(rPos);
123 0 : fRet = rDoc.RoundValueAsShown(fRet, nFormat);
124 : }
125 : }
126 130 : break;
127 : case CELLTYPE_FORMULA:
128 : {
129 0 : ScFormulaCell* pFCell = rDoc.GetFormulaCell(rPos);
130 0 : if (pFCell && !pFCell->GetErrCode() && pFCell->IsValue())
131 0 : fRet = pFCell->GetValue();
132 : }
133 0 : break;
134 : default:
135 : ;
136 : }
137 232 : return fRet;
138 : }
139 :
140 : }
141 :
142 8 : ScMemChart* ScChartArray::CreateMemChartSingle()
143 : {
144 : SCSIZE nCol;
145 : SCSIZE nRow;
146 :
147 : // real size (without hidden rows/columns)
148 :
149 8 : SCCOL nColAdd = HasRowHeaders() ? 1 : 0;
150 8 : SCROW nRowAdd = HasColHeaders() ? 1 : 0;
151 :
152 : SCCOL nCol1;
153 : SCROW nRow1;
154 : SCTAB nTab1;
155 : SCCOL nCol2;
156 : SCROW nRow2;
157 : SCTAB nTab2;
158 8 : ScRangeListRef aRangeListRef(GetRangeList());
159 8 : aRangeListRef->front()->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
160 :
161 8 : SCCOL nStrCol = nCol1; // remember for labeling
162 8 : SCROW nStrRow = nRow1;
163 : // Skip hidden columns.
164 : // TODO: make use of last column value once implemented.
165 8 : SCCOL nLastCol = -1;
166 16 : while (pDocument->ColHidden(nCol1, nTab1, NULL, &nLastCol))
167 0 : ++nCol1;
168 :
169 : // Skip hidden rows.
170 8 : SCROW nLastRow = -1;
171 8 : if (pDocument->RowHidden(nRow1, nTab1, NULL, &nLastRow))
172 0 : nRow1 = nLastRow + 1;
173 :
174 : // if everything is hidden then the label remains at the beginning
175 8 : if ( nCol1 <= nCol2 )
176 : {
177 8 : nStrCol = nCol1;
178 8 : nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nColAdd );
179 : }
180 8 : if ( nRow1 <= nRow2 )
181 : {
182 8 : nStrRow = nRow1;
183 8 : nRow1 = sal::static_int_cast<SCROW>( nRow1 + nRowAdd );
184 : }
185 :
186 8 : SCSIZE nTotalCols = ( nCol1 <= nCol2 ? nCol2 - nCol1 + 1 : 0 );
187 16 : vector<SCCOL> aCols;
188 8 : aCols.reserve(nTotalCols);
189 32 : for (SCSIZE i=0; i<nTotalCols; i++)
190 : {
191 24 : SCCOL nThisCol = sal::static_int_cast<SCCOL>(nCol1+i);
192 24 : if (!pDocument->ColHidden(nThisCol, nTab1, NULL, &nLastCol))
193 24 : aCols.push_back(nThisCol);
194 : }
195 8 : SCSIZE nColCount = aCols.size();
196 :
197 8 : SCSIZE nTotalRows = ( nRow1 <= nRow2 ? nRow2 - nRow1 + 1 : 0 );
198 16 : vector<SCROW> aRows;
199 8 : aRows.reserve(nTotalRows);
200 8 : if (nRow1 <= nRow2)
201 : {
202 : // Get all visible rows between nRow1 and nRow2.
203 8 : SCROW nThisRow = nRow1;
204 48 : while (nThisRow <= nRow2)
205 : {
206 32 : if (pDocument->RowHidden(nThisRow, nTab1, NULL, &nLastRow))
207 0 : nThisRow = nLastRow;
208 : else
209 32 : aRows.push_back(nThisRow);
210 32 : ++nThisRow;
211 : }
212 : }
213 8 : SCSIZE nRowCount = aRows.size();
214 :
215 : // May happen at least with more than 32k rows.
216 8 : if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
217 : {
218 0 : nColCount = 0;
219 0 : nRowCount = 0;
220 : }
221 :
222 8 : bool bValidData = true;
223 8 : if ( !nColCount )
224 : {
225 0 : bValidData = false;
226 0 : nColCount = 1;
227 0 : aCols.push_back(nStrCol);
228 : }
229 8 : if ( !nRowCount )
230 : {
231 0 : bValidData = false;
232 0 : nRowCount = 1;
233 0 : aRows.push_back(nStrRow);
234 : }
235 :
236 : // Data
237 8 : ScMemChart* pMemChart = new ScMemChart( nColCount, nRowCount );
238 :
239 8 : if ( bValidData )
240 : {
241 8 : bool bCalcAsShown = pDocument->GetDocOptions().IsCalcAsShown();
242 32 : for (nCol=0; nCol<nColCount; nCol++)
243 : {
244 120 : for (nRow=0; nRow<nRowCount; nRow++)
245 : {
246 : // DBL_MIN is a Hack for Chart to recognize empty cells.
247 96 : ScAddress aPos(aCols[nCol], aRows[nRow], nTab1);
248 96 : double nVal = getCellValue(*pDocument, aPos, DBL_MIN, bCalcAsShown);
249 96 : pMemChart->SetData(nCol, nRow, nVal);
250 : }
251 : }
252 : }
253 : else
254 : {
255 : // Flag marking data as invalid?
256 0 : for (nCol=0; nCol<nColCount; nCol++)
257 0 : for (nRow=0; nRow<nRowCount; nRow++)
258 0 : pMemChart->SetData( nCol, nRow, DBL_MIN );
259 : }
260 :
261 : // Column Header
262 :
263 32 : for (nCol=0; nCol<nColCount; nCol++)
264 : {
265 24 : OUString aString;
266 24 : if (HasColHeaders())
267 24 : aString = pDocument->GetString(aCols[nCol], nStrRow, nTab1);
268 24 : if (aString.isEmpty())
269 : {
270 21 : OUStringBuffer aBuf;
271 21 : aBuf.append(ScGlobal::GetRscString(STR_COLUMN));
272 21 : aBuf.append(' ');
273 :
274 21 : ScAddress aPos( aCols[ nCol ], 0, 0 );
275 21 : aBuf.append(aPos.Format(SCA_VALID_COL, NULL));
276 :
277 21 : aString = aBuf.makeStringAndClear();
278 : }
279 24 : pMemChart->SetColText( nCol, aString);
280 24 : }
281 :
282 : // Row Header
283 :
284 40 : for (nRow=0; nRow<nRowCount; nRow++)
285 : {
286 32 : OUString aString;
287 32 : if (HasRowHeaders())
288 : {
289 32 : ScAddress aAddr( nStrCol, aRows[nRow], nTab1 );
290 32 : aString = pDocument->GetString(nStrCol, aRows[nRow], nTab1);
291 : }
292 32 : if (aString.isEmpty())
293 : {
294 20 : OUStringBuffer aBuf;
295 20 : aBuf.append(ScGlobal::GetRscString(STR_ROW));
296 20 : aBuf.append(' ');
297 20 : aBuf.append(static_cast<sal_Int32>(aRows[nRow]+1));
298 20 : aString = aBuf.makeStringAndClear();
299 : }
300 32 : pMemChart->SetRowText( nRow, aString);
301 32 : }
302 :
303 16 : return pMemChart;
304 : }
305 :
306 10 : ScMemChart* ScChartArray::CreateMemChartMulti()
307 : {
308 10 : SCSIZE nColCount = GetPositionMap()->GetColCount();
309 10 : SCSIZE nRowCount = GetPositionMap()->GetRowCount();
310 :
311 : // May happen at least with more than 32k rows.
312 10 : if (nColCount > SHRT_MAX || nRowCount > SHRT_MAX)
313 : {
314 0 : nColCount = 0;
315 0 : nRowCount = 0;
316 : }
317 :
318 10 : bool bValidData = true;
319 10 : if ( !nColCount )
320 : {
321 0 : bValidData = false;
322 0 : nColCount = 1;
323 : }
324 10 : if ( !nRowCount )
325 : {
326 0 : bValidData = false;
327 0 : nRowCount = 1;
328 : }
329 :
330 : // Data
331 10 : ScMemChart* pMemChart = new ScMemChart( nColCount, nRowCount );
332 :
333 10 : SCSIZE nCol = 0;
334 10 : SCSIZE nRow = 0;
335 10 : bool bCalcAsShown = pDocument->GetDocOptions().IsCalcAsShown();
336 10 : sal_uLong nIndex = 0;
337 10 : if (bValidData)
338 : {
339 22 : for ( nCol = 0; nCol < nColCount; nCol++ )
340 : {
341 148 : for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
342 : {
343 136 : double nVal = DBL_MIN; // Hack for Chart to recognize empty cells
344 136 : const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
345 136 : if (pPos)
346 : // otherwise: Gap
347 136 : nVal = getCellValue(*pDocument, *pPos, DBL_MIN, bCalcAsShown);
348 :
349 136 : pMemChart->SetData(nCol, nRow, nVal);
350 : }
351 : }
352 : }
353 : else
354 : {
355 0 : for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
356 : {
357 0 : double nVal = DBL_MIN; // Hack for Chart to recognize empty cells
358 0 : const ScAddress* pPos = GetPositionMap()->GetPosition( nIndex );
359 0 : if (pPos)
360 : // otherwise: Gap
361 0 : nVal = getCellValue(*pDocument, *pPos, DBL_MIN, bCalcAsShown);
362 :
363 0 : pMemChart->SetData(nCol, nRow, nVal);
364 : }
365 : }
366 :
367 : //TODO: Label when gaps
368 :
369 : // Column header
370 :
371 10 : SCCOL nPosCol = 0;
372 22 : for ( nCol = 0; nCol < nColCount; nCol++ )
373 : {
374 12 : OUString aString;
375 12 : const ScAddress* pPos = GetPositionMap()->GetColHeaderPosition( static_cast<SCCOL>(nCol) );
376 12 : if ( HasColHeaders() && pPos )
377 8 : aString = pDocument->GetString(pPos->Col(), pPos->Row(), pPos->Tab());
378 :
379 12 : if (aString.isEmpty())
380 : {
381 4 : OUStringBuffer aBuf(ScGlobal::GetRscString(STR_COLUMN));
382 4 : aBuf.append(' ');
383 4 : if ( pPos )
384 4 : nPosCol = pPos->Col() + 1;
385 : else
386 0 : nPosCol++;
387 4 : ScAddress aPos( nPosCol - 1, 0, 0 );
388 4 : aBuf.append(aPos.Format(SCA_VALID_COL, NULL));
389 4 : aString = aBuf.makeStringAndClear();
390 : }
391 12 : pMemChart->SetColText( nCol, aString);
392 12 : }
393 :
394 : // Row header
395 :
396 10 : SCROW nPosRow = 0;
397 122 : for ( nRow = 0; nRow < nRowCount; nRow++ )
398 : {
399 112 : OUString aString;
400 112 : const ScAddress* pPos = GetPositionMap()->GetRowHeaderPosition( nRow );
401 112 : if ( HasRowHeaders() && pPos )
402 88 : aString = pDocument->GetString(pPos->Col(), pPos->Row(), pPos->Tab());
403 :
404 112 : if (aString.isEmpty())
405 : {
406 24 : OUStringBuffer aBuf(ScGlobal::GetRscString(STR_ROW));
407 24 : aBuf.append(' ');
408 24 : if ( pPos )
409 24 : nPosRow = pPos->Row() + 1;
410 : else
411 0 : nPosRow++;
412 24 : aBuf.append(static_cast<sal_Int32>(nPosRow));
413 24 : aString = aBuf.makeStringAndClear();
414 : }
415 112 : pMemChart->SetRowText( nRow, aString);
416 112 : }
417 :
418 10 : return pMemChart;
419 : }
420 :
421 2320 : ScChartCollection::ScChartCollection() {}
422 0 : ScChartCollection::ScChartCollection(const ScChartCollection& r) :
423 0 : maData(r.maData) {}
424 :
425 0 : void ScChartCollection::push_back(ScChartArray* p)
426 : {
427 0 : maData.push_back(p);
428 0 : }
429 :
430 0 : void ScChartCollection::clear()
431 : {
432 0 : maData.clear();
433 0 : }
434 :
435 0 : size_t ScChartCollection::size() const
436 : {
437 0 : return maData.size();
438 : }
439 :
440 0 : bool ScChartCollection::empty() const
441 : {
442 0 : return maData.empty();
443 : }
444 :
445 0 : ScChartArray* ScChartCollection::operator[](size_t nIndex)
446 : {
447 0 : if (maData.size() <= nIndex)
448 0 : return NULL;
449 0 : return &maData[nIndex];
450 : }
451 :
452 0 : const ScChartArray* ScChartCollection::operator[](size_t nIndex) const
453 : {
454 0 : if (maData.size() <= nIndex)
455 0 : return NULL;
456 0 : return &maData[nIndex];
457 : }
458 :
459 0 : bool ScChartCollection::operator==(const ScChartCollection& rCmp) const
460 : {
461 0 : return maData == rCmp.maData;
462 156 : }
463 :
464 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|