1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: consoli.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 // INCLUDE ---------------------------------------------------------------
38 #include <tools/debug.hxx>
40 #include "consoli.hxx"
41 #include "document.hxx"
42 #include "olinetab.hxx"
43 #include "globstr.hrc"
44 #include "subtotal.hxx"
45 #include "formula/errorcodes.hxx"
51 #define SC_CONS_NOTFOUND -1
53 // STATIC DATA -----------------------------------------------------------
55 /* Strings bei Gelegenheit ganz raus...
56 static USHORT nFuncRes[] = { // Reihenfolge wie bei enum ScSubTotalFunc
65 STR_PIVOTFUNC_STDDEV2,
71 static OpCode eOpCodeTable
[] = { // Reihenfolge wie bei enum ScSubTotalFunc
85 // -----------------------------------------------------------------------
87 void ScReferenceList::AddEntry( SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
89 ScReferenceEntry
* pOldData
= pData
;
90 pData
= new ScReferenceEntry
[ nFullSize
+1 ];
93 memmove( pData
, pOldData
, nCount
* sizeof(ScReferenceEntry
) );
96 while (nCount
< nFullSize
)
98 pData
[nCount
].nCol
= SC_CONS_NOTFOUND
;
99 pData
[nCount
].nRow
= SC_CONS_NOTFOUND
;
100 pData
[nCount
].nTab
= SC_CONS_NOTFOUND
;
103 pData
[nCount
].nCol
= nCol
;
104 pData
[nCount
].nRow
= nRow
;
105 pData
[nCount
].nTab
= nTab
;
110 template< typename T
>
111 void lcl_AddString( String
**& pData
, T
& nCount
, const String
& rInsert
)
113 String
** pOldData
= pData
;
114 pData
= new String
*[ nCount
+1 ];
117 memmove( pData
, pOldData
, nCount
* sizeof(String
*) );
120 pData
[nCount
] = new String(rInsert
);
124 // -----------------------------------------------------------------------
126 ScConsData::ScConsData() :
127 eFunction(SUBTOTAL_FUNC_SUM
),
149 ScConsData::~ScConsData()
155 #define DELETEARR(ppArray,nCount) \
159 for(i=0; i<nCount; i++) \
160 delete[] ppArray[i]; \
165 #define DELETESTR(ppArray,nCount) \
169 for(i=0; i<nCount; i++) \
175 void ScConsData::DeleteData()
179 for (SCSIZE i
=0; i
<nColCount
; i
++)
181 for (SCSIZE j
=0; j
<nRowCount
; j
++)
183 ppRefs
[i
][j
].Clear();
190 // DELETEARR( ppData1, nColCount );
191 // DELETEARR( ppData2, nColCount );
192 DELETEARR( ppCount
, nColCount
);
193 DELETEARR( ppSum
, nColCount
);
194 DELETEARR( ppSumSqr
,nColCount
);
195 DELETEARR( ppUsed
, nColCount
); // erst nach ppRefs !!!
196 DELETEARR( ppTitlePos
, nRowCount
);
197 DELETESTR( ppColHeaders
, nColCount
);
198 DELETESTR( ppRowHeaders
, nRowCount
);
199 DELETESTR( ppTitles
, nTitleCount
);
203 if (bColByName
) nColCount
= 0; // sonst stimmt ppColHeaders nicht
204 if (bRowByName
) nRowCount
= 0;
213 void ScConsData::InitData( BOOL bDelete
)
218 if (bReference
&& nColCount
&& !ppRefs
)
220 ppRefs
= new ScReferenceList
*[nColCount
];
221 for (SCSIZE i
=0; i
<nColCount
; i
++)
222 ppRefs
[i
] = new ScReferenceList
[nRowCount
];
224 else if (nColCount
&& !ppCount
)
226 ppCount
= new double*[nColCount
];
227 ppSum
= new double*[nColCount
];
228 ppSumSqr
= new double*[nColCount
];
229 for (SCSIZE i
=0; i
<nColCount
; i
++)
231 ppCount
[i
] = new double[nRowCount
];
232 ppSum
[i
] = new double[nRowCount
];
233 ppSumSqr
[i
] = new double[nRowCount
];
237 if (nColCount
&& !ppUsed
)
239 ppUsed
= new BOOL
*[nColCount
];
240 for (SCSIZE i
=0; i
<nColCount
; i
++)
242 ppUsed
[i
] = new BOOL
[nRowCount
];
243 memset( ppUsed
[i
], 0, nRowCount
* sizeof(BOOL
) );
247 if (nRowCount
&& nDataCount
&& !ppTitlePos
)
249 ppTitlePos
= new SCSIZE
*[nRowCount
];
250 for (SCSIZE i
=0; i
<nRowCount
; i
++)
252 ppTitlePos
[i
] = new SCSIZE
[nDataCount
];
253 memset( ppTitlePos
[i
], 0, nDataCount
* sizeof(SCSIZE
) ); //! unnoetig ?
257 // CornerText: einzelner String
260 void ScConsData::DoneFields()
265 void ScConsData::SetSize( SCCOL nCols
, SCROW nRows
)
268 nColCount
= static_cast<SCSIZE
>(nCols
);
269 nRowCount
= static_cast<SCSIZE
>(nRows
);
272 void ScConsData::GetSize( SCCOL
& rCols
, SCROW
& rRows
) const
274 rCols
= static_cast<SCCOL
>(nColCount
);
275 rRows
= static_cast<SCROW
>(nRowCount
);
278 void ScConsData::SetFlags( ScSubTotalFunc eFunc
, BOOL bColName
, BOOL bRowName
, BOOL bRef
)
282 bColByName
= bColName
;
283 if (bColName
) nColCount
= 0;
284 bRowByName
= bRowName
;
285 if (bRowName
) nRowCount
= 0;
289 void ScConsData::AddFields( ScDocument
* pSrcDoc
, SCTAB nTab
,
290 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
296 SCCOL nStartCol
= nCol1
;
297 SCROW nStartRow
= nRow1
;
298 if (bColByName
) ++nStartRow
;
299 if (bRowByName
) ++nStartCol
;
303 for (SCCOL nCol
=nStartCol
; nCol
<=nCol2
; nCol
++)
305 pSrcDoc
->GetString( nCol
, nRow1
, nTab
, aTitle
);
309 for (SCSIZE i
=0; i
<nColCount
&& !bFound
; i
++)
310 if ( *ppColHeaders
[i
] == aTitle
)
313 lcl_AddString( ppColHeaders
, nColCount
, aTitle
);
320 for (SCROW nRow
=nStartRow
; nRow
<=nRow2
; nRow
++)
322 pSrcDoc
->GetString( nCol1
, nRow
, nTab
, aTitle
);
326 for (SCSIZE i
=0; i
<nRowCount
&& !bFound
; i
++)
327 if ( *ppRowHeaders
[i
] == aTitle
)
330 lcl_AddString( ppRowHeaders
, nRowCount
, aTitle
);
336 void ScConsData::AddName( const String
& rName
)
343 lcl_AddString( ppTitles
, nTitleCount
, rName
);
345 for (nArrY
=0; nArrY
<nRowCount
; nArrY
++)
347 // Daten auf gleiche Laenge bringen
350 for (nArrX
=0; nArrX
<nColCount
; nArrX
++)
351 if (ppUsed
[nArrX
][nArrY
])
352 nMax
= Max( nMax
, ppRefs
[nArrX
][nArrY
].GetCount() );
354 for (nArrX
=0; nArrX
<nColCount
; nArrX
++)
356 if (!ppUsed
[nArrX
][nArrY
])
358 ppUsed
[nArrX
][nArrY
] = TRUE
;
359 ppRefs
[nArrX
][nArrY
].Init();
361 ppRefs
[nArrX
][nArrY
].SetFullSize(nMax
);
364 // Positionen eintragen
367 if (nTitleCount
< nDataCount
)
368 ppTitlePos
[nArrY
][nTitleCount
] = nMax
;
373 // rCount < 0 <=> Fehler aufgetreten
375 void lcl_UpdateArray( ScSubTotalFunc eFunc
,
376 double& rCount
, double& rSum
, double& rSumSqr
, double nVal
)
382 case SUBTOTAL_FUNC_SUM
:
383 if (!SubTotal::SafePlus(rSum
, nVal
))
386 case SUBTOTAL_FUNC_PROD
:
387 if (!SubTotal::SafeMult(rSum
, nVal
))
390 case SUBTOTAL_FUNC_CNT
:
391 case SUBTOTAL_FUNC_CNT2
:
394 case SUBTOTAL_FUNC_AVE
:
395 if (!SubTotal::SafePlus(rSum
, nVal
))
400 case SUBTOTAL_FUNC_MAX
:
404 case SUBTOTAL_FUNC_MIN
:
408 case SUBTOTAL_FUNC_STD
:
409 case SUBTOTAL_FUNC_STDP
:
410 case SUBTOTAL_FUNC_VAR
:
411 case SUBTOTAL_FUNC_VARP
:
413 BOOL bOk
= SubTotal::SafePlus(rSum
, nVal
);
414 bOk
= bOk
&& SubTotal::SafeMult(nVal
, nVal
);
415 bOk
= bOk
&& SubTotal::SafePlus(rSumSqr
, nVal
);
424 // added to avoid warnings
429 void lcl_InitArray( ScSubTotalFunc eFunc
,
430 double& rCount
, double& rSum
, double& rSumSqr
, double nVal
)
435 case SUBTOTAL_FUNC_SUM
:
436 case SUBTOTAL_FUNC_MAX
:
437 case SUBTOTAL_FUNC_MIN
:
438 case SUBTOTAL_FUNC_PROD
:
439 case SUBTOTAL_FUNC_AVE
:
442 case SUBTOTAL_FUNC_STD
:
443 case SUBTOTAL_FUNC_STDP
:
444 case SUBTOTAL_FUNC_VAR
:
445 case SUBTOTAL_FUNC_VARP
:
448 BOOL bOk
= SubTotal::SafeMult(nVal
, nVal
);
460 double lcl_CalcData( ScSubTotalFunc eFunc
,
461 double fCount
, double fSum
, double fSumSqr
)
468 case SUBTOTAL_FUNC_CNT
:
469 case SUBTOTAL_FUNC_CNT2
:
472 case SUBTOTAL_FUNC_SUM
:
473 case SUBTOTAL_FUNC_MAX
:
474 case SUBTOTAL_FUNC_MIN
:
475 case SUBTOTAL_FUNC_PROD
:
478 case SUBTOTAL_FUNC_AVE
:
480 fVal
= fSum
/ fCount
;
484 case SUBTOTAL_FUNC_STD
:
486 if (fCount
> 1 && SubTotal::SafeMult(fSum
, fSum
))
487 fVal
= sqrt((fSumSqr
- fSum
/fCount
)/(fCount
-1.0));
492 case SUBTOTAL_FUNC_STDP
:
494 if (fCount
> 0 && SubTotal::SafeMult(fSum
, fSum
))
495 fVal
= sqrt((fSumSqr
- fSum
/fCount
)/fCount
);
500 case SUBTOTAL_FUNC_VAR
:
502 if (fCount
> 1 && SubTotal::SafeMult(fSum
, fSum
))
503 fVal
= (fSumSqr
- fSum
/fCount
)/(fCount
-1.0);
508 case SUBTOTAL_FUNC_VARP
:
510 if (fCount
> 0 && SubTotal::SafeMult(fSum
, fSum
))
511 fVal
= (fSumSqr
- fSum
/fCount
)/fCount
;
518 DBG_ERROR("unbekannte Funktion bei Consoli::CalcData");
526 void ScConsData::AddData( ScDocument
* pSrcDoc
, SCTAB nTab
,
527 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
529 PutInOrder(nCol1
,nCol2
);
530 PutInOrder(nRow1
,nRow2
);
531 if ( nCol2
>= sal::static_int_cast
<SCCOL
>(nCol1
+ nColCount
) && !bColByName
)
533 DBG_ASSERT(0,"Bereich zu gross");
534 nCol2
= sal::static_int_cast
<SCCOL
>( nCol1
+ nColCount
- 1 );
536 if ( nRow2
>= sal::static_int_cast
<SCROW
>(nRow1
+ nRowCount
) && !bRowByName
)
538 DBG_ASSERT(0,"Bereich zu gross");
539 nRow2
= sal::static_int_cast
<SCROW
>( nRow1
+ nRowCount
- 1 );
547 if ( bColByName
&& bRowByName
)
550 pSrcDoc
->GetString(nCol1
,nRow1
,nTab
,aThisCorner
);
553 if (aCornerText
!= aThisCorner
)
558 aCornerText
= aThisCorner
;
565 SCCOL nStartCol
= nCol1
;
566 SCROW nStartRow
= nRow1
;
567 if (bColByName
) ++nStartRow
;
568 if (bRowByName
) ++nStartCol
;
570 SCCOL
* pDestCols
= NULL
;
571 SCROW
* pDestRows
= NULL
;
574 pDestCols
= new SCCOL
[nCol2
-nStartCol
+1];
575 for (nCol
=nStartCol
; nCol
<=nCol2
; nCol
++)
577 pSrcDoc
->GetString(nCol
,nRow1
,nTab
,aTitle
);
578 SCCOL nPos
= SC_CONS_NOTFOUND
;
582 for (SCSIZE i
=0; i
<nColCount
&& !bFound
; i
++)
583 if ( *ppColHeaders
[i
] == aTitle
)
585 nPos
= static_cast<SCCOL
>(i
);
588 DBG_ASSERT(bFound
, "Spalte nicht gefunden");
590 pDestCols
[nCol
-nStartCol
] = nPos
;
595 pDestRows
= new SCROW
[nRow2
-nStartRow
+1];
596 for (nRow
=nStartRow
; nRow
<=nRow2
; nRow
++)
598 pSrcDoc
->GetString(nCol1
,nRow
,nTab
,aTitle
);
599 SCROW nPos
= SC_CONS_NOTFOUND
;
603 for (SCSIZE i
=0; i
<nRowCount
&& !bFound
; i
++)
604 if ( *ppRowHeaders
[i
] == aTitle
)
606 nPos
= static_cast<SCROW
>(i
);
609 DBG_ASSERT(bFound
, "Zeile nicht gefunden");
611 pDestRows
[nRow
-nStartRow
] = nPos
;
619 BOOL bAnyCell
= ( eFunction
== SUBTOTAL_FUNC_CNT2
);
620 for (nCol
=nCol1
; nCol
<=nCol2
; nCol
++)
622 SCCOL nArrX
= nCol
-nCol1
;
623 if (bColByName
) nArrX
= pDestCols
[nArrX
];
624 if (nArrX
!= SC_CONS_NOTFOUND
)
626 for (nRow
=nRow1
; nRow
<=nRow2
; nRow
++)
628 SCROW nArrY
= nRow
-nRow1
;
629 if (bRowByName
) nArrY
= pDestRows
[nArrY
];
630 if ( nArrY
!= SC_CONS_NOTFOUND
&& (
631 bAnyCell
? pSrcDoc
->HasData( nCol
, nRow
, nTab
)
632 : pSrcDoc
->HasValueData( nCol
, nRow
, nTab
) ) )
636 if (ppUsed
[nArrX
][nArrY
])
637 ppRefs
[nArrX
][nArrY
].AddEntry( nCol
, nRow
, nTab
);
640 ppUsed
[nArrX
][nArrY
] = TRUE
;
641 ppRefs
[nArrX
][nArrY
].Init();
642 ppRefs
[nArrX
][nArrY
].AddEntry( nCol
, nRow
, nTab
);
648 pSrcDoc
->GetValue( nCol
, nRow
, nTab
, nVal
);
649 if (ppUsed
[nArrX
][nArrY
])
650 lcl_UpdateArray( eFunction
, ppCount
[nArrX
][nArrY
],
651 ppSum
[nArrX
][nArrY
], ppSumSqr
[nArrX
][nArrY
],
655 ppUsed
[nArrX
][nArrY
] = TRUE
;
656 lcl_InitArray( eFunction
, ppCount
[nArrX
][nArrY
],
658 ppSumSqr
[nArrX
][nArrY
], nVal
);
670 // vorher testen, wieviele Zeilen eingefuegt werden (fuer Undo)
672 SCROW
ScConsData::GetInsertCount() const
677 if ( ppRefs
&& ppUsed
)
679 for (nArrY
=0; nArrY
<nRowCount
; nArrY
++)
682 for (nArrX
=0; nArrX
<nColCount
; nArrX
++)
683 if (ppUsed
[nArrX
][nArrY
])
684 nNeeded
= Max( nNeeded
, ppRefs
[nArrX
][nArrY
].GetCount() );
692 // fertige Daten ins Dokument schreiben
693 //! optimieren nach Spalten?
695 void ScConsData::OutputToDocument( ScDocument
* pDestDoc
, SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
697 OpCode eOpCode
= eOpCodeTable
[eFunction
];
704 if ( bColByName
&& bRowByName
&& aCornerText
.Len() )
705 pDestDoc
->SetString( nCol
, nRow
, nTab
, aCornerText
);
709 SCCOL nStartCol
= nCol
;
710 SCROW nStartRow
= nRow
;
711 if (bColByName
) ++nStartRow
;
712 if (bRowByName
) ++nStartCol
;
715 for (SCSIZE i
=0; i
<nColCount
; i
++)
716 pDestDoc
->SetString( sal::static_int_cast
<SCCOL
>(nStartCol
+i
), nRow
, nTab
, *ppColHeaders
[i
] );
718 for (SCSIZE j
=0; j
<nRowCount
; j
++)
719 pDestDoc
->SetString( nCol
, sal::static_int_cast
<SCROW
>(nStartRow
+j
), nTab
, *ppRowHeaders
[j
] );
726 if ( ppCount
&& ppUsed
) // Werte direkt einfuegen
728 for (nArrX
=0; nArrX
<nColCount
; nArrX
++)
729 for (nArrY
=0; nArrY
<nRowCount
; nArrY
++)
730 if (ppUsed
[nArrX
][nArrY
])
732 double fVal
= lcl_CalcData( eFunction
, ppCount
[nArrX
][nArrY
],
734 ppSumSqr
[nArrX
][nArrY
]);
735 if (ppCount
[nArrX
][nArrY
] < 0.0)
736 pDestDoc
->SetError( sal::static_int_cast
<SCCOL
>(nCol
+nArrX
),
737 sal::static_int_cast
<SCROW
>(nRow
+nArrY
), nTab
, errNoValue
);
739 pDestDoc
->SetValue( sal::static_int_cast
<SCCOL
>(nCol
+nArrX
),
740 sal::static_int_cast
<SCROW
>(nRow
+nArrY
), nTab
, fVal
);
744 if ( ppRefs
&& ppUsed
) // Referenzen einfuegen
746 //! unterscheiden, ob nach Kategorien aufgeteilt
749 ScSingleRefData aSRef
; // Daten fuer Referenz-Formelzellen
751 aSRef
.SetFlag3D(TRUE
);
753 ScComplexRefData aCRef
; // Daten fuer Summen-Zellen
755 aCRef
.Ref1
.SetColRel(TRUE
); aCRef
.Ref1
.SetRowRel(TRUE
); aCRef
.Ref1
.SetTabRel(TRUE
);
756 aCRef
.Ref2
.SetColRel(TRUE
); aCRef
.Ref2
.SetRowRel(TRUE
); aCRef
.Ref2
.SetTabRel(TRUE
);
758 for (nArrY
=0; nArrY
<nRowCount
; nArrY
++)
761 for (nArrX
=0; nArrX
<nColCount
; nArrX
++)
762 if (ppUsed
[nArrX
][nArrY
])
763 nNeeded
= Max( nNeeded
, ppRefs
[nArrX
][nArrY
].GetCount() );
767 pDestDoc
->InsertRow( 0,nTab
, MAXCOL
,nTab
, nRow
+nArrY
, nNeeded
);
769 for (nArrX
=0; nArrX
<nColCount
; nArrX
++)
770 if (ppUsed
[nArrX
][nArrY
])
772 ScReferenceList
& rList
= ppRefs
[nArrX
][nArrY
];
773 SCSIZE nCount
= rList
.GetCount();
776 for (SCSIZE nPos
=0; nPos
<nCount
; nPos
++)
778 ScReferenceEntry aRef
= rList
.GetEntry(nPos
);
779 if (aRef
.nTab
!= SC_CONS_NOTFOUND
)
781 // Referenz einfuegen (absolut, 3d)
783 aSRef
.nCol
= aRef
.nCol
;
784 aSRef
.nRow
= aRef
.nRow
;
785 aSRef
.nTab
= aRef
.nTab
;
787 ScTokenArray aRefArr
;
788 aRefArr
.AddSingleReference(aSRef
);
789 aRefArr
.AddOpCode(ocStop
);
790 ScAddress
aDest( sal::static_int_cast
<SCCOL
>(nCol
+nArrX
),
791 sal::static_int_cast
<SCROW
>(nRow
+nArrY
+nPos
), nTab
);
792 ScBaseCell
* pCell
= new ScFormulaCell( pDestDoc
, aDest
, &aRefArr
);
793 pDestDoc
->PutCell( aDest
.Col(), aDest
.Row(), aDest
.Tab(), pCell
);
797 // Summe einfuegen (relativ, nicht 3d)
799 ScAddress
aDest( sal::static_int_cast
<SCCOL
>(nCol
+nArrX
),
800 sal::static_int_cast
<SCROW
>(nRow
+nArrY
+nNeeded
), nTab
);
802 aCRef
.Ref1
.nTab
= aCRef
.Ref2
.nTab
= nTab
;
803 aCRef
.Ref1
.nCol
= aCRef
.Ref2
.nCol
= sal::static_int_cast
<SCsCOL
>( nCol
+nArrX
);
804 aCRef
.Ref1
.nRow
= nRow
+nArrY
;
805 aCRef
.Ref2
.nRow
= nRow
+nArrY
+nNeeded
-1;
806 aCRef
.CalcRelFromAbs( aDest
);
809 aArr
.AddOpCode(eOpCode
); // ausgewaehlte Funktion
810 aArr
.AddOpCode(ocOpen
);
811 aArr
.AddDoubleReference(aCRef
);
812 aArr
.AddOpCode(ocClose
);
813 aArr
.AddOpCode(ocStop
);
814 ScBaseCell
* pCell
= new ScFormulaCell( pDestDoc
, aDest
, &aArr
);
815 pDestDoc
->PutCell( aDest
.Col(), aDest
.Row(), aDest
.Tab(), pCell
);
819 // Gliederung einfuegen
821 ScOutlineArray
* pOutArr
= pDestDoc
->GetOutlineTable( nTab
, TRUE
)->GetRowArray();
822 SCROW nOutStart
= nRow
+nArrY
;
823 SCROW nOutEnd
= nRow
+nArrY
+nNeeded
-1;
825 pOutArr
->Insert( nOutStart
, nOutEnd
, bSize
);
826 for (SCROW nOutRow
=nOutStart
; nOutRow
<=nOutEnd
; nOutRow
++)
827 pDestDoc
->ShowRow( nOutRow
, nTab
, FALSE
);
828 pDestDoc
->UpdateOutlineRow( nOutStart
, nOutEnd
, nTab
, FALSE
);
832 if (ppTitlePos
&& ppTitles
&& ppRowHeaders
)
834 String
aDelim( RTL_CONSTASCII_USTRINGPARAM(" / ") );
835 for (SCSIZE nPos
=0; nPos
<nDataCount
; nPos
++)
837 SCSIZE nTPos
= ppTitlePos
[nArrY
][nPos
];
839 if (nPos
+1<nDataCount
)
840 if (ppTitlePos
[nArrY
][nPos
+1] == nTPos
)
842 if ( bDo
&& nTPos
< nNeeded
)
844 aString
= *ppRowHeaders
[nArrY
];
846 aString
+= *ppTitles
[nPos
];
847 pDestDoc
->SetString( nCol
-1, nRow
+nArrY
+nTPos
, nTab
, aString
);