LibreOffice Module xmloff (master)  1
XMLTextMarkImportContext.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  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
21 
22 
23 #include <rtl/ustring.hxx>
24 #include <sal/log.hxx>
25 #include <osl/diagnose.h>
26 #include <xmloff/xmluconv.hxx>
27 #include <xmloff/xmltoken.hxx>
28 #include <xmloff/xmlimp.hxx>
29 #include <xmloff/namespacemap.hxx>
30 #include <xmloff/xmlnamespace.hxx>
31 #include <xmloff/odffields.hxx>
32 #include <xmloff/xmlement.hxx>
33 #include <com/sun/star/frame/XModel.hpp>
34 #include <com/sun/star/xml/sax/XAttributeList.hpp>
35 #include <com/sun/star/text/ControlCharacter.hpp>
36 #include <com/sun/star/text/XTextContent.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
39 #include <com/sun/star/container/XNamed.hpp>
40 #include <com/sun/star/rdf/XMetadatable.hpp>
41 
42 #include <com/sun/star/text/XFormField.hpp>
43 
44 #include <RDFaImportHelper.hxx>
45 
46 
47 using namespace ::com::sun::star;
48 using namespace ::com::sun::star::text;
49 using namespace ::com::sun::star::uno;
50 using namespace ::com::sun::star::beans;
51 using namespace ::com::sun::star::lang;
52 using namespace ::com::sun::star::container;
53 using namespace ::com::sun::star::xml::sax;
54 using namespace ::xmloff::token;
55 
56 
58  SvXMLImport& rImport,
59  XMLTextImportHelper& rHlp ) :
60  SvXMLImportContext(rImport),
61  rHelper(rHlp)
62 {
63 }
64 
65 
66 void XMLFieldParamImportContext::startFastElement(sal_Int32 /*nElement*/, const css::uno::Reference< css::xml::sax::XFastAttributeList> & xAttrList)
67 {
68  OUString sName;
69  OUString sValue;
70 
71  for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
72  {
73  switch (aIter.getToken())
74  {
75  case XML_ELEMENT(FIELD, XML_NAME):
76  sName = aIter.toString();
77  break;
79  sValue = aIter.toString();
80  break;
81  default:
82  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
83  }
84  }
85  if (rHelper.hasCurrentFieldCtx() && !sName.isEmpty()) {
86  rHelper.addFieldParam(sName, sValue);
87  }
88 }
89 
90 
92  SvXMLImport& rImport,
93  XMLTextImportHelper& rHlp,
94  uno::Reference<uno::XInterface> & io_rxCrossRefHeadingBookmark )
95  : SvXMLImportContext(rImport)
96  , m_rHelper(rHlp)
97  , m_rxCrossRefHeadingBookmark(io_rxCrossRefHeadingBookmark)
98  , m_bHaveAbout(false)
99 {
100 }
101 
102 namespace {
103 
104 enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd,
105  TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd,
106  TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkEnd
107  };
108 
109 }
110 
112 {
113  { XML_REFERENCE_MARK, TypeReference },
114  { XML_REFERENCE_MARK_START, TypeReferenceStart },
115  { XML_REFERENCE_MARK_END, TypeReferenceEnd },
117  { XML_BOOKMARK_START, TypeBookmarkStart },
118  { XML_BOOKMARK_END, TypeBookmarkEnd },
119  { XML_FIELDMARK, TypeFieldmark },
120  { XML_FIELDMARK_START, TypeFieldmarkStart },
121  { XML_FIELDMARK_END, TypeFieldmarkEnd },
123 };
124 
125 
126 static const sal_Unicode *lcl_getFormFieldmarkName(std::u16string_view name)
127 {
128  if (name == ODF_FORMCHECKBOX ||
129  name == u"msoffice.field.FORMCHECKBOX" ||
130  name == u"ecma.office-open-xml.field.FORMCHECKBOX")
131  return ODF_FORMCHECKBOX;
132  else if (name == ODF_FORMDROPDOWN ||
133  name == u"ecma.office-open-xml.field.FORMDROPDOWN")
134  return ODF_FORMDROPDOWN;
135  else
136  return nullptr;
137 }
138 
139 static OUString lcl_getFieldmarkName(OUString const& name)
140 {
141  if (name == "msoffice.field.FORMTEXT" ||
142  name == "ecma.office-open-xml.field.FORMTEXT")
143  return ODF_FORMTEXT;
144  else
145  return name;
146 }
147 
148 
150  const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
151 {
152  if (!FindName(xAttrList))
153  {
154  m_sBookmarkName.clear();
155  }
156 
157  if ((nElement & TOKEN_MASK) == XML_FIELDMARK_START ||
158  (nElement & TOKEN_MASK) == XML_FIELDMARK)
159  {
160  if (m_sBookmarkName.isEmpty())
161  {
162  m_sBookmarkName = "Unknown";
163  }
165  }
166 
167  if ((nElement & TOKEN_MASK) == XML_BOOKMARK_START)
168  {
169  const OUString sHidden = xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_HIDDEN));
170  const OUString sCondition = xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_CONDITION));
171  m_rHelper.setBookmarkAttributes(m_sBookmarkName, sHidden == "true", sCondition);
172  }
173 }
174 
175 static auto InsertFieldmark(SvXMLImport & rImport,
176  XMLTextImportHelper & rHelper, OUString const& rName) -> void
177 {
178  assert(rHelper.hasCurrentFieldCtx()); // was set up in StartElement()
179 
180  // fdo#86795 check if it's actually a checkbox first
181  OUString const type(rHelper.getCurrentFieldType());
182  OUString const fieldmarkTypeName = lcl_getFieldmarkName(type);
183  if (fieldmarkTypeName == ODF_FORMCHECKBOX ||
184  fieldmarkTypeName == ODF_FORMDROPDOWN)
185  { // sw can't handle checkbox with start+end
186  SAL_INFO("xmloff.text", "invalid fieldmark-start/fieldmark-end ignored");
187  return;
188  }
189 
190  Reference<XTextContent> const xContent = XMLTextMarkImportContext::CreateAndInsertMark(
191  rImport, "com.sun.star.text.Fieldmark",
192  rName, rHelper.GetCursorAsRange());
193 
194  if (!xContent.is())
195  return;
196 
197  // setup fieldmark...
198  Reference<text::XFormField> const xFormField(xContent, UNO_QUERY);
199  assert(xFormField.is());
200  xFormField->setFieldType(fieldmarkTypeName);
201  rHelper.setCurrentFieldParamsTo(xFormField);
202  // move cursor after setFieldType as that may delete/re-insert
203  rHelper.GetCursor()->gotoRange(xContent->getAnchor()->getEnd(), false);
204  rHelper.GetCursor()->goLeft(1, false); // move before CH_TXT_ATR_FIELDEND
205  // tdf#129520: AppendTextNode() ignores the content index!
206  // plan B: insert a spurious paragraph break now and join
207  // it in PopFieldmark()!
208  rHelper.GetText()->insertControlCharacter(rHelper.GetCursor(),
209  text::ControlCharacter::PARAGRAPH_BREAK, false);
210  rHelper.GetCursor()->goLeft(1, false); // back to previous paragraph
211 }
212 
213 static auto PopFieldmark(XMLTextImportHelper & rHelper) -> void
214 {
215  // can't verify name because it's not written as an attribute...
216  uno::Reference<text::XTextContent> const xField(rHelper.popFieldCtx(),
217  uno::UNO_QUERY);
218  if (!xField.is())
219  return;
220 
221  if (rHelper.GetText() == xField->getAnchor()->getText())
222  {
223  try
224  { // skip CH_TXT_ATR_FIELDEND
225  rHelper.GetCursor()->goRight(1, true);
226  rHelper.GetCursor()->setString(OUString()); // undo AppendTextNode from InsertFieldmark
227  rHelper.GetCursor()->gotoRange(xField->getAnchor()->getEnd(), false);
228  }
229  catch (uno::Exception const&)
230  {
231  assert(false); // must succeed
232  }
233  }
234  else
235  {
236  SAL_INFO("xmloff.text", "fieldmark has invalid positions");
237  // could either dispose it or leave it to end at the end of the document?
238  xField->dispose();
239  }
240 }
241 
243 {
244  static constexpr OUStringLiteral sAPI_bookmark = u"com.sun.star.text.Bookmark";
245 
246  lcl_MarkType nTmp{};
247  if (!SvXMLUnitConverter::convertEnum(nTmp, SvXMLImport::getNameFromToken(nElement), lcl_aMarkTypeMap))
248  return;
249 
250  if (m_sBookmarkName.isEmpty() && TypeFieldmarkEnd != nTmp)
251  return;
252 
253  switch (nTmp)
254  {
255  case TypeReference:
256  // export point reference mark
258  "com.sun.star.text.ReferenceMark",
260  m_rHelper.GetCursorAsRange()->getStart());
261  break;
262 
263  case TypeBookmark:
264  {
265  // tdf#94804: detect duplicate heading cross reference bookmarks
266  if (m_sBookmarkName.startsWith("__RefHeading__"))
267  {
269  {
270  uno::Reference<container::XNamed> const xNamed(
271  m_rxCrossRefHeadingBookmark, uno::UNO_QUERY);
273  m_sBookmarkName, xNamed->getName());
274  break; // don't insert
275  }
276  }
277  }
278  [[fallthrough]];
279  case TypeFieldmark:
280  {
281  const sal_Unicode *formFieldmarkName=lcl_getFormFieldmarkName(m_sFieldName);
282  bool bImportAsField = (nTmp==TypeFieldmark && formFieldmarkName!=nullptr); //@TODO handle abbreviation cases...
283  // export point bookmark
284  const Reference<XInterface> xContent(
286  (bImportAsField ? OUString("com.sun.star.text.FormFieldmark") : OUString(sAPI_bookmark)),
288  m_rHelper.GetCursorAsRange()->getStart(),
289  m_sXmlId) );
290  if (nTmp==TypeFieldmark) {
291  if (xContent.is() && bImportAsField) {
292  // setup fieldmark...
293  Reference< css::text::XFormField> xFormField(xContent, UNO_QUERY);
294  xFormField->setFieldType(OUString(formFieldmarkName));
295  if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) {
297  }
298  }
300  }
301  if (TypeBookmark == nTmp
302  && m_sBookmarkName.startsWith("__RefHeading__"))
303  {
304  assert(xContent.is());
305  m_rxCrossRefHeadingBookmark = xContent;
306  }
307  }
308  break;
309 
310  case TypeBookmarkStart:
311  // save XTextRange for later construction of bookmark
312  {
313  std::shared_ptr< ::xmloff::ParsedRDFaAttributes >
314  xRDFaAttributes;
315  if (m_bHaveAbout && TypeBookmarkStart == nTmp)
316  {
317  xRDFaAttributes =
318  GetImport().GetRDFaImportHelper().ParseRDFa(
321  }
324  m_rHelper.GetCursorAsRange()->getStart(),
325  m_sXmlId, xRDFaAttributes);
326  }
327  break;
328 
329  case TypeBookmarkEnd:
330  {
331  // tdf#94804: detect duplicate heading cross reference bookmarks
332  if (m_sBookmarkName.startsWith("__RefHeading__"))
333  {
335  {
336  uno::Reference<container::XNamed> const xNamed(
337  m_rxCrossRefHeadingBookmark, uno::UNO_QUERY);
339  m_sBookmarkName, xNamed->getName());
340  break; // don't insert
341  }
342  }
343 
344  // get old range, and construct
345  Reference<XTextRange> xStartRange;
346  std::shared_ptr< ::xmloff::ParsedRDFaAttributes >
347  xRDFaAttributes;
349  m_sBookmarkName, xStartRange,
350  m_sXmlId, xRDFaAttributes))
351  {
352  Reference<XTextRange> xEndRange(
353  m_rHelper.GetCursorAsRange()->getStart());
354 
355  // check if beginning and end are in same XText
356  if (xStartRange.is() && xEndRange.is() && xStartRange->getText() == xEndRange->getText())
357  {
358  // create range for insertion
359  Reference<XTextCursor> xInsertionCursor =
360  m_rHelper.GetText()->createTextCursorByRange(
361  xEndRange);
362  try {
363  xInsertionCursor->gotoRange(xStartRange, true);
364  } catch (uno::Exception&) {
365  OSL_ENSURE(false,
366  "cannot go to end position of bookmark");
367  }
368 
369  //DBG_ASSERT(! xInsertionCursor->isCollapsed(),
370  // "we want no point mark");
371  // can't assert, because someone could
372  // create a file with subsequence
373  // start/end elements
374 
375  Reference<XInterface> xContent;
376  // insert reference
377  xContent = CreateAndInsertMark(GetImport(),
378  sAPI_bookmark,
380  xInsertionCursor,
381  m_sXmlId);
382  if (xRDFaAttributes)
383  {
384  const Reference<rdf::XMetadatable>
385  xMeta(xContent, UNO_QUERY);
386  GetImport().GetRDFaImportHelper().AddRDFa(
387  xMeta, xRDFaAttributes);
388  }
389  const Reference<XPropertySet> xPropertySet(xContent, UNO_QUERY);
390  if (xPropertySet.is())
391  {
392  xPropertySet->setPropertyValue("BookmarkHidden", uno::Any(m_rHelper.getBookmarkHidden(m_sBookmarkName)));
393  xPropertySet->setPropertyValue("BookmarkCondition", uno::Any(m_rHelper.getBookmarkCondition(m_sBookmarkName)));
394  }
395  if (m_sBookmarkName.startsWith("__RefHeading__"))
396  {
397  assert(xContent.is());
398  m_rxCrossRefHeadingBookmark = xContent;
399  }
400  }
401  // else: beginning/end in different XText -> ignore!
402  }
403  // else: no start found -> ignore!
404  break;
405  }
406  case TypeFieldmarkStart: // no separator, so insert at start
407  {
409  break;
410  }
411  case TypeFieldmarkEnd:
412  {
414  break;
415  }
416  case TypeReferenceStart:
417  case TypeReferenceEnd:
418  OSL_FAIL("reference start/end are handled in txtparai !");
419  break;
420 
421  default:
422  OSL_FAIL("unknown mark type");
423  break;
424  }
425 }
426 
427 css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextMarkImportContext::createFastChildContext(
428  sal_Int32 ,
429  const css::uno::Reference< css::xml::sax::XFastAttributeList >& )
430 {
432 }
433 
434 
436  SvXMLImport& rImport,
437  const OUString& sServiceName,
438  const OUString& sMarkName,
439  const Reference<XTextRange> & rRange,
440  const OUString& i_rXmlId)
441 {
442  // create mark
443  const Reference<XMultiServiceFactory> xFactory(rImport.GetModel(),
444  UNO_QUERY);
445  Reference<XInterface> xIfc;
446 
447  if (xFactory.is())
448  {
449  xIfc = xFactory->createInstance(sServiceName);
450 
451  if (!xIfc.is())
452  {
453  OSL_FAIL("CreateAndInsertMark: cannot create service?");
454  return nullptr;
455  }
456 
457  // set name (unless there is no name (text:meta))
458  const Reference<XNamed> xNamed(xIfc, UNO_QUERY);
459  if (xNamed.is())
460  {
461  xNamed->setName(sMarkName);
462  }
463  else
464  {
465  if (!sMarkName.isEmpty())
466  {
467  OSL_FAIL("name given, but XNamed not supported?");
468  return nullptr;
469  }
470  }
471 
472  // cast to XTextContent and attach to document
473  const Reference<XTextContent> xTextContent(xIfc, UNO_QUERY);
474  if (xTextContent.is())
475  {
476  try
477  {
478  // if inserting marks, bAbsorb==sal_False will cause
479  // collapsing of the given XTextRange.
480  rImport.GetTextImport()->GetText()->insertTextContent(rRange,
481  xTextContent, true);
482 
483  // xml:id for RDF metadata -- after insertion!
484  rImport.SetXmlId(xIfc, i_rXmlId);
485 
486  return xTextContent;
487  }
488  catch (css::lang::IllegalArgumentException &)
489  {
490  OSL_FAIL("CreateAndInsertMark: cannot insert?");
491  return nullptr;
492  }
493  }
494  }
495  return nullptr;
496 }
497 
499  const Reference<XFastAttributeList> & xAttrList)
500 {
501  bool bNameOK = false;
502 
503  // find name attribute first
504  for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
505  {
506  OUString sValue = aIter.toString();
507  switch(aIter.getToken())
508  {
509  case XML_ELEMENT(TEXT, XML_NAME):
510  m_sBookmarkName = sValue;
511  bNameOK = true;
512  break;
513  case XML_ELEMENT(XML, XML_ID):
514  m_sXmlId = sValue;
515  break;
516  // RDFa
517  case XML_ELEMENT(XHTML, XML_ABOUT):
518  m_sAbout = sValue;
519  m_bHaveAbout = true;
520  break;
521  case XML_ELEMENT(XHTML, XML_PROPERTY):
522  m_sProperty = sValue;
523  break;
524  case XML_ELEMENT(XHTML, XML_CONTENT):
525  m_sContent = sValue;
526  break;
527  case XML_ELEMENT(XHTML, XML_DATATYPE):
528  m_sDatatype = sValue;
529  break;
530  case XML_ELEMENT(FIELD, XML_TYPE):
531  m_sFieldName = sValue;
532  break;
533  default:
534  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
535  }
536  }
537 
538  return bNameOK;
539 }
540 
541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SAL_DLLPRIVATE::xmloff::RDFaImportHelper & GetRDFaImportHelper()
do not dllexport this; only for advanced cases (bookmark-start)
Definition: xmlimp.cxx:1876
void AddCrossRefHeadingMapping(OUString const &rFrom, OUString const &rTo)
Definition: txtimp.cxx:2373
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:56
#define ODF_FORMCHECKBOX
Definition: odffields.hxx:26
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
rtl::Reference< XMLTextImportHelper > const & GetTextImport()
Definition: xmlimp.hxx:595
SvXMLEnumMapEntry< lcl_MarkType > const lcl_aMarkTypeMap[]
static auto InsertFieldmark(SvXMLImport &rImport, XMLTextImportHelper &rHelper, OUString const &rName) -> void
sal_uInt16 sal_Unicode
virtual void SAL_CALL endFastElement(sal_Int32 nElement) override
endFastElement is called before a context will be destructed, but after an elements context has been ...
static css::uno::Reference< css::text::XTextContent > CreateAndInsertMark(SvXMLImport &rImport, const OUString &sServiceName, const OUString &sMarkName, const css::uno::Reference< css::text::XTextRange > &rRange, const OUString &i_rXmlId=OUString())
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
#define XMLOFF_WARN_UNKNOWN(area, rIter)
Definition: xmlictxt.hxx:110
const OUString & getBookmarkCondition(OUString const &bookmark) const
Definition: txtimp.cxx:2440
virtual void SAL_CALL startFastElement(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
void addFieldParam(const OUString &name, const OUString &value)
Definition: txtimp.cxx:2125
const char * sName
css::uno::Reference< css::text::XText > & GetText()
Definition: txtimp.cxx:211
virtual void SAL_CALL startFastElement(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
char const sHidden[]
css::uno::Reference< css::text::XTextRange > & GetCursorAsRange()
Definition: txtimp.cxx:221
static OUString lcl_getFieldmarkName(OUString const &name)
bool FindAndRemoveBookmarkStartRange(const OUString &sName, css::uno::Reference< css::text::XTextRange > &o_rRange, OUString &o_rXmlId, std::shared_ptr< ::xmloff::ParsedRDFaAttributes > &o_rpRDFaAttributes)
process the start of a range reference
Definition: txtimp.cxx:2076
float u
static auto PopFieldmark(XMLTextImportHelper &rHelper) -> void
bool getBookmarkHidden(OUString const &bookmark) const
Definition: txtimp.cxx:2435
bool hasCurrentFieldCtx() const
Definition: txtimp.cxx:2147
bool FindName(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
static const sal_Unicode * lcl_getFormFieldmarkName(std::u16string_view name)
void SetXmlId(css::uno::Reference< css::uno::XInterface > const &i_xIfc, OUString const &i_rXmlId)
set the XmlId attribute of given UNO object (for RDF metadata)
Definition: xmlimp.cxx:1851
static const OUString & getNameFromToken(sal_Int32 nToken)
Definition: xmlimp.cxx:1907
This class deliberately does not support XWeak, to improve performance when loading large documents...
Definition: xmlictxt.hxx:45
void InsertBookmarkStartRange(const OUString &sName, const css::uno::Reference< css::text::XTextRange > &rRange, OUString const &i_rXmlId, std::shared_ptr< ::xmloff::ParsedRDFaAttributes > &i_rpRDFaAttributes)
save the start of a range reference
Definition: txtimp.cxx:2065
Map an XMLTokenEnum to an enum value.
Definition: ximpshap.hxx:40
css::uno::Reference< css::text::XFormField > popFieldCtx()
Definition: txtimp.cxx:2110
Handling of tokens in XML:
#define SAL_INFO(area, stream)
#define ODF_FORMTEXT
Definition: odffields.hxx:23
void pushFieldCtx(const OUString &name, const OUString &type)
Definition: txtimp.cxx:2103
#define XML_ELEMENT(prefix, name)
Definition: xmlimp.hxx:96
static bool convertEnum(EnumT &rEnum, std::u16string_view rValue, const SvXMLEnumMapEntry< EnumT > *pMap)
convert string to enum using given enum map, if the enum is not found in the map, this method will re...
Definition: xmluconv.hxx:138
const css::uno::Reference< css::frame::XModel > & GetModel() const
Definition: xmlimp.hxx:399
css::uno::Reference< css::uno::XInterface > & m_rxCrossRefHeadingBookmark
uno::Reference< ucb::XContent > xContent
ResultType type
Reference< XSingleServiceFactory > xFactory
constexpr sal_Int32 TOKEN_MASK
Definition: xmlimp.hxx:93
XMLFieldParamImportContext(SvXMLImport &rImport, XMLTextImportHelper &rHlp)
void setBookmarkAttributes(OUString const &bookmark, bool hidden, OUString const &condition)
Definition: txtimp.cxx:2429
TEXT
void setCurrentFieldParamsTo(css::uno::Reference< css::text::XFormField > const &xFormField)
Definition: txtimp.cxx:2152
XMLTextMarkImportContext(SvXMLImport &rImport, XMLTextImportHelper &rHlp, css::uno::Reference< css::uno::XInterface > &io_rxCrossRefHeadingBookmark)
#define ODF_FORMDROPDOWN
Definition: odffields.hxx:31