/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"
#include <com/sun/star/presentation/EffectNodeType.hpp>
#include <com/sun/star/animations/Timing.hpp>
#include <com/sun/star/animations/Event.hpp>
#include <com/sun/star/animations/EventTrigger.hpp>
#include <com/sun/star/animations/AnimationFill.hpp>
#include <com/sun/star/presentation/TextAnimationType.hpp>
#include <com/sun/star/animations/ValuePair.hpp>
#include <com/sun/star/awt/FontSlant.hpp>
#include <com/sun/star/awt/FontWeight.hpp>
#include <com/sun/star/awt/FontUnderline.hpp>
#include <com/sun/star/drawing/XDrawPage.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/media/XManager.hpp>
#include <com/sun/star/media/XPlayer.hpp>

#ifndef BOOST_SHARED_PTR_HPP_INCLUDED
#include <boost/shared_ptr.hpp>
#endif

#ifndef _UNOTOOLS_PROCESSFACTORY_HXX
#include <comphelper/processfactory.hxx>
#endif
#include <unotools/pathoptions.hxx>
#include <vcl/tabctrl.hxx>
#include <vcl/tabpage.hxx>
#include <vcl/menubtn.hxx>
#include <vcl/svapp.hxx>
#include <vcl/fixed.hxx>
#include <vcl/lstbox.hxx>
#include <vcl/field.hxx>
#include <vcl/msgbox.hxx>
#include <vcl/decoview.hxx>
#include <vcl/combobox.hxx>
#include <vcl/menu.hxx>
#include <svtools/ctrlbox.hxx>
#include <svtools/ctrltool.hxx>
#include <sfx2/objsh.hxx>

#ifndef _SVX_SVXIDS_HRC
#include <svx/svxids.hrc>
#endif
#include <svx/dialmgr.hxx>
#include <editeng/flstitem.hxx>
#include <svx/drawitem.hxx>

#include <svx/xtable.hxx>
#include <svx/gallery.hxx>

#ifndef _SVX_DIALOGS_HRC
#include <svx/dialogs.hrc>
#endif
#include "sdresid.hxx"

#include "glob.hrc"
#include "CustomAnimationDialog.hxx"
#ifndef _SD_CUSTOMANIMATIONDIALOG_HRC
#include "CustomAnimationDialog.hrc"
#endif
#ifndef _SD_CUSTOMANIMATION_HRC
#include "CustomAnimation.hrc"
#endif
#include "STLPropertySet.hxx"

#include <avmedia/mediawindow.hxx>

#include "filedlg.hxx"
#include "strings.hrc"
#include "helpids.h"

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

using ::rtl::OUString;
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::makeAny;
using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Exception;
using ::com::sun::star::drawing::XShape;
using ::com::sun::star::drawing::XDrawPage;
using ::com::sun::star::beans::XPropertySet;

namespace sd {

extern void fillRepeatComboBox( ComboBox* pBox );
extern void fillDurationComboBox( ComboBox* pBox );
extern OUString getShapeDescription( const Reference< XShape >& xShape, bool bWithText = true );
extern OUString getPropertyName( sal_Int32 nPropertyType );

// ====================================================================

class PresetPropertyBox  : public PropertySubControl
{
public:
	PresetPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const OUString& aPresetId, const Link& rModifyHdl );
	~PresetPropertyBox();

	virtual Any getValue();
	virtual void setValue( const Any& rValue, const OUString& rPresetId );
	virtual Control* getControl();

private:
	std::map< sal_uInt16, rtl::OUString > maPropertyValues;
	ListBox* mpControl;
};

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

PresetPropertyBox::PresetPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const OUString& aPresetId, const Link& rModifyHdl )
: PropertySubControl( nControlType )
{
	mpControl = new ListBox( pParent, WB_BORDER|WB_TABSTOP|WB_DROPDOWN );
	mpControl->SetDropDownLineCount( 10 );
	mpControl->SetSelectHdl( rModifyHdl );
	mpControl->SetHelpId( HID_SD_CUSTOMANIMATIONPANE_PRESETPROPERTYBOX );

	setValue( rValue, aPresetId );

}

void PresetPropertyBox::setValue( const Any& rValue, const OUString& rPresetId )
{
	if( mpControl )
	{
		mpControl->Clear();

		const CustomAnimationPresets& rPresets = CustomAnimationPresets::getCustomAnimationPresets();
		CustomAnimationPresetPtr pDescriptor = rPresets.getEffectDescriptor( rPresetId );
		if( pDescriptor.get() )
		{

			OUString aPropertyValue;
			rValue >>= aPropertyValue;

			UStringList aSubTypes( pDescriptor->getSubTypes() );
			UStringList::iterator aIter( aSubTypes.begin() );
			const UStringList::iterator aEnd( aSubTypes.end() );

			mpControl->Enable( aIter != aEnd );

			while( aIter != aEnd )
			{
				sal_uInt16 nPos = mpControl->InsertEntry( rPresets.getUINameForProperty( (*aIter) ) );
				if( (*aIter) == aPropertyValue )
					mpControl->SelectEntryPos( nPos );
				maPropertyValues[nPos] = (*aIter++);
			}
		}
		else
		{
			mpControl->Enable( sal_False );
		}
	}
}

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

PresetPropertyBox::~PresetPropertyBox()
{
	delete mpControl;
}

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

Any PresetPropertyBox::getValue()
{
	return makeAny( maPropertyValues[mpControl->GetSelectEntryPos()] );
}

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

Control* PresetPropertyBox::getControl()
{
	return mpControl;
}

// ====================================================================

class ColorPropertyBox  : public PropertySubControl
{
public:
	ColorPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl );
	~ColorPropertyBox();

	virtual Any getValue();
	virtual void setValue( const Any& rValue, const OUString& rPresetId  );
	virtual Control* getControl();

private:
	ColorListBox* mpControl;
};

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

ColorPropertyBox::ColorPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl )
: PropertySubControl( nControlType )
{
	mpControl = new ColorListBox( pParent, WB_BORDER|WB_TABSTOP|WB_DROPDOWN );
	mpControl->SetDropDownLineCount( 10 );
	mpControl->SetSelectHdl( rModifyHdl );
	mpControl->SetHelpId( HID_SD_CUSTOMANIMATIONPANE_COLORPROPERTYBOX );

	SfxObjectShell* pDocSh = SfxObjectShell::Current();
	DBG_ASSERT( pDocSh, "DocShell not found!" );
	XColorTable* pColorTable = NULL;
	bool bKillTable = false;
	const SfxPoolItem* pItem = NULL;

	if ( pDocSh && ( ( pItem = pDocSh->GetItem( SID_COLOR_TABLE ) ) != 0) )
		pColorTable = ( (SvxColorTableItem*)pItem )->GetColorTable();

	if ( !pColorTable )
	{
		pColorTable = new XColorTable( SvtPathOptions().GetPalettePath() );
		bKillTable = sal_True;
	}

	sal_Int32 nColor = 0;
	rValue >>= nColor;

	for ( long i = 0; i < pColorTable->Count(); i++ )
	{
		XColorEntry* pEntry = pColorTable->GetColor(i);
		sal_uInt16 nPos = mpControl->InsertEntry( pEntry->GetColor(), pEntry->GetName() );
		if( pEntry->GetColor().GetRGBColor() == (sal_uInt32)nColor )
			mpControl->SelectEntryPos( nPos );
	}

	if ( bKillTable )
		delete pColorTable;
}

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

ColorPropertyBox::~ColorPropertyBox()
{
	delete mpControl;
}

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

void ColorPropertyBox::setValue( const Any& rValue, const OUString& )
{
	if( mpControl )
	{
		sal_Int32 nColor = 0;
		rValue >>= nColor;

		mpControl->SetNoSelection();
		mpControl->SelectEntryPos( mpControl->GetEntryPos( (Color)nColor ) );
	}
}

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

Any ColorPropertyBox::getValue()
{
	return makeAny( (sal_Int32)mpControl->GetSelectEntryColor().GetRGBColor() );
}

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

Control* ColorPropertyBox::getControl()
{
	return mpControl;
}

// ====================================================================

class FontPropertyBox : public PropertySubControl
{
public:
	FontPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl );
	virtual ~FontPropertyBox();

	virtual Any getValue();
	virtual void setValue( const Any& rValue, const OUString& rPresetId  );

	virtual Control* getControl();

private:
	FontNameBox* mpControl;
};

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

FontPropertyBox::FontPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl )
: PropertySubControl( nControlType )
{
	mpControl = new FontNameBox( pParent, WB_BORDER|WB_TABSTOP|WB_DROPDOWN );
	mpControl->SetDropDownLineCount( 10 );
	mpControl->SetSelectHdl( rModifyHdl );
	mpControl->SetHelpId( HID_SD_CUSTOMANIMATIONPANE_FONTPROPERTYBOX );

	SfxObjectShell* pDocSh = SfxObjectShell::Current();
	const SfxPoolItem* pItem;

	const FontList* pFontList = 0;
	bool bMustDelete = false;

    if ( pDocSh && ( (pItem = pDocSh->GetItem( SID_ATTR_CHAR_FONTLIST ) ) != 0) )
        pFontList = ( (SvxFontListItem*)pItem )->GetFontList();

	if(!pFontList)
	{
        pFontList = new FontList( Application::GetDefaultDevice(), NULL, sal_False );
		bMustDelete = true;
	}

	mpControl->Fill( pFontList );

	if( bMustDelete )
		delete pFontList;

	OUString aPresetId;
	setValue( rValue, aPresetId );
}

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

void FontPropertyBox::setValue( const Any& rValue, const OUString& )
{
	if( mpControl )
	{
		OUString aFontName;
		rValue >>= aFontName;
		mpControl->SetText( aFontName );
	}
}

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

FontPropertyBox::~FontPropertyBox()
{
	delete mpControl;
}

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

Any FontPropertyBox::getValue()
{
	OUString aFontName( mpControl->GetText() );
	return makeAny( aFontName );
}

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

Control* FontPropertyBox::getControl()
{
	return mpControl;
}

// ====================================================================

class DropdownMenuBox : public Edit
{
public:
	DropdownMenuBox( Window* pParent, Edit* pSubControl, PopupMenu* pMenu );
	~DropdownMenuBox();

	void Resize();
	long PreNotify( NotifyEvent& rNEvt );

	void SetMenuSelectHdl( const Link& rLink ) { mpDropdownButton->SetSelectHdl( rLink ); }

private:
	Edit* mpSubControl;
	MenuButton* mpDropdownButton;
	PopupMenu* mpMenu;
};

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

DropdownMenuBox::DropdownMenuBox( Window* pParent, Edit* pSubControl, PopupMenu* pMenu )
:	Edit( pParent, WB_BORDER|WB_TABSTOP| WB_DIALOGCONTROL ),
	mpSubControl(pSubControl),mpDropdownButton(0),mpMenu(pMenu)
{
	mpDropdownButton = new MenuButton( this, WB_NOLIGHTBORDER | WB_RECTSTYLE | WB_NOTABSTOP);
	mpDropdownButton->SetSymbol(SYMBOL_SPIN_DOWN);
	mpDropdownButton->Show();
	mpDropdownButton->SetPopupMenu( pMenu );

	SetSubEdit( mpSubControl );
	mpSubControl->SetParent( this );
	mpSubControl->Show();
}

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

DropdownMenuBox::~DropdownMenuBox()
{
	SetSubEdit( 0 );
	delete mpSubControl;
	delete mpDropdownButton;
	delete mpMenu;
}

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

void DropdownMenuBox::Resize()
{
	Size aOutSz = GetOutputSizePixel();

	long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
	nSBWidth = CalcZoom( nSBWidth );
	mpSubControl->SetPosSizePixel( 0, 1, aOutSz.Width() - nSBWidth, aOutSz.Height()-2 );
	mpDropdownButton->SetPosSizePixel( aOutSz.Width() - nSBWidth, 0, nSBWidth, aOutSz.Height() );
}

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

long DropdownMenuBox::PreNotify( NotifyEvent& rNEvt )
{
	long nResult=sal_True;

	sal_uInt16 nSwitch=rNEvt.GetType();
	if (nSwitch==EVENT_KEYINPUT)
	{
		const KeyCode& aKeyCode=rNEvt.GetKeyEvent()->GetKeyCode();
		sal_uInt16 nKey=aKeyCode.GetCode();

		if (nKey==KEY_DOWN && aKeyCode.IsMod2())
		{
			mpDropdownButton->KeyInput( *rNEvt.GetKeyEvent() );
		}
		else
		{
			nResult=Edit::PreNotify(rNEvt);
		}
	}
	else
		nResult=Edit::PreNotify(rNEvt);

	return nResult;
}

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

class CharHeightPropertyBox : public PropertySubControl
{
public:
	CharHeightPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl );
	virtual ~CharHeightPropertyBox();

	virtual Any getValue();
	virtual void setValue( const Any& rValue, const OUString& );

	virtual Control* getControl();

	DECL_LINK( implMenuSelectHdl, MenuButton* );

private:
	DropdownMenuBox* mpControl;
	PopupMenu* mpMenu;
	MetricField* mpMetric;
};

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

CharHeightPropertyBox::CharHeightPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl )
: PropertySubControl( nControlType )
{
	mpMetric = new MetricField( pParent, WB_TABSTOP|WB_IGNORETAB| WB_NOBORDER);
	mpMetric->SetUnit( FUNIT_PERCENT );
	mpMetric->SetMin( 0 );
	mpMetric->SetMax( 1000 );

	mpMenu = new PopupMenu(SdResId( RID_CUSTOMANIMATION_FONTSIZE_POPUP ) );
	mpControl = new DropdownMenuBox( pParent, mpMetric, mpMenu );
	mpControl->SetMenuSelectHdl( LINK( this, CharHeightPropertyBox, implMenuSelectHdl ));
	mpControl->SetModifyHdl( rModifyHdl );
	mpControl->SetHelpId( HID_SD_CUSTOMANIMATIONPANE_CHARHEIGHTPROPERTYBOX );

	OUString aPresetId;
	setValue( rValue, aPresetId );
}

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

CharHeightPropertyBox::~CharHeightPropertyBox()
{
	delete mpControl;
}

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

IMPL_LINK( CharHeightPropertyBox, implMenuSelectHdl, MenuButton*, pPb )
{
	long nValue = 100;
	switch( pPb->GetCurItemId() )
	{
	case CM_SIZE_25: nValue = 25; break;
	case CM_SIZE_50: nValue = 50; break;
	case CM_SIZE_150: nValue = 150; break;
	case CM_SIZE_400: nValue = 400; break;
	}
	mpMetric->SetValue( nValue );
	mpMetric->Modify();
	return 0;
}

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

void CharHeightPropertyBox::setValue( const Any& rValue, const OUString& )
{
	if( mpMetric )
	{
		double fValue = 0.0;
		rValue >>= fValue;
		mpMetric->SetValue( (long)(fValue * 100.0) );
	}
}

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

Any CharHeightPropertyBox::getValue()
{
	return makeAny( (double)((double)mpMetric->GetValue() / 100.0) );
}

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

Control* CharHeightPropertyBox::getControl()
{
	return mpControl;
}

// ====================================================================

class TransparencyPropertyBox : public PropertySubControl
{
public:
	TransparencyPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl );
	~TransparencyPropertyBox();

	virtual Any getValue();
	virtual void setValue( const Any& rValue, const OUString& rPresetId  );

	virtual Control* getControl();

	DECL_LINK( implMenuSelectHdl, MenuButton* );
	DECL_LINK( implModifyHdl, Control* );

	void updateMenu();

private:
	DropdownMenuBox* mpControl;
	PopupMenu* mpMenu;
	MetricField* mpMetric;
	Link maModifyHdl;
};

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

TransparencyPropertyBox::TransparencyPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl )
: PropertySubControl( nControlType )
, maModifyHdl( rModifyHdl )
{
	mpMetric = new MetricField( pParent ,WB_TABSTOP|WB_IGNORETAB| WB_NOBORDER);
	mpMetric->SetUnit( FUNIT_PERCENT );
	mpMetric->SetMin( 0 );
	mpMetric->SetMax( 100 );

	mpMenu = new PopupMenu();
	for( sal_uInt16 i = 25; i < 101; i += 25 )
	{
		String aStr( String::CreateFromInt32( i ) );
		aStr += sal_Unicode('%');
		mpMenu->InsertItem( i, aStr );
	}

	mpControl = new DropdownMenuBox( pParent, mpMetric, mpMenu );
	mpControl->SetMenuSelectHdl( LINK( this, TransparencyPropertyBox, implMenuSelectHdl ));
	mpControl->SetHelpId( HID_SD_CUSTOMANIMATIONPANE_TRANSPARENCYPROPERTYBOX );

	Link aLink( LINK( this, TransparencyPropertyBox, implModifyHdl ) );
	mpControl->SetModifyHdl( aLink );

	OUString aPresetId;
	setValue( rValue, aPresetId  );
}

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

TransparencyPropertyBox::~TransparencyPropertyBox()
{
	delete mpControl;
}

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

void TransparencyPropertyBox::updateMenu()
{
	sal_Int64 nValue = mpMetric->GetValue();
	for( sal_uInt16 i = 25; i < 101; i += 25 )
		mpMenu->CheckItem( i, nValue == i );
}

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

IMPL_LINK( TransparencyPropertyBox, implModifyHdl, Control*, EMPTYARG )
{
	updateMenu();
	maModifyHdl.Call(mpMetric);

	return 0;
}

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

IMPL_LINK( TransparencyPropertyBox, implMenuSelectHdl, MenuButton*, pPb )
{
	if( pPb->GetCurItemId() != mpMetric->GetValue() )
	{
		mpMetric->SetValue( pPb->GetCurItemId() );
		mpMetric->Modify();
	}

	return 0;
}

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

void TransparencyPropertyBox::setValue( const Any& rValue, const OUString& )
{
	if( mpMetric )
	{
		double fValue = 0.0;
		rValue >>= fValue;
		long nValue = (long)(fValue * 100);
		mpMetric->SetValue( nValue );
		updateMenu();
	}
}

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

Any TransparencyPropertyBox::getValue()
{
	return makeAny( (double)((double)mpMetric->GetValue()) / 100.0 );
}

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

Control* TransparencyPropertyBox::getControl()
{
	return mpControl;
}

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

class RotationPropertyBox : public PropertySubControl
{
public:
	RotationPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl );
	~RotationPropertyBox();

	virtual Any getValue();
	virtual void setValue( const Any& rValue, const OUString& );

	virtual Control* getControl();

	DECL_LINK( implMenuSelectHdl, MenuButton* );
	DECL_LINK( implModifyHdl, Control* );

	void updateMenu();

private:
	DropdownMenuBox* mpControl;
	PopupMenu* mpMenu;
	MetricField* mpMetric;
	Link maModifyHdl;
};

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

RotationPropertyBox::RotationPropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl )
: PropertySubControl( nControlType )
, maModifyHdl( rModifyHdl )
{
	mpMetric = new MetricField( pParent ,WB_TABSTOP|WB_IGNORETAB| WB_NOBORDER);
	mpMetric->SetUnit( FUNIT_CUSTOM );
	mpMetric->SetCustomUnitText( OUString( sal_Unicode(0xb0)) ); // degree sign
	mpMetric->SetMin( -10000 );
	mpMetric->SetMax( 10000 );

	mpMenu = new PopupMenu(SdResId( RID_CUSTOMANIMATION_ROTATION_POPUP ) );
	mpControl = new DropdownMenuBox( pParent, mpMetric, mpMenu );
	mpControl->SetMenuSelectHdl( LINK( this, RotationPropertyBox, implMenuSelectHdl ));
	mpControl->SetHelpId( HID_SD_CUSTOMANIMATIONPANE_ROTATIONPROPERTYBOX );

	Link aLink( LINK( this, RotationPropertyBox, implModifyHdl ) );
	mpControl->SetModifyHdl( aLink );

	OUString aPresetId;
	setValue( rValue, aPresetId );
}

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

RotationPropertyBox::~RotationPropertyBox()
{
	delete mpControl;
}

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

void RotationPropertyBox::updateMenu()
{
	sal_Int64 nValue = mpMetric->GetValue();
	bool bDirection = nValue >= 0;
	nValue = (nValue < 0 ? -nValue : nValue);

	mpMenu->CheckItem( CM_QUARTER_SPIN, nValue == 90 );
	mpMenu->CheckItem( CM_HALF_SPIN, nValue == 180 );
	mpMenu->CheckItem( CM_FULL_SPIN, nValue == 360 );
	mpMenu->CheckItem( CM_TWO_SPINS, nValue == 720 );

	mpMenu->CheckItem( CM_CLOCKWISE, bDirection );
	mpMenu->CheckItem( CM_COUNTERCLOCKWISE, !bDirection );
}

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

IMPL_LINK( RotationPropertyBox, implModifyHdl, Control*, EMPTYARG )
{
	updateMenu();
	maModifyHdl.Call(mpMetric);

	return 0;
}

IMPL_LINK( RotationPropertyBox, implMenuSelectHdl, MenuButton*, pPb )
{
	sal_Int64 nValue = mpMetric->GetValue();
	bool bDirection = nValue >= 0;
	nValue = (nValue < 0 ? -nValue : nValue);

	switch( pPb->GetCurItemId() )
	{
	case CM_QUARTER_SPIN: nValue = 90; break;
	case CM_HALF_SPIN: nValue = 180; break;
	case CM_FULL_SPIN: nValue = 360; break;
	case CM_TWO_SPINS: nValue = 720; break;

	case CM_CLOCKWISE: bDirection = true; break;
	case CM_COUNTERCLOCKWISE: bDirection = false; break;

	}

	if( !bDirection )
		nValue = -nValue;

	if( nValue != mpMetric->GetValue() )
	{
		mpMetric->SetValue( nValue );
		mpMetric->Modify();
	}

	return 0;
}

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

void RotationPropertyBox::setValue( const Any& rValue, const OUString& )
{
	if( mpMetric )
	{
		double fValue = 0.0;
		rValue >>= fValue;
		long nValue = (long)(fValue);
		mpMetric->SetValue( nValue );
		updateMenu();
	}
}

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

Any RotationPropertyBox::getValue()
{
	return makeAny( (double)((double)mpMetric->GetValue()) );
}

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

Control* RotationPropertyBox::getControl()
{
	return mpControl;
}

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

class ScalePropertyBox : public PropertySubControl
{
public:
	ScalePropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl );
	~ScalePropertyBox();

	virtual Any getValue();
	virtual void setValue( const Any& rValue, const OUString& );

	virtual Control* getControl();

	DECL_LINK( implMenuSelectHdl, MenuButton* );
	DECL_LINK( implModifyHdl, Control* );

	void updateMenu();

private:
	DropdownMenuBox* mpControl;
	PopupMenu* mpMenu;
	MetricField* mpMetric;
	Link maModifyHdl;
	int mnDirection;
};

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

ScalePropertyBox::ScalePropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl )
: PropertySubControl( nControlType )
, maModifyHdl( rModifyHdl )
{
	mpMetric = new MetricField( pParent ,WB_TABSTOP|WB_IGNORETAB| WB_NOBORDER);
	mpMetric->SetUnit( FUNIT_PERCENT );
	mpMetric->SetMin( 0 );
	mpMetric->SetMax( 10000 );

	mpMenu = new PopupMenu(SdResId( RID_CUSTOMANIMATION_SCALE_POPUP ) );
	mpControl = new DropdownMenuBox( pParent, mpMetric, mpMenu );
	mpControl->SetMenuSelectHdl( LINK( this, ScalePropertyBox, implMenuSelectHdl ));
	mpControl->SetHelpId( HID_SD_CUSTOMANIMATIONPANE_SCALEPROPERTYBOX );

	Link aLink( LINK( this, ScalePropertyBox, implModifyHdl ) );
	mpControl->SetModifyHdl( aLink );

	OUString aPresetId;
	setValue( rValue, aPresetId );
}

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

ScalePropertyBox::~ScalePropertyBox()
{
	delete mpControl;
}

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

void ScalePropertyBox::updateMenu()
{
	sal_Int64 nValue = mpMetric->GetValue();

	mpMenu->CheckItem( 25, nValue == 25 );
	mpMenu->CheckItem( 50, nValue == 50 );
	mpMenu->CheckItem( 150, nValue == 150 );
	mpMenu->CheckItem( 400, nValue == 400 );

	mpMenu->CheckItem( CM_HORIZONTAL, mnDirection == 1 );
	mpMenu->CheckItem( CM_VERTICAL, mnDirection == 2 );
	mpMenu->CheckItem( CM_BOTH, mnDirection == 3 );
}

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

IMPL_LINK( ScalePropertyBox, implModifyHdl, Control*, EMPTYARG )
{
	updateMenu();
	maModifyHdl.Call(mpMetric);

	return 0;
}

IMPL_LINK( ScalePropertyBox, implMenuSelectHdl, MenuButton*, pPb )
{
	sal_Int64 nValue = mpMetric->GetValue();

	int nDirection = mnDirection;

	switch( pPb->GetCurItemId() )
	{
	case CM_HORIZONTAL: nDirection = 1; break;
	case CM_VERTICAL: nDirection = 2; break;
	case CM_BOTH: nDirection = 3; break;

	default:
		nValue = pPb->GetCurItemId();
	}

	bool bModified = false;

	if( nDirection != mnDirection )
	{
		mnDirection = nDirection;
		bModified = true;
	}

	if( nValue != mpMetric->GetValue() )
	{
		mpMetric->SetValue( nValue );
		bModified = true;
	}

	if( bModified )
	{
		mpMetric->Modify();
		updateMenu();
	}

	return 0;
}

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

void ScalePropertyBox::setValue( const Any& rValue, const OUString& )
{
	if( mpMetric )
	{
		ValuePair aValues;
		rValue >>= aValues;

		double fValue1 = 0.0;
		double fValue2 = 0.0;

		aValues.First >>= fValue1;
		aValues.Second >>= fValue2;

		if( fValue2 == 0.0 )
			mnDirection = 1;
		else if( fValue1 == 0.0 )
			mnDirection = 2;
		else
			mnDirection = 3;

		long nValue;
		if( fValue1 )
			nValue = (long)(fValue1 * 100.0);
		else
			nValue = (long)(fValue2 * 100.0);
		mpMetric->SetValue( nValue );
		updateMenu();
	}
}

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

Any ScalePropertyBox::getValue()
{
	double fValue1 = (double)((double)mpMetric->GetValue() / 100.0);
	double fValue2 = fValue1;

	if( mnDirection == 1 )
		fValue2 = 0.0;
	else if( mnDirection == 2 )
		fValue1 = 0.0;

	ValuePair aValues;
	aValues.First <<= fValue1;
	aValues.Second <<= fValue2;

	return makeAny( aValues );
}

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

Control* ScalePropertyBox::getControl()
{
	return mpControl;
}

// ====================================================================

class FontStylePropertyBox : public PropertySubControl
{
public:
	FontStylePropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl );
	~FontStylePropertyBox();

	virtual Any getValue();
	virtual void setValue( const Any& rValue, const OUString& );

	virtual Control* getControl();

	DECL_LINK( implMenuSelectHdl, MenuButton* );

	void update();

private:
	DropdownMenuBox* mpControl;
	PopupMenu* mpMenu;
	Edit* mpEdit;
	Link maModifyHdl;

	float mfFontWeight;
	awt::FontSlant meFontSlant;
	sal_Int16 mnFontUnderline;
};

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

FontStylePropertyBox::FontStylePropertyBox( sal_Int32 nControlType, Window* pParent, const Any& rValue, const Link& rModifyHdl )
: PropertySubControl( nControlType )
, maModifyHdl( rModifyHdl )
{
	mpEdit = new Edit( pParent, WB_TABSTOP|WB_IGNORETAB|WB_NOBORDER|WB_READONLY);
	mpEdit->SetText( String( SdResId( STR_CUSTOMANIMATION_SAMPLE ) ) );

	mpMenu = new PopupMenu(SdResId( RID_CUSTOMANIMATION_FONTSTYLE_POPUP ) );
	mpControl = new DropdownMenuBox( pParent, mpEdit, mpMenu );
	mpControl->SetMenuSelectHdl( LINK( this, FontStylePropertyBox, implMenuSelectHdl ));
	mpControl->SetHelpId( HID_SD_CUSTOMANIMATIONPANE_FONTSTYLEPROPERTYBOX );

	OUString aPresetId;
	setValue( rValue, aPresetId );
}

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

FontStylePropertyBox::~FontStylePropertyBox()
{
	delete mpControl;
}

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

void FontStylePropertyBox::update()
{
	// update menu
	mpMenu->CheckItem( CM_BOLD, mfFontWeight == awt::FontWeight::BOLD );
	mpMenu->CheckItem( CM_ITALIC, meFontSlant == awt::FontSlant_ITALIC);
	mpMenu->CheckItem( CM_UNDERLINED, mnFontUnderline != awt::FontUnderline::NONE );

	// update sample edit
	Font aFont( mpEdit->GetFont() );
	aFont.SetWeight( mfFontWeight == awt::FontWeight::BOLD ? WEIGHT_BOLD : WEIGHT_NORMAL );
	aFont.SetItalic( meFontSlant == awt::FontSlant_ITALIC ? ITALIC_NORMAL : ITALIC_NONE  );
	aFont.SetUnderline( mnFontUnderline == awt::FontUnderline::NONE ? UNDERLINE_NONE : UNDERLINE_SINGLE );
	mpEdit->SetFont( aFont );
	mpEdit->Invalidate();
}

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

IMPL_LINK( FontStylePropertyBox, implMenuSelectHdl, MenuButton*, pPb )
{
	switch( pPb->GetCurItemId() )
	{
	case CM_BOLD:
		if( mfFontWeight == awt::FontWeight::BOLD )
			mfFontWeight = awt::FontWeight::NORMAL;
		else
			mfFontWeight = awt::FontWeight::BOLD;
		break;
	case CM_ITALIC:
		if( meFontSlant == awt::FontSlant_ITALIC )
			meFontSlant = awt::FontSlant_NONE;
		else
			meFontSlant = awt::FontSlant_ITALIC;
		break;
	case CM_UNDERLINED:
		if( mnFontUnderline == awt::FontUnderline::SINGLE )
			mnFontUnderline = awt::FontUnderline::NONE;
		else
			mnFontUnderline = awt::FontUnderline::SINGLE;
		break;
	default:
		return 0;
	}

	update();
	maModifyHdl.Call(mpEdit);

	return 0;
}

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

void FontStylePropertyBox::setValue( const Any& rValue, const OUString& )
{
	Sequence<Any> aValues;
	rValue >>= aValues;

	aValues[0] >>= mfFontWeight;
	aValues[1] >>= meFontSlant;
	aValues[2] >>= mnFontUnderline;

	update();
}

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

Any FontStylePropertyBox::getValue()
{
	Sequence<Any> aValues(3);
	aValues[0] <<= mfFontWeight;
	aValues[1] <<= meFontSlant;
	aValues[2] <<= mnFontUnderline;
	return makeAny( aValues );
}

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

Control* FontStylePropertyBox::getControl()
{
	return mpControl;
}

// ====================================================================

class CustomAnimationEffectTabPage : public TabPage
{
public:
	CustomAnimationEffectTabPage( Window* pParent, const ResId& rResId, const STLPropertySet* pSet );
	~CustomAnimationEffectTabPage();

	void update( STLPropertySet* pSet );
	DECL_LINK( implSelectHdl, Control* );

private:
	void updateControlStates();
	void fillSoundListBox();
	void clearSoundListBox();
	sal_Int32 getSoundObject( const String& rStr );
	void openSoundFileDialog();
	void onSoundPreview();

private:
	List maSoundList;
	sal_Bool mbHasText;
	const STLPropertySet* mpSet;

	FixedLine*		mpFLSettings;
	FixedText*		mpFTProperty1;
	PropertyControl* mpLBProperty1;
	FixedText*		mpFTProperty2;
	PropertyControl* mpLBProperty2;
	CheckBox*		mpCBSmoothStart;
	CheckBox*		mpCBSmoothEnd;
	CheckBox*		mpCBAutoRestart;

	FixedLine*		mpFLPlay;
	RadioButton*	mpRBFromStart;
	RadioButton*	mpRBFromLast;
	RadioButton*	mpRBFromTime;
	MetricField*	mpMFStartTime;
	FixedLine*		mpFLStop;
	RadioButton*	mpRBStopOnClick;
	RadioButton*	mpRBStopOnNextSlide;
	RadioButton*	mpRBStopAfterSlides;
	MetricField*	mpMFStopAfterSlides;

	FixedLine*		mpFLEnhancements;
	FixedText*		mpFTSound;
	ListBox*		mpLBSound;
	PushButton*		mpPBSoundPreview;
	FixedText*		mpFTAfterEffect;
	ListBox*		mpLBAfterEffect;
	FixedText*		mpFTDimColor;
	ColorListBox*	mpCLBDimColor;
	FixedText*		mpFTTextAnim;
	ListBox*		mpLBTextAnim;
	MetricField*	mpMFTextDelay;
	FixedText*		mpFTTextDelay;

	::com::sun::star::uno::Reference< ::com::sun::star::media::XPlayer > mxPlayer;
};


static void move_down( Control* pControl, int nOffsetX, int nOffsetY )
{
	Point aPos( pControl->GetPosPixel() );
	aPos.X() += nOffsetX;
	aPos.Y() += nOffsetY;
	pControl->SetPosPixel( aPos );
}

CustomAnimationEffectTabPage::CustomAnimationEffectTabPage( Window* pParent, const ResId& rResId, const STLPropertySet* pSet )
: TabPage( pParent, rResId ), mbHasText( sal_False ), mpSet(pSet )
{
	mpFLSettings = new FixedLine( this, SdResId( FL_SETTINGS ) );
	mpFTProperty1 = new FixedText( this, SdResId( FT_PROPERTY_1 ) );
	mpLBProperty1 = new PropertyControl( this, SdResId( LB_PROPERTY_1 ) );
	mpFTProperty2 = new FixedText( this, SdResId( FT_PROPERTY_2 ) );
	mpLBProperty2 = new PropertyControl( this, SdResId( LB_PROPERTY_2 ) );
	mpCBSmoothStart = new CheckBox( this, SdResId( CB_SMOOTH_START ) );
	mpCBSmoothEnd = new CheckBox( this, SdResId( CB_SMOOTH_END ) );
	mpCBAutoRestart = new CheckBox( this, SdResId( CB_AUTORESTART ) );
/*
	mpFLPlay = new FixedLine( this, SdResId( FL_PLAY ) );
	mpRBFromStart = new RadioButton( this, SdResId( RB_FROM_START ) );
	mpRBFromLast = new RadioButton( this, SdResId( RB_FROM_LAST ) );
	mpRBFromTime = new RadioButton( this, SdResId( RB_FROM_TIME ) );
	mpMFStartTime = new MetricField( this, SdResId( MF_START_TIME ) );
	mpFLStop = new FixedLine( this, SdResId( FL_STOP ) );
	mpRBStopOnClick = new RadioButton( this, SdResId( RB_STOP_ON_CLICK ) );
	mpRBStopOnNextSlide = new RadioButton( this, SdResId( RB_STOP_ON_NEXT_SLIDE ) );
	mpRBStopAfterSlides = new RadioButton( this, SdResId( RB_STOP_AFTER_N_SLIDES ) );
	mpMFStopAfterSlides = new MetricField( this, SdResId( MF_STOP_AFTER_SLIDES ) );
*/
	mpFLEnhancements = new FixedLine( this, SdResId( FL_ENHANCEMENTS ) );
	mpFTSound = new FixedText( this, SdResId( FT_SOUND ) );
	mpLBSound = new ListBox( this, SdResId( LB_SOUND ) );
	mpPBSoundPreview = new PushButton( this, SdResId( PB_SOUND_PREVIEW ) );
	mpFTAfterEffect = new FixedText( this, SdResId( FT_AFTER_EFFECT ) );
	mpLBAfterEffect = new ListBox( this, SdResId( LB_AFTER_EFFECT ) );
	mpFTDimColor = new FixedText( this, SdResId( FT_DIMCOLOR ) );
	mpCLBDimColor = new ColorListBox( this, SdResId( CLB_DIMCOLOR ) );
	mpFTTextAnim = new FixedText( this, SdResId( FT_TEXT_ANIM ) );
	mpLBTextAnim = new ListBox( this, SdResId( LB_TEXT_ANIM ) );
	mpMFTextDelay = new MetricField( this, SdResId( MF_TEXT_DELAY ) );
	mpFTTextDelay = new FixedText( this, SdResId( FT_TEXT_DELAY ) );

	FreeResource();

	// fill the soundbox
	fillSoundListBox();

	mpLBSound->SetSelectHdl( LINK( this, CustomAnimationEffectTabPage, implSelectHdl ) );

	mpPBSoundPreview->SetClickHdl( LINK( this, CustomAnimationEffectTabPage, implSelectHdl ) );
	mpPBSoundPreview->SetSymbol( SYMBOL_PLAY );

	// fill the color box
	SfxObjectShell* pDocSh = SfxObjectShell::Current();
	DBG_ASSERT( pDocSh, "DocShell not found!" );
	XColorTable* pColorTable = NULL;
	bool bKillTable = false;
	const SfxPoolItem* pItem = NULL;

	if ( pDocSh && ( (pItem = pDocSh->GetItem( SID_COLOR_TABLE ) ) != 0 ) )
		pColorTable = ( (SvxColorTableItem*)pItem )->GetColorTable();

	if ( !pColorTable )
	{
		pColorTable = new XColorTable( SvtPathOptions().GetPalettePath() );
		bKillTable = sal_True;
	}

    mpCLBDimColor->SetUpdateMode( sal_False );

    for ( long i = 0; i < pColorTable->Count(); i++ )
	{
		XColorEntry* pEntry = pColorTable->GetColor(i);
        mpCLBDimColor->InsertEntry( pEntry->GetColor(), pEntry->GetName() );
	}

    mpCLBDimColor->SetUpdateMode( sal_True );

	if ( bKillTable )
		delete pColorTable;

	//
	// init settings controls
	//

	int nOffsetY = 0;
	int nOffsetX = 0;

	Size aSpace( LogicToPixel( Size( 3, 3 ), MAP_APPFONT ) );

	// only show settings if all selected effects have the same preset-id
	if( pSet->getPropertyState( nHandlePresetId ) != STLPropertyState_AMBIGUOUS )
	{
		OUString aPresetId;
		pSet->getPropertyValue( nHandlePresetId ) >>= aPresetId;

		//
		// property 1
		//

		if( pSet->getPropertyState( nHandleProperty1Type ) != STLPropertyState_AMBIGUOUS )
		{
			sal_Int32 nType = 0;
			pSet->getPropertyValue( nHandleProperty1Type ) >>= nType;

			if( nType != nPropertyTypeNone )
			{
				// set ui name for property at fixed text
				OUString aPropertyName( getPropertyName( nType ) );

				if( aPropertyName.getLength() )
				{
					mpFTProperty1->Show();
					mpLBProperty1->Show();

					nOffsetY += mpLBProperty1->GetSizePixel().Height() + aSpace.Height();

					mpFTProperty1->SetText( aPropertyName );
				}

				// get property value
				const Any aValue( pSet->getPropertyValue( nHandleProperty1Value ) );

				Link aModifyLink;
				// create property sub control
				mpLBProperty1->setSubControl( PropertySubControl::create( nType, this, aValue, aPresetId, aModifyLink ));
			}
		}

		mpFTProperty1->Enable( mpLBProperty1->IsEnabled() );

		//
		// accelerate & deccelerate
		//

		if( pSet->getPropertyState( nHandleAccelerate ) == STLPropertyState_DIRECT )
		{
			mpCBSmoothStart->Show();
			mpCBSmoothEnd->Show();

			move_down( mpCBSmoothStart, nOffsetX, nOffsetY );
			move_down( mpCBSmoothEnd, nOffsetX, nOffsetY );

			nOffsetY += mpCBSmoothStart->GetSizePixel().Height() + aSpace.Height();

			double fTemp = 0.0;
			pSet->getPropertyValue( nHandleAccelerate ) >>= fTemp;
			mpCBSmoothStart->Check( fTemp > 0.0 );

			pSet->getPropertyValue( nHandleDecelerate ) >>= fTemp;
			mpCBSmoothEnd->Check( fTemp > 0.0 );
		}

		//
		// auto reverse
		//


		if( nOffsetY )
		{
			nOffsetY += mpFLSettings->GetSizePixel().Height() + aSpace.Height();
			mpFLSettings->Show();

			mpFLEnhancements->Show();
			move_down( mpFLEnhancements, nOffsetX, nOffsetY );

			nOffsetY += mpFLEnhancements->GetSizePixel().Height() + aSpace.Height();

			nOffsetX = 2* aSpace.Width();
		}
	}

	if( (nOffsetY != 0) || (nOffsetX != 0) )
	{
		move_down( mpFTSound, nOffsetX, nOffsetY );
		move_down( mpLBSound, nOffsetX, nOffsetY );
		move_down( mpPBSoundPreview, nOffsetX, nOffsetY );
		move_down( mpFTAfterEffect, nOffsetX, nOffsetY );
		move_down( mpLBAfterEffect, nOffsetX, nOffsetY );
		move_down( mpFTDimColor, nOffsetX, nOffsetY );
		move_down( mpCLBDimColor, nOffsetX, nOffsetY );
		move_down( mpFTTextAnim, nOffsetX, nOffsetY );
		move_down( mpLBTextAnim, nOffsetX, nOffsetY );
		move_down( mpMFTextDelay, nOffsetX, nOffsetY );
		move_down( mpFTTextDelay, nOffsetX, nOffsetY );
	}

	//
	// init after effect controls
	//

    mpLBAfterEffect->SetSelectHdl( LINK( this, CustomAnimationEffectTabPage, implSelectHdl ) );
    mpLBTextAnim->SetSelectHdl( LINK( this, CustomAnimationEffectTabPage, implSelectHdl ) );

	if( (pSet->getPropertyState( nHandleHasAfterEffect ) != STLPropertyState_AMBIGUOUS) &&
		(pSet->getPropertyState( nHandleAfterEffectOnNextEffect ) != STLPropertyState_AMBIGUOUS) &&
		(pSet->getPropertyState( nHandleDimColor ) != STLPropertyState_AMBIGUOUS))
	{
		sal_Bool bHasAfterEffect = sal_False;
		pSet->getPropertyValue( nHandleHasAfterEffect ) >>= bHasAfterEffect;

		sal_uInt16 nPos = 0;
		if( bHasAfterEffect )
		{
			nPos++;

			sal_Bool bAfterEffectOnNextClick = sal_False;
			pSet->getPropertyValue( nHandleAfterEffectOnNextEffect ) >>= bAfterEffectOnNextClick;
			Any aDimColor( pSet->getPropertyValue( nHandleDimColor ) );

			if( aDimColor.hasValue() )
			{
				sal_Int32 nColor = 0;
				aDimColor >>= nColor;
				Color aColor( nColor );
	            sal_uInt16 nColorPos = mpCLBDimColor->GetEntryPos( aColor );
				if ( LISTBOX_ENTRY_NOTFOUND != nColorPos )
					mpCLBDimColor->SelectEntryPos( nColorPos );
				else
                    mpCLBDimColor->SelectEntryPos(
                        mpCLBDimColor->InsertEntry( aColor, String( SVX_RES( RID_SVXSTR_COLOR_USER ) ) ) );
			}
			else
			{
				nPos++;
				if( bAfterEffectOnNextClick )
					nPos++;
			}
		}

		mpLBAfterEffect->SelectEntryPos( nPos );
	}

	if( pSet->getPropertyState( nHandleHasText ) != STLPropertyState_AMBIGUOUS )
		pSet->getPropertyValue( nHandleHasText ) >>= mbHasText;

	if( mbHasText )
	{
		if( pSet->getPropertyState( nHandleIterateType ) != STLPropertyState_AMBIGUOUS)
		{
			sal_uInt16 nPos = LISTBOX_ENTRY_NOTFOUND;

			sal_Int32 nIterateType = 0;
			pSet->getPropertyValue( nHandleIterateType ) >>= nIterateType;
			switch( nIterateType )
			{
			case TextAnimationType::BY_PARAGRAPH:	nPos = 0; break;
			case TextAnimationType::BY_WORD:		nPos = 1; break;
			case TextAnimationType::BY_LETTER:		nPos = 2; break;
			}

			mpLBTextAnim->SelectEntryPos( nPos );
		}

		if( pSet->getPropertyState( nHandleIterateInterval ) )
		{
			double fIterateInterval = 0.0;
			pSet->getPropertyValue( nHandleIterateInterval ) >>= fIterateInterval;
			mpMFTextDelay->SetValue( (long)(fIterateInterval*10) );
		}
	}
	else
	{
		mpFTTextAnim->Enable( sal_False );
		mpLBTextAnim->Enable( sal_False );
		mpMFTextDelay->Enable( sal_False );
		mpFTTextDelay->Enable( sal_False );

	}

	if( pSet->getPropertyState( nHandleSoundURL ) != STLPropertyState_AMBIGUOUS )
	{
		sal_uInt16 nPos = 0;

		const Any aValue( pSet->getPropertyValue( nHandleSoundURL ) );

		if( aValue.getValueType() == ::getCppuType((const sal_Bool*)0) )
		{
			nPos = 1;
		}
		else
		{
			OUString aSoundURL;
			aValue >>= aSoundURL;

			if( aSoundURL.getLength() )
			{
				const String aTmp( aSoundURL );

				sal_uLong i;
				for( i = 0; i < maSoundList.Count(); i++ )
				{
					String* pString = (String*)maSoundList.GetObject( i );
					if( *pString == aTmp )
					{
						nPos = (sal_uInt16)i+2;
						break;
					}
				}

				if( nPos == 0 )
				{
					nPos = (sal_uInt16)maSoundList.Count()+2;
					maSoundList.Insert( new String( aTmp ), LIST_APPEND );
					INetURLObject aURL( aTmp );
					nPos = mpLBSound->InsertEntry( aURL.GetBase(), nPos );
				}
			}
		}

		if( nPos != LISTBOX_ENTRY_NOTFOUND )
			mpLBSound->SelectEntryPos( nPos );
	}

	updateControlStates();

	Size aSize( GetSizePixel() );
	aSize.Height() += mpMFTextDelay->GetPosPixel().X() + GetSizePixel().Height() + aSpace.Height();
	SetSizePixel( aSize );
}

CustomAnimationEffectTabPage::~CustomAnimationEffectTabPage()
{
	clearSoundListBox();

	delete mpFLSettings;
	delete mpFTProperty1;
	delete mpLBProperty1;
	delete mpFTProperty2;
	delete mpLBProperty2;
	delete mpCBSmoothStart;
	delete mpCBSmoothEnd;
	delete mpCBAutoRestart;

	delete mpFLEnhancements;
	delete mpFTSound;
	delete mpLBSound;
	delete mpPBSoundPreview;
	delete mpFTAfterEffect;
	delete mpLBAfterEffect;
	delete mpFTDimColor;
	delete mpCLBDimColor;
	delete mpFTTextAnim;
	delete mpLBTextAnim;
	delete mpMFTextDelay;
	delete mpFTTextDelay;
}

void CustomAnimationEffectTabPage::updateControlStates()
{
	sal_uInt16 nPos = mpLBAfterEffect->GetSelectEntryPos();
	mpCLBDimColor->Enable( nPos == 1 );
	mpFTDimColor->Enable( nPos == 1 );

	if( mbHasText )
	{
		nPos = mpLBTextAnim->GetSelectEntryPos();
		mpMFTextDelay->Enable( nPos != 0 );
		mpFTTextDelay->Enable( nPos != 0 );
	}

	nPos = mpLBSound->GetSelectEntryPos();
	mpPBSoundPreview->Enable( nPos >= 2 );
}

IMPL_LINK( CustomAnimationEffectTabPage, implSelectHdl, Control*, pControl )
{
	if( pControl == mpLBAfterEffect )
	{
		sal_uInt16 nPos = static_cast<ListBox*>( mpLBAfterEffect )->GetSelectEntryPos();
		if( nPos == 1 )
		{
			if( mpCLBDimColor->GetSelectEntryPos() == LISTBOX_ENTRY_NOTFOUND )
				mpCLBDimColor->SelectEntryPos(0);
		}
	}
	else if( pControl == mpLBTextAnim )
	{
		if( mpMFTextDelay->GetValue() == 0 )
			mpMFTextDelay->SetValue( 100 );
	}
	else if( pControl == mpLBSound )
	{
		sal_uInt16 nPos = mpLBSound->GetSelectEntryPos();
		if( nPos == (mpLBSound->GetEntryCount() - 1) )
		{
			openSoundFileDialog();
		}
	}
	else if( pControl == mpPBSoundPreview )
	{
		onSoundPreview();
	}

	updateControlStates();
	return 0;
}

void CustomAnimationEffectTabPage::update( STLPropertySet* pSet )
{
	if( mpLBProperty1->getSubControl() )
	{
		Any aNewValue( mpLBProperty1->getSubControl()->getValue() );
		Any aOldValue;
		if( mpSet->getPropertyState( nHandleProperty1Value ) != STLPropertyState_AMBIGUOUS)
			aOldValue = mpSet->getPropertyValue( nHandleProperty1Value );

		if( aOldValue != aNewValue )
			pSet->setPropertyValue( nHandleProperty1Value, aNewValue );
	}

	if( mpLBProperty2->getSubControl() )
	{
		Any aNewValue( mpLBProperty2->getSubControl()->getValue() );
		Any aOldValue;
		if( mpSet->getPropertyState( nHandleProperty2Value ) != STLPropertyState_AMBIGUOUS)
			aOldValue = mpSet->getPropertyValue( nHandleProperty2Value );

		if( aOldValue != aNewValue )
			pSet->setPropertyValue( nHandleProperty2Value, aNewValue );
	}

	if( mpCBSmoothStart->IsVisible() )
	{
		// set selected value for accelerate if different then in original set

		double fTemp = mpCBSmoothStart->IsChecked() ? 0.5 : 0.0;

		double fOldTemp = 0.0;
		if(mpSet->getPropertyState( nHandleAccelerate ) != STLPropertyState_AMBIGUOUS)
			mpSet->getPropertyValue( nHandleAccelerate ) >>= fOldTemp;
		else
			fOldTemp = -2.0;

		if( fOldTemp != fTemp )
			pSet->setPropertyValue( nHandleAccelerate, makeAny( fTemp ) );

		// set selected value for decelerate if different then in original set
		fTemp = mpCBSmoothEnd->IsChecked() ? 0.5 : 0.0;

		if(mpSet->getPropertyState( nHandleDecelerate ) != STLPropertyState_AMBIGUOUS)
			mpSet->getPropertyValue( nHandleDecelerate ) >>= fOldTemp;
		else
			fOldTemp = -2.0;

		if( fOldTemp != fTemp )
			pSet->setPropertyValue( nHandleDecelerate, makeAny( fTemp ) );
	}

	sal_uInt16 nPos = mpLBAfterEffect->GetSelectEntryPos();
	if( nPos != LISTBOX_ENTRY_NOTFOUND )
	{
		sal_Bool bAfterEffect = nPos != 0;

		sal_Bool bOldAfterEffect = sal_False;

		if(mpSet->getPropertyState( nHandleHasAfterEffect ) != STLPropertyState_AMBIGUOUS)
			mpSet->getPropertyValue( nHandleHasAfterEffect ) >>= bOldAfterEffect;
		else
			bOldAfterEffect = !bAfterEffect;

		if( bOldAfterEffect != bAfterEffect )
			pSet->setPropertyValue( nHandleHasAfterEffect, makeAny( bAfterEffect ) );

		Any aDimColor;
		if( nPos == 1 )
		{
			Color aSelectedColor;
			if ( mpCLBDimColor->GetSelectEntryPos() != LISTBOX_ENTRY_NOTFOUND )
				aSelectedColor = mpCLBDimColor->GetSelectEntryColor();

			aDimColor = makeAny( makeAny( (sal_Int32)aSelectedColor.GetRGBColor() ) );
		}

		if( (mpSet->getPropertyState( nHandleDimColor ) == STLPropertyState_AMBIGUOUS) ||
			(mpSet->getPropertyValue( nHandleDimColor ) != aDimColor) )
			pSet->setPropertyValue( nHandleDimColor, makeAny( aDimColor ) );

		sal_Bool bAfterEffectOnNextEffect = nPos != 2 ? sal_True : sal_False;
		sal_Bool bOldAfterEffectOnNextEffect = !bAfterEffectOnNextEffect;

		if( mpSet->getPropertyState( nHandleAfterEffectOnNextEffect ) != STLPropertyState_AMBIGUOUS)
			mpSet->getPropertyValue( nHandleAfterEffectOnNextEffect ) >>= bOldAfterEffectOnNextEffect;

		if( bAfterEffectOnNextEffect != bOldAfterEffectOnNextEffect )
			pSet->setPropertyValue( nHandleAfterEffectOnNextEffect, makeAny( bAfterEffectOnNextEffect ) );
	}

	// ---

	nPos = mpLBTextAnim->GetSelectEntryPos();
	if( nPos != LISTBOX_ENTRY_NOTFOUND )
	{
		sal_Int16 nIterateType;

		switch( nPos )
		{
		case 1: nIterateType = TextAnimationType::BY_WORD; break;
		case 2: nIterateType = TextAnimationType::BY_LETTER; break;
		default:
			nIterateType = TextAnimationType::BY_PARAGRAPH;
		}

		sal_Int16 nOldIterateType = nIterateType-1;

		if(mpSet->getPropertyState( nHandleIterateType ) != STLPropertyState_AMBIGUOUS)
			mpSet->getPropertyValue( nHandleIterateType ) >>= nOldIterateType;

		if( nIterateType != nOldIterateType )
			pSet->setPropertyValue( nHandleIterateType, makeAny( nIterateType ) );
	}

	// ---

	{
		double fIterateInterval = static_cast< double >( mpMFTextDelay->GetValue() ) / 10;
		double fOldIterateInterval = -1.0;

		if( mpSet->getPropertyState( nHandleIterateInterval ) != STLPropertyState_AMBIGUOUS )
			mpSet->getPropertyValue( nHandleIterateInterval ) >>= fOldIterateInterval;

		if( fIterateInterval != fOldIterateInterval )
			pSet->setPropertyValue( nHandleIterateInterval, makeAny( fIterateInterval ) );
	}

	nPos = mpLBSound->GetSelectEntryPos();
	if( nPos != LISTBOX_ENTRY_NOTFOUND )
	{
		Any aNewSoundURL, aOldSoundURL( makeAny( (sal_Int32) 0 ) );

		if( nPos == 0 )
		{
			// 0 means no sound, so leave any empty
		}
		else if( nPos == 1 )
		{
			// this means stop sound
			aNewSoundURL = makeAny( (sal_Bool)sal_True );
		}
		else
		{
			OUString aSoundURL( *(String*)maSoundList.GetObject( nPos-2 ) );
			aNewSoundURL = makeAny( aSoundURL );
		}

		if( mpSet->getPropertyState( nHandleSoundURL ) != STLPropertyState_AMBIGUOUS )
			mpSet->getPropertyValue( nHandleSoundURL  ) >>= aOldSoundURL;

		if( aNewSoundURL != aOldSoundURL )
			pSet->setPropertyValue( nHandleSoundURL, aNewSoundURL );
	}
}

void CustomAnimationEffectTabPage::fillSoundListBox()
{
	GalleryExplorer::FillObjList( GALLERY_THEME_SOUNDS, maSoundList );
	GalleryExplorer::FillObjList( GALLERY_THEME_USERSOUNDS, maSoundList );

	mpLBSound->InsertEntry( String( SdResId( STR_CUSTOMANIMATION_NO_SOUND ) ) );
	mpLBSound->InsertEntry( String( SdResId( STR_CUSTOMANIMATION_STOP_PREVIOUS_SOUND ) ) );
	for( sal_uLong i = 0; i < maSoundList.Count(); i++ )
	{
		String* pString = (String*)maSoundList.GetObject( i );
		INetURLObject aURL( *pString );
		mpLBSound->InsertEntry( aURL.GetBase() );
	}
	mpLBSound->InsertEntry( String( SdResId( STR_CUSTOMANIMATION_BROWSE_SOUND ) ) );
}

void CustomAnimationEffectTabPage::clearSoundListBox()
{
	const sal_uInt32 nCount = maSoundList.Count();
	sal_uInt32 i;
	for( i = 0; i < nCount; i++ )
		delete (String*)maSoundList.GetObject( i );
	maSoundList.Clear();

	mpLBSound->Clear();
}

sal_Int32 CustomAnimationEffectTabPage::getSoundObject( const String& rStr )
{
	String aStrIn( rStr );
	aStrIn.ToLowerAscii();

	sal_uInt32 i;
	const sal_uInt32 nCount = maSoundList.Count();
	for( i = 0; i < nCount; i++ )
	{
		String aTmpStr( *(String*)maSoundList.GetObject( i ) );
		aTmpStr.ToLowerAscii();

		if( aTmpStr == aStrIn )
			return i+2;
	}

	return -1;
}

void CustomAnimationEffectTabPage::openSoundFileDialog()
{
	SdOpenSoundFileDialog	aFileDialog;

	String aFile( SvtPathOptions().GetGraphicPath() );
	aFileDialog.SetPath( aFile );

	bool bValidSoundFile = false;
	bool bQuitLoop = false;
	long nPos = 0;

	while( !bQuitLoop && (aFileDialog.Execute() == ERRCODE_NONE) )
	{
		aFile = aFileDialog.GetPath();
		nPos = getSoundObject( aFile );

		if( nPos < 0 ) // not in Soundliste
		{
			// try to insert in Gallery
			if( GalleryExplorer::InsertURL( GALLERY_THEME_USERSOUNDS, aFile, SGA_FORMAT_SOUND ) )
			{
				clearSoundListBox();
				fillSoundListBox();

				nPos = getSoundObject( aFile );
				DBG_ASSERT( nPos >= 0, "sd::CustomAnimationEffectTabPage::openSoundFileDialog(), Recently inserted sound not in list!" );

				bValidSoundFile=true;
				bQuitLoop=true;
			}
			else
			{
				String aStrWarning(SdResId(STR_WARNING_NOSOUNDFILE));
				String aStr; aStr += sal_Unicode('%');
				aStrWarning.SearchAndReplace( aStr , aFile );
				WarningBox aWarningBox( NULL, WB_3DLOOK | WB_RETRY_CANCEL, aStrWarning );
				aWarningBox.SetModalInputMode (sal_True);
				bQuitLoop = aWarningBox.Execute()==RET_RETRY ? sal_False : sal_True;

				bValidSoundFile=false;
			}
		}
		else
		{
			bValidSoundFile=true;
			bQuitLoop=true;
		}
	}

	if( !bValidSoundFile )
		nPos = 0;

	mpLBSound->SelectEntryPos( (sal_uInt16) nPos );
}

void CustomAnimationEffectTabPage::onSoundPreview()
{
	const sal_uInt16 nPos = mpLBSound->GetSelectEntryPos();

	if( nPos >= 2 ) try
    {
		const OUString aSoundURL( *(String*)maSoundList.GetObject( nPos-2 ) );
                mxPlayer.set( avmedia::MediaWindow::createPlayer( aSoundURL ), uno::UNO_QUERY_THROW );
		mxPlayer->start();
	}
    catch( uno::Exception& e )
    {
		(void)e;
        DBG_ERROR("CustomAnimationEffectTabPage::onSoundPreview(), exception caught!" );
    }
}

class CustomAnimationDurationTabPage : public TabPage
{
public:
	CustomAnimationDurationTabPage( Window* pParent, const ResId& rResId, const STLPropertySet* pSet );
	~CustomAnimationDurationTabPage();

	void update( STLPropertySet* pSet );

	DECL_LINK( implControlHdl, Control* );

private:
	const STLPropertySet* mpSet;

	boost::shared_ptr< FixedText > mpFTStart;
	boost::shared_ptr< ListBox > mpLBStart;
	boost::shared_ptr< FixedText > mpFTStartDelay;
	boost::shared_ptr< MetricField > mpMFStartDelay;
	boost::shared_ptr< FixedText > mpFTDuration;
	boost::shared_ptr< ComboBox > mpCBDuration;
	boost::shared_ptr< FixedText > mpFTRepeat;
	boost::shared_ptr< ComboBox > mpCBRepeat;
	boost::shared_ptr< CheckBox > mpCBXRewind;
	boost::shared_ptr< FixedLine > mpFLTrigger;
	boost::shared_ptr< RadioButton > mpRBClickSequence;
	boost::shared_ptr< RadioButton > mpRBInteractive;
	boost::shared_ptr< ListBox > mpLBTrigger;
};

CustomAnimationDurationTabPage::CustomAnimationDurationTabPage(Window* pParent, const ResId& rResId, const STLPropertySet* pSet)
: TabPage( pParent, rResId ), mpSet( pSet )
{
	mpFTStart.reset( new FixedText( this, SdResId( FT_START ) ) );
	mpLBStart.reset( new ListBox( this, SdResId( LB_START ) ) );
	mpFTStartDelay.reset( new FixedText( this, SdResId( FT_START_DELAY ) ) );
	mpMFStartDelay.reset( new MetricField( this, SdResId( MF_START_DELAY ) ) );
	mpFTDuration.reset( new FixedText( this, SdResId( FT_DURATION ) ) );
	mpCBDuration.reset( new ComboBox( this, SdResId( CB_DURATION ) ) );
	mpFTRepeat.reset( new FixedText( this, SdResId( FT_REPEAT ) ) );
	mpCBRepeat.reset( new ComboBox( this, SdResId( CB_REPEAT ) ) );
	mpCBXRewind.reset( new CheckBox( this, SdResId( CBX_REWIND ) ) );
	mpFLTrigger.reset( new FixedLine( this, SdResId( FL_TRIGGER ) ) );
	mpRBClickSequence.reset( new RadioButton( this, SdResId( RB_CLICKSEQUENCE ) ) );
	mpRBInteractive.reset( new RadioButton( this, SdResId( RB_INTERACTIVE ) ) );
	mpLBTrigger.reset( new ListBox( this, SdResId( LB_TRIGGER ) ) );

	fillRepeatComboBox( mpCBRepeat.get() );
	fillDurationComboBox( mpCBDuration.get() );

	FreeResource();

    mpRBClickSequence->SetClickHdl( LINK( this, CustomAnimationDurationTabPage, implControlHdl ) );
    mpRBClickSequence->SetClickHdl( LINK( this, CustomAnimationDurationTabPage, implControlHdl ) );
    mpLBTrigger->SetSelectHdl( LINK( this, CustomAnimationDurationTabPage, implControlHdl ) );

	if( pSet->getPropertyState( nHandleStart ) != STLPropertyState_AMBIGUOUS )
	{
		sal_Int16 nStart = 0;
		pSet->getPropertyValue( nHandleStart ) >>= nStart;
		sal_uInt16 nPos = 0;
		switch( nStart )
		{
			case EffectNodeType::WITH_PREVIOUS:		nPos = 1; break;
			case EffectNodeType::AFTER_PREVIOUS:	nPos = 2; break;
		}
		mpLBStart->SelectEntryPos( nPos );
	}

	if( pSet->getPropertyState( nHandleBegin ) != STLPropertyState_AMBIGUOUS )
	{
		double fBegin = 0.0;
		pSet->getPropertyValue( nHandleBegin ) >>= fBegin;
		mpMFStartDelay->SetValue( (long)(fBegin*10) );
	}

	if( pSet->getPropertyState( nHandleDuration ) != STLPropertyState_AMBIGUOUS )
	{
		double fDuration = 0.0;
		pSet->getPropertyValue( nHandleDuration ) >>= fDuration;

		if( fDuration == 0.001 )
		{
			mpFTDuration->Disable();
			mpCBDuration->Disable();
			mpFTRepeat->Disable();
			mpCBRepeat->Disable();
			mpCBXRewind->Disable();
		}
		else
		{
			sal_uInt16 nPos = LISTBOX_ENTRY_NOTFOUND;

			if( fDuration == 5.0 )
				nPos = 0;
			else if( fDuration == 3.0 )
				nPos = 1;
			else if( fDuration == 2.0 )
				nPos = 2;
			else if( fDuration == 1.0 )
				nPos = 3;
			else if( fDuration == 0.5 )
				nPos = 4;

			if( nPos != LISTBOX_ENTRY_NOTFOUND )
				mpCBDuration->SelectEntryPos( nPos );
			else
				mpCBDuration->SetText( String::CreateFromDouble( fDuration ) );
		}
	}

	if( pSet->getPropertyState( nHandleRepeat ) != STLPropertyState_AMBIGUOUS )
	{
		Any aRepeatCount( pSet->getPropertyValue( nHandleRepeat ) );
		if( (aRepeatCount.getValueType() == ::getCppuType((const double*)0)) || !aRepeatCount.hasValue() )
		{
			double fRepeat = 0.0;
			if( aRepeatCount.hasValue() )
				aRepeatCount >>= fRepeat;

			sal_uInt16 nPos = LISTBOX_ENTRY_NOTFOUND;

			if( fRepeat == 0 )
				nPos = 0;
			else if( fRepeat == 2.0 )
				nPos = 1;
			else if( fRepeat == 3.0 )
				nPos = 2;
			else if( fRepeat == 4.0 )
				nPos = 3;
			else if( fRepeat == 5.0 )
				nPos = 4;
			else if( fRepeat == 10.0 )
				nPos = 5;

			if( nPos != LISTBOX_ENTRY_NOTFOUND )
				mpCBRepeat->SelectEntryPos( nPos );
			else
				mpCBRepeat->SetText( String::CreateFromDouble( fRepeat ) );
		}
		else if( aRepeatCount.getValueType() == ::getCppuType((const Timing*)0) )
		{
			Any aEnd;
			if( pSet->getPropertyState( nHandleEnd ) != STLPropertyState_AMBIGUOUS )
				aEnd = pSet->getPropertyValue( nHandleEnd );

			mpCBRepeat->SelectEntryPos( aEnd.hasValue() ? 6 : 7 );
		}
	}

	if( pSet->getPropertyState( nHandleRewind ) != STLPropertyState_AMBIGUOUS )
	{
		sal_Int16 nFill = 0;
		if( pSet->getPropertyValue( nHandleRewind ) >>= nFill )
		{
			mpCBXRewind->Check( (nFill == AnimationFill::REMOVE) ? sal_True : sal_False );
		}
		else
		{
			mpCBXRewind->SetState( STATE_DONTKNOW );
		}
	}

	Reference< XShape > xTrigger;

	if( pSet->getPropertyState( nHandleTrigger ) != STLPropertyState_AMBIGUOUS )
	{
		pSet->getPropertyValue( nHandleTrigger ) >>= xTrigger;

		mpRBInteractive->Check( xTrigger.is() );
		mpRBClickSequence->Check( !xTrigger.is() );
	}

	Reference< XDrawPage > xCurrentPage;
	pSet->getPropertyValue( nHandleCurrentPage ) >>= xCurrentPage;
	if( xCurrentPage.is() )
	{
		const OUString aStrIsEmptyPresObj( RTL_CONSTASCII_USTRINGPARAM( "IsEmptyPresentationObject" ) );

		sal_Int32 nShape, nCount = xCurrentPage->getCount();
		for( nShape = 0; nShape < nCount; nShape++ )
		{
			Reference< XShape > xShape( xCurrentPage->getByIndex( nShape ), UNO_QUERY );

			if( !xShape.is() )
				continue;

			Reference< XPropertySet > xSet( xShape, UNO_QUERY );
			if( xSet.is() && xSet->getPropertySetInfo()->hasPropertyByName( aStrIsEmptyPresObj ) )
			{
				sal_Bool bIsEmpty = sal_False;
				xSet->getPropertyValue( aStrIsEmptyPresObj ) >>= bIsEmpty;
				if( bIsEmpty )
					continue;
			}

			String aDescription( getShapeDescription( xShape, true ) );
			sal_uInt16 nPos = mpLBTrigger->InsertEntry( aDescription );

			mpLBTrigger->SetEntryData( nPos, (void*)nShape );
			if( xShape == xTrigger )
				mpLBTrigger->SelectEntryPos( nPos );
		}
	}
}

CustomAnimationDurationTabPage::~CustomAnimationDurationTabPage()
{
}

IMPL_LINK( CustomAnimationDurationTabPage, implControlHdl, Control*, pControl )
{
	if( pControl == mpLBTrigger.get() )
	{
		mpRBClickSequence->Check( sal_False );
		mpRBInteractive->Check( sal_True );
	}

	return 0;
}

void CustomAnimationDurationTabPage::update( STLPropertySet* pSet )
{
	sal_uInt16 nPos = mpLBStart->GetSelectEntryPos();
	if( nPos != LISTBOX_ENTRY_NOTFOUND )
	{
		sal_Int16 nStart;
		sal_Int16 nOldStart = -1;

		switch( nPos )
		{
		case 1: nStart = EffectNodeType::WITH_PREVIOUS; break;
		case 2: nStart = EffectNodeType::AFTER_PREVIOUS; break;
		default:
			nStart = EffectNodeType::ON_CLICK; break;
		}

		if(mpSet->getPropertyState( nHandleStart ) != STLPropertyState_AMBIGUOUS)
			mpSet->getPropertyValue( nHandleStart ) >>= nOldStart;

		if( nStart != nOldStart )
			pSet->setPropertyValue( nHandleStart, makeAny( nStart ) );
	}

	// ---

	{
		double fBegin = static_cast<double>( mpMFStartDelay->GetValue()) / 10.0;
		double fOldBegin = -1.0;

		if( mpSet->getPropertyState( nHandleBegin ) != STLPropertyState_AMBIGUOUS )
			mpSet->getPropertyValue( nHandleBegin ) >>= fOldBegin;

		if( fBegin != fOldBegin )
			pSet->setPropertyValue( nHandleBegin, makeAny( fBegin ) );
	}

	// ---

	nPos = mpCBRepeat->GetSelectEntryPos();
	if( (nPos != LISTBOX_ENTRY_NOTFOUND) || (mpCBRepeat->GetText().Len() != 0) )
	{
		Any aRepeatCount;
		Any aEnd;

		switch( nPos )
		{
		case 0:
			break;
		case 6:
			{
				Event aEvent;
				aEvent.Trigger = EventTrigger::ON_NEXT;
				aEvent.Repeat = 0;
				aEnd <<= aEvent;
			}
			// ATTENTION: FALL THROUGH INTENDED!
		case 7:
			aRepeatCount <<= Timing_INDEFINITE;
			break;
		default:
			{
				String aText( mpCBRepeat->GetText() );
				if( aText.Len() )
					aRepeatCount <<= aText.ToDouble();
			}
		}

		Any aOldRepeatCount( aRepeatCount );
		if( mpSet->getPropertyState( nHandleRepeat ) != STLPropertyState_AMBIGUOUS )
			aOldRepeatCount = mpSet->getPropertyValue( nHandleRepeat );

		if( aRepeatCount != aOldRepeatCount )
			pSet->setPropertyValue( nHandleRepeat, aRepeatCount );

		Any aOldEnd( aEnd );
		if( mpSet->getPropertyState( nHandleEnd ) != STLPropertyState_AMBIGUOUS )
			aOldEnd = mpSet->getPropertyValue( nHandleEnd );

		if( aEnd != aOldEnd )
			pSet->setPropertyValue( nHandleEnd, aEnd );
	}

	// ---

	double fDuration = -1.0;
	nPos = mpCBDuration->GetSelectEntryPos();
	if( nPos != LISTBOX_ENTRY_NOTFOUND )
	{
		fDuration = *static_cast< const double * >( mpCBDuration->GetEntryData(nPos) );
	}
	else
	{
		String aText( mpCBDuration->GetText() );
		if( aText.Len() )
		{
			fDuration = aText.ToDouble();
		}
	}

	if( fDuration != -1.0 )
	{
		double fOldDuration = -1;

		if( mpSet->getPropertyState( nHandleDuration ) != STLPropertyState_AMBIGUOUS )
			mpSet->getPropertyValue( nHandleDuration ) >>= fOldDuration;

		if( fDuration != fOldDuration )
			pSet->setPropertyValue( nHandleDuration, makeAny( fDuration ) );
	}

	// ---

	if( mpCBXRewind->GetState() != STATE_DONTKNOW )
	{
		sal_Int16 nFill = mpCBXRewind->IsChecked() ? AnimationFill::REMOVE : AnimationFill::HOLD;

		bool bSet = true;

		if( mpSet->getPropertyState( nHandleRewind ) != STLPropertyState_AMBIGUOUS )
		{
			sal_Int16 nOldFill = 0;
			mpSet->getPropertyValue( nHandleRewind ) >>= nOldFill;
			bSet = nFill != nOldFill;
		}

		if( bSet )
			pSet->setPropertyValue( nHandleRewind, makeAny( nFill ) );
	}

	Reference< XShape > xTrigger;

	if( mpRBInteractive->IsChecked() )
	{
		nPos = mpLBTrigger->GetSelectEntryPos();
		if( nPos != LISTBOX_ENTRY_NOTFOUND )
		{
			sal_Int32 nShape = (sal_Int32)(sal_IntPtr)mpLBTrigger->GetEntryData( nPos );

			Reference< XDrawPage > xCurrentPage;
			mpSet->getPropertyValue( nHandleCurrentPage ) >>= xCurrentPage;

			if( xCurrentPage.is() && (nShape >= 0) && (nShape < xCurrentPage->getCount()) )
				xCurrentPage->getByIndex( nShape ) >>= xTrigger;
		}
	}


	if( xTrigger.is() || mpRBClickSequence->IsChecked() )
	{
		Any aNewValue( makeAny( xTrigger ) );
		Any aOldValue;

		if( mpSet->getPropertyState( nHandleTrigger ) != STLPropertyState_AMBIGUOUS )
			aOldValue = mpSet->getPropertyValue( nHandleTrigger );

		if( aNewValue != aOldValue )
			pSet->setPropertyValue( nHandleTrigger, aNewValue );
	}
}

class CustomAnimationTextAnimTabPage : public TabPage
{
public:
	CustomAnimationTextAnimTabPage( Window* pParent, const ResId& rResId, const STLPropertySet* pSet );

	void update( STLPropertySet* pSet );

	void updateControlStates();
	DECL_LINK( implSelectHdl, Control* );

private:
	FixedText	maFTGroupText;
	ListBox		maLBGroupText;
	CheckBox	maCBXGroupAuto;
	MetricField	maMFGroupAuto;
	CheckBox	maCBXAnimateForm;
	CheckBox	maCBXReverse;

	const STLPropertySet* mpSet;

	bool mbHasVisibleShapes;
};

CustomAnimationTextAnimTabPage::CustomAnimationTextAnimTabPage(Window* pParent, const ResId& rResId, const STLPropertySet* pSet)
:	TabPage( pParent, rResId ),
	maFTGroupText( this, SdResId( FT_GROUP_TEXT ) ),
	maLBGroupText( this, SdResId( LB_GROUP_TEXT ) ),
	maCBXGroupAuto( this, SdResId( CBX_GROUP_AUTO ) ),
	maMFGroupAuto( this, SdResId( MF_GROUP_AUTO ) ),
	maCBXAnimateForm( this, SdResId( CBX_ANIMATE_FORM ) ),
	maCBXReverse( this, SdResId( CBX_REVERSE ) ),
	mpSet( pSet ),
	mbHasVisibleShapes(true)
{
	FreeResource();

	maLBGroupText.SetSelectHdl( LINK( this, CustomAnimationTextAnimTabPage, implSelectHdl ) );

	if( pSet->getPropertyState( nHandleTextGrouping ) != STLPropertyState_AMBIGUOUS )
	{
		sal_Int32 nTextGrouping = 0;
		if( pSet->getPropertyValue( nHandleTextGrouping ) >>= nTextGrouping )
			maLBGroupText.SelectEntryPos( (sal_uInt16)(nTextGrouping + 1) );
	}

	if( pSet->getPropertyState( nHandleHasVisibleShape ) != STLPropertyState_AMBIGUOUS )
		pSet->getPropertyValue( nHandleHasVisibleShape ) >>= mbHasVisibleShapes;

	if( pSet->getPropertyState( nHandleTextGroupingAuto ) != STLPropertyState_AMBIGUOUS )
	{
		double fTextGroupingAuto = 0.0;
		if( pSet->getPropertyValue( nHandleTextGroupingAuto ) >>= fTextGroupingAuto )
		{
			maCBXGroupAuto.Check( fTextGroupingAuto >= 0.0 );
			if( fTextGroupingAuto >= 0.0 )
				maMFGroupAuto.SetValue( (long)(fTextGroupingAuto*10) );
		}
	}
	else
	{
		maCBXGroupAuto.SetState( STATE_DONTKNOW );
	}

	maCBXAnimateForm.SetState( STATE_DONTKNOW );
	if( pSet->getPropertyState( nHandleAnimateForm ) != STLPropertyState_AMBIGUOUS )
	{
		sal_Bool bAnimateForm = sal_False;
		if( pSet->getPropertyValue( nHandleAnimateForm ) >>= bAnimateForm )
		{
			maCBXAnimateForm.Check( bAnimateForm );
		}
	}
	else
	{
		maCBXAnimateForm.Enable( sal_False );
	}

	maCBXReverse.SetState( STATE_DONTKNOW );
	if( pSet->getPropertyState( nHandleTextReverse ) != STLPropertyState_AMBIGUOUS )
	{
		sal_Bool bTextReverse = sal_False;
		if( pSet->getPropertyValue( nHandleTextReverse ) >>= bTextReverse )
		{
			maCBXReverse.Check( bTextReverse );
		}
	}

	if( pSet->getPropertyState( nHandleMaxParaDepth ) == STLPropertyState_DIRECT )
	{
		sal_Int32 nMaxParaDepth = 0;
		pSet->getPropertyValue( nHandleMaxParaDepth ) >>= nMaxParaDepth;
		nMaxParaDepth += 1;

		sal_Int32 nPos = 6;
		while( (nPos > 2) && (nPos > nMaxParaDepth) )
		{
			maLBGroupText.RemoveEntry( (sal_uInt16)nPos );
			nPos--;
		}
	}

	updateControlStates();
}

void CustomAnimationTextAnimTabPage::update( STLPropertySet* pSet )
{
	sal_uInt16 nPos = maLBGroupText.GetSelectEntryPos();
	if( nPos != LISTBOX_ENTRY_NOTFOUND )
	{
		sal_Int32 nTextGrouping = nPos - 1;
		sal_Int32 nOldGrouping = -2;

		if(mpSet->getPropertyState( nHandleTextGrouping ) != STLPropertyState_AMBIGUOUS)
			mpSet->getPropertyValue( nHandleTextGrouping ) >>= nOldGrouping;

		if( nTextGrouping != nOldGrouping )
			pSet->setPropertyValue( nHandleTextGrouping, makeAny( nTextGrouping ) );
	}

	if( nPos > 0 )
	{
		sal_Bool bTextReverse = maCBXReverse.IsChecked();
		sal_Bool bOldTextReverse = !bTextReverse;

		if(mpSet->getPropertyState( nHandleTextReverse ) != STLPropertyState_AMBIGUOUS)
			mpSet->getPropertyValue( nHandleTextReverse ) >>= bOldTextReverse;

		if( bTextReverse != bOldTextReverse )
			pSet->setPropertyValue( nHandleTextReverse, makeAny( bTextReverse ) );

		if( nPos > 1 )
		{
			double fTextGroupingAuto = maCBXGroupAuto.IsChecked() ? maMFGroupAuto.GetValue() / 10.0 : -1.0;
			double fOldTextGroupingAuto = -2.0;

			if(mpSet->getPropertyState( nHandleTextGroupingAuto ) != STLPropertyState_AMBIGUOUS)
				mpSet->getPropertyValue( nHandleTextGroupingAuto ) >>= fOldTextGroupingAuto;

			if( fTextGroupingAuto != fOldTextGroupingAuto )
				pSet->setPropertyValue( nHandleTextGroupingAuto, makeAny( fTextGroupingAuto ) );
		}
	}
	//bug 120049
	//[crash] Aoo crash when modify the "Random effects" animation effect's trigger condition to "Start effect on click of" .
	//If this control is disabled, we should ignore its value
	if (maCBXAnimateForm.IsEnabled())
	{
		sal_Bool bAnimateForm = maCBXAnimateForm.IsChecked();
		sal_Bool bOldAnimateForm = !bAnimateForm;

		if(mpSet->getPropertyState( nHandleAnimateForm ) != STLPropertyState_AMBIGUOUS)
			mpSet->getPropertyValue( nHandleAnimateForm ) >>= bOldAnimateForm;

		if( bAnimateForm != bOldAnimateForm )
			pSet->setPropertyValue( nHandleAnimateForm, makeAny( bAnimateForm ) );
	}
}

void CustomAnimationTextAnimTabPage::updateControlStates()
{
	sal_uInt16 nPos = maLBGroupText.GetSelectEntryPos();

	maCBXGroupAuto.Enable( nPos > 1 );
	maMFGroupAuto.Enable( nPos > 1 );
	maCBXReverse.Enable( nPos > 0 );

	if( !mbHasVisibleShapes && nPos > 0 )
	{
		maCBXAnimateForm.Check(sal_False);
		maCBXAnimateForm.Enable(sal_False);
	}
	else
	{
		maCBXAnimateForm.Enable(sal_True);
	}
}

IMPL_LINK( CustomAnimationTextAnimTabPage, implSelectHdl, Control*, EMPTYARG )
{
	updateControlStates();
	return 0;
}

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

CustomAnimationDialog::CustomAnimationDialog( Window* pParent, STLPropertySet* pSet, sal_uInt16 nPage /* = 0 */  )
: TabDialog( pParent, SdResId( DLG_CUSTOMANIMATION ) ), mpSet( pSet ), mpResultSet( 0 )
{
	mpTabControl = new TabControl( this, SdResId( 1 ) );
	mpOKButton = new OKButton(this, SdResId( 1 ) ) ;
	mpCancelButton = new CancelButton(this, SdResId( 1 ) );
	mpHelpButton = new HelpButton(this, SdResId( 1 ) );

	FreeResource();

	mpEffectTabPage = new CustomAnimationEffectTabPage( mpTabControl, SdResId( RID_TP_CUSTOMANIMATION_EFFECT ), mpSet );
	mpTabControl->SetTabPage( RID_TP_CUSTOMANIMATION_EFFECT, mpEffectTabPage );
	mpDurationTabPage = new CustomAnimationDurationTabPage( mpTabControl, SdResId( RID_TP_CUSTOMANIMATION_DURATION ), mpSet );
	mpTabControl->SetTabPage( RID_TP_CUSTOMANIMATION_DURATION, mpDurationTabPage );

	sal_Bool bHasText = sal_False;
	if( pSet->getPropertyState( nHandleHasText ) != STLPropertyState_AMBIGUOUS )
		pSet->getPropertyValue( nHandleHasText ) >>= bHasText;

	if( bHasText )
	{
		mpTextAnimTabPage = new CustomAnimationTextAnimTabPage( mpTabControl, SdResId( RID_TP_CUSTOMANIMATION_TEXT ), mpSet );
		mpTabControl->SetTabPage( RID_TP_CUSTOMANIMATION_TEXT, mpTextAnimTabPage );
	}
	else
	{
		mpTextAnimTabPage = 0;
		mpTabControl->RemovePage( RID_TP_CUSTOMANIMATION_TEXT );
	}

	if( nPage )
		mpTabControl->SelectTabPage( nPage );
}

CustomAnimationDialog::~CustomAnimationDialog()
{
	delete mpEffectTabPage;
	delete mpDurationTabPage;
	delete mpTextAnimTabPage;

	delete mpTabControl;
	delete mpOKButton;
	delete mpCancelButton;
	delete mpHelpButton;

	delete mpSet;
	delete mpResultSet;
}

STLPropertySet* CustomAnimationDialog::getResultSet()
{
	if( mpResultSet )
		delete mpResultSet;

	mpResultSet = createDefaultSet();

	mpEffectTabPage->update( mpResultSet );
	mpDurationTabPage->update( mpResultSet );
	if( mpTextAnimTabPage )
		mpTextAnimTabPage->update( mpResultSet );

	return mpResultSet;
}

STLPropertySet* CustomAnimationDialog::createDefaultSet()
{
	Any aEmpty;

	STLPropertySet* pSet = new STLPropertySet();
	pSet->setPropertyDefaultValue( nHandleMaxParaDepth, makeAny( (sal_Int32)-1 ) );

	pSet->setPropertyDefaultValue( nHandleHasAfterEffect, makeAny( (sal_Bool)sal_False ) );
	pSet->setPropertyDefaultValue( nHandleAfterEffectOnNextEffect, makeAny( (sal_Bool)sal_False ) );
	pSet->setPropertyDefaultValue( nHandleDimColor, aEmpty );
	pSet->setPropertyDefaultValue( nHandleIterateType, makeAny( (sal_Int16)0 ) );
	pSet->setPropertyDefaultValue( nHandleIterateInterval, makeAny( (double)0.0 ) );

	pSet->setPropertyDefaultValue( nHandleStart, makeAny( (sal_Int16)EffectNodeType::ON_CLICK ) );
	pSet->setPropertyDefaultValue( nHandleBegin, makeAny( (double)0.0 ) );
	pSet->setPropertyDefaultValue( nHandleDuration, makeAny( (double)2.0 ) );
	pSet->setPropertyDefaultValue( nHandleRepeat, aEmpty );
	pSet->setPropertyDefaultValue( nHandleRewind, makeAny( AnimationFill::HOLD ) );

	pSet->setPropertyDefaultValue( nHandleEnd, aEmpty );

	pSet->setPropertyDefaultValue( nHandlePresetId, aEmpty );
	pSet->setPropertyDefaultValue( nHandleProperty1Type, makeAny( nPropertyTypeNone ) );
	pSet->setPropertyDefaultValue( nHandleProperty1Value, aEmpty );
	pSet->setPropertyDefaultValue( nHandleProperty2Type, makeAny( nPropertyTypeNone ) );
	pSet->setPropertyDefaultValue( nHandleProperty2Value, aEmpty );
	pSet->setPropertyDefaultValue( nHandleAccelerate, aEmpty );
	pSet->setPropertyDefaultValue( nHandleDecelerate, aEmpty );
	pSet->setPropertyDefaultValue( nHandleAutoReverse, aEmpty );
	pSet->setPropertyDefaultValue( nHandleTrigger, aEmpty );

	pSet->setPropertyDefaultValue( nHandleHasText, makeAny( sal_False ) );
	pSet->setPropertyDefaultValue( nHandleHasVisibleShape, makeAny( sal_False ) );
	pSet->setPropertyDefaultValue( nHandleTextGrouping, makeAny( (sal_Int32)-1 ) );
	pSet->setPropertyDefaultValue( nHandleAnimateForm, makeAny( sal_True ) );
	pSet->setPropertyDefaultValue( nHandleTextGroupingAuto, makeAny( (double)-1.0 ) );
	pSet->setPropertyDefaultValue( nHandleTextReverse, makeAny( sal_False ) );

	pSet->setPropertyDefaultValue( nHandleCurrentPage, aEmpty );

	pSet->setPropertyDefaultValue( nHandleSoundURL, aEmpty );
	pSet->setPropertyDefaultValue( nHandleSoundVolumne, makeAny( (double)1.0) );
	pSet->setPropertyDefaultValue( nHandleSoundEndAfterSlide, makeAny( (sal_Int32)0 ) );

	pSet->setPropertyDefaultValue( nHandleCommand, makeAny( (sal_Int16)0 ) );
	return pSet;
}

PropertyControl::PropertyControl( Window* pParent, const ResId& rResId )
: ListBox( pParent, rResId ), mpSubControl(0)
{
}

PropertyControl::~PropertyControl()
{
	if( mpSubControl )
		delete mpSubControl;
}

void PropertyControl::setSubControl( PropertySubControl* pSubControl )
{
	if( mpSubControl && mpSubControl != pSubControl )
		delete mpSubControl;

	mpSubControl = pSubControl;

	Control* pControl = pSubControl ? pSubControl->getControl() : 0;

	if( pControl )
	{
		pControl->SetPosSizePixel( GetPosPixel(), GetSizePixel() );
		pControl->SetZOrder( this, WINDOW_ZORDER_BEFOR );
		pControl->Show();
		Hide();
	}
	else
	{
		Show();
	}
}

void PropertyControl::Resize()
{
	Control* pControl = mpSubControl ? mpSubControl->getControl() : 0;
	if( pControl )
		pControl->SetPosSizePixel( GetPosPixel(), GetSizePixel() );
	ListBox::Resize();
}

// ====================================================================

PropertySubControl::~PropertySubControl()
{
}

PropertySubControl* PropertySubControl::create( sal_Int32 nType, Window* pParent, const Any& rValue, const OUString& rPresetId, const Link& rModifyHdl )
{
	PropertySubControl* pSubControl = NULL;
	switch( nType )
	{
	case nPropertyTypeDirection:
	case nPropertyTypeSpokes:
	case nPropertyTypeZoom:
		pSubControl = new PresetPropertyBox( nType, pParent, rValue, rPresetId, rModifyHdl );
		break;

	case nPropertyTypeColor:
	case nPropertyTypeFillColor:
	case nPropertyTypeFirstColor:
	case nPropertyTypeCharColor:
	case nPropertyTypeLineColor:
		pSubControl = new ColorPropertyBox( nType, pParent, rValue, rModifyHdl );
		break;

	case nPropertyTypeFont:
		pSubControl = new FontPropertyBox( nType, pParent, rValue, rModifyHdl );
		break;

	case nPropertyTypeCharHeight:
		pSubControl = new CharHeightPropertyBox( nType, pParent, rValue, rModifyHdl );
		break;

	case nPropertyTypeRotate:
		pSubControl = new RotationPropertyBox( nType, pParent, rValue, rModifyHdl );
		break;

	case nPropertyTypeTransparency:
		pSubControl = new TransparencyPropertyBox( nType, pParent, rValue, rModifyHdl );
		break;

	case nPropertyTypeScale:
		pSubControl = new ScalePropertyBox( nType, pParent, rValue, rModifyHdl );
		break;

	case nPropertyTypeCharDecoration:
		pSubControl = new FontStylePropertyBox( nType, pParent, rValue, rModifyHdl );
		break;
	}

	return pSubControl;
}

}
