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