merge the formfield patch from ooo-build
[ooovba.git] / xmloff / source / text / XMLTextMarkImportContext.cxx
blob51be51651781a237166a663dd0e5010959c719e4
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: XMLTextMarkImportContext.cxx,v $
10 * $Revision: 1.15 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_xmloff.hxx"
35 #include "XMLTextMarkImportContext.hxx"
38 #include <rtl/ustring.hxx>
39 #include <tools/debug.hxx>
40 #include <xmloff/xmluconv.hxx>
41 #include <xmloff/xmltoken.hxx>
42 #include <xmloff/xmlimp.hxx>
43 #include <xmloff/nmspmap.hxx>
44 #include <xmloff/ecmaflds.hxx>
45 #include "xmlnmspe.hxx"
46 #include <com/sun/star/xml/sax/XAttributeList.hpp>
47 #include <com/sun/star/text/XTextContent.hpp>
48 #include <com/sun/star/beans/XPropertySet.hpp>
49 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
50 #include <com/sun/star/container/XNamed.hpp>
51 #include <com/sun/star/rdf/XMetadatable.hpp>
53 #include <com/sun/star/text/XFormField.hpp>
56 using ::rtl::OUString;
57 using ::rtl::OUStringBuffer;
59 using namespace ::com::sun::star::text;
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::beans;
62 using namespace ::com::sun::star::lang;
63 using namespace ::com::sun::star::container;
64 using namespace ::com::sun::star::xml::sax;
65 using namespace ::xmloff::token;
68 XMLFieldParamImportContext::XMLFieldParamImportContext(
69 SvXMLImport& rImport,
70 XMLTextImportHelper& rHlp,
71 sal_uInt16 nPrefix,
72 const OUString& rLocalName ) :
73 SvXMLImportContext(rImport, nPrefix, rLocalName),
74 rHelper(rHlp)
79 void XMLFieldParamImportContext::StartElement(const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList> & xAttrList)
81 SvXMLImport& rImport = GetImport();
82 ::rtl::OUString sName;
83 ::rtl::OUString sValue;
85 sal_Int16 nLength = xAttrList->getLength();
86 for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
88 OUString sLocalName;
89 sal_uInt16 nPrefix = rImport.GetNamespaceMap().
90 GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
91 &sLocalName );
93 if ( (XML_NAMESPACE_FIELD == nPrefix) &&
94 IsXMLToken(sLocalName, XML_NAME) )
96 sName = xAttrList->getValueByIndex(nAttr);
98 if ( (XML_NAMESPACE_FIELD == nPrefix) &&
99 IsXMLToken(sLocalName, XML_VALUE) )
101 sValue = xAttrList->getValueByIndex(nAttr);
104 if (rHelper.hasCurrentFieldCtx() && sName.getLength()>0) {
105 rHelper.addFieldParam(sName, sValue);
110 TYPEINIT1( XMLTextMarkImportContext, SvXMLImportContext);
112 XMLTextMarkImportContext::XMLTextMarkImportContext(
113 SvXMLImport& rImport,
114 XMLTextImportHelper& rHlp,
115 sal_uInt16 nPrefix,
116 const OUString& rLocalName )
117 : SvXMLImportContext(rImport, nPrefix, rLocalName)
118 , m_rHelper(rHlp)
119 , m_bHaveAbout(false)
123 enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd,
124 TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd,
125 TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkEnd
128 static SvXMLEnumMapEntry __READONLY_DATA lcl_aMarkTypeMap[] =
130 { XML_REFERENCE_MARK, TypeReference },
131 { XML_REFERENCE_MARK_START, TypeReferenceStart },
132 { XML_REFERENCE_MARK_END, TypeReferenceEnd },
133 { XML_BOOKMARK, TypeBookmark },
134 { XML_BOOKMARK_START, TypeBookmarkStart },
135 { XML_BOOKMARK_END, TypeBookmarkEnd },
136 { XML_FIELDMARK, TypeFieldmark },
137 { XML_FIELDMARK_START, TypeFieldmarkStart },
138 { XML_FIELDMARK_END, TypeFieldmarkEnd },
139 { XML_TOKEN_INVALID, 0 },
143 static const char *lcl_getFormFieldmarkName(rtl::OUString &name)
145 static const char sCheckbox[]=ECMA_FORMCHECKBOX;
146 static const char sFormDropDown[]=ECMA_FORMDROPDOWN;
147 if (name.compareToAscii("msoffice.field.FORMCHECKBOX")==0)
148 return sCheckbox;
149 else if (name.compareToAscii(ECMA_FORMCHECKBOX)==0)
150 return sCheckbox;
151 if (name.compareToAscii(ECMA_FORMDROPDOWN)==0)
152 return sFormDropDown;
153 else
154 return NULL;
157 static rtl::OUString lcl_getFieldmarkName(rtl::OUString &name)
159 static const char sFormtext[]=ECMA_FORMTEXT;
160 if (name.compareToAscii("msoffice.field.FORMTEXT")==0)
161 return rtl::OUString::createFromAscii(sFormtext);
162 else if (name.compareToAscii(ECMA_FORMTEXT)==0)
163 return rtl::OUString::createFromAscii(sFormtext);
164 else
165 return name;
169 void XMLTextMarkImportContext::StartElement(
170 const Reference<XAttributeList> & xAttrList)
172 if (!FindName(GetImport(), xAttrList))
174 m_sBookmarkName = OUString();
177 if (IsXMLToken(GetLocalName(), XML_FIELDMARK_END))
179 m_sBookmarkName = m_rHelper.FindActiveBookmarkName();
182 if (IsXMLToken(GetLocalName(), XML_FIELDMARK_START) || IsXMLToken(GetLocalName(), XML_FIELDMARK))
184 if (m_sBookmarkName.getLength() == 0)
186 m_sBookmarkName = ::rtl::OUString::createFromAscii("Unknown");
188 m_rHelper.pushFieldCtx( m_sBookmarkName, m_sFieldName );
192 void XMLTextMarkImportContext::EndElement()
194 SvXMLImportContext::EndElement();
196 const OUString sAPI_reference_mark(
197 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.ReferenceMark"));
198 const OUString sAPI_bookmark(
199 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.Bookmark"));
200 const OUString sAPI_fieldmark(
201 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.Fieldmark"));
202 const OUString sAPI_formfieldmark(
203 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.FormFieldmark"));
205 if (m_sBookmarkName.getLength() > 0)
207 sal_uInt16 nTmp;
208 if (SvXMLUnitConverter::convertEnum(nTmp, GetLocalName(),
209 lcl_aMarkTypeMap))
211 switch ((lcl_MarkType)nTmp)
213 case TypeReference:
214 // export point reference mark
215 CreateAndInsertMark(GetImport(),
216 sAPI_reference_mark,
217 m_sBookmarkName,
218 m_rHelper.GetCursorAsRange()->getStart(),
219 ::rtl::OUString());
220 break;
222 case TypeFieldmark:
223 case TypeBookmark:
225 const char *formFieldmarkName=lcl_getFormFieldmarkName(m_sFieldName);
226 bool bImportAsField=((lcl_MarkType)nTmp==TypeFieldmark && formFieldmarkName!=NULL); //@TODO handle abbreviation cases..
227 // export point bookmark
228 const Reference<XInterface> xContent(
229 CreateAndInsertMark(GetImport(),
230 (bImportAsField?sAPI_formfieldmark:sAPI_bookmark),
231 m_sBookmarkName,
232 m_rHelper.GetCursorAsRange()->getStart(),
233 m_sXmlId) );
234 if (m_bHaveAbout)
236 const Reference<com::sun::star::rdf::XMetadatable>
237 xMeta( xContent, UNO_QUERY);
238 GetImport().AddRDFa(xMeta,
239 m_sAbout, m_sProperty, m_sContent, m_sDatatype);
241 if ((lcl_MarkType)nTmp==TypeFieldmark) {
242 if (xContent.is() && bImportAsField) {
243 // setup fieldmark...
244 Reference< ::com::sun::star::text::XFormField> xFormField(xContent, UNO_QUERY);
245 xFormField->setFieldType(rtl::OUString::createFromAscii(formFieldmarkName));
246 if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) {
247 m_rHelper.setCurrentFieldParamsTo(xFormField);
250 m_rHelper.popFieldCtx();
253 break;
255 case TypeFieldmarkStart:
256 case TypeBookmarkStart:
257 // save XTextRange for later construction of bookmark
258 m_rHelper.InsertBookmarkStartRange(
259 m_sBookmarkName, m_rHelper.GetCursorAsRange()->getStart(),
260 m_sXmlId);
261 break;
263 case TypeFieldmarkEnd:
264 case TypeBookmarkEnd:
266 // get old range, and construct
267 Reference<XTextRange> xStartRange;
268 if (m_rHelper.FindAndRemoveBookmarkStartRange(m_sBookmarkName,
269 xStartRange, m_sXmlId))
271 Reference<XTextRange> xEndRange(
272 m_rHelper.GetCursorAsRange()->getStart());
274 // check if beginning and end are in same XText
275 if (xStartRange->getText() == xEndRange->getText())
277 // create range for insertion
278 Reference<XTextCursor> xInsertionCursor =
279 m_rHelper.GetText()->createTextCursorByRange(
280 xEndRange);
281 xInsertionCursor->gotoRange(xStartRange, sal_True);
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());
294 // insert reference
295 const Reference<XInterface> xContent(
296 CreateAndInsertMark(GetImport(),
297 (bImportAsField?sAPI_fieldmark:sAPI_bookmark),
298 m_sBookmarkName,
299 xInsertionRange,
300 m_sXmlId) );
301 if (m_bHaveAbout)
303 const Reference<com::sun::star::rdf::XMetadatable>
304 xMeta( xContent, UNO_QUERY);
305 GetImport().AddRDFa(xMeta,
306 m_sAbout, m_sProperty, m_sContent, m_sDatatype);
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 rtl::OUString givenTypeName=m_rHelper.getCurrentFieldType();
315 rtl::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!
327 break;
330 case TypeReferenceStart:
331 case TypeReferenceEnd:
332 DBG_ERROR("reference start/end are handled in txtparai !");
333 break;
335 default:
336 DBG_ERROR("unknown mark type");
337 break;
343 SvXMLImportContext *XMLTextMarkImportContext::CreateChildContext( USHORT nPrefix,
344 const ::rtl::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)
359 // create mark
360 const Reference<XMultiServiceFactory> xFactory(rImport.GetModel(),
361 UNO_QUERY);
362 Reference<XInterface> xIfc;
364 if (xFactory.is())
366 xIfc = xFactory->createInstance(sServiceName);
368 if (!xIfc.is())
370 OSL_ENSURE(false, "CreateAndInsertMark: cannot create service?");
371 return 0;
374 // set name (unless there is no name (text:meta))
375 const Reference<XNamed> xNamed(xIfc, UNO_QUERY);
376 if (xNamed.is())
378 xNamed->setName(sMarkName);
380 else
382 if (sMarkName.getLength())
384 OSL_ENSURE(false, "name given, but XNamed not supported?");
385 return 0;
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);
403 return xTextContent;
405 catch (com::sun::star::lang::IllegalArgumentException &)
407 OSL_ENSURE(false, "CreateAndInsertMark: cannot insert?");
408 return 0;
412 return 0;
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++)
425 OUString sLocalName;
426 const sal_uInt16 nPrefix = rImport.GetNamespaceMap().
427 GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
428 &sLocalName );
430 if ( (XML_NAMESPACE_TEXT == nPrefix) &&
431 IsXMLToken(sLocalName, XML_NAME) )
433 m_sBookmarkName = xAttrList->getValueByIndex(nAttr);
434 bNameOK = sal_True;
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 )
443 // RDFa
444 if ( IsXMLToken( sLocalName, XML_ABOUT) )
446 m_sAbout = xAttrList->getValueByIndex(nAttr);
447 m_bHaveAbout = true;
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);
469 return bNameOK;