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