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