| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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()); |
| } |