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