LibreOffice Module sc (master)  1
dpoutput.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <scitems.hxx>
21 #include <editeng/borderline.hxx>
22 #include <editeng/boxitem.hxx>
23 #include <editeng/wghtitem.hxx>
24 #include <editeng/justifyitem.hxx>
25 #include <o3tl/safeint.hxx>
26 #include <osl/diagnose.h>
27 #include <svl/itemset.hxx>
28 
29 #include <dpoutput.hxx>
30 #include <document.hxx>
31 #include <attrib.hxx>
32 #include <formula/errorcodes.hxx>
33 #include <miscuno.hxx>
34 #include <globstr.hrc>
35 #include <stlpool.hxx>
36 #include <stlsheet.hxx>
37 #include <scresid.hxx>
38 #include <unonames.hxx>
39 #include <strings.hrc>
40 #include <stringutil.hxx>
41 #include <dputil.hxx>
42 
43 #include <com/sun/star/beans/XPropertySet.hpp>
44 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
45 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
46 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
47 #include <com/sun/star/sheet/DataPilotTableResultData.hpp>
48 #include <com/sun/star/sheet/MemberResultFlags.hpp>
49 #include <com/sun/star/sheet/DataResultFlags.hpp>
50 #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
51 #include <com/sun/star/sheet/GeneralFunction2.hpp>
52 #include <com/sun/star/sheet/MemberResult.hpp>
53 #include <com/sun/star/sheet/XDataPilotMemberResults.hpp>
54 #include <com/sun/star/sheet/XDataPilotResults.hpp>
55 #include <com/sun/star/sheet/XDimensionsSupplier.hpp>
56 #include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
57 #include <com/sun/star/sheet/XLevelsSupplier.hpp>
58 #include <com/sun/star/sheet/XMembersAccess.hpp>
59 #include <com/sun/star/sheet/XMembersSupplier.hpp>
60 #include <vector>
61 
62 using namespace com::sun::star;
63 using ::std::vector;
64 using ::com::sun::star::beans::XPropertySet;
65 using ::com::sun::star::uno::Sequence;
66 using ::com::sun::star::uno::UNO_QUERY;
67 using ::com::sun::star::uno::Reference;
68 using ::com::sun::star::sheet::DataPilotTablePositionData;
69 using ::com::sun::star::sheet::DataPilotTableResultData;
70 
71 #define SC_DP_FRAME_INNER_BOLD 20
72 #define SC_DP_FRAME_OUTER_BOLD 40
73 
74 #define SC_DP_FRAME_COLOR Color(0,0,0) //( 0x20, 0x40, 0x68 )
75 
77 {
82  sal_uInt32 mnSrcNumFmt;
83  uno::Sequence<sheet::MemberResult> maResult;
84  OUString maName;
85  OUString maCaption;
86  bool mbHasHiddenMember:1;
87  bool mbDataLayout:1;
88  bool mbPageDim:1;
89 
90  ScDPOutLevelData(tools::Long nDim, tools::Long nHier, tools::Long nLevel, tools::Long nDimPos, sal_uInt32 nSrcNumFmt, const uno::Sequence<sheet::MemberResult> &aResult,
91  const OUString &aName, const OUString &aCaption, bool bHasHiddenMember, bool bDataLayout, bool bPageDim) :
92  mnDim(nDim), mnHier(nHier), mnLevel(nLevel), mnDimPos(nDimPos), mnSrcNumFmt(nSrcNumFmt), maResult(aResult),
93  maName(aName), maCaption(aCaption), mbHasHiddenMember(bHasHiddenMember), mbDataLayout(bDataLayout),
94  mbPageDim(bPageDim)
95  {
96  }
97 
98  // bug (73840) in uno::Sequence - copy and then assign doesn't work!
99 };
100 
101 
102 
103 namespace {
104  struct ScDPOutLevelDataComparator
105  {
106  bool operator()(const ScDPOutLevelData & rA, const ScDPOutLevelData & rB)
107  {
108  return rA.mnDimPos<rB.mnDimPos || ( rA.mnDimPos==rB.mnDimPos && rA.mnHier<rB.mnHier ) ||
109  ( rA.mnDimPos==rB.mnDimPos && rA.mnHier==rB.mnHier && rA.mnLevel<rB.mnLevel );
110  }
111  };
112 
113 
114 class ScDPOutputImpl
115 {
116  ScDocument* mpDoc;
117  sal_uInt16 mnTab;
118  ::std::vector< bool > mbNeedLineCols;
119  ::std::vector< SCCOL > mnCols;
120 
121  ::std::vector< bool > mbNeedLineRows;
122  ::std::vector< SCROW > mnRows;
123 
124  SCCOL mnTabStartCol;
125  SCROW mnTabStartRow;
126 
127  SCCOL mnDataStartCol;
128  SCROW mnDataStartRow;
129  SCCOL mnTabEndCol;
130  SCROW mnTabEndRow;
131 
132 public:
133  ScDPOutputImpl( ScDocument* pDoc, sal_uInt16 nTab,
134  SCCOL nTabStartCol,
135  SCROW nTabStartRow,
136  SCCOL nDataStartCol,
137  SCROW nDataStartRow,
138  SCCOL nTabEndCol,
139  SCROW nTabEndRow );
140  bool AddRow( SCROW nRow );
141  bool AddCol( SCCOL nCol );
142 
143  void OutputDataArea();
144  void OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bHori = false );
145 
146 };
147 
148 void ScDPOutputImpl::OutputDataArea()
149 {
150  AddRow( mnDataStartRow );
151  AddCol( mnDataStartCol );
152 
153  mnCols.push_back( mnTabEndCol+1); //set last row bottom
154  mnRows.push_back( mnTabEndRow+1); //set last col bottom
155 
156  bool bAllRows = ( ( mnTabEndRow - mnDataStartRow + 2 ) == static_cast<SCROW>(mnRows.size()) );
157 
158  std::sort( mnCols.begin(), mnCols.end());
159  std::sort( mnRows.begin(), mnRows.end());
160 
161  for( SCCOL nCol = 0; nCol < static_cast<SCCOL>(mnCols.size())-1; nCol ++ )
162  {
163  if ( !bAllRows )
164  {
165  if ( nCol < static_cast<SCCOL>(mnCols.size())-2)
166  {
167  for ( SCROW i = nCol%2; i < static_cast<SCROW>(mnRows.size())-2; i +=2 )
168  OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 );
169  if ( mnRows.size()>=2 )
170  OutputBlockFrame( mnCols[nCol], mnRows[mnRows.size()-2], mnCols[nCol+1]-1, mnRows[mnRows.size()-1]-1 );
171  }
172  else
173  {
174  for ( SCROW i = 0 ; i < static_cast<SCROW>(mnRows.size())-1; i++ )
175  OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 );
176  }
177  }
178  else
179  OutputBlockFrame( mnCols[nCol], mnRows.front(), mnCols[nCol+1]-1, mnRows.back()-1, bAllRows );
180  }
181  //out put rows area outer framer
182  if ( mnTabStartCol != mnDataStartCol )
183  {
184  if ( mnTabStartRow != mnDataStartRow )
185  OutputBlockFrame( mnTabStartCol, mnTabStartRow, mnDataStartCol-1, mnDataStartRow-1 );
186  OutputBlockFrame( mnTabStartCol, mnDataStartRow, mnDataStartCol-1, mnTabEndRow );
187  }
188  //out put cols area outer framer
189  OutputBlockFrame( mnDataStartCol, mnTabStartRow, mnTabEndCol, mnDataStartRow-1 );
190 }
191 
192 ScDPOutputImpl::ScDPOutputImpl( ScDocument* pDoc, sal_uInt16 nTab,
193  SCCOL nTabStartCol,
194  SCROW nTabStartRow,
195  SCCOL nDataStartCol,
196  SCROW nDataStartRow,
197  SCCOL nTabEndCol,
198  SCROW nTabEndRow ):
199  mpDoc( pDoc ),
200  mnTab( nTab ),
201  mnTabStartCol( nTabStartCol ),
202  mnTabStartRow( nTabStartRow ),
203  mnDataStartCol ( nDataStartCol ),
204  mnDataStartRow ( nDataStartRow ),
205  mnTabEndCol( nTabEndCol ),
206  mnTabEndRow( nTabEndRow )
207 {
208  mbNeedLineCols.resize( nTabEndCol-nDataStartCol+1, false );
209  mbNeedLineRows.resize( nTabEndRow-nDataStartRow+1, false );
210 
211 }
212 
213 bool ScDPOutputImpl::AddRow( SCROW nRow )
214 {
215  if ( !mbNeedLineRows[ nRow - mnDataStartRow ] )
216  {
217  mbNeedLineRows[ nRow - mnDataStartRow ] = true;
218  mnRows.push_back( nRow );
219  return true;
220  }
221  else
222  return false;
223 }
224 
225 bool ScDPOutputImpl::AddCol( SCCOL nCol )
226 {
227 
228  if ( !mbNeedLineCols[ nCol - mnDataStartCol ] )
229  {
230  mbNeedLineCols[ nCol - mnDataStartCol ] = true;
231  mnCols.push_back( nCol );
232  return true;
233  }
234  else
235  return false;
236 }
237 
238 void ScDPOutputImpl::OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bHori )
239 {
243 
244  SvxBoxItem aBox( ATTR_BORDER );
245 
246  if ( nStartCol == mnTabStartCol )
247  aBox.SetLine(&aOutLine, SvxBoxItemLine::LEFT);
248  else
249  aBox.SetLine(&aLine, SvxBoxItemLine::LEFT);
250 
251  if ( nStartRow == mnTabStartRow )
252  aBox.SetLine(&aOutLine, SvxBoxItemLine::TOP);
253  else
254  aBox.SetLine(&aLine, SvxBoxItemLine::TOP);
255 
256  if ( nEndCol == mnTabEndCol ) //bottom row
257  aBox.SetLine(&aOutLine, SvxBoxItemLine::RIGHT);
258  else
259  aBox.SetLine(&aLine, SvxBoxItemLine::RIGHT);
260 
261  if ( nEndRow == mnTabEndRow ) //bottom
262  aBox.SetLine(&aOutLine, SvxBoxItemLine::BOTTOM);
263  else
264  aBox.SetLine(&aLine, SvxBoxItemLine::BOTTOM);
265 
266  SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
267  aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT,false );
268  if ( bHori )
269  {
270  aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI);
271  aBoxInfo.SetLine( &aLine, SvxBoxInfoItemLine::HORI );
272  }
273  else
274  aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI,false );
275 
276  aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE,false);
277 
278  mpDoc->ApplyFrameAreaTab(ScRange(nStartCol, nStartRow, mnTab, nEndCol, nEndRow , mnTab), aBox, aBoxInfo);
279 
280 }
281 
282 void lcl_SetStyleById(ScDocument* pDoc, SCTAB nTab,
283  SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
284  const char* pStrId)
285 {
286  if ( nCol1 > nCol2 || nRow1 > nRow2 )
287  {
288  OSL_FAIL("SetStyleById: invalid range");
289  return;
290  }
291 
292  OUString aStyleName = ScResId(pStrId);
293  ScStyleSheetPool* pStlPool = pDoc->GetStyleSheetPool();
294  ScStyleSheet* pStyle = static_cast<ScStyleSheet*>( pStlPool->Find( aStyleName, SfxStyleFamily::Para ) );
295  if (!pStyle)
296  {
297  // create new style (was in ScPivot::SetStyle)
298 
299  pStyle = static_cast<ScStyleSheet*>( &pStlPool->Make( aStyleName, SfxStyleFamily::Para,
300  SfxStyleSearchBits::UserDefined ) );
301  pStyle->SetParent( ScResId(STR_STYLENAME_STANDARD_CELL) );
302  SfxItemSet& rSet = pStyle->GetItemSet();
303  if (strcmp(pStrId, STR_PIVOT_STYLENAME_RESULT) == 0 || strcmp(pStrId, STR_PIVOT_STYLENAME_TITLE) == 0){
304  rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
305  rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_CJK_FONT_WEIGHT ) );
306  rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_CTL_FONT_WEIGHT ) );
307  }
308  if (strcmp(pStrId, STR_PIVOT_STYLENAME_CATEGORY) == 0 || strcmp(pStrId, STR_PIVOT_STYLENAME_TITLE) == 0)
309  rSet.Put( SvxHorJustifyItem( SvxCellHorJustify::Left, ATTR_HOR_JUSTIFY ) );
310  }
311 
312  pDoc->ApplyStyleAreaTab( nCol1, nRow1, nCol2, nRow2, nTab, *pStyle );
313 }
314 
315 void lcl_SetFrame( ScDocument* pDoc, SCTAB nTab,
316  SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
317  sal_uInt16 nWidth )
318 {
319  ::editeng::SvxBorderLine aLine(nullptr, nWidth, SvxBorderLineStyle::SOLID);
320  SvxBoxItem aBox( ATTR_BORDER );
321  aBox.SetLine(&aLine, SvxBoxItemLine::LEFT);
322  aBox.SetLine(&aLine, SvxBoxItemLine::TOP);
323  aBox.SetLine(&aLine, SvxBoxItemLine::RIGHT);
324  aBox.SetLine(&aLine, SvxBoxItemLine::BOTTOM);
325  SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
326  aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI,false);
327  aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT,false);
328  aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE,false);
329 
330  pDoc->ApplyFrameAreaTab(ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab), aBox, aBoxInfo);
331 }
332 
333 void lcl_FillNumberFormats( std::unique_ptr<sal_uInt32[]>& rFormats, tools::Long& rCount,
334  const uno::Reference<sheet::XDataPilotMemberResults>& xLevRes,
335  const uno::Reference<container::XIndexAccess>& xDims )
336 {
337  if ( rFormats )
338  return; // already set
339 
340  // xLevRes is from the data layout dimension
341  //TODO: use result sequence from ScDPOutLevelData!
342 
343  uno::Sequence<sheet::MemberResult> aResult = xLevRes->getResults();
344 
345  tools::Long nSize = aResult.getLength();
346  if (!nSize)
347  return;
348 
349  // get names/formats for all data dimensions
350  //TODO: merge this with the loop to collect ScDPOutLevelData?
351 
352  std::vector <OUString> aDataNames;
353  std::vector <sal_uInt32> aDataFormats;
354  sal_Int32 nDimCount = xDims->getCount();
355  sal_Int32 nDim = 0;
356  for ( ; nDim < nDimCount ; nDim++)
357  {
358  uno::Reference<uno::XInterface> xDim(xDims->getByIndex(nDim), uno::UNO_QUERY);
359  uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
360  uno::Reference<container::XNamed> xDimName( xDim, uno::UNO_QUERY );
361  if ( xDimProp.is() && xDimName.is() )
362  {
363  sheet::DataPilotFieldOrientation eDimOrient =
365  xDimProp, SC_UNO_DP_ORIENTATION,
366  sheet::DataPilotFieldOrientation_HIDDEN );
367  if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
368  {
369  aDataNames.push_back(xDimName->getName());
371  xDimProp,
373  aDataFormats.push_back(nFormat);
374  }
375  }
376  }
377 
378  if (aDataFormats.empty())
379  return;
380 
381  const sheet::MemberResult* pArray = aResult.getConstArray();
382 
383  OUString aName;
384  sal_uInt32* pNumFmt = new sal_uInt32[nSize];
385  if (aDataFormats.size() == 1)
386  {
387  // only one data dimension -> use its numberformat everywhere
388  tools::Long nFormat = aDataFormats[0];
389  for (tools::Long nPos=0; nPos<nSize; nPos++)
390  pNumFmt[nPos] = nFormat;
391  }
392  else
393  {
394  for (tools::Long nPos=0; nPos<nSize; nPos++)
395  {
396  // if CONTINUE bit is set, keep previous name
397  //TODO: keep number format instead!
398  if ( !(pArray[nPos].Flags & sheet::MemberResultFlags::CONTINUE) )
399  aName = pArray[nPos].Name;
400 
401  sal_uInt32 nFormat = 0;
402  for (size_t i=0; i<aDataFormats.size(); i++)
403  if (aName == aDataNames[i]) //TODO: search more efficiently?
404  {
405  nFormat = aDataFormats[i];
406  break;
407  }
408  pNumFmt[nPos] = nFormat;
409  }
410  }
411 
412  rFormats.reset( pNumFmt );
413  rCount = nSize;
414 }
415 
416 sal_uInt32 lcl_GetFirstNumberFormat( const uno::Reference<container::XIndexAccess>& xDims )
417 {
418  tools::Long nDimCount = xDims->getCount();
419  for (tools::Long nDim=0; nDim<nDimCount; nDim++)
420  {
421  uno::Reference<beans::XPropertySet> xDimProp(xDims->getByIndex(nDim), uno::UNO_QUERY);
422  if ( xDimProp.is() )
423  {
424  sheet::DataPilotFieldOrientation eDimOrient =
426  xDimProp, SC_UNO_DP_ORIENTATION,
427  sheet::DataPilotFieldOrientation_HIDDEN );
428  if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
429  {
431  xDimProp,
433 
434  return nFormat; // use format from first found data dimension
435  }
436  }
437  }
438 
439  return 0; // none found
440 }
441 
442 bool lcl_MemberEmpty( const uno::Sequence<sheet::MemberResult>& rSeq )
443 {
444  // used to skip levels that have no members
445 
446  return std::none_of(rSeq.begin(), rSeq.end(),
447  [](const sheet::MemberResult& rMem) {
448  return rMem.Flags & sheet::MemberResultFlags::HASMEMBER; });
449 }
450 
455 uno::Sequence<sheet::MemberResult> getVisiblePageMembersAsResults( const uno::Reference<uno::XInterface>& xLevel )
456 {
457  if (!xLevel.is())
458  return uno::Sequence<sheet::MemberResult>();
459 
460  uno::Reference<sheet::XMembersSupplier> xMSupplier(xLevel, UNO_QUERY);
461  if (!xMSupplier.is())
462  return uno::Sequence<sheet::MemberResult>();
463 
464  uno::Reference<sheet::XMembersAccess> xNA = xMSupplier->getMembers();
465  if (!xNA.is())
466  return uno::Sequence<sheet::MemberResult>();
467 
468  std::vector<sheet::MemberResult> aRes;
469  const uno::Sequence<OUString> aNames = xNA->getElementNames();
470  for (const OUString& rName : aNames)
471  {
472  xNA->getByName(rName);
473 
474  uno::Reference<beans::XPropertySet> xMemPS(xNA->getByName(rName), UNO_QUERY);
475  if (!xMemPS.is())
476  continue;
477 
478  OUString aCaption = ScUnoHelpFunctions::GetStringProperty(xMemPS, SC_UNO_DP_LAYOUTNAME, OUString());
479  if (aCaption.isEmpty())
480  aCaption = rName;
481 
483 
484  if (bVisible)
485  {
486  /* TODO: any numeric value to obtain? */
487  double fValue;
488  rtl::math::setNan(&fValue);
489  aRes.emplace_back(rName, aCaption, 0, fValue);
490  }
491  }
492 
493  if (aNames.getLength() == static_cast<sal_Int32>(aRes.size()))
494  // All members are visible. Return empty result.
495  return uno::Sequence<sheet::MemberResult>();
496 
498 }
499 
500 }
501 
502 ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsSupplier>& xSrc,
503  const ScAddress& rPos, bool bFilter ) :
504  pDoc( pD ),
505  xSource( xSrc ),
506  aStartPos( rPos ),
507  nColFmtCount( 0 ),
508  nRowFmtCount( 0 ),
509  nSingleNumFmt( 0 ),
510  nColCount(0),
511  nRowCount(0),
512  nHeaderSize(0),
513  bDoFilter(bFilter),
514  bResultsError(false),
515  bSizesValid(false),
516  bSizeOverflow(false),
517  mbHeaderLayout(false)
518 {
519  nTabStartCol = nMemberStartCol = nDataStartCol = nTabEndCol = 0;
520  nTabStartRow = nMemberStartRow = nDataStartRow = nTabEndRow = 0;
521 
522  uno::Reference<sheet::XDataPilotResults> xResult( xSource, uno::UNO_QUERY );
523  if ( xSource.is() && xResult.is() )
524  {
525  // get dimension results:
526 
527  uno::Reference<container::XIndexAccess> xDims =
528  new ScNameToIndexAccess( xSource->getDimensions() );
529  tools::Long nDimCount = xDims->getCount();
530  for (tools::Long nDim=0; nDim<nDimCount; nDim++)
531  {
532  uno::Reference<uno::XInterface> xDim(xDims->getByIndex(nDim), uno::UNO_QUERY);
533  uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
534  uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
535  if ( xDimProp.is() && xDimSupp.is() )
536  {
537  sheet::DataPilotFieldOrientation eDimOrient =
539  xDimProp, SC_UNO_DP_ORIENTATION,
540  sheet::DataPilotFieldOrientation_HIDDEN );
543  bool bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty(
544  xDimProp, SC_UNO_DP_ISDATALAYOUT);
545  bool bHasHiddenMember = ScUnoHelpFunctions::GetBoolProperty(
546  xDimProp, SC_UNO_DP_HAS_HIDDEN_MEMBER);
547  sal_Int32 nNumFmt = ScUnoHelpFunctions::GetLongProperty(
548  xDimProp, SC_UNO_DP_NUMBERFO);
549 
550  if ( eDimOrient != sheet::DataPilotFieldOrientation_HIDDEN )
551  {
552  uno::Reference<container::XIndexAccess> xHiers =
553  new ScNameToIndexAccess( xDimSupp->getHierarchies() );
555  xDimProp,
557  if ( nHierarchy >= xHiers->getCount() )
558  nHierarchy = 0;
559 
560  uno::Reference<sheet::XLevelsSupplier> xHierSupp(xHiers->getByIndex(nHierarchy),
561  uno::UNO_QUERY);
562  if ( xHierSupp.is() )
563  {
564  uno::Reference<container::XIndexAccess> xLevels =
565  new ScNameToIndexAccess( xHierSupp->getLevels() );
566  tools::Long nLevCount = xLevels->getCount();
567  for (tools::Long nLev=0; nLev<nLevCount; nLev++)
568  {
569  uno::Reference<uno::XInterface> xLevel(xLevels->getByIndex(nLev),
570  uno::UNO_QUERY);
571  uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
572  uno::Reference<sheet::XDataPilotMemberResults> xLevRes(
573  xLevel, uno::UNO_QUERY );
574  if ( xLevNam.is() && xLevRes.is() )
575  {
576  OUString aName = xLevNam->getName();
577  Reference<XPropertySet> xPropSet(xLevel, UNO_QUERY);
578  // Caption equals the field name by default.
579  // #i108948# use ScUnoHelpFunctions::GetStringProperty, because
580  // LayoutName is new and may not be present in external implementation
581  OUString aCaption = ScUnoHelpFunctions::GetStringProperty( xPropSet,
582  SC_UNO_DP_LAYOUTNAME, aName );
583 
584  switch ( eDimOrient )
585  {
586  case sheet::DataPilotFieldOrientation_COLUMN:
587  {
588  uno::Sequence<sheet::MemberResult> aResult = xLevRes->getResults();
589  if (!lcl_MemberEmpty(aResult))
590  {
591  ScDPOutLevelData tmp(nDim, nHierarchy, nLev, nDimPos, nNumFmt, aResult, aName,
592  aCaption, bHasHiddenMember, bIsDataLayout, false);
593  pColFields.push_back(tmp);
594  }
595  }
596  break;
597  case sheet::DataPilotFieldOrientation_ROW:
598  {
599  uno::Sequence<sheet::MemberResult> aResult = xLevRes->getResults();
600  if (!lcl_MemberEmpty(aResult))
601  {
602  ScDPOutLevelData tmp(nDim, nHierarchy, nLev, nDimPos, nNumFmt, aResult, aName,
603  aCaption, bHasHiddenMember, bIsDataLayout, false);
604  pRowFields.push_back(tmp);
605  }
606  }
607  break;
608  case sheet::DataPilotFieldOrientation_PAGE:
609  {
610  uno::Sequence<sheet::MemberResult> aResult = getVisiblePageMembersAsResults(xLevel);
611  // no check on results for page fields
612  ScDPOutLevelData tmp(nDim, nHierarchy, nLev, nDimPos, nNumFmt, aResult, aName,
613  aCaption, bHasHiddenMember, false, true);
614  pPageFields.push_back(tmp);
615  }
616  break;
617  default:
618  {
619  // added to avoid warnings
620  }
621  }
622 
623  // get number formats from data dimensions
624  if ( bIsDataLayout )
625  {
626  OSL_ENSURE( nLevCount == 1, "data layout: multiple levels?" );
627  if ( eDimOrient == sheet::DataPilotFieldOrientation_COLUMN )
628  lcl_FillNumberFormats( pColNumFmt, nColFmtCount, xLevRes, xDims );
629  else if ( eDimOrient == sheet::DataPilotFieldOrientation_ROW )
630  lcl_FillNumberFormats( pRowNumFmt, nRowFmtCount, xLevRes, xDims );
631  }
632  }
633  }
634  }
635  }
636  else if ( bIsDataLayout )
637  {
638  // data layout dimension is hidden (allowed if there is only one data dimension)
639  // -> use the number format from the first data dimension for all results
640 
641  nSingleNumFmt = lcl_GetFirstNumberFormat( xDims );
642  }
643  }
644  }
645  std::sort(pColFields.begin(), pColFields.end(), ScDPOutLevelDataComparator());
646  std::sort(pRowFields.begin(), pRowFields.end(), ScDPOutLevelDataComparator());
647  std::sort(pPageFields.begin(), pPageFields.end(), ScDPOutLevelDataComparator());
648 
649  // get data results:
650 
651  try
652  {
653  aData = xResult->getResults();
654  }
655  catch (const uno::RuntimeException&)
656  {
657  bResultsError = true;
658  }
659  }
660 
661  // get "DataDescription" property (may be missing in external sources)
662 
663  uno::Reference<beans::XPropertySet> xSrcProp( xSource, uno::UNO_QUERY );
664  if ( !xSrcProp.is() )
665  return;
666 
667  try
668  {
669  uno::Any aAny = xSrcProp->getPropertyValue( SC_UNO_DP_DATADESC );
670  OUString aUStr;
671  aAny >>= aUStr;
672  aDataDescription = aUStr;
673  }
674  catch(const uno::Exception&)
675  {
676  }
677 }
678 
680 {
681 }
682 
684 {
685  aStartPos = rPos;
686  bSizesValid = bSizeOverflow = false;
687 }
688 
689 void ScDPOutput::DataCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const sheet::DataResult& rData )
690 {
691  tools::Long nFlags = rData.Flags;
692  if ( nFlags & sheet::DataResultFlags::ERROR )
693  {
694  pDoc->SetError( nCol, nRow, nTab, FormulaError::NoValue );
695  }
696  else if ( nFlags & sheet::DataResultFlags::HASDATA )
697  {
698  pDoc->SetValue( nCol, nRow, nTab, rData.Value );
699 
700  // use number formats from source
701 
702  OSL_ENSURE( bSizesValid, "DataCell: !bSizesValid" );
703  sal_uInt32 nFormat = 0;
704  bool bApplyFormat = false;
705  if ( pColNumFmt )
706  {
707  if ( nCol >= nDataStartCol )
708  {
710  if ( nIndex < nColFmtCount )
711  {
712  nFormat = pColNumFmt[nIndex];
713  bApplyFormat = true;
714  }
715  }
716  }
717  else if ( pRowNumFmt )
718  {
719  if ( nRow >= nDataStartRow )
720  {
722  if ( nIndex < nRowFmtCount )
723  {
724  nFormat = pRowNumFmt[nIndex];
725  bApplyFormat = true;
726  }
727  }
728  }
729  else if ( nSingleNumFmt != 0 )
730  {
731  nFormat = nSingleNumFmt; // single format is used everywhere
732  bApplyFormat = true;
733  }
734 
735  if (bApplyFormat)
736  pDoc->ApplyAttr(nCol, nRow, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat));
737  }
738  // SubTotal formatting is controlled by headers
739 }
740 
741 void ScDPOutput::HeaderCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
742  const sheet::MemberResult& rData, bool bColHeader, tools::Long nLevel )
743 {
744  tools::Long nFlags = rData.Flags;
745 
746  if ( nFlags & sheet::MemberResultFlags::HASMEMBER )
747  {
748  bool bNumeric = (nFlags & sheet::MemberResultFlags::NUMERIC) != 0;
749  if (bNumeric && std::isfinite( rData.Value))
750  {
751  pDoc->SetValue( nCol, nRow, nTab, rData.Value);
752  }
753  else
754  {
755  ScSetStringParam aParam;
756  if (bNumeric)
757  aParam.setNumericInput();
758  else
759  aParam.setTextInput();
760 
761  pDoc->SetString(nCol, nRow, nTab, rData.Caption, &aParam);
762  }
763  }
764 
765  if ( !(nFlags & sheet::MemberResultFlags::SUBTOTAL) )
766  return;
767 
768  ScDPOutputImpl outputimp( pDoc, nTab,
769  nTabStartCol, nTabStartRow,
770  nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow );
771  //TODO: limit frames to horizontal or vertical?
772  if (bColHeader)
773  {
774  outputimp.OutputBlockFrame( nCol,nMemberStartRow+static_cast<SCROW>(nLevel), nCol,nDataStartRow-1 );
775 
776  lcl_SetStyleById( pDoc,nTab, nCol,nMemberStartRow+static_cast<SCROW>(nLevel), nCol,nDataStartRow-1,
777  STR_PIVOT_STYLENAME_TITLE );
778  lcl_SetStyleById( pDoc,nTab, nCol,nDataStartRow, nCol,nTabEndRow,
779  STR_PIVOT_STYLENAME_RESULT );
780  }
781  else
782  {
783  outputimp.OutputBlockFrame( nMemberStartCol+static_cast<SCCOL>(nLevel),nRow, nDataStartCol-1,nRow );
784  lcl_SetStyleById( pDoc,nTab, nMemberStartCol+static_cast<SCCOL>(nLevel),nRow, nDataStartCol-1,nRow,
785  STR_PIVOT_STYLENAME_TITLE );
786  lcl_SetStyleById( pDoc,nTab, nDataStartCol,nRow, nTabEndCol,nRow,
787  STR_PIVOT_STYLENAME_RESULT );
788  }
789 }
790 
792  SCCOL nCol, SCROW nRow, SCTAB nTab, const ScDPOutLevelData& rData, bool bInTable)
793 {
794  // Avoid unwanted automatic format detection.
795  ScSetStringParam aParam;
796  aParam.mbDetectNumberFormat = false;
798  aParam.mbHandleApostrophe = false;
799  pDoc->SetString(nCol, nRow, nTab, rData.maCaption, &aParam);
800 
801  if (bInTable)
802  lcl_SetFrame( pDoc,nTab, nCol,nRow, nCol,nRow, 20 );
803 
804  // For field button drawing
805  ScMF nMergeFlag = ScMF::NONE;
806  if (rData.mbHasHiddenMember)
807  nMergeFlag |= ScMF::HiddenMember;
808 
809  if (rData.mbPageDim)
810  {
811  nMergeFlag |= ScMF::ButtonPopup;
812  pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, ScMF::Button);
813  pDoc->ApplyFlagsTab(nCol+1, nRow, nCol+1, nRow, nTab, nMergeFlag);
814  }
815  else
816  {
817  nMergeFlag |= ScMF::Button;
818  if (!rData.mbDataLayout)
819  nMergeFlag |= ScMF::ButtonPopup;
820  pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, nMergeFlag);
821  }
822 
823  lcl_SetStyleById( pDoc,nTab, nCol,nRow, nCol,nRow, STR_PIVOT_STYLENAME_FIELDNAME );
824 }
825 
826 static void lcl_DoFilterButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
827 {
828  pDoc->SetString( nCol, nRow, nTab, ScResId(STR_CELL_FILTER) );
829  pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, ScMF::Button);
830 }
831 
833 {
834  if (bSizesValid)
835  return;
836 
837  // get column size of data from first row
838  //TODO: allow different sizes (and clear following areas) ???
839 
840  nRowCount = aData.getLength();
841  const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
842  nColCount = nRowCount ? ( pRowAry[0].getLength() ) : 0;
843 
844  nHeaderSize = 1;
845  if (GetHeaderLayout() && pColFields.empty())
846  // Insert an extra header row only when there is no column field.
847  nHeaderSize = 2;
848 
849  // calculate output positions and sizes
850 
851  tools::Long nPageSize = 0; // use page fields!
852  if ( bDoFilter || !pPageFields.empty() )
853  {
854  nPageSize += pPageFields.size() + 1; // plus one empty row
855  if ( bDoFilter )
856  ++nPageSize; // filter button above the page fields
857  }
858 
859  if ( aStartPos.Col() + static_cast<tools::Long>(pRowFields.size()) + nColCount - 1 > MAXCOL ||
860  aStartPos.Row() + nPageSize + nHeaderSize + pColFields.size() + nRowCount > MAXROW )
861  {
862  bSizeOverflow = true;
863  }
864 
865  nTabStartCol = aStartPos.Col();
866  nTabStartRow = aStartPos.Row() + static_cast<SCROW>(nPageSize); // below page fields
868  nMemberStartRow = nTabStartRow + static_cast<SCROW>(nHeaderSize);
869  nDataStartCol = nMemberStartCol + static_cast<SCCOL>(pRowFields.size());
870  nDataStartRow = nMemberStartRow + static_cast<SCROW>(pColFields.size());
871  if ( nColCount > 0 )
872  nTabEndCol = nDataStartCol + static_cast<SCCOL>(nColCount) - 1;
873  else
874  nTabEndCol = nDataStartCol; // single column will remain empty
875  // if page fields are involved, include the page selection cells
876  if ( !pPageFields.empty() && nTabEndCol < nTabStartCol + 1 )
877  nTabEndCol = nTabStartCol + 1;
878  if ( nRowCount > 0 )
879  nTabEndRow = nDataStartRow + static_cast<SCROW>(nRowCount) - 1;
880  else
881  nTabEndRow = nDataStartRow; // single row will remain empty
882  bSizesValid = true;
883 }
884 
886 {
887  using namespace ::com::sun::star::sheet;
888 
889  SCCOL nCol = rPos.Col();
890  SCROW nRow = rPos.Row();
891  SCTAB nTab = rPos.Tab();
892  if ( nTab != aStartPos.Tab() )
893  return DataPilotTablePositionType::NOT_IN_TABLE;
894 
895  CalcSizes();
896 
897  // Make sure the cursor is within the table.
898  if (nCol < nTabStartCol || nRow < nTabStartRow || nCol > nTabEndCol || nRow > nTabEndRow)
899  return DataPilotTablePositionType::NOT_IN_TABLE;
900 
901  // test for result data area.
902  if (nCol >= nDataStartCol && nCol <= nTabEndCol && nRow >= nDataStartRow && nRow <= nTabEndRow)
903  return DataPilotTablePositionType::RESULT;
904 
905  bool bInColHeader = (nRow >= nTabStartRow && nRow < nDataStartRow);
906  bool bInRowHeader = (nCol >= nTabStartCol && nCol < nDataStartCol);
907 
908  if (bInColHeader && bInRowHeader)
909  // probably in that ugly little box at the upper-left corner of the table.
910  return DataPilotTablePositionType::OTHER;
911 
912  if (bInColHeader)
913  {
914  if (nRow == nTabStartRow)
915  // first row in the column header area is always used for column
916  // field buttons.
917  return DataPilotTablePositionType::OTHER;
918 
920  }
921 
922  if (bInRowHeader)
924 
925  return DataPilotTablePositionType::OTHER;
926 }
927 
929 {
930  SCTAB nTab = aStartPos.Tab();
931  const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
932 
933  // calculate output positions and sizes
934 
935  CalcSizes();
936  if ( bSizeOverflow || bResultsError ) // does output area exceed sheet limits?
937  return; // nothing
938 
939  // clear whole (new) output area
940  // when modifying table, clear old area !
941  //TODO: include InsertDeleteFlags::OBJECTS ???
943 
944  if ( bDoFilter )
945  lcl_DoFilterButton( pDoc, aStartPos.Col(), aStartPos.Row(), nTab );
946 
947  // output page fields:
948 
949  for (size_t nField=0; nField<pPageFields.size(); ++nField)
950  {
951  SCCOL nHdrCol = aStartPos.Col();
952  SCROW nHdrRow = aStartPos.Row() + nField + ( bDoFilter ? 1 : 0 );
953  // draw without frame for consistency with filter button:
954  FieldCell(nHdrCol, nHdrRow, nTab, pPageFields[nField], false);
955  SCCOL nFldCol = nHdrCol + 1;
956 
957  OUString aPageValue = ScResId(SCSTR_ALL);
958  const uno::Sequence<sheet::MemberResult>& rRes = pPageFields[nField].maResult;
959  sal_Int32 n = rRes.getLength();
960  if (n == 1)
961  {
962  if (rRes[0].Caption.isEmpty())
963  aPageValue = ScResId(STR_EMPTYDATA);
964  else
965  aPageValue = rRes[0].Caption;
966  }
967  else if (n > 1)
968  aPageValue = ScResId(SCSTR_MULTIPLE);
969 
970  ScSetStringParam aParam;
971  aParam.setTextInput();
972  pDoc->SetString(nFldCol, nHdrRow, nTab, aPageValue, &aParam);
973 
974  lcl_SetFrame( pDoc,nTab, nFldCol,nHdrRow, nFldCol,nHdrRow, 20 );
975  }
976 
977  // data description
978  // (may get overwritten by first row field)
979 
980  if (aDataDescription.isEmpty())
981  {
982  //TODO: use default string ("result") ?
983  }
984  pDoc->SetString(nTabStartCol, nTabStartRow, nTab, aDataDescription);
985 
986  // set STR_PIVOT_STYLENAME_INNER for whole data area (subtotals are overwritten)
987 
988  if ( nDataStartRow > nTabStartRow )
989  lcl_SetStyleById( pDoc, nTab, nTabStartCol, nTabStartRow, nTabEndCol, nDataStartRow-1,
990  STR_PIVOT_STYLENAME_TOP );
991  lcl_SetStyleById( pDoc, nTab, nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow,
992  STR_PIVOT_STYLENAME_INNER );
993 
994  // output column headers:
995  ScDPOutputImpl outputimp( pDoc, nTab,
996  nTabStartCol, nTabStartRow,
997  nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow );
998  for (size_t nField=0; nField<pColFields.size(); nField++)
999  {
1000  SCCOL nHdrCol = nDataStartCol + static_cast<SCCOL>(nField); //TODO: check for overflow
1001  FieldCell(nHdrCol, nTabStartRow, nTab, pColFields[nField], true);
1002 
1003  SCROW nRowPos = nMemberStartRow + static_cast<SCROW>(nField); //TODO: check for overflow
1004  const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].maResult;
1005  const sheet::MemberResult* pArray = rSequence.getConstArray();
1006  tools::Long nThisColCount = rSequence.getLength();
1007  OSL_ENSURE( nThisColCount == nColCount, "count mismatch" ); //TODO: ???
1008  for (tools::Long nCol=0; nCol<nThisColCount; nCol++)
1009  {
1010  SCCOL nColPos = nDataStartCol + static_cast<SCCOL>(nCol); //TODO: check for overflow
1011  HeaderCell( nColPos, nRowPos, nTab, pArray[nCol], true, nField );
1012  if ( ( pArray[nCol].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
1013  !( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
1014  {
1015  tools::Long nEnd = nCol;
1016  while ( nEnd+1 < nThisColCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
1017  ++nEnd;
1018  SCCOL nEndColPos = nDataStartCol + static_cast<SCCOL>(nEnd); //TODO: check for overflow
1019  if ( nField+1 < pColFields.size())
1020  {
1021  if ( nField == pColFields.size() - 2 )
1022  {
1023  outputimp.AddCol( nColPos );
1024  if ( nColPos + 1 == nEndColPos )
1025  outputimp.OutputBlockFrame( nColPos,nRowPos, nEndColPos,nRowPos+1, true );
1026  }
1027  else
1028  outputimp.OutputBlockFrame( nColPos,nRowPos, nEndColPos,nRowPos );
1029 
1030  lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nEndColPos,nDataStartRow-1, STR_PIVOT_STYLENAME_CATEGORY );
1031  }
1032  else
1033  lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nColPos,nDataStartRow-1, STR_PIVOT_STYLENAME_CATEGORY );
1034  }
1035  else if ( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL )
1036  outputimp.AddCol( nColPos );
1037 
1038  // Apply the same number format as in data source.
1039  pDoc->ApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, pColFields[nField].mnSrcNumFmt));
1040  }
1041  if ( nField== 0 && pColFields.size() == 1 )
1042  outputimp.OutputBlockFrame( nDataStartCol,nTabStartRow, nTabEndCol,nRowPos-1 );
1043  }
1044 
1045  // output row headers:
1046  std::vector<bool> vbSetBorder;
1047  vbSetBorder.resize( nTabEndRow - nDataStartRow + 1, false );
1048  for (size_t nField=0; nField<pRowFields.size(); nField++)
1049  {
1050  SCCOL nHdrCol = nTabStartCol + static_cast<SCCOL>(nField); //TODO: check for overflow
1051  SCROW nHdrRow = nDataStartRow - 1;
1052  FieldCell(nHdrCol, nHdrRow, nTab, pRowFields[nField], true);
1053 
1054  SCCOL nColPos = nMemberStartCol + static_cast<SCCOL>(nField); //TODO: check for overflow
1055  const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].maResult;
1056  const sheet::MemberResult* pArray = rSequence.getConstArray();
1057  tools::Long nThisRowCount = rSequence.getLength();
1058  OSL_ENSURE( nThisRowCount == nRowCount, "count mismatch" ); //TODO: ???
1059  for (tools::Long nRow=0; nRow<nThisRowCount; nRow++)
1060  {
1061  SCROW nRowPos = nDataStartRow + static_cast<SCROW>(nRow); //TODO: check for overflow
1062  HeaderCell( nColPos, nRowPos, nTab, pArray[nRow], false, nField );
1063  if ( ( pArray[nRow].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
1064  !( pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
1065  {
1066  if ( nField+1 < pRowFields.size() )
1067  {
1068  tools::Long nEnd = nRow;
1069  while ( nEnd+1 < nThisRowCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
1070  ++nEnd;
1071  SCROW nEndRowPos = nDataStartRow + static_cast<SCROW>(nEnd); //TODO: check for overflow
1072  outputimp.AddRow( nRowPos );
1073  if ( !vbSetBorder[ nRow ] )
1074  {
1075  outputimp.OutputBlockFrame( nColPos, nRowPos, nTabEndCol, nEndRowPos );
1076  vbSetBorder[ nRow ] = true;
1077  }
1078  outputimp.OutputBlockFrame( nColPos, nRowPos, nColPos, nEndRowPos );
1079 
1080  if ( nField == pRowFields.size() - 2 )
1081  outputimp.OutputBlockFrame( nColPos+1, nRowPos, nColPos+1, nEndRowPos );
1082 
1083  lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nEndRowPos, STR_PIVOT_STYLENAME_CATEGORY );
1084  }
1085  else
1086  lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nRowPos, STR_PIVOT_STYLENAME_CATEGORY );
1087  }
1088  else if ( pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL )
1089  outputimp.AddRow( nRowPos );
1090 
1091  // Apply the same number format as in data source.
1092  pDoc->ApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, pRowFields[nField].mnSrcNumFmt));
1093  }
1094  }
1095 
1096  if (nColCount == 1 && nRowCount > 0 && pColFields.empty())
1097  {
1098  // the table contains exactly one data field and no column fields.
1099  // Display data description at top right corner.
1100  ScSetStringParam aParam;
1101  aParam.setTextInput();
1102  pDoc->SetString(nDataStartCol, nDataStartRow-1, nTab, aDataDescription, &aParam);
1103  }
1104 
1105  // output data results:
1106 
1107  for (tools::Long nRow=0; nRow<nRowCount; nRow++)
1108  {
1109  SCROW nRowPos = nDataStartRow + static_cast<SCROW>(nRow); //TODO: check for overflow
1110  const sheet::DataResult* pColAry = pRowAry[nRow].getConstArray();
1111  tools::Long nThisColCount = pRowAry[nRow].getLength();
1112  OSL_ENSURE( nThisColCount == nColCount, "count mismatch" ); //TODO: ???
1113  for (tools::Long nCol=0; nCol<nThisColCount; nCol++)
1114  {
1115  SCCOL nColPos = nDataStartCol + static_cast<SCCOL>(nCol); //TODO: check for overflow
1116  DataCell( nColPos, nRowPos, nTab, pColAry[nCol] );
1117  }
1118  }
1119 
1120  outputimp.OutputDataArea();
1121 }
1122 
1123 ScRange ScDPOutput::GetOutputRange( sal_Int32 nRegionType )
1124 {
1125  using namespace ::com::sun::star::sheet;
1126 
1127  CalcSizes();
1128 
1129  SCTAB nTab = aStartPos.Tab();
1130  switch (nRegionType)
1131  {
1132  case DataPilotOutputRangeType::RESULT:
1133  return ScRange(nDataStartCol, nDataStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
1135  return ScRange(aStartPos.Col(), nTabStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
1136  default:
1137  OSL_ENSURE(nRegionType == DataPilotOutputRangeType::WHOLE, "ScDPOutput::GetOutputRange: unknown region type");
1138  break;
1139  }
1140  return ScRange(aStartPos.Col(), aStartPos.Row(), nTab, nTabEndCol, nTabEndRow, nTab);
1141 }
1142 
1144 {
1145  CalcSizes();
1146 
1147  return bSizeOverflow || bResultsError;
1148 }
1149 
1151 {
1152  return pPageFields.size() + ( bDoFilter ? 1 : 0 );
1153 }
1154 
1155 namespace
1156 {
1157  void insertNames(ScDPUniqueStringSet& rNames, const uno::Sequence<sheet::MemberResult>& rMemberResults)
1158  {
1159  for (const sheet::MemberResult& rMemberResult : rMemberResults)
1160  {
1161  if (rMemberResult.Flags & sheet::MemberResultFlags::HASMEMBER)
1162  rNames.insert(rMemberResult.Name);
1163  }
1164  }
1165 }
1166 
1168 {
1169  // Return the list of all member names in a dimension's MemberResults.
1170  // Only the dimension has to be compared because this is only used with table data,
1171  // where each dimension occurs only once.
1172 
1173  auto lFindDimension = [nDimension](const ScDPOutLevelData& rField) { return rField.mnDim == nDimension; };
1174 
1175  // look in column fields
1176  auto colit = std::find_if(pColFields.begin(), pColFields.end(), lFindDimension);
1177  if (colit != pColFields.end())
1178  {
1179  // collect the member names
1180  insertNames(rNames, colit->maResult);
1181  return;
1182  }
1183 
1184  // look in row fields
1185  auto rowit = std::find_if(pRowFields.begin(), pRowFields.end(), lFindDimension);
1186  if (rowit != pRowFields.end())
1187  {
1188  // collect the member names
1189  insertNames(rNames, rowit->maResult);
1190  }
1191 }
1192 
1193 void ScDPOutput::SetHeaderLayout(bool bUseGrid)
1194 {
1195  mbHeaderLayout = bUseGrid;
1196  bSizesValid = false;
1197 }
1198 
1199 namespace {
1200 
1201 void lcl_GetTableVars( sal_Int32& rGrandTotalCols, sal_Int32& rGrandTotalRows, sal_Int32& rDataLayoutIndex,
1202  std::vector<OUString>& rDataNames, std::vector<OUString>& rGivenNames,
1203  sheet::DataPilotFieldOrientation& rDataOrient,
1204  const uno::Reference<sheet::XDimensionsSupplier>& xSource )
1205 {
1206  rDataLayoutIndex = -1; // invalid
1207  rGrandTotalCols = 0;
1208  rGrandTotalRows = 0;
1209  rDataOrient = sheet::DataPilotFieldOrientation_HIDDEN;
1210 
1211  uno::Reference<beans::XPropertySet> xSrcProp( xSource, uno::UNO_QUERY );
1212  bool bColGrand = ScUnoHelpFunctions::GetBoolProperty(
1213  xSrcProp, SC_UNO_DP_COLGRAND);
1214  if ( bColGrand )
1215  rGrandTotalCols = 1; // default if data layout not in columns
1216 
1217  bool bRowGrand = ScUnoHelpFunctions::GetBoolProperty(
1218  xSrcProp, SC_UNO_DP_ROWGRAND);
1219  if ( bRowGrand )
1220  rGrandTotalRows = 1; // default if data layout not in rows
1221 
1222  if ( !xSource.is() )
1223  return;
1224 
1225  // find index and orientation of "data layout" dimension, count data dimensions
1226 
1227  sal_Int32 nDataCount = 0;
1228 
1229  uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xSource->getDimensions() );
1230  tools::Long nDimCount = xDims->getCount();
1231  for (tools::Long nDim=0; nDim<nDimCount; nDim++)
1232  {
1233  uno::Reference<uno::XInterface> xDim(xDims->getByIndex(nDim), uno::UNO_QUERY);
1234  uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1235  if ( xDimProp.is() )
1236  {
1237  sheet::DataPilotFieldOrientation eDimOrient =
1239  xDimProp, SC_UNO_DP_ORIENTATION,
1240  sheet::DataPilotFieldOrientation_HIDDEN );
1241  if ( ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1243  {
1244  rDataLayoutIndex = nDim;
1245  rDataOrient = eDimOrient;
1246  }
1247  if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
1248  {
1249  OUString aSourceName;
1250  OUString aGivenName;
1251  ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xDim );
1252  try
1253  {
1254  uno::Any aValue = xDimProp->getPropertyValue( SC_UNO_DP_LAYOUTNAME );
1255 
1256  if( aValue.hasValue() )
1257  {
1258  OUString strLayoutName;
1259 
1260  if( ( aValue >>= strLayoutName ) && !strLayoutName.isEmpty() )
1261  aGivenName = strLayoutName;
1262  }
1263  }
1264  catch(const uno::Exception&)
1265  {
1266  }
1267  rDataNames.push_back( aSourceName );
1268  rGivenNames.push_back( aGivenName );
1269 
1270  ++nDataCount;
1271  }
1272  }
1273  }
1274 
1275  if ( ( rDataOrient == sheet::DataPilotFieldOrientation_COLUMN ) && bColGrand )
1276  rGrandTotalCols = nDataCount;
1277  else if ( ( rDataOrient == sheet::DataPilotFieldOrientation_ROW ) && bRowGrand )
1278  rGrandTotalRows = nDataCount;
1279 }
1280 
1281 }
1282 
1283 void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
1284 {
1285  using namespace ::com::sun::star::sheet;
1286 
1287  SCCOL nCol = rPos.Col();
1288  SCROW nRow = rPos.Row();
1289  SCTAB nTab = rPos.Tab();
1290  if ( nTab != aStartPos.Tab() )
1291  return; // wrong sheet
1292 
1293  // calculate output positions and sizes
1294 
1295  CalcSizes();
1296 
1297  rPosData.PositionType = GetPositionType(rPos);
1298  switch (rPosData.PositionType)
1299  {
1300  case DataPilotTablePositionType::RESULT:
1301  {
1302  vector<DataPilotFieldFilter> aFilters;
1303  GetDataResultPositionData(aFilters, rPos);
1304  sal_Int32 nSize = aFilters.size();
1305 
1306  DataPilotTableResultData aResData;
1307  aResData.FieldFilters.realloc(nSize);
1308  for (sal_Int32 i = 0; i < nSize; ++i)
1309  aResData.FieldFilters[i] = aFilters[i];
1310 
1311  aResData.DataFieldIndex = 0;
1312  Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
1313  if (xPropSet.is())
1314  {
1315  sal_Int32 nDataFieldCount = ScUnoHelpFunctions::GetLongProperty( xPropSet,
1317  if (nDataFieldCount > 0)
1318  aResData.DataFieldIndex = (nRow - nDataStartRow) % nDataFieldCount;
1319  }
1320 
1321  // Copy appropriate DataResult object from the cached sheet::DataResult table.
1322  if (aData.getLength() > nRow - nDataStartRow &&
1323  aData[nRow-nDataStartRow].getLength() > nCol-nDataStartCol)
1324  aResData.Result = aData[nRow-nDataStartRow][nCol-nDataStartCol];
1325 
1326  rPosData.PositionData <<= aResData;
1327  return;
1328  }
1330  {
1331  tools::Long nField = nRow - nTabStartRow - 1; // 1st line is used for the buttons
1332  if (nField < 0)
1333  break;
1334 
1335  const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].maResult;
1336  if (!rSequence.hasElements())
1337  break;
1338  const sheet::MemberResult* pArray = rSequence.getConstArray();
1339 
1340  tools::Long nItem = nCol - nDataStartCol;
1341  // get origin of "continue" fields
1342  while (nItem > 0 && ( pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1343  --nItem;
1344 
1345  if (nItem < 0)
1346  break;
1347 
1348  DataPilotTableHeaderData aHeaderData;
1349  aHeaderData.MemberName = pArray[nItem].Name;
1350  aHeaderData.Flags = pArray[nItem].Flags;
1351  aHeaderData.Dimension = static_cast<sal_Int32>(pColFields[nField].mnDim);
1352  aHeaderData.Hierarchy = static_cast<sal_Int32>(pColFields[nField].mnHier);
1353  aHeaderData.Level = static_cast<sal_Int32>(pColFields[nField].mnLevel);
1354 
1355  rPosData.PositionData <<= aHeaderData;
1356  return;
1357  }
1359  {
1360  tools::Long nField = nCol - nTabStartCol;
1361  if (nField < 0)
1362  break;
1363 
1364  const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].maResult;
1365  if (!rSequence.hasElements())
1366  break;
1367  const sheet::MemberResult* pArray = rSequence.getConstArray();
1368 
1369  tools::Long nItem = nRow - nDataStartRow;
1370  // get origin of "continue" fields
1371  while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1372  --nItem;
1373 
1374  if (nItem < 0)
1375  break;
1376 
1377  DataPilotTableHeaderData aHeaderData;
1378  aHeaderData.MemberName = pArray[nItem].Name;
1379  aHeaderData.Flags = pArray[nItem].Flags;
1380  aHeaderData.Dimension = static_cast<sal_Int32>(pRowFields[nField].mnDim);
1381  aHeaderData.Hierarchy = static_cast<sal_Int32>(pRowFields[nField].mnHier);
1382  aHeaderData.Level = static_cast<sal_Int32>(pRowFields[nField].mnLevel);
1383 
1384  rPosData.PositionData <<= aHeaderData;
1385  return;
1386  }
1387  }
1388 }
1389 
1390 bool ScDPOutput::GetDataResultPositionData(vector<sheet::DataPilotFieldFilter>& rFilters, const ScAddress& rPos)
1391 {
1392  // Check to make sure there is at least one data field.
1393  Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
1394  if (!xPropSet.is())
1395  return false;
1396 
1397  sal_Int32 nDataFieldCount = ScUnoHelpFunctions::GetLongProperty( xPropSet,
1399  if (nDataFieldCount == 0)
1400  // No data field is present in this datapilot table.
1401  return false;
1402 
1403  // #i111421# use lcl_GetTableVars for correct size of totals and data layout position
1404  sal_Int32 nGrandTotalCols;
1405  sal_Int32 nGrandTotalRows;
1406  sal_Int32 nDataLayoutIndex;
1407  std::vector<OUString> aDataNames;
1408  std::vector<OUString> aGivenNames;
1409  sheet::DataPilotFieldOrientation eDataOrient;
1410  lcl_GetTableVars( nGrandTotalCols, nGrandTotalRows, nDataLayoutIndex, aDataNames, aGivenNames, eDataOrient, xSource );
1411 
1412  SCCOL nCol = rPos.Col();
1413  SCROW nRow = rPos.Row();
1414  SCTAB nTab = rPos.Tab();
1415  if ( nTab != aStartPos.Tab() )
1416  return false; // wrong sheet
1417 
1418  CalcSizes();
1419 
1420  // test for data area.
1421  if (nCol < nDataStartCol || nCol > nTabEndCol || nRow < nDataStartRow || nRow > nTabEndRow)
1422  {
1423  // Cell is outside the data field area.
1424  return false;
1425  }
1426 
1427  bool bFilterByCol = (nCol <= static_cast<SCCOL>(nTabEndCol - nGrandTotalCols));
1428  bool bFilterByRow = (nRow <= static_cast<SCROW>(nTabEndRow - nGrandTotalRows));
1429 
1430  // column fields
1431  for (size_t nColField = 0; nColField < pColFields.size() && bFilterByCol; ++nColField)
1432  {
1433  if (pColFields[nColField].mnDim == nDataLayoutIndex)
1434  // There is no sense including the data layout field for filtering.
1435  continue;
1436 
1437  sheet::DataPilotFieldFilter filter;
1438  filter.FieldName = pColFields[nColField].maName;
1439 
1440  const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nColField].maResult;
1441  const sheet::MemberResult* pArray = rSequence.getConstArray();
1442 
1443  OSL_ENSURE(nDataStartCol + rSequence.getLength() - 1 == nTabEndCol, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1444 
1445  tools::Long nItem = nCol - nDataStartCol;
1446  // get origin of "continue" fields
1447  while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1448  --nItem;
1449 
1450  filter.MatchValueName = pArray[nItem].Name;
1451  rFilters.push_back(filter);
1452  }
1453 
1454  // row fields
1455  for (size_t nRowField = 0; nRowField < pRowFields.size() && bFilterByRow; ++nRowField)
1456  {
1457  if (pRowFields[nRowField].mnDim == nDataLayoutIndex)
1458  // There is no sense including the data layout field for filtering.
1459  continue;
1460 
1461  sheet::DataPilotFieldFilter filter;
1462  filter.FieldName = pRowFields[nRowField].maName;
1463 
1464  const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nRowField].maResult;
1465  const sheet::MemberResult* pArray = rSequence.getConstArray();
1466 
1467  OSL_ENSURE(nDataStartRow + rSequence.getLength() - 1 == nTabEndRow, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1468 
1469  tools::Long nItem = nRow - nDataStartRow;
1470  // get origin of "continue" fields
1471  while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1472  --nItem;
1473 
1474  filter.MatchValueName = pArray[nItem].Name;
1475  rFilters.push_back(filter);
1476  }
1477 
1478  return true;
1479 }
1480 
1481 namespace {
1482 
1483 OUString lcl_GetDataFieldName( const OUString& rSourceName, sal_Int16 eFunc )
1484 {
1485  const char* pStrId = nullptr;
1486  switch ( eFunc )
1487  {
1488  case sheet::GeneralFunction2::SUM: pStrId = STR_FUN_TEXT_SUM; break;
1490  case sheet::GeneralFunction2::COUNTNUMS: pStrId = STR_FUN_TEXT_COUNT; break;
1491  case sheet::GeneralFunction2::AVERAGE: pStrId = STR_FUN_TEXT_AVG; break;
1492  case sheet::GeneralFunction2::MEDIAN: pStrId = STR_FUN_TEXT_MEDIAN; break;
1493  case sheet::GeneralFunction2::MAX: pStrId = STR_FUN_TEXT_MAX; break;
1494  case sheet::GeneralFunction2::MIN: pStrId = STR_FUN_TEXT_MIN; break;
1495  case sheet::GeneralFunction2::PRODUCT: pStrId = STR_FUN_TEXT_PRODUCT; break;
1496  case sheet::GeneralFunction2::STDEV:
1497  case sheet::GeneralFunction2::STDEVP: pStrId = STR_FUN_TEXT_STDDEV; break;
1498  case sheet::GeneralFunction2::VAR:
1499  case sheet::GeneralFunction2::VARP: pStrId = STR_FUN_TEXT_VAR; break;
1501  case sheet::GeneralFunction2::AUTO: break;
1502  default:
1503  {
1504  assert(false);
1505  }
1506  }
1507  if (!pStrId)
1508  return OUString();
1509 
1510  return ScResId(pStrId) + " - " + rSourceName;
1511 }
1512 
1513 }
1514 
1516  OUString& rSourceName, OUString& rGivenName, const uno::Reference<uno::XInterface>& xDim )
1517 {
1518  uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1519  uno::Reference<container::XNamed> xDimName( xDim, uno::UNO_QUERY );
1520  if ( !(xDimProp.is() && xDimName.is()) )
1521  return;
1522 
1523  // Asterisks are added in ScDPSaveData::WriteToSource to create unique names.
1524  //TODO: preserve original name there?
1525  rSourceName = ScDPUtil::getSourceDimensionName(xDimName->getName());
1526 
1527  // Generate "given name" the same way as in dptabres.
1528  //TODO: Should use a stored name when available
1529 
1530  sal_Int16 eFunc = ScUnoHelpFunctions::GetShortProperty(
1531  xDimProp, SC_UNO_DP_FUNCTION2,
1533  rGivenName = lcl_GetDataFieldName( rSourceName, eFunc );
1534 }
1535 
1537 {
1538  SCCOL nCol = rPos.Col();
1539  SCROW nRow = rPos.Row();
1540  SCTAB nTab = rPos.Tab();
1541  if ( nTab != aStartPos.Tab() || !bDoFilter )
1542  return false; // wrong sheet or no button at all
1543 
1544  // filter button is at top left
1545  return ( nCol == aStartPos.Col() && nRow == aStartPos.Row() );
1546 }
1547 
1548 tools::Long ScDPOutput::GetHeaderDim( const ScAddress& rPos, sheet::DataPilotFieldOrientation& rOrient )
1549 {
1550  SCCOL nCol = rPos.Col();
1551  SCROW nRow = rPos.Row();
1552  SCTAB nTab = rPos.Tab();
1553  if ( nTab != aStartPos.Tab() )
1554  return -1; // wrong sheet
1555 
1556  // calculate output positions and sizes
1557 
1558  CalcSizes();
1559 
1560  // test for column header
1561 
1562  if ( nRow == nTabStartRow && nCol >= nDataStartCol && o3tl::make_unsigned(nCol) < nDataStartCol + pColFields.size())
1563  {
1564  rOrient = sheet::DataPilotFieldOrientation_COLUMN;
1565  tools::Long nField = nCol - nDataStartCol;
1566  return pColFields[nField].mnDim;
1567  }
1568 
1569  // test for row header
1570 
1571  if ( nRow+1 == nDataStartRow && nCol >= nTabStartCol && o3tl::make_unsigned(nCol) < nTabStartCol + pRowFields.size() )
1572  {
1573  rOrient = sheet::DataPilotFieldOrientation_ROW;
1574  tools::Long nField = nCol - nTabStartCol;
1575  return pRowFields[nField].mnDim;
1576  }
1577 
1578  // test for page field
1579 
1580  SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 );
1581  if ( nCol == aStartPos.Col() && nRow >= nPageStartRow && o3tl::make_unsigned(nRow) < nPageStartRow + pPageFields.size() )
1582  {
1583  rOrient = sheet::DataPilotFieldOrientation_PAGE;
1584  tools::Long nField = nRow - nPageStartRow;
1585  return pPageFields[nField].mnDim;
1586  }
1587 
1588  //TODO: single data field (?)
1589 
1590  rOrient = sheet::DataPilotFieldOrientation_HIDDEN;
1591  return -1; // invalid
1592 }
1593 
1594 bool ScDPOutput::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMouseTop,
1595  tools::Long nDragDim,
1596  tools::Rectangle& rPosRect, sheet::DataPilotFieldOrientation& rOrient, tools::Long& rDimPos )
1597 {
1598  // Rectangle instead of ScRange for rPosRect to allow for negative values
1599 
1600  SCCOL nCol = rPos.Col();
1601  SCROW nRow = rPos.Row();
1602  SCTAB nTab = rPos.Tab();
1603  if ( nTab != aStartPos.Tab() )
1604  return false; // wrong sheet
1605 
1606  // calculate output positions and sizes
1607 
1608  CalcSizes();
1609 
1610  // test for column header
1611 
1612  if ( nCol >= nDataStartCol && nCol <= nTabEndCol &&
1613  nRow + 1 >= nMemberStartRow && o3tl::make_unsigned(nRow) < nMemberStartRow + pColFields.size())
1614  {
1615  tools::Long nField = nRow - nMemberStartRow;
1616  if (nField < 0)
1617  {
1618  nField = 0;
1619  bMouseTop = true;
1620  }
1621  //TODO: find start of dimension
1622 
1623  rPosRect = tools::Rectangle( nDataStartCol, nMemberStartRow + nField,
1624  nTabEndCol, nMemberStartRow + nField -1 );
1625 
1626  bool bFound = false; // is this within the same orientation?
1627  bool bBeforeDrag = false;
1628  bool bAfterDrag = false;
1629  for (tools::Long nPos=0; o3tl::make_unsigned(nPos)<pColFields.size() && !bFound; nPos++)
1630  {
1631  if (pColFields[nPos].mnDim == nDragDim)
1632  {
1633  bFound = true;
1634  if ( nField < nPos )
1635  bBeforeDrag = true;
1636  else if ( nField > nPos )
1637  bAfterDrag = true;
1638  }
1639  }
1640 
1641  if ( bFound )
1642  {
1643  if (!bBeforeDrag)
1644  {
1645  rPosRect.AdjustBottom( 1 );
1646  if (bAfterDrag)
1647  rPosRect.AdjustTop( 1 );
1648  }
1649  }
1650  else
1651  {
1652  if ( !bMouseTop )
1653  {
1654  rPosRect.AdjustTop( 1 );
1655  rPosRect.AdjustBottom( 1 );
1656  ++nField;
1657  }
1658  }
1659 
1660  rOrient = sheet::DataPilotFieldOrientation_COLUMN;
1661  rDimPos = nField;
1662  return true;
1663  }
1664 
1665  // test for row header
1666 
1667  // special case if no row fields
1668  bool bSpecial = ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow &&
1669  pRowFields.empty() && nCol == nTabStartCol && bMouseLeft );
1670 
1671  if ( bSpecial || ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow &&
1672  nCol + 1 >= nTabStartCol && o3tl::make_unsigned(nCol) < nTabStartCol + pRowFields.size() ) )
1673  {
1674  tools::Long nField = nCol - nTabStartCol;
1675  //TODO: find start of dimension
1676 
1677  rPosRect = tools::Rectangle( nTabStartCol + nField, nDataStartRow - 1,
1678  nTabStartCol + nField - 1, nTabEndRow );
1679 
1680  bool bFound = false; // is this within the same orientation?
1681  bool bBeforeDrag = false;
1682  bool bAfterDrag = false;
1683  for (tools::Long nPos=0; o3tl::make_unsigned(nPos)<pRowFields.size() && !bFound; nPos++)
1684  {
1685  if (pRowFields[nPos].mnDim == nDragDim)
1686  {
1687  bFound = true;
1688  if ( nField < nPos )
1689  bBeforeDrag = true;
1690  else if ( nField > nPos )
1691  bAfterDrag = true;
1692  }
1693  }
1694 
1695  if ( bFound )
1696  {
1697  if (!bBeforeDrag)
1698  {
1699  rPosRect.AdjustRight( 1 );
1700  if (bAfterDrag)
1701  rPosRect.AdjustLeft( 1 );
1702  }
1703  }
1704  else
1705  {
1706  if ( !bMouseLeft )
1707  {
1708  rPosRect.AdjustLeft( 1 );
1709  rPosRect.AdjustRight( 1 );
1710  ++nField;
1711  }
1712  }
1713 
1714  rOrient = sheet::DataPilotFieldOrientation_ROW;
1715  rDimPos = nField;
1716  return true;
1717  }
1718 
1719  // test for page fields
1720 
1721  SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 );
1722  if ( nCol >= aStartPos.Col() && nCol <= nTabEndCol &&
1723  nRow + 1 >= nPageStartRow && o3tl::make_unsigned(nRow) < nPageStartRow + pPageFields.size() )
1724  {
1725  tools::Long nField = nRow - nPageStartRow;
1726  if (nField < 0)
1727  {
1728  nField = 0;
1729  bMouseTop = true;
1730  }
1731  //TODO: find start of dimension
1732 
1733  rPosRect = tools::Rectangle( aStartPos.Col(), nPageStartRow + nField,
1734  nTabEndCol, nPageStartRow + nField - 1 );
1735 
1736  bool bFound = false; // is this within the same orientation?
1737  bool bBeforeDrag = false;
1738  bool bAfterDrag = false;
1739  for (tools::Long nPos=0; o3tl::make_unsigned(nPos)<pPageFields.size() && !bFound; nPos++)
1740  {
1741  if (pPageFields[nPos].mnDim == nDragDim)
1742  {
1743  bFound = true;
1744  if ( nField < nPos )
1745  bBeforeDrag = true;
1746  else if ( nField > nPos )
1747  bAfterDrag = true;
1748  }
1749  }
1750 
1751  if ( bFound )
1752  {
1753  if (!bBeforeDrag)
1754  {
1755  rPosRect.AdjustBottom( 1 );
1756  if (bAfterDrag)
1757  rPosRect.AdjustTop( 1 );
1758  }
1759  }
1760  else
1761  {
1762  if ( !bMouseTop )
1763  {
1764  rPosRect.AdjustTop( 1 );
1765  rPosRect.AdjustBottom( 1 );
1766  ++nField;
1767  }
1768  }
1769 
1770  rOrient = sheet::DataPilotFieldOrientation_PAGE;
1771  rDimPos = nField;
1772  return true;
1773  }
1774 
1775  return false;
1776 }
1777 
1778 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void CalcSizes()
Definition: dpoutput.cxx:832
sal_uInt32 mnSrcNumFmt
Definition: dpoutput.cxx:82
const int nColCount
constexpr TypedWhichId< SvxWeightItem > ATTR_CTL_FONT_WEIGHT(118)
virtual sal_Int32 SAL_CALL getCount() override
Definition: miscuno.cxx:250
SC_DLLPUBLIC void ApplyStyleAreaTab(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet &rStyle)
Definition: document.cxx:4851
bool hasValue()
sal_Int32 nIndex
bool bVisible
void Output()
Definition: dpoutput.cxx:928
SCROW nDataStartRow
Definition: dpoutput.hxx:75
Store parameters used in the ScDocument::SetString() method.
Definition: stringutil.hxx:35
bool mbHandleApostrophe
When true, treat input with a leading apostrophe as an escape character for a numeric value content...
Definition: stringutil.hxx:92
constexpr TypedWhichId< SvxBoxItem > ATTR_BORDER(150)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
virtual bool SetParent(const OUString &rParentName) override
Definition: stlsheet.cxx:88
SCROW Row() const
Definition: address.hxx:262
Flags
static sal_Int32 GetLongProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName)
Definition: miscuno.cxx:71
#define SC_DP_FRAME_INNER_BOLD
Definition: dpoutput.cxx:71
void setTextInput()
Call this whenever you need to unconditionally set input as text, no matter what the input is...
Definition: stringutil.cxx:38
static css::uno::Sequence< ValueType > VectorToSequence(const std::vector< ValueType > &rVector)
Definition: miscuno.hxx:188
static void GetDataDimensionNames(OUString &rSourceName, OUString &rGivenName, const css::uno::Reference< css::uno::XInterface > &xDim)
Definition: dpoutput.cxx:1515
OUString maName
Definition: dpoutput.cxx:84
#define SC_DP_FRAME_OUTER_BOLD
Definition: dpoutput.cxx:72
ScDPOutLevelData(tools::Long nDim, tools::Long nHier, tools::Long nLevel, tools::Long nDimPos, sal_uInt32 nSrcNumFmt, const uno::Sequence< sheet::MemberResult > &aResult, const OUString &aName, const OUString &aCaption, bool bHasHiddenMember, bool bDataLayout, bool bPageDim)
Definition: dpoutput.cxx:90
long Long
void GetMemberResultNames(ScDPUniqueStringSet &rNames, tools::Long nDimension)
Definition: dpoutput.cxx:1167
#define SC_UNO_DP_COLGRAND
Definition: unonames.hxx:587
SC_DLLPUBLIC bool ApplyFlagsTab(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, ScMF nFlags)
Definition: document.cxx:5012
sal_Int64 n
tools::Long mnHier
Definition: dpoutput.cxx:79
bool mbHasHiddenMember
Caption is the name visible in the output table.
Definition: dpoutput.cxx:86
bool bSizesValid
Definition: dpoutput.hxx:80
#define SC_DP_FRAME_COLOR
Definition: dpoutput.cxx:74
constexpr TypedWhichId< SvxBoxInfoItem > ATTR_BORDER_INNER(151)
bool mbHeaderLayout
Definition: dpoutput.hxx:82
static EnumT GetEnumProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName, EnumT nDefault)
Definition: miscuno.hxx:160
SC_DLLPUBLIC void SetValue(SCCOL nCol, SCROW nRow, SCTAB nTab, const double &rVal)
Definition: document.cxx:3458
#define SC_UNO_DP_POSITION
Definition: unonames.hxx:593
static OUString GetStringProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName, const OUString &rDefault)
Definition: miscuno.cxx:119
SC_DLLPUBLIC void ApplyAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem &rAttr)
Definition: document.cxx:4757
int nDimCount
css::uno::Sequence< css::uno::Sequence< css::sheet::DataResult > > aData
Definition: dpoutput.hxx:54
sal_Int32 GetPositionType(const ScAddress &rPos)
Query which sub-area of the table the cell is in.
Definition: dpoutput.cxx:885
tools::Long nRowCount
Definition: dpoutput.hxx:68
bool GetDataResultPositionData(::std::vector< css::sheet::DataPilotFieldFilter > &rFilters, const ScAddress &rPos)
Get filtering criteria based on the position of the cell within data field region.
Definition: dpoutput.cxx:1390
SCCOL nDataStartCol
Definition: dpoutput.hxx:74
TextFormatPolicy meSetTextNumFormat
Determine when to set the 'Text' number format to the cell where the input string is being set...
Definition: stringutil.hxx:84
std::unique_ptr< sal_uInt32[]> pRowNumFmt
Definition: dpoutput.hxx:61
#define SC_UNO_DP_LAYOUTNAME
Definition: unonames.hxx:611
tools::Long nColFmtCount
Definition: dpoutput.hxx:62
SCCOL nTabStartCol
Definition: dpoutput.hxx:70
tools::Long nRowFmtCount
Definition: dpoutput.hxx:63
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
uno::Sequence< sheet::MemberResult > maResult
Prevailing number format used in the source data.
Definition: dpoutput.cxx:83
std::vector< ScDPOutLevelData > pPageFields
Definition: dpoutput.hxx:53
const SCROW MAXROW
Definition: address.hxx:69
bool GetHeaderDrag(const ScAddress &rPos, bool bMouseLeft, bool bMouseTop, tools::Long nDragDim, tools::Rectangle &rPosRect, css::sheet::DataPilotFieldOrientation &rOrient, tools::Long &rDimPos)
Definition: dpoutput.cxx:1594
SCTAB Tab() const
Definition: address.hxx:271
void SetError(SCCOL nCol, SCROW nRow, SCTAB nTab, const FormulaError nError)
Definition: documen2.cxx:1056
ScRange GetOutputRange(sal_Int32 nRegionType=css::sheet::DataPilotOutputRangeType::WHOLE)
Refresh?
Definition: dpoutput.cxx:1123
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
static void lcl_DoFilterButton(ScDocument *pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: dpoutput.cxx:826
css::uno::Reference< css::sheet::XDimensionsSupplier > xSource
Definition: dpoutput.hxx:49
tools::Long GetHeaderDim(const ScAddress &rPos, css::sheet::DataPilotFieldOrientation &rOrient)
Definition: dpoutput.cxx:1548
std::vector< ScDPOutLevelData > pRowFields
Definition: dpoutput.hxx:52
SC_DLLPUBLIC bool SetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString &rString, const ScSetStringParam *pParam=nullptr)
Definition: document.cxx:3363
dp button with popup arrow
void ApplyFrameAreaTab(const ScRange &rRange, const SvxBoxItem &rLineOuter, const SvxBoxInfoItem &rLineInner)
Definition: document.cxx:5861
#define SC_UNO_DP_FUNCTION2
Definition: unonames.hxx:595
ScDPOutput(ScDocument *pD, const css::uno::Reference< css::sheet::XDimensionsSupplier > &xSrc, const ScAddress &rPos, bool bFilter)
Definition: dpoutput.cxx:502
int i
void HeaderCell(SCCOL nCol, SCROW nRow, SCTAB nTab, const css::sheet::MemberResult &rData, bool bColHeader, tools::Long nLevel)
Definition: dpoutput.cxx:741
void SetHeaderLayout(bool bUseGrid)
Definition: dpoutput.cxx:1193
sal_Int16 SCCOL
Definition: types.hxx:22
const SCCOL MAXCOL
Definition: address.hxx:70
static SC_DLLPUBLIC OUString getSourceDimensionName(const OUString &rName)
Definition: dputil.cxx:64
autofilter arrow
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
static bool GetBoolProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName, bool bDefault=false)
Definition: miscuno.cxx:35
std::vector< ScDPOutLevelData > pColFields
Definition: dpoutput.hxx:51
OUString ScResId(const char *pId)
Definition: scdll.cxx:95
const int COUNT
Definition: sheetevents.cxx:56
OUString maCaption
Name is the internal field name.
Definition: dpoutput.cxx:85
constexpr TypedWhichId< SfxUInt32Item > ATTR_VALUE_FORMAT(146)
bool HasError()
Definition: dpoutput.cxx:1143
SCCOL nMemberStartCol
Definition: dpoutput.hxx:72
void GetPositionData(const ScAddress &rPos, css::sheet::DataPilotTablePositionData &rPosData)
Definition: dpoutput.cxx:1283
void FieldCell(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScDPOutLevelData &rData, bool bInTable)
Definition: dpoutput.cxx:791
tools::Long nColCount
Definition: dpoutput.hxx:67
#define SC_UNO_DP_HAS_HIDDEN_MEMBER
Definition: unonames.hxx:614
tools::Long mnLevel
Definition: dpoutput.cxx:80
tools::Long mnDim
Definition: dpoutput.cxx:78
tools::Long GetHeaderRows() const
Definition: dpoutput.cxx:1150
SCCOL Col() const
Definition: address.hxx:267
bool bSizeOverflow
Definition: dpoutput.hxx:81
tools::Long AdjustTop(tools::Long nVertMoveDelta)
#define SC_UNO_DP_ROWGRAND
Definition: unonames.hxx:588
#define SC_UNO_DP_DATAFIELDCOUNT
Definition: unonames.hxx:610
#define SC_UNO_DP_ORIENTATION
Definition: unonames.hxx:592
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
sal_Int32 SCROW
Definition: types.hxx:18
bool bResultsError
Definition: dpoutput.hxx:79
ScMF
Definition: attrib.hxx:35
bool mbDetectNumberFormat
When true, we try to detect special number format (dates etc) from the input string, when false, we only try to detect a basic decimal number format.
Definition: stringutil.hxx:78
#define SC_UNO_DP_USEDHIERARCHY
Definition: unonames.hxx:596
bool bDoFilter
Definition: dpoutput.hxx:78
void SetPosition(const ScAddress &rPos)
Definition: dpoutput.cxx:683
#define SC_UNO_DP_DATADESC
Definition: unonames.hxx:606
std::unordered_set< OUString > ScDPUniqueStringSet
Definition: dptypes.hxx:17
SCROW nTabEndRow
Definition: dpoutput.hxx:77
ScAddress aStartPos
Definition: dpoutput.hxx:50
#define SC_UNONAME_NUMFMT
Definition: unonames.hxx:106
void DataCell(SCCOL nCol, SCROW nRow, SCTAB nTab, const css::sheet::DataResult &rData)
Definition: dpoutput.cxx:689
OUString aName
virtual SfxStyleSheetBase & Make(const OUString &, SfxStyleFamily eFam, SfxStyleSearchBits nMask=SfxStyleSearchBits::All) override
Definition: stlpool.cxx:72
#define SC_UNO_DP_ISVISIBLE
Definition: unonames.hxx:602
OUString aDataDescription
Definition: dpoutput.hxx:55
virtual SC_DLLPUBLIC SfxItemSet & GetItemSet() override
Definition: stlsheet.cxx:126
constexpr TypedWhichId< SvxWeightItem > ATTR_FONT_WEIGHT(102)
constexpr TypedWhichId< SvxHorJustifyItem > ATTR_HOR_JUSTIFY(129)
sal_uInt32 nSingleNumFmt
Definition: dpoutput.hxx:64
bool GetHeaderLayout() const
Definition: dpoutput.hxx:127
static sal_Int16 GetShortProperty(const css::uno::Reference< css::beans::XPropertySet > &xProp, const OUString &rName, sal_Int16 nDefault)
Definition: miscuno.cxx:53
Set Text number format if the input string can be parsed as a number or formula text.
Definition: stringutil.hxx:46
SC_DLLPUBLIC ScStyleSheetPool * GetStyleSheetPool() const
Definition: document.cxx:6066
SCROW nTabStartRow
Definition: dpoutput.hxx:71
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
SCCOL nTabEndCol
Definition: dpoutput.hxx:76
#define SC_UNO_DP_ISDATALAYOUT
Definition: unonames.hxx:591
tools::Long nHeaderSize
Definition: dpoutput.hxx:69
void setNumericInput()
Call this whenever you need to maximize the chance of input being detected as a numeric value (number...
Definition: stringutil.cxx:45
SC_DLLPUBLIC void DeleteAreaTab(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab, InsertDeleteFlags nDelFlag)
Definition: document.cxx:1955
virtual SfxStyleSheetBase * Find(const OUString &, SfxStyleFamily eFam, SfxStyleSearchBits n=SfxStyleSearchBits::All)
SCROW nMemberStartRow
Definition: dpoutput.hxx:73
constexpr TypedWhichId< SvxWeightItem > ATTR_CJK_FONT_WEIGHT(113)
tools::Long mnDimPos
Definition: dpoutput.cxx:81
bool IsFilterButton(const ScAddress &rPos)
Definition: dpoutput.cxx:1536
#define SC_UNO_DP_NUMBERFO
Definition: unonames.hxx:607
sal_uInt16 nPos
sal_Int16 SCTAB
Definition: types.hxx:23
std::unique_ptr< sal_uInt32[]> pColNumFmt
Definition: dpoutput.hxx:59