LibreOffice Module sw (master)  1
StoredChapterNumbering.cxx
Go to the documentation of this file.
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/lang/IndexOutOfBoundsException.hpp>
17 #include <com/sun/star/util/MeasureUnit.hpp>
18 #include <com/sun/star/xml/sax/Writer.hpp>
19 
21 
22 #include <unotools/streamwrap.hxx>
23 
24 #include <xmloff/xmlnmspe.hxx>
25 #include <xmloff/xmltoken.hxx>
26 #include <xmloff/nmspmap.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>
32 
33 #include <vcl/svapp.hxx>
34 #include <tools/diagnose_ex.h>
35 
36 #include <unosett.hxx>
37 
38 
39 using namespace ::com::sun::star;
40 using namespace ::xmloff::token;
41 
42 namespace sw {
43 
45  : public ::cppu::WeakImplHelper<container::XNamed,container::XIndexReplace>
46 {
47 private:
48  // TODO in case this ever becomes accessible via API need an invalidate
50  sal_uInt16 const m_nIndex;
51 
53  {
54  SwNumRulesWithName const* pRules(m_rNumRules.GetRules(m_nIndex));
55  if (!pRules)
56  {
57  m_rNumRules.CreateEmptyNumRule(m_nIndex);
58  pRules = m_rNumRules.GetRules(m_nIndex);
59  assert(pRules);
60  }
61  return const_cast<SwNumRulesWithName*>(pRules);
62  }
63 
64 public:
66  SwChapterNumRules & rNumRules, sal_uInt16 const nIndex)
67  : m_rNumRules(rNumRules)
68  , m_nIndex(nIndex)
69  {
70  assert(m_nIndex < SwChapterNumRules::nMaxRules);
71  }
72 
73  // XNamed
74  virtual OUString SAL_CALL getName() override
75  {
77  SwNumRulesWithName const* pRules(m_rNumRules.GetRules(m_nIndex));
78  if (!pRules)
79  {
80  return OUString();
81  }
82  return pRules->GetName();
83  }
84 
85  virtual void SAL_CALL setName(OUString const& rName) override
86  {
88  SwNumRulesWithName *const pRules(GetOrCreateRules());
89  pRules->SetName(rName);
90  }
91 
92  // XElementAccess
93  virtual uno::Type SAL_CALL getElementType() override
94  {
95  return ::cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get();
96  }
97 
98  virtual ::sal_Bool SAL_CALL hasElements() override
99  {
100  return true;
101  }
102 
103  // XIndexAccess
104  virtual sal_Int32 SAL_CALL getCount() override
105  {
106  return MAXLEVEL;
107  }
108 
109  virtual uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override
110  {
111  if (nIndex < 0 || MAXLEVEL <= nIndex)
112  throw lang::IndexOutOfBoundsException();
113 
114  SolarMutexGuard g;
115  SwNumRulesWithName const* pRules(m_rNumRules.GetRules(m_nIndex));
116  if (!pRules)
117  {
118  return uno::Any();
119  }
120  SwNumFormat const* pNumFormat(nullptr);
121  OUString const* pCharStyleName(nullptr);
122  pRules->GetNumFormat(nIndex, pNumFormat, pCharStyleName);
123  if (!pNumFormat)
124  { // the dialog only fills in those levels that are non-default
125  return uno::Any(); // the export will ignore this level, yay
126  }
127  assert(pCharStyleName);
128  OUString dummy; // pass in empty HeadingStyleName - can't import anyway
129  uno::Sequence<beans::PropertyValue> const ret(
131  *pNumFormat, *pCharStyleName, &dummy, ""));
132  return uno::makeAny(ret);
133  }
134 
135  // XIndexReplace
136  virtual void SAL_CALL replaceByIndex(
137  sal_Int32 nIndex, uno::Any const& rElement) override
138  {
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);
145 
146  SolarMutexGuard g;
147  SwNumFormat aNumberFormat;
148  OUString charStyleName;
150  aNumberFormat,
151  charStyleName,
152  nullptr, nullptr, nullptr, nullptr, nullptr,
153  props);
154  SwNumRulesWithName *const pRules(GetOrCreateRules());
155  pRules->SetNumFormat(nIndex, aNumberFormat, charStyleName);
156  }
157 };
158 
159 namespace {
160 
161 class StoredChapterNumberingExport
162  : public SvXMLExport
163 {
164 public:
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)
171  {
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);
182  }
183 
184  virtual void ExportAutoStyles_() override {}
185  virtual void ExportMasterStyles_() override {}
186  virtual void ExportContent_() override {}
187 
188  void ExportRule(SvxXMLNumRuleExport & rExport,
189  uno::Reference<container::XIndexReplace> const& xRule)
190  {
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) );
196  if (bEncoded)
197  {
198  AddAttribute(XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, name);
199  }
200 
201  SvXMLElementExport aElem( *this, XML_NAMESPACE_TEXT,
202  XML_OUTLINE_STYLE, true, true );
203  rExport.exportLevelStyles(xRule, true);
204  }
205 
206  void ExportRules(
207  std::set<OUString> const& rCharStyles,
208  std::vector<uno::Reference<container::XIndexReplace>> const& rRules)
209  {
210  GetDocHandler()->startDocument();
211 
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));
227 
228  {
229  // let's just have an office:styles as a dummy root
231  XML_NAMESPACE_OFFICE, XML_STYLES, true, true);
232 
233  // horrible hack for char styles to get display-name mapping
234  for (const auto& rCharStyle : rCharStyles)
235  {
236  AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, XML_TEXT );
237  bool bEncoded(false);
238  AddAttribute( XML_NAMESPACE_STYLE, XML_NAME,
239  EncodeStyleName(rCharStyle, &bEncoded) );
240  if (bEncoded)
241  {
242  AddAttribute(XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, rCharStyle);
243  }
244 
245  SvXMLElementExport style(*this,
246  XML_NAMESPACE_STYLE, XML_STYLE, true, true);
247  }
248 
249  SvxXMLNumRuleExport numRuleExport(*this);
250 
251  for (const auto& rRule : rRules)
252  {
253  ExportRule(numRuleExport, rRule);
254  }
255  }
256 
257  GetDocHandler()->endDocument();
258  }
259 };
260 
267 class StoredChapterNumberingDummyStyleContext
268  : public SvXMLImportContext
269 {
270 public:
271  StoredChapterNumberingDummyStyleContext(
272  SvXMLImport & rImport,
273  uno::Reference<xml::sax::XFastAttributeList> const& xAttrList)
274  : SvXMLImportContext(rImport)
275  {
276  OUString name;
277  OUString displayName;
278  XmlStyleFamily nFamily(XmlStyleFamily::DATA_STYLE);
279 
280  sax_fastparser::FastAttributeList *pAttribList =
282 
283  for (auto &aIter : *pAttribList)
284  if (aIter.getToken() == (XML_NAMESPACE_STYLE | XML_FAMILY))
285  {
286  if (IsXMLToken(aIter.toString(), XML_TEXT))
287  nFamily = XmlStyleFamily::TEXT_TEXT;
288  else if (IsXMLToken(aIter.toString(), XML_NAME))
289  name = aIter.toString();
290  else if (IsXMLToken(aIter.toString(), XML_DISPLAY_NAME))
291  displayName = aIter.toString();
292  else
293  SAL_WARN("xmloff", "unknown value for style:family=" << aIter.toString());
294  }
295  else
296  SAL_WARN("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString());
297 
298  if (nFamily != XmlStyleFamily::DATA_STYLE && !name.isEmpty() && !displayName.isEmpty())
299  {
300  rImport.AddStyleDisplayName(nFamily, name, displayName);
301  }
302  }
303 };
304 
305 class StoredChapterNumberingImport;
306 
307 class StoredChapterNumberingRootContext
308  : public SvXMLImportContext
309 {
310 private:
311  SwChapterNumRules & m_rNumRules;
312  size_t m_nCounter;
313  std::vector<rtl::Reference<SvxXMLListStyleContext>> m_Contexts;
314 
315 public:
316  StoredChapterNumberingRootContext(
317  SwChapterNumRules & rNumRules, SvXMLImport & rImport)
318  : SvXMLImportContext(rImport)
319  , m_rNumRules(rNumRules)
320  , m_nCounter(0)
321  {
322  }
323 
324  virtual void SAL_CALL startFastElement(
325  sal_Int32 /*nElement*/,
326  const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) override {}
327 
328  virtual void SAL_CALL endFastElement(sal_Int32 /*Element*/) override
329  {
330  assert(m_Contexts.size() < SwChapterNumRules::nMaxRules);
331  for (auto iter = m_Contexts.begin(); iter != m_Contexts.end(); ++iter)
332  {
333  uno::Reference<container::XIndexReplace> const xRule(
334  new sw::StoredChapterNumberingRules(m_rNumRules,
335  iter - m_Contexts.begin()));
336  (*iter)->FillUnoNumRule(xRule);
337  // TODO: xmloff's outline-style import seems to ignore this???
338  uno::Reference<container::XNamed> const xNamed(xRule, uno::UNO_QUERY);
339  xNamed->setName((*iter)->GetDisplayName());
340  }
341  }
342 
343  virtual SvXMLImportContextRef CreateChildContext(
344  sal_uInt16 nPrefix,
345  const OUString& rLocalName,
346  const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override
347  {
348  if (XML_NAMESPACE_TEXT == nPrefix && IsXMLToken(rLocalName, XML_OUTLINE_STYLE))
349  {
350  ++m_nCounter;
351  if (m_nCounter <= SwChapterNumRules::nMaxRules)
352  {
353  SvxXMLListStyleContext *const pContext(
354  new SvxXMLListStyleContext(GetImport(),
355  nPrefix, rLocalName, xAttrList, true));
356  m_Contexts.emplace_back(pContext);
357  return pContext;
358  }
359  }
360  return nullptr;
361  }
362 
363  virtual css::uno::Reference<XFastContextHandler> SAL_CALL createFastChildContext(
364  sal_Int32 Element,
365  const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override
366  {
367  if (Element == XML_ELEMENT(TEXT, XML_OUTLINE_STYLE))
368  {
369  // handled in CreateChildContext
370  }
371  else if (Element == XML_ELEMENT(STYLE, XML_STYLE))
372  {
373  return new StoredChapterNumberingDummyStyleContext(GetImport(), xAttrList);
374  }
375 
376  return nullptr;
377  }
378 };
379 
380 class StoredChapterNumberingImport
381  : public SvXMLImport
382 {
383 private:
384  SwChapterNumRules & m_rNumRules;
385 
386 public:
387  StoredChapterNumberingImport(
388  uno::Reference<uno::XComponentContext> const& xContext,
389  SwChapterNumRules & rNumRules)
390  : SvXMLImport(xContext, "sw::StoredChapterNumberingImport", SvXMLImportFlags::ALL)
391  , m_rNumRules(rNumRules)
392  {
393  }
394 
395  virtual SvXMLImportContext *CreateFastContext( sal_Int32 Element,
396  const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ ) override
397  {
398  if (Element == XML_ELEMENT(OFFICE, XML_STYLES))
399  return new StoredChapterNumberingRootContext(m_rNumRules, *this);
400  return nullptr;
401  }
402 };
403 
404 }
405 
407  SvStream & rStream, OUString const& rFileName)
408 {
409  uno::Reference<uno::XComponentContext> const xContext(
411 
412  uno::Reference<io::XOutputStream> const xOutStream(
413  new ::utl::OOutputStreamWrapper(rStream));
414 
415  uno::Reference<xml::sax::XWriter> const xWriter(
416  xml::sax::Writer::create(xContext));
417 
418  xWriter->setOutputStream(xOutStream);
419 
420  rtl::Reference<StoredChapterNumberingExport> exp(new StoredChapterNumberingExport(xContext, rFileName, xWriter));
421 
422  // if style name contains a space then name != display-name
423  // ... and the import needs to map from name to display-name then!
424  std::set<OUString> charStyles;
425  std::vector<uno::Reference<container::XIndexReplace>> numRules;
426  for (size_t i = 0; i < SwChapterNumRules::nMaxRules; ++i)
427  {
428  if (SwNumRulesWithName const* pRule = rRules.GetRules(i))
429  {
430  for (size_t j = 0; j < MAXLEVEL; ++j)
431  {
432  SwNumFormat const* pDummy(nullptr);
433  OUString const* pCharStyleName(nullptr);
434  pRule->GetNumFormat(j, pDummy, pCharStyleName);
435  if (pCharStyleName && !pCharStyleName->isEmpty())
436  {
437  charStyles.insert(*pCharStyleName);
438  }
439  }
440  numRules.push_back(new StoredChapterNumberingRules(rRules, i));
441  }
442  }
443 
444  try
445  {
446  exp->ExportRules(charStyles, numRules);
447  }
448  catch (uno::Exception const&)
449  {
450  TOOLS_WARN_EXCEPTION("sw.ui", "ExportStoredChapterNumberingRules");
451  }
452 }
453 
455  SvStream & rStream, OUString const& rFileName)
456 {
457  uno::Reference<uno::XComponentContext> const xContext(
459 
460  uno::Reference<io::XInputStream> const xInStream(
461  new ::utl::OInputStreamWrapper(rStream));
462 
463  rtl::Reference<StoredChapterNumberingImport> const xImport(new StoredChapterNumberingImport(xContext, rRules));
464 
465  xml::sax::InputSource const source(xInStream, "", "", rFileName);
466 
467  try
468  {
469  xImport->parseStream(source);
470  }
471  catch (uno::Exception const&)
472  {
473  TOOLS_WARN_EXCEPTION("sw.ui", "ImportStoredChapterNumberingRules");
474  }
475 }
476 
477 } // namespace sw
478 
479 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
void SetNumFormat(size_t, SwNumFormat const &, OUString const &)
Definition: uinums.cxx:168
bool IsXMLToken(const OUString &rString, enum XMLTokenEnum eToken)
constexpr sal_uInt16 XML_NAMESPACE_STYLE
XML_DISPLAY_NAME
void CreateEmptyNumRule(sal_uInt16 nIdx)
Definition: uinums.cxx:89
XML_NAME
void ImportStoredChapterNumberingRules(SwChapterNumRules &rRules, SvStream &rStream, OUString const &rFileName)
Dialog to specify the properties of date form field.
void ExportStoredChapterNumberingRules(SwChapterNumRules &rRules, SvStream &rStream, OUString const &rFileName)
virtual uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override
void SetName(const OUString &rSet)
Definition: uinums.hxx:63
XmlStyleFamily
virtual OUString SAL_CALL getName() override
SvXMLImportFlags
const SwNumRulesWithName * GetRules(sal_uInt16 nIdx) const
Definition: uinums.hxx:100
const sal_uInt8 MAXLEVEL
Definition: swtypes.hxx:95
virtual ::sal_Bool SAL_CALL hasElements() override
static OUString getPrefixAndNameFromToken(sal_Int32 nToken)
#define TOOLS_WARN_EXCEPTION(area, stream)
int i
sal_Int32 & m_nCounter
static FastAttributeList * castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
dictionary props
virtual sal_Int32 SAL_CALL getCount() override
static css::uno::Sequence< css::beans::PropertyValue > GetPropertiesForNumFormat(const SwNumFormat &rFormat, OUString const &rCharFormatName, OUString const *pHeadingStyleName, OUString const &referer)
Definition: unosett.cxx:1310
XML_TEXT
static void SetPropertiesToNumFormat(SwNumFormat &aFormat, OUString &rCharStyleName, OUString *const pBulletFontName, OUString *const pHeadingStyleName, OUString *const pParagraphStyleName, SwDoc *const pDoc, SwDocShell *const pDocShell, css::uno::Sequence< css::beans::PropertyValue > const &rProperties)
Definition: unosett.cxx:1535
StoredChapterNumberingRules(SwChapterNumRules &rNumRules, sal_uInt16 const nIndex)
PointerStyles const styles[]
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
void exportLevelStyles(const css::uno::Reference< css::container::XIndexReplace > &xNumRule, bool bOutline=false)
virtual uno::Type SAL_CALL getElementType() override
#define XML_ELEMENT(prefix, name)
virtual void SAL_CALL replaceByIndex(sal_Int32 nIndex, uno::Any const &rElement) override
Reference< XComponentContext > getProcessComponentContext()
const char * name
void AddStyleDisplayName(XmlStyleFamily nFamily, const OUString &rName, const OUString &rDisplayName)
#define SAL_WARN(area, stream)
virtual void SAL_CALL setName(OUString const &rName) override
XML_FAMILY