1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_xmloff.hxx" 30 31 32 #include "XMLTextMarkImportContext.hxx" 33 34 35 #include <rtl/ustring.hxx> 36 #include <tools/debug.hxx> 37 #include <xmloff/xmluconv.hxx> 38 #include <xmloff/xmltoken.hxx> 39 #include <xmloff/xmlimp.hxx> 40 #include <xmloff/nmspmap.hxx> 41 #include "xmloff/xmlnmspe.hxx" 42 #include <xmloff/odffields.hxx> 43 #include <com/sun/star/xml/sax/XAttributeList.hpp> 44 #include <com/sun/star/text/XTextContent.hpp> 45 #include <com/sun/star/beans/XPropertySet.hpp> 46 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 47 #include <com/sun/star/container/XNamed.hpp> 48 #include <com/sun/star/rdf/XMetadatable.hpp> 49 50 #include <com/sun/star/text/XFormField.hpp> 51 52 #include "RDFaImportHelper.hxx" 53 54 55 using ::rtl::OUString; 56 using ::rtl::OUStringBuffer; 57 58 using namespace ::com::sun::star; 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; 66 67 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) 75 { 76 } 77 78 79 void XMLFieldParamImportContext::StartElement(const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList> & xAttrList) 80 { 81 SvXMLImport& rImport = GetImport(); 82 ::rtl::OUString sName; 83 ::rtl::OUString sValue; 84 85 sal_Int16 nLength = xAttrList->getLength(); 86 for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++) 87 { 88 OUString sLocalName; 89 sal_uInt16 nPrefix = rImport.GetNamespaceMap(). 90 GetKeyByAttrName( xAttrList->getNameByIndex(nAttr), 91 &sLocalName ); 92 93 if ( (XML_NAMESPACE_FIELD == nPrefix) && 94 IsXMLToken(sLocalName, XML_NAME) ) 95 { 96 sName = xAttrList->getValueByIndex(nAttr); 97 } 98 if ( (XML_NAMESPACE_FIELD == nPrefix) && 99 IsXMLToken(sLocalName, XML_VALUE) ) 100 { 101 sValue = xAttrList->getValueByIndex(nAttr); 102 } 103 } 104 if (rHelper.hasCurrentFieldCtx() && sName.getLength()>0) { 105 rHelper.addFieldParam(sName, sValue); 106 } 107 } 108 109 110 TYPEINIT1( XMLTextMarkImportContext, SvXMLImportContext); 111 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) 120 { 121 } 122 123 enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd, 124 TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd, 125 TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkEnd 126 }; 127 128 static SvXMLEnumMapEntry __READONLY_DATA lcl_aMarkTypeMap[] = 129 { 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 }, 140 }; 141 142 143 static const char *lcl_getFormFieldmarkName(rtl::OUString &name) 144 { 145 static const char sCheckbox[]=ODF_FORMCHECKBOX; 146 static const char sFormDropDown[]=ODF_FORMDROPDOWN; 147 if (name.compareToAscii("msoffice.field.FORMCHECKBOX")==0) 148 return sCheckbox; 149 else if (name.compareToAscii(ODF_FORMCHECKBOX)==0) 150 return sCheckbox; 151 if (name.compareToAscii(ODF_FORMDROPDOWN)==0) 152 return sFormDropDown; 153 else 154 return NULL; 155 } 156 157 static rtl::OUString lcl_getFieldmarkName(rtl::OUString &name) 158 { 159 static const char sFormtext[]=ODF_FORMTEXT; 160 if (name.compareToAscii("msoffice.field.FORMTEXT")==0) 161 return rtl::OUString::createFromAscii(sFormtext); 162 else if (name.compareToAscii(ODF_FORMTEXT)==0) 163 return rtl::OUString::createFromAscii(sFormtext); 164 else 165 return name; 166 } 167 168 169 void XMLTextMarkImportContext::StartElement( 170 const Reference<XAttributeList> & xAttrList) 171 { 172 if (!FindName(GetImport(), xAttrList)) 173 { 174 m_sBookmarkName = OUString(); 175 } 176 177 if (IsXMLToken(GetLocalName(), XML_FIELDMARK_END)) 178 { 179 m_sBookmarkName = m_rHelper.FindActiveBookmarkName(); 180 } 181 182 if (IsXMLToken(GetLocalName(), XML_FIELDMARK_START) || IsXMLToken(GetLocalName(), XML_FIELDMARK)) 183 { 184 if (m_sBookmarkName.getLength() == 0) 185 { 186 m_sBookmarkName = ::rtl::OUString::createFromAscii("Unknown"); 187 } 188 m_rHelper.pushFieldCtx( m_sBookmarkName, m_sFieldName ); 189 } 190 } 191 192 void XMLTextMarkImportContext::EndElement() 193 { 194 SvXMLImportContext::EndElement(); 195 196 static const OUString sAPI_reference_mark( 197 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.ReferenceMark")); 198 static const OUString sAPI_bookmark( 199 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.Bookmark")); 200 static const OUString sAPI_fieldmark( 201 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.Fieldmark")); 202 static const OUString sAPI_formfieldmark( 203 RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.FormFieldmark")); 204 205 if (m_sBookmarkName.getLength() > 0) 206 { 207 sal_uInt16 nTmp; 208 if (SvXMLUnitConverter::convertEnum(nTmp, GetLocalName(), 209 lcl_aMarkTypeMap)) 210 { 211 switch ((lcl_MarkType)nTmp) 212 { 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; 221 222 case TypeFieldmark: 223 case TypeBookmark: 224 { 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 ((lcl_MarkType)nTmp==TypeFieldmark) { 235 if (xContent.is() && bImportAsField) { 236 // setup fieldmark... 237 Reference< ::com::sun::star::text::XFormField> xFormField(xContent, UNO_QUERY); 238 xFormField->setFieldType(rtl::OUString::createFromAscii(formFieldmarkName)); 239 if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) { 240 m_rHelper.setCurrentFieldParamsTo(xFormField); 241 } 242 } 243 m_rHelper.popFieldCtx(); 244 } 245 } 246 break; 247 248 case TypeFieldmarkStart: 249 case TypeBookmarkStart: 250 // save XTextRange for later construction of bookmark 251 { 252 ::boost::shared_ptr< ::xmloff::ParsedRDFaAttributes > 253 pRDFaAttributes; 254 if (m_bHaveAbout && (TypeBookmarkStart 255 == static_cast<lcl_MarkType>(nTmp))) 256 { 257 pRDFaAttributes = 258 GetImport().GetRDFaImportHelper().ParseRDFa( 259 m_sAbout, m_sProperty, 260 m_sContent, m_sDatatype); 261 } 262 m_rHelper.InsertBookmarkStartRange( 263 m_sBookmarkName, 264 m_rHelper.GetCursorAsRange()->getStart(), 265 m_sXmlId, pRDFaAttributes); 266 } 267 break; 268 269 case TypeFieldmarkEnd: 270 case TypeBookmarkEnd: 271 { 272 // get old range, and construct 273 Reference<XTextRange> xStartRange; 274 ::boost::shared_ptr< ::xmloff::ParsedRDFaAttributes > 275 pRDFaAttributes; 276 if (m_rHelper.FindAndRemoveBookmarkStartRange( 277 m_sBookmarkName, xStartRange, 278 m_sXmlId, pRDFaAttributes)) 279 { 280 Reference<XTextRange> xEndRange( 281 m_rHelper.GetCursorAsRange()->getStart()); 282 283 // check if beginning and end are in same XText 284 if (xStartRange->getText() == xEndRange->getText()) 285 { 286 // create range for insertion 287 Reference<XTextCursor> xInsertionCursor = 288 m_rHelper.GetText()->createTextCursorByRange( 289 xEndRange); 290 try { 291 xInsertionCursor->gotoRange(xStartRange, sal_True); 292 } catch (uno::Exception&) { 293 OSL_ENSURE(false, 294 "cannot go to end position of bookmark"); 295 } 296 297 //DBG_ASSERT(! xInsertionCursor->isCollapsed(), 298 // "we want no point mark"); 299 // can't assert, because someone could 300 // create a file with subsequence 301 // start/end elements 302 303 Reference<XTextRange> xInsertionRange( 304 xInsertionCursor, UNO_QUERY); 305 306 bool bImportAsField=((lcl_MarkType)nTmp==TypeFieldmarkEnd && m_rHelper.hasCurrentFieldCtx()); 307 308 // insert reference 309 const Reference<XInterface> xContent( 310 CreateAndInsertMark(GetImport(), 311 (bImportAsField?sAPI_fieldmark:sAPI_bookmark), 312 m_sBookmarkName, 313 xInsertionRange, 314 m_sXmlId) ); 315 if (pRDFaAttributes) 316 { 317 const Reference<rdf::XMetadatable> 318 xMeta(xContent, UNO_QUERY); 319 GetImport().GetRDFaImportHelper().AddRDFa( 320 xMeta, pRDFaAttributes); 321 } 322 323 if ((lcl_MarkType)nTmp==TypeFieldmarkEnd) { 324 if (xContent.is() && bImportAsField) { 325 // setup fieldmark... 326 Reference< ::com::sun::star::text::XFormField> xFormField(xContent, UNO_QUERY); 327 if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) { 328 rtl::OUString givenTypeName=m_rHelper.getCurrentFieldType(); 329 rtl::OUString fieldmarkTypeName=lcl_getFieldmarkName(givenTypeName); 330 331 xFormField->setFieldType(fieldmarkTypeName); 332 m_rHelper.setCurrentFieldParamsTo(xFormField); 333 } 334 } 335 m_rHelper.popFieldCtx(); 336 } 337 } 338 // else: beginning/end in different XText -> ignore! 339 } 340 // else: no start found -> ignore! 341 break; 342 } 343 344 case TypeReferenceStart: 345 case TypeReferenceEnd: 346 DBG_ERROR("reference start/end are handled in txtparai !"); 347 break; 348 349 default: 350 DBG_ERROR("unknown mark type"); 351 break; 352 } 353 } 354 } 355 } 356 357 SvXMLImportContext *XMLTextMarkImportContext::CreateChildContext( sal_uInt16 nPrefix, 358 const ::rtl::OUString& rLocalName, 359 const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList >& ) 360 { 361 return new XMLFieldParamImportContext(GetImport(), m_rHelper, 362 nPrefix, rLocalName); 363 } 364 365 366 Reference<XTextContent> XMLTextMarkImportContext::CreateAndInsertMark( 367 SvXMLImport& rImport, 368 const OUString& sServiceName, 369 const OUString& sMarkName, 370 const Reference<XTextRange> & rRange, 371 const OUString& i_rXmlId) 372 { 373 // create mark 374 const Reference<XMultiServiceFactory> xFactory(rImport.GetModel(), 375 UNO_QUERY); 376 Reference<XInterface> xIfc; 377 378 if (xFactory.is()) 379 { 380 xIfc = xFactory->createInstance(sServiceName); 381 382 if (!xIfc.is()) 383 { 384 OSL_ENSURE(false, "CreateAndInsertMark: cannot create service?"); 385 return 0; 386 } 387 388 // set name (unless there is no name (text:meta)) 389 const Reference<XNamed> xNamed(xIfc, UNO_QUERY); 390 if (xNamed.is()) 391 { 392 xNamed->setName(sMarkName); 393 } 394 else 395 { 396 if (sMarkName.getLength()) 397 { 398 OSL_ENSURE(false, "name given, but XNamed not supported?"); 399 return 0; 400 } 401 } 402 403 // cast to XTextContent and attach to document 404 const Reference<XTextContent> xTextContent(xIfc, UNO_QUERY); 405 if (xTextContent.is()) 406 { 407 try 408 { 409 // if inserting marks, bAbsorb==sal_False will cause 410 // collapsing of the given XTextRange. 411 rImport.GetTextImport()->GetText()->insertTextContent(rRange, 412 xTextContent, sal_True); 413 414 // xml:id for RDF metadata -- after insertion! 415 rImport.SetXmlId(xIfc, i_rXmlId); 416 417 return xTextContent; 418 } 419 catch (com::sun::star::lang::IllegalArgumentException &) 420 { 421 OSL_ENSURE(false, "CreateAndInsertMark: cannot insert?"); 422 return 0; 423 } 424 } 425 } 426 return 0; 427 } 428 429 sal_Bool XMLTextMarkImportContext::FindName( 430 SvXMLImport& rImport, 431 const Reference<XAttributeList> & xAttrList) 432 { 433 sal_Bool bNameOK = sal_False; 434 435 // find name attribute first 436 const sal_Int16 nLength = xAttrList->getLength(); 437 for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++) 438 { 439 OUString sLocalName; 440 const sal_uInt16 nPrefix = rImport.GetNamespaceMap(). 441 GetKeyByAttrName( xAttrList->getNameByIndex(nAttr), 442 &sLocalName ); 443 444 if ( (XML_NAMESPACE_TEXT == nPrefix) && 445 IsXMLToken(sLocalName, XML_NAME) ) 446 { 447 m_sBookmarkName = xAttrList->getValueByIndex(nAttr); 448 bNameOK = sal_True; 449 } 450 else if ( (XML_NAMESPACE_XML == nPrefix) && 451 IsXMLToken(sLocalName, XML_ID) ) 452 { 453 m_sXmlId = xAttrList->getValueByIndex(nAttr); 454 } 455 else if ( XML_NAMESPACE_XHTML == nPrefix ) 456 { 457 // RDFa 458 if ( IsXMLToken( sLocalName, XML_ABOUT) ) 459 { 460 m_sAbout = xAttrList->getValueByIndex(nAttr); 461 m_bHaveAbout = true; 462 } 463 else if ( IsXMLToken( sLocalName, XML_PROPERTY) ) 464 { 465 m_sProperty = xAttrList->getValueByIndex(nAttr); 466 } 467 else if ( IsXMLToken( sLocalName, XML_CONTENT) ) 468 { 469 m_sContent = xAttrList->getValueByIndex(nAttr); 470 } 471 else if ( IsXMLToken( sLocalName, XML_DATATYPE) ) 472 { 473 m_sDatatype = xAttrList->getValueByIndex(nAttr); 474 } 475 } 476 else if ( (XML_NAMESPACE_FIELD == nPrefix) && 477 IsXMLToken(sLocalName, XML_TYPE) ) 478 { 479 m_sFieldName = xAttrList->getValueByIndex(nAttr); 480 } 481 } 482 483 return bNameOK; 484 } 485 486