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