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 67640 : 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 67598 : ScDPOutLevelData() :
92 67598 : nDim(-1), nHier(-1), nLevel(-1), nDimPos(-1), mnSrcNumFmt(0), mbHasHiddenMember(false), mbDataLayout(false), mbPageDim(false)
93 67598 : {}
94 :
95 26 : bool operator<(const ScDPOutLevelData& r) const
96 52 : { return nDimPos<r.nDimPos || ( nDimPos==r.nDimPos && nHier<r.nHier ) ||
97 38 : ( nDimPos==r.nDimPos && nHier==r.nHier && nLevel<r.nLevel ); }
98 :
99 14 : void Swap(ScDPOutLevelData& r)
100 14 : { 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 244 : bool lcl_compareColfuc ( SCCOL i, SCCOL j) { return (i<j); }
108 340 : bool lcl_compareRowfuc ( SCROW i, SCROW j) { return (i<j); }
109 :
110 199 : 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 87 : void ScDPOutputImpl::OutputDataArea()
145 : {
146 87 : AddRow( mnDataStartRow );
147 87 : AddCol( mnDataStartCol );
148 :
149 87 : mnCols.push_back( mnTabEndCol+1); //set last row bottom
150 87 : mnRows.push_back( mnTabEndRow+1); //set last col bottom
151 :
152 87 : bool bAllRows = ( ( mnTabEndRow - mnDataStartRow + 2 ) == (SCROW) mnRows.size() );
153 :
154 87 : std::sort( mnCols.begin(), mnCols.end(), lcl_compareColfuc );
155 87 : std::sort( mnRows.begin(), mnRows.end(), lcl_compareRowfuc );
156 :
157 228 : for( SCCOL nCol = 0; nCol < (SCCOL)mnCols.size()-1; nCol ++ )
158 : {
159 141 : if ( !bAllRows )
160 : {
161 102 : if ( nCol < (SCCOL)mnCols.size()-2)
162 : {
163 75 : for ( SCROW i = nCol%2; i < (SCROW)mnRows.size()-2; i +=2 )
164 39 : OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 );
165 36 : if ( mnRows.size()>=2 )
166 36 : OutputBlockFrame( mnCols[nCol], mnRows[mnRows.size()-2], mnCols[nCol+1]-1, mnRows[mnRows.size()-1]-1 );
167 : }
168 : else
169 : {
170 215 : for ( SCROW i = 0 ; i < (SCROW)mnRows.size()-1; i++ )
171 149 : OutputBlockFrame( mnCols[nCol], mnRows[i], mnCols[nCol+1]-1, mnRows[i+1]-1 );
172 : }
173 : }
174 : else
175 39 : OutputBlockFrame( mnCols[nCol], mnRows.front(), mnCols[nCol+1]-1, mnRows.back()-1, bAllRows );
176 : }
177 : //out put rows area outer framer
178 87 : if ( mnTabStartCol != mnDataStartCol )
179 : {
180 72 : if ( mnTabStartRow != mnDataStartRow )
181 72 : OutputBlockFrame( mnTabStartCol, mnTabStartRow, mnDataStartCol-1, mnDataStartRow-1 );
182 72 : OutputBlockFrame( mnTabStartCol, mnDataStartRow, mnDataStartCol-1, mnTabEndRow );
183 : }
184 : //out put cols area outer framer
185 87 : OutputBlockFrame( mnDataStartCol, mnTabStartRow, mnTabEndCol, mnDataStartRow-1 );
186 87 : }
187 :
188 199 : 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 199 : mnTabEndRow( nTabEndRow )
203 : {
204 199 : mbNeedLineCols.resize( nTabEndCol-nDataStartCol+1, false );
205 199 : mbNeedLineRows.resize( nTabEndRow-nDataStartRow+1, false );
206 :
207 199 : }
208 :
209 216 : bool ScDPOutputImpl::AddRow( SCROW nRow )
210 : {
211 216 : if ( !mbNeedLineRows[ nRow - mnDataStartRow ] )
212 : {
213 195 : mbNeedLineRows[ nRow - mnDataStartRow ] = true;
214 195 : mnRows.push_back( nRow );
215 195 : return true;
216 : }
217 : else
218 21 : return false;
219 : }
220 :
221 145 : bool ScDPOutputImpl::AddCol( SCCOL nCol )
222 : {
223 :
224 145 : if ( !mbNeedLineCols[ nCol - mnDataStartCol ] )
225 : {
226 141 : mbNeedLineCols[ nCol - mnDataStartCol ] = true;
227 141 : mnCols.push_back( nCol );
228 141 : return true;
229 : }
230 : else
231 4 : return false;
232 : }
233 :
234 806 : void ScDPOutputImpl::OutputBlockFrame ( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bHori )
235 : {
236 806 : Color color = SC_DP_FRAME_COLOR;
237 806 : ::editeng::SvxBorderLine aLine( &color, SC_DP_FRAME_INNER_BOLD );
238 806 : ::editeng::SvxBorderLine aOutLine( &color, SC_DP_FRAME_OUTER_BOLD );
239 :
240 806 : SvxBoxItem aBox( ATTR_BORDER );
241 :
242 806 : if ( nStartCol == mnTabStartCol )
243 344 : aBox.SetLine(&aOutLine, SvxBoxItemLine::LEFT);
244 : else
245 462 : aBox.SetLine(&aLine, SvxBoxItemLine::LEFT);
246 :
247 806 : if ( nStartRow == mnTabStartRow )
248 200 : aBox.SetLine(&aOutLine, SvxBoxItemLine::TOP);
249 : else
250 606 : aBox.SetLine(&aLine, SvxBoxItemLine::TOP);
251 :
252 806 : if ( nEndCol == mnTabEndCol ) //bottom row
253 392 : aBox.SetLine(&aOutLine, SvxBoxItemLine::RIGHT);
254 : else
255 414 : aBox.SetLine(&aLine, SvxBoxItemLine::RIGHT);
256 :
257 806 : if ( nEndRow == mnTabEndRow ) //bottom
258 281 : aBox.SetLine(&aOutLine, SvxBoxItemLine::BOTTOM);
259 : else
260 525 : aBox.SetLine(&aLine, SvxBoxItemLine::BOTTOM);
261 :
262 1612 : SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
263 806 : aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT,false );
264 806 : if ( bHori )
265 : {
266 39 : aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI,true);
267 39 : aBoxInfo.SetLine( &aLine, SvxBoxInfoItemLine::HORI );
268 : }
269 : else
270 767 : aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI,false );
271 :
272 806 : aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE,false);
273 :
274 1612 : mpDoc->ApplyFrameAreaTab( ScRange( nStartCol, nStartRow, mnTab, nEndCol, nEndRow , mnTab ), &aBox, &aBoxInfo );
275 :
276 806 : }
277 :
278 1152 : void lcl_SetStyleById( ScDocument* pDoc, SCTAB nTab,
279 : SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
280 : sal_uInt16 nStrId )
281 : {
282 1152 : if ( nCol1 > nCol2 || nRow1 > nRow2 )
283 : {
284 : OSL_FAIL("SetStyleById: invalid range");
285 1152 : return;
286 : }
287 :
288 1152 : OUString aStyleName = ScGlobal::GetRscString( nStrId );
289 1152 : ScStyleSheetPool* pStlPool = pDoc->GetStyleSheetPool();
290 1152 : ScStyleSheet* pStyle = static_cast<ScStyleSheet*>( pStlPool->Find( aStyleName, SFX_STYLE_FAMILY_PARA ) );
291 1152 : 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 200 : SFXSTYLEBIT_USERDEF ) );
297 200 : pStyle->SetParent( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) );
298 200 : SfxItemSet& rSet = pStyle->GetItemSet();
299 200 : if ( nStrId==STR_PIVOT_STYLE_RESULT || nStrId==STR_PIVOT_STYLE_TITLE )
300 62 : rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
301 200 : if ( nStrId==STR_PIVOT_STYLE_CATEGORY || nStrId==STR_PIVOT_STYLE_TITLE )
302 63 : rSet.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
303 : }
304 :
305 1152 : pDoc->ApplyStyleAreaTab( nCol1, nRow1, nCol2, nRow2, nTab, *pStyle );
306 : }
307 :
308 164 : void lcl_SetFrame( ScDocument* pDoc, SCTAB nTab,
309 : SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
310 : sal_uInt16 nWidth )
311 : {
312 164 : ::editeng::SvxBorderLine aLine(0, nWidth, table::BorderLineStyle::SOLID);
313 164 : SvxBoxItem aBox( ATTR_BORDER );
314 164 : aBox.SetLine(&aLine, SvxBoxItemLine::LEFT);
315 164 : aBox.SetLine(&aLine, SvxBoxItemLine::TOP);
316 164 : aBox.SetLine(&aLine, SvxBoxItemLine::RIGHT);
317 164 : aBox.SetLine(&aLine, SvxBoxItemLine::BOTTOM);
318 328 : SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
319 164 : aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI,false);
320 164 : aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT,false);
321 164 : aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE,false);
322 :
323 328 : pDoc->ApplyFrameAreaTab( ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab ), &aBox, &aBoxInfo );
324 164 : }
325 :
326 49 : void lcl_FillNumberFormats( sal_uInt32*& rFormats, long& rCount,
327 : const uno::Reference<sheet::XDataPilotMemberResults>& xLevRes,
328 : const uno::Reference<container::XIndexAccess>& xDims )
329 : {
330 49 : if ( rFormats )
331 1 : return; // already set
332 :
333 : // xLevRes is from the data layout dimension
334 : //TODO: use result sequence from ScDPOutLevelData!
335 :
336 49 : uno::Sequence<sheet::MemberResult> aResult = xLevRes->getResults();
337 :
338 49 : long nSize = aResult.getLength();
339 49 : if (!nSize)
340 0 : return;
341 :
342 : // get names/formats for all data dimensions
343 : //TODO: merge this with the loop to collect ScDPOutLevelData?
344 :
345 12593 : OUString aDataNames[SC_DPOUT_MAXLEVELS];
346 : sal_uInt32 nDataFormats[SC_DPOUT_MAXLEVELS];
347 49 : long nDataCount = 0;
348 49 : long nDimCount = xDims->getCount();
349 258 : for (long nDim=0; nDim<nDimCount; nDim++)
350 : {
351 : uno::Reference<uno::XInterface> xDim =
352 209 : ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
353 418 : uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
354 418 : uno::Reference<container::XNamed> xDimName( xDim, uno::UNO_QUERY );
355 209 : if ( xDimProp.is() && xDimName.is() )
356 : {
357 : sheet::DataPilotFieldOrientation eDimOrient =
358 : (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
359 : xDimProp, OUString(SC_UNO_DP_ORIENTATION),
360 209 : sheet::DataPilotFieldOrientation_HIDDEN );
361 209 : if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
362 : {
363 57 : aDataNames[nDataCount] = xDimName->getName();
364 : long nFormat = ScUnoHelpFunctions::GetLongProperty(
365 : xDimProp,
366 57 : OUString(SC_UNONAME_NUMFMT) );
367 57 : nDataFormats[nDataCount] = nFormat;
368 57 : ++nDataCount;
369 : }
370 : }
371 209 : }
372 :
373 49 : if (!nDataCount)
374 1 : return;
375 :
376 48 : const sheet::MemberResult* pArray = aResult.getConstArray();
377 :
378 96 : OUString aName;
379 48 : sal_uInt32* pNumFmt = new sal_uInt32[nSize];
380 48 : if (nDataCount == 1)
381 : {
382 : // only one data dimension -> use its numberformat everywhere
383 39 : long nFormat = nDataFormats[0];
384 259 : for (long nPos=0; nPos<nSize; nPos++)
385 220 : pNumFmt[nPos] = nFormat;
386 : }
387 : else
388 : {
389 35 : for (long nPos=0; nPos<nSize; nPos++)
390 : {
391 : // if CONTINUE bit is set, keep previous name
392 : //TODO: keep number format instead!
393 26 : if ( !(pArray[nPos].Flags & sheet::MemberResultFlags::CONTINUE) )
394 26 : aName = pArray[nPos].Name;
395 :
396 26 : sal_uInt32 nFormat = 0;
397 39 : for (long i=0; i<nDataCount; i++)
398 39 : if (aName == aDataNames[i]) //TODO: search more efficiently?
399 : {
400 26 : nFormat = nDataFormats[i];
401 26 : break;
402 : }
403 26 : pNumFmt[nPos] = nFormat;
404 : }
405 : }
406 :
407 48 : rFormats = pNumFmt;
408 96 : rCount = nSize;
409 : }
410 :
411 39 : sal_uInt32 lcl_GetFirstNumberFormat( const uno::Reference<container::XIndexAccess>& xDims )
412 : {
413 39 : long nDimCount = xDims->getCount();
414 155 : for (long nDim=0; nDim<nDimCount; nDim++)
415 : {
416 : uno::Reference<uno::XInterface> xDim =
417 145 : ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
418 261 : uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
419 145 : if ( xDimProp.is() )
420 : {
421 : sheet::DataPilotFieldOrientation eDimOrient =
422 : (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
423 : xDimProp, OUString(SC_UNO_DP_ORIENTATION),
424 145 : sheet::DataPilotFieldOrientation_HIDDEN );
425 145 : if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
426 : {
427 : long nFormat = ScUnoHelpFunctions::GetLongProperty(
428 : xDimProp,
429 29 : OUString(SC_UNONAME_NUMFMT) );
430 :
431 29 : return nFormat; // use format from first found data dimension
432 : }
433 : }
434 116 : }
435 :
436 10 : return 0; // none found
437 : }
438 :
439 264 : void lcl_SortFields( ScDPOutLevelData* pFields, long nFieldCount )
440 : {
441 287 : for (long i=0; i+1<nFieldCount; i++)
442 : {
443 49 : for (long j=0; j+i+1<nFieldCount; j++)
444 26 : if ( pFields[j+1] < pFields[j] )
445 14 : pFields[j].Swap( pFields[j+1] );
446 : }
447 264 : }
448 :
449 179 : bool lcl_MemberEmpty( const uno::Sequence<sheet::MemberResult>& rSeq )
450 : {
451 : // used to skip levels that have no members
452 :
453 179 : long nLen = rSeq.getLength();
454 179 : const sheet::MemberResult* pArray = rSeq.getConstArray();
455 404 : for (long i=0; i<nLen; i++)
456 364 : if (pArray[i].Flags & sheet::MemberResultFlags::HASMEMBER)
457 139 : return false;
458 :
459 40 : 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 27 : uno::Sequence<sheet::MemberResult> getVisiblePageMembersAsResults( const uno::Reference<uno::XInterface>& xLevel )
467 : {
468 27 : if (!xLevel.is())
469 0 : return uno::Sequence<sheet::MemberResult>();
470 :
471 27 : uno::Reference<sheet::XMembersSupplier> xMSupplier(xLevel, UNO_QUERY);
472 27 : if (!xMSupplier.is())
473 0 : return uno::Sequence<sheet::MemberResult>();
474 :
475 54 : uno::Reference<container::XNameAccess> xNA = xMSupplier->getMembers();
476 27 : if (!xNA.is())
477 0 : return uno::Sequence<sheet::MemberResult>();
478 :
479 54 : std::vector<sheet::MemberResult> aRes;
480 54 : uno::Sequence<OUString> aNames = xNA->getElementNames();
481 138 : for (sal_Int32 i = 0; i < aNames.getLength(); ++i)
482 : {
483 111 : const OUString& rName = aNames[i];
484 111 : xNA->getByName(rName);
485 :
486 111 : uno::Reference<beans::XPropertySet> xMemPS(xNA->getByName(rName), UNO_QUERY);
487 111 : if (!xMemPS.is())
488 0 : continue;
489 :
490 222 : OUString aCaption = ScUnoHelpFunctions::GetStringProperty(xMemPS, SC_UNO_DP_LAYOUTNAME, OUString());
491 111 : if (aCaption.isEmpty())
492 111 : aCaption = rName;
493 :
494 111 : bool bVisible = ScUnoHelpFunctions::GetBoolProperty(xMemPS, SC_UNO_DP_ISVISIBLE, false);
495 :
496 111 : if (bVisible)
497 103 : aRes.push_back(sheet::MemberResult(rName, aCaption, 0));
498 111 : }
499 :
500 27 : if (aNames.getLength() == static_cast<sal_Int32>(aRes.size()))
501 : // All members are visible. Return empty result.
502 23 : return uno::Sequence<sheet::MemberResult>();
503 :
504 31 : return ScUnoHelpFunctions::VectorToSequence(aRes);
505 : }
506 :
507 : }
508 :
509 88 : 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 88 : mbHeaderLayout(false)
528 : {
529 88 : nTabStartCol = nMemberStartCol = nDataStartCol = nTabEndCol = 0;
530 88 : nTabStartRow = nMemberStartRow = nDataStartRow = nTabEndRow = 0;
531 :
532 88 : pColFields = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS];
533 88 : pRowFields = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS];
534 88 : pPageFields = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS];
535 88 : nColFieldCount = 0;
536 88 : nRowFieldCount = 0;
537 88 : nPageFieldCount = 0;
538 :
539 88 : uno::Reference<sheet::XDataPilotResults> xResult( xSource, uno::UNO_QUERY );
540 88 : if ( xSource.is() && xResult.is() )
541 : {
542 : // get dimension results:
543 :
544 : uno::Reference<container::XIndexAccess> xDims =
545 88 : new ScNameToIndexAccess( xSource->getDimensions() );
546 88 : long nDimCount = xDims->getCount();
547 540 : for (long nDim=0; nDim<nDimCount; nDim++)
548 : {
549 : uno::Reference<uno::XInterface> xDim =
550 452 : ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
551 904 : uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
552 904 : uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
553 452 : if ( xDimProp.is() && xDimSupp.is() )
554 : {
555 : sheet::DataPilotFieldOrientation eDimOrient =
556 : (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
557 : xDimProp, OUString(SC_UNO_DP_ORIENTATION),
558 452 : sheet::DataPilotFieldOrientation_HIDDEN );
559 : long nDimPos = ScUnoHelpFunctions::GetLongProperty( xDimProp,
560 452 : OUString(SC_UNO_DP_POSITION) );
561 : bool bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty(
562 452 : xDimProp, OUString(SC_UNO_DP_ISDATALAYOUT));
563 : bool bHasHiddenMember = ScUnoHelpFunctions::GetBoolProperty(
564 452 : xDimProp, OUString(SC_UNO_DP_HAS_HIDDEN_MEMBER));
565 : sal_Int32 nNumFmt = ScUnoHelpFunctions::GetLongProperty(
566 452 : xDimProp, SC_UNO_DP_NUMBERFO, 0);
567 :
568 452 : if ( eDimOrient != sheet::DataPilotFieldOrientation_HIDDEN )
569 : {
570 : uno::Reference<container::XIndexAccess> xHiers =
571 292 : new ScNameToIndexAccess( xDimSupp->getHierarchies() );
572 : long nHierarchy = ScUnoHelpFunctions::GetLongProperty(
573 : xDimProp,
574 292 : OUString(SC_UNO_DP_USEDHIERARCHY) );
575 292 : if ( nHierarchy >= xHiers->getCount() )
576 0 : nHierarchy = 0;
577 :
578 : uno::Reference<uno::XInterface> xHier =
579 : ScUnoHelpFunctions::AnyToInterface(
580 584 : xHiers->getByIndex(nHierarchy) );
581 584 : uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
582 292 : if ( xHierSupp.is() )
583 : {
584 : uno::Reference<container::XIndexAccess> xLevels =
585 292 : new ScNameToIndexAccess( xHierSupp->getLevels() );
586 292 : long nLevCount = xLevels->getCount();
587 584 : for (long nLev=0; nLev<nLevCount; nLev++)
588 : {
589 : uno::Reference<uno::XInterface> xLevel =
590 : ScUnoHelpFunctions::AnyToInterface(
591 292 : xLevels->getByIndex(nLev) );
592 584 : uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
593 : uno::Reference<sheet::XDataPilotMemberResults> xLevRes(
594 584 : xLevel, uno::UNO_QUERY );
595 292 : if ( xLevNam.is() && xLevRes.is() )
596 : {
597 292 : OUString aName = xLevNam->getName();
598 584 : 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 584 : OUString(SC_UNO_DP_LAYOUTNAME), aName );
604 :
605 292 : bool bRowFieldHasMember = false;
606 292 : switch ( eDimOrient )
607 : {
608 : case sheet::DataPilotFieldOrientation_COLUMN:
609 49 : pColFields[nColFieldCount].nDim = nDim;
610 49 : pColFields[nColFieldCount].nHier = nHierarchy;
611 49 : pColFields[nColFieldCount].nLevel = nLev;
612 49 : pColFields[nColFieldCount].nDimPos = nDimPos;
613 49 : pColFields[nColFieldCount].aResult = xLevRes->getResults();
614 49 : pColFields[nColFieldCount].mnSrcNumFmt = nNumFmt;
615 49 : pColFields[nColFieldCount].maName = aName;
616 49 : pColFields[nColFieldCount].maCaption= aCaption;
617 49 : pColFields[nColFieldCount].mbHasHiddenMember = bHasHiddenMember;
618 49 : pColFields[nColFieldCount].mbDataLayout = bIsDataLayout;
619 49 : if (!lcl_MemberEmpty(pColFields[nColFieldCount].aResult))
620 49 : ++nColFieldCount;
621 49 : break;
622 : case sheet::DataPilotFieldOrientation_ROW:
623 130 : pRowFields[nRowFieldCount].nDim = nDim;
624 130 : pRowFields[nRowFieldCount].nHier = nHierarchy;
625 130 : pRowFields[nRowFieldCount].nLevel = nLev;
626 130 : pRowFields[nRowFieldCount].nDimPos = nDimPos;
627 130 : pRowFields[nRowFieldCount].aResult = xLevRes->getResults();
628 130 : pRowFields[nRowFieldCount].mnSrcNumFmt = nNumFmt;
629 130 : pRowFields[nRowFieldCount].maName = aName;
630 130 : pRowFields[nRowFieldCount].maCaption= aCaption;
631 130 : pRowFields[nRowFieldCount].mbHasHiddenMember = bHasHiddenMember;
632 130 : pRowFields[nRowFieldCount].mbDataLayout = bIsDataLayout;
633 130 : if (!lcl_MemberEmpty(pRowFields[nRowFieldCount].aResult))
634 : {
635 90 : ++nRowFieldCount;
636 90 : bRowFieldHasMember = true;
637 : }
638 130 : break;
639 : case sheet::DataPilotFieldOrientation_PAGE:
640 27 : pPageFields[nPageFieldCount].nDim = nDim;
641 27 : pPageFields[nPageFieldCount].nHier = nHierarchy;
642 27 : pPageFields[nPageFieldCount].nLevel = nLev;
643 27 : pPageFields[nPageFieldCount].nDimPos = nDimPos;
644 27 : pPageFields[nPageFieldCount].aResult = getVisiblePageMembersAsResults(xLevel);
645 27 : pPageFields[nPageFieldCount].mnSrcNumFmt = nNumFmt;
646 27 : pPageFields[nPageFieldCount].maName = aName;
647 27 : pPageFields[nPageFieldCount].maCaption= aCaption;
648 27 : pPageFields[nPageFieldCount].mbHasHiddenMember = bHasHiddenMember;
649 27 : pPageFields[nPageFieldCount].mbPageDim = true;
650 : // no check on results for page fields
651 27 : ++nPageFieldCount;
652 27 : break;
653 : default:
654 : {
655 : // added to avoid warnings
656 : }
657 : }
658 :
659 : // get number formats from data dimensions
660 292 : if ( bIsDataLayout )
661 : {
662 49 : if (bRowFieldHasMember)
663 6 : mbHasDataLayout = true;
664 :
665 : OSL_ENSURE( nLevCount == 1, "data layout: multiple levels?" );
666 49 : if ( eDimOrient == sheet::DataPilotFieldOrientation_COLUMN )
667 3 : lcl_FillNumberFormats( pColNumFmt, nColFmtCount, xLevRes, xDims );
668 46 : else if ( eDimOrient == sheet::DataPilotFieldOrientation_ROW )
669 46 : lcl_FillNumberFormats( pRowNumFmt, nRowFmtCount, xLevRes, xDims );
670 292 : }
671 : }
672 584 : }
673 292 : }
674 : }
675 160 : 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 39 : nSingleNumFmt = lcl_GetFirstNumberFormat( xDims );
681 : }
682 : }
683 452 : }
684 88 : lcl_SortFields( pColFields, nColFieldCount );
685 88 : lcl_SortFields( pRowFields, nRowFieldCount );
686 88 : lcl_SortFields( pPageFields, nPageFieldCount );
687 :
688 : // get data results:
689 :
690 : try
691 : {
692 88 : aData = xResult->getResults();
693 : }
694 0 : catch (const uno::RuntimeException&)
695 : {
696 0 : bResultsError = true;
697 88 : }
698 : }
699 :
700 : // get "DataDescription" property (may be missing in external sources)
701 :
702 88 : uno::Reference<beans::XPropertySet> xSrcProp( xSource, uno::UNO_QUERY );
703 88 : if ( xSrcProp.is() )
704 : {
705 : try
706 : {
707 88 : uno::Any aAny = xSrcProp->getPropertyValue(
708 88 : OUString(SC_UNO_DP_DATADESC) );
709 176 : OUString aUStr;
710 88 : aAny >>= aUStr;
711 176 : aDataDescription = aUStr;
712 : }
713 0 : catch(const uno::Exception&)
714 : {
715 : }
716 88 : }
717 88 : }
718 :
719 176 : ScDPOutput::~ScDPOutput()
720 : {
721 88 : delete[] pColFields;
722 88 : delete[] pRowFields;
723 88 : delete[] pPageFields;
724 :
725 88 : delete[] pColNumFmt;
726 88 : delete[] pRowNumFmt;
727 88 : }
728 :
729 153 : void ScDPOutput::SetPosition( const ScAddress& rPos )
730 : {
731 153 : aStartPos = rPos;
732 153 : bSizesValid = bSizeOverflow = false;
733 153 : }
734 :
735 1438 : void ScDPOutput::DataCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const sheet::DataResult& rData )
736 : {
737 1438 : long nFlags = rData.Flags;
738 1438 : if ( nFlags & sheet::DataResultFlags::ERROR )
739 : {
740 0 : pDoc->SetError( nCol, nRow, nTab, errNoValue );
741 : }
742 1438 : else if ( nFlags & sheet::DataResultFlags::HASDATA )
743 : {
744 750 : pDoc->SetValue( nCol, nRow, nTab, rData.Value );
745 :
746 : // use number formats from source
747 :
748 : OSL_ENSURE( bSizesValid, "DataCell: !bSizesValid" );
749 750 : sal_uInt32 nFormat = 0;
750 750 : bool bApplyFormat = false;
751 750 : if ( pColNumFmt )
752 : {
753 38 : if ( nCol >= nDataStartCol )
754 : {
755 38 : long nIndex = nCol - nDataStartCol;
756 38 : if ( nIndex < nColFmtCount )
757 : {
758 38 : nFormat = pColNumFmt[nIndex];
759 38 : bApplyFormat = true;
760 : }
761 : }
762 : }
763 712 : else if ( pRowNumFmt )
764 : {
765 371 : if ( nRow >= nDataStartRow )
766 : {
767 371 : long nIndex = nRow - nDataStartRow;
768 371 : if ( nIndex < nRowFmtCount )
769 : {
770 371 : nFormat = pRowNumFmt[nIndex];
771 371 : bApplyFormat = true;
772 : }
773 : }
774 : }
775 341 : else if ( nSingleNumFmt != 0 )
776 : {
777 0 : nFormat = nSingleNumFmt; // single format is used everywhere
778 0 : bApplyFormat = true;
779 : }
780 :
781 750 : if (bApplyFormat)
782 409 : pDoc->ApplyAttr(nCol, nRow, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat));
783 : }
784 : // SubTotal formatting is controlled by headers
785 1438 : }
786 :
787 759 : void ScDPOutput::HeaderCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
788 : const sheet::MemberResult& rData, bool bColHeader, long nLevel )
789 : {
790 759 : long nFlags = rData.Flags;
791 :
792 759 : if ( nFlags & sheet::MemberResultFlags::HASMEMBER )
793 : {
794 702 : bool bNumeric = (nFlags & sheet::MemberResultFlags::NUMERIC) != 0;
795 702 : ScSetStringParam aParam;
796 702 : if (bNumeric)
797 340 : aParam.setNumericInput();
798 : else
799 362 : aParam.setTextInput();
800 :
801 702 : pDoc->SetString(nCol, nRow, nTab, rData.Caption, &aParam);
802 : }
803 :
804 759 : if ( nFlags & sheet::MemberResultFlags::SUBTOTAL )
805 : {
806 : ScDPOutputImpl outputimp( pDoc, nTab,
807 : nTabStartCol, nTabStartRow,
808 112 : nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow );
809 : //TODO: limit frames to horizontal or vertical?
810 112 : if (bColHeader)
811 : {
812 42 : outputimp.OutputBlockFrame( nCol,nMemberStartRow+(SCROW)nLevel, nCol,nDataStartRow-1 );
813 :
814 : lcl_SetStyleById( pDoc,nTab, nCol,nMemberStartRow+(SCROW)nLevel, nCol,nDataStartRow-1,
815 42 : STR_PIVOT_STYLE_TITLE );
816 : lcl_SetStyleById( pDoc,nTab, nCol,nDataStartRow, nCol,nTabEndRow,
817 42 : STR_PIVOT_STYLE_RESULT );
818 : }
819 : else
820 : {
821 70 : outputimp.OutputBlockFrame( nMemberStartCol+(SCCOL)nLevel,nRow, nDataStartCol-1,nRow );
822 : lcl_SetStyleById( pDoc,nTab, nMemberStartCol+(SCCOL)nLevel,nRow, nDataStartCol-1,nRow,
823 70 : STR_PIVOT_STYLE_TITLE );
824 : lcl_SetStyleById( pDoc,nTab, nDataStartCol,nRow, nTabEndCol,nRow,
825 70 : STR_PIVOT_STYLE_RESULT );
826 112 : }
827 : }
828 759 : }
829 :
830 164 : void ScDPOutput::FieldCell(
831 : SCCOL nCol, SCROW nRow, SCTAB nTab, const ScDPOutLevelData& rData, bool bInTable)
832 : {
833 : // Avoid unwanted automatic format detection.
834 164 : ScSetStringParam aParam;
835 164 : aParam.mbDetectNumberFormat = false;
836 164 : aParam.meSetTextNumFormat = ScSetStringParam::Always;
837 164 : aParam.mbHandleApostrophe = false;
838 164 : pDoc->SetString(nCol, nRow, nTab, rData.maCaption, &aParam);
839 :
840 164 : if (bInTable)
841 138 : lcl_SetFrame( pDoc,nTab, nCol,nRow, nCol,nRow, 20 );
842 :
843 : // For field button drawing
844 164 : sal_uInt16 nMergeFlag = 0;
845 164 : if (rData.mbHasHiddenMember)
846 4 : nMergeFlag |= SC_MF_HIDDEN_MEMBER;
847 :
848 164 : if (rData.mbPageDim)
849 : {
850 26 : nMergeFlag |= SC_MF_BUTTON_POPUP;
851 26 : pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON);
852 26 : pDoc->ApplyFlagsTab(nCol+1, nRow, nCol+1, nRow, nTab, nMergeFlag);
853 : }
854 : else
855 : {
856 138 : nMergeFlag |= SC_MF_BUTTON;
857 138 : if (!rData.mbDataLayout)
858 129 : nMergeFlag |= SC_MF_BUTTON_POPUP;
859 138 : pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, nMergeFlag);
860 : }
861 :
862 164 : lcl_SetStyleById( pDoc,nTab, nCol,nRow, nCol,nRow, STR_PIVOT_STYLE_FIELDNAME );
863 164 : }
864 :
865 50 : static void lcl_DoFilterButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
866 : {
867 50 : pDoc->SetString( nCol, nRow, nTab, ScGlobal::GetRscString(STR_CELL_FILTER) );
868 50 : pDoc->ApplyFlagsTab(nCol, nRow, nCol, nRow, nTab, SC_MF_BUTTON);
869 50 : }
870 :
871 1242 : void ScDPOutput::CalcSizes()
872 : {
873 1242 : if (!bSizesValid)
874 : {
875 : // get column size of data from first row
876 : //TODO: allow different sizes (and clear following areas) ???
877 :
878 188 : nRowCount = aData.getLength();
879 188 : const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
880 188 : nColCount = nRowCount ? ( pRowAry[0].getLength() ) : 0;
881 :
882 188 : nHeaderSize = 1;
883 188 : 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 188 : long nPageSize = 0; // use page fields!
890 188 : if ( bDoFilter || nPageFieldCount )
891 : {
892 122 : nPageSize += nPageFieldCount + 1; // plus one empty row
893 122 : if ( bDoFilter )
894 116 : ++nPageSize; // filter button above the page fields
895 : }
896 :
897 376 : if ( aStartPos.Col() + nRowFieldCount + nColCount - 1 > MAXCOL ||
898 188 : aStartPos.Row() + nPageSize + nHeaderSize + nColFieldCount + nRowCount > MAXROW )
899 : {
900 0 : bSizeOverflow = true;
901 : }
902 :
903 188 : nTabStartCol = aStartPos.Col();
904 188 : nTabStartRow = aStartPos.Row() + (SCROW)nPageSize; // below page fields
905 188 : nMemberStartCol = nTabStartCol;
906 188 : nMemberStartRow = nTabStartRow + (SCROW) nHeaderSize;
907 188 : nDataStartCol = nMemberStartCol + (SCCOL)nRowFieldCount;
908 188 : nDataStartRow = nMemberStartRow + (SCROW)nColFieldCount;
909 188 : if ( nColCount > 0 )
910 186 : nTabEndCol = nDataStartCol + (SCCOL)nColCount - 1;
911 : else
912 2 : nTabEndCol = nDataStartCol; // single column will remain empty
913 : // if page fields are involved, include the page selection cells
914 188 : if ( nPageFieldCount > 0 && nTabEndCol < nTabStartCol + 1 )
915 2 : nTabEndCol = nTabStartCol + 1;
916 188 : if ( nRowCount > 0 )
917 186 : nTabEndRow = nDataStartRow + (SCROW)nRowCount - 1;
918 : else
919 2 : nTabEndRow = nDataStartRow; // single row will remain empty
920 188 : bSizesValid = true;
921 : }
922 1242 : }
923 :
924 266 : sal_Int32 ScDPOutput::GetPositionType(const ScAddress& rPos)
925 : {
926 : using namespace ::com::sun::star::sheet;
927 :
928 266 : SCCOL nCol = rPos.Col();
929 266 : SCROW nRow = rPos.Row();
930 266 : SCTAB nTab = rPos.Tab();
931 266 : if ( nTab != aStartPos.Tab() )
932 0 : return DataPilotTablePositionType::NOT_IN_TABLE;
933 :
934 266 : CalcSizes();
935 :
936 : // Make sure the cursor is within the table.
937 266 : if (nCol < nTabStartCol || nRow < nTabStartRow || nCol > nTabEndCol || nRow > nTabEndRow)
938 0 : return DataPilotTablePositionType::NOT_IN_TABLE;
939 :
940 : // test for result data area.
941 266 : if (nCol >= nDataStartCol && nCol <= nTabEndCol && nRow >= nDataStartRow && nRow <= nTabEndRow)
942 194 : return DataPilotTablePositionType::RESULT;
943 :
944 72 : bool bInColHeader = (nRow >= nTabStartRow && nRow < nDataStartRow);
945 72 : bool bInRowHeader = (nCol >= nTabStartCol && nCol < nDataStartCol);
946 :
947 72 : if (bInColHeader && bInRowHeader)
948 : // probably in that ugly little box at the upper-left corner of the table.
949 12 : return DataPilotTablePositionType::OTHER;
950 :
951 60 : if (bInColHeader)
952 : {
953 36 : if (nRow == nTabStartRow)
954 : // first row in the column header area is always used for column
955 : // field buttons.
956 12 : return DataPilotTablePositionType::OTHER;
957 :
958 24 : return DataPilotTablePositionType::COLUMN_HEADER;
959 : }
960 :
961 24 : if (bInRowHeader)
962 24 : return DataPilotTablePositionType::ROW_HEADER;
963 :
964 0 : return DataPilotTablePositionType::OTHER;
965 : }
966 :
967 87 : void ScDPOutput::Output()
968 : {
969 : long nField;
970 87 : SCTAB nTab = aStartPos.Tab();
971 87 : const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
972 :
973 : // calculate output positions and sizes
974 :
975 87 : CalcSizes();
976 87 : if ( bSizeOverflow || bResultsError ) // does output area exceed sheet limits?
977 87 : return; // nothing
978 :
979 : // clear whole (new) output area
980 : // when modifying table, clear old area !
981 : //TODO: include IDF_OBJECTS ???
982 87 : pDoc->DeleteAreaTab( aStartPos.Col(), aStartPos.Row(), nTabEndCol, nTabEndRow, nTab, IDF_ALL );
983 :
984 87 : if ( bDoFilter )
985 50 : lcl_DoFilterButton( pDoc, aStartPos.Col(), aStartPos.Row(), nTab );
986 :
987 : // output page fields:
988 :
989 113 : for (nField=0; nField<nPageFieldCount; nField++)
990 : {
991 26 : SCCOL nHdrCol = aStartPos.Col();
992 26 : SCROW nHdrRow = aStartPos.Row() + nField + ( bDoFilter ? 1 : 0 );
993 : // draw without frame for consistency with filter button:
994 26 : FieldCell(nHdrCol, nHdrRow, nTab, pPageFields[nField], false);
995 26 : SCCOL nFldCol = nHdrCol + 1;
996 :
997 26 : OUString aPageValue = ScResId(SCSTR_ALL).toString();
998 26 : const uno::Sequence<sheet::MemberResult>& rRes = pPageFields[nField].aResult;
999 26 : sal_Int32 n = rRes.getLength();
1000 26 : if (n == 1)
1001 3 : aPageValue = rRes[0].Caption;
1002 23 : else if (n > 1)
1003 0 : aPageValue = ScResId(SCSTR_MULTIPLE).toString();
1004 :
1005 26 : ScSetStringParam aParam;
1006 26 : aParam.setTextInput();
1007 26 : pDoc->SetString(nFldCol, nHdrRow, nTab, aPageValue, &aParam);
1008 :
1009 26 : lcl_SetFrame( pDoc,nTab, nFldCol,nHdrRow, nFldCol,nHdrRow, 20 );
1010 26 : }
1011 :
1012 : // data description
1013 : // (may get overwritten by first row field)
1014 :
1015 87 : if (aDataDescription.isEmpty())
1016 : {
1017 : //TODO: use default string ("result") ?
1018 : }
1019 87 : pDoc->SetString(nTabStartCol, nTabStartRow, nTab, aDataDescription);
1020 :
1021 : // set STR_PIVOT_STYLE_INNER for whole data area (subtotals are overwritten)
1022 :
1023 87 : if ( nDataStartRow > nTabStartRow )
1024 : lcl_SetStyleById( pDoc, nTab, nTabStartCol, nTabStartRow, nTabEndCol, nDataStartRow-1,
1025 87 : STR_PIVOT_STYLE_TOP );
1026 : lcl_SetStyleById( pDoc, nTab, nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow,
1027 87 : STR_PIVOT_STYLE_INNER );
1028 :
1029 : // output column headers:
1030 : ScDPOutputImpl outputimp( pDoc, nTab,
1031 : nTabStartCol, nTabStartRow,
1032 87 : nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow );
1033 136 : for (nField=0; nField<nColFieldCount; nField++)
1034 : {
1035 49 : SCCOL nHdrCol = nDataStartCol + (SCCOL)nField; //TODO: check for overflow
1036 49 : FieldCell(nHdrCol, nTabStartRow, nTab, pColFields[nField], true);
1037 :
1038 49 : SCROW nRowPos = nMemberStartRow + (SCROW)nField; //TODO: check for overflow
1039 49 : const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].aResult;
1040 49 : const sheet::MemberResult* pArray = rSequence.getConstArray();
1041 49 : long nThisColCount = rSequence.getLength();
1042 : OSL_ENSURE( nThisColCount == nColCount, "count mismatch" ); //TODO: ???
1043 308 : for (long nCol=0; nCol<nThisColCount; nCol++)
1044 : {
1045 259 : SCCOL nColPos = nDataStartCol + (SCCOL)nCol; //TODO: check for overflow
1046 259 : HeaderCell( nColPos, nRowPos, nTab, pArray[nCol], true, nField );
1047 510 : if ( ( pArray[nCol].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
1048 251 : !( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
1049 : {
1050 209 : long nEnd = nCol;
1051 422 : while ( nEnd+1 < nThisColCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
1052 4 : ++nEnd;
1053 209 : SCCOL nEndColPos = nDataStartCol + (SCCOL)nEnd; //TODO: check for overflow
1054 209 : if ( nField+1 < nColFieldCount )
1055 : {
1056 16 : if ( nField == nColFieldCount - 2 )
1057 : {
1058 16 : outputimp.AddCol( nColPos );
1059 16 : 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 16 : lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nEndColPos,nDataStartRow-1, STR_PIVOT_STYLE_CATEGORY );
1066 : }
1067 : else
1068 193 : lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nColPos,nDataStartRow-1, STR_PIVOT_STYLE_CATEGORY );
1069 : }
1070 50 : else if ( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL )
1071 42 : outputimp.AddCol( nColPos );
1072 :
1073 : // Apply the same number format as in data source.
1074 259 : pDoc->ApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, pColFields[nField].mnSrcNumFmt));
1075 : }
1076 49 : if ( nField== 0 && nColFieldCount == 1 )
1077 41 : outputimp.OutputBlockFrame( nDataStartCol,nTabStartRow, nTabEndCol,nRowPos-1 );
1078 49 : }
1079 :
1080 : // output row headers:
1081 174 : std::vector<bool> vbSetBorder;
1082 87 : vbSetBorder.resize( nTabEndRow - nDataStartRow + 1, false );
1083 176 : for (nField=0; nField<nRowFieldCount; nField++)
1084 : {
1085 89 : SCCOL nHdrCol = nTabStartCol + (SCCOL)nField; //TODO: check for overflow
1086 89 : SCROW nHdrRow = nDataStartRow - 1;
1087 89 : FieldCell(nHdrCol, nHdrRow, nTab, pRowFields[nField], true);
1088 :
1089 89 : SCCOL nColPos = nMemberStartCol + (SCCOL)nField; //TODO: check for overflow
1090 89 : const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].aResult;
1091 89 : const sheet::MemberResult* pArray = rSequence.getConstArray();
1092 89 : long nThisRowCount = rSequence.getLength();
1093 : OSL_ENSURE( nThisRowCount == nRowCount, "count mismatch" ); //TODO: ???
1094 589 : for (long nRow=0; nRow<nThisRowCount; nRow++)
1095 : {
1096 500 : SCROW nRowPos = nDataStartRow + (SCROW)nRow; //TODO: check for overflow
1097 500 : HeaderCell( nColPos, nRowPos, nTab, pArray[nRow], false, nField );
1098 951 : if ( ( pArray[nRow].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
1099 451 : !( pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
1100 : {
1101 381 : if ( nField+1 < nRowFieldCount )
1102 : {
1103 59 : long nEnd = nRow;
1104 154 : while ( nEnd+1 < nThisRowCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
1105 36 : ++nEnd;
1106 59 : SCROW nEndRowPos = nDataStartRow + (SCROW)nEnd; //TODO: check for overflow
1107 59 : outputimp.AddRow( nRowPos );
1108 59 : if ( !vbSetBorder[ nRow ] )
1109 : {
1110 52 : outputimp.OutputBlockFrame( nColPos, nRowPos, nTabEndCol, nEndRowPos );
1111 52 : vbSetBorder[ nRow ] = true;
1112 : }
1113 59 : outputimp.OutputBlockFrame( nColPos, nRowPos, nColPos, nEndRowPos );
1114 :
1115 59 : if ( nField == nRowFieldCount - 2 )
1116 48 : outputimp.OutputBlockFrame( nColPos+1, nRowPos, nColPos+1, nEndRowPos );
1117 :
1118 59 : lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nEndRowPos, STR_PIVOT_STYLE_CATEGORY );
1119 : }
1120 : else
1121 322 : lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nRowPos, STR_PIVOT_STYLE_CATEGORY );
1122 : }
1123 119 : else if ( pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL )
1124 70 : outputimp.AddRow( nRowPos );
1125 :
1126 : // Apply the same number format as in data source.
1127 500 : pDoc->ApplyAttr(nColPos, nRowPos, nTab, SfxUInt32Item(ATTR_VALUE_FORMAT, pRowFields[nField].mnSrcNumFmt));
1128 : }
1129 89 : }
1130 :
1131 87 : 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 41 : ScSetStringParam aParam;
1136 41 : aParam.setTextInput();
1137 41 : pDoc->SetString(nDataStartCol, nDataStartRow-1, nTab, aDataDescription, &aParam);
1138 : }
1139 :
1140 : // output data results:
1141 :
1142 493 : for (long nRow=0; nRow<nRowCount; nRow++)
1143 : {
1144 406 : SCROW nRowPos = nDataStartRow + (SCROW)nRow; //TODO: check for overflow
1145 406 : const sheet::DataResult* pColAry = pRowAry[nRow].getConstArray();
1146 406 : long nThisColCount = pRowAry[nRow].getLength();
1147 : OSL_ENSURE( nThisColCount == nColCount, "count mismatch" ); //TODO: ???
1148 1844 : for (long nCol=0; nCol<nThisColCount; nCol++)
1149 : {
1150 1438 : SCCOL nColPos = nDataStartCol + (SCCOL)nCol; //TODO: check for overflow
1151 1438 : DataCell( nColPos, nRowPos, nTab, pColAry[nCol] );
1152 : }
1153 : }
1154 :
1155 174 : outputimp.OutputDataArea();
1156 : }
1157 :
1158 191 : ScRange ScDPOutput::GetOutputRange( sal_Int32 nRegionType )
1159 : {
1160 : using namespace ::com::sun::star::sheet;
1161 :
1162 191 : CalcSizes();
1163 :
1164 191 : SCTAB nTab = aStartPos.Tab();
1165 191 : switch (nRegionType)
1166 : {
1167 : case DataPilotOutputRangeType::RESULT:
1168 7 : return ScRange(nDataStartCol, nDataStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
1169 : case DataPilotOutputRangeType::TABLE:
1170 7 : return ScRange(aStartPos.Col(), nTabStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
1171 : default:
1172 : OSL_ENSURE(nRegionType == DataPilotOutputRangeType::WHOLE, "ScDPOutput::GetOutputRange: unknown region type");
1173 177 : break;
1174 : }
1175 177 : 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 104 : bool ScDPOutput::HasError()
1200 : {
1201 104 : CalcSizes();
1202 :
1203 104 : return bSizeOverflow || bResultsError;
1204 : }
1205 :
1206 88 : long ScDPOutput::GetHeaderRows()
1207 : {
1208 88 : 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 88 : void ScDPOutput::SetHeaderLayout(bool bUseGrid)
1255 : {
1256 88 : mbHeaderLayout = bUseGrid;
1257 88 : bSizesValid = false;
1258 88 : }
1259 :
1260 : namespace {
1261 :
1262 327 : 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 327 : rDataLayoutIndex = -1; // invalid
1268 327 : rGrandTotalCols = 0;
1269 327 : rGrandTotalRows = 0;
1270 327 : rDataOrient = sheet::DataPilotFieldOrientation_HIDDEN;
1271 :
1272 327 : uno::Reference<beans::XPropertySet> xSrcProp( xSource, uno::UNO_QUERY );
1273 : bool bColGrand = ScUnoHelpFunctions::GetBoolProperty(
1274 327 : xSrcProp, OUString(SC_UNO_DP_COLGRAND));
1275 327 : if ( bColGrand )
1276 327 : rGrandTotalCols = 1; // default if data layout not in columns
1277 :
1278 : bool bRowGrand = ScUnoHelpFunctions::GetBoolProperty(
1279 327 : xSrcProp, OUString(SC_UNO_DP_ROWGRAND));
1280 327 : if ( bRowGrand )
1281 327 : rGrandTotalRows = 1; // default if data layout not in rows
1282 :
1283 327 : if ( xSource.is() )
1284 : {
1285 : // find index and orientation of "data layout" dimension, count data dimensions
1286 :
1287 327 : sal_Int32 nDataCount = 0;
1288 :
1289 327 : uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xSource->getDimensions() );
1290 327 : long nDimCount = xDims->getCount();
1291 2289 : for (long nDim=0; nDim<nDimCount; nDim++)
1292 : {
1293 : uno::Reference<uno::XInterface> xDim =
1294 1962 : ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
1295 3924 : uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1296 1962 : if ( xDimProp.is() )
1297 : {
1298 : sheet::DataPilotFieldOrientation eDimOrient =
1299 : (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
1300 : xDimProp, OUString(SC_UNO_DP_ORIENTATION),
1301 1962 : sheet::DataPilotFieldOrientation_HIDDEN );
1302 3924 : if ( ScUnoHelpFunctions::GetBoolProperty( xDimProp,
1303 3924 : OUString(SC_UNO_DP_ISDATALAYOUT) ) )
1304 : {
1305 327 : rDataLayoutIndex = nDim;
1306 327 : rDataOrient = eDimOrient;
1307 : }
1308 1962 : if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
1309 : {
1310 327 : OUString aSourceName;
1311 654 : OUString aGivenName;
1312 327 : ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xDim );
1313 : try
1314 : {
1315 327 : uno::Any aValue = xDimProp->getPropertyValue( SC_UNO_DP_LAYOUTNAME );
1316 :
1317 327 : if( aValue.hasValue() )
1318 : {
1319 327 : OUString strLayoutName;
1320 :
1321 327 : if( ( aValue >>= strLayoutName ) && !strLayoutName.isEmpty() )
1322 0 : aGivenName = strLayoutName;
1323 327 : }
1324 : }
1325 0 : catch(const uno::Exception&)
1326 : {
1327 : }
1328 327 : rDataNames.push_back( aSourceName );
1329 327 : rGivenNames.push_back( aGivenName );
1330 :
1331 654 : ++nDataCount;
1332 : }
1333 : }
1334 1962 : }
1335 :
1336 327 : if ( ( rDataOrient == sheet::DataPilotFieldOrientation_COLUMN ) && bColGrand )
1337 0 : rGrandTotalCols = nDataCount;
1338 327 : else if ( ( rDataOrient == sheet::DataPilotFieldOrientation_ROW ) && bRowGrand )
1339 0 : rGrandTotalRows = nDataCount;
1340 327 : }
1341 327 : }
1342 :
1343 : }
1344 :
1345 266 : void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
1346 : {
1347 : using namespace ::com::sun::star::sheet;
1348 :
1349 266 : SCCOL nCol = rPos.Col();
1350 266 : SCROW nRow = rPos.Row();
1351 266 : SCTAB nTab = rPos.Tab();
1352 266 : if ( nTab != aStartPos.Tab() )
1353 0 : return; // wrong sheet
1354 :
1355 : // calculate output positions and sizes
1356 :
1357 266 : CalcSizes();
1358 :
1359 266 : rPosData.PositionType = GetPositionType(rPos);
1360 266 : switch (rPosData.PositionType)
1361 : {
1362 : case DataPilotTablePositionType::RESULT:
1363 : {
1364 194 : vector<DataPilotFieldFilter> aFilters;
1365 194 : GetDataResultPositionData(aFilters, rPos);
1366 194 : sal_Int32 nSize = aFilters.size();
1367 :
1368 388 : DataPilotTableResultData aResData;
1369 194 : aResData.FieldFilters.realloc(nSize);
1370 874 : for (sal_Int32 i = 0; i < nSize; ++i)
1371 680 : aResData.FieldFilters[i] = aFilters[i];
1372 :
1373 194 : aResData.DataFieldIndex = 0;
1374 388 : Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
1375 194 : if (xPropSet.is())
1376 : {
1377 : sal_Int32 nDataFieldCount = ScUnoHelpFunctions::GetLongProperty( xPropSet,
1378 194 : OUString(SC_UNO_DP_DATAFIELDCOUNT) );
1379 194 : if (nDataFieldCount > 0)
1380 194 : aResData.DataFieldIndex = (nRow - nDataStartRow) % nDataFieldCount;
1381 : }
1382 :
1383 : // Copy appropriate DataResult object from the cached sheet::DataResult table.
1384 388 : if (aData.getLength() > nRow - nDataStartRow &&
1385 194 : aData[nRow-nDataStartRow].getLength() > nCol-nDataStartCol)
1386 194 : aResData.Result = aData[nRow-nDataStartRow][nCol-nDataStartCol];
1387 :
1388 194 : rPosData.PositionData = makeAny(aResData);
1389 388 : return;
1390 : }
1391 : case DataPilotTablePositionType::COLUMN_HEADER:
1392 : {
1393 24 : long nField = nRow - nTabStartRow - 1; // 1st line is used for the buttons
1394 24 : if (nField < 0)
1395 0 : break;
1396 :
1397 24 : const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].aResult;
1398 24 : if (rSequence.getLength() == 0)
1399 0 : break;
1400 24 : const sheet::MemberResult* pArray = rSequence.getConstArray();
1401 :
1402 24 : long nItem = nCol - nDataStartCol;
1403 : // get origin of "continue" fields
1404 48 : while (nItem > 0 && ( pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1405 0 : --nItem;
1406 :
1407 24 : if (nItem < 0)
1408 0 : break;
1409 :
1410 48 : DataPilotTableHeaderData aHeaderData;
1411 24 : aHeaderData.MemberName = OUString(pArray[nItem].Name);
1412 24 : aHeaderData.Flags = pArray[nItem].Flags;
1413 24 : aHeaderData.Dimension = static_cast<sal_Int32>(pColFields[nField].nDim);
1414 24 : aHeaderData.Hierarchy = static_cast<sal_Int32>(pColFields[nField].nHier);
1415 24 : aHeaderData.Level = static_cast<sal_Int32>(pColFields[nField].nLevel);
1416 :
1417 24 : rPosData.PositionData = makeAny(aHeaderData);
1418 24 : return;
1419 : }
1420 : case DataPilotTablePositionType::ROW_HEADER:
1421 : {
1422 24 : long nField = nCol - nTabStartCol;
1423 24 : if (nField < 0)
1424 0 : break;
1425 :
1426 24 : const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].aResult;
1427 24 : if (rSequence.getLength() == 0)
1428 0 : break;
1429 24 : const sheet::MemberResult* pArray = rSequence.getConstArray();
1430 :
1431 24 : long nItem = nRow - nDataStartRow;
1432 : // get origin of "continue" fields
1433 48 : while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1434 0 : --nItem;
1435 :
1436 24 : if (nItem < 0)
1437 0 : break;
1438 :
1439 48 : DataPilotTableHeaderData aHeaderData;
1440 24 : aHeaderData.MemberName = OUString(pArray[nItem].Name);
1441 24 : aHeaderData.Flags = pArray[nItem].Flags;
1442 24 : aHeaderData.Dimension = static_cast<sal_Int32>(pRowFields[nField].nDim);
1443 24 : aHeaderData.Hierarchy = static_cast<sal_Int32>(pRowFields[nField].nHier);
1444 24 : aHeaderData.Level = static_cast<sal_Int32>(pRowFields[nField].nLevel);
1445 :
1446 24 : rPosData.PositionData = makeAny(aHeaderData);
1447 24 : return;
1448 : }
1449 : }
1450 : }
1451 :
1452 327 : bool ScDPOutput::GetDataResultPositionData(vector<sheet::DataPilotFieldFilter>& rFilters, const ScAddress& rPos)
1453 : {
1454 : // Check to make sure there is at least one data field.
1455 327 : Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
1456 327 : if (!xPropSet.is())
1457 0 : return false;
1458 :
1459 : sal_Int32 nDataFieldCount = ScUnoHelpFunctions::GetLongProperty( xPropSet,
1460 327 : OUString(SC_UNO_DP_DATAFIELDCOUNT) );
1461 327 : 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 654 : std::vector<OUString> aDataNames;
1470 654 : std::vector<OUString> aGivenNames;
1471 : sheet::DataPilotFieldOrientation eDataOrient;
1472 327 : lcl_GetTableVars( nGrandTotalCols, nGrandTotalRows, nDataLayoutIndex, aDataNames, aGivenNames, eDataOrient, xSource );
1473 :
1474 327 : SCCOL nCol = rPos.Col();
1475 327 : SCROW nRow = rPos.Row();
1476 327 : SCTAB nTab = rPos.Tab();
1477 327 : if ( nTab != aStartPos.Tab() )
1478 0 : return false; // wrong sheet
1479 :
1480 327 : CalcSizes();
1481 :
1482 : // test for data area.
1483 327 : 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 327 : bool bFilterByCol = (nCol <= static_cast<SCCOL>(nTabEndCol - nGrandTotalCols));
1490 327 : bool bFilterByRow = (nRow <= static_cast<SCROW>(nTabEndRow - nGrandTotalRows));
1491 :
1492 : // column fields
1493 897 : for (SCCOL nColField = 0; nColField < nColFieldCount && bFilterByCol; ++nColField)
1494 : {
1495 570 : if (pColFields[nColField].nDim == nDataLayoutIndex)
1496 : // There is no sense including the data layout field for filtering.
1497 0 : continue;
1498 :
1499 570 : sheet::DataPilotFieldFilter filter;
1500 570 : filter.FieldName = pColFields[nColField].maName;
1501 :
1502 1140 : const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nColField].aResult;
1503 570 : const sheet::MemberResult* pArray = rSequence.getConstArray();
1504 :
1505 : OSL_ENSURE(nDataStartCol + rSequence.getLength() - 1 == nTabEndCol, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1506 :
1507 570 : long nItem = nCol - nDataStartCol;
1508 : // get origin of "continue" fields
1509 1140 : while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1510 0 : --nItem;
1511 :
1512 570 : filter.MatchValue = pArray[nItem].Name;
1513 570 : rFilters.push_back(filter);
1514 570 : }
1515 :
1516 : // row fields
1517 897 : for (SCROW nRowField = 0; nRowField < nRowFieldCount && bFilterByRow; ++nRowField)
1518 : {
1519 570 : if (pRowFields[nRowField].nDim == nDataLayoutIndex)
1520 : // There is no sense including the data layout field for filtering.
1521 0 : continue;
1522 :
1523 570 : sheet::DataPilotFieldFilter filter;
1524 570 : filter.FieldName = pRowFields[nRowField].maName;
1525 :
1526 1140 : const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nRowField].aResult;
1527 570 : const sheet::MemberResult* pArray = rSequence.getConstArray();
1528 :
1529 : OSL_ENSURE(nDataStartRow + rSequence.getLength() - 1 == nTabEndRow, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
1530 :
1531 570 : long nItem = nRow - nDataStartRow;
1532 : // get origin of "continue" fields
1533 1140 : while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
1534 0 : --nItem;
1535 :
1536 570 : filter.MatchValue = pArray[nItem].Name;
1537 570 : rFilters.push_back(filter);
1538 570 : }
1539 :
1540 654 : return true;
1541 : }
1542 :
1543 : namespace {
1544 :
1545 346 : OUString lcl_GetDataFieldName( const OUString& rSourceName, sheet::GeneralFunction eFunc )
1546 : {
1547 346 : sal_uInt16 nStrId = 0;
1548 346 : switch ( eFunc )
1549 : {
1550 19 : 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 346 : if ( !nStrId )
1569 327 : return OUString();
1570 :
1571 19 : OUStringBuffer aRet( ScGlobal::GetRscString( nStrId ) );
1572 19 : aRet.append(" - ");
1573 19 : aRet.append(rSourceName);
1574 19 : return aRet.makeStringAndClear();
1575 : }
1576 :
1577 : }
1578 :
1579 346 : void ScDPOutput::GetDataDimensionNames(
1580 : OUString& rSourceName, OUString& rGivenName, const uno::Reference<uno::XInterface>& xDim )
1581 : {
1582 346 : uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
1583 692 : uno::Reference<container::XNamed> xDimName( xDim, uno::UNO_QUERY );
1584 346 : if ( xDimProp.is() && xDimName.is() )
1585 : {
1586 : // Asterisks are added in ScDPSaveData::WriteToSource to create unique names.
1587 : //TODO: preserve original name there?
1588 346 : rSourceName = ScDPUtil::getSourceDimensionName(xDimName->getName());
1589 :
1590 : // Generate "given name" the same way as in dptabres.
1591 : //TODO: Should use a stored name when available
1592 :
1593 : sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
1594 : xDimProp, OUString(SC_UNO_DP_FUNCTION),
1595 346 : sheet::GeneralFunction_NONE );
1596 346 : rGivenName = lcl_GetDataFieldName( rSourceName, eFunc );
1597 346 : }
1598 346 : }
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 1 : long ScDPOutput::GetHeaderDim( const ScAddress& rPos, sal_uInt16& rOrient )
1613 : {
1614 1 : SCCOL nCol = rPos.Col();
1615 1 : SCROW nRow = rPos.Row();
1616 1 : SCTAB nTab = rPos.Tab();
1617 1 : if ( nTab != aStartPos.Tab() )
1618 0 : return -1; // wrong sheet
1619 :
1620 : // calculate output positions and sizes
1621 :
1622 1 : CalcSizes();
1623 :
1624 : // test for column header
1625 :
1626 1 : 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 1 : 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 1 : SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 );
1645 1 : if ( nCol == aStartPos.Col() && nRow >= nPageStartRow && nRow < nPageStartRow + nPageFieldCount )
1646 : {
1647 1 : rOrient = sheet::DataPilotFieldOrientation_PAGE;
1648 1 : long nField = nRow - nPageStartRow;
1649 1 : return pPageFields[nField].nDim;
1650 : }
1651 :
1652 : //TODO: 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 : //TODO: 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 : //TODO: 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 : //TODO: 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 156 : }
1841 :
1842 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|