Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : */
9 :
10 : #include <xepivotxml.hxx>
11 : #include <dpcache.hxx>
12 : #include <dpobject.hxx>
13 : #include <dpsave.hxx>
14 : #include <dputil.hxx>
15 : #include <document.hxx>
16 :
17 : #include <oox/export/utils.hxx>
18 :
19 : #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
20 : #include <com/sun/star/sheet/DataPilotOutputRangeType.hpp>
21 : #include <com/sun/star/sheet/GeneralFunction.hpp>
22 :
23 : #include <vector>
24 :
25 : using namespace oox;
26 : using namespace com::sun::star;
27 :
28 : namespace {
29 :
30 2 : void savePivotCacheRecordsXml( XclExpXmlStream& rStrm, const ScDPCache& rCache )
31 : {
32 2 : SCROW nCount = rCache.GetDataSize();
33 2 : size_t nFieldCount = rCache.GetFieldCount();
34 :
35 2 : sax_fastparser::FSHelperPtr& pRecStrm = rStrm.GetCurrentStream();
36 : pRecStrm->startElement(XML_pivotCacheRecords,
37 : XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
38 : FSNS(XML_xmlns, XML_r), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
39 : XML_count, OString::number(static_cast<long>(nCount)).getStr(),
40 2 : FSEND);
41 :
42 11 : for (SCROW i = 0; i < nCount; ++i)
43 : {
44 9 : pRecStrm->startElement(XML_r, FSEND);
45 43 : for (size_t nField = 0; nField < nFieldCount; ++nField)
46 : {
47 34 : const ScDPCache::IndexArrayType* pArray = rCache.GetFieldIndexArray(nField);
48 : assert(pArray);
49 : assert(static_cast<size_t>(i) < pArray->size());
50 34 : pRecStrm->singleElement(XML_x, XML_v, OString::number((*pArray)[i]), FSEND);
51 : }
52 9 : pRecStrm->endElement(XML_r);
53 : }
54 :
55 2 : pRecStrm->endElement(XML_pivotCacheRecords);
56 2 : }
57 :
58 5 : const char* toOOXMLAxisType( sheet::DataPilotFieldOrientation eOrient )
59 : {
60 5 : switch (eOrient)
61 : {
62 : case sheet::DataPilotFieldOrientation_COLUMN:
63 1 : return "axisCol";
64 : case sheet::DataPilotFieldOrientation_ROW:
65 2 : return "axisRow";
66 : case sheet::DataPilotFieldOrientation_PAGE:
67 2 : return "axisPage";
68 : case sheet::DataPilotFieldOrientation_DATA:
69 0 : return "axisValues";
70 : case sheet::DataPilotFieldOrientation_HIDDEN:
71 : default:
72 : ;
73 : }
74 :
75 0 : return "";
76 : }
77 :
78 3 : const char* toOOXMLSubtotalType( sheet::GeneralFunction eFunc )
79 : {
80 3 : switch (eFunc)
81 : {
82 : case sheet::GeneralFunction_SUM:
83 2 : return "sum";
84 : case sheet::GeneralFunction_COUNT:
85 1 : return "count";
86 : case sheet::GeneralFunction_AVERAGE:
87 0 : return "average";
88 : case sheet::GeneralFunction_MAX:
89 0 : return "max";
90 : case sheet::GeneralFunction_MIN:
91 0 : return "min";
92 : case sheet::GeneralFunction_PRODUCT:
93 0 : return "product";
94 : case sheet::GeneralFunction_COUNTNUMS:
95 0 : return "countNums";
96 : case sheet::GeneralFunction_STDEV:
97 0 : return "stdDev";
98 : case sheet::GeneralFunction_STDEVP:
99 0 : return "stdDevp";
100 : case sheet::GeneralFunction_VAR:
101 0 : return "var";
102 : case sheet::GeneralFunction_VARP:
103 0 : return "varp";
104 : case sheet::GeneralFunction_NONE:
105 : case sheet::GeneralFunction_AUTO:
106 : default:
107 : ;
108 : }
109 0 : return NULL;
110 : }
111 :
112 : }
113 :
114 55 : XclExpXmlPivotCaches::XclExpXmlPivotCaches( const XclExpRoot& rRoot ) :
115 55 : XclExpRoot(rRoot) {}
116 :
117 2 : void XclExpXmlPivotCaches::SaveXml( XclExpXmlStream& rStrm )
118 : {
119 2 : sax_fastparser::FSHelperPtr& pWorkbookStrm = rStrm.GetCurrentStream();
120 2 : pWorkbookStrm->startElement(XML_pivotCaches, FSEND);
121 :
122 4 : for (size_t i = 0, n = maCaches.size(); i < n; ++i)
123 : {
124 2 : const Entry& rEntry = maCaches[i];
125 :
126 2 : sal_Int32 nCacheId = i + 1;
127 2 : OUString aRelId;
128 : sax_fastparser::FSHelperPtr pPCStrm = rStrm.CreateOutputStream(
129 : XclXmlUtils::GetStreamName("xl/pivotCache/", "pivotCacheDefinition", nCacheId),
130 : XclXmlUtils::GetStreamName(NULL, "pivotCache/pivotCacheDefinition", nCacheId),
131 2 : rStrm.GetCurrentStream()->getOutputStream(),
132 : CREATE_XL_CONTENT_TYPE("pivotCacheDefinition"),
133 : CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheDefinition"),
134 4 : &aRelId);
135 :
136 : pWorkbookStrm->singleElement(XML_pivotCache,
137 : XML_cacheId, OString::number(nCacheId).getStr(),
138 : FSNS(XML_r, XML_id), XclXmlUtils::ToOString(aRelId).getStr(),
139 2 : FSEND);
140 :
141 2 : rStrm.PushStream(pPCStrm);
142 2 : SavePivotCacheXml(rStrm, rEntry, nCacheId);
143 2 : rStrm.PopStream();
144 2 : }
145 :
146 2 : pWorkbookStrm->endElement(XML_pivotCaches);
147 2 : }
148 :
149 2 : void XclExpXmlPivotCaches::SetCaches( const std::vector<Entry>& rCaches )
150 : {
151 2 : maCaches = rCaches;
152 2 : }
153 :
154 55 : bool XclExpXmlPivotCaches::HasCaches() const
155 : {
156 55 : return !maCaches.empty();
157 : }
158 :
159 2 : const XclExpXmlPivotCaches::Entry* XclExpXmlPivotCaches::GetCache( sal_Int32 nCacheId ) const
160 : {
161 2 : if (nCacheId <= 0)
162 : // cache ID is 1-based.
163 0 : return NULL;
164 :
165 2 : size_t nPos = nCacheId - 1;
166 2 : if (nPos >= maCaches.size())
167 0 : return NULL;
168 :
169 2 : return &maCaches[nPos];
170 : }
171 :
172 2 : void XclExpXmlPivotCaches::SavePivotCacheXml( XclExpXmlStream& rStrm, const Entry& rEntry, sal_Int32 nCounter )
173 : {
174 : assert(rEntry.mpCache);
175 2 : const ScDPCache& rCache = *rEntry.mpCache;
176 :
177 2 : sax_fastparser::FSHelperPtr& pDefStrm = rStrm.GetCurrentStream();
178 :
179 2 : OUString aRelId;
180 : sax_fastparser::FSHelperPtr pRecStrm = rStrm.CreateOutputStream(
181 : XclXmlUtils::GetStreamName("xl/pivotCache/", "pivotCacheRecords", nCounter),
182 : XclXmlUtils::GetStreamName(NULL, "pivotCacheRecords", nCounter),
183 : pDefStrm->getOutputStream(),
184 : CREATE_XL_CONTENT_TYPE("pivotCacheRecords"),
185 : CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheRecords"),
186 4 : &aRelId);
187 :
188 2 : rStrm.PushStream(pRecStrm);
189 2 : savePivotCacheRecordsXml(rStrm, rCache);
190 2 : rStrm.PopStream();
191 :
192 : pDefStrm->startElement(XML_pivotCacheDefinition,
193 : XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
194 : FSNS(XML_xmlns, XML_r), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
195 : FSNS(XML_r, XML_id), XclXmlUtils::ToOString(aRelId).getStr(),
196 : XML_recordCount, OString::number(rEntry.mpCache->GetDataSize()).getStr(),
197 2 : FSEND);
198 :
199 2 : if (rEntry.meType == Worksheet)
200 : {
201 : pDefStrm->startElement(XML_cacheSource,
202 : XML_type, "worksheet",
203 2 : FSEND);
204 :
205 2 : OUString aSheetName;
206 2 : GetDoc().GetName(rEntry.maSrcRange.aStart.Tab(), aSheetName);
207 : pDefStrm->singleElement(XML_worksheetSource,
208 : XML_ref, XclXmlUtils::ToOString(rEntry.maSrcRange).getStr(),
209 : XML_sheet, XclXmlUtils::ToOString(aSheetName).getStr(),
210 2 : FSEND);
211 :
212 2 : pDefStrm->endElement(XML_cacheSource);
213 : }
214 :
215 2 : size_t nCount = rCache.GetFieldCount();
216 : pDefStrm->startElement(XML_cacheFields,
217 : XML_count, OString::number(static_cast<long>(nCount)).getStr(),
218 2 : FSEND);
219 :
220 14 : for (size_t i = 0; i < nCount; ++i)
221 : {
222 12 : OUString aName = rCache.GetDimensionName(i);
223 :
224 : pDefStrm->startElement(XML_cacheField,
225 : XML_name, XclXmlUtils::ToOString(aName).getStr(),
226 : XML_numFmtId, OString::number(0).getStr(),
227 12 : FSEND);
228 :
229 12 : const ScDPCache::ItemsType& rFieldItems = rCache.GetDimMemberValues(i);
230 :
231 : pDefStrm->startElement(XML_sharedItems,
232 12 : XML_count, OString::number(static_cast<long>(rFieldItems.size())).getStr(),
233 12 : FSEND);
234 :
235 12 : ScDPCache::ItemsType::const_iterator it = rFieldItems.begin(), itEnd = rFieldItems.end();
236 46 : for (; it != itEnd; ++it)
237 : {
238 34 : const ScDPItemData& rItem = *it;
239 34 : switch (rItem.GetType())
240 : {
241 : case ScDPItemData::String:
242 : pDefStrm->singleElement(XML_s,
243 : XML_v, XclXmlUtils::ToOString(rItem.GetString()).getStr(),
244 21 : FSEND);
245 21 : break;
246 : case ScDPItemData::Value:
247 : pDefStrm->singleElement(XML_n,
248 : XML_v, OString::number(rItem.GetValue()).getStr(),
249 13 : FSEND);
250 13 : break;
251 : case ScDPItemData::Empty:
252 0 : pDefStrm->singleElement(XML_m, FSEND);
253 0 : break;
254 : case ScDPItemData::Error:
255 : pDefStrm->singleElement(XML_e,
256 : XML_v, XclXmlUtils::ToOString(rItem.GetString()).getStr(),
257 0 : FSEND);
258 0 : break;
259 : case ScDPItemData::GroupValue:
260 : case ScDPItemData::RangeStart:
261 : // TODO : What do we do with these types?
262 0 : pDefStrm->singleElement(XML_m, FSEND);
263 0 : break;
264 : default:
265 : ;
266 : }
267 : }
268 :
269 12 : pDefStrm->endElement(XML_sharedItems);
270 12 : pDefStrm->endElement(XML_cacheField);
271 12 : }
272 :
273 2 : pDefStrm->endElement(XML_cacheFields);
274 :
275 4 : pDefStrm->endElement(XML_pivotCacheDefinition);
276 2 : }
277 :
278 55 : XclExpXmlPivotTableManager::XclExpXmlPivotTableManager( const XclExpRoot& rRoot ) :
279 55 : XclExpRoot(rRoot), maCaches(rRoot) {}
280 :
281 55 : void XclExpXmlPivotTableManager::Initialize()
282 : {
283 55 : const ScDocument& rDoc = GetDoc();
284 55 : if (!rDoc.HasPivotTable())
285 : // No pivot table to export.
286 106 : return;
287 :
288 2 : const ScDPCollection* pDPColl = rDoc.GetDPCollection();
289 2 : if (!pDPColl)
290 0 : return;
291 :
292 : // Go through the caches first.
293 :
294 2 : std::vector<XclExpXmlPivotCaches::Entry> aCaches;
295 2 : const ScDPCollection::SheetCaches& rSheetCaches = pDPColl->GetSheetCaches();
296 2 : const std::vector<ScRange>& rRanges = rSheetCaches.getAllRanges();
297 4 : for (size_t i = 0, n = rRanges.size(); i < n; ++i)
298 : {
299 2 : const ScDPCache* pCache = rSheetCaches.getExistingCache(rRanges[i]);
300 2 : if (!pCache)
301 0 : continue;
302 :
303 : // Get all pivot objects that reference this cache, and set up an
304 : // object to cache ID mapping.
305 2 : const ScDPCache::ObjectSetType& rRefs = pCache->GetAllReferences();
306 2 : ScDPCache::ObjectSetType::const_iterator it = rRefs.begin(), itEnd = rRefs.end();
307 4 : for (; it != itEnd; ++it)
308 2 : maCacheIdMap.insert(CacheIdMapType::value_type(*it, aCaches.size()+1));
309 :
310 2 : XclExpXmlPivotCaches::Entry aEntry;
311 2 : aEntry.meType = XclExpXmlPivotCaches::Worksheet;
312 2 : aEntry.mpCache = pCache;
313 2 : aEntry.maSrcRange = rRanges[i];
314 2 : aCaches.push_back(aEntry); // Cache ID equals position + 1.
315 : }
316 :
317 : // TODO : Handle name and database caches as well.
318 :
319 4 : for (size_t i = 0, n = pDPColl->GetCount(); i < n; ++i)
320 : {
321 2 : const ScDPObject* pDPObj = (*pDPColl)[i];
322 : assert(pDPObj); // We don't store NULL here.
323 :
324 : // Get the cache ID for this pivot table.
325 2 : CacheIdMapType::iterator itCache = maCacheIdMap.find(pDPObj);
326 2 : if (itCache == maCacheIdMap.end())
327 : // No cache ID found. Something is wrong here....
328 0 : continue;
329 :
330 2 : sal_Int32 nCacheId = itCache->second;
331 2 : SCTAB nTab = pDPObj->GetOutRange().aStart.Tab();
332 :
333 2 : TablesType::iterator it = maTables.find(nTab);
334 2 : if (it == maTables.end())
335 : {
336 : // Insert a new instance for this sheet index.
337 : std::pair<TablesType::iterator, bool> r =
338 2 : maTables.insert(nTab, new XclExpXmlPivotTables(GetRoot(), maCaches));
339 2 : it = r.first;
340 : }
341 :
342 2 : XclExpXmlPivotTables* p = it->second;
343 2 : p->AppendTable(pDPObj, nCacheId, i+1);
344 : }
345 :
346 2 : maCaches.SetCaches(aCaches);
347 : }
348 :
349 55 : XclExpXmlPivotCaches& XclExpXmlPivotTableManager::GetCaches()
350 : {
351 55 : return maCaches;
352 : }
353 :
354 100 : XclExpXmlPivotTables* XclExpXmlPivotTableManager::GetTablesBySheet( SCTAB nTab )
355 : {
356 100 : TablesType::iterator it = maTables.find(nTab);
357 100 : return it == maTables.end() ? NULL : it->second;
358 : }
359 :
360 2 : XclExpXmlPivotTables::Entry::Entry( const ScDPObject* pTable, sal_Int32 nCacheId, sal_Int32 nPivotId ) :
361 2 : mpTable(pTable), mnCacheId(nCacheId), mnPivotId(nPivotId) {}
362 :
363 2 : XclExpXmlPivotTables::XclExpXmlPivotTables( const XclExpRoot& rRoot, const XclExpXmlPivotCaches& rCaches ) :
364 2 : XclExpRoot(rRoot), mrCaches(rCaches) {}
365 :
366 2 : void XclExpXmlPivotTables::SaveXml( XclExpXmlStream& rStrm )
367 : {
368 2 : sax_fastparser::FSHelperPtr& pWSStrm = rStrm.GetCurrentStream(); // worksheet stream
369 :
370 2 : sal_Int32 nCounter = 1; // 1-based
371 2 : TablesType::iterator it = maTables.begin(), itEnd = maTables.end();
372 4 : for (; it != itEnd; ++it, ++nCounter)
373 : {
374 2 : const ScDPObject& rObj = *it->mpTable;
375 2 : sal_Int32 nCacheId = it->mnCacheId;
376 2 : sal_Int32 nPivotId = it->mnPivotId;
377 :
378 : sax_fastparser::FSHelperPtr pPivotStrm = rStrm.CreateOutputStream(
379 : XclXmlUtils::GetStreamName("xl/pivotTables/", "pivotTable", nPivotId),
380 : XclXmlUtils::GetStreamName(NULL, "../pivotTables/pivotTable", nPivotId),
381 : pWSStrm->getOutputStream(),
382 : CREATE_XL_CONTENT_TYPE("pivotTable"),
383 : CREATE_OFFICEDOC_RELATION_TYPE("pivotTable"),
384 2 : NULL);
385 :
386 2 : rStrm.PushStream(pPivotStrm);
387 2 : SavePivotTableXml(rStrm, rObj, nCacheId);
388 2 : rStrm.PopStream();
389 2 : }
390 2 : }
391 :
392 : namespace {
393 :
394 : struct DataField
395 : {
396 : long mnPos; // field index in pivot cache.
397 : const ScDPSaveDimension* mpDim;
398 :
399 3 : DataField( long nPos, const ScDPSaveDimension* pDim ) : mnPos(nPos), mpDim(pDim) {}
400 : };
401 :
402 : }
403 :
404 2 : void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDPObject& rDPObj, sal_Int32 nCacheId )
405 : {
406 : typedef std::unordered_map<OUString, long, OUStringHash> NameToIdMapType;
407 :
408 2 : const XclExpXmlPivotCaches::Entry* pCacheEntry = mrCaches.GetCache(nCacheId);
409 2 : if (!pCacheEntry)
410 : // Something is horribly wrong. Check your logic.
411 2 : return;
412 :
413 2 : const ScDPCache& rCache = *pCacheEntry->mpCache;
414 :
415 2 : const ScDPSaveData& rSaveData = *rDPObj.GetSaveData();
416 :
417 2 : size_t nFieldCount = rCache.GetFieldCount();
418 2 : std::vector<const ScDPSaveDimension*> aCachedDims;
419 4 : NameToIdMapType aNameToIdMap;
420 :
421 2 : aCachedDims.reserve(nFieldCount);
422 14 : for (size_t i = 0; i < nFieldCount; ++i)
423 : {
424 12 : OUString aName = rCache.GetDimensionName(i);
425 12 : aNameToIdMap.insert(NameToIdMapType::value_type(aName, aCachedDims.size()));
426 12 : const ScDPSaveDimension* pDim = rSaveData.GetExistingDimensionByName(aName);
427 12 : aCachedDims.push_back(pDim);
428 12 : }
429 :
430 4 : std::vector<long> aRowFields;
431 4 : std::vector<long> aColFields;
432 4 : std::vector<long> aPageFields;
433 4 : std::vector<DataField> aDataFields;
434 :
435 : // Use dimensions in the save data to get their correct ordering.
436 : // Dimension order here is significant as they specify the order of
437 : // appearance in each axis.
438 2 : const ScDPSaveData::DimsType& rDims = rSaveData.GetDimensions();
439 :
440 16 : for (size_t i = 0, n = rDims.size(); i < n; ++i)
441 : {
442 14 : const ScDPSaveDimension& rDim = rDims[i];
443 :
444 14 : long nPos = -1; // position in cache
445 14 : if (rDim.IsDataLayout())
446 1 : nPos = -2; // Excel uses an index of -2 to indicate a data layout field.
447 : else
448 : {
449 13 : OUString aSrcName = ScDPUtil::getSourceDimensionName(rDim.GetName());
450 13 : NameToIdMapType::iterator it = aNameToIdMap.find(aSrcName);
451 13 : if (it != aNameToIdMap.end())
452 13 : nPos = it->second;
453 :
454 13 : if (nPos == -1)
455 0 : continue;
456 :
457 13 : if (!aCachedDims[nPos])
458 0 : continue;
459 : }
460 :
461 : sheet::DataPilotFieldOrientation eOrient =
462 14 : static_cast<sheet::DataPilotFieldOrientation>(rDim.GetOrientation());
463 :
464 14 : switch (eOrient)
465 : {
466 : case sheet::DataPilotFieldOrientation_COLUMN:
467 2 : aColFields.push_back(nPos);
468 2 : break;
469 : case sheet::DataPilotFieldOrientation_ROW:
470 2 : aRowFields.push_back(nPos);
471 2 : break;
472 : case sheet::DataPilotFieldOrientation_PAGE:
473 2 : aPageFields.push_back(nPos);
474 2 : break;
475 : case sheet::DataPilotFieldOrientation_DATA:
476 3 : aDataFields.push_back(DataField(nPos, &rDim));
477 3 : break;
478 : case sheet::DataPilotFieldOrientation_HIDDEN:
479 : default:
480 : ;
481 : }
482 : }
483 :
484 2 : sax_fastparser::FSHelperPtr& pPivotStrm = rStrm.GetCurrentStream();
485 : pPivotStrm->startElement(XML_pivotTableDefinition,
486 : XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
487 2 : XML_name, XclXmlUtils::ToOString(rDPObj.GetName()).getStr(),
488 : XML_cacheId, OString::number(nCacheId).getStr(),
489 : XML_applyNumberFormats, BS(false),
490 : XML_applyBorderFormats, BS(false),
491 : XML_applyFontFormats, BS(false),
492 : XML_applyPatternFormats, BS(false),
493 : XML_applyAlignmentFormats, BS(false),
494 : XML_applyWidthHeightFormats, BS(false),
495 : XML_dataCaption, "Values",
496 : XML_useAutoFormatting, BS(false),
497 : XML_itemPrintTitles, BS(true),
498 : XML_indent, BS(false),
499 : XML_outline, BS(true),
500 : XML_outlineData, BS(true),
501 4 : FSEND);
502 :
503 : // NB: Excel's range does not include page field area (if any).
504 2 : ScRange aOutRange = rDPObj.GetOutputRangeByType(sheet::DataPilotOutputRangeType::TABLE);
505 :
506 2 : sal_Int32 nFirstHeaderRow = aColFields.size();
507 2 : sal_Int32 nFirstDataRow = 2;
508 2 : sal_Int32 nFirstDataCol = 1;
509 2 : ScRange aResRange = rDPObj.GetOutputRangeByType(sheet::DataPilotOutputRangeType::RESULT);
510 2 : if (aOutRange.IsValid() && aResRange.IsValid())
511 : {
512 2 : nFirstDataRow = aResRange.aStart.Row() - aOutRange.aStart.Row();
513 2 : nFirstDataCol = aResRange.aStart.Col() - aOutRange.aStart.Col();
514 : }
515 :
516 2 : if (!aOutRange.IsValid())
517 0 : aOutRange = rDPObj.GetOutRange();
518 :
519 2 : pPivotStrm->write("<")->writeId(XML_location);
520 : rStrm.WriteAttributes(XML_ref,
521 : XclXmlUtils::ToOString(aOutRange),
522 4 : XML_firstHeaderRow, OString::number(nFirstHeaderRow).getStr(),
523 4 : XML_firstDataRow, OString::number(nFirstDataRow).getStr(),
524 4 : XML_firstDataCol, OString::number(nFirstDataCol).getStr(),
525 12 : FSEND);
526 :
527 2 : if (!aPageFields.empty())
528 : {
529 1 : rStrm.WriteAttributes(XML_rowPageCount, OString::number(static_cast<long>(aPageFields.size())).getStr(), FSEND);
530 1 : rStrm.WriteAttributes(XML_colPageCount, OString::number(1).getStr(), FSEND);
531 : }
532 :
533 2 : pPivotStrm->write("/>");
534 :
535 : // <pivotFields> - It must contain all fields in the pivot cache even if
536 : // only some of them are used in the pivot table. The order must be as
537 : // they appear in the cache.
538 :
539 : pPivotStrm->startElement(XML_pivotFields,
540 2 : XML_count, OString::number(static_cast<long>(aCachedDims.size())).getStr(),
541 2 : FSEND);
542 :
543 14 : for (size_t i = 0, n = aCachedDims.size(); i < n; ++i)
544 : {
545 12 : const ScDPSaveDimension* pDim = aCachedDims[i];
546 12 : if (!pDim)
547 : {
548 : pPivotStrm->singleElement(XML_pivotField,
549 : XML_showAll, BS(false),
550 0 : FSEND);
551 0 : continue;
552 : }
553 :
554 : sheet::DataPilotFieldOrientation eOrient =
555 12 : static_cast<sheet::DataPilotFieldOrientation>(pDim->GetOrientation());
556 :
557 12 : if (eOrient == sheet::DataPilotFieldOrientation_HIDDEN)
558 : {
559 : pPivotStrm->singleElement(XML_pivotField,
560 : XML_showAll, BS(false),
561 5 : FSEND);
562 5 : continue;
563 : }
564 :
565 7 : if (eOrient == sheet::DataPilotFieldOrientation_DATA)
566 : {
567 : pPivotStrm->singleElement(XML_pivotField,
568 : XML_dataField, BS(true),
569 : XML_showAll, BS(false),
570 2 : FSEND);
571 :
572 2 : continue;
573 : }
574 :
575 : pPivotStrm->startElement(XML_pivotField,
576 : XML_axis, toOOXMLAxisType(eOrient),
577 : XML_showAll, BS(false),
578 5 : FSEND);
579 :
580 : // TODO : Dump field items.
581 :
582 5 : pPivotStrm->endElement(XML_pivotField);
583 : }
584 :
585 2 : pPivotStrm->endElement(XML_pivotFields);
586 :
587 : // <rowFields>
588 :
589 2 : if (!aRowFields.empty())
590 : {
591 : pPivotStrm->startElement(XML_rowFields,
592 2 : XML_count, OString::number(static_cast<long>(aRowFields.size())),
593 2 : FSEND);
594 :
595 2 : std::vector<long>::iterator it = aRowFields.begin(), itEnd = aRowFields.end();
596 4 : for (; it != itEnd; ++it)
597 : {
598 : pPivotStrm->singleElement(XML_field,
599 2 : XML_x, OString::number(*it),
600 2 : FSEND);
601 : }
602 :
603 2 : pPivotStrm->endElement(XML_rowFields);
604 : }
605 :
606 : // <rowItems>
607 :
608 : // <colFields>
609 :
610 2 : if (!aColFields.empty())
611 : {
612 : pPivotStrm->startElement(XML_colFields,
613 2 : XML_count, OString::number(static_cast<long>(aColFields.size())),
614 2 : FSEND);
615 :
616 2 : std::vector<long>::iterator it = aColFields.begin(), itEnd = aColFields.end();
617 4 : for (; it != itEnd; ++it)
618 : {
619 : pPivotStrm->singleElement(XML_field,
620 2 : XML_x, OString::number(*it),
621 2 : FSEND);
622 : }
623 :
624 2 : pPivotStrm->endElement(XML_colFields);
625 : }
626 :
627 : // <colItems>
628 :
629 : // <pageFields>
630 :
631 2 : if (!aPageFields.empty())
632 : {
633 : pPivotStrm->startElement(XML_pageFields,
634 1 : XML_count, OString::number(static_cast<long>(aPageFields.size())),
635 1 : FSEND);
636 :
637 1 : std::vector<long>::iterator it = aPageFields.begin(), itEnd = aPageFields.end();
638 3 : for (; it != itEnd; ++it)
639 : {
640 : pPivotStrm->singleElement(XML_pageField,
641 2 : XML_fld, OString::number(*it),
642 : XML_hier, OString::number(-1), // TODO : handle this correctly.
643 4 : FSEND);
644 : }
645 :
646 1 : pPivotStrm->endElement(XML_pageFields);
647 : }
648 :
649 : // <dataFields>
650 :
651 2 : if (!aDataFields.empty())
652 : {
653 : pPivotStrm->startElement(XML_dataFields,
654 2 : XML_count, OString::number(static_cast<long>(aDataFields.size())),
655 2 : FSEND);
656 :
657 2 : std::vector<DataField>::iterator it = aDataFields.begin(), itEnd = aDataFields.end();
658 5 : for (; it != itEnd; ++it)
659 : {
660 3 : long nDimIdx = it->mnPos;
661 : assert(aCachedDims[nDimIdx]); // the loop above should have screened for NULL's.
662 3 : const ScDPSaveDimension& rDim = *it->mpDim;
663 3 : const OUString* pName = rDim.GetLayoutName();
664 3 : pPivotStrm->write("<")->writeId(XML_dataField);
665 3 : if (pName)
666 0 : rStrm.WriteAttributes(XML_name, XclXmlUtils::ToOString(*pName), FSEND);
667 :
668 3 : rStrm.WriteAttributes(XML_fld, OString::number(nDimIdx).getStr(), FSEND);
669 :
670 3 : sheet::GeneralFunction eFunc = static_cast<sheet::GeneralFunction>(rDim.GetFunction());
671 3 : const char* pSubtotal = toOOXMLSubtotalType(eFunc);
672 3 : if (pSubtotal)
673 3 : rStrm.WriteAttributes(XML_subtotal, pSubtotal, FSEND);
674 :
675 3 : pPivotStrm->write("/>");
676 : }
677 :
678 2 : pPivotStrm->endElement(XML_dataFields);
679 : }
680 :
681 2 : OUStringBuffer aBuf("../pivotCache/pivotCacheDefinition");
682 2 : aBuf.append(nCacheId);
683 2 : aBuf.append(".xml");
684 :
685 : rStrm.addRelation(
686 : pPivotStrm->getOutputStream(),
687 : CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheDefinition"),
688 2 : aBuf.makeStringAndClear());
689 :
690 4 : pPivotStrm->endElement(XML_pivotTableDefinition);
691 : }
692 :
693 2 : void XclExpXmlPivotTables::AppendTable( const ScDPObject* pTable, sal_Int32 nCacheId, sal_Int32 nPivotId )
694 : {
695 2 : maTables.push_back(Entry(pTable, nCacheId, nPivotId));
696 32 : }
697 :
698 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|