Line data Source code
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 <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>
37 :
38 : #include <com/sun/star/text/XFormField.hpp>
39 :
40 : #include "RDFaImportHelper.hxx"
41 :
42 :
43 :
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;
52 :
53 :
54 :
55 0 : XMLFieldParamImportContext::XMLFieldParamImportContext(
56 : SvXMLImport& rImport,
57 : XMLTextImportHelper& rHlp,
58 : sal_uInt16 nPrefix,
59 : const OUString& rLocalName ) :
60 : SvXMLImportContext(rImport, nPrefix, rLocalName),
61 0 : rHelper(rHlp)
62 : {
63 0 : }
64 :
65 :
66 0 : void XMLFieldParamImportContext::StartElement(const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList> & xAttrList)
67 : {
68 0 : SvXMLImport& rImport = GetImport();
69 0 : OUString sName;
70 0 : OUString sValue;
71 :
72 0 : sal_Int16 nLength = xAttrList->getLength();
73 0 : for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
74 : {
75 0 : OUString sLocalName;
76 0 : sal_uInt16 nPrefix = rImport.GetNamespaceMap().
77 0 : GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
78 0 : &sLocalName );
79 :
80 0 : if ( (XML_NAMESPACE_FIELD == nPrefix) &&
81 0 : IsXMLToken(sLocalName, XML_NAME) )
82 : {
83 0 : sName = xAttrList->getValueByIndex(nAttr);
84 : }
85 0 : if ( (XML_NAMESPACE_FIELD == nPrefix) &&
86 0 : IsXMLToken(sLocalName, XML_VALUE) )
87 : {
88 0 : sValue = xAttrList->getValueByIndex(nAttr);
89 : }
90 0 : }
91 0 : if (rHelper.hasCurrentFieldCtx() && !sName.isEmpty()) {
92 0 : rHelper.addFieldParam(sName, sValue);
93 0 : }
94 0 : }
95 :
96 :
97 0 : TYPEINIT1( XMLTextMarkImportContext, SvXMLImportContext);
98 :
99 0 : XMLTextMarkImportContext::XMLTextMarkImportContext(
100 : SvXMLImport& rImport,
101 : XMLTextImportHelper& rHlp,
102 : sal_uInt16 nPrefix,
103 : const OUString& rLocalName )
104 : : SvXMLImportContext(rImport, nPrefix, rLocalName)
105 : , m_rHelper(rHlp)
106 0 : , m_bHaveAbout(false)
107 : {
108 0 : }
109 :
110 : enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd,
111 : TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd,
112 : TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkEnd
113 : };
114 :
115 : static SvXMLEnumMapEntry const lcl_aMarkTypeMap[] =
116 : {
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 },
127 : };
128 :
129 :
130 0 : static const char *lcl_getFormFieldmarkName(OUString &name)
131 : {
132 : static const char sCheckbox[]=ODF_FORMCHECKBOX;
133 : static const char sFormDropDown[]=ODF_FORMDROPDOWN;
134 0 : if (name.equalsAscii("msoffice.field.FORMCHECKBOX") ||
135 0 : name.equalsAscii("ecma.office-open-xml.field.FORMCHECKBOX") )
136 0 : return sCheckbox;
137 0 : else if (name.equalsAscii(ODF_FORMCHECKBOX) )
138 0 : return sCheckbox;
139 0 : if (name.equalsAscii(ODF_FORMDROPDOWN) ||
140 0 : name.equalsAscii("ecma.office-open-xml.field.FORMDROPDOWN") )
141 0 : return sFormDropDown;
142 : else
143 0 : return NULL;
144 : }
145 :
146 0 : static OUString lcl_getFieldmarkName(OUString &name)
147 : {
148 : static const char sFormtext[]=ODF_FORMTEXT;
149 0 : if (name.equalsAscii("msoffice.field.FORMTEXT") ||
150 0 : name.equalsAscii("ecma.office-open-xml.field.FORMTEXT") )
151 0 : return OUString::createFromAscii(sFormtext);
152 0 : else if (name.equalsAscii(ODF_FORMTEXT) )
153 0 : return OUString::createFromAscii(sFormtext);
154 : else
155 0 : return name;
156 : }
157 :
158 :
159 0 : void XMLTextMarkImportContext::StartElement(
160 : const Reference<XAttributeList> & xAttrList)
161 : {
162 0 : if (!FindName(GetImport(), xAttrList))
163 : {
164 0 : m_sBookmarkName = OUString();
165 : }
166 :
167 0 : if (IsXMLToken(GetLocalName(), XML_FIELDMARK_END))
168 : {
169 0 : m_sBookmarkName = m_rHelper.FindActiveBookmarkName();
170 : }
171 :
172 0 : if (IsXMLToken(GetLocalName(), XML_FIELDMARK_START) || IsXMLToken(GetLocalName(), XML_FIELDMARK))
173 : {
174 0 : if (m_sBookmarkName.isEmpty())
175 : {
176 0 : m_sBookmarkName = "Unknown";
177 : }
178 0 : m_rHelper.pushFieldCtx( m_sBookmarkName, m_sFieldName );
179 : }
180 0 : }
181 :
182 0 : void XMLTextMarkImportContext::EndElement()
183 : {
184 0 : SvXMLImportContext::EndElement();
185 :
186 0 : static const OUString sAPI_reference_mark( "com.sun.star.text.ReferenceMark");
187 0 : static const OUString sAPI_bookmark( "com.sun.star.text.Bookmark");
188 0 : static const OUString sAPI_fieldmark( "com.sun.star.text.Fieldmark");
189 0 : static const OUString sAPI_formfieldmark( "com.sun.star.text.FormFieldmark");
190 :
191 0 : if (!m_sBookmarkName.isEmpty())
192 : {
193 : sal_uInt16 nTmp;
194 0 : if (SvXMLUnitConverter::convertEnum(nTmp, GetLocalName(),
195 : lcl_aMarkTypeMap))
196 : {
197 0 : switch ((lcl_MarkType)nTmp)
198 : {
199 : case TypeReference:
200 : // export point reference mark
201 0 : CreateAndInsertMark(GetImport(),
202 : sAPI_reference_mark,
203 : m_sBookmarkName,
204 0 : m_rHelper.GetCursorAsRange()->getStart(),
205 0 : OUString());
206 0 : break;
207 :
208 : case TypeFieldmark:
209 : case TypeBookmark:
210 : {
211 0 : const char *formFieldmarkName=lcl_getFormFieldmarkName(m_sFieldName);
212 0 : bool bImportAsField=((lcl_MarkType)nTmp==TypeFieldmark && formFieldmarkName!=NULL); //@TODO handle abbreviation cases..
213 : // export point bookmark
214 : const Reference<XInterface> xContent(
215 0 : CreateAndInsertMark(GetImport(),
216 : (bImportAsField?sAPI_formfieldmark:sAPI_bookmark),
217 : m_sBookmarkName,
218 0 : m_rHelper.GetCursorAsRange()->getStart(),
219 0 : m_sXmlId) );
220 0 : if ((lcl_MarkType)nTmp==TypeFieldmark) {
221 0 : if (xContent.is() && bImportAsField) {
222 : // setup fieldmark...
223 0 : Reference< ::com::sun::star::text::XFormField> xFormField(xContent, UNO_QUERY);
224 0 : xFormField->setFieldType(OUString::createFromAscii(formFieldmarkName));
225 0 : if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) {
226 0 : m_rHelper.setCurrentFieldParamsTo(xFormField);
227 0 : }
228 : }
229 0 : m_rHelper.popFieldCtx();
230 0 : }
231 : }
232 0 : break;
233 :
234 : case TypeFieldmarkStart:
235 : case TypeBookmarkStart:
236 : // save XTextRange for later construction of bookmark
237 : {
238 : ::boost::shared_ptr< ::xmloff::ParsedRDFaAttributes >
239 0 : pRDFaAttributes;
240 0 : if (m_bHaveAbout && (TypeBookmarkStart
241 0 : == static_cast<lcl_MarkType>(nTmp)))
242 : {
243 0 : pRDFaAttributes =
244 0 : GetImport().GetRDFaImportHelper().ParseRDFa(
245 : m_sAbout, m_sProperty,
246 0 : m_sContent, m_sDatatype);
247 : }
248 : m_rHelper.InsertBookmarkStartRange(
249 : m_sBookmarkName,
250 0 : m_rHelper.GetCursorAsRange()->getStart(),
251 0 : m_sXmlId, pRDFaAttributes);
252 : }
253 0 : break;
254 :
255 : case TypeFieldmarkEnd:
256 : case TypeBookmarkEnd:
257 : {
258 : // get old range, and construct
259 0 : Reference<XTextRange> xStartRange;
260 : ::boost::shared_ptr< ::xmloff::ParsedRDFaAttributes >
261 0 : pRDFaAttributes;
262 0 : if (m_rHelper.FindAndRemoveBookmarkStartRange(
263 : m_sBookmarkName, xStartRange,
264 0 : m_sXmlId, pRDFaAttributes))
265 : {
266 : Reference<XTextRange> xEndRange(
267 0 : m_rHelper.GetCursorAsRange()->getStart());
268 :
269 : // check if beginning and end are in same XText
270 0 : if (xStartRange->getText() == xEndRange->getText())
271 : {
272 : // create range for insertion
273 : Reference<XTextCursor> xInsertionCursor =
274 0 : m_rHelper.GetText()->createTextCursorByRange(
275 0 : xEndRange);
276 : try {
277 0 : xInsertionCursor->gotoRange(xStartRange, sal_True);
278 0 : } catch (uno::Exception&) {
279 : OSL_ENSURE(false,
280 : "cannot go to end position of bookmark");
281 : }
282 :
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
288 :
289 0 : bool bImportAsField=((lcl_MarkType)nTmp==TypeFieldmarkEnd && m_rHelper.hasCurrentFieldCtx());
290 :
291 : // insert reference
292 : const Reference<XInterface> xContent(
293 0 : CreateAndInsertMark(GetImport(),
294 : (bImportAsField?sAPI_fieldmark:sAPI_bookmark),
295 : m_sBookmarkName,
296 : xInsertionCursor,
297 0 : m_sXmlId) );
298 0 : if (pRDFaAttributes)
299 : {
300 : const Reference<rdf::XMetadatable>
301 0 : xMeta(xContent, UNO_QUERY);
302 0 : GetImport().GetRDFaImportHelper().AddRDFa(
303 0 : xMeta, pRDFaAttributes);
304 : }
305 :
306 0 : if ((lcl_MarkType)nTmp==TypeFieldmarkEnd) {
307 0 : if (xContent.is() && bImportAsField) {
308 : // setup fieldmark...
309 0 : Reference< ::com::sun::star::text::XFormField> xFormField(xContent, UNO_QUERY);
310 0 : if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) {
311 0 : OUString givenTypeName=m_rHelper.getCurrentFieldType();
312 0 : OUString fieldmarkTypeName=lcl_getFieldmarkName(givenTypeName);
313 :
314 0 : xFormField->setFieldType(fieldmarkTypeName);
315 0 : m_rHelper.setCurrentFieldParamsTo(xFormField);
316 0 : }
317 : }
318 0 : m_rHelper.popFieldCtx();
319 0 : }
320 0 : }
321 : // else: beginning/end in different XText -> ignore!
322 : }
323 : // else: no start found -> ignore!
324 0 : break;
325 : }
326 :
327 : case TypeReferenceStart:
328 : case TypeReferenceEnd:
329 : OSL_FAIL("reference start/end are handled in txtparai !");
330 0 : break;
331 :
332 : default:
333 : OSL_FAIL("unknown mark type");
334 0 : break;
335 : }
336 : }
337 : }
338 0 : }
339 :
340 0 : SvXMLImportContext *XMLTextMarkImportContext::CreateChildContext( sal_uInt16 nPrefix,
341 : const OUString& rLocalName,
342 : const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& )
343 : {
344 0 : return new XMLFieldParamImportContext(GetImport(), m_rHelper,
345 0 : nPrefix, rLocalName);
346 : }
347 :
348 :
349 0 : Reference<XTextContent> XMLTextMarkImportContext::CreateAndInsertMark(
350 : SvXMLImport& rImport,
351 : const OUString& sServiceName,
352 : const OUString& sMarkName,
353 : const Reference<XTextRange> & rRange,
354 : const OUString& i_rXmlId)
355 : {
356 : // create mark
357 0 : const Reference<XMultiServiceFactory> xFactory(rImport.GetModel(),
358 0 : UNO_QUERY);
359 0 : Reference<XInterface> xIfc;
360 :
361 0 : if (xFactory.is())
362 : {
363 0 : xIfc = xFactory->createInstance(sServiceName);
364 :
365 0 : if (!xIfc.is())
366 : {
367 : OSL_FAIL("CreateAndInsertMark: cannot create service?");
368 0 : return 0;
369 : }
370 :
371 : // set name (unless there is no name (text:meta))
372 0 : const Reference<XNamed> xNamed(xIfc, UNO_QUERY);
373 0 : if (xNamed.is())
374 : {
375 0 : xNamed->setName(sMarkName);
376 : }
377 : else
378 : {
379 0 : if (!sMarkName.isEmpty())
380 : {
381 : OSL_FAIL("name given, but XNamed not supported?");
382 0 : return 0;
383 : }
384 : }
385 :
386 : // cast to XTextContent and attach to document
387 0 : const Reference<XTextContent> xTextContent(xIfc, UNO_QUERY);
388 0 : if (xTextContent.is())
389 : {
390 : try
391 : {
392 : // if inserting marks, bAbsorb==sal_False will cause
393 : // collapsing of the given XTextRange.
394 0 : rImport.GetTextImport()->GetText()->insertTextContent(rRange,
395 0 : xTextContent, sal_True);
396 :
397 : // xml:id for RDF metadata -- after insertion!
398 0 : rImport.SetXmlId(xIfc, i_rXmlId);
399 :
400 0 : return xTextContent;
401 : }
402 0 : catch (com::sun::star::lang::IllegalArgumentException &)
403 : {
404 : OSL_FAIL("CreateAndInsertMark: cannot insert?");
405 0 : return 0;
406 : }
407 0 : }
408 : }
409 0 : return 0;
410 : }
411 :
412 0 : sal_Bool XMLTextMarkImportContext::FindName(
413 : SvXMLImport& rImport,
414 : const Reference<XAttributeList> & xAttrList)
415 : {
416 0 : sal_Bool bNameOK = sal_False;
417 :
418 : // find name attribute first
419 0 : const sal_Int16 nLength = xAttrList->getLength();
420 0 : for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++)
421 : {
422 0 : OUString sLocalName;
423 0 : const sal_uInt16 nPrefix = rImport.GetNamespaceMap().
424 0 : GetKeyByAttrName( xAttrList->getNameByIndex(nAttr),
425 0 : &sLocalName );
426 :
427 0 : if ( (XML_NAMESPACE_TEXT == nPrefix) &&
428 0 : IsXMLToken(sLocalName, XML_NAME) )
429 : {
430 0 : m_sBookmarkName = xAttrList->getValueByIndex(nAttr);
431 0 : bNameOK = sal_True;
432 : }
433 0 : else if ( (XML_NAMESPACE_XML == nPrefix) &&
434 0 : IsXMLToken(sLocalName, XML_ID) )
435 : {
436 0 : m_sXmlId = xAttrList->getValueByIndex(nAttr);
437 : }
438 0 : else if ( XML_NAMESPACE_XHTML == nPrefix )
439 : {
440 : // RDFa
441 0 : if ( IsXMLToken( sLocalName, XML_ABOUT) )
442 : {
443 0 : m_sAbout = xAttrList->getValueByIndex(nAttr);
444 0 : m_bHaveAbout = true;
445 : }
446 0 : else if ( IsXMLToken( sLocalName, XML_PROPERTY) )
447 : {
448 0 : m_sProperty = xAttrList->getValueByIndex(nAttr);
449 : }
450 0 : else if ( IsXMLToken( sLocalName, XML_CONTENT) )
451 : {
452 0 : m_sContent = xAttrList->getValueByIndex(nAttr);
453 : }
454 0 : else if ( IsXMLToken( sLocalName, XML_DATATYPE) )
455 : {
456 0 : m_sDatatype = xAttrList->getValueByIndex(nAttr);
457 : }
458 : }
459 0 : else if ( (XML_NAMESPACE_FIELD == nPrefix) &&
460 0 : IsXMLToken(sLocalName, XML_TYPE) )
461 : {
462 0 : m_sFieldName = xAttrList->getValueByIndex(nAttr);
463 : }
464 0 : }
465 :
466 0 : return bNameOK;
467 : }
468 :
469 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|