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