/* -*- 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/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include "XMLExportDatabaseRanges.hxx" #include #include #include #include #include "xmlexprt.hxx" #include "XMLExportIterator.hxx" #include "XMLConverter.hxx" #include #include #include #include #include "XMLExportSharedData.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include //! not found in unonames.hxx #define SC_USERLIST "UserList" using namespace com::sun::star; using namespace xmloff::token; void writeSort(ScXMLExport& mrExport, const ScSortParam& aParam, const ScRange& aRange, const ScDocument* mpDoc) { // Count sort items first. size_t nSortCount = 0; for (; nSortCount < aParam.GetSortKeyCount(); ++nSortCount) { if (!aParam.maKeyState[nSortCount].bDoSort) break; } if (!nSortCount) // Nothing to export. return; ScAddress aOutPos(aParam.nDestCol, aParam.nDestRow, aParam.nDestTab); if (!aParam.bIncludePattern) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_BIND_STYLES_TO_CONTENT, XML_FALSE); if (!aParam.bInplace) { OUString aStr; ScRangeStringConverter::GetStringFromAddress( aStr, aOutPos, mpDoc, ::formula::FormulaGrammar::CONV_OOO); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TARGET_RANGE_ADDRESS, aStr); } if (aParam.bCaseSens) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_CASE_SENSITIVE, XML_TRUE); mrExport.AddLanguageTagAttributes( XML_NAMESPACE_TABLE, XML_NAMESPACE_TABLE, aParam.aCollatorLocale, false); if (!aParam.aCollatorAlgorithm.isEmpty()) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_ALGORITHM, aParam.aCollatorAlgorithm); SvXMLElementExport aElemS(mrExport, XML_NAMESPACE_TABLE, XML_SORT, true, true); SCCOLROW nFieldStart = aParam.bByRow ? aRange.aStart.Col() : aRange.aStart.Row(); for (size_t i = 0; i < nSortCount; ++i) { // Convert field value from absolute to relative. SCCOLROW nField = aParam.maKeyState[i].nField - nFieldStart; mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_FIELD_NUMBER, OUString::number(nField)); if (!aParam.maKeyState[i].bAscending) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_ORDER, XML_DESCENDING); if (aParam.bUserDef) { OUStringBuffer aBuf; aBuf.append(SC_USERLIST); aBuf.append(static_cast(aParam.nUserIndex)); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATA_TYPE, aBuf.makeStringAndClear()); } else { // Right now we only support automatic field type. In the // future we may support numeric or alphanumeric field type. mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATA_TYPE, XML_AUTOMATIC); } SvXMLElementExport aElemSb(mrExport, XML_NAMESPACE_TABLE, XML_SORT_BY, true, true); } } ScXMLExportDatabaseRanges::ScXMLExportDatabaseRanges(ScXMLExport& rTempExport) : rExport(rTempExport), pDoc( nullptr ) { } ScXMLExportDatabaseRanges::~ScXMLExportDatabaseRanges() { } ScMyEmptyDatabaseRangesContainer ScXMLExportDatabaseRanges::GetEmptyDatabaseRanges() { ScMyEmptyDatabaseRangesContainer aSkipRanges; if (rExport.GetModel().is()) { uno::Reference xPropertySet (rExport.GetModel(), uno::UNO_QUERY); if (xPropertySet.is()) { uno::Reference xDatabaseRanges(xPropertySet->getPropertyValue(SC_UNO_DATABASERNG), uno::UNO_QUERY); rExport.CheckAttrList(); if (xDatabaseRanges.is()) { const uno::Sequence aRanges(xDatabaseRanges->getElementNames()); for (const OUString& sDatabaseRangeName : aRanges) { uno::Reference xDatabaseRange(xDatabaseRanges->getByName(sDatabaseRangeName), uno::UNO_QUERY); if (xDatabaseRange.is()) { uno::Reference xDatabaseRangePropertySet (xDatabaseRange, uno::UNO_QUERY); if (xDatabaseRangePropertySet.is() && ::cppu::any2bool(xDatabaseRangePropertySet->getPropertyValue(SC_UNONAME_STRIPDAT))) { const uno::Sequence aImportProperties(xDatabaseRange->getImportDescriptor()); sheet::DataImportMode nSourceType = sheet::DataImportMode_NONE; for (const auto& rProp : aImportProperties) if ( rProp.Name == SC_UNONAME_SRCTYPE ) rProp.Value >>= nSourceType; if (nSourceType != sheet::DataImportMode_NONE) { table::CellRangeAddress aArea = xDatabaseRange->getDataArea(); aSkipRanges.AddNewEmptyDatabaseRange(aArea); // #105276#; set last row/column so default styles are collected rExport.GetSharedData()->SetLastColumn(aArea.Sheet, aArea.EndColumn); rExport.GetSharedData()->SetLastRow(aArea.Sheet, aArea.EndRow); } } } } } } } return aSkipRanges; } namespace { class WriteDatabaseRange { ScXMLExport& mrExport; ScDocument* const mpDoc; sal_Int32 mnCounter; ScDBCollection::RangeType meRangeType; public: WriteDatabaseRange(ScXMLExport& rExport, ScDocument* pDoc) : mrExport(rExport), mpDoc(pDoc), mnCounter(0), meRangeType(ScDBCollection::GlobalNamed) {} void setRangeType(ScDBCollection::RangeType eNew) { meRangeType = eNew; } void operator() (const ::std::pair& r) { if (meRangeType != ScDBCollection::SheetAnonymous) return; // name OUStringBuffer aBuf; aBuf.append(STR_DB_LOCAL_NONAME); aBuf.append(static_cast(r.first)); // appended number equals sheet index on import. write(aBuf.makeStringAndClear(), *r.second); } void operator() (const ScDBData& rData) { if (meRangeType == ScDBCollection::GlobalAnonymous) { // name OUStringBuffer aBuf; aBuf.append(STR_DB_GLOBAL_NONAME); aBuf.append(++mnCounter); // 1-based, for entirely arbitrary reasons. The numbers are ignored on import. write(aBuf.makeStringAndClear(), rData); } else if (meRangeType == ScDBCollection::GlobalNamed) write(rData.GetName(), rData); } void operator() (std::unique_ptr const& p) { return operator()(*p); } private: void write(const OUString& rName, const ScDBData& rData) { mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, rName); // range ScRange aRange; rData.GetArea(aRange); OUString aRangeStr; ScRangeStringConverter::GetStringFromRange( aRangeStr, aRange, mpDoc, ::formula::FormulaGrammar::CONV_OOO); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TARGET_RANGE_ADDRESS, aRangeStr); // various boolean flags. if (rData.HasImportSelection()) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_IS_SELECTION, XML_TRUE); if (rData.HasAutoFilter()) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY_FILTER_BUTTONS, XML_TRUE); if (rData.IsKeepFmt()) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_ON_UPDATE_KEEP_STYLES, XML_TRUE); if (rData.IsDoSize()) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_ON_UPDATE_KEEP_SIZE, XML_FALSE); if (rData.IsStripData()) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_HAS_PERSISTENT_DATA, XML_FALSE); ScQueryParam aQueryParam; rData.GetQueryParam(aQueryParam); if (!aQueryParam.bHasHeader) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_CONTAINS_HEADER, XML_FALSE); ScSortParam aSortParam; rData.GetSortParam(aSortParam); if (!aSortParam.bByRow) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_ORIENTATION, XML_COLUMN); sal_Int32 nRefresh = rData.GetRefreshDelay(); if (nRefresh) { OUStringBuffer aBuf; ::sax::Converter::convertDuration(aBuf, static_cast(nRefresh) / 86400.0); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_REFRESH_DELAY, aBuf.makeStringAndClear()); } SvXMLElementExport aElemDR(mrExport, XML_NAMESPACE_TABLE, XML_DATABASE_RANGE, true, true); ScSortParam aParam; rData.GetSortParam(aParam); writeImport(rData); writeFilter(rData); writeSort(mrExport, aParam, aRange, mpDoc); writeSubtotals(rData); } void writeImport(const ScDBData& rData) { ScImportParam aParam; rData.GetImportParam(aParam); OUString sDatabaseName; OUString sConRes; svx::ODataAccessDescriptor aDescriptor; aDescriptor.setDataSource(aParam.aDBName); if (aDescriptor.has(svx::DataAccessDescriptorProperty::DataSource)) { sDatabaseName = aParam.aDBName; } else if (aDescriptor.has(svx::DataAccessDescriptorProperty::ConnectionResource)) { sConRes = aParam.aDBName; } sheet::DataImportMode nSourceType = sheet::DataImportMode_NONE; if (aParam.bImport) { if (aParam.bSql) nSourceType = sheet::DataImportMode_SQL; else if (aParam.nType == ScDbQuery) nSourceType = sheet::DataImportMode_QUERY; else nSourceType = sheet::DataImportMode_TABLE; } switch (nSourceType) { case sheet::DataImportMode_NONE : break; case sheet::DataImportMode_QUERY : { if (!sDatabaseName.isEmpty()) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATABASE_NAME, sDatabaseName); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_QUERY_NAME, aParam.aStatement); SvXMLElementExport aElemID(mrExport, XML_NAMESPACE_TABLE, XML_DATABASE_SOURCE_QUERY, true, true); if (!sConRes.isEmpty()) { mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sConRes ); SvXMLElementExport aElemCR(mrExport, XML_NAMESPACE_FORM, XML_CONNECTION_RESOURCE, true, true); } } break; case sheet::DataImportMode_TABLE : { if (!sDatabaseName.isEmpty()) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATABASE_NAME, sDatabaseName); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATABASE_TABLE_NAME, aParam.aStatement); SvXMLElementExport aElemID(mrExport, XML_NAMESPACE_TABLE, XML_DATABASE_SOURCE_TABLE, true, true); if (!sConRes.isEmpty()) { mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sConRes ); SvXMLElementExport aElemCR(mrExport, XML_NAMESPACE_FORM, XML_CONNECTION_RESOURCE, true, true); } } break; case sheet::DataImportMode_SQL : { if (!sDatabaseName.isEmpty()) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATABASE_NAME, sDatabaseName); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_SQL_STATEMENT, aParam.aStatement); if (!aParam.bNative) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_PARSE_SQL_STATEMENT, XML_TRUE); SvXMLElementExport aElemID(mrExport, XML_NAMESPACE_TABLE, XML_DATABASE_SOURCE_SQL, true, true); if (!sConRes.isEmpty()) { mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sConRes ); SvXMLElementExport aElemCR(mrExport, XML_NAMESPACE_FORM, XML_CONNECTION_RESOURCE, true, true); } } break; default: { // added to avoid warnings } } } static OUString getOperatorXML(const ScQueryEntry& rEntry, utl::SearchParam::SearchType eSearchType) { switch (rEntry.eOp) { case SC_BEGINS_WITH: return GetXMLToken(XML_BEGINS_WITH); case SC_BOTPERC: return GetXMLToken(XML_BOTTOM_PERCENT); case SC_BOTVAL: return GetXMLToken(XML_BOTTOM_VALUES); case SC_CONTAINS: return GetXMLToken(XML_CONTAINS); case SC_DOES_NOT_BEGIN_WITH: return GetXMLToken(XML_DOES_NOT_BEGIN_WITH); case SC_DOES_NOT_CONTAIN: return GetXMLToken(XML_DOES_NOT_CONTAIN); case SC_DOES_NOT_END_WITH: return GetXMLToken(XML_DOES_NOT_END_WITH); case SC_ENDS_WITH: return GetXMLToken(XML_ENDS_WITH); case SC_EQUAL: { if (rEntry.IsQueryByEmpty()) return GetXMLToken(XML_EMPTY); else if (rEntry.IsQueryByNonEmpty()) return GetXMLToken(XML_NOEMPTY); if (eSearchType == utl::SearchParam::SearchType::Regexp) return GetXMLToken(XML_MATCH); else return "="; } case SC_GREATER: return ">"; case SC_GREATER_EQUAL: return ">="; case SC_LESS: return "<"; case SC_LESS_EQUAL: return "<="; case SC_NOT_EQUAL: if (eSearchType == utl::SearchParam::SearchType::Regexp) return GetXMLToken(XML_NOMATCH); else return "!="; case SC_TOPPERC: return GetXMLToken(XML_TOP_PERCENT); case SC_TOPVAL: return GetXMLToken(XML_TOP_VALUES); default: ; } return "="; } class WriteSetItem { ScXMLExport& mrExport; public: explicit WriteSetItem(ScXMLExport& r) : mrExport(r) {} void operator() (const ScQueryEntry::Item& rItem) const { mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_VALUE, rItem.maString.getString()); SvXMLElementExport aElem(mrExport, XML_NAMESPACE_TABLE, XML_FILTER_SET_ITEM, true, true); } }; void writeCondition(const ScQueryEntry& rEntry, SCCOLROW nFieldStart, bool bCaseSens, utl::SearchParam::SearchType eSearchType) { const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems(); if (rItems.empty()) { OSL_FAIL("Query entry has no items at all! It must have at least one!"); return; } mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_FIELD_NUMBER, OUString::number(rEntry.nField - nFieldStart)); if (bCaseSens) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_CASE_SENSITIVE, XML_TRUE); if (rItems.size() == 1) { // Single item condition. const ScQueryEntry::Item& rItem = rItems.front(); if (rItem.meType == ScQueryEntry::ByString) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_VALUE, rItem.maString.getString()); else { mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATA_TYPE, XML_NUMBER); OUStringBuffer aBuf; ::sax::Converter::convertDouble(aBuf, rItem.mfVal); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_VALUE, aBuf.makeStringAndClear()); } mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_OPERATOR, getOperatorXML(rEntry, eSearchType)); SvXMLElementExport aElemC(mrExport, XML_NAMESPACE_TABLE, XML_FILTER_CONDITION, true, true); } else { // Multi-item condition. assert( rItems.size() > 1 && "rItems should have more than 1 element"); // Store the 1st value for backward compatibility. const ScQueryEntry::Item& rItem = rItems.front(); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_VALUE, rItem.maString.getString()); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_OPERATOR, OUString("=")); SvXMLElementExport aElemC(mrExport, XML_NAMESPACE_TABLE, XML_FILTER_CONDITION, true, true); std::for_each(rItems.begin(), rItems.end(), WriteSetItem(mrExport)); } } void writeFilter(const ScDBData& rData) { ScQueryParam aParam; rData.GetQueryParam(aParam); size_t nCount = 0; for (size_t n = aParam.GetEntryCount(); nCount < n; ++nCount) { if (!aParam.GetEntry(nCount).bDoQuery) break; } if (!nCount) // No filter criteria to save. Bail out. return; if (!aParam.bInplace) { OUString aAddrStr; ScRangeStringConverter::GetStringFromAddress( aAddrStr, ScAddress(aParam.nDestCol, aParam.nDestRow, aParam.nDestTab), mpDoc, ::formula::FormulaGrammar::CONV_OOO); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TARGET_RANGE_ADDRESS, aAddrStr); } ScRange aAdvSource; if (rData.GetAdvancedQuerySource(aAdvSource)) { OUString aAddrStr; ScRangeStringConverter::GetStringFromRange( aAddrStr, aAdvSource, mpDoc, ::formula::FormulaGrammar::CONV_OOO); if (!aAddrStr.isEmpty()) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_CONDITION_SOURCE_RANGE_ADDRESS, aAddrStr); } if (!aParam.bDuplicate) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DISPLAY_DUPLICATES, XML_FALSE); SvXMLElementExport aElemF(mrExport, XML_NAMESPACE_TABLE, XML_FILTER, true, true); bool bAnd = false; bool bOr = false; for (size_t i = 0; i < nCount; ++i) { const ScQueryEntry& rEntry = aParam.GetEntry(i); if (rEntry.eConnect == SC_AND) bAnd = true; else bOr = true; } // Note that export field index values are relative to the first field. ScRange aRange; rData.GetArea(aRange); SCCOLROW nFieldStart = aParam.bByRow ? aRange.aStart.Col() : aRange.aStart.Row(); if (bOr && !bAnd) { SvXMLElementExport aElemOr(mrExport, XML_NAMESPACE_TABLE, XML_FILTER_OR, true, true); for (size_t i = 0; i < nCount; ++i) writeCondition(aParam.GetEntry(i), nFieldStart, aParam.bCaseSens, aParam.eSearchType); } else if (bAnd && !bOr) { SvXMLElementExport aElemAnd(mrExport, XML_NAMESPACE_TABLE, XML_FILTER_AND, true, true); for (size_t i = 0; i < nCount; ++i) writeCondition(aParam.GetEntry(i), nFieldStart, aParam.bCaseSens, aParam.eSearchType); } else if (nCount == 1) { writeCondition(aParam.GetEntry(0), nFieldStart, aParam.bCaseSens, aParam.eSearchType); } else { SvXMLElementExport aElemC(mrExport, XML_NAMESPACE_TABLE, XML_FILTER_OR, true, true); ScQueryEntry aPrevEntry = aParam.GetEntry(0); ScQueryConnect eConnect = aParam.GetEntry(1).eConnect; bool bOpenAndElement = false; OUString aName = mrExport.GetNamespaceMap().GetQNameByKey(XML_NAMESPACE_TABLE, GetXMLToken(XML_FILTER_AND)); if (eConnect == SC_AND) { mrExport.StartElement(aName, true); bOpenAndElement = true; } else bOpenAndElement = false; for (size_t i = 1; i < nCount; ++i) { const ScQueryEntry& rEntry = aParam.GetEntry(i); if (eConnect != rEntry.eConnect) { eConnect = rEntry.eConnect; if (rEntry.eConnect == SC_AND) { mrExport.StartElement(aName, true ); bOpenAndElement = true; writeCondition(aPrevEntry, nFieldStart, aParam.bCaseSens, aParam.eSearchType); aPrevEntry = rEntry; if (i == nCount - 1) { writeCondition(aPrevEntry, nFieldStart, aParam.bCaseSens, aParam.eSearchType); mrExport.EndElement(aName, true); bOpenAndElement = false; } } else { writeCondition(aPrevEntry, nFieldStart, aParam.bCaseSens, aParam.eSearchType); aPrevEntry = rEntry; if (bOpenAndElement) { mrExport.EndElement(aName, true); bOpenAndElement = false; } if (i == nCount - 1) writeCondition(aPrevEntry, nFieldStart, aParam.bCaseSens, aParam.eSearchType); } } else { writeCondition(aPrevEntry, nFieldStart, aParam.bCaseSens, aParam.eSearchType); aPrevEntry = rEntry; if (i == nCount - 1) writeCondition(aPrevEntry, nFieldStart, aParam.bCaseSens, aParam.eSearchType); } } if(bOpenAndElement) mrExport.EndElement(aName, true); } } void writeSubtotals(const ScDBData& rData) { ScSubTotalParam aParam; rData.GetSubTotalParam(aParam); size_t nCount = 0; for (; nCount < MAXSUBTOTAL; ++nCount) { if (!aParam.bGroupActive[nCount]) break; } if (!nCount) return; if (!aParam.bIncludePattern) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_BIND_STYLES_TO_CONTENT, XML_FALSE); if (aParam.bPagebreak) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_PAGE_BREAKS_ON_GROUP_CHANGE, XML_TRUE); if (aParam.bCaseSens) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_CASE_SENSITIVE, XML_TRUE); SvXMLElementExport aElemSTRs(mrExport, XML_NAMESPACE_TABLE, XML_SUBTOTAL_RULES, true, true); if (aParam.bDoSort) { if (!aParam.bAscending) mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_ORDER, XML_DESCENDING); if (aParam.bUserDef) { OUStringBuffer aBuf; aBuf.append(SC_USERLIST); aBuf.append(static_cast(aParam.nUserIndex)); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DATA_TYPE, aBuf.makeStringAndClear()); } SvXMLElementExport aElemSGs(mrExport, XML_NAMESPACE_TABLE, XML_SORT_GROUPS, true, true); } for (size_t i = 0; i < MAXSUBTOTAL; ++i) { if (!aParam.bGroupActive[i]) // We're done! break; sal_Int32 nFieldCol = static_cast(aParam.nField[i]); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_GROUP_BY_FIELD_NUMBER, OUString::number(nFieldCol)); SvXMLElementExport aElemSTR(mrExport, XML_NAMESPACE_TABLE, XML_SUBTOTAL_RULE, true, true); for (SCCOL j = 0, n = aParam.nSubTotals[i]; j < n; ++j) { sal_Int32 nCol = static_cast(aParam.pSubTotals[i][j]); ScSubTotalFunc eFunc = aParam.pFunctions[i][j]; mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_FIELD_NUMBER, OUString::number(nCol)); OUString aFuncStr; ScXMLConverter::GetStringFromFunction(aFuncStr, eFunc); mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_FUNCTION, aFuncStr); SvXMLElementExport aElemSTF(mrExport, XML_NAMESPACE_TABLE, XML_SUBTOTAL_FIELD, true, true); } } } }; } void ScXMLExportDatabaseRanges::WriteDatabaseRanges() { typedef ::std::map SheetLocalDBs; pDoc = rExport.GetDocument(); if (!pDoc) return; // Get sheet-local anonymous ranges. SCTAB nTabCount = pDoc->GetTableCount(); SheetLocalDBs aSheetDBs; for (SCTAB i = 0; i < nTabCount; ++i) { const ScDBData* p = pDoc->GetAnonymousDBData(i); if (p) aSheetDBs.emplace(i, p); } bool bHasRanges = !aSheetDBs.empty(); // See if we have global ranges. ScDBCollection* pDBCollection = pDoc->GetDBCollection(); if (pDBCollection) { if (!pDBCollection->getNamedDBs().empty() || !pDBCollection->getAnonDBs().empty()) bHasRanges = true; } if (!bHasRanges) // No ranges to export. Bail out. return; SvXMLElementExport aElemDRs(rExport, XML_NAMESPACE_TABLE, XML_DATABASE_RANGES, true, true); WriteDatabaseRange func(rExport, pDoc); if (pDBCollection) { // Write global named ranges. func.setRangeType(ScDBCollection::GlobalNamed); const ScDBCollection::NamedDBs& rNamedDBs = pDBCollection->getNamedDBs(); ::std::for_each(rNamedDBs.begin(), rNamedDBs.end(), func); // Add global anonymous DB ranges. func.setRangeType(ScDBCollection::GlobalAnonymous); const ScDBCollection::AnonDBs& rAnonDBs = pDBCollection->getAnonDBs(); ::std::for_each(rAnonDBs.begin(), rAnonDBs.end(), func); } // Write sheet-local ranges. func.setRangeType(ScDBCollection::SheetAnonymous); ::std::for_each(aSheetDBs.begin(), aSheetDBs.end(), func); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */