Kaydet (Commit) f5aeaa38 authored tarafından Kohei Yoshida's avatar Kohei Yoshida

bnc#822173: Initial work on exporting pivot cache and pivot table to xlsx.

Still not perfect, but it somewhat does work.

Change-Id: Ic248e20f7ab18a37f56b2034f57551dded956bab
üst 902e3898
......@@ -50,7 +50,8 @@ namespace core {
#define CREATE_MSOFFICE_RELATION_TYPE( ascii ) \
( "http://schemas.microsoft.com/office/2006/relationships/" ascii )
#define CREATE_XL_CONTENT_TYPE( ascii ) \
( "application/vnd.openxmlformats-officedocument.spreadsheetml." ascii "+xml" )
struct Relation
{
......
......@@ -96,6 +96,7 @@ $(eval $(call gb_Library_add_exception_objects,scfilt,\
sc/source/filter/excel/xename \
sc/source/filter/excel/xepage \
sc/source/filter/excel/xepivot \
sc/source/filter/excel/xepivotxml \
sc/source/filter/excel/xerecord \
sc/source/filter/excel/xeroot \
sc/source/filter/excel/xestream \
......
......@@ -156,6 +156,7 @@ public:
long GetDimMemberCount(long nDim) const;
SCROW GetOrder( long nDim, SCROW nIndex ) const;
const IndexArrayType* GetFieldIndexArray( size_t nDim ) const;
const ItemsType& GetDimMemberValues( SCCOL nDim ) const;
bool InitFromDoc(ScDocument* pDoc, const ScRange& rRange);
bool InitFromDataBase(DBConnector& rDB);
......
......@@ -132,6 +132,7 @@ public:
ScRange GetNewOutputRange( bool& rOverflow );
ScRange GetOutputRangeByType( sal_Int32 nType );
ScRange GetOutputRangeByType( sal_Int32 nType ) const;
void SetSaveData(const ScDPSaveData& rData);
ScDPSaveData* GetSaveData() const { return pSaveData; }
......@@ -287,9 +288,12 @@ public:
UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz);
SC_DLLPUBLIC ScDPCache* getExistingCache(const ScRange& rRange);
SC_DLLPUBLIC const ScDPCache* getExistingCache(const ScRange& rRange) const;
void updateCache(const ScRange& rRange, std::set<ScDPObject*>& rRefs);
bool remove(const ScDPCache* p);
SC_DLLPUBLIC const std::vector<ScRange>& getAllRanges() const;
};
/**
......
......@@ -112,7 +112,8 @@ public:
void SetPosition( const ScAddress& rPos );
void Output(); //! Refresh?
ScRange GetOutputRange( sal_Int32 nRegionType = ::com::sun::star::sheet::DataPilotOutputRangeType::WHOLE );
ScRange GetOutputRange( sal_Int32 nRegionType = ::com::sun::star::sheet::DataPilotOutputRangeType::WHOLE );
ScRange GetOutputRange( sal_Int32 nRegionType = ::com::sun::star::sheet::DataPilotOutputRangeType::WHOLE ) const;
long GetHeaderRows();
bool HasError(); // range overflow or exception from source
......
......@@ -850,6 +850,14 @@ SCROW ScDPCache::GetDataSize() const
return mnDataSize >= 0 ? mnDataSize : 0;
}
const ScDPCache::IndexArrayType* ScDPCache::GetFieldIndexArray( size_t nDim ) const
{
if (nDim >= maFields.size())
return NULL;
return &maFields[nDim].maData;
}
const ScDPCache::ItemsType& ScDPCache::GetDimMemberValues(SCCOL nDim) const
{
OSL_ENSURE( nDim>=0 && nDim < mnColumnCount ," nDim < mnColumnCount ");
......
......@@ -936,6 +936,14 @@ ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
return pOutput->GetOutputRange(nType);
}
ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType ) const
{
if (!pOutput || pOutput->HasError())
return ScRange(ScAddress::INITIALIZE_INVALID);
return pOutput->GetOutputRange(nType);
}
static bool lcl_HasButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
{
return ((const ScMergeFlagAttr*)pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->HasPivotButton();
......@@ -2905,6 +2913,25 @@ ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange)
return itCache->second;
}
const ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange) const
{
RangeIndexType::const_iterator it = std::find(maRanges.begin(), maRanges.end(), rRange);
if (it == maRanges.end())
// Not cached.
return NULL;
// Already cached.
size_t nIndex = std::distance(maRanges.begin(), it);
CachesType::const_iterator itCache = maCaches.find(nIndex);
if (itCache == maCaches.end())
{
OSL_FAIL("Cache pool and index pool out-of-sync !!!");
return NULL;
}
return itCache->second;
}
size_t ScDPCollection::SheetCaches::size() const
{
return maCaches.size();
......@@ -2990,6 +3017,11 @@ bool ScDPCollection::SheetCaches::remove(const ScDPCache* p)
return false;
}
const std::vector<ScRange>& ScDPCollection::SheetCaches::getAllRanges() const
{
return maRanges;
}
ScDPCollection::NameCaches::NameCaches(ScDocument* pDoc) : mpDoc(pDoc) {}
bool ScDPCollection::NameCaches::hasCache(const OUString& rName) const
......
......@@ -1166,6 +1166,27 @@ ScRange ScDPOutput::GetOutputRange( sal_Int32 nRegionType )
return ScRange(aStartPos.Col(), aStartPos.Row(), nTab, nTabEndCol, nTabEndRow, nTab);
}
ScRange ScDPOutput::GetOutputRange( sal_Int32 nRegionType ) const
{
using namespace ::com::sun::star::sheet;
if (!bSizesValid)
return ScRange(ScAddress::INITIALIZE_INVALID);
SCTAB nTab = aStartPos.Tab();
switch (nRegionType)
{
case DataPilotOutputRangeType::RESULT:
return ScRange(nDataStartCol, nDataStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
case DataPilotOutputRangeType::TABLE:
return ScRange(aStartPos.Col(), nTabStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
default:
OSL_ENSURE(nRegionType == DataPilotOutputRangeType::WHOLE, "ScDPOutput::GetOutputRange: unknown region type");
break;
}
return ScRange(aStartPos.Col(), aStartPos.Row(), nTab, nTabEndCol, nTabEndRow, nTab);
}
bool ScDPOutput::HasError()
{
CalcSizes();
......
......@@ -68,6 +68,7 @@
#include "xeescher.hxx"
#include "xepivot.hxx"
#include "XclExpChangeTrack.hxx"
#include <xepivotxml.hxx>
#include <math.h>
......@@ -405,10 +406,6 @@ void ExcTable::FillAsHeaderXml( ExcBoundsheetList& rBoundsheetList )
// Formatting: FONT, FORMAT, XF, STYLE, PALETTE
aRecList.AppendNewRecord( new XclExpXmlStyleSheet( *this ) );
// Pivot Cache
GetPivotTableManager().CreatePivotTables();
aRecList.AppendRecord( GetPivotTableManager().CreatePivotCachesRecord() );
// Change tracking
if( rDoc.GetChangeTrack() )
{
......@@ -641,10 +638,6 @@ void ExcTable::FillAsTableXml()
// cell table: DEFCOLWIDTH, COLINFO, DIMENSIONS, ROW, cell records
aRecList.AppendRecord( mxCellTable );
// pivot tables
// not in the worksheet file
aRecList.AppendRecord( GetPivotTableManager().CreatePivotTablesRecord( mnScTab ) );
// list of NOTE records, generated by the cell table
// not in the worksheet file
if( mxNoteList != 0 && !mxNoteList->IsEmpty() )
......@@ -742,6 +735,10 @@ void ExcTable::WriteXml( XclExpXmlStream& rStrm )
mxCellTable->Finalize();
aRecList.SaveXml( rStrm );
XclExpXmlPivotTables* pPT = GetXmlPivotTableManager().GetTablesBySheet(mnScTab);
if (pPT)
pPT->SaveXml(rStrm);
rStrm.GetCurrentStream()->endElement( XML_worksheet );
rStrm.PopStream();
}
......@@ -766,7 +763,10 @@ void ExcDocument::ReadDoc( void )
if (GetOutput() == EXC_OUTPUT_BINARY)
aHeader.FillAsHeaderBinary(maBoundsheetList);
else
{
aHeader.FillAsHeaderXml(maBoundsheetList);
GetXmlPivotTableManager().Initialize();
}
SCTAB nScTab = 0, nScTabCount = GetTabInfo().GetScTabCount();
SCTAB nCodeNameIdx = 0, nCodeNameCount = GetExtDocOptions().GetCodeNameCount();
......@@ -873,6 +873,10 @@ void ExcDocument::WriteXml( XclExpXmlStream& rStrm )
if( pExpChangeTrack )
pExpChangeTrack->WriteXml( rStrm );
XclExpXmlPivotCaches& rCaches = GetXmlPivotTableManager().GetCaches();
if (rCaches.HasCaches())
rCaches.SaveXml(rStrm);
rWorkbook->endElement( XML_workbook );
rWorkbook.reset();
......
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <xepivotxml.hxx>
#include <dpcache.hxx>
#include <dpobject.hxx>
#include <dpsave.hxx>
#include <dputil.hxx>
#include <document.hxx>
#include <oox/export/utils.hxx>
#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
#include <com/sun/star/sheet/DataPilotOutputRangeType.hpp>
#include <vector>
using namespace oox;
using namespace com::sun::star;
namespace {
void savePivotCacheRecordsXml( XclExpXmlStream& rStrm, const ScDPCache& rCache )
{
SCROW nCount = rCache.GetDataSize();
size_t nFieldCount = rCache.GetFieldCount();
sax_fastparser::FSHelperPtr& pRecStrm = rStrm.GetCurrentStream();
pRecStrm->startElement(XML_pivotCacheRecords,
XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
FSNS(XML_xmlns, XML_r), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
XML_count, OString::number(static_cast<long>(nCount)).getStr(),
FSEND);
for (SCROW i = 0; i < nCount; ++i)
{
pRecStrm->startElement(XML_r, FSEND);
for (size_t nField = 0; nField < nFieldCount; ++nField)
{
const ScDPCache::IndexArrayType* pArray = rCache.GetFieldIndexArray(nField);
assert(pArray);
assert(static_cast<size_t>(i) < pArray->size());
pRecStrm->singleElement(XML_x, XML_v, OString::number((*pArray)[i]), FSEND);
}
pRecStrm->endElement(XML_r);
}
pRecStrm->endElement(XML_pivotCacheRecords);
}
const char* toOOXMLAxisType( sheet::DataPilotFieldOrientation eOrient )
{
switch (eOrient)
{
case sheet::DataPilotFieldOrientation_COLUMN:
return "axisCol";
case sheet::DataPilotFieldOrientation_ROW:
return "axisRow";
case sheet::DataPilotFieldOrientation_PAGE:
return "axisPage";
case sheet::DataPilotFieldOrientation_DATA:
return "axisValues";
case sheet::DataPilotFieldOrientation_HIDDEN:
default:
;
}
return "";
}
}
XclExpXmlPivotCaches::XclExpXmlPivotCaches( const XclExpRoot& rRoot ) :
XclExpRoot(rRoot) {}
void XclExpXmlPivotCaches::SaveXml( XclExpXmlStream& rStrm )
{
sax_fastparser::FSHelperPtr& pWorkbookStrm = rStrm.GetCurrentStream();
pWorkbookStrm->startElement(XML_pivotCaches, FSEND);
for (size_t i = 0, n = maCaches.size(); i < n; ++i)
{
const Entry& rEntry = maCaches[i];
sal_Int32 nCacheId = i + 1;
OUString aRelId;
sax_fastparser::FSHelperPtr pPCStrm = rStrm.CreateOutputStream(
XclXmlUtils::GetStreamName("xl/pivotCache/", "pivotCacheDefinition", nCacheId),
XclXmlUtils::GetStreamName(NULL, "pivotCache/pivotCacheDefinition", nCacheId),
rStrm.GetCurrentStream()->getOutputStream(),
CREATE_XL_CONTENT_TYPE("pivotCacheDefinition"),
CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheDefinition"),
&aRelId);
pWorkbookStrm->singleElement(XML_pivotCache,
XML_cacheId, OString::number(nCacheId).getStr(),
FSNS(XML_r, XML_id), XclXmlUtils::ToOString(aRelId).getStr(),
FSEND);
rStrm.PushStream(pPCStrm);
SavePivotCacheXml(rStrm, rEntry, nCacheId);
rStrm.PopStream();
}
pWorkbookStrm->endElement(XML_pivotCaches);
}
void XclExpXmlPivotCaches::SetCaches( const std::vector<Entry>& rCaches )
{
maCaches = rCaches;
}
bool XclExpXmlPivotCaches::HasCaches() const
{
return !maCaches.empty();
}
const XclExpXmlPivotCaches::Entry* XclExpXmlPivotCaches::GetCache( sal_Int32 nCacheId ) const
{
if (nCacheId <= 0)
// cache ID is 1-based.
return NULL;
size_t nPos = nCacheId - 1;
if (nPos >= maCaches.size())
return NULL;
return &maCaches[nPos];
}
void XclExpXmlPivotCaches::SavePivotCacheXml( XclExpXmlStream& rStrm, const Entry& rEntry, sal_Int32 nCounter )
{
assert(rEntry.mpCache);
const ScDPCache& rCache = *rEntry.mpCache;
sax_fastparser::FSHelperPtr& pDefStrm = rStrm.GetCurrentStream();
OUString aRelId;
sax_fastparser::FSHelperPtr pRecStrm = rStrm.CreateOutputStream(
XclXmlUtils::GetStreamName("xl/pivotCache/", "pivotCacheRecords", nCounter),
XclXmlUtils::GetStreamName(NULL, "pivotCacheRecords", nCounter),
pDefStrm->getOutputStream(),
CREATE_XL_CONTENT_TYPE("pivotCacheRecords"),
CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheRecords"),
&aRelId);
rStrm.PushStream(pRecStrm);
savePivotCacheRecordsXml(rStrm, rCache);
rStrm.PopStream();
pDefStrm->startElement(XML_pivotCacheDefinition,
XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
FSNS(XML_xmlns, XML_r), "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
FSNS(XML_r, XML_id), XclXmlUtils::ToOString(aRelId).getStr(),
XML_recordCount, OString::number(rEntry.mpCache->GetDataSize()).getStr(),
FSEND);
if (rEntry.meType == Worksheet)
{
pDefStrm->startElement(XML_cacheSource,
XML_type, "worksheet",
FSEND);
OUString aSheetName;
GetDoc().GetName(rEntry.maSrcRange.aStart.Tab(), aSheetName);
pDefStrm->singleElement(XML_worksheetSource,
XML_ref, XclXmlUtils::ToOString(rEntry.maSrcRange).getStr(),
XML_sheet, XclXmlUtils::ToOString(aSheetName).getStr(),
FSEND);
pDefStrm->endElement(XML_cacheSource);
}
size_t nCount = rCache.GetFieldCount();
pDefStrm->startElement(XML_cacheFields,
XML_count, OString::number(static_cast<long>(nCount)).getStr(),
FSEND);
for (size_t i = 0; i < nCount; ++i)
{
OUString aName = rCache.GetDimensionName(i);
pDefStrm->startElement(XML_cacheField,
XML_name, XclXmlUtils::ToOString(aName).getStr(),
XML_numFmtId, OString::number(0).getStr(),
FSEND);
const ScDPCache::ItemsType& rFieldItems = rCache.GetDimMemberValues(i);
pDefStrm->startElement(XML_sharedItems,
XML_count, OString::number(static_cast<long>(rFieldItems.size())).getStr(),
FSEND);
ScDPCache::ItemsType::const_iterator it = rFieldItems.begin(), itEnd = rFieldItems.end();
for (; it != itEnd; ++it)
{
const ScDPItemData& rItem = *it;
switch (rItem.GetType())
{
case ScDPItemData::String:
pDefStrm->singleElement(XML_s,
XML_v, XclXmlUtils::ToOString(rItem.GetString()).getStr(),
FSEND);
break;
case ScDPItemData::Value:
pDefStrm->singleElement(XML_n,
XML_v, OString::number(rItem.GetValue()).getStr(),
FSEND);
break;
case ScDPItemData::Empty:
pDefStrm->singleElement(XML_m, FSEND);
break;
case ScDPItemData::Error:
pDefStrm->singleElement(XML_e,
XML_v, XclXmlUtils::ToOString(rItem.GetString()).getStr(),
FSEND);
break;
case ScDPItemData::GroupValue:
case ScDPItemData::RangeStart:
// TODO : What do we do with these types?
pDefStrm->singleElement(XML_m, FSEND);
break;
default:
;
}
}
pDefStrm->endElement(XML_sharedItems);
pDefStrm->endElement(XML_cacheField);
}
pDefStrm->endElement(XML_cacheFields);
pDefStrm->endElement(XML_pivotCacheDefinition);
}
XclExpXmlPivotTableManager::XclExpXmlPivotTableManager( const XclExpRoot& rRoot ) :
XclExpRoot(rRoot), maCaches(rRoot) {}
void XclExpXmlPivotTableManager::Initialize()
{
const ScDocument& rDoc = GetDoc();
if (!rDoc.HasPivotTable())
// No pivot table to export.
return;
const ScDPCollection* pDPColl = rDoc.GetDPCollection();
if (!pDPColl)
return;
// Go through the caches first.
std::vector<XclExpXmlPivotCaches::Entry> aCaches;
const ScDPCollection::SheetCaches& rSheetCaches = pDPColl->GetSheetCaches();
const std::vector<ScRange>& rRanges = rSheetCaches.getAllRanges();
for (size_t i = 0, n = rRanges.size(); i < n; ++i)
{
const ScDPCache* pCache = rSheetCaches.getExistingCache(rRanges[i]);
if (!pCache)
continue;
// Get all pivot objects that reference this cache, and set up an
// object to cache ID mapping.
const ScDPCache::ObjectSetType& rRefs = pCache->GetAllReferences();
ScDPCache::ObjectSetType::const_iterator it = rRefs.begin(), itEnd = rRefs.end();
for (; it != itEnd; ++it)
maCacheIdMap.insert(CacheIdMapType::value_type(*it, aCaches.size()+1));
XclExpXmlPivotCaches::Entry aEntry;
aEntry.meType = XclExpXmlPivotCaches::Worksheet;
aEntry.mpCache = pCache;
aEntry.maSrcRange = rRanges[i];
aCaches.push_back(aEntry); // Cache ID equals position + 1.
}
// TODO : Handle name and database caches as well.
for (size_t i = 0, n = pDPColl->GetCount(); i < n; ++i)
{
const ScDPObject* pDPObj = (*pDPColl)[i];
assert(pDPObj); // We don't store NULL here.
// Get the cache ID for this pivot table.
CacheIdMapType::iterator itCache = maCacheIdMap.find(pDPObj);
if (itCache == maCacheIdMap.end())
// No cache ID found. Something is wrong here....
continue;
sal_Int32 nCacheId = itCache->second;
SCTAB nTab = pDPObj->GetOutRange().aStart.Tab();
TablesType::iterator it = maTables.find(nTab);
if (it == maTables.end())
{
// Insert a new instance for this sheet index.
std::pair<TablesType::iterator, bool> r =
maTables.insert(nTab, new XclExpXmlPivotTables(GetRoot(), maCaches));
it = r.first;
}
XclExpXmlPivotTables* p = it->second;
p->AppendTable(pDPObj, nCacheId, i+1);
}
maCaches.SetCaches(aCaches);
}
XclExpXmlPivotCaches& XclExpXmlPivotTableManager::GetCaches()
{
return maCaches;
}
XclExpXmlPivotTables* XclExpXmlPivotTableManager::GetTablesBySheet( SCTAB nTab )
{
TablesType::iterator it = maTables.find(nTab);
return it == maTables.end() ? NULL : it->second;
}
XclExpXmlPivotTables::Entry::Entry( const ScDPObject* pTable, sal_Int32 nCacheId, sal_Int32 nPivotId ) :
mpTable(pTable), mnCacheId(nCacheId), mnPivotId(nPivotId) {}
XclExpXmlPivotTables::XclExpXmlPivotTables( const XclExpRoot& rRoot, const XclExpXmlPivotCaches& rCaches ) :
XclExpRoot(rRoot), mrCaches(rCaches) {}
void XclExpXmlPivotTables::SaveXml( XclExpXmlStream& rStrm )
{
sax_fastparser::FSHelperPtr& pWSStrm = rStrm.GetCurrentStream(); // worksheet stream
sal_Int32 nCounter = 1; // 1-based
TablesType::iterator it = maTables.begin(), itEnd = maTables.end();
for (; it != itEnd; ++it, ++nCounter)
{
const ScDPObject& rObj = *it->mpTable;
sal_Int32 nCacheId = it->mnCacheId;
sal_Int32 nPivotId = it->mnPivotId;
sax_fastparser::FSHelperPtr pPivotStrm = rStrm.CreateOutputStream(
XclXmlUtils::GetStreamName("xl/pivotTables/", "pivotTable", nPivotId),
XclXmlUtils::GetStreamName(NULL, "../pivotTables/pivotTable", nPivotId),
pWSStrm->getOutputStream(),
CREATE_XL_CONTENT_TYPE("pivotTable"),
CREATE_OFFICEDOC_RELATION_TYPE("pivotTable"),
NULL);
rStrm.PushStream(pPivotStrm);
SavePivotTableXml(rStrm, rObj, nCacheId);
rStrm.PopStream();
}
}
void XclExpXmlPivotTables::SavePivotTableXml( XclExpXmlStream& rStrm, const ScDPObject& rDPObj, sal_Int32 nCacheId )
{
typedef boost::unordered_map<OUString, long, OUStringHash> NameToIdMapType;
const XclExpXmlPivotCaches::Entry* pCacheEntry = mrCaches.GetCache(nCacheId);
if (!pCacheEntry)
// Something is horribly wrong. Check your logic.
return;
const ScDPCache& rCache = *pCacheEntry->mpCache;
const ScDPSaveData& rSaveData = *rDPObj.GetSaveData();
size_t nFieldCount = rCache.GetFieldCount();
std::vector<const ScDPSaveDimension*> aCachedDims;
NameToIdMapType aNameToIdMap;
aCachedDims.reserve(nFieldCount);
for (size_t i = 0; i < nFieldCount; ++i)
{
OUString aName = rCache.GetDimensionName(i);
aNameToIdMap.insert(NameToIdMapType::value_type(aName, aCachedDims.size()));
const ScDPSaveDimension* pDim = rSaveData.GetExistingDimensionByName(aName);
aCachedDims.push_back(pDim);
}
std::vector<long> aRowFields;
std::vector<long> aColFields;
std::vector<long> aPageFields;
std::vector<long> aDataFields;
// Use dimensions in the save data to get their correct ordering.
// Dimension order here is significant as they specify the order of
// appearance in each axis.
const ScDPSaveData::DimsType& rDims = rSaveData.GetDimensions();
for (size_t i = 0, n = rDims.size(); i < n; ++i)
{
const ScDPSaveDimension& rDim = rDims[i];
long nPos = -1; // position in cache
OUString aSrcName = ScDPUtil::getSourceDimensionName(rDim.GetName());
NameToIdMapType::iterator it = aNameToIdMap.find(aSrcName);
if (it != aNameToIdMap.end())
nPos = it->second;
if (nPos == -1)
continue;
if (!aCachedDims[nPos])
continue;
sheet::DataPilotFieldOrientation eOrient =
static_cast<sheet::DataPilotFieldOrientation>(rDim.GetOrientation());
switch (eOrient)
{
case sheet::DataPilotFieldOrientation_COLUMN:
aColFields.push_back(nPos);
break;
case sheet::DataPilotFieldOrientation_ROW:
aRowFields.push_back(nPos);
break;
case sheet::DataPilotFieldOrientation_PAGE:
aPageFields.push_back(nPos);
break;
case sheet::DataPilotFieldOrientation_DATA:
aDataFields.push_back(nPos);
break;
case sheet::DataPilotFieldOrientation_HIDDEN:
default:
;
}
}
sax_fastparser::FSHelperPtr& pPivotStrm = rStrm.GetCurrentStream();
pPivotStrm->startElement(XML_pivotTableDefinition,
XML_xmlns, "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
XML_name, XclXmlUtils::ToOString(rDPObj.GetName()).getStr(),
XML_cacheId, OString::number(nCacheId).getStr(),
XML_applyNumberFormats, BS(false),
XML_applyBorderFormats, BS(false),
XML_applyFontFormats, BS(false),
XML_applyPatternFormats, BS(false),
XML_applyAlignmentFormats, BS(false),
XML_applyWidthHeightFormats, BS(false),
XML_dataCaption, "Values",
XML_useAutoFormatting, BS(false),
XML_itemPrintTitles, BS(true),
XML_indent, BS(false),
XML_outline, BS(true),
XML_outlineData, BS(true),
FSEND);
// NB: Excel's range does not include page field area (if any).
ScRange aOutRange = rDPObj.GetOutputRangeByType(sheet::DataPilotOutputRangeType::TABLE);
sal_Int32 nFirstHeaderRow = aColFields.size();
sal_Int32 nFirstDataRow = 2;
sal_Int32 nFirstDataCol = 1;
ScRange aResRange = rDPObj.GetOutputRangeByType(sheet::DataPilotOutputRangeType::RESULT);
if (aOutRange.IsValid() && aResRange.IsValid())
{
nFirstDataRow = aResRange.aStart.Row() - aOutRange.aStart.Row();
nFirstDataCol = aResRange.aStart.Col() - aOutRange.aStart.Col();
}
if (!aOutRange.IsValid())
aOutRange = rDPObj.GetOutRange();
pPivotStrm->write("<")->writeId(XML_location);
rStrm.WriteAttributes(XML_ref,
XclXmlUtils::ToOString(aOutRange),
XML_firstHeaderRow, OString::number(nFirstHeaderRow).getStr(),
XML_firstDataRow, OString::number(nFirstDataRow).getStr(),
XML_firstDataCol, OString::number(nFirstDataCol).getStr(),
FSEND);
if (!aPageFields.empty())
{
rStrm.WriteAttributes(XML_rowPageCount, OString::number(static_cast<long>(aPageFields.size())).getStr(), FSEND);
rStrm.WriteAttributes(XML_colPageCount, OString::number(1).getStr(), FSEND);
}
pPivotStrm->write("/>");
// <pivotFields> - It must contain all fields in the pivot cache even if
// only some of them are used in the pivot table. The order must be as
// they appear in the cache.
pPivotStrm->startElement(XML_pivotFields,
XML_count, OString::number(static_cast<long>(aCachedDims.size())).getStr(),
FSEND);
for (size_t i = 0, n = aCachedDims.size(); i < n; ++i)
{
const ScDPSaveDimension* pDim = aCachedDims[i];
if (!pDim)
{
pPivotStrm->singleElement(XML_pivotField,
XML_showAll, BS(false),
FSEND);
continue;
}
sheet::DataPilotFieldOrientation eOrient =
static_cast<sheet::DataPilotFieldOrientation>(pDim->GetOrientation());
if (eOrient == sheet::DataPilotFieldOrientation_HIDDEN)
{
pPivotStrm->singleElement(XML_pivotField,
XML_showAll, BS(false),
FSEND);
continue;
}
if (eOrient == sheet::DataPilotFieldOrientation_DATA)
{
pPivotStrm->singleElement(XML_pivotField,
XML_dataField, BS(true),
XML_showAll, BS(false),
FSEND);
continue;
}
pPivotStrm->startElement(XML_pivotField,
XML_axis, toOOXMLAxisType(eOrient),
XML_showAll, BS(false),
FSEND);
// TODO : Dump field items.
pPivotStrm->endElement(XML_pivotField);
}
pPivotStrm->endElement(XML_pivotFields);
// <rowFields>
if (!aRowFields.empty())
{
pPivotStrm->startElement(XML_rowFields,
XML_count, OString::number(static_cast<long>(aRowFields.size())),
FSEND);
std::vector<long>::iterator it = aRowFields.begin(), itEnd = aRowFields.end();
for (; it != itEnd; ++it)
{
pPivotStrm->singleElement(XML_field,
XML_x, OString::number(*it),
FSEND);
}
pPivotStrm->endElement(XML_rowFields);
}
// <rowItems>
// <colFields>
if (!aColFields.empty())
{
pPivotStrm->startElement(XML_colFields,
XML_count, OString::number(static_cast<long>(aColFields.size())),
FSEND);
std::vector<long>::iterator it = aColFields.begin(), itEnd = aColFields.end();
for (; it != itEnd; ++it)
{
pPivotStrm->singleElement(XML_field,
XML_x, OString::number(*it),
FSEND);
}
pPivotStrm->endElement(XML_colFields);
}
// <colItems>
// <pageFields>
if (!aPageFields.empty())
{
pPivotStrm->startElement(XML_pageFields,
XML_count, OString::number(static_cast<long>(aPageFields.size())),
FSEND);
std::vector<long>::iterator it = aPageFields.begin(), itEnd = aPageFields.end();
for (; it != itEnd; ++it)
{
pPivotStrm->singleElement(XML_pageField,
XML_fld, OString::number(*it),
XML_hier, OString::number(-1), // TODO : handle this correctly.
FSEND);
}
pPivotStrm->endElement(XML_pageFields);
}
// <dataFields>
if (!aDataFields.empty())
{
pPivotStrm->startElement(XML_dataFields,
XML_count, OString::number(static_cast<long>(aDataFields.size())),
FSEND);
std::vector<long>::iterator it = aDataFields.begin(), itEnd = aDataFields.end();
for (; it != itEnd; ++it)
{
long nDimIdx = *it;
assert(aCachedDims[nDimIdx]); // the loop above should have screened for NULL's.
const ScDPSaveDimension& rDim = *aCachedDims[nDimIdx];
const OUString* pName = rDim.GetLayoutName();
pPivotStrm->write("<")->writeId(XML_dataField);
if (pName)
rStrm.WriteAttributes(XML_name, XclXmlUtils::ToOString(*pName), FSEND);
rStrm.WriteAttributes(XML_fld, OString::number(nDimIdx).getStr(), FSEND);
pPivotStrm->write("/>");
}
pPivotStrm->endElement(XML_dataFields);
}
OUStringBuffer aBuf("../pivotCache/pivotCacheDefinition");
aBuf.append(nCacheId);
aBuf.append(".xml");
rStrm.addRelation(
pPivotStrm->getOutputStream(),
CREATE_OFFICEDOC_RELATION_TYPE("pivotCacheDefinition"),
aBuf.makeStringAndClear());
pPivotStrm->endElement(XML_pivotTableDefinition);
}
void XclExpXmlPivotTables::AppendTable( const ScDPObject* pTable, sal_Int32 nCacheId, sal_Int32 nPivotId )
{
maTables.push_back(Entry(pTable, nCacheId, nPivotId));
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -37,6 +37,7 @@
#include "xepivot.hxx"
#include "xestyle.hxx"
#include "xeroot.hxx"
#include <xepivotxml.hxx>
#include "excrecds.hxx"
#include "tabprotection.hxx"
......@@ -164,6 +165,12 @@ XclExpPivotTableManager& XclExpRoot::GetPivotTableManager() const
return *mrExpData.mxPTableMgr;
}
XclExpXmlPivotTableManager& XclExpRoot::GetXmlPivotTableManager()
{
assert(mrExpData.mxXmlPTableMgr);
return *mrExpData.mxXmlPTableMgr;
}
void XclExpRoot::InitializeConvert()
{
mrExpData.mxTabInfo.reset( new XclExpTabInfo( GetRoot() ) );
......@@ -201,6 +208,8 @@ void XclExpRoot::InitializeGlobals()
if( GetOutput() == EXC_OUTPUT_XML_2007 )
{
mrExpData.mxXmlPTableMgr.reset(new XclExpXmlPivotTableManager(GetRoot()));
do
{
ScDocument& rDoc = GetDoc();
......
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef INCLUDED_SC_FILTER_XEPIVOTXML_HXX
#define INCLUDED_SC_FILTER_XEPIVOTXML_HXX
#include <xerecord.hxx>
#include <xeroot.hxx>
#include <boost/ptr_container/ptr_map.hpp>
#include <boost/unordered_map.hpp>
class ScDPCache;
class ScDPCollection;
class ScDPObject;
class XclExpXmlPivotCaches : public XclExpRecordBase, protected XclExpRoot
{
public:
enum EntryType { Worksheet, Name, Database };
struct Entry
{
const ScDPCache* mpCache;
EntryType meType;
ScRange maSrcRange;
};
XclExpXmlPivotCaches( const XclExpRoot& rRoot );
virtual void SaveXml( XclExpXmlStream& rStrm ) SAL_OVERRIDE;
void SetCaches( const std::vector<Entry>& rCaches );
bool HasCaches() const;
const Entry* GetCache( sal_Int32 nCacheId ) const;
private:
void SavePivotCacheXml( XclExpXmlStream& rStrm, const Entry& rEntry, sal_Int32 nCacheId );
private:
std::vector<Entry> maCaches;
};
class XclExpXmlPivotTables : public XclExpRecordBase, protected XclExpRoot
{
struct Entry
{
const ScDPObject* mpTable;
sal_Int32 mnCacheId;
sal_Int32 mnPivotId; /// used as [n] in pivotTable[n].xml part name.
Entry( const ScDPObject* pTable, sal_Int32 nCacheId, sal_Int32 nPivotId );
};
const XclExpXmlPivotCaches& mrCaches;
typedef std::vector<Entry> TablesType;
TablesType maTables;
public:
XclExpXmlPivotTables( const XclExpRoot& rRoot, const XclExpXmlPivotCaches& rCaches );
virtual void SaveXml( XclExpXmlStream& rStrm ) SAL_OVERRIDE;
void AppendTable( const ScDPObject* pTable, sal_Int32 nCacheId, sal_Int32 nPivotId );
private:
void SavePivotTableXml( XclExpXmlStream& rStrm, const ScDPObject& rObj, sal_Int32 nCacheId );
};
class XclExpXmlPivotTableManager : protected XclExpRoot
{
typedef boost::ptr_map<SCTAB, XclExpXmlPivotTables> TablesType;
typedef boost::unordered_map<const ScDPObject*, sal_Int32> CacheIdMapType;
public:
XclExpXmlPivotTableManager( const XclExpRoot& rRoot );
void Initialize();
XclExpXmlPivotCaches& GetCaches();
XclExpXmlPivotTables* GetTablesBySheet( SCTAB nTab );
private:
XclExpXmlPivotCaches maCaches;
TablesType maTables;
CacheIdMapType maCacheIdMap;
};
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -51,6 +51,7 @@ class XclExpObjectManager;
class XclExpFilterManager;
class XclExpPivotTableManager;
class XclExpDxfs;
class XclExpXmlPivotTableManager;
/** Stores global buffers and data needed for Excel export filter. */
struct XclExpRootData : public XclRootData
......@@ -90,6 +91,8 @@ struct XclExpRootData : public XclRootData
XclExpPTableMgrRef mxPTableMgr; /// All pivot tables and pivot caches.
XclExpDxfsRef mxDxfs; /// All delta formatting entries
boost::shared_ptr<XclExpXmlPivotTableManager> mxXmlPTableMgr;
ScCompiler::OpCodeMapPtr mxOpCodeMap; /// mapping between op-codes and names
bool mbRelUrl; /// true = Store URLs relative.
......@@ -144,6 +147,8 @@ public:
/** Returns the differential formatting list */
XclExpDxfs& GetDxfs() const;
XclExpXmlPivotTableManager& GetXmlPivotTableManager();
/** Is called when export filter starts to create the Excel document (all BIFF versions). */
void InitializeConvert();
/** Is called when export filter starts to create the workbook global data (>=BIFF5). */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment