diff options
Diffstat (limited to 'sc/source/filter/xml/xmlexternaltabi.cxx')
-rw-r--r-- | sc/source/filter/xml/xmlexternaltabi.cxx | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/sc/source/filter/xml/xmlexternaltabi.cxx b/sc/source/filter/xml/xmlexternaltabi.cxx new file mode 100644 index 000000000000..1e2277465c2a --- /dev/null +++ b/sc/source/filter/xml/xmlexternaltabi.cxx @@ -0,0 +1,440 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------------- + +#include "xmlexternaltabi.hxx" +#include "xmlimprt.hxx" +#include "xmltabi.hxx" +#include "xmlstyli.hxx" + +#include "token.hxx" +#include "document.hxx" + +#include <xmloff/nmspmap.hxx> +#include <xmloff/xmlnmspe.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> +#include <com/sun/star/util/NumberFormat.hpp> + +using namespace ::com::sun::star; + +using ::rtl::OUString; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; + +// ============================================================================ + +ScXMLExternalRefTabSourceContext::ScXMLExternalRefTabSourceContext( + ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName, + const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) : + SvXMLImportContext( rImport, nPrefix, rLName ), + mrScImport(rImport), + mrExternalRefInfo(rRefInfo) +{ + using namespace ::xmloff::token; + + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for (sal_Int16 i = 0; i < nAttrCount; ++i) + { + const rtl::OUString& sAttrName = xAttrList->getNameByIndex(i); + rtl::OUString aLocalName; + sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName); + const rtl::OUString& sValue = xAttrList->getValueByIndex(i); + if (nAttrPrefix == XML_NAMESPACE_XLINK) + { + if (IsXMLToken(aLocalName, XML_HREF)) + maRelativeUrl = sValue; + } + else if (nAttrPrefix == XML_NAMESPACE_TABLE) + { + if (IsXMLToken(aLocalName, XML_TABLE_NAME)) + maTableName = sValue; + else if (IsXMLToken(aLocalName, XML_FILTER_NAME)) + maFilterName = sValue; + else if (IsXMLToken(aLocalName, XML_FILTER_OPTIONS)) + maFilterOptions = sValue; + } + } +} + +ScXMLExternalRefTabSourceContext::~ScXMLExternalRefTabSourceContext() +{ +} + +SvXMLImportContext* ScXMLExternalRefTabSourceContext::CreateChildContext( + sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& /*xAttrList*/ ) +{ + return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); +} + +/** + * Make sure the URL is a valid relative URL, mainly to avoid storing + * absolute URL as relative URL by accident. For now, we only check the first + * three characters which are assumed to be always '../', because the relative + * URL for an external document is always in reference to the content.xml + * fragment of the original document. + */ +static bool lcl_isValidRelativeURL(const OUString& rUrl) +{ + sal_Int32 n = ::std::min( rUrl.getLength(), static_cast<sal_Int32>(3)); + if (n < 3) + return false; + const sal_Unicode* p = rUrl.getStr(); + for (sal_Int32 i = 0; i < n; ++i) + { + sal_Unicode c = p[i]; + if (i < 2 && c != '.') + // the path must begin with '..' + return false; + else if (i == 2 && c != '/') + // a '/' path separator must follow + return false; + } + return true; +} + +void ScXMLExternalRefTabSourceContext::EndElement() +{ + ScDocument* pDoc = mrScImport.GetDocument(); + if (!pDoc) + return; + + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + if (lcl_isValidRelativeURL(maRelativeUrl)) + pRefMgr->setRelativeFileName(mrExternalRefInfo.mnFileId, maRelativeUrl); + pRefMgr->setFilterData(mrExternalRefInfo.mnFileId, maFilterName, maFilterOptions); +} + +// ============================================================================ + +ScXMLExternalRefRowsContext::ScXMLExternalRefRowsContext( + ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName, + const Reference<XAttributeList>& /* xAttrList */, ScXMLExternalTabData& rRefInfo ) : + SvXMLImportContext( rImport, nPrefix, rLName ), + mrScImport(rImport), + mrExternalRefInfo(rRefInfo) +{ +} + +ScXMLExternalRefRowsContext::~ScXMLExternalRefRowsContext() +{ +} + +SvXMLImportContext* ScXMLExternalRefRowsContext::CreateChildContext( + sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList ) +{ + // #i101319# row elements inside group, rows or header-rows + // are treated like row elements directly in the table element + + const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowsElemTokenMap(); + sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName); + switch (nToken) + { + case XML_TOK_TABLE_ROWS_ROW_GROUP: + case XML_TOK_TABLE_ROWS_HEADER_ROWS: + case XML_TOK_TABLE_ROWS_ROWS: + return new ScXMLExternalRefRowsContext( + mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo); + case XML_TOK_TABLE_ROWS_ROW: + return new ScXMLExternalRefRowContext( + mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo); + default: + ; + } + return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); +} + +void ScXMLExternalRefRowsContext::EndElement() +{ +} + +// ============================================================================ + +ScXMLExternalRefRowContext::ScXMLExternalRefRowContext( + ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName, + const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) : + SvXMLImportContext( rImport, nPrefix, rLName ), + mrScImport(rImport), + mrExternalRefInfo(rRefInfo), + mnRepeatRowCount(1) +{ + mrExternalRefInfo.mnCol = 0; + + sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0); + const SvXMLTokenMap& rAttrTokenMap = mrScImport.GetTableRowAttrTokenMap(); + for( sal_Int16 i=0; i < nAttrCount; ++i ) + { + const rtl::OUString& sAttrName = xAttrList->getNameByIndex(i); + rtl::OUString aLocalName; + sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName); + const rtl::OUString& sValue = xAttrList->getValueByIndex(i); + + switch (rAttrTokenMap.Get(nAttrPrefix, aLocalName)) + { + case XML_TOK_TABLE_ROW_ATTR_REPEATED: + { + mnRepeatRowCount = std::max(sValue.toInt32(), static_cast<sal_Int32>(1)); + } + break; + } + } +} + +ScXMLExternalRefRowContext::~ScXMLExternalRefRowContext() +{ +} + +SvXMLImportContext* ScXMLExternalRefRowContext::CreateChildContext( + sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList ) +{ + const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowElemTokenMap(); + sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName); + if (nToken == XML_TOK_TABLE_ROW_CELL || nToken == XML_TOK_TABLE_ROW_COVERED_CELL) + return new ScXMLExternalRefCellContext(mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo); + + return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); +} + +void ScXMLExternalRefRowContext::EndElement() +{ + ScExternalRefCache::TableTypeRef pTab = mrExternalRefInfo.mpCacheTable; + + for (sal_Int32 i = 1; i < mnRepeatRowCount; ++i) + { + // Performance: duplicates of a non-existent row will still not exist. + // Don't find that out for every cell. + // External references often are a sparse matrix. + if (i == 1 && !pTab->hasRow( mrExternalRefInfo.mnRow)) + { + mrExternalRefInfo.mnRow += mnRepeatRowCount; + return; + } + + for (sal_Int32 j = 0; j < mrExternalRefInfo.mnCol; ++j) + { + ScExternalRefCache::TokenRef pToken = pTab->getCell( + static_cast<SCCOL>(j), static_cast<SCROW>(mrExternalRefInfo.mnRow)); + + if (pToken.get()) + { + pTab->setCell(static_cast<SCCOL>(j), + static_cast<SCROW>(mrExternalRefInfo.mnRow+i), pToken); + } + } + } + mrExternalRefInfo.mnRow += mnRepeatRowCount; +} + +// ============================================================================ + +ScXMLExternalRefCellContext::ScXMLExternalRefCellContext( + ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName, + const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) : + SvXMLImportContext( rImport, nPrefix, rLName ), + mrScImport(rImport), + mrExternalRefInfo(rRefInfo), + mfCellValue(0.0), + mnRepeatCount(1), + mnNumberFormat(-1), + mnCellType(::com::sun::star::util::NumberFormat::UNDEFINED), + mbIsNumeric(false), + mbIsEmpty(true) +{ + using namespace ::xmloff::token; + + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + const SvXMLTokenMap& rTokenMap = rImport.GetTableRowCellAttrTokenMap(); + for (sal_Int16 i = 0; i < nAttrCount; ++i) + { + OUString aLocalName; + sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( + xAttrList->getNameByIndex(i), &aLocalName); + + const rtl::OUString& sValue = xAttrList->getValueByIndex(i); + sal_uInt16 nToken = rTokenMap.Get(nAttrPrefix, aLocalName); + + switch (nToken) + { + case XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME: + { + XMLTableStylesContext* pStyles = static_cast<XMLTableStylesContext*>(mrScImport.GetAutoStyles()); + const XMLTableStyleContext* pStyle = static_cast<const XMLTableStyleContext*>( + pStyles->FindStyleChildContext(XML_STYLE_FAMILY_TABLE_CELL, sValue, true)); + if (pStyle) + mnNumberFormat = const_cast<XMLTableStyleContext*>(pStyle)->GetNumberFormat(); + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED: + { + mnRepeatCount = ::std::max(sValue.toInt32(), static_cast<sal_Int32>(1)); + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE: + { + mnCellType = mrScImport.GetCellType(sValue); + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE: + { + if (sValue.getLength()) + { + mrScImport.GetMM100UnitConverter().convertDouble(mfCellValue, sValue); + mbIsNumeric = true; + mbIsEmpty = false; + } + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE: + { + if (sValue.getLength() && mrScImport.SetNullDateOnUnitConverter()) + { + mrScImport.GetMM100UnitConverter().convertDateTime(mfCellValue, sValue); + mbIsNumeric = true; + mbIsEmpty = false; + } + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE: + { + if (sValue.getLength()) + { + mrScImport.GetMM100UnitConverter().convertTime(mfCellValue, sValue); + mbIsNumeric = true; + mbIsEmpty = false; + } + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE: + { + if (sValue.getLength()) + { + maCellString = sValue; + mbIsNumeric = false; + mbIsEmpty = false; + } + } + break; + case XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE: + { + if (sValue.getLength()) + { + mfCellValue = IsXMLToken(sValue, XML_TRUE) ? 1.0 : 0.0; + mbIsNumeric = true; + mbIsEmpty = false; + } + } + break; + default: + ; + } + } +} + +ScXMLExternalRefCellContext::~ScXMLExternalRefCellContext() +{ +} + +SvXMLImportContext* ScXMLExternalRefCellContext::CreateChildContext( + sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList ) +{ + const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowCellElemTokenMap(); + sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName); + if (nToken == XML_TOK_TABLE_ROW_CELL_P) + return new ScXMLExternalRefCellTextContext(mrScImport, nPrefix, rLocalName, xAttrList, *this); + + return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); +} + +void ScXMLExternalRefCellContext::EndElement() +{ + if (maCellString.getLength()) + mbIsEmpty = false; + + for (sal_Int32 i = 0; i < mnRepeatCount; ++i, ++mrExternalRefInfo.mnCol) + { + if (mbIsEmpty) + continue; + + ScExternalRefCache::TokenRef aToken; + if (mbIsNumeric) + aToken.reset(new formula::FormulaDoubleToken(mfCellValue)); + else + aToken.reset(new formula::FormulaStringToken(maCellString)); + + sal_uInt32 nNumFmt = mnNumberFormat >= 0 ? static_cast<sal_uInt32>(mnNumberFormat) : 0; + mrExternalRefInfo.mpCacheTable->setCell( + static_cast<SCCOL>(mrExternalRefInfo.mnCol), + static_cast<SCROW>(mrExternalRefInfo.mnRow), + aToken, nNumFmt); + } +} + +void ScXMLExternalRefCellContext::SetCellString(const OUString& rStr) +{ + maCellString = rStr; +} + +// ============================================================================ + +ScXMLExternalRefCellTextContext::ScXMLExternalRefCellTextContext( + ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName, + const Reference<XAttributeList>& /*xAttrList*/, + ScXMLExternalRefCellContext& rParent ) : + SvXMLImportContext( rImport, nPrefix, rLName ), + mrScImport(rImport), + mrParent(rParent) +{ +} + +ScXMLExternalRefCellTextContext::~ScXMLExternalRefCellTextContext() +{ +} + +SvXMLImportContext* ScXMLExternalRefCellTextContext::CreateChildContext( + sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& /*xAttrList*/ ) +{ + return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); +} + +void ScXMLExternalRefCellTextContext::Characters(const OUString& rChar) +{ + maCellStrBuf.append(rChar); +} + +void ScXMLExternalRefCellTextContext::EndElement() +{ + mrParent.SetCellString(maCellStrBuf.makeStringAndClear()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |