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 4 : void savePivotCacheRecordsXml( XclExpXmlStream& rStrm, const ScDPCache& rCache )
31 : {
32 4 : SCROW nCount = rCache.GetDataSize();
33 4 : size_t nFieldCount = rCache.GetFieldCount();
34 :
35 4 : 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 4 : FSEND);
41 :
42 22 : for (SCROW i = 0; i < nCount; ++i)
43 : {
44 18 : pRecStrm->startElement(XML_r, FSEND);
45 86 : for (size_t nField = 0; nField < nFieldCount; ++nField)
46 : {
47 68 : const ScDPCache::IndexArrayType* pArray = rCache.GetFieldIndexArray(nField);
48 : assert(pArray);
49 : assert(static_cast<size_t>(i) < pArray->size());
50 68 : pRecStrm->singleElement(XML_x, XML_v, OString::number((*pArray)[i]), FSEND);
51 : }
52 18 : pRecStrm->endElement(XML_r);
53 : }
54 :
55 4 : pRecStrm->endElement(XML_pivotCacheRecords);
56 4 : }
57 :
58 10 : const char* toOOXMLAxisType( sheet::DataPilotFieldOrientation eOrient )
59 : {
60 10 : switch (eOrient)
61 : {
62 : case sheet::DataPilotFieldOrientation_COLUMN:
63 2 : return "axisCol";
64 : case sheet::DataPilotFieldOrientation_ROW:
65 4 : return "axisRow";
66 : case sheet::DataPilotFieldOrientation_PAGE:
67 4 : 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 6 : const char* toOOXMLSubtotalType( sheet::GeneralFunction eFunc )
79 : {
80 6 : switch (eFunc)
81 : {
82 : case sheet::GeneralFunction_SUM:
83 4 : return "sum";
84 : case sheet::GeneralFunction_COUNT:
85 2 : 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 38 : XclExpXmlPivotCaches::XclExpXmlPivotCaches( const XclExpRoot& rRoot ) :
115 38 : XclExpRoot(rRoot) {}
116 :
117 4 : void XclExpXmlPivotCaches::SaveXml( XclExpXmlStream& rStrm )
118 : {
119 4 : sax_fastparser::FSHelperPtr& pWorkbookStrm = rStrm.GetCurrentStream();
120 4 : pWorkbookStrm->startElement(XML_pivotCaches, FSEND);
121 :
122 8 : for (size_t i = 0, n = maCaches.size(); i < n; ++i)
123 : {
124 4 : const Entry& rEntry = maCaches[i];
125 :
126 4 : sal_Int32 nCacheId = i + 1;
127 4 : OUString aRelId;
128 : sax_fastparser::FSHelperPtr pPCStrm = rStrm.CreateOutputStream(
129 : XclXmlUtils::GetStreamName("xl/pivotCache/", "pivotCacheDefinition", nCacheId),
130 : XclXmlUtils::GetStreamName(NULL, "pivotCache/pivotCacheDefinition", nCacheId),
131 4 : rStrm.GetCurrentStream()->getOutputStream(),
132 : CREATE_XL_CONTENT_TYPE("pivotCacheDefinition"),
133 : CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheDefinition"),
134 8 : &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 4 : FSEND);
140 :
141 4 : rStrm.PushStream(pPCStrm);
142 4 : SavePivotCacheXml(rStrm, rEntry, nCacheId);
143 4 : rStrm.PopStream();
144 4 : }
145 :
146 4 : pWorkbookStrm->endElement(XML_pivotCaches);
147 4 : }
148 :
149 4 : void XclExpXmlPivotCaches::SetCaches( const std::vector<Entry>& rCaches )
150 : {
151 4 : maCaches = rCaches;
152 4 : }
153 :
154 38 : bool XclExpXmlPivotCaches::HasCaches() const
155 : {
156 38 : return !maCaches.empty();
157 : }
158 :
159 4 : const XclExpXmlPivotCaches::Entry* XclExpXmlPivotCaches::GetCache( sal_Int32 nCacheId ) const
160 : {
161 4 : if (nCacheId <= 0)
162 : // cache ID is 1-based.
163 0 : return NULL;
164 :
165 4 : size_t nPos = nCacheId - 1;
166 4 : if (nPos >= maCaches.size())
167 0 : return NULL;
168 :
169 4 : return &maCaches[nPos];
170 : }
171 :
172 4 : void XclExpXmlPivotCaches::SavePivotCacheXml( XclExpXmlStream& rStrm, const Entry& rEntry, sal_Int32 nCounter )
173 : {
174 : assert(rEntry.mpCache);
175 4 : const ScDPCache& rCache = *rEntry.mpCache;
176 :
177 4 : sax_fastparser::FSHelperPtr& pDefStrm = rStrm.GetCurrentStream();
178 :
179 4 : 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 8 : &aRelId);
187 :
188 4 : rStrm.PushStream(pRecStrm);
189 4 : savePivotCacheRecordsXml(rStrm, rCache);
190 4 : 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 4 : FSEND);
198 :
199 4 : if (rEntry.meType == Worksheet)
200 : {
201 : pDefStrm->startElement(XML_cacheSource,
202 : XML_type, "worksheet",
203 4 : FSEND);
204 :
205 4 : OUString aSheetName;
206 4 : 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 4 : FSEND);
211 :
212 4 : pDefStrm->endElement(XML_cacheSource);
213 : }
214 :
215 4 : size_t nCount = rCache.GetFieldCount();
216 : pDefStrm->startElement(XML_cacheFields,
217 : XML_count, OString::number(static_cast<long>(nCount)).getStr(),
218 4 : FSEND);
219 :
220 28 : for (size_t i = 0; i < nCount; ++i)
221 : {
222 24 : 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 24 : FSEND);
228 :
229 24 : const ScDPCache::ItemsType& rFieldItems = rCache.GetDimMemberValues(i);
230 :
231 : pDefStrm->startElement(XML_sharedItems,
232 24 : XML_count, OString::number(static_cast<long>(rFieldItems.size())).getStr(),
233 24 : FSEND);
234 :
235 24 : ScDPCache::ItemsType::const_iterator it = rFieldItems.begin(), itEnd = rFieldItems.end();
236 92 : for (; it != itEnd; ++it)
237 : {
238 68 : const ScDPItemData& rItem = *it;
239 68 : switch (rItem.GetType())
240 : {
241 : case ScDPItemData::String:
242 : pDefStrm->singleElement(XML_s,
243 : XML_v, XclXmlUtils::ToOString(rItem.GetString()).getStr(),
244 42 : FSEND);
245 42 : break;
246 : case ScDPItemData::Value:
247 : pDefStrm->singleElement(XML_n,
248 : XML_v, OString::number(rItem.GetValue()).getStr(),
249 26 : FSEND);
250 26 : 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 24 : pDefStrm->endElement(XML_sharedItems);
270 24 : pDefStrm->endElement(XML_cacheField);
271 24 : }
272 :
273 4 : pDefStrm->endElement(XML_cacheFields);
274 :
275 8 : pDefStrm->endElement(XML_pivotCacheDefinition);
276 4 : }
277 :
278 38 : XclExpXmlPivotTableManager::XclExpXmlPivotTableManager( const XclExpRoot& rRoot ) :
279 38 : XclExpRoot(rRoot), maCaches(rRoot) {}
280 :
281 38 : void XclExpXmlPivotTableManager::Initialize()
282 : {
283 38 : const ScDocument& rDoc = GetDoc();
284 38 : if (!rDoc.HasPivotTable())
285 : // No pivot table to export.
286 68 : return;
287 :
288 4 : const ScDPCollection* pDPColl = rDoc.GetDPCollection();
289 4 : if (!pDPColl)
290 0 : return;
291 :
292 : // Go through the caches first.
293 :
294 4 : std::vector<XclExpXmlPivotCaches::Entry> aCaches;
295 4 : const ScDPCollection::SheetCaches& rSheetCaches = pDPColl->GetSheetCaches();
296 4 : const std::vector<ScRange>& rRanges = rSheetCaches.getAllRanges();
297 8 : for (size_t i = 0, n = rRanges.size(); i < n; ++i)
298 : {
299 4 : const ScDPCache* pCache = rSheetCaches.getExistingCache(rRanges[i]);
300 4 : 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 4 : const ScDPCache::ObjectSetType& rRefs = pCache->GetAllReferences();
306 4 : ScDPCache::ObjectSetType::const_iterator it = rRefs.begin(), itEnd = rRefs.end();
307 8 : for (; it != itEnd; ++it)
308 4 : maCacheIdMap.insert(CacheIdMapType::value_type(*it, aCaches.size()+1));
309 :
310 4 : XclExpXmlPivotCaches::Entry aEntry;
311 4 : aEntry.meType = XclExpXmlPivotCaches::Worksheet;
312 4 : aEntry.mpCache = pCache;
313 4 : aEntry.maSrcRange = rRanges[i];
314 4 : aCaches.push_back(aEntry); // Cache ID equals position + 1.
315 : }
316 :
317 : // TODO : Handle name and database caches as well.
318 :
319 8 : for (size_t i = 0, n = pDPColl->GetCount(); i < n; ++i)
320 : {
321 4 : 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 4 : CacheIdMapType::iterator itCache = maCacheIdMap.find(pDPObj);
326 4 : if (itCache == maCacheIdMap.end())
327 : // No cache ID found. Something is wrong here....
328 0 : continue;
329 :
330 4 : sal_Int32 nCacheId = itCache->second;
331 4 : SCTAB nTab = pDPObj->GetOutRange().aStart.Tab();
332 :
333 4 : TablesType::iterator it = maTables.find(nTab);
334 4 : if (it == maTables.end())
335 : {
336 : // Insert a new instance for this sheet index.
337 : std::pair<TablesType::iterator, bool> r =
338 4 : maTables.insert(nTab, new XclExpXmlPivotTables(GetRoot(), maCaches));
339 4 : it = r.first;
340 : }
341 :
342 4 : XclExpXmlPivotTables* p = it->second;
343 4 : p->AppendTable(pDPObj, nCacheId, i+1);
344 : }
345 :
346 4 : maCaches.SetCaches(aCaches);
347 : }
348 :
349 38 : XclExpXmlPivotCaches& XclExpXmlPivotTableManager::GetCaches()
350 : {
351 38 : return maCaches;
352 : }
353 :
354 74 : XclExpXmlPivotTables* XclExpXmlPivotTableManager::GetTablesBySheet( SCTAB nTab )
355 : {
356 74 : TablesType::iterator it = maTables.find(nTab);
357 74 : return it == maTables.end() ? NULL : it->second;
358 : }
359 :
360 4 : XclExpXmlPivotTables::Entry::Entry( const ScDPObject* pTable, sal_Int32 nCacheId, sal_Int32 nPivotId ) :
361 4 : mpTable(pTable), mnCacheId(nCacheId), mnPivotId(nPivotId) {}
362 :
363 4 : XclExpXmlPivotTables::XclExpXmlPivotTables( const XclExpRoot& rRoot, const XclExpXmlPivotCaches& rCaches ) :
364 4 : XclExpRoot(rRoot), mrCaches(rCaches) {}
365 :
366 4 : void XclExpXmlPivotTables::SaveXml( XclExpXmlStream& rStrm )
367 : {
368 4 : sax_fastparser::FSHelperPtr& pWSStrm = rStrm.GetCurrentStream(); // worksheet stream
369 :
370 4 : sal_Int32 nCounter = 1; // 1-based
371 4 : TablesType::iterator it = maTables.begin(), itEnd = maTables.end();
372 8 : for (; it != itEnd; ++it, ++nCounter)
373 : {
374 4 : const ScDPObject& rObj = *it->mpTable;
375 4 : sal_Int32 nCacheId = it->mnCacheId;
376 4 : 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 4 : NULL);
385 :
386 4 : rStrm.PushStream(pPivotStrm);
387 4 : SavePivotTableXml(rStrm, rObj, nCacheId);
388 4 : rStrm.PopStream();
389 4 : }
390 4 : }
391 :
392 : namespace {
393 :
394 : struct DataField
395 : {
396 : long mnPos; // field index in pivot cache.
397 : const ScDPSaveDimension* mpDim;
398 :
399 6 : DataField( long nPos, const ScDPSaveDimension* pDim ) : mnPos(nPos), mpDim(pDim) {}
400 : };
401 :
402 : }
403 :
404 4 : void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDPObject& rDPObj, sal_Int32 nCacheId )
405 : {
406 : typedef boost::unordered_map<OUString, long, OUStringHash> NameToIdMapType;
407 :
408 4 : const XclExpXmlPivotCaches::Entry* pCacheEntry = mrCaches.GetCache(nCacheId);
409 4 : if (!pCacheEntry)
410 : // Something is horribly wrong. Check your logic.
411 4 : return;
412 :
413 4 : const ScDPCache& rCache = *pCacheEntry->mpCache;
414 :
415 4 : const ScDPSaveData& rSaveData = *rDPObj.GetSaveData();
416 :
417 4 : size_t nFieldCount = rCache.GetFieldCount();
418 4 : std::vector<const ScDPSaveDimension*> aCachedDims;
419 8 : NameToIdMapType aNameToIdMap;
420 :
421 4 : aCachedDims.reserve(nFieldCount);
422 28 : for (size_t i = 0; i < nFieldCount; ++i)
423 : {
424 24 : OUString aName = rCache.GetDimensionName(i);
425 24 : aNameToIdMap.insert(NameToIdMapType::value_type(aName, aCachedDims.size()));
426 24 : const ScDPSaveDimension* pDim = rSaveData.GetExistingDimensionByName(aName);
427 24 : aCachedDims.push_back(pDim);
428 24 : }
429 :
430 8 : std::vector<long> aRowFields;
431 8 : std::vector<long> aColFields;
432 8 : std::vector<long> aPageFields;
433 8 : 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 4 : const ScDPSaveData::DimsType& rDims = rSaveData.GetDimensions();
439 :
440 32 : for (size_t i = 0, n = rDims.size(); i < n; ++i)
441 : {
442 28 : const ScDPSaveDimension& rDim = rDims[i];
443 :
444 28 : long nPos = -1; // position in cache
445 28 : if (rDim.IsDataLayout())
446 2 : nPos = -2; // Excel uses an index of -2 to indicate a data layout field.
447 : else
448 : {
449 26 : OUString aSrcName = ScDPUtil::getSourceDimensionName(rDim.GetName());
450 26 : NameToIdMapType::iterator it = aNameToIdMap.find(aSrcName);
451 26 : if (it != aNameToIdMap.end())
452 26 : nPos = it->second;
453 :
454 26 : if (nPos == -1)
455 0 : continue;
456 :
457 26 : if (!aCachedDims[nPos])
458 0 : continue;
459 : }
460 :
461 : sheet::DataPilotFieldOrientation eOrient =
462 28 : static_cast<sheet::DataPilotFieldOrientation>(rDim.GetOrientation());
463 :
464 28 : switch (eOrient)
465 : {
466 : case sheet::DataPilotFieldOrientation_COLUMN:
467 4 : aColFields.push_back(nPos);
468 4 : break;
469 : case sheet::DataPilotFieldOrientation_ROW:
470 4 : aRowFields.push_back(nPos);
471 4 : break;
472 : case sheet::DataPilotFieldOrientation_PAGE:
473 4 : aPageFields.push_back(nPos);
474 4 : break;
475 : case sheet::DataPilotFieldOrientation_DATA:
476 6 : aDataFields.push_back(DataField(nPos, &rDim));
477 6 : break;
478 : case sheet::DataPilotFieldOrientation_HIDDEN:
479 : default:
480 : ;
481 : }
482 : }
483 :
484 4 : sax_fastparser::FSHelperPtr& pPivotStrm = rStrm.GetCurrentStream();
485 : pPivotStrm->startElement(XML_pivotTableDefinition,
486 : XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
487 4 : 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 8 : FSEND);
502 :
503 : // NB: Excel's range does not include page field area (if any).
504 4 : ScRange aOutRange = rDPObj.GetOutputRangeByType(sheet::DataPilotOutputRangeType::TABLE);
505 :
506 4 : sal_Int32 nFirstHeaderRow = aColFields.size();
507 4 : sal_Int32 nFirstDataRow = 2;
508 4 : sal_Int32 nFirstDataCol = 1;
509 4 : ScRange aResRange = rDPObj.GetOutputRangeByType(sheet::DataPilotOutputRangeType::RESULT);
510 4 : if (aOutRange.IsValid() && aResRange.IsValid())
511 : {
512 4 : nFirstDataRow = aResRange.aStart.Row() - aOutRange.aStart.Row();
513 4 : nFirstDataCol = aResRange.aStart.Col() - aOutRange.aStart.Col();
514 : }
515 :
516 4 : if (!aOutRange.IsValid())
517 0 : aOutRange = rDPObj.GetOutRange();
518 :
519 4 : pPivotStrm->write("<")->writeId(XML_location);
520 : rStrm.WriteAttributes(XML_ref,
521 : XclXmlUtils::ToOString(aOutRange),
522 8 : XML_firstHeaderRow, OString::number(nFirstHeaderRow).getStr(),
523 8 : XML_firstDataRow, OString::number(nFirstDataRow).getStr(),
524 8 : XML_firstDataCol, OString::number(nFirstDataCol).getStr(),
525 24 : FSEND);
526 :
527 4 : if (!aPageFields.empty())
528 : {
529 2 : rStrm.WriteAttributes(XML_rowPageCount, OString::number(static_cast<long>(aPageFields.size())).getStr(), FSEND);
530 2 : rStrm.WriteAttributes(XML_colPageCount, OString::number(1).getStr(), FSEND);
531 : }
532 :
533 4 : 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 4 : XML_count, OString::number(static_cast<long>(aCachedDims.size())).getStr(),
541 4 : FSEND);
542 :
543 28 : for (size_t i = 0, n = aCachedDims.size(); i < n; ++i)
544 : {
545 24 : const ScDPSaveDimension* pDim = aCachedDims[i];
546 24 : 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 24 : static_cast<sheet::DataPilotFieldOrientation>(pDim->GetOrientation());
556 :
557 24 : if (eOrient == sheet::DataPilotFieldOrientation_HIDDEN)
558 : {
559 : pPivotStrm->singleElement(XML_pivotField,
560 : XML_showAll, BS(false),
561 10 : FSEND);
562 10 : continue;
563 : }
564 :
565 14 : if (eOrient == sheet::DataPilotFieldOrientation_DATA)
566 : {
567 : pPivotStrm->singleElement(XML_pivotField,
568 : XML_dataField, BS(true),
569 : XML_showAll, BS(false),
570 4 : FSEND);
571 :
572 4 : continue;
573 : }
574 :
575 : pPivotStrm->startElement(XML_pivotField,
576 : XML_axis, toOOXMLAxisType(eOrient),
577 : XML_showAll, BS(false),
578 10 : FSEND);
579 :
580 : // TODO : Dump field items.
581 :
582 10 : pPivotStrm->endElement(XML_pivotField);
583 : }
584 :
585 4 : pPivotStrm->endElement(XML_pivotFields);
586 :
587 : // <rowFields>
588 :
589 4 : if (!aRowFields.empty())
590 : {
591 : pPivotStrm->startElement(XML_rowFields,
592 4 : XML_count, OString::number(static_cast<long>(aRowFields.size())),
593 4 : FSEND);
594 :
595 4 : std::vector<long>::iterator it = aRowFields.begin(), itEnd = aRowFields.end();
596 8 : for (; it != itEnd; ++it)
597 : {
598 : pPivotStrm->singleElement(XML_field,
599 4 : XML_x, OString::number(*it),
600 4 : FSEND);
601 : }
602 :
603 4 : pPivotStrm->endElement(XML_rowFields);
604 : }
605 :
606 : // <rowItems>
607 :
608 : // <colFields>
609 :
610 4 : if (!aColFields.empty())
611 : {
612 : pPivotStrm->startElement(XML_colFields,
613 4 : XML_count, OString::number(static_cast<long>(aColFields.size())),
614 4 : FSEND);
615 :
616 4 : std::vector<long>::iterator it = aColFields.begin(), itEnd = aColFields.end();
617 8 : for (; it != itEnd; ++it)
618 : {
619 : pPivotStrm->singleElement(XML_field,
620 4 : XML_x, OString::number(*it),
621 4 : FSEND);
622 : }
623 :
624 4 : pPivotStrm->endElement(XML_colFields);
625 : }
626 :
627 : // <colItems>
628 :
629 : // <pageFields>
630 :
631 4 : if (!aPageFields.empty())
632 : {
633 : pPivotStrm->startElement(XML_pageFields,
634 2 : XML_count, OString::number(static_cast<long>(aPageFields.size())),
635 2 : FSEND);
636 :
637 2 : std::vector<long>::iterator it = aPageFields.begin(), itEnd = aPageFields.end();
638 6 : for (; it != itEnd; ++it)
639 : {
640 : pPivotStrm->singleElement(XML_pageField,
641 4 : XML_fld, OString::number(*it),
642 : XML_hier, OString::number(-1), // TODO : handle this correctly.
643 8 : FSEND);
644 : }
645 :
646 2 : pPivotStrm->endElement(XML_pageFields);
647 : }
648 :
649 : // <dataFields>
650 :
651 4 : if (!aDataFields.empty())
652 : {
653 : pPivotStrm->startElement(XML_dataFields,
654 4 : XML_count, OString::number(static_cast<long>(aDataFields.size())),
655 4 : FSEND);
656 :
657 4 : std::vector<DataField>::iterator it = aDataFields.begin(), itEnd = aDataFields.end();
658 10 : for (; it != itEnd; ++it)
659 : {
660 6 : long nDimIdx = it->mnPos;
661 : assert(aCachedDims[nDimIdx]); // the loop above should have screened for NULL's.
662 6 : const ScDPSaveDimension& rDim = *it->mpDim;
663 6 : const OUString* pName = rDim.GetLayoutName();
664 6 : pPivotStrm->write("<")->writeId(XML_dataField);
665 6 : if (pName)
666 0 : rStrm.WriteAttributes(XML_name, XclXmlUtils::ToOString(*pName), FSEND);
667 :
668 6 : rStrm.WriteAttributes(XML_fld, OString::number(nDimIdx).getStr(), FSEND);
669 :
670 6 : sheet::GeneralFunction eFunc = static_cast<sheet::GeneralFunction>(rDim.GetFunction());
671 6 : const char* pSubtotal = toOOXMLSubtotalType(eFunc);
672 6 : if (pSubtotal)
673 6 : rStrm.WriteAttributes(XML_subtotal, pSubtotal, FSEND);
674 :
675 6 : pPivotStrm->write("/>");
676 : }
677 :
678 4 : pPivotStrm->endElement(XML_dataFields);
679 : }
680 :
681 4 : OUStringBuffer aBuf("../pivotCache/pivotCacheDefinition");
682 4 : aBuf.append(nCacheId);
683 4 : aBuf.append(".xml");
684 :
685 : rStrm.addRelation(
686 : pPivotStrm->getOutputStream(),
687 : CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheDefinition"),
688 4 : aBuf.makeStringAndClear());
689 :
690 8 : pPivotStrm->endElement(XML_pivotTableDefinition);
691 : }
692 :
693 4 : void XclExpXmlPivotTables::AppendTable( const ScDPObject* pTable, sal_Int32 nCacheId, sal_Int32 nPivotId )
694 : {
695 4 : maTables.push_back(Entry(pTable, nCacheId, nPivotId));
696 52 : }
697 :
698 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|