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