summaryrefslogtreecommitdiffstats
path: root/sw/source/uibase/config/StoredChapterNumbering.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/uibase/config/StoredChapterNumbering.cxx')
-rw-r--r--sw/source/uibase/config/StoredChapterNumbering.cxx476
1 files changed, 476 insertions, 0 deletions
diff --git a/sw/source/uibase/config/StoredChapterNumbering.cxx b/sw/source/uibase/config/StoredChapterNumbering.cxx
new file mode 100644
index 000000000..89b72040a
--- /dev/null
+++ b/sw/source/uibase/config/StoredChapterNumbering.cxx
@@ -0,0 +1,476 @@
+/* -*- 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 <uinums.hxx>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/container/XIndexReplace.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/util/MeasureUnit.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+
+#include <comphelper/processfactory.hxx>
+
+#include <unotools/streamwrap.hxx>
+
+#include <xmloff/xmlnmspe.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/nmspmap.hxx>
+#include <xmloff/xmlexp.hxx>
+#include <xmloff/xmlnume.hxx>
+#include <xmloff/xmlimp.hxx>
+#include <xmloff/xmlictxt.hxx>
+#include <xmloff/xmlnumi.hxx>
+
+#include <vcl/svapp.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <unosett.hxx>
+
+
+using namespace ::com::sun::star;
+using namespace ::xmloff::token;
+
+namespace sw {
+
+class StoredChapterNumberingRules
+ : public ::cppu::WeakImplHelper<container::XNamed,container::XIndexReplace>
+{
+private:
+ // TODO in case this ever becomes accessible via API need an 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<SwNumRulesWithName*>(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() 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) override
+ {
+ SolarMutexGuard g;
+ SwNumRulesWithName *const pRules(GetOrCreateRules());
+ pRules->SetName(rName);
+ }
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override
+ {
+ return ::cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get();
+ }
+
+ virtual ::sal_Bool SAL_CALL hasElements() override
+ {
+ return true;
+ }
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override
+ {
+ return MAXLEVEL;
+ }
+
+ virtual uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override
+ {
+ if (nIndex < 0 || MAXLEVEL <= nIndex)
+ throw lang::IndexOutOfBoundsException();
+
+ SolarMutexGuard g;
+ SwNumRulesWithName const* pRules(m_rNumRules.GetRules(m_nIndex));
+ if (!pRules)
+ {
+ return uno::Any();
+ }
+ SwNumFormat const* pNumFormat(nullptr);
+ OUString const* pCharStyleName(nullptr);
+ pRules->GetNumFormat(nIndex, pNumFormat, pCharStyleName);
+ if (!pNumFormat)
+ { // 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<beans::PropertyValue> const ret(
+ SwXNumberingRules::GetPropertiesForNumFormat(
+ *pNumFormat, *pCharStyleName, &dummy, ""));
+ return uno::makeAny(ret);
+ }
+
+ // XIndexReplace
+ virtual void SAL_CALL replaceByIndex(
+ sal_Int32 nIndex, uno::Any const& rElement) override
+ {
+ if (nIndex < 0 || MAXLEVEL <= nIndex)
+ throw lang::IndexOutOfBoundsException();
+ uno::Sequence<beans::PropertyValue> props;
+ if (!(rElement >>= props))
+ throw lang::IllegalArgumentException("invalid type",
+ static_cast< ::cppu::OWeakObject*>(this), 1);
+
+ SolarMutexGuard g;
+ SwNumFormat aNumberFormat;
+ OUString charStyleName;
+ SwXNumberingRules::SetPropertiesToNumFormat(
+ aNumberFormat,
+ charStyleName,
+ nullptr, nullptr, nullptr, nullptr,
+ props);
+ SwNumRulesWithName *const pRules(GetOrCreateRules());
+ pRules->SetNumFormat(nIndex, aNumberFormat, charStyleName);
+ }
+};
+
+namespace {
+
+class StoredChapterNumberingExport
+ : public SvXMLExport
+{
+public:
+ StoredChapterNumberingExport(
+ uno::Reference<uno::XComponentContext> const& xContext,
+ OUString const& rFileName,
+ uno::Reference<xml::sax::XDocumentHandler> 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_() override {}
+ virtual void ExportMasterStyles_() override {}
+ virtual void ExportContent_() override {}
+
+ void ExportRule(SvxXMLNumRuleExport & rExport,
+ uno::Reference<container::XIndexReplace> const& xRule)
+ {
+ uno::Reference<container::XNamed> 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<OUString> const& rCharStyles,
+ std::vector<uno::Reference<container::XIndexReplace>> 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 an 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 (const auto& rCharStyle : rCharStyles)
+ {
+ AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, XML_TEXT );
+ bool bEncoded(false);
+ AddAttribute( XML_NAMESPACE_STYLE, XML_NAME,
+ EncodeStyleName(rCharStyle, &bEncoded) );
+ if (bEncoded)
+ {
+ AddAttribute(XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, rCharStyle);
+ }
+
+ SvXMLElementExport style(*this,
+ XML_NAMESPACE_STYLE, XML_STYLE, true, true);
+ }
+
+ SvxXMLNumRuleExport numRuleExport(*this);
+
+ for (const auto& rRule : rRules)
+ {
+ ExportRule(numRuleExport, rRule);
+ }
+ }
+
+ 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,
+ uno::Reference<xml::sax::XFastAttributeList> const& xAttrList)
+ : SvXMLImportContext(rImport)
+ {
+ OUString name;
+ OUString displayName;
+ XmlStyleFamily nFamily(XmlStyleFamily::DATA_STYLE);
+
+ for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
+ if (aIter.getToken() == (XML_NAMESPACE_STYLE | XML_FAMILY))
+ {
+ if (IsXMLToken(aIter, XML_TEXT))
+ nFamily = XmlStyleFamily::TEXT_TEXT;
+ else if (IsXMLToken(aIter, XML_NAME))
+ name = aIter.toString();
+ else if (IsXMLToken(aIter, XML_DISPLAY_NAME))
+ displayName = aIter.toString();
+ else
+ SAL_WARN("xmloff", "unknown value for style:family=" << aIter.toString());
+ }
+ else
+ SAL_WARN("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString());
+
+ if (nFamily != XmlStyleFamily::DATA_STYLE && !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<rtl::Reference<SvxXMLListStyleContext>> m_Contexts;
+
+public:
+ StoredChapterNumberingRootContext(
+ SwChapterNumRules & rNumRules, SvXMLImport & rImport)
+ : SvXMLImportContext(rImport)
+ , m_rNumRules(rNumRules)
+ , m_nCounter(0)
+ {
+ }
+
+ virtual void SAL_CALL startFastElement(
+ sal_Int32 /*nElement*/,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) override {}
+
+ virtual void SAL_CALL endFastElement(sal_Int32 /*Element*/) override
+ {
+ assert(m_Contexts.size() < SwChapterNumRules::nMaxRules);
+ for (auto iter = m_Contexts.begin(); iter != m_Contexts.end(); ++iter)
+ {
+ uno::Reference<container::XIndexReplace> 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<container::XNamed> const xNamed(xRule, uno::UNO_QUERY);
+ xNamed->setName((*iter)->GetDisplayName());
+ }
+ }
+
+ virtual SvXMLImportContextRef CreateChildContext(
+ sal_uInt16 nPrefix,
+ const OUString& rLocalName,
+ const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) 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.emplace_back(pContext);
+ return pContext;
+ }
+ }
+ return nullptr;
+ }
+
+ virtual css::uno::Reference<XFastContextHandler> SAL_CALL createFastChildContext(
+ sal_Int32 Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override
+ {
+ if (Element == XML_ELEMENT(TEXT, XML_OUTLINE_STYLE))
+ {
+ // handled in CreateChildContext
+ }
+ else if (Element == XML_ELEMENT(STYLE, XML_STYLE))
+ {
+ return new StoredChapterNumberingDummyStyleContext(GetImport(), xAttrList);
+ }
+
+ return nullptr;
+ }
+};
+
+class StoredChapterNumberingImport
+ : public SvXMLImport
+{
+private:
+ SwChapterNumRules & m_rNumRules;
+
+public:
+ StoredChapterNumberingImport(
+ uno::Reference<uno::XComponentContext> const& xContext,
+ SwChapterNumRules & rNumRules)
+ : SvXMLImport(xContext, "sw::StoredChapterNumberingImport", SvXMLImportFlags::ALL)
+ , m_rNumRules(rNumRules)
+ {
+ }
+
+ virtual SvXMLImportContext *CreateFastContext( sal_Int32 Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ ) override
+ {
+ if (Element == XML_ELEMENT(OFFICE, XML_STYLES))
+ return new StoredChapterNumberingRootContext(m_rNumRules, *this);
+ return nullptr;
+ }
+};
+
+}
+
+void ExportStoredChapterNumberingRules(SwChapterNumRules & rRules,
+ SvStream & rStream, OUString const& rFileName)
+{
+ uno::Reference<uno::XComponentContext> const xContext(
+ ::comphelper::getProcessComponentContext());
+
+ uno::Reference<io::XOutputStream> const xOutStream(
+ new ::utl::OOutputStreamWrapper(rStream));
+
+ uno::Reference<xml::sax::XWriter> const xWriter(
+ xml::sax::Writer::create(xContext));
+
+ xWriter->setOutputStream(xOutStream);
+
+ rtl::Reference<StoredChapterNumberingExport> exp(new StoredChapterNumberingExport(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<OUString> charStyles;
+ std::vector<uno::Reference<container::XIndexReplace>> 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)
+ {
+ SwNumFormat const* pDummy(nullptr);
+ OUString const* pCharStyleName(nullptr);
+ pRule->GetNumFormat(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&)
+ {
+ TOOLS_WARN_EXCEPTION("sw.ui", "ExportStoredChapterNumberingRules");
+ }
+}
+
+void ImportStoredChapterNumberingRules(SwChapterNumRules & rRules,
+ SvStream & rStream, OUString const& rFileName)
+{
+ uno::Reference<uno::XComponentContext> const xContext(
+ ::comphelper::getProcessComponentContext());
+
+ uno::Reference<io::XInputStream> const xInStream(
+ new ::utl::OInputStreamWrapper(rStream));
+
+ rtl::Reference<StoredChapterNumberingImport> const xImport(new StoredChapterNumberingImport(xContext, rRules));
+
+ xml::sax::InputSource const source(xInStream, "", "", rFileName);
+
+ try
+ {
+ xImport->parseStream(source);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("sw.ui", "ImportStoredChapterNumberingRules");
+ }
+}
+
+} // namespace sw
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */