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