1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "scitems.hxx"
21 #include <svx/algitem.hxx>
22 #include <editeng/boxitem.hxx>
23 #include <editeng/brushitem.hxx>
24 #include <editeng/wghtitem.hxx>
25 #include <editeng/justifyitem.hxx>
26 #include <unotools/transliterationwrapper.hxx>
28 #include "dpoutput.hxx"
29 #include "dptabsrc.hxx"
30 #include "dpfilteredcache.hxx"
31 #include "document.hxx"
32 #include "patattr.hxx"
33 #include "docpool.hxx"
34 #include "markdata.hxx"
36 #include "formula/errorcodes.hxx"
37 #include "miscuno.hxx"
38 #include "globstr.hrc"
39 #include "stlpool.hxx"
40 #include "stlsheet.hxx"
41 #include "scresid.hxx"
42 #include "unonames.hxx"
44 #include "stringutil.hxx"
47 #include <com/sun/star/beans/XPropertySet.hpp>
48 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
49 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
50 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
51 #include <com/sun/star/sheet/DataPilotTableResultData.hpp>
52 #include <com/sun/star/sheet/MemberResultFlags.hpp>
53 #include <com/sun/star/sheet/TableFilterField.hpp>
54 #include <com/sun/star/sheet/DataResultFlags.hpp>
55 #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
59 using namespace com::sun::star
;
61 using ::com::sun::star::beans::XPropertySet
;
62 using ::com::sun::star::uno::Sequence
;
63 using ::com::sun::star::uno::UNO_QUERY
;
64 using ::com::sun::star::uno::Reference
;
65 using ::com::sun::star::sheet::DataPilotTablePositionData
;
66 using ::com::sun::star::sheet::DataPilotTableResultData
;
67 using ::com::sun::star::uno::makeAny
;
68 using ::com::sun::star::uno::Any
;
70 #define SC_DP_FRAME_INNER_BOLD 20
71 #define SC_DP_FRAME_OUTER_BOLD 40
73 #define SC_DP_FRAME_COLOR Color(0,0,0) //( 0x20, 0x40, 0x68 )
75 #define SC_DPOUT_MAXLEVELS 256
77 struct ScDPOutLevelData
83 sal_uInt32 mnSrcNumFmt
; /// Prevailing number format used in the source data.
84 uno::Sequence
<sheet::MemberResult
> aResult
;
85 OUString maName
; /// Name is the internal field name.
86 OUString maCaption
; /// Caption is the name visible in the output table.
87 bool mbHasHiddenMember
:1;
92 nDim(-1), nHier(-1), nLevel(-1), nDimPos(-1), mnSrcNumFmt(0), mbHasHiddenMember(false), mbDataLayout(false), mbPageDim(false)
95 bool operator<(const ScDPOutLevelData
& r
) const
96 { return nDimPos
<r
.nDimPos
|| ( nDimPos
==r
.nDimPos
&& nHier
<r
.nHier
) ||
97 ( nDimPos
==r
.nDimPos
&& nHier
==r
.nHier
&& nLevel
<r
.nLevel
); }
99 void Swap(ScDPOutLevelData
& r
)
100 { ScDPOutLevelData aTemp
; aTemp
= r
; r
= *this; *this = aTemp
; }
102 //! bug (73840) in uno::Sequence - copy and then assign doesn't work!
107 bool lcl_compareColfuc ( SCCOL i
, SCCOL j
) { return (i
<j
); }
108 bool lcl_compareRowfuc ( SCROW i
, SCROW j
) { return (i
<j
); }
114 ::std::vector
< bool > mbNeedLineCols
;
115 ::std::vector
< SCCOL
> mnCols
;
117 ::std::vector
< bool > mbNeedLineRows
;
118 ::std::vector
< SCROW
> mnRows
;
123 SCCOL mnDataStartCol
;
124 SCROW mnDataStartRow
;
129 ScDPOutputImpl( ScDocument
* pDoc
, sal_uInt16 nTab
,
136 bool AddRow( SCROW nRow
);
137 bool AddCol( SCCOL nCol
);
139 void OutputDataArea();
140 void OutputBlockFrame ( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
, bool bHori
= false );
144 void ScDPOutputImpl::OutputDataArea()
146 AddRow( mnDataStartRow
);
147 AddCol( mnDataStartCol
);
149 mnCols
.push_back( mnTabEndCol
+1); //set last row bottom
150 mnRows
.push_back( mnTabEndRow
+1); //set last col bottom
152 bool bAllRows
= ( ( mnTabEndRow
- mnDataStartRow
+ 2 ) == (SCROW
) mnRows
.size() );
154 std::sort( mnCols
.begin(), mnCols
.end(), lcl_compareColfuc
);
155 std::sort( mnRows
.begin(), mnRows
.end(), lcl_compareRowfuc
);
157 for( SCCOL nCol
= 0; nCol
< (SCCOL
)mnCols
.size()-1; nCol
++ )
161 if ( nCol
< (SCCOL
)mnCols
.size()-2)
163 for ( SCROW i
= nCol
%2; i
< (SCROW
)mnRows
.size()-2; i
+=2 )
164 OutputBlockFrame( mnCols
[nCol
], mnRows
[i
], mnCols
[nCol
+1]-1, mnRows
[i
+1]-1 );
165 if ( mnRows
.size()>=2 )
166 OutputBlockFrame( mnCols
[nCol
], mnRows
[mnRows
.size()-2], mnCols
[nCol
+1]-1, mnRows
[mnRows
.size()-1]-1 );
170 for ( SCROW i
= 0 ; i
< (SCROW
)mnRows
.size()-1; i
++ )
171 OutputBlockFrame( mnCols
[nCol
], mnRows
[i
], mnCols
[nCol
+1]-1, mnRows
[i
+1]-1 );
175 OutputBlockFrame( mnCols
[nCol
], mnRows
.front(), mnCols
[nCol
+1]-1, mnRows
.back()-1, bAllRows
);
177 //out put rows area outer framer
178 if ( mnTabStartCol
!= mnDataStartCol
)
180 if ( mnTabStartRow
!= mnDataStartRow
)
181 OutputBlockFrame( mnTabStartCol
, mnTabStartRow
, mnDataStartCol
-1, mnDataStartRow
-1 );
182 OutputBlockFrame( mnTabStartCol
, mnDataStartRow
, mnDataStartCol
-1, mnTabEndRow
);
184 //out put cols area outer framer
185 OutputBlockFrame( mnDataStartCol
, mnTabStartRow
, mnTabEndCol
, mnDataStartRow
-1 );
188 ScDPOutputImpl::ScDPOutputImpl( ScDocument
* pDoc
, sal_uInt16 nTab
,
197 mnTabStartCol( nTabStartCol
),
198 mnTabStartRow( nTabStartRow
),
199 mnDataStartCol ( nDataStartCol
),
200 mnDataStartRow ( nDataStartRow
),
201 mnTabEndCol( nTabEndCol
),
202 mnTabEndRow( nTabEndRow
)
204 mbNeedLineCols
.resize( nTabEndCol
-nDataStartCol
+1, false );
205 mbNeedLineRows
.resize( nTabEndRow
-nDataStartRow
+1, false );
209 bool ScDPOutputImpl::AddRow( SCROW nRow
)
211 if ( !mbNeedLineRows
[ nRow
- mnDataStartRow
] )
213 mbNeedLineRows
[ nRow
- mnDataStartRow
] = true;
214 mnRows
.push_back( nRow
);
221 bool ScDPOutputImpl::AddCol( SCCOL nCol
)
224 if ( !mbNeedLineCols
[ nCol
- mnDataStartCol
] )
226 mbNeedLineCols
[ nCol
- mnDataStartCol
] = true;
227 mnCols
.push_back( nCol
);
234 void ScDPOutputImpl::OutputBlockFrame ( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
, bool bHori
)
236 Color color
= SC_DP_FRAME_COLOR
;
237 ::editeng::SvxBorderLine
aLine( &color
, SC_DP_FRAME_INNER_BOLD
);
238 ::editeng::SvxBorderLine
aOutLine( &color
, SC_DP_FRAME_OUTER_BOLD
);
240 SvxBoxItem
aBox( ATTR_BORDER
);
242 if ( nStartCol
== mnTabStartCol
)
243 aBox
.SetLine(&aOutLine
, BOX_LINE_LEFT
);
245 aBox
.SetLine(&aLine
, BOX_LINE_LEFT
);
247 if ( nStartRow
== mnTabStartRow
)
248 aBox
.SetLine(&aOutLine
, BOX_LINE_TOP
);
250 aBox
.SetLine(&aLine
, BOX_LINE_TOP
);
252 if ( nEndCol
== mnTabEndCol
) //bottom row
253 aBox
.SetLine(&aOutLine
, BOX_LINE_RIGHT
);
255 aBox
.SetLine(&aLine
, BOX_LINE_RIGHT
);
257 if ( nEndRow
== mnTabEndRow
) //bottom
258 aBox
.SetLine(&aOutLine
, BOX_LINE_BOTTOM
);
260 aBox
.SetLine(&aLine
, BOX_LINE_BOTTOM
);
263 SvxBoxInfoItem
aBoxInfo( ATTR_BORDER_INNER
);
264 aBoxInfo
.SetValid(VALID_VERT
,false );
267 aBoxInfo
.SetValid(VALID_HORI
,true);
268 aBoxInfo
.SetLine( &aLine
, BOXINFO_LINE_HORI
);
271 aBoxInfo
.SetValid(VALID_HORI
,false );
273 aBoxInfo
.SetValid(VALID_DISTANCE
,false);
275 mpDoc
->ApplyFrameAreaTab( ScRange( nStartCol
, nStartRow
, mnTab
, nEndCol
, nEndRow
, mnTab
), &aBox
, &aBoxInfo
);
279 void lcl_SetStyleById( ScDocument
* pDoc
, SCTAB nTab
,
280 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
283 if ( nCol1
> nCol2
|| nRow1
> nRow2
)
285 OSL_FAIL("SetStyleById: invalid range");
289 OUString aStyleName
= ScGlobal::GetRscString( nStrId
);
290 ScStyleSheetPool
* pStlPool
= pDoc
->GetStyleSheetPool();
291 ScStyleSheet
* pStyle
= (ScStyleSheet
*) pStlPool
->Find( aStyleName
, SFX_STYLE_FAMILY_PARA
);
294 // create new style (was in ScPivot::SetStyle)
296 pStyle
= (ScStyleSheet
*) &pStlPool
->Make( aStyleName
, SFX_STYLE_FAMILY_PARA
,
297 SFXSTYLEBIT_USERDEF
);
298 pStyle
->SetParent( ScGlobal::GetRscString(STR_STYLENAME_STANDARD
) );
299 SfxItemSet
& rSet
= pStyle
->GetItemSet();
300 if ( nStrId
==STR_PIVOT_STYLE_RESULT
|| nStrId
==STR_PIVOT_STYLE_TITLE
)
301 rSet
.Put( SvxWeightItem( WEIGHT_BOLD
, ATTR_FONT_WEIGHT
) );
302 if ( nStrId
==STR_PIVOT_STYLE_CATEGORY
|| nStrId
==STR_PIVOT_STYLE_TITLE
)
303 rSet
.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT
, ATTR_HOR_JUSTIFY
) );
306 pDoc
->ApplyStyleAreaTab( nCol1
, nRow1
, nCol2
, nRow2
, nTab
, *pStyle
);
309 void lcl_SetFrame( ScDocument
* pDoc
, SCTAB nTab
,
310 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
313 ::editeng::SvxBorderLine
aLine(0, nWidth
, table::BorderLineStyle::SOLID
);
314 SvxBoxItem
aBox( ATTR_BORDER
);
315 aBox
.SetLine(&aLine
, BOX_LINE_LEFT
);
316 aBox
.SetLine(&aLine
, BOX_LINE_TOP
);
317 aBox
.SetLine(&aLine
, BOX_LINE_RIGHT
);
318 aBox
.SetLine(&aLine
, BOX_LINE_BOTTOM
);
319 SvxBoxInfoItem
aBoxInfo( ATTR_BORDER_INNER
);
320 aBoxInfo
.SetValid(VALID_HORI
,false);
321 aBoxInfo
.SetValid(VALID_VERT
,false);
322 aBoxInfo
.SetValid(VALID_DISTANCE
,false);
324 pDoc
->ApplyFrameAreaTab( ScRange( nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
), &aBox
, &aBoxInfo
);
327 // -----------------------------------------------------------------------
329 void lcl_FillNumberFormats( sal_uInt32
*& rFormats
, long& rCount
,
330 const uno::Reference
<sheet::XDataPilotMemberResults
>& xLevRes
,
331 const uno::Reference
<container::XIndexAccess
>& xDims
)
334 return; // already set
336 // xLevRes is from the data layout dimension
337 //! use result sequence from ScDPOutLevelData!
339 uno::Sequence
<sheet::MemberResult
> aResult
= xLevRes
->getResults();
341 long nSize
= aResult
.getLength();
345 // get names/formats for all data dimensions
346 //! merge this with the loop to collect ScDPOutLevelData?
348 OUString aDataNames
[SC_DPOUT_MAXLEVELS
];
349 sal_uInt32 nDataFormats
[SC_DPOUT_MAXLEVELS
];
351 long nDimCount
= xDims
->getCount();
352 for (long nDim
=0; nDim
<nDimCount
; nDim
++)
354 uno::Reference
<uno::XInterface
> xDim
=
355 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
356 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
357 uno::Reference
<container::XNamed
> xDimName( xDim
, uno::UNO_QUERY
);
358 if ( xDimProp
.is() && xDimName
.is() )
360 sheet::DataPilotFieldOrientation eDimOrient
=
361 (sheet::DataPilotFieldOrientation
) ScUnoHelpFunctions::GetEnumProperty(
362 xDimProp
, OUString(SC_UNO_DP_ORIENTATION
),
363 sheet::DataPilotFieldOrientation_HIDDEN
);
364 if ( eDimOrient
== sheet::DataPilotFieldOrientation_DATA
)
366 aDataNames
[nDataCount
] = xDimName
->getName();
367 long nFormat
= ScUnoHelpFunctions::GetLongProperty(
369 OUString(SC_UNONAME_NUMFMT
) );
370 nDataFormats
[nDataCount
] = nFormat
;
379 const sheet::MemberResult
* pArray
= aResult
.getConstArray();
382 sal_uInt32
* pNumFmt
= new sal_uInt32
[nSize
];
385 // only one data dimension -> use its numberformat everywhere
386 long nFormat
= nDataFormats
[0];
387 for (long nPos
=0; nPos
<nSize
; nPos
++)
388 pNumFmt
[nPos
] = nFormat
;
392 for (long nPos
=0; nPos
<nSize
; nPos
++)
394 // if CONTINUE bit is set, keep previous name
395 //! keep number format instead!
396 if ( !(pArray
[nPos
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
397 aName
= pArray
[nPos
].Name
;
399 sal_uInt32 nFormat
= 0;
400 for (long i
=0; i
<nDataCount
; i
++)
401 if (aName
== aDataNames
[i
]) //! search more efficiently?
403 nFormat
= nDataFormats
[i
];
406 pNumFmt
[nPos
] = nFormat
;
414 sal_uInt32
lcl_GetFirstNumberFormat( const uno::Reference
<container::XIndexAccess
>& xDims
)
416 long nDimCount
= xDims
->getCount();
417 for (long nDim
=0; nDim
<nDimCount
; nDim
++)
419 uno::Reference
<uno::XInterface
> xDim
=
420 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
421 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
424 sheet::DataPilotFieldOrientation eDimOrient
=
425 (sheet::DataPilotFieldOrientation
) ScUnoHelpFunctions::GetEnumProperty(
426 xDimProp
, OUString(SC_UNO_DP_ORIENTATION
),
427 sheet::DataPilotFieldOrientation_HIDDEN
);
428 if ( eDimOrient
== sheet::DataPilotFieldOrientation_DATA
)
430 long nFormat
= ScUnoHelpFunctions::GetLongProperty(
432 OUString(SC_UNONAME_NUMFMT
) );
434 return nFormat
; // use format from first found data dimension
439 return 0; // none found
442 void lcl_SortFields( ScDPOutLevelData
* pFields
, long nFieldCount
)
444 for (long i
=0; i
+1<nFieldCount
; i
++)
446 for (long j
=0; j
+i
+1<nFieldCount
; j
++)
447 if ( pFields
[j
+1] < pFields
[j
] )
448 pFields
[j
].Swap( pFields
[j
+1] );
452 bool lcl_MemberEmpty( const uno::Sequence
<sheet::MemberResult
>& rSeq
)
454 // used to skip levels that have no members
456 long nLen
= rSeq
.getLength();
457 const sheet::MemberResult
* pArray
= rSeq
.getConstArray();
458 for (long i
=0; i
<nLen
; i
++)
459 if (pArray
[i
].Flags
& sheet::MemberResultFlags::HASMEMBER
)
462 return true; // no member data -> empty
466 * Get visible page dimension members as results, except that, if all
467 * members are visible, then this function returns empty result.
469 uno::Sequence
<sheet::MemberResult
> getVisiblePageMembersAsResults( const uno::Reference
<uno::XInterface
>& xLevel
)
472 return uno::Sequence
<sheet::MemberResult
>();
474 uno::Reference
<sheet::XMembersSupplier
> xMSupplier(xLevel
, UNO_QUERY
);
475 if (!xMSupplier
.is())
476 return uno::Sequence
<sheet::MemberResult
>();
478 uno::Reference
<container::XNameAccess
> xNA
= xMSupplier
->getMembers();
480 return uno::Sequence
<sheet::MemberResult
>();
482 std::vector
<sheet::MemberResult
> aRes
;
483 uno::Sequence
<OUString
> aNames
= xNA
->getElementNames();
484 for (sal_Int32 i
= 0; i
< aNames
.getLength(); ++i
)
486 const OUString
& rName
= aNames
[i
];
487 xNA
->getByName(rName
);
489 uno::Reference
<beans::XPropertySet
> xMemPS(xNA
->getByName(rName
), UNO_QUERY
);
493 OUString aCaption
= ScUnoHelpFunctions::GetStringProperty(xMemPS
, SC_UNO_DP_LAYOUTNAME
, OUString());
494 if (aCaption
.isEmpty())
497 bool bVisible
= ScUnoHelpFunctions::GetBoolProperty(xMemPS
, SC_UNO_DP_ISVISIBLE
, false);
500 aRes
.push_back(sheet::MemberResult(rName
, aCaption
, 0));
503 if (aNames
.getLength() == static_cast<sal_Int32
>(aRes
.size()))
504 // All members are visible. Return empty result.
505 return uno::Sequence
<sheet::MemberResult
>();
507 return ScUnoHelpFunctions::VectorToSequence(aRes
);
512 ScDPOutput::ScDPOutput( ScDocument
* pD
, const uno::Reference
<sheet::XDimensionsSupplier
>& xSrc
,
513 const ScAddress
& rPos
, bool bFilter
) :
523 bResultsError(false),
524 mbHasDataLayout(false),
526 bSizeOverflow(false),
527 mbHeaderLayout(false)
529 nTabStartCol
= nMemberStartCol
= nDataStartCol
= nTabEndCol
= 0;
530 nTabStartRow
= nMemberStartRow
= nDataStartRow
= nTabEndRow
= 0;
532 pColFields
= new ScDPOutLevelData
[SC_DPOUT_MAXLEVELS
];
533 pRowFields
= new ScDPOutLevelData
[SC_DPOUT_MAXLEVELS
];
534 pPageFields
= new ScDPOutLevelData
[SC_DPOUT_MAXLEVELS
];
539 uno::Reference
<sheet::XDataPilotResults
> xResult( xSource
, uno::UNO_QUERY
);
540 if ( xSource
.is() && xResult
.is() )
542 // get dimension results:
544 uno::Reference
<container::XIndexAccess
> xDims
=
545 new ScNameToIndexAccess( xSource
->getDimensions() );
546 long nDimCount
= xDims
->getCount();
547 for (long nDim
=0; nDim
<nDimCount
; nDim
++)
549 uno::Reference
<uno::XInterface
> xDim
=
550 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
551 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
552 uno::Reference
<sheet::XHierarchiesSupplier
> xDimSupp( xDim
, uno::UNO_QUERY
);
553 if ( xDimProp
.is() && xDimSupp
.is() )
555 sheet::DataPilotFieldOrientation eDimOrient
=
556 (sheet::DataPilotFieldOrientation
) ScUnoHelpFunctions::GetEnumProperty(
557 xDimProp
, OUString(SC_UNO_DP_ORIENTATION
),
558 sheet::DataPilotFieldOrientation_HIDDEN
);
559 long nDimPos
= ScUnoHelpFunctions::GetLongProperty( xDimProp
,
560 OUString(SC_UNO_DP_POSITION
) );
561 bool bIsDataLayout
= ScUnoHelpFunctions::GetBoolProperty(
562 xDimProp
, OUString(SC_UNO_DP_ISDATALAYOUT
));
563 bool bHasHiddenMember
= ScUnoHelpFunctions::GetBoolProperty(
564 xDimProp
, OUString(SC_UNO_DP_HAS_HIDDEN_MEMBER
));
565 sal_Int32 nNumFmt
= ScUnoHelpFunctions::GetLongProperty(
566 xDimProp
, SC_UNO_DP_NUMBERFO
, 0);
568 if ( eDimOrient
!= sheet::DataPilotFieldOrientation_HIDDEN
)
570 uno::Reference
<container::XIndexAccess
> xHiers
=
571 new ScNameToIndexAccess( xDimSupp
->getHierarchies() );
572 long nHierarchy
= ScUnoHelpFunctions::GetLongProperty(
574 OUString(SC_UNO_DP_USEDHIERARCHY
) );
575 if ( nHierarchy
>= xHiers
->getCount() )
578 uno::Reference
<uno::XInterface
> xHier
=
579 ScUnoHelpFunctions::AnyToInterface(
580 xHiers
->getByIndex(nHierarchy
) );
581 uno::Reference
<sheet::XLevelsSupplier
> xHierSupp( xHier
, uno::UNO_QUERY
);
582 if ( xHierSupp
.is() )
584 uno::Reference
<container::XIndexAccess
> xLevels
=
585 new ScNameToIndexAccess( xHierSupp
->getLevels() );
586 long nLevCount
= xLevels
->getCount();
587 for (long nLev
=0; nLev
<nLevCount
; nLev
++)
589 uno::Reference
<uno::XInterface
> xLevel
=
590 ScUnoHelpFunctions::AnyToInterface(
591 xLevels
->getByIndex(nLev
) );
592 uno::Reference
<container::XNamed
> xLevNam( xLevel
, uno::UNO_QUERY
);
593 uno::Reference
<sheet::XDataPilotMemberResults
> xLevRes(
594 xLevel
, uno::UNO_QUERY
);
595 if ( xLevNam
.is() && xLevRes
.is() )
597 OUString aName
= xLevNam
->getName();
598 Reference
<XPropertySet
> xPropSet(xLevel
, UNO_QUERY
);
599 // Caption equals the field name by default.
600 // #i108948# use ScUnoHelpFunctions::GetStringProperty, because
601 // LayoutName is new and may not be present in external implementation
602 OUString aCaption
= ScUnoHelpFunctions::GetStringProperty( xPropSet
,
603 OUString(SC_UNO_DP_LAYOUTNAME
), aName
);
605 bool bRowFieldHasMember
= false;
606 switch ( eDimOrient
)
608 case sheet::DataPilotFieldOrientation_COLUMN
:
609 pColFields
[nColFieldCount
].nDim
= nDim
;
610 pColFields
[nColFieldCount
].nHier
= nHierarchy
;
611 pColFields
[nColFieldCount
].nLevel
= nLev
;
612 pColFields
[nColFieldCount
].nDimPos
= nDimPos
;
613 pColFields
[nColFieldCount
].aResult
= xLevRes
->getResults();
614 pColFields
[nColFieldCount
].mnSrcNumFmt
= nNumFmt
;
615 pColFields
[nColFieldCount
].maName
= aName
;
616 pColFields
[nColFieldCount
].maCaption
= aCaption
;
617 pColFields
[nColFieldCount
].mbHasHiddenMember
= bHasHiddenMember
;
618 pColFields
[nColFieldCount
].mbDataLayout
= bIsDataLayout
;
619 if (!lcl_MemberEmpty(pColFields
[nColFieldCount
].aResult
))
622 case sheet::DataPilotFieldOrientation_ROW
:
623 pRowFields
[nRowFieldCount
].nDim
= nDim
;
624 pRowFields
[nRowFieldCount
].nHier
= nHierarchy
;
625 pRowFields
[nRowFieldCount
].nLevel
= nLev
;
626 pRowFields
[nRowFieldCount
].nDimPos
= nDimPos
;
627 pRowFields
[nRowFieldCount
].aResult
= xLevRes
->getResults();
628 pRowFields
[nRowFieldCount
].mnSrcNumFmt
= nNumFmt
;
629 pRowFields
[nRowFieldCount
].maName
= aName
;
630 pRowFields
[nRowFieldCount
].maCaption
= aCaption
;
631 pRowFields
[nRowFieldCount
].mbHasHiddenMember
= bHasHiddenMember
;
632 pRowFields
[nRowFieldCount
].mbDataLayout
= bIsDataLayout
;
633 if (!lcl_MemberEmpty(pRowFields
[nRowFieldCount
].aResult
))
636 bRowFieldHasMember
= true;
639 case sheet::DataPilotFieldOrientation_PAGE
:
640 pPageFields
[nPageFieldCount
].nDim
= nDim
;
641 pPageFields
[nPageFieldCount
].nHier
= nHierarchy
;
642 pPageFields
[nPageFieldCount
].nLevel
= nLev
;
643 pPageFields
[nPageFieldCount
].nDimPos
= nDimPos
;
644 pPageFields
[nPageFieldCount
].aResult
= getVisiblePageMembersAsResults(xLevel
);
645 pPageFields
[nPageFieldCount
].mnSrcNumFmt
= nNumFmt
;
646 pPageFields
[nPageFieldCount
].maName
= aName
;
647 pPageFields
[nPageFieldCount
].maCaption
= aCaption
;
648 pPageFields
[nPageFieldCount
].mbHasHiddenMember
= bHasHiddenMember
;
649 pPageFields
[nPageFieldCount
].mbPageDim
= true;
650 // no check on results for page fields
655 // added to avoid warnings
659 // get number formats from data dimensions
662 if (bRowFieldHasMember
)
663 mbHasDataLayout
= true;
665 OSL_ENSURE( nLevCount
== 1, "data layout: multiple levels?" );
666 if ( eDimOrient
== sheet::DataPilotFieldOrientation_COLUMN
)
667 lcl_FillNumberFormats( pColNumFmt
, nColFmtCount
, xLevRes
, xDims
);
668 else if ( eDimOrient
== sheet::DataPilotFieldOrientation_ROW
)
669 lcl_FillNumberFormats( pRowNumFmt
, nRowFmtCount
, xLevRes
, xDims
);
675 else if ( bIsDataLayout
)
677 // data layout dimension is hidden (allowed if there is only one data dimension)
678 // -> use the number format from the first data dimension for all results
680 nSingleNumFmt
= lcl_GetFirstNumberFormat( xDims
);
684 lcl_SortFields( pColFields
, nColFieldCount
);
685 lcl_SortFields( pRowFields
, nRowFieldCount
);
686 lcl_SortFields( pPageFields
, nPageFieldCount
);
692 aData
= xResult
->getResults();
694 catch (const uno::RuntimeException
&)
696 bResultsError
= true;
700 // get "DataDescription" property (may be missing in external sources)
702 uno::Reference
<beans::XPropertySet
> xSrcProp( xSource
, uno::UNO_QUERY
);
707 uno::Any aAny
= xSrcProp
->getPropertyValue(
708 OUString(SC_UNO_DP_DATADESC
) );
711 aDataDescription
= aUStr
;
713 catch(const uno::Exception
&)
719 ScDPOutput::~ScDPOutput()
723 delete[] pPageFields
;
729 void ScDPOutput::SetPosition( const ScAddress
& rPos
)
732 bSizesValid
= bSizeOverflow
= false;
735 void ScDPOutput::DataCell( SCCOL nCol
, SCROW nRow
, SCTAB nTab
, const sheet::DataResult
& rData
)
737 long nFlags
= rData
.Flags
;
738 if ( nFlags
& sheet::DataResultFlags::ERROR
)
740 pDoc
->SetError( nCol
, nRow
, nTab
, errNoValue
);
742 else if ( nFlags
& sheet::DataResultFlags::HASDATA
)
744 pDoc
->SetValue( nCol
, nRow
, nTab
, rData
.Value
);
746 // use number formats from source
748 OSL_ENSURE( bSizesValid
, "DataCell: !bSizesValid" );
749 sal_uInt32 nFormat
= 0;
750 bool bApplyFormat
= false;
753 if ( nCol
>= nDataStartCol
)
755 long nIndex
= nCol
- nDataStartCol
;
756 if ( nIndex
< nColFmtCount
)
758 nFormat
= pColNumFmt
[nIndex
];
763 else if ( pRowNumFmt
)
765 if ( nRow
>= nDataStartRow
)
767 long nIndex
= nRow
- nDataStartRow
;
768 if ( nIndex
< nRowFmtCount
)
770 nFormat
= pRowNumFmt
[nIndex
];
775 else if ( nSingleNumFmt
!= 0 )
777 nFormat
= nSingleNumFmt
; // single format is used everywhere
782 pDoc
->ApplyAttr(nCol
, nRow
, nTab
, SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
784 // SubTotal formatting is controlled by headers
787 void ScDPOutput::HeaderCell( SCCOL nCol
, SCROW nRow
, SCTAB nTab
,
788 const sheet::MemberResult
& rData
, bool bColHeader
, long nLevel
)
790 long nFlags
= rData
.Flags
;
792 if ( nFlags
& sheet::MemberResultFlags::HASMEMBER
)
794 bool bNumeric
= (nFlags
& sheet::MemberResultFlags::NUMERIC
) != 0;
795 ScSetStringParam aParam
;
797 aParam
.setNumericInput();
799 aParam
.setTextInput();
801 pDoc
->SetString(nCol
, nRow
, nTab
, rData
.Caption
, &aParam
);
804 if ( nFlags
& sheet::MemberResultFlags::SUBTOTAL
)
806 ScDPOutputImpl
outputimp( pDoc
, nTab
,
807 nTabStartCol
, nTabStartRow
,
808 nDataStartCol
, nDataStartRow
, nTabEndCol
, nTabEndRow
);
809 //! limit frames to horizontal or vertical?
812 outputimp
.OutputBlockFrame( nCol
,nMemberStartRow
+(SCROW
)nLevel
, nCol
,nDataStartRow
-1 );
814 lcl_SetStyleById( pDoc
,nTab
, nCol
,nMemberStartRow
+(SCROW
)nLevel
, nCol
,nDataStartRow
-1,
815 STR_PIVOT_STYLE_TITLE
);
816 lcl_SetStyleById( pDoc
,nTab
, nCol
,nDataStartRow
, nCol
,nTabEndRow
,
817 STR_PIVOT_STYLE_RESULT
);
821 outputimp
.OutputBlockFrame( nMemberStartCol
+(SCCOL
)nLevel
,nRow
, nDataStartCol
-1,nRow
);
822 lcl_SetStyleById( pDoc
,nTab
, nMemberStartCol
+(SCCOL
)nLevel
,nRow
, nDataStartCol
-1,nRow
,
823 STR_PIVOT_STYLE_TITLE
);
824 lcl_SetStyleById( pDoc
,nTab
, nDataStartCol
,nRow
, nTabEndCol
,nRow
,
825 STR_PIVOT_STYLE_RESULT
);
830 void ScDPOutput::FieldCell(
831 SCCOL nCol
, SCROW nRow
, SCTAB nTab
, const ScDPOutLevelData
& rData
, bool bInTable
)
833 // Avoid unwanted automatic format detection.
834 ScSetStringParam aParam
;
835 aParam
.mbDetectNumberFormat
= false;
836 aParam
.meSetTextNumFormat
= ScSetStringParam::Always
;
837 aParam
.mbHandleApostrophe
= false;
838 pDoc
->SetString(nCol
, nRow
, nTab
, rData
.maCaption
, &aParam
);
841 lcl_SetFrame( pDoc
,nTab
, nCol
,nRow
, nCol
,nRow
, 20 );
843 // For field button drawing
844 sal_uInt16 nMergeFlag
= 0;
845 if (rData
.mbHasHiddenMember
)
846 nMergeFlag
|= SC_MF_HIDDEN_MEMBER
;
850 nMergeFlag
|= SC_MF_BUTTON_POPUP
;
851 pDoc
->ApplyFlagsTab(nCol
, nRow
, nCol
, nRow
, nTab
, SC_MF_BUTTON
);
852 pDoc
->ApplyFlagsTab(nCol
+1, nRow
, nCol
+1, nRow
, nTab
, nMergeFlag
);
856 nMergeFlag
|= SC_MF_BUTTON
;
857 if (!rData
.mbDataLayout
)
858 nMergeFlag
|= SC_MF_BUTTON_POPUP
;
859 pDoc
->ApplyFlagsTab(nCol
, nRow
, nCol
, nRow
, nTab
, nMergeFlag
);
863 lcl_SetStyleById( pDoc
,nTab
, nCol
,nRow
, nCol
,nRow
, STR_PIVOT_STYLE_FIELDNAME
);
866 static void lcl_DoFilterButton( ScDocument
* pDoc
, SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
868 pDoc
->SetString( nCol
, nRow
, nTab
, ScGlobal::GetRscString(STR_CELL_FILTER
) );
869 pDoc
->ApplyFlagsTab(nCol
, nRow
, nCol
, nRow
, nTab
, SC_MF_BUTTON
);
872 void ScDPOutput::CalcSizes()
876 // get column size of data from first row
877 //! allow different sizes (and clear following areas) ???
879 nRowCount
= aData
.getLength();
880 const uno::Sequence
<sheet::DataResult
>* pRowAry
= aData
.getConstArray();
881 nColCount
= nRowCount
? ( pRowAry
[0].getLength() ) : 0;
884 if (GetHeaderLayout() && nColFieldCount
== 0)
885 // Insert an extra header row only when there is no column field.
888 // calculate output positions and sizes
890 long nPageSize
= 0; //! use page fields!
891 if ( bDoFilter
|| nPageFieldCount
)
893 nPageSize
+= nPageFieldCount
+ 1; // plus one empty row
895 ++nPageSize
; // filter button above the page fields
898 if ( aStartPos
.Col() + nRowFieldCount
+ nColCount
- 1 > MAXCOL
||
899 aStartPos
.Row() + nPageSize
+ nHeaderSize
+ nColFieldCount
+ nRowCount
> MAXROW
)
901 bSizeOverflow
= true;
904 nTabStartCol
= aStartPos
.Col();
905 nTabStartRow
= aStartPos
.Row() + (SCROW
)nPageSize
; // below page fields
906 nMemberStartCol
= nTabStartCol
;
907 nMemberStartRow
= nTabStartRow
+ (SCROW
) nHeaderSize
;
908 nDataStartCol
= nMemberStartCol
+ (SCCOL
)nRowFieldCount
;
909 nDataStartRow
= nMemberStartRow
+ (SCROW
)nColFieldCount
;
911 nTabEndCol
= nDataStartCol
+ (SCCOL
)nColCount
- 1;
913 nTabEndCol
= nDataStartCol
; // single column will remain empty
914 // if page fields are involved, include the page selection cells
915 if ( nPageFieldCount
> 0 && nTabEndCol
< nTabStartCol
+ 1 )
916 nTabEndCol
= nTabStartCol
+ 1;
918 nTabEndRow
= nDataStartRow
+ (SCROW
)nRowCount
- 1;
920 nTabEndRow
= nDataStartRow
; // single row will remain empty
925 sal_Int32
ScDPOutput::GetPositionType(const ScAddress
& rPos
)
927 using namespace ::com::sun::star::sheet
;
929 SCCOL nCol
= rPos
.Col();
930 SCROW nRow
= rPos
.Row();
931 SCTAB nTab
= rPos
.Tab();
932 if ( nTab
!= aStartPos
.Tab() )
933 return DataPilotTablePositionType::NOT_IN_TABLE
;
937 // Make sure the cursor is within the table.
938 if (nCol
< nTabStartCol
|| nRow
< nTabStartRow
|| nCol
> nTabEndCol
|| nRow
> nTabEndRow
)
939 return DataPilotTablePositionType::NOT_IN_TABLE
;
941 // test for result data area.
942 if (nCol
>= nDataStartCol
&& nCol
<= nTabEndCol
&& nRow
>= nDataStartRow
&& nRow
<= nTabEndRow
)
943 return DataPilotTablePositionType::RESULT
;
945 bool bInColHeader
= (nRow
>= nTabStartRow
&& nRow
< nDataStartRow
);
946 bool bInRowHeader
= (nCol
>= nTabStartCol
&& nCol
< nDataStartCol
);
948 if (bInColHeader
&& bInRowHeader
)
949 // probably in that ugly little box at the upper-left corner of the table.
950 return DataPilotTablePositionType::OTHER
;
954 if (nRow
== nTabStartRow
)
955 // first row in the column header area is always used for column
957 return DataPilotTablePositionType::OTHER
;
959 return DataPilotTablePositionType::COLUMN_HEADER
;
963 return DataPilotTablePositionType::ROW_HEADER
;
965 return DataPilotTablePositionType::OTHER
;
968 void ScDPOutput::Output()
971 SCTAB nTab
= aStartPos
.Tab();
972 const uno::Sequence
<sheet::DataResult
>* pRowAry
= aData
.getConstArray();
974 // calculate output positions and sizes
977 if ( bSizeOverflow
|| bResultsError
) // does output area exceed sheet limits?
980 // clear whole (new) output area
981 //! when modifying table, clear old area
982 //! include IDF_OBJECTS ???
983 pDoc
->DeleteAreaTab( aStartPos
.Col(), aStartPos
.Row(), nTabEndCol
, nTabEndRow
, nTab
, IDF_ALL
);
986 lcl_DoFilterButton( pDoc
, aStartPos
.Col(), aStartPos
.Row(), nTab
);
988 // output page fields:
990 for (nField
=0; nField
<nPageFieldCount
; nField
++)
992 SCCOL nHdrCol
= aStartPos
.Col();
993 SCROW nHdrRow
= aStartPos
.Row() + nField
+ ( bDoFilter
? 1 : 0 );
994 // draw without frame for consistency with filter button:
995 FieldCell(nHdrCol
, nHdrRow
, nTab
, pPageFields
[nField
], false);
996 SCCOL nFldCol
= nHdrCol
+ 1;
998 OUString aPageValue
= ScResId(SCSTR_ALL
).toString();
999 const uno::Sequence
<sheet::MemberResult
>& rRes
= pPageFields
[nField
].aResult
;
1000 sal_Int32 n
= rRes
.getLength();
1002 aPageValue
= rRes
[0].Caption
;
1004 aPageValue
= ScResId(SCSTR_MULTIPLE
).toString();
1006 pDoc
->SetString( nFldCol
, nHdrRow
, nTab
, aPageValue
);
1008 lcl_SetFrame( pDoc
,nTab
, nFldCol
,nHdrRow
, nFldCol
,nHdrRow
, 20 );
1012 // (may get overwritten by first row field)
1014 if (aDataDescription
.isEmpty())
1016 //! use default string ("result") ?
1018 pDoc
->SetString(nTabStartCol
, nTabStartRow
, nTab
, aDataDescription
);
1020 // set STR_PIVOT_STYLE_INNER for whole data area (subtotals are overwritten)
1022 if ( nDataStartRow
> nTabStartRow
)
1023 lcl_SetStyleById( pDoc
, nTab
, nTabStartCol
, nTabStartRow
, nTabEndCol
, nDataStartRow
-1,
1024 STR_PIVOT_STYLE_TOP
);
1025 lcl_SetStyleById( pDoc
, nTab
, nDataStartCol
, nDataStartRow
, nTabEndCol
, nTabEndRow
,
1026 STR_PIVOT_STYLE_INNER
);
1028 // output column headers:
1029 ScDPOutputImpl
outputimp( pDoc
, nTab
,
1030 nTabStartCol
, nTabStartRow
,
1031 nDataStartCol
, nDataStartRow
, nTabEndCol
, nTabEndRow
);
1032 for (nField
=0; nField
<nColFieldCount
; nField
++)
1034 SCCOL nHdrCol
= nDataStartCol
+ (SCCOL
)nField
; //! check for overflow
1035 FieldCell(nHdrCol
, nTabStartRow
, nTab
, pColFields
[nField
], true);
1037 SCROW nRowPos
= nMemberStartRow
+ (SCROW
)nField
; //! check for overflow
1038 const uno::Sequence
<sheet::MemberResult
> rSequence
= pColFields
[nField
].aResult
;
1039 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1040 long nThisColCount
= rSequence
.getLength();
1041 OSL_ENSURE( nThisColCount
== nColCount
, "count mismatch" ); //! ???
1042 for (long nCol
=0; nCol
<nThisColCount
; nCol
++)
1044 SCCOL nColPos
= nDataStartCol
+ (SCCOL
)nCol
; //! check for overflow
1045 HeaderCell( nColPos
, nRowPos
, nTab
, pArray
[nCol
], true, nField
);
1046 if ( ( pArray
[nCol
].Flags
& sheet::MemberResultFlags::HASMEMBER
) &&
1047 !( pArray
[nCol
].Flags
& sheet::MemberResultFlags::SUBTOTAL
) )
1050 while ( nEnd
+1 < nThisColCount
&& ( pArray
[nEnd
+1].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1052 SCCOL nEndColPos
= nDataStartCol
+ (SCCOL
)nEnd
; //! check for overflow
1053 if ( nField
+1 < nColFieldCount
)
1055 if ( nField
== nColFieldCount
- 2 )
1057 outputimp
.AddCol( nColPos
);
1058 if ( nColPos
+ 1 == nEndColPos
)
1059 outputimp
.OutputBlockFrame( nColPos
,nRowPos
, nEndColPos
,nRowPos
+1, true );
1062 outputimp
.OutputBlockFrame( nColPos
,nRowPos
, nEndColPos
,nRowPos
);
1064 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nEndColPos
,nDataStartRow
-1, STR_PIVOT_STYLE_CATEGORY
);
1067 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nColPos
,nDataStartRow
-1, STR_PIVOT_STYLE_CATEGORY
);
1069 else if ( pArray
[nCol
].Flags
& sheet::MemberResultFlags::SUBTOTAL
)
1070 outputimp
.AddCol( nColPos
);
1072 // Apply the same number format as in data source.
1073 pDoc
->ApplyAttr(nColPos
, nRowPos
, nTab
, SfxUInt32Item(ATTR_VALUE_FORMAT
, pColFields
[nField
].mnSrcNumFmt
));
1075 if ( nField
== 0 && nColFieldCount
== 1 )
1076 outputimp
.OutputBlockFrame( nDataStartCol
,nTabStartRow
, nTabEndCol
,nRowPos
-1 );
1079 // output row headers:
1080 std::vector
<bool> vbSetBorder
;
1081 vbSetBorder
.resize( nTabEndRow
- nDataStartRow
+ 1, false );
1082 for (nField
=0; nField
<nRowFieldCount
; nField
++)
1084 SCCOL nHdrCol
= nTabStartCol
+ (SCCOL
)nField
; //! check for overflow
1085 SCROW nHdrRow
= nDataStartRow
- 1;
1086 FieldCell(nHdrCol
, nHdrRow
, nTab
, pRowFields
[nField
], true);
1088 SCCOL nColPos
= nMemberStartCol
+ (SCCOL
)nField
; //! check for overflow
1089 const uno::Sequence
<sheet::MemberResult
> rSequence
= pRowFields
[nField
].aResult
;
1090 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1091 long nThisRowCount
= rSequence
.getLength();
1092 OSL_ENSURE( nThisRowCount
== nRowCount
, "count mismatch" ); //! ???
1093 for (long nRow
=0; nRow
<nThisRowCount
; nRow
++)
1095 SCROW nRowPos
= nDataStartRow
+ (SCROW
)nRow
; //! check for overflow
1096 HeaderCell( nColPos
, nRowPos
, nTab
, pArray
[nRow
], false, nField
);
1097 if ( ( pArray
[nRow
].Flags
& sheet::MemberResultFlags::HASMEMBER
) &&
1098 !( pArray
[nRow
].Flags
& sheet::MemberResultFlags::SUBTOTAL
) )
1100 if ( nField
+1 < nRowFieldCount
)
1103 while ( nEnd
+1 < nThisRowCount
&& ( pArray
[nEnd
+1].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1105 SCROW nEndRowPos
= nDataStartRow
+ (SCROW
)nEnd
; //! check for overflow
1106 outputimp
.AddRow( nRowPos
);
1107 if ( vbSetBorder
[ nRow
] == false )
1109 outputimp
.OutputBlockFrame( nColPos
, nRowPos
, nTabEndCol
, nEndRowPos
);
1110 vbSetBorder
[ nRow
] = true;
1112 outputimp
.OutputBlockFrame( nColPos
, nRowPos
, nColPos
, nEndRowPos
);
1114 if ( nField
== nRowFieldCount
- 2 )
1115 outputimp
.OutputBlockFrame( nColPos
+1, nRowPos
, nColPos
+1, nEndRowPos
);
1117 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nDataStartCol
-1,nEndRowPos
, STR_PIVOT_STYLE_CATEGORY
);
1120 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nDataStartCol
-1,nRowPos
, STR_PIVOT_STYLE_CATEGORY
);
1122 else if ( pArray
[nRow
].Flags
& sheet::MemberResultFlags::SUBTOTAL
)
1123 outputimp
.AddRow( nRowPos
);
1125 // Apply the same number format as in data source.
1126 pDoc
->ApplyAttr(nColPos
, nRowPos
, nTab
, SfxUInt32Item(ATTR_VALUE_FORMAT
, pRowFields
[nField
].mnSrcNumFmt
));
1130 // output data results:
1132 for (long nRow
=0; nRow
<nRowCount
; nRow
++)
1134 SCROW nRowPos
= nDataStartRow
+ (SCROW
)nRow
; //! check for overflow
1135 const sheet::DataResult
* pColAry
= pRowAry
[nRow
].getConstArray();
1136 long nThisColCount
= pRowAry
[nRow
].getLength();
1137 OSL_ENSURE( nThisColCount
== nColCount
, "count mismatch" ); //! ???
1138 for (long nCol
=0; nCol
<nThisColCount
; nCol
++)
1140 SCCOL nColPos
= nDataStartCol
+ (SCCOL
)nCol
; //! check for overflow
1141 DataCell( nColPos
, nRowPos
, nTab
, pColAry
[nCol
] );
1145 outputimp
.OutputDataArea();
1148 ScRange
ScDPOutput::GetOutputRange( sal_Int32 nRegionType
)
1150 using namespace ::com::sun::star::sheet
;
1154 SCTAB nTab
= aStartPos
.Tab();
1155 switch (nRegionType
)
1157 case DataPilotOutputRangeType::RESULT
:
1158 return ScRange(nDataStartCol
, nDataStartRow
, nTab
, nTabEndCol
, nTabEndRow
, nTab
);
1159 case DataPilotOutputRangeType::TABLE
:
1160 return ScRange(aStartPos
.Col(), nTabStartRow
, nTab
, nTabEndCol
, nTabEndRow
, nTab
);
1162 OSL_ENSURE(nRegionType
== DataPilotOutputRangeType::WHOLE
, "ScDPOutput::GetOutputRange: unknown region type");
1165 return ScRange(aStartPos
.Col(), aStartPos
.Row(), nTab
, nTabEndCol
, nTabEndRow
, nTab
);
1168 bool ScDPOutput::HasError()
1172 return bSizeOverflow
|| bResultsError
;
1175 long ScDPOutput::GetHeaderRows()
1177 return nPageFieldCount
+ ( bDoFilter
? 1 : 0 );
1180 void ScDPOutput::GetMemberResultNames(ScDPUniqueStringSet
& rNames
, long nDimension
)
1182 // Return the list of all member names in a dimension's MemberResults.
1183 // Only the dimension has to be compared because this is only used with table data,
1184 // where each dimension occurs only once.
1186 uno::Sequence
<sheet::MemberResult
> aMemberResults
;
1187 bool bFound
= false;
1190 // look in column fields
1192 for (nField
=0; nField
<nColFieldCount
&& !bFound
; nField
++)
1193 if ( pColFields
[nField
].nDim
== nDimension
)
1195 aMemberResults
= pColFields
[nField
].aResult
;
1199 // look in row fields
1201 for (nField
=0; nField
<nRowFieldCount
&& !bFound
; nField
++)
1202 if ( pRowFields
[nField
].nDim
== nDimension
)
1204 aMemberResults
= pRowFields
[nField
].aResult
;
1208 // collect the member names
1212 const sheet::MemberResult
* pArray
= aMemberResults
.getConstArray();
1213 long nResultCount
= aMemberResults
.getLength();
1215 for (long nItem
=0; nItem
<nResultCount
; nItem
++)
1217 if ( pArray
[nItem
].Flags
& sheet::MemberResultFlags::HASMEMBER
)
1218 rNames
.insert(pArray
[nItem
].Name
);
1223 void ScDPOutput::SetHeaderLayout(bool bUseGrid
)
1225 mbHeaderLayout
= bUseGrid
;
1226 bSizesValid
= false;
1229 bool ScDPOutput::GetHeaderLayout() const
1231 return mbHeaderLayout
;
1236 void lcl_GetTableVars( sal_Int32
& rGrandTotalCols
, sal_Int32
& rGrandTotalRows
, sal_Int32
& rDataLayoutIndex
,
1237 std::vector
<OUString
>& rDataNames
, std::vector
<OUString
>& rGivenNames
,
1238 sheet::DataPilotFieldOrientation
& rDataOrient
,
1239 const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
)
1241 rDataLayoutIndex
= -1; // invalid
1242 rGrandTotalCols
= 0;
1243 rGrandTotalRows
= 0;
1244 rDataOrient
= sheet::DataPilotFieldOrientation_HIDDEN
;
1246 uno::Reference
<beans::XPropertySet
> xSrcProp( xSource
, uno::UNO_QUERY
);
1247 bool bColGrand
= ScUnoHelpFunctions::GetBoolProperty(
1248 xSrcProp
, OUString(SC_UNO_DP_COLGRAND
));
1250 rGrandTotalCols
= 1; // default if data layout not in columns
1252 bool bRowGrand
= ScUnoHelpFunctions::GetBoolProperty(
1253 xSrcProp
, OUString(SC_UNO_DP_ROWGRAND
));
1255 rGrandTotalRows
= 1; // default if data layout not in rows
1259 // find index and orientation of "data layout" dimension, count data dimensions
1261 sal_Int32 nDataCount
= 0;
1263 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xSource
->getDimensions() );
1264 long nDimCount
= xDims
->getCount();
1265 for (long nDim
=0; nDim
<nDimCount
; nDim
++)
1267 uno::Reference
<uno::XInterface
> xDim
=
1268 ScUnoHelpFunctions::AnyToInterface( xDims
->getByIndex(nDim
) );
1269 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
1270 if ( xDimProp
.is() )
1272 sheet::DataPilotFieldOrientation eDimOrient
=
1273 (sheet::DataPilotFieldOrientation
) ScUnoHelpFunctions::GetEnumProperty(
1274 xDimProp
, OUString(SC_UNO_DP_ORIENTATION
),
1275 sheet::DataPilotFieldOrientation_HIDDEN
);
1276 if ( ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
1277 OUString(SC_UNO_DP_ISDATALAYOUT
) ) )
1279 rDataLayoutIndex
= nDim
;
1280 rDataOrient
= eDimOrient
;
1282 if ( eDimOrient
== sheet::DataPilotFieldOrientation_DATA
)
1284 OUString aSourceName
;
1285 OUString aGivenName
;
1286 ScDPOutput::GetDataDimensionNames( aSourceName
, aGivenName
, xDim
);
1289 uno::Any aValue
= xDimProp
->getPropertyValue( SC_UNO_DP_LAYOUTNAME
);
1291 if( aValue
.hasValue() )
1293 OUString strLayoutName
;
1295 if( ( aValue
>>= strLayoutName
) && !strLayoutName
.isEmpty() )
1296 aGivenName
= strLayoutName
;
1299 catch(const uno::Exception
&)
1302 rDataNames
.push_back( aSourceName
);
1303 rGivenNames
.push_back( aGivenName
);
1310 if ( ( rDataOrient
== sheet::DataPilotFieldOrientation_COLUMN
) && bColGrand
)
1311 rGrandTotalCols
= nDataCount
;
1312 else if ( ( rDataOrient
== sheet::DataPilotFieldOrientation_ROW
) && bRowGrand
)
1313 rGrandTotalRows
= nDataCount
;
1319 void ScDPOutput::GetPositionData(const ScAddress
& rPos
, DataPilotTablePositionData
& rPosData
)
1321 using namespace ::com::sun::star::sheet
;
1323 SCCOL nCol
= rPos
.Col();
1324 SCROW nRow
= rPos
.Row();
1325 SCTAB nTab
= rPos
.Tab();
1326 if ( nTab
!= aStartPos
.Tab() )
1327 return; // wrong sheet
1329 // calculate output positions and sizes
1333 rPosData
.PositionType
= GetPositionType(rPos
);
1334 switch (rPosData
.PositionType
)
1336 case DataPilotTablePositionType::RESULT
:
1338 vector
<DataPilotFieldFilter
> aFilters
;
1339 GetDataResultPositionData(aFilters
, rPos
);
1340 sal_Int32 nSize
= aFilters
.size();
1342 DataPilotTableResultData aResData
;
1343 aResData
.FieldFilters
.realloc(nSize
);
1344 for (sal_Int32 i
= 0; i
< nSize
; ++i
)
1345 aResData
.FieldFilters
[i
] = aFilters
[i
];
1347 aResData
.DataFieldIndex
= 0;
1348 Reference
<beans::XPropertySet
> xPropSet(xSource
, UNO_QUERY
);
1351 sal_Int32 nDataFieldCount
= ScUnoHelpFunctions::GetLongProperty( xPropSet
,
1352 OUString(SC_UNO_DP_DATAFIELDCOUNT
) );
1353 if (nDataFieldCount
> 0)
1354 aResData
.DataFieldIndex
= (nRow
- nDataStartRow
) % nDataFieldCount
;
1357 // Copy appropriate DataResult object from the cached sheet::DataResult table.
1358 if (aData
.getLength() > nRow
- nDataStartRow
&&
1359 aData
[nRow
-nDataStartRow
].getLength() > nCol
-nDataStartCol
)
1360 aResData
.Result
= aData
[nRow
-nDataStartRow
][nCol
-nDataStartCol
];
1362 rPosData
.PositionData
= makeAny(aResData
);
1365 case DataPilotTablePositionType::COLUMN_HEADER
:
1367 long nField
= nRow
- nTabStartRow
- 1; // 1st line is used for the buttons
1371 const uno::Sequence
<sheet::MemberResult
> rSequence
= pColFields
[nField
].aResult
;
1372 if (rSequence
.getLength() == 0)
1374 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1376 long nItem
= nCol
- nDataStartCol
;
1377 // get origin of "continue" fields
1378 while (nItem
> 0 && ( pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1384 DataPilotTableHeaderData aHeaderData
;
1385 aHeaderData
.MemberName
= OUString(pArray
[nItem
].Name
);
1386 aHeaderData
.Flags
= pArray
[nItem
].Flags
;
1387 aHeaderData
.Dimension
= static_cast<sal_Int32
>(pColFields
[nField
].nDim
);
1388 aHeaderData
.Hierarchy
= static_cast<sal_Int32
>(pColFields
[nField
].nHier
);
1389 aHeaderData
.Level
= static_cast<sal_Int32
>(pColFields
[nField
].nLevel
);
1391 rPosData
.PositionData
= makeAny(aHeaderData
);
1394 case DataPilotTablePositionType::ROW_HEADER
:
1396 long nField
= nCol
- nTabStartCol
;
1400 const uno::Sequence
<sheet::MemberResult
> rSequence
= pRowFields
[nField
].aResult
;
1401 if (rSequence
.getLength() == 0)
1403 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1405 long nItem
= nRow
- nDataStartRow
;
1406 // get origin of "continue" fields
1407 while ( nItem
> 0 && (pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1413 DataPilotTableHeaderData aHeaderData
;
1414 aHeaderData
.MemberName
= OUString(pArray
[nItem
].Name
);
1415 aHeaderData
.Flags
= pArray
[nItem
].Flags
;
1416 aHeaderData
.Dimension
= static_cast<sal_Int32
>(pRowFields
[nField
].nDim
);
1417 aHeaderData
.Hierarchy
= static_cast<sal_Int32
>(pRowFields
[nField
].nHier
);
1418 aHeaderData
.Level
= static_cast<sal_Int32
>(pRowFields
[nField
].nLevel
);
1420 rPosData
.PositionData
= makeAny(aHeaderData
);
1426 bool ScDPOutput::GetDataResultPositionData(vector
<sheet::DataPilotFieldFilter
>& rFilters
, const ScAddress
& rPos
)
1428 // Check to make sure there is at least one data field.
1429 Reference
<beans::XPropertySet
> xPropSet(xSource
, UNO_QUERY
);
1433 sal_Int32 nDataFieldCount
= ScUnoHelpFunctions::GetLongProperty( xPropSet
,
1434 OUString(SC_UNO_DP_DATAFIELDCOUNT
) );
1435 if (nDataFieldCount
== 0)
1436 // No data field is present in this datapilot table.
1439 // #i111421# use lcl_GetTableVars for correct size of totals and data layout position
1440 sal_Int32 nGrandTotalCols
;
1441 sal_Int32 nGrandTotalRows
;
1442 sal_Int32 nDataLayoutIndex
;
1443 std::vector
<OUString
> aDataNames
;
1444 std::vector
<OUString
> aGivenNames
;
1445 sheet::DataPilotFieldOrientation eDataOrient
;
1446 lcl_GetTableVars( nGrandTotalCols
, nGrandTotalRows
, nDataLayoutIndex
, aDataNames
, aGivenNames
, eDataOrient
, xSource
);
1448 SCCOL nCol
= rPos
.Col();
1449 SCROW nRow
= rPos
.Row();
1450 SCTAB nTab
= rPos
.Tab();
1451 if ( nTab
!= aStartPos
.Tab() )
1452 return false; // wrong sheet
1456 // test for data area.
1457 if (nCol
< nDataStartCol
|| nCol
> nTabEndCol
|| nRow
< nDataStartRow
|| nRow
> nTabEndRow
)
1459 // Cell is outside the data field area.
1463 bool bFilterByCol
= (nCol
<= static_cast<SCCOL
>(nTabEndCol
- nGrandTotalCols
));
1464 bool bFilterByRow
= (nRow
<= static_cast<SCROW
>(nTabEndRow
- nGrandTotalRows
));
1467 for (SCCOL nColField
= 0; nColField
< nColFieldCount
&& bFilterByCol
; ++nColField
)
1469 if (pColFields
[nColField
].nDim
== nDataLayoutIndex
)
1470 // There is no sense including the data layout field for filtering.
1473 sheet::DataPilotFieldFilter filter
;
1474 filter
.FieldName
= pColFields
[nColField
].maName
;
1476 const uno::Sequence
<sheet::MemberResult
> rSequence
= pColFields
[nColField
].aResult
;
1477 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1479 OSL_ENSURE(nDataStartCol
+ rSequence
.getLength() - 1 == nTabEndCol
, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1481 long nItem
= nCol
- nDataStartCol
;
1482 // get origin of "continue" fields
1483 while ( nItem
> 0 && (pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1486 filter
.MatchValue
= pArray
[nItem
].Name
;
1487 rFilters
.push_back(filter
);
1491 for (SCROW nRowField
= 0; nRowField
< nRowFieldCount
&& bFilterByRow
; ++nRowField
)
1493 if (pRowFields
[nRowField
].nDim
== nDataLayoutIndex
)
1494 // There is no sense including the data layout field for filtering.
1497 sheet::DataPilotFieldFilter filter
;
1498 filter
.FieldName
= pRowFields
[nRowField
].maName
;
1500 const uno::Sequence
<sheet::MemberResult
> rSequence
= pRowFields
[nRowField
].aResult
;
1501 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1503 OSL_ENSURE(nDataStartRow
+ rSequence
.getLength() - 1 == nTabEndRow
, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1505 long nItem
= nRow
- nDataStartRow
;
1506 // get origin of "continue" fields
1507 while ( nItem
> 0 && (pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1510 filter
.MatchValue
= pArray
[nItem
].Name
;
1511 rFilters
.push_back(filter
);
1519 OUString
lcl_GetDataFieldName( const OUString
& rSourceName
, sheet::GeneralFunction eFunc
)
1521 sal_uInt16 nStrId
= 0;
1524 case sheet::GeneralFunction_SUM
: nStrId
= STR_FUN_TEXT_SUM
; break;
1525 case sheet::GeneralFunction_COUNT
:
1526 case sheet::GeneralFunction_COUNTNUMS
: nStrId
= STR_FUN_TEXT_COUNT
; break;
1527 case sheet::GeneralFunction_AVERAGE
: nStrId
= STR_FUN_TEXT_AVG
; break;
1528 case sheet::GeneralFunction_MAX
: nStrId
= STR_FUN_TEXT_MAX
; break;
1529 case sheet::GeneralFunction_MIN
: nStrId
= STR_FUN_TEXT_MIN
; break;
1530 case sheet::GeneralFunction_PRODUCT
: nStrId
= STR_FUN_TEXT_PRODUCT
; break;
1531 case sheet::GeneralFunction_STDEV
:
1532 case sheet::GeneralFunction_STDEVP
: nStrId
= STR_FUN_TEXT_STDDEV
; break;
1533 case sheet::GeneralFunction_VAR
:
1534 case sheet::GeneralFunction_VARP
: nStrId
= STR_FUN_TEXT_VAR
; break;
1535 case sheet::GeneralFunction_NONE
:
1536 case sheet::GeneralFunction_AUTO
:
1539 OSL_FAIL("wrong function");
1545 OUStringBuffer
aRet( ScGlobal::GetRscString( nStrId
) );
1547 aRet
.append(rSourceName
);
1548 return aRet
.makeStringAndClear();
1553 void ScDPOutput::GetDataDimensionNames(
1554 OUString
& rSourceName
, OUString
& rGivenName
, const uno::Reference
<uno::XInterface
>& xDim
)
1556 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
1557 uno::Reference
<container::XNamed
> xDimName( xDim
, uno::UNO_QUERY
);
1558 if ( xDimProp
.is() && xDimName
.is() )
1560 // Asterisks are added in ScDPSaveData::WriteToSource to create unique names.
1561 //! preserve original name there?
1562 rSourceName
= ScDPUtil::getSourceDimensionName(xDimName
->getName());
1564 // Generate "given name" the same way as in dptabres.
1565 //! Should use a stored name when available
1567 sheet::GeneralFunction eFunc
= (sheet::GeneralFunction
)ScUnoHelpFunctions::GetEnumProperty(
1568 xDimProp
, OUString(SC_UNO_DP_FUNCTION
),
1569 sheet::GeneralFunction_NONE
);
1570 rGivenName
= lcl_GetDataFieldName( rSourceName
, eFunc
);
1574 bool ScDPOutput::IsFilterButton( const ScAddress
& rPos
)
1576 SCCOL nCol
= rPos
.Col();
1577 SCROW nRow
= rPos
.Row();
1578 SCTAB nTab
= rPos
.Tab();
1579 if ( nTab
!= aStartPos
.Tab() || !bDoFilter
)
1580 return false; // wrong sheet or no button at all
1582 // filter button is at top left
1583 return ( nCol
== aStartPos
.Col() && nRow
== aStartPos
.Row() );
1586 long ScDPOutput::GetHeaderDim( const ScAddress
& rPos
, sal_uInt16
& rOrient
)
1588 SCCOL nCol
= rPos
.Col();
1589 SCROW nRow
= rPos
.Row();
1590 SCTAB nTab
= rPos
.Tab();
1591 if ( nTab
!= aStartPos
.Tab() )
1592 return -1; // wrong sheet
1594 // calculate output positions and sizes
1598 // test for column header
1600 if ( nRow
== nTabStartRow
&& nCol
>= nDataStartCol
&& nCol
< nDataStartCol
+ nColFieldCount
)
1602 rOrient
= sheet::DataPilotFieldOrientation_COLUMN
;
1603 long nField
= nCol
- nDataStartCol
;
1604 return pColFields
[nField
].nDim
;
1607 // test for row header
1609 if ( nRow
+1 == nDataStartRow
&& nCol
>= nTabStartCol
&& nCol
< nTabStartCol
+ nRowFieldCount
)
1611 rOrient
= sheet::DataPilotFieldOrientation_ROW
;
1612 long nField
= nCol
- nTabStartCol
;
1613 return pRowFields
[nField
].nDim
;
1616 // test for page field
1618 SCROW nPageStartRow
= aStartPos
.Row() + ( bDoFilter
? 1 : 0 );
1619 if ( nCol
== aStartPos
.Col() && nRow
>= nPageStartRow
&& nRow
< nPageStartRow
+ nPageFieldCount
)
1621 rOrient
= sheet::DataPilotFieldOrientation_PAGE
;
1622 long nField
= nRow
- nPageStartRow
;
1623 return pPageFields
[nField
].nDim
;
1626 //! single data field (?)
1628 rOrient
= sheet::DataPilotFieldOrientation_HIDDEN
;
1629 return -1; // invalid
1632 bool ScDPOutput::GetHeaderDrag( const ScAddress
& rPos
, bool bMouseLeft
, bool bMouseTop
,
1634 Rectangle
& rPosRect
, sal_uInt16
& rOrient
, long& rDimPos
)
1636 // Rectangle instead of ScRange for rPosRect to allow for negative values
1638 SCCOL nCol
= rPos
.Col();
1639 SCROW nRow
= rPos
.Row();
1640 SCTAB nTab
= rPos
.Tab();
1641 if ( nTab
!= aStartPos
.Tab() )
1642 return false; // wrong sheet
1644 // calculate output positions and sizes
1648 // test for column header
1650 if ( nCol
>= nDataStartCol
&& nCol
<= nTabEndCol
&&
1651 nRow
+ 1 >= nMemberStartRow
&& nRow
< nMemberStartRow
+ nColFieldCount
)
1653 long nField
= nRow
- nMemberStartRow
;
1659 //! find start of dimension
1661 rPosRect
= Rectangle( nDataStartCol
, nMemberStartRow
+ nField
,
1662 nTabEndCol
, nMemberStartRow
+ nField
-1 );
1664 bool bFound
= false; // is this within the same orientation?
1665 bool bBeforeDrag
= false;
1666 bool bAfterDrag
= false;
1667 for (long nPos
=0; nPos
<nColFieldCount
&& !bFound
; nPos
++)
1669 if (pColFields
[nPos
].nDim
== nDragDim
)
1672 if ( nField
< nPos
)
1674 else if ( nField
> nPos
)
1683 ++rPosRect
.Bottom();
1693 ++rPosRect
.Bottom();
1698 rOrient
= sheet::DataPilotFieldOrientation_COLUMN
;
1699 rDimPos
= nField
; //!...
1703 // test for row header
1705 // special case if no row fields
1706 bool bSpecial
= ( nRow
+1 >= nDataStartRow
&& nRow
<= nTabEndRow
&&
1707 nRowFieldCount
== 0 && nCol
== nTabStartCol
&& bMouseLeft
);
1709 if ( bSpecial
|| ( nRow
+1 >= nDataStartRow
&& nRow
<= nTabEndRow
&&
1710 nCol
+ 1 >= nTabStartCol
&& nCol
< nTabStartCol
+ nRowFieldCount
) )
1712 long nField
= nCol
- nTabStartCol
;
1713 //! find start of dimension
1715 rPosRect
= Rectangle( nTabStartCol
+ nField
, nDataStartRow
- 1,
1716 nTabStartCol
+ nField
- 1, nTabEndRow
);
1718 bool bFound
= false; // is this within the same orientation?
1719 bool bBeforeDrag
= false;
1720 bool bAfterDrag
= false;
1721 for (long nPos
=0; nPos
<nRowFieldCount
&& !bFound
; nPos
++)
1723 if (pRowFields
[nPos
].nDim
== nDragDim
)
1726 if ( nField
< nPos
)
1728 else if ( nField
> nPos
)
1752 rOrient
= sheet::DataPilotFieldOrientation_ROW
;
1753 rDimPos
= nField
; //!...
1757 // test for page fields
1759 SCROW nPageStartRow
= aStartPos
.Row() + ( bDoFilter
? 1 : 0 );
1760 if ( nCol
>= aStartPos
.Col() && nCol
<= nTabEndCol
&&
1761 nRow
+ 1 >= nPageStartRow
&& nRow
< nPageStartRow
+ nPageFieldCount
)
1763 long nField
= nRow
- nPageStartRow
;
1769 //! find start of dimension
1771 rPosRect
= Rectangle( aStartPos
.Col(), nPageStartRow
+ nField
,
1772 nTabEndCol
, nPageStartRow
+ nField
- 1 );
1774 bool bFound
= false; // is this within the same orientation?
1775 bool bBeforeDrag
= false;
1776 bool bAfterDrag
= false;
1777 for (long nPos
=0; nPos
<nPageFieldCount
&& !bFound
; nPos
++)
1779 if (pPageFields
[nPos
].nDim
== nDragDim
)
1782 if ( nField
< nPos
)
1784 else if ( nField
> nPos
)
1793 ++rPosRect
.Bottom();
1803 ++rPosRect
.Bottom();
1808 rOrient
= sheet::DataPilotFieldOrientation_PAGE
;
1809 rDimPos
= nField
; //!...
1817 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */