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 #include "XMLSectionImportContext.hxx" 31 #include "XMLSectionSourceImportContext.hxx" 32 #include "XMLSectionSourceDDEImportContext.hxx" 33 #include <xmloff/xmlictxt.hxx> 34 #include <xmloff/xmlimp.hxx> 35 #include <xmloff/txtimp.hxx> 36 #include <xmloff/nmspmap.hxx> 37 #include "xmloff/xmlnmspe.hxx" 38 #include <xmloff/xmltoken.hxx> 39 #include <xmloff/xmluconv.hxx> 40 #include <xmloff/prstylei.hxx> 41 #include <com/sun/star/container/XNamed.hpp> 42 #include <com/sun/star/uno/Reference.h> 43 #include <com/sun/star/text/XTextContent.hpp> 44 #include <com/sun/star/beans/XPropertySet.hpp> 45 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 46 #include <com/sun/star/text/ControlCharacter.hpp> 47 48 49 using ::rtl::OUString; 50 using ::com::sun::star::beans::XPropertySet; 51 using ::com::sun::star::uno::Reference; 52 using ::com::sun::star::xml::sax::XAttributeList; 53 using ::com::sun::star::lang::XMultiServiceFactory; 54 using ::com::sun::star::container::XNamed; 55 56 using namespace ::com::sun::star::uno; 57 using namespace ::com::sun::star::text; 58 using namespace ::xmloff::token; 59 60 61 TYPEINIT1( XMLSectionImportContext, SvXMLImportContext ); 62 63 const sal_Char sAPI_TextSection[] = "com.sun.star.text.TextSection"; 64 const sal_Char sAPI_IndexHeaderSection[] = "com.sun.star.text.IndexHeaderSection"; 65 const sal_Char sAPI_IsProtected[] = "IsProtected"; 66 const sal_Char sAPI_Condition[] = "Condition"; 67 const sal_Char sAPI_IsVisible[] = "IsVisible"; 68 const sal_Char sAPI_IsCurrentlyVisible[] = "IsCurrentlyVisible"; 69 const sal_Char sAPI_ProtectionKey[] = "ProtectionKey"; 70 71 enum XMLSectionToken 72 { 73 XML_TOK_SECTION_XMLID, 74 XML_TOK_SECTION_STYLE_NAME, 75 XML_TOK_SECTION_NAME, 76 XML_TOK_SECTION_CONDITION, 77 XML_TOK_SECTION_DISPLAY, 78 XML_TOK_SECTION_PROTECT, 79 XML_TOK_SECTION_PROTECTION_KEY, 80 XML_TOK_SECTION_IS_HIDDEN 81 }; 82 83 static __FAR_DATA SvXMLTokenMapEntry aSectionTokenMap[] = 84 { 85 { XML_NAMESPACE_XML , XML_ID, XML_TOK_SECTION_XMLID }, 86 { XML_NAMESPACE_TEXT, XML_STYLE_NAME, XML_TOK_SECTION_STYLE_NAME }, 87 { XML_NAMESPACE_TEXT, XML_NAME, XML_TOK_SECTION_NAME }, 88 { XML_NAMESPACE_TEXT, XML_CONDITION, XML_TOK_SECTION_CONDITION }, 89 { XML_NAMESPACE_TEXT, XML_DISPLAY, XML_TOK_SECTION_DISPLAY }, 90 { XML_NAMESPACE_TEXT, XML_PROTECTED, XML_TOK_SECTION_PROTECT }, 91 { XML_NAMESPACE_TEXT, XML_PROTECTION_KEY, XML_TOK_SECTION_PROTECTION_KEY}, 92 { XML_NAMESPACE_TEXT, XML_IS_HIDDEN, XML_TOK_SECTION_IS_HIDDEN }, 93 // compatibility with SRC629 (or earlier) versions 94 { XML_NAMESPACE_TEXT, XML_PROTECT, XML_TOK_SECTION_PROTECT }, 95 XML_TOKEN_MAP_END 96 }; 97 98 99 // section import: This one is fairly tricky due to a variety of 100 // limits of the core or the API. The main problem is that if you 101 // insert a section within another section, you can't move the cursor 102 // between the ends of the inner and the enclosing section. To avoid 103 // these problems, additional markers are first inserted and later deleted. 104 XMLSectionImportContext::XMLSectionImportContext( 105 SvXMLImport& rImport, 106 sal_uInt16 nPrfx, 107 const OUString& rLocalName ) 108 : SvXMLImportContext(rImport, nPrfx, rLocalName) 109 , sTextSection(RTL_CONSTASCII_USTRINGPARAM(sAPI_TextSection)) 110 , sIndexHeaderSection(RTL_CONSTASCII_USTRINGPARAM(sAPI_IndexHeaderSection)) 111 , sCondition(RTL_CONSTASCII_USTRINGPARAM(sAPI_Condition)) 112 , sIsVisible(RTL_CONSTASCII_USTRINGPARAM(sAPI_IsVisible)) 113 , sProtectionKey(RTL_CONSTASCII_USTRINGPARAM(sAPI_ProtectionKey)) 114 , sIsProtected(RTL_CONSTASCII_USTRINGPARAM(sAPI_IsProtected)) 115 , sIsCurrentlyVisible(RTL_CONSTASCII_USTRINGPARAM(sAPI_IsCurrentlyVisible)) 116 , bProtect(sal_False) 117 , bCondOK(sal_False) 118 , bIsVisible(sal_True) 119 , bValid(sal_False) 120 , bSequenceOK(sal_False) 121 , bIsCurrentlyVisible(sal_True) 122 , bIsCurrentlyVisibleOK(sal_False) 123 , bHasContent(sal_False) 124 { 125 } 126 127 XMLSectionImportContext::~XMLSectionImportContext() 128 { 129 } 130 131 void XMLSectionImportContext::StartElement( 132 const Reference<XAttributeList> & xAttrList) 133 { 134 // process attributes 135 ProcessAttributes(xAttrList); 136 137 // process index headers: 138 sal_Bool bIsIndexHeader = IsXMLToken( GetLocalName(), XML_INDEX_TITLE ); 139 if (bIsIndexHeader) 140 { 141 bValid = sal_True; 142 } 143 144 UniReference<XMLTextImportHelper> rHelper = GetImport().GetTextImport(); 145 146 // valid? 147 if (bValid) 148 { 149 // create text section (as XPropertySet) 150 Reference<XMultiServiceFactory> xFactory( 151 GetImport().GetModel(),UNO_QUERY); 152 if (xFactory.is()) 153 { 154 Reference<XInterface> xIfc = 155 xFactory->createInstance( bIsIndexHeader ? sIndexHeaderSection 156 : sTextSection ); 157 if (xIfc.is()) 158 { 159 Reference<XPropertySet> xPropSet(xIfc, UNO_QUERY); 160 161 // save PropertySet (for CreateChildContext) 162 xSectionPropertySet = xPropSet; 163 164 // name 165 Reference<XNamed> xNamed(xPropSet, UNO_QUERY); 166 xNamed->setName(sName); 167 168 // stylename? 169 if (sStyleName.getLength() > 0) 170 { 171 XMLPropStyleContext* pStyle = rHelper-> 172 FindSectionStyle(sStyleName); 173 174 if (pStyle != NULL) 175 { 176 pStyle->FillPropertySet( xPropSet ); 177 } 178 } 179 180 // IsVisible and condition (not for index headers) 181 if (! bIsIndexHeader) 182 { 183 Any aAny; 184 aAny.setValue( &bIsVisible, ::getBooleanCppuType() ); 185 xPropSet->setPropertyValue( sIsVisible, aAny ); 186 187 // #97450# hidden sections must be hidden on reload 188 // For backwards compatibilty, set flag only if it is 189 // present 190 if( bIsCurrentlyVisibleOK ) 191 { 192 aAny.setValue( &bIsCurrentlyVisible, 193 ::getBooleanCppuType() ); 194 xPropSet->setPropertyValue( sIsCurrentlyVisible, aAny); 195 } 196 197 if (bCondOK) 198 { 199 aAny <<= sCond; 200 xPropSet->setPropertyValue( sCondition, aAny ); 201 } 202 } 203 204 // password (only for regular sections) 205 if ( bSequenceOK && 206 IsXMLToken(GetLocalName(), XML_SECTION) ) 207 { 208 Any aAny; 209 aAny <<= aSequence; 210 xPropSet->setPropertyValue(sProtectionKey, aAny); 211 } 212 213 // protection 214 Any aAny; 215 aAny.setValue( &bProtect, ::getBooleanCppuType() ); 216 xPropSet->setPropertyValue( sIsProtected, aAny ); 217 218 // insert marker, <paragraph>, marker; then insert 219 // section over the first marker character, and delete the 220 // last paragraph (and marker) when closing a section. 221 Reference<XTextRange> xStart = 222 rHelper->GetCursor()->getStart(); 223 #ifndef DBG_UTIL 224 static const sal_Char sMarker[] = " "; 225 #else 226 static const sal_Char sMarker[] = "X"; 227 #endif 228 OUString sMarkerString(RTL_CONSTASCII_USTRINGPARAM(sMarker)); 229 rHelper->InsertString(sMarkerString); 230 rHelper->InsertControlCharacter( 231 ControlCharacter::APPEND_PARAGRAPH ); 232 rHelper->InsertString(sMarkerString); 233 234 // select first marker 235 rHelper->GetCursor()->gotoRange(xStart, sal_False); 236 rHelper->GetCursor()->goRight(1, sal_True); 237 238 // convert section to XTextContent 239 Reference<XTextContent> xTextContent(xSectionPropertySet, 240 UNO_QUERY); 241 242 // and insert (over marker) 243 rHelper->GetText()->insertTextContent( 244 rHelper->GetCursorAsRange(), xTextContent, sal_True ); 245 246 // and delete first marker (in section) 247 rHelper->GetText()->insertString( 248 rHelper->GetCursorAsRange(), sEmpty, sal_True); 249 250 // finally, check for redlines that should start at 251 // the section start node 252 rHelper->RedlineAdjustStartNodeCursor(sal_True); // start ??? 253 254 // xml:id for RDF metadata 255 GetImport().SetXmlId(xIfc, sXmlId); 256 } 257 } 258 } 259 } 260 261 void XMLSectionImportContext::ProcessAttributes( 262 const Reference<XAttributeList> & xAttrList ) 263 { 264 SvXMLTokenMap aTokenMap(aSectionTokenMap); 265 266 sal_Int16 nLength = xAttrList->getLength(); 267 for(sal_Int16 nAttr = 0; nAttr < nLength; nAttr++) 268 { 269 OUString sLocalName; 270 sal_uInt16 nNamePrefix = GetImport().GetNamespaceMap(). 271 GetKeyByAttrName( xAttrList->getNameByIndex(nAttr), 272 &sLocalName ); 273 OUString sAttr = xAttrList->getValueByIndex(nAttr); 274 275 switch (aTokenMap.Get(nNamePrefix, sLocalName)) 276 { 277 case XML_TOK_SECTION_XMLID: 278 sXmlId = sAttr; 279 break; 280 case XML_TOK_SECTION_STYLE_NAME: 281 sStyleName = sAttr; 282 break; 283 case XML_TOK_SECTION_NAME: 284 sName = sAttr; 285 bValid = sal_True; 286 break; 287 case XML_TOK_SECTION_CONDITION: 288 { 289 OUString sTmp; 290 sal_uInt16 nPrefix = GetImport().GetNamespaceMap(). 291 _GetKeyByAttrName( sAttr, &sTmp, sal_False ); 292 if( XML_NAMESPACE_OOOW == nPrefix ) 293 { 294 sCond = sTmp; 295 bCondOK = sal_True; 296 } 297 else 298 sCond = sAttr; 299 } 300 break; 301 case XML_TOK_SECTION_DISPLAY: 302 if (IsXMLToken(sAttr, XML_TRUE)) 303 { 304 bIsVisible = sal_True; 305 } 306 else if ( IsXMLToken(sAttr, XML_NONE) || 307 IsXMLToken(sAttr, XML_CONDITION) ) 308 { 309 bIsVisible = sal_False; 310 } 311 // else: ignore 312 break; 313 case XML_TOK_SECTION_IS_HIDDEN: 314 { 315 sal_Bool bTmp; 316 if (SvXMLUnitConverter::convertBool(bTmp, sAttr)) 317 { 318 bIsCurrentlyVisible = !bTmp; 319 bIsCurrentlyVisibleOK = sal_True; 320 } 321 } 322 break; 323 case XML_TOK_SECTION_PROTECTION_KEY: 324 SvXMLUnitConverter::decodeBase64(aSequence, sAttr); 325 bSequenceOK = sal_True; 326 break; 327 case XML_TOK_SECTION_PROTECT: 328 { 329 sal_Bool bTmp; 330 if (SvXMLUnitConverter::convertBool(bTmp, sAttr)) 331 { 332 bProtect = bTmp; 333 } 334 break; 335 } 336 default: 337 ; // ignore 338 break; 339 } 340 } 341 } 342 343 void XMLSectionImportContext::EndElement() 344 { 345 // get rid of last paragraph 346 // (unless it's the only paragraph in the section) 347 UniReference<XMLTextImportHelper> rHelper = GetImport().GetTextImport(); 348 rHelper->GetCursor()->goRight(1, sal_False); 349 if (bHasContent) 350 { 351 rHelper->GetCursor()->goLeft(1, sal_True); 352 rHelper->GetText()->insertString(rHelper->GetCursorAsRange(), 353 sEmpty, sal_True); 354 } 355 356 // and delete second marker 357 rHelper->GetCursor()->goRight(1, sal_True); 358 rHelper->GetText()->insertString(rHelper->GetCursorAsRange(), 359 sEmpty, sal_True); 360 361 // check for redlines to our endnode 362 rHelper->RedlineAdjustStartNodeCursor(sal_False); 363 } 364 365 SvXMLImportContext* XMLSectionImportContext::CreateChildContext( 366 sal_uInt16 nPrefix, 367 const OUString& rLocalName, 368 const Reference<XAttributeList> & xAttrList ) 369 { 370 SvXMLImportContext* pContext = NULL; 371 372 // section-source (-dde) elements 373 if ( (XML_NAMESPACE_TEXT == nPrefix) && 374 IsXMLToken(rLocalName, XML_SECTION_SOURCE) ) 375 { 376 pContext = new XMLSectionSourceImportContext(GetImport(), 377 nPrefix, rLocalName, 378 xSectionPropertySet); 379 } 380 else if ( (XML_NAMESPACE_OFFICE == nPrefix) && 381 IsXMLToken(rLocalName, XML_DDE_SOURCE) ) 382 { 383 pContext = new XMLSectionSourceDDEImportContext(GetImport(), 384 nPrefix, rLocalName, 385 xSectionPropertySet); 386 } 387 else 388 { 389 // otherwise: text context 390 pContext = GetImport().GetTextImport()->CreateTextChildContext( 391 GetImport(), nPrefix, rLocalName, xAttrList, 392 XML_TEXT_TYPE_SECTION ); 393 394 // if that fails, default context 395 if (NULL == pContext) 396 { 397 pContext = new SvXMLImportContext( GetImport(), 398 nPrefix, rLocalName ); 399 } 400 else 401 bHasContent = sal_True; 402 } 403 404 return pContext; 405 } 406 407