summaryrefslogtreecommitdiffstats
path: root/sd/source/core/drawdoc.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sd/source/core/drawdoc.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sd/source/core/drawdoc.cxx')
-rw-r--r--sd/source/core/drawdoc.cxx1206
1 files changed, 1206 insertions, 0 deletions
diff --git a/sd/source/core/drawdoc.cxx b/sd/source/core/drawdoc.cxx
new file mode 100644
index 000000000..182ffe7f2
--- /dev/null
+++ b/sd/source/core/drawdoc.cxx
@@ -0,0 +1,1206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <libxml/xmlwriter.h>
+
+#include "PageListWatcher.hxx"
+#include <com/sun/star/document/PrinterIndependentLayout.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/beans/XPropertyContainer.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <editeng/forbiddencharacterstable.hxx>
+
+#include <svl/srchitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/scriptspaceitem.hxx>
+#include <tools/debug.hxx>
+
+#include <unotools/configmgr.hxx>
+#include <unotools/useroptions.hxx>
+#include <officecfg/Office/Impress.hxx>
+
+#include <sfx2/linkmgr.hxx>
+#include <Outliner.hxx>
+#include <sdmod.hxx>
+#include <editeng/editstat.hxx>
+#include <svx/svdotext.hxx>
+#include <editeng/unolingu.hxx>
+#include <svl/itempool.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <editeng/outlobj.hxx>
+#include <comphelper/getexpandeduri.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <unotools/charclass.hxx>
+#include <comphelper/processfactory.hxx>
+#include <unotools/lingucfg.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
+#include <com/sun/star/xml/dom/XDocument.hpp>
+#include <com/sun/star/xml/dom/XNodeList.hpp>
+#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <rtl/ustring.hxx>
+
+#include <editeng/outliner.hxx>
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <strings.hrc>
+#include <glob.hxx>
+#include <stlpool.hxx>
+#include <sdresid.hxx>
+#include <customshowlist.hxx>
+#include <DrawDocShell.hxx>
+#include <GraphicDocShell.hxx>
+#include <sdxfer.hxx>
+#include <optsitem.hxx>
+#include <FrameView.hxx>
+#include <undo/undomanager.hxx>
+#include <sdundogr.hxx>
+#include <undopage.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <unokywds.hxx>
+
+namespace com::sun::star::linguistic2 { class XHyphenator; }
+namespace com::sun::star::linguistic2 { class XSpellChecker1; }
+
+using namespace ::sd;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::linguistic2;
+
+using namespace com::sun::star::xml::dom;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::lang::XMultiServiceFactory;
+
+
+SdDrawDocument* SdDrawDocument::s_pDocLockedInsertingLinks = nullptr;
+
+PresentationSettings::PresentationSettings()
+: mbAll( true ),
+ mbEndless( false ),
+ mbCustomShow(false),
+ mbManual( false ),
+ mbMouseVisible( false ),
+ mbMouseAsPen( false ),
+ mbLockedPages( false ),
+ mbAlwaysOnTop( false ),
+ mbFullScreen( true ),
+ mbAnimationAllowed( true ),
+ mnPauseTimeout( 0 ),
+ mbShowPauseLogo( false ),
+ mbStartCustomShow( false )
+{
+}
+
+SdDrawDocument::SdDrawDocument(DocumentType eType, SfxObjectShell* pDrDocSh)
+: FmFormModel(
+ nullptr,
+ pDrDocSh)
+, mpDocSh(static_cast< ::sd::DrawDocShell*>(pDrDocSh))
+, mpCreatingTransferable( nullptr )
+, mbHasOnlineSpellErrors(false)
+, mbInitialOnlineSpellingEnabled(true)
+, mbNewOrLoadCompleted(false)
+, mbOnlineSpell(false)
+, mbStartWithPresentation( false )
+, mbExitAfterPresenting( false )
+, meLanguage( LANGUAGE_SYSTEM )
+, meLanguageCJK( LANGUAGE_SYSTEM )
+, meLanguageCTL( LANGUAGE_SYSTEM )
+, mePageNumType(SVX_NUM_ARABIC)
+, mbAllocDocSh(false)
+, meDocType(eType)
+, mbEmbedFonts(false)
+, mbEmbedUsedFontsOnly(false)
+, mbEmbedFontScriptLatin(true)
+, mbEmbedFontScriptAsian(true)
+, mbEmbedFontScriptComplex(true)
+, mnImagePreferredDPI(0)
+{
+ mpDrawPageListWatcher.reset(new ImpDrawPageListWatcher(*this));
+ mpMasterPageListWatcher.reset(new ImpMasterPageListWatcher(*this));
+
+ InitLayoutVector();
+ InitObjectVector();
+ SetObjectShell(pDrDocSh); // for VCDrawModel
+
+ if (mpDocSh)
+ {
+ SetSwapGraphics();
+ }
+
+ // Set measuring unit (of the application) and scale (of SdMod)
+ sal_Int32 nX, nY;
+ SdOptions* pOptions = SD_MOD()->GetSdOptions(meDocType);
+ pOptions->GetScale( nX, nY );
+
+ // Allow UI scale only for draw documents.
+ if( eType == DocumentType::Draw )
+ SetUIUnit( static_cast<FieldUnit>(pOptions->GetMetric()), Fraction( nX, nY ) ); // user-defined
+ else
+ SetUIUnit( static_cast<FieldUnit>(pOptions->GetMetric()), Fraction( 1, 1 ) ); // default
+
+ SetScaleUnit(MapUnit::Map100thMM);
+ SetScaleFraction(Fraction(1, 1));
+ SetDefaultFontHeight(o3tl::convert(24, o3tl::Length::pt, o3tl::Length::mm100));
+
+ m_pItemPool->SetDefaultMetric(MapUnit::Map100thMM);
+ m_pItemPool->FreezeIdRanges();
+ SetTextDefaults();
+
+ // DrawingEngine has to know where it is...
+ FmFormModel::SetStyleSheetPool( new SdStyleSheetPool( GetPool(), this ) );
+
+ // Set StyleSheetPool for DrawOutliner, so text objects can be read correctly.
+ // The link to the StyleRequest handler of the document is set later, in
+ // NewOrLoadCompleted, because only then do all the templates exist.
+ SdrOutliner& rOutliner = GetDrawOutliner();
+ rOutliner.SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ SetCalcFieldValueHdl( &rOutliner );
+
+ // set linguistic options
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ const SvtLinguConfig aLinguConfig;
+ SvtLinguOptions aOptions;
+ aLinguConfig.GetOptions( aOptions );
+
+ SetLanguage( MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage,
+ css::i18n::ScriptType::LATIN), EE_CHAR_LANGUAGE );
+ SetLanguage( MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage_CJK,
+ css::i18n::ScriptType::ASIAN), EE_CHAR_LANGUAGE_CJK );
+ SetLanguage( MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage_CTL,
+ css::i18n::ScriptType::COMPLEX), EE_CHAR_LANGUAGE_CTL );
+
+ mbOnlineSpell = aOptions.bIsSpellAuto;
+ }
+
+ LanguageType eRealLanguage = MsLangId::getRealLanguage( meLanguage );
+ mpCharClass.reset(new CharClass( LanguageTag( eRealLanguage) ));
+
+ // If the current application language is a language that uses right-to-left text...
+ LanguageType eRealCTLLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
+
+ // for korean and japanese languages we have a different default for apply spacing between asian, latin and ctl text
+ if (MsLangId::isKorean(eRealCTLLanguage) || (LANGUAGE_JAPANESE == eRealCTLLanguage))
+ {
+ GetPool().GetSecondaryPool()->SetPoolDefaultItem( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
+ }
+
+ // Set DefTab and SpellOptions for the SD module
+ sal_uInt16 nDefTab = pOptions->GetDefTab();
+ SetDefaultTabulator( nDefTab );
+
+ try
+ {
+ Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() );
+ if ( xSpellChecker.is() )
+ rOutliner.SetSpeller( xSpellChecker );
+
+ Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() );
+ if( xHyphenator.is() )
+ rOutliner.SetHyphenator( xHyphenator );
+
+ SetForbiddenCharsTable(SvxForbiddenCharactersTable::makeForbiddenCharactersTable(::comphelper::getProcessComponentContext()));
+ }
+ catch(...)
+ {
+ OSL_FAIL("Can't get SpellChecker");
+ }
+
+ rOutliner.SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
+
+ if (mpDocSh)
+ {
+ SetLinkManager( new sfx2::LinkManager(mpDocSh) );
+ }
+
+ EEControlBits nCntrl = rOutliner.GetControlWord();
+ nCntrl |= EEControlBits::ALLOWBIGOBJS;
+
+ if (mbOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+
+ nCntrl &= ~ EEControlBits::ULSPACESUMMATION;
+ if ( meDocType != DocumentType::Impress )
+ SetSummationOfParagraphs( false );
+ else
+ {
+ SetSummationOfParagraphs( pOptions->IsSummationOfParagraphs() );
+ if ( pOptions->IsSummationOfParagraphs() )
+ nCntrl |= EEControlBits::ULSPACESUMMATION;
+ }
+ rOutliner.SetControlWord(nCntrl);
+
+ // Initialize the printer independent layout mode
+ SetPrinterIndependentLayout (pOptions->GetPrinterIndependentLayout());
+
+ // Set the StyleSheetPool for HitTestOutliner.
+ // The link to the StyleRequest handler of the document is set later, in
+ // NewOrLoadCompleted, because only then do all the templates exist.
+ m_pHitTestOutliner->SetStyleSheetPool( static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()) );
+
+ SetCalcFieldValueHdl( m_pHitTestOutliner.get() );
+
+ try
+ {
+ Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() );
+ if ( xSpellChecker.is() )
+ m_pHitTestOutliner->SetSpeller( xSpellChecker );
+
+ Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() );
+ if( xHyphenator.is() )
+ m_pHitTestOutliner->SetHyphenator( xHyphenator );
+ }
+ catch(...)
+ {
+ OSL_FAIL("Can't get SpellChecker");
+ }
+
+ m_pHitTestOutliner->SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
+
+ EEControlBits nCntrl2 = m_pHitTestOutliner->GetControlWord();
+ nCntrl2 |= EEControlBits::ALLOWBIGOBJS;
+ nCntrl2 &= ~EEControlBits::ONLINESPELLING;
+
+ nCntrl2 &= ~ EEControlBits::ULSPACESUMMATION;
+ if ( pOptions->IsSummationOfParagraphs() )
+ nCntrl2 |= EEControlBits::ULSPACESUMMATION;
+
+ m_pHitTestOutliner->SetControlWord( nCntrl2 );
+
+ /** Create layers
+ *
+ * We create the following default layers on all pages and master pages:
+ *
+ * sUNO_LayerName_layout; "layout": default layer for drawing objects of normal pages
+ * localized by SdResId(STR_LAYER_LAYOUT)
+ *
+ * sUNO_LayerName_background; "background": background of the master page
+ * localized by SdResId(STR_LAYER_BCKGRND)
+ * (currently unused within normal pages and not visible to users)
+ *
+ * sUNO_LayerName_background_objects; "backgroundobjects": objects on the background of master pages
+ * localized by SdResId(STR_LAYER_BCKGRNDOBJ)
+ * (currently unused within normal pages)
+ *
+ * sUNO_LayerName_controls; "controls": default layer for controls
+ * localized by SdResId(STR_LAYER_CONTROLS)
+ * (currently special handling in regard to z-order)
+ *
+ * sUNO_LayerName_measurelines; "measurelines" : default layer for measure lines
+ * localized by SdResId(STR_LAYER_MEASURELINES)
+ */
+
+ {
+ SdrLayerAdmin& rLayerAdmin = GetLayerAdmin();
+ rLayerAdmin.NewLayer( sUNO_LayerName_layout );
+ rLayerAdmin.NewLayer( sUNO_LayerName_background );
+ rLayerAdmin.NewLayer( sUNO_LayerName_background_objects );
+ rLayerAdmin.NewLayer( sUNO_LayerName_controls);
+ rLayerAdmin.NewLayer( sUNO_LayerName_measurelines );
+
+ rLayerAdmin.SetControlLayerName(sUNO_LayerName_controls);
+ }
+
+}
+
+// Destructor
+SdDrawDocument::~SdDrawDocument()
+{
+ Broadcast(SdrHint(SdrHintKind::ModelCleared));
+
+ if (mpWorkStartupTimer)
+ {
+ if ( mpWorkStartupTimer->IsActive() )
+ mpWorkStartupTimer->Stop();
+
+ mpWorkStartupTimer.reset();
+ }
+
+ StopOnlineSpelling();
+ mpOnlineSearchItem.reset();
+
+ CloseBookmarkDoc();
+ SetAllocDocSh(false);
+
+ ClearModel(true);
+
+ if (m_pLinkManager)
+ {
+ // Release BaseLinks
+ if ( !m_pLinkManager->GetLinks().empty() )
+ {
+ m_pLinkManager->Remove( 0, m_pLinkManager->GetLinks().size() );
+ }
+
+ delete m_pLinkManager;
+ m_pLinkManager = nullptr;
+ }
+
+ maFrameViewList.clear();
+ mpCustomShowList.reset();
+ mpOutliner.reset();
+ mpInternalOutliner.reset();
+ mpCharClass.reset();
+}
+
+void SdDrawDocument::adaptSizeAndBorderForAllPages(
+ const Size& rNewSize,
+ ::tools::Long nLeft,
+ ::tools::Long nRight,
+ ::tools::Long nUpper,
+ ::tools::Long nLower)
+{
+ const sal_uInt16 nMasterPageCnt(GetMasterSdPageCount(PageKind::Standard));
+ const sal_uInt16 nPageCnt(GetSdPageCount(PageKind::Standard));
+
+ if(0 == nMasterPageCnt && 0 == nPageCnt)
+ {
+ return;
+ }
+
+ SdPage* pPage(0 != nPageCnt ? GetSdPage(0, PageKind::Standard) : GetMasterSdPage(0, PageKind::Standard));
+
+ // call fully implemented local version, including getting
+ // some more information from one of the Pages (1st one)
+ AdaptPageSizeForAllPages(
+ rNewSize,
+ PageKind::Standard,
+ nullptr,
+ nLeft,
+ nRight,
+ nUpper,
+ nLower,
+ true,
+ pPage->GetOrientation(),
+ pPage->GetPaperBin(),
+ pPage->IsBackgroundFullSize());
+
+ // adjust handout page to new format of the standard page
+ if(0 != nPageCnt)
+ {
+ GetSdPage(0, PageKind::Handout)->CreateTitleAndLayout(true);
+ }
+}
+
+void SdDrawDocument::AdaptPageSizeForAllPages(
+ const Size& rNewSize,
+ PageKind ePageKind,
+ SdUndoGroup* pUndoGroup,
+ ::tools::Long nLeft,
+ ::tools::Long nRight,
+ ::tools::Long nUpper,
+ ::tools::Long nLower,
+ bool bScaleAll,
+ Orientation eOrientation,
+ sal_uInt16 nPaperBin,
+ bool bBackgroundFullSize)
+{
+ sal_uInt16 i;
+ const sal_uInt16 nMasterPageCnt(GetMasterSdPageCount(ePageKind));
+ const sal_uInt16 nPageCnt(GetSdPageCount(ePageKind));
+
+ if(0 == nMasterPageCnt && 0 == nPageCnt)
+ {
+ return;
+ }
+
+ for (i = 0; i < nMasterPageCnt; i++)
+ {
+ // first, handle all master pages
+ SdPage* pPage(GetMasterSdPage(i, ePageKind));
+
+ if(pUndoGroup)
+ {
+ SdUndoAction* pUndo(
+ new SdPageFormatUndoAction(
+ this,
+ pPage,
+ pPage->GetSize(),
+ pPage->GetLeftBorder(), pPage->GetRightBorder(),
+ pPage->GetUpperBorder(), pPage->GetLowerBorder(),
+ pPage->GetOrientation(),
+ pPage->GetPaperBin(),
+ pPage->IsBackgroundFullSize(),
+ rNewSize,
+ nLeft, nRight,
+ nUpper, nLower,
+ bScaleAll,
+ eOrientation,
+ nPaperBin,
+ bBackgroundFullSize));
+ pUndoGroup->AddAction(pUndo);
+ }
+
+ if (rNewSize.Width() > 0 || nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0)
+ {
+ ::tools::Rectangle aNewBorderRect(nLeft, nUpper, nRight, nLower);
+ pPage->ScaleObjects(rNewSize, aNewBorderRect, bScaleAll);
+
+ if (rNewSize.Width() > 0)
+ {
+ pPage->SetSize(rNewSize);
+ }
+ }
+
+ if( nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0 )
+ {
+ pPage->SetBorder(nLeft, nUpper, nRight, nLower);
+ }
+
+ pPage->SetOrientation(eOrientation);
+ pPage->SetPaperBin( nPaperBin );
+ pPage->SetBackgroundFullSize( bBackgroundFullSize );
+
+ if ( ePageKind == PageKind::Standard )
+ {
+ GetMasterSdPage(i, PageKind::Notes)->CreateTitleAndLayout();
+ }
+
+ pPage->CreateTitleAndLayout();
+ }
+
+ for (i = 0; i < nPageCnt; i++)
+ {
+ // then, handle all pages
+ SdPage* pPage(GetSdPage(i, ePageKind));
+
+ if(pUndoGroup)
+ {
+ SdUndoAction* pUndo(
+ new SdPageFormatUndoAction(
+ this,
+ pPage,
+ pPage->GetSize(),
+ pPage->GetLeftBorder(), pPage->GetRightBorder(),
+ pPage->GetUpperBorder(), pPage->GetLowerBorder(),
+ pPage->GetOrientation(),
+ pPage->GetPaperBin(),
+ pPage->IsBackgroundFullSize(),
+ rNewSize,
+ nLeft, nRight,
+ nUpper, nLower,
+ bScaleAll,
+ eOrientation,
+ nPaperBin,
+ bBackgroundFullSize));
+ pUndoGroup->AddAction(pUndo);
+ }
+
+ if (rNewSize.Width() > 0 || nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0)
+ {
+ ::tools::Rectangle aNewBorderRect(nLeft, nUpper, nRight, nLower);
+ pPage->ScaleObjects(rNewSize, aNewBorderRect, bScaleAll);
+
+ if (rNewSize.Width() > 0)
+ {
+ pPage->SetSize(rNewSize);
+ }
+ }
+
+ if( nLeft >= 0 || nRight >= 0 || nUpper >= 0 || nLower >= 0 )
+ {
+ pPage->SetBorder(nLeft, nUpper, nRight, nLower);
+ }
+
+ pPage->SetOrientation(eOrientation);
+ pPage->SetPaperBin( nPaperBin );
+ pPage->SetBackgroundFullSize( bBackgroundFullSize );
+
+ if ( ePageKind == PageKind::Standard )
+ {
+ SdPage* pNotesPage = GetSdPage(i, PageKind::Notes);
+ pNotesPage->SetAutoLayout( pNotesPage->GetAutoLayout() );
+ }
+
+ pPage->SetAutoLayout( pPage->GetAutoLayout() );
+ }
+}
+
+SdrModel* SdDrawDocument::AllocModel() const
+{
+ return AllocSdDrawDocument();
+}
+
+namespace
+{
+
+/// Copies all user-defined properties from pSource to pDestination.
+void lcl_copyUserDefinedProperties(const SfxObjectShell* pSource, const SfxObjectShell* pDestination)
+{
+ if (!pSource || !pDestination)
+ return;
+
+ uno::Reference<document::XDocumentProperties> xSource = pSource->getDocProperties();
+ uno::Reference<document::XDocumentProperties> xDestination = pDestination->getDocProperties();
+ uno::Reference<beans::XPropertyContainer> xSourcePropertyContainer = xSource->getUserDefinedProperties();
+ uno::Reference<beans::XPropertyContainer> xDestinationPropertyContainer = xDestination->getUserDefinedProperties();
+ uno::Reference<beans::XPropertySet> xSourcePropertySet(xSourcePropertyContainer, uno::UNO_QUERY);
+ const uno::Sequence<beans::Property> aProperties = xSourcePropertySet->getPropertySetInfo()->getProperties();
+
+ for (const beans::Property& rProperty : aProperties)
+ {
+ const OUString& rKey = rProperty.Name;
+ uno::Any aValue = xSourcePropertySet->getPropertyValue(rKey);
+ // We know that pDestination was just created, so has no properties: addProperty() will never throw.
+ xDestinationPropertyContainer->addProperty(rKey, beans::PropertyAttribute::REMOVABLE, aValue);
+ }
+}
+
+}
+
+// This method creates a new document (SdDrawDocument) and returns a pointer to
+// said document. The drawing engine uses this method to put the document (or
+// parts of it) into the clipboard/DragServer.
+SdDrawDocument* SdDrawDocument::AllocSdDrawDocument() const
+{
+ SdDrawDocument* pNewModel = nullptr;
+
+ if( mpCreatingTransferable )
+ {
+ // Document is created for drag & drop/clipboard. To be able to
+ // do this, the document has to know a DocShell (SvPersist).
+ SfxObjectShell* pObj = nullptr;
+ ::sd::DrawDocShell* pNewDocSh = nullptr;
+
+ if( meDocType == DocumentType::Impress )
+ mpCreatingTransferable->SetDocShell( new ::sd::DrawDocShell(
+ SfxObjectCreateMode::EMBEDDED, true, meDocType ) );
+ else
+ mpCreatingTransferable->SetDocShell( new ::sd::GraphicDocShell(
+ SfxObjectCreateMode::EMBEDDED ) );
+
+ pObj = mpCreatingTransferable->GetDocShell().get();
+ pNewDocSh = static_cast< ::sd::DrawDocShell*>( pObj );
+ pNewDocSh->DoInitNew();
+ pNewModel = pNewDocSh->GetDoc();
+
+ // Only necessary for clipboard -
+ // for drag & drop this is handled by DragServer
+ SdStyleSheetPool* pOldStylePool = static_cast<SdStyleSheetPool*>( GetStyleSheetPool() );
+ SdStyleSheetPool* pNewStylePool = static_cast<SdStyleSheetPool*>( pNewModel->GetStyleSheetPool() );
+
+ pNewStylePool->CopyGraphicSheets(*pOldStylePool);
+ pNewStylePool->CopyCellSheets(*pOldStylePool);
+ pNewStylePool->CopyTableStyles(*pOldStylePool);
+
+ for (sal_uInt16 i = 0; i < GetMasterSdPageCount(PageKind::Standard); i++)
+ {
+ // Move with all of the master page's layouts
+ OUString aOldLayoutName(const_cast<SdDrawDocument*>(this)->GetMasterSdPage(i, PageKind::Standard)->GetLayoutName());
+ aOldLayoutName = aOldLayoutName.copy( 0, aOldLayoutName.indexOf( SD_LT_SEPARATOR ) );
+ StyleSheetCopyResultVector aCreatedSheets;
+ pNewStylePool->CopyLayoutSheets(aOldLayoutName, *pOldStylePool, aCreatedSheets );
+ }
+
+ lcl_copyUserDefinedProperties(GetDocSh(), pNewDocSh);
+
+ pNewModel->NewOrLoadCompleted( DocCreationMode::Loaded ); // loaded from source document
+ }
+ else if( mbAllocDocSh )
+ {
+ // Create a DocShell which is then returned with GetAllocedDocSh()
+ SdDrawDocument* pDoc = const_cast<SdDrawDocument*>(this);
+ pDoc->SetAllocDocSh(false);
+ pDoc->mxAllocedDocShRef = new ::sd::DrawDocShell(
+ SfxObjectCreateMode::EMBEDDED, true, meDocType);
+ pDoc->mxAllocedDocShRef->DoInitNew();
+ pNewModel = pDoc->mxAllocedDocShRef->GetDoc();
+ }
+ else
+ {
+ pNewModel = new SdDrawDocument(meDocType, nullptr);
+ }
+
+ return pNewModel;
+}
+
+rtl::Reference<SdPage> SdDrawDocument::AllocSdPage(bool bMasterPage)
+{
+ return new SdPage(*this, bMasterPage);
+}
+
+// This method creates a new page (SdPage) and returns a pointer to said page.
+// The drawing engine uses this method to create pages (whose types it does
+// not know, as they are _derivatives_ of SdrPage) when loading.
+rtl::Reference<SdrPage> SdDrawDocument::AllocPage(bool bMasterPage)
+{
+ return AllocSdPage(bMasterPage);
+}
+
+// When the model has changed
+void SdDrawDocument::SetChanged(bool bFlag)
+{
+ if (mpDocSh)
+ {
+ if (mbNewOrLoadCompleted && mpDocSh->IsEnableSetModified())
+ {
+ // Pass on to base class
+ FmFormModel::SetChanged(bFlag);
+
+ // Forward to ObjectShell
+ mpDocSh->SetModified(bFlag);
+ }
+ }
+ else
+ {
+ // Pass on to base class
+ FmFormModel::SetChanged(bFlag);
+ }
+}
+
+// The model changed, don't call anything else
+void SdDrawDocument::NbcSetChanged(bool bFlag)
+{
+ // forward to baseclass
+ FmFormModel::SetChanged(bFlag);
+}
+
+// NewOrLoadCompleted is called when the document is loaded, or when it is clear
+// it won't load any more.
+void SdDrawDocument::NewOrLoadCompleted(DocCreationMode eMode)
+{
+ if (eMode == DocCreationMode::New)
+ {
+ // New document:
+ // create slideshow and default templates,
+ // create pool for virtual controls
+ CreateLayoutTemplates();
+ CreateDefaultCellStyles();
+
+ static_cast< SdStyleSheetPool* >( mxStyleSheetPool.get() )->CreatePseudosIfNecessary();
+ }
+ else if (eMode == DocCreationMode::Loaded)
+ {
+ // Document has finished loading
+
+ CheckMasterPages();
+
+ if ( GetMasterSdPageCount(PageKind::Standard) > 1 )
+ RemoveUnnecessaryMasterPages( nullptr, true, false );
+
+ for ( sal_uInt16 i = 0; i < GetPageCount(); i++ )
+ {
+ // Check for correct layout names
+ SdPage* pPage = static_cast<SdPage*>( GetPage( i ) );
+
+ if(pPage->TRG_HasMasterPage())
+ {
+ SdPage& rMaster = static_cast<SdPage&>(pPage->TRG_GetMasterPage() );
+
+ if(rMaster.GetLayoutName() != pPage->GetLayoutName())
+ {
+ pPage->SetLayoutName(rMaster.GetLayoutName());
+ }
+ }
+ }
+
+ for ( sal_uInt16 nPage = 0; nPage < GetMasterPageCount(); nPage++)
+ {
+ // LayoutName and PageName must be the same
+ SdPage* pPage = static_cast<SdPage*>( GetMasterPage( nPage ) );
+
+ OUString aName( pPage->GetLayoutName() );
+ aName = aName.copy( 0, aName.indexOf( SD_LT_SEPARATOR ) );
+
+ if( aName != pPage->GetName() )
+ pPage->SetName( aName );
+ }
+
+ // Create names of the styles in the user's language
+ static_cast<SdStyleSheetPool*>(mxStyleSheetPool.get())->UpdateStdNames();
+
+ // Create any missing styles - eg. formerly, there was no Subtitle style
+ static_cast<SdStyleSheetPool*>(mxStyleSheetPool.get())->CreatePseudosIfNecessary();
+ }
+
+ // Set default style of Drawing Engine
+ OUString aName( SdResId(STR_STANDARD_STYLESHEET_NAME));
+ SetDefaultStyleSheet(static_cast<SfxStyleSheet*>(mxStyleSheetPool->Find(aName, SfxStyleFamily::Para)));
+
+ // #i119287# Set default StyleSheet for SdrGrafObj and SdrOle2Obj
+ SetDefaultStyleSheetForSdrGrafObjAndSdrOle2Obj(static_cast<SfxStyleSheet*>(mxStyleSheetPool->Find(SdResId(STR_POOLSHEET_OBJNOLINENOFILL), SfxStyleFamily::Para)));
+
+ // Initialize DrawOutliner and DocumentOutliner, but don't initialize the
+ // global outliner, as it is not document specific like StyleSheetPool and
+ // StyleRequestHandler are.
+ ::Outliner& rDrawOutliner = GetDrawOutliner();
+ rDrawOutliner.SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ EEControlBits nCntrl = rDrawOutliner.GetControlWord();
+ if (mbOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+ rDrawOutliner.SetControlWord(nCntrl);
+
+ // Initialize HitTestOutliner and DocumentOutliner, but don't initialize the
+ // global outliner, as it is not document specific like StyleSheetPool and
+ // StyleRequestHandler are.
+ m_pHitTestOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+
+ if(mpOutliner)
+ {
+ mpOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ }
+ if(mpInternalOutliner)
+ {
+ mpInternalOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ }
+
+ if ( eMode == DocCreationMode::Loaded )
+ {
+ // Make presentation objects listeners of the appropriate styles
+ SdStyleSheetPool* pSPool = static_cast<SdStyleSheetPool*>( GetStyleSheetPool() );
+ sal_uInt16 nPage, nPageCount;
+
+ // create missing layout style sheets for broken documents
+ // that were created with the 5.2
+ nPageCount = GetMasterSdPageCount( PageKind::Standard );
+ for (nPage = 0; nPage < nPageCount; nPage++)
+ {
+ SdPage* pPage = GetMasterSdPage(nPage, PageKind::Standard);
+ pSPool->CreateLayoutStyleSheets( pPage->GetName(), true );
+ }
+
+ // Default and notes pages:
+ for (nPage = 0; nPage < GetPageCount(); nPage++)
+ {
+ SdPage* pPage = static_cast<SdPage*>(GetPage(nPage));
+ NewOrLoadCompleted( pPage, pSPool );
+ }
+
+ // Master pages:
+ for (nPage = 0; nPage < GetMasterPageCount(); nPage++)
+ {
+ SdPage* pPage = static_cast<SdPage*>(GetMasterPage(nPage));
+
+ NewOrLoadCompleted( pPage, pSPool );
+ }
+ }
+
+ mbNewOrLoadCompleted = true;
+ UpdateAllLinks();
+ SetChanged( false );
+}
+
+/** updates all links, only links in this document should by resolved */
+void SdDrawDocument::UpdateAllLinks()
+{
+ if (s_pDocLockedInsertingLinks || !m_pLinkManager || m_pLinkManager->GetLinks().empty())
+ return;
+
+ s_pDocLockedInsertingLinks = this; // lock inserting links. only links in this document should by resolved
+
+ if (mpDocSh)
+ {
+ comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = mpDocSh->getEmbeddedObjectContainer();
+ rEmbeddedObjectContainer.setUserAllowsLinkUpdate(true);
+ }
+
+ m_pLinkManager->UpdateAllLinks(true, false, nullptr); // query box: update all links?
+
+ if (s_pDocLockedInsertingLinks == this)
+ s_pDocLockedInsertingLinks = nullptr; // unlock inserting links
+}
+
+/** this loops over the presentation objects of a page and repairs some new settings
+ from old binary files and resets all default strings for empty presentation objects.
+*/
+void SdDrawDocument::NewOrLoadCompleted( SdPage* pPage, SdStyleSheetPool* pSPool )
+{
+ sd::ShapeList& rPresentationShapes( pPage->GetPresentationShapeList() );
+ if(rPresentationShapes.isEmpty())
+ return;
+
+ // Create lists of title and outline styles
+ OUString aName = pPage->GetLayoutName();
+ aName = aName.copy( 0, aName.indexOf( SD_LT_SEPARATOR ) );
+
+ std::vector<SfxStyleSheetBase*> aOutlineList;
+ pSPool->CreateOutlineSheetList(aName,aOutlineList);
+
+ SfxStyleSheet* pTitleSheet = static_cast<SfxStyleSheet*>(pSPool->GetTitleSheet(aName));
+
+ SdrObject* pObj = nullptr;
+ rPresentationShapes.seekShape(0);
+
+ // Now look for title and outline text objects, then make those objects
+ // listeners.
+ while( (pObj = rPresentationShapes.getNextShape()) )
+ {
+ if (pObj->GetObjInventor() == SdrInventor::Default)
+ {
+ OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
+ SdrObjKind nId = pObj->GetObjIdentifier();
+
+ if (nId == SdrObjKind::TitleText)
+ {
+ if( pOPO && pOPO->GetOutlinerMode() == OutlinerMode::DontKnow )
+ pOPO->SetOutlinerMode( OutlinerMode::TitleObject );
+
+ // sal_True: don't delete "hard" attributes when doing this.
+ if (pTitleSheet)
+ pObj->SetStyleSheet(pTitleSheet, true);
+ }
+ else if (nId == SdrObjKind::OutlineText)
+ {
+ if( pOPO && pOPO->GetOutlinerMode() == OutlinerMode::DontKnow )
+ pOPO->SetOutlinerMode( OutlinerMode::OutlineObject );
+
+ std::vector<SfxStyleSheetBase*>::iterator iter;
+ for (iter = aOutlineList.begin(); iter != aOutlineList.end(); ++iter)
+ {
+ SfxStyleSheet* pSheet = static_cast<SfxStyleSheet*>(*iter);
+
+ if (pSheet)
+ {
+ pObj->StartListening(*pSheet);
+
+ if( iter == aOutlineList.begin())
+ // text frame listens to stylesheet of layer 1
+ pObj->NbcSetStyleSheet(pSheet, true);
+ }
+ }
+ }
+
+ if( auto pTextObj = dynamic_cast<SdrTextObj *>( pObj ) )
+ if (pTextObj->IsEmptyPresObj())
+ {
+ PresObjKind ePresObjKind = pPage->GetPresObjKind(pObj);
+ OUString aString( pPage->GetPresObjText(ePresObjKind) );
+
+ if (!aString.isEmpty())
+ {
+ SdOutliner* pInternalOutl = GetInternalOutliner();
+ pPage->SetObjText( pTextObj, pInternalOutl, ePresObjKind, aString );
+ pObj->NbcSetStyleSheet( pPage->GetStyleSheetForPresObj( ePresObjKind ), true );
+ pInternalOutl->Clear();
+ }
+ }
+ }
+ }
+}
+
+// Local outliner that is used for outline mode. In this outliner, OutlinerViews
+// may be inserted.
+SdOutliner* SdDrawDocument::GetOutliner(bool bCreateOutliner)
+{
+ if (!mpOutliner && bCreateOutliner)
+ {
+ mpOutliner.reset(new SdOutliner( this, OutlinerMode::TextObject ));
+
+ if (mpDocSh)
+ mpOutliner->SetRefDevice( SD_MOD()->GetVirtualRefDevice() );
+
+ mpOutliner->SetDefTab( m_nDefaultTabulator );
+ mpOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ }
+
+ return mpOutliner.get();
+}
+
+// Internal outliner that is used to create text objects. We don't insert any
+// OutlinerViews into this outliner!
+SdOutliner* SdDrawDocument::GetInternalOutliner(bool bCreateOutliner)
+{
+ if ( !mpInternalOutliner && bCreateOutliner )
+ {
+ mpInternalOutliner.reset( new SdOutliner( this, OutlinerMode::TextObject ) );
+
+ // This outliner is only used to create special text objects. As no
+ // information about portions is saved in this outliner, the update mode
+ // can/should always remain sal_False.
+ mpInternalOutliner->SetUpdateLayout( false );
+ mpInternalOutliner->EnableUndo( false );
+
+ if (mpDocSh)
+ mpInternalOutliner->SetRefDevice( SD_MOD()->GetVirtualRefDevice() );
+
+ mpInternalOutliner->SetDefTab( m_nDefaultTabulator );
+ mpInternalOutliner->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>(GetStyleSheetPool()));
+ }
+
+ DBG_ASSERT( !mpInternalOutliner || ( ! mpInternalOutliner->IsUpdateLayout() ) , "InternalOutliner: UpdateMode = sal_True !" );
+ DBG_ASSERT( !mpInternalOutliner || ( ! mpInternalOutliner->IsUndoEnabled() ), "InternalOutliner: Undo = sal_True !" );
+
+ // If you add stuff here, always clear it out.
+ // Advantages:
+ // a) no unnecessary Clear calls
+ // b) no wasted memory
+ DBG_ASSERT( !mpInternalOutliner || ( ( mpInternalOutliner->GetParagraphCount() == 1 ) && ( mpInternalOutliner->GetText( mpInternalOutliner->GetParagraph( 0 ) ).isEmpty() ) ), "InternalOutliner: not empty!" );
+
+ return mpInternalOutliner.get();
+}
+
+// OnlineSpelling on/off
+void SdDrawDocument::SetOnlineSpell(bool bIn)
+{
+ mbOnlineSpell = bIn;
+ EEControlBits nCntrl;
+
+ if(mpOutliner)
+ {
+ nCntrl = mpOutliner->GetControlWord();
+
+ if(mbOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+
+ mpOutliner->SetControlWord(nCntrl);
+ }
+
+ if (mpInternalOutliner)
+ {
+ nCntrl = mpInternalOutliner->GetControlWord();
+
+ if (mbOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+
+ mpInternalOutliner->SetControlWord(nCntrl);
+ }
+
+ ::Outliner& rOutliner = GetDrawOutliner();
+
+ nCntrl = rOutliner.GetControlWord();
+
+ if (mbOnlineSpell)
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+
+ rOutliner.SetControlWord(nCntrl);
+
+ if (mbOnlineSpell)
+ {
+ StartOnlineSpelling();
+ }
+ else
+ {
+ StopOnlineSpelling();
+ }
+}
+
+// OnlineSpelling: highlighting on/off
+uno::Reference< uno::XInterface > SdDrawDocument::createUnoModel()
+{
+ uno::Reference< uno::XInterface > xModel;
+
+ try
+ {
+ if ( mpDocSh )
+ xModel = mpDocSh->GetModel();
+ }
+ catch( uno::RuntimeException& )
+ {
+ }
+
+ return xModel;
+}
+
+SvxNumType SdDrawDocument::GetPageNumType() const
+{
+ return mePageNumType;
+}
+
+void SdDrawDocument::SetPrinterIndependentLayout (sal_Int32 nMode)
+{
+ switch (nMode)
+ {
+ case css::document::PrinterIndependentLayout::DISABLED:
+ case css::document::PrinterIndependentLayout::ENABLED:
+ // Just store supported modes and inform the doc shell
+ mnPrinterIndependentLayout = nMode;
+
+ // Since it is possible that a SdDrawDocument is constructed without a
+ // SdDrawDocShell the pointer member mpDocSh needs to be tested
+ // before the call is executed. This is e. g. used for copy/paste.
+ if(mpDocSh)
+ {
+ mpDocSh->UpdateRefDevice ();
+ }
+
+ break;
+
+ default:
+ // Ignore unknown values
+ break;
+ }
+}
+
+void SdDrawDocument::SetStartWithPresentation( bool bStartWithPresentation )
+{
+ mbStartWithPresentation = bStartWithPresentation;
+}
+
+void SdDrawDocument::SetExitAfterPresenting( bool bExitAfterPresenting )
+{
+ mbExitAfterPresenting = bExitAfterPresenting;
+}
+
+void SdDrawDocument::PageListChanged()
+{
+ mpDrawPageListWatcher->Invalidate();
+}
+
+void SdDrawDocument::MasterPageListChanged()
+{
+ mpMasterPageListWatcher->Invalidate();
+}
+
+void SdDrawDocument::SetCalcFieldValueHdl(::Outliner* pOutliner)
+{
+ pOutliner->SetCalcFieldValueHdl(LINK(SD_MOD(), SdModule, CalcFieldValueHdl));
+}
+
+sal_uInt16 SdDrawDocument::GetAnnotationAuthorIndex( const OUString& rAuthor )
+{
+ // force current user to have first color
+ if( maAnnotationAuthors.empty() )
+ {
+ SvtUserOptions aUserOptions;
+ maAnnotationAuthors.push_back( aUserOptions.GetFullName() );
+ }
+
+ auto iter = std::find(maAnnotationAuthors.begin(), maAnnotationAuthors.end(), rAuthor);
+ sal_uInt16 idx = static_cast<sal_uInt16>(std::distance(maAnnotationAuthors.begin(), iter));
+
+ if( idx == maAnnotationAuthors.size() )
+ {
+ maAnnotationAuthors.push_back( rAuthor );
+ }
+
+ return idx;
+}
+
+void SdDrawDocument::InitLayoutVector()
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return;
+
+ const Reference<css::uno::XComponentContext> xContext(
+ ::comphelper::getProcessComponentContext() );
+
+ // get file list from configuration
+ const Sequence< OUString > aFiles(
+ officecfg::Office::Impress::Misc::LayoutListFiles::get() );
+
+ if (aFiles.getLength() == 0)
+ return;
+ const Reference<XDocumentBuilder> xDocBuilder = DocumentBuilder::create( xContext );
+
+ for( const auto& rFile : aFiles )
+ {
+ OUString sFilename = comphelper::getExpandedUri(xContext, rFile);
+
+ // load layout file into DOM
+
+ try
+ {
+ // loop over every layout entry in current file
+ const Reference<XDocument> xDoc = xDocBuilder->parseURI( sFilename );
+ const Reference<XNodeList> layoutlist = xDoc->getElementsByTagName("layout");
+ const int nElements = layoutlist->getLength();
+ for(int index=0; index < nElements; index++)
+ maLayoutInfo.push_back( layoutlist->item(index) );
+ }
+ catch (const uno::Exception &)
+ {
+ // skip missing config. files
+ }
+ }
+}
+
+void SdDrawDocument::InitObjectVector()
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return;
+
+ const Reference<css::uno::XComponentContext> xContext(
+ ::comphelper::getProcessComponentContext() );
+
+ // get file list from configuration
+ const Sequence< OUString > aFiles(
+ officecfg::Office::Impress::Misc::PresObjListFiles::get() );
+
+ if (aFiles.getLength() == 0)
+ return;
+ const Reference<XDocumentBuilder> xDocBuilder = DocumentBuilder::create( xContext );
+ for( const auto& rFile : aFiles )
+ {
+ OUString sFilename = comphelper::getExpandedUri(xContext, rFile);
+
+ // load presentation object file into DOM
+
+ try
+ {
+ // loop over every object entry in current file
+ const Reference<XDocument> xDoc = xDocBuilder->parseURI( sFilename );
+ const Reference<XNodeList> objectlist = xDoc->getElementsByTagName("object");
+ const int nElements = objectlist->getLength();
+ for(int index=0; index < nElements; index++)
+ maPresObjectInfo.push_back( objectlist->item(index) );
+ }
+ catch (const uno::Exception &)
+ {
+ // skip missing config. files
+ }
+ }
+}
+
+void SdDrawDocument::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ bool bOwns = false;
+ if (!pWriter)
+ {
+ pWriter = xmlNewTextWriterFilename("model.xml", 0);
+ xmlTextWriterSetIndent(pWriter,1);
+ (void)xmlTextWriterSetIndentString(pWriter, BAD_CAST(" "));
+ (void)xmlTextWriterStartDocument(pWriter, nullptr, nullptr, nullptr);
+ bOwns = true;
+ }
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdDrawDocument"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+
+ if (mpOutliner)
+ mpOutliner->dumpAsXml(pWriter);
+ FmFormModel::dumpAsXml(pWriter);
+ if (GetUndoManager())
+ GetUndoManager()->dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+ if (bOwns)
+ {
+ (void)xmlTextWriterEndDocument(pWriter);
+ xmlFreeTextWriter(pWriter);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */