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 "consoli.hxx"
21 : #include "document.hxx"
22 : #include "olinetab.hxx"
23 : #include "globstr.hrc"
24 : #include "subtotal.hxx"
25 : #include "formula/errorcodes.hxx"
26 : #include "formulacell.hxx"
27 : #include "tokenarray.hxx"
28 :
29 : #include <math.h>
30 : #include <string.h>
31 :
32 : #define SC_CONS_NOTFOUND -1
33 :
34 : // STATIC DATA
35 : static const OpCode eOpCodeTable[] = { // Reihenfolge wie bei enum ScSubTotalFunc
36 : ocBad, // none
37 : ocAverage,
38 : ocCount,
39 : ocCount2,
40 : ocMax,
41 : ocMin,
42 : ocProduct,
43 : ocStDev,
44 : ocStDevP,
45 : ocSum,
46 : ocVar,
47 : ocVarP };
48 :
49 0 : void ScReferenceList::AddEntry( SCCOL nCol, SCROW nRow, SCTAB nTab )
50 : {
51 0 : ScReferenceEntry* pOldData = pData;
52 0 : pData = new ScReferenceEntry[ nFullSize+1 ];
53 0 : if (pOldData)
54 : {
55 0 : memcpy( pData, pOldData, nCount * sizeof(ScReferenceEntry) );
56 0 : delete[] pOldData;
57 : }
58 0 : while (nCount < nFullSize)
59 : {
60 0 : pData[nCount].nCol = SC_CONS_NOTFOUND;
61 0 : pData[nCount].nRow = SC_CONS_NOTFOUND;
62 0 : pData[nCount].nTab = SC_CONS_NOTFOUND;
63 0 : ++nCount;
64 : }
65 0 : pData[nCount].nCol = nCol;
66 0 : pData[nCount].nRow = nRow;
67 0 : pData[nCount].nTab = nTab;
68 0 : ++nCount;
69 0 : nFullSize = nCount;
70 0 : }
71 :
72 : template< typename T >
73 0 : static void lcl_AddString( OUString*& pData, T& nCount, const OUString& rInsert )
74 : {
75 0 : OUString* pOldData = pData;
76 0 : pData = new OUString[ nCount+1 ];
77 0 : if (pOldData)
78 : {
79 0 : memcpy( pData, pOldData, nCount * sizeof(OUString) );
80 0 : delete[] pOldData;
81 : }
82 0 : pData[nCount] = rInsert;
83 0 : ++nCount;
84 0 : }
85 :
86 0 : ScConsData::ScConsData() :
87 : eFunction(SUBTOTAL_FUNC_SUM),
88 : bReference(false),
89 : bColByName(false),
90 : bRowByName(false),
91 : nColCount(0),
92 : nRowCount(0),
93 : ppUsed(NULL),
94 : ppSum(NULL),
95 : ppCount(NULL),
96 : ppSumSqr(NULL),
97 : ppRefs(NULL),
98 : mpColHeaders(NULL),
99 : mpRowHeaders(NULL),
100 : nDataCount(0),
101 : nTitleCount(0),
102 : mpTitles(NULL),
103 : ppTitlePos(NULL),
104 0 : bCornerUsed(false)
105 : {
106 0 : }
107 :
108 0 : ScConsData::~ScConsData()
109 : {
110 0 : DeleteData();
111 0 : }
112 :
113 : #define DELETEARR(ppArray,nCount) \
114 : { \
115 : sal_uLong i; \
116 : if (ppArray) \
117 : for(i=0; i<nCount; i++) \
118 : delete[] ppArray[i]; \
119 : delete[] ppArray; \
120 : ppArray = NULL; \
121 : }
122 :
123 0 : void ScConsData::DeleteData()
124 : {
125 0 : if (ppRefs)
126 : {
127 0 : for (SCSIZE i=0; i<nColCount; i++)
128 : {
129 0 : for (SCSIZE j=0; j<nRowCount; j++)
130 0 : if (ppUsed[i][j])
131 0 : ppRefs[i][j].Clear();
132 0 : delete[] ppRefs[i];
133 : }
134 0 : delete[] ppRefs;
135 0 : ppRefs = NULL;
136 : }
137 :
138 0 : DELETEARR( ppCount, nColCount );
139 0 : DELETEARR( ppSum, nColCount );
140 0 : DELETEARR( ppSumSqr,nColCount );
141 0 : DELETEARR( ppUsed, nColCount ); // erst nach ppRefs !!!
142 0 : DELETEARR( ppTitlePos, nRowCount );
143 0 : delete[] mpColHeaders;
144 0 : mpColHeaders = NULL;
145 0 : delete[] mpRowHeaders;
146 0 : mpRowHeaders = NULL;
147 0 : delete[] mpTitles;
148 0 : mpTitles = NULL;
149 0 : nTitleCount = 0;
150 0 : nDataCount = 0;
151 :
152 0 : if (bColByName) nColCount = 0; // sonst stimmt mpColHeaders nicht
153 0 : if (bRowByName) nRowCount = 0;
154 :
155 0 : bCornerUsed = false;
156 0 : aCornerText = "";
157 0 : }
158 :
159 : #undef DELETEARR
160 : #undef DELETESTR
161 :
162 0 : void ScConsData::InitData()
163 : {
164 0 : if (bReference && nColCount && !ppRefs)
165 : {
166 0 : ppRefs = new ScReferenceList*[nColCount];
167 0 : for (SCSIZE i=0; i<nColCount; i++)
168 0 : ppRefs[i] = new ScReferenceList[nRowCount];
169 : }
170 0 : else if (nColCount && !ppCount)
171 : {
172 0 : ppCount = new double*[nColCount];
173 0 : ppSum = new double*[nColCount];
174 0 : ppSumSqr = new double*[nColCount];
175 0 : for (SCSIZE i=0; i<nColCount; i++)
176 : {
177 0 : ppCount[i] = new double[nRowCount];
178 0 : ppSum[i] = new double[nRowCount];
179 0 : ppSumSqr[i] = new double[nRowCount];
180 : }
181 : }
182 :
183 0 : if (nColCount && !ppUsed)
184 : {
185 0 : ppUsed = new bool*[nColCount];
186 0 : for (SCSIZE i=0; i<nColCount; i++)
187 : {
188 0 : ppUsed[i] = new bool[nRowCount];
189 0 : memset( ppUsed[i], 0, nRowCount * sizeof(bool) );
190 : }
191 : }
192 :
193 0 : if (nRowCount && nDataCount && !ppTitlePos)
194 : {
195 0 : ppTitlePos = new SCSIZE*[nRowCount];
196 0 : for (SCSIZE i=0; i<nRowCount; i++)
197 : {
198 0 : ppTitlePos[i] = new SCSIZE[nDataCount];
199 0 : memset( ppTitlePos[i], 0, nDataCount * sizeof(SCSIZE) ); //! unnoetig ?
200 : }
201 : }
202 :
203 : // CornerText: einzelner String
204 0 : }
205 :
206 0 : void ScConsData::DoneFields()
207 : {
208 0 : InitData();
209 0 : }
210 :
211 0 : void ScConsData::SetSize( SCCOL nCols, SCROW nRows )
212 : {
213 0 : DeleteData();
214 0 : nColCount = static_cast<SCSIZE>(nCols);
215 0 : nRowCount = static_cast<SCSIZE>(nRows);
216 0 : }
217 :
218 0 : void ScConsData::GetSize( SCCOL& rCols, SCROW& rRows ) const
219 : {
220 0 : rCols = static_cast<SCCOL>(nColCount);
221 0 : rRows = static_cast<SCROW>(nRowCount);
222 0 : }
223 :
224 0 : void ScConsData::SetFlags( ScSubTotalFunc eFunc, bool bColName, bool bRowName, bool bRef )
225 : {
226 0 : DeleteData();
227 0 : bReference = bRef;
228 0 : bColByName = bColName;
229 0 : if (bColName) nColCount = 0;
230 0 : bRowByName = bRowName;
231 0 : if (bRowName) nRowCount = 0;
232 0 : eFunction = eFunc;
233 0 : }
234 :
235 0 : void ScConsData::AddFields( ScDocument* pSrcDoc, SCTAB nTab,
236 : SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
237 : {
238 0 : ++nDataCount;
239 :
240 0 : OUString aTitle;
241 :
242 0 : SCCOL nStartCol = nCol1;
243 0 : SCROW nStartRow = nRow1;
244 0 : if (bColByName) ++nStartRow;
245 0 : if (bRowByName) ++nStartCol;
246 :
247 0 : if (bColByName)
248 : {
249 0 : for (SCCOL nCol=nStartCol; nCol<=nCol2; nCol++)
250 : {
251 0 : aTitle = pSrcDoc->GetString(nCol, nRow1, nTab);
252 0 : if (!aTitle.isEmpty())
253 : {
254 0 : bool bFound = false;
255 0 : for (SCSIZE i=0; i<nColCount && !bFound; i++)
256 0 : if ( mpColHeaders[i] == aTitle )
257 0 : bFound = true;
258 0 : if (!bFound)
259 0 : lcl_AddString( mpColHeaders, nColCount, aTitle );
260 : }
261 : }
262 : }
263 :
264 0 : if (bRowByName)
265 : {
266 0 : for (SCROW nRow=nStartRow; nRow<=nRow2; nRow++)
267 : {
268 0 : aTitle = pSrcDoc->GetString(nCol1, nRow, nTab);
269 0 : if (!aTitle.isEmpty())
270 : {
271 0 : bool bFound = false;
272 0 : for (SCSIZE i=0; i<nRowCount && !bFound; i++)
273 0 : if ( mpRowHeaders[i] == aTitle )
274 0 : bFound = true;
275 0 : if (!bFound)
276 0 : lcl_AddString( mpRowHeaders, nRowCount, aTitle );
277 : }
278 : }
279 0 : }
280 0 : }
281 :
282 0 : void ScConsData::AddName( const OUString& rName )
283 : {
284 : SCSIZE nArrX;
285 : SCSIZE nArrY;
286 :
287 0 : if (bReference)
288 : {
289 0 : lcl_AddString( mpTitles, nTitleCount, rName );
290 :
291 0 : for (nArrY=0; nArrY<nRowCount; nArrY++)
292 : {
293 : // Daten auf gleiche Laenge bringen
294 :
295 0 : SCSIZE nMax = 0;
296 0 : for (nArrX=0; nArrX<nColCount; nArrX++)
297 0 : if (ppUsed[nArrX][nArrY])
298 0 : nMax = std::max( nMax, ppRefs[nArrX][nArrY].GetCount() );
299 :
300 0 : for (nArrX=0; nArrX<nColCount; nArrX++)
301 : {
302 0 : if (!ppUsed[nArrX][nArrY])
303 : {
304 0 : ppUsed[nArrX][nArrY] = true;
305 0 : ppRefs[nArrX][nArrY].Init();
306 : }
307 0 : ppRefs[nArrX][nArrY].SetFullSize(nMax);
308 : }
309 :
310 : // Positionen eintragen
311 :
312 0 : if (ppTitlePos)
313 0 : if (nTitleCount < nDataCount)
314 0 : ppTitlePos[nArrY][nTitleCount] = nMax;
315 : }
316 : }
317 0 : }
318 :
319 : // rCount < 0 <=> Fehler aufgetreten
320 :
321 0 : static void lcl_UpdateArray( ScSubTotalFunc eFunc,
322 : double& rCount, double& rSum, double& rSumSqr, double nVal )
323 : {
324 0 : if (rCount < 0.0)
325 0 : return;
326 0 : switch (eFunc)
327 : {
328 : case SUBTOTAL_FUNC_SUM:
329 0 : if (!SubTotal::SafePlus(rSum, nVal))
330 0 : rCount = -MAXDOUBLE;
331 0 : break;
332 : case SUBTOTAL_FUNC_PROD:
333 0 : if (!SubTotal::SafeMult(rSum, nVal))
334 0 : rCount = -MAXDOUBLE;
335 0 : break;
336 : case SUBTOTAL_FUNC_CNT:
337 : case SUBTOTAL_FUNC_CNT2:
338 0 : rCount += 1.0;
339 0 : break;
340 : case SUBTOTAL_FUNC_AVE:
341 0 : if (!SubTotal::SafePlus(rSum, nVal))
342 0 : rCount = -MAXDOUBLE;
343 : else
344 0 : rCount += 1.0;
345 0 : break;
346 : case SUBTOTAL_FUNC_MAX:
347 0 : if (nVal > rSum)
348 0 : rSum = nVal;
349 0 : break;
350 : case SUBTOTAL_FUNC_MIN:
351 0 : if (nVal < rSum)
352 0 : rSum = nVal;
353 0 : break;
354 : case SUBTOTAL_FUNC_STD:
355 : case SUBTOTAL_FUNC_STDP:
356 : case SUBTOTAL_FUNC_VAR:
357 : case SUBTOTAL_FUNC_VARP:
358 : {
359 0 : sal_Bool bOk = SubTotal::SafePlus(rSum, nVal);
360 0 : bOk = bOk && SubTotal::SafeMult(nVal, nVal);
361 0 : bOk = bOk && SubTotal::SafePlus(rSumSqr, nVal);
362 0 : if (!bOk)
363 0 : rCount = -MAXDOUBLE;
364 : else
365 0 : rCount += 1.0;
366 0 : break;
367 : }
368 : default:
369 : {
370 : // added to avoid warnings
371 : }
372 : }
373 : }
374 :
375 0 : static void lcl_InitArray( ScSubTotalFunc eFunc,
376 : double& rCount, double& rSum, double& rSumSqr, double nVal )
377 : {
378 0 : rCount = 1.0;
379 0 : switch (eFunc)
380 : {
381 : case SUBTOTAL_FUNC_SUM:
382 : case SUBTOTAL_FUNC_MAX:
383 : case SUBTOTAL_FUNC_MIN:
384 : case SUBTOTAL_FUNC_PROD:
385 : case SUBTOTAL_FUNC_AVE:
386 0 : rSum = nVal;
387 0 : break;
388 : case SUBTOTAL_FUNC_STD:
389 : case SUBTOTAL_FUNC_STDP:
390 : case SUBTOTAL_FUNC_VAR:
391 : case SUBTOTAL_FUNC_VARP:
392 : {
393 0 : rSum = nVal;
394 0 : sal_Bool bOk = SubTotal::SafeMult(nVal, nVal);
395 0 : if (bOk)
396 0 : rSumSqr = nVal;
397 : else
398 0 : rCount = -MAXDOUBLE;
399 : }
400 0 : break;
401 : default:
402 0 : break;
403 : }
404 0 : }
405 :
406 0 : static double lcl_CalcData( ScSubTotalFunc eFunc,
407 : double& fCount, double fSum, double fSumSqr)
408 : {
409 0 : if (fCount < 0.0)
410 0 : return 0.0;
411 0 : double fVal = 0.0;
412 0 : switch (eFunc)
413 : {
414 : case SUBTOTAL_FUNC_CNT:
415 : case SUBTOTAL_FUNC_CNT2:
416 0 : fVal = fCount;
417 0 : break;
418 : case SUBTOTAL_FUNC_SUM:
419 : case SUBTOTAL_FUNC_MAX:
420 : case SUBTOTAL_FUNC_MIN:
421 : case SUBTOTAL_FUNC_PROD:
422 0 : fVal = fSum;
423 0 : break;
424 : case SUBTOTAL_FUNC_AVE:
425 0 : if (fCount > 0.0)
426 0 : fVal = fSum / fCount;
427 : else
428 0 : fCount = -MAXDOUBLE;
429 0 : break;
430 : case SUBTOTAL_FUNC_STD:
431 : {
432 0 : if (fCount > 1 && SubTotal::SafeMult(fSum, fSum))
433 0 : fVal = sqrt((fSumSqr - fSum/fCount)/(fCount-1.0));
434 : else
435 0 : fCount = -MAXDOUBLE;
436 : }
437 0 : break;
438 : case SUBTOTAL_FUNC_STDP:
439 : {
440 0 : if (fCount > 0 && SubTotal::SafeMult(fSum, fSum))
441 0 : fVal = sqrt((fSumSqr - fSum/fCount)/fCount);
442 : else
443 0 : fCount = -MAXDOUBLE;
444 : }
445 0 : break;
446 : case SUBTOTAL_FUNC_VAR:
447 : {
448 0 : if (fCount > 1 && SubTotal::SafeMult(fSum, fSum))
449 0 : fVal = (fSumSqr - fSum/fCount)/(fCount-1.0);
450 : else
451 0 : fCount = -MAXDOUBLE;
452 : }
453 0 : break;
454 : case SUBTOTAL_FUNC_VARP:
455 : {
456 0 : if (fCount > 0 && SubTotal::SafeMult(fSum, fSum))
457 0 : fVal = (fSumSqr - fSum/fCount)/fCount;
458 : else
459 0 : fCount = -MAXDOUBLE;
460 : }
461 0 : break;
462 : default:
463 : {
464 : OSL_FAIL("Consoli::CalcData: unknown function");
465 0 : fCount = -MAXDOUBLE;
466 : }
467 0 : break;
468 : }
469 0 : return fVal;
470 : }
471 :
472 0 : void ScConsData::AddData( ScDocument* pSrcDoc, SCTAB nTab,
473 : SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
474 : {
475 0 : PutInOrder(nCol1,nCol2);
476 0 : PutInOrder(nRow1,nRow2);
477 0 : if ( nCol2 >= sal::static_int_cast<SCCOL>(nCol1 + nColCount) && !bColByName )
478 : {
479 : OSL_FAIL("range too big");
480 0 : nCol2 = sal::static_int_cast<SCCOL>( nCol1 + nColCount - 1 );
481 : }
482 0 : if ( nRow2 >= sal::static_int_cast<SCROW>(nRow1 + nRowCount) && !bRowByName )
483 : {
484 : OSL_FAIL("range too big");
485 0 : nRow2 = sal::static_int_cast<SCROW>( nRow1 + nRowCount - 1 );
486 : }
487 :
488 : SCCOL nCol;
489 : SCROW nRow;
490 :
491 : // Ecke links oben
492 :
493 0 : if ( bColByName && bRowByName )
494 : {
495 0 : OUString aThisCorner = pSrcDoc->GetString(nCol1, nRow1, nTab);
496 0 : if (bCornerUsed)
497 : {
498 0 : if (aCornerText != aThisCorner)
499 0 : aCornerText = "";
500 : }
501 : else
502 : {
503 0 : aCornerText = aThisCorner;
504 0 : bCornerUsed = true;
505 0 : }
506 : }
507 :
508 : // Titel suchen
509 :
510 0 : SCCOL nStartCol = nCol1;
511 0 : SCROW nStartRow = nRow1;
512 0 : if (bColByName) ++nStartRow;
513 0 : if (bRowByName) ++nStartCol;
514 0 : OUString aTitle;
515 0 : SCCOL* pDestCols = NULL;
516 0 : SCROW* pDestRows = NULL;
517 0 : if (bColByName)
518 : {
519 0 : pDestCols = new SCCOL[nCol2-nStartCol+1];
520 0 : for (nCol=nStartCol; nCol<=nCol2; nCol++)
521 : {
522 0 : aTitle = pSrcDoc->GetString(nCol, nRow1, nTab);
523 0 : SCCOL nPos = SC_CONS_NOTFOUND;
524 0 : if (!aTitle.isEmpty())
525 : {
526 0 : bool bFound = false;
527 0 : for (SCSIZE i=0; i<nColCount && !bFound; i++)
528 0 : if ( mpColHeaders[i] == aTitle )
529 : {
530 0 : nPos = static_cast<SCCOL>(i);
531 0 : bFound = true;
532 : }
533 : OSL_ENSURE(bFound, "column not found");
534 : }
535 0 : pDestCols[nCol-nStartCol] = nPos;
536 : }
537 : }
538 0 : if (bRowByName)
539 : {
540 0 : pDestRows = new SCROW[nRow2-nStartRow+1];
541 0 : for (nRow=nStartRow; nRow<=nRow2; nRow++)
542 : {
543 0 : aTitle = pSrcDoc->GetString(nCol1, nRow, nTab);
544 0 : SCROW nPos = SC_CONS_NOTFOUND;
545 0 : if (!aTitle.isEmpty())
546 : {
547 0 : bool bFound = false;
548 0 : for (SCSIZE i=0; i<nRowCount && !bFound; i++)
549 0 : if ( mpRowHeaders[i] == aTitle )
550 : {
551 0 : nPos = static_cast<SCROW>(i);
552 0 : bFound = true;
553 : }
554 : OSL_ENSURE(bFound, "row not found");
555 : }
556 0 : pDestRows[nRow-nStartRow] = nPos;
557 : }
558 : }
559 0 : nCol1 = nStartCol;
560 0 : nRow1 = nStartRow;
561 :
562 : // Daten
563 :
564 0 : bool bAnyCell = ( eFunction == SUBTOTAL_FUNC_CNT2 );
565 0 : for (nCol=nCol1; nCol<=nCol2; nCol++)
566 : {
567 0 : SCCOL nArrX = nCol-nCol1;
568 0 : if (bColByName) nArrX = pDestCols[nArrX];
569 0 : if (nArrX != SC_CONS_NOTFOUND)
570 : {
571 0 : for (nRow=nRow1; nRow<=nRow2; nRow++)
572 : {
573 0 : SCROW nArrY = nRow-nRow1;
574 0 : if (bRowByName) nArrY = pDestRows[nArrY];
575 0 : if ( nArrY != SC_CONS_NOTFOUND && (
576 0 : bAnyCell ? pSrcDoc->HasData( nCol, nRow, nTab )
577 0 : : pSrcDoc->HasValueData( nCol, nRow, nTab ) ) )
578 : {
579 0 : if (bReference)
580 : {
581 0 : if (ppUsed[nArrX][nArrY])
582 0 : ppRefs[nArrX][nArrY].AddEntry( nCol, nRow, nTab );
583 : else
584 : {
585 0 : ppUsed[nArrX][nArrY] = true;
586 0 : ppRefs[nArrX][nArrY].Init();
587 0 : ppRefs[nArrX][nArrY].AddEntry( nCol, nRow, nTab );
588 : }
589 : }
590 : else
591 : {
592 : double nVal;
593 0 : pSrcDoc->GetValue( nCol, nRow, nTab, nVal );
594 0 : if (ppUsed[nArrX][nArrY])
595 0 : lcl_UpdateArray( eFunction, ppCount[nArrX][nArrY],
596 0 : ppSum[nArrX][nArrY], ppSumSqr[nArrX][nArrY],
597 0 : nVal);
598 : else
599 : {
600 0 : ppUsed[nArrX][nArrY] = true;
601 0 : lcl_InitArray( eFunction, ppCount[nArrX][nArrY],
602 0 : ppSum[nArrX][nArrY],
603 0 : ppSumSqr[nArrX][nArrY], nVal );
604 : }
605 : }
606 : }
607 : }
608 : }
609 : }
610 :
611 0 : delete[] pDestCols;
612 0 : delete[] pDestRows;
613 0 : }
614 :
615 : // vorher testen, wieviele Zeilen eingefuegt werden (fuer Undo)
616 :
617 0 : SCROW ScConsData::GetInsertCount() const
618 : {
619 0 : SCROW nInsert = 0;
620 : SCSIZE nArrX;
621 : SCSIZE nArrY;
622 0 : if ( ppRefs && ppUsed )
623 : {
624 0 : for (nArrY=0; nArrY<nRowCount; nArrY++)
625 : {
626 0 : SCSIZE nNeeded = 0;
627 0 : for (nArrX=0; nArrX<nColCount; nArrX++)
628 0 : if (ppUsed[nArrX][nArrY])
629 0 : nNeeded = std::max( nNeeded, ppRefs[nArrX][nArrY].GetCount() );
630 :
631 0 : nInsert += nNeeded;
632 : }
633 : }
634 0 : return nInsert;
635 : }
636 :
637 : // fertige Daten ins Dokument schreiben
638 : //! optimieren nach Spalten?
639 :
640 0 : void ScConsData::OutputToDocument( ScDocument* pDestDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
641 : {
642 0 : OpCode eOpCode = eOpCodeTable[eFunction];
643 :
644 : SCSIZE nArrX;
645 : SCSIZE nArrY;
646 :
647 : // Ecke links oben
648 :
649 0 : if ( bColByName && bRowByName && !aCornerText.isEmpty() )
650 0 : pDestDoc->SetString( nCol, nRow, nTab, aCornerText );
651 :
652 : // Titel
653 :
654 0 : SCCOL nStartCol = nCol;
655 0 : SCROW nStartRow = nRow;
656 0 : if (bColByName) ++nStartRow;
657 0 : if (bRowByName) ++nStartCol;
658 :
659 0 : if (bColByName)
660 0 : for (SCSIZE i=0; i<nColCount; i++)
661 0 : pDestDoc->SetString( sal::static_int_cast<SCCOL>(nStartCol+i), nRow, nTab, mpColHeaders[i] );
662 0 : if (bRowByName)
663 0 : for (SCSIZE j=0; j<nRowCount; j++)
664 0 : pDestDoc->SetString( nCol, sal::static_int_cast<SCROW>(nStartRow+j), nTab, mpRowHeaders[j] );
665 :
666 0 : nCol = nStartCol;
667 0 : nRow = nStartRow;
668 :
669 : // Daten
670 :
671 0 : if ( ppCount && ppUsed ) // Werte direkt einfuegen
672 : {
673 0 : for (nArrX=0; nArrX<nColCount; nArrX++)
674 0 : for (nArrY=0; nArrY<nRowCount; nArrY++)
675 0 : if (ppUsed[nArrX][nArrY])
676 : {
677 0 : double fVal = lcl_CalcData( eFunction, ppCount[nArrX][nArrY],
678 0 : ppSum[nArrX][nArrY],
679 0 : ppSumSqr[nArrX][nArrY]);
680 0 : if (ppCount[nArrX][nArrY] < 0.0)
681 0 : pDestDoc->SetError( sal::static_int_cast<SCCOL>(nCol+nArrX),
682 0 : sal::static_int_cast<SCROW>(nRow+nArrY), nTab, errNoValue );
683 : else
684 0 : pDestDoc->SetValue( sal::static_int_cast<SCCOL>(nCol+nArrX),
685 0 : sal::static_int_cast<SCROW>(nRow+nArrY), nTab, fVal );
686 : }
687 : }
688 :
689 0 : if ( ppRefs && ppUsed ) // Referenzen einfuegen
690 : {
691 : //! unterscheiden, ob nach Kategorien aufgeteilt
692 0 : OUString aString;
693 :
694 : ScSingleRefData aSRef; // Daten fuer Referenz-Formelzellen
695 0 : aSRef.InitFlags(); // This reference is absolute at all times.
696 0 : aSRef.SetFlag3D(true);
697 :
698 : ScComplexRefData aCRef; // Daten fuer Summen-Zellen
699 0 : aCRef.InitFlags();
700 0 : aCRef.Ref1.SetColRel(true); aCRef.Ref1.SetRowRel(true); aCRef.Ref1.SetTabRel(true);
701 0 : aCRef.Ref2.SetColRel(true); aCRef.Ref2.SetRowRel(true); aCRef.Ref2.SetTabRel(true);
702 :
703 0 : for (nArrY=0; nArrY<nRowCount; nArrY++)
704 : {
705 0 : SCSIZE nNeeded = 0;
706 0 : for (nArrX=0; nArrX<nColCount; nArrX++)
707 0 : if (ppUsed[nArrX][nArrY])
708 0 : nNeeded = std::max( nNeeded, ppRefs[nArrX][nArrY].GetCount() );
709 :
710 0 : if (nNeeded)
711 : {
712 0 : pDestDoc->InsertRow( 0,nTab, MAXCOL,nTab, nRow+nArrY, nNeeded );
713 :
714 0 : for (nArrX=0; nArrX<nColCount; nArrX++)
715 0 : if (ppUsed[nArrX][nArrY])
716 : {
717 0 : ScReferenceList& rList = ppRefs[nArrX][nArrY];
718 0 : SCSIZE nCount = rList.GetCount();
719 0 : if (nCount)
720 : {
721 0 : for (SCSIZE nPos=0; nPos<nCount; nPos++)
722 : {
723 0 : ScReferenceEntry aRef = rList.GetEntry(nPos);
724 0 : if (aRef.nTab != SC_CONS_NOTFOUND)
725 : {
726 : // Referenz einfuegen (absolut, 3d)
727 :
728 0 : aSRef.SetAddress(ScAddress(aRef.nCol,aRef.nRow,aRef.nTab), ScAddress());
729 :
730 0 : ScTokenArray aRefArr;
731 0 : aRefArr.AddSingleReference(aSRef);
732 0 : aRefArr.AddOpCode(ocStop);
733 0 : ScAddress aDest( sal::static_int_cast<SCCOL>(nCol+nArrX),
734 0 : sal::static_int_cast<SCROW>(nRow+nArrY+nPos), nTab );
735 0 : ScFormulaCell* pCell = new ScFormulaCell(pDestDoc, aDest, aRefArr);
736 0 : pDestDoc->SetFormulaCell(aDest, pCell);
737 : }
738 : }
739 :
740 : // Summe einfuegen (relativ, nicht 3d)
741 :
742 0 : ScAddress aDest( sal::static_int_cast<SCCOL>(nCol+nArrX),
743 0 : sal::static_int_cast<SCROW>(nRow+nArrY+nNeeded), nTab );
744 :
745 0 : ScRange aRange(sal::static_int_cast<SCCOL>(nCol+nArrX), nRow+nArrY, nTab);
746 0 : aRange.aEnd.SetRow(nRow+nArrY+nNeeded-1);
747 0 : aCRef.SetRange(aRange, aDest);
748 :
749 0 : ScTokenArray aArr;
750 0 : aArr.AddOpCode(eOpCode); // ausgewaehlte Funktion
751 0 : aArr.AddOpCode(ocOpen);
752 0 : aArr.AddDoubleReference(aCRef);
753 0 : aArr.AddOpCode(ocClose);
754 0 : aArr.AddOpCode(ocStop);
755 0 : ScFormulaCell* pCell = new ScFormulaCell(pDestDoc, aDest, aArr);
756 0 : pDestDoc->SetFormulaCell(aDest, pCell);
757 : }
758 : }
759 :
760 : // Gliederung einfuegen
761 :
762 0 : ScOutlineArray* pOutArr = pDestDoc->GetOutlineTable( nTab, true )->GetRowArray();
763 0 : SCROW nOutStart = nRow+nArrY;
764 0 : SCROW nOutEnd = nRow+nArrY+nNeeded-1;
765 0 : bool bSize = false;
766 0 : pOutArr->Insert( nOutStart, nOutEnd, bSize );
767 0 : for (SCROW nOutRow=nOutStart; nOutRow<=nOutEnd; nOutRow++)
768 0 : pDestDoc->ShowRow( nOutRow, nTab, false );
769 0 : pDestDoc->SetDrawPageSize(nTab);
770 0 : pDestDoc->UpdateOutlineRow( nOutStart, nOutEnd, nTab, false );
771 :
772 : // Zwischentitel
773 :
774 0 : if (ppTitlePos && mpTitles && mpRowHeaders)
775 : {
776 0 : OUString aDelim( " / " );
777 0 : for (SCSIZE nPos=0; nPos<nDataCount; nPos++)
778 : {
779 0 : SCSIZE nTPos = ppTitlePos[nArrY][nPos];
780 0 : bool bDo = true;
781 0 : if (nPos+1<nDataCount)
782 0 : if (ppTitlePos[nArrY][nPos+1] == nTPos)
783 0 : bDo = false; // leer
784 0 : if ( bDo && nTPos < nNeeded )
785 : {
786 0 : aString = mpRowHeaders[nArrY];
787 0 : aString += aDelim;
788 0 : aString += mpTitles[nPos];
789 0 : pDestDoc->SetString( nCol-1, nRow+nArrY+nTPos, nTab, aString );
790 : }
791 0 : }
792 : }
793 :
794 0 : nRow += nNeeded;
795 : }
796 0 : }
797 : }
798 0 : }
799 :
800 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|