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>
22 #include <comphelper/sequence.hxx>
23 #include <editeng/borderline.hxx>
24 #include <editeng/boxitem.hxx>
25 #include <editeng/wghtitem.hxx>
26 #include <editeng/justifyitem.hxx>
27 #include <o3tl/safeint.hxx>
28 #include <osl/diagnose.h>
29 #include <svl/itemset.hxx>
31 #include <dpoutput.hxx>
32 #include <document.hxx>
34 #include <formula/errorcodes.hxx>
35 #include <miscuno.hxx>
36 #include <globstr.hrc>
37 #include <stlpool.hxx>
38 #include <stlsheet.hxx>
39 #include <scresid.hxx>
40 #include <unonames.hxx>
41 #include <strings.hrc>
42 #include <stringutil.hxx>
45 #include <com/sun/star/beans/XPropertySet.hpp>
46 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
47 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
48 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
49 #include <com/sun/star/sheet/DataPilotTableResultData.hpp>
50 #include <com/sun/star/sheet/MemberResultFlags.hpp>
51 #include <com/sun/star/sheet/DataResultFlags.hpp>
52 #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
53 #include <com/sun/star/sheet/GeneralFunction2.hpp>
54 #include <com/sun/star/sheet/MemberResult.hpp>
55 #include <com/sun/star/sheet/XDataPilotMemberResults.hpp>
56 #include <com/sun/star/sheet/XDataPilotResults.hpp>
57 #include <com/sun/star/sheet/XDimensionsSupplier.hpp>
58 #include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
59 #include <com/sun/star/sheet/XLevelsSupplier.hpp>
60 #include <com/sun/star/sheet/XMembersAccess.hpp>
61 #include <com/sun/star/sheet/XMembersSupplier.hpp>
64 #include <string_view>
67 using namespace com::sun::star
;
69 using ::com::sun::star::beans::XPropertySet
;
70 using ::com::sun::star::uno::Sequence
;
71 using ::com::sun::star::uno::UNO_QUERY
;
72 using ::com::sun::star::uno::Reference
;
73 using ::com::sun::star::sheet::DataPilotTablePositionData
;
74 using ::com::sun::star::sheet::DataPilotTableResultData
;
76 #define SC_DP_FRAME_INNER_BOLD 20
77 #define SC_DP_FRAME_OUTER_BOLD 40
79 #define SC_DP_FRAME_COLOR Color(0,0,0) //( 0x20, 0x40, 0x68 )
81 struct ScDPOutLevelData
87 sal_uInt32 mnSrcNumFmt
; /// Prevailing number format used in the source data.
88 uno::Sequence
<sheet::MemberResult
> maResult
;
89 OUString maName
; /// Name is the internal field name.
90 OUString maCaption
; /// Caption is the name visible in the output table.
91 bool mbHasHiddenMember
:1;
95 ScDPOutLevelData(tools::Long nDim
, tools::Long nHier
, tools::Long nLevel
, tools::Long nDimPos
, sal_uInt32 nSrcNumFmt
, const uno::Sequence
<sheet::MemberResult
> &aResult
,
96 const OUString
&aName
, const OUString
&aCaption
, bool bHasHiddenMember
, bool bDataLayout
, bool bPageDim
) :
97 mnDim(nDim
), mnHier(nHier
), mnLevel(nLevel
), mnDimPos(nDimPos
), mnSrcNumFmt(nSrcNumFmt
), maResult(aResult
),
98 maName(aName
), maCaption(aCaption
), mbHasHiddenMember(bHasHiddenMember
), mbDataLayout(bDataLayout
),
103 // bug (73840) in uno::Sequence - copy and then assign doesn't work!
109 struct ScDPOutLevelDataComparator
111 bool operator()(const ScDPOutLevelData
& rA
, const ScDPOutLevelData
& rB
)
113 return rA
.mnDimPos
<rB
.mnDimPos
|| ( rA
.mnDimPos
==rB
.mnDimPos
&& rA
.mnHier
<rB
.mnHier
) ||
114 ( rA
.mnDimPos
==rB
.mnDimPos
&& rA
.mnHier
==rB
.mnHier
&& rA
.mnLevel
<rB
.mnLevel
);
123 ::std::vector
< bool > mbNeedLineCols
;
124 ::std::vector
< SCCOL
> mnCols
;
126 ::std::vector
< bool > mbNeedLineRows
;
127 ::std::vector
< SCROW
> mnRows
;
132 SCCOL mnDataStartCol
;
133 SCROW mnDataStartRow
;
138 ScDPOutputImpl( ScDocument
* pDoc
, sal_uInt16 nTab
,
145 bool AddRow( SCROW nRow
);
146 bool AddCol( SCCOL nCol
);
148 void OutputDataArea();
149 void OutputBlockFrame ( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
, bool bHori
= false );
153 void ScDPOutputImpl::OutputDataArea()
155 AddRow( mnDataStartRow
);
156 AddCol( mnDataStartCol
);
158 mnCols
.push_back( mnTabEndCol
+1); //set last row bottom
159 mnRows
.push_back( mnTabEndRow
+1); //set last col bottom
161 bool bAllRows
= ( ( mnTabEndRow
- mnDataStartRow
+ 2 ) == static_cast<SCROW
>(mnRows
.size()) );
163 std::sort( mnCols
.begin(), mnCols
.end());
164 std::sort( mnRows
.begin(), mnRows
.end());
166 for( SCCOL nCol
= 0; nCol
< static_cast<SCCOL
>(mnCols
.size())-1; nCol
++ )
170 if ( nCol
< static_cast<SCCOL
>(mnCols
.size())-2)
172 for ( SCROW i
= nCol
%2; i
< static_cast<SCROW
>(mnRows
.size())-2; i
+=2 )
173 OutputBlockFrame( mnCols
[nCol
], mnRows
[i
], mnCols
[nCol
+1]-1, mnRows
[i
+1]-1 );
174 if ( mnRows
.size()>=2 )
175 OutputBlockFrame( mnCols
[nCol
], mnRows
[mnRows
.size()-2], mnCols
[nCol
+1]-1, mnRows
[mnRows
.size()-1]-1 );
179 for ( SCROW i
= 0 ; i
< static_cast<SCROW
>(mnRows
.size())-1; i
++ )
180 OutputBlockFrame( mnCols
[nCol
], mnRows
[i
], mnCols
[nCol
+1]-1, mnRows
[i
+1]-1 );
184 OutputBlockFrame( mnCols
[nCol
], mnRows
.front(), mnCols
[nCol
+1]-1, mnRows
.back()-1, bAllRows
);
186 //out put rows area outer framer
187 if ( mnTabStartCol
!= mnDataStartCol
)
189 if ( mnTabStartRow
!= mnDataStartRow
)
190 OutputBlockFrame( mnTabStartCol
, mnTabStartRow
, mnDataStartCol
-1, mnDataStartRow
-1 );
191 OutputBlockFrame( mnTabStartCol
, mnDataStartRow
, mnDataStartCol
-1, mnTabEndRow
);
193 //out put cols area outer framer
194 OutputBlockFrame( mnDataStartCol
, mnTabStartRow
, mnTabEndCol
, mnDataStartRow
-1 );
197 ScDPOutputImpl::ScDPOutputImpl( ScDocument
* pDoc
, sal_uInt16 nTab
,
206 mnTabStartCol( nTabStartCol
),
207 mnTabStartRow( nTabStartRow
),
208 mnDataStartCol ( nDataStartCol
),
209 mnDataStartRow ( nDataStartRow
),
210 mnTabEndCol( nTabEndCol
),
211 mnTabEndRow( nTabEndRow
)
213 mbNeedLineCols
.resize( nTabEndCol
-nDataStartCol
+1, false );
214 mbNeedLineRows
.resize( nTabEndRow
-nDataStartRow
+1, false );
218 bool ScDPOutputImpl::AddRow( SCROW nRow
)
220 if ( !mbNeedLineRows
[ nRow
- mnDataStartRow
] )
222 mbNeedLineRows
[ nRow
- mnDataStartRow
] = true;
223 mnRows
.push_back( nRow
);
230 bool ScDPOutputImpl::AddCol( SCCOL nCol
)
233 if ( !mbNeedLineCols
[ nCol
- mnDataStartCol
] )
235 mbNeedLineCols
[ nCol
- mnDataStartCol
] = true;
236 mnCols
.push_back( nCol
);
243 void ScDPOutputImpl::OutputBlockFrame ( SCCOL nStartCol
, SCROW nStartRow
, SCCOL nEndCol
, SCROW nEndRow
, bool bHori
)
245 Color color
= SC_DP_FRAME_COLOR
;
246 ::editeng::SvxBorderLine
aLine( &color
, SC_DP_FRAME_INNER_BOLD
);
247 ::editeng::SvxBorderLine
aOutLine( &color
, SC_DP_FRAME_OUTER_BOLD
);
249 SvxBoxItem
aBox( ATTR_BORDER
);
251 if ( nStartCol
== mnTabStartCol
)
252 aBox
.SetLine(&aOutLine
, SvxBoxItemLine::LEFT
);
254 aBox
.SetLine(&aLine
, SvxBoxItemLine::LEFT
);
256 if ( nStartRow
== mnTabStartRow
)
257 aBox
.SetLine(&aOutLine
, SvxBoxItemLine::TOP
);
259 aBox
.SetLine(&aLine
, SvxBoxItemLine::TOP
);
261 if ( nEndCol
== mnTabEndCol
) //bottom row
262 aBox
.SetLine(&aOutLine
, SvxBoxItemLine::RIGHT
);
264 aBox
.SetLine(&aLine
, SvxBoxItemLine::RIGHT
);
266 if ( nEndRow
== mnTabEndRow
) //bottom
267 aBox
.SetLine(&aOutLine
, SvxBoxItemLine::BOTTOM
);
269 aBox
.SetLine(&aLine
, SvxBoxItemLine::BOTTOM
);
271 SvxBoxInfoItem
aBoxInfo( ATTR_BORDER_INNER
);
272 aBoxInfo
.SetValid(SvxBoxInfoItemValidFlags::VERT
,false );
275 aBoxInfo
.SetValid(SvxBoxInfoItemValidFlags::HORI
);
276 aBoxInfo
.SetLine( &aLine
, SvxBoxInfoItemLine::HORI
);
279 aBoxInfo
.SetValid(SvxBoxInfoItemValidFlags::HORI
,false );
281 aBoxInfo
.SetValid(SvxBoxInfoItemValidFlags::DISTANCE
,false);
283 mpDoc
->ApplyFrameAreaTab(ScRange(nStartCol
, nStartRow
, mnTab
, nEndCol
, nEndRow
, mnTab
), aBox
, aBoxInfo
);
287 void lcl_SetStyleById(ScDocument
* pDoc
, SCTAB nTab
,
288 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
291 if ( nCol1
> nCol2
|| nRow1
> nRow2
)
293 OSL_FAIL("SetStyleById: invalid range");
297 OUString aStyleName
= ScResId(pStrId
);
298 ScStyleSheetPool
* pStlPool
= pDoc
->GetStyleSheetPool();
299 ScStyleSheet
* pStyle
= static_cast<ScStyleSheet
*>( pStlPool
->Find( aStyleName
, SfxStyleFamily::Para
) );
302 // create new style (was in ScPivot::SetStyle)
304 pStyle
= static_cast<ScStyleSheet
*>( &pStlPool
->Make( aStyleName
, SfxStyleFamily::Para
,
305 SfxStyleSearchBits::UserDefined
) );
306 pStyle
->SetParent( ScResId(STR_STYLENAME_STANDARD
) );
307 SfxItemSet
& rSet
= pStyle
->GetItemSet();
308 if (pStrId
== STR_PIVOT_STYLENAME_RESULT
|| pStrId
== STR_PIVOT_STYLENAME_TITLE
){
309 rSet
.Put( SvxWeightItem( WEIGHT_BOLD
, ATTR_FONT_WEIGHT
) );
310 rSet
.Put( SvxWeightItem( WEIGHT_BOLD
, ATTR_CJK_FONT_WEIGHT
) );
311 rSet
.Put( SvxWeightItem( WEIGHT_BOLD
, ATTR_CTL_FONT_WEIGHT
) );
313 if (pStrId
== STR_PIVOT_STYLENAME_CATEGORY
|| pStrId
== STR_PIVOT_STYLENAME_TITLE
)
314 rSet
.Put( SvxHorJustifyItem( SvxCellHorJustify::Left
, ATTR_HOR_JUSTIFY
) );
317 pDoc
->ApplyStyleAreaTab( nCol1
, nRow1
, nCol2
, nRow2
, nTab
, *pStyle
);
320 void lcl_SetFrame( ScDocument
* pDoc
, SCTAB nTab
,
321 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
,
324 ::editeng::SvxBorderLine
aLine(nullptr, nWidth
, SvxBorderLineStyle::SOLID
);
325 SvxBoxItem
aBox( ATTR_BORDER
);
326 aBox
.SetLine(&aLine
, SvxBoxItemLine::LEFT
);
327 aBox
.SetLine(&aLine
, SvxBoxItemLine::TOP
);
328 aBox
.SetLine(&aLine
, SvxBoxItemLine::RIGHT
);
329 aBox
.SetLine(&aLine
, SvxBoxItemLine::BOTTOM
);
330 SvxBoxInfoItem
aBoxInfo( ATTR_BORDER_INNER
);
331 aBoxInfo
.SetValid(SvxBoxInfoItemValidFlags::HORI
,false);
332 aBoxInfo
.SetValid(SvxBoxInfoItemValidFlags::VERT
,false);
333 aBoxInfo
.SetValid(SvxBoxInfoItemValidFlags::DISTANCE
,false);
335 pDoc
->ApplyFrameAreaTab(ScRange(nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
), aBox
, aBoxInfo
);
338 void lcl_FillNumberFormats( std::unique_ptr
<sal_uInt32
[]>& rFormats
, sal_Int32
& rCount
,
339 const uno::Reference
<sheet::XDataPilotMemberResults
>& xLevRes
,
340 const uno::Reference
<container::XIndexAccess
>& xDims
)
343 return; // already set
345 // xLevRes is from the data layout dimension
346 //TODO: use result sequence from ScDPOutLevelData!
348 uno::Sequence
<sheet::MemberResult
> aResult
= xLevRes
->getResults();
350 tools::Long nSize
= aResult
.getLength();
354 // get names/formats for all data dimensions
355 //TODO: merge this with the loop to collect ScDPOutLevelData?
357 std::vector
<OUString
> aDataNames
;
358 std::vector
<sal_uInt32
> aDataFormats
;
359 sal_Int32 nDimCount
= xDims
->getCount();
361 for ( ; nDim
< nDimCount
; nDim
++)
363 uno::Reference
<uno::XInterface
> xDim(xDims
->getByIndex(nDim
), uno::UNO_QUERY
);
364 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
365 uno::Reference
<container::XNamed
> xDimName( xDim
, uno::UNO_QUERY
);
366 if ( xDimProp
.is() && xDimName
.is() )
368 sheet::DataPilotFieldOrientation eDimOrient
=
369 ScUnoHelpFunctions::GetEnumProperty(
370 xDimProp
, SC_UNO_DP_ORIENTATION
,
371 sheet::DataPilotFieldOrientation_HIDDEN
);
372 if ( eDimOrient
== sheet::DataPilotFieldOrientation_DATA
)
374 aDataNames
.push_back(xDimName
->getName());
375 tools::Long nFormat
= ScUnoHelpFunctions::GetLongProperty(
378 aDataFormats
.push_back(nFormat
);
383 if (aDataFormats
.empty())
386 const sheet::MemberResult
* pArray
= aResult
.getConstArray();
389 sal_uInt32
* pNumFmt
= new sal_uInt32
[nSize
];
390 if (aDataFormats
.size() == 1)
392 // only one data dimension -> use its numberformat everywhere
393 tools::Long nFormat
= aDataFormats
[0];
394 for (tools::Long nPos
=0; nPos
<nSize
; nPos
++)
395 pNumFmt
[nPos
] = nFormat
;
399 for (tools::Long nPos
=0; nPos
<nSize
; nPos
++)
401 // if CONTINUE bit is set, keep previous name
402 //TODO: keep number format instead!
403 if ( !(pArray
[nPos
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
404 aName
= pArray
[nPos
].Name
;
406 sal_uInt32 nFormat
= 0;
407 for (size_t i
=0; i
<aDataFormats
.size(); i
++)
408 if (aName
== aDataNames
[i
]) //TODO: search more efficiently?
410 nFormat
= aDataFormats
[i
];
413 pNumFmt
[nPos
] = nFormat
;
417 rFormats
.reset( pNumFmt
);
421 sal_uInt32
lcl_GetFirstNumberFormat( const uno::Reference
<container::XIndexAccess
>& xDims
)
423 tools::Long nDimCount
= xDims
->getCount();
424 for (tools::Long nDim
=0; nDim
<nDimCount
; nDim
++)
426 uno::Reference
<beans::XPropertySet
> xDimProp(xDims
->getByIndex(nDim
), uno::UNO_QUERY
);
429 sheet::DataPilotFieldOrientation eDimOrient
=
430 ScUnoHelpFunctions::GetEnumProperty(
431 xDimProp
, SC_UNO_DP_ORIENTATION
,
432 sheet::DataPilotFieldOrientation_HIDDEN
);
433 if ( eDimOrient
== sheet::DataPilotFieldOrientation_DATA
)
435 tools::Long nFormat
= ScUnoHelpFunctions::GetLongProperty(
439 return nFormat
; // use format from first found data dimension
444 return 0; // none found
447 bool lcl_MemberEmpty( const uno::Sequence
<sheet::MemberResult
>& rSeq
)
449 // used to skip levels that have no members
451 return std::none_of(rSeq
.begin(), rSeq
.end(),
452 [](const sheet::MemberResult
& rMem
) {
453 return rMem
.Flags
& sheet::MemberResultFlags::HASMEMBER
; });
457 * Get visible page dimension members as results, except that, if all
458 * members are visible, then this function returns empty result.
460 uno::Sequence
<sheet::MemberResult
> getVisiblePageMembersAsResults( const uno::Reference
<uno::XInterface
>& xLevel
)
463 return uno::Sequence
<sheet::MemberResult
>();
465 uno::Reference
<sheet::XMembersSupplier
> xMSupplier(xLevel
, UNO_QUERY
);
466 if (!xMSupplier
.is())
467 return uno::Sequence
<sheet::MemberResult
>();
469 uno::Reference
<sheet::XMembersAccess
> xNA
= xMSupplier
->getMembers();
471 return uno::Sequence
<sheet::MemberResult
>();
473 std::vector
<sheet::MemberResult
> aRes
;
474 const uno::Sequence
<OUString
> aNames
= xNA
->getElementNames();
475 for (const OUString
& rName
: aNames
)
477 xNA
->getByName(rName
);
479 uno::Reference
<beans::XPropertySet
> xMemPS(xNA
->getByName(rName
), UNO_QUERY
);
483 OUString aCaption
= ScUnoHelpFunctions::GetStringProperty(xMemPS
, SC_UNO_DP_LAYOUTNAME
, OUString());
484 if (aCaption
.isEmpty())
487 bool bVisible
= ScUnoHelpFunctions::GetBoolProperty(xMemPS
, SC_UNO_DP_ISVISIBLE
);
491 /* TODO: any numeric value to obtain? */
492 aRes
.emplace_back(rName
, aCaption
, 0, std::numeric_limits
<double>::quiet_NaN());
496 if (aNames
.getLength() == static_cast<sal_Int32
>(aRes
.size()))
497 // All members are visible. Return empty result.
498 return uno::Sequence
<sheet::MemberResult
>();
500 return ScUnoHelpFunctions::VectorToSequence(aRes
);
505 ScDPOutput::ScDPOutput( ScDocument
* pD
, const uno::Reference
<sheet::XDimensionsSupplier
>& xSrc
,
506 const ScAddress
& rPos
, bool bFilter
) :
517 bResultsError(false),
519 bSizeOverflow(false),
520 mbHeaderLayout(false)
522 nTabStartCol
= nMemberStartCol
= nDataStartCol
= nTabEndCol
= 0;
523 nTabStartRow
= nMemberStartRow
= nDataStartRow
= nTabEndRow
= 0;
525 uno::Reference
<sheet::XDataPilotResults
> xResult( xSource
, uno::UNO_QUERY
);
526 if ( xSource
.is() && xResult
.is() )
528 // get dimension results:
530 uno::Reference
<container::XIndexAccess
> xDims
=
531 new ScNameToIndexAccess( xSource
->getDimensions() );
532 tools::Long nDimCount
= xDims
->getCount();
533 for (tools::Long nDim
=0; nDim
<nDimCount
; nDim
++)
535 uno::Reference
<uno::XInterface
> xDim(xDims
->getByIndex(nDim
), uno::UNO_QUERY
);
536 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
537 uno::Reference
<sheet::XHierarchiesSupplier
> xDimSupp( xDim
, uno::UNO_QUERY
);
538 if ( xDimProp
.is() && xDimSupp
.is() )
540 sheet::DataPilotFieldOrientation eDimOrient
=
541 ScUnoHelpFunctions::GetEnumProperty(
542 xDimProp
, SC_UNO_DP_ORIENTATION
,
543 sheet::DataPilotFieldOrientation_HIDDEN
);
544 tools::Long nDimPos
= ScUnoHelpFunctions::GetLongProperty( xDimProp
,
545 SC_UNO_DP_POSITION
);
546 bool bIsDataLayout
= ScUnoHelpFunctions::GetBoolProperty(
547 xDimProp
, SC_UNO_DP_ISDATALAYOUT
);
548 bool bHasHiddenMember
= ScUnoHelpFunctions::GetBoolProperty(
549 xDimProp
, SC_UNO_DP_HAS_HIDDEN_MEMBER
);
550 sal_Int32 nNumFmt
= ScUnoHelpFunctions::GetLongProperty(
551 xDimProp
, SC_UNO_DP_NUMBERFO
);
553 if ( eDimOrient
!= sheet::DataPilotFieldOrientation_HIDDEN
)
555 uno::Reference
<container::XIndexAccess
> xHiers
=
556 new ScNameToIndexAccess( xDimSupp
->getHierarchies() );
557 tools::Long nHierarchy
= ScUnoHelpFunctions::GetLongProperty(
559 SC_UNO_DP_USEDHIERARCHY
);
560 if ( nHierarchy
>= xHiers
->getCount() )
563 uno::Reference
<sheet::XLevelsSupplier
> xHierSupp(xHiers
->getByIndex(nHierarchy
),
565 if ( xHierSupp
.is() )
567 uno::Reference
<container::XIndexAccess
> xLevels
=
568 new ScNameToIndexAccess( xHierSupp
->getLevels() );
569 tools::Long nLevCount
= xLevels
->getCount();
570 for (tools::Long nLev
=0; nLev
<nLevCount
; nLev
++)
572 uno::Reference
<uno::XInterface
> xLevel(xLevels
->getByIndex(nLev
),
574 uno::Reference
<container::XNamed
> xLevNam( xLevel
, uno::UNO_QUERY
);
575 uno::Reference
<sheet::XDataPilotMemberResults
> xLevRes(
576 xLevel
, uno::UNO_QUERY
);
577 if ( xLevNam
.is() && xLevRes
.is() )
579 OUString aName
= xLevNam
->getName();
580 Reference
<XPropertySet
> xPropSet(xLevel
, UNO_QUERY
);
581 // Caption equals the field name by default.
582 // #i108948# use ScUnoHelpFunctions::GetStringProperty, because
583 // LayoutName is new and may not be present in external implementation
584 OUString aCaption
= ScUnoHelpFunctions::GetStringProperty( xPropSet
,
585 SC_UNO_DP_LAYOUTNAME
, aName
);
587 switch ( eDimOrient
)
589 case sheet::DataPilotFieldOrientation_COLUMN
:
591 uno::Sequence
<sheet::MemberResult
> aResult
= xLevRes
->getResults();
592 if (!lcl_MemberEmpty(aResult
))
594 ScDPOutLevelData
tmp(nDim
, nHierarchy
, nLev
, nDimPos
, nNumFmt
, aResult
, aName
,
595 aCaption
, bHasHiddenMember
, bIsDataLayout
, false);
596 pColFields
.push_back(tmp
);
600 case sheet::DataPilotFieldOrientation_ROW
:
602 uno::Sequence
<sheet::MemberResult
> aResult
= xLevRes
->getResults();
603 // We want only to remove the DATA column if it is empty
604 // and not any other empty columns (to still show the
606 bool bSkip
= lcl_MemberEmpty(aResult
) && bIsDataLayout
;
609 ScDPOutLevelData
tmp(nDim
, nHierarchy
, nLev
, nDimPos
, nNumFmt
, aResult
, aName
,
610 aCaption
, bHasHiddenMember
, bIsDataLayout
, false);
611 pRowFields
.push_back(tmp
);
615 case sheet::DataPilotFieldOrientation_PAGE
:
617 uno::Sequence
<sheet::MemberResult
> aResult
= getVisiblePageMembersAsResults(xLevel
);
618 // no check on results for page fields
619 ScDPOutLevelData
tmp(nDim
, nHierarchy
, nLev
, nDimPos
, nNumFmt
, aResult
, aName
,
620 aCaption
, bHasHiddenMember
, false, true);
621 pPageFields
.push_back(tmp
);
626 // added to avoid warnings
630 // get number formats from data dimensions
633 OSL_ENSURE( nLevCount
== 1, "data layout: multiple levels?" );
634 if ( eDimOrient
== sheet::DataPilotFieldOrientation_COLUMN
)
635 lcl_FillNumberFormats( pColNumFmt
, nColFmtCount
, xLevRes
, xDims
);
636 else if ( eDimOrient
== sheet::DataPilotFieldOrientation_ROW
)
637 lcl_FillNumberFormats( pRowNumFmt
, nRowFmtCount
, xLevRes
, xDims
);
643 else if ( bIsDataLayout
)
645 // data layout dimension is hidden (allowed if there is only one data dimension)
646 // -> use the number format from the first data dimension for all results
648 nSingleNumFmt
= lcl_GetFirstNumberFormat( xDims
);
652 std::sort(pColFields
.begin(), pColFields
.end(), ScDPOutLevelDataComparator());
653 std::sort(pRowFields
.begin(), pRowFields
.end(), ScDPOutLevelDataComparator());
654 std::sort(pPageFields
.begin(), pPageFields
.end(), ScDPOutLevelDataComparator());
660 aData
= xResult
->getResults();
662 catch (const uno::RuntimeException
&)
664 bResultsError
= true;
668 // get "DataDescription" property (may be missing in external sources)
670 uno::Reference
<beans::XPropertySet
> xSrcProp( xSource
, uno::UNO_QUERY
);
671 if ( !xSrcProp
.is() )
676 uno::Any aAny
= xSrcProp
->getPropertyValue( SC_UNO_DP_DATADESC
);
679 aDataDescription
= aUStr
;
681 catch(const uno::Exception
&)
686 ScDPOutput::~ScDPOutput()
690 void ScDPOutput::SetPosition( const ScAddress
& rPos
)
693 bSizesValid
= bSizeOverflow
= false;
696 void ScDPOutput::DataCell( SCCOL nCol
, SCROW nRow
, SCTAB nTab
, const sheet::DataResult
& rData
)
698 tools::Long nFlags
= rData
.Flags
;
699 if ( nFlags
& sheet::DataResultFlags::ERROR
)
701 pDoc
->SetError( nCol
, nRow
, nTab
, FormulaError::NoValue
);
703 else if ( nFlags
& sheet::DataResultFlags::HASDATA
)
705 pDoc
->SetValue( nCol
, nRow
, nTab
, rData
.Value
);
707 // use number formats from source
709 OSL_ENSURE( bSizesValid
, "DataCell: !bSizesValid" );
710 sal_uInt32 nFormat
= 0;
711 bool bApplyFormat
= false;
714 if ( nCol
>= nDataStartCol
)
716 tools::Long nIndex
= nCol
- nDataStartCol
;
717 if ( nIndex
< nColFmtCount
)
719 nFormat
= pColNumFmt
[nIndex
];
724 else if ( pRowNumFmt
)
726 if ( nRow
>= nDataStartRow
)
728 tools::Long nIndex
= nRow
- nDataStartRow
;
729 if ( nIndex
< nRowFmtCount
)
731 nFormat
= pRowNumFmt
[nIndex
];
736 else if ( nSingleNumFmt
!= 0 )
738 nFormat
= nSingleNumFmt
; // single format is used everywhere
743 pDoc
->ApplyAttr(nCol
, nRow
, nTab
, SfxUInt32Item(ATTR_VALUE_FORMAT
, nFormat
));
745 // SubTotal formatting is controlled by headers
748 void ScDPOutput::HeaderCell( SCCOL nCol
, SCROW nRow
, SCTAB nTab
,
749 const sheet::MemberResult
& rData
, bool bColHeader
, tools::Long nLevel
)
751 tools::Long nFlags
= rData
.Flags
;
753 if ( nFlags
& sheet::MemberResultFlags::HASMEMBER
)
755 bool bNumeric
= (nFlags
& sheet::MemberResultFlags::NUMERIC
) != 0;
756 if (bNumeric
&& std::isfinite( rData
.Value
))
758 pDoc
->SetValue( nCol
, nRow
, nTab
, rData
.Value
);
762 ScSetStringParam aParam
;
764 aParam
.setNumericInput();
766 aParam
.setTextInput();
768 pDoc
->SetString(nCol
, nRow
, nTab
, rData
.Caption
, &aParam
);
772 if ( !(nFlags
& sheet::MemberResultFlags::SUBTOTAL
) )
775 ScDPOutputImpl
outputimp( pDoc
, nTab
,
776 nTabStartCol
, nTabStartRow
,
777 nDataStartCol
, nDataStartRow
, nTabEndCol
, nTabEndRow
);
778 //TODO: limit frames to horizontal or vertical?
781 outputimp
.OutputBlockFrame( nCol
,nMemberStartRow
+static_cast<SCROW
>(nLevel
), nCol
,nDataStartRow
-1 );
783 lcl_SetStyleById( pDoc
,nTab
, nCol
,nMemberStartRow
+static_cast<SCROW
>(nLevel
), nCol
,nDataStartRow
-1,
784 STR_PIVOT_STYLENAME_TITLE
);
785 lcl_SetStyleById( pDoc
,nTab
, nCol
,nDataStartRow
, nCol
,nTabEndRow
,
786 STR_PIVOT_STYLENAME_RESULT
);
790 outputimp
.OutputBlockFrame( nMemberStartCol
+static_cast<SCCOL
>(nLevel
),nRow
, nDataStartCol
-1,nRow
);
791 lcl_SetStyleById( pDoc
,nTab
, nMemberStartCol
+static_cast<SCCOL
>(nLevel
),nRow
, nDataStartCol
-1,nRow
,
792 STR_PIVOT_STYLENAME_TITLE
);
793 lcl_SetStyleById( pDoc
,nTab
, nDataStartCol
,nRow
, nTabEndCol
,nRow
,
794 STR_PIVOT_STYLENAME_RESULT
);
798 void ScDPOutput::FieldCell(
799 SCCOL nCol
, SCROW nRow
, SCTAB nTab
, const ScDPOutLevelData
& rData
, bool bInTable
)
801 // Avoid unwanted automatic format detection.
802 ScSetStringParam aParam
;
803 aParam
.mbDetectNumberFormat
= false;
804 aParam
.meSetTextNumFormat
= ScSetStringParam::Always
;
805 aParam
.mbHandleApostrophe
= false;
806 pDoc
->SetString(nCol
, nRow
, nTab
, rData
.maCaption
, &aParam
);
809 lcl_SetFrame( pDoc
,nTab
, nCol
,nRow
, nCol
,nRow
, 20 );
811 // For field button drawing
812 ScMF nMergeFlag
= ScMF::NONE
;
813 if (rData
.mbHasHiddenMember
)
814 nMergeFlag
|= ScMF::HiddenMember
;
818 nMergeFlag
|= ScMF::ButtonPopup
;
819 pDoc
->ApplyFlagsTab(nCol
, nRow
, nCol
, nRow
, nTab
, ScMF::Button
);
820 pDoc
->ApplyFlagsTab(nCol
+1, nRow
, nCol
+1, nRow
, nTab
, nMergeFlag
);
824 nMergeFlag
|= ScMF::Button
;
825 if (!rData
.mbDataLayout
)
826 nMergeFlag
|= ScMF::ButtonPopup
;
827 pDoc
->ApplyFlagsTab(nCol
, nRow
, nCol
, nRow
, nTab
, nMergeFlag
);
830 lcl_SetStyleById( pDoc
,nTab
, nCol
,nRow
, nCol
,nRow
, STR_PIVOT_STYLENAME_FIELDNAME
);
833 static void lcl_DoFilterButton( ScDocument
* pDoc
, SCCOL nCol
, SCROW nRow
, SCTAB nTab
)
835 pDoc
->SetString( nCol
, nRow
, nTab
, ScResId(STR_CELL_FILTER
) );
836 pDoc
->ApplyFlagsTab(nCol
, nRow
, nCol
, nRow
, nTab
, ScMF::Button
);
839 void ScDPOutput::CalcSizes()
844 // get column size of data from first row
845 //TODO: allow different sizes (and clear following areas) ???
847 nRowCount
= aData
.getLength();
848 const uno::Sequence
<sheet::DataResult
>* pRowAry
= aData
.getConstArray();
849 nColCount
= nRowCount
? ( pRowAry
[0].getLength() ) : 0;
852 if (GetHeaderLayout() && pColFields
.empty())
853 // Insert an extra header row only when there is no column field.
856 // calculate output positions and sizes
858 tools::Long nPageSize
= 0; // use page fields!
859 if ( bDoFilter
|| !pPageFields
.empty() )
861 nPageSize
+= pPageFields
.size() + 1; // plus one empty row
863 ++nPageSize
; // filter button above the page fields
866 if ( aStartPos
.Col() + static_cast<tools::Long
>(pRowFields
.size()) + nColCount
- 1 > MAXCOL
||
867 aStartPos
.Row() + nPageSize
+ nHeaderSize
+ pColFields
.size() + nRowCount
> MAXROW
)
869 bSizeOverflow
= true;
872 nTabStartCol
= aStartPos
.Col();
873 nTabStartRow
= aStartPos
.Row() + static_cast<SCROW
>(nPageSize
); // below page fields
874 nMemberStartCol
= nTabStartCol
;
875 nMemberStartRow
= nTabStartRow
+ static_cast<SCROW
>(nHeaderSize
);
876 nDataStartCol
= nMemberStartCol
+ static_cast<SCCOL
>(pRowFields
.size());
877 nDataStartRow
= nMemberStartRow
+ static_cast<SCROW
>(pColFields
.size());
879 nTabEndCol
= nDataStartCol
+ static_cast<SCCOL
>(nColCount
) - 1;
881 nTabEndCol
= nDataStartCol
; // single column will remain empty
882 // if page fields are involved, include the page selection cells
883 if ( !pPageFields
.empty() && nTabEndCol
< nTabStartCol
+ 1 )
884 nTabEndCol
= nTabStartCol
+ 1;
886 nTabEndRow
= nDataStartRow
+ static_cast<SCROW
>(nRowCount
) - 1;
888 nTabEndRow
= nDataStartRow
; // single row will remain empty
892 sal_Int32
ScDPOutput::GetPositionType(const ScAddress
& rPos
)
894 using namespace ::com::sun::star::sheet
;
896 SCCOL nCol
= rPos
.Col();
897 SCROW nRow
= rPos
.Row();
898 SCTAB nTab
= rPos
.Tab();
899 if ( nTab
!= aStartPos
.Tab() )
900 return DataPilotTablePositionType::NOT_IN_TABLE
;
904 // Make sure the cursor is within the table.
905 if (nCol
< nTabStartCol
|| nRow
< nTabStartRow
|| nCol
> nTabEndCol
|| nRow
> nTabEndRow
)
906 return DataPilotTablePositionType::NOT_IN_TABLE
;
908 // test for result data area.
909 if (nCol
>= nDataStartCol
&& nCol
<= nTabEndCol
&& nRow
>= nDataStartRow
&& nRow
<= nTabEndRow
)
910 return DataPilotTablePositionType::RESULT
;
912 bool bInColHeader
= (nRow
>= nTabStartRow
&& nRow
< nDataStartRow
);
913 bool bInRowHeader
= (nCol
>= nTabStartCol
&& nCol
< nDataStartCol
);
915 if (bInColHeader
&& bInRowHeader
)
916 // probably in that ugly little box at the upper-left corner of the table.
917 return DataPilotTablePositionType::OTHER
;
921 if (nRow
== nTabStartRow
)
922 // first row in the column header area is always used for column
924 return DataPilotTablePositionType::OTHER
;
926 return DataPilotTablePositionType::COLUMN_HEADER
;
930 return DataPilotTablePositionType::ROW_HEADER
;
932 return DataPilotTablePositionType::OTHER
;
935 void ScDPOutput::Output()
937 SCTAB nTab
= aStartPos
.Tab();
938 const uno::Sequence
<sheet::DataResult
>* pRowAry
= aData
.getConstArray();
940 // calculate output positions and sizes
943 if ( bSizeOverflow
|| bResultsError
) // does output area exceed sheet limits?
946 // clear whole (new) output area
947 // when modifying table, clear old area !
948 //TODO: include InsertDeleteFlags::OBJECTS ???
949 pDoc
->DeleteAreaTab( aStartPos
.Col(), aStartPos
.Row(), nTabEndCol
, nTabEndRow
, nTab
, InsertDeleteFlags::ALL
);
952 lcl_DoFilterButton( pDoc
, aStartPos
.Col(), aStartPos
.Row(), nTab
);
954 // output page fields:
956 for (size_t nField
=0; nField
<pPageFields
.size(); ++nField
)
958 SCCOL nHdrCol
= aStartPos
.Col();
959 SCROW nHdrRow
= aStartPos
.Row() + nField
+ ( bDoFilter
? 1 : 0 );
960 // draw without frame for consistency with filter button:
961 FieldCell(nHdrCol
, nHdrRow
, nTab
, pPageFields
[nField
], false);
962 SCCOL nFldCol
= nHdrCol
+ 1;
964 OUString aPageValue
= ScResId(SCSTR_ALL
);
965 const uno::Sequence
<sheet::MemberResult
>& rRes
= pPageFields
[nField
].maResult
;
966 sal_Int32 n
= rRes
.getLength();
969 if (rRes
[0].Caption
.isEmpty())
970 aPageValue
= ScResId(STR_EMPTYDATA
);
972 aPageValue
= rRes
[0].Caption
;
975 aPageValue
= ScResId(SCSTR_MULTIPLE
);
977 ScSetStringParam aParam
;
978 aParam
.setTextInput();
979 pDoc
->SetString(nFldCol
, nHdrRow
, nTab
, aPageValue
, &aParam
);
981 lcl_SetFrame( pDoc
,nTab
, nFldCol
,nHdrRow
, nFldCol
,nHdrRow
, 20 );
985 // (may get overwritten by first row field)
987 if (aDataDescription
.isEmpty())
989 //TODO: use default string ("result") ?
991 pDoc
->SetString(nTabStartCol
, nTabStartRow
, nTab
, aDataDescription
);
993 // set STR_PIVOT_STYLENAME_INNER for whole data area (subtotals are overwritten)
995 if ( nDataStartRow
> nTabStartRow
)
996 lcl_SetStyleById( pDoc
, nTab
, nTabStartCol
, nTabStartRow
, nTabEndCol
, nDataStartRow
-1,
997 STR_PIVOT_STYLENAME_TOP
);
998 lcl_SetStyleById( pDoc
, nTab
, nDataStartCol
, nDataStartRow
, nTabEndCol
, nTabEndRow
,
999 STR_PIVOT_STYLENAME_INNER
);
1001 // output column headers:
1002 ScDPOutputImpl
outputimp( pDoc
, nTab
,
1003 nTabStartCol
, nTabStartRow
,
1004 nDataStartCol
, nDataStartRow
, nTabEndCol
, nTabEndRow
);
1005 for (size_t nField
=0; nField
<pColFields
.size(); nField
++)
1007 SCCOL nHdrCol
= nDataStartCol
+ static_cast<SCCOL
>(nField
); //TODO: check for overflow
1008 FieldCell(nHdrCol
, nTabStartRow
, nTab
, pColFields
[nField
], true);
1010 SCROW nRowPos
= nMemberStartRow
+ static_cast<SCROW
>(nField
); //TODO: check for overflow
1011 const uno::Sequence
<sheet::MemberResult
> rSequence
= pColFields
[nField
].maResult
;
1012 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1013 tools::Long nThisColCount
= rSequence
.getLength();
1014 OSL_ENSURE( nThisColCount
== nColCount
, "count mismatch" ); //TODO: ???
1015 for (tools::Long nCol
=0; nCol
<nThisColCount
; nCol
++)
1017 SCCOL nColPos
= nDataStartCol
+ static_cast<SCCOL
>(nCol
); //TODO: check for overflow
1018 HeaderCell( nColPos
, nRowPos
, nTab
, pArray
[nCol
], true, nField
);
1019 if ( ( pArray
[nCol
].Flags
& sheet::MemberResultFlags::HASMEMBER
) &&
1020 !( pArray
[nCol
].Flags
& sheet::MemberResultFlags::SUBTOTAL
) )
1022 tools::Long nEnd
= nCol
;
1023 while ( nEnd
+1 < nThisColCount
&& ( pArray
[nEnd
+1].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1025 SCCOL nEndColPos
= nDataStartCol
+ static_cast<SCCOL
>(nEnd
); //TODO: check for overflow
1026 if ( nField
+1 < pColFields
.size())
1028 if ( nField
== pColFields
.size() - 2 )
1030 outputimp
.AddCol( nColPos
);
1031 if ( nColPos
+ 1 == nEndColPos
)
1032 outputimp
.OutputBlockFrame( nColPos
,nRowPos
, nEndColPos
,nRowPos
+1, true );
1035 outputimp
.OutputBlockFrame( nColPos
,nRowPos
, nEndColPos
,nRowPos
);
1037 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nEndColPos
,nDataStartRow
-1, STR_PIVOT_STYLENAME_CATEGORY
);
1040 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nColPos
,nDataStartRow
-1, STR_PIVOT_STYLENAME_CATEGORY
);
1042 else if ( pArray
[nCol
].Flags
& sheet::MemberResultFlags::SUBTOTAL
)
1043 outputimp
.AddCol( nColPos
);
1045 // Apply the same number format as in data source.
1046 pDoc
->ApplyAttr(nColPos
, nRowPos
, nTab
, SfxUInt32Item(ATTR_VALUE_FORMAT
, pColFields
[nField
].mnSrcNumFmt
));
1048 if ( nField
== 0 && pColFields
.size() == 1 )
1049 outputimp
.OutputBlockFrame( nDataStartCol
,nTabStartRow
, nTabEndCol
,nRowPos
-1 );
1052 // output row headers:
1053 std::vector
<bool> vbSetBorder
;
1054 vbSetBorder
.resize( nTabEndRow
- nDataStartRow
+ 1, false );
1055 for (size_t nField
=0; nField
<pRowFields
.size(); nField
++)
1057 SCCOL nHdrCol
= nTabStartCol
+ static_cast<SCCOL
>(nField
); //TODO: check for overflow
1058 SCROW nHdrRow
= nDataStartRow
- 1;
1059 FieldCell(nHdrCol
, nHdrRow
, nTab
, pRowFields
[nField
], true);
1061 SCCOL nColPos
= nMemberStartCol
+ static_cast<SCCOL
>(nField
); //TODO: check for overflow
1062 const uno::Sequence
<sheet::MemberResult
> rSequence
= pRowFields
[nField
].maResult
;
1063 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1064 sal_Int32 nThisRowCount
= rSequence
.getLength();
1065 OSL_ENSURE( nThisRowCount
== nRowCount
, "count mismatch" ); //TODO: ???
1066 for (sal_Int32 nRow
=0; nRow
<nThisRowCount
; nRow
++)
1068 SCROW nRowPos
= nDataStartRow
+ static_cast<SCROW
>(nRow
); //TODO: check for overflow
1069 HeaderCell( nColPos
, nRowPos
, nTab
, pArray
[nRow
], false, nField
);
1070 if ( ( pArray
[nRow
].Flags
& sheet::MemberResultFlags::HASMEMBER
) &&
1071 !( pArray
[nRow
].Flags
& sheet::MemberResultFlags::SUBTOTAL
) )
1073 if ( nField
+1 < pRowFields
.size() )
1075 tools::Long nEnd
= nRow
;
1076 while ( nEnd
+1 < nThisRowCount
&& ( pArray
[nEnd
+1].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1078 SCROW nEndRowPos
= nDataStartRow
+ static_cast<SCROW
>(nEnd
); //TODO: check for overflow
1079 outputimp
.AddRow( nRowPos
);
1080 if ( !vbSetBorder
[ nRow
] )
1082 outputimp
.OutputBlockFrame( nColPos
, nRowPos
, nTabEndCol
, nEndRowPos
);
1083 vbSetBorder
[ nRow
] = true;
1085 outputimp
.OutputBlockFrame( nColPos
, nRowPos
, nColPos
, nEndRowPos
);
1087 if ( nField
== pRowFields
.size() - 2 )
1088 outputimp
.OutputBlockFrame( nColPos
+1, nRowPos
, nColPos
+1, nEndRowPos
);
1090 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nDataStartCol
-1,nEndRowPos
, STR_PIVOT_STYLENAME_CATEGORY
);
1093 lcl_SetStyleById( pDoc
, nTab
, nColPos
,nRowPos
, nDataStartCol
-1,nRowPos
, STR_PIVOT_STYLENAME_CATEGORY
);
1095 else if ( pArray
[nRow
].Flags
& sheet::MemberResultFlags::SUBTOTAL
)
1096 outputimp
.AddRow( nRowPos
);
1098 // Apply the same number format as in data source.
1099 pDoc
->ApplyAttr(nColPos
, nRowPos
, nTab
, SfxUInt32Item(ATTR_VALUE_FORMAT
, pRowFields
[nField
].mnSrcNumFmt
));
1103 if (nColCount
== 1 && nRowCount
> 0 && pColFields
.empty())
1105 // the table contains exactly one data field and no column fields.
1106 // Display data description at top right corner.
1107 ScSetStringParam aParam
;
1108 aParam
.setTextInput();
1109 pDoc
->SetString(nDataStartCol
, nDataStartRow
-1, nTab
, aDataDescription
, &aParam
);
1112 // output data results:
1114 for (sal_Int32 nRow
=0; nRow
<nRowCount
; nRow
++)
1116 SCROW nRowPos
= nDataStartRow
+ static_cast<SCROW
>(nRow
); //TODO: check for overflow
1117 const sheet::DataResult
* pColAry
= pRowAry
[nRow
].getConstArray();
1118 sal_Int32 nThisColCount
= pRowAry
[nRow
].getLength();
1119 OSL_ENSURE( nThisColCount
== nColCount
, "count mismatch" ); //TODO: ???
1120 for (sal_Int32 nCol
=0; nCol
<nThisColCount
; nCol
++)
1122 SCCOL nColPos
= nDataStartCol
+ static_cast<SCCOL
>(nCol
); //TODO: check for overflow
1123 DataCell( nColPos
, nRowPos
, nTab
, pColAry
[nCol
] );
1127 outputimp
.OutputDataArea();
1130 ScRange
ScDPOutput::GetOutputRange( sal_Int32 nRegionType
)
1132 using namespace ::com::sun::star::sheet
;
1136 SCTAB nTab
= aStartPos
.Tab();
1137 switch (nRegionType
)
1139 case DataPilotOutputRangeType::RESULT
:
1140 return ScRange(nDataStartCol
, nDataStartRow
, nTab
, nTabEndCol
, nTabEndRow
, nTab
);
1141 case DataPilotOutputRangeType::TABLE
:
1142 return ScRange(aStartPos
.Col(), nTabStartRow
, nTab
, nTabEndCol
, nTabEndRow
, nTab
);
1144 OSL_ENSURE(nRegionType
== DataPilotOutputRangeType::WHOLE
, "ScDPOutput::GetOutputRange: unknown region type");
1147 return ScRange(aStartPos
.Col(), aStartPos
.Row(), nTab
, nTabEndCol
, nTabEndRow
, nTab
);
1150 bool ScDPOutput::HasError()
1154 return bSizeOverflow
|| bResultsError
;
1157 sal_Int32
ScDPOutput::GetHeaderRows() const
1159 return pPageFields
.size() + ( bDoFilter
? 1 : 0 );
1164 void insertNames(ScDPUniqueStringSet
& rNames
, const uno::Sequence
<sheet::MemberResult
>& rMemberResults
)
1166 for (const sheet::MemberResult
& rMemberResult
: rMemberResults
)
1168 if (rMemberResult
.Flags
& sheet::MemberResultFlags::HASMEMBER
)
1169 rNames
.insert(rMemberResult
.Name
);
1174 void ScDPOutput::GetMemberResultNames(ScDPUniqueStringSet
& rNames
, tools::Long nDimension
)
1176 // Return the list of all member names in a dimension's MemberResults.
1177 // Only the dimension has to be compared because this is only used with table data,
1178 // where each dimension occurs only once.
1180 auto lFindDimension
= [nDimension
](const ScDPOutLevelData
& rField
) { return rField
.mnDim
== nDimension
; };
1182 // look in column fields
1183 auto colit
= std::find_if(pColFields
.begin(), pColFields
.end(), lFindDimension
);
1184 if (colit
!= pColFields
.end())
1186 // collect the member names
1187 insertNames(rNames
, colit
->maResult
);
1191 // look in row fields
1192 auto rowit
= std::find_if(pRowFields
.begin(), pRowFields
.end(), lFindDimension
);
1193 if (rowit
!= pRowFields
.end())
1195 // collect the member names
1196 insertNames(rNames
, rowit
->maResult
);
1200 void ScDPOutput::SetHeaderLayout(bool bUseGrid
)
1202 mbHeaderLayout
= bUseGrid
;
1203 bSizesValid
= false;
1208 void lcl_GetTableVars( sal_Int32
& rGrandTotalCols
, sal_Int32
& rGrandTotalRows
, sal_Int32
& rDataLayoutIndex
,
1209 std::vector
<OUString
>& rDataNames
, std::vector
<OUString
>& rGivenNames
,
1210 sheet::DataPilotFieldOrientation
& rDataOrient
,
1211 const uno::Reference
<sheet::XDimensionsSupplier
>& xSource
)
1213 rDataLayoutIndex
= -1; // invalid
1214 rGrandTotalCols
= 0;
1215 rGrandTotalRows
= 0;
1216 rDataOrient
= sheet::DataPilotFieldOrientation_HIDDEN
;
1218 uno::Reference
<beans::XPropertySet
> xSrcProp( xSource
, uno::UNO_QUERY
);
1219 bool bColGrand
= ScUnoHelpFunctions::GetBoolProperty(
1220 xSrcProp
, SC_UNO_DP_COLGRAND
);
1222 rGrandTotalCols
= 1; // default if data layout not in columns
1224 bool bRowGrand
= ScUnoHelpFunctions::GetBoolProperty(
1225 xSrcProp
, SC_UNO_DP_ROWGRAND
);
1227 rGrandTotalRows
= 1; // default if data layout not in rows
1229 if ( !xSource
.is() )
1232 // find index and orientation of "data layout" dimension, count data dimensions
1234 sal_Int32 nDataCount
= 0;
1236 uno::Reference
<container::XIndexAccess
> xDims
= new ScNameToIndexAccess( xSource
->getDimensions() );
1237 tools::Long nDimCount
= xDims
->getCount();
1238 for (tools::Long nDim
=0; nDim
<nDimCount
; nDim
++)
1240 uno::Reference
<uno::XInterface
> xDim(xDims
->getByIndex(nDim
), uno::UNO_QUERY
);
1241 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
1242 if ( xDimProp
.is() )
1244 sheet::DataPilotFieldOrientation eDimOrient
=
1245 ScUnoHelpFunctions::GetEnumProperty(
1246 xDimProp
, SC_UNO_DP_ORIENTATION
,
1247 sheet::DataPilotFieldOrientation_HIDDEN
);
1248 if ( ScUnoHelpFunctions::GetBoolProperty( xDimProp
,
1249 SC_UNO_DP_ISDATALAYOUT
) )
1251 rDataLayoutIndex
= nDim
;
1252 rDataOrient
= eDimOrient
;
1254 if ( eDimOrient
== sheet::DataPilotFieldOrientation_DATA
)
1256 OUString aSourceName
;
1257 OUString aGivenName
;
1258 ScDPOutput::GetDataDimensionNames( aSourceName
, aGivenName
, xDim
);
1261 uno::Any aValue
= xDimProp
->getPropertyValue( SC_UNO_DP_LAYOUTNAME
);
1263 if( aValue
.hasValue() )
1265 OUString strLayoutName
;
1267 if( ( aValue
>>= strLayoutName
) && !strLayoutName
.isEmpty() )
1268 aGivenName
= strLayoutName
;
1271 catch(const uno::Exception
&)
1274 rDataNames
.push_back( aSourceName
);
1275 rGivenNames
.push_back( aGivenName
);
1282 if ( ( rDataOrient
== sheet::DataPilotFieldOrientation_COLUMN
) && bColGrand
)
1283 rGrandTotalCols
= nDataCount
;
1284 else if ( ( rDataOrient
== sheet::DataPilotFieldOrientation_ROW
) && bRowGrand
)
1285 rGrandTotalRows
= nDataCount
;
1290 void ScDPOutput::GetPositionData(const ScAddress
& rPos
, DataPilotTablePositionData
& rPosData
)
1292 using namespace ::com::sun::star::sheet
;
1294 SCCOL nCol
= rPos
.Col();
1295 SCROW nRow
= rPos
.Row();
1296 SCTAB nTab
= rPos
.Tab();
1297 if ( nTab
!= aStartPos
.Tab() )
1298 return; // wrong sheet
1300 // calculate output positions and sizes
1304 rPosData
.PositionType
= GetPositionType(rPos
);
1305 switch (rPosData
.PositionType
)
1307 case DataPilotTablePositionType::RESULT
:
1309 vector
<DataPilotFieldFilter
> aFilters
;
1310 GetDataResultPositionData(aFilters
, rPos
);
1312 DataPilotTableResultData aResData
;
1313 aResData
.FieldFilters
= comphelper::containerToSequence(aFilters
);
1314 aResData
.DataFieldIndex
= 0;
1315 Reference
<beans::XPropertySet
> xPropSet(xSource
, UNO_QUERY
);
1318 sal_Int32 nDataFieldCount
= ScUnoHelpFunctions::GetLongProperty( xPropSet
,
1319 SC_UNO_DP_DATAFIELDCOUNT
);
1320 if (nDataFieldCount
> 0)
1321 aResData
.DataFieldIndex
= (nRow
- nDataStartRow
) % nDataFieldCount
;
1324 // Copy appropriate DataResult object from the cached sheet::DataResult table.
1325 if (aData
.getLength() > nRow
- nDataStartRow
&&
1326 aData
[nRow
-nDataStartRow
].getLength() > nCol
-nDataStartCol
)
1327 aResData
.Result
= aData
[nRow
-nDataStartRow
][nCol
-nDataStartCol
];
1329 rPosData
.PositionData
<<= aResData
;
1332 case DataPilotTablePositionType::COLUMN_HEADER
:
1334 tools::Long nField
= nRow
- nTabStartRow
- 1; // 1st line is used for the buttons
1338 if (pColFields
.size() < o3tl::make_unsigned(nField
) + 1 )
1340 const uno::Sequence
<sheet::MemberResult
> rSequence
= pColFields
[nField
].maResult
;
1341 if (!rSequence
.hasElements())
1343 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1345 tools::Long nItem
= nCol
- nDataStartCol
;
1346 // get origin of "continue" fields
1347 while (nItem
> 0 && ( pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1353 DataPilotTableHeaderData aHeaderData
;
1354 aHeaderData
.MemberName
= pArray
[nItem
].Name
;
1355 aHeaderData
.Flags
= pArray
[nItem
].Flags
;
1356 aHeaderData
.Dimension
= static_cast<sal_Int32
>(pColFields
[nField
].mnDim
);
1357 aHeaderData
.Hierarchy
= static_cast<sal_Int32
>(pColFields
[nField
].mnHier
);
1358 aHeaderData
.Level
= static_cast<sal_Int32
>(pColFields
[nField
].mnLevel
);
1360 rPosData
.PositionData
<<= aHeaderData
;
1363 case DataPilotTablePositionType::ROW_HEADER
:
1365 tools::Long nField
= nCol
- nTabStartCol
;
1369 if (pRowFields
.size() < o3tl::make_unsigned(nField
) + 1 )
1371 const uno::Sequence
<sheet::MemberResult
> rSequence
= pRowFields
[nField
].maResult
;
1372 if (!rSequence
.hasElements())
1374 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1376 tools::Long nItem
= nRow
- nDataStartRow
;
1377 // get origin of "continue" fields
1378 while ( nItem
> 0 && (pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1384 DataPilotTableHeaderData aHeaderData
;
1385 aHeaderData
.MemberName
= pArray
[nItem
].Name
;
1386 aHeaderData
.Flags
= pArray
[nItem
].Flags
;
1387 aHeaderData
.Dimension
= static_cast<sal_Int32
>(pRowFields
[nField
].mnDim
);
1388 aHeaderData
.Hierarchy
= static_cast<sal_Int32
>(pRowFields
[nField
].mnHier
);
1389 aHeaderData
.Level
= static_cast<sal_Int32
>(pRowFields
[nField
].mnLevel
);
1391 rPosData
.PositionData
<<= aHeaderData
;
1397 bool ScDPOutput::GetDataResultPositionData(vector
<sheet::DataPilotFieldFilter
>& rFilters
, const ScAddress
& rPos
)
1399 // Check to make sure there is at least one data field.
1400 Reference
<beans::XPropertySet
> xPropSet(xSource
, UNO_QUERY
);
1404 sal_Int32 nDataFieldCount
= ScUnoHelpFunctions::GetLongProperty( xPropSet
,
1405 SC_UNO_DP_DATAFIELDCOUNT
);
1406 if (nDataFieldCount
== 0)
1407 // No data field is present in this datapilot table.
1410 // #i111421# use lcl_GetTableVars for correct size of totals and data layout position
1411 sal_Int32 nGrandTotalCols
;
1412 sal_Int32 nGrandTotalRows
;
1413 sal_Int32 nDataLayoutIndex
;
1414 std::vector
<OUString
> aDataNames
;
1415 std::vector
<OUString
> aGivenNames
;
1416 sheet::DataPilotFieldOrientation eDataOrient
;
1417 lcl_GetTableVars( nGrandTotalCols
, nGrandTotalRows
, nDataLayoutIndex
, aDataNames
, aGivenNames
, eDataOrient
, xSource
);
1419 SCCOL nCol
= rPos
.Col();
1420 SCROW nRow
= rPos
.Row();
1421 SCTAB nTab
= rPos
.Tab();
1422 if ( nTab
!= aStartPos
.Tab() )
1423 return false; // wrong sheet
1427 // test for data area.
1428 if (nCol
< nDataStartCol
|| nCol
> nTabEndCol
|| nRow
< nDataStartRow
|| nRow
> nTabEndRow
)
1430 // Cell is outside the data field area.
1434 bool bFilterByCol
= (nCol
<= static_cast<SCCOL
>(nTabEndCol
- nGrandTotalCols
));
1435 bool bFilterByRow
= (nRow
<= static_cast<SCROW
>(nTabEndRow
- nGrandTotalRows
));
1438 for (size_t nColField
= 0; nColField
< pColFields
.size() && bFilterByCol
; ++nColField
)
1440 if (pColFields
[nColField
].mnDim
== nDataLayoutIndex
)
1441 // There is no sense including the data layout field for filtering.
1444 sheet::DataPilotFieldFilter filter
;
1445 filter
.FieldName
= pColFields
[nColField
].maName
;
1447 const uno::Sequence
<sheet::MemberResult
> rSequence
= pColFields
[nColField
].maResult
;
1448 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1450 OSL_ENSURE(nDataStartCol
+ rSequence
.getLength() - 1 == nTabEndCol
, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1452 tools::Long nItem
= nCol
- nDataStartCol
;
1453 // get origin of "continue" fields
1454 while ( nItem
> 0 && (pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1457 filter
.MatchValueName
= pArray
[nItem
].Name
;
1458 rFilters
.push_back(filter
);
1462 for (size_t nRowField
= 0; nRowField
< pRowFields
.size() && bFilterByRow
; ++nRowField
)
1464 if (pRowFields
[nRowField
].mnDim
== nDataLayoutIndex
)
1465 // There is no sense including the data layout field for filtering.
1468 sheet::DataPilotFieldFilter filter
;
1469 filter
.FieldName
= pRowFields
[nRowField
].maName
;
1471 const uno::Sequence
<sheet::MemberResult
> rSequence
= pRowFields
[nRowField
].maResult
;
1472 const sheet::MemberResult
* pArray
= rSequence
.getConstArray();
1474 OSL_ENSURE(nDataStartRow
+ rSequence
.getLength() - 1 == nTabEndRow
, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1476 tools::Long nItem
= nRow
- nDataStartRow
;
1477 // get origin of "continue" fields
1478 while ( nItem
> 0 && (pArray
[nItem
].Flags
& sheet::MemberResultFlags::CONTINUE
) )
1481 filter
.MatchValueName
= pArray
[nItem
].Name
;
1482 rFilters
.push_back(filter
);
1490 OUString
lcl_GetDataFieldName( std::u16string_view rSourceName
, sal_Int16 eFunc
)
1495 case sheet::GeneralFunction2::SUM
: pStrId
= STR_FUN_TEXT_SUM
; break;
1496 case sheet::GeneralFunction2::COUNT
:
1497 case sheet::GeneralFunction2::COUNTNUMS
: pStrId
= STR_FUN_TEXT_COUNT
; break;
1498 case sheet::GeneralFunction2::AVERAGE
: pStrId
= STR_FUN_TEXT_AVG
; break;
1499 case sheet::GeneralFunction2::MEDIAN
: pStrId
= STR_FUN_TEXT_MEDIAN
; break;
1500 case sheet::GeneralFunction2::MAX
: pStrId
= STR_FUN_TEXT_MAX
; break;
1501 case sheet::GeneralFunction2::MIN
: pStrId
= STR_FUN_TEXT_MIN
; break;
1502 case sheet::GeneralFunction2::PRODUCT
: pStrId
= STR_FUN_TEXT_PRODUCT
; break;
1503 case sheet::GeneralFunction2::STDEV
:
1504 case sheet::GeneralFunction2::STDEVP
: pStrId
= STR_FUN_TEXT_STDDEV
; break;
1505 case sheet::GeneralFunction2::VAR
:
1506 case sheet::GeneralFunction2::VARP
: pStrId
= STR_FUN_TEXT_VAR
; break;
1507 case sheet::GeneralFunction2::NONE
:
1508 case sheet::GeneralFunction2::AUTO
: break;
1517 return ScResId(pStrId
) + " - " + rSourceName
;
1522 void ScDPOutput::GetDataDimensionNames(
1523 OUString
& rSourceName
, OUString
& rGivenName
, const uno::Reference
<uno::XInterface
>& xDim
)
1525 uno::Reference
<beans::XPropertySet
> xDimProp( xDim
, uno::UNO_QUERY
);
1526 uno::Reference
<container::XNamed
> xDimName( xDim
, uno::UNO_QUERY
);
1527 if ( !(xDimProp
.is() && xDimName
.is()) )
1530 // Asterisks are added in ScDPSaveData::WriteToSource to create unique names.
1531 //TODO: preserve original name there?
1532 rSourceName
= ScDPUtil::getSourceDimensionName(xDimName
->getName());
1534 // Generate "given name" the same way as in dptabres.
1535 //TODO: Should use a stored name when available
1537 sal_Int16 eFunc
= ScUnoHelpFunctions::GetShortProperty(
1538 xDimProp
, SC_UNO_DP_FUNCTION2
,
1539 sheet::GeneralFunction2::NONE
);
1540 rGivenName
= lcl_GetDataFieldName( rSourceName
, eFunc
);
1543 bool ScDPOutput::IsFilterButton( const ScAddress
& rPos
)
1545 SCCOL nCol
= rPos
.Col();
1546 SCROW nRow
= rPos
.Row();
1547 SCTAB nTab
= rPos
.Tab();
1548 if ( nTab
!= aStartPos
.Tab() || !bDoFilter
)
1549 return false; // wrong sheet or no button at all
1551 // filter button is at top left
1552 return ( nCol
== aStartPos
.Col() && nRow
== aStartPos
.Row() );
1555 tools::Long
ScDPOutput::GetHeaderDim( const ScAddress
& rPos
, sheet::DataPilotFieldOrientation
& rOrient
)
1557 SCCOL nCol
= rPos
.Col();
1558 SCROW nRow
= rPos
.Row();
1559 SCTAB nTab
= rPos
.Tab();
1560 if ( nTab
!= aStartPos
.Tab() )
1561 return -1; // wrong sheet
1563 // calculate output positions and sizes
1567 // test for column header
1569 if ( nRow
== nTabStartRow
&& nCol
>= nDataStartCol
&& o3tl::make_unsigned(nCol
) < nDataStartCol
+ pColFields
.size())
1571 rOrient
= sheet::DataPilotFieldOrientation_COLUMN
;
1572 tools::Long nField
= nCol
- nDataStartCol
;
1573 return pColFields
[nField
].mnDim
;
1576 // test for row header
1578 if ( nRow
+1 == nDataStartRow
&& nCol
>= nTabStartCol
&& o3tl::make_unsigned(nCol
) < nTabStartCol
+ pRowFields
.size() )
1580 rOrient
= sheet::DataPilotFieldOrientation_ROW
;
1581 tools::Long nField
= nCol
- nTabStartCol
;
1582 return pRowFields
[nField
].mnDim
;
1585 // test for page field
1587 SCROW nPageStartRow
= aStartPos
.Row() + ( bDoFilter
? 1 : 0 );
1588 if ( nCol
== aStartPos
.Col() && nRow
>= nPageStartRow
&& o3tl::make_unsigned(nRow
) < nPageStartRow
+ pPageFields
.size() )
1590 rOrient
= sheet::DataPilotFieldOrientation_PAGE
;
1591 tools::Long nField
= nRow
- nPageStartRow
;
1592 return pPageFields
[nField
].mnDim
;
1595 //TODO: single data field (?)
1597 rOrient
= sheet::DataPilotFieldOrientation_HIDDEN
;
1598 return -1; // invalid
1601 bool ScDPOutput::GetHeaderDrag( const ScAddress
& rPos
, bool bMouseLeft
, bool bMouseTop
,
1602 tools::Long nDragDim
,
1603 tools::Rectangle
& rPosRect
, sheet::DataPilotFieldOrientation
& rOrient
, tools::Long
& rDimPos
)
1605 // Rectangle instead of ScRange for rPosRect to allow for negative values
1607 SCCOL nCol
= rPos
.Col();
1608 SCROW nRow
= rPos
.Row();
1609 SCTAB nTab
= rPos
.Tab();
1610 if ( nTab
!= aStartPos
.Tab() )
1611 return false; // wrong sheet
1613 // calculate output positions and sizes
1617 // test for column header
1619 if ( nCol
>= nDataStartCol
&& nCol
<= nTabEndCol
&&
1620 nRow
+ 1 >= nMemberStartRow
&& o3tl::make_unsigned(nRow
) < nMemberStartRow
+ pColFields
.size())
1622 tools::Long nField
= nRow
- nMemberStartRow
;
1628 //TODO: find start of dimension
1630 rPosRect
= tools::Rectangle( nDataStartCol
, nMemberStartRow
+ nField
,
1631 nTabEndCol
, nMemberStartRow
+ nField
-1 );
1633 bool bFound
= false; // is this within the same orientation?
1634 bool bBeforeDrag
= false;
1635 bool bAfterDrag
= false;
1636 for (tools::Long nPos
=0; o3tl::make_unsigned(nPos
)<pColFields
.size() && !bFound
; nPos
++)
1638 if (pColFields
[nPos
].mnDim
== nDragDim
)
1641 if ( nField
< nPos
)
1643 else if ( nField
> nPos
)
1652 rPosRect
.AdjustBottom( 1 );
1654 rPosRect
.AdjustTop( 1 );
1661 rPosRect
.AdjustTop( 1 );
1662 rPosRect
.AdjustBottom( 1 );
1667 rOrient
= sheet::DataPilotFieldOrientation_COLUMN
;
1668 rDimPos
= nField
; //!...
1672 // test for row header
1674 // special case if no row fields
1675 bool bSpecial
= ( nRow
+1 >= nDataStartRow
&& nRow
<= nTabEndRow
&&
1676 pRowFields
.empty() && nCol
== nTabStartCol
&& bMouseLeft
);
1678 if ( bSpecial
|| ( nRow
+1 >= nDataStartRow
&& nRow
<= nTabEndRow
&&
1679 nCol
+ 1 >= nTabStartCol
&& o3tl::make_unsigned(nCol
) < nTabStartCol
+ pRowFields
.size() ) )
1681 tools::Long nField
= nCol
- nTabStartCol
;
1682 //TODO: find start of dimension
1684 rPosRect
= tools::Rectangle( nTabStartCol
+ nField
, nDataStartRow
- 1,
1685 nTabStartCol
+ nField
- 1, nTabEndRow
);
1687 bool bFound
= false; // is this within the same orientation?
1688 bool bBeforeDrag
= false;
1689 bool bAfterDrag
= false;
1690 for (tools::Long nPos
=0; o3tl::make_unsigned(nPos
)<pRowFields
.size() && !bFound
; nPos
++)
1692 if (pRowFields
[nPos
].mnDim
== nDragDim
)
1695 if ( nField
< nPos
)
1697 else if ( nField
> nPos
)
1706 rPosRect
.AdjustRight( 1 );
1708 rPosRect
.AdjustLeft( 1 );
1715 rPosRect
.AdjustLeft( 1 );
1716 rPosRect
.AdjustRight( 1 );
1721 rOrient
= sheet::DataPilotFieldOrientation_ROW
;
1722 rDimPos
= nField
; //!...
1726 // test for page fields
1728 SCROW nPageStartRow
= aStartPos
.Row() + ( bDoFilter
? 1 : 0 );
1729 if ( nCol
>= aStartPos
.Col() && nCol
<= nTabEndCol
&&
1730 nRow
+ 1 >= nPageStartRow
&& o3tl::make_unsigned(nRow
) < nPageStartRow
+ pPageFields
.size() )
1732 tools::Long nField
= nRow
- nPageStartRow
;
1738 //TODO: find start of dimension
1740 rPosRect
= tools::Rectangle( aStartPos
.Col(), nPageStartRow
+ nField
,
1741 nTabEndCol
, nPageStartRow
+ nField
- 1 );
1743 bool bFound
= false; // is this within the same orientation?
1744 bool bBeforeDrag
= false;
1745 bool bAfterDrag
= false;
1746 for (tools::Long nPos
=0; o3tl::make_unsigned(nPos
)<pPageFields
.size() && !bFound
; nPos
++)
1748 if (pPageFields
[nPos
].mnDim
== nDragDim
)
1751 if ( nField
< nPos
)
1753 else if ( nField
> nPos
)
1762 rPosRect
.AdjustBottom( 1 );
1764 rPosRect
.AdjustTop( 1 );
1771 rPosRect
.AdjustTop( 1 );
1772 rPosRect
.AdjustBottom( 1 );
1777 rOrient
= sheet::DataPilotFieldOrientation_PAGE
;
1778 rDimPos
= nField
; //!...
1785 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */