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