1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <svl/zforlist.hxx>
21 #include <unotools/charclass.hxx>
22
23 #include <dpcache.hxx>
24 #include <dpshttab.hxx>
25 #include <document.hxx>
26 #include <dpfilteredcache.hxx>
27 #include <dpobject.hxx>
28 #include <globstr.hrc>
29 #include <scresid.hxx>
30 #include <rangenam.hxx>
31 #include <queryentry.hxx>
32
33 #include <osl/diagnose.h>
34
35 #include <vector>
36
37 using namespace ::com::sun::star;
38 using ::com::sun::star::uno::Any;
39 using ::com::sun::star::uno::Sequence;
40 using ::std::vector;
41
ScSheetDPData(const ScDocument * pD,const ScSheetSourceDesc & rDesc,const ScDPCache & rCache)42 ScSheetDPData::ScSheetDPData(const ScDocument* pD, const ScSheetSourceDesc& rDesc, const ScDPCache& rCache) :
43 ScDPTableData(pD),
44 aQuery ( rDesc.GetQueryParam() ),
45 bIgnoreEmptyRows( false ),
46 bRepeatIfEmpty(false),
47 aCacheTable(rCache)
48 {
49 SCSIZE nEntryCount( aQuery.GetEntryCount());
50 for (SCSIZE j = 0; j < nEntryCount; ++j)
51 {
52 ScQueryEntry& rEntry = aQuery.GetEntry(j);
53 if (rEntry.bDoQuery)
54 {
55 ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
56 if (rItem.meType == ScQueryEntry::ByString)
57 {
58 sal_uInt32 nIndex = 0;
59 bool bNumber = pD->GetFormatTable()->IsNumberFormat(
60 rItem.maString.getString(), nIndex, rItem.mfVal);
61 rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
62 }
63 }
64 }
65 }
66
~ScSheetDPData()67 ScSheetDPData::~ScSheetDPData()
68 {
69 }
70
DisposeData()71 void ScSheetDPData::DisposeData()
72 {
73 aCacheTable.clear();
74 }
75
GetColumnCount()76 sal_Int32 ScSheetDPData::GetColumnCount()
77 {
78 CreateCacheTable();
79 return aCacheTable.getColSize();
80 }
81
getDimensionName(sal_Int32 nColumn)82 OUString ScSheetDPData::getDimensionName(sal_Int32 nColumn)
83 {
84 CreateCacheTable();
85 if (getIsDataLayoutDimension(nColumn))
86 {
87 //TODO: different internal and display names?
88 //return "Data";
89 return ScResId(STR_PIVOT_DATA);
90 }
91 else if (nColumn >= aCacheTable.getColSize())
92 {
93 OSL_FAIL("getDimensionName: invalid dimension");
94 return OUString();
95 }
96 else
97 {
98 return aCacheTable.getFieldName(static_cast<SCCOL>(nColumn));
99 }
100 }
101
IsDateDimension(sal_Int32 nDim)102 bool ScSheetDPData::IsDateDimension(sal_Int32 nDim)
103 {
104 CreateCacheTable();
105 tools::Long nColCount = aCacheTable.getColSize();
106 if (getIsDataLayoutDimension(nDim))
107 {
108 return false;
109 }
110 else if (nDim >= nColCount)
111 {
112 OSL_FAIL("IsDateDimension: invalid dimension");
113 return false;
114 }
115 else
116 {
117 return GetCacheTable().getCache().IsDateDimension( nDim);
118 }
119 }
120
GetNumberFormat(sal_Int32 nDim)121 sal_uInt32 ScSheetDPData::GetNumberFormat(sal_Int32 nDim)
122 {
123 CreateCacheTable();
124 if (getIsDataLayoutDimension(nDim))
125 {
126 return 0;
127 }
128 else if (nDim >= GetCacheTable().getColSize())
129 {
130 OSL_FAIL("GetNumberFormat: invalid dimension");
131 return 0;
132 }
133 else
134 {
135 return GetCacheTable().getCache().GetNumberFormat( nDim );
136 }
137 }
GetNumberFormatByIdx(NfIndexTableOffset eIdx)138 sal_uInt32 ScDPTableData::GetNumberFormatByIdx( NfIndexTableOffset eIdx )
139 {
140 if( !mpDoc )
141 return 0;
142
143 if ( SvNumberFormatter* pFormatter = mpDoc->GetFormatTable() )
144 return pFormatter->GetFormatIndex( eIdx, LANGUAGE_SYSTEM );
145
146 return 0;
147 }
148
getIsDataLayoutDimension(sal_Int32 nColumn)149 bool ScSheetDPData::getIsDataLayoutDimension(sal_Int32 nColumn)
150 {
151 CreateCacheTable();
152 return (nColumn ==static_cast<tools::Long>( aCacheTable.getColSize()));
153 }
154
SetEmptyFlags(bool bIgnoreEmptyRowsP,bool bRepeatIfEmptyP)155 void ScSheetDPData::SetEmptyFlags( bool bIgnoreEmptyRowsP, bool bRepeatIfEmptyP )
156 {
157 bIgnoreEmptyRows = bIgnoreEmptyRowsP;
158 bRepeatIfEmpty = bRepeatIfEmptyP;
159 }
160
IsRepeatIfEmpty()161 bool ScSheetDPData::IsRepeatIfEmpty()
162 {
163 return bRepeatIfEmpty;
164 }
165
CreateCacheTable()166 void ScSheetDPData::CreateCacheTable()
167 {
168 // Scan and store the data from the source range.
169 if (!aCacheTable.empty())
170 // already cached.
171 return;
172
173 aCacheTable.fillTable(aQuery, bIgnoreEmptyRows, bRepeatIfEmpty);
174 }
175
FilterCacheTable(const vector<ScDPFilteredCache::Criterion> & rCriteria,const std::unordered_set<sal_Int32> & rCatDims)176 void ScSheetDPData::FilterCacheTable(const vector<ScDPFilteredCache::Criterion>& rCriteria, const std::unordered_set<sal_Int32>& rCatDims)
177 {
178 CreateCacheTable();
179 aCacheTable.filterByPageDimension(
180 rCriteria, (IsRepeatIfEmpty() ? rCatDims : std::unordered_set<sal_Int32>()));
181 }
182
GetDrillDownData(const vector<ScDPFilteredCache::Criterion> & rCriteria,const std::unordered_set<sal_Int32> & rCatDims,Sequence<Sequence<Any>> & rData)183 void ScSheetDPData::GetDrillDownData(const vector<ScDPFilteredCache::Criterion>& rCriteria, const std::unordered_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
184 {
185 CreateCacheTable();
186 sal_Int32 nRowSize = aCacheTable.getRowSize();
187 if (!nRowSize)
188 return;
189
190 aCacheTable.filterTable(
191 rCriteria, rData, IsRepeatIfEmpty() ? rCatDims : std::unordered_set<sal_Int32>());
192 }
193
CalcResults(CalcInfo & rInfo,bool bAutoShow)194 void ScSheetDPData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
195 {
196 CreateCacheTable();
197 CalcResultsFromCacheTable(aCacheTable, rInfo, bAutoShow);
198 }
199
GetCacheTable() const200 const ScDPFilteredCache& ScSheetDPData::GetCacheTable() const
201 {
202 return aCacheTable;
203 }
204
ReloadCacheTable()205 void ScSheetDPData::ReloadCacheTable()
206 {
207 aCacheTable.clear();
208 CreateCacheTable();
209 }
210
211 #if DUMP_PIVOT_TABLE
212
Dump() const213 void ScSheetDPData::Dump() const
214 {
215 // TODO : Implement this.
216 }
217
218 #endif
219
ScSheetSourceDesc(ScDocument * pDoc)220 ScSheetSourceDesc::ScSheetSourceDesc(ScDocument* pDoc) :
221 mpDoc(pDoc) {}
222
SetSourceRange(const ScRange & rRange)223 void ScSheetSourceDesc::SetSourceRange(const ScRange& rRange)
224 {
225 maSourceRange = rRange;
226 maRangeName.clear(); // overwrite existing range name if any.
227 }
228
GetSourceRange() const229 const ScRange& ScSheetSourceDesc::GetSourceRange() const
230 {
231 if (!maRangeName.isEmpty())
232 {
233 // Obtain the source range from the range name first.
234 maSourceRange = ScRange();
235 ScRangeName* pRangeName = mpDoc->GetRangeName();
236 do
237 {
238 if (!pRangeName)
239 break;
240
241 OUString aUpper = ScGlobal::getCharClassPtr()->uppercase(maRangeName);
242 const ScRangeData* pData = pRangeName->findByUpperName(aUpper);
243 if (!pData)
244 break;
245
246 // range name found. Fow now, we only use the first token and
247 // ignore the rest.
248 ScRange aRange;
249 if (!pData->IsReference(aRange))
250 break;
251
252 maSourceRange = aRange;
253 }
254 while (false);
255 }
256 return maSourceRange;
257 }
258
SetRangeName(const OUString & rName)259 void ScSheetSourceDesc::SetRangeName(const OUString& rName)
260 {
261 maRangeName = rName;
262 }
263
HasRangeName() const264 bool ScSheetSourceDesc::HasRangeName() const
265 {
266 return !maRangeName.isEmpty();
267 }
268
SetQueryParam(const ScQueryParam & rParam)269 void ScSheetSourceDesc::SetQueryParam(const ScQueryParam& rParam)
270 {
271 maQueryParam = rParam;
272 }
273
operator ==(const ScSheetSourceDesc & rOther) const274 bool ScSheetSourceDesc::operator== (const ScSheetSourceDesc& rOther) const
275 {
276 return maSourceRange == rOther.maSourceRange &&
277 maRangeName == rOther.maRangeName &&
278 maQueryParam == rOther.maQueryParam;
279 }
280
CreateCache(const ScDPDimensionSaveData * pDimData) const281 const ScDPCache* ScSheetSourceDesc::CreateCache(const ScDPDimensionSaveData* pDimData) const
282 {
283 if (!mpDoc)
284 return nullptr;
285
286 const char* pErrId = CheckSourceRange();
287 if (pErrId)
288 {
289 OSL_FAIL( "Error Create Cache" );
290 return nullptr;
291 }
292
293 // All cache instances are managed centrally by ScDPCollection.
294 ScDPCollection* pDPs = mpDoc->GetDPCollection();
295 if (HasRangeName())
296 {
297 // Name-based data source.
298 ScDPCollection::NameCaches& rCaches = pDPs->GetNameCaches();
299 return rCaches.getCache(GetRangeName(), GetSourceRange(), pDimData);
300 }
301
302 ScDPCollection::SheetCaches& rCaches = pDPs->GetSheetCaches();
303 return rCaches.getCache(GetSourceRange(), pDimData);
304 }
305
CheckSourceRange() const306 const char* ScSheetSourceDesc::CheckSourceRange() const
307 {
308 if (!mpDoc)
309 return STR_ERR_DATAPILOTSOURCE;
310
311 // Make sure the range is valid and sane.
312 const ScRange& rSrcRange = GetSourceRange();
313 if (!rSrcRange.IsValid())
314 return STR_ERR_DATAPILOTSOURCE;
315
316 if (rSrcRange.aStart.Col() > rSrcRange.aEnd.Col() || rSrcRange.aStart.Row() > rSrcRange.aEnd.Row())
317 return STR_ERR_DATAPILOTSOURCE;
318
319 return nullptr;
320 }
321
322 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
323