update emoji autocorrect entries from po-files
[LibreOffice.git] / sc / source / core / data / dpoutput.cxx
blob450c5bb7393d52c8d4a903a906212de595a99c19
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, SvxBoxItemLine::LEFT);
244 else
245 aBox.SetLine(&aLine, SvxBoxItemLine::LEFT);
247 if ( nStartRow == mnTabStartRow )
248 aBox.SetLine(&aOutLine, SvxBoxItemLine::TOP);
249 else
250 aBox.SetLine(&aLine, SvxBoxItemLine::TOP);
252 if ( nEndCol == mnTabEndCol ) //bottom row
253 aBox.SetLine(&aOutLine, SvxBoxItemLine::RIGHT);
254 else
255 aBox.SetLine(&aLine, SvxBoxItemLine::RIGHT);
257 if ( nEndRow == mnTabEndRow ) //bottom
258 aBox.SetLine(&aOutLine, SvxBoxItemLine::BOTTOM);
259 else
260 aBox.SetLine(&aLine, SvxBoxItemLine::BOTTOM);
262 SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
263 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT,false );
264 if ( bHori )
266 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI,true);
267 aBoxInfo.SetLine( &aLine, SvxBoxInfoItemLine::HORI );
269 else
270 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI,false );
272 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE,false);
274 mpDoc->ApplyFrameAreaTab( ScRange( nStartCol, nStartRow, mnTab, nEndCol, nEndRow , mnTab ), &aBox, &aBoxInfo );
278 void lcl_SetStyleById( ScDocument* pDoc, SCTAB nTab,
279 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
280 sal_uInt16 nStrId )
282 if ( nCol1 > nCol2 || nRow1 > nRow2 )
284 OSL_FAIL("SetStyleById: invalid range");
285 return;
288 OUString aStyleName = ScGlobal::GetRscString( nStrId );
289 ScStyleSheetPool* pStlPool = pDoc->GetStyleSheetPool();
290 ScStyleSheet* pStyle = static_cast<ScStyleSheet*>( pStlPool->Find( aStyleName, SFX_STYLE_FAMILY_PARA ) );
291 if (!pStyle)
293 // create new style (was in ScPivot::SetStyle)
295 pStyle = static_cast<ScStyleSheet*>( &pStlPool->Make( aStyleName, SFX_STYLE_FAMILY_PARA,
296 SFXSTYLEBIT_USERDEF ) );
297 pStyle->SetParent( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) );
298 SfxItemSet& rSet = pStyle->GetItemSet();
299 if ( nStrId==STR_PIVOT_STYLE_RESULT || nStrId==STR_PIVOT_STYLE_TITLE )
300 rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
301 if ( nStrId==STR_PIVOT_STYLE_CATEGORY || nStrId==STR_PIVOT_STYLE_TITLE )
302 rSet.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
305 pDoc->ApplyStyleAreaTab( nCol1, nRow1, nCol2, nRow2, nTab, *pStyle );
308 void lcl_SetFrame( ScDocument* pDoc, SCTAB nTab,
309 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
310 sal_uInt16 nWidth )
312 ::editeng::SvxBorderLine aLine(0, nWidth, table::BorderLineStyle::SOLID);
313 SvxBoxItem aBox( ATTR_BORDER );
314 aBox.SetLine(&aLine, SvxBoxItemLine::LEFT);
315 aBox.SetLine(&aLine, SvxBoxItemLine::TOP);
316 aBox.SetLine(&aLine, SvxBoxItemLine::RIGHT);
317 aBox.SetLine(&aLine, SvxBoxItemLine::BOTTOM);
318 SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
319 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI,false);
320 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT,false);
321 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE,false);
323 pDoc->ApplyFrameAreaTab( ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab ), &aBox, &aBoxInfo );
326 void lcl_FillNumberFormats( sal_uInt32*& rFormats, long& rCount,
327 const uno::Reference<sheet::XDataPilotMemberResults>& xLevRes,
328 const uno::Reference<container::XIndexAccess>& xDims )
330 if ( rFormats )
331 return; // already set
333 // xLevRes is from the data layout dimension
334 //TODO: use result sequence from ScDPOutLevelData!
336 uno::Sequence<sheet::MemberResult> aResult = xLevRes->getResults();
338 long nSize = aResult.getLength();
339 if (!nSize)
340 return;
342 // get names/formats for all data dimensions
343 //TODO: merge this with the loop to collect ScDPOutLevelData?
345 OUString aDataNames[SC_DPOUT_MAXLEVELS];
346 sal_uInt32 nDataFormats[SC_DPOUT_MAXLEVELS];
347 long nDataCount = 0;
348 long nDimCount = xDims->getCount();
349 for (long nDim=0; nDim<nDimCount; nDim++)
351 uno::Reference<uno::XInterface> xDim =
352 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
353 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
354 uno::Reference<container::XNamed> xDimName( xDim, uno::UNO_QUERY );
355 if ( xDimProp.is() && xDimName.is() )
357 sheet::DataPilotFieldOrientation eDimOrient =
358 (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
359 xDimProp, OUString(SC_UNO_DP_ORIENTATION),
360 sheet::DataPilotFieldOrientation_HIDDEN );
361 if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
363 aDataNames[nDataCount] = xDimName->getName();
364 long nFormat = ScUnoHelpFunctions::GetLongProperty(
365 xDimProp,
366 OUString(SC_UNONAME_NUMFMT) );
367 nDataFormats[nDataCount] = nFormat;
368 ++nDataCount;
373 if (!nDataCount)
374 return;
376 const sheet::MemberResult* pArray = aResult.getConstArray();
378 OUString aName;
379 sal_uInt32* pNumFmt = new sal_uInt32[nSize];
380 if (nDataCount == 1)
382 // only one data dimension -> use its numberformat everywhere
383 long nFormat = nDataFormats[0];
384 for (long nPos=0; nPos<nSize; nPos++)
385 pNumFmt[nPos] = nFormat;
387 else
389 for (long nPos=0; nPos<nSize; nPos++)
391 // if CONTINUE bit is set, keep previous name
392 //TODO: keep number format instead!
393 if ( !(pArray[nPos].Flags & sheet::MemberResultFlags::CONTINUE) )
394 aName = pArray[nPos].Name;
396 sal_uInt32 nFormat = 0;
397 for (long i=0; i<nDataCount; i++)
398 if (aName == aDataNames[i]) //TODO: search more efficiently?
400 nFormat = nDataFormats[i];
401 break;
403 pNumFmt[nPos] = nFormat;
407 rFormats = pNumFmt;
408 rCount = nSize;
411 sal_uInt32 lcl_GetFirstNumberFormat( const uno::Reference<container::XIndexAccess>& xDims )
413 long nDimCount = xDims->getCount();
414 for (long nDim=0; nDim<nDimCount; nDim++)
416 uno::Reference<uno::XInterface> xDim =
417 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
418 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
419 if ( xDimProp.is() )
421 sheet::DataPilotFieldOrientation eDimOrient =
422 (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
423 xDimProp, OUString(SC_UNO_DP_ORIENTATION),
424 sheet::DataPilotFieldOrientation_HIDDEN );
425 if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
427 long nFormat = ScUnoHelpFunctions::GetLongProperty(
428 xDimProp,
429 OUString(SC_UNONAME_NUMFMT) );
431 return nFormat; // use format from first found data dimension
436 return 0; // none found
439 void lcl_SortFields( ScDPOutLevelData* pFields, long nFieldCount )
441 for (long i=0; i+1<nFieldCount; i++)
443 for (long j=0; j+i+1<nFieldCount; j++)
444 if ( pFields[j+1] < pFields[j] )
445 pFields[j].Swap( pFields[j+1] );
449 bool lcl_MemberEmpty( const uno::Sequence<sheet::MemberResult>& rSeq )
451 // used to skip levels that have no members
453 long nLen = rSeq.getLength();
454 const sheet::MemberResult* pArray = rSeq.getConstArray();
455 for (long i=0; i<nLen; i++)
456 if (pArray[i].Flags & sheet::MemberResultFlags::HASMEMBER)
457 return false;
459 return true; // no member data -> empty
463 * Get visible page dimension members as results, except that, if all
464 * members are visible, then this function returns empty result.
466 uno::Sequence<sheet::MemberResult> getVisiblePageMembersAsResults( const uno::Reference<uno::XInterface>& xLevel )
468 if (!xLevel.is())
469 return uno::Sequence<sheet::MemberResult>();
471 uno::Reference<sheet::XMembersSupplier> xMSupplier(xLevel, UNO_QUERY);
472 if (!xMSupplier.is())
473 return uno::Sequence<sheet::MemberResult>();
475 uno::Reference<container::XNameAccess> xNA = xMSupplier->getMembers();
476 if (!xNA.is())
477 return uno::Sequence<sheet::MemberResult>();
479 std::vector<sheet::MemberResult> aRes;
480 uno::Sequence<OUString> aNames = xNA->getElementNames();
481 for (sal_Int32 i = 0; i < aNames.getLength(); ++i)
483 const OUString& rName = aNames[i];
484 xNA->getByName(rName);
486 uno::Reference<beans::XPropertySet> xMemPS(xNA->getByName(rName), UNO_QUERY);
487 if (!xMemPS.is())
488 continue;
490 OUString aCaption = ScUnoHelpFunctions::GetStringProperty(xMemPS, SC_UNO_DP_LAYOUTNAME, OUString());
491 if (aCaption.isEmpty())
492 aCaption = rName;
494 bool bVisible = ScUnoHelpFunctions::GetBoolProperty(xMemPS, SC_UNO_DP_ISVISIBLE, false);
496 if (bVisible)
497 aRes.push_back(sheet::MemberResult(rName, aCaption, 0));
500 if (aNames.getLength() == static_cast<sal_Int32>(aRes.size()))
501 // All members are visible. Return empty result.
502 return uno::Sequence<sheet::MemberResult>();
504 return ScUnoHelpFunctions::VectorToSequence(aRes);
509 ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsSupplier>& xSrc,
510 const ScAddress& rPos, bool bFilter ) :
511 pDoc( pD ),
512 xSource( xSrc ),
513 aStartPos( rPos ),
514 pColNumFmt( NULL ),
515 pRowNumFmt( NULL ),
516 nColFmtCount( 0 ),
517 nRowFmtCount( 0 ),
518 nSingleNumFmt( 0 ),
519 nColCount(0),
520 nRowCount(0),
521 nHeaderSize(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 //TODO: 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);
862 lcl_SetStyleById( pDoc,nTab, nCol,nRow, nCol,nRow, STR_PIVOT_STYLE_FIELDNAME );
865 static void lcl_DoFilterButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
867 pDoc->SetString( nCol, nRow, nTab, ScGlobal::GetRscString(STR_CELL_FILTER) );
868 pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON);
871 void ScDPOutput::CalcSizes()
873 if (!bSizesValid)
875 // get column size of data from first row
876 //TODO: allow different sizes (and clear following areas) ???
878 nRowCount = aData.getLength();
879 const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
880 nColCount = nRowCount ? ( pRowAry[0].getLength() ) : 0;
882 nHeaderSize = 1;
883 if (GetHeaderLayout() && nColFieldCount == 0)
884 // Insert an extra header row only when there is no column field.
885 nHeaderSize = 2;
887 // calculate output positions and sizes
889 long nPageSize = 0; // use page fields!
890 if ( bDoFilter || nPageFieldCount )
892 nPageSize += nPageFieldCount + 1; // plus one empty row
893 if ( bDoFilter )
894 ++nPageSize; // filter button above the page fields
897 if ( aStartPos.Col() + nRowFieldCount + nColCount - 1 > MAXCOL ||
898 aStartPos.Row() + nPageSize + nHeaderSize + nColFieldCount + nRowCount > MAXROW )
900 bSizeOverflow = true;
903 nTabStartCol = aStartPos.Col();
904 nTabStartRow = aStartPos.Row() + (SCROW)nPageSize; // below page fields
905 nMemberStartCol = nTabStartCol;
906 nMemberStartRow = nTabStartRow + (SCROW) nHeaderSize;
907 nDataStartCol = nMemberStartCol + (SCCOL)nRowFieldCount;
908 nDataStartRow = nMemberStartRow + (SCROW)nColFieldCount;
909 if ( nColCount > 0 )
910 nTabEndCol = nDataStartCol + (SCCOL)nColCount - 1;
911 else
912 nTabEndCol = nDataStartCol; // single column will remain empty
913 // if page fields are involved, include the page selection cells
914 if ( nPageFieldCount > 0 && nTabEndCol < nTabStartCol + 1 )
915 nTabEndCol = nTabStartCol + 1;
916 if ( nRowCount > 0 )
917 nTabEndRow = nDataStartRow + (SCROW)nRowCount - 1;
918 else
919 nTabEndRow = nDataStartRow; // single row will remain empty
920 bSizesValid = true;
924 sal_Int32 ScDPOutput::GetPositionType(const ScAddress& rPos)
926 using namespace ::com::sun::star::sheet;
928 SCCOL nCol = rPos.Col();
929 SCROW nRow = rPos.Row();
930 SCTAB nTab = rPos.Tab();
931 if ( nTab != aStartPos.Tab() )
932 return DataPilotTablePositionType::NOT_IN_TABLE;
934 CalcSizes();
936 // Make sure the cursor is within the table.
937 if (nCol < nTabStartCol || nRow < nTabStartRow || nCol > nTabEndCol || nRow > nTabEndRow)
938 return DataPilotTablePositionType::NOT_IN_TABLE;
940 // test for result data area.
941 if (nCol >= nDataStartCol && nCol <= nTabEndCol && nRow >= nDataStartRow && nRow <= nTabEndRow)
942 return DataPilotTablePositionType::RESULT;
944 bool bInColHeader = (nRow >= nTabStartRow && nRow < nDataStartRow);
945 bool bInRowHeader = (nCol >= nTabStartCol && nCol < nDataStartCol);
947 if (bInColHeader && bInRowHeader)
948 // probably in that ugly little box at the upper-left corner of the table.
949 return DataPilotTablePositionType::OTHER;
951 if (bInColHeader)
953 if (nRow == nTabStartRow)
954 // first row in the column header area is always used for column
955 // field buttons.
956 return DataPilotTablePositionType::OTHER;
958 return DataPilotTablePositionType::COLUMN_HEADER;
961 if (bInRowHeader)
962 return DataPilotTablePositionType::ROW_HEADER;
964 return DataPilotTablePositionType::OTHER;
967 void ScDPOutput::Output()
969 long nField;
970 SCTAB nTab = aStartPos.Tab();
971 const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
973 // calculate output positions and sizes
975 CalcSizes();
976 if ( bSizeOverflow || bResultsError ) // does output area exceed sheet limits?
977 return; // nothing
979 // clear whole (new) output area
980 // when modifying table, clear old area !
981 //TODO: include IDF_OBJECTS ???
982 pDoc->DeleteAreaTab( aStartPos.Col(), aStartPos.Row(), nTabEndCol, nTabEndRow, nTab, IDF_ALL );
984 if ( bDoFilter )
985 lcl_DoFilterButton( pDoc, aStartPos.Col(), aStartPos.Row(), nTab );
987 // output page fields:
989 for (nField=0; nField<nPageFieldCount; nField++)
991 SCCOL nHdrCol = aStartPos.Col();
992 SCROW nHdrRow = aStartPos.Row() + nField + ( bDoFilter ? 1 : 0 );
993 // draw without frame for consistency with filter button:
994 FieldCell(nHdrCol, nHdrRow, nTab, pPageFields[nField], false);
995 SCCOL nFldCol = nHdrCol + 1;
997 OUString aPageValue = ScResId(SCSTR_ALL).toString();
998 const uno::Sequence<sheet::MemberResult>& rRes = pPageFields[nField].aResult;
999 sal_Int32 n = rRes.getLength();
1000 if (n == 1)
1001 aPageValue = rRes[0].Caption;
1002 else if (n > 1)
1003 aPageValue = ScResId(SCSTR_MULTIPLE).toString();
1005 ScSetStringParam aParam;
1006 aParam.setTextInput();
1007 pDoc->SetString(nFldCol, nHdrRow, nTab, aPageValue, &aParam);
1009 lcl_SetFrame( pDoc,nTab, nFldCol,nHdrRow, nFldCol,nHdrRow, 20 );
1012 // data description
1013 // (may get overwritten by first row field)
1015 if (aDataDescription.isEmpty())
1017 //TODO: use default string ("result") ?
1019 pDoc->SetString(nTabStartCol, nTabStartRow, nTab, aDataDescription);
1021 // set STR_PIVOT_STYLE_INNER for whole data area (subtotals are overwritten)
1023 if ( nDataStartRow > nTabStartRow )
1024 lcl_SetStyleById( pDoc, nTab, nTabStartCol, nTabStartRow, nTabEndCol, nDataStartRow-1,
1025 STR_PIVOT_STYLE_TOP );
1026 lcl_SetStyleById( pDoc, nTab, nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow,
1027 STR_PIVOT_STYLE_INNER );
1029 // output column headers:
1030 ScDPOutputImpl outputimp( pDoc, nTab,
1031 nTabStartCol, nTabStartRow,
1032 nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow );
1033 for (nField=0; nField<nColFieldCount; nField++)
1035 SCCOL nHdrCol = nDataStartCol + (SCCOL)nField; //TODO: check for overflow
1036 FieldCell(nHdrCol, nTabStartRow, nTab, pColFields[nField], true);
1038 SCROW nRowPos = nMemberStartRow + (SCROW)nField; //TODO: check for overflow
1039 const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].aResult;
1040 const sheet::MemberResult* pArray = rSequence.getConstArray();
1041 long nThisColCount = rSequence.getLength();
1042 OSL_ENSURE( nThisColCount == nColCount, "count mismatch" ); //TODO: ???
1043 for (long nCol=0; nCol<nThisColCount; nCol++)
1045 SCCOL nColPos = nDataStartCol + (SCCOL)nCol; //TODO: check for overflow
1046 HeaderCell( nColPos, nRowPos, nTab, pArray[nCol], true, nField );
1047 if ( ( pArray[nCol].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
1048 !( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
1050 long nEnd = nCol;
1051 while ( nEnd+1 < nThisColCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
1052 ++nEnd;
1053 SCCOL nEndColPos = nDataStartCol + (SCCOL)nEnd; //TODO: check for overflow
1054 if ( nField+1 < nColFieldCount )
1056 if ( nField == nColFieldCount - 2 )
1058 outputimp.AddCol( nColPos );
1059 if ( nColPos + 1 == nEndColPos )
1060 outputimp.OutputBlockFrame( nColPos,nRowPos, nEndColPos,nRowPos+1, true );
1062 else
1063 outputimp.OutputBlockFrame( nColPos,nRowPos, nEndColPos,nRowPos );
1065 lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nEndColPos,nDataStartRow-1, STR_PIVOT_STYLE_CATEGORY );
1067 else
1068 lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nColPos,nDataStartRow-1, STR_PIVOT_STYLE_CATEGORY );
1070 else if ( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL )
1071 outputimp.AddCol( nColPos );
1073 // Apply the same number format as in data source.
1074 pDoc->ApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, pColFields[nField].mnSrcNumFmt));
1076 if ( nField== 0 && nColFieldCount == 1 )
1077 outputimp.OutputBlockFrame( nDataStartCol,nTabStartRow, nTabEndCol,nRowPos-1 );
1080 // output row headers:
1081 std::vector<bool> vbSetBorder;
1082 vbSetBorder.resize( nTabEndRow - nDataStartRow + 1, false );
1083 for (nField=0; nField<nRowFieldCount; nField++)
1085 SCCOL nHdrCol = nTabStartCol + (SCCOL)nField; //TODO: check for overflow
1086 SCROW nHdrRow = nDataStartRow - 1;
1087 FieldCell(nHdrCol, nHdrRow, nTab, pRowFields[nField], true);
1089 SCCOL nColPos = nMemberStartCol + (SCCOL)nField; //TODO: check for overflow
1090 const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].aResult;
1091 const sheet::MemberResult* pArray = rSequence.getConstArray();
1092 long nThisRowCount = rSequence.getLength();
1093 OSL_ENSURE( nThisRowCount == nRowCount, "count mismatch" ); //TODO: ???
1094 for (long nRow=0; nRow<nThisRowCount; nRow++)
1096 SCROW nRowPos = nDataStartRow + (SCROW)nRow; //TODO: check for overflow
1097 HeaderCell( nColPos, nRowPos, nTab, pArray[nRow], false, nField );
1098 if ( ( pArray[nRow].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
1099 !( pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
1101 if ( nField+1 < nRowFieldCount )
1103 long nEnd = nRow;
1104 while ( nEnd+1 < nThisRowCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
1105 ++nEnd;
1106 SCROW nEndRowPos = nDataStartRow + (SCROW)nEnd; //TODO: check for overflow
1107 outputimp.AddRow( nRowPos );
1108 if ( !vbSetBorder[ nRow ] )
1110 outputimp.OutputBlockFrame( nColPos, nRowPos, nTabEndCol, nEndRowPos );
1111 vbSetBorder[ nRow ] = true;
1113 outputimp.OutputBlockFrame( nColPos, nRowPos, nColPos, nEndRowPos );
1115 if ( nField == nRowFieldCount - 2 )
1116 outputimp.OutputBlockFrame( nColPos+1, nRowPos, nColPos+1, nEndRowPos );
1118 lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nEndRowPos, STR_PIVOT_STYLE_CATEGORY );
1120 else
1121 lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nRowPos, STR_PIVOT_STYLE_CATEGORY );
1123 else if ( pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL )
1124 outputimp.AddRow( nRowPos );
1126 // Apply the same number format as in data source.
1127 pDoc->ApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, pRowFields[nField].mnSrcNumFmt));
1131 if (nColCount == 1 && nRowCount > 0 && nColFieldCount == 0)
1133 // the table contains exactly one data field and no column fields.
1134 // Display data description at top right corner.
1135 ScSetStringParam aParam;
1136 aParam.setTextInput();
1137 pDoc->SetString(nDataStartCol, nDataStartRow-1, nTab, aDataDescription, &aParam);
1140 // output data results:
1142 for (long nRow=0; nRow<nRowCount; nRow++)
1144 SCROW nRowPos = nDataStartRow + (SCROW)nRow; //TODO: check for overflow
1145 const sheet::DataResult* pColAry = pRowAry[nRow].getConstArray();
1146 long nThisColCount = pRowAry[nRow].getLength();
1147 OSL_ENSURE( nThisColCount == nColCount, "count mismatch" ); //TODO: ???
1148 for (long nCol=0; nCol<nThisColCount; nCol++)
1150 SCCOL nColPos = nDataStartCol + (SCCOL)nCol; //TODO: check for overflow
1151 DataCell( nColPos, nRowPos, nTab, pColAry[nCol] );
1155 outputimp.OutputDataArea();
1158 ScRange ScDPOutput::GetOutputRange( sal_Int32 nRegionType )
1160 using namespace ::com::sun::star::sheet;
1162 CalcSizes();
1164 SCTAB nTab = aStartPos.Tab();
1165 switch (nRegionType)
1167 case DataPilotOutputRangeType::RESULT:
1168 return ScRange(nDataStartCol, nDataStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
1169 case DataPilotOutputRangeType::TABLE:
1170 return ScRange(aStartPos.Col(), nTabStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
1171 default:
1172 OSL_ENSURE(nRegionType == DataPilotOutputRangeType::WHOLE, "ScDPOutput::GetOutputRange: unknown region type");
1173 break;
1175 return ScRange(aStartPos.Col(), aStartPos.Row(), nTab, nTabEndCol, nTabEndRow, nTab);
1178 ScRange ScDPOutput::GetOutputRange( sal_Int32 nRegionType ) const
1180 using namespace ::com::sun::star::sheet;
1182 if (!bSizesValid)
1183 return ScRange(ScAddress::INITIALIZE_INVALID);
1185 SCTAB nTab = aStartPos.Tab();
1186 switch (nRegionType)
1188 case DataPilotOutputRangeType::RESULT:
1189 return ScRange(nDataStartCol, nDataStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
1190 case DataPilotOutputRangeType::TABLE:
1191 return ScRange(aStartPos.Col(), nTabStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
1192 default:
1193 OSL_ENSURE(nRegionType == DataPilotOutputRangeType::WHOLE, "ScDPOutput::GetOutputRange: unknown region type");
1194 break;
1196 return ScRange(aStartPos.Col(), aStartPos.Row(), nTab, nTabEndCol, nTabEndRow, nTab);
1199 bool ScDPOutput::HasError()
1201 CalcSizes();
1203 return bSizeOverflow || bResultsError;
1206 long ScDPOutput::GetHeaderRows()
1208 return nPageFieldCount + ( bDoFilter ? 1 : 0 );
1211 void ScDPOutput::GetMemberResultNames(ScDPUniqueStringSet& rNames, long nDimension)
1213 // Return the list of all member names in a dimension's MemberResults.
1214 // Only the dimension has to be compared because this is only used with table data,
1215 // where each dimension occurs only once.
1217 uno::Sequence<sheet::MemberResult> aMemberResults;
1218 bool bFound = false;
1219 long nField;
1221 // look in column fields
1223 for (nField=0; nField<nColFieldCount && !bFound; nField++)
1224 if ( pColFields[nField].nDim == nDimension )
1226 aMemberResults = pColFields[nField].aResult;
1227 bFound = true;
1230 // look in row fields
1232 for (nField=0; nField<nRowFieldCount && !bFound; nField++)
1233 if ( pRowFields[nField].nDim == nDimension )
1235 aMemberResults = pRowFields[nField].aResult;
1236 bFound = true;
1239 // collect the member names
1241 if ( bFound )
1243 const sheet::MemberResult* pArray = aMemberResults.getConstArray();
1244 long nResultCount = aMemberResults.getLength();
1246 for (long nItem=0; nItem<nResultCount; nItem++)
1248 if ( pArray[nItem].Flags & sheet::MemberResultFlags::HASMEMBER )
1249 rNames.insert(pArray[nItem].Name);
1254 void ScDPOutput::SetHeaderLayout(bool bUseGrid)
1256 mbHeaderLayout = bUseGrid;
1257 bSizesValid = false;
1260 namespace {
1262 void lcl_GetTableVars( sal_Int32& rGrandTotalCols, sal_Int32& rGrandTotalRows, sal_Int32& rDataLayoutIndex,
1263 std::vector<OUString>& rDataNames, std::vector<OUString>& rGivenNames,
1264 sheet::DataPilotFieldOrientation& rDataOrient,
1265 const uno::Reference<sheet::XDimensionsSupplier>& xSource )
1267 rDataLayoutIndex = -1; // invalid
1268 rGrandTotalCols = 0;
1269 rGrandTotalRows = 0;
1270 rDataOrient = sheet::DataPilotFieldOrientation_HIDDEN;
1272 uno::Reference<beans::XPropertySet> xSrcProp( xSource, uno::UNO_QUERY );
1273 bool bColGrand = ScUnoHelpFunctions::GetBoolProperty(
1274 xSrcProp, OUString(SC_UNO_DP_COLGRAND));
1275 if ( bColGrand )
1276 rGrandTotalCols = 1; // default if data layout not in columns
1278 bool bRowGrand = ScUnoHelpFunctions::GetBoolProperty(
1279 xSrcProp, OUString(SC_UNO_DP_ROWGRAND));
1280 if ( bRowGrand )
1281 rGrandTotalRows = 1; // default if data layout not in rows
1283 if ( xSource.is() )
1285 // find index and orientation of "data layout" dimension, count data dimensions
1287 sal_Int32 nDataCount = 0;
1289 uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xSource->getDimensions() );
1290 long nDimCount = xDims->getCount();
1291 for (long nDim=0; nDim<nDimCount; nDim++)
1293 uno::Reference<uno::XInterface> xDim =
1294 ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1295 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1296 if ( xDimProp.is() )
1298 sheet::DataPilotFieldOrientation eDimOrient =
1299 (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
1300 xDimProp, OUString(SC_UNO_DP_ORIENTATION),
1301 sheet::DataPilotFieldOrientation_HIDDEN );
1302 if ( ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1303 OUString(SC_UNO_DP_ISDATALAYOUT) ) )
1305 rDataLayoutIndex = nDim;
1306 rDataOrient = eDimOrient;
1308 if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
1310 OUString aSourceName;
1311 OUString aGivenName;
1312 ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xDim );
1315 uno::Any aValue = xDimProp->getPropertyValue( SC_UNO_DP_LAYOUTNAME );
1317 if( aValue.hasValue() )
1319 OUString strLayoutName;
1321 if( ( aValue >>= strLayoutName ) && !strLayoutName.isEmpty() )
1322 aGivenName = strLayoutName;
1325 catch(const uno::Exception&)
1328 rDataNames.push_back( aSourceName );
1329 rGivenNames.push_back( aGivenName );
1331 ++nDataCount;
1336 if ( ( rDataOrient == sheet::DataPilotFieldOrientation_COLUMN ) && bColGrand )
1337 rGrandTotalCols = nDataCount;
1338 else if ( ( rDataOrient == sheet::DataPilotFieldOrientation_ROW ) && bRowGrand )
1339 rGrandTotalRows = nDataCount;
1345 void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
1347 using namespace ::com::sun::star::sheet;
1349 SCCOL nCol = rPos.Col();
1350 SCROW nRow = rPos.Row();
1351 SCTAB nTab = rPos.Tab();
1352 if ( nTab != aStartPos.Tab() )
1353 return; // wrong sheet
1355 // calculate output positions and sizes
1357 CalcSizes();
1359 rPosData.PositionType = GetPositionType(rPos);
1360 switch (rPosData.PositionType)
1362 case DataPilotTablePositionType::RESULT:
1364 vector<DataPilotFieldFilter> aFilters;
1365 GetDataResultPositionData(aFilters, rPos);
1366 sal_Int32 nSize = aFilters.size();
1368 DataPilotTableResultData aResData;
1369 aResData.FieldFilters.realloc(nSize);
1370 for (sal_Int32 i = 0; i < nSize; ++i)
1371 aResData.FieldFilters[i] = aFilters[i];
1373 aResData.DataFieldIndex = 0;
1374 Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
1375 if (xPropSet.is())
1377 sal_Int32 nDataFieldCount = ScUnoHelpFunctions::GetLongProperty( xPropSet,
1378 OUString(SC_UNO_DP_DATAFIELDCOUNT) );
1379 if (nDataFieldCount > 0)
1380 aResData.DataFieldIndex = (nRow - nDataStartRow) % nDataFieldCount;
1383 // Copy appropriate DataResult object from the cached sheet::DataResult table.
1384 if (aData.getLength() > nRow - nDataStartRow &&
1385 aData[nRow-nDataStartRow].getLength() > nCol-nDataStartCol)
1386 aResData.Result = aData[nRow-nDataStartRow][nCol-nDataStartCol];
1388 rPosData.PositionData = makeAny(aResData);
1389 return;
1391 case DataPilotTablePositionType::COLUMN_HEADER:
1393 long nField = nRow - nTabStartRow - 1; // 1st line is used for the buttons
1394 if (nField < 0)
1395 break;
1397 const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].aResult;
1398 if (rSequence.getLength() == 0)
1399 break;
1400 const sheet::MemberResult* pArray = rSequence.getConstArray();
1402 long nItem = nCol - nDataStartCol;
1403 // get origin of "continue" fields
1404 while (nItem > 0 && ( pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1405 --nItem;
1407 if (nItem < 0)
1408 break;
1410 DataPilotTableHeaderData aHeaderData;
1411 aHeaderData.MemberName = OUString(pArray[nItem].Name);
1412 aHeaderData.Flags = pArray[nItem].Flags;
1413 aHeaderData.Dimension = static_cast<sal_Int32>(pColFields[nField].nDim);
1414 aHeaderData.Hierarchy = static_cast<sal_Int32>(pColFields[nField].nHier);
1415 aHeaderData.Level = static_cast<sal_Int32>(pColFields[nField].nLevel);
1417 rPosData.PositionData = makeAny(aHeaderData);
1418 return;
1420 case DataPilotTablePositionType::ROW_HEADER:
1422 long nField = nCol - nTabStartCol;
1423 if (nField < 0)
1424 break;
1426 const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].aResult;
1427 if (rSequence.getLength() == 0)
1428 break;
1429 const sheet::MemberResult* pArray = rSequence.getConstArray();
1431 long nItem = nRow - nDataStartRow;
1432 // get origin of "continue" fields
1433 while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1434 --nItem;
1436 if (nItem < 0)
1437 break;
1439 DataPilotTableHeaderData aHeaderData;
1440 aHeaderData.MemberName = OUString(pArray[nItem].Name);
1441 aHeaderData.Flags = pArray[nItem].Flags;
1442 aHeaderData.Dimension = static_cast<sal_Int32>(pRowFields[nField].nDim);
1443 aHeaderData.Hierarchy = static_cast<sal_Int32>(pRowFields[nField].nHier);
1444 aHeaderData.Level = static_cast<sal_Int32>(pRowFields[nField].nLevel);
1446 rPosData.PositionData = makeAny(aHeaderData);
1447 return;
1452 bool ScDPOutput::GetDataResultPositionData(vector<sheet::DataPilotFieldFilter>& rFilters, const ScAddress& rPos)
1454 // Check to make sure there is at least one data field.
1455 Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
1456 if (!xPropSet.is())
1457 return false;
1459 sal_Int32 nDataFieldCount = ScUnoHelpFunctions::GetLongProperty( xPropSet,
1460 OUString(SC_UNO_DP_DATAFIELDCOUNT) );
1461 if (nDataFieldCount == 0)
1462 // No data field is present in this datapilot table.
1463 return false;
1465 // #i111421# use lcl_GetTableVars for correct size of totals and data layout position
1466 sal_Int32 nGrandTotalCols;
1467 sal_Int32 nGrandTotalRows;
1468 sal_Int32 nDataLayoutIndex;
1469 std::vector<OUString> aDataNames;
1470 std::vector<OUString> aGivenNames;
1471 sheet::DataPilotFieldOrientation eDataOrient;
1472 lcl_GetTableVars( nGrandTotalCols, nGrandTotalRows, nDataLayoutIndex, aDataNames, aGivenNames, eDataOrient, xSource );
1474 SCCOL nCol = rPos.Col();
1475 SCROW nRow = rPos.Row();
1476 SCTAB nTab = rPos.Tab();
1477 if ( nTab != aStartPos.Tab() )
1478 return false; // wrong sheet
1480 CalcSizes();
1482 // test for data area.
1483 if (nCol < nDataStartCol || nCol > nTabEndCol || nRow < nDataStartRow || nRow > nTabEndRow)
1485 // Cell is outside the data field area.
1486 return false;
1489 bool bFilterByCol = (nCol <= static_cast<SCCOL>(nTabEndCol - nGrandTotalCols));
1490 bool bFilterByRow = (nRow <= static_cast<SCROW>(nTabEndRow - nGrandTotalRows));
1492 // column fields
1493 for (SCCOL nColField = 0; nColField < nColFieldCount && bFilterByCol; ++nColField)
1495 if (pColFields[nColField].nDim == nDataLayoutIndex)
1496 // There is no sense including the data layout field for filtering.
1497 continue;
1499 sheet::DataPilotFieldFilter filter;
1500 filter.FieldName = pColFields[nColField].maName;
1502 const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nColField].aResult;
1503 const sheet::MemberResult* pArray = rSequence.getConstArray();
1505 OSL_ENSURE(nDataStartCol + rSequence.getLength() - 1 == nTabEndCol, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1507 long nItem = nCol - nDataStartCol;
1508 // get origin of "continue" fields
1509 while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1510 --nItem;
1512 filter.MatchValue = pArray[nItem].Name;
1513 rFilters.push_back(filter);
1516 // row fields
1517 for (SCROW nRowField = 0; nRowField < nRowFieldCount && bFilterByRow; ++nRowField)
1519 if (pRowFields[nRowField].nDim == nDataLayoutIndex)
1520 // There is no sense including the data layout field for filtering.
1521 continue;
1523 sheet::DataPilotFieldFilter filter;
1524 filter.FieldName = pRowFields[nRowField].maName;
1526 const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nRowField].aResult;
1527 const sheet::MemberResult* pArray = rSequence.getConstArray();
1529 OSL_ENSURE(nDataStartRow + rSequence.getLength() - 1 == nTabEndRow, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1531 long nItem = nRow - nDataStartRow;
1532 // get origin of "continue" fields
1533 while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1534 --nItem;
1536 filter.MatchValue = pArray[nItem].Name;
1537 rFilters.push_back(filter);
1540 return true;
1543 namespace {
1545 OUString lcl_GetDataFieldName( const OUString& rSourceName, sheet::GeneralFunction eFunc )
1547 sal_uInt16 nStrId = 0;
1548 switch ( eFunc )
1550 case sheet::GeneralFunction_SUM: nStrId = STR_FUN_TEXT_SUM; break;
1551 case sheet::GeneralFunction_COUNT:
1552 case sheet::GeneralFunction_COUNTNUMS: nStrId = STR_FUN_TEXT_COUNT; break;
1553 case sheet::GeneralFunction_AVERAGE: nStrId = STR_FUN_TEXT_AVG; break;
1554 case sheet::GeneralFunction_MAX: nStrId = STR_FUN_TEXT_MAX; break;
1555 case sheet::GeneralFunction_MIN: nStrId = STR_FUN_TEXT_MIN; break;
1556 case sheet::GeneralFunction_PRODUCT: nStrId = STR_FUN_TEXT_PRODUCT; break;
1557 case sheet::GeneralFunction_STDEV:
1558 case sheet::GeneralFunction_STDEVP: nStrId = STR_FUN_TEXT_STDDEV; break;
1559 case sheet::GeneralFunction_VAR:
1560 case sheet::GeneralFunction_VARP: nStrId = STR_FUN_TEXT_VAR; break;
1561 case sheet::GeneralFunction_NONE:
1562 case sheet::GeneralFunction_AUTO:
1563 default:
1565 OSL_FAIL("wrong function");
1568 if ( !nStrId )
1569 return OUString();
1571 OUStringBuffer aRet( ScGlobal::GetRscString( nStrId ) );
1572 aRet.append(" - ");
1573 aRet.append(rSourceName);
1574 return aRet.makeStringAndClear();
1579 void ScDPOutput::GetDataDimensionNames(
1580 OUString& rSourceName, OUString& rGivenName, const uno::Reference<uno::XInterface>& xDim )
1582 uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1583 uno::Reference<container::XNamed> xDimName( xDim, uno::UNO_QUERY );
1584 if ( xDimProp.is() && xDimName.is() )
1586 // Asterisks are added in ScDPSaveData::WriteToSource to create unique names.
1587 //TODO: preserve original name there?
1588 rSourceName = ScDPUtil::getSourceDimensionName(xDimName->getName());
1590 // Generate "given name" the same way as in dptabres.
1591 //TODO: Should use a stored name when available
1593 sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
1594 xDimProp, OUString(SC_UNO_DP_FUNCTION),
1595 sheet::GeneralFunction_NONE );
1596 rGivenName = lcl_GetDataFieldName( rSourceName, eFunc );
1600 bool ScDPOutput::IsFilterButton( const ScAddress& rPos )
1602 SCCOL nCol = rPos.Col();
1603 SCROW nRow = rPos.Row();
1604 SCTAB nTab = rPos.Tab();
1605 if ( nTab != aStartPos.Tab() || !bDoFilter )
1606 return false; // wrong sheet or no button at all
1608 // filter button is at top left
1609 return ( nCol == aStartPos.Col() && nRow == aStartPos.Row() );
1612 long ScDPOutput::GetHeaderDim( const ScAddress& rPos, sal_uInt16& rOrient )
1614 SCCOL nCol = rPos.Col();
1615 SCROW nRow = rPos.Row();
1616 SCTAB nTab = rPos.Tab();
1617 if ( nTab != aStartPos.Tab() )
1618 return -1; // wrong sheet
1620 // calculate output positions and sizes
1622 CalcSizes();
1624 // test for column header
1626 if ( nRow == nTabStartRow && nCol >= nDataStartCol && nCol < nDataStartCol + nColFieldCount )
1628 rOrient = sheet::DataPilotFieldOrientation_COLUMN;
1629 long nField = nCol - nDataStartCol;
1630 return pColFields[nField].nDim;
1633 // test for row header
1635 if ( nRow+1 == nDataStartRow && nCol >= nTabStartCol && nCol < nTabStartCol + nRowFieldCount )
1637 rOrient = sheet::DataPilotFieldOrientation_ROW;
1638 long nField = nCol - nTabStartCol;
1639 return pRowFields[nField].nDim;
1642 // test for page field
1644 SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 );
1645 if ( nCol == aStartPos.Col() && nRow >= nPageStartRow && nRow < nPageStartRow + nPageFieldCount )
1647 rOrient = sheet::DataPilotFieldOrientation_PAGE;
1648 long nField = nRow - nPageStartRow;
1649 return pPageFields[nField].nDim;
1652 //TODO: single data field (?)
1654 rOrient = sheet::DataPilotFieldOrientation_HIDDEN;
1655 return -1; // invalid
1658 bool ScDPOutput::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMouseTop,
1659 long nDragDim,
1660 Rectangle& rPosRect, sal_uInt16& rOrient, long& rDimPos )
1662 // Rectangle instead of ScRange for rPosRect to allow for negative values
1664 SCCOL nCol = rPos.Col();
1665 SCROW nRow = rPos.Row();
1666 SCTAB nTab = rPos.Tab();
1667 if ( nTab != aStartPos.Tab() )
1668 return false; // wrong sheet
1670 // calculate output positions and sizes
1672 CalcSizes();
1674 // test for column header
1676 if ( nCol >= nDataStartCol && nCol <= nTabEndCol &&
1677 nRow + 1 >= nMemberStartRow && nRow < nMemberStartRow + nColFieldCount )
1679 long nField = nRow - nMemberStartRow;
1680 if (nField < 0)
1682 nField = 0;
1683 bMouseTop = true;
1685 //TODO: find start of dimension
1687 rPosRect = Rectangle( nDataStartCol, nMemberStartRow + nField,
1688 nTabEndCol, nMemberStartRow + nField -1 );
1690 bool bFound = false; // is this within the same orientation?
1691 bool bBeforeDrag = false;
1692 bool bAfterDrag = false;
1693 for (long nPos=0; nPos<nColFieldCount && !bFound; nPos++)
1695 if (pColFields[nPos].nDim == nDragDim)
1697 bFound = true;
1698 if ( nField < nPos )
1699 bBeforeDrag = true;
1700 else if ( nField > nPos )
1701 bAfterDrag = true;
1705 if ( bFound )
1707 if (!bBeforeDrag)
1709 ++rPosRect.Bottom();
1710 if (bAfterDrag)
1711 ++rPosRect.Top();
1714 else
1716 if ( !bMouseTop )
1718 ++rPosRect.Top();
1719 ++rPosRect.Bottom();
1720 ++nField;
1724 rOrient = sheet::DataPilotFieldOrientation_COLUMN;
1725 rDimPos = nField; //!...
1726 return true;
1729 // test for row header
1731 // special case if no row fields
1732 bool bSpecial = ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow &&
1733 nRowFieldCount == 0 && nCol == nTabStartCol && bMouseLeft );
1735 if ( bSpecial || ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow &&
1736 nCol + 1 >= nTabStartCol && nCol < nTabStartCol + nRowFieldCount ) )
1738 long nField = nCol - nTabStartCol;
1739 //TODO: find start of dimension
1741 rPosRect = Rectangle( nTabStartCol + nField, nDataStartRow - 1,
1742 nTabStartCol + nField - 1, nTabEndRow );
1744 bool bFound = false; // is this within the same orientation?
1745 bool bBeforeDrag = false;
1746 bool bAfterDrag = false;
1747 for (long nPos=0; nPos<nRowFieldCount && !bFound; nPos++)
1749 if (pRowFields[nPos].nDim == nDragDim)
1751 bFound = true;
1752 if ( nField < nPos )
1753 bBeforeDrag = true;
1754 else if ( nField > nPos )
1755 bAfterDrag = true;
1759 if ( bFound )
1761 if (!bBeforeDrag)
1763 ++rPosRect.Right();
1764 if (bAfterDrag)
1765 ++rPosRect.Left();
1768 else
1770 if ( !bMouseLeft )
1772 ++rPosRect.Left();
1773 ++rPosRect.Right();
1774 ++nField;
1778 rOrient = sheet::DataPilotFieldOrientation_ROW;
1779 rDimPos = nField; //!...
1780 return true;
1783 // test for page fields
1785 SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 );
1786 if ( nCol >= aStartPos.Col() && nCol <= nTabEndCol &&
1787 nRow + 1 >= nPageStartRow && nRow < nPageStartRow + nPageFieldCount )
1789 long nField = nRow - nPageStartRow;
1790 if (nField < 0)
1792 nField = 0;
1793 bMouseTop = true;
1795 //TODO: find start of dimension
1797 rPosRect = Rectangle( aStartPos.Col(), nPageStartRow + nField,
1798 nTabEndCol, nPageStartRow + nField - 1 );
1800 bool bFound = false; // is this within the same orientation?
1801 bool bBeforeDrag = false;
1802 bool bAfterDrag = false;
1803 for (long nPos=0; nPos<nPageFieldCount && !bFound; nPos++)
1805 if (pPageFields[nPos].nDim == nDragDim)
1807 bFound = true;
1808 if ( nField < nPos )
1809 bBeforeDrag = true;
1810 else if ( nField > nPos )
1811 bAfterDrag = true;
1815 if ( bFound )
1817 if (!bBeforeDrag)
1819 ++rPosRect.Bottom();
1820 if (bAfterDrag)
1821 ++rPosRect.Top();
1824 else
1826 if ( !bMouseTop )
1828 ++rPosRect.Top();
1829 ++rPosRect.Bottom();
1830 ++nField;
1834 rOrient = sheet::DataPilotFieldOrientation_PAGE;
1835 rDimPos = nField; //!...
1836 return true;
1839 return false;
1842 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */