/src/libreoffice/xmloff/source/text/XMLTextMarkImportContext.cxx
Line | Count | Source |
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 | | |
20 | | #include "XMLTextMarkImportContext.hxx" |
21 | | |
22 | | |
23 | | #include <rtl/ustring.hxx> |
24 | | #include <sal/log.hxx> |
25 | | #include <osl/diagnose.h> |
26 | | #include <sax/tools/converter.hxx> |
27 | | #include <xmloff/xmluconv.hxx> |
28 | | #include <xmloff/xmltoken.hxx> |
29 | | #include <xmloff/xmlimp.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/text/ControlCharacter.hpp> |
35 | | #include <com/sun/star/text/XTextContent.hpp> |
36 | | #include <com/sun/star/text/XTextRangeCompare.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 | | #include <comphelper/diagnose_ex.hxx> |
44 | | |
45 | | #include <RDFaImportHelper.hxx> |
46 | | |
47 | | |
48 | | using namespace ::com::sun::star; |
49 | | using namespace ::com::sun::star::text; |
50 | | using namespace ::com::sun::star::uno; |
51 | | using namespace ::com::sun::star::beans; |
52 | | using namespace ::com::sun::star::lang; |
53 | | using namespace ::com::sun::star::container; |
54 | | using namespace ::com::sun::star::xml::sax; |
55 | | using namespace ::xmloff::token; |
56 | | |
57 | | |
58 | | XMLFieldParamImportContext::XMLFieldParamImportContext( |
59 | | SvXMLImport& rImport, |
60 | | XMLTextImportHelper& rHlp ) : |
61 | 31 | SvXMLImportContext(rImport), |
62 | 31 | rHelper(rHlp) |
63 | 31 | { |
64 | 31 | } |
65 | | |
66 | | |
67 | | void XMLFieldParamImportContext::startFastElement(sal_Int32 /*nElement*/, const css::uno::Reference< css::xml::sax::XFastAttributeList> & xAttrList) |
68 | 31 | { |
69 | 31 | OUString sName; |
70 | 31 | OUString sValue; |
71 | | |
72 | 31 | for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) |
73 | 52 | { |
74 | 52 | switch (aIter.getToken()) |
75 | 52 | { |
76 | 26 | case XML_ELEMENT(FIELD, XML_NAME): |
77 | 26 | sName = aIter.toString(); |
78 | 26 | break; |
79 | 26 | case XML_ELEMENT(FIELD, XML_VALUE): |
80 | 26 | sValue = aIter.toString(); |
81 | 26 | break; |
82 | 0 | default: |
83 | 0 | XMLOFF_WARN_UNKNOWN("xmloff", aIter); |
84 | 52 | } |
85 | 52 | } |
86 | 31 | if (rHelper.hasCurrentFieldCtx() && !sName.isEmpty()) { |
87 | 26 | rHelper.addFieldParam(sName, sValue); |
88 | 26 | } |
89 | 31 | } |
90 | | |
91 | | |
92 | | XMLTextMarkImportContext::XMLTextMarkImportContext( |
93 | | SvXMLImport& rImport, |
94 | | XMLTextImportHelper& rHlp, |
95 | | uno::Reference<uno::XInterface> & io_rxCrossRefHeadingBookmark ) |
96 | 826 | : SvXMLImportContext(rImport) |
97 | 826 | , m_rHelper(rHlp) |
98 | 826 | , m_rxCrossRefHeadingBookmark(io_rxCrossRefHeadingBookmark) |
99 | 826 | , m_isHidden(false) |
100 | 826 | , m_bHaveAbout(false) |
101 | 826 | { |
102 | 826 | } |
103 | | |
104 | | namespace { |
105 | | |
106 | | enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd, |
107 | | TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd, |
108 | | TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkSeparator, TypeFieldmarkEnd |
109 | | }; |
110 | | |
111 | | } |
112 | | |
113 | | SvXMLEnumMapEntry<lcl_MarkType> const lcl_aMarkTypeMap[] = |
114 | | { |
115 | | { XML_REFERENCE_MARK, TypeReference }, |
116 | | { XML_REFERENCE_MARK_START, TypeReferenceStart }, |
117 | | { XML_REFERENCE_MARK_END, TypeReferenceEnd }, |
118 | | { XML_BOOKMARK, TypeBookmark }, |
119 | | { XML_BOOKMARK_START, TypeBookmarkStart }, |
120 | | { XML_BOOKMARK_END, TypeBookmarkEnd }, |
121 | | { XML_FIELDMARK, TypeFieldmark }, |
122 | | { XML_FIELDMARK_START, TypeFieldmarkStart }, |
123 | | { XML_FIELDMARK_SEPARATOR, TypeFieldmarkSeparator }, |
124 | | { XML_FIELDMARK_END, TypeFieldmarkEnd }, |
125 | | { XML_TOKEN_INVALID, lcl_MarkType(0) }, |
126 | | }; |
127 | | |
128 | | |
129 | | static const OUString & lcl_getFormFieldmarkName(std::u16string_view name) |
130 | 532 | { |
131 | 532 | if (name == ODF_FORMCHECKBOX || |
132 | 532 | name == u"msoffice.field.FORMCHECKBOX" || |
133 | 532 | name == u"ecma.office-open-xml.field.FORMCHECKBOX") |
134 | 0 | return ODF_FORMCHECKBOX; |
135 | 532 | else if (name == ODF_FORMDROPDOWN || |
136 | 532 | name == u"ecma.office-open-xml.field.FORMDROPDOWN") |
137 | 0 | return ODF_FORMDROPDOWN; |
138 | 532 | else |
139 | 532 | return EMPTY_OUSTRING; |
140 | 532 | } |
141 | | |
142 | | static OUString lcl_getFieldmarkName(OUString const& name) |
143 | 11 | { |
144 | 11 | if (name == "msoffice.field.FORMTEXT" || |
145 | 11 | name == "ecma.office-open-xml.field.FORMTEXT") |
146 | 0 | return ODF_FORMTEXT; |
147 | 11 | else |
148 | 11 | return name; |
149 | 11 | } |
150 | | |
151 | | |
152 | | void XMLTextMarkImportContext::startFastElement( sal_Int32 nElement, |
153 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) |
154 | 826 | { |
155 | 826 | if (!FindName(xAttrList)) |
156 | 20 | { |
157 | 20 | m_sBookmarkName.clear(); |
158 | 20 | } |
159 | | |
160 | 826 | if ((nElement & TOKEN_MASK) == XML_FIELDMARK_START || |
161 | 813 | (nElement & TOKEN_MASK) == XML_FIELDMARK) |
162 | 13 | { |
163 | 13 | if (m_sBookmarkName.isEmpty()) |
164 | 0 | { |
165 | 0 | m_sBookmarkName = "Unknown"; |
166 | 0 | } |
167 | 13 | m_rHelper.pushFieldCtx( m_sBookmarkName, m_sFieldName ); |
168 | 13 | } |
169 | | |
170 | 826 | if ((nElement & TOKEN_MASK) == XML_BOOKMARK_START) |
171 | 22 | { |
172 | 22 | m_rHelper.setBookmarkAttributes(m_sBookmarkName, m_isHidden, m_sCondition); |
173 | 22 | } |
174 | 826 | } |
175 | | |
176 | | static auto InsertFieldmark(SvXMLImport & rImport, |
177 | | XMLTextImportHelper & rHelper, bool const isFieldmarkSeparatorMissing) -> void |
178 | 11 | { |
179 | 11 | assert(rHelper.hasCurrentFieldCtx()); // was set up in StartElement() |
180 | | |
181 | | // fdo#86795 check if it's actually a checkbox first |
182 | 11 | auto const [ name, type ] = rHelper.getCurrentFieldType(); |
183 | 11 | OUString const fieldmarkTypeName = lcl_getFieldmarkName(type); |
184 | 11 | if (fieldmarkTypeName == ODF_FORMCHECKBOX || |
185 | 11 | fieldmarkTypeName == ODF_FORMDROPDOWN) |
186 | 0 | { // sw can't handle checkbox with start+end |
187 | 0 | SAL_INFO("xmloff.text", "invalid fieldmark-start/fieldmark-end ignored"); |
188 | 0 | return; |
189 | 0 | } |
190 | | |
191 | 11 | uno::Reference<text::XTextRange> const xStartRange(rHelper.getCurrentFieldStart()); |
192 | 11 | uno::Reference<text::XTextCursor> const xCursor( |
193 | 11 | rHelper.GetText()->createTextCursorByRange(xStartRange)); |
194 | 11 | uno::Reference<text::XTextRangeCompare> const xCompare(rHelper.GetText(), uno::UNO_QUERY); |
195 | 11 | if (xCompare->compareRegionStarts(xStartRange, rHelper.GetCursorAsRange()) < 0) |
196 | 0 | { |
197 | 0 | SAL_WARN("xmloff.text", "invalid field mark positions"); |
198 | 0 | assert(false); |
199 | 0 | } |
200 | 11 | xCursor->gotoRange(rHelper.GetCursorAsRange(), true); |
201 | | |
202 | 11 | Reference<XTextContent> const xContent = XMLTextMarkImportContext::CreateAndInsertMark( |
203 | 11 | rImport, u"com.sun.star.text.Fieldmark"_ustr, name, xCursor, |
204 | 11 | OUString(), isFieldmarkSeparatorMissing); |
205 | | |
206 | 11 | if (!xContent.is()) |
207 | 0 | return; |
208 | | |
209 | | // setup fieldmark... |
210 | 11 | Reference<text::XFormField> const xFormField(xContent, UNO_QUERY); |
211 | 11 | assert(xFormField.is()); |
212 | 11 | try { |
213 | 11 | xFormField->setFieldType(fieldmarkTypeName); |
214 | 11 | } catch (uno::RuntimeException const&) { |
215 | | // tdf#140437 somehow old documents had the field code in the type |
216 | | // attribute instead of field:param |
217 | 1 | SAL_INFO("xmloff.text", "invalid fieldmark type, converting to param"); |
218 | | // add without checking: FieldParamImporter::Import() catches ElementExistException |
219 | 1 | rHelper.addFieldParam(ODF_CODE_PARAM, fieldmarkTypeName); |
220 | 1 | xFormField->setFieldType(ODF_UNHANDLED); |
221 | 1 | } |
222 | 11 | rHelper.setCurrentFieldParamsTo(xFormField); |
223 | | // move cursor after setFieldType as that may delete/re-insert |
224 | 11 | rHelper.GetCursor()->gotoRange(xContent->getAnchor()->getEnd(), false); |
225 | 11 | rHelper.GetCursor()->goLeft(1, false); // move before CH_TXT_ATR_FIELDEND |
226 | | // tdf#129520: AppendTextNode() ignores the content index! |
227 | | // plan B: insert a spurious paragraph break now and join |
228 | | // it in PopFieldmark()! |
229 | 11 | rHelper.GetText()->insertControlCharacter(rHelper.GetCursor(), |
230 | 11 | text::ControlCharacter::PARAGRAPH_BREAK, false); |
231 | 11 | rHelper.GetCursor()->goLeft(1, false); // back to previous paragraph |
232 | 11 | } |
233 | | |
234 | | static auto PopFieldmark(XMLTextImportHelper & rHelper) -> void |
235 | 11 | { |
236 | | // can't verify name because it's not written as an attribute... |
237 | 11 | uno::Reference<text::XTextContent> const xField(rHelper.popFieldCtx(), |
238 | 11 | uno::UNO_QUERY); |
239 | 11 | if (!xField.is()) |
240 | 0 | return; |
241 | | |
242 | 11 | if (rHelper.GetText() == xField->getAnchor()->getText()) |
243 | 11 | { |
244 | 11 | try |
245 | 11 | { // skip CH_TXT_ATR_FIELDEND |
246 | 11 | rHelper.GetCursor()->goRight(1, true); |
247 | 11 | rHelper.GetCursor()->setString(OUString()); // undo AppendTextNode from InsertFieldmark |
248 | 11 | rHelper.GetCursor()->gotoRange(xField->getAnchor()->getEnd(), false); |
249 | 11 | } |
250 | 11 | catch (uno::Exception const&) |
251 | 11 | { |
252 | 0 | assert(false); // must succeed |
253 | 0 | } |
254 | 11 | } |
255 | 0 | else |
256 | 0 | { |
257 | 0 | SAL_INFO("xmloff.text", "fieldmark has invalid positions"); |
258 | | // could either dispose it or leave it to end at the end of the document? |
259 | 0 | xField->dispose(); |
260 | 0 | } |
261 | 11 | } |
262 | | |
263 | | void XMLTextMarkImportContext::endFastElement(sal_Int32 nElement) |
264 | 823 | { |
265 | 823 | static constexpr OUString sAPI_bookmark = u"com.sun.star.text.Bookmark"_ustr; |
266 | | |
267 | 823 | lcl_MarkType nTmp{}; |
268 | 823 | if (!SvXMLUnitConverter::convertEnum(nTmp, SvXMLImport::getNameFromToken(nElement), lcl_aMarkTypeMap)) |
269 | 0 | return; |
270 | | |
271 | 823 | if (m_sBookmarkName.isEmpty() && TypeFieldmarkEnd != nTmp && TypeFieldmarkSeparator != nTmp) |
272 | 6 | return; |
273 | | |
274 | 817 | switch (nTmp) |
275 | 817 | { |
276 | 0 | case TypeReference: |
277 | | // export point reference mark |
278 | 0 | CreateAndInsertMark(GetImport(), |
279 | 0 | u"com.sun.star.text.ReferenceMark"_ustr, |
280 | 0 | m_sBookmarkName, |
281 | 0 | m_rHelper.GetCursorAsRange()->getStart()); |
282 | 0 | break; |
283 | | |
284 | 532 | case TypeBookmark: |
285 | 532 | { |
286 | | // tdf#94804: detect duplicate heading cross reference bookmarks |
287 | 532 | if (m_sBookmarkName.startsWith("__RefHeading__")) |
288 | 0 | { |
289 | 0 | if (m_rxCrossRefHeadingBookmark.is()) |
290 | 0 | { |
291 | 0 | uno::Reference<container::XNamed> const xNamed( |
292 | 0 | m_rxCrossRefHeadingBookmark, uno::UNO_QUERY); |
293 | 0 | m_rHelper.AddCrossRefHeadingMapping( |
294 | 0 | m_sBookmarkName, xNamed->getName()); |
295 | 0 | break; // don't insert |
296 | 0 | } |
297 | 0 | } |
298 | 532 | } |
299 | 532 | [[fallthrough]]; |
300 | 532 | case TypeFieldmark: |
301 | 532 | { |
302 | 532 | const OUString formFieldmarkName=lcl_getFormFieldmarkName(m_sFieldName); |
303 | 532 | bool bImportAsField = (nTmp==TypeFieldmark && !formFieldmarkName.isEmpty()); //@TODO handle abbreviation cases... |
304 | | // export point bookmark |
305 | 532 | const Reference<XInterface> xContent( |
306 | 532 | CreateAndInsertMark(GetImport(), |
307 | 532 | (bImportAsField ? u"com.sun.star.text.FormFieldmark"_ustr : sAPI_bookmark), |
308 | 532 | m_sBookmarkName, |
309 | 532 | m_rHelper.GetCursorAsRange()->getStart(), |
310 | 532 | m_sXmlId) ); |
311 | 532 | if (nTmp==TypeFieldmark) { |
312 | 0 | if (xContent.is() && bImportAsField) { |
313 | | // setup fieldmark... |
314 | 0 | Reference< css::text::XFormField> xFormField(xContent, UNO_QUERY); |
315 | 0 | xFormField->setFieldType(formFieldmarkName); |
316 | 0 | if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) { |
317 | 0 | m_rHelper.setCurrentFieldParamsTo(xFormField); |
318 | 0 | } |
319 | 0 | } |
320 | 0 | m_rHelper.popFieldCtx(); |
321 | 0 | } |
322 | 532 | if (TypeBookmark == nTmp |
323 | 532 | && m_sBookmarkName.startsWith("__RefHeading__")) |
324 | 0 | { |
325 | 0 | assert(xContent.is()); |
326 | 0 | m_rxCrossRefHeadingBookmark = xContent; |
327 | 0 | } |
328 | 532 | } |
329 | 532 | break; |
330 | | |
331 | 22 | case TypeBookmarkStart: |
332 | | // save XTextRange for later construction of bookmark |
333 | 22 | { |
334 | 22 | std::shared_ptr< ::xmloff::ParsedRDFaAttributes > |
335 | 22 | xRDFaAttributes; |
336 | 22 | if (m_bHaveAbout && TypeBookmarkStart == nTmp) |
337 | 0 | { |
338 | 0 | xRDFaAttributes = |
339 | 0 | GetImport().GetRDFaImportHelper().ParseRDFa( |
340 | 0 | m_sAbout, m_sProperty, |
341 | 0 | m_sContent, m_sDatatype); |
342 | 0 | } |
343 | 22 | m_rHelper.InsertBookmarkStartRange( |
344 | 22 | m_sBookmarkName, |
345 | 22 | m_rHelper.GetCursorAsRange()->getStart(), |
346 | 22 | m_sXmlId, xRDFaAttributes); |
347 | 22 | } |
348 | 22 | break; |
349 | | |
350 | 239 | case TypeBookmarkEnd: |
351 | 239 | { |
352 | | // tdf#94804: detect duplicate heading cross reference bookmarks |
353 | 239 | if (m_sBookmarkName.startsWith("__RefHeading__")) |
354 | 0 | { |
355 | 0 | if (m_rxCrossRefHeadingBookmark.is()) |
356 | 0 | { |
357 | 0 | uno::Reference<container::XNamed> const xNamed( |
358 | 0 | m_rxCrossRefHeadingBookmark, uno::UNO_QUERY); |
359 | 0 | m_rHelper.AddCrossRefHeadingMapping( |
360 | 0 | m_sBookmarkName, xNamed->getName()); |
361 | 0 | break; // don't insert |
362 | 0 | } |
363 | 0 | } |
364 | | |
365 | | // get old range, and construct |
366 | 239 | Reference<XTextRange> xStartRange; |
367 | 239 | std::shared_ptr< ::xmloff::ParsedRDFaAttributes > |
368 | 239 | xRDFaAttributes; |
369 | 239 | if (m_rHelper.FindAndRemoveBookmarkStartRange( |
370 | 239 | m_sBookmarkName, xStartRange, |
371 | 239 | m_sXmlId, xRDFaAttributes)) |
372 | 21 | { |
373 | 21 | Reference<XTextRange> xEndRange( |
374 | 21 | m_rHelper.GetCursorAsRange()->getStart()); |
375 | | |
376 | | // check if beginning and end are in same XText |
377 | 21 | if (xStartRange.is() && xEndRange.is() && xStartRange->getText() == xEndRange->getText()) |
378 | 21 | { |
379 | | // create range for insertion |
380 | 21 | Reference<XTextCursor> xInsertionCursor = |
381 | 21 | m_rHelper.GetText()->createTextCursorByRange( |
382 | 21 | xEndRange); |
383 | 21 | try { |
384 | 21 | xInsertionCursor->gotoRange(xStartRange, true); |
385 | 21 | } catch (uno::Exception&) { |
386 | 0 | TOOLS_WARN_EXCEPTION("xmloff.text", |
387 | 0 | "cannot go to end position of bookmark"); |
388 | 0 | } |
389 | | |
390 | | //DBG_ASSERT(! xInsertionCursor->isCollapsed(), |
391 | | // "we want no point mark"); |
392 | | // can't assert, because someone could |
393 | | // create a file with subsequence |
394 | | // start/end elements |
395 | | |
396 | 21 | Reference<XInterface> xContent; |
397 | | // insert reference |
398 | 21 | xContent = CreateAndInsertMark(GetImport(), |
399 | 21 | sAPI_bookmark, |
400 | 21 | m_sBookmarkName, |
401 | 21 | xInsertionCursor, |
402 | 21 | m_sXmlId); |
403 | 21 | if (xRDFaAttributes) |
404 | 0 | { |
405 | 0 | const Reference<rdf::XMetadatable> |
406 | 0 | xMeta(xContent, UNO_QUERY); |
407 | 0 | GetImport().GetRDFaImportHelper().AddRDFa( |
408 | 0 | xMeta, xRDFaAttributes); |
409 | 0 | } |
410 | 21 | const Reference<XPropertySet> xPropertySet(xContent, UNO_QUERY); |
411 | 21 | if (xPropertySet.is()) |
412 | 21 | { |
413 | 21 | xPropertySet->setPropertyValue(u"BookmarkHidden"_ustr, uno::Any(m_rHelper.getBookmarkHidden(m_sBookmarkName))); |
414 | 21 | xPropertySet->setPropertyValue(u"BookmarkCondition"_ustr, uno::Any(m_rHelper.getBookmarkCondition(m_sBookmarkName))); |
415 | 21 | } |
416 | 21 | if (m_sBookmarkName.startsWith("__RefHeading__")) |
417 | 0 | { |
418 | 0 | assert(xContent.is()); |
419 | 0 | m_rxCrossRefHeadingBookmark = std::move(xContent); |
420 | 0 | } |
421 | 21 | } |
422 | | // else: beginning/end in different XText -> ignore! |
423 | 21 | } |
424 | | // else: no start found -> ignore! |
425 | 239 | break; |
426 | 239 | } |
427 | 239 | case TypeFieldmarkStart: |
428 | 13 | { |
429 | 13 | break; |
430 | 239 | } |
431 | 0 | case TypeFieldmarkSeparator: |
432 | 0 | { |
433 | 0 | InsertFieldmark(GetImport(), m_rHelper, false); |
434 | 0 | break; |
435 | 239 | } |
436 | 11 | case TypeFieldmarkEnd: |
437 | 11 | { |
438 | 11 | if (m_rHelper.hasCurrentFieldCtx() && !m_rHelper.hasCurrentFieldSeparator()) |
439 | 11 | { // backward compat for old files without separator |
440 | 11 | InsertFieldmark(GetImport(), m_rHelper, true); |
441 | 11 | } |
442 | 11 | PopFieldmark(m_rHelper); |
443 | 11 | break; |
444 | 239 | } |
445 | 0 | case TypeReferenceStart: |
446 | 0 | case TypeReferenceEnd: |
447 | 0 | OSL_FAIL("reference start/end are handled in txtparai !"); |
448 | 0 | break; |
449 | | |
450 | 0 | default: |
451 | 0 | OSL_FAIL("unknown mark type"); |
452 | 0 | break; |
453 | 817 | } |
454 | 817 | } |
455 | | |
456 | | css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextMarkImportContext::createFastChildContext( |
457 | | sal_Int32 , |
458 | | const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) |
459 | 31 | { |
460 | 31 | return new XMLFieldParamImportContext(GetImport(), m_rHelper); |
461 | 31 | } |
462 | | |
463 | | |
464 | | Reference<XTextContent> XMLTextMarkImportContext::CreateAndInsertMark( |
465 | | SvXMLImport& rImport, |
466 | | const OUString& sServiceName, |
467 | | const OUString& sMarkName, |
468 | | const Reference<XTextRange> & rRange, |
469 | | const OUString& i_rXmlId, |
470 | | bool const isFieldmarkSeparatorMissing) |
471 | 569 | { |
472 | | // create mark |
473 | 569 | const Reference<XMultiServiceFactory> xFactory(rImport.GetModel(), |
474 | 569 | UNO_QUERY); |
475 | 569 | Reference<XInterface> xIfc; |
476 | | |
477 | 569 | if (xFactory.is()) |
478 | 569 | { |
479 | 569 | xIfc = xFactory->createInstance(sServiceName); |
480 | | |
481 | 569 | if (!xIfc.is()) |
482 | 0 | { |
483 | 0 | OSL_FAIL("CreateAndInsertMark: cannot create service?"); |
484 | 0 | return nullptr; |
485 | 0 | } |
486 | | |
487 | | // set name (unless there is no name (text:meta)) |
488 | 569 | const Reference<XNamed> xNamed(xIfc, UNO_QUERY); |
489 | 569 | if (xNamed.is()) |
490 | 569 | { |
491 | 569 | xNamed->setName(sMarkName); |
492 | 569 | } |
493 | 0 | else |
494 | 0 | { |
495 | 0 | if (!sMarkName.isEmpty()) |
496 | 0 | { |
497 | 0 | OSL_FAIL("name given, but XNamed not supported?"); |
498 | 0 | return nullptr; |
499 | 0 | } |
500 | 0 | } |
501 | | |
502 | 569 | if (isFieldmarkSeparatorMissing) |
503 | 11 | { |
504 | 11 | uno::Reference<beans::XPropertySet> const xProps(xIfc, uno::UNO_QUERY_THROW); |
505 | 11 | xProps->setPropertyValue(u"PrivateSeparatorAtStart"_ustr, uno::Any(true)); |
506 | 11 | } |
507 | | |
508 | | // cast to XTextContent and attach to document |
509 | 569 | const Reference<XTextContent> xTextContent(xIfc, UNO_QUERY); |
510 | 569 | if (xTextContent.is()) |
511 | 569 | { |
512 | 569 | try |
513 | 569 | { |
514 | | // if inserting marks, bAbsorb==sal_False will cause |
515 | | // collapsing of the given XTextRange. |
516 | 569 | rImport.GetTextImport()->GetText()->insertTextContent(rRange, |
517 | 569 | xTextContent, true); |
518 | | |
519 | | // xml:id for RDF metadata -- after insertion! |
520 | 569 | rImport.SetXmlId(xIfc, i_rXmlId); |
521 | | |
522 | 569 | return xTextContent; |
523 | 569 | } |
524 | 569 | catch (css::lang::IllegalArgumentException &) |
525 | 569 | { |
526 | 0 | OSL_FAIL("CreateAndInsertMark: cannot insert?"); |
527 | 0 | return nullptr; |
528 | 0 | } |
529 | 569 | } |
530 | 569 | } |
531 | 0 | return nullptr; |
532 | 569 | } |
533 | | |
534 | | bool XMLTextMarkImportContext::FindName( |
535 | | const Reference<XFastAttributeList> & xAttrList) |
536 | 826 | { |
537 | 826 | bool bNameOK = false; |
538 | | |
539 | | // find name attribute first |
540 | 826 | for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) |
541 | 821 | { |
542 | 821 | OUString sValue = aIter.toString(); |
543 | 821 | switch(aIter.getToken()) |
544 | 821 | { |
545 | 806 | case XML_ELEMENT(TEXT, XML_NAME): |
546 | 806 | m_sBookmarkName = sValue; |
547 | 806 | bNameOK = true; |
548 | 806 | break; |
549 | 0 | case XML_ELEMENT(XML, XML_ID): |
550 | 0 | m_sXmlId = sValue; |
551 | 0 | break; |
552 | | // RDFa |
553 | 0 | case XML_ELEMENT(XHTML, XML_ABOUT): |
554 | 0 | m_sAbout = sValue; |
555 | 0 | m_bHaveAbout = true; |
556 | 0 | break; |
557 | 0 | case XML_ELEMENT(XHTML, XML_PROPERTY): |
558 | 0 | m_sProperty = sValue; |
559 | 0 | break; |
560 | 0 | case XML_ELEMENT(XHTML, XML_CONTENT): |
561 | 0 | m_sContent = sValue; |
562 | 0 | break; |
563 | 0 | case XML_ELEMENT(XHTML, XML_DATATYPE): |
564 | 0 | m_sDatatype = sValue; |
565 | 0 | break; |
566 | 13 | case XML_ELEMENT(FIELD, XML_TYPE): |
567 | 13 | m_sFieldName = sValue; |
568 | 13 | break; |
569 | 0 | case XML_ELEMENT(LO_EXT, XML_HIDDEN): |
570 | 0 | ::sax::Converter::convertBool(m_isHidden, sValue); |
571 | 0 | break; |
572 | 0 | case XML_ELEMENT(LO_EXT, XML_CONDITION): |
573 | 0 | m_sCondition = sValue; |
574 | 0 | break; |
575 | 2 | default: |
576 | 2 | XMLOFF_WARN_UNKNOWN("xmloff", aIter); |
577 | 821 | } |
578 | 821 | } |
579 | | |
580 | 826 | return bNameOK; |
581 | 826 | } |
582 | | |
583 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |