xref: /AOO41X/main/xmloff/source/text/XMLTextMarkImportContext.cxx (revision 63bba73cc51e0afb45f8a8d578158724bb5afee8) !
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