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