1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "XMLTextMarkImportContext.hxx"
23 #include <rtl/ustring.hxx>
24 #include <tools/debug.hxx>
25 #include <xmloff/xmluconv.hxx>
26 #include <xmloff/xmltoken.hxx>
27 #include <xmloff/xmlimp.hxx>
28 #include <xmloff/nmspmap.hxx>
29 #include "xmloff/xmlnmspe.hxx"
30 #include <xmloff/odffields.hxx>
31 #include <com/sun/star/xml/sax/XAttributeList.hpp>
32 #include <com/sun/star/text/XTextContent.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
35 #include <com/sun/star/container/XNamed.hpp>
36 #include <com/sun/star/rdf/XMetadatable.hpp>
38 #include <com/sun/star/text/XFormField.hpp>
40 #include "RDFaImportHelper.hxx"
44 using namespace ::com::sun::star
;
45 using namespace ::com::sun::star::text
;
46 using namespace ::com::sun::star::uno
;
47 using namespace ::com::sun::star::beans
;
48 using namespace ::com::sun::star::lang
;
49 using namespace ::com::sun::star::container
;
50 using namespace ::com::sun::star::xml::sax
;
51 using namespace ::xmloff::token
;
55 XMLFieldParamImportContext::XMLFieldParamImportContext(
57 XMLTextImportHelper
& rHlp
,
59 const OUString
& rLocalName
) :
60 SvXMLImportContext(rImport
, nPrefix
, rLocalName
),
66 void XMLFieldParamImportContext::StartElement(const ::com::sun::star::uno::Reference
< ::com::sun::star::xml::sax::XAttributeList
> & xAttrList
)
68 SvXMLImport
& rImport
= GetImport();
72 sal_Int16 nLength
= xAttrList
->getLength();
73 for(sal_Int16 nAttr
= 0; nAttr
< nLength
; nAttr
++)
76 sal_uInt16 nPrefix
= rImport
.GetNamespaceMap().
77 GetKeyByAttrName( xAttrList
->getNameByIndex(nAttr
),
80 if ( (XML_NAMESPACE_FIELD
== nPrefix
) &&
81 IsXMLToken(sLocalName
, XML_NAME
) )
83 sName
= xAttrList
->getValueByIndex(nAttr
);
85 if ( (XML_NAMESPACE_FIELD
== nPrefix
) &&
86 IsXMLToken(sLocalName
, XML_VALUE
) )
88 sValue
= xAttrList
->getValueByIndex(nAttr
);
91 if (rHelper
.hasCurrentFieldCtx() && !sName
.isEmpty()) {
92 rHelper
.addFieldParam(sName
, sValue
);
97 TYPEINIT1( XMLTextMarkImportContext
, SvXMLImportContext
);
99 XMLTextMarkImportContext::XMLTextMarkImportContext(
100 SvXMLImport
& rImport
,
101 XMLTextImportHelper
& rHlp
,
103 const OUString
& rLocalName
)
104 : SvXMLImportContext(rImport
, nPrefix
, rLocalName
)
106 , m_bHaveAbout(false)
110 enum lcl_MarkType
{ TypeReference
, TypeReferenceStart
, TypeReferenceEnd
,
111 TypeBookmark
, TypeBookmarkStart
, TypeBookmarkEnd
,
112 TypeFieldmark
, TypeFieldmarkStart
, TypeFieldmarkEnd
115 static SvXMLEnumMapEntry
const lcl_aMarkTypeMap
[] =
117 { XML_REFERENCE_MARK
, TypeReference
},
118 { XML_REFERENCE_MARK_START
, TypeReferenceStart
},
119 { XML_REFERENCE_MARK_END
, TypeReferenceEnd
},
120 { XML_BOOKMARK
, TypeBookmark
},
121 { XML_BOOKMARK_START
, TypeBookmarkStart
},
122 { XML_BOOKMARK_END
, TypeBookmarkEnd
},
123 { XML_FIELDMARK
, TypeFieldmark
},
124 { XML_FIELDMARK_START
, TypeFieldmarkStart
},
125 { XML_FIELDMARK_END
, TypeFieldmarkEnd
},
126 { XML_TOKEN_INVALID
, 0 },
130 static const char *lcl_getFormFieldmarkName(OUString
&name
)
132 static const char sCheckbox
[]=ODF_FORMCHECKBOX
;
133 static const char sFormDropDown
[]=ODF_FORMDROPDOWN
;
134 if (name
.compareToAscii("msoffice.field.FORMCHECKBOX")==0 ||
135 name
.compareToAscii("ecma.office-open-xml.field.FORMCHECKBOX")==0)
137 else if (name
.compareToAscii(ODF_FORMCHECKBOX
)==0)
139 if (name
.compareToAscii(ODF_FORMDROPDOWN
)==0 ||
140 name
.compareToAscii("ecma.office-open-xml.field.FORMDROPDOWN")==0)
141 return sFormDropDown
;
146 static OUString
lcl_getFieldmarkName(OUString
&name
)
148 static const char sFormtext
[]=ODF_FORMTEXT
;
149 if (name
.compareToAscii("msoffice.field.FORMTEXT")==0 ||
150 name
.compareToAscii("ecma.office-open-xml.field.FORMTEXT")==0)
151 return OUString::createFromAscii(sFormtext
);
152 else if (name
.compareToAscii(ODF_FORMTEXT
)==0)
153 return OUString::createFromAscii(sFormtext
);
159 void XMLTextMarkImportContext::StartElement(
160 const Reference
<XAttributeList
> & xAttrList
)
162 if (!FindName(GetImport(), xAttrList
))
164 m_sBookmarkName
= OUString();
167 if (IsXMLToken(GetLocalName(), XML_FIELDMARK_END
))
169 m_sBookmarkName
= m_rHelper
.FindActiveBookmarkName();
172 if (IsXMLToken(GetLocalName(), XML_FIELDMARK_START
) || IsXMLToken(GetLocalName(), XML_FIELDMARK
))
174 if (m_sBookmarkName
.isEmpty())
176 m_sBookmarkName
= "Unknown";
178 m_rHelper
.pushFieldCtx( m_sBookmarkName
, m_sFieldName
);
182 void XMLTextMarkImportContext::EndElement()
184 SvXMLImportContext::EndElement();
186 static const OUString
sAPI_reference_mark( "com.sun.star.text.ReferenceMark");
187 static const OUString
sAPI_bookmark( "com.sun.star.text.Bookmark");
188 static const OUString
sAPI_fieldmark( "com.sun.star.text.Fieldmark");
189 static const OUString
sAPI_formfieldmark( "com.sun.star.text.FormFieldmark");
191 if (!m_sBookmarkName
.isEmpty())
194 if (SvXMLUnitConverter::convertEnum(nTmp
, GetLocalName(),
197 switch ((lcl_MarkType
)nTmp
)
200 // export point reference mark
201 CreateAndInsertMark(GetImport(),
204 m_rHelper
.GetCursorAsRange()->getStart(),
211 const char *formFieldmarkName
=lcl_getFormFieldmarkName(m_sFieldName
);
212 bool bImportAsField
=((lcl_MarkType
)nTmp
==TypeFieldmark
&& formFieldmarkName
!=NULL
); //@TODO handle abbreviation cases..
213 // export point bookmark
214 const Reference
<XInterface
> xContent(
215 CreateAndInsertMark(GetImport(),
216 (bImportAsField
?sAPI_formfieldmark
:sAPI_bookmark
),
218 m_rHelper
.GetCursorAsRange()->getStart(),
220 if ((lcl_MarkType
)nTmp
==TypeFieldmark
) {
221 if (xContent
.is() && bImportAsField
) {
222 // setup fieldmark...
223 Reference
< ::com::sun::star::text::XFormField
> xFormField(xContent
, UNO_QUERY
);
224 xFormField
->setFieldType(OUString::createFromAscii(formFieldmarkName
));
225 if (xFormField
.is() && m_rHelper
.hasCurrentFieldCtx()) {
226 m_rHelper
.setCurrentFieldParamsTo(xFormField
);
229 m_rHelper
.popFieldCtx();
234 case TypeFieldmarkStart
:
235 case TypeBookmarkStart
:
236 // save XTextRange for later construction of bookmark
238 ::boost::shared_ptr
< ::xmloff::ParsedRDFaAttributes
>
240 if (m_bHaveAbout
&& (TypeBookmarkStart
241 == static_cast<lcl_MarkType
>(nTmp
)))
244 GetImport().GetRDFaImportHelper().ParseRDFa(
245 m_sAbout
, m_sProperty
,
246 m_sContent
, m_sDatatype
);
248 m_rHelper
.InsertBookmarkStartRange(
250 m_rHelper
.GetCursorAsRange()->getStart(),
251 m_sXmlId
, pRDFaAttributes
);
255 case TypeFieldmarkEnd
:
256 case TypeBookmarkEnd
:
258 // get old range, and construct
259 Reference
<XTextRange
> xStartRange
;
260 ::boost::shared_ptr
< ::xmloff::ParsedRDFaAttributes
>
262 if (m_rHelper
.FindAndRemoveBookmarkStartRange(
263 m_sBookmarkName
, xStartRange
,
264 m_sXmlId
, pRDFaAttributes
))
266 Reference
<XTextRange
> xEndRange(
267 m_rHelper
.GetCursorAsRange()->getStart());
269 // check if beginning and end are in same XText
270 if (xStartRange
->getText() == xEndRange
->getText())
272 // create range for insertion
273 Reference
<XTextCursor
> xInsertionCursor
=
274 m_rHelper
.GetText()->createTextCursorByRange(
277 xInsertionCursor
->gotoRange(xStartRange
, sal_True
);
278 } catch (uno::Exception
&) {
280 "cannot go to end position of bookmark");
283 //DBG_ASSERT(! xInsertionCursor->isCollapsed(),
284 // "we want no point mark");
285 // can't assert, because someone could
286 // create a file with subsequence
287 // start/end elements
289 Reference
<XTextRange
> xInsertionRange(
290 xInsertionCursor
, UNO_QUERY
);
292 bool bImportAsField
=((lcl_MarkType
)nTmp
==TypeFieldmarkEnd
&& m_rHelper
.hasCurrentFieldCtx());
295 const Reference
<XInterface
> xContent(
296 CreateAndInsertMark(GetImport(),
297 (bImportAsField
?sAPI_fieldmark
:sAPI_bookmark
),
303 const Reference
<rdf::XMetadatable
>
304 xMeta(xContent
, UNO_QUERY
);
305 GetImport().GetRDFaImportHelper().AddRDFa(
306 xMeta
, pRDFaAttributes
);
309 if ((lcl_MarkType
)nTmp
==TypeFieldmarkEnd
) {
310 if (xContent
.is() && bImportAsField
) {
311 // setup fieldmark...
312 Reference
< ::com::sun::star::text::XFormField
> xFormField(xContent
, UNO_QUERY
);
313 if (xFormField
.is() && m_rHelper
.hasCurrentFieldCtx()) {
314 OUString givenTypeName
=m_rHelper
.getCurrentFieldType();
315 OUString fieldmarkTypeName
=lcl_getFieldmarkName(givenTypeName
);
317 xFormField
->setFieldType(fieldmarkTypeName
);
318 m_rHelper
.setCurrentFieldParamsTo(xFormField
);
321 m_rHelper
.popFieldCtx();
324 // else: beginning/end in different XText -> ignore!
326 // else: no start found -> ignore!
330 case TypeReferenceStart
:
331 case TypeReferenceEnd
:
332 OSL_FAIL("reference start/end are handled in txtparai !");
336 OSL_FAIL("unknown mark type");
343 SvXMLImportContext
*XMLTextMarkImportContext::CreateChildContext( sal_uInt16 nPrefix
,
344 const OUString
& rLocalName
,
345 const ::com::sun::star::uno::Reference
< ::com::sun::star::xml::sax::XAttributeList
>& )
347 return new XMLFieldParamImportContext(GetImport(), m_rHelper
,
348 nPrefix
, rLocalName
);
352 Reference
<XTextContent
> XMLTextMarkImportContext::CreateAndInsertMark(
353 SvXMLImport
& rImport
,
354 const OUString
& sServiceName
,
355 const OUString
& sMarkName
,
356 const Reference
<XTextRange
> & rRange
,
357 const OUString
& i_rXmlId
)
360 const Reference
<XMultiServiceFactory
> xFactory(rImport
.GetModel(),
362 Reference
<XInterface
> xIfc
;
366 xIfc
= xFactory
->createInstance(sServiceName
);
370 OSL_FAIL("CreateAndInsertMark: cannot create service?");
374 // set name (unless there is no name (text:meta))
375 const Reference
<XNamed
> xNamed(xIfc
, UNO_QUERY
);
378 xNamed
->setName(sMarkName
);
382 if (!sMarkName
.isEmpty())
384 OSL_FAIL("name given, but XNamed not supported?");
389 // cast to XTextContent and attach to document
390 const Reference
<XTextContent
> xTextContent(xIfc
, UNO_QUERY
);
391 if (xTextContent
.is())
395 // if inserting marks, bAbsorb==sal_False will cause
396 // collapsing of the given XTextRange.
397 rImport
.GetTextImport()->GetText()->insertTextContent(rRange
,
398 xTextContent
, sal_True
);
400 // xml:id for RDF metadata -- after insertion!
401 rImport
.SetXmlId(xIfc
, i_rXmlId
);
405 catch (com::sun::star::lang::IllegalArgumentException
&)
407 OSL_FAIL("CreateAndInsertMark: cannot insert?");
415 sal_Bool
XMLTextMarkImportContext::FindName(
416 SvXMLImport
& rImport
,
417 const Reference
<XAttributeList
> & xAttrList
)
419 sal_Bool bNameOK
= sal_False
;
421 // find name attribute first
422 const sal_Int16 nLength
= xAttrList
->getLength();
423 for(sal_Int16 nAttr
= 0; nAttr
< nLength
; nAttr
++)
426 const sal_uInt16 nPrefix
= rImport
.GetNamespaceMap().
427 GetKeyByAttrName( xAttrList
->getNameByIndex(nAttr
),
430 if ( (XML_NAMESPACE_TEXT
== nPrefix
) &&
431 IsXMLToken(sLocalName
, XML_NAME
) )
433 m_sBookmarkName
= xAttrList
->getValueByIndex(nAttr
);
436 else if ( (XML_NAMESPACE_XML
== nPrefix
) &&
437 IsXMLToken(sLocalName
, XML_ID
) )
439 m_sXmlId
= xAttrList
->getValueByIndex(nAttr
);
441 else if ( XML_NAMESPACE_XHTML
== nPrefix
)
444 if ( IsXMLToken( sLocalName
, XML_ABOUT
) )
446 m_sAbout
= xAttrList
->getValueByIndex(nAttr
);
449 else if ( IsXMLToken( sLocalName
, XML_PROPERTY
) )
451 m_sProperty
= xAttrList
->getValueByIndex(nAttr
);
453 else if ( IsXMLToken( sLocalName
, XML_CONTENT
) )
455 m_sContent
= xAttrList
->getValueByIndex(nAttr
);
457 else if ( IsXMLToken( sLocalName
, XML_DATATYPE
) )
459 m_sDatatype
= xAttrList
->getValueByIndex(nAttr
);
462 else if ( (XML_NAMESPACE_FIELD
== nPrefix
) &&
463 IsXMLToken(sLocalName
, XML_TYPE
) )
465 m_sFieldName
= xAttrList
->getValueByIndex(nAttr
);
472 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */