/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: slideshowimpl.cxx,v $
 *
 *  $Revision: 1.51 $
 *
 *  last change: $Author: obo $ $Date: 2008-02-25 15:51:01 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 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
 *
 ************************************************************************/


// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include <boost/scoped_ptr.hpp>

#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/document/XEventsSupplier.hpp>
#include <com/sun/star/drawing/XMasterPageTarget.hpp>
#include <com/sun/star/container/XNameReplace.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/awt/SystemPointer.hpp>
#include <com/sun/star/util/XURLTransformer.hpp>
#include <com/sun/star/frame/XDispatch.hpp>

#ifndef _VOS_PROCESS_HXX_
#include <vos/process.hxx>
#endif

#ifndef _AEITEM_HXX
#include <svtools/aeitem.hxx>
#endif

#ifndef SVTOOLS_URIHELPER_HXX
#include <svtools/urihelper.hxx>
#endif

#include <sfx2/imagemgr.hxx>

#ifndef _SFXREQUEST_HXX
#include <sfx2/request.hxx>
#endif
#include "sfx2/docfile.hxx"

#ifndef _SVX_UNOAPI_HXX_
#include <svx/unoapi.hxx>
#endif
#ifndef _SVDOOLE2_HXX
#include <svx/svdoole2.hxx>
#endif

// for child window ids
#include <sfx2/templdlg.hxx>
#include <svx/f3dchild.hxx>
#include <svx/imapdlg.hxx>
#include <svx/fontwork.hxx>
#include <svx/colrctrl.hxx>
#include <svx/bmpmask.hxx>
#include <svx/srchdlg.hxx>
#include <svx/hyprlink.hxx>
#include <svx/hyperdlg.hxx>
#include <svx/galbrws.hxx>

#ifndef SD_NAVIGATOR_CHILD_WINDOW_HXX
#include "NavigatorChildWindow.hxx"
#endif
#ifndef SD_ANIMATION_CHILD_WINDOW_HXX
#include "AnimationChildWindow.hxx"
#endif

#ifndef _SD_SLIDESHOWIMPL_HXX_
#include <slideshowimpl.hxx>
#endif
#ifndef _SD_SLIDESHOWVIEWIMPL_HXX_
#include <slideshowviewimpl.hxx>
#endif
#ifndef _SD_PGJUMP_HXX
#include <pgjump.hxx>
#endif
#include "PaneHider.hxx"

#include "glob.hrc"
#include "res_bmp.hrc"
#include "sdresid.hxx"
#include "vcl/canvastools.hxx"
#include "comphelper/anytostring.hxx"
#include "cppuhelper/exc_hlp.hxx"
#include "rtl/ref.hxx"
#include "slideshow.hrc"
#include "canvas/elapsedtime.hxx"
#include "canvas/prioritybooster.hxx"
#include "avmedia/mediawindow.hxx"

// TODO(Q3): This breaks encapsulation. Either export
// these strings from avmedia, or provide an XManager
// factory there
#ifdef WNT
#   define AVMEDIA_MANAGER_SERVICE_NAME "com.sun.star.media.Manager_DirectX"
#elif defined QUARTZ
#   define AVMEDIA_MANAGER_SERVICE_NAME "com.sun.star.media.Manager_QuickTime"
#else
#   define AVMEDIA_MANAGER_SERVICE_NAME "com.sun.star.media.Manager_Java"
#endif

using ::com::sun::star::uno::UNO_QUERY;
using ::com::sun::star::uno::UNO_QUERY_THROW;
using ::com::sun::star::uno::Any;
using ::com::sun::star::uno::XInterface;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::RuntimeException;
using ::com::sun::star::lang::XComponent;
using ::com::sun::star::lang::EventObject;
using ::com::sun::star::lang::XInitialization;
using ::com::sun::star::uno::Exception;
using ::com::sun::star::document::XEventsSupplier;
using ::com::sun::star::container::XNameReplace;
using ::com::sun::star::container::XIndexAccess;
using ::com::sun::star::beans::PropertyValue;
using ::com::sun::star::beans::XPropertySet;
using ::com::sun::star::beans::XPropertySetInfo;
using ::com::sun::star::animations::XAnimationNode;

using ::rtl::OUString;
using ::rtl::OString;
using ::comphelper::ImplementationReference;

using namespace ::com::sun::star;
using namespace ::com::sun::star;
using namespace ::com::sun::star::presentation;
using namespace ::com::sun::star::drawing;


extern String getUiNameFromPageApiNameImpl( const ::rtl::OUString& rApiName );
namespace sd
{
///////////////////////////////////////////////////////////////////////

// Slots, welche im Sfx verwaltet werden und in der SlideShow disabled
// werden sollen (muss in Reihenfolge der SIDs geordnet sein)
static USHORT __READONLY_DATA pAllowed[] =
{
    SID_OPENDOC                             , //     5501   // damit interne Spruenge klappen
    SID_JUMPTOMARK                          , //     5598
//  SID_SHOWPOPUPS                          , //     5929
//    SID_GALLERY                             , //     5960
//    SID_GALLERY_FORMATS                     , //    10280
    SID_NAVIGATOR                           , //    10366
//  SID_FM_DESIGN_MODE                      , //    10629
    SID_PRESENTATION_END                    , //    27218
    SID_NAVIGATOR_PAGENAME                  , //    27287
    SID_NAVIGATOR_STATE                     , //    27288
    SID_NAVIGATOR_INIT                      , //    27289
    SID_NAVIGATOR_PEN                       , //    27291
    SID_NAVIGATOR_PAGE                      , //    27292
    SID_NAVIGATOR_OBJECT                      //    27293
};

///////////////////////////////////////////////////////////////////////
// AnimationSlideController
///////////////////////////////////////////////////////////////////////

class AnimationSlideController
{
public:
    enum Mode { ALL, FROM, CUSTOM, PREVIEW };

public:
    AnimationSlideController( Reference< XIndexAccess > xSlides, Mode eMode );

    void setStartSlideNumber( sal_Int32 nSlideNumber ) { mnStartSlideNumber = nSlideNumber; }
    sal_Int32 getStartSlideIndex() const;

    sal_Int32 getCurrentSlideNumber() const;
    sal_Int32 getCurrentSlideIndex() const;

    sal_Int32 getSlideIndexCount() const { return maSlideNumbers.size(); }
    sal_Int32 getSlideNumberCount() const { return mnSlideCount; }

    sal_Int32 getSlideNumber( sal_Int32 nSlideIndex ) const;

    void insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible = true );
    void setPreviewNode( const Reference< XAnimationNode >& xPreviewNode );

    bool jumpToSlideIndex( sal_Int32 nNewSlideIndex );
    bool jumpToSlideNumber( sal_Int32 nNewSlideIndex );

    bool nextSlide();
    bool previousSlide();

    void displayCurrentSlide( const Reference< XSlideShow >& xShow );

    sal_Int32 getNextSlideIndex() const;
    sal_Int32 getPreviousSlideIndex() const;

    bool isVisibleSlideNumber( sal_Int32 nSlideNumber ) const;

    bool hasSlides() const { return !maSlideNumbers.empty(); }

private:
    sal_Int32 getNextSlideNumber() const;
    bool getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode );
    sal_Int32 findSlideIndex( sal_Int32 nSlideNumber ) const;

    bool isValidIndex( sal_Int32 nIndex ) const { return (nIndex >= 0) && (nIndex < (sal_Int32)maSlideNumbers.size()); }
    bool isValidSlideNumber( sal_Int32 nSlideNumber ) const { return (nSlideNumber >= 0) && (nSlideNumber < mnSlideCount); }

private:
    Mode meMode;
    sal_Int32 mnStartSlideNumber;
    std::vector< sal_Int32 > maSlideNumbers;
    std::vector< bool > maSlideVisible;
    std::vector< bool > maSlideVisited;
    Reference< XAnimationNode > mxPreviewNode;
    sal_Int32 mnSlideCount;
    sal_Int32 mnCurrentSlideIndex;
    sal_Int32 mnHiddenSlideNumber;
    Reference< XIndexAccess > mxSlides;
};


bool AnimationSlideController::isVisibleSlideNumber( sal_Int32 nSlideNumber ) const
{
    sal_Int32 nIndex = findSlideIndex( nSlideNumber );

    if( nIndex != -1 )
        return maSlideVisible[ nIndex ];
    else
        return false;
}


void AnimationSlideController::setPreviewNode( const Reference< XAnimationNode >& xPreviewNode )
{
    mxPreviewNode = xPreviewNode;
}

AnimationSlideController::AnimationSlideController( Reference< XIndexAccess > xSlides, Mode eMode  )
:   meMode( eMode )
,   mnStartSlideNumber(-1)
,   mnSlideCount( 0 )
,   mnCurrentSlideIndex(0)
,   mnHiddenSlideNumber( -1 )
,   mxSlides( xSlides )
{
    if( mxSlides.is() )
        mnSlideCount = xSlides->getCount();
}

sal_Int32 AnimationSlideController::getStartSlideIndex() const
{
    if( mnStartSlideNumber >= 0 )
    {
        sal_Int32 nIndex;
        const sal_Int32 nCount = maSlideNumbers.size();

        for( nIndex = 0; nIndex < nCount; nIndex++ )
        {
            if( maSlideNumbers[nIndex] == mnStartSlideNumber )
                return nIndex;
        }
    }

    return 0;
}

sal_Int32 AnimationSlideController::getCurrentSlideNumber() const
{
    if( mnHiddenSlideNumber != -1 )
        return mnHiddenSlideNumber;
    else if( !maSlideNumbers.empty() )
        return maSlideNumbers[mnCurrentSlideIndex];
    else
        return 0;
}

sal_Int32 AnimationSlideController::getCurrentSlideIndex() const
{
    if( mnHiddenSlideNumber != -1 )
        return -1;
    else
        return mnCurrentSlideIndex;
}

bool AnimationSlideController::jumpToSlideIndex( sal_Int32 nNewSlideIndex )
{
    if( isValidIndex( nNewSlideIndex ) )
    {
        mnCurrentSlideIndex = nNewSlideIndex;
        mnHiddenSlideNumber = -1;
        maSlideVisited[mnCurrentSlideIndex] = true;
        return true;
    }
    else
    {
        return false;
    }
}

bool AnimationSlideController::jumpToSlideNumber( sal_Int32 nNewSlideNumber )
{
    sal_Int32 nIndex = findSlideIndex( nNewSlideNumber );
    if( isValidIndex( nIndex ) )
    {
        return jumpToSlideIndex( nIndex );
    }
    else if( (nNewSlideNumber >= 0) && (nNewSlideNumber < mnSlideCount) )
    {
        // jump to a hidden slide
        mnHiddenSlideNumber = nNewSlideNumber;
        return true;
    }
    else
    {
        return false;
    }
}

sal_Int32 AnimationSlideController::getSlideNumber( sal_Int32 nSlideIndex ) const
{
    if( isValidIndex( nSlideIndex ) )
        return maSlideNumbers[nSlideIndex];
    else
        return -1;
}

void AnimationSlideController::insertSlideNumber( sal_Int32 nSlideNumber, bool bVisible /* = true */ )
{
    DBG_ASSERT( isValidSlideNumber( nSlideNumber ), "sd::AnimationSlideController::insertSlideNumber(), illegal index" );
    if( isValidSlideNumber( nSlideNumber ) )
    {
        maSlideNumbers.push_back( nSlideNumber );
        maSlideVisible.push_back( bVisible );
        maSlideVisited.push_back( false );
    }
}

bool AnimationSlideController::getSlideAPI( sal_Int32 nSlideNumber, Reference< XDrawPage >& xSlide, Reference< XAnimationNode >& xAnimNode )
{
    if( isValidSlideNumber( nSlideNumber ) ) try
    {
        xSlide = Reference< XDrawPage >( mxSlides->getByIndex(nSlideNumber), UNO_QUERY_THROW );

        if( meMode == PREVIEW )
        {
            xAnimNode = mxPreviewNode;
        }
        else
        {
               Reference< animations::XAnimationNodeSupplier > xAnimNodeSupplier( xSlide, UNO_QUERY_THROW );
            xAnimNode = xAnimNodeSupplier->getAnimationNode();
        }

        return true;
    }
    catch( Exception& e )
    {
        (void)e;
        DBG_ERROR(
            (OString("sd::AnimationSlideController::getSlideAPI(), "
                    "exception caught: ") +
            rtl::OUStringToOString(
                comphelper::anyToString( cppu::getCaughtException() ),
                RTL_TEXTENCODING_UTF8 )).getStr() );

    }

    return false;
}

sal_Int32 AnimationSlideController::findSlideIndex( sal_Int32 nSlideNumber ) const
{
    sal_Int32 nIndex;
    const sal_Int32 nCount = maSlideNumbers.size();

    for( nIndex = 0; nIndex < nCount; nIndex++ )
    {
        if( maSlideNumbers[nIndex] == nSlideNumber )
            return nIndex;
    }

    return -1;
}

sal_Int32 AnimationSlideController::getNextSlideIndex() const
{
    switch( meMode )
    {
    case ALL:
        {
            sal_Int32 nNewSlideIndex = mnCurrentSlideIndex + 1;
            if( isValidIndex( nNewSlideIndex ) )
            {
                // if the current slide is not excluded, make sure the
                // next slide is also not excluded.
                // if the current slide is excluded, we want to go
                // to the next slide, even if this is also excluded.
                if( maSlideVisible[mnCurrentSlideIndex] )
                {
                    while( isValidIndex( nNewSlideIndex ) )
                    {
                        if( maSlideVisible[nNewSlideIndex] )
                            break;

                        nNewSlideIndex++;
                    }
                }
            }
            return isValidIndex( nNewSlideIndex ) ? nNewSlideIndex : -1;
        }

    case FROM:
    case CUSTOM:
        return mnHiddenSlideNumber == -1 ? mnCurrentSlideIndex + 1 : mnCurrentSlideIndex;

    default:
    case PREVIEW:
        return -1;

    }
}

sal_Int32 AnimationSlideController::getNextSlideNumber() const
{
    sal_Int32 nNextSlideIndex = getNextSlideIndex();
    if( isValidIndex( nNextSlideIndex ) )
    {
        return maSlideNumbers[nNextSlideIndex];
    }
    else
    {
        return -1;
    }
}


bool AnimationSlideController::nextSlide()
{
    return jumpToSlideIndex( getNextSlideIndex() );
}

sal_Int32 AnimationSlideController::getPreviousSlideIndex() const
{
    sal_Int32 nNewSlideIndex = mnCurrentSlideIndex - 1;

    switch( meMode )
    {
        case ALL:
        {
            // make sure the previous slide is visible
            // or was already visited
            while( isValidIndex( nNewSlideIndex ) )
            {
                if( maSlideVisible[nNewSlideIndex] || maSlideVisited[nNewSlideIndex] )
                    break;

                nNewSlideIndex--;
            }

            break;
        }

        case PREVIEW:
            return -1;

        default:
            break;
    }

    return nNewSlideIndex;
}

bool AnimationSlideController::previousSlide()
{
    return jumpToSlideIndex( getPreviousSlideIndex() );
}

void AnimationSlideController::displayCurrentSlide( const Reference< XSlideShow >& xShow )
{
    const sal_Int32 nCurrentSlideNumber = getCurrentSlideNumber();

    if( xShow.is() && (nCurrentSlideNumber != -1 ) )
    {
        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aProperties;
        Reference< XDrawPage > xSlide;
        Reference< XAnimationNode > xAnimNode;

        const sal_Int32 nNextSlideNumber = getNextSlideNumber();
        if( getSlideAPI( nNextSlideNumber, xSlide, xAnimNode )  )
        {
            Sequence< Any > aValue(2);
            aValue[0] <<= xSlide;
            aValue[1] <<= xAnimNode;
            aProperties.realloc(1);
            aProperties[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "Prefetch" ) );
            aProperties[0].Value <<= aValue;
        }

        if( getSlideAPI( nCurrentSlideNumber, xSlide, xAnimNode ) )
            xShow->displaySlide( xSlide, xAnimNode, aProperties );
    }
}

///////////////////////////////////////////////////////////////////////
// class SlideshowImpl
///////////////////////////////////////////////////////////////////////

SlideshowImpl::SlideshowImpl(
    ViewShell* pViewSh,
    ::sd::View* pView,
    SdDrawDocument* pDoc,
    ::Window* pParentWindow )
:   SlideshowImpl_base( m_aMutex ),
    mxModel(pDoc->getUnoModel(),UNO_QUERY_THROW),
    mpView(pView),
    mpViewShell(pViewSh),
    mpDocSh(pDoc->GetDocSh()),
    mpDoc(pDoc),
    mpNewAttr(0),
    mpParentWindow(pParentWindow),
    mpShowWindow(0),
    mpTimeButton(0),
    mnRestoreSlide(0),
    maPresSize( -1, -1 ),
    meAnimationMode(ANIMATIONMODE_SHOW),
    mpOldActiveWindow(0),
    mnChildMask( 0 ),
    mbGridVisible(false),
    mbBordVisible(false),
    mbSlideBorderVisible(false),
    mbSetOnlineSpelling(false),
    mbDisposed(false),
    mbRehearseTimings(false),
    mbDesignMode(false),
    mbIsPaused(false),
    mbInputFreeze(false),
    maPresSettings( pDoc->getPresentationSettings() ),
    mnEntryCounter(0),
    mnLastSlideNumber(-1),
    msOnClick( RTL_CONSTASCII_USTRINGPARAM("OnClick") ),
    msBookmark( RTL_CONSTASCII_USTRINGPARAM("Bookmark") ),
    msVerb( RTL_CONSTASCII_USTRINGPARAM("Verb") ),
    mnEndShowEvent(0)
,   mnContextMenuEvent(0)
,   mnUpdateEvent(0)
{
    if( mpViewShell )
        mpOldActiveWindow = mpViewShell->GetActiveWindow();

    maUpdateTimer.SetTimeoutHdl(LINK(this, SlideshowImpl, updateHdl));

    maInputFreezeTimer.SetTimeoutHdl( LINK( this, SlideshowImpl, ReadyForNextInputHdl ) );
    maInputFreezeTimer.SetTimeout( 20 );

    SvtSaveOptions aOptions;

        // no autosave during show
    if( aOptions.IsAutoSave() )
        mbAutoSaveWasOn = true;
}

SlideshowImpl::~SlideshowImpl()
{
    if( mbAutoSaveWasOn )
        setAutoSaveState( true );

    if( mnEndShowEvent )
        Application::RemoveUserEvent( mnEndShowEvent );
    if( mnContextMenuEvent )
        Application::RemoveUserEvent( mnContextMenuEvent );

    maInputFreezeTimer.Stop();

    stopShow();

}

bool SlideshowImpl::startPreview(
        const Reference< XDrawPage >& xDrawPage,
        const Reference< XAnimationNode >& xAnimationNode,
        ::Window* pParent )
{
    bool bRet = false;

    try
    {
        const Reference<lang::XServiceInfo> xServiceInfo( xDrawPage, UNO_QUERY );
        if (xServiceInfo.is()) {
            const Sequence<OUString> supportedServices(
                xServiceInfo->getSupportedServiceNames() );
            for ( sal_Int32 pos = supportedServices.getLength(); pos--; ) {
                if (supportedServices[pos].equalsAsciiL(
                        RTL_CONSTASCII_STRINGPARAM(
                            "com.sun.star.drawing.MasterPage") )) {
                    DBG_ERROR("sd::SlideshowImpl::startPreview() "
                              "not allowed on master page!");
                    return false;
                }
            }
        }

        mxPreviewDrawPage = xDrawPage;
        mxPreviewAnimationNode = xAnimationNode;
        meAnimationMode = ANIMATIONMODE_PREVIEW;

        maPresSettings.mbAll = sal_False;
        maPresSettings.mbEndless = sal_False;
        maPresSettings.mbCustomShow = sal_False;
        maPresSettings.mbManual = sal_False;
        maPresSettings.mbMouseVisible = sal_False;
        maPresSettings.mbMouseAsPen = sal_False;
        maPresSettings.mbLockedPages = sal_False;
        maPresSettings.mbAlwaysOnTop = sal_False;
        maPresSettings.mbFullScreen = sal_False;
        maPresSettings.mbAnimationAllowed = sal_True;
        maPresSettings.mnPauseTimeout = 0;
        maPresSettings.mbShowPauseLogo = sal_False;
        maPresSettings.mbStartWithNavigator = sal_False;

        Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
        Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
        mpSlideController.reset( new AnimationSlideController( xSlides, AnimationSlideController::PREVIEW ) );

        sal_Int32 nSlideNumber = 0;
        Reference< XPropertySet > xSet( mxPreviewDrawPage, UNO_QUERY_THROW );
        xSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "Number" ) ) ) >>= nSlideNumber;
        mpSlideController->insertSlideNumber( nSlideNumber-1 );
        mpSlideController->setPreviewNode( xAnimationNode );

        mpShowWindow = new ShowWindow( ((pParent == 0) && mpViewShell) ?  mpParentWindow : pParent );
        if( mpViewShell )
        {
            mpViewShell->SetActiveWindow( mpShowWindow );
            mpShowWindow->SetViewShell (mpViewShell);
            mpViewShell->ShowUIControls (false);
        }

        if( mpView )
        {
            mpView->AddWindowToPaintView( mpShowWindow );
            mpView->SetAnimationPause( TRUE );
        }

        // call resize handler
        if( pParent )
        {
            maPresSize = pParent->GetSizePixel();
        }
        else if( mpViewShell )
        {
            Rectangle aContentRect (mpViewShell->GetViewShellBase().getClientRectangle());
            if (Application::GetSettings().GetLayoutRTL())
            {
                aContentRect.nLeft = aContentRect.nRight;
                aContentRect.nRight += aContentRect.nRight;
            }
            maPresSize = aContentRect.GetSize();
            mpShowWindow->SetPosPixel( aContentRect.TopLeft() );
        }
        else
        {
            DBG_ERROR("sd::SlideshowImpl::startPreview(), I need either a parent window or a viewshell!");
        }
        resize( maPresSize );

        sal_Int32 nPropertyCount = 1;
        if( mxPreviewAnimationNode.is() )
            nPropertyCount++;

        Sequence< beans::PropertyValue > aProperties(nPropertyCount);
        aProperties[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("AutomaticAdvancement") );
        aProperties[0].Value = uno::makeAny( (double)1.0 ); // one second timeout

        if( mxPreviewAnimationNode.is() )
        {
            aProperties[1].Name = OUString( RTL_CONSTASCII_USTRINGPARAM("NoSlideTransitions") );
            aProperties[1].Value = uno::makeAny( sal_True );
        }

        bRet = startShowImpl( aProperties );

        if( mpShowWindow != 0 && meAnimationMode == ANIMATIONMODE_PREVIEW )
            mpShowWindow->SetPreviewMode();

    }
    catch( Exception& e )
    {
        (void)e;
        DBG_ERROR(
            (OString("sd::SlideshowImpl::startPreview(), "
                     "exception caught: ") +
             rtl::OUStringToOString(
                 comphelper::anyToString( cppu::getCaughtException() ),
                 RTL_TEXTENCODING_UTF8 )).getStr() );
        bRet = false;
    }

    return bRet;
}

bool SlideshowImpl::startShow( PresentationSettings* pPresSettings )
{
    const rtl::Reference<SlideshowImpl> this_(this);

    DBG_ASSERT( !mxShow.is(), "sd::SlideshowImpl::startShow(), called twice!" );
    if( mxShow.is() )
        return true;
    DBG_ASSERT( mpParentWindow!=NULL, "sd::SlideshowImpl::startShow() called without parent window" );
    if (mpParentWindow == NULL)
        return false;

    bool bRet = false;

    try
    {
        if( pPresSettings )
            maPresSettings = *pPresSettings;

        // ---

        String  aPresSlide( maPresSettings.maPresPage );
        SdPage* pStartPage = mpViewShell ? mpViewShell->GetActualPage() : 0;
        bool    bStartWithActualSlide =  pStartPage &&
                                        ( (meAnimationMode != ANIMATIONMODE_SHOW) ||
                                           SD_MOD()->GetSdOptions( mpDoc->GetDocumentType() )->IsStartWithActualPage() );

        // sollen Zeiten gestoppt werden?
        if( mbRehearseTimings )
        {
            maPresSettings.mbEndless = sal_False;
            maPresSettings.mbManual = sal_True;
            maPresSettings.mbMouseVisible = sal_True;
            maPresSettings.mbMouseAsPen = sal_False;
            maPresSettings.mnPauseTimeout = 0;
            maPresSettings.mbShowPauseLogo = sal_False;
            maPresSettings.mbStartWithNavigator = sal_False;
        }

        if( pStartPage )
        {
            if( pStartPage->GetPageKind() == PK_NOTES )
            {
                // we are in notes page mode, so get
                // the corresponding draw page
                const USHORT nPgNum = ( pStartPage->GetPageNum() - 2 ) >> 1;
                pStartPage = mpDoc->GetSdPage( nPgNum, PK_STANDARD );
            }
        }

        if( bStartWithActualSlide )
        {
            if( meAnimationMode != ANIMATIONMODE_SHOW )
            {
                if( pStartPage->GetPageKind() == PK_STANDARD )
                {
                    aPresSlide = pStartPage->GetName();
                    maPresSettings.mbAll = false;
                }
                else
                {
                    bStartWithActualSlide = false;
                }
            }
        }
        else
        {
            if( pStartPage->GetPageKind() != PK_STANDARD )
            {
                bStartWithActualSlide = false;
            }
        }

        // build page list
        createSlideList( maPresSettings.mbAll, false, aPresSlide );

        if( bStartWithActualSlide )
        {
            sal_Int32 nSlideNum = ( pStartPage->GetPageNum() - 1 ) >> 1;

            if( !maPresSettings.mbAll && !maPresSettings.mbCustomShow )
            {
                // its start from dia, find out if it is located before our current Slide
                const sal_Int32 nSlideCount = mpDoc->GetSdPageCount( PK_STANDARD );
                sal_Int32 nSlide;
                for( nSlide = 0; (nSlide < nSlideCount); nSlide++ )
                {
                    if( mpDoc->GetSdPage( (USHORT) nSlide, PK_STANDARD )->GetName() == aPresSlide )
                        break;
                }

                if( nSlide > nSlideNum )
                    nSlideNum = -1;
            }

            if( nSlideNum != -1 )
                mpSlideController->setStartSlideNumber( nSlideNum );
        }

        // remember Slide number from where the show was started
        if( pStartPage )
            mnRestoreSlide = ( pStartPage->GetPageNum() - 1 ) / 2;

        if( mpSlideController->hasSlides() )
        {
            // hide child windows
            hideChildWindows();

            mpShowWindow = new ShowWindow( mpParentWindow );
            mpShowWindow->SetMouseAutoHide( !maPresSettings.mbMouseVisible );
            if( mpViewShell )
            {
                mpViewShell->SetActiveWindow( mpShowWindow );
                mpShowWindow->SetViewShell (mpViewShell);
                mpViewShell->GetViewShellBase().ShowUIControls (false);
                mpPaneHider.reset(new PaneHider(*mpViewShell));

                if( getViewFrame() )
                    getViewFrame()->SetChildWindow( SID_NAVIGATOR, maPresSettings.mbStartWithNavigator );
            }

            // these Slots are forbiden in other views for this document
            if( mpDocSh )
            {
                mpDocSh->SetSlotFilter( TRUE, sizeof( pAllowed ) / sizeof( USHORT ), pAllowed );
                mpDocSh->ApplySlotFilter();
            }

            Help::DisableContextHelp();
            Help::DisableExtHelp();

        //  mpTimeButton = new PushButton( mpShowWindow, SdResId( RID_TIME_BUTTON ) );
        //  maPencil = Pointer( POINTER_PEN );
        //  mpTimeButton->Hide();

            if( maPresSettings.mbFullScreen )
            {
                // disable basic ide error handling
                maStarBASICGlobalErrorHdl = StarBASIC::GetGlobalErrorHdl();
                StarBASIC::SetGlobalErrorHdl( Link() );
            }

            // call resize handler
            maPresSize = mpParentWindow->GetSizePixel();
            if( !maPresSettings.mbFullScreen && mpViewShell )
            {
                const Rectangle& aClientRect = mpViewShell->GetViewShellBase().getClientRectangle();
                maPresSize = aClientRect.GetSize();
                mpShowWindow->SetPosPixel( aClientRect.TopLeft() );
                resize( maPresSize );
            }

            // #i41824#
            // Note: In FullScreen Mode the OS (window manager) sends a resize to
            // the WorkWindow once it actually resized it to full size.  The
            // WorkWindow propagates the resize to the DrawViewShell which calls
            // resize() at the SlideShow (this).  Calling resize here results in a
            // temporary display of a black window in the window's default size

/*
            if ( mbRehearseTimings )
            {
                Size  aButtonSizePixel( pTimeButton->GetSizePixel() );
                Point aButtonPosPixel( aButtonSizePixel.Width() >> 1, pShowWindow->GetSizePixel().Height() - aButtonSizePixel.Height() * 5 / 2);

                pTimeButton->SetPosPixel( aButtonPosPixel );
                aTimer.SetTimeoutHdl( LINK( this,FuSlideShow, TimeButtonTimeOutHdl ) );
                pTimeButton->SetClickHdl( LINK( this, FuSlideShow, TimeButtonHdl ) );
            }
*/

            if( mpView )
            {
                mpView->AddWindowToPaintView( mpShowWindow );
                mpView->SetAnimationPause( TRUE );
            }

            SfxBindings* pBindings = getBindings();
            if( pBindings )
            {
                pBindings->Invalidate( SID_PRESENTATION );
                pBindings->Invalidate( SID_REHEARSE_TIMINGS );
            }

            mpShowWindow->GrabFocus();

            std::vector<beans::PropertyValue> aProperties;
            aProperties.reserve( 4 );

            aProperties.push_back(
                beans::PropertyValue(
                    OUString( RTL_CONSTASCII_USTRINGPARAM("AdvanceOnClick") ),
                    -1, Any( ! (maPresSettings.mbLockedPages != sal_False) ),
                    beans::PropertyState_DIRECT_VALUE ) );

            aProperties.push_back(
                beans::PropertyValue(
                    OUString( RTL_CONSTASCII_USTRINGPARAM("ImageAnimationsAllowed") ),
                    -1, Any( maPresSettings.mbAnimationAllowed != sal_False ),
                    beans::PropertyState_DIRECT_VALUE ) );

            const sal_Bool bZOrderEnabled(
                SD_MOD()->GetSdOptions( mpDoc->GetDocumentType() )->IsSlideshowRespectZOrder() );
            aProperties.push_back(
                beans::PropertyValue(
                    OUString( RTL_CONSTASCII_USTRINGPARAM("DisableAnimationZOrder") ),
                    -1, Any( bZOrderEnabled == sal_False ),
                    beans::PropertyState_DIRECT_VALUE ) );

/*
            aProperties.push_back(
                beans::PropertyValue(
                    OUString( RTL_CONSTASCII_USTRINGPARAM("MouseVisible") ),
                    -1, Any( maPresSettings.mbMouseVisible != sal_False ),
                    beans::PropertyState_DIRECT_VALUE ) );
*/
            aProperties.push_back(
                beans::PropertyValue(
                    OUString( RTL_CONSTASCII_USTRINGPARAM("ForceManualAdvance") ),
                    -1, Any( maPresSettings.mbManual != sal_False ),
                    beans::PropertyState_DIRECT_VALUE ) );

            if( maPresSettings.mbMouseAsPen )
             {
                aProperties.push_back(
                    beans::PropertyValue(
                        OUString( RTL_CONSTASCII_USTRINGPARAM("UserPaintColor") ),
                        -1, Any( static_cast<sal_Int32>(0x0000FF00L) ),
                        beans::PropertyState_DIRECT_VALUE ) );
            }

            if (mbRehearseTimings) {
                aProperties.push_back(
                    beans::PropertyValue(
                        OUString( RTL_CONSTASCII_USTRINGPARAM("RehearseTimings") ),
                        -1, Any(true), beans::PropertyState_DIRECT_VALUE ) );
            }

            bRet = startShowImpl( Sequence<beans::PropertyValue>(
                                      &aProperties[0], aProperties.size() ) );
        }
    }
    catch( Exception& e )
    {
        (void)e;
        DBG_ERROR(
            (OString("sd::SlideshowImpl::startShow(), "
                     "exception caught: ") +
             rtl::OUStringToOString(
                 comphelper::anyToString( cppu::getCaughtException() ),
                 RTL_TEXTENCODING_UTF8 )).getStr() );
        stopShow();
        bRet = false;
    }

    return bRet;
}

bool SlideshowImpl::startShowImpl( const Sequence< beans::PropertyValue >& aProperties )
{
    try
    {
        mxShow = Reference< XSlideShow >( createSlideShow(), UNO_QUERY_THROW );
        mxView = mxView.createFromQuery( new SlideShowView(
                                             *mpShowWindow,
                                             mpDoc,
                                             meAnimationMode,
                                             this,
                                             maPresSettings.mbFullScreen) );

        // try add wait symbol to properties:
        const Reference<rendering::XSpriteCanvas> xSpriteCanvas(
            mxView->getCanvas() );
        if (xSpriteCanvas.is())
        {
            BitmapEx waitSymbolBitmap( SdResId(BMP_WAIT_ICON) );
            const Reference<rendering::XBitmap> xBitmap(
                vcl::unotools::xBitmapFromBitmapEx(
                    xSpriteCanvas->getDevice(), waitSymbolBitmap ) );
            if (xBitmap.is())
            {
                mxShow->setProperty(
                    beans::PropertyValue(
                        OUString( RTL_CONSTASCII_USTRINGPARAM("WaitSymbolBitmap") ),
                        -1,
                        makeAny( xBitmap ),
                        beans::PropertyState_DIRECT_VALUE ) );
            }
        }

        const sal_Int32 nCount = aProperties.getLength();
        sal_Int32 nIndex;
        for( nIndex = 0; nIndex < nCount; nIndex++ )
            mxShow->setProperty( aProperties[nIndex] );

        mxShow->addView( mxView.getRef() );
        mxShow->addSlideShowListener( Reference< XSlideShowListener >( this ) );

        displaySlideIndex( mpSlideController->getStartSlideIndex() );

        return true;
    }
    catch( Exception& e )
    {
        (void)e;
        DBG_ERROR(
            (OString("sd::SlideshowImpl::startShowImpl(), "
                     "exception caught: ") +
             rtl::OUStringToOString(
                 comphelper::anyToString( cppu::getCaughtException() ),
                 RTL_TEXTENCODING_UTF8 )).getStr() );
        stopShow();
        return false;
    }
}

void SlideshowImpl::stopShow()
{
    if( !mxShow.is() )
        return;

    maUpdateTimer.Stop();

    if( mnUpdateEvent )
    {
        Application::RemoveUserEvent( mnUpdateEvent );
        mnUpdateEvent = 0;
    }

    removeShapeEvents();

    try
    {

        mxShow->removeSlideShowListener( Reference< XSlideShowListener >(this) );

        if( mxView.is() )
            mxShow->removeView( mxView.getRef() );

        Reference< XComponent > xComponent( mxShow, UNO_QUERY );
        if( xComponent.is() )
        {
            xComponent->dispose();
            xComponent.clear();
        }
        mxShow.clear();

        if( mxView.is() )
        {
            mxView->dispose();
            mxView.reset();
        }
    }
    catch( Exception& e )
    {
        static_cast<void>(e);
        DBG_ERROR(
            (OString("sd::SlideshowImpl::stopShow(), "
                    "exception caught: ") +
            rtl::OUStringToOString(
                comphelper::anyToString( cppu::getCaughtException() ),
                RTL_TEXTENCODING_UTF8 )).getStr() );

        mxShow.clear();
        mxView.reset();
    }

/*
    if( mpShowWindow )
    {
        if(maPresSettings.mbMouseAsPen)
            mpShowWindow->SetPointer( maOldPointer );

        mpShowWindow->ShowPointer( TRUE );
    }
*/

    mpSlideController.reset();

    // der DrawView das Praesentationfenster wegnehmen und ihr dafuer ihre alten Fenster wiedergeben
    if( mpShowWindow && mpView )
        mpView->DeleteWindowFromPaintView( mpShowWindow );

    if( mpView )
        mpView->SetAnimationPause( FALSE );

    if( mpViewShell )
    {
        mpViewShell->SetActiveWindow(mpOldActiveWindow);
        mpShowWindow->SetViewShell( NULL );
    }

    if( mpView )
        mpView->InvalidateAllWin();

    if( maPresSettings.mbFullScreen )
    {
        // restore StarBASICErrorHdl
        StarBASIC::SetGlobalErrorHdl(maStarBASICGlobalErrorHdl);
        maStarBASICGlobalErrorHdl = Link();
    }
    else
    {
        if( mpShowWindow )
            mpShowWindow->Hide();
    }

    if( meAnimationMode == ANIMATIONMODE_SHOW )
    {
        mpDocSh->SetSlotFilter();
        mpDocSh->ApplySlotFilter();

        Help::EnableContextHelp();
        Help::EnableExtHelp();

        showChildWindows();
        mnChildMask = 0UL;
    }

    // aktuelle Fenster wieder einblenden
    if( mpViewShell && !mpViewShell->ISA(PresentationViewShell))
    {
        if( meAnimationMode == ANIMATIONMODE_SHOW )
        {
            mpViewShell->GetViewShellBase().ShowUIControls (true);
            mpPaneHider.reset();
        }
        else if( meAnimationMode == ANIMATIONMODE_PREVIEW )
        {
            mpViewShell->ShowUIControls (true);
        }
    }

    if( mpTimeButton )
    {
        mpTimeButton->Hide();
        delete mpTimeButton;
        mpTimeButton = 0;
    }

    if( mpShowWindow )
    {
        mpShowWindow->Hide();
        delete mpShowWindow;
        mpShowWindow = 0;
    }

    if ( mpViewShell )
    {
        if( meAnimationMode == ANIMATIONMODE_SHOW )
        {
            // switch to the previously visible Slide
            static_cast<DrawViewShell*>(mpViewShell)->SwitchPage( (USHORT)mnRestoreSlide );

            // invalidate the view shell so the presentation slot will be re-enabled
            // and the rehersing will be updated
            mpViewShell->Invalidate();

            ::sd::Window* pActWin = mpViewShell->GetActiveWindow();

            if (pActWin)
            {
                Size aVisSizePixel = pActWin->GetOutputSizePixel();
                Rectangle aVisAreaWin = pActWin->PixelToLogic( Rectangle( Point(0,0), aVisSizePixel) );
                mpViewShell->VisAreaChanged(aVisAreaWin);
                mpView->VisAreaChanged(pActWin);
                pActWin->GrabFocus();
            }
        }

        // restart the custom show dialog if he started us
        if( mpViewShell->IsStartShowWithDialog() && getDispatcher() )
        {
            mpViewShell->SetStartShowWithDialog( FALSE );
            getDispatcher()->Execute( SID_CUSTOMSHOW_DLG, SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD );
        }

        mpViewShell->GetViewShellBase().UpdateBorder(true);
    }
}

/** called only by the slideshow view when the first paint event occurs.
    This actually starts the slideshow. */
void SlideshowImpl::onFirstPaint()
{
    if( mpShowWindow )
    {
        mpShowWindow->SetBackground( Wallpaper( Color( COL_BLACK ) ) );
        mpShowWindow->Erase();
        mpShowWindow->SetBackground();
    }

    ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
    maUpdateTimer.SetTimeout( (ULONG)100 );
    maUpdateTimer.Start();
}

void SlideshowImpl::paint( const Rectangle& /* rRect */ )
{
    if( mxView.is() ) try
    {
        awt::PaintEvent aEvt;
        // aEvt.UpdateRect = TODO
        mxView->paint( aEvt );
    }
    catch( Exception& e )
    {
        static_cast<void>(e);
        DBG_ERROR(
            (OString("sd::SlideshowImpl::paint(), "
                    "exception caught: ") +
            rtl::OUStringToOString(
                comphelper::anyToString( cppu::getCaughtException() ),
                RTL_TEXTENCODING_UTF8 )).getStr() );
    }
}

void SlideshowImpl::slideEnded() throw (uno::RuntimeException)
{
    ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
    gotoNextSlide();
}

void SlideshowImpl::removeShapeEvents()
{
    try
    {
        Reference< XShapeEventListener > xListener( this );

        WrappedShapeEventImplMap::iterator aIter;
        const WrappedShapeEventImplMap::iterator aEnd( maShapeEventMap.end() );

        for( aIter = maShapeEventMap.begin(); aIter != aEnd; aIter++ )
        {
            mxShow->removeShapeEventListener( xListener, (*aIter).first );
            mxShow->setShapeCursor( (*aIter).first, awt::SystemPointer::ARROW );
        }

        maShapeEventMap.clear();
    }
    catch( Exception& e )
    {
        (void)e;
        DBG_ERROR(
            (OString("sd::SlideshowImpl::removeShapeEvents(), "
                     "exception caught: ") +
             rtl::OUStringToOString(
                 comphelper::anyToString( cppu::getCaughtException() ),
                 RTL_TEXTENCODING_UTF8 )).getStr() );
    }
}

void SlideshowImpl::registerShapeEvents(sal_Int32 nSlideNumber)
{
    if( nSlideNumber >= 0 ) try
    {
        Reference< XDrawPagesSupplier > xDrawPages( mxModel, UNO_QUERY_THROW );
        Reference< XIndexAccess > xPages( xDrawPages->getDrawPages(), UNO_QUERY_THROW );

        Reference< XShapes > xDrawPage;
        xPages->getByIndex(nSlideNumber) >>= xDrawPage;

        if( xDrawPage.is() )
        {
            Reference< XMasterPageTarget > xMasterPageTarget( xDrawPage, UNO_QUERY );
            if( xMasterPageTarget.is() )
            {
                Reference< XShapes > xMasterPage( xMasterPageTarget->getMasterPage(), UNO_QUERY );
                if( xMasterPage.is() )
                    registerShapeEvents( xMasterPage );
            }
            registerShapeEvents( xDrawPage );
        }
    }
    catch( Exception& e )
    {
        (void)e;
        DBG_ERROR(
            (OString("sd::SlideshowImpl::registerShapeEvents(), "
                     "exception caught: ") +
             rtl::OUStringToOString(
                 comphelper::anyToString( cppu::getCaughtException() ),
                 RTL_TEXTENCODING_UTF8 )).getStr() );
    }
}

void SlideshowImpl::registerShapeEvents( Reference< XShapes >& xShapes )
    throw( Exception )
{
    try
    {
        Reference< XShapeEventListener > xListener( this );

        const sal_Int32 nShapeCount = xShapes->getCount();
        sal_Int32 nShape;
        for( nShape = 0; nShape < nShapeCount; nShape++ )
        {
            Reference< XShape > xShape;
            xShapes->getByIndex( nShape ) >>= xShape;

            if( xShape.is() &&
                xShape->getShapeType().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.GroupShape") ) )
            {
                Reference< XShapes > xSubShapes( xShape, UNO_QUERY );
                if( xSubShapes.is() )
                    registerShapeEvents( xSubShapes );
            }

            Reference< XPropertySet > xSet( xShape, UNO_QUERY );
            if( !xSet.is() )
                continue;

            Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
            if( !xSetInfo.is() || !xSetInfo->hasPropertyByName( msOnClick ) )
                continue;

            WrappedShapeEventImplPtr pEvent( new WrappedShapeEventImpl );
            xSet->getPropertyValue( msOnClick ) >>= pEvent->meClickAction;

            switch( pEvent->meClickAction )
            {
            case ClickAction_PREVPAGE:
            case ClickAction_NEXTPAGE:
            case ClickAction_FIRSTPAGE:
            case ClickAction_LASTPAGE:
            case ClickAction_STOPPRESENTATION:
                break;
            case ClickAction_BOOKMARK:
                if( xSetInfo->hasPropertyByName( msBookmark ) )
                    xSet->getPropertyValue( msBookmark ) >>= pEvent->maStrBookmark;
                if( getSlideNumberForBookmark( pEvent->maStrBookmark ) == -1 )
                    continue;
                break;
            case ClickAction_DOCUMENT:
            case ClickAction_SOUND:
            case ClickAction_PROGRAM:
            case ClickAction_MACRO:
                if( xSetInfo->hasPropertyByName( msBookmark ) )
                    xSet->getPropertyValue( msBookmark ) >>= pEvent->maStrBookmark;
                break;
            case ClickAction_VERB:
                if( xSetInfo->hasPropertyByName( msVerb ) )
                    xSet->getPropertyValue( msVerb ) >>= pEvent->mnVerb;
                break;
            default:
                continue; // skip all others
            }

            maShapeEventMap[ xShape ] = pEvent;

            mxShow->addShapeEventListener( xListener, xShape );
                mxShow->setShapeCursor( xShape, awt::SystemPointer::REFHAND );
        }
    }
    catch( Exception& e )
    {
        static_cast<void>(e);
        DBG_ERROR(
            (OString("sd::SlideshowImpl::registerShapeEvents(), "
                    "exception caught: ") +
            rtl::OUStringToOString(
                comphelper::anyToString( cppu::getCaughtException() ),
                RTL_TEXTENCODING_UTF8 )).getStr() );
    }
}

void SlideshowImpl::gotoNextEffect()
{
    if( mxShow.is() && mpSlideController.get() && mpShowWindow )
    {
        const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
        if( eMode == SHOWWINDOWMODE_END )
        {
            mpShowWindow->TerminateShow();
        }
        else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
        {
            mpShowWindow->RestartShow();
        }
        else
        {
            mxShow->nextEffect();
            update();
        }
    }
}

void SlideshowImpl::gotoPreviousSlide()
{
    if( mxShow.is() && mpSlideController.get() ) try
    {
        const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
        if( eMode == SHOWWINDOWMODE_END )
        {
            const sal_Int32 nLastSlideIndex = mpSlideController->getSlideIndexCount() - 1;
            if( nLastSlideIndex >= 0 )
                mpShowWindow->RestartShow( nLastSlideIndex );
        }
        else if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
        {
            mpShowWindow->RestartShow();
        }
        else
        {
            if( mpSlideController->previousSlide() )
                displayCurrentSlide();
        }
    }
    catch( Exception& e )
    {
        static_cast<void>(e);
        DBG_ERROR(
            (OString("sd::SlideshowImpl::gotoPreviousSlide(), "
                    "exception caught: ") +
            rtl::OUStringToOString(
                comphelper::anyToString( cppu::getCaughtException() ),
                RTL_TEXTENCODING_UTF8 )).getStr() );
    }
}

void SlideshowImpl::stopSound()
{
    try
    {
        if( mxPlayer.is() )
        {
            mxPlayer->stop();
            mxPlayer.clear();
        }
    }
    catch( Exception& e )
    {
        static_cast<void>(e);
        DBG_ERROR(
            (OString("sd::SlideshowImpl::stopSound(), "
                    "exception caught: ") +
            rtl::OUStringToOString(
                comphelper::anyToString( cppu::getCaughtException() ),
                RTL_TEXTENCODING_UTF8 )).getStr() );
    }
}

void SlideshowImpl::displayCurrentSlide()
{
    stopSound();
    removeShapeEvents();

    if( mpSlideController.get() && mxShow.is() )
    {
        mpSlideController->displayCurrentSlide( mxShow );
        registerShapeEvents(mpSlideController->getCurrentSlideNumber());
        update();

        SfxBindings* pBindings = getBindings();
        if( pBindings )
        {
            pBindings->Invalidate( SID_NAVIGATOR_STATE );
            pBindings->Invalidate( SID_NAVIGATOR_PAGENAME );
        }
    }
}

void SlideshowImpl::gotoNextSlide()
{
    const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
    if( (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
    {
        mpShowWindow->RestartShow();
    }
    else
    {
        // if this is a show, ignore user inputs and
        // start 20ms timer to reenable inputs to fiter
        // buffered inputs during slide transition
        if( meAnimationMode == ANIMATIONMODE_SHOW )
        {
            mbInputFreeze = true;
            maInputFreezeTimer.Start();
        }

        if( mpSlideController.get() )
        {
            if( mpSlideController->nextSlide() )
            {
                displayCurrentSlide();
            }
            else
            {
                stopSound();

                if( meAnimationMode == ANIMATIONMODE_PREVIEW )
                {
                    endPresentation();
                }
                else if( maPresSettings.mbEndless )
                {
                    if( maPresSettings.mnPauseTimeout )
                    {
                        boost::scoped_ptr< Graphic > pGraphic;

                        if( maPresSettings.mbShowPauseLogo )
                        {
                            // load about image from module path
                            String aBmpFileName( RTL_CONSTASCII_USTRINGPARAM("about.bmp") );
                            INetURLObject aObj( SvtPathOptions().GetModulePath(), INET_PROT_FILE );
                            aObj.insertName( aBmpFileName );
                            SvFileStream aStrm( aObj.PathToFileName(), STREAM_STD_READ );
                            if ( !aStrm.GetError() )
                            {
                                Bitmap aBmp;
                                aStrm >> aBmp;
                                pGraphic.reset( new Graphic(aBmp) );
                                pGraphic->SetPrefMapMode(MAP_PIXEL);
                            }
                            else
                            {
                                //if no image is located in the module path
                                //use default logo from iso resource:

                                String aMgrName( RTL_CONSTASCII_USTRINGPARAM( "iso" ) );
                                boost::scoped_ptr< ResMgr > pResMgr( ResMgr::CreateResMgr( U2S( aMgrName )) );
                                DBG_ASSERT(pResMgr,"No ResMgr found");
                                if(pResMgr.get())
                                {
                                    pGraphic.reset( new Graphic( Bitmap( ResId( RID_DEFAULT_ABOUT_BMP_LOGO, *pResMgr.get() ) ) ) );
                                    pGraphic->SetPrefMapMode(MAP_PIXEL);
                                }
                            }
                        }
                        if( mpShowWindow )
                            mpShowWindow->SetPauseMode( 0, maPresSettings.mnPauseTimeout, pGraphic.get() );
                    }
                    else
                    {
                        displaySlideIndex( 0 );
                    }
                }
                else
                {
                    if( mpShowWindow )
                        mpShowWindow->SetEndMode();
                }
            }
        }
    }
}

void SlideshowImpl::gotoFirstSlide()
{
    if( mpShowWindow && mpSlideController.get() )
    {
        if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
        {
            if( mpSlideController->getSlideIndexCount() )
                mpShowWindow->RestartShow( 0);
        }
        else
        {
            displaySlideIndex( 0 );
        }
    }
}

void SlideshowImpl::gotoLastSlide()
{
    if( mpSlideController.get() )
    {
        const sal_Int32 nLastSlideIndex = mpSlideController->getSlideIndexCount() - 1;
        if( nLastSlideIndex >= 0 )
        {
            if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_END )
            {
                mpShowWindow->RestartShow( nLastSlideIndex );
            }
            else
            {
                displaySlideIndex( nLastSlideIndex );
            }
        }
    }
}

void SlideshowImpl::endPresentation()
{
    if( !mnEndShowEvent )
        mnEndShowEvent = Application::PostUserEvent( LINK(this, SlideshowImpl, endPresentationHdl) );
}

IMPL_LINK( SlideshowImpl, endPresentationHdl, void*, EMPTYARG )
{
    mnEndShowEvent = 0;

    if( mpViewShell )
        mpViewShell->GetViewShellBase().StopPresentation();
    else
        stopShow();

    return 0;
}

void SlideshowImpl::enablePen()
{
    if( mxShow.is()) try
    {
        uno::Any aValue;
        if( maPresSettings.mbMouseAsPen )
            // todo: take color from configuration
            aValue <<= (sal_Int32)0x0000FF00L;

        beans::PropertyValue aPenProp;
        aPenProp.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "UserPaintColor" ));
        aPenProp.Value = aValue;

        mxShow->setProperty( aPenProp );
    }
    catch( Exception& e )
    {
        static_cast<void>(e);
        DBG_ERROR(
            (OString("sd::SlideshowImpl::enablePen(), "
                    "exception caught: ") +
            rtl::OUStringToOString(
                comphelper::anyToString( cppu::getCaughtException() ),
                RTL_TEXTENCODING_UTF8 )).getStr() );
    }
}

bool SlideshowImpl::pause( bool bPause )
{
    if( bPause != mbIsPaused ) try
    {
        mbIsPaused = bPause;
        if( mxShow.is() )
        {
            bool bRet = mxShow->pause(bPause);
            if( !bPause )
                update();

            return bRet;
        }
        else
        {
            return false;
        }
    }
    catch( Exception& e )
    {
        static_cast<void>(e);
        DBG_ERROR(
            (OString("sd::SlideshowImpl::pause(), "
                    "exception caught: ") +
            rtl::OUStringToOString(
                comphelper::anyToString( cppu::getCaughtException() ),
                RTL_TEXTENCODING_UTF8 )).getStr() );
    }

    return false;
}

// XShapeEventListener
void SAL_CALL SlideshowImpl::click( const Reference< XShape >& xShape, const ::com::sun::star::awt::MouseEvent& /* aOriginalEvent */ ) throw (RuntimeException)
{
    ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );

    WrappedShapeEventImplPtr pEvent = maShapeEventMap[xShape];
    if( !pEvent.get() )
        return;

    switch( pEvent->meClickAction )
    {
    case ClickAction_PREVPAGE:          gotoPreviousSlide();        break;
    case ClickAction_NEXTPAGE:          gotoNextSlide();            break;
    case ClickAction_FIRSTPAGE:         gotoFirstSlide();           break;
    case ClickAction_LASTPAGE:          gotoLastSlide();            break;
    case ClickAction_STOPPRESENTATION:  endPresentation();          break;
    case ClickAction_BOOKMARK:
    {
        sal_Int32 nSlideNumber = getSlideNumberForBookmark( pEvent->maStrBookmark );
        if( nSlideNumber != -1 )
            displaySlideNumber( nSlideNumber );
    }
    break;
    case ClickAction_SOUND:
    {
        try
        {
                        mxPlayer.set(avmedia::MediaWindow::createPlayer(pEvent->maStrBookmark), uno::UNO_QUERY_THROW );
            mxPlayer->start();
        }
        catch( uno::Exception& e )
        {
            (void)e;
            DBG_ERROR("sd::SlideshowImpl::click(), exception caught!" );
        }
    }
    break;

    case ClickAction_DOCUMENT:
    {
        OUString aBookmark( pEvent->maStrBookmark );

        sal_Int32 nPos = aBookmark.indexOf( sal_Unicode('#') );
        if( nPos >= 0 )
        {
            OUString aURL( aBookmark.copy( 0, nPos+1 ) );
            OUString aName( aBookmark.copy( nPos+1 ) );
            aURL += getUiNameFromPageApiNameImpl( aName );
            aBookmark = aURL;
        }

        mpDocSh->OpenBookmark( aBookmark );
    }
    break;

    case ClickAction_PROGRAM:
    {
        INetURLObject aURL(
            ::URIHelper::SmartRel2Abs(
                INetURLObject(mpDocSh->GetMedium()->GetBaseURL()),
                pEvent->maStrBookmark, ::URIHelper::GetMaybeFileHdl(), true,
                false, INetURLObject::WAS_ENCODED,
                INetURLObject::DECODE_UNAMBIGUOUS ) );

        if( INET_PROT_FILE == aURL.GetProtocol() )
        {
            SfxStringItem aUrl( SID_FILE_NAME, aURL.GetMainURL( INetURLObject::NO_DECODE ) );
            SfxBoolItem aBrowsing( SID_BROWSE, TRUE );

            SfxViewFrame* pViewFrm = SfxViewFrame::Current();
            if (pViewFrm)
                pViewFrm->GetDispatcher()->Execute( SID_OPENDOC,
                                              SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD,
                                            &aUrl,
                                            &aBrowsing,
                                            0L );
        }
    }
    break;

    case presentation::ClickAction_MACRO:
    {
        const String aMacro( pEvent->maStrBookmark );

        if ( SfxApplication::IsXScriptURL( aMacro ) )
        {
            Any aRet;
            Sequence< sal_Int16 > aOutArgsIndex;
            Sequence< Any > aOutArgs;
            Sequence< Any >* pInArgs = new Sequence< Any >(0);
            mpDocSh->CallXScript( aMacro, *pInArgs, aRet, aOutArgsIndex, aOutArgs);
        }
        else
        {
            // aMacro has the following syntax:
            // "Macroname.Modulname.Libname.Dokumentname" or
            // "Macroname.Modulname.Libname.Applikationsname"
            String aMacroName = aMacro.GetToken(0, sal_Unicode('.'));
            String aModulName = aMacro.GetToken(1, sal_Unicode('.'));
            String aLibName   = aMacro.GetToken(2, sal_Unicode('.'));
            String aDocName   = aMacro.GetToken(3, sal_Unicode('.'));

            // todo: is the limitation still given that only
            // Modulname+Macroname can be used here?
            String aExecMacro(aModulName);
            aExecMacro.Append( sal_Unicode('.') );
            aExecMacro.Append( aMacroName );
            mpDocSh->GetBasic()->Call(aExecMacro);
        }
    }
    break;

    case ClickAction_VERB:
    {
        // todo, better do it async?
        SdrObject* pObj = GetSdrObjectFromXShape( xShape );
        SdrOle2Obj* pOleObject = PTR_CAST(SdrOle2Obj, pObj);
        if (pOleObject && mpViewShell )
            mpViewShell->ActivateObject(pOleObject, pEvent->mnVerb);
    }
    break;
    default:
        break;
    }
}

sal_Int32 SlideshowImpl::getSlideNumberForBookmark( const OUString& rStrBookmark )
{
    BOOL bIsMasterPage;
    OUString aBookmark = getUiNameFromPageApiNameImpl( rStrBookmark );
    USHORT nPgNum = mpDoc->GetPageByName( aBookmark, bIsMasterPage );

    if( nPgNum == SDRPAGE_NOTFOUND )
    {
        // Ist das Bookmark ein Objekt?
        SdrObject* pObj = mpDoc->GetObj( aBookmark );

        if( pObj )
        {
            nPgNum = pObj->GetPage()->GetPageNum();
            bIsMasterPage = (BOOL)pObj->GetPage()->IsMasterPage();
        }
    }

    if( (nPgNum == SDRPAGE_NOTFOUND) || bIsMasterPage || static_cast<SdPage*>(mpDoc->GetPage(nPgNum))->GetPageKind() != PK_STANDARD )
        return -1;

    return ( nPgNum - 1) >> 1;
}

void SlideshowImpl::hyperLinkClicked( rtl::OUString const& aHyperLink )
    throw (RuntimeException)
{
    OUString aBookmark( aHyperLink );

    sal_Int32 nPos = aBookmark.indexOf( sal_Unicode('#') );
    if( nPos >= 0 )
    {
        OUString aURL( aBookmark.copy( 0, nPos+1 ) );
        OUString aName( aBookmark.copy( nPos+1 ) );
        aURL += getUiNameFromPageApiNameImpl( aName );
        aBookmark = aURL;
    }

    mpDocSh->OpenBookmark( aBookmark );
}

void SAL_CALL SlideshowImpl::disposing(  const EventObject& /* Source */ ) throw (RuntimeException)
{
}

void SlideshowImpl::displaySlideNumber( sal_Int32 nSlideNumber )
{
    if( mpSlideController.get() )
    {
        if( mpSlideController->jumpToSlideNumber( nSlideNumber ) )
        {
            displayCurrentSlide();
        }
    }
}

/** nSlideIndex == -1 displays current slide again */
void SlideshowImpl::displaySlideIndex( sal_Int32 nSlideIndex )
{
    if( mpSlideController.get() )
    {
        if( (nSlideIndex == -1) || mpSlideController->jumpToSlideIndex( nSlideIndex ) )
        {
            displayCurrentSlide();
        }
    }
}

void SlideshowImpl::jumpToBookmark( const String& sBookmark )
{
    sal_Int32 nSlideNumber = getSlideNumberForBookmark( sBookmark );
    if( nSlideNumber != -1 )
        displaySlideNumber( nSlideNumber );
}

sal_Int32 SlideshowImpl::getCurrentSlideNumber()
{
    return mpSlideController.get() ? mpSlideController->getCurrentSlideNumber() : -1;
}

sal_Int32 SlideshowImpl::getCurrentSlideIndex()
{
    return mpSlideController.get() ? mpSlideController->getCurrentSlideIndex() : -1;
}

sal_Int32 SlideshowImpl::getFirstSlideNumber()
{
    sal_Int32 nRet = 0;
    if( mpSlideController.get() )
    {
        sal_Int32 nSlideIndexCount = mpSlideController->getSlideIndexCount() - 1;
        if( nSlideIndexCount >= 0 )
        {
            nRet = mpSlideController->getSlideNumber( nSlideIndexCount );
            while( nSlideIndexCount-- )
            {
                sal_Int32 nTemp = mpSlideController->getSlideNumber( nSlideIndexCount );
                if( nRet > nTemp )
                    nRet = nTemp;
            }
        }
    }

    return nRet;
}

sal_Int32 SlideshowImpl::getLastSlideNumber()
{
    sal_Int32 nRet = 0;
    if( mpSlideController.get() )
    {
        sal_Int32 nSlideIndexCount = mpSlideController->getSlideIndexCount() - 1;
        if( nSlideIndexCount >= 0 )
        {
            nRet = mpSlideController->getSlideNumber( nSlideIndexCount );
            while( nSlideIndexCount-- )
            {
                sal_Int32 nTemp = mpSlideController->getSlideNumber( nSlideIndexCount );
                if( nRet < nTemp )
                    nRet = nTemp;
            }
        }
    }

    return nRet;
}

bool SlideshowImpl::isEndless()
{
    return maPresSettings.mbEndless;
}

bool SlideshowImpl::isDrawingPossible()
{
    return maPresSettings.mbMouseAsPen;
}

double SlideshowImpl::update()
{
    startUpdateTimer();
    return -1;
}

void SlideshowImpl::startUpdateTimer()
{
    ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
    maUpdateTimer.SetTimeout( 0 );
    maUpdateTimer.Start();
}

/** this timer is called 20ms after a new slide was displayed.
    This is used to unfreeze user input that was disabled after
    slide change to skip input that was buffered during slide
    transition preperation */
IMPL_LINK( SlideshowImpl, ReadyForNextInputHdl, Timer*, EMPTYARG )
{
    mbInputFreeze = false;
    return 0;
}

/** if I catch someone someday who calls this method by hand
    and not by using the timer, I will personaly punish this
    person seriously, even if this person is me.
*/
IMPL_LINK( SlideshowImpl, updateHdl, Timer*, EMPTYARG )
{
    mnUpdateEvent = 0;

    // doing some nMagic
    const rtl::Reference<SlideshowImpl> this_(this);

    try
    {
        // TODO(Q3): Evaluate under various systems and setups,
        // whether this is really necessary. Under WinXP and Matrox
        // G550, the frame rates were much more steadier with this
        // tweak, although.

// currently no solution, because this kills sound (at least on Windows)
//         // Boost our prio, as long as we're in the render loop
//         ::canvas::tools::PriorityBooster aBooster(2);

        Reference< XSlideShow > xShow( mxShow );

        double fUpdate = 0.0;
        if( !xShow->update(fUpdate) )
             fUpdate = -1.0;

        if( mxShow.is() && ( fUpdate >= 0.0 ) )
        {
            if( fUpdate < 0.5 )
            {
                Application::Reschedule(TRUE);
                if( mxShow.is() )
                    mnUpdateEvent = Application::PostUserEvent(LINK(this,SlideshowImpl, updateHdl ));
            }
            else
            {
                const float MAX_UPDATE = 60.0; // do not wait longer than 60 seconds for next refresh
                if( fUpdate > MAX_UPDATE )
                    fUpdate = MAX_UPDATE;
                maUpdateTimer.SetTimeout(
                    ::std::max( 1UL, static_cast<ULONG>(fUpdate * 1000.0) ) );
                maUpdateTimer.Start();
            }
        }
    }
    catch( Exception& e )
    {
        static_cast<void>(e);
        DBG_ERROR(
            (OString("sd::SlideshowImpl::updateHdl(), "
                     "exception caught: ") +
             rtl::OUStringToOString(
                 comphelper::anyToString( cppu::getCaughtException() ),
                 RTL_TEXTENCODING_UTF8 )).getStr() );
    }
    return 0;
}

bool SlideshowImpl::keyInput(const KeyEvent& rKEvt)
{
    if( !mxShow.is() || mbInputFreeze )
        return false;

    bool bRet = true;

    try
    {
        const int nKeyCode = rKEvt.GetKeyCode().GetCode();
        switch( nKeyCode )
        {
            case awt::Key::CONTEXTMENU:
                if( !mnContextMenuEvent )
                {
                    if( mpShowWindow )
                        maPopupMousePos = mpShowWindow->GetPointerState().maPos;
                    mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
                }
                break;

            // cancel show
            case KEY_ESCAPE:
            case KEY_SUBTRACT:
                // in case the user cancels the presentation, switch to current slide
                // in edit mode
                if( mpSlideController.get() && (ANIMATIONMODE_SHOW == meAnimationMode) )
                {
                    if( mpSlideController->getCurrentSlideNumber() != -1 )
                        mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
                }
                endPresentation();
                break;

            // advance show
            case KEY_PAGEDOWN:
                if(rKEvt.GetKeyCode().IsMod2())
                {
                    gotoNextSlide();
                    break;
                }
                // warning, fall through!
            case KEY_SPACE:
            case KEY_RIGHT:
            case KEY_DOWN:
            case KEY_N:
                gotoNextEffect();
                break;

            case KEY_RETURN:
            {
                if( maCharBuffer.Len() )
                {
                    if( mpSlideController.get() )
                    {
                        if( mpSlideController->jumpToSlideNumber( maCharBuffer.ToInt32() - 1 ) )
                            displayCurrentSlide();
                    }
                    maCharBuffer.Erase();
                }
                else
                {
                    gotoNextEffect();
                }
            }
            break;

            // numeric: add to buffer
            case KEY_0:
            case KEY_1:
            case KEY_2:
            case KEY_3:
            case KEY_4:
            case KEY_5:
            case KEY_6:
            case KEY_7:
            case KEY_8:
            case KEY_9:
                maCharBuffer.Append( rKEvt.GetCharCode() );
                break;

            case KEY_PAGEUP:
            case KEY_LEFT:
            case KEY_UP:
            case KEY_P:
            case KEY_BACKSPACE:
                gotoPreviousSlide();
                break;

            case KEY_HOME:
                gotoFirstSlide();
                break;

            case KEY_END:
                gotoLastSlide();
                break;

            case KEY_B:
            case KEY_W:
            case KEY_POINT:
            case KEY_COMMA:
            {
                if( mpShowWindow )
                {
                    const Color aBlankColor( ((nKeyCode == KEY_W ) || (nKeyCode == KEY_COMMA)) ? COL_WHITE : COL_BLACK );
                    if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), aBlankColor ) )
                        pause( true );
                }
            }
            break;

            default:
                bRet = false;
            break;
        }
    }
    catch( Exception& e )
    {
        bRet = false;
        static_cast<void>(e);
        DBG_ERROR(
            (OString("sd::SlideshowImpl::keyInput(), "
                    "exception caught: ") +
            rtl::OUStringToOString(
                comphelper::anyToString( cppu::getCaughtException() ),
                RTL_TEXTENCODING_UTF8 )).getStr() );
    }

    return bRet;
}

void SlideshowImpl::mouseButtonUp(const MouseEvent& rMEvt)
{
    if( rMEvt.IsRight() && !mnContextMenuEvent )
    {
        maPopupMousePos = rMEvt.GetPosPixel();
        mnContextMenuEvent = Application::PostUserEvent( LINK( this, SlideshowImpl, ContextMenuHdl ) );
    }
}

IMPL_LINK( SlideshowImpl, ContextMenuHdl, void*, EMPTYARG )
{
    mnContextMenuEvent = 0;

    if( mpSlideController.get() == 0 )
        return 0;

    mbWasPaused = mbIsPaused;
    if( !mbWasPaused )
        pause( true );

    PopupMenu* pMenu = new PopupMenu( SdResId( RID_SLIDESHOW_CONTEXTMENU ) );

    const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
    pMenu->EnableItem( CM_NEXT_SLIDE, ( mpSlideController->getNextSlideIndex() != -1 ) );
    pMenu->EnableItem( CM_PREV_SLIDE, ( mpSlideController->getPreviousSlideIndex() != -1 ) || (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) );

    PopupMenu* pPageMenu = pMenu->GetPopupMenu( CM_GOTO );

    SfxViewFrame* pViewFrame = getViewFrame();
    if( pViewFrame && pViewFrame->GetFrame() )
    {
        ::com::sun::star::uno::Reference< ::com::sun::star::frame::XFrame > xFrame( pViewFrame->GetFrame()->GetFrameInterface() );
        if( xFrame.is() )
        {
            pMenu->SetItemImage( CM_NEXT_SLIDE, GetImage( xFrame, OUString( RTL_CONSTASCII_USTRINGPARAM( "slot:10617") ), FALSE, FALSE ) );
            pMenu->SetItemImage( CM_PREV_SLIDE, GetImage( xFrame, OUString( RTL_CONSTASCII_USTRINGPARAM( "slot:10618") ), FALSE, FALSE ) );

            if( pPageMenu )
            {
                pPageMenu->SetItemImage( CM_FIRST_SLIDE, GetImage( xFrame, OUString( RTL_CONSTASCII_USTRINGPARAM( "slot:10616") ), FALSE, FALSE ) );
                pPageMenu->SetItemImage( CM_LAST_SLIDE, GetImage( xFrame, OUString( RTL_CONSTASCII_USTRINGPARAM( "slot:10619") ), FALSE, FALSE ) );
            }
        }
    }

    // populate slide goto list
    if( pPageMenu )
    {
        const sal_Int32 nPageNumberCount = mpSlideController->getSlideNumberCount();
        if( nPageNumberCount <= 1 )
        {
            pMenu->EnableItem( CM_GOTO, FALSE );
        }
        else
        {
            sal_Int32 nCurrentSlideNumber = mpSlideController->getCurrentSlideNumber();
            if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
                nCurrentSlideNumber = -1;

            pPageMenu->EnableItem( CM_FIRST_SLIDE, ( mpSlideController->getSlideNumber(0) != nCurrentSlideNumber ) );
            pPageMenu->EnableItem( CM_LAST_SLIDE, ( mpSlideController->getSlideNumber( mpSlideController->getSlideIndexCount() - 1) != nCurrentSlideNumber ) );

            sal_Int32 nPageNumber;

            for( nPageNumber = 0; nPageNumber < nPageNumberCount; nPageNumber++ )
            {
                if( mpSlideController->isVisibleSlideNumber( nPageNumber ) )
                {
                    SdPage* pPage = mpDoc->GetSdPage((USHORT)nPageNumber, PK_STANDARD);
                    if (pPage)
                    {
                        pPageMenu->InsertItem( (USHORT)(CM_SLIDES + nPageNumber), pPage->GetName() );
                        if( nPageNumber == nCurrentSlideNumber )
                            pPageMenu->CheckItem( (USHORT)(CM_SLIDES + nPageNumber) );
                    }
                }
            }
        }
    }

    if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK )
    {
        PopupMenu* pBlankMenu = pMenu->GetPopupMenu( CM_SCREEN );
        if( pBlankMenu )
        {
            pBlankMenu->CheckItem( ( mpShowWindow->GetBlankColor() == Color( COL_WHITE ) ) ? CM_SCREEN_WHITE : CM_SCREEN_BLACK  );
        }
    }

    pMenu->SetSelectHdl( LINK( this, SlideshowImpl, ContextMenuSelectHdl ) );
    pMenu->Execute( mpShowWindow, maPopupMousePos );
    delete pMenu;

    if( mxView.is() )
        mxView->ignoreNextMouseReleased();

    pause( mbWasPaused );
    return 0;
}

IMPL_LINK( SlideshowImpl, ContextMenuSelectHdl, Menu *, pMenu )
{
    if( pMenu )
    {
        sal_uInt16 nMenuId = pMenu->GetCurItemId();

        switch( nMenuId )
        {
        case CM_PREV_SLIDE:
            gotoPreviousSlide();
            mbWasPaused = false;
            break;
        case CM_NEXT_SLIDE:
            gotoNextSlide();
            mbWasPaused = false;
            break;
        case CM_FIRST_SLIDE:
            gotoFirstSlide();
            mbWasPaused = false;
            break;
        case CM_LAST_SLIDE:
            gotoLastSlide();
            mbWasPaused = false;
            break;
        case CM_SCREEN_BLACK:
        case CM_SCREEN_WHITE:
        {
            const Color aBlankColor( (nMenuId == CM_SCREEN_WHITE) ? COL_WHITE : COL_BLACK );
            if( mbWasPaused )
            {
                if( mpShowWindow->GetShowWindowMode() == SHOWWINDOWMODE_BLANK )
                {
                    if( mpShowWindow->GetBlankColor() == aBlankColor )
                    {
                        mbWasPaused = false;
                        mpShowWindow->RestartShow();
                        break;
                    }
                }
                mpShowWindow->RestartShow();
            }
            if( mpShowWindow->SetBlankMode( mpSlideController->getCurrentSlideIndex(), aBlankColor ) )
            {
                mbWasPaused = true;
            }
        }
        break;

        case CM_ENDSHOW:
            // in case the user cancels the presentation, switch to current slide
            // in edit mode
            if( mpSlideController.get() && (ANIMATIONMODE_SHOW == meAnimationMode) )
            {
                if( mpSlideController->getCurrentSlideNumber() != -1 )
                {
                    mnRestoreSlide = mpSlideController->getCurrentSlideNumber();
                }
            }
            endPresentation();
            break;
        default:
            sal_Int32 nPageNumber = nMenuId - CM_SLIDES;
            const ShowWindowMode eMode = mpShowWindow->GetShowWindowMode();
            if( (eMode == SHOWWINDOWMODE_END) || (eMode == SHOWWINDOWMODE_PAUSE) || (eMode == SHOWWINDOWMODE_BLANK) )
            {
                mpShowWindow->RestartShow( nPageNumber );
            }
            else if( nPageNumber != mpSlideController->getCurrentSlideNumber() )
            {
                displaySlideNumber( nPageNumber );
            }
            mbWasPaused = false;
            break;
        }
    }

    return 0;
}


Reference< XSlideShow > SlideshowImpl::createSlideShow() const
{
    Reference< XSlideShow > xShow;

    try
    {
        Reference< lang::XMultiServiceFactory > xFactory(
            ::comphelper::getProcessServiceFactory(),
            UNO_QUERY_THROW );

        Reference< XInterface > xInt( xFactory->createInstance(
                ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.presentation.SlideShow")) ) );

        xShow.set( xInt, UNO_QUERY_THROW );
    }
    catch( uno::Exception& e )
    {
        (void)e;
        DBG_ERROR(
            (OString("sd::SlideshowImpl::createSlideShow(), "
                     "exception caught: ") +
             rtl::OUStringToOString(
                 comphelper::anyToString( cppu::getCaughtException() ),
                 RTL_TEXTENCODING_UTF8 )).getStr() );
    }

    return xShow;
}

void SlideshowImpl::createSlideList( bool bAll, bool bStartWithActualSlide, const String& rPresSlide )
{
    const long nSlideCount = mpDoc->GetSdPageCount( PK_STANDARD );

    if( nSlideCount )
    {
        SdCustomShow*   pCustomShow;

        if( !bStartWithActualSlide && mpDoc->GetCustomShowList() && maPresSettings.mbCustomShow )
            pCustomShow = (SdCustomShow*) mpDoc->GetCustomShowList()->GetCurObject();
        else
            pCustomShow = NULL;

        // create animation slide controller
        AnimationSlideController::Mode eMode =
            ( pCustomShow && pCustomShow->Count() ) ? AnimationSlideController::CUSTOM :
                (bAll ? AnimationSlideController::ALL : AnimationSlideController::FROM);

        Reference< XDrawPagesSupplier > xDrawPages( mpDoc->getUnoModel(), UNO_QUERY_THROW );
        Reference< XIndexAccess > xSlides( xDrawPages->getDrawPages(), UNO_QUERY_THROW );
        mpSlideController.reset( new AnimationSlideController( xSlides, eMode ) );

        if( eMode != AnimationSlideController::CUSTOM )
        {
            sal_Int32 nFirstSlide = 0;

            // normale Praesentation
            if( eMode == AnimationSlideController::FROM )
            {
                if( rPresSlide.Len() )
                {
                    sal_Int32 nSlide;
                    BOOL bTakeNextAvailable = FALSE;

                    for( nSlide = 0, nFirstSlide = -1; ( nSlide < nSlideCount ) && ( -1 == nFirstSlide ); nSlide++ )
                    {
                        SdPage* pTestSlide = mpDoc->GetSdPage( (USHORT)nSlide, PK_STANDARD );

                        if( pTestSlide->GetName() == rPresSlide )
                        {
                            if( pTestSlide->IsExcluded() )
                                bTakeNextAvailable = TRUE;
                            else
                                nFirstSlide = nSlide;
                        }
                        else if( bTakeNextAvailable && !pTestSlide->IsExcluded() )
                            nFirstSlide = nSlide;
                    }

                    if( -1 == nFirstSlide )
                        nFirstSlide = 0;
                }
            }

            for( sal_Int32 i = 0; i < nSlideCount; i++ )
            {
                bool bVisible = ( mpDoc->GetSdPage( (USHORT)i, PK_STANDARD ) )->IsExcluded() ? false : true;
                if( bVisible || (eMode == AnimationSlideController::ALL) )
                    mpSlideController->insertSlideNumber( i, bVisible );
            }

            mpSlideController->setStartSlideNumber( nFirstSlide );
        }
        else
        {
            if( meAnimationMode != ANIMATIONMODE_SHOW && rPresSlide.Len() )
            {
                sal_Int32 nSlide;
                for( nSlide = 0; nSlide < nSlideCount; nSlide++ )
                    if( rPresSlide == mpDoc->GetSdPage( (USHORT) nSlide, PK_STANDARD )->GetName() )
                        break;

                if( nSlide < nSlideCount )
                    mpSlideController->insertSlideNumber( (USHORT) nSlide );
            }

            void* pCustomSlide;
            sal_Int32 nSlideIndex;
            for( pCustomSlide = pCustomShow->First(),nSlideIndex=0; pCustomSlide; pCustomSlide = pCustomShow->Next(), nSlideIndex++ )
            {
                const USHORT nSdSlide = ( ( (SdPage*) pCustomSlide )->GetPageNum() - 1 ) / 2;

                if( !( mpDoc->GetSdPage( nSdSlide, PK_STANDARD ) )->IsExcluded())
                    mpSlideController->insertSlideNumber( nSdSlide );
            }
        }
    }
}

typedef USHORT (*FncGetChildWindowId)();

FncGetChildWindowId aShowChilds[] =
{
    &AnimationChildWindow::GetChildWindowId,
    &Svx3DChildWindow::GetChildWindowId,
    &SvxFontWorkChildWindow::GetChildWindowId,
    &SvxColorChildWindow::GetChildWindowId,
    &SvxSearchDialogWrapper::GetChildWindowId,
    &SvxBmpMaskChildWindow::GetChildWindowId,
    &SvxIMapDlgChildWindow::GetChildWindowId,
    &SvxHyperlinkDlgWrapper::GetChildWindowId,
    &SvxHlinkDlgWrapper::GetChildWindowId,
    &SfxTemplateDialogWrapper::GetChildWindowId,
    &GalleryChildWindow::GetChildWindowId
};

#define NAVIGATOR_CHILD_MASK        0x80000000UL

void SlideshowImpl::hideChildWindows()
{
    mnChildMask = 0UL;

    if( ANIMATIONMODE_SHOW == meAnimationMode )
    {
        SfxViewFrame* pViewFrame = getViewFrame();

        if( pViewFrame )
        {
            if( pViewFrame->GetChildWindow( SID_NAVIGATOR ) != NULL )
                mnChildMask |= NAVIGATOR_CHILD_MASK;

            for( ULONG i = 0, nCount = sizeof( aShowChilds ) / sizeof( FncGetChildWindowId ); i < nCount; i++ )
            {
                const USHORT nId = ( *aShowChilds[ i ] )();

                if( pViewFrame->GetChildWindow( nId ) )
                {
                    pViewFrame->SetChildWindow( nId, FALSE );
                    mnChildMask |= 1 << i;
                }
            }
        }
    }
}

void SlideshowImpl::showChildWindows()
{
    if( ANIMATIONMODE_SHOW == meAnimationMode )
    {
        SfxViewFrame* pViewFrame = getViewFrame();
        if( pViewFrame )
        {
            pViewFrame->SetChildWindow( SID_NAVIGATOR, ( mnChildMask & NAVIGATOR_CHILD_MASK ) != 0 );

            for( ULONG i = 0, nCount = sizeof( aShowChilds ) / sizeof( FncGetChildWindowId ); i < nCount; i++ )
            {
                if( mnChildMask & ( 1 << i ) )
                    pViewFrame->SetChildWindow( ( *aShowChilds[ i ] )(), TRUE );
            }
        }
    }
}

SfxViewFrame* SlideshowImpl::getViewFrame() const
{
    return mpViewShell ? mpViewShell->GetViewFrame() : 0;
}

SfxDispatcher* SlideshowImpl::getDispatcher() const
{
    return (mpViewShell && mpViewShell->GetViewFrame()) ? mpViewShell->GetViewFrame()->GetDispatcher() : 0;
}

SfxBindings* SlideshowImpl::getBindings() const
{
    return (mpViewShell && mpViewShell->GetViewFrame()) ? &mpViewShell->GetViewFrame()->GetBindings() : 0;
}

void SlideshowImpl::resize( const Size& rSize )
{
    maPresSize = rSize;

    if( mpShowWindow && (ANIMATIONMODE_VIEW != meAnimationMode) )
    {
        mpShowWindow->SetSizePixel( maPresSize );
        mpShowWindow->Show();

        // Call ToTop() to bring the window to top if
        // a) the old size is not degenerate (then the window will be closed
        // soon) and
        // b) the animation mode is not that of a preview (on the one hand
        // this leaves the old behaviour for the slide show mode unmodified
        // and on the other hand does not move the focus from the document
        // to the (preview) window; the ToTop() seems not to be necessary at
        // least for the preview).
//        if( !aOldSize.Width() && !aOldSize.Height() )
//          mpShowWindow->ToTop();
    }

    if( mxView.is() ) try
    {
        awt::WindowEvent aEvt;
        mxView->windowResized(aEvt);
    }
    catch( Exception& e )
    {
        static_cast<void>(e);
        DBG_ERROR(
            (OString("sd::SlideshowImpl::resize(), "
                    "exception caught: ") +
            rtl::OUStringToOString(
                comphelper::anyToString( cppu::getCaughtException() ),
                RTL_TEXTENCODING_UTF8 )).getStr() );
    }
}

void SlideshowImpl::activate()
{
    if(!mxShow.is())
        return;

    if( ANIMATIONMODE_SHOW == meAnimationMode )
    {
        if( mbAutoSaveWasOn )
            setAutoSaveState( false );

        if( mpShowWindow )
        {
            SfxViewFrame* pViewFrame = getViewFrame();
            SfxDispatcher* pDispatcher = pViewFrame ? pViewFrame->GetDispatcher() : 0;

            hideChildWindows();

            if( pDispatcher )
            {
                // filter all forbiden slots
                pDispatcher->SetSlotFilter( TRUE, sizeof(pAllowed) / sizeof(USHORT), pAllowed );
            }

            if( getBindings() )
                getBindings()->InvalidateAll(TRUE);

            mpShowWindow->GrabFocus();
        }
    }

    pause( false );
}

// -----------------------------------------------------------------------------

void SlideshowImpl::deactivate()
{
    if( !mxShow.is() )
        return;

    pause( true );

    if( ANIMATIONMODE_SHOW == meAnimationMode )
    {
        if( mbAutoSaveWasOn )
            setAutoSaveState( true );

        if( mpShowWindow )
        {
            showChildWindows();
        }
    }
}

// -----------------------------------------------------------------------------

void SlideshowImpl::receiveRequest(SfxRequest& rReq)
{
    const SfxItemSet* pArgs      = rReq.GetArgs();

    switch ( rReq.GetSlot() )
    {
        case SID_NAVIGATOR_PEN:
            maPresSettings.mbMouseAsPen = !maPresSettings.mbMouseAsPen;
            enablePen();
        break;

        case SID_NAVIGATOR_PAGE:
        {
            PageJump    eJump = (PageJump)((SfxAllEnumItem&) pArgs->Get(SID_NAVIGATOR_PAGE)).GetValue();
            switch( eJump )
            {
                case PAGE_FIRST:        gotoFirstSlide(); break;
                case PAGE_LAST:         gotoLastSlide(); break;
                case PAGE_NEXT:         gotoNextSlide(); break;
                case PAGE_PREVIOUS:     gotoPreviousSlide(); break;
                case PAGE_NONE:         break;
            }
        }
        break;

        case SID_NAVIGATOR_OBJECT:
        {
            const String aTarget( ((SfxStringItem&) pArgs->Get(SID_NAVIGATOR_OBJECT)).GetValue() );

            // is the bookmark a Slide?
            BOOL        bIsMasterPage;
            USHORT      nPgNum = mpDoc->GetPageByName( aTarget, bIsMasterPage );
            SdrObject*  pObj   = NULL;

            if( nPgNum == SDRPAGE_NOTFOUND )
            {
                // is the bookmark an object?
                pObj = mpDoc->GetObj( aTarget );

                if( pObj )
                    nPgNum = pObj->GetPage()->GetPageNum();
            }

            if( nPgNum != SDRPAGE_NOTFOUND )
            {
                nPgNum = ( nPgNum - 1 ) >> 1;
                displaySlideNumber( nPgNum );
            }
        }
        break;
    }
}

void SlideshowImpl::setAutoSaveState( bool bOn)
{
    try
    {
        uno::Reference<lang::XMultiServiceFactory> xFac( ::comphelper::getProcessServiceFactory() );

        uno::Reference< util::XURLTransformer > xParser(
            xFac->createInstance( OUString::createFromAscii("com.sun.star.util.URLTransformer" ) ),
                uno::UNO_QUERY_THROW);
        util::URL aURL;
        aURL.Complete = OUString::createFromAscii("vnd.sun.star.autorecovery:/setAutoSaveState");
        xParser->parseStrict(aURL);

        Sequence< beans::PropertyValue > aArgs(1);
        aArgs[0].Name = OUString::createFromAscii("AutoSaveState");
        aArgs[0].Value <<= bOn ? sal_True : sal_False;

        uno::Reference< frame::XDispatch > xAutoSave(
            xFac->createInstance(OUString::createFromAscii("com.sun.star.frame.AutoRecovery")),
            uno::UNO_QUERY_THROW);
        xAutoSave->dispatch(aURL, aArgs);
    }
    catch( Exception& )
    {
        DBG_ERROR("sd::SlideshowImpl::setAutoSaveState(), exception caught!");
    }
}

SlideShowImplGuard::SlideShowImplGuard( SlideshowImpl* pImpl )
{
    mpImpl = pImpl;
    if( mpImpl )
        mpImpl->acquire();
}

SlideShowImplGuard::~SlideShowImplGuard()
{
    if( mpImpl )
        mpImpl->release();
}

} // namespace ::sd