1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_xmloff.hxx"
26
27
28 #include "XMLTextMarkImportContext.hxx"
29
30
31 #include <rtl/ustring.hxx>
32 #include <tools/debug.hxx>
33 #include <xmloff/xmluconv.hxx>
34 #include <xmloff/xmltoken.hxx>
35 #include <xmloff/xmlimp.hxx>
36 #include <xmloff/nmspmap.hxx>
37 #include "xmloff/xmlnmspe.hxx"
38 #include <xmloff/odffields.hxx>
39 #include <com/sun/star/xml/sax/XAttributeList.hpp>
40 #include <com/sun/star/text/XTextContent.hpp>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
43 #include <com/sun/star/container/XNamed.hpp>
44 #include <com/sun/star/rdf/XMetadatable.hpp>
45
46 #include <com/sun/star/text/XFormField.hpp>
47
48 #include "RDFaImportHelper.hxx"
49
50
51 using ::rtl::OUString;
52 using ::rtl::OUStringBuffer;
53
54 using namespace ::com::sun::star;
55 using namespace ::com::sun::star::text;
56 using namespace ::com::sun::star::uno;
57 using namespace ::com::sun::star::beans;
58 using namespace ::com::sun::star::lang;
59 using namespace ::com::sun::star::container;
60 using namespace ::com::sun::star::xml::sax;
61 using namespace ::xmloff::token;
62
63
XMLFieldParamImportContext(SvXMLImport & rImport,XMLTextImportHelper & rHlp,sal_uInt16 nPrefix,const OUString & rLocalName)64 XMLFieldParamImportContext::XMLFieldParamImportContext(
65 SvXMLImport& rImport,
66 XMLTextImportHelper& rHlp,
67 sal_uInt16 nPrefix,
68 const OUString& rLocalName ) :
69 SvXMLImportContext(rImport, nPrefix, rLocalName),
70 rHelper(rHlp)
71 {
72 }
73
74
StartElement(const::com::sun::star::uno::Reference<::com::sun::star::xml::sax::XAttributeList> & xAttrList)75 void XMLFieldParamImportContext::StartElement(const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList> & xAttrList)
76 {
77 SvXMLImport& rImport = GetImport();
78 ::rtl::OUString sName;
79 ::rtl::OUString sValue;
80
81 sal_Int16 nLength = xAttrList->getLength();
82 for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
83 {
84 OUString sLocalName;
85 sal_uInt16 nPrefix = rImport.GetNamespaceMap().
86 GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
87 &sLocalName );
88
89 if ( (XML_NAMESPACE_FIELD == nPrefix) &&
90 IsXMLToken(sLocalName, XML_NAME) )
91 {
92 sName = xAttrList->getValueByIndex(nAttr);
93 }
94 if ( (XML_NAMESPACE_FIELD == nPrefix) &&
95 IsXMLToken(sLocalName, XML_VALUE) )
96 {
97 sValue = xAttrList->getValueByIndex(nAttr);
98 }
99 }
100 if (rHelper.hasCurrentFieldCtx() && sName.getLength()>0) {
101 rHelper.addFieldParam(sName, sValue);
102 }
103 }
104
105
106 TYPEINIT1( XMLTextMarkImportContext, SvXMLImportContext);
107
XMLTextMarkImportContext(SvXMLImport & rImport,XMLTextImportHelper & rHlp,sal_uInt16 nPrefix,const OUString & rLocalName)108 XMLTextMarkImportContext::XMLTextMarkImportContext(
109 SvXMLImport& rImport,
110 XMLTextImportHelper& rHlp,
111 sal_uInt16 nPrefix,
112 const OUString& rLocalName )
113 : SvXMLImportContext(rImport, nPrefix, rLocalName)
114 , m_rHelper(rHlp)
115 , m_bHaveAbout(false)
116 {
117 }
118
119 enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd,
120 TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd,
121 TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkEnd
122 };
123
124 static SvXMLEnumMapEntry __READONLY_DATA lcl_aMarkTypeMap[] =
125 {
126 { XML_REFERENCE_MARK, TypeReference },
127 { XML_REFERENCE_MARK_START, TypeReferenceStart },
128 { XML_REFERENCE_MARK_END, TypeReferenceEnd },
129 { XML_BOOKMARK, TypeBookmark },
130 { XML_BOOKMARK_START, TypeBookmarkStart },
131 { XML_BOOKMARK_END, TypeBookmarkEnd },
132 { XML_FIELDMARK, TypeFieldmark },
133 { XML_FIELDMARK_START, TypeFieldmarkStart },
134 { XML_FIELDMARK_END, TypeFieldmarkEnd },
135 { XML_TOKEN_INVALID, 0 },
136 };
137
138
lcl_getFormFieldmarkName(rtl::OUString & name)139 static const char *lcl_getFormFieldmarkName(rtl::OUString &name)
140 {
141 static const char sCheckbox[]=ODF_FORMCHECKBOX;
142 static const char sFormDropDown[]=ODF_FORMDROPDOWN;
143 if (name.compareToAscii("msoffice.field.FORMCHECKBOX")==0)
144 return sCheckbox;
145 else if (name.compareToAscii(ODF_FORMCHECKBOX)==0)
146 return sCheckbox;
147 if (name.compareToAscii(ODF_FORMDROPDOWN)==0)
148 return sFormDropDown;
149 else
150 return NULL;
151 }
152
lcl_getFieldmarkName(rtl::OUString & name)153 static rtl::OUString lcl_getFieldmarkName(rtl::OUString &name)
154 {
155 static const char sFormtext[]=ODF_FORMTEXT;
156 if (name.compareToAscii("msoffice.field.FORMTEXT")==0)
157 return rtl::OUString::createFromAscii(sFormtext);
158 else if (name.compareToAscii(ODF_FORMTEXT)==0)
159 return rtl::OUString::createFromAscii(sFormtext);
160 else
161 return name;
162 }
163
164
StartElement(const Reference<XAttributeList> & xAttrList)165 void XMLTextMarkImportContext::StartElement(
166 const Reference<XAttributeList> & xAttrList)
167 {
168 if (!FindName(GetImport(), xAttrList))
169 {
170 m_sBookmarkName = OUString();
171 }
172
173 if (IsXMLToken(GetLocalName(), XML_FIELDMARK_END))
174 {
175 m_sBookmarkName = m_rHelper.FindActiveBookmarkName();
176 }
177
178 if (IsXMLToken(GetLocalName(), XML_FIELDMARK_START) || IsXMLToken(GetLocalName(), XML_FIELDMARK))
179 {
180 if (m_sBookmarkName.getLength() == 0)
181 {
182 m_sBookmarkName = ::rtl::OUString::createFromAscii("Unknown");
183 }
184 m_rHelper.pushFieldCtx( m_sBookmarkName, m_sFieldName );
185 }
186 }
187
EndElement()188 void XMLTextMarkImportContext::EndElement()
189 {
190 SvXMLImportContext::EndElement();
191
192 static const OUString sAPI_reference_mark(
193 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.ReferenceMark"));
194 static const OUString sAPI_bookmark(
195 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.Bookmark"));
196 static const OUString sAPI_fieldmark(
197 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.Fieldmark"));
198 static const OUString sAPI_formfieldmark(
199 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.FormFieldmark"));
200
201 if (m_sBookmarkName.getLength() > 0)
202 {
203 sal_uInt16 nTmp;
204 if (SvXMLUnitConverter::convertEnum(nTmp, GetLocalName(),
205 lcl_aMarkTypeMap))
206 {
207 switch ((lcl_MarkType)nTmp)
208 {
209 case TypeReference:
210 // export point reference mark
211 CreateAndInsertMark(GetImport(),
212 sAPI_reference_mark,
213 m_sBookmarkName,
214 m_rHelper.GetCursorAsRange()->getStart(),
215 ::rtl::OUString());
216 break;
217
218 case TypeFieldmark:
219 case TypeBookmark:
220 {
221 const char *formFieldmarkName=lcl_getFormFieldmarkName(m_sFieldName);
222 bool bImportAsField=((lcl_MarkType)nTmp==TypeFieldmark && formFieldmarkName!=NULL); //@TODO handle abbreviation cases..
223 // export point bookmark
224 const Reference<XInterface> xContent(
225 CreateAndInsertMark(GetImport(),
226 (bImportAsField?sAPI_formfieldmark:sAPI_bookmark),
227 m_sBookmarkName,
228 m_rHelper.GetCursorAsRange()->getStart(),
229 m_sXmlId) );
230 if ((lcl_MarkType)nTmp==TypeFieldmark) {
231 if (xContent.is() && bImportAsField) {
232 // setup fieldmark...
233 Reference< ::com::sun::star::text::XFormField> xFormField(xContent, UNO_QUERY);
234 xFormField->setFieldType(rtl::OUString::createFromAscii(formFieldmarkName));
235 if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) {
236 m_rHelper.setCurrentFieldParamsTo(xFormField);
237 }
238 }
239 m_rHelper.popFieldCtx();
240 }
241 }
242 break;
243
244 case TypeFieldmarkStart:
245 case TypeBookmarkStart:
246 // save XTextRange for later construction of bookmark
247 {
248 ::boost::shared_ptr< ::xmloff::ParsedRDFaAttributes >
249 pRDFaAttributes;
250 if (m_bHaveAbout && (TypeBookmarkStart
251 == static_cast<lcl_MarkType>(nTmp)))
252 {
253 pRDFaAttributes =
254 GetImport().GetRDFaImportHelper().ParseRDFa(
255 m_sAbout, m_sProperty,
256 m_sContent, m_sDatatype);
257 }
258 m_rHelper.InsertBookmarkStartRange(
259 m_sBookmarkName,
260 m_rHelper.GetCursorAsRange()->getStart(),
261 m_sXmlId, pRDFaAttributes);
262 }
263 break;
264
265 case TypeFieldmarkEnd:
266 case TypeBookmarkEnd:
267 {
268 // get old range, and construct
269 Reference<XTextRange> xStartRange;
270 ::boost::shared_ptr< ::xmloff::ParsedRDFaAttributes >
271 pRDFaAttributes;
272 if (m_rHelper.FindAndRemoveBookmarkStartRange(
273 m_sBookmarkName, xStartRange,
274 m_sXmlId, pRDFaAttributes))
275 {
276 Reference<XTextRange> xEndRange(
277 m_rHelper.GetCursorAsRange()->getStart());
278
279 // check if beginning and end are in same XText
280 if (xStartRange->getText() == xEndRange->getText())
281 {
282 // create range for insertion
283 Reference<XTextCursor> xInsertionCursor =
284 m_rHelper.GetText()->createTextCursorByRange(
285 xEndRange);
286 try {
287 xInsertionCursor->gotoRange(xStartRange, sal_True);
288 } catch (uno::Exception&) {
289 OSL_ENSURE(false,
290 "cannot go to end position of bookmark");
291 }
292
293 //DBG_ASSERT(! xInsertionCursor->isCollapsed(),
294 // "we want no point mark");
295 // can't assert, because someone could
296 // create a file with subsequence
297 // start/end elements
298
299 Reference<XTextRange> xInsertionRange(
300 xInsertionCursor, UNO_QUERY);
301
302 bool bImportAsField=((lcl_MarkType)nTmp==TypeFieldmarkEnd && m_rHelper.hasCurrentFieldCtx());
303
304 // insert reference
305 const Reference<XInterface> xContent(
306 CreateAndInsertMark(GetImport(),
307 (bImportAsField?sAPI_fieldmark:sAPI_bookmark),
308 m_sBookmarkName,
309 xInsertionRange,
310 m_sXmlId) );
311 if (pRDFaAttributes)
312 {
313 const Reference<rdf::XMetadatable>
314 xMeta(xContent, UNO_QUERY);
315 GetImport().GetRDFaImportHelper().AddRDFa(
316 xMeta, pRDFaAttributes);
317 }
318
319 if ((lcl_MarkType)nTmp==TypeFieldmarkEnd) {
320 if (xContent.is() && bImportAsField) {
321 // setup fieldmark...
322 Reference< ::com::sun::star::text::XFormField> xFormField(xContent, UNO_QUERY);
323 if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) {
324 rtl::OUString givenTypeName=m_rHelper.getCurrentFieldType();
325 rtl::OUString fieldmarkTypeName=lcl_getFieldmarkName(givenTypeName);
326
327 xFormField->setFieldType(fieldmarkTypeName);
328 m_rHelper.setCurrentFieldParamsTo(xFormField);
329 }
330 }
331 m_rHelper.popFieldCtx();
332 }
333 }
334 // else: beginning/end in different XText -> ignore!
335 }
336 // else: no start found -> ignore!
337 break;
338 }
339
340 case TypeReferenceStart:
341 case TypeReferenceEnd:
342 DBG_ERROR("reference start/end are handled in txtparai !");
343 break;
344
345 default:
346 DBG_ERROR("unknown mark type");
347 break;
348 }
349 }
350 }
351 }
352
CreateChildContext(sal_uInt16 nPrefix,const::rtl::OUString & rLocalName,const::com::sun::star::uno::Reference<::com::sun::star::xml::sax::XAttributeList> &)353 SvXMLImportContext *XMLTextMarkImportContext::CreateChildContext( sal_uInt16 nPrefix,
354 const ::rtl::OUString& rLocalName,
355 const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& )
356 {
357 return new XMLFieldParamImportContext(GetImport(), m_rHelper,
358 nPrefix, rLocalName);
359 }
360
361
CreateAndInsertMark(SvXMLImport & rImport,const OUString & sServiceName,const OUString & sMarkName,const Reference<XTextRange> & rRange,const OUString & i_rXmlId)362 Reference<XTextContent> XMLTextMarkImportContext::CreateAndInsertMark(
363 SvXMLImport& rImport,
364 const OUString& sServiceName,
365 const OUString& sMarkName,
366 const Reference<XTextRange> & rRange,
367 const OUString& i_rXmlId)
368 {
369 // create mark
370 const Reference<XMultiServiceFactory> xFactory(rImport.GetModel(),
371 UNO_QUERY);
372 Reference<XInterface> xIfc;
373
374 if (xFactory.is())
375 {
376 xIfc = xFactory->createInstance(sServiceName);
377
378 if (!xIfc.is())
379 {
380 OSL_ENSURE(false, "CreateAndInsertMark: cannot create service?");
381 return 0;
382 }
383
384 // set name (unless there is no name (text:meta))
385 const Reference<XNamed> xNamed(xIfc, UNO_QUERY);
386 if (xNamed.is())
387 {
388 xNamed->setName(sMarkName);
389 }
390 else
391 {
392 if (sMarkName.getLength())
393 {
394 OSL_ENSURE(false, "name given, but XNamed not supported?");
395 return 0;
396 }
397 }
398
399 // cast to XTextContent and attach to document
400 const Reference<XTextContent> xTextContent(xIfc, UNO_QUERY);
401 if (xTextContent.is())
402 {
403 try
404 {
405 // if inserting marks, bAbsorb==sal_False will cause
406 // collapsing of the given XTextRange.
407 rImport.GetTextImport()->GetText()->insertTextContent(rRange,
408 xTextContent, sal_True);
409
410 // xml:id for RDF metadata -- after insertion!
411 rImport.SetXmlId(xIfc, i_rXmlId);
412
413 return xTextContent;
414 }
415 catch (com::sun::star::lang::IllegalArgumentException &)
416 {
417 OSL_ENSURE(false, "CreateAndInsertMark: cannot insert?");
418 return 0;
419 }
420 }
421 }
422 return 0;
423 }
424
FindName(SvXMLImport & rImport,const Reference<XAttributeList> & xAttrList)425 sal_Bool XMLTextMarkImportContext::FindName(
426 SvXMLImport& rImport,
427 const Reference<XAttributeList> & xAttrList)
428 {
429 sal_Bool bNameOK = sal_False;
430
431 // find name attribute first
432 const sal_Int16 nLength = xAttrList->getLength();
433 for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
434 {
435 OUString sLocalName;
436 const sal_uInt16 nPrefix = rImport.GetNamespaceMap().
437 GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
438 &sLocalName );
439
440 if ( (XML_NAMESPACE_TEXT == nPrefix) &&
441 IsXMLToken(sLocalName, XML_NAME) )
442 {
443 m_sBookmarkName = xAttrList->getValueByIndex(nAttr);
444 bNameOK = sal_True;
445 }
446 else if ( (XML_NAMESPACE_XML == nPrefix) &&
447 IsXMLToken(sLocalName, XML_ID) )
448 {
449 m_sXmlId = xAttrList->getValueByIndex(nAttr);
450 }
451 else if ( XML_NAMESPACE_XHTML == nPrefix )
452 {
453 // RDFa
454 if ( IsXMLToken( sLocalName, XML_ABOUT) )
455 {
456 m_sAbout = xAttrList->getValueByIndex(nAttr);
457 m_bHaveAbout = true;
458 }
459 else if ( IsXMLToken( sLocalName, XML_PROPERTY) )
460 {
461 m_sProperty = xAttrList->getValueByIndex(nAttr);
462 }
463 else if ( IsXMLToken( sLocalName, XML_CONTENT) )
464 {
465 m_sContent = xAttrList->getValueByIndex(nAttr);
466 }
467 else if ( IsXMLToken( sLocalName, XML_DATATYPE) )
468 {
469 m_sDatatype = xAttrList->getValueByIndex(nAttr);
470 }
471 }
472 else if ( (XML_NAMESPACE_FIELD == nPrefix) &&
473 IsXMLToken(sLocalName, XML_TYPE) )
474 {
475 m_sFieldName = xAttrList->getValueByIndex(nAttr);
476 }
477 }
478
479 return bNameOK;
480 }
481
482