1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sd.hxx"
26 
27 #include <com/sun/star/presentation/EffectPresetClass.hpp>
28 #include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
29 #include <com/sun/star/view/XSelectionSupplier.hpp>
30 #include <com/sun/star/drawing/XDrawView.hpp>
31 #include <com/sun/star/drawing/XShape.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/presentation/EffectNodeType.hpp>
34 #include <com/sun/star/presentation/EffectCommands.hpp>
35 #include <com/sun/star/animations/AnimationTransformType.hpp>
36 #include <com/sun/star/text/XTextRangeCompare.hpp>
37 #include <com/sun/star/container/XEnumerationAccess.hpp>
38 #include <com/sun/star/container/XIndexAccess.hpp>
39 #include <com/sun/star/presentation/ParagraphTarget.hpp>
40 #include <com/sun/star/text/XText.hpp>
41 #include <com/sun/star/awt/XWindow.hpp>
42 #include <com/sun/star/drawing/LineStyle.hpp>
43 #include <com/sun/star/drawing/FillStyle.hpp>
44 #include <comphelper/processfactory.hxx>
45 #include <sfx2/dispatch.hxx>
46 #include "STLPropertySet.hxx"
47 #include "CustomAnimationPane.hxx"
48 #include "CustomAnimationDialog.hxx"
49 #include "CustomAnimationCreateDialog.hxx"
50 #include "CustomAnimationPane.hrc"
51 #include "CustomAnimation.hrc"
52 #include "CustomAnimationList.hxx"
53 #include <vcl/lstbox.hxx>
54 #include <vcl/fixed.hxx>
55 
56 #include <vcl/button.hxx>
57 #include <vcl/combobox.hxx>
58 #include <vcl/scrbar.hxx>
59 
60 #include <comphelper/sequence.hxx>
61 #include <sfx2/frame.hxx>
62 
63 #include <svx/unoapi.hxx>
64 #include <svx/svxids.hrc>
65 #include <DrawDocShell.hxx>
66 #include <ViewShellBase.hxx>
67 #include "DrawViewShell.hxx"
68 #include "DrawController.hxx"
69 #include "sdresid.hxx"
70 #include "drawview.hxx"
71 #include "slideshow.hxx"
72 #include "undoanim.hxx"
73 #include "optsitem.hxx"
74 #include "sddll.hxx"
75 #include "framework/FrameworkHelper.hxx"
76 
77 #include "EventMultiplexer.hxx"
78 #include "DialogListBox.hxx"
79 
80 #include "glob.hrc"
81 #include "sdpage.hxx"
82 #include "drawdoc.hxx"
83 #include "app.hrc"
84 
85 #include <memory>
86 #include <algorithm>
87 
88 #include <basegfx/polygon/b2dpolypolygontools.hxx>
89 #include <basegfx/matrix/b2dhommatrix.hxx>
90 #include <basegfx/range/b2drange.hxx>
91 
92 using namespace ::com::sun::star;
93 using namespace ::com::sun::star::animations;
94 using namespace ::com::sun::star::presentation;
95 using namespace ::com::sun::star::text;
96 
97 using ::rtl::OUString;
98 using namespace ::com::sun::star::uno;
99 using namespace ::com::sun::star::drawing;
100 using ::com::sun::star::view::XSelectionSupplier;
101 using ::com::sun::star::view::XSelectionChangeListener;
102 using ::com::sun::star::frame::XController;
103 using ::com::sun::star::frame::XModel;
104 using ::com::sun::star::beans::XPropertySet;
105 using ::com::sun::star::beans::XPropertyChangeListener;
106 using ::com::sun::star::container::XIndexAccess;
107 using ::com::sun::star::container::XEnumerationAccess;
108 using ::com::sun::star::container::XEnumeration;
109 using ::com::sun::star::text::XText;
110 using ::sd::framework::FrameworkHelper;
111 
112 namespace sd {
113 
114 // --------------------------------------------------------------------
115 
116 void fillDurationComboBox( ComboBox* pBox )
117 {
118 	static const double gdVerySlow = 5.0;
119 	static const double gdSlow = 3.0;
120 	static const double gdNormal = 2.0;
121 	static const double gdFast = 1.0;
122 	static const double gdVeryFast = 0.5;
123 
124 	String aVerySlow( SdResId( STR_CUSTOMANIMATION_DURATION_VERY_SLOW ) );
125 	pBox->SetEntryData( pBox->InsertEntry( aVerySlow ), (void*)&gdVerySlow );
126 
127 	String aSlow( SdResId( STR_CUSTOMANIMATION_DURATION_SLOW ) );
128 	pBox->SetEntryData( pBox->InsertEntry( aSlow ), (void*)&gdSlow );
129 
130 	String aNormal( SdResId( STR_CUSTOMANIMATION_DURATION_NORMAL ) );
131 	pBox->SetEntryData( pBox->InsertEntry( aNormal ), (void*)&gdNormal );
132 
133 	String aFast( SdResId( STR_CUSTOMANIMATION_DURATION_FAST ) );
134 	pBox->SetEntryData( pBox->InsertEntry( aFast ), (void*)&gdFast );
135 
136 	String aVeryFast( SdResId( STR_CUSTOMANIMATION_DURATION_VERY_FAST ) );
137 	pBox->SetEntryData( pBox->InsertEntry( aVeryFast ), (void*)&gdVeryFast );
138 }
139 
140 void fillRepeatComboBox( ComboBox* pBox )
141 {
142 	String aNone( SdResId( STR_CUSTOMANIMATION_REPEAT_NONE ) );
143 	pBox->SetEntryData( pBox->InsertEntry( aNone ), (void*)((sal_Int32)0) );
144 
145 	pBox->SetEntryData( pBox->InsertEntry( String::CreateFromInt32( 2 ) ), (void*)((sal_Int32)1) );
146 	pBox->SetEntryData( pBox->InsertEntry( String::CreateFromInt32( 3 ) ), (void*)((sal_Int32)3) );
147 	pBox->SetEntryData( pBox->InsertEntry( String::CreateFromInt32( 4 ) ), (void*)((sal_Int32)4) );
148 	pBox->SetEntryData( pBox->InsertEntry( String::CreateFromInt32( 5 ) ), (void*)((sal_Int32)5) );
149 	pBox->SetEntryData( pBox->InsertEntry( String::CreateFromInt32( 10 ) ), (void*)((sal_Int32)10) );
150 
151 	String aUntilClick( SdResId( STR_CUSTOMANIMATION_REPEAT_UNTIL_NEXT_CLICK ) );
152 	pBox->SetEntryData( pBox->InsertEntry( aUntilClick ), (void*)((sal_Int32)-1) );
153 
154 	String aEndOfSlide( SdResId( STR_CUSTOMANIMATION_REPEAT_UNTIL_END_OF_SLIDE ) );
155 	pBox->SetEntryData( pBox->InsertEntry( aEndOfSlide ), (void*)((sal_Int32)-2) );
156 }
157 
158 // --------------------------------------------------------------------
159 
160 CustomAnimationPane::CustomAnimationPane( ::Window* pParent, ViewShellBase& rBase, const Size& rMinSize )
161 :	Control( pParent, SdResId(DLG_CUSTOMANIMATIONPANE) ),
162 	mrBase( rBase ),
163 	mpCustomAnimationPresets(NULL),
164 	mnPropertyType( nPropertyTypeNone ),
165 	maMinSize( rMinSize ),
166 	mxModel( rBase.GetDocShell()->GetDoc()->getUnoModel(), UNO_QUERY ),
167 	maLateInitTimer()
168 {
169 	// load resources
170 	mpFLEffect = new FixedLine( this, SdResId( FL_EFFECT ) );
171 
172 	mpPBAddEffect = new PushButton( this, SdResId( PB_ADD_EFFECT ) );
173 	mpPBChangeEffect = new PushButton( this, SdResId( PB_CHANGE_EFFECT ) );
174 	mpPBRemoveEffect = new PushButton( this, SdResId( PB_REMOVE_EFFECT ) );
175 
176 	mpFLModify = new FixedLine( this, SdResId( FL_MODIFY ) );
177 
178 	mpFTStart = new FixedText( this, SdResId( FT_START ) );
179 	mpLBStart = new ListBox( this, SdResId( LB_START ) );
180 	mpFTProperty = new FixedText( this, SdResId( FT_PROPERTY ) );
181 	mpLBProperty = new PropertyControl( this, SdResId( LB_PROPERTY ) );
182 	mpPBPropertyMore = new PushButton( this, SdResId( PB_PROPERTY_MORE ) );
183 
184 	mpFTSpeed = new FixedText( this, SdResId( FT_SPEED ) );
185 	mpCBSpeed = new ComboBox( this, SdResId( CB_SPEED ) );
186 
187 	mpCustomAnimationList = new CustomAnimationList( this, SdResId( CT_CUSTOM_ANIMATION_LIST ), this );
188 
189 	mpPBMoveUp = new PushButton( this, SdResId( PB_MOVE_UP ) );
190 	mpPBMoveDown = new PushButton( this, SdResId( PB_MOVE_DOWN ) );
191 	mpFTChangeOrder = new FixedText( this, SdResId( FT_CHANGE_ORDER ) );
192 	mpFLSeperator1 = new FixedLine( this, SdResId( FL_SEPERATOR1 ) );
193 	mpPBPlay = new PushButton( this, SdResId( PB_PLAY ) );
194 	mpPBSlideShow = new PushButton( this, SdResId( PB_SLIDE_SHOW ) );
195 	mpFLSeperator2 = new FixedLine( this, SdResId( FL_SEPERATOR2 ) );
196 	mpCBAutoPreview = new CheckBox( this, SdResId( CB_AUTOPREVIEW ) );
197 
198 	maStrProperty = mpFTProperty->GetText();
199 
200 	FreeResource();
201 
202     // use bold font for group headings (same font for all fixed lines):
203     Font font( mpFLEffect->GetFont() );
204     font.SetWeight( WEIGHT_BOLD );
205     mpFLEffect->SetFont( font );
206     mpFLModify->SetFont( font );
207 
208 	fillDurationComboBox( mpCBSpeed );
209 	mpPBMoveUp->SetSymbol( SYMBOL_ARROW_UP );
210 	mpPBMoveDown->SetSymbol( SYMBOL_ARROW_DOWN );
211 
212 	mpPBAddEffect->SetClickHdl( LINK( this, CustomAnimationPane, implControlHdl ) );
213 	mpPBChangeEffect->SetClickHdl( LINK( this, CustomAnimationPane, implControlHdl ) );
214 	mpPBRemoveEffect->SetClickHdl( LINK( this, CustomAnimationPane, implControlHdl ) );
215 	mpLBStart->SetSelectHdl( LINK( this, CustomAnimationPane, implControlHdl ) );
216 	mpCBSpeed->SetSelectHdl( LINK( this, CustomAnimationPane, implControlHdl ) );
217 	mpPBPropertyMore->SetClickHdl( LINK( this, CustomAnimationPane, implControlHdl ) );
218 	mpPBMoveUp->SetClickHdl( LINK( this, CustomAnimationPane, implControlHdl ) );
219 	mpPBMoveDown->SetClickHdl( LINK( this, CustomAnimationPane, implControlHdl ) );
220 	mpPBPlay->SetClickHdl( LINK( this, CustomAnimationPane, implControlHdl ) );
221 	mpPBSlideShow->SetClickHdl( LINK( this, CustomAnimationPane, implControlHdl ) );
222 	mpCBAutoPreview->SetClickHdl( LINK( this, CustomAnimationPane, implControlHdl ) );
223 
224 	maStrModify = mpFLEffect->GetText();
225 
226 	// resize controls according to current size
227 	updateLayout();
228 
229 	// get current controller and initialize listeners
230 	try
231 	{
232 		mxView = Reference< XDrawView >::query(mrBase.GetController());
233 		addListener();
234 	}
235 	catch( Exception& e )
236 	{
237 		(void)e;
238 		DBG_ERROR( "sd::CustomAnimationPane::CustomAnimationPane(), Exception cought!" );
239 	}
240 
241 	// get current page and update custom animation list
242 	onChangeCurrentPage();
243 
244     // Wait a short time before the presets list is created.  This gives the
245     // system time to paint the control.
246     maLateInitTimer.SetTimeout(100);
247     maLateInitTimer.SetTimeoutHdl(LINK(this, CustomAnimationPane, lateInitCallback));
248     maLateInitTimer.Start();
249 }
250 
251 CustomAnimationPane::~CustomAnimationPane()
252 {
253     maLateInitTimer.Stop();
254 
255 	removeListener();
256 
257 	MotionPathTagVector aTags;
258 	aTags.swap( maMotionPathTags );
259 	MotionPathTagVector::iterator aIter;
260 	for( aIter = aTags.begin(); aIter != aTags.end(); aIter++ )
261 		(*aIter)->Dispose();
262 
263 	delete mpFLModify;
264 	delete mpPBAddEffect;
265 	delete mpPBChangeEffect;
266 	delete mpPBRemoveEffect;
267 	delete mpFLEffect;
268 	delete mpFTStart;
269 	delete mpLBStart;
270 	delete mpFTProperty;
271 	delete mpLBProperty;
272 	delete mpPBPropertyMore;
273 	delete mpFTSpeed;
274 	delete mpCBSpeed;
275 	delete mpCustomAnimationList;
276 	delete mpFTChangeOrder;
277 	delete mpPBMoveUp;
278 	delete mpPBMoveDown;
279 	delete mpFLSeperator1;
280 	delete mpPBPlay;
281 	delete mpPBSlideShow;
282 	delete mpFLSeperator2;
283 	delete mpCBAutoPreview;
284 }
285 
286 void CustomAnimationPane::addUndo()
287 {
288 	::svl::IUndoManager* pManager = mrBase.GetDocShell()->GetUndoManager();
289 	if( pManager )
290 	{
291 		SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
292 		if( pPage )
293 			pManager->AddUndoAction( new UndoAnimation( mrBase.GetDocShell()->GetDoc(), pPage ) );
294 	}
295 }
296 
297 void CustomAnimationPane::Resize()
298 {
299 	updateLayout();
300 }
301 
302 void CustomAnimationPane::StateChanged( StateChangedType nStateChange )
303 {
304 	Control::StateChanged( nStateChange );
305 
306 	if( nStateChange == STATE_CHANGE_VISIBLE )
307 		updateMotionPathTags();
308 }
309 
310 void CustomAnimationPane::KeyInput( const KeyEvent& rKEvt )
311 {
312 	if( mpCustomAnimationList )
313 		mpCustomAnimationList->KeyInput( rKEvt );
314 }
315 
316 void CustomAnimationPane::addListener()
317 {
318 	Link aLink( LINK(this,CustomAnimationPane,EventMultiplexerListener) );
319     mrBase.GetEventMultiplexer()->AddEventListener (
320         aLink,
321         tools::EventMultiplexerEvent::EID_EDIT_VIEW_SELECTION
322         | tools::EventMultiplexerEvent::EID_CURRENT_PAGE
323         | tools::EventMultiplexerEvent::EID_MAIN_VIEW_REMOVED
324         | tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED
325         | tools::EventMultiplexerEvent::EID_DISPOSING
326         | tools::EventMultiplexerEvent::EID_END_TEXT_EDIT);
327 }
328 
329 void CustomAnimationPane::removeListener()
330 {
331 	Link aLink( LINK(this,CustomAnimationPane,EventMultiplexerListener) );
332     mrBase.GetEventMultiplexer()->RemoveEventListener( aLink );
333 }
334 
335 IMPL_LINK(CustomAnimationPane,EventMultiplexerListener,
336     tools::EventMultiplexerEvent*,pEvent)
337 {
338     switch (pEvent->meEventId)
339     {
340         case tools::EventMultiplexerEvent::EID_EDIT_VIEW_SELECTION:
341             onSelectionChanged();
342             break;
343 
344         case tools::EventMultiplexerEvent::EID_CURRENT_PAGE:
345             onChangeCurrentPage();
346             break;
347 
348         case tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED:
349             // At this moment the controller may not yet been set at model
350             // or ViewShellBase.  Take it from the view shell passed with
351             // the event.
352             if (mrBase.GetMainViewShell() != NULL)
353             {
354 				if( mrBase.GetMainViewShell()->GetShellType() == ViewShell::ST_IMPRESS )
355 				{
356 					mxView = Reference<XDrawView>::query(mrBase.GetDrawController());
357 	                onSelectionChanged();
358 		            onChangeCurrentPage();
359 					break;
360 				}
361             }
362 		// fall through intended
363         case tools::EventMultiplexerEvent::EID_MAIN_VIEW_REMOVED:
364             mxView = 0;
365 			mxCurrentPage = 0;
366 			updateControls();
367             break;
368 
369         case tools::EventMultiplexerEvent::EID_DISPOSING:
370             mxView = Reference<XDrawView>();
371             onSelectionChanged();
372             onChangeCurrentPage();
373             break;
374 		case tools::EventMultiplexerEvent::EID_END_TEXT_EDIT:
375 			if( mpMainSequence.get() && pEvent->mpUserData )
376 				mpCustomAnimationList->update( mpMainSequence );
377 			break;
378     }
379     return 0;
380 }
381 
382 
383 void CustomAnimationPane::updateLayout()
384 {
385 	Size aPaneSize( GetSizePixel() );
386 	if( aPaneSize.Width() < maMinSize.Width() )
387 		aPaneSize.Width() = maMinSize.Width();
388 
389 	if( aPaneSize.Height() < maMinSize.Height() )
390 		aPaneSize.Height() = maMinSize.Height();
391 
392 	Point aOffset( LogicToPixel( Point(3,3), MAP_APPFONT ) );
393 	Point aCursor( aOffset );
394 
395 	// place the modify fixed line
396 
397 	// place the "modify effect" fixed line
398 	Size aSize( mpFLModify->GetSizePixel() );
399 	aSize.Width() = aPaneSize.Width() - 2 * aOffset.X();
400 
401 	mpFLModify->SetPosSizePixel( aCursor, aSize );
402 
403 	aCursor.Y() += aSize.Height() + aOffset.Y();
404 
405 	const int nButtonExtraWidth = 4 * aOffset.X();
406 
407 	// the "add effect" button is placed top-left
408     Size aCtrlSize( mpPBAddEffect->GetSizePixel() );
409     aCtrlSize.setWidth( mpPBAddEffect->CalcMinimumSize( aSize.Width() ).getWidth() + nButtonExtraWidth );
410     mpPBAddEffect->SetPosSizePixel( aCursor, aCtrlSize );
411 
412 	aCursor.X() += aOffset.X() + aCtrlSize.Width();
413 
414 	// place the "change effect" button
415 
416 	// if the "change" button does not fit right of the "add effect", put it on the next line
417     aCtrlSize = mpPBChangeEffect->GetSizePixel();
418     aCtrlSize.setWidth( mpPBChangeEffect->CalcMinimumSize( aSize.Width() ).getWidth() + nButtonExtraWidth );
419 	if( ( aCursor.X() + aCtrlSize.Width() + aOffset.X() ) > aPaneSize.Width() )
420 	{
421 		aCursor.X() = aOffset.X();
422 		aCursor.Y() += aCtrlSize.Height() + aOffset.Y();
423 	}
424 	mpPBChangeEffect->SetPosSizePixel( aCursor, aCtrlSize );
425 
426 	aCursor.X() += aOffset.X() + aCtrlSize.Width();
427 
428 	// place the "remove effect" button
429 
430 	// if the "remove" button does not fit right of the "add effect", put it on the next line
431     aCtrlSize = mpPBRemoveEffect->GetSizePixel();
432     aCtrlSize.setWidth( mpPBRemoveEffect->CalcMinimumSize( aSize.Width() ).getWidth() + nButtonExtraWidth );
433 	if( ( aCursor.X() + aCtrlSize.Width() + aOffset.X() ) > aPaneSize.Width() )
434 	{
435 		aCursor.X() = aOffset.X();
436 		aCursor.Y() += aCtrlSize.Height() + aOffset.Y();
437 	}
438 
439 	mpPBRemoveEffect->SetPosSizePixel( aCursor, aCtrlSize );
440 
441 	aCursor.X() = aOffset.X();
442 	aCursor.Y() += aCtrlSize.Height() + 2 * aOffset.Y();
443 
444 	// place the "modify effect" fixed line
445 	aSize = mpFLEffect->GetSizePixel();
446 	aSize.Width() = aPaneSize.Width() - 2 * aOffset.X();
447 
448 	mpFLEffect->SetPosSizePixel( aCursor, aSize );
449 
450 	aCursor.Y() += aSize.Height() + aOffset.Y();
451 
452 	// ---------------------------------------------------------------------------
453 	// place the properties controls
454 
455 	// calc minimum width for fixedtext
456 
457 	Size aFixedTextSize( mpFTStart->CalcMinimumSize() );
458 	long nWidth = aFixedTextSize.Width();
459     aFixedTextSize = mpFTProperty->CalcMinimumSize();
460 	nWidth = std::max( nWidth, aFixedTextSize.Width() );
461     aFixedTextSize = mpFTSpeed->CalcMinimumSize();
462 	aFixedTextSize.Width() = std::max( nWidth, aFixedTextSize.Width() ) + aOffset.X();
463 	mpFTStart->SetSizePixel(aFixedTextSize);
464 	mpFTProperty->SetSizePixel(aFixedTextSize);
465 	mpFTSpeed->SetSizePixel(aFixedTextSize);
466 
467 	aSize = mpPBPropertyMore->GetSizePixel();
468 
469 	// place the "start" fixed text
470 
471 	Point aFTPos( aCursor );
472 	Point aLBPos( aCursor );
473 	Size aListBoxSize( LogicToPixel( Size( 60, 12 ), MAP_APPFONT ) );
474 	long nDeltaY = aListBoxSize.Height() + aOffset.Y();
475 
476 	// linebreak?
477 	if( (aFixedTextSize.Width() + aListBoxSize.Width() + aSize.Width() + 4 * aOffset.X()) > aPaneSize.Width() )
478 	{
479 		// y position for list box is below fixed text
480 		aLBPos.Y() += aFixedTextSize.Height() + aOffset.Y();
481 
482 		// height of fixed text + list box + something = 2 * list box
483 		nDeltaY = aListBoxSize.Height() +  aFixedTextSize.Height() + 2*aOffset.Y();
484 	}
485 	else
486 	{
487 		// x position for list box is right of fixed text
488 		aLBPos.X() += aFixedTextSize.Width() + aOffset.X();
489 
490 		if( aListBoxSize.Height() > aFixedTextSize.Height() )
491 			aFTPos.Y() = aLBPos.Y() + ((aListBoxSize.Height() - aFixedTextSize.Height()) >> 1);
492 		else
493 			aLBPos.Y() = aFTPos.Y() + ((aFixedTextSize.Height() - aListBoxSize.Height()) >> 1);
494 	}
495 
496 	// width of the listbox is from its left side until end of pane
497 	aListBoxSize.Width() = aPaneSize.Width() - aLBPos.X() - aSize.Width() - 2 * aOffset.X();
498 
499 	mpFTStart->SetPosPixel( aFTPos );
500 	mpLBStart->SetPosSizePixel( aLBPos, aListBoxSize );
501 
502 	aFTPos.Y() += nDeltaY; aLBPos.Y() += nDeltaY;
503 
504 	mpFTProperty->SetPosPixel( aFTPos );
505 	mpLBProperty->SetPosSizePixel( aLBPos, aListBoxSize );
506 	mpLBProperty->Resize();
507 
508 	Point aMorePos( aLBPos );
509 	aMorePos.X() += aListBoxSize.Width() + aOffset.X();
510 	mpPBPropertyMore->SetPosPixel( aMorePos );
511 
512 	aFTPos.Y() += nDeltaY; aLBPos.Y() += nDeltaY;
513 
514 	mpFTSpeed->SetPosPixel( aFTPos );
515 	mpCBSpeed->SetPosSizePixel( aLBPos, aListBoxSize );
516 
517 	aFTPos.Y() += nDeltaY + aOffset.Y();
518 
519 	Point aListPos( aFTPos );
520 
521 	// positionate the buttons on the bottom
522 
523 	// place the auto preview checkbox
524 	aCursor = Point( aOffset.X(), aPaneSize.Height() - mpCBAutoPreview->GetSizePixel().Height() - aOffset.Y() );
525 	mpCBAutoPreview->SetPosPixel( aCursor );
526 
527 	// place the seperator 2 fixed line
528 	aCursor.Y() -= /* aOffset.Y() + */ mpFLSeperator2->GetSizePixel().Height();
529 	aSize = mpFLSeperator2->GetSizePixel();
530 	aSize.Width() = aPaneSize.Width() - 2 * aOffset.X();
531 	mpFLSeperator2->SetPosSizePixel( aCursor, aSize );
532 
533 	// next, layout and place the play and slide show buttons
534     aCtrlSize = mpPBSlideShow->GetSizePixel();
535     aCtrlSize.setWidth( mpPBSlideShow->CalcMinimumSize( aSize.Width() ).getWidth() + nButtonExtraWidth );
536 
537 	Size aPlaySize( mpPBPlay->GetSizePixel() );
538     aPlaySize.setWidth( mpPBPlay->CalcMinimumSize( aSize.Width() ).getWidth() + nButtonExtraWidth );
539 
540 	aCursor.Y() -= aCtrlSize.Height() /* + aOffset.Y() */;
541 
542 	// do we need two lines for the buttons?
543 	int aTestWidth = aCursor.X() + mpPBPlay->GetSizePixel().Width() + 2 * aOffset.X() + mpPBSlideShow->GetSizePixel().Width();
544 	if( aTestWidth > aPaneSize.Width() )
545 	{
546 		mpPBSlideShow->SetPosSizePixel( aCursor, aCtrlSize );
547 		aCursor.Y() -= aCtrlSize.Height() + aOffset.Y();
548 		mpPBPlay->SetPosSizePixel( aCursor, aPlaySize );
549 	}
550 	else
551 	{
552 		mpPBPlay->SetPosSizePixel( aCursor, aPlaySize );
553 		aCursor.X() += aPlaySize.Width() + aOffset.X();
554 		mpPBSlideShow->SetPosSizePixel( aCursor, aCtrlSize );
555 	}
556 
557 	// place the seperator 1 fixed line
558 	aCursor.X() = aOffset.X();
559 	aCursor.Y() -= /* aOffset.Y() + */ mpFLSeperator1->GetSizePixel().Height();
560 	aSize = mpFLSeperator1->GetSizePixel();
561 	aSize.Width() = aPaneSize.Width() - 2 * aOffset.X();
562 	mpFLSeperator1->SetPosSizePixel( aCursor, aSize );
563 
564 	// place the move down button
565 	aSize = mpPBMoveDown->GetSizePixel();
566 
567 	aCursor.X() = aPaneSize.Width() - aOffset.X() - aSize.Width();
568 	aCursor.Y() -= aOffset.Y() + aSize.Height();
569 	mpPBMoveDown->SetPosPixel( aCursor );
570 
571 	aCursor.X() -= aOffset.X() + aSize.Width();
572 	mpPBMoveUp->SetPosPixel( aCursor );
573 
574     // Place the change order label.
575     // Its width has to be calculated dynamically so that is can be
576     // displayed flush right without having too much space to the buttons
577     // with some languages or truncated text with others.
578 	mpFTChangeOrder->SetSizePixel(mpFTChangeOrder->CalcMinimumSize());
579 
580 	aCursor.X() -= aOffset.X() + mpFTChangeOrder->GetSizePixel().Width();
581     aCursor.Y() += (aSize.Height() - mpFTChangeOrder->GetSizePixel().Height()) >> 1;
582     mpFTChangeOrder->SetPosPixel( aCursor );
583 
584 	// positionate the custom animation list control
585 	Size aCustomAnimationListSize( aPaneSize.Width() - aListPos.X() - aOffset.X(), aCursor.Y() - aListPos.Y() - 2 * aOffset.Y() );
586 	mpCustomAnimationList->SetPosSizePixel( aListPos, aCustomAnimationListSize );
587 }
588 
589 static sal_Int32 getPropertyType( const OUString& rProperty )
590 {
591 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Direction") ) )
592 		return nPropertyTypeDirection;
593 
594 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Spokes") ) )
595 		return nPropertyTypeSpokes;
596 
597 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Zoom") ) )
598 		return nPropertyTypeZoom;
599 
600 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Accelerate") ) )
601 		return nPropertyTypeAccelerate;
602 
603 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Decelerate") ) )
604 		return nPropertyTypeDecelerate;
605 
606 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Color1") ) )
607 		return nPropertyTypeFirstColor;
608 
609 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Color2") ) )
610 		return nPropertyTypeSecondColor;
611 
612 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("FillColor") ) )
613 		return nPropertyTypeFillColor;
614 
615 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("ColorStyle") ) )
616 		return nPropertyTypeColorStyle;
617 
618 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("AutoReverse") ) )
619 		return nPropertyTypeAutoReverse;
620 
621 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("FontStyle") ) )
622 		return nPropertyTypeFont;
623 
624 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CharColor") ) )
625 		return nPropertyTypeCharColor;
626 
627 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CharHeight") ) )
628 		return nPropertyTypeCharHeight;
629 
630 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CharDecoration") ) )
631 		return nPropertyTypeCharDecoration;
632 
633 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("LineColor") ) )
634 		return nPropertyTypeLineColor;
635 
636 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Rotate") ) )
637 		return nPropertyTypeRotate;
638 
639 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Transparency") ) )
640 		return nPropertyTypeTransparency;
641 
642 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Color") ) )
643 		return nPropertyTypeColor;
644 
645 	if( rProperty.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Scale") ) )
646 		return nPropertyTypeScale;
647 
648 	return nPropertyTypeNone;
649 }
650 
651 OUString getPropertyName( sal_Int32 nPropertyType )
652 {
653 	switch( nPropertyType )
654 	{
655 	case nPropertyTypeDirection:
656 		return OUString( String( SdResId( STR_CUSTOMANIMATION_DIRECTION_PROPERTY ) ) );
657 
658 	case nPropertyTypeSpokes:
659 		return OUString( String( SdResId( STR_CUSTOMANIMATION_SPOKES_PROPERTY ) ) );
660 
661 	case nPropertyTypeFirstColor:
662 		return OUString( String( SdResId( STR_CUSTOMANIMATION_FIRST_COLOR_PROPERTY ) ) );
663 
664 	case nPropertyTypeSecondColor:
665 		return OUString( String( SdResId( STR_CUSTOMANIMATION_SECOND_COLOR_PROPERTY ) ) );
666 
667 	case nPropertyTypeZoom:
668 		return OUString( String( SdResId( STR_CUSTOMANIMATION_ZOOM_PROPERTY ) ) );
669 
670 	case nPropertyTypeFillColor:
671 		return OUString( String( SdResId( STR_CUSTOMANIMATION_FILL_COLOR_PROPERTY ) ) );
672 
673 	case nPropertyTypeColorStyle:
674 		return OUString( String( SdResId( STR_CUSTOMANIMATION_STYLE_PROPERTY ) ) );
675 
676 	case nPropertyTypeFont:
677 		return OUString( String( SdResId( STR_CUSTOMANIMATION_FONT_PROPERTY ) ) );
678 
679 	case nPropertyTypeCharHeight:
680 		return OUString( String( SdResId( STR_CUSTOMANIMATION_SIZE_PROPERTY ) ) );
681 
682 	case nPropertyTypeCharColor:
683 		return OUString( String( SdResId( STR_CUSTOMANIMATION_FONT_COLOR_PROPERTY ) ) );
684 
685 	case nPropertyTypeCharHeightStyle:
686 		return OUString( String( SdResId( STR_CUSTOMANIMATION_FONT_SIZE_STYLE_PROPERTY ) ) );
687 
688 	case nPropertyTypeCharDecoration:
689 		return OUString( String( SdResId( STR_CUSTOMANIMATION_FONT_STYLE_PROPERTY ) ) );
690 
691 	case nPropertyTypeLineColor:
692 		return OUString( String( SdResId( STR_CUSTOMANIMATION_LINE_COLOR_PROPERTY ) ) );
693 
694 	case nPropertyTypeRotate:
695 		return OUString( String( SdResId( STR_CUSTOMANIMATION_AMOUNT_PROPERTY ) ) );
696 
697 	case nPropertyTypeColor:
698 		return OUString( String( SdResId( STR_CUSTOMANIMATION_COLOR_PROPERTY ) ) );
699 
700 	case nPropertyTypeTransparency:
701 		return OUString( String( SdResId( STR_CUSTOMANIMATION_AMOUNT_PROPERTY ) ) );
702 
703 	case nPropertyTypeScale:
704 		return OUString( String( SdResId( STR_CUSTOMANIMATION_SCALE_PROPERTY ) ) );
705 	}
706 
707 	OUString aStr;
708 	return aStr;
709 }
710 
711 void CustomAnimationPane::updateControls()
712 {
713 	mpFLModify->Enable( mxView.is() );
714 	mpFTSpeed->Enable( mxView.is() );
715 	mpCBSpeed->Enable( mxView.is() );
716 	mpCustomAnimationList->Enable( mxView.is() );
717 	mpFTChangeOrder->Enable( mxView.is() );
718 	mpPBMoveUp->Enable( mxView.is() );
719 	mpPBMoveDown->Enable( mxView.is() );
720 	mpFLSeperator1->Enable( mxView.is() );
721 	mpPBPlay->Enable( mxView.is() );
722 	mpPBSlideShow->Enable( mxView.is() );
723 	mpFLSeperator2->Enable( mxView.is() );
724 	mpCBAutoPreview->Enable( mxView.is() );
725 
726 	if( !mxView.is() )
727 	{
728 		mpPBAddEffect->Enable( sal_False );
729 		mpPBChangeEffect->Enable( sal_False );
730 		mpPBRemoveEffect->Enable( sal_False );
731 		mpFLEffect->Enable( sal_False );
732 		mpFTStart->Enable( sal_False );
733 		mpLBStart->Enable( sal_False );
734 		mpPBPropertyMore->Enable( sal_False );
735 		mpLBProperty->Enable( sal_False );
736 		mpFTProperty->Enable( sal_False );
737 		mpCustomAnimationList->clear();
738 		return;
739 	}
740 
741 	const int nSelectionCount = maListSelection.size();
742 
743 	mpPBAddEffect->Enable( maViewSelection.hasValue() );
744 	mpPBChangeEffect->Enable( nSelectionCount);
745 	mpPBRemoveEffect->Enable(nSelectionCount);
746 
747 	mpFLEffect->Enable(nSelectionCount > 0);
748 	mpFTStart->Enable(nSelectionCount > 0);
749 	mpLBStart->Enable(nSelectionCount > 0);
750 	mpPBPropertyMore->Enable(nSelectionCount > 0);
751 
752 //	mpPBPlay->Enable(nSelectionCount > 0);
753 
754 	mpFTProperty->SetText( maStrProperty );
755 
756 	mnPropertyType = nPropertyTypeNone;
757 
758 	if( nSelectionCount == 1 )
759 	{
760 		CustomAnimationEffectPtr pEffect = maListSelection.front();
761 
762 		OUString aUIName( getPresets().getUINameForPresetId( pEffect->getPresetId() ) );
763 
764 		OUString aTemp( maStrModify );
765 
766 		if( aUIName.getLength() )
767 		{
768 			aTemp += OUString( (sal_Unicode)' ' );
769 			aTemp += aUIName;
770 		}
771 		mpFLEffect->SetText( aTemp );
772 
773 		CustomAnimationPresetPtr pDescriptor = getPresets().getEffectDescriptor( pEffect->getPresetId() );
774 		if( pDescriptor.get() )
775 		{
776 			PropertySubControl* pSubControl = NULL;
777 
778 			Any aValue;
779 
780 			UStringList aProperties( pDescriptor->getProperties() );
781 			if( aProperties.size() >= 1 )
782 			{
783 				OUString aProperty( aProperties.front() );
784 
785 				mnPropertyType = getPropertyType( aProperties.front() );
786 
787 				mpFTProperty->SetText( getPropertyName( mnPropertyType )  );
788 
789 				aValue = getProperty1Value( mnPropertyType, pEffect );
790 			}
791 
792 			if( aValue.hasValue() )
793 			{
794 				pSubControl = mpLBProperty->getSubControl();
795 				if( !pSubControl || (pSubControl->getControlType() != mnPropertyType) )
796 				{
797 					pSubControl = PropertySubControl::create( mnPropertyType, this, aValue, pEffect->getPresetId(), LINK( this, CustomAnimationPane, implPropertyHdl ) );
798 					mpLBProperty->setSubControl( pSubControl );
799 				}
800 				else
801 				{
802 					pSubControl->setValue( aValue, pEffect->getPresetId() );
803 				}
804 			}
805 			else
806 			{
807 				mpLBProperty->setSubControl( 0 );
808 			}
809 
810 			bool bEnable = (pSubControl != 0) && (pSubControl->getControl()->IsEnabled());
811 			mpLBProperty->Enable( bEnable );
812 			mpFTProperty->Enable( bEnable );
813 		}
814 		else
815 		{
816 			mpLBProperty->setSubControl( 0 );
817 			mpFTProperty->Enable( sal_False );
818 			mpLBProperty->Enable( sal_False );
819 			mpPBPropertyMore->Enable( sal_False );
820 		}
821 
822 		//
823 		// ---
824 		//
825 		sal_uInt16 nPos = 0xffff;
826 
827 		sal_Int16 nNodeType = pEffect->getNodeType();
828 		switch( nNodeType )
829 		{
830 		case EffectNodeType::ON_CLICK:			nPos = 0; break;
831 		case EffectNodeType::WITH_PREVIOUS:		nPos = 1; break;
832 		case EffectNodeType::AFTER_PREVIOUS:	nPos = 2; break;
833 		}
834 
835 		mpLBStart->SelectEntryPos( nPos );
836 
837 		double fDuration = pEffect->getDuration();
838 		const bool bHasSpeed = fDuration > 0.001;
839 
840 		mpFTSpeed->Enable(bHasSpeed);
841 		mpCBSpeed->Enable(bHasSpeed);
842 
843 		if( bHasSpeed )
844 		{
845 			if( fDuration == 5.0 )
846 				nPos = 0;
847 			else if( fDuration == 3.0 )
848 				nPos = 1;
849 			else if( fDuration == 2.0 )
850 				nPos = 2;
851 			else if( fDuration == 1.0 )
852 				nPos = 3;
853 			else if( fDuration == 0.5 )
854 				nPos = 4;
855 			else
856 				nPos = 0xffff;
857 
858 			mpCBSpeed->SelectEntryPos( nPos );
859 		}
860 
861 		mpPBPropertyMore->Enable( sal_True );
862 
863 		mpFTChangeOrder->Enable( sal_True );
864 	}
865 	else
866 	{
867 		mpLBProperty->setSubControl( 0 );
868 		mpFTProperty->Enable( sal_False );
869 		mpLBProperty->Enable( sal_False );
870 		mpPBPropertyMore->Enable( sal_False );
871 		mpFTSpeed->Enable(sal_False);
872 		mpCBSpeed->Enable(sal_False);
873 		mpFTChangeOrder->Enable( sal_False );
874 		mpLBStart->SetNoSelection();
875 		mpCBSpeed->SetNoSelection();
876 		mpFLEffect->SetText( maStrModify );
877 	}
878 
879 	bool bEnableUp = true;
880 	bool bEnableDown = true;
881 	if( nSelectionCount == 0 )
882 	{
883 		bEnableUp = false;
884 		bEnableDown = false;
885 	}
886 	else
887 	{
888 		if( mpMainSequence->find( maListSelection.front() ) == mpMainSequence->getBegin() )
889 			bEnableUp = false;
890 
891 		EffectSequence::iterator aIter( mpMainSequence->find( maListSelection.back() ) );
892 		if( aIter == mpMainSequence->getEnd() )
893 		{
894 			bEnableDown = false;
895 		}
896 		else
897 		{
898 			do
899 			{
900 				aIter++;
901 			}
902 			while( (aIter != mpMainSequence->getEnd()) && !(mpCustomAnimationList->isExpanded((*aIter)) ) );
903 
904 			if( aIter == mpMainSequence->getEnd() )
905 				bEnableDown = false;
906 		}
907 
908 		if( bEnableUp || bEnableDown )
909 		{
910 			MainSequenceRebuildGuard aGuard( mpMainSequence );
911 
912 			EffectSequenceHelper* pSequence = 0;
913 			EffectSequence::iterator aRebuildIter( maListSelection.begin() );
914 			const EffectSequence::iterator aRebuildEnd( maListSelection.end() );
915 			while( aRebuildIter != aRebuildEnd )
916 			{
917 				CustomAnimationEffectPtr pEffect = (*aRebuildIter++);
918 
919 				if( pEffect.get() )
920 				{
921 					if( pSequence == 0 )
922 					{
923 						pSequence = pEffect->getEffectSequence();
924 					}
925 					else
926 					{
927 						if( pSequence != pEffect->getEffectSequence() )
928 						{
929 							bEnableUp = false;
930 							bEnableDown = false;
931 							break;
932 						}
933 					}
934 				}
935 			}
936 		}
937 	}
938 
939 	mpPBMoveUp->Enable(bEnableUp);
940 	mpPBMoveDown->Enable(bEnableDown);
941 
942 	SdOptions* pOptions = SD_MOD()->GetSdOptions(DOCUMENT_TYPE_IMPRESS);
943 	mpCBAutoPreview->Check( pOptions->IsPreviewChangedEffects() == sal_True );
944 
945 	updateMotionPathTags();
946 }
947 
948 static bool updateMotionPathImpl( CustomAnimationPane& rPane, ::sd::View& rView,  EffectSequence::iterator aIter, EffectSequence::iterator aEnd, MotionPathTagVector& rOldTags, MotionPathTagVector& rNewTags )
949 {
950 	bool bChanges = false;
951 	while( aIter != aEnd )
952 	{
953 		CustomAnimationEffectPtr pEffect( (*aIter++) );
954 		if( pEffect.get() && pEffect->getPresetClass() == ::com::sun::star::presentation::EffectPresetClass::MOTIONPATH )
955 		{
956 			rtl::Reference< MotionPathTag > xMotionPathTag;
957 			// first try to find if there is already a tag for this
958 			MotionPathTagVector::iterator aMIter( rOldTags.begin() );
959 			for( ; aMIter != rOldTags.end(); aMIter++ )
960 			{
961 				rtl::Reference< MotionPathTag > xTag( (*aMIter) );
962 				if( xTag->getEffect() == pEffect )
963 				{
964 					if( !xTag->isDisposed() )
965 					{
966 						xMotionPathTag = xTag;
967 						rOldTags.erase( aMIter );
968 					}
969 					break;
970 				}
971 			}
972 
973 			// if not found, create new one
974 			if( !xMotionPathTag.is() )
975 			{
976 				xMotionPathTag.set( new MotionPathTag( rPane, rView, pEffect ) );
977 				bChanges = true;
978 			}
979 
980 			if( xMotionPathTag.is() )
981 				rNewTags.push_back( xMotionPathTag );
982 		}
983 	}
984 
985 	return bChanges;
986 }
987 
988 void CustomAnimationPane::updateMotionPathTags()
989 {
990 	bool bChanges = false;
991 
992 	MotionPathTagVector aTags;
993 	aTags.swap( maMotionPathTags );
994 
995 	::sd::View* pView = 0;
996 
997 	if( mxView.is() )
998 	{
999 		::boost::shared_ptr<ViewShell> xViewShell( mrBase.GetMainViewShell() );
1000 		if( xViewShell.get() )
1001 			pView = xViewShell->GetView();
1002 	}
1003 
1004 	if( IsVisible() && mpMainSequence.get() && pView )
1005 	{
1006 		bChanges = updateMotionPathImpl( *this, *pView, mpMainSequence->getBegin(), mpMainSequence->getEnd(), aTags, maMotionPathTags );
1007 
1008 		const InteractiveSequenceList& rISL = mpMainSequence->getInteractiveSequenceList();
1009 		InteractiveSequenceList::const_iterator aISI( rISL.begin() );
1010 		while( aISI != rISL.end() )
1011 		{
1012 			InteractiveSequencePtr pIS( (*aISI++) );
1013 			bChanges |= updateMotionPathImpl( *this, *pView, pIS->getBegin(), pIS->getEnd(), aTags, maMotionPathTags );
1014 		}
1015 	}
1016 
1017 	if( !aTags.empty() )
1018 	{
1019 		bChanges = true;
1020 		MotionPathTagVector::iterator aIter( aTags.begin() );
1021 		while( aIter != aTags.end() )
1022 		{
1023 			rtl::Reference< MotionPathTag > xTag( (*aIter++) );
1024 			xTag->Dispose();
1025 		}
1026 	}
1027 
1028 	if( bChanges && pView )
1029 		pView->updateHandles();
1030 }
1031 
1032 void CustomAnimationPane::onSelectionChanged()
1033 {
1034 	if( !maSelectionLock.isLocked() )
1035 	{
1036 		ScopeLockGuard aGuard( maSelectionLock );
1037 
1038 		if( mxView.is() ) try
1039 		{
1040 			Reference< XSelectionSupplier >  xSel( mxView, UNO_QUERY_THROW );
1041 			if (xSel.is())
1042 			{
1043 				maViewSelection = xSel->getSelection();
1044 				mpCustomAnimationList->onSelectionChanged( maViewSelection );
1045 				updateControls();
1046 			}
1047 		}
1048 		catch( Exception& )
1049 		{
1050 			DBG_ERROR( "sd::CustomAnimationPane::onSelectionChanged(), Exception catched!" );
1051 		}
1052 	}
1053 }
1054 
1055 void CustomAnimationPane::onDoubleClick()
1056 {
1057 	showOptions();
1058 }
1059 
1060 void CustomAnimationPane::onContextMenu( sal_uInt16 nSelectedPopupEntry )
1061 {
1062 	switch( nSelectedPopupEntry )
1063 	{
1064 	case CM_WITH_CLICK:		onChangeStart( EffectNodeType::ON_CLICK ); break;
1065 	case CM_WITH_PREVIOUS:	onChangeStart( EffectNodeType::WITH_PREVIOUS  ); break;
1066 	case CM_AFTER_PREVIOUS:	onChangeStart( EffectNodeType::AFTER_PREVIOUS ); break;
1067 	case CM_OPTIONS:		showOptions(); break;
1068 	case CM_DURATION:		showOptions(RID_TP_CUSTOMANIMATION_DURATION); break;
1069 	case CM_REMOVE:			onRemove(); break;
1070 	case CM_CREATE:			if( maViewSelection.hasValue() ) onChange( true ); break;
1071 	}
1072 
1073 	updateControls();
1074 }
1075 
1076 void addValue( STLPropertySet* pSet, sal_Int32 nHandle, const Any& rValue )
1077 {
1078 	switch( pSet->getPropertyState( nHandle ) )
1079 	{
1080 	case STLPropertyState_AMBIGUOUS:
1081 		// value is already ambiguous, do nothing
1082 		break;
1083 	case STLPropertyState_DIRECT:
1084 		// set to ambiguous if existing value is different
1085 		if( rValue != pSet->getPropertyValue( nHandle ) )
1086 			pSet->setPropertyState( nHandle, STLPropertyState_AMBIGUOUS );
1087 		break;
1088 	case STLPropertyState_DEFAULT:
1089 		// just set new value
1090 		pSet->setPropertyValue( nHandle, rValue );
1091 		break;
1092 	}
1093 }
1094 
1095 static sal_Int32 calcMaxParaDepth( Reference< XShape > xTargetShape )
1096 {
1097 	sal_Int32 nMaxParaDepth = -1;
1098 
1099 	if( xTargetShape.is() )
1100 	{
1101 		Reference< XEnumerationAccess > xText( xTargetShape, UNO_QUERY );
1102 		if( xText.is() )
1103 		{
1104 			Reference< XPropertySet > xParaSet;
1105 			const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") );
1106 
1107 			Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_QUERY_THROW );
1108 			while( xEnumeration->hasMoreElements() )
1109 			{
1110 				xEnumeration->nextElement() >>= xParaSet;
1111 				if( xParaSet.is() )
1112 				{
1113 					sal_Int32 nParaDepth = 0;
1114 					xParaSet->getPropertyValue( strNumberingLevel ) >>= nParaDepth;
1115 
1116 					if( nParaDepth > nMaxParaDepth )
1117 						nMaxParaDepth = nParaDepth;
1118 				}
1119 			}
1120 		}
1121 	}
1122 
1123 	return nMaxParaDepth + 1;
1124 }
1125 
1126 Any CustomAnimationPane::getProperty1Value( sal_Int32 nType, CustomAnimationEffectPtr pEffect )
1127 {
1128 	switch( nType )
1129 	{
1130 	case nPropertyTypeDirection:
1131 	case nPropertyTypeSpokes:
1132 	case nPropertyTypeZoom:
1133 		return makeAny( pEffect->getPresetSubType() );
1134 
1135 	case nPropertyTypeColor:
1136 	case nPropertyTypeFillColor:
1137 	case nPropertyTypeFirstColor:
1138 	case nPropertyTypeSecondColor:
1139 	case nPropertyTypeCharColor:
1140 	case nPropertyTypeLineColor:
1141 		{
1142 			const sal_Int32 nIndex = (nPropertyTypeFirstColor == nType) ? 0 : 1;
1143 			return pEffect->getColor( nIndex );
1144 		}
1145 
1146 	case nPropertyTypeFont:
1147 		return pEffect->getProperty( AnimationNodeType::SET, OUString( RTL_CONSTASCII_USTRINGPARAM("CharFontName") ), VALUE_TO );
1148 
1149 	case nPropertyTypeCharHeight:
1150 		{
1151 			const OUString aAttributeName( RTL_CONSTASCII_USTRINGPARAM( "CharHeight" ) );
1152             Any aValue( pEffect->getProperty( AnimationNodeType::SET, aAttributeName, VALUE_TO ) );
1153 			if( !aValue.hasValue() )
1154 				aValue = pEffect->getProperty( AnimationNodeType::ANIMATE, aAttributeName, VALUE_TO );
1155 			return aValue;
1156 		}
1157 
1158 	case nPropertyTypeRotate:
1159 		return pEffect->getTransformationProperty( AnimationTransformType::ROTATE, VALUE_BY);
1160 
1161 	case nPropertyTypeTransparency:
1162 		return pEffect->getProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("Opacity")), VALUE_TO );
1163 
1164 	case nPropertyTypeScale:
1165 		return pEffect->getTransformationProperty( AnimationTransformType::SCALE, VALUE_BY );
1166 
1167 	case nPropertyTypeCharDecoration:
1168 		{
1169 			Sequence< Any > aValues(3);
1170 			aValues[0] = pEffect->getProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharWeight")), VALUE_TO );
1171 			aValues[1] = pEffect->getProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharPosture")), VALUE_TO );
1172 			aValues[2] = pEffect->getProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharUnderline")), VALUE_TO );
1173 			return makeAny( aValues );
1174 		}
1175 	}
1176 
1177 	Any aAny;
1178 	return aAny;
1179 }
1180 
1181 bool CustomAnimationPane::setProperty1Value( sal_Int32 nType, CustomAnimationEffectPtr pEffect, const Any& rValue )
1182 {
1183 	bool bEffectChanged = false;
1184 	switch( nType )
1185 	{
1186 	case nPropertyTypeDirection:
1187 	case nPropertyTypeSpokes:
1188 	case nPropertyTypeZoom:
1189 		{
1190 			OUString aPresetSubType;
1191 			rValue >>= aPresetSubType;
1192 			if( aPresetSubType != pEffect->getPresetSubType() )
1193 			{
1194 				getPresets().changePresetSubType( pEffect, aPresetSubType );
1195 				bEffectChanged = true;
1196 			}
1197 		}
1198 		break;
1199 
1200 	case nPropertyTypeFillColor:
1201 	case nPropertyTypeColor:
1202 	case nPropertyTypeFirstColor:
1203 	case nPropertyTypeSecondColor:
1204 	case nPropertyTypeCharColor:
1205 	case nPropertyTypeLineColor:
1206 		{
1207 			const sal_Int32 nIndex = (nPropertyTypeFirstColor == nType) ? 0 : 1;
1208 			Any aOldColor( pEffect->getColor( nIndex ) );
1209 			if( aOldColor != rValue )
1210 			{
1211 				pEffect->setColor( nIndex, rValue );
1212 				bEffectChanged = true;
1213 			}
1214 		}
1215 		break;
1216 
1217 	case nPropertyTypeFont:
1218 		bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, OUString( RTL_CONSTASCII_USTRINGPARAM( "CharFontName" ) ), VALUE_TO, rValue );
1219 		break;
1220 
1221 	case nPropertyTypeCharHeight:
1222 		{
1223 			const OUString aAttributeName( RTL_CONSTASCII_USTRINGPARAM( "CharHeight" ) );
1224 			bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, aAttributeName, VALUE_TO, rValue );
1225 			if( !bEffectChanged )
1226 				bEffectChanged = pEffect->setProperty( AnimationNodeType::ANIMATE, aAttributeName, VALUE_TO, rValue );
1227 		}
1228 		break;
1229 	case nPropertyTypeRotate:
1230 		bEffectChanged = pEffect->setTransformationProperty( AnimationTransformType::ROTATE, VALUE_BY , rValue );
1231 		break;
1232 
1233 	case nPropertyTypeTransparency:
1234 		bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, OUString( RTL_CONSTASCII_USTRINGPARAM("Opacity") ), VALUE_TO, rValue );
1235 		break;
1236 
1237 	case nPropertyTypeScale:
1238 		bEffectChanged = pEffect->setTransformationProperty( AnimationTransformType::SCALE, VALUE_BY, rValue );
1239 		break;
1240 
1241 	case nPropertyTypeCharDecoration:
1242 		{
1243 			Sequence< Any > aValues(3);
1244 			rValue >>= aValues;
1245 			bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharWeight")), VALUE_TO, aValues[0] );
1246 			bEffectChanged |= pEffect->setProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharPosture")), VALUE_TO, aValues[1] );
1247 			bEffectChanged |= pEffect->setProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharUnderline")), VALUE_TO, aValues[2] );
1248 		}
1249 		break;
1250 
1251 	}
1252 
1253 	return bEffectChanged;
1254 }
1255 
1256 static sal_Bool hasVisibleShape( const Reference< XShape >& xShape )
1257 {
1258 	try
1259 	{
1260 		const OUString sShapeType( xShape->getShapeType() );
1261 
1262 		if( sShapeType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation.TitleTextShape") ) ||
1263 			sShapeType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation.OutlinerShape") ) ||
1264 			sShapeType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation.SubtitleShape") ) ||
1265 			sShapeType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.TextShape") ) )
1266 		{
1267 			const OUString sFillStyle( RTL_CONSTASCII_USTRINGPARAM("FillStyle" ) );
1268 			const OUString sLineStyle( RTL_CONSTASCII_USTRINGPARAM("LineStyle" ) );
1269 			Reference< XPropertySet > xSet( xShape, UNO_QUERY_THROW );
1270 
1271 			FillStyle eFillStyle;
1272 			xSet->getPropertyValue( sFillStyle ) >>= eFillStyle;
1273 
1274 			::com::sun::star::drawing::LineStyle eLineStyle;
1275 			xSet->getPropertyValue( sLineStyle ) >>= eLineStyle;
1276 
1277 			return eFillStyle != FillStyle_NONE || eLineStyle != ::com::sun::star::drawing::LineStyle_NONE;
1278 		}
1279 	}
1280 	catch( Exception& e )
1281 	{
1282 		(void)e;
1283 	}
1284 	return sal_True;
1285 }
1286 
1287 STLPropertySet* CustomAnimationPane::createSelectionSet()
1288 {
1289 	STLPropertySet* pSet = CustomAnimationDialog::createDefaultSet();
1290 
1291 	pSet->setPropertyValue( nHandleCurrentPage, makeAny( mxCurrentPage ) );
1292 
1293 	sal_Int32 nMaxParaDepth = 0;
1294 
1295 	// get options from selected effects
1296 	EffectSequence::iterator aIter( maListSelection.begin() );
1297 	const EffectSequence::iterator aEnd( maListSelection.end() );
1298     const CustomAnimationPresets& rPresets (getPresets());
1299     while( aIter != aEnd )
1300 	{
1301 		CustomAnimationEffectPtr pEffect = (*aIter++);
1302 
1303 		EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
1304 		if( !pEffectSequence )
1305 			pEffectSequence = mpMainSequence.get();
1306 
1307 		if( pEffect->hasText() )
1308 		{
1309 			sal_Int32 n = calcMaxParaDepth(pEffect->getTargetShape());
1310 			if( n > nMaxParaDepth )
1311 				nMaxParaDepth = n;
1312 		}
1313 
1314 		addValue( pSet, nHandleHasAfterEffect, makeAny( pEffect->hasAfterEffect() ) );
1315 		addValue( pSet, nHandleAfterEffectOnNextEffect, makeAny( pEffect->IsAfterEffectOnNext() ? sal_True : sal_False ) );
1316 		addValue( pSet, nHandleDimColor, pEffect->getDimColor() );
1317 		addValue( pSet, nHandleIterateType, makeAny( pEffect->getIterateType() ) );
1318 
1319 		// convert absolute time to percentage value
1320         // This calculation is done in float to avoid some rounding artifacts.
1321 		float fIterateInterval = (float)pEffect->getIterateInterval();
1322 		if( pEffect->getDuration() )
1323 			fIterateInterval = (float)(fIterateInterval / pEffect->getDuration() );
1324 		fIterateInterval *= 100.0;
1325 		addValue( pSet, nHandleIterateInterval, makeAny( (double)fIterateInterval ) );
1326 
1327 		addValue( pSet, nHandleBegin, makeAny( pEffect->getBegin() ) );
1328 		addValue( pSet, nHandleDuration, makeAny( pEffect->getDuration() ) );
1329 		addValue( pSet, nHandleStart, makeAny( pEffect->getNodeType() ) );
1330 		addValue( pSet, nHandleRepeat, makeAny( pEffect->getRepeatCount() ) );
1331 		addValue( pSet, nHandleEnd, pEffect->getEnd() );
1332 		addValue( pSet, nHandleRewind, makeAny( pEffect->getFill() ) );
1333 
1334 		addValue( pSet, nHandlePresetId, makeAny( pEffect->getPresetId() ) );
1335 
1336 		addValue( pSet, nHandleHasText, makeAny( (sal_Bool)pEffect->hasText() ) );
1337 
1338 		addValue( pSet, nHandleHasVisibleShape, Any( hasVisibleShape( pEffect->getTargetShape() ) ) );
1339 
1340 		Any aSoundSource;
1341 		if( pEffect->getAudio().is() )
1342 		{
1343 			aSoundSource = pEffect->getAudio()->getSource();
1344 			addValue( pSet, nHandleSoundVolumne, makeAny( pEffect->getAudio()->getVolume() ) );
1345 // todo		addValue( pSet, nHandleSoundEndAfterSlide, makeAny( pEffect->getAudio()->getEndAfterSlide() ) );
1346 // this is now stored at the XCommand parameter sequence
1347 		}
1348 		else if( pEffect->getCommand() == EffectCommands::STOPAUDIO )
1349 		{
1350 			aSoundSource = makeAny( (sal_Bool)sal_True );
1351 		}
1352 		addValue( pSet, nHandleSoundURL, aSoundSource );
1353 
1354 		sal_Int32 nGroupId = pEffect->getGroupId();
1355 		CustomAnimationTextGroupPtr pTextGroup;
1356 		if( nGroupId != -1 )
1357 			pTextGroup = pEffectSequence->findGroup( nGroupId );
1358 
1359 		addValue( pSet, nHandleTextGrouping, makeAny( pTextGroup.get() ? pTextGroup->getTextGrouping() : (sal_Int32)-1 ) );
1360 		addValue( pSet, nHandleAnimateForm, makeAny( pTextGroup.get() ? (sal_Bool)pTextGroup->getAnimateForm() : sal_True ) );
1361 		addValue( pSet, nHandleTextGroupingAuto, makeAny( pTextGroup.get() ? pTextGroup->getTextGroupingAuto() : (double)-1.0 ) );
1362 		addValue( pSet, nHandleTextReverse, makeAny( pTextGroup.get() ? (sal_Bool)pTextGroup->getTextReverse() : sal_False ) );
1363 
1364 		if( pEffectSequence->getSequenceType() == EffectNodeType::INTERACTIVE_SEQUENCE  )
1365 		{
1366 			InteractiveSequence* pIS = static_cast< InteractiveSequence* >( pEffectSequence );
1367 			addValue( pSet, nHandleTrigger, makeAny( pIS->getTriggerShape() ) );
1368 		}
1369 
1370 		//
1371 
1372 		CustomAnimationPresetPtr pDescriptor = rPresets.getEffectDescriptor( pEffect->getPresetId() );
1373 		if( pDescriptor.get() )
1374 		{
1375 			sal_Int32 nType = nPropertyTypeNone;
1376 
1377 			UStringList aProperties( pDescriptor->getProperties() );
1378 			if( aProperties.size() >= 1 )
1379 				nType = getPropertyType( aProperties.front() );
1380 
1381 			if( nType != nPropertyTypeNone )
1382 			{
1383 				addValue( pSet, nHandleProperty1Type, makeAny( nType ) );
1384 				addValue( pSet, nHandleProperty1Value, getProperty1Value( nType, pEffect ) );
1385 			}
1386 
1387 			if( pDescriptor->hasProperty( OUString( RTL_CONSTASCII_USTRINGPARAM( "Accelerate" ) ) ) )
1388 			{
1389 				addValue( pSet, nHandleAccelerate, makeAny( pEffect->getAcceleration() ) );
1390 			}
1391 
1392 			if( pDescriptor->hasProperty( OUString( RTL_CONSTASCII_USTRINGPARAM( "Decelerate" ) ) ) )
1393 			{
1394 				addValue( pSet, nHandleDecelerate, makeAny( pEffect->getDecelerate() ) );
1395 			}
1396 
1397 			if( pDescriptor->hasProperty( OUString( RTL_CONSTASCII_USTRINGPARAM( "AutoReverse" ) ) ) )
1398 			{
1399 				addValue( pSet, nHandleAutoReverse, makeAny( pEffect->getAutoReverse() ) );
1400 			}
1401 		}
1402 	}
1403 
1404 	addValue( pSet, nHandleMaxParaDepth, makeAny( nMaxParaDepth ) );
1405 
1406 	return pSet;
1407 }
1408 
1409 void CustomAnimationPane::changeSelection( STLPropertySet* pResultSet, STLPropertySet* pOldSet )
1410 {
1411 	// change selected effect
1412 	bool bChanged = false;
1413 
1414 	MainSequenceRebuildGuard aGuard( mpMainSequence );
1415 
1416 	EffectSequence::iterator aIter( maListSelection.begin() );
1417 	const EffectSequence::iterator aEnd( maListSelection.end() );
1418 	while( aIter != aEnd )
1419 	{
1420 		CustomAnimationEffectPtr pEffect = (*aIter++);
1421 
1422 		DBG_ASSERT( pEffect->getEffectSequence(), "sd::CustomAnimationPane::changeSelection(), dead effect in selection!" );
1423 		if( !pEffect->getEffectSequence() )
1424 			continue;
1425 
1426 		double fDuration = 0.0; // we might need this for iterate-interval
1427 		if( pResultSet->getPropertyState( nHandleDuration ) == STLPropertyState_DIRECT )
1428 		{
1429 			pResultSet->getPropertyValue( nHandleDuration ) >>= fDuration;
1430 		}
1431 		else
1432 		{
1433 			fDuration = pEffect->getDuration();
1434 		}
1435 
1436 		if( pResultSet->getPropertyState( nHandleIterateType ) == STLPropertyState_DIRECT )
1437 		{
1438 			sal_Int16 nIterateType = 0;
1439 			pResultSet->getPropertyValue( nHandleIterateType ) >>= nIterateType;
1440 			if( pEffect->getIterateType() != nIterateType )
1441 			{
1442 				pEffect->setIterateType( nIterateType );
1443 				bChanged = true;
1444 			}
1445 		}
1446 
1447 		if( pEffect->getIterateType() )
1448 		{
1449 			if( pResultSet->getPropertyState( nHandleIterateInterval ) == STLPropertyState_DIRECT )
1450 			{
1451 				double fIterateInterval = 0.0;
1452 				pResultSet->getPropertyValue( nHandleIterateInterval ) >>= fIterateInterval;
1453 				if( pEffect->getIterateInterval() != fIterateInterval )
1454 				{
1455 					const double f = fIterateInterval * pEffect->getDuration() / 100;
1456 					pEffect->setIterateInterval( f );
1457 					bChanged = true;
1458 				}
1459 			}
1460 		}
1461 
1462 		if( pResultSet->getPropertyState( nHandleBegin ) == STLPropertyState_DIRECT )
1463 		{
1464 			double fBegin = 0.0;
1465 			pResultSet->getPropertyValue( nHandleBegin ) >>= fBegin;
1466 			if( pEffect->getBegin() != fBegin )
1467 			{
1468 				pEffect->setBegin( fBegin );
1469 				bChanged = true;
1470 			}
1471 		}
1472 
1473 		if( pResultSet->getPropertyState( nHandleDuration ) == STLPropertyState_DIRECT )
1474 		{
1475 			if( pEffect->getDuration() != fDuration )
1476 			{
1477 				pEffect->setDuration( fDuration );
1478 				bChanged = true;
1479 			}
1480 		}
1481 
1482 		if( pResultSet->getPropertyState( nHandleStart ) == STLPropertyState_DIRECT )
1483 		{
1484 			sal_Int16 nNodeType = 0;
1485 			pResultSet->getPropertyValue( nHandleStart ) >>= nNodeType;
1486 			if( pEffect->getNodeType() != nNodeType )
1487 			{
1488 				pEffect->setNodeType( nNodeType );
1489 				bChanged = true;
1490 			}
1491 		}
1492 
1493 		if( pResultSet->getPropertyState( nHandleRepeat ) == STLPropertyState_DIRECT )
1494 		{
1495 			Any aRepeatCount( pResultSet->getPropertyValue( nHandleRepeat ) );
1496 			if( aRepeatCount != pEffect->getRepeatCount() )
1497 			{
1498 				pEffect->setRepeatCount( aRepeatCount );
1499 				bChanged = true;
1500 			}
1501 		}
1502 
1503 		if( pResultSet->getPropertyState( nHandleEnd ) == STLPropertyState_DIRECT )
1504 		{
1505 			Any aEndValue( pResultSet->getPropertyValue( nHandleEnd ) );
1506 			if( pEffect->getEnd() != aEndValue )
1507 			{
1508 				pEffect->setEnd( aEndValue );
1509 				bChanged = true;
1510 			}
1511 		}
1512 
1513 		if( pResultSet->getPropertyState( nHandleRewind ) == STLPropertyState_DIRECT )
1514 		{
1515 			sal_Int16 nFill = 0;
1516 			pResultSet->getPropertyValue( nHandleRewind ) >>= nFill;
1517 			if( pEffect->getFill() != nFill )
1518 			{
1519 				pEffect->setFill( nFill );
1520 				bChanged = true;
1521 			}
1522 		}
1523 
1524 		if( pResultSet->getPropertyState( nHandleHasAfterEffect ) == STLPropertyState_DIRECT )
1525 		{
1526 			sal_Bool bHasAfterEffect = sal_False;
1527 			if( pResultSet->getPropertyValue( nHandleHasAfterEffect )  >>= bHasAfterEffect )
1528 			{
1529 				if( pEffect->hasAfterEffect() != bHasAfterEffect )
1530 				{
1531 					pEffect->setHasAfterEffect( bHasAfterEffect );
1532 					bChanged = true;
1533 				}
1534 			}
1535 		}
1536 
1537 		if( pResultSet->getPropertyState( nHandleAfterEffectOnNextEffect ) == STLPropertyState_DIRECT )
1538 		{
1539 			sal_Bool bAfterEffectOnNextEffect = sal_False;
1540 			if( (pResultSet->getPropertyValue( nHandleAfterEffectOnNextEffect ) >>= bAfterEffectOnNextEffect) && ((pEffect->IsAfterEffectOnNext() ? sal_True : sal_False) != bAfterEffectOnNextEffect) )
1541 			{
1542 				pEffect->setAfterEffectOnNext( bAfterEffectOnNextEffect );
1543 				bChanged = true;
1544 			}
1545 		}
1546 
1547 		if( pResultSet->getPropertyState( nHandleDimColor ) == STLPropertyState_DIRECT )
1548 		{
1549 			Any aDimColor( pResultSet->getPropertyValue( nHandleDimColor ) );
1550 			if( pEffect->getDimColor() != aDimColor )
1551 			{
1552 				pEffect->setDimColor( aDimColor );
1553 				bChanged = true;
1554 			}
1555 		}
1556 
1557 		if( pResultSet->getPropertyState( nHandleAccelerate ) == STLPropertyState_DIRECT )
1558 		{
1559 			double fAccelerate = 0.0;
1560 			pResultSet->getPropertyValue( nHandleAccelerate ) >>= fAccelerate;
1561 			if( pEffect->getAcceleration() != fAccelerate )
1562 			{
1563 				pEffect->setAcceleration( fAccelerate );
1564 				bChanged = true;
1565 			}
1566 		}
1567 
1568 		if( pResultSet->getPropertyState( nHandleDecelerate ) == STLPropertyState_DIRECT )
1569 		{
1570 			double fDecelerate = 0.0;
1571 			pResultSet->getPropertyValue( nHandleDecelerate ) >>= fDecelerate;
1572 			if( pEffect->getDecelerate() != fDecelerate )
1573 			{
1574 				pEffect->setDecelerate( fDecelerate );
1575 				bChanged = true;
1576 			}
1577 		}
1578 
1579 		if( pResultSet->getPropertyState( nHandleAutoReverse ) == STLPropertyState_DIRECT )
1580 		{
1581 			sal_Bool bAutoReverse = sal_False;
1582 			pResultSet->getPropertyValue( nHandleAutoReverse ) >>= bAutoReverse;
1583 			if( pEffect->getAutoReverse() != bAutoReverse )
1584 			{
1585 				pEffect->setAutoReverse( bAutoReverse );
1586 				bChanged = true;
1587 			}
1588 		}
1589 
1590 		if( pResultSet->getPropertyState( nHandleProperty1Value ) == STLPropertyState_DIRECT )
1591 		{
1592 			sal_Int32 nType = 0;
1593 			pOldSet->getPropertyValue( nHandleProperty1Type ) >>= nType;
1594 
1595 			bChanged |= setProperty1Value( nType, pEffect, pResultSet->getPropertyValue( nHandleProperty1Value ) );
1596 		}
1597 
1598 		if( pResultSet->getPropertyState( nHandleSoundURL ) == STLPropertyState_DIRECT )
1599 		{
1600 			const Any aSoundSource( pResultSet->getPropertyValue( nHandleSoundURL ) );
1601 
1602 			if( aSoundSource.getValueType() == ::getCppuType((const sal_Bool*)0) )
1603 			{
1604 				pEffect->setStopAudio();
1605 				bChanged = true;
1606 			}
1607 			else
1608 			{
1609 				OUString aSoundURL;
1610 				aSoundSource >>= aSoundURL;
1611 
1612 				if( aSoundURL.getLength() )
1613 				{
1614 					if( !pEffect->getAudio().is() )
1615 					{
1616 						pEffect->createAudio( aSoundSource );
1617 						bChanged = true;
1618 					}
1619 					else
1620 					{
1621 						if( pEffect->getAudio()->getSource() != aSoundSource )
1622 						{
1623 							pEffect->getAudio()->setSource( aSoundSource );
1624 							bChanged = true;
1625 						}
1626 					}
1627 				}
1628 				else
1629 				{
1630 					if( pEffect->getAudio().is() || pEffect->getStopAudio() )
1631 					{
1632 						pEffect->removeAudio();
1633 						bChanged = true;
1634 					}
1635 				}
1636 			}
1637 		}
1638 
1639 		if( pResultSet->getPropertyState( nHandleTrigger ) == STLPropertyState_DIRECT )
1640 		{
1641 			Reference< XShape > xTriggerShape;
1642 			pResultSet->getPropertyValue( nHandleTrigger ) >>= xTriggerShape;
1643 			bChanged |= mpMainSequence->setTrigger( pEffect, xTriggerShape );
1644 		}
1645 	}
1646 
1647 	const bool bHasTextGrouping = pResultSet->getPropertyState( nHandleTextGrouping ) == STLPropertyState_DIRECT;
1648 	const bool bHasAnimateForm = pResultSet->getPropertyState( nHandleAnimateForm ) == STLPropertyState_DIRECT;
1649 	const bool bHasTextGroupingAuto = pResultSet->getPropertyState( nHandleTextGroupingAuto ) == STLPropertyState_DIRECT;
1650 	const bool bHasTextReverse = pResultSet->getPropertyState( nHandleTextReverse ) == STLPropertyState_DIRECT;
1651 
1652 	if( bHasTextGrouping || bHasAnimateForm || bHasTextGroupingAuto || bHasTextReverse )
1653 	{
1654 		// we need to do a second pass for text grouping options
1655 		// since changing them can cause effects to be removed
1656 		// or replaced, we do this after we aplied all other options
1657 		// above
1658 
1659 		sal_Int32 nTextGrouping = 0;
1660 		sal_Bool bAnimateForm = sal_True, bTextReverse = sal_False;
1661 		double fTextGroupingAuto = -1.0;
1662 
1663 		if( bHasTextGrouping )
1664 			pResultSet->getPropertyValue(nHandleTextGrouping) >>= nTextGrouping;
1665 
1666 		if( bHasAnimateForm )
1667 			pResultSet->getPropertyValue(nHandleAnimateForm) >>= bAnimateForm;
1668 
1669 		if( bHasTextGroupingAuto )
1670 			pResultSet->getPropertyValue(nHandleTextGroupingAuto) >>= fTextGroupingAuto;
1671 
1672 		if( bHasTextReverse )
1673 			pResultSet->getPropertyValue(nHandleTextReverse) >>= bTextReverse;
1674 
1675 		EffectSequence const aSelectedEffects( maListSelection );
1676 		EffectSequence::const_iterator iter( aSelectedEffects.begin() );
1677 		const EffectSequence::const_iterator iEnd( aSelectedEffects.end() );
1678 		while( iter != iEnd )
1679 		{
1680 			CustomAnimationEffectPtr const& pEffect = (*iter++);
1681 
1682 			EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
1683 			if( !pEffectSequence )
1684 				pEffectSequence = mpMainSequence.get();
1685 
1686 			sal_Int32 nGroupId = pEffect->getGroupId();
1687 			CustomAnimationTextGroupPtr pTextGroup;
1688 			if( (nGroupId != -1) )
1689 			{
1690 				// use existing group
1691 				pTextGroup = pEffectSequence->findGroup( nGroupId );
1692 			}
1693 			else
1694 			{
1695 				// somethings changed so we need a group now
1696 				pTextGroup = pEffectSequence->createTextGroup( pEffect, nTextGrouping, fTextGroupingAuto, bAnimateForm, bTextReverse );
1697 				bChanged = true;
1698 			}
1699 
1700 			//#Bug 119988#
1701 			/************************************************************************/
1702 			/*
1703 			Note, the setAnimateForm means set the animation from TextGroup to Object's Shape
1704 			And on the UI in means "Animate attached shape" in "Effect Option" dialog
1705 			The setTextGrouping means set animation to Object's Text,
1706 			the nTextGrouping is Text Animation Type
1707 			nTextGrouping = -1 is "As one Object", means no text animation.
1708 
1709 			The previous call order first do the setTextGrouping and then do the setAnimateForm,
1710 			that will cause such defect: in the setTextGrouping, the effect has been removed,
1711 			but in setAnimateForm still need this effect, then a NULL pointer of that effect will
1712 			be gotten, and cause crash.
1713 
1714 			[]bHasAnimateForm means the UI has changed, bAnimateForm is it value
1715 
1716 			So if create a new textgroup animation, the following animation will never be run!
1717 			Since the ��Animate attached shape�� is default checked.
1718 			And the bHasAnimateForm default is false, and if user uncheck it the value bAnimateForm will be false,
1719 			it same as the TextGroup��s default value, also could not be run setAnimateForm.
1720 			if( bHasAnimateForm )
1721 			{
1722 			if( pTextGroup->getAnimateForm() != bAnimateForm )
1723 			{
1724 			pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1725 			bChanged = true;
1726 			}
1727 			}
1728 
1729 			In setTextGrouping, there are three case:
1730 			1.	Create new text effects for empty TextGroup
1731 			2.	Remove all text effects of TextGroup (nTextGrouping == -1)
1732 			3.	Change all the text effects�� start type
1733 
1734 			So here is the right logic:
1735 			If set the animation from text to shape and remove text animation,
1736 			should do setAnimateForm first, then do setTextGrouping.
1737 			Other case,do setTextGrouping first, then do setAnimateForm.
1738 
1739 			*/
1740 			/************************************************************************/
1741 
1742 			bool	bDoSetAnimateFormFirst = false;
1743 			bool	bNeedDoSetAnimateForm = false;
1744 
1745 			if( bHasAnimateForm )
1746 			{
1747 				if( pTextGroup->getAnimateForm() != bAnimateForm )
1748 				{
1749 					if( (pTextGroup->getTextGrouping() >= 0) && (nTextGrouping == -1 ) )
1750 					{
1751 						bDoSetAnimateFormFirst = true;
1752 					}
1753 					bNeedDoSetAnimateForm = true;
1754 				}
1755 			}
1756 
1757 			if (bDoSetAnimateFormFirst)
1758 			{
1759 				pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1760 				bChanged = true;
1761 			}
1762 
1763 			if( bHasTextGrouping )
1764 			{
1765 				if( (pTextGroup->getTextGrouping() != nTextGrouping) )
1766 				{
1767 					pEffectSequence->setTextGrouping( pTextGroup, nTextGrouping );
1768 					bChanged = true;
1769 				}
1770 			}
1771 
1772 			if (!bDoSetAnimateFormFirst&&bNeedDoSetAnimateForm)
1773 			{
1774 				pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1775 				bChanged = true;
1776 			}
1777 
1778 			if( bHasTextGroupingAuto )
1779 			{
1780 				if( pTextGroup->getTextGroupingAuto() != fTextGroupingAuto )
1781 				{
1782 					pEffectSequence->setTextGroupingAuto( pTextGroup, fTextGroupingAuto );
1783 					bChanged = true;
1784 				}
1785 			}
1786 
1787 			if( bHasTextReverse )
1788 			{
1789 				if( pTextGroup->getTextReverse() != bTextReverse )
1790 				{
1791 					pEffectSequence->setTextReverse( pTextGroup, bTextReverse );
1792 					bChanged = true;
1793 				}
1794 			}
1795 		}
1796 	}
1797 
1798 	if( bChanged )
1799 	{
1800 		mpMainSequence->rebuild();
1801 		updateControls();
1802 		mrBase.GetDocShell()->SetModified();
1803 	}
1804 }
1805 
1806 void CustomAnimationPane::showOptions( sal_uInt16 nPage /* = 0 */ )
1807 {
1808 	STLPropertySet* pSet = createSelectionSet();
1809 
1810 	CustomAnimationDialog* pDlg = new CustomAnimationDialog( this, pSet, nPage );
1811 	if( pDlg->Execute() )
1812 	{
1813 		addUndo();
1814 		changeSelection( pDlg->getResultSet(), pSet );
1815 		updateControls();
1816 	}
1817 
1818 	delete pDlg;
1819 }
1820 
1821 void CustomAnimationPane::onChangeCurrentPage()
1822 {
1823 	if( mxView.is() ) try
1824 	{
1825 		Reference< XDrawPage > xNewPage( mxView->getCurrentPage() );
1826 		if( xNewPage != mxCurrentPage )
1827 		{
1828 			mxCurrentPage = xNewPage;
1829 			SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
1830 			if( pPage )
1831 			{
1832 				mpMainSequence = pPage->getMainSequence();
1833 				mpCustomAnimationList->update( mpMainSequence );
1834 			}
1835 			updateControls();
1836 		}
1837 	}
1838 	catch( Exception& )
1839 	{
1840 		DBG_ERROR( "sd::CustomAnimationPane::onChangeCurrentPage(), exception catched!" );
1841 	}
1842 }
1843 
1844 bool getTextSelection( const Any& rSelection, Reference< XShape >& xShape, std::list< sal_Int16 >& rParaList )
1845 {
1846 	Reference< XTextRange > xSelectedText;
1847 	rSelection >>= xSelectedText;
1848 	if( xSelectedText.is() ) try
1849 	{
1850 		xShape.set( xSelectedText->getText(), UNO_QUERY_THROW );
1851 
1852 		Reference< XTextRangeCompare > xTextRangeCompare( xShape, UNO_QUERY_THROW );
1853 		Reference< XEnumerationAccess > xParaEnumAccess( xShape, UNO_QUERY_THROW );
1854 		Reference< XEnumeration > xParaEnum( xParaEnumAccess->createEnumeration(), UNO_QUERY_THROW );
1855 		Reference< XTextRange > xRange;
1856 		Reference< XTextRange > xStart( xSelectedText->getStart() );
1857 		Reference< XTextRange > xEnd( xSelectedText->getEnd() );
1858 
1859 		if( xTextRangeCompare->compareRegionEnds( xStart, xEnd ) < 0 )
1860 		{
1861 			Reference< XTextRange > xTemp( xStart );
1862 			xStart = xEnd;
1863 			xEnd = xTemp;
1864 		}
1865 
1866 		sal_Int16 nPara = 0;
1867 		while( xParaEnum->hasMoreElements() )
1868 		{
1869 			xParaEnum->nextElement() >>= xRange;
1870 
1871 			// break if start of selection is prior to end of current paragraph
1872 			if( xRange.is() && (xTextRangeCompare->compareRegionEnds( xStart, xRange ) >= 0 ) )
1873 				break;
1874 
1875 			nPara++;
1876 		}
1877 
1878 		while( xRange.is() )
1879 		{
1880 			if( xRange.is() && xRange->getString().getLength() )
1881 				rParaList.push_back( nPara );
1882 
1883 			// break if end of selection is before or at end of current paragraph
1884 			if( xRange.is() && xTextRangeCompare->compareRegionEnds( xEnd, xRange ) >= 0 )
1885 				break;
1886 
1887 			nPara++;
1888 
1889 			if( xParaEnum->hasMoreElements() )
1890 				xParaEnum->nextElement() >>= xRange;
1891 			else
1892 				xRange.clear();
1893 		}
1894 
1895 		return true;
1896 	}
1897 	catch( Exception& e )
1898 	{
1899 		(void)e;
1900 		DBG_ERROR( "sd::CustomAnimationPane::getTextSelection(), exception cought!" );
1901 	}
1902 
1903 	return false;
1904 }
1905 
1906 void CustomAnimationPane::onChange( bool bCreate )
1907 {
1908 	bool bHasText = true;
1909 
1910 	// first create vector of targets for dialog preview
1911 	std::vector< Any > aTargets;
1912 	OUString sPresetId;
1913 	double fDuration = 2.0f;
1914 
1915 	if( bCreate )
1916 	{
1917 		// gather shapes from the selection
1918 		Reference< XSelectionSupplier >  xSel( mxView, UNO_QUERY_THROW );
1919 		maViewSelection = xSel->getSelection();
1920 
1921 		if( maViewSelection.getValueType() == ::getCppuType((const Reference< XShapes >*)0) )
1922 		{
1923 			Reference< XIndexAccess > xShapes;
1924 			maViewSelection >>= xShapes;
1925 
1926 			sal_Int32 nCount = xShapes->getCount();
1927 			sal_Int32 nIndex;
1928 			for( nIndex = 0; nIndex < nCount; nIndex++ )
1929 			{
1930 				Any aTarget( xShapes->getByIndex( nIndex ) );
1931 				aTargets.push_back( aTarget );
1932 				if( bHasText )
1933 				{
1934 					Reference< XText > xText;
1935 					aTarget >>= xText;
1936 					if( !xText.is() || xText->getString().getLength() == 0 )
1937 						bHasText = false;
1938 				}
1939 			}
1940 		}
1941 		else if ( maViewSelection.getValueType() == ::getCppuType((const Reference< XShape >*)0) )
1942 		{
1943 			aTargets.push_back( maViewSelection );
1944 			Reference< XText > xText;
1945 			maViewSelection >>= xText;
1946 			if( !xText.is() || xText->getString().getLength() == 0 )
1947 				bHasText = false;
1948 		}
1949 		else if ( maViewSelection.getValueType() == ::getCppuType((const Reference< XTextCursor >*)0) )
1950 		{
1951 			Reference< XShape > xShape;
1952 			std::list< sal_Int16 > aParaList;
1953 			if( getTextSelection( maViewSelection, xShape, aParaList ) )
1954 			{
1955 				ParagraphTarget aParaTarget;
1956 				aParaTarget.Shape = xShape;
1957 
1958 				std::list< sal_Int16 >::iterator aIter( aParaList.begin() );
1959 				for( ; aIter != aParaList.end(); aIter++ )
1960 				{
1961 					aParaTarget.Paragraph = (*aIter);
1962 					aTargets.push_back( makeAny( aParaTarget ) );
1963    				}
1964 			}
1965 		}
1966 		else
1967 		{
1968 			DBG_ERROR("sd::CustomAnimationPane::onChange(), unknown view selection!" );
1969 			return;
1970 		}
1971 	}
1972 	else
1973 	{
1974 		// get selected effect
1975 		EffectSequence::iterator aIter( maListSelection.begin() );
1976 		const EffectSequence::iterator aEnd( maListSelection.end() );
1977 		while( aIter != aEnd )
1978 		{
1979 			if( !bHasText || !(*aIter)->hasText() )
1980 				bHasText = false;
1981 
1982 			if( sPresetId.getLength() == 0 )
1983 			{
1984 				sPresetId = (*aIter)->getPresetId();
1985 				fDuration = (*aIter)->getDuration();
1986 			}
1987 
1988 			aTargets.push_back( (*aIter++)->getTarget() );
1989 		}
1990 	}
1991 
1992 	CustomAnimationCreateDialog* pDlg = new CustomAnimationCreateDialog( this, this, aTargets, bHasText, sPresetId, fDuration );
1993 	if( pDlg->Execute() )
1994 	{
1995 		addUndo();
1996 		fDuration = pDlg->getSelectedDuration();
1997 		CustomAnimationPresetPtr pDescriptor = pDlg->getSelectedPreset();
1998 		if( pDescriptor.get() )
1999 		{
2000 			if( bCreate )
2001 			{
2002 				mpCustomAnimationList->SelectAll( sal_False );
2003 
2004 				// gather shapes from the selection
2005 				std::vector< Any >::iterator aIter( aTargets.begin() );
2006 				const std::vector< Any >::iterator aEnd( aTargets.end() );
2007 				bool bFirst = true;
2008 				for( ; aIter != aEnd; aIter++ )
2009 				{
2010 					CustomAnimationEffectPtr pCreated = mpMainSequence->append( pDescriptor, (*aIter), fDuration );
2011 
2012 					// if only one shape with text and no fill or outline is selected, animate only by first level paragraphs
2013 					if( bHasText && (aTargets.size() == 1) )
2014 					{
2015 						Reference< XShape > xShape( (*aIter), UNO_QUERY );
2016 						if( xShape.is() && !hasVisibleShape( xShape ) )
2017 						{
2018 							mpMainSequence->createTextGroup( pCreated, 1, -1.0, sal_False, sal_False );
2019 						}
2020 					}
2021 
2022 					if( bFirst )
2023 						bFirst = false;
2024 					else
2025 						pCreated->setNodeType( EffectNodeType::WITH_PREVIOUS );
2026 
2027 					if( pCreated.get() )
2028 					{
2029 						mpCustomAnimationList->select( pCreated );
2030 					}
2031 				}
2032 			}
2033 			else
2034 			{
2035 				MainSequenceRebuildGuard aGuard( mpMainSequence );
2036 
2037 				// get selected effect
2038 				EffectSequence::iterator aIter( maListSelection.begin() );
2039 				const EffectSequence::iterator aEnd( maListSelection.end() );
2040 				while( aIter != aEnd )
2041 				{
2042 					CustomAnimationEffectPtr pEffect = (*aIter++);
2043 
2044 					EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
2045 					if( !pEffectSequence )
2046 						pEffectSequence = mpMainSequence.get();
2047 
2048 					pEffectSequence->replace( pEffect, pDescriptor, fDuration );
2049 				}
2050 			}
2051 		}
2052 		else
2053 		{
2054 			PathKind eKind = pDlg->getCreatePathKind();
2055 			if( eKind != NONE )
2056 				createPath( eKind, aTargets, fDuration );
2057 		}
2058 		mrBase.GetDocShell()->SetModified();
2059 	}
2060 
2061 	delete pDlg;
2062 
2063 	updateControls();
2064 
2065 	// stop running preview from dialog
2066 	SlideShow::Stop( mrBase );
2067 }
2068 
2069 void CustomAnimationPane::createPath( PathKind eKind, std::vector< Any >& rTargets, double fDuration)
2070 {
2071 	sal_uInt16 nSID = 0;
2072 
2073 	switch( eKind )
2074 	{
2075 	case CURVE:		nSID = SID_DRAW_BEZIER_NOFILL; break;
2076 	case POLYGON:	nSID = SID_DRAW_POLYGON_NOFILL; break;
2077 	case FREEFORM:	nSID = SID_DRAW_FREELINE_NOFILL; break;
2078 	default: break;
2079 	}
2080 
2081 	if( nSID )
2082 	{
2083 		DrawViewShell* pViewShell = dynamic_cast< DrawViewShell* >(
2084 		    FrameworkHelper::Instance(mrBase)->GetViewShell(FrameworkHelper::msCenterPaneURL).get());
2085 
2086 		if( pViewShell )
2087 		{
2088 			DrawView* pView = pViewShell->GetDrawView();
2089 			if( pView )
2090 				pView->UnmarkAllObj();
2091 
2092 			std::vector< Any > aTargets( 1, Any( fDuration ) );
2093 			aTargets.insert( aTargets.end(), rTargets.begin(), rTargets.end() );
2094 			Sequence< Any > aTargetSequence( comphelper::containerToSequence( aTargets ) );
2095 			const SfxUnoAnyItem aItem( SID_ADD_MOTION_PATH, Any( aTargetSequence ) );
2096 			pViewShell->GetViewFrame()->GetDispatcher()->Execute( nSID, SFX_CALLMODE_ASYNCHRON, &aItem, 0 );
2097 		}
2098 	}
2099 }
2100 
2101 void CustomAnimationPane::onRemove()
2102 {
2103 	if( !maListSelection.empty() )
2104 	{
2105 		addUndo();
2106 
2107 		MainSequenceRebuildGuard aGuard( mpMainSequence );
2108 
2109 		EffectSequence aList( maListSelection );
2110 
2111 		EffectSequence::iterator aIter( aList.begin() );
2112 		const EffectSequence::iterator aEnd( aList.end() );
2113 		while( aIter != aEnd )
2114 		{
2115 			CustomAnimationEffectPtr pEffect = (*aIter++);
2116 			if( pEffect->getEffectSequence() )
2117 				pEffect->getEffectSequence()->remove( pEffect );
2118 		}
2119 
2120 		maListSelection.clear();
2121 		mrBase.GetDocShell()->SetModified();
2122 	}
2123 }
2124 
2125 void CustomAnimationPane::remove( CustomAnimationEffectPtr& pEffect )
2126 {
2127 	if( pEffect->getEffectSequence() )
2128 	{
2129 		addUndo();
2130 		pEffect->getEffectSequence()->remove( pEffect );
2131 		mrBase.GetDocShell()->SetModified();
2132 	}
2133 }
2134 
2135 void CustomAnimationPane::onChangeStart()
2136 {
2137 	if( mpLBStart->GetSelectEntryCount() == 1 )
2138 	{
2139 		sal_Int16 nNodeType;
2140 		sal_uInt16 nPos= mpLBStart->GetSelectEntryPos();
2141 		switch( nPos )
2142 		{
2143 		case 0:	nNodeType = EffectNodeType::ON_CLICK; break;
2144 		case 1:	nNodeType = EffectNodeType::WITH_PREVIOUS; break;
2145 		case 2:	nNodeType = EffectNodeType::AFTER_PREVIOUS; break;
2146 		default:
2147 			return;
2148 		}
2149 
2150 		onChangeStart( nNodeType );
2151 	}
2152 }
2153 
2154 void CustomAnimationPane::onChangeStart( sal_Int16 nNodeType )
2155 {
2156 	addUndo();
2157 
2158 	MainSequenceRebuildGuard aGuard( mpMainSequence );
2159 
2160 	bool bNeedRebuild = false;
2161 
2162 	EffectSequence::iterator aIter( maListSelection.begin() );
2163 	const EffectSequence::iterator aEnd( maListSelection.end() );
2164 	while( aIter != aEnd )
2165 	{
2166 		CustomAnimationEffectPtr pEffect = (*aIter++);
2167 		if( pEffect->getNodeType() != nNodeType )
2168 		{
2169 			pEffect->setNodeType( nNodeType );
2170 			bNeedRebuild = true;
2171 		}
2172 	}
2173 
2174 	if( bNeedRebuild )
2175 	{
2176 		mpMainSequence->rebuild();
2177 		updateControls();
2178 		mrBase.GetDocShell()->SetModified();
2179 	}
2180 }
2181 
2182 void CustomAnimationPane::onChangeProperty()
2183 {
2184 	if( mpLBProperty->getSubControl() )
2185 	{
2186 		addUndo();
2187 
2188 		MainSequenceRebuildGuard aGuard( mpMainSequence );
2189 
2190 		const Any aValue( mpLBProperty->getSubControl()->getValue() );
2191 
2192 		bool bNeedUpdate = false;
2193 
2194 		// change selected effect
2195 		EffectSequence::iterator aIter( maListSelection.begin() );
2196 		const EffectSequence::iterator aEnd( maListSelection.end() );
2197 		while( aIter != aEnd )
2198 		{
2199 			CustomAnimationEffectPtr pEffect = (*aIter++);
2200 
2201 			if( setProperty1Value( mnPropertyType, pEffect, aValue ) )
2202 				bNeedUpdate = true;
2203 		}
2204 
2205 		if( bNeedUpdate )
2206 		{
2207 			mpMainSequence->rebuild();
2208 			updateControls();
2209 			mrBase.GetDocShell()->SetModified();
2210 		}
2211 
2212 		onPreview( false );
2213 	}
2214 }
2215 
2216 void CustomAnimationPane::onChangeSpeed()
2217 {
2218 	if( mpCBSpeed->GetSelectEntryCount() == 1 )
2219 	{
2220 		addUndo();
2221 
2222 		MainSequenceRebuildGuard aGuard( mpMainSequence );
2223 
2224 		double fDuration;
2225 
2226 		sal_uInt16 nPos= mpCBSpeed->GetSelectEntryPos();
2227 
2228 		switch( nPos )
2229 		{
2230 		case 0: fDuration = 5.0; break;
2231 		case 1: fDuration = 3.0; break;
2232 		case 2: fDuration = 2.0; break;
2233 		case 3: fDuration = 1.0; break;
2234 		case 4: fDuration = 0.5; break;
2235 		default:
2236 			return;
2237 		}
2238 
2239 		// change selected effect
2240 		EffectSequence::iterator aIter( maListSelection.begin() );
2241 		const EffectSequence::iterator aEnd( maListSelection.end() );
2242 		while( aIter != aEnd )
2243 		{
2244 			CustomAnimationEffectPtr pEffect = (*aIter++);
2245 			pEffect->setDuration( fDuration );
2246 		}
2247 
2248 		mpMainSequence->rebuild();
2249 		updateControls();
2250 		mrBase.GetDocShell()->SetModified();
2251 
2252 		onPreview( false );
2253 	}
2254 }
2255 
2256 /// this link is called when the property box is modified by the user
2257 IMPL_LINK( CustomAnimationPane, implPropertyHdl, Control*, EMPTYARG )
2258 {
2259 	onChangeProperty();
2260 	return 0;
2261 }
2262 
2263 /// this link is called when one of the controls is modified
2264 IMPL_LINK( CustomAnimationPane, implControlHdl, Control*, pControl )
2265 {
2266 	if( pControl == mpPBAddEffect )
2267 		onChange(true);
2268 	else if( pControl == mpPBChangeEffect )
2269 		onChange(false);
2270 	else if( pControl == mpPBRemoveEffect )
2271 		onRemove();
2272 	else if( pControl == mpLBStart )
2273 		onChangeStart();
2274 	else if( pControl == mpCBSpeed )
2275 		onChangeSpeed();
2276 	else if( pControl == mpPBPropertyMore )
2277 		showOptions();
2278 	else if( pControl == mpPBMoveUp )
2279 		moveSelection( true );
2280 	else if( pControl == mpPBMoveDown )
2281 		moveSelection( false );
2282 	else if( pControl == mpPBPlay )
2283 		onPreview( true );
2284 	else if( pControl == mpPBSlideShow )
2285 	{
2286 		mrBase.StartPresentation();
2287 	}
2288 	else if( pControl == mpCBAutoPreview )
2289 	{
2290 		SdOptions* pOptions = SD_MOD()->GetSdOptions(DOCUMENT_TYPE_IMPRESS);
2291 		pOptions->SetPreviewChangedEffects( mpCBAutoPreview->IsChecked() ? sal_True : sal_False );
2292 	}
2293 
2294 	updateControls();
2295 
2296 	return 0;
2297 }
2298 
2299 IMPL_LINK(CustomAnimationPane, lateInitCallback, Timer*, EMPTYARG )
2300 {
2301     // Call getPresets() to initiate the (expensive) construction of the
2302     // presets list.
2303     getPresets();
2304 
2305     // update selection and control states
2306     onSelectionChanged();
2307 
2308     return 0;
2309 }
2310 
2311 void CustomAnimationPane::moveSelection( bool bUp )
2312 {
2313 	if( maListSelection.empty() )
2314 		return;
2315 
2316 	EffectSequenceHelper* pSequence = maListSelection.front()->getEffectSequence();
2317 	if( pSequence == 0 )
2318 		return;
2319 
2320 	addUndo();
2321 
2322 	bool bChanged = false;
2323 
2324 	MainSequenceRebuildGuard aGuard( mpMainSequence );
2325 	EffectSequence& rEffectSequence = pSequence->getSequence();
2326 
2327 	if( bUp )
2328 	{
2329 		EffectSequence::iterator aIter( maListSelection.begin() );
2330 		const EffectSequence::iterator aEnd( maListSelection.end() );
2331 
2332 		while( aIter != aEnd )
2333 		{
2334 			CustomAnimationEffectPtr pEffect = (*aIter++);
2335 
2336 			EffectSequence::iterator aEffectPos( pSequence->find( pEffect ) );
2337 			if( aEffectPos != rEffectSequence.end() )
2338 			{
2339 				EffectSequence::iterator aInsertPos( rEffectSequence.erase( aEffectPos ) );
2340 
2341 				if( aInsertPos != rEffectSequence.begin() )
2342 				{
2343 					aInsertPos--;
2344 					while( (aInsertPos != rEffectSequence.begin()) && !mpCustomAnimationList->isExpanded(*aInsertPos))
2345 						aInsertPos--;
2346 
2347 					rEffectSequence.insert( aInsertPos, pEffect );
2348 				}
2349 				else
2350 				{
2351 					rEffectSequence.push_front( pEffect );
2352 				}
2353 				bChanged = true;
2354 			}
2355 		}
2356 	}
2357 	else
2358 	{
2359 		EffectSequence::reverse_iterator aIter( maListSelection.rbegin() );
2360 		const EffectSequence::reverse_iterator aEnd( maListSelection.rend() );
2361 
2362 		while( aIter != aEnd )
2363 		{
2364 			CustomAnimationEffectPtr pEffect = (*aIter++);
2365 
2366 			EffectSequence::iterator aEffectPos( pSequence->find( pEffect ) );
2367 			if( aEffectPos != rEffectSequence.end() )
2368 			{
2369 				EffectSequence::iterator aInsertPos( rEffectSequence.erase( aEffectPos ) );
2370 
2371 				if( aInsertPos != rEffectSequence.end() )
2372 				{
2373 					aInsertPos++;
2374 					while( (aInsertPos != rEffectSequence.end()) && !mpCustomAnimationList->isExpanded(*aInsertPos))
2375 						aInsertPos++;
2376 
2377 					rEffectSequence.insert( aInsertPos, pEffect );
2378 				}
2379 				else
2380 				{
2381 					rEffectSequence.push_back( pEffect );
2382 				}
2383 				bChanged = true;
2384 			}
2385 		}
2386 	}
2387 
2388 	if( bChanged )
2389 	{
2390 		mpMainSequence->rebuild();
2391 		updateControls();
2392 		mrBase.GetDocShell()->SetModified();
2393 	}
2394 }
2395 
2396 void CustomAnimationPane::onPreview( bool bForcePreview )
2397 {
2398 	if( !bForcePreview && !mpCBAutoPreview->IsChecked() )
2399 		return;
2400 
2401 	if( maListSelection.empty() )
2402 	{
2403 		rtl::Reference< MotionPathTag > xMotionPathTag;
2404 		MotionPathTagVector::iterator aIter;
2405 		for( aIter = maMotionPathTags.begin(); aIter != maMotionPathTags.end(); aIter++ )
2406 		{
2407 			if( (*aIter)->isSelected() )
2408 			{
2409 				xMotionPathTag = (*aIter);
2410 				break;
2411 			}
2412 		}
2413 
2414 		if( xMotionPathTag.is() )
2415 		{
2416 			MainSequencePtr pSequence( new MainSequence() );
2417 			pSequence->append( xMotionPathTag->getEffect()->clone() );
2418 			preview( pSequence->getRootNode() );
2419 		}
2420 		else
2421 		{
2422 			Reference< XAnimationNodeSupplier > xNodeSupplier( mxCurrentPage, UNO_QUERY );
2423 			if( !xNodeSupplier.is() )
2424 				return;
2425 
2426 			preview( xNodeSupplier->getAnimationNode() );
2427 		}
2428 	}
2429 	else
2430 	{
2431 		MainSequencePtr pSequence( new MainSequence() );
2432 
2433 		EffectSequence::iterator aIter( maListSelection.begin() );
2434 		const EffectSequence::iterator aEnd( maListSelection.end() );
2435 
2436 		while( aIter != aEnd )
2437 		{
2438 			CustomAnimationEffectPtr pEffect = (*aIter++);
2439 			pSequence->append( pEffect->clone() );
2440 		}
2441 
2442 		preview( pSequence->getRootNode() );
2443 	}
2444 }
2445 
2446 void CustomAnimationPane::preview( const Reference< XAnimationNode >& xAnimationNode )
2447 {
2448 	Reference< XTimeContainer > xRoot(::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer"))), UNO_QUERY);
2449 	if( xRoot.is() )
2450 	{
2451 		Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
2452 		aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
2453 		aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::TIMING_ROOT;
2454 		xRoot->setUserData( aUserData );
2455 		xRoot->appendChild( xAnimationNode );
2456 
2457 		Reference< XAnimationNode > xNode( xRoot, UNO_QUERY );
2458 		SlideShow::StartPreview( mrBase, mxCurrentPage, xNode );
2459 	}
2460 }
2461 
2462 
2463 // ICustomAnimationListController
2464 void CustomAnimationPane::onSelect()
2465 {
2466 	maListSelection = mpCustomAnimationList->getSelection();
2467 	updateControls();
2468 	markShapesFromSelectedEffects();
2469 }
2470 
2471 
2472 
2473 
2474 const CustomAnimationPresets& CustomAnimationPane::getPresets (void)
2475 {
2476     if (mpCustomAnimationPresets == NULL)
2477         mpCustomAnimationPresets = &CustomAnimationPresets::getCustomAnimationPresets();
2478     return *mpCustomAnimationPresets;
2479 }
2480 
2481 
2482 
2483 void CustomAnimationPane::markShapesFromSelectedEffects()
2484 {
2485 	if( !maSelectionLock.isLocked() )
2486 	{
2487 		ScopeLockGuard aGuard( maSelectionLock );
2488 		DrawViewShell* pViewShell = dynamic_cast< DrawViewShell* >(
2489 			FrameworkHelper::Instance(mrBase)->GetViewShell(FrameworkHelper::msCenterPaneURL).get());
2490 		DrawView* pView = pViewShell ? pViewShell->GetDrawView() : NULL;
2491 
2492 		if( pView )
2493 		{
2494 			pView->UnmarkAllObj();
2495 			EffectSequence::iterator aIter( maListSelection.begin() );
2496 			const EffectSequence::iterator aEnd( maListSelection.end() );
2497 			while( aIter != aEnd )
2498 			{
2499 				CustomAnimationEffectPtr pEffect = (*aIter++);
2500 
2501 				Reference< XShape > xShape( pEffect->getTargetShape() );
2502 				SdrObject* pObj = GetSdrObjectFromXShape( xShape );
2503 				if( pObj )
2504 					pView->MarkObj(pObj, pView->GetSdrPageView(), sal_False, sal_False);
2505 			}
2506 		}
2507 	}
2508 }
2509 
2510 
2511 void CustomAnimationPane::updatePathFromMotionPathTag( const rtl::Reference< MotionPathTag >& xTag )
2512 {
2513 	MainSequenceRebuildGuard aGuard( mpMainSequence );
2514 	if( xTag.is() )
2515 	{
2516 		SdrPathObj* pPathObj = xTag->getPathObj();
2517 		CustomAnimationEffectPtr pEffect = xTag->getEffect();
2518 		if( (pPathObj != 0) && pEffect.get() != 0 )
2519 		{
2520 			::svl::IUndoManager* pManager = mrBase.GetDocShell()->GetUndoManager();
2521 			if( pManager )
2522 			{
2523 				SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
2524 				if( pPage )
2525 					pManager->AddUndoAction( new UndoAnimationPath( mrBase.GetDocShell()->GetDoc(), pPage, pEffect->getNode() ) );
2526 			}
2527 
2528 			pEffect->updatePathFromSdrPathObj( *pPathObj );
2529 		}
2530 	}
2531 }
2532 
2533 // ====================================================================
2534 
2535 ::Window * createCustomAnimationPanel( ::Window* pParent, ViewShellBase& rBase )
2536 {
2537 	DialogListBox* pWindow = 0;
2538 
2539 	DrawDocShell* pDocSh = rBase.GetDocShell();
2540 	if( pDocSh )
2541 	{
2542 		pWindow = new DialogListBox( pParent, WB_CLIPCHILDREN|WB_TABSTOP|WB_AUTOHSCROLL );
2543 
2544 		Size aMinSize( pWindow->LogicToPixel( Size( 80, 256 ), MAP_APPFONT ) );
2545 		::Window* pPaneWindow = new CustomAnimationPane( pWindow, rBase, aMinSize );
2546 		pWindow->SetChildWindow( pPaneWindow, aMinSize );
2547 		pWindow->SetText( pPaneWindow->GetText() );
2548 	}
2549 
2550 	return pWindow;
2551 }
2552 
2553 
2554 
2555 }
2556