Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright IBM Corporation 2009.
7 : : * Copyright 2009 by Sun Microsystems, Inc.
8 : : *
9 : : * OpenOffice.org - a multi-platform office productivity suite
10 : : *
11 : : * This file is part of OpenOffice.org.
12 : : *
13 : : * OpenOffice.org is free software: you can redistribute it and/or modify
14 : : * it under the terms of the GNU Lesser General Public License version 3
15 : : * only, as published by the Free Software Foundation.
16 : : *
17 : : * OpenOffice.org is distributed in the hope that it will be useful,
18 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : : * GNU Lesser General Public License version 3 for more details
21 : : * (a copy is included in the LICENSE file that accompanied this code).
22 : : *
23 : : * You should have received a copy of the GNU Lesser General Public License
24 : : * version 3 along with OpenOffice.org. If not, see
25 : : * <http://www.openoffice.org/license.html>
26 : : * for a copy of the LGPLv3 License.
27 : : *
28 : : ************************************************************************/
29 : :
30 : : #include "dpcache.hxx"
31 : :
32 : : #include "document.hxx"
33 : : #include "queryentry.hxx"
34 : : #include "queryparam.hxx"
35 : : #include "dpglobal.hxx"
36 : : #include "dpobject.hxx"
37 : : #include "globstr.hrc"
38 : : #include "docoptio.hxx"
39 : : #include "dpitemdata.hxx"
40 : : #include "dputil.hxx"
41 : : #include "dpnumgroupinfo.hxx"
42 : :
43 : : #include <rtl/math.hxx>
44 : : #include <unotools/textsearch.hxx>
45 : : #include <unotools/localedatawrapper.hxx>
46 : : #include <svl/zforlist.hxx>
47 : :
48 : : #include <memory>
49 : :
50 : : using namespace ::com::sun::star;
51 : :
52 : : using ::com::sun::star::uno::Exception;
53 : : using ::com::sun::star::uno::Reference;
54 : : using ::com::sun::star::uno::UNO_QUERY;
55 : : using ::com::sun::star::uno::UNO_QUERY_THROW;
56 : :
57 [ + - ][ + - ]: 17 : ScDPCache::GroupItems::GroupItems() : mnGroupType(0) {}
58 : :
59 : 6 : ScDPCache::GroupItems::GroupItems(const ScDPNumGroupInfo& rInfo, sal_Int32 nGroupType) :
60 [ + - ][ + - ]: 6 : maInfo(rInfo), mnGroupType(nGroupType) {}
61 : :
62 [ + - ][ + - ]: 309 : ScDPCache::Field::Field() : mnNumFormat(0) {}
63 : :
64 : 95 : ScDPCache::ScDPCache(ScDocument* pDoc) :
65 : : mpDoc( pDoc ),
66 : : mnColumnCount ( 0 ),
67 : : maEmptyRows(0, MAXROW, true),
68 [ + - ][ + - ]: 95 : mbDisposing(false)
[ + - ][ + - ]
[ + - ][ + - ]
69 : : {
70 : 95 : }
71 : :
72 : : namespace {
73 : :
74 : : struct ClearObjectSource : std::unary_function<ScDPObject*, void>
75 : : {
76 : 17 : void operator() (ScDPObject* p) const
77 : : {
78 : 17 : p->ClearTableData();
79 : 17 : }
80 : : };
81 : :
82 : : }
83 : :
84 [ + - ][ + - ]: 95 : ScDPCache::~ScDPCache()
[ + - ][ + - ]
85 : : {
86 : : // Make sure no live ScDPObject instances hold reference to this cache any
87 : : // more.
88 : 95 : mbDisposing = true;
89 [ + - ]: 95 : std::for_each(maRefObjects.begin(), maRefObjects.end(), ClearObjectSource());
90 : 95 : }
91 : :
92 : : namespace {
93 : :
94 : : /**
95 : : * While the macro interpret level is incremented, the formula cells are
96 : : * (semi-)guaranteed to be interpreted.
97 : : */
98 : : class MacroInterpretIncrementer
99 : : {
100 : : public:
101 : 103 : MacroInterpretIncrementer(ScDocument* pDoc) :
102 : 103 : mpDoc(pDoc)
103 : : {
104 : 103 : mpDoc->IncMacroInterpretLevel();
105 : 103 : }
106 : 103 : ~MacroInterpretIncrementer()
107 : : {
108 : 103 : mpDoc->DecMacroInterpretLevel();
109 : 103 : }
110 : : private:
111 : : ScDocument* mpDoc;
112 : : };
113 : :
114 : 309 : rtl::OUString createLabelString(ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab)
115 : : {
116 : 309 : rtl::OUString aDocStr = pDoc->GetString(nCol, nRow, nTab);
117 [ + + ]: 309 : if (aDocStr.isEmpty())
118 : : {
119 : : // Replace an empty label string with column name.
120 : 39 : rtl::OUStringBuffer aBuf;
121 [ + - ][ + - ]: 39 : aBuf.append(ScGlobal::GetRscString(STR_COLUMN));
[ + - ]
122 [ + - ]: 39 : aBuf.append(sal_Unicode(' '));
123 : :
124 : 39 : ScAddress aColAddr(nCol, 0, 0);
125 : 39 : rtl::OUString aColStr;
126 [ + - ]: 39 : aColAddr.Format(aColStr, SCA_VALID_COL, NULL);
127 [ + - ]: 39 : aBuf.append(aColStr);
128 [ + - ]: 39 : aDocStr = aBuf.makeStringAndClear();
129 : : }
130 : 309 : return aDocStr;
131 : : }
132 : :
133 : 1657 : void initFromCell(
134 : : ScDPCache& rCache, ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab,
135 : : ScDPItemData& rData, sal_uLong& rNumFormat)
136 : : {
137 [ + - ]: 1657 : rtl::OUString aDocStr = pDoc->GetString(nCol, nRow, nTab);
138 : 1657 : rNumFormat = 0;
139 : :
140 : 1657 : ScAddress aPos(nCol, nRow, nTab);
141 : :
142 [ - + ][ + - ]: 1657 : if (pDoc->GetErrCode(aPos))
143 : : {
144 [ # # ][ # # ]: 0 : rData.SetErrorString(rCache.InternString(aDocStr));
145 : : }
146 [ + - ][ + + ]: 1657 : else if (pDoc->HasValueData(nCol, nRow, nTab))
147 : : {
148 [ + - ]: 1083 : double fVal = pDoc->GetValue(aPos);
149 [ + - ]: 1083 : rNumFormat = pDoc->GetNumberFormat(aPos);
150 [ + - ]: 1083 : rData.SetValue(fVal);
151 : : }
152 [ + - ][ + + ]: 574 : else if (pDoc->HasData(nCol, nRow, nTab))
153 : : {
154 [ + - ][ + - ]: 454 : rData.SetString(rCache.InternString(aDocStr));
155 : : }
156 : : else
157 [ + - ]: 1657 : rData.SetEmpty();
158 : 1657 : }
159 : :
160 : 19149 : struct Bucket
161 : : {
162 : : ScDPItemData maValue;
163 : : SCROW mnOrderIndex;
164 : : SCROW mnDataIndex;
165 : : SCROW mnValueSortIndex;
166 : 1657 : Bucket(const ScDPItemData& rValue, SCROW nOrder, SCROW nData) :
167 : 1657 : maValue(rValue), mnOrderIndex(nOrder), mnDataIndex(nData), mnValueSortIndex(0) {}
168 : : };
169 : :
170 : : struct LessByValue : std::binary_function<Bucket, Bucket, bool>
171 : : {
172 : 3100 : bool operator() (const Bucket& left, const Bucket& right) const
173 : : {
174 : 3100 : return left.maValue < right.maValue;
175 : : }
176 : : };
177 : :
178 : : struct LessByValueSortIndex : std::binary_function<Bucket, Bucket, bool>
179 : : {
180 : 3100 : bool operator() (const Bucket& left, const Bucket& right) const
181 : : {
182 : 3100 : return left.mnValueSortIndex < right.mnValueSortIndex;
183 : : }
184 : : };
185 : :
186 : : struct LessByDataIndex : std::binary_function<Bucket, Bucket, bool>
187 : : {
188 : 3121 : bool operator() (const Bucket& left, const Bucket& right) const
189 : : {
190 : 3121 : return left.mnDataIndex < right.mnDataIndex;
191 : : }
192 : : };
193 : :
194 : : struct EqualByValue : std::binary_function<Bucket, Bucket, bool>
195 : : {
196 : 1367 : bool operator() (const Bucket& left, const Bucket& right) const
197 : : {
198 : 1367 : return left.maValue.IsCaseInsEqual(right.maValue);
199 : : }
200 : : };
201 : :
202 : : class PushBackValue : std::unary_function<Bucket, void>
203 : : {
204 : : ScDPCache::ItemsType& mrItems;
205 : : public:
206 : 290 : PushBackValue(ScDPCache::ItemsType& _items) : mrItems(_items) {}
207 : 1342 : void operator() (const Bucket& v)
208 : : {
209 : 1342 : mrItems.push_back(v.maValue);
210 : 1342 : }
211 : : };
212 : :
213 : : class PushBackOrderIndex : std::unary_function<Bucket, void>
214 : : {
215 : : ScDPCache::IndexArrayType& mrData;
216 : : public:
217 : 290 : PushBackOrderIndex(ScDPCache::IndexArrayType& _items) : mrData(_items) {}
218 : 1657 : void operator() (const Bucket& v)
219 : : {
220 : 1657 : mrData.push_back(v.mnOrderIndex);
221 : 1657 : }
222 : : };
223 : :
224 : : class TagValueSortOrder : std::unary_function<Bucket, void>
225 : : {
226 : : SCROW mnCurIndex;
227 : : public:
228 : 290 : TagValueSortOrder() : mnCurIndex(0) {}
229 : 1657 : void operator() (Bucket& v)
230 : : {
231 : 1657 : v.mnValueSortIndex = mnCurIndex++;
232 : 1657 : }
233 : : };
234 : :
235 : 309 : void processBuckets(std::vector<Bucket>& aBuckets, ScDPCache::Field& rField)
236 : : {
237 [ + + ]: 309 : if (aBuckets.empty())
238 : 309 : return;
239 : :
240 : : // Sort by the value.
241 [ + - ]: 290 : std::sort(aBuckets.begin(), aBuckets.end(), LessByValue());
242 : :
243 : : // Remember this sort order.
244 [ + - ]: 290 : std::for_each(aBuckets.begin(), aBuckets.end(), TagValueSortOrder());
245 : :
246 : : {
247 : : // Set order index such that unique values have identical index value.
248 : 290 : SCROW nCurIndex = 0;
249 : 290 : std::vector<Bucket>::iterator it = aBuckets.begin(), itEnd = aBuckets.end();
250 [ + - ]: 290 : ScDPItemData aPrev = it->maValue;
251 : 290 : it->mnOrderIndex = nCurIndex;
252 [ + - ][ + + ]: 1657 : for (++it; it != itEnd; ++it)
253 : : {
254 [ + - ][ + + ]: 1367 : if (!aPrev.IsCaseInsEqual(it->maValue))
255 : 1052 : ++nCurIndex;
256 : :
257 : 1367 : it->mnOrderIndex = nCurIndex;
258 [ + - ]: 1367 : aPrev = it->maValue;
259 [ + - ]: 290 : }
260 : : }
261 : :
262 : : // Re-sort the bucket this time by the data index.
263 [ + - ]: 290 : std::sort(aBuckets.begin(), aBuckets.end(), LessByDataIndex());
264 : :
265 : : // Copy the order index series into the field object.
266 [ + - ]: 290 : rField.maData.reserve(aBuckets.size());
267 [ + - ]: 290 : std::for_each(aBuckets.begin(), aBuckets.end(), PushBackOrderIndex(rField.maData));
268 : :
269 : : // Sort by the value again.
270 [ + - ]: 290 : std::sort(aBuckets.begin(), aBuckets.end(), LessByValueSortIndex());
271 : :
272 : : // Unique by value.
273 : : std::vector<Bucket>::iterator itUniqueEnd =
274 [ + - ]: 290 : std::unique(aBuckets.begin(), aBuckets.end(), EqualByValue());
275 : :
276 : : // Copy the unique values into items.
277 : 290 : std::vector<Bucket>::iterator itBeg = aBuckets.begin();
278 [ + - ]: 290 : size_t nLen = distance(itBeg, itUniqueEnd);
279 [ + - ]: 290 : rField.maItems.reserve(nLen);
280 [ + - ]: 309 : std::for_each(itBeg, itUniqueEnd, PushBackValue(rField.maItems));
281 : : }
282 : :
283 : : }
284 : :
285 : 103 : bool ScDPCache::InitFromDoc(ScDocument* pDoc, const ScRange& rRange)
286 : : {
287 [ + - ]: 103 : Clear();
288 : :
289 : : // Make sure the formula cells within the data range are interpreted
290 : : // during this call, for this method may be called from the interpretation
291 : : // of GETPIVOTDATA, which disables nested formula interpretation without
292 : : // increasing the macro level.
293 : 103 : MacroInterpretIncrementer aMacroInc(pDoc);
294 : :
295 : 103 : SCROW nStartRow = rRange.aStart.Row(); // start of data
296 : 103 : SCROW nEndRow = rRange.aEnd.Row();
297 : 103 : sal_uInt16 nStartCol = rRange.aStart.Col();
298 : 103 : sal_uInt16 nEndCol = rRange.aEnd.Col();
299 : 103 : sal_uInt16 nDocTab = rRange.aStart.Tab();
300 : :
301 : 103 : mnColumnCount = nEndCol - nStartCol + 1;
302 : :
303 [ + - ]: 103 : maFields.reserve(mnColumnCount);
304 [ + + ]: 412 : for (size_t i = 0; i < static_cast<size_t>(mnColumnCount); ++i)
305 [ + - ][ + - ]: 309 : maFields.push_back(new Field);
[ + - ]
306 : :
307 [ + - ]: 103 : maLabelNames.reserve(mnColumnCount+1);
308 : :
309 [ + - ]: 103 : ScDPItemData aData;
310 [ + + ]: 412 : for (sal_uInt16 nCol = nStartCol; nCol <= nEndCol; ++nCol)
311 : : {
312 [ + - ][ + - ]: 309 : AddLabel(createLabelString(pDoc, nCol, nStartRow, nDocTab));
313 [ + - ]: 309 : Field& rField = maFields[nCol-nStartCol];
314 [ + - ]: 309 : std::vector<Bucket> aBuckets;
315 [ + - ]: 309 : aBuckets.reserve(nEndRow-nStartRow); // skip the topmost label cell.
316 : :
317 : : // Push back all original values.
318 : 309 : SCROW nOffset = nStartRow + 1;
319 [ + + ]: 1966 : for (SCROW i = 0, n = nEndRow-nStartRow; i < n; ++i)
320 : : {
321 : 1657 : SCROW nRow = i + nOffset;
322 : 1657 : sal_uLong nNumFormat = 0;
323 [ + - ]: 1657 : initFromCell(*this, pDoc, nCol, nRow, nDocTab, aData, nNumFormat);
324 [ + - ][ + - ]: 1657 : aBuckets.push_back(Bucket(aData, 0, i));
[ + - ]
325 : :
326 [ + - ][ + + ]: 1657 : if (!aData.IsEmpty())
327 : : {
328 [ + - ]: 1537 : maEmptyRows.insert_back(i, i+1, false);
329 : 1537 : rField.mnNumFormat = nNumFormat;
330 : : }
331 : : }
332 : :
333 [ + - ]: 309 : processBuckets(aBuckets, rField);
334 : 309 : }
335 : :
336 [ + - ]: 103 : PostInit();
337 [ + - ]: 103 : return true;
338 : : }
339 : :
340 : 0 : bool ScDPCache::InitFromDataBase(DBConnector& rDB)
341 : : {
342 : 0 : Clear();
343 : :
344 : : try
345 : : {
346 [ # # ]: 0 : mnColumnCount = rDB.getColumnCount();
347 [ # # ]: 0 : maFields.clear();
348 [ # # ]: 0 : maFields.reserve(mnColumnCount);
349 [ # # ]: 0 : for (size_t i = 0; i < static_cast<size_t>(mnColumnCount); ++i)
350 [ # # ][ # # ]: 0 : maFields.push_back(new Field);
[ # # ]
351 : :
352 : : // Get column titles and types.
353 : 0 : maLabelNames.clear();
354 [ # # ]: 0 : maLabelNames.reserve(mnColumnCount+1);
355 : :
356 [ # # ]: 0 : std::vector<sal_Int32> aColTypes(mnColumnCount);
357 : :
358 [ # # ]: 0 : for (sal_Int32 nCol = 0; nCol < mnColumnCount; ++nCol)
359 : : {
360 [ # # ]: 0 : rtl::OUString aColTitle = rDB.getColumnLabel(nCol);
361 [ # # ]: 0 : AddLabel(aColTitle);
362 : 0 : }
363 : :
364 [ # # ]: 0 : std::vector<Bucket> aBuckets;
365 [ # # ]: 0 : ScDPItemData aData;
366 [ # # ]: 0 : for (sal_Int32 nCol = 0; nCol < mnColumnCount; ++nCol)
367 : : {
368 [ # # ][ # # ]: 0 : if (!rDB.first())
369 : 0 : continue;
370 : :
371 : 0 : aBuckets.clear();
372 [ # # ]: 0 : Field& rField = maFields[nCol];
373 : 0 : SCROW nRow = 0;
374 [ # # ][ # # ]: 0 : do
375 : : {
376 : 0 : short nFormatType = NUMBERFORMAT_UNDEFINED;
377 [ # # ]: 0 : aData.SetEmpty();
378 [ # # ]: 0 : rDB.getValue(nCol, aData, nFormatType);
379 [ # # ][ # # ]: 0 : aBuckets.push_back(Bucket(aData, 0, nRow));
[ # # ]
380 [ # # ][ # # ]: 0 : if (!aData.IsEmpty())
381 : : {
382 [ # # ]: 0 : maEmptyRows.insert_back(nRow, nRow+1, false);
383 [ # # ]: 0 : SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
384 [ # # ][ # # ]: 0 : rField.mnNumFormat = pFormatter ? pFormatter->GetStandardFormat(nFormatType) : 0;
385 : : }
386 : :
387 : 0 : ++nRow;
388 : : }
389 : 0 : while (rDB.next());
390 : :
391 [ # # ]: 0 : processBuckets(aBuckets, rField);
392 : : }
393 : :
394 [ # # ]: 0 : rDB.finish();
395 : :
396 [ # # ]: 0 : PostInit();
397 [ # # ][ # # ]: 0 : return true;
398 : : }
399 : 0 : catch (const Exception&)
400 : : {
401 : 0 : return false;
402 : : }
403 : : }
404 : :
405 : 3825 : bool ScDPCache::ValidQuery( SCROW nRow, const ScQueryParam &rParam) const
406 : : {
407 [ + - ][ - + ]: 3825 : if (!rParam.GetEntryCount())
408 : 0 : return true;
409 : :
410 [ + - ][ + + ]: 3825 : if (!rParam.GetEntry(0).bDoQuery)
411 : 3115 : return true;
412 : :
413 [ + - ]: 710 : bool bMatchWholeCell = mpDoc->GetDocOptions().IsMatchWholeCell();
414 : :
415 [ + - ]: 710 : SCSIZE nEntryCount = rParam.GetEntryCount();
416 [ + - ]: 710 : std::vector<bool> aPassed(nEntryCount, false);
417 : :
418 : 710 : long nPos = -1;
419 : : CollatorWrapper* pCollator = (rParam.bCaseSens ? ScGlobal::GetCaseCollator() :
420 [ # # ][ + - ]: 710 : ScGlobal::GetCollator() );
[ - + ]
421 : : ::utl::TransliterationWrapper* pTransliteration = (rParam.bCaseSens ?
422 [ - + ][ # # ]: 710 : ScGlobal::GetCaseTransliteration() : ScGlobal::GetpTransliteration());
[ + - ]
423 : :
424 [ + - ][ + - ]: 2010 : for (size_t i = 0; i < nEntryCount && rParam.GetEntry(i).bDoQuery; ++i)
[ + + ][ + + ]
425 : : {
426 [ + - ]: 1300 : const ScQueryEntry& rEntry = rParam.GetEntry(i);
427 [ + - ]: 1300 : const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
428 : : // we can only handle one single direct query
429 : : // #i115431# nField in QueryParam is the sheet column, not the field within the source range
430 : 1300 : SCCOL nQueryCol = (SCCOL)rEntry.nField;
431 [ - + ]: 1300 : if ( nQueryCol < rParam.nCol1 )
432 : 0 : nQueryCol = rParam.nCol1;
433 [ - + ]: 1300 : if ( nQueryCol > rParam.nCol2 )
434 : 0 : nQueryCol = rParam.nCol2;
435 : 1300 : SCCOL nSourceField = nQueryCol - rParam.nCol1;
436 [ + - ]: 1300 : SCROW nId = GetItemDataId( nSourceField, nRow, false );
437 [ + - ]: 1300 : const ScDPItemData* pCellData = GetItemDataById( nSourceField, nId );
438 : :
439 : 1300 : bool bOk = false;
440 : :
441 [ + - ][ - + ]: 1300 : if (rEntry.GetQueryItem().meType == ScQueryEntry::ByEmpty)
442 : : {
443 [ # # ][ # # ]: 0 : if (rEntry.IsQueryByEmpty())
444 [ # # ]: 0 : bOk = pCellData->IsEmpty();
445 : : else
446 : : {
447 : : OSL_ASSERT(rEntry.IsQueryByNonEmpty());
448 [ # # ]: 0 : bOk = !pCellData->IsEmpty();
449 : : }
450 : : }
451 [ + - ][ + - ]: 1300 : else if (rEntry.GetQueryItem().meType != ScQueryEntry::ByString && pCellData->IsValue())
[ + - ][ + + ]
[ + + ]
452 : : { // by Value
453 [ + - ]: 1220 : double nCellVal = pCellData->GetValue();
454 : :
455 [ + - + + : 1220 : switch (rEntry.eOp)
- - - ]
456 : : {
457 : : case SC_EQUAL :
458 : 120 : bOk = ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
459 : 120 : break;
460 : : case SC_LESS :
461 [ # # ][ # # ]: 0 : bOk = (nCellVal < rItem.mfVal) && !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
462 : 0 : break;
463 : : case SC_GREATER :
464 [ + + ][ + - ]: 550 : bOk = (nCellVal > rItem.mfVal) && !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
465 : 550 : break;
466 : : case SC_LESS_EQUAL :
467 [ + + ][ - + ]: 550 : bOk = (nCellVal < rItem.mfVal) || ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
468 : 550 : break;
469 : : case SC_GREATER_EQUAL :
470 [ # # ][ # # ]: 0 : bOk = (nCellVal > rItem.mfVal) || ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
471 : 0 : break;
472 : : case SC_NOT_EQUAL :
473 : 0 : bOk = !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
474 : 0 : break;
475 : : default:
476 : 0 : bOk= false;
477 : 1220 : break;
478 : : }
479 : : }
480 [ + - ][ + - ]: 160 : else if ((rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
[ - + ][ # # ]
[ - + ]
481 [ + - ]: 80 : || (rEntry.GetQueryItem().meType == ScQueryEntry::ByString
482 [ # # ]: 0 : && pCellData->HasStringData() )
483 : : )
484 : : { // by String
485 [ # # ][ # # ]: 0 : String aCellStr = pCellData->GetString();
486 : :
487 : : bool bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL)
488 [ # # ][ # # ]: 0 : || (rEntry.eOp == SC_NOT_EQUAL)));
[ # # ]
489 : 0 : bool bTestRegExp = false;
490 [ # # ][ # # ]: 0 : if (bRealRegExp || bTestRegExp)
491 : : {
492 : 0 : xub_StrLen nStart = 0;
493 : 0 : xub_StrLen nEnd = aCellStr.Len();
494 : : bool bMatch = (bool) rEntry.GetSearchTextPtr( rParam.bCaseSens )
495 [ # # ][ # # ]: 0 : ->SearchFrwrd( aCellStr, &nStart, &nEnd );
496 : : // from 614 on, nEnd is behind the found text
497 [ # # ][ # # ]: 0 : if (bMatch && bMatchWholeCell
[ # # # # ]
[ # # ]
498 : 0 : && (nStart != 0 || nEnd != aCellStr.Len()))
499 : 0 : bMatch = false; // RegExp must match entire cell string
500 [ # # ]: 0 : if (bRealRegExp)
501 [ # # ]: 0 : bOk = ((rEntry.eOp == SC_NOT_EQUAL) ? !bMatch : bMatch);
502 : : }
503 [ # # ]: 0 : if (!bRealRegExp)
504 : : {
505 [ # # ][ # # ]: 0 : if (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
506 : : {
507 [ # # ]: 0 : if (bMatchWholeCell)
508 : : {
509 [ # # ][ # # ]: 0 : String aStr = rEntry.GetQueryItem().maString;
510 [ # # ]: 0 : bOk = pTransliteration->isEqual(aCellStr, aStr);
511 : 0 : bool bHasStar = false;
512 : : xub_StrLen nIndex;
513 [ # # ][ # # ]: 0 : if (( nIndex = aStr.Search('*') ) != STRING_NOTFOUND)
514 : 0 : bHasStar = sal_True;
515 [ # # ][ # # ]: 0 : if (bHasStar && (nIndex>0))
516 : : {
517 [ # # ][ # # ]: 0 : for (i=0;(i<nIndex) && (i< aCellStr.Len()) ; i++)
[ # # ]
518 : : {
519 [ # # ]: 0 : if (aCellStr.GetChar( (sal_uInt16)i ) == aStr.GetChar((sal_uInt16) i ))
520 : : {
521 : 0 : bOk=1;
522 : : }
523 : : else
524 : : {
525 : 0 : bOk=0;
526 : 0 : break;
527 : : }
528 : : }
529 [ # # ]: 0 : }
530 : : }
531 : : else
532 : : {
533 [ # # ]: 0 : const rtl::OUString& rQueryStr = rEntry.GetQueryItem().maString;
534 [ # # ]: 0 : ::com::sun::star::uno::Sequence< sal_Int32 > xOff;
535 : : String aCell = pTransliteration->transliterate(
536 [ # # ]: 0 : aCellStr, ScGlobal::eLnge, 0, aCellStr.Len(), &xOff);
537 : : String aQuer = pTransliteration->transliterate(
538 [ # # ][ # # ]: 0 : rQueryStr, ScGlobal::eLnge, 0, rQueryStr.getLength(), &xOff);
[ # # ]
539 [ # # ][ # # ]: 0 : bOk = (aCell.Search( aQuer ) != STRING_NOTFOUND);
[ # # ][ # # ]
540 : : }
541 [ # # ]: 0 : if (rEntry.eOp == SC_NOT_EQUAL)
542 : 0 : bOk = !bOk;
543 : : }
544 : : else
545 : : { // use collator here because data was probably sorted
546 : : sal_Int32 nCompare = pCollator->compareString(
547 [ # # ][ # # ]: 0 : aCellStr, rEntry.GetQueryItem().maString);
[ # # ]
548 [ # # # # : 0 : switch (rEntry.eOp)
# # ]
549 : : {
550 : : case SC_LESS :
551 : 0 : bOk = (nCompare < 0);
552 : 0 : break;
553 : : case SC_GREATER :
554 : 0 : bOk = (nCompare > 0);
555 : 0 : break;
556 : : case SC_LESS_EQUAL :
557 : 0 : bOk = (nCompare <= 0);
558 : 0 : break;
559 : : case SC_GREATER_EQUAL :
560 : 0 : bOk = (nCompare >= 0);
561 : 0 : break;
562 : : case SC_NOT_EQUAL:
563 : : OSL_FAIL("SC_NOT_EQUAL");
564 : 0 : break;
565 : : case SC_TOPVAL:
566 : : case SC_BOTVAL:
567 : : case SC_TOPPERC:
568 : : case SC_BOTPERC:
569 : : default:
570 : 0 : break;
571 : : }
572 : : }
573 [ # # ]: 0 : }
574 : : }
575 : :
576 [ + + ]: 1300 : if (nPos == -1)
577 : : {
578 : 710 : nPos++;
579 [ + - ]: 710 : aPassed[nPos] = bOk;
580 : : }
581 : : else
582 : : {
583 [ + - ]: 590 : if (rEntry.eConnect == SC_AND)
584 : : {
585 [ + - ][ + + ]: 590 : aPassed[nPos] = aPassed[nPos] && bOk;
[ + + ][ + - ]
[ + - ][ # # ]
586 : : }
587 : : else
588 : : {
589 : 0 : nPos++;
590 [ # # ]: 0 : aPassed[nPos] = bOk;
591 : : }
592 : : }
593 : : }
594 : :
595 [ - + ]: 710 : for (long j=1; j <= nPos; j++)
596 [ # # ][ # # ]: 0 : aPassed[0] = aPassed[0] || aPassed[j];
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
[ # # # # ]
597 : :
598 [ + - ]: 710 : bool bRet = aPassed[0];
599 : 3825 : return bRet;
600 : : }
601 : :
602 : 72 : bool ScDPCache::IsRowEmpty(SCROW nRow) const
603 : : {
604 : 72 : bool bEmpty = true;
605 [ + - ]: 72 : maEmptyRows.search_tree(nRow, bEmpty);
606 : 72 : return bEmpty;
607 : : }
608 : :
609 : 84 : const ScDPCache::GroupItems* ScDPCache::GetGroupItems(long nDim) const
610 : : {
611 [ - + ]: 84 : if (nDim < 0)
612 : 0 : return NULL;
613 : :
614 : 84 : long nSourceCount = static_cast<long>(maFields.size());
615 [ + + ]: 84 : if (nDim < nSourceCount)
616 : 45 : return maFields[nDim].mpGroup.get();
617 : :
618 : 39 : nDim -= nSourceCount;
619 [ + - ]: 39 : if (nDim < static_cast<long>(maGroupFields.size()))
620 : 39 : return &maGroupFields[nDim];
621 : :
622 : 84 : return NULL;
623 : : }
624 : :
625 : 36838 : rtl::OUString ScDPCache::GetDimensionName(LabelsType::size_type nDim) const
626 : : {
627 : : OSL_ENSURE(nDim < maLabelNames.size()-1 , "ScDPTableDataCache::GetDimensionName");
628 : : OSL_ENSURE(maLabelNames.size() == static_cast <sal_uInt16> (mnColumnCount+1), "ScDPTableDataCache::GetDimensionName");
629 : :
630 [ + - ]: 36838 : if ( nDim+1 < maLabelNames.size() )
631 : : {
632 : 36838 : return maLabelNames[nDim+1];
633 : : }
634 : : else
635 : 36838 : return rtl::OUString();
636 : : }
637 : :
638 : : namespace {
639 : :
640 : : typedef boost::unordered_set<rtl::OUString, rtl::OUStringHash> LabelSet;
641 : :
642 : : class InsertLabel : public std::unary_function<rtl::OUString, void>
643 : : {
644 : : LabelSet& mrNames;
645 : : public:
646 : 309 : InsertLabel(LabelSet& rNames) : mrNames(rNames) {}
647 : 742 : void operator() (const rtl::OUString& r)
648 : : {
649 : 742 : mrNames.insert(r);
650 : 742 : }
651 : : };
652 : :
653 : : }
654 : :
655 : 103 : void ScDPCache::PostInit()
656 : : {
657 : 103 : maEmptyRows.build_tree();
658 : 103 : }
659 : :
660 : 103 : void ScDPCache::Clear()
661 : : {
662 : 103 : maFields.clear();
663 : 103 : maLabelNames.clear();
664 : 103 : maGroupFields.clear();
665 : 103 : maEmptyRows.clear();
666 : 103 : maStringPool.clear();
667 : 103 : }
668 : :
669 : 309 : void ScDPCache::AddLabel(const rtl::OUString& rLabel)
670 : : {
671 : :
672 [ + + ]: 309 : if ( maLabelNames.empty() )
673 [ + - ][ + - ]: 103 : maLabelNames.push_back(ScGlobal::GetRscString(STR_PIVOT_DATA));
[ + - ]
674 : :
675 : : //reset name if needed
676 [ + - ]: 309 : LabelSet aExistingNames;
677 [ + - ]: 309 : std::for_each(maLabelNames.begin(), maLabelNames.end(), InsertLabel(aExistingNames));
678 : 309 : sal_Int32 nSuffix = 1;
679 : 309 : rtl::OUString aNewName = rLabel;
680 : 0 : while (true)
681 : : {
682 [ + - ][ + - ]: 309 : if (!aExistingNames.count(aNewName))
683 : : {
684 : : // unique name found!
685 [ + - ]: 309 : maLabelNames.push_back(aNewName);
686 : 309 : return;
687 : : }
688 : :
689 : : // Name already exists.
690 [ # # ]: 0 : rtl::OUStringBuffer aBuf(rLabel);
691 [ # # ]: 0 : aBuf.append(++nSuffix);
692 [ # # ]: 0 : aNewName = aBuf.makeStringAndClear();
693 [ + - ]: 309 : }
694 : : }
695 : :
696 : 8882 : SCROW ScDPCache::GetItemDataId(sal_uInt16 nDim, SCROW nRow, bool bRepeatIfEmpty) const
697 : : {
698 : : OSL_ENSURE(nDim < mnColumnCount, "ScDPTableDataCache::GetItemDataId ");
699 : :
700 : 8882 : const Field& rField = maFields[nDim];
701 [ - + ]: 8882 : if (bRepeatIfEmpty)
702 : : {
703 [ # # ][ # # ]: 0 : while (nRow > 0 && rField.maItems[rField.maData[nRow]].IsEmpty())
[ # # ]
704 : 0 : --nRow;
705 : : }
706 : :
707 : 8882 : return rField.maData[nRow];
708 : : }
709 : :
710 : 14284 : const ScDPItemData* ScDPCache::GetItemDataById(long nDim, SCROW nId) const
711 : : {
712 [ + - ][ - + ]: 14284 : if (nDim < 0 || nId < 0)
713 : 0 : return NULL;
714 : :
715 : 14284 : size_t nSourceCount = maFields.size();
716 : 14284 : size_t nDimPos = static_cast<size_t>(nDim);
717 : 14284 : size_t nItemId = static_cast<size_t>(nId);
718 [ + + ]: 14284 : if (nDimPos < nSourceCount)
719 : : {
720 : : // source field.
721 : 13703 : const Field& rField = maFields[nDimPos];
722 [ + + ]: 13703 : if (nItemId < rField.maItems.size())
723 : 13265 : return &rField.maItems[nItemId];
724 : :
725 [ + + ]: 438 : if (!rField.mpGroup)
726 : 9 : return NULL;
727 : :
728 : 429 : nItemId -= rField.maItems.size();
729 : 429 : const ItemsType& rGI = rField.mpGroup->maItems;
730 [ - + ]: 429 : if (nItemId >= rGI.size())
731 : 0 : return NULL;
732 : :
733 : 429 : return &rGI[nItemId];
734 : : }
735 : :
736 : : // Try group fields.
737 : 581 : nDimPos -= nSourceCount;
738 [ - + ]: 581 : if (nDimPos >= maGroupFields.size())
739 : 0 : return NULL;
740 : :
741 : 581 : const ItemsType& rGI = maGroupFields[nDimPos].maItems;
742 [ - + ]: 581 : if (nItemId >= rGI.size())
743 : 0 : return NULL;
744 : :
745 : 14284 : return &rGI[nItemId];
746 : : }
747 : :
748 : 976 : SCROW ScDPCache::GetRowCount() const
749 : : {
750 [ + - ][ + + ]: 976 : if (maFields.empty() || maFields[0].maData.empty())
[ + + ]
751 : 342 : return 0;
752 : :
753 : 976 : return maFields[0].maData.size();
754 : : }
755 : :
756 : 23 : const ScDPCache::ItemsType& ScDPCache::GetDimMemberValues(SCCOL nDim) const
757 : : {
758 : : OSL_ENSURE( nDim>=0 && nDim < mnColumnCount ," nDim < mnColumnCount ");
759 : 23 : return maFields.at(nDim).maItems;
760 : : }
761 : :
762 : 1841 : sal_uLong ScDPCache::GetNumberFormat( long nDim ) const
763 : : {
764 [ - + ]: 1841 : if ( nDim >= mnColumnCount )
765 : 0 : return 0;
766 : :
767 : : // TODO: Find a way to determine the dominant number format in presence of
768 : : // multiple number formats in the same field.
769 : 1841 : return maFields[nDim].mnNumFormat;
770 : : }
771 : :
772 : 2653 : bool ScDPCache::IsDateDimension( long nDim ) const
773 : : {
774 [ - + ]: 2653 : if (nDim >= mnColumnCount)
775 : 0 : return false;
776 : :
777 : 2653 : SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
778 [ - + ]: 2653 : if (!pFormatter)
779 : 0 : return false;
780 : :
781 : 2653 : short eType = pFormatter->GetType(maFields[nDim].mnNumFormat);
782 [ - + ][ + + ]: 2653 : return (eType == NUMBERFORMAT_DATE) || (eType == NUMBERFORMAT_DATETIME);
783 : : }
784 : :
785 : 695 : long ScDPCache::GetDimMemberCount(long nDim) const
786 : : {
787 : : OSL_ENSURE( nDim>=0 && nDim < mnColumnCount ," ScDPTableDataCache::GetDimMemberCount : out of bound ");
788 : 695 : return maFields[nDim].maItems.size();
789 : : }
790 : :
791 : 23 : SCCOL ScDPCache::GetDimensionIndex(const rtl::OUString& sName) const
792 : : {
793 [ + - ]: 23 : for (size_t i = 1; i < maLabelNames.size(); ++i)
794 : : {
795 [ + - ]: 23 : if (maLabelNames[i].equals(sName))
796 : 23 : return static_cast<SCCOL>(i-1);
797 : : }
798 : 23 : return -1;
799 : : }
800 : :
801 : 454 : const rtl::OUString* ScDPCache::InternString(const rtl::OUString& rStr) const
802 : : {
803 [ + - ]: 454 : StringSetType::iterator it = maStringPool.find(rStr);
804 [ + - ][ + + ]: 454 : if (it != maStringPool.end())
805 : : // In the pool.
806 [ + - ]: 135 : return &(*it);
807 : :
808 [ + - ]: 319 : std::pair<StringSetType::iterator, bool> r = maStringPool.insert(rStr);
809 [ + - ][ + - ]: 454 : return r.second ? &(*r.first) : NULL;
810 : : }
811 : :
812 : 117 : void ScDPCache::AddReference(ScDPObject* pObj) const
813 : : {
814 : 117 : maRefObjects.insert(pObj);
815 : 117 : }
816 : :
817 : 117 : void ScDPCache::RemoveReference(ScDPObject* pObj) const
818 : : {
819 [ + + ]: 117 : if (mbDisposing)
820 : : // Object being deleted.
821 : 117 : return;
822 : :
823 : 100 : maRefObjects.erase(pObj);
824 [ + + ]: 100 : if (maRefObjects.empty())
825 : 76 : mpDoc->GetDPCollection()->RemoveCache(this);
826 : : }
827 : :
828 : 8 : const ScDPCache::ObjectSetType& ScDPCache::GetAllReferences() const
829 : : {
830 : 8 : return maRefObjects;
831 : : }
832 : :
833 : 271 : SCROW ScDPCache::GetIdByItemData(long nDim, const ScDPItemData& rItem) const
834 : : {
835 [ - + ]: 271 : if (nDim < 0)
836 : 0 : return -1;
837 : :
838 [ + + ]: 271 : if (nDim < mnColumnCount)
839 : : {
840 : : // source field.
841 : 108 : const ItemsType& rItems = maFields[nDim].maItems;
842 [ + + ]: 1356 : for (size_t i = 0, n = rItems.size(); i < n; ++i)
843 : : {
844 [ + + ]: 1254 : if (rItems[i] == rItem)
845 : 6 : return i;
846 : : }
847 : :
848 [ - + ]: 102 : if (!maFields[nDim].mpGroup)
849 : 0 : return -1;
850 : :
851 : : // grouped source field.
852 : 102 : const ItemsType& rGI = maFields[nDim].mpGroup->maItems;
853 [ + - ]: 390 : for (size_t i = 0, n = rGI.size(); i < n; ++i)
854 : : {
855 [ + + ]: 390 : if (rGI[i] == rItem)
856 : 102 : return rItems.size() + i;
857 : : }
858 : 0 : return -1;
859 : : }
860 : :
861 : : // group field.
862 : 163 : nDim -= mnColumnCount;
863 [ + - ]: 163 : if (static_cast<size_t>(nDim) < maGroupFields.size())
864 : : {
865 : 163 : const ItemsType& rGI = maGroupFields[nDim].maItems;
866 [ + - ]: 277 : for (size_t i = 0, n = rGI.size(); i < n; ++i)
867 : : {
868 [ + + ]: 277 : if (rGI[i] == rItem)
869 : 163 : return i;
870 : : }
871 : : }
872 : :
873 : 271 : return -1;
874 : : }
875 : :
876 : 2256 : rtl::OUString ScDPCache::GetFormattedString(long nDim, const ScDPItemData& rItem) const
877 : : {
878 [ + + ]: 2256 : if (nDim < 0)
879 : 195 : return rItem.GetString();
880 : :
881 : 2061 : ScDPItemData::Type eType = rItem.GetType();
882 [ + + ]: 2061 : if (eType == ScDPItemData::Value)
883 : : {
884 : : // Format value using the stored number format.
885 : 1627 : sal_uLong nNumFormat = GetNumberFormat(nDim);
886 : 1627 : SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
887 [ + - ]: 1627 : if (pFormatter)
888 : : {
889 : 1627 : Color* pColor = NULL;
890 [ + - ]: 1627 : String aStr;
891 [ + - ][ + - ]: 1627 : pFormatter->GetOutputString(rItem.GetValue(), nNumFormat, aStr, &pColor);
892 [ + - ][ + - ]: 1627 : return aStr;
893 : : }
894 : : }
895 : :
896 [ + + ]: 434 : if (eType == ScDPItemData::GroupValue)
897 : : {
898 [ + - ]: 69 : ScDPItemData::GroupValueAttr aAttr = rItem.GetGroupValue();
899 : 69 : double fStart = 0.0, fEnd = 0.0;
900 [ + - ]: 69 : const GroupItems* p = GetGroupItems(nDim);
901 [ + - ]: 69 : if (p)
902 : : {
903 : 69 : fStart = p->maInfo.mfStart;
904 : 69 : fEnd = p->maInfo.mfEnd;
905 : : }
906 : : return ScDPUtil::getDateGroupName(
907 [ + - ][ + - ]: 69 : aAttr.mnGroupType, aAttr.mnValue, mpDoc->GetFormatTable(), fStart, fEnd);
908 : : }
909 : :
910 [ + + ]: 365 : if (eType == ScDPItemData::RangeStart)
911 : : {
912 : 15 : double fVal = rItem.GetValue();
913 : 15 : const GroupItems* p = GetGroupItems(nDim);
914 [ - + ]: 15 : if (!p)
915 : 0 : return rItem.GetString();
916 : :
917 : 15 : sal_Unicode cDecSep = ScGlobal::pLocaleData->getNumDecimalSep()[0];
918 : 15 : return ScDPUtil::getNumGroupName(fVal, p->maInfo, cDecSep, mpDoc->GetFormatTable());
919 : : }
920 : :
921 : 2256 : return rItem.GetString();
922 : : }
923 : :
924 : 17 : long ScDPCache::AppendGroupField()
925 : : {
926 [ + - ]: 17 : maGroupFields.push_back(new GroupItems);
927 : 17 : return static_cast<long>(maFields.size() + maGroupFields.size() - 1);
928 : : }
929 : :
930 : 23 : void ScDPCache::ResetGroupItems(long nDim, const ScDPNumGroupInfo& rNumInfo, sal_Int32 nGroupType)
931 : : {
932 [ - + ]: 23 : if (nDim < 0)
933 : 0 : return;
934 : :
935 : 23 : long nSourceCount = static_cast<long>(maFields.size());
936 [ + + ]: 23 : if (nDim < nSourceCount)
937 : : {
938 [ + - ]: 6 : maFields.at(nDim).mpGroup.reset(new GroupItems(rNumInfo, nGroupType));
939 : 6 : return;
940 : : }
941 : :
942 : 17 : nDim -= nSourceCount;
943 [ + - ]: 17 : if (nDim < static_cast<long>(maGroupFields.size()))
944 : : {
945 : 17 : GroupItems& rGI = maGroupFields[nDim];
946 : 17 : rGI.maItems.clear();
947 : 17 : rGI.maInfo = rNumInfo;
948 : 23 : rGI.mnGroupType = nGroupType;
949 : : }
950 : : }
951 : :
952 : 122 : SCROW ScDPCache::SetGroupItem(long nDim, const ScDPItemData& rData)
953 : : {
954 [ - + ]: 122 : if (nDim < 0)
955 : 0 : return -1;
956 : :
957 : 122 : long nSourceCount = static_cast<long>(maFields.size());
958 [ + + ]: 122 : if (nDim < nSourceCount)
959 : : {
960 : 57 : GroupItems& rGI = *maFields.at(nDim).mpGroup;
961 : 57 : rGI.maItems.push_back(rData);
962 : 57 : SCROW nId = maFields[nDim].maItems.size() + rGI.maItems.size() - 1;
963 : 57 : return nId;
964 : : }
965 : :
966 : 65 : nDim -= nSourceCount;
967 [ + - ]: 65 : if (nDim < static_cast<long>(maGroupFields.size()))
968 : : {
969 : 65 : ItemsType& rItems = maGroupFields.at(nDim).maItems;
970 : 65 : rItems.push_back(rData);
971 : 65 : return rItems.size()-1;
972 : : }
973 : :
974 : 122 : return -1;
975 : : }
976 : :
977 : 32 : void ScDPCache::GetGroupDimMemberIds(long nDim, std::vector<SCROW>& rIds) const
978 : : {
979 [ - + ]: 32 : if (nDim < 0)
980 : 0 : return;
981 : :
982 : 32 : long nSourceCount = static_cast<long>(maFields.size());
983 [ + + ]: 32 : if (nDim < nSourceCount)
984 : : {
985 [ - + ]: 9 : if (!maFields.at(nDim).mpGroup)
986 : 0 : return;
987 : :
988 : 9 : size_t nOffset = maFields[nDim].maItems.size();
989 : 9 : const ItemsType& rGI = maFields[nDim].mpGroup->maItems;
990 [ + + ]: 108 : for (size_t i = 0, n = rGI.size(); i < n; ++i)
991 [ + - ]: 99 : rIds.push_back(static_cast<SCROW>(i + nOffset));
992 : :
993 : 9 : return;
994 : : }
995 : :
996 : 23 : nDim -= nSourceCount;
997 [ + - ]: 23 : if (nDim < static_cast<long>(maGroupFields.size()))
998 : : {
999 : 23 : const ItemsType& rGI = maGroupFields.at(nDim).maItems;
1000 [ + + ]: 127 : for (size_t i = 0, n = rGI.size(); i < n; ++i)
1001 [ + - ]: 95 : rIds.push_back(static_cast<SCROW>(i));
1002 : : }
1003 : : }
1004 : :
1005 : : namespace {
1006 : :
1007 : : struct ClearGroupItems : std::unary_function<ScDPCache::Field, void>
1008 : : {
1009 : 49 : void operator() (ScDPCache::Field& r) const
1010 : : {
1011 : 49 : r.mpGroup.reset();
1012 : 49 : }
1013 : : };
1014 : :
1015 : : }
1016 : :
1017 : 17 : void ScDPCache::ClearGroupFields()
1018 : : {
1019 : 17 : maGroupFields.clear();
1020 [ + - ][ + - ]: 17 : std::for_each(maFields.begin(), maFields.end(), ClearGroupItems());
[ + - ]
1021 : 17 : }
1022 : :
1023 : 367 : const ScDPNumGroupInfo* ScDPCache::GetNumGroupInfo(long nDim) const
1024 : : {
1025 [ - + ]: 367 : if (nDim < 0)
1026 : 0 : return NULL;
1027 : :
1028 : 367 : long nSourceCount = static_cast<long>(maFields.size());
1029 [ + + ]: 367 : if (nDim < nSourceCount)
1030 : : {
1031 [ + + ]: 204 : if (!maFields.at(nDim).mpGroup)
1032 : 102 : return NULL;
1033 : :
1034 : 102 : return &maFields[nDim].mpGroup->maInfo;
1035 : : }
1036 : :
1037 : 163 : nDim -= nSourceCount;
1038 [ + - ]: 163 : if (nDim < static_cast<long>(maGroupFields.size()))
1039 : 163 : return &maGroupFields.at(nDim).maInfo;
1040 : :
1041 : 367 : return NULL;
1042 : : }
1043 : :
1044 : 144 : sal_Int32 ScDPCache::GetGroupType(long nDim) const
1045 : : {
1046 [ - + ]: 144 : if (nDim < 0)
1047 : 0 : return 0;
1048 : :
1049 : 144 : long nSourceCount = static_cast<long>(maFields.size());
1050 [ + + ]: 144 : if (nDim < nSourceCount)
1051 : : {
1052 [ - + ]: 48 : if (!maFields.at(nDim).mpGroup)
1053 : 0 : return 0;
1054 : :
1055 : 48 : return maFields[nDim].mpGroup->mnGroupType;
1056 : : }
1057 : :
1058 : 96 : nDim -= nSourceCount;
1059 [ + - ]: 96 : if (nDim < static_cast<long>(maGroupFields.size()))
1060 : 96 : return maGroupFields.at(nDim).mnGroupType;
1061 : :
1062 : 144 : return 0;
1063 : : }
1064 : :
1065 : 6953 : SCROW ScDPCache::GetOrder(long /*nDim*/, SCROW nIndex) const
1066 : : {
1067 : 6953 : return nIndex;
1068 : : }
1069 : :
1070 : 20 : ScDocument* ScDPCache::GetDoc() const
1071 : : {
1072 : 20 : return mpDoc;
1073 : : };
1074 : :
1075 : 129566 : long ScDPCache::GetColumnCount() const
1076 : : {
1077 : 129566 : return mnColumnCount;
1078 [ + - ][ + - ]: 153 : }
1079 : :
1080 : : #if DEBUG_PIVOT_TABLE
1081 : :
1082 : : #include <iostream>
1083 : : using std::cout;
1084 : : using std::endl;
1085 : :
1086 : : namespace {
1087 : :
1088 : : std::ostream& operator<< (::std::ostream& os, const rtl::OUString& str)
1089 : : {
1090 : : return os << ::rtl::OUStringToOString(str, RTL_TEXTENCODING_UTF8).getStr();
1091 : : }
1092 : :
1093 : : void dumpItems(const ScDPCache& rCache, long nDim, const ScDPCache::ItemsType& rItems, size_t nOffset)
1094 : : {
1095 : : for (size_t i = 0; i < rItems.size(); ++i)
1096 : : cout << " " << (i+nOffset) << ": " << rCache.GetFormattedString(nDim, rItems[i]) << endl;
1097 : : }
1098 : :
1099 : : }
1100 : :
1101 : : void ScDPCache::Dump() const
1102 : : {
1103 : : cout << "--- pivot cache dump" << endl;
1104 : : {
1105 : : FieldsType::const_iterator it = maFields.begin(), itEnd = maFields.end();
1106 : : for (size_t i = 0; it != itEnd; ++it, ++i)
1107 : : {
1108 : : const Field& fld = *it;
1109 : : cout << "* source dimension: " << GetDimensionName(i) << " (ID = " << i << ")" << endl;
1110 : : cout << " item count: " << fld.maItems.size() << endl;
1111 : : dumpItems(*this, i, fld.maItems, 0);
1112 : : if (fld.mpGroup)
1113 : : {
1114 : : cout << " group item count: " << fld.mpGroup->maItems.size() << endl;
1115 : : dumpItems(*this, i, fld.mpGroup->maItems, fld.maItems.size());
1116 : : }
1117 : : }
1118 : : }
1119 : :
1120 : : {
1121 : : struct { SCROW start; SCROW end; bool empty; } aRange;
1122 : : cout << "* empty rows: " << endl;
1123 : : mdds::flat_segment_tree<SCROW, bool>::const_iterator it = maEmptyRows.begin(), itEnd = maEmptyRows.end();
1124 : : if (it != itEnd)
1125 : : {
1126 : : aRange.start = it->first;
1127 : : aRange.empty = it->second;
1128 : : ++it;
1129 : : }
1130 : :
1131 : : for (; it != itEnd; ++it)
1132 : : {
1133 : : aRange.end = it->first-1;
1134 : : cout << " rows " << aRange.start << "-" << aRange.end << ": " << (aRange.empty ? "empty" : "not-empty") << endl;
1135 : : aRange.start = it->first;
1136 : : aRange.empty = it->second;
1137 : : }
1138 : : }
1139 : :
1140 : : {
1141 : : GroupFieldsType::const_iterator it = maGroupFields.begin(), itEnd = maGroupFields.end();
1142 : : for (size_t i = maFields.size(); it != itEnd; ++it, ++i)
1143 : : {
1144 : : const GroupItems& gi = *it;
1145 : : cout << "* group dimension: (unnamed) (ID = " << i << ")" << endl;
1146 : : cout << " item count: " << gi.maItems.size() << endl;
1147 : : dumpItems(*this, i, gi.maItems, 0);
1148 : : }
1149 : : }
1150 : :
1151 : : cout << "---" << endl;
1152 : : }
1153 : :
1154 : : #endif
1155 : :
1156 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|