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 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 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 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 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 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 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 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 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 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 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