/* -*- 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 <memory>
#include <boost/property_tree/json_parser.hpp>
 
#include <com/sun/star/presentation/XPresentation2.hpp>
 
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/style/XStyle.hpp>
#include <com/sun/star/awt/XDevice.hpp>
#include <com/sun/star/document/IndexedPropertyValues.hpp>
 
#include <com/sun/star/embed/Aspects.hpp>
 
#include <comphelper/lok.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/servicehelper.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/profilezone.hxx>
 
#include <sal/log.hxx>
#include <editeng/unofield.hxx>
#include <notifydocumentevent.hxx>
#include <unomodel.hxx>
#include "unopool.hxx"
#include <sfx2/dispatch.hxx>
#include <sfx2/bindings.hxx>
#include <vcl/commandevent.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
 
#include <editeng/UnoForbiddenCharsTable.hxx>
#include <svx/svdoutl.hxx>
#include <editeng/forbiddencharacterstable.hxx>
#include <o3tl/safeint.hxx>
#include <svx/UnoNamespaceMap.hxx>
#include <svx/svdlayer.hxx>
#include <svx/svdsob.hxx>
#include <svx/svdundo.hxx>
#include <svx/unoapi.hxx>
#include <svx/unofill.hxx>
#include <svx/unopool.hxx>
#include <svx/svdorect.hxx>
#include <editeng/flditem.hxx>
#include <editeng/fontitem.hxx>
#include <toolkit/awt/vclxdevice.hxx>
#include <svx/svdpool.hxx>
#include <editeng/unolingu.hxx>
#include <svx/svdpagv.hxx>
#include <svtools/unoimap.hxx>
#include <svx/unoshape.hxx>
#include <editeng/unonrule.hxx>
#include <editeng/eeitem.hxx>
#include <unotools/datetime.hxx>
#include <unotools/saveopt.hxx>
#include <xmloff/autolayout.hxx>
 
// Support creation of GraphicStorageHandler and EmbeddedObjectResolver
#include <svx/xmleohlp.hxx>
#include <svx/xmlgrhlp.hxx>
#include <DrawDocShell.hxx>
#include <ViewShellBase.hxx>
#include "UnoDocumentSettings.hxx"
 
#include <Annotation.hxx>
#include <drawdoc.hxx>
#include <sdmod.hxx>
#include <sdresid.hxx>
#include <sdpage.hxx>
 
#include <strings.hrc>
#include <strings.hxx>
#include "unolayer.hxx"
#include <unoprnms.hxx>
#include <unopage.hxx>
#include "unocpres.hxx"
#include "unoobj.hxx"
#include <stlpool.hxx>
#include "unopback.hxx"
#include <unokywds.hxx>
 
#include <FrameView.hxx>
#include <ClientView.hxx>
#include <DrawViewShell.hxx>
#include <ViewShell.hxx>
#include <Window.hxx>
#include <app.hrc>
#include <optsitem.hxx>
 
#include <vcl/pdfextoutdevdata.hxx>
#include <com/sun/star/presentation/AnimationSpeed.hpp>
#include <com/sun/star/presentation/ClickAction.hpp>
#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
#include <svx/sdr/contact/displayinfo.hxx>
 
#include <com/sun/star/office/XAnnotation.hpp>
#include <com/sun/star/office/XAnnotationAccess.hpp>
#include <com/sun/star/office/XAnnotationEnumeration.hpp>
#include <com/sun/star/geometry/RealPoint2D.hpp>
#include <com/sun/star/util/DateTime.hpp>
 
#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
 
#include <sfx2/lokcharthelper.hxx>
 
#define TWIPS_PER_PIXEL 15
 
using namespace ::cppu;
using namespace ::com::sun::star;
using namespace ::sd;
 
class SdUnoForbiddenCharsTable : public SvxUnoForbiddenCharsTable,
                                 public SfxListener
{
public:
    explicit SdUnoForbiddenCharsTable(SdrModel* pModel);
    virtual ~SdUnoForbiddenCharsTable() override;
 
    // SfxListener
    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) throw () override;
protected:
    virtual void onChange() override;
 
private:
    SdrModel*   mpModel;
};
 
SdUnoForbiddenCharsTable::SdUnoForbiddenCharsTable( SdrModel* pModel )
: SvxUnoForbiddenCharsTable( pModel->GetForbiddenCharsTable() ), mpModel( pModel )
{
    StartListening( *pModel );
}
 
void SdUnoForbiddenCharsTable::onChange()
{
    if( mpModel )
    {
        mpModel->ReformatAllTextObjects();
    }
}
 
SdUnoForbiddenCharsTable::~SdUnoForbiddenCharsTable()
{
    SolarMutexGuard g;
 
    if( mpModel )
        EndListening( *mpModel );
}
 
void SdUnoForbiddenCharsTable::Notify( SfxBroadcaster&, const SfxHint& rHint ) throw()
{
    const SdrHint* pSdrHint = dynamic_cast<const SdrHint*>( &rHint );
 
    if( pSdrHint )
    {
        if( SdrHintKind::ModelCleared == pSdrHint->GetKind() )
        {
            mpModel = nullptr;
        }
    }
}
 
const sal_uInt16 WID_MODEL_LANGUAGE           =  1;
const sal_uInt16 WID_MODEL_TABSTOP            =  2;
const sal_uInt16 WID_MODEL_VISAREA            =  3;
const sal_uInt16 WID_MODEL_MAPUNIT            =  4;
const sal_uInt16 WID_MODEL_FORBCHARS          =  5;
const sal_uInt16 WID_MODEL_CONTFOCUS          =  6;
const sal_uInt16 WID_MODEL_DSGNMODE           =  7;
const sal_uInt16 WID_MODEL_BASICLIBS          =  8;
const sal_uInt16 WID_MODEL_RUNTIMEUID         =  9;
const sal_uInt16 WID_MODEL_BUILDID            = 10;
const sal_uInt16 WID_MODEL_HASVALIDSIGNATURES = 11;
const sal_uInt16 WID_MODEL_DIALOGLIBS         = 12;
const sal_uInt16 WID_MODEL_FONTS              = 13;
const sal_uInt16 WID_MODEL_INTEROPGRABBAG     = 14;
 
const SvxItemPropertySet* ImplGetDrawModelPropertySet()
{
    // Attention: the first parameter HAS TO BE sorted!!!
    const static SfxItemPropertyMapEntry aDrawModelPropertyMap_Impl[] =
    {
        { OUString("BuildId"),                      WID_MODEL_BUILDID,            ::cppu::UnoType<OUString>::get(),                      0, 0},
        { OUString(sUNO_Prop_CharLocale),           WID_MODEL_LANGUAGE,           ::cppu::UnoType<lang::Locale>::get(),                                  0, 0},
        { OUString(sUNO_Prop_TabStop),              WID_MODEL_TABSTOP,            ::cppu::UnoType<sal_Int32>::get(),                                     0, 0},
        { OUString(sUNO_Prop_VisibleArea),          WID_MODEL_VISAREA,            ::cppu::UnoType<awt::Rectangle>::get(),                                0, 0},
        { OUString(sUNO_Prop_MapUnit),              WID_MODEL_MAPUNIT,            ::cppu::UnoType<sal_Int16>::get(),                                     beans::PropertyAttribute::READONLY, 0},
        { OUString(sUNO_Prop_ForbiddenCharacters),  WID_MODEL_FORBCHARS,          cppu::UnoType<i18n::XForbiddenCharacters>::get(), beans::PropertyAttribute::READONLY, 0},
        { OUString(sUNO_Prop_AutomContFocus),       WID_MODEL_CONTFOCUS,          cppu::UnoType<bool>::get(),                                                 0, 0},
        { OUString(sUNO_Prop_ApplyFrmDsgnMode),     WID_MODEL_DSGNMODE,           cppu::UnoType<bool>::get(),                                                 0, 0},
        { OUString("BasicLibraries"),               WID_MODEL_BASICLIBS,          cppu::UnoType<script::XLibraryContainer>::get(),  beans::PropertyAttribute::READONLY, 0},
        { OUString("DialogLibraries"),              WID_MODEL_DIALOGLIBS,         cppu::UnoType<script::XLibraryContainer>::get(),  beans::PropertyAttribute::READONLY, 0},
        { OUString(sUNO_Prop_RuntimeUID),           WID_MODEL_RUNTIMEUID,         ::cppu::UnoType<OUString>::get(),                      beans::PropertyAttribute::READONLY, 0},
        { OUString(sUNO_Prop_HasValidSignatures),   WID_MODEL_HASVALIDSIGNATURES, ::cppu::UnoType<sal_Bool>::get(),                      beans::PropertyAttribute::READONLY, 0},
        { OUString("Fonts"),                        WID_MODEL_FONTS,              cppu::UnoType<uno::Sequence<uno::Any>>::get(),                     beans::PropertyAttribute::READONLY, 0},
        { OUString(sUNO_Prop_InteropGrabBag),       WID_MODEL_INTEROPGRABBAG,     cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get(),       0, 0},
        { OUString(), 0, css::uno::Type(), 0, 0 }
    };
    static SvxItemPropertySet aDrawModelPropertySet_Impl( aDrawModelPropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
    return &aDrawModelPropertySet_Impl;
}
 
// this ctor is used from the DocShell
SdXImpressDocument::SdXImpressDocument(::sd::DrawDocShell* pShell, bool bClipBoard)
:   SfxBaseModel( pShell ),
    mpDocShell( pShell ),
    mpDoc( pShell ? pShell->GetDoc() : nullptr ),
    mbDisposed(false),
    mbImpressDoc( pShell && pShell->GetDoc() && pShell->GetDoc()->GetDocumentType() == DocumentType::Impress ),
    mbClipBoard( bClipBoard ),
    mpPropSet( ImplGetDrawModelPropertySet() )
{
    if( mpDoc )
    {
        StartListening( *mpDoc );
    }
    else
    {
        OSL_FAIL("DocShell is invalid");
    }
}
 
SdXImpressDocument::SdXImpressDocument(SdDrawDocument* pDoc, bool bClipBoard)
:   SfxBaseModel( nullptr ),
    mpDocShell( nullptr ),
    mpDoc( pDoc ),
    mbDisposed(false),
    mbImpressDoc( pDoc && pDoc->GetDocumentType() == DocumentType::Impress ),
    mbClipBoard( bClipBoard ),
    mpPropSet( ImplGetDrawModelPropertySet() )
{
    if( mpDoc )
    {
        StartListening( *mpDoc );
    }
    else
    {
        OSL_FAIL("SdDrawDocument is invalid");
    }
}
 
/***********************************************************************
*                                                                      *
***********************************************************************/
SdXImpressDocument::~SdXImpressDocument() throw()
{
}
 
// XInterface
uno::Any SAL_CALL SdXImpressDocument::queryInterface( const uno::Type & rType )
{
    uno::Any aAny;
 
    if (rType == cppu::UnoType<lang::XServiceInfo>::get())
        aAny <<= uno::Reference<lang::XServiceInfo>(this);
    else if (rType == cppu::UnoType<beans::XPropertySet>::get())
        aAny <<= uno::Reference<beans::XPropertySet>(this);
    else if (rType == cppu::UnoType<lang::XMultiServiceFactory>::get())
        aAny <<= uno::Reference<lang::XMultiServiceFactory>(this);
    else if (rType == cppu::UnoType<drawing::XDrawPageDuplicator>::get())
        aAny <<= uno::Reference<drawing::XDrawPageDuplicator>(this);
    else if (rType == cppu::UnoType<drawing::XLayerSupplier>::get())
        aAny <<= uno::Reference<drawing::XLayerSupplier>(this);
    else if (rType == cppu::UnoType<drawing::XMasterPagesSupplier>::get())
        aAny <<= uno::Reference<drawing::XMasterPagesSupplier>(this);
    else if (rType == cppu::UnoType<drawing::XDrawPagesSupplier>::get())
        aAny <<= uno::Reference<drawing::XDrawPagesSupplier>(this);
    else if (rType == cppu::UnoType<presentation::XHandoutMasterSupplier>::get())
        aAny <<= uno::Reference<presentation::XHandoutMasterSupplier>(this);
    else if (rType == cppu::UnoType<document::XLinkTargetSupplier>::get())
        aAny <<= uno::Reference<document::XLinkTargetSupplier>(this);
    else if (rType == cppu::UnoType<style::XStyleFamiliesSupplier>::get())
        aAny <<= uno::Reference<style::XStyleFamiliesSupplier>(this);
    else if (rType == cppu::UnoType<css::ucb::XAnyCompareFactory>::get())
        aAny <<= uno::Reference<css::ucb::XAnyCompareFactory>(this);
    else if (rType == cppu::UnoType<view::XRenderable>::get())
        aAny <<= uno::Reference<view::XRenderable>(this);
    else if (mbImpressDoc && rType == cppu::UnoType<presentation::XPresentationSupplier>::get())
        aAny <<= uno::Reference< presentation::XPresentationSupplier >(this);
    else if (mbImpressDoc && rType == cppu::UnoType<presentation::XCustomPresentationSupplier>::get())
        aAny <<= uno::Reference< presentation::XCustomPresentationSupplier >(this);
    else
        return SfxBaseModel::queryInterface(rType);
 
    return aAny;
}
 
void SAL_CALL SdXImpressDocument::acquire() throw ( )
{
    SfxBaseModel::acquire();
}
 
void SAL_CALL SdXImpressDocument::release() throw ( )
{
    if (osl_atomic_decrement( &m_refCount ) == 0)
    {
        // restore reference count:
        osl_atomic_increment( &m_refCount );
        if(!mbDisposed)
        {
            try
            {
                dispose();
            }
            catch (const uno::RuntimeException& exc)
            { // don't break throw ()
                SAL_WARN( "sd", exc );
            }
        }
        SfxBaseModel::release();
    }
}
 
namespace
{
    class theSdXImpressDocumentUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSdXImpressDocumentUnoTunnelId> {};
}
 
// XUnoTunnel
const css::uno::Sequence< sal_Int8 > & SdXImpressDocument::getUnoTunnelId() throw()
{
    return theSdXImpressDocumentUnoTunnelId::get().getSeq();
}
 
SdXImpressDocument* SdXImpressDocument::getImplementation( const uno::Reference< uno::XInterface >& xInt )
{
    css::uno::Reference< css::lang::XUnoTunnel > xUT( xInt, uno::UNO_QUERY );
    if( xUT.is() )
        return reinterpret_cast<SdXImpressDocument*>(sal::static_int_cast<sal_IntPtr>(xUT->getSomething( SdXImpressDocument::getUnoTunnelId() )));
    else
        return nullptr;
}
 
sal_Int64 SAL_CALL SdXImpressDocument::getSomething( const css::uno::Sequence< sal_Int8 >& rIdentifier )
{
    if( rIdentifier.getLength() == 16 )
    {
        if( 0 == memcmp( SdXImpressDocument::getUnoTunnelId().getConstArray(), rIdentifier.getConstArray(), 16 ) )
            return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this));
 
        if( 0 == memcmp( SdrModel::getUnoTunnelImplementationId().getConstArray(), rIdentifier.getConstArray(), 16 ) )
            return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(mpDoc));
    }
 
    return SfxBaseModel::getSomething( rIdentifier );
}
 
// XTypeProvider
uno::Sequence< uno::Type > SAL_CALL SdXImpressDocument::getTypes(  )
{
    ::SolarMutexGuard aGuard;
 
    if( maTypeSequence.getLength() == 0 )
    {
        const uno::Sequence< uno::Type > aBaseTypes( SfxBaseModel::getTypes() );
        const sal_Int32 nBaseTypes = aBaseTypes.getLength();
        const uno::Type* pBaseTypes = aBaseTypes.getConstArray();
 
        const sal_Int32 nOwnTypes = mbImpressDoc ? 14 : 11;     // !DANGER! Keep this updated!
 
        maTypeSequence.realloc(  nBaseTypes + nOwnTypes );
        uno::Type* pTypes = maTypeSequence.getArray();
 
        *pTypes++ = cppu::UnoType<beans::XPropertySet>::get();
        *pTypes++ = cppu::UnoType<lang::XServiceInfo>::get();
        *pTypes++ = cppu::UnoType<lang::XMultiServiceFactory>::get();
        *pTypes++ = cppu::UnoType<drawing::XDrawPageDuplicator>::get();
        *pTypes++ = cppu::UnoType<drawing::XLayerSupplier>::get();
        *pTypes++ = cppu::UnoType<drawing::XMasterPagesSupplier>::get();
        *pTypes++ = cppu::UnoType<drawing::XDrawPagesSupplier>::get();
        *pTypes++ = cppu::UnoType<document::XLinkTargetSupplier>::get();
        *pTypes++ = cppu::UnoType<style::XStyleFamiliesSupplier>::get();
        *pTypes++ = cppu::UnoType<css::ucb::XAnyCompareFactory>::get();
        *pTypes++ = cppu::UnoType<view::XRenderable>::get();
        if( mbImpressDoc )
        {
            *pTypes++ = cppu::UnoType<presentation::XPresentationSupplier>::get();
            *pTypes++ = cppu::UnoType<presentation::XCustomPresentationSupplier>::get();
            *pTypes++ = cppu::UnoType<presentation::XHandoutMasterSupplier>::get();
        }
 
        for( sal_Int32 nType = 0; nType < nBaseTypes; nType++ )
            *pTypes++ = *pBaseTypes++;
    }
 
    return maTypeSequence;
}
 
uno::Sequence< sal_Int8 > SAL_CALL SdXImpressDocument::getImplementationId(  )
{
    return css::uno::Sequence<sal_Int8>();
}
 
/***********************************************************************
*                                                                      *
***********************************************************************/
void SdXImpressDocument::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
    if( mpDoc )
    {
        const SdrHint* pSdrHint = dynamic_cast<const SdrHint*>( &rHint );
 
        if( pSdrHint )
        {
            if( hasEventListeners() )
            {
                document::EventObject aEvent;
                if( SvxUnoDrawMSFactory::createEvent( mpDoc, pSdrHint, aEvent ) )
                    notifyEvent( aEvent );
            }
 
            if( pSdrHint->GetKind() == SdrHintKind::ModelCleared )
            {
                if( mpDoc )
                    EndListening( *mpDoc );
                mpDoc = nullptr;
                mpDocShell = nullptr;
            }
        }
        else
        {
            // did our SdDrawDocument just died?
            if(rHint.GetId() == SfxHintId::Dying)
            {
                // yes, so we ask for a new one
                if( mpDocShell )
                {
                    SdDrawDocument *pNewDoc = mpDocShell->GetDoc();
 
                    // is there a new one?
                    if( pNewDoc != mpDoc )
                    {
                        mpDoc = pNewDoc;
                        if(mpDoc)
                            StartListening( *mpDoc );
                    }
                }
            }
        }
    }
    SfxBaseModel::Notify( rBC, rHint );
}
 
/******************************************************************************
*                                                                             *
******************************************************************************/
SdPage* SdXImpressDocument::InsertSdPage( sal_uInt16 nPage, bool bDuplicate )
{
    sal_uInt16 nPageCount = mpDoc->GetSdPageCount( PageKind::Standard );
    SdrLayerAdmin& rLayerAdmin = mpDoc->GetLayerAdmin();
    SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(SdResId(STR_LAYER_BCKGRND));
    SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(SdResId(STR_LAYER_BCKGRNDOBJ));
 
    SdPage* pStandardPage = nullptr;
 
    if( 0 == nPageCount )
    {
        // this is only used for clipboard where we only have one page
        pStandardPage = mpDoc->AllocSdPage(false);
 
        Size aDefSize(21000, 29700);   // A4-Hochformat
        pStandardPage->SetSize( aDefSize );
        mpDoc->InsertPage(pStandardPage, 0);
    }
    else
    {
        // here we determine the page after which we should insert
        SdPage* pPreviousStandardPage = mpDoc->GetSdPage( std::min( static_cast<sal_uInt16>(nPageCount - 1), nPage ), PageKind::Standard );
        SdrLayerIDSet aVisibleLayers = pPreviousStandardPage->TRG_GetMasterPageVisibleLayers();
        bool bIsPageBack = aVisibleLayers.IsSet( aBckgrnd );
        bool bIsPageObj = aVisibleLayers.IsSet( aBckgrndObj );
 
        // AutoLayouts must be ready
        mpDoc->StopWorkStartupDelay();
 
        /* First we create a standard page and then a notes page. It is
           guaranteed, that after a standard page the corresponding notes page
           follows. */
 
        sal_uInt16 nStandardPageNum = pPreviousStandardPage->GetPageNum() + 2;
        SdPage* pPreviousNotesPage = static_cast<SdPage*>( mpDoc->GetPage( nStandardPageNum - 1 ) );
        sal_uInt16 nNotesPageNum = nStandardPageNum + 1;
 
        /**************************************************************
        * standard page
        **************************************************************/
        if( bDuplicate )
            pStandardPage = static_cast<SdPage*>( pPreviousStandardPage->CloneSdrPage(*mpDoc) );
        else
            pStandardPage = mpDoc->AllocSdPage(false);
 
        pStandardPage->SetSize( pPreviousStandardPage->GetSize() );
        pStandardPage->SetBorder( pPreviousStandardPage->GetLeftBorder(),
                                    pPreviousStandardPage->GetUpperBorder(),
                                    pPreviousStandardPage->GetRightBorder(),
                                    pPreviousStandardPage->GetLowerBorder() );
        pStandardPage->SetOrientation( pPreviousStandardPage->GetOrientation() );
        pStandardPage->SetName(OUString());
 
        // insert page after current page
        mpDoc->InsertPage(pStandardPage, nStandardPageNum);
 
        if( !bDuplicate )
        {
            // use MasterPage of the current page
            pStandardPage->TRG_SetMasterPage(pPreviousStandardPage->TRG_GetMasterPage());
            pStandardPage->SetLayoutName( pPreviousStandardPage->GetLayoutName() );
            pStandardPage->SetAutoLayout(AUTOLAYOUT_NONE, true );
        }
 
        aBckgrnd = rLayerAdmin.GetLayerID(SdResId(STR_LAYER_BCKGRND));
        aBckgrndObj = rLayerAdmin.GetLayerID(SdResId(STR_LAYER_BCKGRNDOBJ));
        aVisibleLayers.Set(aBckgrnd, bIsPageBack);
        aVisibleLayers.Set(aBckgrndObj, bIsPageObj);
        pStandardPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers);
 
        /**************************************************************
        * notes page
        **************************************************************/
        SdPage* pNotesPage = nullptr;
 
        if( bDuplicate )
            pNotesPage = static_cast<SdPage*>( pPreviousNotesPage->CloneSdrPage(*mpDoc) );
        else
            pNotesPage = mpDoc->AllocSdPage(false);
 
        pNotesPage->SetSize( pPreviousNotesPage->GetSize() );
        pNotesPage->SetBorder( pPreviousNotesPage->GetLeftBorder(),
                                pPreviousNotesPage->GetUpperBorder(),
                                pPreviousNotesPage->GetRightBorder(),
                                pPreviousNotesPage->GetLowerBorder() );
        pNotesPage->SetOrientation( pPreviousNotesPage->GetOrientation() );
        pNotesPage->SetName(OUString());
        pNotesPage->SetPageKind(PageKind::Notes);
 
        // insert page after current page
        mpDoc->InsertPage(pNotesPage, nNotesPageNum);
 
        if( !bDuplicate )
        {
            // use MasterPage of the current page
            pNotesPage->TRG_SetMasterPage(pPreviousNotesPage->TRG_GetMasterPage());
            pNotesPage->SetLayoutName( pPreviousNotesPage->GetLayoutName() );
            pNotesPage->SetAutoLayout(AUTOLAYOUT_NOTES, true );
        }
    }
 
    SetModified();
 
    return pStandardPage;
}
 
void SdXImpressDocument::SetModified() throw()
{
    if( mpDoc )
        mpDoc->SetChanged();
}
 
// XModel
void SAL_CALL SdXImpressDocument::lockControllers(  )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    mpDoc->setLock(true);
}
 
void SAL_CALL SdXImpressDocument::unlockControllers(  )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    if( mpDoc->isLocked() )
    {
        mpDoc->setLock(false);
    }
}
 
sal_Bool SAL_CALL SdXImpressDocument::hasControllersLocked(  )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    return mpDoc && mpDoc->isLocked();
}
 
uno::Reference < container::XIndexAccess > SAL_CALL SdXImpressDocument::getViewData()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    uno::Reference < container::XIndexAccess > xRet( SfxBaseModel::getViewData() );
 
    if( !xRet.is() )
    {
        const std::vector<std::unique_ptr<sd::FrameView>> &rList = mpDoc->GetFrameViewList();
 
        if( !rList.empty() )
        {
            xRet.set(document::IndexedPropertyValues::create( ::comphelper::getProcessComponentContext() ), uno::UNO_QUERY);
 
            uno::Reference < container::XIndexContainer > xCont( xRet, uno::UNO_QUERY );
            DBG_ASSERT( xCont.is(), "SdXImpressDocument::getViewData() failed for OLE object" );
            if( xCont.is() )
            {
                for( sal_uInt32 i = 0, n = rList.size(); i < n; i++ )
                {
                    ::sd::FrameView* pFrameView = rList[ i ].get();
 
                    uno::Sequence< beans::PropertyValue > aSeq;
                    pFrameView->WriteUserDataSequence( aSeq );
                    xCont->insertByIndex( i, uno::makeAny( aSeq ) );
                }
            }
        }
    }
 
    return xRet;
}
 
void SAL_CALL SdXImpressDocument::setViewData( const uno::Reference < container::XIndexAccess >& xData )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    SfxBaseModel::setViewData( xData );
    if( mpDocShell && (mpDocShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED) && xData.is() )
    {
        const sal_Int32 nCount = xData->getCount();
 
        std::vector<std::unique_ptr<sd::FrameView>> &rViews = mpDoc->GetFrameViewList();
 
        rViews.clear();
 
        uno::Sequence< beans::PropertyValue > aSeq;
        for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
        {
            if( xData->getByIndex( nIndex ) >>= aSeq )
            {
                std::unique_ptr<::sd::FrameView> pFrameView(new ::sd::FrameView( mpDoc ));
                pFrameView->ReadUserDataSequence( aSeq );
                rViews.push_back( std::move(pFrameView) );
            }
        }
    }
}
 
// XDrawPageDuplicator
uno::Reference< drawing::XDrawPage > SAL_CALL SdXImpressDocument::duplicate( const uno::Reference< drawing::XDrawPage >& xPage )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    // get pPage from xPage and determine the Id (nPos ) afterwards
    SvxDrawPage* pSvxPage = SvxDrawPage::getImplementation( xPage );
    if( pSvxPage )
    {
        SdPage* pPage = static_cast<SdPage*>( pSvxPage->GetSdrPage() );
        sal_uInt16 nPos = pPage->GetPageNum();
        nPos = ( nPos - 1 ) / 2;
        pPage = InsertSdPage( nPos, true );
        if( pPage )
        {
            uno::Reference< drawing::XDrawPage > xDrawPage( pPage->getUnoPage(), uno::UNO_QUERY );
            return xDrawPage;
        }
    }
 
    uno::Reference< drawing::XDrawPage > xDrawPage;
    return xDrawPage;
}
 
// XDrawPagesSupplier
uno::Reference< drawing::XDrawPages > SAL_CALL SdXImpressDocument::getDrawPages()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    uno::Reference< drawing::XDrawPages >  xDrawPages( mxDrawPagesAccess );
 
    if( !xDrawPages.is() )
    {
        initializeDocument();
        mxDrawPagesAccess = xDrawPages = static_cast<drawing::XDrawPages*>(new SdDrawPagesAccess(*this));
    }
 
    return xDrawPages;
}
 
// XMasterPagesSupplier
uno::Reference< drawing::XDrawPages > SAL_CALL SdXImpressDocument::getMasterPages()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    uno::Reference< drawing::XDrawPages >  xMasterPages( mxMasterPagesAccess );
 
    if( !xMasterPages.is() )
    {
        if ( !hasControllersLocked() )
            initializeDocument();
        mxMasterPagesAccess = xMasterPages = new SdMasterPagesAccess(*this);
    }
 
    return xMasterPages;
}
 
// XLayerManagerSupplier
uno::Reference< container::XNameAccess > SAL_CALL SdXImpressDocument::getLayerManager(  )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    uno::Reference< container::XNameAccess >  xLayerManager( mxLayerManager );
 
    if( !xLayerManager.is() )
        mxLayerManager = xLayerManager = new SdLayerManager(*this);
 
    return xLayerManager;
}
 
// XCustomPresentationSupplier
uno::Reference< container::XNameContainer > SAL_CALL SdXImpressDocument::getCustomPresentations()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    uno::Reference< container::XNameContainer >  xCustomPres( mxCustomPresentationAccess );
 
    if( !xCustomPres.is() )
        mxCustomPresentationAccess = xCustomPres = new SdXCustomPresentationAccess(*this);
 
    return xCustomPres;
}
 
// XPresentationSupplier
uno::Reference< presentation::XPresentation > SAL_CALL SdXImpressDocument::getPresentation()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    return uno::Reference< presentation::XPresentation >( mpDoc->getPresentation().get() );
}
 
// XHandoutMasterSupplier
uno::Reference< drawing::XDrawPage > SAL_CALL SdXImpressDocument::getHandoutMasterPage()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    uno::Reference< drawing::XDrawPage > xPage;
 
    if( mpDoc )
    {
        initializeDocument();
        SdPage* pPage = mpDoc->GetMasterSdPage( 0, PageKind::Handout );
        if( pPage )
            xPage.set( pPage->getUnoPage(), uno::UNO_QUERY );
    }
    return xPage;
}
 
// XMultiServiceFactory ( SvxFmMSFactory )
 
css::uno::Reference<css::uno::XInterface> SdXImpressDocument::create(
    OUString const & aServiceSpecifier, OUString const & referer)
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    if( aServiceSpecifier == "com.sun.star.drawing.DashTable" )
    {
        if( !mxDashTable.is() )
            mxDashTable = SvxUnoDashTable_createInstance( mpDoc );
 
        return mxDashTable;
    }
    if( aServiceSpecifier == "com.sun.star.drawing.GradientTable" )
    {
        if( !mxGradientTable.is() )
            mxGradientTable = SvxUnoGradientTable_createInstance( mpDoc );
 
        return mxGradientTable;
    }
    if( aServiceSpecifier == "com.sun.star.drawing.HatchTable" )
    {
        if( !mxHatchTable.is() )
            mxHatchTable = SvxUnoHatchTable_createInstance( mpDoc );
 
        return mxHatchTable;
    }
    if( aServiceSpecifier == "com.sun.star.drawing.BitmapTable" )
    {
        if( !mxBitmapTable.is() )
            mxBitmapTable = SvxUnoBitmapTable_createInstance( mpDoc );
 
        return mxBitmapTable;
    }
    if( aServiceSpecifier == "com.sun.star.drawing.TransparencyGradientTable" )
    {
        if( !mxTransGradientTable.is() )
            mxTransGradientTable = SvxUnoTransGradientTable_createInstance( mpDoc );
 
        return mxTransGradientTable;
    }
    if( aServiceSpecifier == "com.sun.star.drawing.MarkerTable" )
    {
        if( !mxMarkerTable.is() )
            mxMarkerTable = SvxUnoMarkerTable_createInstance( mpDoc );
 
        return mxMarkerTable;
    }
    if( aServiceSpecifier == "com.sun.star.text.NumberingRules" )
    {
        return uno::Reference< uno::XInterface >( SvxCreateNumRule( mpDoc ), uno::UNO_QUERY );
    }
    if( aServiceSpecifier == "com.sun.star.drawing.Background" )
    {
        return uno::Reference< uno::XInterface >(
            static_cast<uno::XWeak*>(new SdUnoPageBackground( mpDoc )));
    }
 
    if( aServiceSpecifier == "com.sun.star.drawing.Defaults" )
    {
        if( !mxDrawingPool.is() )
            mxDrawingPool = SdUnoCreatePool( mpDoc );
 
        return mxDrawingPool;
 
    }
 
    if ( aServiceSpecifier == sUNO_Service_ImageMapRectangleObject )
    {
        return SvUnoImageMapRectangleObject_createInstance( ImplGetSupportedMacroItems() );
    }
 
    if ( aServiceSpecifier == sUNO_Service_ImageMapCircleObject )
    {
        return SvUnoImageMapCircleObject_createInstance( ImplGetSupportedMacroItems() );
    }
 
    if ( aServiceSpecifier == sUNO_Service_ImageMapPolygonObject )
    {
        return SvUnoImageMapPolygonObject_createInstance( ImplGetSupportedMacroItems() );
    }
 
    if( aServiceSpecifier == "com.sun.star.document.Settings" ||
        ( !mbImpressDoc && ( aServiceSpecifier == "com.sun.star.drawing.DocumentSettings" ) ) ||
        (  mbImpressDoc && ( aServiceSpecifier == "com.sun.star.presentation.DocumentSettings" ) ) )
    {
        return sd::DocumentSettings_createInstance( this );
    }
 
    if( aServiceSpecifier == "com.sun.star.text.TextField.DateTime" ||
        aServiceSpecifier == "com.sun.star.text.textfield.DateTime" )
    {
        return static_cast<cppu::OWeakObject *>(new SvxUnoTextField( text::textfield::Type::DATE ));
    }
 
    if( aServiceSpecifier == "com.sun.star.presentation.TextField.Header" ||
        aServiceSpecifier == "com.sun.star.presentation.textfield.Header" )
    {
        return static_cast<cppu::OWeakObject *>(new SvxUnoTextField( text::textfield::Type::PRESENTATION_HEADER ));
    }
 
    if( aServiceSpecifier == "com.sun.star.presentation.TextField.Footer" ||
        aServiceSpecifier == "com.sun.star.presentation.textfield.Footer" )
    {
        return static_cast<cppu::OWeakObject *>(new SvxUnoTextField( text::textfield::Type::PRESENTATION_FOOTER ));
    }
 
    if( aServiceSpecifier == "com.sun.star.presentation.TextField.DateTime" ||
        aServiceSpecifier == "com.sun.star.presentation.textfield.DateTime" )
    {
        return static_cast<cppu::OWeakObject *>(new SvxUnoTextField( text::textfield::Type::PRESENTATION_DATE_TIME ));
    }
 
    if( aServiceSpecifier == "com.sun.star.text.TextField.PageName" ||
        aServiceSpecifier == "com.sun.star.text.textfield.PageName" )
    {
        return static_cast<cppu::OWeakObject *>(new SvxUnoTextField( text::textfield::Type::PAGE_NAME ));
    }
 
    if (aServiceSpecifier == "com.sun.star.text.TextField.DocInfo.Custom" ||
        aServiceSpecifier == "com.sun.star.text.textfield.DocInfo.Custom")
    {
        return static_cast<cppu::OWeakObject *>(new SvxUnoTextField(text::textfield::Type::DOCINFO_CUSTOM));
    }
 
    if( aServiceSpecifier == "com.sun.star.xml.NamespaceMap" )
    {
        static sal_uInt16 aWhichIds[] = { SDRATTR_XMLATTRIBUTES, EE_CHAR_XMLATTRIBS, EE_PARA_XMLATTRIBS, 0 };
 
        return svx::NamespaceMap_createInstance( aWhichIds, &mpDoc->GetItemPool() );
    }
 
    // Support creation of GraphicStorageHandler and EmbeddedObjectResolver
    if (aServiceSpecifier == "com.sun.star.document.ExportGraphicStorageHandler")
    {
        return static_cast<cppu::OWeakObject *>(new SvXMLGraphicHelper( SvXMLGraphicHelperMode::Write ));
    }
 
    if (aServiceSpecifier == "com.sun.star.document.ImportGraphicStorageHandler")
    {
        return static_cast<cppu::OWeakObject *>(new SvXMLGraphicHelper( SvXMLGraphicHelperMode::Read ));
    }
 
    if( aServiceSpecifier == "com.sun.star.document.ExportEmbeddedObjectResolver" )
    {
        ::comphelper::IEmbeddedHelper *pPersist = mpDoc ? mpDoc->GetPersist() : nullptr;
        if( nullptr == pPersist )
            throw lang::DisposedException();
 
        return static_cast<cppu::OWeakObject *>(new SvXMLEmbeddedObjectHelper( *pPersist, SvXMLEmbeddedObjectHelperMode::Write ));
    }
 
    if( aServiceSpecifier == "com.sun.star.document.ImportEmbeddedObjectResolver" )
    {
        ::comphelper::IEmbeddedHelper *pPersist = mpDoc ? mpDoc->GetPersist() : nullptr;
        if( nullptr == pPersist )
            throw lang::DisposedException();
 
        return static_cast<cppu::OWeakObject *>(new SvXMLEmbeddedObjectHelper( *pPersist, SvXMLEmbeddedObjectHelperMode::Read ));
    }
 
    uno::Reference< uno::XInterface > xRet;
 
    if( aServiceSpecifier.startsWith( "com.sun.star.presentation.") )
    {
        const OUString aType( aServiceSpecifier.copy(26) );
        SvxShape* pShape = nullptr;
 
        sal_uInt16 nType = OBJ_TEXT;
        // create a shape wrapper
        if( aType.startsWith( "TitleTextShape" ) )
        {
            nType = OBJ_TEXT;
        }
        else if( aType.startsWith( "OutlinerShape" ) )
        {
            nType = OBJ_TEXT;
        }
        else if( aType.startsWith( "SubtitleShape" ) )
        {
            nType = OBJ_TEXT;
        }
        else if( aType.startsWith( "GraphicObjectShape" ) )
        {
            nType = OBJ_GRAF;
        }
        else if( aType.startsWith( "PageShape" ) )
        {
            nType = OBJ_PAGE;
        }
        else if( aType.startsWith( "OLE2Shape" ) )
        {
            nType = OBJ_OLE2;
        }
        else if( aType.startsWith( "ChartShape" ) )
        {
            nType = OBJ_OLE2;
        }
        else if( aType.startsWith( "CalcShape" ) )
        {
            nType = OBJ_OLE2;
        }
        else if( aType.startsWith( "TableShape" ) )
        {
            nType = OBJ_TABLE;
        }
        else if( aType.startsWith( "OrgChartShape" ) )
        {
            nType = OBJ_OLE2;
        }
        else if( aType.startsWith( "NotesShape" ) )
        {
            nType = OBJ_TEXT;
        }
        else if( aType.startsWith( "HandoutShape" ) )
        {
            nType = OBJ_PAGE;
        }
        else if( aType.startsWith( "FooterShape" ) )
        {
            nType = OBJ_TEXT;
        }
        else if( aType.startsWith( "HeaderShape" ) )
        {
            nType = OBJ_TEXT;
        }
        else if( aType.startsWith( "SlideNumberShape" ) )
        {
            nType = OBJ_TEXT;
        }
        else if( aType.startsWith( "DateTimeShape" ) )
        {
            nType = OBJ_TEXT;
        }
        else if( aType.startsWith( "MediaShape" ) )
        {
            nType = OBJ_MEDIA;
        }
        else
        {
            throw lang::ServiceNotRegisteredException();
        }
 
        // create the API wrapper
        pShape = CreateSvxShapeByTypeAndInventor( nType, SdrInventor::Default, referer );
 
        // set shape type
        if( pShape && !mbClipBoard )
            pShape->SetShapeType(aServiceSpecifier);
 
        xRet = static_cast<uno::XWeak*>(pShape);
    }
    else if ( aServiceSpecifier == "com.sun.star.drawing.TableShape" )
    {
        SvxShape* pShape = CreateSvxShapeByTypeAndInventor( OBJ_TABLE, SdrInventor::Default, referer );
        if( pShape && !mbClipBoard )
            pShape->SetShapeType(aServiceSpecifier);
 
        xRet = static_cast<uno::XWeak*>(pShape);
    }
    else
    {
        xRet = SvxFmMSFactory::createInstance( aServiceSpecifier );
    }
 
    uno::Reference< drawing::XShape > xShape( xRet, uno::UNO_QUERY );
    SvxShape* pShape = xShape.is() ? SvxShape::getImplementation(xShape) : nullptr;
    if (pShape)
    {
        xRet.clear();
        new SdXShape( pShape, this );
        xRet = xShape;
        xShape.clear();
    }
 
    return xRet;
}
 
uno::Reference< uno::XInterface > SAL_CALL SdXImpressDocument::createInstance( const OUString& aServiceSpecifier )
{
    return create(aServiceSpecifier, "");
}
 
css::uno::Reference<css::uno::XInterface>
SdXImpressDocument::createInstanceWithArguments(
    OUString const & ServiceSpecifier,
    css::uno::Sequence<css::uno::Any> const & Arguments)
{
    OUString arg;
    if ((ServiceSpecifier == "com.sun.star.drawing.GraphicObjectShape"
         || ServiceSpecifier == "com.sun.star.drawing.MediaShape"
         || ServiceSpecifier == "com.sun.star.presentation.MediaShape")
        && Arguments.getLength() == 1 && (Arguments[0] >>= arg))
    {
        return create(ServiceSpecifier, arg);
    }
    return SvxFmMSFactory::createInstanceWithArguments(
        ServiceSpecifier, Arguments);
}
 
uno::Sequence< OUString > SAL_CALL SdXImpressDocument::getAvailableServiceNames()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    const uno::Sequence< OUString > aSNS_ORG( SvxFmMSFactory::getAvailableServiceNames() );
 
    uno::Sequence< OUString > aSNS( mbImpressDoc ? 36 : 19 );
 
    sal_uInt16 i(0);
 
    aSNS[i++] = "com.sun.star.drawing.DashTable";
    aSNS[i++] = "com.sun.star.drawing.GradientTable";
    aSNS[i++] = "com.sun.star.drawing.HatchTable";
    aSNS[i++] = "com.sun.star.drawing.BitmapTable";
    aSNS[i++] = "com.sun.star.drawing.TransparencyGradientTable";
    aSNS[i++] = "com.sun.star.drawing.MarkerTable";
    aSNS[i++] = "com.sun.star.text.NumberingRules";
    aSNS[i++] = "com.sun.star.drawing.Background";
    aSNS[i++] = "com.sun.star.document.Settings";
    aSNS[i++] = sUNO_Service_ImageMapRectangleObject;
    aSNS[i++] = sUNO_Service_ImageMapCircleObject;
    aSNS[i++] = sUNO_Service_ImageMapPolygonObject;
    aSNS[i++] = "com.sun.star.xml.NamespaceMap";
 
    // Support creation of GraphicStorageHandler and EmbeddedObjectResolver
    aSNS[i++] = "com.sun.star.document.ExportGraphicStorageHandler";
    aSNS[i++] = "com.sun.star.document.ImportGraphicStorageHandler";
    aSNS[i++] = "com.sun.star.document.ExportEmbeddedObjectResolver";
    aSNS[i++] = "com.sun.star.document.ImportEmbeddedObjectResolver";
    aSNS[i++] = "com.sun.star.drawing.TableShape";
 
    if(mbImpressDoc)
    {
        aSNS[i++] = "com.sun.star.presentation.TitleTextShape";
        aSNS[i++] = "com.sun.star.presentation.OutlinerShape";
        aSNS[i++] = "com.sun.star.presentation.SubtitleShape";
        aSNS[i++] = "com.sun.star.presentation.GraphicObjectShape";
        aSNS[i++] = "com.sun.star.presentation.ChartShape";
        aSNS[i++] = "com.sun.star.presentation.PageShape";
        aSNS[i++] = "com.sun.star.presentation.OLE2Shape";
        aSNS[i++] = "com.sun.star.presentation.TableShape";
        aSNS[i++] = "com.sun.star.presentation.OrgChartShape";
        aSNS[i++] = "com.sun.star.presentation.NotesShape";
        aSNS[i++] = "com.sun.star.presentation.HandoutShape";
        aSNS[i++] = "com.sun.star.presentation.DocumentSettings";
        aSNS[i++] = "com.sun.star.presentation.FooterShape";
        aSNS[i++] = "com.sun.star.presentation.HeaderShape";
        aSNS[i++] = "com.sun.star.presentation.SlideNumberShape";
        aSNS[i++] = "com.sun.star.presentation.DateTimeShape";
        aSNS[i++] = "com.sun.star.presentation.CalcShape";
        aSNS[i++] = "com.sun.star.presentation.MediaShape";
    }
    else
    {
        aSNS[i++] = "com.sun.star.drawing.DocumentSettings";
    }
 
    DBG_ASSERT( i == aSNS.getLength(), "Sequence overrun!" );
 
    return comphelper::concatSequences( aSNS_ORG, aSNS );
}
 
// lang::XServiceInfo
OUString SAL_CALL SdXImpressDocument::getImplementationName()
{
    return OUString( "SdXImpressDocument" );
    /* // Matching the .component information:
       return mbImpressDoc
           ? OUString("com.sun.star.comp.Draw.PresentationDocument")
           : OUString("com.sun.star.comp.Draw.DrawingDocument");
    */
}
 
sal_Bool SAL_CALL SdXImpressDocument::supportsService( const OUString& ServiceName )
{
    return cppu::supportsService(this, ServiceName);
}
 
uno::Sequence< OUString > SAL_CALL SdXImpressDocument::getSupportedServiceNames()
{
    ::SolarMutexGuard aGuard;
 
    uno::Sequence< OUString > aSeq( 4 );
    OUString* pServices = aSeq.getArray();
 
    *pServices++ = "com.sun.star.document.OfficeDocument";
    *pServices++ = "com.sun.star.drawing.GenericDrawingDocument";
    *pServices++ = "com.sun.star.drawing.DrawingDocumentFactory";
 
    if( mbImpressDoc )
        *pServices++ = "com.sun.star.presentation.PresentationDocument";
    else
        *pServices++ = "com.sun.star.drawing.DrawingDocument";
 
    return aSeq;
}
 
// XPropertySet
uno::Reference< beans::XPropertySetInfo > SAL_CALL SdXImpressDocument::getPropertySetInfo(  )
{
    ::SolarMutexGuard aGuard;
    return mpPropSet->getPropertySetInfo();
}
 
void SAL_CALL SdXImpressDocument::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    const SfxItemPropertySimpleEntry* pEntry = mpPropSet->getPropertyMapEntry(aPropertyName);
 
    switch( pEntry ? pEntry->nWID : -1 )
    {
        case WID_MODEL_LANGUAGE:
        {
            lang::Locale aLocale;
            if(!(aValue >>= aLocale))
                throw lang::IllegalArgumentException();
 
            mpDoc->SetLanguage( LanguageTag::convertToLanguageType(aLocale), EE_CHAR_LANGUAGE );
            break;
        }
        case WID_MODEL_TABSTOP:
        {
            sal_Int32 nValue = 0;
            if(!(aValue >>= nValue) || nValue < 0 )
                throw lang::IllegalArgumentException();
 
            mpDoc->SetDefaultTabulator(static_cast<sal_uInt16>(nValue));
            break;
        }
        case WID_MODEL_VISAREA:
            {
                SfxObjectShell* pEmbeddedObj = mpDoc->GetDocSh();
                if( !pEmbeddedObj )
                    break;
 
                awt::Rectangle aVisArea;
                if( !(aValue >>= aVisArea) || (aVisArea.Width < 0) || (aVisArea.Height < 0) )
                    throw lang::IllegalArgumentException();
 
                sal_Int32 nRight, nTop;
                if (o3tl::checked_add(aVisArea.X, aVisArea.Width, nRight) || o3tl::checked_add(aVisArea.Y, aVisArea.Height, nTop))
                    throw lang::IllegalArgumentException();
 
                pEmbeddedObj->SetVisArea(::tools::Rectangle(aVisArea.X, aVisArea.Y, nRight, nTop));
            }
            break;
        case WID_MODEL_CONTFOCUS:
            {
                bool bFocus = false;
                if( !(aValue >>= bFocus ) )
                    throw lang::IllegalArgumentException();
                mpDoc->SetAutoControlFocus( bFocus );
            }
            break;
        case WID_MODEL_DSGNMODE:
            {
                bool bMode = false;
                if( !(aValue >>= bMode ) )
                    throw lang::IllegalArgumentException();
                mpDoc->SetOpenInDesignMode( bMode );
            }
            break;
        case WID_MODEL_BUILDID:
            aValue >>= maBuildId;
            return;
        case WID_MODEL_MAPUNIT:
        case WID_MODEL_BASICLIBS:
        case WID_MODEL_RUNTIMEUID: // is read-only
        case WID_MODEL_DIALOGLIBS:
        case WID_MODEL_FONTS:
            throw beans::PropertyVetoException();
        case WID_MODEL_INTEROPGRABBAG:
            setGrabBagItem(aValue);
            break;
        default:
            throw beans::UnknownPropertyException( aPropertyName, static_cast<cppu::OWeakObject*>(this));
    }
 
    SetModified();
}
 
uno::Any SAL_CALL SdXImpressDocument::getPropertyValue( const OUString& PropertyName )
{
    ::SolarMutexGuard aGuard;
 
    uno::Any aAny;
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    const SfxItemPropertySimpleEntry* pEntry = mpPropSet->getPropertyMapEntry(PropertyName);
 
    switch( pEntry ? pEntry->nWID : -1 )
    {
        case WID_MODEL_LANGUAGE:
        {
            LanguageType eLang = mpDoc->GetLanguage( EE_CHAR_LANGUAGE );
            aAny <<= LanguageTag::convertToLocale( eLang);
            break;
        }
        case WID_MODEL_TABSTOP:
            aAny <<= static_cast<sal_Int32>(mpDoc->GetDefaultTabulator());
            break;
        case WID_MODEL_VISAREA:
            {
                SfxObjectShell* pEmbeddedObj = mpDoc->GetDocSh();
                if( !pEmbeddedObj )
                    break;
 
                const ::tools::Rectangle& aRect = pEmbeddedObj->GetVisArea();
                awt::Rectangle aVisArea( aRect.Left(), aRect.Top(), aRect.getWidth(), aRect.getHeight() );
                aAny <<= aVisArea;
            }
            break;
        case WID_MODEL_MAPUNIT:
            {
                SfxObjectShell* pEmbeddedObj = mpDoc->GetDocSh();
                if( !pEmbeddedObj )
                    break;
 
                sal_Int16 nMeasureUnit = 0;
                SvxMapUnitToMeasureUnit( pEmbeddedObj->GetMapUnit(), nMeasureUnit );
                aAny <<= nMeasureUnit;
        }
        break;
        case WID_MODEL_FORBCHARS:
        {
            aAny <<= getForbiddenCharsTable();
        }
        break;
        case WID_MODEL_CONTFOCUS:
            aAny <<= mpDoc->GetAutoControlFocus();
            break;
        case WID_MODEL_DSGNMODE:
            aAny <<= mpDoc->GetOpenInDesignMode();
            break;
        case WID_MODEL_BASICLIBS:
            aAny <<= mpDocShell->GetBasicContainer();
            break;
        case WID_MODEL_DIALOGLIBS:
            aAny <<= mpDocShell->GetDialogContainer();
            break;
        case WID_MODEL_RUNTIMEUID:
            aAny <<= getRuntimeUID();
            break;
        case WID_MODEL_BUILDID:
            return uno::Any( maBuildId );
        case WID_MODEL_HASVALIDSIGNATURES:
            aAny <<= hasValidSignatures();
            break;
        case WID_MODEL_FONTS:
            {
                uno::Sequence<uno::Any> aSeq;
                int nSeqIndex = 0;
 
                sal_uInt16 const aWhichIds[] { EE_CHAR_FONTINFO, EE_CHAR_FONTINFO_CJK,
                                               EE_CHAR_FONTINFO_CTL };
 
                const SfxItemPool& rPool = mpDoc->GetPool();
                const SfxPoolItem* pItem;
 
                for(sal_uInt16 nWhichId : aWhichIds)
                {
                    sal_uInt32 nItems = rPool.GetItemCount2( nWhichId );
 
                    aSeq.realloc( aSeq.getLength() + nItems*5 + 5 );
 
                    for( sal_uInt32 j = 0; j < nItems; ++j )
                    {
                        if( nullptr != (pItem = rPool.GetItem2( nWhichId, j ) ) )
                        {
                            const SvxFontItem *pFont = static_cast<const SvxFontItem *>(pItem);
 
                            aSeq[nSeqIndex++] <<= pFont->GetFamilyName();
                            aSeq[nSeqIndex++] <<= pFont->GetStyleName();
                            aSeq[nSeqIndex++] <<= sal_Int16(pFont->GetFamily());
                            aSeq[nSeqIndex++] <<= sal_Int16(pFont->GetPitch());
                            aSeq[nSeqIndex++] <<= sal_Int16(pFont->GetCharSet());
                        }
                    }
 
                    const SvxFontItem& rFont = static_cast<const SvxFontItem&>(rPool.GetDefaultItem( nWhichId ));
 
                    aSeq[nSeqIndex++] <<= rFont.GetFamilyName();
                    aSeq[nSeqIndex++] <<= rFont.GetStyleName();
                    aSeq[nSeqIndex++] <<= sal_Int16(rFont.GetFamily());
                    aSeq[nSeqIndex++] <<= sal_Int16(rFont.GetPitch());
                    aSeq[nSeqIndex++] <<= sal_Int16(rFont.GetCharSet());
 
                }
 
                aSeq.realloc( nSeqIndex );
                aAny <<= aSeq;
            break;
            }
        case WID_MODEL_INTEROPGRABBAG:
            getGrabBagItem(aAny);
            break;
        default:
            throw beans::UnknownPropertyException( PropertyName, static_cast<cppu::OWeakObject*>(this));
    }
 
    return aAny;
}
 
void SAL_CALL SdXImpressDocument::addPropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >&  ) {}
void SAL_CALL SdXImpressDocument::removePropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >&  ) {}
void SAL_CALL SdXImpressDocument::addVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >&  ) {}
void SAL_CALL SdXImpressDocument::removeVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >&  ) {}
 
// XLinkTargetSupplier
uno::Reference< container::XNameAccess > SAL_CALL SdXImpressDocument::getLinks()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    uno::Reference< container::XNameAccess > xLinks( mxLinks );
    if( !xLinks.is() )
        mxLinks = xLinks = new SdDocLinkTargets( *this );
    return xLinks;
}
 
// XStyleFamiliesSupplier
uno::Reference< container::XNameAccess > SAL_CALL SdXImpressDocument::getStyleFamilies(  )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    uno::Reference< container::XNameAccess > xStyles( dynamic_cast< container::XNameAccess* >( mpDoc->GetStyleSheetPool()) );
    return xStyles;
}
 
// XAnyCompareFactory
uno::Reference< css::ucb::XAnyCompare > SAL_CALL SdXImpressDocument::createAnyCompareByName( const OUString& )
{
    return SvxCreateNumRuleCompare();
}
 
// XRenderable
sal_Int32 SAL_CALL SdXImpressDocument::getRendererCount( const uno::Any& rSelection,
                                                         const uno::Sequence< beans::PropertyValue >&  )
{
    ::SolarMutexGuard aGuard;
    sal_Int32   nRet = 0;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    if( mpDocShell && mpDoc )
    {
        uno::Reference< frame::XModel > xModel;
 
        rSelection >>= xModel;
 
        if( xModel == mpDocShell->GetModel() )
            nRet = mpDoc->GetSdPageCount( PageKind::Standard );
        else
        {
            uno::Reference< drawing::XShapes > xShapes;
 
            rSelection >>= xShapes;
 
            if( xShapes.is() && xShapes->getCount() )
                nRet = 1;
        }
    }
    return nRet;
}
 
uno::Sequence< beans::PropertyValue > SAL_CALL SdXImpressDocument::getRenderer( sal_Int32 , const uno::Any& ,
                                                                                const uno::Sequence< beans::PropertyValue >& rxOptions )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    bool bExportNotesPages = false;
    for( sal_Int32 nProperty = 0, nPropertyCount = rxOptions.getLength(); nProperty < nPropertyCount; ++nProperty )
    {
        if ( rxOptions[ nProperty ].Name == "ExportNotesPages" )
            rxOptions[ nProperty].Value >>= bExportNotesPages;
    }
    uno::Sequence< beans::PropertyValue > aRenderer;
    if( mpDocShell && mpDoc )
    {
        awt::Size aPageSize;
        if ( bExportNotesPages )
        {
            Size aNotesPageSize = mpDoc->GetSdPage( 0, PageKind::Notes )->GetSize();
            aPageSize = awt::Size( aNotesPageSize.Width(), aNotesPageSize.Height() );
        }
        else
        {
            const ::tools::Rectangle aVisArea( mpDocShell->GetVisArea( embed::Aspects::MSOLE_DOCPRINT ) );
            aPageSize = awt::Size( aVisArea.GetWidth(), aVisArea.GetHeight() );
        }
        aRenderer.realloc( 1 );
 
        aRenderer[ 0 ].Name = "PageSize" ;
        aRenderer[ 0 ].Value <<= aPageSize;
    }
    return aRenderer;
}
 
class ImplRenderPaintProc : public sdr::contact::ViewObjectContactRedirector
{
    const SdrLayerAdmin&    rLayerAdmin;
    SdrPageView*            pSdrPageView;
    vcl::PDFExtOutDevData*  pPDFExtOutDevData;
 
    vcl::PDFWriter::StructElement ImplBegStructureTag( SdrObject& rObject );
 
public:
    bool IsVisible  ( const SdrObject* pObj ) const;
    bool IsPrintable( const SdrObject* pObj ) const;
 
    ImplRenderPaintProc( const SdrLayerAdmin& rLA, SdrPageView* pView, vcl::PDFExtOutDevData* pData );
 
    // all default implementations just call the same methods at the original. To do something
    // different, override the method and at least do what the method does.
    virtual drawinglayer::primitive2d::Primitive2DContainer createRedirectedPrimitive2DSequence(
        const sdr::contact::ViewObjectContact& rOriginal,
        const sdr::contact::DisplayInfo& rDisplayInfo) override;
};
 
ImplRenderPaintProc::ImplRenderPaintProc( const SdrLayerAdmin& rLA, SdrPageView* pView, vcl::PDFExtOutDevData* pData )
:   ViewObjectContactRedirector(),
    rLayerAdmin         ( rLA ),
    pSdrPageView        ( pView ),
    pPDFExtOutDevData   ( pData )
{
}
 
sal_Int32 ImplPDFGetBookmarkPage( const OUString& rBookmark, SdDrawDocument const & rDoc )
{
    sal_Int32 nPage = -1;
 
    OUString aBookmark( rBookmark );
 
    if( rBookmark.startsWith("#") )
        aBookmark = rBookmark.copy( 1 );
 
    // is the bookmark a page ?
    bool        bIsMasterPage;
    sal_uInt16  nPgNum = rDoc.GetPageByName( aBookmark, bIsMasterPage );
    SdrObject*  pObj = nullptr;
 
    if ( nPgNum == SDRPAGE_NOTFOUND )
    {
        // is the bookmark a object ?
        pObj = rDoc.GetObj( aBookmark );
        if (pObj)
            nPgNum = pObj->getSdrPageFromSdrObject()->GetPageNum();
    }
    if ( nPgNum != SDRPAGE_NOTFOUND )
        nPage = ( nPgNum - 1 ) / 2;
    return nPage;
}
 
void ImplPDFExportComments( const uno::Reference< drawing::XDrawPage >& xPage, vcl::PDFExtOutDevData& rPDFExtOutDevData )
{
    try
    {
        uno::Reference< office::XAnnotationAccess > xAnnotationAccess( xPage, uno::UNO_QUERY_THROW );
        uno::Reference< office::XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() );
 
        LanguageType eLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
        while( xAnnotationEnumeration->hasMoreElements() )
        {
            uno::Reference< office::XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement() );
 
            geometry::RealPoint2D aRealPoint2D( xAnnotation->getPosition() );
            uno::Reference< text::XText > xText( xAnnotation->getTextRange() );
            util::DateTime aDateTime( xAnnotation->getDateTime() );
 
            Date aDate( aDateTime.Day, aDateTime.Month, aDateTime.Year );
            ::tools::Time aTime( ::tools::Time::EMPTY );
            OUString aStr = SvxDateTimeField::GetFormatted( aDate, aTime,
                                SvxDateFormat::B, SvxTimeFormat::AppDefault,
                                *(SD_MOD()->GetNumberFormatter()), eLanguage );
 
            vcl::PDFNote aNote;
            OUString sTitle( xAnnotation->getAuthor() );
            sTitle += ", ";
            sTitle += aStr;
            aNote.Title = sTitle;
            aNote.Contents = xText->getString();
            rPDFExtOutDevData.CreateNote( ::tools::Rectangle( Point( static_cast< long >( aRealPoint2D.X * 100 ),
                static_cast< long >( aRealPoint2D.Y * 100 ) ), Size( 1000, 1000 ) ), aNote );
        }
    }
    catch (const uno::Exception&)
    {
    }
}
 
void ImplPDFExportShapeInteraction( const uno::Reference< drawing::XShape >& xShape, SdDrawDocument& rDoc, vcl::PDFExtOutDevData& rPDFExtOutDevData )
{
    if ( xShape->getShapeType() == "com.sun.star.drawing.GroupShape" )
    {
        uno::Reference< container::XIndexAccess > xIndexAccess( xShape, uno::UNO_QUERY );
        if ( xIndexAccess.is() )
        {
            sal_Int32 i, nCount = xIndexAccess->getCount();
            for ( i = 0; i < nCount; i++ )
            {
                uno::Reference< drawing::XShape > xSubShape( xIndexAccess->getByIndex( i ), uno::UNO_QUERY );
                if ( xSubShape.is() )
                    ImplPDFExportShapeInteraction( xSubShape, rDoc, rPDFExtOutDevData );
            }
        }
    }
    else
    {
        uno::Reference< beans::XPropertySet > xShapePropSet( xShape, uno::UNO_QUERY );
        if( xShapePropSet.is() )
        {
            Size        aPageSize( rDoc.GetSdPage( 0, PageKind::Standard )->GetSize() );
            Point aPoint( 0, 0 );
            ::tools::Rectangle   aPageRect( aPoint, aPageSize );
 
            awt::Point  aShapePos( xShape->getPosition() );
            awt::Size   aShapeSize( xShape->getSize() );
            ::tools::Rectangle   aLinkRect( Point( aShapePos.X, aShapePos.Y ), Size( aShapeSize.Width, aShapeSize.Height ) );
 
            // Handle linked videos.
            if (xShape->getShapeType() == "com.sun.star.drawing.MediaShape" || xShape->getShapeType() == "com.sun.star.presentation.MediaShape")
            {
                OUString aMediaURL;
                xShapePropSet->getPropertyValue("MediaURL") >>= aMediaURL;
                if (!aMediaURL.isEmpty())
                {
                    sal_Int32 nScreenId = rPDFExtOutDevData.CreateScreen(aLinkRect, rPDFExtOutDevData.GetCurrentPageNumber());
                    if (aMediaURL.startsWith("vnd.sun.star.Package:"))
                    {
                        OUString aTempFileURL;
                        xShapePropSet->getPropertyValue("PrivateTempFileURL") >>= aTempFileURL;
                        rPDFExtOutDevData.SetScreenStream(nScreenId, aTempFileURL);
                    }
                    else
                        rPDFExtOutDevData.SetScreenURL(nScreenId, aMediaURL);
                }
            }
 
            presentation::ClickAction eCa;
            uno::Any aAny( xShapePropSet->getPropertyValue( "OnClick" ) );
            if ( aAny >>= eCa )
            {
                switch ( eCa )
                {
                    case presentation::ClickAction_LASTPAGE :
                    {
                        sal_Int32 nCount = rDoc.GetSdPageCount( PageKind::Standard );
                        sal_Int32 nDestId = rPDFExtOutDevData.CreateDest( aPageRect, nCount - 1, vcl::PDFWriter::DestAreaType::FitRectangle );
                        sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink( aLinkRect );
                        rPDFExtOutDevData.SetLinkDest( nLinkId, nDestId );
                    }
                    break;
                    case presentation::ClickAction_FIRSTPAGE :
                    {
                        sal_Int32 nDestId = rPDFExtOutDevData.CreateDest( aPageRect, 0, vcl::PDFWriter::DestAreaType::FitRectangle );
                        sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink( aLinkRect );
                        rPDFExtOutDevData.SetLinkDest( nLinkId, nDestId );
                    }
                    break;
                    case presentation::ClickAction_PREVPAGE :
                    {
                        sal_Int32 nDestPage = rPDFExtOutDevData.GetCurrentPageNumber();
                        if ( nDestPage )
                            nDestPage--;
                        sal_Int32 nDestId = rPDFExtOutDevData.CreateDest( aPageRect, nDestPage, vcl::PDFWriter::DestAreaType::FitRectangle );
                        sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink( aLinkRect );
                        rPDFExtOutDevData.SetLinkDest( nLinkId, nDestId );
                    }
                    break;
                    case presentation::ClickAction_NEXTPAGE :
                    {
                        sal_Int32 nDestPage = rPDFExtOutDevData.GetCurrentPageNumber() + 1;
                        sal_Int32 nLastPage = rDoc.GetSdPageCount( PageKind::Standard ) - 1;
                        if ( nDestPage > nLastPage )
                            nDestPage = nLastPage;
                        sal_Int32 nDestId = rPDFExtOutDevData.CreateDest( aPageRect, nDestPage, vcl::PDFWriter::DestAreaType::FitRectangle );
                        sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink( aLinkRect );
                        rPDFExtOutDevData.SetLinkDest( nLinkId, nDestId );
                    }
                    break;
 
                    case presentation::ClickAction_PROGRAM :
                    case presentation::ClickAction_BOOKMARK :
                    case presentation::ClickAction_DOCUMENT :
                    {
                        OUString aBookmark;
                        xShapePropSet->getPropertyValue( "Bookmark" ) >>= aBookmark;
                        if( !aBookmark.isEmpty() )
                        {
                            switch( eCa )
                            {
                                case presentation::ClickAction_DOCUMENT :
                                case presentation::ClickAction_PROGRAM :
                                {
                                    sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink( aLinkRect );
                                    rPDFExtOutDevData.SetLinkURL( nLinkId, aBookmark );
                                }
                                break;
                                case presentation::ClickAction_BOOKMARK :
                                {
                                    sal_Int32 nPage = ImplPDFGetBookmarkPage( aBookmark, rDoc );
                                    if ( nPage != -1 )
                                    {
                                        sal_Int32 nDestId = rPDFExtOutDevData.CreateDest( aPageRect, nPage, vcl::PDFWriter::DestAreaType::FitRectangle );
                                        sal_Int32 nLinkId = rPDFExtOutDevData.CreateLink( aLinkRect );
                                        rPDFExtOutDevData.SetLinkDest( nLinkId, nDestId );
                                    }
                                }
                                break;
                                default:
                                    break;
                            }
                        }
                    }
                    break;
 
                    case presentation::ClickAction_STOPPRESENTATION :
                    case presentation::ClickAction_SOUND :
                    case presentation::ClickAction_INVISIBLE :
                    case presentation::ClickAction_VERB :
                    case presentation::ClickAction_VANISH :
                    case presentation::ClickAction_MACRO :
                    default :
                    break;
                }
            }
        }
    }
}
 
vcl::PDFWriter::StructElement ImplRenderPaintProc::ImplBegStructureTag( SdrObject& rObject )
{
    vcl::PDFWriter::StructElement eElement(vcl::PDFWriter::NonStructElement);
 
    if ( pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportTaggedPDF() )
    {
        SdrInventor nInventor   = rObject.GetObjInventor();
        sal_uInt16  nIdentifier = rObject.GetObjIdentifier();
        bool        bIsTextObj  = dynamic_cast< const SdrTextObj *>( &rObject ) !=  nullptr;
 
        if ( nInventor == SdrInventor::Default )
        {
            if ( nIdentifier == OBJ_GRUP )
                eElement = vcl::PDFWriter::Section;
            else if ( nIdentifier == OBJ_TITLETEXT )
                eElement = vcl::PDFWriter::Heading;
            else if ( nIdentifier == OBJ_OUTLINETEXT )
                eElement = vcl::PDFWriter::Division;
            else if ( !bIsTextObj || !static_cast<SdrTextObj&>(rObject).HasText() )
                eElement = vcl::PDFWriter::Figure;
        }
    }
 
    return eElement;
}
 
drawinglayer::primitive2d::Primitive2DContainer ImplRenderPaintProc::createRedirectedPrimitive2DSequence(
    const sdr::contact::ViewObjectContact& rOriginal,
    const sdr::contact::DisplayInfo& rDisplayInfo)
{
    SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
 
    if(pObject)
    {
        drawinglayer::primitive2d::Primitive2DContainer xRetval;
 
        if(pObject->getSdrPageFromSdrObject())
        {
            if(pObject->getSdrPageFromSdrObject()->checkVisibility(rOriginal, rDisplayInfo, false))
            {
                if(IsVisible(pObject) && IsPrintable(pObject))
                {
                    const vcl::PDFWriter::StructElement eElement(ImplBegStructureTag( *pObject ));
                    const bool bTagUsed(vcl::PDFWriter::NonStructElement != eElement);
 
                    xRetval = sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo);
 
                    if(!xRetval.empty() && bTagUsed)
                    {
                        // embed Primitive2DSequence in a structure tag element for
                        // exactly this purpose (StructureTagPrimitive2D)
                        const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::StructureTagPrimitive2D(eElement, xRetval));
                        xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
                    }
                }
            }
        }
 
        return xRetval;
    }
    else
    {
        // not an object, maybe a page
        return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo);
    }
}
 
bool ImplRenderPaintProc::IsVisible( const SdrObject* pObj ) const
{
    bool bVisible = true;
    SdrLayerID nLayerId = pObj->GetLayer();
    if( pSdrPageView )
    {
        const SdrLayer* pSdrLayer = rLayerAdmin.GetLayerPerID( nLayerId );
        if ( pSdrLayer )
        {
            OUString aLayerName = pSdrLayer->GetName();
            bVisible = pSdrPageView->IsLayerVisible( aLayerName );
        }
    }
    return bVisible;
}
bool ImplRenderPaintProc::IsPrintable( const SdrObject* pObj ) const
{
    bool bPrintable = true;
    SdrLayerID nLayerId = pObj->GetLayer();
    if( pSdrPageView )
    {
        const SdrLayer* pSdrLayer = rLayerAdmin.GetLayerPerID( nLayerId );
        if ( pSdrLayer )
        {
            OUString aLayerName = pSdrLayer->GetName();
            bPrintable = pSdrPageView->IsLayerPrintable( aLayerName );
        }
    }
    return bPrintable;
 
}
 
namespace
{
    sal_Int16 CalcOutputPageNum(vcl::PDFExtOutDevData const * pPDFExtOutDevData, SdDrawDocument const *pDoc, sal_Int16 nPageNumber)
    {
        //export all pages, simple one to one case
        if (pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportHiddenSlides())
            return nPageNumber-1;
        //check all preceding pages, and only count non-hidden ones
        sal_Int16 nRet = 0;
        for (sal_Int16 i = 0; i < nPageNumber-1; ++i)
        {
           if (!pDoc->GetSdPage(i, PageKind::Standard)->IsExcluded())
                ++nRet;
        }
        return nRet;
    }
}
 
void SAL_CALL SdXImpressDocument::render( sal_Int32 nRenderer, const uno::Any& rSelection,
                                          const uno::Sequence< beans::PropertyValue >& rxOptions )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpDoc )
        throw lang::DisposedException();
 
    if( mpDocShell && mpDoc )
    {
        uno::Reference< awt::XDevice >  xRenderDevice;
        const sal_Int32                 nPageNumber = nRenderer + 1;
        PageKind                        ePageKind = PageKind::Standard;
        bool                        bExportNotesPages = false;
 
        for( sal_Int32 nProperty = 0, nPropertyCount = rxOptions.getLength(); nProperty < nPropertyCount; ++nProperty )
        {
            if ( rxOptions[ nProperty ].Name == "RenderDevice" )
                rxOptions[ nProperty ].Value >>= xRenderDevice;
            else if ( rxOptions[ nProperty ].Name == "ExportNotesPages" )
            {
                rxOptions[ nProperty].Value >>= bExportNotesPages;
                if ( bExportNotesPages )
                    ePageKind = PageKind::Notes;
            }
        }
 
        if( xRenderDevice.is() && nPageNumber && ( nPageNumber <= mpDoc->GetSdPageCount( ePageKind ) ) )
        {
            VCLXDevice* pDevice = VCLXDevice::GetImplementation( xRenderDevice );
            VclPtr< OutputDevice> pOut = pDevice ? pDevice->GetOutputDevice() : VclPtr< OutputDevice >();
 
            if( pOut )
            {
                vcl::PDFExtOutDevData* pPDFExtOutDevData = dynamic_cast<vcl::PDFExtOutDevData* >( pOut->GetExtOutDevData() );
 
                if ( !( mpDoc->GetSdPage(static_cast<sal_Int16>(nPageNumber)-1, PageKind::Standard)->IsExcluded() ) ||
                    (pPDFExtOutDevData && pPDFExtOutDevData->GetIsExportHiddenSlides()) )
                {
                    std::unique_ptr<::sd::ClientView> pView( new ::sd::ClientView( mpDocShell, pOut ) );
                    ::tools::Rectangle                         aVisArea = ::tools::Rectangle( Point(), mpDoc->GetSdPage( static_cast<sal_uInt16>(nPageNumber) - 1, ePageKind )->GetSize() );
                    vcl::Region                       aRegion( aVisArea );
 
                    ::sd::ViewShell* pOldViewSh = mpDocShell->GetViewShell();
                    ::sd::View* pOldSdView = pOldViewSh ? pOldViewSh->GetView() : nullptr;
 
                    if  ( pOldSdView )
                        pOldSdView->SdrEndTextEdit();
 
                    pView->SetHlplVisible( false );
                    pView->SetGridVisible( false );
                    pView->SetBordVisible( false );
                    pView->SetPageVisible( false );
                    pView->SetGlueVisible( false );
 
                    pOut->SetMapMode(MapMode(MapUnit::Map100thMM));
                    pOut->IntersectClipRegion( aVisArea );
 
                    uno::Reference< frame::XModel > xModel;
                    rSelection >>= xModel;
 
                    if( xModel == mpDocShell->GetModel() )
                    {
                        pView->ShowSdrPage( mpDoc->GetSdPage( static_cast<sal_uInt16>(nPageNumber) - 1, ePageKind ));
                        SdrPageView* pPV = pView->GetSdrPageView();
 
                        if( pOldSdView )
                        {
                            SdrPageView* pOldPV = pOldSdView->GetSdrPageView();
                            if( pPV && pOldPV )
                            {
                                pPV->SetVisibleLayers( pOldPV->GetVisibleLayers() );
                                pPV->SetPrintableLayers( pOldPV->GetPrintableLayers() );
                            }
                        }
 
                        ImplRenderPaintProc aImplRenderPaintProc( mpDoc->GetLayerAdmin(),
                            pPV, pPDFExtOutDevData );
 
                        // background color for outliner :o
                        SdPage* pPage = pPV ? static_cast<SdPage*>(pPV->GetPage()) : nullptr;
                        if( pPage )
                        {
                            SdrOutliner& rOutl = mpDoc->GetDrawOutliner();
                            bool bScreenDisplay(true);
 
                            if(bScreenDisplay && pOut && OUTDEV_PRINTER == pOut->GetOutDevType())
                            {
                                // #i75566# printing; suppress AutoColor BackgroundColor generation
                                // for visibility reasons by giving GetPageBackgroundColor()
                                // the needed hint
                                bScreenDisplay = false;
                            }
 
                            if(bScreenDisplay && pOut && pOut->GetPDFWriter())
                            {
                                // #i75566# PDF export; suppress AutoColor BackgroundColor generation (see above)
                                bScreenDisplay = false;
                            }
 
                            // #i75566# Name change GetBackgroundColor -> GetPageBackgroundColor and
                            // hint value if screen display. Only then the AutoColor mechanisms shall be applied
                            rOutl.SetBackgroundColor( pPage->GetPageBackgroundColor( pPV, bScreenDisplay ) );
                        }
                        pView->SdrPaintView::CompleteRedraw( pOut, aRegion, &aImplRenderPaintProc );
 
                        if ( pPDFExtOutDevData && pPage )
                        {
                            try
                            {
                                uno::Any aAny;
                                uno::Reference< drawing::XDrawPage > xPage( uno::Reference< drawing::XDrawPage >::query( pPage->getUnoPage() ) );
                                if ( xPage.is() )
                                {
                                    if ( pPDFExtOutDevData->GetIsExportNotes() )
                                        ImplPDFExportComments( xPage, *pPDFExtOutDevData );
                                    uno::Reference< beans::XPropertySet > xPagePropSet( xPage, uno::UNO_QUERY );
                                    if( xPagePropSet.is() )
                                    {
                                        // exporting object interactions to pdf
 
                                        // if necessary, the master page interactions will be exported first
                                        bool bIsBackgroundObjectsVisible = false;   // #i39428# IsBackgroundObjectsVisible not available for Draw
                                        if ( mbImpressDoc && xPagePropSet->getPropertySetInfo()->hasPropertyByName( "IsBackgroundObjectsVisible" ) )
                                            xPagePropSet->getPropertyValue( "IsBackgroundObjectsVisible" ) >>= bIsBackgroundObjectsVisible;
                                        if ( bIsBackgroundObjectsVisible && !pPDFExtOutDevData->GetIsExportNotesPages() )
                                        {
                                            uno::Reference< drawing::XMasterPageTarget > xMasterPageTarget( xPage, uno::UNO_QUERY );
                                            if ( xMasterPageTarget.is() )
                                            {
                                                uno::Reference< drawing::XDrawPage > xMasterPage = xMasterPageTarget->getMasterPage();
                                                if ( xMasterPage.is() )
                                                {
                                                    uno::Reference< drawing::XShapes> xShapes( xMasterPage, uno::UNO_QUERY );
                                                    sal_Int32 i, nCount = xShapes->getCount();
                                                    for ( i = 0; i < nCount; i++ )
                                                    {
                                                        aAny = xShapes->getByIndex( i );
                                                        uno::Reference< drawing::XShape > xShape;
                                                        if ( aAny >>= xShape )
                                                            ImplPDFExportShapeInteraction( xShape, *mpDoc, *pPDFExtOutDevData );
                                                    }
                                                }
                                            }
                                        }
 
                                        // exporting slide page object interactions
                                        uno::Reference< drawing::XShapes> xShapes( xPage, uno::UNO_QUERY );
                                        sal_Int32 i, nCount = xShapes->getCount();
                                        for ( i = 0; i < nCount; i++ )
                                        {
                                            aAny = xShapes->getByIndex( i );
                                            uno::Reference< drawing::XShape > xShape;
                                            if ( aAny >>= xShape )
                                                ImplPDFExportShapeInteraction( xShape, *mpDoc, *pPDFExtOutDevData );
                                        }
 
                                        // exporting transition effects to pdf
                                        if ( mbImpressDoc && !pPDFExtOutDevData->GetIsExportNotesPages() && pPDFExtOutDevData->GetIsExportTransitionEffects() )
                                        {
                                            const OUString sEffect( "Effect" );
                                            const OUString sSpeed ( "Speed" );
                                            sal_Int32 nTime = 800;
                                            presentation::AnimationSpeed aAs;
                                            if ( xPagePropSet->getPropertySetInfo( )->hasPropertyByName( sSpeed ) )
                                            {
                                                aAny = xPagePropSet->getPropertyValue( sSpeed );
                                                if ( aAny >>= aAs )
                                                {
                                                    switch( aAs )
                                                    {
                                                        case presentation::AnimationSpeed_SLOW : nTime = 1500; break;
                                                        case presentation::AnimationSpeed_FAST : nTime = 300; break;
                                                        default:
                                                        case presentation::AnimationSpeed_MEDIUM : nTime = 800;
                                                    }
                                                }
                                            }
                                            presentation::FadeEffect eFe;
                                            vcl::PDFWriter::PageTransition eType = vcl::PDFWriter::PageTransition::Regular;
                                            if ( xPagePropSet->getPropertySetInfo( )->hasPropertyByName( sEffect ) )
                                            {
                                                aAny = xPagePropSet->getPropertyValue( sEffect );
                                                if ( aAny >>= eFe )
                                                {
                                                    switch( eFe )
                                                    {
                                                        case presentation::FadeEffect_HORIZONTAL_LINES :
                                                        case presentation::FadeEffect_HORIZONTAL_CHECKERBOARD :
                                                        case presentation::FadeEffect_HORIZONTAL_STRIPES : eType = vcl::PDFWriter::PageTransition::BlindsHorizontal; break;
 
                                                        case presentation::FadeEffect_VERTICAL_LINES :
                                                        case presentation::FadeEffect_VERTICAL_CHECKERBOARD :
                                                        case presentation::FadeEffect_VERTICAL_STRIPES : eType = vcl::PDFWriter::PageTransition::BlindsVertical; break;
 
                                                        case presentation::FadeEffect_UNCOVER_TO_RIGHT :
                                                        case presentation::FadeEffect_UNCOVER_TO_UPPERRIGHT :
                                                        case presentation::FadeEffect_ROLL_FROM_LEFT :
                                                        case presentation::FadeEffect_FADE_FROM_UPPERLEFT :
                                                        case presentation::FadeEffect_MOVE_FROM_UPPERLEFT :
                                                        case presentation::FadeEffect_FADE_FROM_LEFT :
                                                        case presentation::FadeEffect_MOVE_FROM_LEFT : eType = vcl::PDFWriter::PageTransition::WipeLeftToRight; break;
 
                                                        case presentation::FadeEffect_UNCOVER_TO_BOTTOM :
                                                        case presentation::FadeEffect_UNCOVER_TO_LOWERRIGHT :
                                                        case presentation::FadeEffect_ROLL_FROM_TOP :
                                                        case presentation::FadeEffect_FADE_FROM_UPPERRIGHT :
                                                        case presentation::FadeEffect_MOVE_FROM_UPPERRIGHT :
                                                        case presentation::FadeEffect_FADE_FROM_TOP :
                                                        case presentation::FadeEffect_MOVE_FROM_TOP : eType = vcl::PDFWriter::PageTransition::WipeTopToBottom; break;
 
                                                        case presentation::FadeEffect_UNCOVER_TO_LEFT :
                                                        case presentation::FadeEffect_UNCOVER_TO_LOWERLEFT :
                                                        case presentation::FadeEffect_ROLL_FROM_RIGHT :
 
                                                        case presentation::FadeEffect_FADE_FROM_LOWERRIGHT :
                                                        case presentation::FadeEffect_MOVE_FROM_LOWERRIGHT :
                                                        case presentation::FadeEffect_FADE_FROM_RIGHT :
                                                        case presentation::FadeEffect_MOVE_FROM_RIGHT : eType = vcl::PDFWriter::PageTransition::WipeRightToLeft; break;
 
                                                        case presentation::FadeEffect_UNCOVER_TO_TOP :
                                                        case presentation::FadeEffect_UNCOVER_TO_UPPERLEFT :
                                                        case presentation::FadeEffect_ROLL_FROM_BOTTOM :
                                                        case presentation::FadeEffect_FADE_FROM_LOWERLEFT :
                                                        case presentation::FadeEffect_MOVE_FROM_LOWERLEFT :
                                                        case presentation::FadeEffect_FADE_FROM_BOTTOM :
                                                        case presentation::FadeEffect_MOVE_FROM_BOTTOM : eType = vcl::PDFWriter::PageTransition::WipeBottomToTop; break;
 
                                                        case presentation::FadeEffect_OPEN_VERTICAL : eType = vcl::PDFWriter::PageTransition::SplitHorizontalInward; break;
                                                        case presentation::FadeEffect_CLOSE_HORIZONTAL : eType = vcl::PDFWriter::PageTransition::SplitHorizontalOutward; break;
 
                                                        case presentation::FadeEffect_OPEN_HORIZONTAL : eType = vcl::PDFWriter::PageTransition::SplitVerticalInward; break;
                                                        case presentation::FadeEffect_CLOSE_VERTICAL : eType = vcl::PDFWriter::PageTransition::SplitVerticalOutward; break;
 
                                                        case presentation::FadeEffect_FADE_TO_CENTER : eType = vcl::PDFWriter::PageTransition::BoxInward; break;
                                                        case presentation::FadeEffect_FADE_FROM_CENTER : eType = vcl::PDFWriter::PageTransition::BoxOutward; break;
 
                                                        case presentation::FadeEffect_NONE : eType = vcl::PDFWriter::PageTransition::Regular; break;
 
                                                        case presentation::FadeEffect_RANDOM :
                                                        case presentation::FadeEffect_DISSOLVE :
                                                        default: eType = vcl::PDFWriter::PageTransition::Dissolve; break;
                                                    }
                                                }
                                            }
 
                                            if ( xPagePropSet->getPropertySetInfo( )->hasPropertyByName( sEffect ) ||
                                                xPagePropSet->getPropertySetInfo( )->hasPropertyByName( sSpeed ) )
                                            {
                                                pPDFExtOutDevData->SetPageTransition( eType, nTime );
                                            }
                                        }
                                    }
                                }
 
                                Size        aPageSize( mpDoc->GetSdPage( 0, PageKind::Standard )->GetSize() );
                                Point aPoint( 0, 0 );
                                ::tools::Rectangle   aPageRect( aPoint, aPageSize );
 
                                // resolving links found in this page by the method ImpEditEngine::Paint
                                std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks();
                                std::vector< vcl::PDFExtOutDevBookmarkEntry >::iterator aIBeg = rBookmarks.begin();
                                std::vector< vcl::PDFExtOutDevBookmarkEntry >::iterator aIEnd = rBookmarks.end();
                                while ( aIBeg != aIEnd )
                                {
                                    sal_Int32 nPage = ImplPDFGetBookmarkPage( aIBeg->aBookmark, *mpDoc );
                                    if ( nPage != -1 )
                                    {
                                        if ( aIBeg->nLinkId != -1 )
                                            pPDFExtOutDevData->SetLinkDest( aIBeg->nLinkId, pPDFExtOutDevData->CreateDest( aPageRect, nPage, vcl::PDFWriter::DestAreaType::FitRectangle ) );
                                        else
                                            pPDFExtOutDevData->DescribeRegisteredDest( aIBeg->nDestId, aPageRect, nPage, vcl::PDFWriter::DestAreaType::FitRectangle );
                                    }
                                    else
                                        pPDFExtOutDevData->SetLinkURL( aIBeg->nLinkId, aIBeg->aBookmark );
                                    ++aIBeg;
                                }
                                rBookmarks.clear();
                                //---> #i56629, #i40318
                                //get the page name, will be used as outline element in PDF bookmark pane
                                OUString aPageName = mpDoc->GetSdPage( static_cast<sal_uInt16>(nPageNumber) - 1 , PageKind::Standard )->GetName();
                                if( !aPageName.isEmpty() )
                                {
                                    // Destination PageNum
                                    const sal_Int32 nDestPageNum = CalcOutputPageNum(pPDFExtOutDevData, mpDoc, nPageNumber);
 
                                    // insert the bookmark to this page into the NamedDestinations
                                    if( pPDFExtOutDevData->GetIsExportNamedDestinations() )
                                        pPDFExtOutDevData->CreateNamedDest(aPageName, aPageRect, nDestPageNum);
 
                                    // add the name to the outline, (almost) same code as in sc/source/ui/unoobj/docuno.cxx
                                    // issue #i40318.
 
                                    if( pPDFExtOutDevData->GetIsExportBookmarks() )
                                    {
                                        // Destination Export
                                        const sal_Int32 nDestId =
                                            pPDFExtOutDevData->CreateDest(aPageRect , nDestPageNum);
 
                                        // Create a new outline item:
                                        pPDFExtOutDevData->CreateOutlineItem( -1 , aPageName, nDestId );
                                    }
                                }
                                //<--- #i56629, #i40318
                            }
                            catch (const uno::Exception&)
                            {
                            }
 
                        }
                    }
                    else
                    {
                        uno::Reference< drawing::XShapes > xShapes;
                        rSelection >>= xShapes;
 
                        if( xShapes.is() && xShapes->getCount() )
                        {
                        SdrPageView* pPV = nullptr;
 
                        ImplRenderPaintProc  aImplRenderPaintProc( mpDoc->GetLayerAdmin(),
                                            pOldSdView ? pOldSdView->GetSdrPageView() : nullptr, pPDFExtOutDevData );
 
                            for( sal_uInt32 i = 0, nCount = xShapes->getCount(); i < nCount; i++ )
                            {
                                uno::Reference< drawing::XShape > xShape;
                                xShapes->getByIndex( i ) >>= xShape;
 
                                if( xShape.is() )
                                {
                                    SvxShape* pShape = SvxShape::getImplementation( xShape );
 
                                    if( pShape )
                                    {
                                        SdrObject* pObj = pShape->GetSdrObject();
                                        if( pObj && pObj->getSdrPageFromSdrObject()
                                            && aImplRenderPaintProc.IsVisible( pObj )
                                                && aImplRenderPaintProc.IsPrintable( pObj ) )
                                        {
                                            if( !pPV )
                                                pPV = pView->ShowSdrPage( pObj->getSdrPageFromSdrObject() );
 
                                            if( pPV )
                                                pView->MarkObj( pObj, pPV );
                                        }
                                    }
                                }
                            }
                            pView->DrawMarkedObj(*pOut);
                        }
                    }
                }
            }
        }
    }
}
 
DrawViewShell* SdXImpressDocument::GetViewShell()
{
    DrawViewShell* pViewSh = dynamic_cast<DrawViewShell*>(mpDocShell->GetViewShell());
    if (!pViewSh)
    {
        SAL_WARN("sd", "DrawViewShell not available!");
        return nullptr;
    }
    return pViewSh;
}
 
void SdXImpressDocument::paintTile( VirtualDevice& rDevice,
                            int nOutputWidth, int nOutputHeight,
                            int nTilePosX, int nTilePosY,
                            long nTileWidth, long nTileHeight )
{
    DrawViewShell* pViewSh = GetViewShell();
    if (!pViewSh)
        return;
 
    // Scaling. Must convert from pixels to twips. We know
    // that VirtualDevices use a DPI of 96.
    // We specifically calculate these scales first as we're still
    // in TWIPs, and might as well minimize the number of conversions.
    Fraction scaleX = Fraction( nOutputWidth, 96 ) * Fraction(1440) /
                                Fraction( nTileWidth);
    Fraction scaleY = Fraction( nOutputHeight, 96 ) * Fraction(1440) /
                                Fraction( nTileHeight);
 
    // svx seems to be the only component that works natively in
    // 100th mm rather than TWIP. It makes most sense just to
    // convert here and in getDocumentSize, and leave the tiled
    // rendering API working in TWIPs.
    long nTileWidthHMM = convertTwipToMm100( nTileWidth );
    long nTileHeightHMM = convertTwipToMm100( nTileHeight );
    int nTilePosXHMM = convertTwipToMm100( nTilePosX );
    int nTilePosYHMM = convertTwipToMm100( nTilePosY );
 
    MapMode aMapMode = rDevice.GetMapMode();
    aMapMode.SetMapUnit( MapUnit::Map100thMM );
    aMapMode.SetOrigin( Point( -nTilePosXHMM,
                               -nTilePosYHMM) );
    aMapMode.SetScaleX( scaleX );
    aMapMode.SetScaleY( scaleY );
 
    rDevice.SetMapMode( aMapMode );
 
    rDevice.SetOutputSizePixel( Size(nOutputWidth, nOutputHeight) );
 
    Point aPoint(nTilePosXHMM, nTilePosYHMM);
    Size aSize(nTileWidthHMM, nTileHeightHMM);
    ::tools::Rectangle aRect(aPoint, aSize);
 
    pViewSh->GetView()->CompleteRedraw(&rDevice, vcl::Region(aRect));
 
    LokChartHelper::PaintAllChartsOnTile(rDevice, nOutputWidth, nOutputHeight,
                                         nTilePosX, nTilePosY, nTileWidth, nTileHeight);
}
 
void SdXImpressDocument::setPart( int nPart )
{
    DrawViewShell* pViewSh = GetViewShell();
    if (!pViewSh)
        return;
 
    pViewSh->SwitchPage( nPart );
}
 
int SdXImpressDocument::getParts()
{
    // TODO: master pages?
    // Read: drviews1.cxx
    return mpDoc->GetSdPageCount(PageKind::Standard);
}
 
int SdXImpressDocument::getPart()
{
    DrawViewShell* pViewSh = GetViewShell();
    if (!pViewSh)
        return 0;
 
    return pViewSh->GetViewShellBase().getPart();
}
 
OUString SdXImpressDocument::getPartName( int nPart )
{
    SdPage* pPage = mpDoc->GetSdPage( nPart, PageKind::Standard );
    if (!pPage)
    {
        SAL_WARN("sd", "DrawViewShell not available!");
        return OUString();
    }
 
    return pPage->GetName();
}
 
OUString SdXImpressDocument::getPartHash( int nPart )
{
    SdPage* pPage = mpDoc->GetSdPage( nPart, PageKind::Standard );
    if (!pPage)
    {
        SAL_WARN("sd", "DrawViewShell not available!");
        return OUString();
    }
 
    return OUString::number(pPage->GetHashCode());
}
 
VclPtr<vcl::Window> SdXImpressDocument::getDocWindow()
{
    SolarMutexGuard aGuard;
    DrawViewShell* pViewShell = GetViewShell();
    VclPtr<vcl::Window> pWindow;
    if (pViewShell)
        pWindow = pViewShell->GetActiveWindow();
 
    LokChartHelper aChartHelper(pViewShell->GetViewShell());
    VclPtr<vcl::Window> pChartWindow = aChartHelper.GetWindow();
    if (pChartWindow)
        pWindow = pChartWindow;
 
    return pWindow;
}
 
void SdXImpressDocument::setPartMode( int nPartMode )
{
    DrawViewShell* pViewSh = GetViewShell();
    if (!pViewSh)
        return;
 
    PageKind aPageKind( PageKind::Standard );
    switch ( nPartMode )
    {
    case LOK_PARTMODE_SLIDES:
        break;
    case LOK_PARTMODE_NOTES:
        aPageKind = PageKind::Notes;
        break;
    }
    pViewSh->SetPageKind( aPageKind );
}
 
Size SdXImpressDocument::getDocumentSize()
{
    DrawViewShell* pViewSh = GetViewShell();
    if (!pViewSh)
        return Size();
 
    SdrView *pSdrView = pViewSh->GetView();
    if (!pSdrView)
        return Size();
 
    SdrPageView* pCurPageView = pSdrView->GetSdrPageView();
    if (!pCurPageView)
        return Size();
 
    Size aSize = pCurPageView->GetPageRect().GetSize();
    // Convert the size in 100th mm to TWIP
    // See paintTile above for further info.
    return Size(convertMm100ToTwip(aSize.getWidth()), convertMm100ToTwip(aSize.getHeight()));
}
 
OUString SdXImpressDocument::getPostIts()
{
    boost::property_tree::ptree aAnnotations;
    // Return annotations on master pages too ?
    const sal_uInt16 nMaxPages = mpDoc->GetPageCount();
    SdPage* pPage;
    for (sal_uInt16 nPage = 0; nPage < nMaxPages; ++nPage)
    {
        pPage = static_cast<SdPage*>(mpDoc->GetPage(nPage));
        const sd::AnnotationVector& aPageAnnotations = pPage->getAnnotations();
 
        for (const auto& aPageAnnotation : aPageAnnotations)
        {
            uno::Reference<office::XAnnotation> xAnnotation(aPageAnnotation);
 
            boost::property_tree::ptree aAnnotation;
            aAnnotation.put("id", sd::getAnnotationId(xAnnotation));
            aAnnotation.put("author", xAnnotation->getAuthor());
            aAnnotation.put("dateTime", utl::toISO8601(xAnnotation->getDateTime()));
            uno::Reference<text::XText> xText(xAnnotation->getTextRange());
            aAnnotation.put("text", xText->getString());
            aAnnotation.put("parthash", OUString::number(pPage->GetHashCode()));
 
            aAnnotations.push_back(std::make_pair("", aAnnotation));
        }
    }
 
    boost::property_tree::ptree aTree;
    aTree.add_child("comments", aAnnotations);
    std::stringstream aStream;
    boost::property_tree::write_json(aStream, aTree);
 
    return OUString::fromUtf8(aStream.str().c_str());
}
 
void SdXImpressDocument::initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments)
{
    SolarMutexGuard aGuard;
 
    if (DrawViewShell* pViewShell = GetViewShell())
    {
        DrawView* pDrawView = pViewShell->GetDrawView();
        for (sal_Int32 i = 0; i < rArguments.getLength(); ++i)
        {
            const beans::PropertyValue& rValue = rArguments[i];
            if (rValue.Name == ".uno:ShowBorderShadow" && rValue.Value.has<bool>())
                pDrawView->SetPageShadowVisible(rValue.Value.get<bool>());
            else if (rValue.Name == ".uno:Author" && rValue.Value.has<OUString>())
                pDrawView->SetAuthor(rValue.Value.get<OUString>());
        }
 
        // Disable comments if requested
        SdOptions* pOptions = SD_MOD()->GetSdOptions(mpDoc->GetDocumentType());
        pOptions->SetShowComments(comphelper::LibreOfficeKit::isTiledAnnotations());
 
        pViewShell->SetRuler(false);
        pViewShell->SetScrollBarsVisible(false);
 
        if (sd::Window* pWindow = pViewShell->GetActiveWindow())
        {
            // get the full page size in pixels
            pWindow->EnableMapMode();
            Size aSize(pWindow->LogicToPixel(pDrawView->GetSdrPageView()->GetPage()->GetSize()));
            // Disable map mode, so that it's possible to send mouse event
            // coordinates in logic units
            pWindow->EnableMapMode(false);
 
            // arrange UI elements again with new view size
            pViewShell->GetParentWindow()->SetSizePixel(aSize);
            pViewShell->Resize();
        }
 
        // Forces all images to be swapped in synchronously, this
        // ensures that images are available when paintTile is called
        // (whereas with async loading images start being loaded after
        //  we have painted the tile, resulting in an invalidate, followed
        //  by the tile being rerendered - which is wasteful and ugly).
        pDrawView->SetSwapAsynchron(false);
    }
 
    // when the "This document may contain formatting or content that cannot
    // be saved..." dialog appears, it is auto-cancelled with tiled rendering,
    // causing 'Save' being disabled; so let's always save to the original
    // format
    SvtSaveOptions().SetWarnAlienFormat(false);
}
 
void SdXImpressDocument::postKeyEvent(int nType, int nCharCode, int nKeyCode)
{
    SolarMutexGuard aGuard;
 
    VclPtr<vcl::Window> pWindow = getDocWindow();
    if (!pWindow)
        return;
 
    LOKAsyncEventData* pLOKEv = new LOKAsyncEventData;
    pLOKEv->mpWindow = pWindow;
    switch (nType)
    {
    case LOK_KEYEVENT_KEYINPUT:
        pLOKEv->mnEvent = VclEventId::WindowKeyInput;
        break;
    case LOK_KEYEVENT_KEYUP:
        pLOKEv->mnEvent = VclEventId::WindowKeyUp;
        break;
    default:
        assert(false);
    }
 
    pLOKEv->maKeyEvent = KeyEvent(nCharCode, nKeyCode, 0);
    Application::PostUserEvent(Link<void*, void>(pLOKEv, ITiledRenderable::LOKPostAsyncEvent));
}
 
void SdXImpressDocument::postMouseEvent(int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
{
    SolarMutexGuard aGuard;
 
    DrawViewShell* pViewShell = GetViewShell();
    if (!pViewShell)
        return;
 
    double fScale = 1.0/TWIPS_PER_PIXEL;
 
    // check if user hit a chart which is being edited by him
    LokChartHelper aChartHelper(pViewShell->GetViewShell());
    if (aChartHelper.postMouseEvent(nType, nX, nY,
                                    nCount, nButtons, nModifier,
                                    fScale, fScale))
        return;
 
    // check if the user hit a chart which is being edited by someone else
    // and, if so, skip current mouse event
    if (nType != LOK_MOUSEEVENT_MOUSEMOVE)
    {
        if (LokChartHelper::HitAny(Point(nX, nY)))
            return;
    }
 
    LOKAsyncEventData* pLOKEv = new LOKAsyncEventData;
    pLOKEv->mpWindow = pViewShell->GetActiveWindow();
    switch (nType)
    {
    case LOK_MOUSEEVENT_MOUSEBUTTONDOWN:
        pLOKEv->mnEvent = VclEventId::WindowMouseButtonDown;
        break;
    case LOK_MOUSEEVENT_MOUSEBUTTONUP:
        pLOKEv->mnEvent = VclEventId::WindowMouseButtonUp;
        break;
    case LOK_MOUSEEVENT_MOUSEMOVE:
        pLOKEv->mnEvent = VclEventId::WindowMouseMove;
        break;
    default:
        assert(false);
    }
 
    const Point aPos(Point(convertTwipToMm100(nX), convertTwipToMm100(nY)));
    pLOKEv->maMouseEvent = MouseEvent(aPos, nCount,
                                      MouseEventModifiers::SIMPLECLICK,
                                      nButtons, nModifier);
    Application::PostUserEvent(Link<void*, void>(pLOKEv, ITiledRenderable::LOKPostAsyncEvent));
}
 
void SdXImpressDocument::setTextSelection(int nType, int nX, int nY)
{
    SolarMutexGuard aGuard;
 
    DrawViewShell* pViewShell = GetViewShell();
    if (!pViewShell)
        return;
 
    LokChartHelper aChartHelper(pViewShell->GetViewShell());
    if (aChartHelper.setTextSelection(nType, nX, nY))
        return;
 
    Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
    switch (nType)
    {
    case LOK_SETTEXTSELECTION_START:
        pViewShell->SetCursorMm100Position(aPoint, /*bPoint=*/false, /*bClearMark=*/false);
        break;
    case LOK_SETTEXTSELECTION_END:
        pViewShell->SetCursorMm100Position(aPoint, /*bPoint=*/true, /*bClearMark=*/false);
        break;
    case LOK_SETTEXTSELECTION_RESET:
        pViewShell->SetCursorMm100Position(aPoint, /*bPoint=*/true, /*bClearMark=*/true);
        break;
    default:
        assert(false);
        break;
    }
}
 
OString SdXImpressDocument::getTextSelection(const char* pMimeType, OString& rUsedMimeType)
{
    SolarMutexGuard aGuard;
 
    DrawViewShell* pViewShell = GetViewShell();
    if (!pViewShell)
        return OString();
 
    return pViewShell->GetTextSelection(pMimeType, rUsedMimeType);
}
 
void SdXImpressDocument::setGraphicSelection(int nType, int nX, int nY)
{
    SolarMutexGuard aGuard;
 
    DrawViewShell* pViewShell = GetViewShell();
    if (!pViewShell)
        return;
 
    double fScale = 1.0/TWIPS_PER_PIXEL;
 
    LokChartHelper aChartHelper(pViewShell->GetViewShell());
    if (aChartHelper.setGraphicSelection(nType, nX, nY, fScale, fScale))
        return;
 
    Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
    switch (nType)
    {
    case LOK_SETGRAPHICSELECTION_START:
        pViewShell->SetGraphicMm100Position(/*bStart=*/true, aPoint);
        break;
    case LOK_SETGRAPHICSELECTION_END:
        pViewShell->SetGraphicMm100Position(/*bStart=*/false, aPoint);
        break;
    default:
        assert(false);
        break;
    }
}
 
void SdXImpressDocument::resetSelection()
{
    SolarMutexGuard aGuard;
 
    DrawViewShell* pViewShell = GetViewShell();
    if (!pViewShell)
        return;
 
    SdrView* pSdrView = pViewShell->GetView();
    if (!pSdrView)
        return;
 
    if (pSdrView->IsTextEdit())
    {
        // Reset the editeng selection.
        pSdrView->UnmarkAll();
        // Finish editing.
        pSdrView->SdrEndTextEdit();
    }
    // Reset graphic selection.
    pSdrView->UnmarkAll();
}
 
void SdXImpressDocument::setClipboard(const uno::Reference<datatransfer::clipboard::XClipboard>& xClipboard)
{
    SolarMutexGuard aGuard;
 
    DrawViewShell* pViewShell = GetViewShell();
    if (!pViewShell)
        return;
 
    pViewShell->GetActiveWindow()->SetClipboard(xClipboard);
}
 
bool SdXImpressDocument::isMimeTypeSupported()
{
    SolarMutexGuard aGuard;
    DrawViewShell* pViewShell = GetViewShell();
    if (!pViewShell)
        return false;
 
    TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromSystemClipboard(pViewShell->GetActiveWindow()));
    return EditEngine::HasValidData(aDataHelper.GetTransferable());
}
 
Pointer SdXImpressDocument::getPointer()
{
    SolarMutexGuard aGuard;
    DrawViewShell* pViewShell = GetViewShell();
    if (!pViewShell)
        return Pointer();
 
    Window* pWindow = pViewShell->GetActiveWindow();
    if (!pWindow)
        return Pointer();
 
    return pWindow->GetPointer();
}
 
uno::Reference< i18n::XForbiddenCharacters > SdXImpressDocument::getForbiddenCharsTable()
{
    uno::Reference< i18n::XForbiddenCharacters > xForb(mxForbiddenCharacters);
 
    if( !xForb.is() )
        mxForbiddenCharacters = xForb = new SdUnoForbiddenCharsTable( mpDoc );
 
    return xForb;
}
 
void SdXImpressDocument::initializeDocument()
{
    if( !mbClipBoard )
    {
        switch( mpDoc->GetPageCount() )
        {
        case 1:
        {
            // nasty hack to detect clipboard document
            mbClipBoard = true;
            break;
        }
        case 0:
        {
            mpDoc->CreateFirstPages();
            mpDoc->StopWorkStartupDelay();
            break;
        }
        }
    }
}
 
SdrModel& SdXImpressDocument::getSdrModelFromUnoModel() const
{
    OSL_ENSURE(GetDoc(), "No SdrModel in draw/Impress, should not happen");
    return *GetDoc(); // TTTT should be reference
}
 
void SAL_CALL SdXImpressDocument::dispose()
{
    if( !mbDisposed )
    {
        ::SolarMutexGuard aGuard;
 
        if( mpDoc )
        {
            EndListening( *mpDoc );
            mpDoc = nullptr;
        }
 
        // Call the base class dispose() before setting the mbDisposed flag
        // to true.  The reason for this is that if close() has not yet been
        // called this is done in SfxBaseModel::dispose().  At the end of
        // that dispose() is called again.  It is important to forward this
        // second dispose() to the base class, too.
        // As a consequence the following code has to be able to be run twice.
        SfxBaseModel::dispose();
        mbDisposed = true;
 
        uno::Reference< container::XNameAccess > xLinks( mxLinks );
        if( xLinks.is() )
        {
            uno::Reference< lang::XComponent > xComp( xLinks, uno::UNO_QUERY );
            if( xComp.is() )
                xComp->dispose();
 
            xLinks = nullptr;
        }
 
        uno::Reference< drawing::XDrawPages > xDrawPagesAccess( mxDrawPagesAccess );
        if( xDrawPagesAccess.is() )
        {
            uno::Reference< lang::XComponent > xComp( xDrawPagesAccess, uno::UNO_QUERY );
            if( xComp.is() )
                xComp->dispose();
 
            xDrawPagesAccess = nullptr;
        }
 
        uno::Reference< drawing::XDrawPages > xMasterPagesAccess( mxMasterPagesAccess );
        if( xDrawPagesAccess.is() )
        {
            uno::Reference< lang::XComponent > xComp( xMasterPagesAccess, uno::UNO_QUERY );
            if( xComp.is() )
                xComp->dispose();
 
            xDrawPagesAccess = nullptr;
        }
 
        uno::Reference< container::XNameAccess > xLayerManager( mxLayerManager );
        if( xLayerManager.is() )
        {
            uno::Reference< lang::XComponent > xComp( xLayerManager, uno::UNO_QUERY );
            if( xComp.is() )
                xComp->dispose();
 
            xLayerManager = nullptr;
        }
 
        uno::Reference< container::XNameContainer > xCustomPresentationAccess( mxCustomPresentationAccess );
        if( xCustomPresentationAccess.is() )
        {
            uno::Reference< lang::XComponent > xComp( xCustomPresentationAccess, uno::UNO_QUERY );
            if( xComp.is() )
                xComp->dispose();
 
            xCustomPresentationAccess = nullptr;
        }
 
        mxDashTable = nullptr;
        mxGradientTable = nullptr;
        mxHatchTable = nullptr;
        mxBitmapTable = nullptr;
        mxTransGradientTable = nullptr;
        mxMarkerTable = nullptr;
        mxDrawingPool = nullptr;
    }
}
 
// class SdDrawPagesAccess
 
SdDrawPagesAccess::SdDrawPagesAccess( SdXImpressDocument& rMyModel )  throw()
:   mpModel( &rMyModel)
{
}
 
SdDrawPagesAccess::~SdDrawPagesAccess() throw()
{
}
 
// XIndexAccess
sal_Int32 SAL_CALL SdDrawPagesAccess::getCount()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    return mpModel->mpDoc->GetSdPageCount( PageKind::Standard );
}
 
uno::Any SAL_CALL SdDrawPagesAccess::getByIndex( sal_Int32 Index )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    uno::Any aAny;
 
    if( (Index < 0) || (Index >= mpModel->mpDoc->GetSdPageCount( PageKind::Standard ) ) )
        throw lang::IndexOutOfBoundsException();
 
    SdPage* pPage = mpModel->mpDoc->GetSdPage( static_cast<sal_uInt16>(Index), PageKind::Standard );
    if( pPage )
    {
        uno::Reference< drawing::XDrawPage >  xDrawPage( pPage->getUnoPage(), uno::UNO_QUERY );
        aAny <<= xDrawPage;
    }
 
    return aAny;
}
 
// XNameAccess
uno::Any SAL_CALL SdDrawPagesAccess::getByName( const OUString& aName )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    if( !aName.isEmpty() )
    {
        const sal_uInt16 nCount = mpModel->mpDoc->GetSdPageCount( PageKind::Standard );
        sal_uInt16 nPage;
        for( nPage = 0; nPage < nCount; nPage++ )
        {
            SdPage* pPage = mpModel->mpDoc->GetSdPage( nPage, PageKind::Standard );
            if(nullptr == pPage)
                continue;
 
            if( aName == SdDrawPage::getPageApiName( pPage ) )
            {
                uno::Any aAny;
                uno::Reference< drawing::XDrawPage >  xDrawPage( pPage->getUnoPage(), uno::UNO_QUERY );
                aAny <<= xDrawPage;
                return aAny;
            }
        }
    }
 
    throw container::NoSuchElementException();
}
 
uno::Sequence< OUString > SAL_CALL SdDrawPagesAccess::getElementNames()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    const sal_uInt16 nCount = mpModel->mpDoc->GetSdPageCount( PageKind::Standard );
    uno::Sequence< OUString > aNames( nCount );
    OUString* pNames = aNames.getArray();
 
    sal_uInt16 nPage;
    for( nPage = 0; nPage < nCount; nPage++ )
    {
        SdPage* pPage = mpModel->mpDoc->GetSdPage( nPage, PageKind::Standard );
        *pNames++ = SdDrawPage::getPageApiName( pPage );
    }
 
    return aNames;
}
 
sal_Bool SAL_CALL SdDrawPagesAccess::hasByName( const OUString& aName )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    const sal_uInt16 nCount = mpModel->mpDoc->GetSdPageCount( PageKind::Standard );
    sal_uInt16 nPage;
    for( nPage = 0; nPage < nCount; nPage++ )
    {
        SdPage* pPage = mpModel->mpDoc->GetSdPage( nPage, PageKind::Standard );
        if(nullptr == pPage)
            continue;
 
        if( aName == SdDrawPage::getPageApiName( pPage ) )
            return true;
    }
 
    return false;
}
 
// XElementAccess
uno::Type SAL_CALL SdDrawPagesAccess::getElementType()
{
    return cppu::UnoType<drawing::XDrawPage>::get();
}
 
sal_Bool SAL_CALL SdDrawPagesAccess::hasElements()
{
    return getCount() > 0;
}
 
// XDrawPages
 
/**
 * Creates a new page with model at the specified position.
 * @returns corresponding SdDrawPage
 */
uno::Reference< drawing::XDrawPage > SAL_CALL SdDrawPagesAccess::insertNewByIndex( sal_Int32 nIndex )
{
    ::SolarMutexGuard aGuard;
    comphelper::ProfileZone aZone("insertNewByIndex");
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    if( mpModel->mpDoc )
    {
        SdPage* pPage = mpModel->InsertSdPage( static_cast<sal_uInt16>(nIndex), false );
        if( pPage )
        {
            uno::Reference< drawing::XDrawPage > xDrawPage( pPage->getUnoPage(), uno::UNO_QUERY );
            return xDrawPage;
        }
    }
    uno::Reference< drawing::XDrawPage > xDrawPage;
    return xDrawPage;
}
 
/**
 * Removes the specified SdDrawPage from the model and the internal list. It
 * only works, if there is at least one *normal* page in the model after
 * removing this page.
 */
void SAL_CALL SdDrawPagesAccess::remove( const uno::Reference< drawing::XDrawPage >& xPage )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel || mpModel->mpDoc == nullptr )
        throw lang::DisposedException();
 
    SdDrawDocument& rDoc = *mpModel->mpDoc;
 
    sal_uInt16 nPageCount = rDoc.GetSdPageCount( PageKind::Standard );
    if( nPageCount > 1 )
    {
        // get pPage from xPage and determine the Id (nPos ) afterwards
        SdDrawPage* pSvxPage = SdDrawPage::getImplementation( xPage );
        if( pSvxPage )
        {
            SdPage* pPage = static_cast<SdPage*>(pSvxPage->GetSdrPage());
            if(pPage && ( pPage->GetPageKind() == PageKind::Standard ) )
            {
                sal_uInt16 nPage = pPage->GetPageNum();
 
                SdPage* pNotesPage = static_cast< SdPage* >( rDoc.GetPage( nPage+1 ) );
 
                bool bUndo = rDoc.IsUndoEnabled();
                if( bUndo )
                {
                    // Add undo actions and delete the pages.  The order of adding
                    // the undo actions is important.
                    rDoc.BegUndo( SdResId( STR_UNDO_DELETEPAGES ) );
                    rDoc.AddUndo(rDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pNotesPage));
                    rDoc.AddUndo(rDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
                }
 
                rDoc.RemovePage( nPage ); // the page
                rDoc.RemovePage( nPage ); // the notes page
 
                if( bUndo )
                {
                    rDoc.EndUndo();
                }
                else
                {
                    delete pNotesPage;
                    delete pPage;
                }
            }
        }
    }
 
    mpModel->SetModified();
}
 
// XServiceInfo
 
OUString SAL_CALL SdDrawPagesAccess::getImplementationName(  )
{
    return OUString( "SdDrawPagesAccess" );
}
 
sal_Bool SAL_CALL SdDrawPagesAccess::supportsService( const OUString& ServiceName )
{
    return cppu::supportsService(this, ServiceName);
}
 
uno::Sequence< OUString > SAL_CALL SdDrawPagesAccess::getSupportedServiceNames(  )
{
    OUString aService( "com.sun.star.drawing.DrawPages" );
    uno::Sequence< OUString > aSeq( &aService, 1 );
    return aSeq;
}
 
// XComponent
void SAL_CALL SdDrawPagesAccess::dispose(  )
{
    mpModel = nullptr;
}
 
void SAL_CALL SdDrawPagesAccess::addEventListener( const uno::Reference< lang::XEventListener >&  )
{
    OSL_FAIL( "not implemented!" );
}
 
void SAL_CALL SdDrawPagesAccess::removeEventListener( const uno::Reference< lang::XEventListener >&  )
{
    OSL_FAIL( "not implemented!" );
}
 
// class SdMasterPagesAccess
 
SdMasterPagesAccess::SdMasterPagesAccess( SdXImpressDocument& rMyModel ) throw()
:   mpModel(&rMyModel)
{
}
 
SdMasterPagesAccess::~SdMasterPagesAccess() throw()
{
}
 
// XComponent
void SAL_CALL SdMasterPagesAccess::dispose(  )
{
    mpModel = nullptr;
}
 
void SAL_CALL SdMasterPagesAccess::addEventListener( const uno::Reference< lang::XEventListener >&  )
{
    OSL_FAIL( "not implemented!" );
}
 
void SAL_CALL SdMasterPagesAccess::removeEventListener( const uno::Reference< lang::XEventListener >&  )
{
    OSL_FAIL( "not implemented!" );
}
 
// XIndexAccess
sal_Int32 SAL_CALL SdMasterPagesAccess::getCount()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel->mpDoc )
        throw lang::DisposedException();
 
    return mpModel->mpDoc->GetMasterSdPageCount(PageKind::Standard);
}
 
/**
 * Provides a drawing::XDrawPage interface for accessing the Masterpage at the
 * specified position in the model.
 */
uno::Any SAL_CALL SdMasterPagesAccess::getByIndex( sal_Int32 Index )
{
    ::SolarMutexGuard aGuard;
    comphelper::ProfileZone aZone("SdMasterPagesAccess::getByIndex");
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    uno::Any aAny;
 
    if( (Index < 0) || (Index >= mpModel->mpDoc->GetMasterSdPageCount( PageKind::Standard ) ) )
        throw lang::IndexOutOfBoundsException();
 
    SdPage* pPage = mpModel->mpDoc->GetMasterSdPage( static_cast<sal_uInt16>(Index), PageKind::Standard );
    if( pPage )
    {
        uno::Reference< drawing::XDrawPage >  xDrawPage( pPage->getUnoPage(), uno::UNO_QUERY );
        aAny <<= xDrawPage;
    }
 
    return aAny;
}
 
// XElementAccess
uno::Type SAL_CALL SdMasterPagesAccess::getElementType()
{
    return cppu::UnoType<drawing::XDrawPage>::get();
}
 
sal_Bool SAL_CALL SdMasterPagesAccess::hasElements()
{
    return getCount() > 0;
}
 
// XDrawPages
uno::Reference< drawing::XDrawPage > SAL_CALL SdMasterPagesAccess::insertNewByIndex( sal_Int32 nInsertPos )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    uno::Reference< drawing::XDrawPage > xDrawPage;
 
    SdDrawDocument* pDoc = mpModel->mpDoc;
    if( pDoc )
    {
        // calculate internal index and check for range errors
        const sal_Int32 nMPageCount = pDoc->GetMasterPageCount();
        nInsertPos = nInsertPos * 2 + 1;
        if( nInsertPos < 0 || nInsertPos > nMPageCount )
            nInsertPos = nMPageCount;
 
        // now generate a unique name for the new masterpage
        const OUString aStdPrefix( SdResId(STR_LAYOUT_DEFAULT_NAME) );
        OUString aPrefix( aStdPrefix );
 
        bool bUnique = true;
 
        std::vector<OUString> aPageNames;
        for (sal_Int32 nMaster = 1; nMaster < nMPageCount; ++nMaster)
        {
            const SdPage* pPage = static_cast<const SdPage*>(pDoc->GetMasterPage(static_cast<sal_uInt16>(nMaster)));
            if (!pPage)
                continue;
            aPageNames.push_back(pPage->GetName());
            if (aPageNames.back() == aPrefix)
                bUnique = false;
        }
 
        sal_Int32 i = 0;
        while (!bUnique)
        {
            aPrefix = aStdPrefix + " " + OUString::number(++i);
            bUnique = std::find(aPageNames.begin(), aPageNames.end(), aPrefix) == aPageNames.end();
        }
 
        OUString aLayoutName( aPrefix );
        aLayoutName += SD_LT_SEPARATOR;
        aLayoutName += STR_LAYOUT_OUTLINE;
 
        // create styles
        static_cast<SdStyleSheetPool*>(pDoc->GetStyleSheetPool())->CreateLayoutStyleSheets( aPrefix );
 
        // get the first page for initial size and border settings
        SdPage* pPage = mpModel->mpDoc->GetSdPage( sal_uInt16(0), PageKind::Standard );
        SdPage* pRefNotesPage = mpModel->mpDoc->GetSdPage( sal_uInt16(0), PageKind::Notes);
 
        // create and insert new draw masterpage
        SdPage* pMPage = mpModel->mpDoc->AllocSdPage(true);
        pMPage->SetSize( pPage->GetSize() );
        pMPage->SetBorder( pPage->GetLeftBorder(),
                           pPage->GetUpperBorder(),
                           pPage->GetRightBorder(),
                           pPage->GetLowerBorder() );
        pMPage->SetLayoutName( aLayoutName );
        pDoc->InsertMasterPage(pMPage,  static_cast<sal_uInt16>(nInsertPos));
 
        {
            // ensure default MasterPage fill
            pMPage->EnsureMasterPageDefaultBackground();
        }
 
        xDrawPage.set( pMPage->getUnoPage(), uno::UNO_QUERY );
 
        // create and insert new notes masterpage
        SdPage* pMNotesPage = mpModel->mpDoc->AllocSdPage(true);
        pMNotesPage->SetSize( pRefNotesPage->GetSize() );
        pMNotesPage->SetPageKind(PageKind::Notes);
        pMNotesPage->SetBorder( pRefNotesPage->GetLeftBorder(),
                                pRefNotesPage->GetUpperBorder(),
                                pRefNotesPage->GetRightBorder(),
                                pRefNotesPage->GetLowerBorder() );
        pMNotesPage->SetLayoutName( aLayoutName );
        pDoc->InsertMasterPage(pMNotesPage,  static_cast<sal_uInt16>(nInsertPos) + 1);
        pMNotesPage->SetAutoLayout(AUTOLAYOUT_NOTES, true, true);
        mpModel->SetModified();
    }
 
    return xDrawPage;
}
 
/**
 * Removes the specified SdMasterPage from the model and the internal list. It
 * only works, if there is no *normal* page using this page as MasterPage in
 * the model.
 */
void SAL_CALL SdMasterPagesAccess::remove( const uno::Reference< drawing::XDrawPage >& xPage )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel || mpModel->mpDoc == nullptr )
        throw lang::DisposedException();
 
    SdDrawDocument& rDoc = *mpModel->mpDoc;
 
    SdMasterPage* pSdPage = SdMasterPage::getImplementation( xPage );
    if(pSdPage == nullptr)
        return;
 
    SdPage* pPage = dynamic_cast< SdPage* > (pSdPage->GetSdrPage());
 
    DBG_ASSERT( pPage && pPage->IsMasterPage(), "SdMasterPage is not masterpage?");
 
    if( !pPage || !pPage->IsMasterPage() || (mpModel->mpDoc->GetMasterPageUserCount(pPage) > 0))
        return; //Todo: this should be excepted
 
    // only standard pages can be removed directly
    if( pPage->GetPageKind() == PageKind::Standard )
    {
        sal_uInt16 nPage = pPage->GetPageNum();
 
        SdPage* pNotesPage = static_cast< SdPage* >( rDoc.GetMasterPage( nPage+1 ) );
 
        bool bUndo = rDoc.IsUndoEnabled();
        if( bUndo )
        {
            // Add undo actions and delete the pages.  The order of adding
            // the undo actions is important.
            rDoc.BegUndo( SdResId( STR_UNDO_DELETEPAGES ) );
            rDoc.AddUndo(rDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pNotesPage));
            rDoc.AddUndo(rDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage));
        }
 
        // remove both pages
        rDoc.RemoveMasterPage( nPage );
        rDoc.RemoveMasterPage( nPage );
 
        if( bUndo )
        {
            rDoc.EndUndo();
        }
        else
        {
            delete pNotesPage;
            delete pPage;
        }
    }
}
 
// XServiceInfo
 
OUString SAL_CALL SdMasterPagesAccess::getImplementationName(  )
{
    return OUString( "SdMasterPagesAccess" );
}
 
sal_Bool SAL_CALL SdMasterPagesAccess::supportsService( const OUString& ServiceName )
{
    return cppu::supportsService(this, ServiceName);
}
 
uno::Sequence< OUString > SAL_CALL SdMasterPagesAccess::getSupportedServiceNames(  )
{
    OUString aService( "com.sun.star.drawing.MasterPages" );
    uno::Sequence< OUString > aSeq( &aService, 1 );
    return aSeq;
}
 
// class SdDocLinkTargets
 
SdDocLinkTargets::SdDocLinkTargets( SdXImpressDocument& rMyModel ) throw()
: mpModel( &rMyModel )
{
}
 
SdDocLinkTargets::~SdDocLinkTargets() throw()
{
}
 
// XComponent
void SAL_CALL SdDocLinkTargets::dispose(  )
{
    mpModel = nullptr;
}
 
void SAL_CALL SdDocLinkTargets::addEventListener( const uno::Reference< lang::XEventListener >&  )
{
    OSL_FAIL( "not implemented!" );
}
 
void SAL_CALL SdDocLinkTargets::removeEventListener( const uno::Reference< lang::XEventListener >&  )
{
    OSL_FAIL( "not implemented!" );
}
 
// XNameAccess
uno::Any SAL_CALL SdDocLinkTargets::getByName( const OUString& aName )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    SdPage* pPage = FindPage( aName );
 
    if( pPage == nullptr )
        throw container::NoSuchElementException();
 
    uno::Any aAny;
 
    uno::Reference< beans::XPropertySet > xProps( pPage->getUnoPage(), uno::UNO_QUERY );
    if( xProps.is() )
        aAny <<= xProps;
 
    return aAny;
}
 
uno::Sequence< OUString > SAL_CALL SdDocLinkTargets::getElementNames()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    SdDrawDocument* pDoc = mpModel->GetDoc();
    if( pDoc == nullptr )
    {
        uno::Sequence< OUString > aSeq;
        return aSeq;
    }
 
    if( pDoc->GetDocumentType() == DocumentType::Draw )
    {
        const sal_uInt16 nMaxPages = pDoc->GetSdPageCount( PageKind::Standard );
        const sal_uInt16 nMaxMasterPages = pDoc->GetMasterSdPageCount( PageKind::Standard );
 
        uno::Sequence< OUString > aSeq( nMaxPages + nMaxMasterPages );
        OUString* pStr = aSeq.getArray();
 
        sal_uInt16 nPage;
        // standard pages
        for( nPage = 0; nPage < nMaxPages; nPage++ )
            *pStr++ = pDoc->GetSdPage( nPage, PageKind::Standard )->GetName();
 
        // master pages
        for( nPage = 0; nPage < nMaxMasterPages; nPage++ )
            *pStr++ = pDoc->GetMasterSdPage( nPage, PageKind::Standard )->GetName();
        return aSeq;
    }
    else
    {
        const sal_uInt16 nMaxPages = pDoc->GetPageCount();
        const sal_uInt16 nMaxMasterPages = pDoc->GetMasterPageCount();
 
        uno::Sequence< OUString > aSeq( nMaxPages + nMaxMasterPages );
        OUString* pStr = aSeq.getArray();
 
        sal_uInt16 nPage;
        // standard pages
        for( nPage = 0; nPage < nMaxPages; nPage++ )
            *pStr++ = static_cast<SdPage*>(pDoc->GetPage( nPage ))->GetName();
 
        // master pages
        for( nPage = 0; nPage < nMaxMasterPages; nPage++ )
            *pStr++ = static_cast<SdPage*>(pDoc->GetMasterPage( nPage ))->GetName();
        return aSeq;
    }
}
 
sal_Bool SAL_CALL SdDocLinkTargets::hasByName( const OUString& aName )
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    return FindPage( aName ) != nullptr;
}
 
// container::XElementAccess
uno::Type SAL_CALL SdDocLinkTargets::getElementType()
{
    return cppu::UnoType<beans::XPropertySet>::get();
}
 
sal_Bool SAL_CALL SdDocLinkTargets::hasElements()
{
    ::SolarMutexGuard aGuard;
 
    if( nullptr == mpModel )
        throw lang::DisposedException();
 
    return mpModel->GetDoc() != nullptr;
}
 
SdPage* SdDocLinkTargets::FindPage( const OUString& rName ) const
{
    SdDrawDocument* pDoc = mpModel->GetDoc();
    if( pDoc == nullptr )
        return nullptr;
 
    const sal_uInt16 nMaxPages = pDoc->GetPageCount();
    const sal_uInt16 nMaxMasterPages = pDoc->GetMasterPageCount();
 
    sal_uInt16 nPage;
    SdPage* pPage;
 
    const bool bDraw = pDoc->GetDocumentType() == DocumentType::Draw;
 
    // standard pages
    for( nPage = 0; nPage < nMaxPages; nPage++ )
    {
        pPage = static_cast<SdPage*>(pDoc->GetPage( nPage ));
        if( (pPage->GetName() == rName) && (!bDraw || (pPage->GetPageKind() == PageKind::Standard)) )
            return pPage;
    }
 
    // master pages
    for( nPage = 0; nPage < nMaxMasterPages; nPage++ )
    {
        pPage = static_cast<SdPage*>(pDoc->GetMasterPage( nPage ));
        if( (pPage->GetName() == rName) && (!bDraw || (pPage->GetPageKind() == PageKind::Standard)) )
            return pPage;
    }
 
    return nullptr;
}
 
// XServiceInfo
OUString SAL_CALL SdDocLinkTargets::getImplementationName()
{
    return OUString( "SdDocLinkTargets" );
}
 
sal_Bool SAL_CALL SdDocLinkTargets::supportsService( const OUString& ServiceName )
{
    return cppu::supportsService( this, ServiceName );
}
 
uno::Sequence< OUString > SAL_CALL SdDocLinkTargets::getSupportedServiceNames()
{
    const OUString aSN( "com.sun.star.document.LinkTargets" );
    uno::Sequence< OUString > aSeq( &aSN, 1 );
    return aSeq;
}
 
rtl::Reference< SdXImpressDocument > SdXImpressDocument::GetModel( SdDrawDocument const & rDocument )
{
    rtl::Reference< SdXImpressDocument > xRet;
    ::sd::DrawDocShell* pDocShell(rDocument.GetDocSh());
    if( pDocShell )
    {
        uno::Reference<frame::XModel> xModel(pDocShell->GetModel());
 
        xRet.set( dynamic_cast< SdXImpressDocument* >( xModel.get() ) );
    }
 
    return xRet;
}
 
void NotifyDocumentEvent( SdDrawDocument const & rDocument, const OUString& rEventName )
{
    rtl::Reference< SdXImpressDocument > xModel( SdXImpressDocument::GetModel( rDocument ) );
 
    if( xModel.is() )
    {
        uno::Reference< uno::XInterface > xSource( static_cast<uno::XWeak*>( xModel.get() ) );
        css::document::EventObject aEvent( xSource, rEventName );
        xModel->notifyEvent(aEvent );
    }
}
 
void NotifyDocumentEvent( SdDrawDocument const & rDocument, const OUString& rEventName, const uno::Reference< uno::XInterface >& xSource )
{
    rtl::Reference< SdXImpressDocument > xModel( SdXImpressDocument::GetModel( rDocument ) );
 
    if( xModel.is() )
    {
        css::document::EventObject aEvent( xSource, rEventName );
        xModel->notifyEvent(aEvent );
    }
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V560 A part of conditional expression is always true: mpDoc.

V572 It is odd that the object which was created using 'new' operator is immediately cast to another type.

V547 Expression 'mpDoc' is always true.

V547 Expression 'mpDoc' is always true.

V1019 Compound assignment expression 'Arguments[0] >>= arg' is used inside condition.

V560 A part of conditional expression is always true: mpDoc.

V560 A part of conditional expression is always true: mpDoc.

V560 A part of conditional expression is always true: mpDoc.

V1004 The 'pViewShell' pointer was used unsafely after it was verified against nullptr. Check lines: 2348, 2351.

V547 Expression 'mpDoc' is always true.