1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
12 #include <cppuhelper/implbase.hxx>
14 #include <com/sun/star/container/XIndexReplace.hpp>
15 #include <com/sun/star/container/XNamed.hpp>
16 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
17 #include <com/sun/star/util/MeasureUnit.hpp>
18 #include <com/sun/star/xml/sax/Writer.hpp>
20 #include <comphelper/processfactory.hxx>
22 #include <unotools/streamwrap.hxx>
24 #include <xmloff/xmlnamespace.hxx>
25 #include <xmloff/xmltoken.hxx>
26 #include <xmloff/namespacemap.hxx>
27 #include <xmloff/xmlexp.hxx>
28 #include <xmloff/xmlnume.hxx>
29 #include <xmloff/xmlimp.hxx>
30 #include <xmloff/xmlictxt.hxx>
31 #include <xmloff/xmlnumi.hxx>
33 #include <vcl/svapp.hxx>
34 #include <comphelper/diagnose_ex.hxx>
36 #include <unosett.hxx>
39 using namespace ::com::sun::star
;
40 using namespace ::xmloff::token
;
44 class StoredChapterNumberingRules
45 : public ::cppu::WeakImplHelper
<container::XNamed
,container::XIndexReplace
>
48 // TODO in case this ever becomes accessible via API need an invalidate
49 SwChapterNumRules
& m_rNumRules
;
50 sal_uInt16
const m_nIndex
;
52 SwNumRulesWithName
* GetOrCreateRules()
54 SwNumRulesWithName
const* pRules(m_rNumRules
.GetRules(m_nIndex
));
57 m_rNumRules
.CreateEmptyNumRule(m_nIndex
);
58 pRules
= m_rNumRules
.GetRules(m_nIndex
);
61 return const_cast<SwNumRulesWithName
*>(pRules
);
65 StoredChapterNumberingRules(
66 SwChapterNumRules
& rNumRules
, sal_uInt16
const nIndex
)
67 : m_rNumRules(rNumRules
)
70 assert(m_nIndex
< SwChapterNumRules::nMaxRules
);
74 virtual OUString SAL_CALL
getName() override
77 SwNumRulesWithName
const* pRules(m_rNumRules
.GetRules(m_nIndex
));
82 return pRules
->GetName();
85 virtual void SAL_CALL
setName(OUString
const& rName
) override
88 SwNumRulesWithName
*const pRules(GetOrCreateRules());
89 pRules
->SetName(rName
);
93 virtual uno::Type SAL_CALL
getElementType() override
95 return ::cppu::UnoType
<uno::Sequence
<beans::PropertyValue
>>::get();
98 virtual ::sal_Bool SAL_CALL
hasElements() override
104 virtual sal_Int32 SAL_CALL
getCount() override
109 virtual uno::Any SAL_CALL
getByIndex(sal_Int32 nIndex
) override
111 if (nIndex
< 0 || MAXLEVEL
<= nIndex
)
112 throw lang::IndexOutOfBoundsException();
115 SwNumRulesWithName
const* pRules(m_rNumRules
.GetRules(m_nIndex
));
120 SwNumFormat
const* pNumFormat(nullptr);
121 OUString
const* pCharStyleName(nullptr);
122 pRules
->GetNumFormat(nIndex
, pNumFormat
, pCharStyleName
);
124 { // the dialog only fills in those levels that are non-default
125 return uno::Any(); // the export will ignore this level, yay
127 assert(pCharStyleName
);
128 OUString dummy
; // pass in empty HeadingStyleName - can't import anyway
129 uno::Sequence
<beans::PropertyValue
> const ret(
130 SwXNumberingRules::GetPropertiesForNumFormat(
131 *pNumFormat
, *pCharStyleName
, &dummy
, ""));
132 return uno::Any(ret
);
136 virtual void SAL_CALL
replaceByIndex(
137 sal_Int32 nIndex
, uno::Any
const& rElement
) override
139 if (nIndex
< 0 || MAXLEVEL
<= nIndex
)
140 throw lang::IndexOutOfBoundsException();
141 uno::Sequence
<beans::PropertyValue
> props
;
142 if (!(rElement
>>= props
))
143 throw lang::IllegalArgumentException("invalid type",
144 static_cast< ::cppu::OWeakObject
*>(this), 1);
147 SwNumFormat aNumberFormat
;
148 OUString charStyleName
;
149 SwXNumberingRules::SetPropertiesToNumFormat(
152 nullptr, nullptr, nullptr, nullptr, nullptr,
154 SwNumRulesWithName
*const pRules(GetOrCreateRules());
155 pRules
->SetNumFormat(nIndex
, aNumberFormat
, charStyleName
);
161 class StoredChapterNumberingExport
165 StoredChapterNumberingExport(
166 uno::Reference
<uno::XComponentContext
> const& xContext
,
167 OUString
const& rFileName
,
168 uno::Reference
<xml::sax::XDocumentHandler
> const& xHandler
)
169 : SvXMLExport(xContext
, "sw::StoredChapterNumberingExport", rFileName
,
170 util::MeasureUnit::CM
, xHandler
)
172 GetNamespaceMap_().Add(GetXMLToken(XML_NP_OFFICE
),
173 GetXMLToken(XML_N_OFFICE
), XML_NAMESPACE_OFFICE
);
174 GetNamespaceMap_().Add(GetXMLToken(XML_NP_TEXT
),
175 GetXMLToken(XML_N_TEXT
), XML_NAMESPACE_TEXT
);
176 GetNamespaceMap_().Add(GetXMLToken(XML_NP_STYLE
),
177 GetXMLToken(XML_N_STYLE
), XML_NAMESPACE_STYLE
);
178 GetNamespaceMap_().Add(GetXMLToken(XML_NP_FO
),
179 GetXMLToken(XML_N_FO
), XML_NAMESPACE_FO
);
180 GetNamespaceMap_().Add(GetXMLToken(XML_NP_SVG
),
181 GetXMLToken(XML_N_SVG
), XML_NAMESPACE_SVG
);
184 virtual void ExportAutoStyles_() override
{}
185 virtual void ExportMasterStyles_() override
{}
186 virtual void ExportContent_() override
{}
188 void ExportRule(SvxXMLNumRuleExport
& rExport
,
189 uno::Reference
<container::XIndexReplace
> const& xRule
)
191 uno::Reference
<container::XNamed
> const xNamed(xRule
, uno::UNO_QUERY
);
192 OUString
const name(xNamed
->getName());
193 bool bEncoded(false);
194 AddAttribute( XML_NAMESPACE_STYLE
, XML_NAME
,
195 EncodeStyleName(name
, &bEncoded
) );
198 AddAttribute(XML_NAMESPACE_STYLE
, XML_DISPLAY_NAME
, name
);
201 SvXMLElementExport
aElem( *this, XML_NAMESPACE_TEXT
,
202 XML_OUTLINE_STYLE
, true, true );
203 rExport
.exportLevelStyles(xRule
, true);
207 std::set
<OUString
> const& rCharStyles
,
208 std::vector
<uno::Reference
<container::XIndexReplace
>> const& rRules
)
210 GetDocHandler()->startDocument();
212 AddAttribute(XML_NAMESPACE_NONE
,
213 GetNamespaceMap_().GetAttrNameByKey(XML_NAMESPACE_OFFICE
),
214 GetNamespaceMap_().GetNameByKey(XML_NAMESPACE_OFFICE
));
215 AddAttribute(XML_NAMESPACE_NONE
,
216 GetNamespaceMap_().GetAttrNameByKey (XML_NAMESPACE_TEXT
),
217 GetNamespaceMap_().GetNameByKey(XML_NAMESPACE_TEXT
));
218 AddAttribute(XML_NAMESPACE_NONE
,
219 GetNamespaceMap_().GetAttrNameByKey(XML_NAMESPACE_STYLE
),
220 GetNamespaceMap_().GetNameByKey(XML_NAMESPACE_STYLE
));
221 AddAttribute(XML_NAMESPACE_NONE
,
222 GetNamespaceMap_().GetAttrNameByKey(XML_NAMESPACE_FO
),
223 GetNamespaceMap_().GetNameByKey(XML_NAMESPACE_FO
));
224 AddAttribute(XML_NAMESPACE_NONE
,
225 GetNamespaceMap_().GetAttrNameByKey(XML_NAMESPACE_SVG
),
226 GetNamespaceMap_().GetNameByKey(XML_NAMESPACE_SVG
));
229 // let's just have an office:styles as a dummy root
230 SvXMLElementExport
styles(*this,
231 XML_NAMESPACE_OFFICE
, XML_STYLES
, true, true);
233 // horrible hack for char styles to get display-name mapping
234 for (const auto& rCharStyle
: rCharStyles
)
236 AddAttribute( XML_NAMESPACE_STYLE
, XML_FAMILY
, XML_TEXT
);
237 bool bEncoded(false);
238 AddAttribute( XML_NAMESPACE_STYLE
, XML_NAME
,
239 EncodeStyleName(rCharStyle
, &bEncoded
) );
242 AddAttribute(XML_NAMESPACE_STYLE
, XML_DISPLAY_NAME
, rCharStyle
);
245 SvXMLElementExport
style(*this,
246 XML_NAMESPACE_STYLE
, XML_STYLE
, true, true);
249 SvxXMLNumRuleExport
numRuleExport(*this);
251 for (const auto& rRule
: rRules
)
253 ExportRule(numRuleExport
, rRule
);
257 GetDocHandler()->endDocument();
261 /** Dummy import context for style:style element that can just read the
262 attributes needed to map name to display-name.
263 Unfortunately the "real" context for this depends on some other things.
264 The mapping is necessary to import the text:style-name attribute
265 of the text:outline-level-style element.
267 class StoredChapterNumberingDummyStyleContext
268 : public SvXMLImportContext
271 StoredChapterNumberingDummyStyleContext(
272 SvXMLImport
& rImport
,
273 uno::Reference
<xml::sax::XFastAttributeList
> const& xAttrList
)
274 : SvXMLImportContext(rImport
)
277 OUString displayName
;
278 XmlStyleFamily
nFamily(XmlStyleFamily::DATA_STYLE
);
280 for (auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
))
281 if (aIter
.getToken() == (XML_NAMESPACE_STYLE
| XML_FAMILY
))
283 if (IsXMLToken(aIter
, XML_TEXT
))
284 nFamily
= XmlStyleFamily::TEXT_TEXT
;
285 else if (IsXMLToken(aIter
, XML_NAME
))
286 name
= aIter
.toString();
287 else if (IsXMLToken(aIter
, XML_DISPLAY_NAME
))
288 displayName
= aIter
.toString();
290 SAL_WARN("xmloff", "unknown value for style:family=" << aIter
.toString());
293 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
295 if (nFamily
!= XmlStyleFamily::DATA_STYLE
&& !name
.isEmpty() && !displayName
.isEmpty())
297 rImport
.AddStyleDisplayName(nFamily
, name
, displayName
);
302 class StoredChapterNumberingImport
;
304 class StoredChapterNumberingRootContext
305 : public SvXMLImportContext
308 SwChapterNumRules
& m_rNumRules
;
310 std::vector
<rtl::Reference
<SvxXMLListStyleContext
>> m_Contexts
;
313 StoredChapterNumberingRootContext(
314 SwChapterNumRules
& rNumRules
, SvXMLImport
& rImport
)
315 : SvXMLImportContext(rImport
)
316 , m_rNumRules(rNumRules
)
321 virtual void SAL_CALL
endFastElement(sal_Int32
/*Element*/) override
323 assert(m_Contexts
.size() <= SwChapterNumRules::nMaxRules
);
324 for (auto iter
= m_Contexts
.begin(); iter
!= m_Contexts
.end(); ++iter
)
326 uno::Reference
<container::XIndexReplace
> const xRule(
327 new sw::StoredChapterNumberingRules(m_rNumRules
,
328 iter
- m_Contexts
.begin()));
329 (*iter
)->FillUnoNumRule(xRule
);
330 // TODO: xmloff's outline-style import seems to ignore this???
331 uno::Reference
<container::XNamed
> const xNamed(xRule
, uno::UNO_QUERY
);
332 xNamed
->setName((*iter
)->GetDisplayName());
336 virtual css::uno::Reference
<XFastContextHandler
> SAL_CALL
createFastChildContext(
338 const css::uno::Reference
< css::xml::sax::XFastAttributeList
> & xAttrList
) override
340 if (Element
== XML_ELEMENT(STYLE
, XML_STYLE
))
342 return new StoredChapterNumberingDummyStyleContext(GetImport(), xAttrList
);
344 else if (Element
== XML_ELEMENT(TEXT
, XML_OUTLINE_STYLE
))
347 if (m_nCounter
<= SwChapterNumRules::nMaxRules
)
349 SvxXMLListStyleContext
*const pContext(
350 new SvxXMLListStyleContext(GetImport(), true));
351 m_Contexts
.emplace_back(pContext
);
360 class StoredChapterNumberingImport
364 SwChapterNumRules
& m_rNumRules
;
367 StoredChapterNumberingImport(
368 uno::Reference
<uno::XComponentContext
> const& xContext
,
369 SwChapterNumRules
& rNumRules
)
370 : SvXMLImport(xContext
, "sw::StoredChapterNumberingImport", SvXMLImportFlags::ALL
)
371 , m_rNumRules(rNumRules
)
375 virtual SvXMLImportContext
*CreateFastContext( sal_Int32 Element
,
376 const css::uno::Reference
< css::xml::sax::XFastAttributeList
> & /*xAttrList*/ ) override
378 if (Element
== XML_ELEMENT(OFFICE
, XML_STYLES
))
379 return new StoredChapterNumberingRootContext(m_rNumRules
, *this);
386 void ExportStoredChapterNumberingRules(SwChapterNumRules
& rRules
,
387 SvStream
& rStream
, OUString
const& rFileName
)
389 uno::Reference
<uno::XComponentContext
> const xContext(
390 ::comphelper::getProcessComponentContext());
392 uno::Reference
<io::XOutputStream
> const xOutStream(
393 new ::utl::OOutputStreamWrapper(rStream
));
395 uno::Reference
<xml::sax::XWriter
> const xWriter(
396 xml::sax::Writer::create(xContext
));
398 xWriter
->setOutputStream(xOutStream
);
400 rtl::Reference
<StoredChapterNumberingExport
> exp(new StoredChapterNumberingExport(xContext
, rFileName
, xWriter
));
402 // if style name contains a space then name != display-name
403 // ... and the import needs to map from name to display-name then!
404 std::set
<OUString
> charStyles
;
405 std::vector
<uno::Reference
<container::XIndexReplace
>> numRules
;
406 for (size_t i
= 0; i
< SwChapterNumRules::nMaxRules
; ++i
)
408 if (SwNumRulesWithName
const* pRule
= rRules
.GetRules(i
))
410 for (size_t j
= 0; j
< MAXLEVEL
; ++j
)
412 SwNumFormat
const* pDummy(nullptr);
413 OUString
const* pCharStyleName(nullptr);
414 pRule
->GetNumFormat(j
, pDummy
, pCharStyleName
);
415 if (pCharStyleName
&& !pCharStyleName
->isEmpty())
417 charStyles
.insert(*pCharStyleName
);
420 numRules
.push_back(new StoredChapterNumberingRules(rRules
, i
));
426 exp
->ExportRules(charStyles
, numRules
);
428 catch (uno::Exception
const&)
430 TOOLS_WARN_EXCEPTION("sw.ui", "ExportStoredChapterNumberingRules");
434 void ImportStoredChapterNumberingRules(SwChapterNumRules
& rRules
,
435 SvStream
& rStream
, OUString
const& rFileName
)
437 uno::Reference
<uno::XComponentContext
> const xContext(
438 ::comphelper::getProcessComponentContext());
440 uno::Reference
<io::XInputStream
> const xInStream(
441 new ::utl::OInputStreamWrapper(rStream
));
443 rtl::Reference
<StoredChapterNumberingImport
> const xImport(new StoredChapterNumberingImport(xContext
, rRules
));
445 xml::sax::InputSource
const source(xInStream
, "", "", rFileName
);
449 xImport
->parseStream(source
);
451 catch (uno::Exception
const&)
453 TOOLS_WARN_EXCEPTION("sw.ui", "ImportStoredChapterNumberingRules");
459 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */