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