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