Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : */
9 :
10 : #include <uinums.hxx>
11 :
12 : #include <cppuhelper/implbase.hxx>
13 :
14 : #include <com/sun/star/container/XIndexReplace.hpp>
15 : #include <com/sun/star/container/XNamed.hpp>
16 : #include <com/sun/star/io/XActiveDataSource.hpp>
17 : #include <com/sun/star/util/MeasureUnit.hpp>
18 : #include <com/sun/star/xml/sax/Parser.hpp>
19 : #include <com/sun/star/xml/sax/Writer.hpp>
20 :
21 : #include <comphelper/processfactory.hxx>
22 :
23 : #include <unotools/streamwrap.hxx>
24 :
25 : #include <xmloff/xmlnmspe.hxx>
26 : #include <xmloff/xmltoken.hxx>
27 : #include <xmloff/nmspmap.hxx>
28 : #include <xmloff/xmlexp.hxx>
29 : #include <xmloff/xmlnume.hxx>
30 : #include <xmloff/xmlimp.hxx>
31 : #include <xmloff/xmlictxt.hxx>
32 : #include <xmloff/xmlnumi.hxx>
33 :
34 : #include <vcl/svapp.hxx>
35 :
36 : #include <unosett.hxx>
37 :
38 :
39 : using namespace ::com::sun::star;
40 : using namespace ::xmloff::token;
41 :
42 : namespace sw {
43 :
44 0 : class StoredChapterNumberingRules
45 : : public ::cppu::WeakImplHelper<container::XNamed,container::XIndexReplace>
46 : {
47 : private:
48 : // TODO in case this ever becomes accessible via api need a invalidate
49 : SwChapterNumRules & m_rNumRules;
50 : sal_uInt16 const m_nIndex;
51 :
52 0 : SwNumRulesWithName * GetOrCreateRules()
53 : {
54 0 : SwNumRulesWithName const* pRules(m_rNumRules.GetRules(m_nIndex));
55 0 : if (!pRules)
56 : {
57 0 : m_rNumRules.CreateEmptyNumRule(m_nIndex);
58 0 : pRules = m_rNumRules.GetRules(m_nIndex);
59 : assert(pRules);
60 : }
61 0 : return const_cast<SwNumRulesWithName*>(pRules);
62 : }
63 :
64 : public:
65 0 : StoredChapterNumberingRules(
66 : SwChapterNumRules & rNumRules, sal_uInt16 const nIndex)
67 : : m_rNumRules(rNumRules)
68 0 : , m_nIndex(nIndex)
69 : {
70 : assert(m_nIndex < SwChapterNumRules::nMaxRules);
71 0 : }
72 :
73 : // XNamed
74 0 : virtual OUString SAL_CALL getName()
75 : throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
76 : {
77 0 : SolarMutexGuard g;
78 0 : SwNumRulesWithName const* pRules(m_rNumRules.GetRules(m_nIndex));
79 0 : if (!pRules)
80 : {
81 0 : return OUString();
82 : }
83 0 : return pRules->GetName();
84 : }
85 :
86 0 : virtual void SAL_CALL setName(OUString const& rName)
87 : throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
88 : {
89 0 : SolarMutexGuard g;
90 0 : SwNumRulesWithName *const pRules(GetOrCreateRules());
91 0 : pRules->SetName(rName);
92 0 : }
93 :
94 : // XElementAccess
95 0 : virtual uno::Type SAL_CALL getElementType()
96 : throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
97 : {
98 0 : return ::cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get();
99 : }
100 :
101 0 : virtual ::sal_Bool SAL_CALL hasElements()
102 : throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
103 : {
104 0 : return sal_True;
105 : }
106 :
107 : // XIndexAccess
108 0 : virtual sal_Int32 SAL_CALL getCount()
109 : throw (uno::RuntimeException, std::exception) SAL_OVERRIDE
110 : {
111 0 : return MAXLEVEL;
112 : }
113 :
114 0 : virtual uno::Any SAL_CALL getByIndex(sal_Int32 nIndex)
115 : throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException,
116 : uno::RuntimeException, std::exception) SAL_OVERRIDE
117 : {
118 0 : if (nIndex < 0 || MAXLEVEL <= nIndex)
119 0 : throw lang::IndexOutOfBoundsException();
120 :
121 0 : SolarMutexGuard g;
122 0 : SwNumRulesWithName const* pRules(m_rNumRules.GetRules(m_nIndex));
123 0 : if (!pRules)
124 : {
125 0 : return uno::Any();
126 : }
127 0 : SwNumFormat const* pNumFormat(0);
128 0 : OUString const* pCharStyleName(0);
129 0 : pRules->GetNumFormat(nIndex, pNumFormat, pCharStyleName);
130 0 : if (!pNumFormat)
131 : { // the dialog only fills in those levels that are non-default
132 0 : return uno::Any(); // the export will ignore this level, yay
133 : }
134 : assert(pCharStyleName);
135 0 : OUString dummy; // pass in empty HeadingStyleName - can't import anyway
136 : uno::Sequence<beans::PropertyValue> const ret(
137 : SwXNumberingRules::GetPropertiesForNumFormat(
138 0 : *pNumFormat, *pCharStyleName, &dummy));
139 0 : return uno::makeAny(ret);
140 : }
141 :
142 : // XIndexReplace
143 0 : virtual void SAL_CALL replaceByIndex(
144 : sal_Int32 nIndex, uno::Any const& rElement)
145 : throw (lang::IllegalArgumentException, lang::IndexOutOfBoundsException,
146 : lang::WrappedTargetException, uno::RuntimeException,
147 : std::exception) SAL_OVERRIDE
148 : {
149 0 : if (nIndex < 0 || MAXLEVEL <= nIndex)
150 0 : throw lang::IndexOutOfBoundsException();
151 0 : uno::Sequence<beans::PropertyValue> props;
152 0 : if (!(rElement >>= props))
153 : throw lang::IllegalArgumentException("invalid type",
154 0 : static_cast< ::cppu::OWeakObject*>(this), 1);
155 :
156 0 : SolarMutexGuard g;
157 0 : SwNumFormat aNumberFormat;
158 0 : OUString charStyleName;
159 : SwXNumberingRules::SetPropertiesToNumFormat(
160 : aNumberFormat,
161 : charStyleName,
162 : 0, 0, 0, 0, 0,
163 0 : props);
164 0 : SwNumRulesWithName *const pRules(GetOrCreateRules());
165 0 : pRules->SetNumFormat(nIndex, aNumberFormat, charStyleName);
166 0 : }
167 : };
168 :
169 0 : class StoredChapterNumberingExport
170 : : public SvXMLExport
171 : {
172 : public:
173 0 : StoredChapterNumberingExport(
174 : uno::Reference<uno::XComponentContext> const& xContext,
175 : OUString const& rFileName,
176 : uno::Reference<xml::sax::XDocumentHandler> const& xHandler)
177 : : SvXMLExport(xContext, "sw::StoredChapterNumberingExport", rFileName,
178 0 : util::MeasureUnit::CM, xHandler)
179 : {
180 0 : _GetNamespaceMap().Add(GetXMLToken(XML_NP_OFFICE),
181 0 : GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE);
182 0 : _GetNamespaceMap().Add(GetXMLToken(XML_NP_TEXT),
183 0 : GetXMLToken(XML_N_TEXT), XML_NAMESPACE_TEXT);
184 0 : _GetNamespaceMap().Add(GetXMLToken(XML_NP_STYLE),
185 0 : GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE);
186 0 : _GetNamespaceMap().Add(GetXMLToken(XML_NP_FO),
187 0 : GetXMLToken(XML_N_FO), XML_NAMESPACE_FO);
188 0 : _GetNamespaceMap().Add(GetXMLToken(XML_NP_SVG),
189 0 : GetXMLToken(XML_N_SVG), XML_NAMESPACE_SVG);
190 0 : }
191 :
192 0 : virtual void _ExportAutoStyles() SAL_OVERRIDE {}
193 0 : virtual void _ExportMasterStyles() SAL_OVERRIDE {}
194 0 : virtual void _ExportContent() SAL_OVERRIDE {}
195 :
196 0 : void ExportRule(SvxXMLNumRuleExport & rExport,
197 : uno::Reference<container::XIndexReplace> const& xRule)
198 : {
199 0 : uno::Reference<container::XNamed> const xNamed(xRule, uno::UNO_QUERY);
200 0 : OUString const name(xNamed->getName());
201 0 : bool bEncoded(false);
202 : AddAttribute( XML_NAMESPACE_STYLE, XML_NAME,
203 0 : EncodeStyleName(name, &bEncoded) );
204 0 : if (bEncoded)
205 : {
206 0 : AddAttribute(XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, name);
207 : }
208 :
209 : SvXMLElementExport aElem( *this, XML_NAMESPACE_TEXT,
210 0 : XML_OUTLINE_STYLE, true, true );
211 0 : rExport.exportLevelStyles(xRule, true);
212 0 : }
213 :
214 0 : void ExportRules(
215 : std::set<OUString> const& rCharStyles,
216 : std::vector<uno::Reference<container::XIndexReplace>> const& rRules)
217 : {
218 0 : GetDocHandler()->startDocument();
219 :
220 : AddAttribute(XML_NAMESPACE_NONE,
221 0 : _GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_OFFICE),
222 0 : _GetNamespaceMap().GetNameByKey(XML_NAMESPACE_OFFICE));
223 : AddAttribute(XML_NAMESPACE_NONE,
224 0 : _GetNamespaceMap().GetAttrNameByKey (XML_NAMESPACE_TEXT),
225 0 : _GetNamespaceMap().GetNameByKey(XML_NAMESPACE_TEXT));
226 : AddAttribute(XML_NAMESPACE_NONE,
227 0 : _GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_STYLE),
228 0 : _GetNamespaceMap().GetNameByKey(XML_NAMESPACE_STYLE));
229 : AddAttribute(XML_NAMESPACE_NONE,
230 0 : _GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_FO),
231 0 : _GetNamespaceMap().GetNameByKey(XML_NAMESPACE_FO));
232 : AddAttribute(XML_NAMESPACE_NONE,
233 0 : _GetNamespaceMap().GetAttrNameByKey(XML_NAMESPACE_SVG),
234 0 : _GetNamespaceMap().GetNameByKey(XML_NAMESPACE_SVG));
235 :
236 : {
237 : // let's just have a office:styles as a dummy root
238 : SvXMLElementExport styles(*this,
239 0 : XML_NAMESPACE_OFFICE, XML_STYLES, true, true);
240 :
241 : // horrible hack for char styles to get display-name mapping
242 0 : for (auto it = rCharStyles.begin(); it != rCharStyles.end(); ++it)
243 : {
244 0 : AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, XML_TEXT );
245 0 : bool bEncoded(false);
246 : AddAttribute( XML_NAMESPACE_STYLE, XML_NAME,
247 0 : EncodeStyleName(*it, &bEncoded) );
248 0 : if (bEncoded)
249 : {
250 0 : AddAttribute(XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, *it);
251 : }
252 :
253 : SvXMLElementExport style(*this,
254 0 : XML_NAMESPACE_STYLE, XML_STYLE, true, true);
255 0 : }
256 :
257 0 : SvxXMLNumRuleExport numRuleExport(*this);
258 :
259 0 : for (auto it = rRules.begin(); it != rRules.end(); ++it)
260 : {
261 0 : ExportRule(numRuleExport, *it);
262 0 : }
263 : }
264 :
265 0 : GetDocHandler()->endDocument();
266 0 : }
267 : };
268 :
269 : /** Dummy import context for style:style element that can just read the
270 : attributes needed to map name to display-name.
271 : Unfortunately the "real" context for this depends on some other things.
272 : The mapping is necessary to import the text:style-name attribute
273 : of the text:outline-level-style element.
274 : */
275 0 : class StoredChapterNumberingDummyStyleContext
276 : : public SvXMLImportContext
277 : {
278 : public:
279 0 : StoredChapterNumberingDummyStyleContext(
280 : SvXMLImport & rImport,
281 : sal_uInt16 const nPrefix, OUString const& rLocalName,
282 : uno::Reference<xml::sax::XAttributeList> const& xAttrList)
283 0 : : SvXMLImportContext(rImport, nPrefix, rLocalName)
284 : {
285 0 : OUString name;
286 0 : OUString displayName;
287 0 : sal_uInt16 nFamily(0);
288 0 : for (sal_Int32 i = 0; i < xAttrList->getLength(); ++i)
289 : {
290 0 : OUString localName;
291 0 : sal_uInt16 const prefix(rImport.GetNamespaceMap().GetKeyByAttrName(
292 0 : xAttrList->getNameByIndex(i), &localName));
293 0 : OUString const& rValue = xAttrList->getValueByIndex(i);
294 :
295 0 : if (XML_NAMESPACE_STYLE == prefix)
296 : {
297 0 : if (IsXMLToken(localName, XML_FAMILY))
298 : {
299 0 : if (IsXMLToken(rValue, XML_TEXT))
300 : {
301 0 : nFamily = XML_STYLE_FAMILY_TEXT_TEXT;
302 : }
303 : }
304 0 : else if (IsXMLToken(localName, XML_NAME))
305 : {
306 0 : name = rValue;
307 : }
308 0 : else if (IsXMLToken(localName, XML_DISPLAY_NAME))
309 : {
310 0 : displayName = rValue;
311 : }
312 : }
313 0 : }
314 0 : if (nFamily && !name.isEmpty() && !displayName.isEmpty())
315 : {
316 0 : rImport.AddStyleDisplayName(nFamily, name, displayName);
317 0 : }
318 0 : }
319 : };
320 :
321 : class StoredChapterNumberingImport;
322 :
323 0 : class StoredChapterNumberingRootContext
324 : : public SvXMLImportContext
325 : {
326 : private:
327 : SwChapterNumRules & m_rNumRules;
328 : size_t m_nCounter;
329 : ::std::vector<tools::SvRef<SvxXMLListStyleContext>> m_Contexts;
330 :
331 : public:
332 0 : StoredChapterNumberingRootContext(
333 : SwChapterNumRules & rNumRules, SvXMLImport & rImport,
334 : sal_uInt16 const nPrefix, OUString const& rLocalName)
335 : : SvXMLImportContext(rImport, nPrefix, rLocalName)
336 : , m_rNumRules(rNumRules)
337 0 : , m_nCounter(0)
338 : {
339 0 : }
340 :
341 0 : virtual void EndElement() SAL_OVERRIDE
342 : {
343 : assert(m_Contexts.size() < SwChapterNumRules::nMaxRules);
344 0 : for (auto iter = m_Contexts.begin(); iter != m_Contexts.end(); ++iter)
345 : {
346 : uno::Reference<container::XIndexReplace> const xRule(
347 : new sw::StoredChapterNumberingRules(m_rNumRules,
348 0 : iter - m_Contexts.begin()));
349 0 : (*iter)->FillUnoNumRule(xRule);
350 : // TODO: xmloff's outline-style import seems to ignore this???
351 0 : uno::Reference<container::XNamed> const xNamed(xRule, uno::UNO_QUERY);
352 0 : xNamed->setName((*iter)->GetDisplayName());
353 0 : }
354 0 : }
355 :
356 0 : virtual SvXMLImportContext * CreateChildContext(
357 : sal_uInt16 const nPrefix, OUString const& rLocalName,
358 : uno::Reference<xml::sax::XAttributeList> const& xAttrList) SAL_OVERRIDE
359 : {
360 0 : if (XML_NAMESPACE_TEXT == nPrefix && IsXMLToken(rLocalName, XML_OUTLINE_STYLE))
361 : {
362 0 : ++m_nCounter;
363 0 : if (m_nCounter <= SwChapterNumRules::nMaxRules)
364 : {
365 : SvxXMLListStyleContext *const pContext(
366 0 : new SvxXMLListStyleContext(GetImport(),
367 0 : nPrefix, rLocalName, xAttrList, true));
368 0 : m_Contexts.push_back(pContext);
369 0 : return pContext;
370 : }
371 : }
372 0 : else if (XML_NAMESPACE_STYLE == nPrefix && IsXMLToken(rLocalName, XML_STYLE))
373 : {
374 : return new StoredChapterNumberingDummyStyleContext(
375 0 : GetImport(), nPrefix, rLocalName, xAttrList);
376 : }
377 :
378 : return SvXMLImportContext::CreateChildContext(
379 0 : nPrefix, rLocalName, xAttrList);
380 : }
381 : };
382 :
383 0 : class StoredChapterNumberingImport
384 : : public SvXMLImport
385 : {
386 : private:
387 : SwChapterNumRules & m_rNumRules;
388 :
389 : public:
390 0 : StoredChapterNumberingImport(
391 : uno::Reference<uno::XComponentContext> const& xContext,
392 : SwChapterNumRules & rNumRules)
393 : : SvXMLImport(xContext, "sw::StoredChapterNumberingImport", SvXMLImportFlags::ALL)
394 0 : , m_rNumRules(rNumRules)
395 : {
396 0 : }
397 :
398 0 : virtual SvXMLImportContext * CreateContext(
399 : sal_uInt16 const nPrefix, OUString const& rLocalName,
400 : uno::Reference<xml::sax::XAttributeList> const& xAttrList) SAL_OVERRIDE
401 : {
402 0 : if (XML_NAMESPACE_OFFICE == nPrefix && IsXMLToken(rLocalName, XML_STYLES))
403 : {
404 : return new StoredChapterNumberingRootContext(m_rNumRules,
405 0 : *this, nPrefix, rLocalName);
406 : }
407 0 : return SvXMLImport::CreateContext(nPrefix, rLocalName, xAttrList);
408 : }
409 : };
410 :
411 0 : void ExportStoredChapterNumberingRules(SwChapterNumRules & rRules,
412 : SvStream & rStream, OUString const& rFileName)
413 : {
414 : uno::Reference<uno::XComponentContext> const xContext(
415 0 : ::comphelper::getProcessComponentContext());
416 :
417 : uno::Reference<io::XOutputStream> const xOutStream(
418 0 : new ::utl::OOutputStreamWrapper(rStream));
419 :
420 : uno::Reference<xml::sax::XWriter> const xWriter(
421 0 : xml::sax::Writer::create(xContext));
422 :
423 0 : uno::Reference<io::XActiveDataSource> const xADS(xWriter, uno::UNO_QUERY);
424 0 : xADS->setOutputStream(xOutStream);
425 :
426 : uno::Reference<xml::sax::XDocumentHandler> const xHandler(
427 0 : xWriter, uno::UNO_QUERY);
428 :
429 0 : StoredChapterNumberingExport exp(xContext, rFileName, xWriter);
430 :
431 : // if style name contains a space then name != display-name
432 : // ... and the import needs to map from name to display-name then!
433 0 : std::set<OUString> charStyles;
434 0 : std::vector<uno::Reference<container::XIndexReplace>> numRules;
435 0 : for (size_t i = 0; i < SwChapterNumRules::nMaxRules; ++i)
436 : {
437 0 : if (SwNumRulesWithName const* pRule = rRules.GetRules(i))
438 : {
439 0 : for (size_t j = 0; j < MAXLEVEL; ++j)
440 : {
441 0 : SwNumFormat const* pDummy(0);
442 0 : OUString const* pCharStyleName(0);
443 0 : pRule->GetNumFormat(j, pDummy, pCharStyleName);
444 0 : if (pCharStyleName && !pCharStyleName->isEmpty())
445 : {
446 0 : charStyles.insert(*pCharStyleName);
447 : }
448 : }
449 0 : numRules.push_back(new StoredChapterNumberingRules(rRules, i));
450 : }
451 : }
452 :
453 : try
454 : {
455 0 : exp.ExportRules(charStyles, numRules);
456 : }
457 0 : catch (uno::Exception const& e)
458 : {
459 : SAL_WARN("sw.ui",
460 : "ExportStoredChapterNumberingRules: exception: " << e.Message);
461 0 : }
462 0 : }
463 :
464 0 : void ImportStoredChapterNumberingRules(SwChapterNumRules & rRules,
465 : SvStream & rStream, OUString const& rFileName)
466 : {
467 : uno::Reference<uno::XComponentContext> const xContext(
468 0 : ::comphelper::getProcessComponentContext());
469 :
470 : uno::Reference<io::XInputStream> const xInStream(
471 0 : new ::utl::OInputStreamWrapper(rStream));
472 :
473 : uno::Reference<xml::sax::XParser> const xParser(
474 0 : xml::sax::Parser::create(xContext));
475 :
476 : uno::Reference<xml::sax::XDocumentHandler> const xHandler(
477 0 : new StoredChapterNumberingImport(xContext, rRules));
478 :
479 0 : xParser->setDocumentHandler(xHandler);
480 :
481 0 : xml::sax::InputSource const source(xInStream, "", "", rFileName);
482 :
483 : try
484 : {
485 0 : xParser->parseStream(source);
486 : }
487 0 : catch (uno::Exception const& e)
488 : {
489 : SAL_WARN("sw.ui",
490 : "ImportStoredChapterNumberingRules: exception: " << e.Message);
491 0 : }
492 0 : }
493 :
494 : } // namespace sw
495 :
496 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|