/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; using namespace ::xmloff::token; namespace sw { class StoredChapterNumberingRules : public ::cppu::WeakImplHelper { private: // TODO in case this ever becomes accessible via api need a invalidate SwChapterNumRules & m_rNumRules; sal_uInt16 const m_nIndex; SwNumRulesWithName * GetOrCreateRules() { SwNumRulesWithName const* pRules(m_rNumRules.GetRules(m_nIndex)); if (!pRules) { m_rNumRules.CreateEmptyNumRule(m_nIndex); pRules = m_rNumRules.GetRules(m_nIndex); assert(pRules); } return const_cast(pRules); } public: StoredChapterNumberingRules( SwChapterNumRules & rNumRules, sal_uInt16 const nIndex) : m_rNumRules(rNumRules) , m_nIndex(nIndex) { assert(m_nIndex < SwChapterNumRules::nMaxRules); } // XNamed virtual OUString SAL_CALL getName() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE { SolarMutexGuard g; SwNumRulesWithName const* pRules(m_rNumRules.GetRules(m_nIndex)); if (!pRules) { return OUString(); } return pRules->GetName(); } virtual void SAL_CALL setName(OUString const& rName) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE { SolarMutexGuard g; SwNumRulesWithName *const pRules(GetOrCreateRules()); pRules->SetName(rName); } // XElementAccess virtual uno::Type SAL_CALL getElementType() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE { return ::cppu::UnoType>::get(); } virtual ::sal_Bool SAL_CALL hasElements() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE { return sal_True; } // XIndexAccess virtual sal_Int32 SAL_CALL getCount() throw (uno::RuntimeException, std::exception) SAL_OVERRIDE { return MAXLEVEL; } virtual uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException, std::exception) SAL_OVERRIDE { if (nIndex < 0 || MAXLEVEL <= nIndex) throw lang::IndexOutOfBoundsException(); SolarMutexGuard g; SwNumRulesWithName const* pRules(m_rNumRules.GetRules(m_nIndex)); if (!pRules) { return uno::Any(); } SwNumFmt const* pNumFmt(0); OUString const* pCharStyleName(0); pRules->GetNumFmt(nIndex, pNumFmt, pCharStyleName); if (!pNumFmt) { // the dialog only fills in those levels that are non-default return uno::Any(); // the export will ignore this level, yay } assert(pCharStyleName); OUString dummy; // pass in empty HeadingStyleName - can't import anyway uno::Sequence const ret( SwXNumberingRules::GetPropertiesForNumFmt( *pNumFmt, *pCharStyleName, &dummy)); return uno::makeAny(ret); } // XIndexReplace virtual void SAL_CALL replaceByIndex( sal_Int32 nIndex, uno::Any const& rElement) throw (lang::IllegalArgumentException, lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException, std::exception) SAL_OVERRIDE { if (nIndex < 0 || MAXLEVEL <= nIndex) throw lang::IndexOutOfBoundsException(); uno::Sequence props; if (!(rElement >>= props)) throw lang::IllegalArgumentException("invalid type", static_cast< ::cppu::OWeakObject*>(this), 1); SolarMutexGuard g; SwNumFmt aNumberFormat; OUString charStyleName; SwXNumberingRules::SetPropertiesToNumFmt( aNumberFormat, charStyleName, 0, 0, 0, 0, 0, props); SwNumRulesWithName *const pRules(GetOrCreateRules()); pRules->SetNumFmt(nIndex, aNumberFormat, charStyleName); } }; class StoredChapterNumberingExport : public SvXMLExport { public: StoredChapterNumberingExport( uno::Reference const& xContext, OUString const& rFileName, uno::Reference const& xHandler) : SvXMLExport(xContext, "sw::StoredChapterNumberingExport", rFileName, util::MeasureUnit::CM, xHandler) { _GetNamespaceMap().Add(GetXMLToken(XML_NP_OFFICE), GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE); _GetNamespaceMap().Add(GetXMLToken(XML_NP_TEXT), GetXMLToken(XML_N_TEXT), XML_NAMESPACE_TEXT); _GetNamespaceMap().Add(GetXMLToken(XML_NP_STYLE), GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE); _GetNamespaceMap().Add(GetXMLToken(XML_NP_FO), GetXMLToken(XML_N_FO), XML_NAMESPACE_FO); _GetNamespaceMap().Add(GetXMLToken(XML_NP_SVG), GetXMLToken(XML_N_SVG), XML_NAMESPACE_SVG); } virtual void _ExportAutoStyles() SAL_OVERRIDE {} virtual void _ExportMasterStyles() SAL_OVERRIDE {} virtual void _ExportContent() SAL_OVERRIDE {} void ExportRule(SvxXMLNumRuleExport & rExport, uno::Reference const& xRule) { uno::Reference const xNamed(xRule, uno::UNO_QUERY); OUString const name(xNamed->getName()); bool bEncoded(false); AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, EncodeStyleName(name, &bEncoded) ); if (bEncoded) { AddAttribute(XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, name); } SvXMLElementExport aElem( *this, XML_NAMESPACE_TEXT, XML_OUTLINE_STYLE, true, true ); rExport.exportLevelStyles(xRule, true); } void ExportRules( std::set const& rCharStyles, std::vector> const& rRules) { GetDocHandler()->startDocument(); AddAttribute(XML_NAMESPACE_NONE, _GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_OFFICE), _GetNamespaceMap().GetNameByKey(XML_NAMESPACE_OFFICE)); AddAttribute(XML_NAMESPACE_NONE, _GetNamespaceMap().GetAttrNameByKey (XML_NAMESPACE_TEXT), _GetNamespaceMap().GetNameByKey(XML_NAMESPACE_TEXT)); AddAttribute(XML_NAMESPACE_NONE, _GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_STYLE), _GetNamespaceMap().GetNameByKey(XML_NAMESPACE_STYLE)); AddAttribute(XML_NAMESPACE_NONE, _GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_FO), _GetNamespaceMap().GetNameByKey(XML_NAMESPACE_FO)); AddAttribute(XML_NAMESPACE_NONE, _GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_SVG), _GetNamespaceMap().GetNameByKey(XML_NAMESPACE_SVG)); { // let's just have a office:styles as a dummy root SvXMLElementExport styles(*this, XML_NAMESPACE_OFFICE, XML_STYLES, true, true); // horrible hack for char styles to get display-name mapping for (auto it = rCharStyles.begin(); it != rCharStyles.end(); ++it) { AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, XML_TEXT ); bool bEncoded(false); AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, EncodeStyleName(*it, &bEncoded) ); if (bEncoded) { AddAttribute(XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, *it); } SvXMLElementExport style(*this, XML_NAMESPACE_STYLE, XML_STYLE, true, true); } SvxXMLNumRuleExport numRuleExport(*this); for (auto it = rRules.begin(); it != rRules.end(); ++it) { ExportRule(numRuleExport, *it); } } GetDocHandler()->endDocument(); } }; /** Dummy import context for style:style element that can just read the attributes needed to map name to display-name. Unfortunately the "real" context for this depends on some other things. The mapping is necessary to import the text:style-name attribute of the text:outline-level-style element. */ class StoredChapterNumberingDummyStyleContext : public SvXMLImportContext { public: StoredChapterNumberingDummyStyleContext( SvXMLImport & rImport, sal_uInt16 const nPrefix, OUString const& rLocalName, uno::Reference const& xAttrList) : SvXMLImportContext(rImport, nPrefix, rLocalName) { OUString name; OUString displayName; sal_uInt16 nFamily(0); for (sal_Int32 i = 0; i < xAttrList->getLength(); ++i) { OUString localName; sal_uInt16 const prefix(rImport.GetNamespaceMap().GetKeyByAttrName( xAttrList->getNameByIndex(i), &localName)); OUString const& rValue = xAttrList->getValueByIndex(i); if (XML_NAMESPACE_STYLE == prefix) { if (IsXMLToken(localName, XML_FAMILY)) { if (IsXMLToken(rValue, XML_TEXT)) { nFamily = XML_STYLE_FAMILY_TEXT_TEXT; } } else if (IsXMLToken(localName, XML_NAME)) { name = rValue; } else if (IsXMLToken(localName, XML_DISPLAY_NAME)) { displayName = rValue; } } } if (nFamily && !name.isEmpty() && !displayName.isEmpty()) { rImport.AddStyleDisplayName(nFamily, name, displayName); } } }; class StoredChapterNumberingImport; class StoredChapterNumberingRootContext : public SvXMLImportContext { private: SwChapterNumRules & m_rNumRules; size_t m_nCounter; ::std::vector> m_Contexts; public: StoredChapterNumberingRootContext( SwChapterNumRules & rNumRules, SvXMLImport & rImport, sal_uInt16 const nPrefix, OUString const& rLocalName) : SvXMLImportContext(rImport, nPrefix, rLocalName) , m_rNumRules(rNumRules) , m_nCounter(0) { } virtual void EndElement() SAL_OVERRIDE { assert(m_Contexts.size() < SwChapterNumRules::nMaxRules); for (auto iter = m_Contexts.begin(); iter != m_Contexts.end(); ++iter) { uno::Reference const xRule( new sw::StoredChapterNumberingRules(m_rNumRules, iter - m_Contexts.begin())); (*iter)->FillUnoNumRule(xRule); // TODO: xmloff's outline-style import seems to ignore this??? uno::Reference const xNamed(xRule, uno::UNO_QUERY); xNamed->setName((*iter)->GetDisplayName()); } } virtual SvXMLImportContext * CreateChildContext( sal_uInt16 const nPrefix, OUString const& rLocalName, uno::Reference const& xAttrList) SAL_OVERRIDE { if (XML_NAMESPACE_TEXT == nPrefix && IsXMLToken(rLocalName, XML_OUTLINE_STYLE)) { ++m_nCounter; if (m_nCounter <= SwChapterNumRules::nMaxRules) { SvxXMLListStyleContext *const pContext( new SvxXMLListStyleContext(GetImport(), nPrefix, rLocalName, xAttrList, true)); m_Contexts.push_back(pContext); return pContext; } } else if (XML_NAMESPACE_STYLE == nPrefix && IsXMLToken(rLocalName, XML_STYLE)) { return new StoredChapterNumberingDummyStyleContext( GetImport(), nPrefix, rLocalName, xAttrList); } return SvXMLImportContext::CreateChildContext( nPrefix, rLocalName, xAttrList); } }; class StoredChapterNumberingImport : public SvXMLImport { private: SwChapterNumRules & m_rNumRules; public: StoredChapterNumberingImport( uno::Reference const& xContext, SwChapterNumRules & rNumRules) : SvXMLImport(xContext, "sw::StoredChapterNumberingImport", SvXMLImportFlags::ALL) , m_rNumRules(rNumRules) { } virtual SvXMLImportContext * CreateContext( sal_uInt16 const nPrefix, OUString const& rLocalName, uno::Reference const& xAttrList) SAL_OVERRIDE { if (XML_NAMESPACE_OFFICE == nPrefix && IsXMLToken(rLocalName, XML_STYLES)) { return new StoredChapterNumberingRootContext(m_rNumRules, *this, nPrefix, rLocalName); } return SvXMLImport::CreateContext(nPrefix, rLocalName, xAttrList); } }; void ExportStoredChapterNumberingRules(SwChapterNumRules & rRules, SvStream & rStream, OUString const& rFileName) { uno::Reference const xContext( ::comphelper::getProcessComponentContext()); uno::Reference const xOutStream( new ::utl::OOutputStreamWrapper(rStream)); uno::Reference const xWriter( xml::sax::Writer::create(xContext)); uno::Reference const xADS(xWriter, uno::UNO_QUERY); xADS->setOutputStream(xOutStream); uno::Reference const xHandler( xWriter, uno::UNO_QUERY); StoredChapterNumberingExport exp(xContext, rFileName, xWriter); // if style name contains a space then name != display-name // ... and the import needs to map from name to display-name then! std::set charStyles; std::vector> numRules; for (size_t i = 0; i < SwChapterNumRules::nMaxRules; ++i) { if (SwNumRulesWithName const* pRule = rRules.GetRules(i)) { for (size_t j = 0; j < MAXLEVEL; ++j) { SwNumFmt const* pDummy(0); OUString const* pCharStyleName(0); pRule->GetNumFmt(j, pDummy, pCharStyleName); if (pCharStyleName && !pCharStyleName->isEmpty()) { charStyles.insert(*pCharStyleName); } } numRules.push_back(new StoredChapterNumberingRules(rRules, i)); } } try { exp.ExportRules(charStyles, numRules); } catch (uno::Exception const& e) { SAL_WARN("sw.ui", "ExportStoredChapterNumberingRules: exception: " << e.Message); } } void ImportStoredChapterNumberingRules(SwChapterNumRules & rRules, SvStream & rStream, OUString const& rFileName) { uno::Reference const xContext( ::comphelper::getProcessComponentContext()); uno::Reference const xInStream( new ::utl::OInputStreamWrapper(rStream)); uno::Reference const xParser( xml::sax::Parser::create(xContext)); uno::Reference const xHandler( new StoredChapterNumberingImport(xContext, rRules)); xParser->setDocumentHandler(xHandler); xml::sax::InputSource const source(xInStream, "", "", rFileName); try { xParser->parseStream(source); } catch (uno::Exception const& e) { SAL_WARN("sw.ui", "ImportStoredChapterNumberingRules: exception: " << e.Message); } } } // namespace sw /* vim:set shiftwidth=4 softtabstop=4 expandtab: */