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