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