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