Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / dpoutput.cxx
blobcb43eccd54dbadde0fd2b629911eab3c77a0144c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
35 #include "attrib.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"
43 #include "sc.hrc"
44 #include "stringutil.hxx"
45 #include "dputil.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>
57 #include <vector>
59 using namespace com::sun::star;
60 using ::std::vector;
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
79 long nDim;
80 long nHier;
81 long nLevel;
82 long nDimPos;
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;
88 bool mbDataLayout:1;
89 bool mbPageDim:1;
91 ScDPOutLevelData() :
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!
105 namespace {
107 bool lcl_compareColfuc ( SCCOL i, SCCOL j) { return (i<j); }
108 bool lcl_compareRowfuc ( SCROW i, SCROW j) { return (i<j); }
110 class ScDPOutputImpl
112 ScDocument* mpDoc;
113 sal_uInt16 mnTab;
114 ::std::vector< bool > mbNeedLineCols;
115 ::std::vector< SCCOL > mnCols;
117 ::std::vector< bool > mbNeedLineRows;
118 ::std::vector< SCROW > mnRows;
120 SCCOL mnTabStartCol;
121 SCROW mnTabStartRow;
123 SCCOL mnDataStartCol;
124 SCROW mnDataStartRow;
125 SCCOL mnTabEndCol;
126 SCROW mnTabEndRow;
128 public:
129 ScDPOutputImpl( ScDocument* pDoc, sal_uInt16 nTab,
130 SCCOL nTabStartCol,
131 SCROW nTabStartRow,
132 SCCOL nDataStartCol,
133 SCROW nDataStartRow,
134 SCCOL nTabEndCol,
135 SCROW nTabEndRow );
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 ++ )
159 if ( !bAllRows )
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 );
168 else
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 );
174 else
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,
189 SCCOL nTabStartCol,
190 SCROW nTabStartRow,
191 SCCOL nDataStartCol,
192 SCROW nDataStartRow,
193 SCCOL nTabEndCol,
194 SCROW nTabEndRow ):
195 mpDoc( pDoc ),
196 mnTab( 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 );
215 return true;
217 else
218 return false;
221 bool ScDPOutputImpl::AddCol( SCCOL nCol )
224 if ( !mbNeedLineCols[ nCol - mnDataStartCol ] )
226 mbNeedLineCols[ nCol - mnDataStartCol ] = true;
227 mnCols.push_back( nCol );
228 return true;
230 else
231 return false;
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);
244 else
245 aBox.SetLine(&aLine, BOX_LINE_LEFT);
247 if ( nStartRow == mnTabStartRow )
248 aBox.SetLine(&aOutLine, BOX_LINE_TOP);
249 else
250 aBox.SetLine(&aLine, BOX_LINE_TOP);
252 if ( nEndCol == mnTabEndCol ) //bottom row
253 aBox.SetLine(&aOutLine, BOX_LINE_RIGHT);
254 else
255 aBox.SetLine(&aLine, BOX_LINE_RIGHT);
257 if ( nEndRow == mnTabEndRow ) //bottom
258 aBox.SetLine(&aOutLine, BOX_LINE_BOTTOM);
259 else
260 aBox.SetLine(&aLine, BOX_LINE_BOTTOM);
263 SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
264 aBoxInfo.SetValid(VALID_VERT,false );
265 if ( bHori )
267 aBoxInfo.SetValid(VALID_HORI,true);
268 aBoxInfo.SetLine( &aLine, BOXINFO_LINE_HORI );
270 else
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,
281 sal_uInt16 nStrId )
283 if ( nCol1 > nCol2 || nRow1 > nRow2 )
285 OSL_FAIL("SetStyleById: invalid range");
286 return;
289 OUString aStyleName = ScGlobal::GetRscString( nStrId );
290 ScStyleSheetPool* pStlPool = pDoc->GetStyleSheetPool();
291 ScStyleSheet* pStyle = (ScStyleSheet*) pStlPool->Find( aStyleName, SFX_STYLE_FAMILY_PARA );
292 if (!pStyle)
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,
311 sal_uInt16 nWidth )
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 )
333 if ( rFormats )
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();
342 if (!nSize)
343 return;
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];
350 long nDataCount = 0;
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(
368 xDimProp,
369 OUString(SC_UNONAME_NUMFMT) );
370 nDataFormats[nDataCount] = nFormat;
371 ++nDataCount;
376 if (!nDataCount)
377 return;
379 const sheet::MemberResult* pArray = aResult.getConstArray();
381 OUString aName;
382 sal_uInt32* pNumFmt = new sal_uInt32[nSize];
383 if (nDataCount == 1)
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;
390 else
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];
404 break;
406 pNumFmt[nPos] = nFormat;
410 rFormats = pNumFmt;
411 rCount = nSize;
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 );
422 if ( xDimProp.is() )
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(
431 xDimProp,
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)
460 return false;
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 )
471 if (!xLevel.is())
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();
479 if (!xNA.is())
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);
490 if (!xMemPS.is())
491 continue;
493 OUString aCaption = ScUnoHelpFunctions::GetStringProperty(xMemPS, SC_UNO_DP_LAYOUTNAME, OUString());
494 if (aCaption.isEmpty())
495 aCaption = rName;
497 bool bVisible = ScUnoHelpFunctions::GetBoolProperty(xMemPS, SC_UNO_DP_ISVISIBLE, false);
499 if (bVisible)
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 ) :
514 pDoc( pD ),
515 xSource( xSrc ),
516 aStartPos( rPos ),
517 pColNumFmt( NULL ),
518 pRowNumFmt( NULL ),
519 nColFmtCount( 0 ),
520 nRowFmtCount( 0 ),
521 nSingleNumFmt( 0 ),
522 bDoFilter(bFilter),
523 bResultsError(false),
524 mbHasDataLayout(false),
525 bSizesValid(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];
535 nColFieldCount = 0;
536 nRowFieldCount = 0;
537 nPageFieldCount = 0;
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(
573 xDimProp,
574 OUString(SC_UNO_DP_USEDHIERARCHY) );
575 if ( nHierarchy >= xHiers->getCount() )
576 nHierarchy = 0;
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))
620 ++nColFieldCount;
621 break;
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))
635 ++nRowFieldCount;
636 bRowFieldHasMember = true;
638 break;
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
651 ++nPageFieldCount;
652 break;
653 default:
655 // added to avoid warnings
659 // get number formats from data dimensions
660 if ( bIsDataLayout )
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 );
688 // get data results:
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 );
703 if ( xSrcProp.is() )
707 uno::Any aAny = xSrcProp->getPropertyValue(
708 OUString(SC_UNO_DP_DATADESC) );
709 OUString aUStr;
710 aAny >>= aUStr;
711 aDataDescription = aUStr;
713 catch(const uno::Exception&)
719 ScDPOutput::~ScDPOutput()
721 delete[] pColFields;
722 delete[] pRowFields;
723 delete[] pPageFields;
725 delete[] pColNumFmt;
726 delete[] pRowNumFmt;
729 void ScDPOutput::SetPosition( const ScAddress& rPos )
731 aStartPos = 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;
751 if ( pColNumFmt )
753 if ( nCol >= nDataStartCol )
755 long nIndex = nCol - nDataStartCol;
756 if ( nIndex < nColFmtCount )
758 nFormat = pColNumFmt[nIndex];
759 bApplyFormat = true;
763 else if ( pRowNumFmt )
765 if ( nRow >= nDataStartRow )
767 long nIndex = nRow - nDataStartRow;
768 if ( nIndex < nRowFmtCount )
770 nFormat = pRowNumFmt[nIndex];
771 bApplyFormat = true;
775 else if ( nSingleNumFmt != 0 )
777 nFormat = nSingleNumFmt; // single format is used everywhere
778 bApplyFormat = true;
781 if (bApplyFormat)
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;
796 if (bNumeric)
797 aParam.setNumericInput();
798 else
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?
810 if (bColHeader)
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 );
819 else
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);
840 if (bInTable)
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;
848 if (rData.mbPageDim)
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);
854 else
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()
874 if (!bSizesValid)
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;
883 nHeaderSize = 1;
884 if (GetHeaderLayout() && nColFieldCount == 0)
885 // Insert an extra header row only when there is no column field.
886 nHeaderSize = 2;
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
894 if ( bDoFilter )
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;
910 if ( nColCount > 0 )
911 nTabEndCol = nDataStartCol + (SCCOL)nColCount - 1;
912 else
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;
917 if ( nRowCount > 0 )
918 nTabEndRow = nDataStartRow + (SCROW)nRowCount - 1;
919 else
920 nTabEndRow = nDataStartRow; // single row will remain empty
921 bSizesValid = true;
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;
935 CalcSizes();
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;
952 if (bInColHeader)
954 if (nRow == nTabStartRow)
955 // first row in the column header area is always used for column
956 // field buttons.
957 return DataPilotTablePositionType::OTHER;
959 return DataPilotTablePositionType::COLUMN_HEADER;
962 if (bInRowHeader)
963 return DataPilotTablePositionType::ROW_HEADER;
965 return DataPilotTablePositionType::OTHER;
968 void ScDPOutput::Output()
970 long nField;
971 SCTAB nTab = aStartPos.Tab();
972 const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
974 // calculate output positions and sizes
976 CalcSizes();
977 if ( bSizeOverflow || bResultsError ) // does output area exceed sheet limits?
978 return; // nothing
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 );
985 if ( bDoFilter )
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();
1001 if (n == 1)
1002 aPageValue = rRes[0].Caption;
1003 else if (n > 1)
1004 aPageValue = ScResId(SCSTR_MULTIPLE).toString();
1006 pDoc->SetString( nFldCol, nHdrRow, nTab, aPageValue );
1008 lcl_SetFrame( pDoc,nTab, nFldCol,nHdrRow, nFldCol,nHdrRow, 20 );
1011 // data description
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 ) )
1049 long nEnd = nCol;
1050 while ( nEnd+1 < nThisColCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
1051 ++nEnd;
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 );
1061 else
1062 outputimp.OutputBlockFrame( nColPos,nRowPos, nEndColPos,nRowPos );
1064 lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nEndColPos,nDataStartRow-1, STR_PIVOT_STYLE_CATEGORY );
1066 else
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 )
1102 long nEnd = nRow;
1103 while ( nEnd+1 < nThisRowCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
1104 ++nEnd;
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 );
1119 else
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;
1152 CalcSizes();
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);
1161 default:
1162 OSL_ENSURE(nRegionType == DataPilotOutputRangeType::WHOLE, "ScDPOutput::GetOutputRange: unknown region type");
1163 break;
1165 return ScRange(aStartPos.Col(), aStartPos.Row(), nTab, nTabEndCol, nTabEndRow, nTab);
1168 bool ScDPOutput::HasError()
1170 CalcSizes();
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;
1188 long nField;
1190 // look in column fields
1192 for (nField=0; nField<nColFieldCount && !bFound; nField++)
1193 if ( pColFields[nField].nDim == nDimension )
1195 aMemberResults = pColFields[nField].aResult;
1196 bFound = true;
1199 // look in row fields
1201 for (nField=0; nField<nRowFieldCount && !bFound; nField++)
1202 if ( pRowFields[nField].nDim == nDimension )
1204 aMemberResults = pRowFields[nField].aResult;
1205 bFound = true;
1208 // collect the member names
1210 if ( bFound )
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;
1234 namespace {
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));
1249 if ( bColGrand )
1250 rGrandTotalCols = 1; // default if data layout not in columns
1252 bool bRowGrand = ScUnoHelpFunctions::GetBoolProperty(
1253 xSrcProp, OUString(SC_UNO_DP_ROWGRAND));
1254 if ( bRowGrand )
1255 rGrandTotalRows = 1; // default if data layout not in rows
1257 if ( xSource.is() )
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 );
1305 ++nDataCount;
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
1331 CalcSizes();
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);
1349 if (xPropSet.is())
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);
1363 return;
1365 case DataPilotTablePositionType::COLUMN_HEADER:
1367 long nField = nRow - nTabStartRow - 1; // 1st line is used for the buttons
1368 if (nField < 0)
1369 break;
1371 const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].aResult;
1372 if (rSequence.getLength() == 0)
1373 break;
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) )
1379 --nItem;
1381 if (nItem < 0)
1382 break;
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);
1392 return;
1394 case DataPilotTablePositionType::ROW_HEADER:
1396 long nField = nCol - nTabStartCol;
1397 if (nField < 0)
1398 break;
1400 const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].aResult;
1401 if (rSequence.getLength() == 0)
1402 break;
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) )
1408 --nItem;
1410 if (nItem < 0)
1411 break;
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);
1421 return;
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);
1430 if (!xPropSet.is())
1431 return false;
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.
1437 return false;
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
1454 CalcSizes();
1456 // test for data area.
1457 if (nCol < nDataStartCol || nCol > nTabEndCol || nRow < nDataStartRow || nRow > nTabEndRow)
1459 // Cell is outside the data field area.
1460 return false;
1463 bool bFilterByCol = (nCol <= static_cast<SCCOL>(nTabEndCol - nGrandTotalCols));
1464 bool bFilterByRow = (nRow <= static_cast<SCROW>(nTabEndRow - nGrandTotalRows));
1466 // column fields
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.
1471 continue;
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) )
1484 --nItem;
1486 filter.MatchValue = pArray[nItem].Name;
1487 rFilters.push_back(filter);
1490 // row fields
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.
1495 continue;
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) )
1508 --nItem;
1510 filter.MatchValue = pArray[nItem].Name;
1511 rFilters.push_back(filter);
1514 return true;
1517 namespace {
1519 OUString lcl_GetDataFieldName( const OUString& rSourceName, sheet::GeneralFunction eFunc )
1521 sal_uInt16 nStrId = 0;
1522 switch ( eFunc )
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:
1537 default:
1539 OSL_FAIL("wrong function");
1542 if ( !nStrId )
1543 return OUString();
1545 OUStringBuffer aRet( ScGlobal::GetRscString( nStrId ) );
1546 aRet.append(" - ");
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
1596 CalcSizes();
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,
1633 long nDragDim,
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
1646 CalcSizes();
1648 // test for column header
1650 if ( nCol >= nDataStartCol && nCol <= nTabEndCol &&
1651 nRow + 1 >= nMemberStartRow && nRow < nMemberStartRow + nColFieldCount )
1653 long nField = nRow - nMemberStartRow;
1654 if (nField < 0)
1656 nField = 0;
1657 bMouseTop = true;
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)
1671 bFound = true;
1672 if ( nField < nPos )
1673 bBeforeDrag = true;
1674 else if ( nField > nPos )
1675 bAfterDrag = true;
1679 if ( bFound )
1681 if (!bBeforeDrag)
1683 ++rPosRect.Bottom();
1684 if (bAfterDrag)
1685 ++rPosRect.Top();
1688 else
1690 if ( !bMouseTop )
1692 ++rPosRect.Top();
1693 ++rPosRect.Bottom();
1694 ++nField;
1698 rOrient = sheet::DataPilotFieldOrientation_COLUMN;
1699 rDimPos = nField; //!...
1700 return true;
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)
1725 bFound = true;
1726 if ( nField < nPos )
1727 bBeforeDrag = true;
1728 else if ( nField > nPos )
1729 bAfterDrag = true;
1733 if ( bFound )
1735 if (!bBeforeDrag)
1737 ++rPosRect.Right();
1738 if (bAfterDrag)
1739 ++rPosRect.Left();
1742 else
1744 if ( !bMouseLeft )
1746 ++rPosRect.Left();
1747 ++rPosRect.Right();
1748 ++nField;
1752 rOrient = sheet::DataPilotFieldOrientation_ROW;
1753 rDimPos = nField; //!...
1754 return true;
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;
1764 if (nField < 0)
1766 nField = 0;
1767 bMouseTop = true;
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)
1781 bFound = true;
1782 if ( nField < nPos )
1783 bBeforeDrag = true;
1784 else if ( nField > nPos )
1785 bAfterDrag = true;
1789 if ( bFound )
1791 if (!bBeforeDrag)
1793 ++rPosRect.Bottom();
1794 if (bAfterDrag)
1795 ++rPosRect.Top();
1798 else
1800 if ( !bMouseTop )
1802 ++rPosRect.Top();
1803 ++rPosRect.Bottom();
1804 ++nField;
1808 rOrient = sheet::DataPilotFieldOrientation_PAGE;
1809 rDimPos = nField; //!...
1810 return true;
1813 return false;
1817 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */