1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <libxml/xmlwriter.h> 21 22 #include "PageListWatcher.hxx" 23 #include <com/sun/star/document/PrinterIndependentLayout.hpp> 24 #include <com/sun/star/i18n/ScriptType.hpp> 25 #include <com/sun/star/beans/XPropertyContainer.hpp> 26 #include <com/sun/star/beans/PropertyAttribute.hpp> 27 #include <com/sun/star/document/XDocumentProperties.hpp> 28 #include <editeng/forbiddencharacterstable.hxx> 29 30 #include <svl/srchitem.hxx> 31 #include <editeng/eeitem.hxx> 32 #include <editeng/scriptspaceitem.hxx> 33 34 #include <unotools/configmgr.hxx> 35 #include <unotools/useroptions.hxx> 36 #include <officecfg/Office/Impress.hxx> 37 38 #include <sfx2/linkmgr.hxx> 39 #include <Outliner.hxx> 40 #include <sdmod.hxx> 41 #include <editeng/editstat.hxx> 42 #include <svx/svdotext.hxx> 43 #include <editeng/unolingu.hxx> 44 #include <svl/itempool.hxx> 45 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 46 #include <com/sun/star/beans/XPropertySet.hpp> 47 #include <editeng/outlobj.hxx> 48 #include <comphelper/getexpandeduri.hxx> 49 #include <i18nlangtag/mslangid.hxx> 50 #include <i18nlangtag/languagetag.hxx> 51 #include <unotools/charclass.hxx> 52 #include <comphelper/processfactory.hxx> 53 #include <unotools/lingucfg.hxx> 54 #include <com/sun/star/uno/Reference.hxx> 55 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp> 56 #include <com/sun/star/xml/dom/XDocument.hpp> 57 #include <com/sun/star/xml/dom/XNodeList.hpp> 58 #include <com/sun/star/xml/dom/DocumentBuilder.hpp> 59 #include <com/sun/star/uno/XComponentContext.hpp> 60 #include <rtl/ustring.hxx> 61 62 #include <editeng/outliner.hxx> 63 #include <drawdoc.hxx> 64 #include <sdpage.hxx> 65 #include <strings.hrc> 66 #include <glob.hxx> 67 #include <stlpool.hxx> 68 #include <sdresid.hxx> 69 #include <customshowlist.hxx> 70 #include <DrawDocShell.hxx> 71 #include <GraphicDocShell.hxx> 72 #include <sdxfer.hxx> 73 #include <optsitem.hxx> 74 #include <FrameView.hxx> 75 #include <undo/undomanager.hxx> 76 #include <sdundogr.hxx> 77 #include <undopage.hxx> 78 #include <vcl/settings.hxx> 79 #include <unokywds.hxx> 80 81 namespace com { namespace sun { namespace star { namespace linguistic2 { class XHyphenator; } } } } 82 namespace com { namespace sun { namespace star { namespace linguistic2 { class XSpellChecker1; } } } } 83 84 using namespace ::sd; 85 using namespace ::com::sun::star; 86 using namespace ::com::sun::star::uno; 87 using namespace ::com::sun::star::lang; 88 using namespace ::com::sun::star::linguistic2; 89 90 using namespace com::sun::star::xml::dom; 91 using ::com::sun::star::uno::Reference; 92 using ::com::sun::star::lang::XMultiServiceFactory; 93 94 95 SdDrawDocument* SdDrawDocument::s_pDocLockedInsertingLinks = nullptr; 96 97 PresentationSettings::PresentationSettings() 98 : mbAll( true ), 99 mbEndless( false ), 100 mbCustomShow(false), 101 mbManual( false ), 102 mbMouseVisible( false ), 103 mbMouseAsPen( false ), 104 mbLockedPages( false ), 105 mbAlwaysOnTop( false ), 106 mbFullScreen( true ), 107 mbAnimationAllowed( true ), 108 mnPauseTimeout( 10 ), 109 mbShowPauseLogo( false ) 110 { 111 } 112 113 SdDrawDocument::SdDrawDocument(DocumentType eType, SfxObjectShell* pDrDocSh) 114 : FmFormModel( 115 nullptr, 116 pDrDocSh) 117 , mpDocSh(static_cast< ::sd::DrawDocShell*>(pDrDocSh)) 118 , mpCreatingTransferable( nullptr ) 119 , mbHasOnlineSpellErrors(false) 120 , mbInitialOnlineSpellingEnabled(true) 121 , mbNewOrLoadCompleted(false) 122 , mbOnlineSpell(false) 123 , mbStartWithPresentation( false ) 124 , mbExitAfterPresenting( false ) 125 , meLanguage( LANGUAGE_SYSTEM ) 126 , meLanguageCJK( LANGUAGE_SYSTEM ) 127 , meLanguageCTL( LANGUAGE_SYSTEM ) 128 , mePageNumType(SVX_NUM_ARABIC) 129 , mbAllocDocSh(false) 130 , meDocType(eType) 131 , mbEmbedFonts(false) 132 , mbEmbedUsedFontsOnly(false) 133 , mbEmbedFontScriptLatin(true) 134 , mbEmbedFontScriptAsian(true) 135 , mbEmbedFontScriptComplex(true) 136 { 137 mpDrawPageListWatcher.reset(new ImpDrawPageListWatcher(*this)); 138 mpMasterPageListWatcher.reset(new ImpMasterPageListWatcher(*this)); 139 140 InitLayoutVector(); 141 InitObjectVector(); 142 SetObjectShell(pDrDocSh); // for VCDrawModel 143 144 if (mpDocSh) 145 { 146 SetSwapGraphics(); 147 } 148 149 // Set measuring unit (of the application) and scale (of SdMod) 150 sal_Int32 nX, nY; 151 SdOptions* pOptions = SD_MOD()->GetSdOptions(meDocType); 152 pOptions->GetScale( nX, nY ); 153 154 // Allow UI scale only for draw documents. 155 if( eType == DocumentType::Draw ) 156 SetUIUnit( static_cast<FieldUnit>(pOptions->GetMetric()), Fraction( nX, nY ) ); // user-defined 157 else 158 SetUIUnit( static_cast<FieldUnit>(pOptions->GetMetric()), Fraction( 1, 1 ) ); // default 159 160 SetScaleUnit(MapUnit::Map100thMM); 161 SetScaleFraction(Fraction(1, 1)); 162 SetDefaultFontHeight(847); // 24p 163 164 pItemPool->SetDefaultMetric(MapUnit::Map100thMM); 165 pItemPool->FreezeIdRanges(); 166 SetTextDefaults(); 167 168 // DrawingEngine has to know where it is... 169 FmFormModel::SetStyleSheetPool( new SdStyleSheetPool( GetPool(), this ) ); 170 171 // Set StyleSheetPool for DrawOutliner, so text objects can be read correctly. 172 // The link to the StyleRequest handler of the document is set later, in 173 // NewOrLoadCompleted, because only then do all the templates exist. 174 SdrOutliner& rOutliner = GetDrawOutliner(); 175 rOutliner.SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool())); 176 SetCalcFieldValueHdl( &rOutliner ); 177 178 // set linguistic options 179 if (!utl::ConfigManager::IsFuzzing()) 180 { 181 const SvtLinguConfig aLinguConfig; 182 SvtLinguOptions aOptions; 183 aLinguConfig.GetOptions( aOptions ); 184 185 SetLanguage( MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage, 186 css::i18n::ScriptType::LATIN), EE_CHAR_LANGUAGE ); 187 SetLanguage( MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage_CJK, 188 css::i18n::ScriptType::ASIAN), EE_CHAR_LANGUAGE_CJK ); 189 SetLanguage( MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage_CTL, 190 css::i18n::ScriptType::COMPLEX), EE_CHAR_LANGUAGE_CTL ); 191 192 mbOnlineSpell = aOptions.bIsSpellAuto; 193 } 194 195 LanguageType eRealLanguage = MsLangId::getRealLanguage( meLanguage ); 196 LanguageTag aLanguageTag( eRealLanguage); 197 mpCharClass.reset(new CharClass( aLanguageTag )); 198 199 // If the current application language is a language that uses right-to-left text... 200 LanguageType eRealCTLLanguage = Application::GetSettings().GetLanguageTag().getLanguageType(); 201 202 // for korean and japanese languages we have a different default for apply spacing between asian, latin and ctl text 203 if (MsLangId::isKorean(eRealCTLLanguage) || (LANGUAGE_JAPANESE == eRealCTLLanguage)) 204 { 205 GetPool().GetSecondaryPool()->SetPoolDefaultItem( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) ); 206 } 207 208 // Set DefTab and SpellOptions for the SD module 209 sal_uInt16 nDefTab = pOptions->GetDefTab(); 210 SetDefaultTabulator( nDefTab ); 211 212 try 213 { 214 Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() ); 215 if ( xSpellChecker.is() ) 216 rOutliner.SetSpeller( xSpellChecker ); 217 218 Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() ); 219 if( xHyphenator.is() ) 220 rOutliner.SetHyphenator( xHyphenator ); 221 222 SetForbiddenCharsTable(SvxForbiddenCharactersTable::makeForbiddenCharactersTable(::comphelper::getProcessComponentContext())); 223 } 224 catch(...) 225 { 226 OSL_FAIL("Can't get SpellChecker"); 227 } 228 229 rOutliner.SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ); 230 231 if (mpDocSh) 232 { 233 SetLinkManager( new sfx2::LinkManager(mpDocSh) ); 234 } 235 236 EEControlBits nCntrl = rOutliner.GetControlWord(); 237 nCntrl |= EEControlBits::ALLOWBIGOBJS; 238 239 if (mbOnlineSpell) 240 nCntrl |= EEControlBits::ONLINESPELLING; 241 else 242 nCntrl &= ~EEControlBits::ONLINESPELLING; 243 244 nCntrl &= ~ EEControlBits::ULSPACESUMMATION; 245 if ( meDocType != DocumentType::Impress ) 246 SetSummationOfParagraphs( false ); 247 else 248 { 249 SetSummationOfParagraphs( pOptions->IsSummationOfParagraphs() ); 250 if ( pOptions->IsSummationOfParagraphs() ) 251 nCntrl |= EEControlBits::ULSPACESUMMATION; 252 } 253 rOutliner.SetControlWord(nCntrl); 254 255 // Initialize the printer independent layout mode 256 SetPrinterIndependentLayout (pOptions->GetPrinterIndependentLayout()); 257 258 // Set the StyleSheetPool for HitTestOutliner. 259 // The link to the StyleRequest handler of the document is set later, in 260 // NewOrLoadCompleted, because only then do all the templates exist. 261 pHitTestOutliner->SetStyleSheetPool( static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()) ); 262 263 SetCalcFieldValueHdl( pHitTestOutliner.get() ); 264 265 try 266 { 267 Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() ); 268 if ( xSpellChecker.is() ) 269 pHitTestOutliner->SetSpeller( xSpellChecker ); 270 271 Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() ); 272 if( xHyphenator.is() ) 273 pHitTestOutliner->SetHyphenator( xHyphenator ); 274 } 275 catch(...) 276 { 277 OSL_FAIL("Can't get SpellChecker"); 278 } 279 280 pHitTestOutliner->SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ); 281 282 EEControlBits nCntrl2 = pHitTestOutliner->GetControlWord(); 283 nCntrl2 |= EEControlBits::ALLOWBIGOBJS; 284 nCntrl2 &= ~EEControlBits::ONLINESPELLING; 285 286 nCntrl2 &= ~ EEControlBits::ULSPACESUMMATION; 287 if ( pOptions->IsSummationOfParagraphs() ) 288 nCntrl2 |= EEControlBits::ULSPACESUMMATION; 289 290 pHitTestOutliner->SetControlWord( nCntrl2 ); 291 292 /** Create layers 293 * 294 * We create the following default layers on all pages and master pages: 295 * 296 * sUNO_LayerName_layout; "layout": default layer for drawing objects of normal pages 297 * localized by SdResId(STR_LAYER_LAYOUT) 298 * 299 * sUNO_LayerName_background; "background": background of the master page 300 * localized by SdResId(STR_LAYER_BCKGRND) 301 * (currently unused within normal pages and not visible to users) 302 * 303 * sUNO_LayerName_background_objects; "backgroundobjects": objects on the background of master pages 304 * localized by SdResId(STR_LAYER_BCKGRNDOBJ) 305 * (currently unused within normal pages) 306 * 307 * sUNO_LayerName_controls; "controls": default layer for controls 308 * localized by SdResId(STR_LAYER_CONTROLS) 309 * (currently special handling in regard to z-order) 310 * 311 * sUNO_LayerName_measurelines; "measurelines" : default layer for measure lines 312 * localized by SdResId(STR_LAYER_MEASURELINES) 313 */ 314 315 { 316 SdrLayerAdmin& rLayerAdmin = GetLayerAdmin(); 317 rLayerAdmin.NewLayer( sUNO_LayerName_layout ); 318 rLayerAdmin.NewLayer( sUNO_LayerName_background ); 319 rLayerAdmin.NewLayer( sUNO_LayerName_background_objects ); 320 rLayerAdmin.NewLayer( sUNO_LayerName_controls); 321 rLayerAdmin.NewLayer( sUNO_LayerName_measurelines ); 322 323 rLayerAdmin.SetControlLayerName(sUNO_LayerName_controls); 324 } 325 326 } 327 328 // Destructor 329 SdDrawDocument::~SdDrawDocument() 330 { 331 Broadcast(SdrHint(SdrHintKind::ModelCleared)); 332 333 if (mpWorkStartupTimer) 334 { 335 if ( mpWorkStartupTimer->IsActive() ) 336 mpWorkStartupTimer->Stop(); 337 338 mpWorkStartupTimer.reset(); 339 } 340 341 StopOnlineSpelling(); 342 mpOnlineSearchItem.reset(); 343 344 CloseBookmarkDoc(); 345 SetAllocDocSh(false); 346 347 ClearModel(true); 348 349 if (pLinkManager) 350 { 351 // Release BaseLinks 352 if ( !pLinkManager->GetLinks().empty() ) 353 { 354 pLinkManager->Remove( 0, pLinkManager->GetLinks().size() ); 355 } 356 357 delete pLinkManager; 358 pLinkManager = nullptr; 359 } 360 361 maFrameViewList.clear(); 362 mpCustomShowList.reset(); 363 mpOutliner.reset(); 364 mpInternalOutliner.reset(); 365 mpCharClass.reset(); 366 } 367 368 void SdDrawDocument::adaptSizeAndBorderForAllPages( 369 const Size& rNewSize, 370 long nLeft, 371 long nRight, 372 long nUpper, 373 long nLower) 374 { 375 const sal_uInt16 nMasterPageCnt(GetMasterSdPageCount(PageKind::Standard)); 376 const sal_uInt16 nPageCnt(GetSdPageCount(PageKind::Standard)); 377 378 if(0 == nMasterPageCnt && 0 == nPageCnt) 379 { 380 return; 381 } 382 383 SdPage* pPage(0 != nPageCnt ? GetSdPage(0, PageKind::Standard) : GetMasterSdPage(0, PageKind::Standard)); 384 385 // call fully implemented local version, including getting 386 // some more information from one of the Pages (1st one) 387 AdaptPageSizeForAllPages( 388 rNewSize, 389 PageKind::Standard, 390 nullptr, 391 nLeft, 392 nRight, 393 nUpper, 394 nLower, 395 true, 396 pPage->GetOrientation(), 397 pPage->GetPaperBin(), 398 pPage->IsBackgroundFullSize()); 399 400 // adjust handout page to new format of the standard page 401 if(0 != nPageCnt) 402 { 403 GetSdPage(0, PageKind::Handout)->CreateTitleAndLayout(true); 404 } 405 } 406 407 void SdDrawDocument::AdaptPageSizeForAllPages( 408 const Size& rNewSize, 409 PageKind ePageKind, 410 SdUndoGroup* pUndoGroup, 411 long nLeft, 412 long nRight, 413 long nUpper, 414 long nLower, 415 bool bScaleAll, 416 Orientation eOrientation, 417 sal_uInt16 nPaperBin, 418 bool bBackgroundFullSize) 419 { 420 sal_uInt16 i; 421 const sal_uInt16 nMasterPageCnt(GetMasterSdPageCount(ePageKind)); 422 const sal_uInt16 nPageCnt(GetSdPageCount(ePageKind)); 423 424 if(0 == nMasterPageCnt && 0 == nPageCnt) 425 { 426 return; 427 } 428 429 for (i = 0; i < nMasterPageCnt; i++) 430 { 431 // first, handle all master pages 432 SdPage* pPage(GetMasterSdPage(i, ePageKind)); 433 434 if(pUndoGroup) 435 { 436 SdUndoAction* pUndo( 437 new SdPageFormatUndoAction( 438 this, 439 pPage, 440 pPage->GetSize(), 441 pPage->GetLeftBorder(), pPage->GetRightBorder(), 442 pPage->GetUpperBorder(), pPage->GetLowerBorder(), 443 pPage->GetOrientation(), 444 pPage->GetPaperBin(), 445 pPage->IsBackgroundFullSize(), 446 rNewSize, 447 nLeft, nRight, 448 nUpper, nLower, 449 bScaleAll, 450 eOrientation, 451 nPaperBin, 452 bBackgroundFullSize)); 453 pUndoGroup->AddAction(pUndo); 454 } 455 456 if (rNewSize.Width() > 0 || nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0) 457 { 458 ::tools::Rectangle aNewBorderRect(nLeft, nUpper, nRight, nLower); 459 pPage->ScaleObjects(rNewSize, aNewBorderRect, bScaleAll); 460 461 if (rNewSize.Width() > 0) 462 { 463 pPage->SetSize(rNewSize); 464 } 465 } 466 467 if( nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0 ) 468 { 469 pPage->SetBorder(nLeft, nUpper, nRight, nLower); 470 } 471 472 pPage->SetOrientation(eOrientation); 473 pPage->SetPaperBin( nPaperBin ); 474 pPage->SetBackgroundFullSize( bBackgroundFullSize ); 475 476 if ( ePageKind == PageKind::Standard ) 477 { 478 GetMasterSdPage(i, PageKind::Notes)->CreateTitleAndLayout(); 479 } 480 481 pPage->CreateTitleAndLayout(); 482 } 483 484 for (i = 0; i < nPageCnt; i++) 485 { 486 // then, handle all pages 487 SdPage* pPage(GetSdPage(i, ePageKind)); 488 489 if(pUndoGroup) 490 { 491 SdUndoAction* pUndo( 492 new SdPageFormatUndoAction( 493 this, 494 pPage, 495 pPage->GetSize(), 496 pPage->GetLeftBorder(), pPage->GetRightBorder(), 497 pPage->GetUpperBorder(), pPage->GetLowerBorder(), 498 pPage->GetOrientation(), 499 pPage->GetPaperBin(), 500 pPage->IsBackgroundFullSize(), 501 rNewSize, 502 nLeft, nRight, 503 nUpper, nLower, 504 bScaleAll, 505 eOrientation, 506 nPaperBin, 507 bBackgroundFullSize)); 508 pUndoGroup->AddAction(pUndo); 509 } 510 511 if (rNewSize.Width() > 0 || nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0) 512 { 513 ::tools::Rectangle aNewBorderRect(nLeft, nUpper, nRight, nLower); 514 pPage->ScaleObjects(rNewSize, aNewBorderRect, bScaleAll); 515 516 if (rNewSize.Width() > 0) 517 { 518 pPage->SetSize(rNewSize); 519 } 520 } 521 522 if( nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0 ) 523 { 524 pPage->SetBorder(nLeft, nUpper, nRight, nLower); 525 } 526 527 pPage->SetOrientation(eOrientation); 528 pPage->SetPaperBin( nPaperBin ); 529 pPage->SetBackgroundFullSize( bBackgroundFullSize ); 530 531 if ( ePageKind == PageKind::Standard ) 532 { 533 SdPage* pNotesPage = GetSdPage(i, PageKind::Notes); 534 pNotesPage->SetAutoLayout( pNotesPage->GetAutoLayout() ); 535 } 536 537 pPage->SetAutoLayout( pPage->GetAutoLayout() ); 538 } 539 } 540 541 SdrModel* SdDrawDocument::AllocModel() const 542 { 543 return AllocSdDrawDocument(); 544 } 545 546 namespace 547 { 548 549 /// Copies all user-defined properties from pSource to pDestination. 550 void lcl_copyUserDefinedProperties(SfxObjectShell* pSource, SfxObjectShell* pDestination) 551 { 552 if (!pSource || !pDestination) 553 return; 554 555 uno::Reference<document::XDocumentProperties> xSource = pSource->getDocProperties(); 556 uno::Reference<document::XDocumentProperties> xDestination = pDestination->getDocProperties(); 557 uno::Reference<beans::XPropertyContainer> xSourcePropertyContainer = xSource->getUserDefinedProperties(); 558 uno::Reference<beans::XPropertyContainer> xDestinationPropertyContainer = xDestination->getUserDefinedProperties(); 559 uno::Reference<beans::XPropertySet> xSourcePropertySet(xSourcePropertyContainer, uno::UNO_QUERY); 560 uno::Sequence<beans::Property> aProperties = xSourcePropertySet->getPropertySetInfo()->getProperties(); 561 562 for (const beans::Property& rProperty : aProperties) 563 { 564 const OUString& rKey = rProperty.Name; 565 uno::Any aValue = xSourcePropertySet->getPropertyValue(rKey); 566 // We know that pDestination was just created, so has no properties: addProperty() will never throw. 567 xDestinationPropertyContainer->addProperty(rKey, beans::PropertyAttribute::REMOVABLE, aValue); 568 } 569 } 570 571 } 572 573 // This method creates a new document (SdDrawDocument) and returns a pointer to 574 // said document. The drawing engine uses this method to put the document (or 575 // parts of it) into the clipboard/DragServer. 576 SdDrawDocument* SdDrawDocument::AllocSdDrawDocument() const 577 { 578 SdDrawDocument* pNewModel = nullptr; 579 580 if( mpCreatingTransferable ) 581 { 582 // Document is created for drag & drop/clipboard. To be able to 583 // do this, the document has to know a DocShell (SvPersist). 584 SfxObjectShell* pObj = nullptr; 585 ::sd::DrawDocShell* pNewDocSh = nullptr; 586 587 if( meDocType == DocumentType::Impress ) 588 mpCreatingTransferable->SetDocShell( new ::sd::DrawDocShell( 589 SfxObjectCreateMode::EMBEDDED, true, meDocType ) ); 590 else 591 mpCreatingTransferable->SetDocShell( new ::sd::GraphicDocShell( 592 SfxObjectCreateMode::EMBEDDED ) ); 593 594 pObj = mpCreatingTransferable->GetDocShell().get(); 595 pNewDocSh = static_cast< ::sd::DrawDocShell*>( pObj ); 596 pNewDocSh->DoInitNew(); 597 pNewModel = pNewDocSh->GetDoc(); 598 599 // Only necessary for clipboard - 600 // for drag & drop this is handled by DragServer 601 SdStyleSheetPool* pOldStylePool = static_cast<SdStyleSheetPool*>( GetStyleSheetPool() ); 602 SdStyleSheetPool* pNewStylePool = static_cast<SdStyleSheetPool*>( pNewModel->GetStyleSheetPool() ); 603 604 pNewStylePool->CopyGraphicSheets(*pOldStylePool); 605 pNewStylePool->CopyCellSheets(*pOldStylePool); 606 pNewStylePool->CopyTableStyles(*pOldStylePool); 607 608 for (sal_uInt16 i = 0; i < GetMasterSdPageCount(PageKind::Standard); i++) 609 { 610 // Move with all of the master page's layouts 611 OUString aOldLayoutName(const_cast<SdDrawDocument*>(this)->GetMasterSdPage(i, PageKind::Standard)->GetLayoutName()); 612 aOldLayoutName = aOldLayoutName.copy( 0, aOldLayoutName.indexOf( SD_LT_SEPARATOR ) ); 613 StyleSheetCopyResultVector aCreatedSheets; 614 pNewStylePool->CopyLayoutSheets(aOldLayoutName, *pOldStylePool, aCreatedSheets ); 615 } 616 617 lcl_copyUserDefinedProperties(GetDocSh(), pNewDocSh); 618 619 pNewModel->NewOrLoadCompleted( DOC_LOADED ); // loaded from source document 620 } 621 else if( mbAllocDocSh ) 622 { 623 // Create a DocShell which is then returned with GetAllocedDocSh() 624 SdDrawDocument* pDoc = const_cast<SdDrawDocument*>(this); 625 pDoc->SetAllocDocSh(false); 626 pDoc->mxAllocedDocShRef = new ::sd::DrawDocShell( 627 SfxObjectCreateMode::EMBEDDED, true, meDocType); 628 pDoc->mxAllocedDocShRef->DoInitNew(); 629 pNewModel = pDoc->mxAllocedDocShRef->GetDoc(); 630 } 631 else 632 { 633 pNewModel = new SdDrawDocument(meDocType, nullptr); 634 } 635 636 return pNewModel; 637 } 638 639 SdPage* SdDrawDocument::AllocSdPage(bool bMasterPage) 640 { 641 return new SdPage(*this, bMasterPage); 642 } 643 644 // This method creates a new page (SdPage) and returns a pointer to said page. 645 // The drawing engine uses this method to create pages (whose types it does 646 // not know, as they are _derivatives_ of SdrPage) when loading. 647 SdrPage* SdDrawDocument::AllocPage(bool bMasterPage) 648 { 649 return AllocSdPage(bMasterPage); 650 } 651 652 // When the model has changed 653 void SdDrawDocument::SetChanged(bool bFlag) 654 { 655 if (mpDocSh) 656 { 657 if (mbNewOrLoadCompleted && mpDocSh->IsEnableSetModified()) 658 { 659 // Pass on to base class 660 FmFormModel::SetChanged(bFlag); 661 662 // Forward to ObjectShell 663 mpDocSh->SetModified(bFlag); 664 } 665 } 666 else 667 { 668 // Pass on to base class 669 FmFormModel::SetChanged(bFlag); 670 } 671 } 672 673 // The model changed, don't call anything else 674 void SdDrawDocument::NbcSetChanged(bool bFlag) 675 { 676 // forward to baseclass 677 FmFormModel::SetChanged(bFlag); 678 } 679 680 // NewOrLoadCompleted is called when the document is loaded, or when it is clear 681 // it won't load any more. 682 void SdDrawDocument::NewOrLoadCompleted(DocCreationMode eMode) 683 { 684 if (eMode == NEW_DOC) 685 { 686 // New document: 687 // create slideshow and default templates, 688 // create pool for virtual controls 689 CreateLayoutTemplates(); 690 CreateDefaultCellStyles(); 691 692 static_cast< SdStyleSheetPool* >( mxStyleSheetPool.get() )->CreatePseudosIfNecessary(); 693 } 694 else if (eMode == DOC_LOADED) 695 { 696 // Document has finished loading 697 698 CheckMasterPages(); 699 700 if ( GetMasterSdPageCount(PageKind::Standard) > 1 ) 701 RemoveUnnecessaryMasterPages( nullptr, true, false ); 702 703 for ( sal_uInt16 i = 0; i < GetPageCount(); i++ ) 704 { 705 // Check for correct layout names 706 SdPage* pPage = static_cast<SdPage*>( GetPage( i ) ); 707 708 if(pPage->TRG_HasMasterPage()) 709 { 710 SdPage& rMaster = static_cast<SdPage&>(pPage->TRG_GetMasterPage() ); 711 712 if(rMaster.GetLayoutName() != pPage->GetLayoutName()) 713 { 714 pPage->SetLayoutName(rMaster.GetLayoutName()); 715 } 716 } 717 } 718 719 for ( sal_uInt16 nPage = 0; nPage < GetMasterPageCount(); nPage++) 720 { 721 // LayoutName and PageName must be the same 722 SdPage* pPage = static_cast<SdPage*>( GetMasterPage( nPage ) ); 723 724 OUString aName( pPage->GetLayoutName() ); 725 aName = aName.copy( 0, aName.indexOf( SD_LT_SEPARATOR ) ); 726 727 if( aName != pPage->GetName() ) 728 pPage->SetName( aName ); 729 } 730 731 // Create names of the styles in the user's language 732 static_cast<SdStyleSheetPool*>(mxStyleSheetPool.get())->UpdateStdNames(); 733 734 // Create any missing styles - eg. formerly, there was no Subtitle style 735 static_cast<SdStyleSheetPool*>(mxStyleSheetPool.get())->CreatePseudosIfNecessary(); 736 } 737 738 // Set default style of Drawing Engine 739 OUString aName( SdResId(STR_STANDARD_STYLESHEET_NAME)); 740 SetDefaultStyleSheet(static_cast<SfxStyleSheet*>(mxStyleSheetPool->Find(aName, SfxStyleFamily::Para))); 741 742 // #i119287# Set default StyleSheet for SdrGrafObj and SdrOle2Obj 743 SetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj(static_cast<SfxStyleSheet*>(mxStyleSheetPool->Find(SdResId(STR_POOLSHEET_OBJNOLINENOFILL), SfxStyleFamily::Para))); 744 745 // Initialize DrawOutliner and DocumentOutliner, but don't initialize the 746 // global outliner, as it is not document specific like StyleSheetPool and 747 // StyleRequestHandler are. 748 ::Outliner& rDrawOutliner = GetDrawOutliner(); 749 rDrawOutliner.SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool())); 750 EEControlBits nCntrl = rDrawOutliner.GetControlWord(); 751 if (mbOnlineSpell) 752 nCntrl |= EEControlBits::ONLINESPELLING; 753 else 754 nCntrl &= ~EEControlBits::ONLINESPELLING; 755 rDrawOutliner.SetControlWord(nCntrl); 756 757 // Initialize HitTestOutliner and DocumentOutliner, but don't initialize the 758 // global outliner, as it is not document specific like StyleSheetPool and 759 // StyleRequestHandler are. 760 pHitTestOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool())); 761 762 if(mpOutliner) 763 { 764 mpOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool())); 765 } 766 if(mpInternalOutliner) 767 { 768 mpInternalOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool())); 769 } 770 771 if ( eMode == DOC_LOADED ) 772 { 773 // Make presentation objects listeners of the appropriate styles 774 SdStyleSheetPool* pSPool = static_cast<SdStyleSheetPool*>( GetStyleSheetPool() ); 775 sal_uInt16 nPage, nPageCount; 776 777 // create missing layout style sheets for broken documents 778 // that were created with the 5.2 779 nPageCount = GetMasterSdPageCount( PageKind::Standard ); 780 for (nPage = 0; nPage < nPageCount; nPage++) 781 { 782 SdPage* pPage = GetMasterSdPage(nPage, PageKind::Standard); 783 pSPool->CreateLayoutStyleSheets( pPage->GetName(), true ); 784 } 785 786 // Default and notes pages: 787 for (nPage = 0; nPage < GetPageCount(); nPage++) 788 { 789 SdPage* pPage = static_cast<SdPage*>(GetPage(nPage)); 790 NewOrLoadCompleted( pPage, pSPool ); 791 } 792 793 // Master pages: 794 for (nPage = 0; nPage < GetMasterPageCount(); nPage++) 795 { 796 SdPage* pPage = static_cast<SdPage*>(GetMasterPage(nPage)); 797 798 NewOrLoadCompleted( pPage, pSPool ); 799 } 800 } 801 802 mbNewOrLoadCompleted = true; 803 UpdateAllLinks(); 804 SetChanged( false ); 805 } 806 807 /** updates all links, only links in this document should by resolved */ 808 void SdDrawDocument::UpdateAllLinks() 809 { 810 if (s_pDocLockedInsertingLinks || !pLinkManager || pLinkManager->GetLinks().empty()) 811 return; 812 813 s_pDocLockedInsertingLinks = this; // lock inserting links. only links in this document should by resolved 814 815 if (mpDocSh) 816 { 817 comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = mpDocSh->getEmbeddedObjectContainer(); 818 rEmbeddedObjectContainer.setUserAllowsLinkUpdate(true); 819 } 820 821 pLinkManager->UpdateAllLinks(true, false, nullptr); // query box: update all links? 822 823 if (s_pDocLockedInsertingLinks == this) 824 s_pDocLockedInsertingLinks = nullptr; // unlock inserting links 825 } 826 827 /** this loops over the presentation objects of a page and repairs some new settings 828 from old binary files and resets all default strings for empty presentation objects. 829 */ 830 void SdDrawDocument::NewOrLoadCompleted( SdPage* pPage, SdStyleSheetPool* pSPool ) 831 { 832 sd::ShapeList& rPresentationShapes( pPage->GetPresentationShapeList() ); 833 if(rPresentationShapes.isEmpty()) 834 return; 835 836 // Create lists of title and outline styles 837 OUString aName = pPage->GetLayoutName(); 838 aName = aName.copy( 0, aName.indexOf( SD_LT_SEPARATOR ) ); 839 840 std::vector<SfxStyleSheetBase*> aOutlineList; 841 pSPool->CreateOutlineSheetList(aName,aOutlineList); 842 843 SfxStyleSheet* pTitleSheet = static_cast<SfxStyleSheet*>(pSPool->GetTitleSheet(aName)); 844 845 SdrObject* pObj = nullptr; 846 rPresentationShapes.seekShape(0); 847 848 // Now look for title and outline text objects, then make those objects 849 // listeners. 850 while( (pObj = rPresentationShapes.getNextShape()) ) 851 { 852 if (pObj->GetObjInventor() == SdrInventor::Default) 853 { 854 OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject(); 855 sal_uInt16 nId = pObj->GetObjIdentifier(); 856 857 if (nId == OBJ_TITLETEXT) 858 { 859 if( pOPO && pOPO->GetOutlinerMode() == OutlinerMode::DontKnow ) 860 pOPO->SetOutlinerMode( OutlinerMode::TitleObject ); 861 862 // sal_True: don't delete "hard" attributes when doing this. 863 if (pTitleSheet) 864 pObj->SetStyleSheet(pTitleSheet, true); 865 } 866 else if (nId == OBJ_OUTLINETEXT) 867 { 868 if( pOPO && pOPO->GetOutlinerMode() == OutlinerMode::DontKnow ) 869 pOPO->SetOutlinerMode( OutlinerMode::OutlineObject ); 870 871 std::vector<SfxStyleSheetBase*>::iterator iter; 872 for (iter = aOutlineList.begin(); iter != aOutlineList.end(); ++iter) 873 { 874 SfxStyleSheet* pSheet = static_cast<SfxStyleSheet*>(*iter); 875 876 if (pSheet) 877 { 878 pObj->StartListening(*pSheet); 879 880 if( iter == aOutlineList.begin()) 881 // text frame listens to stylesheet of layer 1 882 pObj->NbcSetStyleSheet(pSheet, true); 883 } 884 } 885 } 886 887 if( dynamic_cast< const SdrTextObj *>( pObj ) != nullptr && pObj->IsEmptyPresObj()) 888 { 889 PresObjKind ePresObjKind = pPage->GetPresObjKind(pObj); 890 OUString aString( pPage->GetPresObjText(ePresObjKind) ); 891 892 if (!aString.isEmpty()) 893 { 894 SdOutliner* pInternalOutl = GetInternalOutliner(); 895 pPage->SetObjText( static_cast<SdrTextObj*>(pObj), pInternalOutl, ePresObjKind, aString ); 896 pObj->NbcSetStyleSheet( pPage->GetStyleSheetForPresObj( ePresObjKind ), true ); 897 pInternalOutl->Clear(); 898 } 899 } 900 } 901 } 902 } 903 904 // Local outliner that is used for outline mode. In this outliner, OutlinerViews 905 // may be inserted. 906 SdOutliner* SdDrawDocument::GetOutliner(bool bCreateOutliner) 907 { 908 if (!mpOutliner && bCreateOutliner) 909 { 910 mpOutliner.reset(new SdOutliner( this, OutlinerMode::TextObject )); 911 912 if (mpDocSh) 913 mpOutliner->SetRefDevice( SD_MOD()->GetVirtualRefDevice() ); 914 915 mpOutliner->SetDefTab( nDefaultTabulator ); 916 mpOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool())); 917 } 918 919 return mpOutliner.get(); 920 } 921 922 // Internal outliner that is used to create text objects. We don't insert any 923 // OutlinerViews into this outliner! 924 SdOutliner* SdDrawDocument::GetInternalOutliner(bool bCreateOutliner) 925 { 926 if ( !mpInternalOutliner && bCreateOutliner ) 927 { 928 mpInternalOutliner.reset( new SdOutliner( this, OutlinerMode::TextObject ) ); 929 930 // This outliner is only used to create special text objects. As no 931 // information about portions is saved in this outliner, the update mode 932 // can/should always remain sal_False. 933 mpInternalOutliner->SetUpdateMode( false ); 934 mpInternalOutliner->EnableUndo( false ); 935 936 if (mpDocSh) 937 mpInternalOutliner->SetRefDevice( SD_MOD()->GetVirtualRefDevice() ); 938 939 mpInternalOutliner->SetDefTab( nDefaultTabulator ); 940 mpInternalOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool())); 941 } 942 943 DBG_ASSERT( !mpInternalOutliner || ( ! mpInternalOutliner->GetUpdateMode() ) , "InternalOutliner: UpdateMode = sal_True !" ); 944 DBG_ASSERT( !mpInternalOutliner || ( ! mpInternalOutliner->IsUndoEnabled() ), "InternalOutliner: Undo = sal_True !" ); 945 946 // If you add stuff here, always clear it out. 947 // Advantages: 948 // a) no unnecessary Clear calls 949 // b) no wasted memory 950 DBG_ASSERT( !mpInternalOutliner || ( ( mpInternalOutliner->GetParagraphCount() == 1 ) && ( mpInternalOutliner->GetText( mpInternalOutliner->GetParagraph( 0 ) ).isEmpty() ) ), "InternalOutliner: not empty!" ); 951 952 return mpInternalOutliner.get(); 953 } 954 955 // OnlineSpelling on/off 956 void SdDrawDocument::SetOnlineSpell(bool bIn) 957 { 958 mbOnlineSpell = bIn; 959 EEControlBits nCntrl; 960 961 if(mpOutliner) 962 { 963 nCntrl = mpOutliner->GetControlWord(); 964 965 if(mbOnlineSpell) 966 nCntrl |= EEControlBits::ONLINESPELLING; 967 else 968 nCntrl &= ~EEControlBits::ONLINESPELLING; 969 970 mpOutliner->SetControlWord(nCntrl); 971 } 972 973 if (mpInternalOutliner) 974 { 975 nCntrl = mpInternalOutliner->GetControlWord(); 976 977 if (mbOnlineSpell) 978 nCntrl |= EEControlBits::ONLINESPELLING; 979 else 980 nCntrl &= ~EEControlBits::ONLINESPELLING; 981 982 mpInternalOutliner->SetControlWord(nCntrl); 983 } 984 985 ::Outliner& rOutliner = GetDrawOutliner(); 986 987 nCntrl = rOutliner.GetControlWord(); 988 989 if (mbOnlineSpell) 990 nCntrl |= EEControlBits::ONLINESPELLING; 991 else 992 nCntrl &= ~EEControlBits::ONLINESPELLING; 993 994 rOutliner.SetControlWord(nCntrl); 995 996 if (mbOnlineSpell) 997 { 998 StartOnlineSpelling(); 999 } 1000 else 1001 { 1002 StopOnlineSpelling(); 1003 } 1004 } 1005 1006 // OnlineSpelling: highlighting on/off 1007 uno::Reference< uno::XInterface > SdDrawDocument::createUnoModel() 1008 { 1009 uno::Reference< uno::XInterface > xModel; 1010 1011 try 1012 { 1013 if ( mpDocSh ) 1014 xModel = mpDocSh->GetModel(); 1015 } 1016 catch( uno::RuntimeException& ) 1017 { 1018 } 1019 1020 return xModel; 1021 } 1022 1023 SvxNumType SdDrawDocument::GetPageNumType() const 1024 { 1025 return mePageNumType; 1026 } 1027 1028 void SdDrawDocument::SetPrinterIndependentLayout (sal_Int32 nMode) 1029 { 1030 switch (nMode) 1031 { 1032 case css::document::PrinterIndependentLayout::DISABLED: 1033 case css::document::PrinterIndependentLayout::ENABLED: 1034 // Just store supported modes and inform the doc shell 1035 mnPrinterIndependentLayout = nMode; 1036 1037 // Since it is possible that a SdDrawDocument is constructed without a 1038 // SdDrawDocShell the pointer member mpDocSh needs to be tested 1039 // before the call is executed. This is e. g. used for copy/paste. 1040 if(mpDocSh) 1041 { 1042 mpDocSh->UpdateRefDevice (); 1043 } 1044 1045 break; 1046 1047 default: 1048 // Ignore unknown values 1049 break; 1050 } 1051 } 1052 1053 void SdDrawDocument::SetStartWithPresentation( bool bStartWithPresentation ) 1054 { 1055 mbStartWithPresentation = bStartWithPresentation; 1056 } 1057 1058 void SdDrawDocument::SetExitAfterPresenting( bool bExitAfterPresenting ) 1059 { 1060 mbExitAfterPresenting = bExitAfterPresenting; 1061 } 1062 1063 void SdDrawDocument::PageListChanged() 1064 { 1065 mpDrawPageListWatcher->Invalidate(); 1066 } 1067 1068 void SdDrawDocument::MasterPageListChanged() 1069 { 1070 mpMasterPageListWatcher->Invalidate(); 1071 } 1072 1073 void SdDrawDocument::SetCalcFieldValueHdl(::Outliner* pOutliner) 1074 { 1075 pOutliner->SetCalcFieldValueHdl(LINK(SD_MOD(), SdModule, CalcFieldValueHdl)); 1076 } 1077 1078 sal_uInt16 SdDrawDocument::GetAnnotationAuthorIndex( const OUString& rAuthor ) 1079 { 1080 // force current user to have first color 1081 if( maAnnotationAuthors.empty() ) 1082 { 1083 SvtUserOptions aUserOptions; 1084 maAnnotationAuthors.push_back( aUserOptions.GetFullName() ); 1085 } 1086 1087 auto iter = std::find(maAnnotationAuthors.begin(), maAnnotationAuthors.end(), rAuthor); 1088 sal_uInt16 idx = static_cast<sal_uInt16>(std::distance(maAnnotationAuthors.begin(), iter)); 1089 1090 if( idx == maAnnotationAuthors.size() ) 1091 { 1092 maAnnotationAuthors.push_back( rAuthor ); 1093 } 1094 1095 return idx; 1096 } 1097 1098 void SdDrawDocument::InitLayoutVector() 1099 { 1100 if (utl::ConfigManager::IsFuzzing()) 1101 return; 1102 1103 const Reference<css::uno::XComponentContext> xContext( 1104 ::comphelper::getProcessComponentContext() ); 1105 1106 // get file list from configuration 1107 Sequence< OUString > aFiles( 1108 officecfg::Office::Impress::Misc::LayoutListFiles::get(xContext) ); 1109 1110 OUString sFilename; 1111 for( sal_Int32 i=0; i < aFiles.getLength(); ++i ) 1112 { 1113 sFilename = comphelper::getExpandedUri(xContext, aFiles[i]); 1114 1115 // load layout file into DOM 1116 Reference< XMultiServiceFactory > xServiceFactory( 1117 xContext->getServiceManager() , UNO_QUERY_THROW ); 1118 const Reference<XDocumentBuilder> xDocBuilder( 1119 DocumentBuilder::create( comphelper::getComponentContext (xServiceFactory) )); 1120 1121 try 1122 { 1123 // loop over every layout entry in current file 1124 const Reference<XDocument> xDoc = xDocBuilder->parseURI( sFilename ); 1125 const Reference<XNodeList> layoutlist = xDoc->getElementsByTagName("layout"); 1126 const int nElements = layoutlist->getLength(); 1127 for(int index=0; index < nElements; index++) 1128 maLayoutInfo.push_back( layoutlist->item(index) ); 1129 } 1130 catch (const uno::Exception &) 1131 { 1132 // skip missing config. files 1133 } 1134 } 1135 } 1136 1137 void SdDrawDocument::InitObjectVector() 1138 { 1139 if (utl::ConfigManager::IsFuzzing()) 1140 return; 1141 1142 const Reference<css::uno::XComponentContext> xContext( 1143 ::comphelper::getProcessComponentContext() ); 1144 1145 // get file list from configuration 1146 Sequence< OUString > aFiles( 1147 officecfg::Office::Impress::Misc::PresObjListFiles::get(xContext) ); 1148 1149 OUString sFilename; 1150 for( sal_Int32 i=0; i < aFiles.getLength(); ++i ) 1151 { 1152 sFilename = comphelper::getExpandedUri(xContext, aFiles[i]); 1153 1154 // load presentation object file into DOM 1155 Reference< XMultiServiceFactory > xServiceFactory( 1156 xContext->getServiceManager() , UNO_QUERY_THROW ); 1157 const Reference<XDocumentBuilder> xDocBuilder( 1158 DocumentBuilder::create( comphelper::getComponentContext (xServiceFactory) )); 1159 1160 try 1161 { 1162 // loop over every object entry in current file 1163 const Reference<XDocument> xDoc = xDocBuilder->parseURI( sFilename ); 1164 const Reference<XNodeList> objectlist = xDoc->getElementsByTagName("object"); 1165 const int nElements = objectlist->getLength(); 1166 for(int index=0; index < nElements; index++) 1167 maPresObjectInfo.push_back( objectlist->item(index) ); 1168 } 1169 catch (const uno::Exception &) 1170 { 1171 // skip missing config. files 1172 } 1173 } 1174 } 1175 1176 void SdDrawDocument::dumpAsXml(xmlTextWriterPtr pWriter) const 1177 { 1178 bool bOwns = false; 1179 if (!pWriter) 1180 { 1181 pWriter = xmlNewTextWriterFilename("model.xml", 0); 1182 xmlTextWriterSetIndent(pWriter,1); 1183 xmlTextWriterSetIndentString(pWriter, BAD_CAST(" ")); 1184 xmlTextWriterStartDocument(pWriter, nullptr, nullptr, nullptr); 1185 bOwns = true; 1186 } 1187 xmlTextWriterStartElement(pWriter, BAD_CAST("SdDrawDocument")); 1188 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); 1189 1190 if (mpOutliner) 1191 mpOutliner->dumpAsXml(pWriter); 1192 FmFormModel::dumpAsXml(pWriter); 1193 if (GetUndoManager()) 1194 GetUndoManager()->dumpAsXml(pWriter); 1195 1196 xmlTextWriterEndElement(pWriter); 1197 if (bOwns) 1198 { 1199 xmlTextWriterEndDocument(pWriter); 1200 xmlFreeTextWriter(pWriter); 1201 } 1202 } 1203 1204 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1205
