<commit_before>/*************************************************************************
 *
 *  $RCSfile: MasterPageContainer.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: pjunck $ $Date: 2004-10-28 13:31:57 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "MasterPageContainer.hxx"

#include "TemplateScanner.hxx"
#include "strings.hrc"
#include <algorithm>
#include <vector>
#include <queue>

#include <comphelper/processfactory.hxx>
#include "unomodel.hxx"
#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGESSUPPLIER_HPP_
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGES_HPP_
#include <com/sun/star/drawing/XDrawPages.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XCOMPONENTLOADER_HPP_
#include <com/sun/star/frame/XComponentLoader.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XINDEXACCESS_HPP_
#include <com/sun/star/container/XIndexAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif
#ifndef _COM_SUN_STAR_EMBED_XSTORAGE_HPP_
#include <com/sun/star/embed/XStorage.hpp>
#endif
#ifndef _COM_SUN_STAR_EMBED_ELEMENTMODES_HPP_
#include <com/sun/star/embed/ElementModes.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XSTREAM_HPP_
#include <com/sun/star/io/XStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XCLOSEABLE_HPP_
#include <com/sun/star/util/XCloseable.hpp>
#endif
#ifndef _COMPHELPER_PROCESSFACTORY_HXX_
#include <comphelper/processfactory.hxx>
#endif
#include <unotools/ucbstreamhelper.hxx>
#include <vcl/pngread.hxx>
#include <tools/urlobj.hxx>
#include <sfx2/app.hxx>
#include "DrawDocShell.hxx"
#include "drawdoc.hxx"
#include "sdpage.hxx"
#include <svtools/itemset.hxx>
#include <svtools/eitem.hxx>
#include "stlpool.hxx"
#include "unmovss.hxx"
#include "sdresid.hxx"

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;

namespace {

class PreviewCreationRequest
{
public:
    ::sd::toolpanel::controls::MasterPageContainer::Token maToken;
    int mnWidth;
    Link maCallback;
    void* mpUserData;
    PreviewCreationRequest (
        ::sd::toolpanel::controls::MasterPageContainer::Token aToken,
        int nWidth,
        const Link& rCallback,
        void* pUserData)
        : maToken(aToken),
          mnWidth(nWidth),
          maCallback(rCallback),
          mpUserData(pUserData)
    {}
};


/** A collection of data that is stored for every master page in the
    container.
*/
class MasterPageDescriptor
{
public:
    MasterPageDescriptor (
        const String& rURL,
        const String& rPageName,
        SdPage* pMasterPage,
        SdPage* pSlide,
        const Image& rPreview,
        ::sd::toolpanel::controls::MasterPageContainer::Token aToken
        )
        : msURL(rURL),
          msPageName(rPageName),
          mpMasterPage(pMasterPage),
          mpSlide(pSlide),
          maPreview(rPreview),
          maToken(aToken)
    {}
    MasterPageDescriptor (const MasterPageDescriptor& rDescriptor)
        : msURL(rDescriptor.msURL),
          msPageName(rDescriptor.msPageName),
          mpMasterPage(rDescriptor.mpMasterPage),
          mpSlide(rDescriptor.mpSlide),
          maPreview(rDescriptor.maPreview),
          maToken(rDescriptor.maToken)
    {}
    ~MasterPageDescriptor (void)
    {}

    String msURL;
    String msPageName;
    /// The actual master page.
    SdPage* mpMasterPage;
    /// A slide that uses the master page.
    SdPage* mpSlide;
    /// Preview of the master page.  May be empty.
    Image maPreview;
    ::sd::toolpanel::controls::MasterPageContainer::Token maToken;
};

typedef ::std::vector<MasterPageDescriptor> MasterPageContainerType;

class URLComparator { public:
    String msURL;
    URLComparator (const String& sURL) : msURL(sURL) {};
    bool operator() (const MasterPageContainerType::value_type& rDescriptor)
    { return rDescriptor.msURL.CompareTo(msURL)==0; }
};
class PageNameComparator { public:
    String msPageName;
    PageNameComparator (const String& sPageName) : msPageName(sPageName) {};
    bool operator() (const MasterPageContainerType::value_type& rDescriptor)
    { return rDescriptor.msPageName.CompareTo(msPageName)==0; }
};
class PageObjectComparator { public:
    const SdPage* mpMasterPage;
    PageObjectComparator (const SdPage* pPageObject)
        : mpMasterPage(pPageObject) {};
    bool operator() (const MasterPageContainerType::value_type& rDescriptor)
    { return rDescriptor.mpMasterPage==mpMasterPage; }
};
class AllComparator { public:
    String msURL;
    String msPageName;
    const SdPage* mpMasterPage;
    AllComparator (
        const String& sURL,
        const String& sPageName,
        const SdPage* pPageObject)
        : msURL(sURL),
          msPageName(sPageName),
          mpMasterPage(pPageObject)
    {}
    bool operator() (const MasterPageContainerType::value_type& rDescriptor)
    {
        return
            (msURL.Len()>0
                &&rDescriptor.msURL.CompareTo(msURL)==0)
            || (msPageName.Len()>0
                && rDescriptor.msPageName.CompareTo(msPageName)==0)
            || (mpMasterPage!=NULL
                && rDescriptor.mpMasterPage==mpMasterPage);
    }
};


} // end of anonymous namespace




namespace sd { namespace toolpanel { namespace controls {


/** Inner implementation class of the MasterPageContainer.  For
    documentation of undocumented methods and members please look in
    MasterPageContainer at method or member with the same name.
*/
class MasterPageContainer::Implementation
{
public:
    static MasterPageContainer* mpInstance;

    MasterPageContainerType maContainer;

    Implementation (void);
    ~Implementation (void);

    void AddPreviewCreationRequest (
        Token aToken,
         int nWidth,
        const Link& rCallback,
        void* pUserData);

    SdPage* GetPageObjectForToken (
        MasterPageContainer::Token aToken,
        bool bLoad);
    SdPage* GetSlideForToken (
        MasterPageContainer::Token aToken,
        bool bLoad);
    SdPage* CopyMasterPageToLocalDocument (SdPage* pMasterPage);
    Token PutMasterPage (
        const String& sURL,
        const String& sPageName,
        SdPage* pMasterPage,
        Image aPreview);
    Image GetPreviewForToken (
        Token aToken,
        int nWidth);
    Image GetPreviewForToken (
        Token aToken,
        int nWidth,
        const Link& rCallback,
        void* pUserData);
    void RemoveCallback (const Link& rCallback);

private:
    Timer maDelayedPreviewCreationTimer;
    /** Use a vector for the queue so that we can iterate over all
        elements and remove those that became invalid.
    */
    typedef ::std::queue<PreviewCreationRequest> RequestQueue;
    RequestQueue maRequestQueue;
    ::com::sun::star::uno::Reference<
        ::com::sun::star::frame::XModel> mxModel;
    SdDrawDocument* mpDocument;
    PreviewRenderer maPreviewRenderer;

    /// The time to wait (in milliseconds) between the creation of previews.
    static const int DELAYED_CREATION_TIMEOUT=250;
    DECL_LINK(DelayedPreviewCreation, Timer *);
    ::sd::DrawDocShell* LoadDocument (
        const String& sFileName,
        SfxObjectShellLock& rxDocumentShell);
    SdPage* AddMasterPage (
        SdDrawDocument* pTargetDocument,
        SdPage* pMasterPage);
    void ProvideStyles (
        SdDrawDocument* pSourceDocument,
        SdDrawDocument* pTargetDocument,
        SdPage* pPage);
    SdPage* GetSlideForMasterPage (SdPage* pMasterPage);

    /** Retrieve the preview of the document specified by the given URL.
    */
    BitmapEx LoadPreviewFromURL (const ::rtl::OUString& aURL);

    /** Fetch previews of the master pages of all relevant templates,
        styles, and layouts and put them in the container.
    */
    void FillContainer (void);

    /** This function is used by FillContainer() to add the master page of
        one of the templates.  It tries to load the thumbnail bitmap from
        the file.  If that is not present the preview remains empty save a
        short text indicating what happened.
    */
    void AddTemplate (
        const String& rsPath,
        const String& rsTitle);

    /** Also used by FillContainer() to filter out those templates among
        those provided by the ucb that can be handled by us, i.e. Impress
        templates, layouts, styles.
        @param rsFileName
            The full file name, possibly a URL, that is used to recognize
            whether a template can be handled by this class.
    */
    bool FileFilter (const String& rsFileName);
};




//===== MasterPageContainer ===================================================

MasterPageContainer* MasterPageContainer::Implementation::mpInstance = NULL;
static const MasterPageContainer::Token NIL_TOKEN (-1);

MasterPageContainer& MasterPageContainer::Instance (void)
{
    if (Implementation::mpInstance == NULL)
    {
        ::osl::GetGlobalMutex aMutexFunctor;
        ::osl::MutexGuard aGuard (aMutexFunctor());
        if (Implementation::mpInstance == NULL)
        {
            MasterPageContainer* pInstance = new MasterPageContainer ();
            pInstance->LateInit();
            SdGlobalResourceContainer::Instance().AddResource (
                ::std::auto_ptr<SdGlobalResource>(pInstance));
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
            Implementation::mpInstance = pInstance;
        }
    }
    else
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();

    DBG_ASSERT (Implementation::mpInstance!=NULL,
        "MasterPageContainer::Instance(): instance is NULL");
    return *Implementation::mpInstance;
}




MasterPageContainer::MasterPageContainer (void)
    : mpImpl(new Implementation())
{
}




void MasterPageContainer::LateInit (void)
{
}




MasterPageContainer::~MasterPageContainer (void)
{
}




MasterPageContainer::Token MasterPageContainer::PutMasterPage (
    const String& sURL,
    const String& sPageName,
    SdPage* pMasterPage,
    Image aPreview)
{
    return mpImpl->PutMasterPage (
        sURL,
        sPageName,
        pMasterPage,
        aPreview);
}




int MasterPageContainer::GetTokenCount (void)
{
    return mpImpl->maContainer.size();
}




MasterPageContainer::Token MasterPageContainer::GetTokenForIndex (int nIndex)
{
    Token aResult (NIL_TOKEN);
    if (nIndex>=0 && nIndex<GetTokenCount())
        aResult = mpImpl->maContainer[nIndex].maToken;
    return aResult;
}




MasterPageContainer::Token MasterPageContainer::GetTokenForURL (
    const String& sURL)
{
    Token aResult (NIL_TOKEN);
    if (sURL.Len() > 0)
    {
        MasterPageContainerType::iterator aEntry (
            ::std::find_if (
                mpImpl->maContainer.begin(),
                mpImpl->maContainer.end(),
                URLComparator(sURL)));
        if (aEntry != mpImpl->maContainer.end())
            aResult = aEntry->maToken;
    }
    return aResult;
}




MasterPageContainer::Token MasterPageContainer::GetTokenForPageName (
    const String& sPageName)
{
    Token aResult (NIL_TOKEN);
    if (sPageName.Len() > 0)
    {
        MasterPageContainerType::iterator aEntry (
            ::std::find_if (
                mpImpl->maContainer.begin(),
                mpImpl->maContainer.end(),
                PageNameComparator(sPageName)));
        if (aEntry != mpImpl->maContainer.end())
            return aEntry->maToken;
    }
    return aResult;
}




MasterPageContainer::Token MasterPageContainer::GetTokenForPageObject (
    const SdPage* pPage)
{
    Token aResult (NIL_TOKEN);
    if (pPage != NULL)
    {
        MasterPageContainerType::iterator aEntry (
            ::std::find_if (
                mpImpl->maContainer.begin(),
                mpImpl->maContainer.end(),
                PageObjectComparator(pPage)));
        if (aEntry != mpImpl->maContainer.end())
            return aEntry->maToken;
    }
    return aResult;
}




String MasterPageContainer::GetURLForToken (
    MasterPageContainer::Token aToken)
{
    if (aToken>=0 && (unsigned)aToken<mpImpl->maContainer.size())
        return mpImpl->maContainer[aToken].msURL;
    else
        return String();
}




String MasterPageContainer::GetPageNameForToken (
    MasterPageContainer::Token aToken)
{
    if (aToken>=0 && (unsigned)aToken<mpImpl->maContainer.size())
        return mpImpl->maContainer[aToken].msPageName;
    else
        return String();
}




SdPage* MasterPageContainer::GetPageObjectForToken (
    MasterPageContainer::Token aToken,
    bool bLoad)
{
    return mpImpl->GetPageObjectForToken (aToken, bLoad);
}




SdPage* MasterPageContainer::GetSlideForToken (
    MasterPageContainer::Token aToken,
    bool bLoad)
{
    return mpImpl->GetSlideForToken (aToken, bLoad);
}




Image MasterPageContainer::GetPreviewForToken (
    MasterPageContainer::Token aToken,
    int nWidth)
{
    return mpImpl->GetPreviewForToken (aToken, nWidth);
}




Image MasterPageContainer::GetPreviewForToken (
    MasterPageContainer::Token aToken,
    int nWidth,
    const Link& rCallback,
    void* pUserData)
{
    return mpImpl->GetPreviewForToken (
            aToken,
            nWidth,
            rCallback,
            pUserData);
}




void MasterPageContainer::RemoveCallback (const Link& rCallback)
{
    mpImpl->RemoveCallback (rCallback);
}




//==== Implementation ================================================

MasterPageContainer::Implementation::Implementation (void)
    : maContainer(),
      maDelayedPreviewCreationTimer(),
      maRequestQueue(),
      mxModel(NULL),
      mpDocument(NULL),
      maPreviewRenderer()
{
    try
    {
        // Use the API to create a new document.

        // Get the desktop a s service factory.
        ::rtl::OUString sDesktopServiceName (
            RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop"));
        uno::Reference<frame::XComponentLoader> xDesktop (
            ::comphelper::getProcessServiceFactory()->createInstance(
                sDesktopServiceName),
            uno::UNO_QUERY);

        // Create a new model.
        ::rtl::OUString sModelServiceName (
            RTL_CONSTASCII_USTRINGPARAM(
                "com.sun.star.presentation.PresentationDocument"));
        mxModel = uno::Reference<frame::XModel>(
            ::comphelper::getProcessServiceFactory()->createInstance(
                sModelServiceName),
            uno::UNO_QUERY);

        // Initialize it.
        uno::Reference<frame::XLoadable> xLoadable (mxModel,uno::UNO_QUERY);
        if (xLoadable.is())
            xLoadable->initNew();

        // Use its tunnel to get a pointer to its core implementation.
        uno::Reference<lang::XUnoTunnel> xUnoTunnel (mxModel, uno::UNO_QUERY);
        if (xUnoTunnel.is())
        {
            mpDocument = reinterpret_cast<SdXImpressDocument*>(
                xUnoTunnel->getSomething(
                    SdXImpressDocument::getUnoTunnelId()))->GetDoc();
        }

        // Create one slide that is used to render previews of empty pages
        // (master pages that have not been loaded).
        uno::Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
            mxModel, uno::UNO_QUERY);
        if (xSlideSupplier.is())
        {
            uno::Reference<drawing::XDrawPages> xSlides (
                xSlideSupplier->getDrawPages(), uno::UNO_QUERY);
            if (xSlides.is())
                xSlides->insertNewByIndex (0);
        }
    }
    catch (...)
    {
        mxModel = NULL;
        mpDocument = NULL;
    }

    // Set up the timer for the delayed creation of preview bitmaps.
    maDelayedPreviewCreationTimer.SetTimeout (DELAYED_CREATION_TIMEOUT);
    maDelayedPreviewCreationTimer.SetTimeoutHdl (
        LINK(this,Implementation,DelayedPreviewCreation));

    FillContainer();
}




MasterPageContainer::Implementation::~Implementation (void)
{
    maDelayedPreviewCreationTimer.Stop();
    while ( ! maRequestQueue.empty())
        maRequestQueue.pop();

   uno::Reference<util::XCloseable> xCloseable (mxModel, uno::UNO_QUERY);
    if (xCloseable.is())
    {
        try
        {
            xCloseable->close(true);
        }
        catch (::com::sun::star::util::CloseVetoException aException)
        {
        }
    }
    mxModel = NULL;
}




void MasterPageContainer::Implementation::AddPreviewCreationRequest (
    ::sd::toolpanel::controls::MasterPageContainer::Token aToken,
    int nWidth,
    const Link& rCallback,
    void* pUserData)
{
    maRequestQueue.push (PreviewCreationRequest(
        aToken, nWidth, rCallback, pUserData));
    maDelayedPreviewCreationTimer.Start();
}




IMPL_LINK(MasterPageContainer::Implementation,
    DelayedPreviewCreation,
    Timer*, pTimer)
{
    while (maRequestQueue.size()>0 && ! GetpApp()->AnyInput())
    {
        PreviewCreationRequest aRequest (maRequestQueue.front());
        maRequestQueue.pop();

        if (aRequest.maToken>=0
            && (unsigned)aRequest.maToken<maContainer.size())
        {
            String sURL (maContainer[aRequest.maToken].msURL);
            BitmapEx aBitmap (LoadPreviewFromURL (sURL));
            maContainer[aRequest.maToken].maPreview
                = maPreviewRenderer.ScaleBitmap (aBitmap, aRequest.mnWidth);<commit_msg>INTEGRATION: CWS impress23 (1.7.58); FILE MERGED 2004/12/09 10:36:53 af 1.7.58.1: #i37871# Store loaded previews in full resolution.<commit_after>/*************************************************************************
 *
 *  $RCSfile: MasterPageContainer.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: kz $ $Date: 2005-01-21 16:36:17 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "MasterPageContainer.hxx"

#include "TemplateScanner.hxx"
#include "strings.hrc"
#include <algorithm>
#include <vector>
#include <queue>

#include <comphelper/processfactory.hxx>
#include "unomodel.hxx"
#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGESSUPPLIER_HPP_
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGES_HPP_
#include <com/sun/star/drawing/XDrawPages.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XCOMPONENTLOADER_HPP_
#include <com/sun/star/frame/XComponentLoader.hpp>
#endif
#ifndef _COM_SUN_STAR_CONTAINER_XINDEXACCESS_HPP_
#include <com/sun/star/container/XIndexAccess.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif
#ifndef _COM_SUN_STAR_EMBED_XSTORAGE_HPP_
#include <com/sun/star/embed/XStorage.hpp>
#endif
#ifndef _COM_SUN_STAR_EMBED_ELEMENTMODES_HPP_
#include <com/sun/star/embed/ElementModes.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XSTREAM_HPP_
#include <com/sun/star/io/XStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XCLOSEABLE_HPP_
#include <com/sun/star/util/XCloseable.hpp>
#endif
#ifndef _COMPHELPER_PROCESSFACTORY_HXX_
#include <comphelper/processfactory.hxx>
#endif
#include <unotools/ucbstreamhelper.hxx>
#include <vcl/pngread.hxx>
#include <tools/urlobj.hxx>
#include <sfx2/app.hxx>
#include "DrawDocShell.hxx"
#include "drawdoc.hxx"
#include "sdpage.hxx"
#include <svtools/itemset.hxx>
#include <svtools/eitem.hxx>
#include "stlpool.hxx"
#include "unmovss.hxx"
#include "sdresid.hxx"

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;

namespace {

class PreviewCreationRequest
{
public:
    ::sd::toolpanel::controls::MasterPageContainer::Token maToken;
    int mnWidth;
    Link maCallback;
    void* mpUserData;
    PreviewCreationRequest (
        ::sd::toolpanel::controls::MasterPageContainer::Token aToken,
        int nWidth,
        const Link& rCallback,
        void* pUserData)
        : maToken(aToken),
          mnWidth(nWidth),
          maCallback(rCallback),
          mpUserData(pUserData)
    {}
};


/** A collection of data that is stored for every master page in the
    container.
*/
class MasterPageDescriptor
{
public:
    MasterPageDescriptor (
        const String& rURL,
        const String& rPageName,
        SdPage* pMasterPage,
        SdPage* pSlide,
        const Image& rPreview,
        ::sd::toolpanel::controls::MasterPageContainer::Token aToken
        )
        : msURL(rURL),
          msPageName(rPageName),
          mpMasterPage(pMasterPage),
          mpSlide(pSlide),
          maPreview(rPreview),
          maToken(aToken)
    {}
    MasterPageDescriptor (const MasterPageDescriptor& rDescriptor)
        : msURL(rDescriptor.msURL),
          msPageName(rDescriptor.msPageName),
          mpMasterPage(rDescriptor.mpMasterPage),
          mpSlide(rDescriptor.mpSlide),
          maPreview(rDescriptor.maPreview),
          maToken(rDescriptor.maToken)
    {}
    ~MasterPageDescriptor (void)
    {}

    String msURL;
    String msPageName;
    /// The actual master page.
    SdPage* mpMasterPage;
    /// A slide that uses the master page.
    SdPage* mpSlide;
    /// Preview of the master page.  May be empty.
    Image maPreview;
    ::sd::toolpanel::controls::MasterPageContainer::Token maToken;
};

typedef ::std::vector<MasterPageDescriptor> MasterPageContainerType;

class URLComparator { public:
    String msURL;
    URLComparator (const String& sURL) : msURL(sURL) {};
    bool operator() (const MasterPageContainerType::value_type& rDescriptor)
    { return rDescriptor.msURL.CompareTo(msURL)==0; }
};
class PageNameComparator { public:
    String msPageName;
    PageNameComparator (const String& sPageName) : msPageName(sPageName) {};
    bool operator() (const MasterPageContainerType::value_type& rDescriptor)
    { return rDescriptor.msPageName.CompareTo(msPageName)==0; }
};
class PageObjectComparator { public:
    const SdPage* mpMasterPage;
    PageObjectComparator (const SdPage* pPageObject)
        : mpMasterPage(pPageObject) {};
    bool operator() (const MasterPageContainerType::value_type& rDescriptor)
    { return rDescriptor.mpMasterPage==mpMasterPage; }
};
class AllComparator { public:
    String msURL;
    String msPageName;
    const SdPage* mpMasterPage;
    AllComparator (
        const String& sURL,
        const String& sPageName,
        const SdPage* pPageObject)
        : msURL(sURL),
          msPageName(sPageName),
          mpMasterPage(pPageObject)
    {}
    bool operator() (const MasterPageContainerType::value_type& rDescriptor)
    {
        return
            (msURL.Len()>0
                &&rDescriptor.msURL.CompareTo(msURL)==0)
            || (msPageName.Len()>0
                && rDescriptor.msPageName.CompareTo(msPageName)==0)
            || (mpMasterPage!=NULL
                && rDescriptor.mpMasterPage==mpMasterPage);
    }
};


} // end of anonymous namespace




namespace sd { namespace toolpanel { namespace controls {


/** Inner implementation class of the MasterPageContainer.  For
    documentation of undocumented methods and members please look in
    MasterPageContainer at method or member with the same name.
*/
class MasterPageContainer::Implementation
{
public:
    static MasterPageContainer* mpInstance;

    MasterPageContainerType maContainer;

    Implementation (void);
    ~Implementation (void);

    void AddPreviewCreationRequest (
        Token aToken,
         int nWidth,
        const Link& rCallback,
        void* pUserData);

    SdPage* GetPageObjectForToken (
        MasterPageContainer::Token aToken,
        bool bLoad);
    SdPage* GetSlideForToken (
        MasterPageContainer::Token aToken,
        bool bLoad);
    SdPage* CopyMasterPageToLocalDocument (SdPage* pMasterPage);
    Token PutMasterPage (
        const String& sURL,
        const String& sPageName,
        SdPage* pMasterPage,
        Image aPreview);
    Image GetPreviewForToken (
        Token aToken,
        int nWidth);
    Image GetPreviewForToken (
        Token aToken,
        int nWidth,
        const Link& rCallback,
        void* pUserData);
    void RemoveCallback (const Link& rCallback);

private:
    Timer maDelayedPreviewCreationTimer;
    /** Use a vector for the queue so that we can iterate over all
        elements and remove those that became invalid.
    */
    typedef ::std::queue<PreviewCreationRequest> RequestQueue;
    RequestQueue maRequestQueue;
    ::com::sun::star::uno::Reference<
        ::com::sun::star::frame::XModel> mxModel;
    SdDrawDocument* mpDocument;
    PreviewRenderer maPreviewRenderer;

    /// The time to wait (in milliseconds) between the creation of previews.
    static const int DELAYED_CREATION_TIMEOUT=250;
    DECL_LINK(DelayedPreviewCreation, Timer *);
    ::sd::DrawDocShell* LoadDocument (
        const String& sFileName,
        SfxObjectShellLock& rxDocumentShell);
    SdPage* AddMasterPage (
        SdDrawDocument* pTargetDocument,
        SdPage* pMasterPage);
    void ProvideStyles (
        SdDrawDocument* pSourceDocument,
        SdDrawDocument* pTargetDocument,
        SdPage* pPage);
    SdPage* GetSlideForMasterPage (SdPage* pMasterPage);

    /** Retrieve the preview of the document specified by the given URL.
    */
    BitmapEx LoadPreviewFromURL (const ::rtl::OUString& aURL);

    /** Fetch previews of the master pages of all relevant templates,
        styles, and layouts and put them in the container.
    */
    void FillContainer (void);

    /** This function is used by FillContainer() to add the master page of
        one of the templates.  It tries to load the thumbnail bitmap from
        the file.  If that is not present the preview remains empty save a
        short text indicating what happened.
    */
    void AddTemplate (
        const String& rsPath,
        const String& rsTitle);

    /** Also used by FillContainer() to filter out those templates among
        those provided by the ucb that can be handled by us, i.e. Impress
        templates, layouts, styles.
        @param rsFileName
            The full file name, possibly a URL, that is used to recognize
            whether a template can be handled by this class.
    */
    bool FileFilter (const String& rsFileName);
};




//===== MasterPageContainer ===================================================

MasterPageContainer* MasterPageContainer::Implementation::mpInstance = NULL;
static const MasterPageContainer::Token NIL_TOKEN (-1);

MasterPageContainer& MasterPageContainer::Instance (void)
{
    if (Implementation::mpInstance == NULL)
    {
        ::osl::GetGlobalMutex aMutexFunctor;
        ::osl::MutexGuard aGuard (aMutexFunctor());
        if (Implementation::mpInstance == NULL)
        {
            MasterPageContainer* pInstance = new MasterPageContainer ();
            pInstance->LateInit();
            SdGlobalResourceContainer::Instance().AddResource (
                ::std::auto_ptr<SdGlobalResource>(pInstance));
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
            Implementation::mpInstance = pInstance;
        }
    }
    else
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();

    DBG_ASSERT (Implementation::mpInstance!=NULL,
        "MasterPageContainer::Instance(): instance is NULL");
    return *Implementation::mpInstance;
}




MasterPageContainer::MasterPageContainer (void)
    : mpImpl(new Implementation())
{
}




void MasterPageContainer::LateInit (void)
{
}




MasterPageContainer::~MasterPageContainer (void)
{
}




MasterPageContainer::Token MasterPageContainer::PutMasterPage (
    const String& sURL,
    const String& sPageName,
    SdPage* pMasterPage,
    Image aPreview)
{
    return mpImpl->PutMasterPage (
        sURL,
        sPageName,
        pMasterPage,
        aPreview);
}




int MasterPageContainer::GetTokenCount (void)
{
    return mpImpl->maContainer.size();
}




MasterPageContainer::Token MasterPageContainer::GetTokenForIndex (int nIndex)
{
    Token aResult (NIL_TOKEN);
    if (nIndex>=0 && nIndex<GetTokenCount())
        aResult = mpImpl->maContainer[nIndex].maToken;
    return aResult;
}




MasterPageContainer::Token MasterPageContainer::GetTokenForURL (
    const String& sURL)
{
    Token aResult (NIL_TOKEN);
    if (sURL.Len() > 0)
    {
        MasterPageContainerType::iterator aEntry (
            ::std::find_if (
                mpImpl->maContainer.begin(),
                mpImpl->maContainer.end(),
                URLComparator(sURL)));
        if (aEntry != mpImpl->maContainer.end())
            aResult = aEntry->maToken;
    }
    return aResult;
}




MasterPageContainer::Token MasterPageContainer::GetTokenForPageName (
    const String& sPageName)
{
    Token aResult (NIL_TOKEN);
    if (sPageName.Len() > 0)
    {
        MasterPageContainerType::iterator aEntry (
            ::std::find_if (
                mpImpl->maContainer.begin(),
                mpImpl->maContainer.end(),
                PageNameComparator(sPageName)));
        if (aEntry != mpImpl->maContainer.end())
            return aEntry->maToken;
    }
    return aResult;
}




MasterPageContainer::Token MasterPageContainer::GetTokenForPageObject (
    const SdPage* pPage)
{
    Token aResult (NIL_TOKEN);
    if (pPage != NULL)
    {
        MasterPageContainerType::iterator aEntry (
            ::std::find_if (
                mpImpl->maContainer.begin(),
                mpImpl->maContainer.end(),
                PageObjectComparator(pPage)));
        if (aEntry != mpImpl->maContainer.end())
            return aEntry->maToken;
    }
    return aResult;
}




String MasterPageContainer::GetURLForToken (
    MasterPageContainer::Token aToken)
{
    if (aToken>=0 && (unsigned)aToken<mpImpl->maContainer.size())
        return mpImpl->maContainer[aToken].msURL;
    else
        return String();
}




String MasterPageContainer::GetPageNameForToken (
    MasterPageContainer::Token aToken)
{
    if (aToken>=0 && (unsigned)aToken<mpImpl->maContainer.size())
        return mpImpl->maContainer[aToken].msPageName;
    else
        return String();
}




SdPage* MasterPageContainer::GetPageObjectForToken (
    MasterPageContainer::Token aToken,
    bool bLoad)
{
    return mpImpl->GetPageObjectForToken (aToken, bLoad);
}




SdPage* MasterPageContainer::GetSlideForToken (
    MasterPageContainer::Token aToken,
    bool bLoad)
{
    return mpImpl->GetSlideForToken (aToken, bLoad);
}




Image MasterPageContainer::GetPreviewForToken (
    MasterPageContainer::Token aToken,
    int nWidth)
{
    return mpImpl->GetPreviewForToken (aToken, nWidth);
}




Image MasterPageContainer::GetPreviewForToken (
    MasterPageContainer::Token aToken,
    int nWidth,
    const Link& rCallback,
    void* pUserData)
{
    return mpImpl->GetPreviewForToken (
            aToken,
            nWidth,
            rCallback,
            pUserData);
}




void MasterPageContainer::RemoveCallback (const Link& rCallback)
{
    mpImpl->RemoveCallback (rCallback);
}




//==== Implementation ================================================

MasterPageContainer::Implementation::Implementation (void)
    : maContainer(),
      maDelayedPreviewCreationTimer(),
      maRequestQueue(),
      mxModel(NULL),
      mpDocument(NULL),
      maPreviewRenderer()
{
    try
    {
        // Use the API to create a new document.

        // Get the desktop a s service factory.
        ::rtl::OUString sDesktopServiceName (
            RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop"));
        uno::Reference<frame::XComponentLoader> xDesktop (
            ::comphelper::getProcessServiceFactory()->createInstance(
                sDesktopServiceName),
            uno::UNO_QUERY);

        // Create a new model.
        ::rtl::OUString sModelServiceName (
            RTL_CONSTASCII_USTRINGPARAM(
                "com.sun.star.presentation.PresentationDocument"));
        mxModel = uno::Reference<frame::XModel>(
            ::comphelper::getProcessServiceFactory()->createInstance(
                sModelServiceName),
            uno::UNO_QUERY);

        // Initialize it.
        uno::Reference<frame::XLoadable> xLoadable (mxModel,uno::UNO_QUERY);
        if (xLoadable.is())
            xLoadable->initNew();

        // Use its tunnel to get a pointer to its core implementation.
        uno::Reference<lang::XUnoTunnel> xUnoTunnel (mxModel, uno::UNO_QUERY);
        if (xUnoTunnel.is())
        {
            mpDocument = reinterpret_cast<SdXImpressDocument*>(
                xUnoTunnel->getSomething(
                    SdXImpressDocument::getUnoTunnelId()))->GetDoc();
        }

        // Create one slide that is used to render previews of empty pages
        // (master pages that have not been loaded).
        uno::Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
            mxModel, uno::UNO_QUERY);
        if (xSlideSupplier.is())
        {
            uno::Reference<drawing::XDrawPages> xSlides (
                xSlideSupplier->getDrawPages(), uno::UNO_QUERY);
            if (xSlides.is())
                xSlides->insertNewByIndex (0);
        }
    }
    catch (...)
    {
        mxModel = NULL;
        mpDocument = NULL;
    }

    // Set up the timer for the delayed creation of preview bitmaps.
    maDelayedPreviewCreationTimer.SetTimeout (DELAYED_CREATION_TIMEOUT);
    maDelayedPreviewCreationTimer.SetTimeoutHdl (
        LINK(this,Implementation,DelayedPreviewCreation));

    FillContainer();
}




MasterPageContainer::Implementation::~Implementation (void)
{
    maDelayedPreviewCreationTimer.Stop();
    while ( ! maRequestQueue.empty())
        maRequestQueue.pop();

   uno::Reference<util::XCloseable> xCloseable (mxModel, uno::UNO_QUERY);
    if (xCloseable.is())
    {
        try
        {
            xCloseable->close(true);
        }
        catch (::com::sun::star::util::CloseVetoException aException)
        {
        }
    }
    mxModel = NULL;
}




void MasterPageContainer::Implementation::AddPreviewCreationRequest (
    ::sd::toolpanel::controls::MasterPageContainer::Token aToken,
    int nWidth,
    const Link& rCallback,
    void* pUserData)
{
    maRequestQueue.push (PreviewCreationRequest(
        aToken, nWidth, rCallback, pUserData));
    maDelayedPreviewCreationTimer.Start();
}




IMPL_LINK(MasterPageContainer::Implementation,
    DelayedPreviewCreation,
    Timer*, pTimer)
{
    while (maRequestQueue.size()>0 && ! GetpApp()->AnyInput())
    {
        PreviewCreationRequest aRequest (maRequestQueue.front());
        maRequestQueue.pop();

        if (aRequest.maToken>=0
            && (unsigned)aRequest.maToken<maContainer.size())
        {
            String sURL (maContainer[aRequest.maToken].msURL);
            // Store bitmap in original size so that both preview sizes have
            // access to the full resolution.
            maContainer[aRequest.maToken].maPreview = LoadPreviewFromURL (sURL);
{'fraction_non_alphanumeric': 0.11337369290038525, 'fraction_numerical': 0.0048031220293190575, 'mean_word_length': 3.1986135910093476, 'pattern_counts': {'":': 0, '<': 85, '<?xml version=': 0, '>': 163, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 1, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3868034', 'n_tokens_mistral': 12064, 'n_tokens_neox': 11585, 'n_words': 2776}