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: dpoutput.cxx,v $
10 * $Revision: 1.17.30.2 $
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 "scitems.hxx"
39 #include <svx/algitem.hxx>
40 #include <svx/boxitem.hxx>
41 #include <svx/brshitem.hxx>
42 #include <svx/wghtitem.hxx>
43 #include <unotools/transliterationwrapper.hxx>
45 #include "dpoutput.hxx"
46 #include "dptabsrc.hxx"
47 #include "dpcachetable.hxx"
48 #include "document.hxx"
49 #include "patattr.hxx"
50 #include "docpool.hxx"
51 #include "markdata.hxx"
53 #include "formula/errorcodes.hxx" // errNoValue
54 #include "miscuno.hxx"
55 #include "globstr.hrc"
56 #include "stlpool.hxx"
57 #include "stlsheet.hxx"
58 #include "collect.hxx"
59 #include "scresid.hxx"
60 #include "unonames.hxx"
63 #include <com/sun/star/container/XNamed.hpp>
64 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
65 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
66 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
67 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
68 #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
69 #include <com/sun/star/sheet/DataPilotTableResultData.hpp>
70 #include <com/sun/star/sheet/DataResultFlags.hpp>
71 #include <com/sun/star/sheet/GeneralFunction.hpp>
72 #include <com/sun/star/sheet/MemberResultFlags.hpp>
73 #include <com/sun/star/sheet/TableFilterField.hpp>
74 #include <com/sun/star/sheet/XDataPilotMemberResults.hpp>
75 #include <com/sun/star/sheet/XDataPilotResults.hpp>
76 #include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
77 #include <com/sun/star/sheet/XLevelsSupplier.hpp>
78 #include <com/sun/star/beans/XPropertySet.hpp>
82 using namespace com::sun::star
;
84 using ::com::sun::star::beans::XPropertySet
;
85 using ::com::sun::star::uno::Sequence
;
86 using ::com::sun::star::uno::UNO_QUERY
;
87 using ::com::sun::star::uno::Reference
;
88 using ::com::sun::star::sheet::DataPilotTablePositionData
;
89 using ::com::sun::star::sheet::DataPilotTableResultData
;
90 using ::com::sun::star::uno::makeAny
;
91 using ::com::sun::star::uno::Any
;
92 using ::rtl::OUString
;
94 // -----------------------------------------------------------------------
96 //! move to a header file
97 //! use names from unonames.hxx?
98 #define DP_PROP_FUNCTION "Function"
99 #define DP_PROP_ORIENTATION "Orientation"
100 #define DP_PROP_POSITION "Position"
101 #define DP_PROP_USEDHIERARCHY "UsedHierarchy"
102 #define DP_PROP_ISDATALAYOUT "IsDataLayoutDimension"
103 #define DP_PROP_NUMBERFORMAT "NumberFormat"
104 #define DP_PROP_FILTER "Filter"
105 #define DP_PROP_COLUMNGRAND "ColumnGrand"
106 #define DP_PROP_ROWGRAND "RowGrand"
107 #define DP_PROP_SUBTOTALS "SubTotals"
109 // -----------------------------------------------------------------------
112 #define SC_DPOUT_MAXLEVELS 256
115 struct ScDPOutLevelData
121 uno::Sequence
<sheet::MemberResult
> aResult
;
122 String maName
; /// Name is the internal field name.
123 String aCaption
; /// Caption is the name visible in the output table.
124 bool mbHasHiddenMember
;
128 nDim
= nHier
= nLevel
= nDimPos
= -1;
129 mbHasHiddenMember
= false;
132 BOOL
operator<(const ScDPOutLevelData
& r
) const
133 { return nDimPos
<r
.nDimPos
|| ( nDimPos
==r
.nDimPos
&& nHier
<r
.nHier
) ||
134 ( nDimPos
==r
.nDimPos
&& nHier
==r
.nHier
&& nLevel
<r
.nLevel
); }
136 void Swap(ScDPOutLevelData
& r
)
137 //! { ScDPOutLevelData aTemp = r; r = *this; *this = aTemp; }
138 { ScDPOutLevelData aTemp
; aTemp
= r
; r
= *this; *this = aTemp
; }
140 //! bug (73840) in uno::Sequence - copy and then assign doesn't work!
143 // -----------------------------------------------------------------------
145 void lcl_SetStyleById( ScDocument
* pDoc
, SCTAB nTab
,
146 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
149 if ( nCol1
> nCol2
|| nRow1
> nRow2
)
151 DBG_ERROR("SetStyleById: invalid range");
155 String aStyleName
= ScGlobal::GetRscString( nStrId
);
156 ScStyleSheetPool
* pStlPool
= pDoc
->GetStyleSheetPool();
157 ScStyleSheet
* pStyle
= (ScStyleSheet
*) pStlPool
->Find( aStyleName
, SFX_STYLE_FAMILY_PARA
);
160 // create new style (was in ScPivot::SetStyle)
162 pStyle
= (ScStyleSheet
*) &pStlPool
->Make( aStyleName
, SFX_STYLE_FAMILY_PARA
,
163 SFXSTYLEBIT_USERDEF
);
164 pStyle
->SetParent( ScGlobal::GetRscString(STR_STYLENAME_STANDARD
) );
165 SfxItemSet
& rSet
= pStyle
->GetItemSet();
166 if ( nStrId
==STR_PIVOT_STYLE_RESULT
|| nStrId
==STR_PIVOT_STYLE_TITLE
)
167 rSet
.Put( SvxWeightItem( WEIGHT_BOLD
, ATTR_FONT_WEIGHT
) );
168 if ( nStrId
==STR_PIVOT_STYLE_CATEGORY
|| nStrId
==STR_PIVOT_STYLE_TITLE
)
169 rSet
.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT
, ATTR_HOR_JUSTIFY
) );
172 pDoc
->ApplyStyleAreaTab( nCol1
, nRow1
, nCol2
, nRow2
, nTab
, *pStyle
);
175 void lcl_SetFrame( ScDocument
* pDoc
, SCTAB nTab
,
176 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
180 aLine
.SetOutWidth(nWidth
);
181 SvxBoxItem
aBox( ATTR_BORDER
);
182 aBox
.SetLine(&aLine
, BOX_LINE_LEFT
);
183 aBox
.SetLine(&aLine
, BOX_LINE_TOP
);
184 aBox
.SetLine(&aLine
, BOX_LINE_RIGHT
);
185 aBox
.SetLine(&aLine
, BOX_LINE_BOTTOM
);
186 SvxBoxInfoItem
aBoxInfo( ATTR_BORDER_INNER
);
187 aBoxInfo
.SetValid(VALID_HORI
,FALSE
);
188 aBoxInfo
.SetValid(VALID_VERT
,FALSE
);
189 aBoxInfo
.SetValid(VALID_DISTANCE
,FALSE
);
191 pDoc
->ApplyFrameAreaTab( ScRange( nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
), &aBox
, &aBoxInfo
);
194 // -----------------------------------------------------------------------
196 void lcl_FillNumberFormats( UINT32
*& rFormats
, long& rCount
,
197 const uno::Reference
<sheet::XDataPilotMemberResults
>& xLevRes
,
198 const uno::Reference
<container::XIndexAccess
>& xDims
)
201 return; // already set
203 // xLevRes is from the data layout dimension
204 //! use result sequence from ScDPOutLevelData!
206 uno::Sequence
<sheet::MemberResult
> aResult
= xLevRes
->getResults();
208 long nSize
= aResult
.getLength();
211 // get names/formats for all data dimensions
212 //! merge this with the loop to collect ScDPOutLevelData?
214 String aDataNames
[SC_DPOUT_MAXLEVELS
];
215 UINT32 nDataFormats
[SC_DPOUT_MAXLEVELS
];
217 BOOL bAnySet
= FALSE
;
219 long nDimCount
= xDims
->getCount();
220 for (long nDim
=0; nDim
<nDimCount
; nDim
++)
222 uno::Reference
<uno::XInterface
> xDim
=
223 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
224 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
225 uno::Reference
<container::XNamed
> xDimName( xDim
, uno::UNO_QUERY
);
226 if ( xDimProp
.is() && xDimName
.is() )
228 sheet::DataPilotFieldOrientation eDimOrient
=
229 (sheet::DataPilotFieldOrientation
) ScUnoHelpFunctions::GetEnumProperty(
230 xDimProp
, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION
),
231 sheet::DataPilotFieldOrientation_HIDDEN
);
232 if ( eDimOrient
== sheet::DataPilotFieldOrientation_DATA
)
234 aDataNames
[nDataCount
] = String( xDimName
->getName() );
235 long nFormat
= ScUnoHelpFunctions::GetLongProperty(
237 rtl::OUString::createFromAscii(DP_PROP_NUMBERFORMAT
) );
238 nDataFormats
[nDataCount
] = nFormat
;
246 if ( bAnySet
) // forget everything if all formats are 0 (or no data dimensions)
248 const sheet::MemberResult
* pArray
= aResult
.getConstArray();
251 UINT32
* pNumFmt
= new UINT32
[nSize
];
254 // only one data dimension -> use its numberformat everywhere
255 long nFormat
= nDataFormats
[0];
256 for (long nPos
=0; nPos
<nSize
; nPos
++)
257 pNumFmt
[nPos
] = nFormat
;
261 for (long nPos
=0; nPos
<nSize
; nPos
++)
263 // if CONTINUE bit is set, keep previous name
264 //! keep number format instead!
265 if ( !(pArray
[nPos
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
266 aName
= String( pArray
[nPos
].Name
);
269 for (long i
=0; i
<nDataCount
; i
++)
270 if (aName
== aDataNames
[i
]) //! search more efficiently?
272 nFormat
= nDataFormats
[i
];
275 pNumFmt
[nPos
] = nFormat
;
285 UINT32
lcl_GetFirstNumberFormat( const uno::Reference
<container::XIndexAccess
>& xDims
)
287 long nDimCount
= xDims
->getCount();
288 for (long nDim
=0; nDim
<nDimCount
; nDim
++)
290 uno::Reference
<uno::XInterface
> xDim
=
291 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
292 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
295 sheet::DataPilotFieldOrientation eDimOrient
=
296 (sheet::DataPilotFieldOrientation
) ScUnoHelpFunctions::GetEnumProperty(
297 xDimProp
, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION
),
298 sheet::DataPilotFieldOrientation_HIDDEN
);
299 if ( eDimOrient
== sheet::DataPilotFieldOrientation_DATA
)
301 long nFormat
= ScUnoHelpFunctions::GetLongProperty(
303 rtl::OUString::createFromAscii(DP_PROP_NUMBERFORMAT
) );
305 return nFormat
; // use format from first found data dimension
310 return 0; // none found
313 void lcl_SortFields( ScDPOutLevelData
* pFields
, long nFieldCount
)
315 for (long i
=0; i
+1<nFieldCount
; i
++)
317 for (long j
=0; j
+i
+1<nFieldCount
; j
++)
318 if ( pFields
[j
+1] < pFields
[j
] )
319 pFields
[j
].Swap( pFields
[j
+1] );
323 BOOL
lcl_MemberEmpty( const uno::Sequence
<sheet::MemberResult
>& rSeq
)
325 // used to skip levels that have no members
327 long nLen
= rSeq
.getLength();
328 const sheet::MemberResult
* pArray
= rSeq
.getConstArray();
329 for (long i
=0; i
<nLen
; i
++)
330 if (pArray
[i
].Flags
& sheet::MemberResultFlags::HASMEMBER
)
333 return TRUE
; // no member data -> empty
336 uno::Sequence
<sheet::MemberResult
> lcl_GetSelectedPageAsResult( const uno::Reference
<beans::XPropertySet
>& xDimProp
)
338 uno::Sequence
<sheet::MemberResult
> aRet
;
343 //! merge with ScDPDimension::setPropertyValue?
345 uno::Any aValue
= xDimProp
->getPropertyValue( rtl::OUString::createFromAscii(DP_PROP_FILTER
) );
347 uno::Sequence
<sheet::TableFilterField
> aSeq
;
350 if ( aSeq
.getLength() == 1 )
352 const sheet::TableFilterField
& rField
= aSeq
[0];
353 if ( rField
.Field
== 0 && rField
.Operator
== sheet::FilterOperator_EQUAL
&& !rField
.IsNumeric
)
355 rtl::OUString
aSelectedPage( rField
.StringValue
);
356 //! different name/caption string?
357 sheet::MemberResult
aResult( aSelectedPage
, aSelectedPage
, 0 );
358 aRet
= uno::Sequence
<sheet::MemberResult
>( &aResult
, 1 );
361 // else return empty sequence
364 catch ( uno::Exception
& )
366 // recent addition - allow source to not handle it (no error)
372 ScDPOutput::ScDPOutput( ScDocument
* pD
, const uno::Reference
<sheet::XDimensionsSupplier
>& xSrc
,
373 const ScAddress
& rPos
, BOOL bFilter
) :
377 bDoFilter( bFilter
),
378 bResultsError( FALSE
),
379 mbHasDataLayout(false),
385 bSizesValid( FALSE
),
386 bSizeOverflow( FALSE
),
387 mbHeaderLayout( false )
389 nTabStartCol
= nMemberStartCol
= nDataStartCol
= nTabEndCol
= 0;
390 nTabStartRow
= nMemberStartRow
= nDataStartRow
= nTabEndRow
= 0;
392 pColFields
= new ScDPOutLevelData
[SC_DPOUT_MAXLEVELS
];
393 pRowFields
= new ScDPOutLevelData
[SC_DPOUT_MAXLEVELS
];
394 pPageFields
= new ScDPOutLevelData
[SC_DPOUT_MAXLEVELS
];
399 uno::Reference
<sheet::XDataPilotResults
> xResult( xSource
, uno::UNO_QUERY
);
400 if ( xSource
.is() && xResult
.is() )
402 // get dimension results:
404 uno::Reference
<container::XIndexAccess
> xDims
=
405 new ScNameToIndexAccess( xSource
->getDimensions() );
406 long nDimCount
= xDims
->getCount();
407 for (long nDim
=0; nDim
<nDimCount
; nDim
++)
409 uno::Reference
<uno::XInterface
> xDim
=
410 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
411 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
412 uno::Reference
<sheet::XHierarchiesSupplier
> xDimSupp( xDim
, uno::UNO_QUERY
);
413 if ( xDimProp
.is() && xDimSupp
.is() )
415 sheet::DataPilotFieldOrientation eDimOrient
=
416 (sheet::DataPilotFieldOrientation
) ScUnoHelpFunctions::GetEnumProperty(
417 xDimProp
, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION
),
418 sheet::DataPilotFieldOrientation_HIDDEN
);
419 long nDimPos
= ScUnoHelpFunctions::GetLongProperty( xDimProp
,
420 rtl::OUString::createFromAscii(DP_PROP_POSITION
) );
421 BOOL bIsDataLayout
= ScUnoHelpFunctions::GetBoolProperty(
423 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT
) );
424 bool bHasHiddenMember
= ScUnoHelpFunctions::GetBoolProperty(
425 xDimProp
, OUString::createFromAscii(SC_UNO_HAS_HIDDEN_MEMBER
));
427 if ( eDimOrient
!= sheet::DataPilotFieldOrientation_HIDDEN
)
429 uno::Reference
<container::XIndexAccess
> xHiers
=
430 new ScNameToIndexAccess( xDimSupp
->getHierarchies() );
431 long nHierarchy
= ScUnoHelpFunctions::GetLongProperty(
433 rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY
) );
434 if ( nHierarchy
>= xHiers
->getCount() )
437 uno::Reference
<uno::XInterface
> xHier
=
438 ScUnoHelpFunctions::AnyToInterface(
439 xHiers
->getByIndex(nHierarchy
) );
440 uno::Reference
<sheet::XLevelsSupplier
> xHierSupp( xHier
, uno::UNO_QUERY
);
441 if ( xHierSupp
.is() )
443 uno::Reference
<container::XIndexAccess
> xLevels
=
444 new ScNameToIndexAccess( xHierSupp
->getLevels() );
445 long nLevCount
= xLevels
->getCount();
446 for (long nLev
=0; nLev
<nLevCount
; nLev
++)
448 uno::Reference
<uno::XInterface
> xLevel
=
449 ScUnoHelpFunctions::AnyToInterface(
450 xLevels
->getByIndex(nLev
) );
451 uno::Reference
<container::XNamed
> xLevNam( xLevel
, uno::UNO_QUERY
);
452 uno::Reference
<sheet::XDataPilotMemberResults
> xLevRes(
453 xLevel
, uno::UNO_QUERY
);
454 if ( xLevNam
.is() && xLevRes
.is() )
456 String aName
= xLevNam
->getName();
457 OUString aCaption
= aName
; // Caption equals the field name by default.
458 Reference
<XPropertySet
> xPropSet(xLevel
, UNO_QUERY
);
461 Any any
= xPropSet
->getPropertyValue(
462 OUString::createFromAscii(SC_UNO_LAYOUTNAME
));
466 bool bRowFieldHasMember
= false;
467 switch ( eDimOrient
)
469 case sheet::DataPilotFieldOrientation_COLUMN
:
470 pColFields
[nColFieldCount
].nDim
= nDim
;
471 pColFields
[nColFieldCount
].nHier
= nHierarchy
;
472 pColFields
[nColFieldCount
].nLevel
= nLev
;
473 pColFields
[nColFieldCount
].nDimPos
= nDimPos
;
474 pColFields
[nColFieldCount
].aResult
= xLevRes
->getResults();
475 pColFields
[nColFieldCount
].maName
= aName
;
476 pColFields
[nColFieldCount
].aCaption
= aCaption
;
477 pColFields
[nColFieldCount
].mbHasHiddenMember
= bHasHiddenMember
;
478 if (!lcl_MemberEmpty(pColFields
[nColFieldCount
].aResult
))
481 case sheet::DataPilotFieldOrientation_ROW
:
482 pRowFields
[nRowFieldCount
].nDim
= nDim
;
483 pRowFields
[nRowFieldCount
].nHier
= nHierarchy
;
484 pRowFields
[nRowFieldCount
].nLevel
= nLev
;
485 pRowFields
[nRowFieldCount
].nDimPos
= nDimPos
;
486 pRowFields
[nRowFieldCount
].aResult
= xLevRes
->getResults();
487 pRowFields
[nRowFieldCount
].maName
= aName
;
488 pRowFields
[nRowFieldCount
].aCaption
= aCaption
;
489 pRowFields
[nRowFieldCount
].mbHasHiddenMember
= bHasHiddenMember
;
490 if (!lcl_MemberEmpty(pRowFields
[nRowFieldCount
].aResult
))
493 bRowFieldHasMember
= true;
496 case sheet::DataPilotFieldOrientation_PAGE
:
497 pPageFields
[nPageFieldCount
].nDim
= nDim
;
498 pPageFields
[nPageFieldCount
].nHier
= nHierarchy
;
499 pPageFields
[nPageFieldCount
].nLevel
= nLev
;
500 pPageFields
[nPageFieldCount
].nDimPos
= nDimPos
;
501 pPageFields
[nPageFieldCount
].aResult
= lcl_GetSelectedPageAsResult(xDimProp
);
502 pPageFields
[nPageFieldCount
].maName
= aName
;
503 pPageFields
[nPageFieldCount
].aCaption
= aCaption
;
504 pPageFields
[nPageFieldCount
].mbHasHiddenMember
= bHasHiddenMember
;
505 // no check on results for page fields
510 // added to avoid warnings
514 // get number formats from data dimensions
517 if (bRowFieldHasMember
)
518 mbHasDataLayout
= true;
520 DBG_ASSERT( nLevCount
== 1, "data layout: multiple levels?" );
521 if ( eDimOrient
== sheet::DataPilotFieldOrientation_COLUMN
)
522 lcl_FillNumberFormats( pColNumFmt
, nColFmtCount
, xLevRes
, xDims
);
523 else if ( eDimOrient
== sheet::DataPilotFieldOrientation_ROW
)
524 lcl_FillNumberFormats( pRowNumFmt
, nRowFmtCount
, xLevRes
, xDims
);
530 else if ( bIsDataLayout
)
532 // data layout dimension is hidden (allowed if there is only one data dimension)
533 // -> use the number format from the first data dimension for all results
535 nSingleNumFmt
= lcl_GetFirstNumberFormat( xDims
);
539 lcl_SortFields( pColFields
, nColFieldCount
);
540 lcl_SortFields( pRowFields
, nRowFieldCount
);
541 lcl_SortFields( pPageFields
, nPageFieldCount
);
547 aData
= xResult
->getResults();
549 catch (uno::RuntimeException
&)
551 bResultsError
= TRUE
;
555 // get "DataDescription" property (may be missing in external sources)
557 uno::Reference
<beans::XPropertySet
> xSrcProp( xSource
, uno::UNO_QUERY
);
562 uno::Any aAny
= xSrcProp
->getPropertyValue(
563 rtl::OUString::createFromAscii(SC_UNO_DATADESC
) );
566 aDataDescription
= String( aUStr
);
568 catch(uno::Exception
&)
574 ScDPOutput::~ScDPOutput()
578 delete[] pPageFields
;
584 void ScDPOutput::SetPosition( const ScAddress
& rPos
)
587 bSizesValid
= bSizeOverflow
= FALSE
;
590 void ScDPOutput::DataCell( SCCOL nCol
, SCROW nRow
, SCTAB nTab
, const sheet::DataResult
& rData
)
592 long nFlags
= rData
.Flags
;
593 if ( nFlags
& sheet::DataResultFlags::ERROR
)
595 pDoc
->SetError( nCol
, nRow
, nTab
, errNoValue
);
597 else if ( nFlags
& sheet::DataResultFlags::HASDATA
)
599 pDoc
->SetValue( nCol
, nRow
, nTab
, rData
.Value
);
601 // use number formats from source
603 DBG_ASSERT( bSizesValid
, "DataCell: !bSizesValid" );
607 if ( nCol
>= nDataStartCol
)
609 long nIndex
= nCol
- nDataStartCol
;
610 if ( nIndex
< nColFmtCount
)
611 nFormat
= pColNumFmt
[nIndex
];
614 else if ( pRowNumFmt
)
616 if ( nRow
>= nDataStartRow
)
618 long nIndex
= nRow
- nDataStartRow
;
619 if ( nIndex
< nRowFmtCount
)
620 nFormat
= pRowNumFmt
[nIndex
];
623 else if ( nSingleNumFmt
!= 0 )
624 nFormat
= nSingleNumFmt
; // single format is used everywhere
626 pDoc
->ApplyAttr( nCol
, nRow
, nTab
, SfxUInt32Item( ATTR_VALUE_FORMAT
, nFormat
) );
630 //pDoc->SetString( nCol, nRow, nTab, EMPTY_STRING );
633 // SubTotal formatting is controlled by headers
636 void ScDPOutput::HeaderCell( SCCOL nCol
, SCROW nRow
, SCTAB nTab
,
637 const sheet::MemberResult
& rData
, BOOL bColHeader
, long nLevel
)
639 long nFlags
= rData
.Flags
;
641 rtl::OUStringBuffer aCaptionBuf
;
642 if (!(nFlags
& sheet::MemberResultFlags::NUMERIC
))
643 // This caption is not a number. Make sure it won't get parsed as one.
644 aCaptionBuf
.append(sal_Unicode('\''));
645 aCaptionBuf
.append(rData
.Caption
);
647 if ( nFlags
& sheet::MemberResultFlags::HASMEMBER
)
649 pDoc
->SetString( nCol
, nRow
, nTab
, aCaptionBuf
.makeStringAndClear() );
653 //pDoc->SetString( nCol, nRow, nTab, EMPTY_STRING );
656 if ( nFlags
& sheet::MemberResultFlags::SUBTOTAL
)
658 // SvxWeightItem aItem( WEIGHT_BOLD ); // weight is in the style
660 //! limit frames to horizontal or vertical?
663 lcl_SetFrame( pDoc
,nTab
, nCol
,nMemberStartRow
+(SCROW
)nLevel
, nCol
,nTabEndRow
, 20 );
664 lcl_SetStyleById( pDoc
,nTab
, nCol
,nMemberStartRow
+(SCROW
)nLevel
, nCol
,nDataStartRow
-1,
665 STR_PIVOT_STYLE_TITLE
);
666 lcl_SetStyleById( pDoc
,nTab
, nCol
,nDataStartRow
, nCol
,nTabEndRow
,
667 STR_PIVOT_STYLE_RESULT
);
671 lcl_SetFrame( pDoc
,nTab
, nMemberStartCol
+(SCCOL
)nLevel
,nRow
, nTabEndCol
,nRow
, 20 );
672 lcl_SetStyleById( pDoc
,nTab
, nMemberStartCol
+(SCCOL
)nLevel
,nRow
, nDataStartCol
-1,nRow
,
673 STR_PIVOT_STYLE_TITLE
);
674 lcl_SetStyleById( pDoc
,nTab
, nDataStartCol
,nRow
, nTabEndCol
,nRow
,
675 STR_PIVOT_STYLE_RESULT
);
680 void ScDPOutput::FieldCell( SCCOL nCol
, SCROW nRow
, SCTAB nTab
, const String
& rCaption
,
681 bool bInTable
, bool bPopup
, bool bHasHiddenMember
)
683 pDoc
->SetString( nCol
, nRow
, nTab
, rCaption
);
685 lcl_SetFrame( pDoc
,nTab
, nCol
,nRow
, nCol
,nRow
, 20 );
688 sal_uInt16 nMergeFlag
= SC_MF_BUTTON
;
690 nMergeFlag
|= SC_MF_BUTTON_POPUP
;
691 if (bHasHiddenMember
)
692 nMergeFlag
|= SC_MF_HIDDEN_MEMBER
;
693 pDoc
->ApplyFlagsTab(nCol
, nRow
, nCol
, nRow
, nTab
, nMergeFlag
);
695 lcl_SetStyleById( pDoc
,nTab
, nCol
,nRow
, nCol
,nRow
, STR_PIVOT_STYLE_FIELDNAME
);
698 void lcl_DoFilterButton( ScDocument
* pDoc
, SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
700 pDoc
->SetString( nCol
, nRow
, nTab
, ScGlobal::GetRscString(STR_CELL_FILTER
) );
701 pDoc
->ApplyFlagsTab(nCol
, nRow
, nCol
, nRow
, nTab
, SC_MF_BUTTON
);
704 void ScDPOutput::CalcSizes()
708 // get column size of data from first row
709 //! allow different sizes (and clear following areas) ???
711 nRowCount
= aData
.getLength();
712 const uno::Sequence
<sheet::DataResult
>* pRowAry
= aData
.getConstArray();
713 nColCount
= nRowCount
? ( pRowAry
[0].getLength() ) : 0;
716 if (GetHeaderLayout() && nColFieldCount
== 0)
717 // Insert an extra header row only when there is no column field.
720 // calculate output positions and sizes
722 long nPageSize
= 0; //! use page fields!
723 if ( bDoFilter
|| nPageFieldCount
)
725 nPageSize
+= nPageFieldCount
+ 1; // plus one empty row
727 ++nPageSize
; // filter button above the page fields
730 if ( aStartPos
.Col() + nRowFieldCount
+ nColCount
- 1 > MAXCOL
||
731 aStartPos
.Row() + nPageSize
+ nHeaderSize
+ nColFieldCount
+ nRowCount
> MAXROW
)
733 bSizeOverflow
= TRUE
;
736 nTabStartCol
= aStartPos
.Col();
737 nTabStartRow
= aStartPos
.Row() + (SCROW
)nPageSize
; // below page fields
738 nMemberStartCol
= nTabStartCol
;
739 nMemberStartRow
= nTabStartRow
+ (SCROW
) nHeaderSize
;
740 nDataStartCol
= nMemberStartCol
+ (SCCOL
)nRowFieldCount
;
741 nDataStartRow
= nMemberStartRow
+ (SCROW
)nColFieldCount
;
743 nTabEndCol
= nDataStartCol
+ (SCCOL
)nColCount
- 1;
745 nTabEndCol
= nDataStartCol
; // single column will remain empty
746 // if page fields are involved, include the page selection cells
747 if ( nPageFieldCount
> 0 && nTabEndCol
< nTabStartCol
+ 1 )
748 nTabEndCol
= nTabStartCol
+ 1;
750 nTabEndRow
= nDataStartRow
+ (SCROW
)nRowCount
- 1;
752 nTabEndRow
= nDataStartRow
; // single row will remain empty
757 sal_Int32
ScDPOutput::GetPositionType(const ScAddress
& rPos
)
759 using namespace ::com::sun::star::sheet
;
761 SCCOL nCol
= rPos
.Col();
762 SCROW nRow
= rPos
.Row();
763 SCTAB nTab
= rPos
.Tab();
764 if ( nTab
!= aStartPos
.Tab() )
765 return DataPilotTablePositionType::NOT_IN_TABLE
;
769 // Make sure the cursor is within the table.
770 if (nCol
< nTabStartCol
|| nRow
< nTabStartRow
|| nCol
> nTabEndCol
|| nRow
> nTabEndRow
)
771 return DataPilotTablePositionType::NOT_IN_TABLE
;
773 // test for result data area.
774 if (nCol
>= nDataStartCol
&& nCol
<= nTabEndCol
&& nRow
>= nDataStartRow
&& nRow
<= nTabEndRow
)
775 return DataPilotTablePositionType::RESULT
;
777 bool bInColHeader
= (nRow
>= nTabStartRow
&& nRow
< nDataStartRow
);
778 bool bInRowHeader
= (nCol
>= nTabStartCol
&& nCol
< nDataStartCol
);
780 if (bInColHeader
&& bInRowHeader
)
781 // probably in that ugly little box at the upper-left corner of the table.
782 return DataPilotTablePositionType::OTHER
;
786 if (nRow
== nTabStartRow
)
787 // first row in the column header area is always used for column
789 return DataPilotTablePositionType::OTHER
;
791 return DataPilotTablePositionType::COLUMN_HEADER
;
795 return DataPilotTablePositionType::ROW_HEADER
;
797 return DataPilotTablePositionType::OTHER
;
800 void ScDPOutput::Output()
803 SCTAB nTab
= aStartPos
.Tab();
804 const uno::Sequence
<sheet::DataResult
>* pRowAry
= aData
.getConstArray();
806 // calculate output positions and sizes
809 if ( bSizeOverflow
|| bResultsError
) // does output area exceed sheet limits?
812 // clear whole (new) output area
813 //! when modifying table, clear old area
814 //! include IDF_OBJECTS ???
815 pDoc
->DeleteAreaTab( aStartPos
.Col(), aStartPos
.Row(), nTabEndCol
, nTabEndRow
, nTab
, IDF_ALL
);
818 lcl_DoFilterButton( pDoc
, aStartPos
.Col(), aStartPos
.Row(), nTab
);
820 // output page fields:
822 for (nField
=0; nField
<nPageFieldCount
; nField
++)
824 SCCOL nHdrCol
= aStartPos
.Col();
825 SCROW nHdrRow
= aStartPos
.Row() + nField
+ ( bDoFilter
? 1 : 0 );
826 // draw without frame for consistency with filter button:
827 FieldCell( nHdrCol
, nHdrRow
, nTab
, pPageFields
[nField
].aCaption
, false, false, pPageFields
[nField
].mbHasHiddenMember
);
828 SCCOL nFldCol
= nHdrCol
+ 1;
831 if ( pPageFields
[nField
].aResult
.getLength() == 1 )
832 aPageValue
= pPageFields
[nField
].aResult
[0].Caption
;
834 aPageValue
= String( ScResId( SCSTR_ALL
) ); //! separate string?
836 pDoc
->SetString( nFldCol
, nHdrRow
, nTab
, aPageValue
);
838 lcl_SetFrame( pDoc
,nTab
, nFldCol
,nHdrRow
, nFldCol
,nHdrRow
, 20 );
839 pDoc
->ApplyAttr( nFldCol
, nHdrRow
, nTab
, ScMergeFlagAttr(SC_MF_AUTO
) );
844 // (may get overwritten by first row field)
846 String aDesc
= aDataDescription
;
849 //! use default string ("result") ?
851 pDoc
->SetString( nTabStartCol
, nTabStartRow
, nTab
, aDesc
);
853 // set STR_PIVOT_STYLE_INNER for whole data area (subtotals are overwritten)
855 if ( nDataStartRow
> nTabStartRow
)
856 lcl_SetStyleById( pDoc
, nTab
, nTabStartCol
, nTabStartRow
, nTabEndCol
, nDataStartRow
-1,
857 STR_PIVOT_STYLE_TOP
);
858 lcl_SetStyleById( pDoc
, nTab
, nDataStartCol
, nDataStartRow
, nTabEndCol
, nTabEndRow
,
859 STR_PIVOT_STYLE_INNER
);
861 // output column headers:
863 for (nField
=0; nField
<nColFieldCount
; nField
++)
865 SCCOL nHdrCol
= nDataStartCol
+ (SCCOL
)nField
; //! check for overflow
866 FieldCell( nHdrCol
, nTabStartRow
, nTab
, pColFields
[nField
].aCaption
, true, true, pColFields
[nField
].mbHasHiddenMember
);
868 SCROW nRowPos
= nMemberStartRow
+ (SCROW
)nField
; //! check for overflow
869 const uno::Sequence
<sheet::MemberResult
> rSequence
= pColFields
[nField
].aResult
;
870 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
871 long nThisColCount
= rSequence
.getLength();
872 DBG_ASSERT( nThisColCount
== nColCount
, "count mismatch" ); //! ???
873 for (long nCol
=0; nCol
<nThisColCount
; nCol
++)
875 SCCOL nColPos
= nDataStartCol
+ (SCCOL
)nCol
; //! check for overflow
876 HeaderCell( nColPos
, nRowPos
, nTab
, pArray
[nCol
], TRUE
, nField
);
877 if ( ( pArray
[nCol
].Flags
& sheet::MemberResultFlags::HASMEMBER
) &&
878 !( pArray
[nCol
].Flags
& sheet::MemberResultFlags::SUBTOTAL
) )
880 if ( nField
+1 < nColFieldCount
)
883 while ( nEnd
+1 < nThisColCount
&& ( pArray
[nEnd
+1].Flags
& sheet::MemberResultFlags::CONTINUE
) )
885 SCCOL nEndColPos
= nDataStartCol
+ (SCCOL
)nEnd
; //! check for overflow
886 lcl_SetFrame( pDoc
,nTab
, nColPos
,nRowPos
, nEndColPos
,nRowPos
, 20 );
887 lcl_SetFrame( pDoc
,nTab
, nColPos
,nRowPos
, nEndColPos
,nTabEndRow
, 20 );
889 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nEndColPos
,nDataStartRow
-1, STR_PIVOT_STYLE_CATEGORY
);
892 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nColPos
,nDataStartRow
-1, STR_PIVOT_STYLE_CATEGORY
);
897 // output row headers:
899 for (nField
=0; nField
<nRowFieldCount
; nField
++)
901 bool bDataLayout
= mbHasDataLayout
&& (nField
== nRowFieldCount
-1);
903 SCCOL nHdrCol
= nTabStartCol
+ (SCCOL
)nField
; //! check for overflow
904 SCROW nHdrRow
= nDataStartRow
- 1;
905 FieldCell( nHdrCol
, nHdrRow
, nTab
, pRowFields
[nField
].aCaption
, true, !bDataLayout
,
906 pRowFields
[nField
].mbHasHiddenMember
);
908 SCCOL nColPos
= nMemberStartCol
+ (SCCOL
)nField
; //! check for overflow
909 const uno::Sequence
<sheet::MemberResult
> rSequence
= pRowFields
[nField
].aResult
;
910 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
911 long nThisRowCount
= rSequence
.getLength();
912 DBG_ASSERT( nThisRowCount
== nRowCount
, "count mismatch" ); //! ???
913 for (long nRow
=0; nRow
<nThisRowCount
; nRow
++)
915 SCROW nRowPos
= nDataStartRow
+ (SCROW
)nRow
; //! check for overflow
916 HeaderCell( nColPos
, nRowPos
, nTab
, pArray
[nRow
], FALSE
, nField
);
917 if ( ( pArray
[nRow
].Flags
& sheet::MemberResultFlags::HASMEMBER
) &&
918 !( pArray
[nRow
].Flags
& sheet::MemberResultFlags::SUBTOTAL
) )
920 if ( nField
+1 < nRowFieldCount
)
923 while ( nEnd
+1 < nThisRowCount
&& ( pArray
[nEnd
+1].Flags
& sheet::MemberResultFlags::CONTINUE
) )
925 SCROW nEndRowPos
= nDataStartRow
+ (SCROW
)nEnd
; //! check for overflow
926 lcl_SetFrame( pDoc
,nTab
, nColPos
,nRowPos
, nColPos
,nEndRowPos
, 20 );
927 lcl_SetFrame( pDoc
,nTab
, nColPos
,nRowPos
, nTabEndCol
,nEndRowPos
, 20 );
929 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nDataStartCol
-1,nEndRowPos
, STR_PIVOT_STYLE_CATEGORY
);
932 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nDataStartCol
-1,nRowPos
, STR_PIVOT_STYLE_CATEGORY
);
937 // output data results:
939 for (long nRow
=0; nRow
<nRowCount
; nRow
++)
941 SCROW nRowPos
= nDataStartRow
+ (SCROW
)nRow
; //! check for overflow
942 const sheet::DataResult
* pColAry
= pRowAry
[nRow
].getConstArray();
943 long nThisColCount
= pRowAry
[nRow
].getLength();
944 DBG_ASSERT( nThisColCount
== nColCount
, "count mismatch" ); //! ???
945 for (long nCol
=0; nCol
<nThisColCount
; nCol
++)
947 SCCOL nColPos
= nDataStartCol
+ (SCCOL
)nCol
; //! check for overflow
948 DataCell( nColPos
, nRowPos
, nTab
, pColAry
[nCol
] );
952 // frame around the whole table
954 lcl_SetFrame( pDoc
,nTab
, nDataStartCol
,nDataStartRow
, nTabEndCol
,nTabEndRow
, 20 );
955 if ( nDataStartCol
> nMemberStartCol
)
956 lcl_SetFrame( pDoc
,nTab
, nMemberStartCol
,nDataStartRow
, nDataStartCol
-1,nTabEndRow
, 20 );
957 if ( nDataStartRow
> nMemberStartRow
)
958 lcl_SetFrame( pDoc
,nTab
, nDataStartCol
,nMemberStartRow
, nTabEndCol
,nDataStartRow
-1, 20 );
960 lcl_SetFrame( pDoc
,nTab
, nTabStartCol
,nTabStartRow
, nTabEndCol
,nTabEndRow
, 40 );
963 ScRange
ScDPOutput::GetOutputRange( sal_Int32 nRegionType
)
965 using namespace ::com::sun::star::sheet
;
969 // fprintf(stdout, "ScDPOutput::GetOutputRange: aStartPos = (%ld, %d)\n", aStartPos.Row(), aStartPos.Col());fflush(stdout);
970 // fprintf(stdout, "ScDPOutput::GetOutputRange: nTabStart (Row = %ld, Col = %ld)\n", nTabStartRow, nTabStartCol);fflush(stdout);
971 // fprintf(stdout, "ScDPOutput::GetOutputRange: nMemberStart (Row = %ld, Col = %ld)\n", nMemberStartRow, nMemberStartCol);fflush(stdout);
972 // fprintf(stdout, "ScDPOutput::GetOutputRange: nDataStart (Row = %ld, Col = %ld)\n", nDataStartRow, nDataStartCol);fflush(stdout);
973 // fprintf(stdout, "ScDPOutput::GetOutputRange: nTabEnd (Row = %ld, Col = %ld)\n", nTabEndRow, nTabStartCol);fflush(stdout);
975 SCTAB nTab
= aStartPos
.Tab();
978 case DataPilotOutputRangeType::RESULT
:
979 return ScRange(nDataStartCol
, nDataStartRow
, nTab
, nTabEndCol
, nTabEndRow
, nTab
);
980 case DataPilotOutputRangeType::TABLE
:
981 return ScRange(aStartPos
.Col(), nTabStartRow
, nTab
, nTabEndCol
, nTabEndRow
, nTab
);
983 DBG_ASSERT(nRegionType
== DataPilotOutputRangeType::WHOLE
, "ScDPOutput::GetOutputRange: unknown region type");
986 return ScRange(aStartPos
.Col(), aStartPos
.Row(), nTab
, nTabEndCol
, nTabEndRow
, nTab
);
989 BOOL
ScDPOutput::HasError()
993 return bSizeOverflow
|| bResultsError
;
996 long ScDPOutput::GetHeaderRows()
998 return nPageFieldCount
+ ( bDoFilter
? 1 : 0 );
1001 void ScDPOutput::GetMemberResultNames( ScStrCollection
& rNames
, long nDimension
)
1003 // Return the list of all member names in a dimension's MemberResults.
1004 // Only the dimension has to be compared because this is only used with table data,
1005 // where each dimension occurs only once.
1007 uno::Sequence
<sheet::MemberResult
> aMemberResults
;
1008 bool bFound
= false;
1011 // look in column fields
1013 for (nField
=0; nField
<nColFieldCount
&& !bFound
; nField
++)
1014 if ( pColFields
[nField
].nDim
== nDimension
)
1016 aMemberResults
= pColFields
[nField
].aResult
;
1020 // look in row fields
1022 for (nField
=0; nField
<nRowFieldCount
&& !bFound
; nField
++)
1023 if ( pRowFields
[nField
].nDim
== nDimension
)
1025 aMemberResults
= pRowFields
[nField
].aResult
;
1029 // collect the member names
1033 const sheet::MemberResult
* pArray
= aMemberResults
.getConstArray();
1034 long nResultCount
= aMemberResults
.getLength();
1036 for (long nItem
=0; nItem
<nResultCount
; nItem
++)
1038 if ( pArray
[nItem
].Flags
& sheet::MemberResultFlags::HASMEMBER
)
1040 StrData
* pNew
= new StrData( pArray
[nItem
].Name
);
1041 if ( !rNames
.Insert( pNew
) )
1048 void ScDPOutput::SetHeaderLayout(bool bUseGrid
)
1050 mbHeaderLayout
= bUseGrid
;
1051 bSizesValid
= false;
1054 bool ScDPOutput::GetHeaderLayout() const
1056 return mbHeaderLayout
;
1059 void ScDPOutput::GetPositionData(const ScAddress
& rPos
, DataPilotTablePositionData
& rPosData
)
1061 using namespace ::com::sun::star::sheet
;
1063 SCCOL nCol
= rPos
.Col();
1064 SCROW nRow
= rPos
.Row();
1065 SCTAB nTab
= rPos
.Tab();
1066 if ( nTab
!= aStartPos
.Tab() )
1067 return; // wrong sheet
1069 // calculate output positions and sizes
1073 rPosData
.PositionType
= GetPositionType(rPos
);
1074 switch (rPosData
.PositionType
)
1076 case DataPilotTablePositionType::RESULT
:
1078 vector
<DataPilotFieldFilter
> aFilters
;
1079 GetDataResultPositionData(aFilters
, rPos
);
1080 sal_Int32 nSize
= aFilters
.size();
1082 DataPilotTableResultData aResData
;
1083 aResData
.FieldFilters
.realloc(nSize
);
1084 for (sal_Int32 i
= 0; i
< nSize
; ++i
)
1085 aResData
.FieldFilters
[i
] = aFilters
[i
];
1087 aResData
.DataFieldIndex
= 0;
1088 Reference
<beans::XPropertySet
> xPropSet(xSource
, UNO_QUERY
);
1091 sal_Int32 nDataFieldCount
= 0;
1092 Any any
= xPropSet
->getPropertyValue(rtl::OUString::createFromAscii("DataFieldCount"));
1093 if ((any
>>= nDataFieldCount
) && nDataFieldCount
> 0)
1094 aResData
.DataFieldIndex
= (nRow
- nDataStartRow
) % nDataFieldCount
;
1097 // Copy appropriate DataResult object from the cached sheet::DataResult table.
1098 if (aData
.getLength() > nRow
- nDataStartRow
&&
1099 aData
[nRow
-nDataStartRow
].getLength() > nCol
-nDataStartCol
)
1100 aResData
.Result
= aData
[nRow
-nDataStartRow
][nCol
-nDataStartCol
];
1102 rPosData
.PositionData
= makeAny(aResData
);
1105 case DataPilotTablePositionType::COLUMN_HEADER
:
1107 long nField
= nRow
- nTabStartRow
- 1; // 1st line is used for the buttons
1111 const uno::Sequence
<sheet::MemberResult
> rSequence
= pColFields
[nField
].aResult
;
1112 if (rSequence
.getLength() == 0)
1114 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1116 long nItem
= nCol
- nDataStartCol
;
1117 // get origin of "continue" fields
1118 while (nItem
> 0 && ( pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1124 DataPilotTableHeaderData aHeaderData
;
1125 aHeaderData
.MemberName
= OUString(pArray
[nItem
].Name
);
1126 aHeaderData
.Flags
= pArray
[nItem
].Flags
;
1127 aHeaderData
.Dimension
= static_cast<sal_Int32
>(pColFields
[nField
].nDim
);
1128 aHeaderData
.Hierarchy
= static_cast<sal_Int32
>(pColFields
[nField
].nHier
);
1129 aHeaderData
.Level
= static_cast<sal_Int32
>(pColFields
[nField
].nLevel
);
1131 rPosData
.PositionData
= makeAny(aHeaderData
);
1134 case DataPilotTablePositionType::ROW_HEADER
:
1136 long nField
= nCol
- nTabStartCol
;
1140 const uno::Sequence
<sheet::MemberResult
> rSequence
= pRowFields
[nField
].aResult
;
1141 if (rSequence
.getLength() == 0)
1143 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1145 long nItem
= nRow
- nDataStartRow
;
1146 // get origin of "continue" fields
1147 while ( nItem
> 0 && (pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1153 DataPilotTableHeaderData aHeaderData
;
1154 aHeaderData
.MemberName
= OUString(pArray
[nItem
].Name
);
1155 aHeaderData
.Flags
= pArray
[nItem
].Flags
;
1156 aHeaderData
.Dimension
= static_cast<sal_Int32
>(pRowFields
[nField
].nDim
);
1157 aHeaderData
.Hierarchy
= static_cast<sal_Int32
>(pRowFields
[nField
].nHier
);
1158 aHeaderData
.Level
= static_cast<sal_Int32
>(pRowFields
[nField
].nLevel
);
1160 rPosData
.PositionData
= makeAny(aHeaderData
);
1166 bool ScDPOutput::GetDataResultPositionData(vector
<sheet::DataPilotFieldFilter
>& rFilters
, const ScAddress
& rPos
)
1168 // Check to make sure there is at least one data field.
1169 Reference
<beans::XPropertySet
> xPropSet(xSource
, UNO_QUERY
);
1173 sal_Int32 nDataFieldCount
= 0;
1174 Any any
= xPropSet
->getPropertyValue(rtl::OUString::createFromAscii("DataFieldCount"));
1175 if (!(any
>>= nDataFieldCount
) || nDataFieldCount
== 0)
1176 // No data field is present in this datapilot table.
1179 bool bColGrand
= bool();
1180 any
= xPropSet
->getPropertyValue(rtl::OUString::createFromAscii(SC_UNO_COLGRAND
));
1181 if (!(any
>>= bColGrand
))
1184 bool bRowGrand
= bool();
1185 any
= xPropSet
->getPropertyValue(rtl::OUString::createFromAscii(SC_UNO_ROWGRAND
));
1186 if (!(any
>>= bRowGrand
))
1189 SCCOL nCol
= rPos
.Col();
1190 SCROW nRow
= rPos
.Row();
1191 SCTAB nTab
= rPos
.Tab();
1192 if ( nTab
!= aStartPos
.Tab() )
1193 return false; // wrong sheet
1197 // test for data area.
1198 if (nCol
< nDataStartCol
|| nCol
> nTabEndCol
|| nRow
< nDataStartRow
|| nRow
> nTabEndRow
)
1200 // Cell is outside the data field area.
1204 bool bFilterByCol
= !(bColGrand
&& (nCol
== nTabEndCol
));
1205 bool bFilterByRow
= !(bRowGrand
&& (nRow
== nTabEndRow
));
1208 for (SCCOL nColField
= 0; nColField
< nColFieldCount
&& bFilterByCol
; ++nColField
)
1210 sheet::DataPilotFieldFilter filter
;
1211 filter
.FieldName
= pColFields
[nColField
].maName
;
1213 const uno::Sequence
<sheet::MemberResult
> rSequence
= pColFields
[nColField
].aResult
;
1214 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1216 DBG_ASSERT(nDataStartCol
+ rSequence
.getLength() - 1 == nTabEndCol
, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1218 long nItem
= nCol
- nDataStartCol
;
1219 // get origin of "continue" fields
1220 while ( nItem
> 0 && (pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1223 filter
.MatchValue
= pArray
[nItem
].Name
;
1224 rFilters
.push_back(filter
);
1228 bool bDataLayoutExists
= (nDataFieldCount
> 1);
1229 for (SCROW nRowField
= 0; nRowField
< nRowFieldCount
&& bFilterByRow
; ++nRowField
)
1231 if (bDataLayoutExists
&& nRowField
== nRowFieldCount
- 1)
1232 // There is no sense including the data layout field for filtering.
1235 sheet::DataPilotFieldFilter filter
;
1236 filter
.FieldName
= pRowFields
[nRowField
].maName
;
1238 const uno::Sequence
<sheet::MemberResult
> rSequence
= pRowFields
[nRowField
].aResult
;
1239 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1241 DBG_ASSERT(nDataStartRow
+ rSequence
.getLength() - 1 == nTabEndRow
, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1243 long nItem
= nRow
- nDataStartRow
;
1244 // get origin of "continue" fields
1245 while ( nItem
> 0 && (pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1248 filter
.MatchValue
= pArray
[nItem
].Name
;
1249 rFilters
.push_back(filter
);
1256 // helper functions for ScDPOutput::GetPivotData
1259 bool lcl_IsNamedDataField( const ScDPGetPivotDataField
& rTarget
, const String
& rSourceName
, const String
& rGivenName
)
1261 // match one of the names, ignoring case
1262 return ScGlobal::GetpTransliteration()->isEqual( rTarget
.maFieldName
, rSourceName
) ||
1263 ScGlobal::GetpTransliteration()->isEqual( rTarget
.maFieldName
, rGivenName
);
1266 bool lcl_IsNamedCategoryField( const ScDPGetPivotDataField
& rFilter
, const ScDPOutLevelData
& rField
)
1268 //! name from source instead of caption?
1269 return ScGlobal::GetpTransliteration()->isEqual( rFilter
.maFieldName
, rField
.maName
);
1272 bool lcl_IsCondition( const sheet::MemberResult
& rResultEntry
, const ScDPGetPivotDataField
& rFilter
)
1274 //! handle numeric conditions?
1275 return ScGlobal::GetpTransliteration()->isEqual( rResultEntry
.Name
, rFilter
.maValStr
);
1278 bool lcl_CheckPageField( const ScDPOutLevelData
& rField
,
1279 const std::vector
< ScDPGetPivotDataField
>& rFilters
,
1280 std::vector
< BOOL
>& rFilterUsed
)
1282 for (SCSIZE nFilterPos
= 0; nFilterPos
< rFilters
.size(); ++nFilterPos
)
1284 if ( lcl_IsNamedCategoryField( rFilters
[nFilterPos
], rField
) )
1286 rFilterUsed
[nFilterPos
] = TRUE
;
1288 // page field result is empty or the selection as single entry (see lcl_GetSelectedPageAsResult)
1289 if ( rField
.aResult
.getLength() == 1 &&
1290 lcl_IsCondition( rField
.aResult
[0], rFilters
[nFilterPos
] ) )
1292 return true; // condition matches page selection
1296 return false; // no page selection or different entry
1301 return true; // valid if the page field doesn't have a filter
1304 uno::Sequence
<sheet::GeneralFunction
> lcl_GetSubTotals(
1305 const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
, const ScDPOutLevelData
& rField
)
1307 uno::Sequence
<sheet::GeneralFunction
> aSubTotals
;
1309 uno::Reference
<sheet::XHierarchiesSupplier
> xHierSupp
;
1310 uno::Reference
<container::XNameAccess
> xDimsName
= xSource
->getDimensions();
1311 uno::Reference
<container::XIndexAccess
> xIntDims
= new ScNameToIndexAccess( xDimsName
);
1312 sal_Int32 nIntCount
= xIntDims
->getCount();
1313 if ( rField
.nDim
< nIntCount
)
1315 uno::Reference
<uno::XInterface
> xIntDim
= ScUnoHelpFunctions::AnyToInterface(
1316 xIntDims
->getByIndex( rField
.nDim
) );
1317 xHierSupp
= uno::Reference
<sheet::XHierarchiesSupplier
>( xIntDim
, uno::UNO_QUERY
);
1319 DBG_ASSERT( xHierSupp
.is(), "dimension not found" );
1321 sal_Int32 nHierCount
= 0;
1322 uno::Reference
<container::XIndexAccess
> xHiers
;
1323 if ( xHierSupp
.is() )
1325 uno::Reference
<container::XNameAccess
> xHiersName
= xHierSupp
->getHierarchies();
1326 xHiers
= new ScNameToIndexAccess( xHiersName
);
1327 nHierCount
= xHiers
->getCount();
1329 uno::Reference
<uno::XInterface
> xHier
;
1330 if ( rField
.nHier
< nHierCount
)
1331 xHier
= ScUnoHelpFunctions::AnyToInterface( xHiers
->getByIndex( rField
.nHier
) );
1332 DBG_ASSERT( xHier
.is(), "hierarchy not found" );
1334 sal_Int32 nLevCount
= 0;
1335 uno::Reference
<container::XIndexAccess
> xLevels
;
1336 uno::Reference
<sheet::XLevelsSupplier
> xLevSupp( xHier
, uno::UNO_QUERY
);
1337 if ( xLevSupp
.is() )
1339 uno::Reference
<container::XNameAccess
> xLevsName
= xLevSupp
->getLevels();
1340 xLevels
= new ScNameToIndexAccess( xLevsName
);
1341 nLevCount
= xLevels
->getCount();
1343 uno::Reference
<uno::XInterface
> xLevel
;
1344 if ( rField
.nLevel
< nLevCount
)
1345 xLevel
= ScUnoHelpFunctions::AnyToInterface( xLevels
->getByIndex( rField
.nLevel
) );
1346 DBG_ASSERT( xLevel
.is(), "level not found" );
1348 uno::Reference
<beans::XPropertySet
> xLevelProp( xLevel
, uno::UNO_QUERY
);
1349 if ( xLevelProp
.is() )
1353 uno::Any aValue
= xLevelProp
->getPropertyValue( rtl::OUString::createFromAscii(DP_PROP_SUBTOTALS
) );
1354 aValue
>>= aSubTotals
;
1356 catch(uno::Exception
&)
1364 void lcl_FilterInclude( std::vector
< BOOL
>& rResult
, std::vector
< sal_Int32
>& rSubtotal
,
1365 const ScDPOutLevelData
& rField
,
1366 const std::vector
< ScDPGetPivotDataField
>& rFilters
,
1367 std::vector
< BOOL
>& rFilterUsed
,
1368 bool& rBeforeDataLayout
,
1369 sal_Int32 nGrandTotals
, sal_Int32 nDataLayoutIndex
,
1370 const std::vector
<String
>& rDataNames
, const std::vector
<String
>& rGivenNames
,
1371 const ScDPGetPivotDataField
& rTarget
, const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
)
1373 // returns true if a filter was given for the field
1375 DBG_ASSERT( rFilters
.size() == rFilterUsed
.size(), "wrong size" );
1377 const bool bIsDataLayout
= ( rField
.nDim
== nDataLayoutIndex
);
1379 rBeforeDataLayout
= false;
1381 bool bHasFilter
= false;
1382 ScDPGetPivotDataField aFilter
;
1383 if ( !bIsDataLayout
) // selection of data field is handled separately
1385 for (SCSIZE nFilterPos
= 0; nFilterPos
< rFilters
.size() && !bHasFilter
; ++nFilterPos
)
1387 if ( lcl_IsNamedCategoryField( rFilters
[nFilterPos
], rField
) )
1389 aFilter
= rFilters
[nFilterPos
];
1390 rFilterUsed
[nFilterPos
] = TRUE
;
1396 bool bHasFunc
= bHasFilter
&& aFilter
.meFunction
!= sheet::GeneralFunction_NONE
;
1398 uno::Sequence
<sheet::GeneralFunction
> aSubTotals
;
1399 if ( !bIsDataLayout
)
1400 aSubTotals
= lcl_GetSubTotals( xSource
, rField
);
1401 bool bManualSub
= ( aSubTotals
.getLength() > 0 && aSubTotals
[0] != sheet::GeneralFunction_AUTO
);
1403 const uno::Sequence
<sheet::MemberResult
>& rSequence
= rField
.aResult
;
1404 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1405 sal_Int32 nSize
= rSequence
.getLength();
1407 DBG_ASSERT( (sal_Int32
)rResult
.size() == nSize
, "Number of fields do not match result count" );
1409 sal_Int32 nContCount
= 0;
1410 sal_Int32 nSubTotalCount
= 0;
1411 sheet::MemberResult aPrevious
;
1412 for( sal_Int32 j
=0; j
< nSize
; j
++ )
1414 sheet::MemberResult aResultEntry
= pArray
[j
];
1415 if ( aResultEntry
.Flags
& sheet::MemberResultFlags::CONTINUE
)
1417 aResultEntry
= aPrevious
;
1420 else if ( ( aResultEntry
.Flags
& sheet::MemberResultFlags::SUBTOTAL
) == 0 )
1422 // count the CONTINUE entries before a SUBTOTAL
1426 if ( j
>= nSize
- nGrandTotals
)
1428 // mark as subtotal for the preceding data
1429 if ( ( aResultEntry
.Flags
& sheet::MemberResultFlags::SUBTOTAL
) != 0 )
1431 rSubtotal
[j
] = nSize
- nGrandTotals
;
1433 if ( rResult
[j
] && nGrandTotals
> 1 )
1435 // grand total is always automatic
1436 sal_Int32 nDataPos
= j
- ( nSize
- nGrandTotals
);
1437 DBG_ASSERT( nDataPos
< (sal_Int32
)rDataNames
.size(), "wrong data count" );
1438 String
aSourceName( rDataNames
[nDataPos
] ); // vector contains source names
1439 String
aGivenName( rGivenNames
[nDataPos
] );
1441 rResult
[j
] = lcl_IsNamedDataField( rTarget
, aSourceName
, aGivenName
);
1445 // treat "grand total" columns/rows as empty description, as if they were marked
1446 // in a previous field
1448 DBG_ASSERT( ( aResultEntry
.Flags
&
1449 ( sheet::MemberResultFlags::HASMEMBER
| sheet::MemberResultFlags::SUBTOTAL
) ) == 0 ||
1450 ( aResultEntry
.Flags
&
1451 ( sheet::MemberResultFlags::HASMEMBER
| sheet::MemberResultFlags::SUBTOTAL
) ) ==
1452 ( sheet::MemberResultFlags::HASMEMBER
| sheet::MemberResultFlags::SUBTOTAL
),
1453 "non-subtotal member found in grand total result" );
1454 aResultEntry
.Flags
= 0;
1457 // mark subtotals (not grand total) for preceding data (assume CONTINUE is set)
1458 if ( ( aResultEntry
.Flags
& sheet::MemberResultFlags::SUBTOTAL
) != 0 )
1460 rSubtotal
[j
] = nContCount
+ 1 + nSubTotalCount
;
1466 if ( rBeforeDataLayout
)
1468 // manual subtotals and several data fields
1470 sal_Int32 nDataCount
= rDataNames
.size();
1471 sal_Int32 nFuncPos
= nSubTotalCount
/ nDataCount
; // outer order: subtotal functions
1472 sal_Int32 nDataPos
= nSubTotalCount
% nDataCount
; // inner order: data fields
1474 String
aSourceName( rDataNames
[nDataPos
] ); // vector contains source names
1475 String
aGivenName( rGivenNames
[nDataPos
] );
1477 DBG_ASSERT( nFuncPos
< aSubTotals
.getLength(), "wrong subtotal count" );
1478 rResult
[j
] = lcl_IsNamedDataField( rTarget
, aSourceName
, aGivenName
) &&
1479 aSubTotals
[nFuncPos
] == aFilter
.meFunction
;
1483 // manual subtotals for a single data field
1485 DBG_ASSERT( nSubTotalCount
< aSubTotals
.getLength(), "wrong subtotal count" );
1486 rResult
[j
] = ( aSubTotals
[nSubTotalCount
] == aFilter
.meFunction
);
1489 else // automatic subtotals
1491 if ( rBeforeDataLayout
)
1493 DBG_ASSERT( nSubTotalCount
< (sal_Int32
)rDataNames
.size(), "wrong data count" );
1494 String
aSourceName( rDataNames
[nSubTotalCount
] ); // vector contains source names
1495 String
aGivenName( rGivenNames
[nSubTotalCount
] );
1497 rResult
[j
] = lcl_IsNamedDataField( rTarget
, aSourceName
, aGivenName
);
1500 // if a function was specified, automatic subtotals never match
1513 if ( bIsDataLayout
)
1515 if ( ( aResultEntry
.Flags
& sheet::MemberResultFlags::HASMEMBER
) != 0 )
1517 // Asterisks are added in ScDPSaveData::WriteToSource to create unique names.
1518 //! preserve original name there?
1519 String
aSourceName( aResultEntry
.Name
);
1520 aSourceName
.EraseTrailingChars( '*' );
1522 String
aGivenName( aResultEntry
.Caption
); //! Should use a stored name when available
1523 aGivenName
.EraseLeadingChars( '\'' );
1525 rResult
[j
] = lcl_IsNamedDataField( rTarget
, aSourceName
, aGivenName
);
1528 else if ( bHasFilter
)
1530 // name must match (simple value or subtotal)
1531 rResult
[j
] = ( ( aResultEntry
.Flags
& sheet::MemberResultFlags::HASMEMBER
) != 0 ) &&
1532 lcl_IsCondition( aResultEntry
, aFilter
);
1534 // if a function was specified, simple (non-subtotal) values never match
1535 if ( bHasFunc
&& nSubTotalCount
== 0 )
1538 // if no condition is given, keep the columns/rows included
1540 aPrevious
= aResultEntry
;
1544 void lcl_StripSubTotals( std::vector
< BOOL
>& rResult
, const std::vector
< sal_Int32
>& rSubtotal
)
1546 sal_Int32 nSize
= rResult
.size();
1547 DBG_ASSERT( (sal_Int32
)rSubtotal
.size() == nSize
, "sizes don't match" );
1549 for (sal_Int32 nPos
=0; nPos
<nSize
; nPos
++)
1550 if ( rResult
[nPos
] && rSubtotal
[nPos
] )
1552 // if a subtotal is included, clear the result flag for the columns/rows that the subtotal includes
1553 sal_Int32 nStart
= nPos
- rSubtotal
[nPos
];
1554 DBG_ASSERT( nStart
>= 0, "invalid subtotal count" );
1556 for (sal_Int32 nPrev
= nStart
; nPrev
< nPos
; nPrev
++)
1557 rResult
[nPrev
] = FALSE
;
1561 String
lcl_GetDataFieldName( const String
& rSourceName
, sheet::GeneralFunction eFunc
)
1566 case sheet::GeneralFunction_SUM
: nStrId
= STR_FUN_TEXT_SUM
; break;
1567 case sheet::GeneralFunction_COUNT
:
1568 case sheet::GeneralFunction_COUNTNUMS
: nStrId
= STR_FUN_TEXT_COUNT
; break;
1569 case sheet::GeneralFunction_AVERAGE
: nStrId
= STR_FUN_TEXT_AVG
; break;
1570 case sheet::GeneralFunction_MAX
: nStrId
= STR_FUN_TEXT_MAX
; break;
1571 case sheet::GeneralFunction_MIN
: nStrId
= STR_FUN_TEXT_MIN
; break;
1572 case sheet::GeneralFunction_PRODUCT
: nStrId
= STR_FUN_TEXT_PRODUCT
; break;
1573 case sheet::GeneralFunction_STDEV
:
1574 case sheet::GeneralFunction_STDEVP
: nStrId
= STR_FUN_TEXT_STDDEV
; break;
1575 case sheet::GeneralFunction_VAR
:
1576 case sheet::GeneralFunction_VARP
: nStrId
= STR_FUN_TEXT_VAR
; break;
1577 case sheet::GeneralFunction_NONE
:
1578 case sheet::GeneralFunction_AUTO
:
1581 DBG_ERRORFILE("wrong function");
1587 String
aRet( ScGlobal::GetRscString( nStrId
) );
1588 aRet
.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " - " ));
1589 aRet
.Append( rSourceName
);
1594 void ScDPOutput::GetDataDimensionNames( String
& rSourceName
, String
& rGivenName
,
1595 const uno::Reference
<uno::XInterface
>& xDim
)
1597 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
1598 uno::Reference
<container::XNamed
> xDimName( xDim
, uno::UNO_QUERY
);
1599 if ( xDimProp
.is() && xDimName
.is() )
1601 // Asterisks are added in ScDPSaveData::WriteToSource to create unique names.
1602 //! preserve original name there?
1603 rSourceName
= xDimName
->getName();
1604 rSourceName
.EraseTrailingChars( '*' );
1606 // Generate "given name" the same way as in dptabres.
1607 //! Should use a stored name when available
1609 sheet::GeneralFunction eFunc
= (sheet::GeneralFunction
)ScUnoHelpFunctions::GetEnumProperty(
1610 xDimProp
, rtl::OUString::createFromAscii(DP_PROP_FUNCTION
),
1611 sheet::GeneralFunction_NONE
);
1612 rGivenName
= lcl_GetDataFieldName( rSourceName
, eFunc
);
1616 void lcl_GetTableVars( sal_Int32
& rGrandTotalCols
, sal_Int32
& rGrandTotalRows
, sal_Int32
& rDataLayoutIndex
,
1617 std::vector
<String
>& rDataNames
, std::vector
<String
>& rGivenNames
,
1618 sheet::DataPilotFieldOrientation
& rDataOrient
,
1619 const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
)
1621 rDataLayoutIndex
= -1; // invalid
1622 rGrandTotalCols
= 0;
1623 rGrandTotalRows
= 0;
1624 rDataOrient
= sheet::DataPilotFieldOrientation_HIDDEN
;
1626 uno::Reference
<beans::XPropertySet
> xSrcProp( xSource
, uno::UNO_QUERY
);
1627 BOOL bColGrand
= ScUnoHelpFunctions::GetBoolProperty( xSrcProp
,
1628 rtl::OUString::createFromAscii(DP_PROP_COLUMNGRAND
) );
1630 rGrandTotalCols
= 1; // default if data layout not in columns
1632 BOOL bRowGrand
= ScUnoHelpFunctions::GetBoolProperty( xSrcProp
,
1633 rtl::OUString::createFromAscii(DP_PROP_ROWGRAND
) );
1635 rGrandTotalRows
= 1; // default if data layout not in rows
1639 // find index and orientation of "data layout" dimension, count data dimensions
1641 sal_Int32 nDataCount
= 0;
1643 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xSource
->getDimensions() );
1644 long nDimCount
= xDims
->getCount();
1645 for (long nDim
=0; nDim
<nDimCount
; nDim
++)
1647 uno::Reference
<uno::XInterface
> xDim
=
1648 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
1649 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
1650 if ( xDimProp
.is() )
1652 sheet::DataPilotFieldOrientation eDimOrient
=
1653 (sheet::DataPilotFieldOrientation
) ScUnoHelpFunctions::GetEnumProperty(
1654 xDimProp
, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION
),
1655 sheet::DataPilotFieldOrientation_HIDDEN
);
1656 if ( ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
1657 rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT
) ) )
1659 rDataLayoutIndex
= nDim
;
1660 rDataOrient
= eDimOrient
;
1662 if ( eDimOrient
== sheet::DataPilotFieldOrientation_DATA
)
1666 ScDPOutput::GetDataDimensionNames( aSourceName
, aGivenName
, xDim
);
1667 rDataNames
.push_back( aSourceName
);
1668 rGivenNames
.push_back( aGivenName
);
1675 if ( ( rDataOrient
== sheet::DataPilotFieldOrientation_COLUMN
) && bColGrand
)
1676 rGrandTotalCols
= nDataCount
;
1677 else if ( ( rDataOrient
== sheet::DataPilotFieldOrientation_ROW
) && bRowGrand
)
1678 rGrandTotalRows
= nDataCount
;
1682 // Returns TRUE on success and stores the result in rTarget
1683 // Returns FALSE if rFilters or rTarget describes something that is not visible
1684 BOOL
ScDPOutput::GetPivotData( ScDPGetPivotDataField
& rTarget
,
1685 const std::vector
< ScDPGetPivotDataField
>& rFilters
)
1689 // need to know about grand total columns/rows:
1690 sal_Int32 nGrandTotalCols
;
1691 sal_Int32 nGrandTotalRows
;
1692 sal_Int32 nDataLayoutIndex
;
1693 std::vector
<String
> aDataNames
;
1694 std::vector
<String
> aGivenNames
;
1695 sheet::DataPilotFieldOrientation eDataOrient
;
1696 lcl_GetTableVars( nGrandTotalCols
, nGrandTotalRows
, nDataLayoutIndex
, aDataNames
, aGivenNames
, eDataOrient
, xSource
);
1698 if ( aDataNames
.empty() )
1699 return FALSE
; // incomplete table without data fields -> no result
1701 if ( eDataOrient
== sheet::DataPilotFieldOrientation_HIDDEN
)
1703 // no data layout field -> single data field -> must match the selected field in rTarget
1705 DBG_ASSERT( aDataNames
.size() == 1, "several data fields but no data layout field" );
1706 if ( !lcl_IsNamedDataField( rTarget
, aDataNames
[0], aGivenNames
[0] ) )
1710 std::vector
< BOOL
> aIncludeCol( nColCount
, TRUE
);
1711 std::vector
< sal_Int32
> aSubtotalCol( nColCount
, 0 );
1712 std::vector
< BOOL
> aIncludeRow( nRowCount
, TRUE
);
1713 std::vector
< sal_Int32
> aSubtotalRow( nRowCount
, 0 );
1715 std::vector
< BOOL
> aFilterUsed( rFilters
.size(), FALSE
);
1720 bool bBeforeDataLayout
;
1722 // look in column fields
1724 bBeforeDataLayout
= ( eDataOrient
== sheet::DataPilotFieldOrientation_COLUMN
);
1725 for (nField
=0; nField
<nColFieldCount
; nField
++)
1726 lcl_FilterInclude( aIncludeCol
, aSubtotalCol
, pColFields
[nField
], rFilters
, aFilterUsed
, bBeforeDataLayout
,
1727 nGrandTotalCols
, nDataLayoutIndex
, aDataNames
, aGivenNames
, rTarget
, xSource
);
1729 // look in row fields
1731 bBeforeDataLayout
= ( eDataOrient
== sheet::DataPilotFieldOrientation_ROW
);
1732 for (nField
=0; nField
<nRowFieldCount
; nField
++)
1733 lcl_FilterInclude( aIncludeRow
, aSubtotalRow
, pRowFields
[nField
], rFilters
, aFilterUsed
, bBeforeDataLayout
,
1734 nGrandTotalRows
, nDataLayoutIndex
, aDataNames
, aGivenNames
, rTarget
, xSource
);
1738 for (nField
=0; nField
<nPageFieldCount
; nField
++)
1739 if ( !lcl_CheckPageField( pPageFields
[nField
], rFilters
, aFilterUsed
) )
1742 // all filter fields must be used
1743 for (SCSIZE nFilter
=0; nFilter
<aFilterUsed
.size(); nFilter
++)
1744 if (!aFilterUsed
[nFilter
])
1747 lcl_StripSubTotals( aIncludeCol
, aSubtotalCol
);
1748 lcl_StripSubTotals( aIncludeRow
, aSubtotalRow
);
1751 long nColIncluded
= 0;
1752 for (nCol
=0; nCol
<nColCount
; nCol
++)
1753 if (aIncludeCol
[nCol
])
1760 long nRowIncluded
= 0;
1761 for (nRow
=0; nRow
<nRowCount
; nRow
++)
1762 if (aIncludeRow
[nRow
])
1768 if ( nColIncluded
!= 1 || nRowIncluded
!= 1 )
1771 const uno::Sequence
<sheet::DataResult
>& rDataRow
= aData
[nRowPos
];
1772 if ( nColPos
>= rDataRow
.getLength() )
1775 const sheet::DataResult
& rResult
= rDataRow
[nColPos
];
1776 if ( rResult
.Flags
& sheet::DataResultFlags::ERROR
)
1777 return FALSE
; //! different error?
1779 rTarget
.mbValIsStr
= FALSE
;
1780 rTarget
.mnValNum
= rResult
.Value
;
1785 BOOL
ScDPOutput::IsFilterButton( const ScAddress
& rPos
)
1787 SCCOL nCol
= rPos
.Col();
1788 SCROW nRow
= rPos
.Row();
1789 SCTAB nTab
= rPos
.Tab();
1790 if ( nTab
!= aStartPos
.Tab() || !bDoFilter
)
1791 return FALSE
; // wrong sheet or no button at all
1793 // filter button is at top left
1794 return ( nCol
== aStartPos
.Col() && nRow
== aStartPos
.Row() );
1797 long ScDPOutput::GetHeaderDim( const ScAddress
& rPos
, USHORT
& rOrient
)
1799 SCCOL nCol
= rPos
.Col();
1800 SCROW nRow
= rPos
.Row();
1801 SCTAB nTab
= rPos
.Tab();
1802 if ( nTab
!= aStartPos
.Tab() )
1803 return -1; // wrong sheet
1805 // calculate output positions and sizes
1809 // test for column header
1811 if ( nRow
== nTabStartRow
&& nCol
>= nDataStartCol
&& nCol
< nDataStartCol
+ nColFieldCount
)
1813 rOrient
= sheet::DataPilotFieldOrientation_COLUMN
;
1814 long nField
= nCol
- nDataStartCol
;
1815 return pColFields
[nField
].nDim
;
1818 // test for row header
1820 if ( nRow
+1 == nDataStartRow
&& nCol
>= nTabStartCol
&& nCol
< nTabStartCol
+ nRowFieldCount
)
1822 rOrient
= sheet::DataPilotFieldOrientation_ROW
;
1823 long nField
= nCol
- nTabStartCol
;
1824 return pRowFields
[nField
].nDim
;
1827 // test for page field
1829 SCROW nPageStartRow
= aStartPos
.Row() + ( bDoFilter
? 1 : 0 );
1830 if ( nCol
== aStartPos
.Col() && nRow
>= nPageStartRow
&& nRow
< nPageStartRow
+ nPageFieldCount
)
1832 rOrient
= sheet::DataPilotFieldOrientation_PAGE
;
1833 long nField
= nRow
- nPageStartRow
;
1834 return pPageFields
[nField
].nDim
;
1837 //! single data field (?)
1839 rOrient
= sheet::DataPilotFieldOrientation_HIDDEN
;
1840 return -1; // invalid
1843 BOOL
ScDPOutput::GetHeaderDrag( const ScAddress
& rPos
, BOOL bMouseLeft
, BOOL bMouseTop
,
1845 Rectangle
& rPosRect
, USHORT
& rOrient
, long& rDimPos
)
1847 // Rectangle instead of ScRange for rPosRect to allow for negative values
1849 SCCOL nCol
= rPos
.Col();
1850 SCROW nRow
= rPos
.Row();
1851 SCTAB nTab
= rPos
.Tab();
1852 if ( nTab
!= aStartPos
.Tab() )
1853 return FALSE
; // wrong sheet
1855 // calculate output positions and sizes
1859 // test for column header
1861 if ( nCol
>= nDataStartCol
&& nCol
<= nTabEndCol
&&
1862 nRow
+ 1 >= nMemberStartRow
&& nRow
< nMemberStartRow
+ nColFieldCount
)
1864 long nField
= nRow
- nMemberStartRow
;
1870 //! find start of dimension
1872 rPosRect
= Rectangle( nDataStartCol
, nMemberStartRow
+ nField
,
1873 nTabEndCol
, nMemberStartRow
+ nField
-1 );
1875 BOOL bFound
= FALSE
; // is this within the same orientation?
1876 BOOL bBeforeDrag
= FALSE
;
1877 BOOL bAfterDrag
= FALSE
;
1878 for (long nPos
=0; nPos
<nColFieldCount
&& !bFound
; nPos
++)
1880 if (pColFields
[nPos
].nDim
== nDragDim
)
1883 if ( nField
< nPos
)
1885 else if ( nField
> nPos
)
1894 ++rPosRect
.Bottom();
1904 ++rPosRect
.Bottom();
1909 rOrient
= sheet::DataPilotFieldOrientation_COLUMN
;
1910 rDimPos
= nField
; //!...
1914 // test for row header
1916 // special case if no row fields
1917 BOOL bSpecial
= ( nRow
+1 >= nDataStartRow
&& nRow
<= nTabEndRow
&&
1918 nRowFieldCount
== 0 && nCol
== nTabStartCol
&& bMouseLeft
);
1920 if ( bSpecial
|| ( nRow
+1 >= nDataStartRow
&& nRow
<= nTabEndRow
&&
1921 nCol
+ 1 >= nTabStartCol
&& nCol
< nTabStartCol
+ nRowFieldCount
) )
1923 long nField
= nCol
- nTabStartCol
;
1924 //! find start of dimension
1926 rPosRect
= Rectangle( nTabStartCol
+ nField
, nDataStartRow
- 1,
1927 nTabStartCol
+ nField
- 1, nTabEndRow
);
1929 BOOL bFound
= FALSE
; // is this within the same orientation?
1930 BOOL bBeforeDrag
= FALSE
;
1931 BOOL bAfterDrag
= FALSE
;
1932 for (long nPos
=0; nPos
<nRowFieldCount
&& !bFound
; nPos
++)
1934 if (pRowFields
[nPos
].nDim
== nDragDim
)
1937 if ( nField
< nPos
)
1939 else if ( nField
> nPos
)
1963 rOrient
= sheet::DataPilotFieldOrientation_ROW
;
1964 rDimPos
= nField
; //!...
1968 // test for page fields
1970 SCROW nPageStartRow
= aStartPos
.Row() + ( bDoFilter
? 1 : 0 );
1971 if ( nCol
>= aStartPos
.Col() && nCol
<= nTabEndCol
&&
1972 nRow
+ 1 >= nPageStartRow
&& nRow
< nPageStartRow
+ nPageFieldCount
)
1974 long nField
= nRow
- nPageStartRow
;
1980 //! find start of dimension
1982 rPosRect
= Rectangle( aStartPos
.Col(), nPageStartRow
+ nField
,
1983 nTabEndCol
, nPageStartRow
+ nField
- 1 );
1985 BOOL bFound
= FALSE
; // is this within the same orientation?
1986 BOOL bBeforeDrag
= FALSE
;
1987 BOOL bAfterDrag
= FALSE
;
1988 for (long nPos
=0; nPos
<nPageFieldCount
&& !bFound
; nPos
++)
1990 if (pPageFields
[nPos
].nDim
== nDragDim
)
1993 if ( nField
< nPos
)
1995 else if ( nField
> nPos
)
2004 ++rPosRect
.Bottom();
2014 ++rPosRect
.Bottom();
2019 rOrient
= sheet::DataPilotFieldOrientation_PAGE
;
2020 rDimPos
= nField
; //!...