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( bool(mrBase.GetMainViewShell()) )
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     const Wallpaper aBackground (
1094         ::sfx2::sidebar::Theme::GetWallpaper(
1095             ::sfx2::sidebar::Theme::Paint_PanelBackground));
1096     SetBackground(aBackground);
1097     if (mpFLModify != NULL)
1098         mpFLModify->SetBackground(aBackground);
1099 	if (mpFLEffect != NULL)
1100         mpFLEffect->SetBackground(aBackground);
1101 	if (mpFTStart != NULL)
1102         mpFTStart->SetBackground(aBackground);
1103     if (mpFTProperty != NULL)
1104         mpFTProperty->SetBackground(aBackground);
1105     if (mpFTSpeed != NULL)
1106         mpFTSpeed->SetBackground(aBackground);
1107 	if (mpFTChangeOrder != NULL)
1108         mpFTChangeOrder->SetBackground(aBackground);
1109 	if (mpFLSeperator1 != NULL)
1110         mpFLSeperator1->SetBackground(aBackground);
1111     if (mpFLSeperator2 != NULL)
1112         mpFLSeperator2->SetBackground(aBackground);
1113 }
1114 
1115 
1116 
1117 
1118 void addValue( STLPropertySet* pSet, sal_Int32 nHandle, const Any& rValue )
1119 {
1120 	switch( pSet->getPropertyState( nHandle ) )
1121 	{
1122 	case STLPropertyState_AMBIGUOUS:
1123 		// value is already ambiguous, do nothing
1124 		break;
1125 	case STLPropertyState_DIRECT:
1126 		// set to ambiguous if existing value is different
1127 		if( rValue != pSet->getPropertyValue( nHandle ) )
1128 			pSet->setPropertyState( nHandle, STLPropertyState_AMBIGUOUS );
1129 		break;
1130 	case STLPropertyState_DEFAULT:
1131 		// just set new value
1132 		pSet->setPropertyValue( nHandle, rValue );
1133 		break;
1134 	}
1135 }
1136 
1137 static sal_Int32 calcMaxParaDepth( Reference< XShape > xTargetShape )
1138 {
1139 	sal_Int32 nMaxParaDepth = -1;
1140 
1141 	if( xTargetShape.is() )
1142 	{
1143 		Reference< XEnumerationAccess > xText( xTargetShape, UNO_QUERY );
1144 		if( xText.is() )
1145 		{
1146 			Reference< XPropertySet > xParaSet;
1147 			const OUString strNumberingLevel( RTL_CONSTASCII_USTRINGPARAM("NumberingLevel") );
1148 
1149 			Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_QUERY_THROW );
1150 			while( xEnumeration->hasMoreElements() )
1151 			{
1152 				xEnumeration->nextElement() >>= xParaSet;
1153 				if( xParaSet.is() )
1154 				{
1155 					sal_Int32 nParaDepth = 0;
1156 					xParaSet->getPropertyValue( strNumberingLevel ) >>= nParaDepth;
1157 
1158 					if( nParaDepth > nMaxParaDepth )
1159 						nMaxParaDepth = nParaDepth;
1160 				}
1161 			}
1162 		}
1163 	}
1164 
1165 	return nMaxParaDepth + 1;
1166 }
1167 
1168 Any CustomAnimationPane::getProperty1Value( sal_Int32 nType, CustomAnimationEffectPtr pEffect )
1169 {
1170 	switch( nType )
1171 	{
1172 	case nPropertyTypeDirection:
1173 	case nPropertyTypeSpokes:
1174 	case nPropertyTypeZoom:
1175 		return makeAny( pEffect->getPresetSubType() );
1176 
1177 	case nPropertyTypeColor:
1178 	case nPropertyTypeFillColor:
1179 	case nPropertyTypeFirstColor:
1180 	case nPropertyTypeSecondColor:
1181 	case nPropertyTypeCharColor:
1182 	case nPropertyTypeLineColor:
1183 		{
1184 			const sal_Int32 nIndex = (nPropertyTypeFirstColor == nType) ? 0 : 1;
1185 			return pEffect->getColor( nIndex );
1186 		}
1187 
1188 	case nPropertyTypeFont:
1189 		return pEffect->getProperty( AnimationNodeType::SET, OUString( RTL_CONSTASCII_USTRINGPARAM("CharFontName") ), VALUE_TO );
1190 
1191 	case nPropertyTypeCharHeight:
1192 		{
1193 			const OUString aAttributeName( RTL_CONSTASCII_USTRINGPARAM( "CharHeight" ) );
1194             Any aValue( pEffect->getProperty( AnimationNodeType::SET, aAttributeName, VALUE_TO ) );
1195 			if( !aValue.hasValue() )
1196 				aValue = pEffect->getProperty( AnimationNodeType::ANIMATE, aAttributeName, VALUE_TO );
1197 			return aValue;
1198 		}
1199 
1200 	case nPropertyTypeRotate:
1201 		return pEffect->getTransformationProperty( AnimationTransformType::ROTATE, VALUE_BY);
1202 
1203 	case nPropertyTypeTransparency:
1204 		return pEffect->getProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("Opacity")), VALUE_TO );
1205 
1206 	case nPropertyTypeScale:
1207 		return pEffect->getTransformationProperty( AnimationTransformType::SCALE, VALUE_BY );
1208 
1209 	case nPropertyTypeCharDecoration:
1210 		{
1211 			Sequence< Any > aValues(3);
1212 			aValues[0] = pEffect->getProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharWeight")), VALUE_TO );
1213 			aValues[1] = pEffect->getProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharPosture")), VALUE_TO );
1214 			aValues[2] = pEffect->getProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharUnderline")), VALUE_TO );
1215 			return makeAny( aValues );
1216 		}
1217 	}
1218 
1219 	Any aAny;
1220 	return aAny;
1221 }
1222 
1223 bool CustomAnimationPane::setProperty1Value( sal_Int32 nType, CustomAnimationEffectPtr pEffect, const Any& rValue )
1224 {
1225 	bool bEffectChanged = false;
1226 	switch( nType )
1227 	{
1228 	case nPropertyTypeDirection:
1229 	case nPropertyTypeSpokes:
1230 	case nPropertyTypeZoom:
1231 		{
1232 			OUString aPresetSubType;
1233 			rValue >>= aPresetSubType;
1234 			if( aPresetSubType != pEffect->getPresetSubType() )
1235 			{
1236 				getPresets().changePresetSubType( pEffect, aPresetSubType );
1237 				bEffectChanged = true;
1238 			}
1239 		}
1240 		break;
1241 
1242 	case nPropertyTypeFillColor:
1243 	case nPropertyTypeColor:
1244 	case nPropertyTypeFirstColor:
1245 	case nPropertyTypeSecondColor:
1246 	case nPropertyTypeCharColor:
1247 	case nPropertyTypeLineColor:
1248 		{
1249 			const sal_Int32 nIndex = (nPropertyTypeFirstColor == nType) ? 0 : 1;
1250 			Any aOldColor( pEffect->getColor( nIndex ) );
1251 			if( aOldColor != rValue )
1252 			{
1253 				pEffect->setColor( nIndex, rValue );
1254 				bEffectChanged = true;
1255 			}
1256 		}
1257 		break;
1258 
1259 	case nPropertyTypeFont:
1260 		bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, OUString( RTL_CONSTASCII_USTRINGPARAM( "CharFontName" ) ), VALUE_TO, rValue );
1261 		break;
1262 
1263 	case nPropertyTypeCharHeight:
1264 		{
1265 			const OUString aAttributeName( RTL_CONSTASCII_USTRINGPARAM( "CharHeight" ) );
1266 			bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, aAttributeName, VALUE_TO, rValue );
1267 			if( !bEffectChanged )
1268 				bEffectChanged = pEffect->setProperty( AnimationNodeType::ANIMATE, aAttributeName, VALUE_TO, rValue );
1269 		}
1270 		break;
1271 	case nPropertyTypeRotate:
1272 		bEffectChanged = pEffect->setTransformationProperty( AnimationTransformType::ROTATE, VALUE_BY , rValue );
1273 		break;
1274 
1275 	case nPropertyTypeTransparency:
1276 		bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, OUString( RTL_CONSTASCII_USTRINGPARAM("Opacity") ), VALUE_TO, rValue );
1277 		break;
1278 
1279 	case nPropertyTypeScale:
1280 		bEffectChanged = pEffect->setTransformationProperty( AnimationTransformType::SCALE, VALUE_BY, rValue );
1281 		break;
1282 
1283 	case nPropertyTypeCharDecoration:
1284 		{
1285 			Sequence< Any > aValues(3);
1286 			rValue >>= aValues;
1287 			bEffectChanged = pEffect->setProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharWeight")), VALUE_TO, aValues[0] );
1288 			bEffectChanged |= pEffect->setProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharPosture")), VALUE_TO, aValues[1] );
1289 			bEffectChanged |= pEffect->setProperty( AnimationNodeType::SET, OUString(RTL_CONSTASCII_USTRINGPARAM("CharUnderline")), VALUE_TO, aValues[2] );
1290 		}
1291 		break;
1292 
1293 	}
1294 
1295 	return bEffectChanged;
1296 }
1297 
1298 static sal_Bool hasVisibleShape( const Reference< XShape >& xShape )
1299 {
1300 	try
1301 	{
1302 		const OUString sShapeType( xShape->getShapeType() );
1303 
1304 		if( sShapeType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation.TitleTextShape") ) ||
1305 			sShapeType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation.OutlinerShape") ) ||
1306 			sShapeType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.presentation.SubtitleShape") ) ||
1307 			sShapeType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.drawing.TextShape") ) )
1308 		{
1309 			const OUString sFillStyle( RTL_CONSTASCII_USTRINGPARAM("FillStyle" ) );
1310 			const OUString sLineStyle( RTL_CONSTASCII_USTRINGPARAM("LineStyle" ) );
1311 			Reference< XPropertySet > xSet( xShape, UNO_QUERY_THROW );
1312 
1313 			FillStyle eFillStyle;
1314 			xSet->getPropertyValue( sFillStyle ) >>= eFillStyle;
1315 
1316 			::com::sun::star::drawing::LineStyle eLineStyle;
1317 			xSet->getPropertyValue( sLineStyle ) >>= eLineStyle;
1318 
1319 			return eFillStyle != FillStyle_NONE || eLineStyle != ::com::sun::star::drawing::LineStyle_NONE;
1320 		}
1321 	}
1322 	catch( Exception& e )
1323 	{
1324 		(void)e;
1325 	}
1326 	return sal_True;
1327 }
1328 
1329 STLPropertySet* CustomAnimationPane::createSelectionSet()
1330 {
1331 	STLPropertySet* pSet = CustomAnimationDialog::createDefaultSet();
1332 
1333 	pSet->setPropertyValue( nHandleCurrentPage, makeAny( mxCurrentPage ) );
1334 
1335 	sal_Int32 nMaxParaDepth = 0;
1336 
1337 	// get options from selected effects
1338 	EffectSequence::iterator aIter( maListSelection.begin() );
1339 	const EffectSequence::iterator aEnd( maListSelection.end() );
1340     const CustomAnimationPresets& rPresets (getPresets());
1341     while( aIter != aEnd )
1342 	{
1343 		CustomAnimationEffectPtr pEffect = (*aIter++);
1344 
1345 		EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
1346 		if( !pEffectSequence )
1347 			pEffectSequence = mpMainSequence.get();
1348 
1349 		if( pEffect->hasText() )
1350 		{
1351 			sal_Int32 n = calcMaxParaDepth(pEffect->getTargetShape());
1352 			if( n > nMaxParaDepth )
1353 				nMaxParaDepth = n;
1354 		}
1355 
1356 		addValue( pSet, nHandleHasAfterEffect, makeAny( pEffect->hasAfterEffect() ) );
1357 		addValue( pSet, nHandleAfterEffectOnNextEffect, makeAny( pEffect->IsAfterEffectOnNext() ? sal_True : sal_False ) );
1358 		addValue( pSet, nHandleDimColor, pEffect->getDimColor() );
1359 		addValue( pSet, nHandleIterateType, makeAny( pEffect->getIterateType() ) );
1360 
1361 		// convert absolute time to percentage value
1362         // This calculation is done in float to avoid some rounding artifacts.
1363 		float fIterateInterval = (float)pEffect->getIterateInterval();
1364 		if( pEffect->getDuration() )
1365 			fIterateInterval = (float)(fIterateInterval / pEffect->getDuration() );
1366 		fIterateInterval *= 100.0;
1367 		addValue( pSet, nHandleIterateInterval, makeAny( (double)fIterateInterval ) );
1368 
1369 		addValue( pSet, nHandleBegin, makeAny( pEffect->getBegin() ) );
1370 		addValue( pSet, nHandleDuration, makeAny( pEffect->getDuration() ) );
1371 		addValue( pSet, nHandleStart, makeAny( pEffect->getNodeType() ) );
1372 		addValue( pSet, nHandleRepeat, makeAny( pEffect->getRepeatCount() ) );
1373 		addValue( pSet, nHandleEnd, pEffect->getEnd() );
1374 		addValue( pSet, nHandleRewind, makeAny( pEffect->getFill() ) );
1375 
1376 		addValue( pSet, nHandlePresetId, makeAny( pEffect->getPresetId() ) );
1377 
1378 		addValue( pSet, nHandleHasText, makeAny( (sal_Bool)pEffect->hasText() ) );
1379 
1380 		addValue( pSet, nHandleHasVisibleShape, Any( hasVisibleShape( pEffect->getTargetShape() ) ) );
1381 
1382 		Any aSoundSource;
1383 		if( pEffect->getAudio().is() )
1384 		{
1385 			aSoundSource = pEffect->getAudio()->getSource();
1386 			addValue( pSet, nHandleSoundVolumne, makeAny( pEffect->getAudio()->getVolume() ) );
1387 // todo		addValue( pSet, nHandleSoundEndAfterSlide, makeAny( pEffect->getAudio()->getEndAfterSlide() ) );
1388 // this is now stored at the XCommand parameter sequence
1389 		}
1390 		else if( pEffect->getCommand() == EffectCommands::STOPAUDIO )
1391 		{
1392 			aSoundSource = makeAny( (sal_Bool)sal_True );
1393 		}
1394 		addValue( pSet, nHandleSoundURL, aSoundSource );
1395 
1396 		sal_Int32 nGroupId = pEffect->getGroupId();
1397 		CustomAnimationTextGroupPtr pTextGroup;
1398 		if( nGroupId != -1 )
1399 			pTextGroup = pEffectSequence->findGroup( nGroupId );
1400 
1401 		addValue( pSet, nHandleTextGrouping, makeAny( pTextGroup.get() ? pTextGroup->getTextGrouping() : (sal_Int32)-1 ) );
1402 		addValue( pSet, nHandleAnimateForm, makeAny( pTextGroup.get() ? (sal_Bool)pTextGroup->getAnimateForm() : sal_True ) );
1403 		addValue( pSet, nHandleTextGroupingAuto, makeAny( pTextGroup.get() ? pTextGroup->getTextGroupingAuto() : (double)-1.0 ) );
1404 		addValue( pSet, nHandleTextReverse, makeAny( pTextGroup.get() ? (sal_Bool)pTextGroup->getTextReverse() : sal_False ) );
1405 
1406 		if( pEffectSequence->getSequenceType() == EffectNodeType::INTERACTIVE_SEQUENCE  )
1407 		{
1408 			InteractiveSequence* pIS = static_cast< InteractiveSequence* >( pEffectSequence );
1409 			addValue( pSet, nHandleTrigger, makeAny( pIS->getTriggerShape() ) );
1410 		}
1411 
1412 		//
1413 
1414 		CustomAnimationPresetPtr pDescriptor = rPresets.getEffectDescriptor( pEffect->getPresetId() );
1415 		if( pDescriptor.get() )
1416 		{
1417 			sal_Int32 nType = nPropertyTypeNone;
1418 
1419 			UStringList aProperties( pDescriptor->getProperties() );
1420 			if( aProperties.size() >= 1 )
1421 				nType = getPropertyType( aProperties.front() );
1422 
1423 			if( nType != nPropertyTypeNone )
1424 			{
1425 				addValue( pSet, nHandleProperty1Type, makeAny( nType ) );
1426 				addValue( pSet, nHandleProperty1Value, getProperty1Value( nType, pEffect ) );
1427 			}
1428 
1429 			if( pDescriptor->hasProperty( OUString( RTL_CONSTASCII_USTRINGPARAM( "Accelerate" ) ) ) )
1430 			{
1431 				addValue( pSet, nHandleAccelerate, makeAny( pEffect->getAcceleration() ) );
1432 			}
1433 
1434 			if( pDescriptor->hasProperty( OUString( RTL_CONSTASCII_USTRINGPARAM( "Decelerate" ) ) ) )
1435 			{
1436 				addValue( pSet, nHandleDecelerate, makeAny( pEffect->getDecelerate() ) );
1437 			}
1438 
1439 			if( pDescriptor->hasProperty( OUString( RTL_CONSTASCII_USTRINGPARAM( "AutoReverse" ) ) ) )
1440 			{
1441 				addValue( pSet, nHandleAutoReverse, makeAny( pEffect->getAutoReverse() ) );
1442 			}
1443 		}
1444 	}
1445 
1446 	addValue( pSet, nHandleMaxParaDepth, makeAny( nMaxParaDepth ) );
1447 
1448 	return pSet;
1449 }
1450 
1451 void CustomAnimationPane::changeSelection( STLPropertySet* pResultSet, STLPropertySet* pOldSet )
1452 {
1453 	// change selected effect
1454 	bool bChanged = false;
1455 
1456 	MainSequenceRebuildGuard aGuard( mpMainSequence );
1457 
1458 	EffectSequence::iterator aIter( maListSelection.begin() );
1459 	const EffectSequence::iterator aEnd( maListSelection.end() );
1460 	while( aIter != aEnd )
1461 	{
1462 		CustomAnimationEffectPtr pEffect = (*aIter++);
1463 
1464 		DBG_ASSERT( pEffect->getEffectSequence(), "sd::CustomAnimationPane::changeSelection(), dead effect in selection!" );
1465 		if( !pEffect->getEffectSequence() )
1466 			continue;
1467 
1468 		double fDuration = 0.0; // we might need this for iterate-interval
1469 		if( pResultSet->getPropertyState( nHandleDuration ) == STLPropertyState_DIRECT )
1470 		{
1471 			pResultSet->getPropertyValue( nHandleDuration ) >>= fDuration;
1472 		}
1473 		else
1474 		{
1475 			fDuration = pEffect->getDuration();
1476 		}
1477 
1478 		if( pResultSet->getPropertyState( nHandleIterateType ) == STLPropertyState_DIRECT )
1479 		{
1480 			sal_Int16 nIterateType = 0;
1481 			pResultSet->getPropertyValue( nHandleIterateType ) >>= nIterateType;
1482 			if( pEffect->getIterateType() != nIterateType )
1483 			{
1484 				pEffect->setIterateType( nIterateType );
1485 				bChanged = true;
1486 			}
1487 		}
1488 
1489 		if( pEffect->getIterateType() )
1490 		{
1491 			if( pResultSet->getPropertyState( nHandleIterateInterval ) == STLPropertyState_DIRECT )
1492 			{
1493 				double fIterateInterval = 0.0;
1494 				pResultSet->getPropertyValue( nHandleIterateInterval ) >>= fIterateInterval;
1495 				if( pEffect->getIterateInterval() != fIterateInterval )
1496 				{
1497 					const double f = fIterateInterval * pEffect->getDuration() / 100;
1498 					pEffect->setIterateInterval( f );
1499 					bChanged = true;
1500 				}
1501 			}
1502 		}
1503 
1504 		if( pResultSet->getPropertyState( nHandleBegin ) == STLPropertyState_DIRECT )
1505 		{
1506 			double fBegin = 0.0;
1507 			pResultSet->getPropertyValue( nHandleBegin ) >>= fBegin;
1508 			if( pEffect->getBegin() != fBegin )
1509 			{
1510 				pEffect->setBegin( fBegin );
1511 				bChanged = true;
1512 			}
1513 		}
1514 
1515 		if( pResultSet->getPropertyState( nHandleDuration ) == STLPropertyState_DIRECT )
1516 		{
1517 			if( pEffect->getDuration() != fDuration )
1518 			{
1519 				pEffect->setDuration( fDuration );
1520 				bChanged = true;
1521 			}
1522 		}
1523 
1524 		if( pResultSet->getPropertyState( nHandleStart ) == STLPropertyState_DIRECT )
1525 		{
1526 			sal_Int16 nNodeType = 0;
1527 			pResultSet->getPropertyValue( nHandleStart ) >>= nNodeType;
1528 			if( pEffect->getNodeType() != nNodeType )
1529 			{
1530 				pEffect->setNodeType( nNodeType );
1531 				bChanged = true;
1532 			}
1533 		}
1534 
1535 		if( pResultSet->getPropertyState( nHandleRepeat ) == STLPropertyState_DIRECT )
1536 		{
1537 			Any aRepeatCount( pResultSet->getPropertyValue( nHandleRepeat ) );
1538 			if( aRepeatCount != pEffect->getRepeatCount() )
1539 			{
1540 				pEffect->setRepeatCount( aRepeatCount );
1541 				bChanged = true;
1542 			}
1543 		}
1544 
1545 		if( pResultSet->getPropertyState( nHandleEnd ) == STLPropertyState_DIRECT )
1546 		{
1547 			Any aEndValue( pResultSet->getPropertyValue( nHandleEnd ) );
1548 			if( pEffect->getEnd() != aEndValue )
1549 			{
1550 				pEffect->setEnd( aEndValue );
1551 				bChanged = true;
1552 			}
1553 		}
1554 
1555 		if( pResultSet->getPropertyState( nHandleRewind ) == STLPropertyState_DIRECT )
1556 		{
1557 			sal_Int16 nFill = 0;
1558 			pResultSet->getPropertyValue( nHandleRewind ) >>= nFill;
1559 			if( pEffect->getFill() != nFill )
1560 			{
1561 				pEffect->setFill( nFill );
1562 				bChanged = true;
1563 			}
1564 		}
1565 
1566 		if( pResultSet->getPropertyState( nHandleHasAfterEffect ) == STLPropertyState_DIRECT )
1567 		{
1568 			sal_Bool bHasAfterEffect = sal_False;
1569 			if( pResultSet->getPropertyValue( nHandleHasAfterEffect )  >>= bHasAfterEffect )
1570 			{
1571 				if( pEffect->hasAfterEffect() != bHasAfterEffect )
1572 				{
1573 					pEffect->setHasAfterEffect( bHasAfterEffect );
1574 					bChanged = true;
1575 				}
1576 			}
1577 		}
1578 
1579 		if( pResultSet->getPropertyState( nHandleAfterEffectOnNextEffect ) == STLPropertyState_DIRECT )
1580 		{
1581 			sal_Bool bAfterEffectOnNextEffect = sal_False;
1582 			if( (pResultSet->getPropertyValue( nHandleAfterEffectOnNextEffect ) >>= bAfterEffectOnNextEffect) && ((pEffect->IsAfterEffectOnNext() ? sal_True : sal_False) != bAfterEffectOnNextEffect) )
1583 			{
1584 				pEffect->setAfterEffectOnNext( bAfterEffectOnNextEffect );
1585 				bChanged = true;
1586 			}
1587 		}
1588 
1589 		if( pResultSet->getPropertyState( nHandleDimColor ) == STLPropertyState_DIRECT )
1590 		{
1591 			Any aDimColor( pResultSet->getPropertyValue( nHandleDimColor ) );
1592 			if( pEffect->getDimColor() != aDimColor )
1593 			{
1594 				pEffect->setDimColor( aDimColor );
1595 				bChanged = true;
1596 			}
1597 		}
1598 
1599 		if( pResultSet->getPropertyState( nHandleAccelerate ) == STLPropertyState_DIRECT )
1600 		{
1601 			double fAccelerate = 0.0;
1602 			pResultSet->getPropertyValue( nHandleAccelerate ) >>= fAccelerate;
1603 			if( pEffect->getAcceleration() != fAccelerate )
1604 			{
1605 				pEffect->setAcceleration( fAccelerate );
1606 				bChanged = true;
1607 			}
1608 		}
1609 
1610 		if( pResultSet->getPropertyState( nHandleDecelerate ) == STLPropertyState_DIRECT )
1611 		{
1612 			double fDecelerate = 0.0;
1613 			pResultSet->getPropertyValue( nHandleDecelerate ) >>= fDecelerate;
1614 			if( pEffect->getDecelerate() != fDecelerate )
1615 			{
1616 				pEffect->setDecelerate( fDecelerate );
1617 				bChanged = true;
1618 			}
1619 		}
1620 
1621 		if( pResultSet->getPropertyState( nHandleAutoReverse ) == STLPropertyState_DIRECT )
1622 		{
1623 			sal_Bool bAutoReverse = sal_False;
1624 			pResultSet->getPropertyValue( nHandleAutoReverse ) >>= bAutoReverse;
1625 			if( pEffect->getAutoReverse() != bAutoReverse )
1626 			{
1627 				pEffect->setAutoReverse( bAutoReverse );
1628 				bChanged = true;
1629 			}
1630 		}
1631 
1632 		if( pResultSet->getPropertyState( nHandleProperty1Value ) == STLPropertyState_DIRECT )
1633 		{
1634 			sal_Int32 nType = 0;
1635 			pOldSet->getPropertyValue( nHandleProperty1Type ) >>= nType;
1636 
1637 			bChanged |= setProperty1Value( nType, pEffect, pResultSet->getPropertyValue( nHandleProperty1Value ) );
1638 		}
1639 
1640 		if( pResultSet->getPropertyState( nHandleSoundURL ) == STLPropertyState_DIRECT )
1641 		{
1642 			const Any aSoundSource( pResultSet->getPropertyValue( nHandleSoundURL ) );
1643 
1644 			if( aSoundSource.getValueType() == ::getCppuType((const sal_Bool*)0) )
1645 			{
1646 				pEffect->setStopAudio();
1647 				bChanged = true;
1648 			}
1649 			else
1650 			{
1651 				OUString aSoundURL;
1652 				aSoundSource >>= aSoundURL;
1653 
1654 				if( aSoundURL.getLength() )
1655 				{
1656 					if( !pEffect->getAudio().is() )
1657 					{
1658 						pEffect->createAudio( aSoundSource );
1659 						bChanged = true;
1660 					}
1661 					else
1662 					{
1663 						if( pEffect->getAudio()->getSource() != aSoundSource )
1664 						{
1665 							pEffect->getAudio()->setSource( aSoundSource );
1666 							bChanged = true;
1667 						}
1668 					}
1669 				}
1670 				else
1671 				{
1672 					if( pEffect->getAudio().is() || pEffect->getStopAudio() )
1673 					{
1674 						pEffect->removeAudio();
1675 						bChanged = true;
1676 					}
1677 				}
1678 			}
1679 		}
1680 
1681 		if( pResultSet->getPropertyState( nHandleTrigger ) == STLPropertyState_DIRECT )
1682 		{
1683 			Reference< XShape > xTriggerShape;
1684 			pResultSet->getPropertyValue( nHandleTrigger ) >>= xTriggerShape;
1685 			bChanged |= mpMainSequence->setTrigger( pEffect, xTriggerShape );
1686 		}
1687 	}
1688 
1689 	const bool bHasTextGrouping = pResultSet->getPropertyState( nHandleTextGrouping ) == STLPropertyState_DIRECT;
1690 	const bool bHasAnimateForm = pResultSet->getPropertyState( nHandleAnimateForm ) == STLPropertyState_DIRECT;
1691 	const bool bHasTextGroupingAuto = pResultSet->getPropertyState( nHandleTextGroupingAuto ) == STLPropertyState_DIRECT;
1692 	const bool bHasTextReverse = pResultSet->getPropertyState( nHandleTextReverse ) == STLPropertyState_DIRECT;
1693 
1694 	if( bHasTextGrouping || bHasAnimateForm || bHasTextGroupingAuto || bHasTextReverse )
1695 	{
1696 		// we need to do a second pass for text grouping options
1697 		// since changing them can cause effects to be removed
1698 		// or replaced, we do this after we applied all other options
1699 		// above
1700 
1701 		sal_Int32 nTextGrouping = 0;
1702 		sal_Bool bAnimateForm = sal_True, bTextReverse = sal_False;
1703 		double fTextGroupingAuto = -1.0;
1704 
1705 		if( bHasTextGrouping )
1706 			pResultSet->getPropertyValue(nHandleTextGrouping) >>= nTextGrouping;
1707 
1708 		if( bHasAnimateForm )
1709 			pResultSet->getPropertyValue(nHandleAnimateForm) >>= bAnimateForm;
1710 
1711 		if( bHasTextGroupingAuto )
1712 			pResultSet->getPropertyValue(nHandleTextGroupingAuto) >>= fTextGroupingAuto;
1713 
1714 		if( bHasTextReverse )
1715 			pResultSet->getPropertyValue(nHandleTextReverse) >>= bTextReverse;
1716 
1717 		EffectSequence const aSelectedEffects( maListSelection );
1718 		EffectSequence::const_iterator iter( aSelectedEffects.begin() );
1719 		const EffectSequence::const_iterator iEnd( aSelectedEffects.end() );
1720 		while( iter != iEnd )
1721 		{
1722 			CustomAnimationEffectPtr const& pEffect = (*iter++);
1723 
1724 			EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
1725 			if( !pEffectSequence )
1726 				pEffectSequence = mpMainSequence.get();
1727 
1728 			sal_Int32 nGroupId = pEffect->getGroupId();
1729 			CustomAnimationTextGroupPtr pTextGroup;
1730 			if( (nGroupId != -1) )
1731 			{
1732 				// use existing group
1733 				pTextGroup = pEffectSequence->findGroup( nGroupId );
1734 			}
1735 			else
1736 			{
1737 				// somethings changed so we need a group now
1738 				pTextGroup = pEffectSequence->createTextGroup( pEffect, nTextGrouping, fTextGroupingAuto, bAnimateForm, bTextReverse );
1739 				bChanged = true;
1740 			}
1741 
1742 			//#Bug 119988#
1743 			/************************************************************************/
1744 			/*
1745 			Note, the setAnimateForm means set the animation from TextGroup to Object's Shape
1746 			And on the UI in means "Animate attached shape" in "Effect Option" dialog
1747 			The setTextGrouping means set animation to Object's Text,
1748 			the nTextGrouping is Text Animation Type
1749 			nTextGrouping = -1 is "As one Object", means no text animation.
1750 
1751 			The previous call order first do the setTextGrouping and then do the setAnimateForm,
1752 			that will cause such defect: in the setTextGrouping, the effect has been removed,
1753 			but in setAnimateForm still need this effect, then a NULL pointer of that effect will
1754 			be gotten, and cause crash.
1755 
1756 			[]bHasAnimateForm means the UI has changed, bAnimateForm is it value
1757 
1758 			So if create a new textgroup animation, the following animation will never be run!
1759 			Since the ��Animate attached shape�� is default checked.
1760 			And the bHasAnimateForm default is false, and if user uncheck it the value bAnimateForm will be false,
1761 			it same as the TextGroup��s default value, also could not be run setAnimateForm.
1762 			if( bHasAnimateForm )
1763 			{
1764 			if( pTextGroup->getAnimateForm() != bAnimateForm )
1765 			{
1766 			pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1767 			bChanged = true;
1768 			}
1769 			}
1770 
1771 			In setTextGrouping, there are three case:
1772 			1.	Create new text effects for empty TextGroup
1773 			2.	Remove all text effects of TextGroup (nTextGrouping == -1)
1774 			3.	Change all the text effects�� start type
1775 
1776 			So here is the right logic:
1777 			If set the animation from text to shape and remove text animation,
1778 			should do setAnimateForm first, then do setTextGrouping.
1779 			Other case,do setTextGrouping first, then do setAnimateForm.
1780 
1781 			*/
1782 			/************************************************************************/
1783 
1784 			bool	bDoSetAnimateFormFirst = false;
1785 			bool	bNeedDoSetAnimateForm = false;
1786 
1787 			if( bHasAnimateForm )
1788 			{
1789 				if( pTextGroup.get() && pTextGroup->getAnimateForm() != bAnimateForm )
1790 				{
1791 					if( (pTextGroup->getTextGrouping() >= 0) && (nTextGrouping == -1 ) )
1792 					{
1793 						bDoSetAnimateFormFirst = true;
1794 					}
1795 					bNeedDoSetAnimateForm = true;
1796 				}
1797 			}
1798 
1799 			if (bDoSetAnimateFormFirst)
1800 			{
1801 				pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1802 				bChanged = true;
1803 			}
1804 
1805 			if( bHasTextGrouping )
1806 			{
1807 				if( pTextGroup.get() && pTextGroup->getTextGrouping() != nTextGrouping )
1808 				{
1809 					pEffectSequence->setTextGrouping( pTextGroup, nTextGrouping );
1810 					bChanged = true;
1811 				}
1812 			}
1813 
1814 			if (!bDoSetAnimateFormFirst && bNeedDoSetAnimateForm)
1815 			{
1816                 if( pTextGroup.get() )
1817                 {
1818                     pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1819                     bChanged = true;
1820                 }
1821 			}
1822 
1823 			if( bHasTextGroupingAuto )
1824 			{
1825 				if( pTextGroup.get() && pTextGroup->getTextGroupingAuto() != fTextGroupingAuto )
1826 				{
1827 					pEffectSequence->setTextGroupingAuto( pTextGroup, fTextGroupingAuto );
1828 					bChanged = true;
1829 				}
1830 			}
1831 
1832 			if( bHasTextReverse )
1833 			{
1834 				if( pTextGroup.get() && pTextGroup->getTextReverse() != bTextReverse )
1835 				{
1836 					pEffectSequence->setTextReverse( pTextGroup, bTextReverse );
1837 					bChanged = true;
1838 				}
1839 			}
1840 		}
1841 	}
1842 
1843 	if( bChanged )
1844 	{
1845 		mpMainSequence->rebuild();
1846 		updateControls();
1847 		mrBase.GetDocShell()->SetModified();
1848 	}
1849 }
1850 
1851 void CustomAnimationPane::showOptions( sal_uInt16 nPage /* = 0 */ )
1852 {
1853 	STLPropertySet* pSet = createSelectionSet();
1854 
1855 	CustomAnimationDialog* pDlg = new CustomAnimationDialog( this, pSet, nPage );
1856 	if( pDlg->Execute() )
1857 	{
1858 		addUndo();
1859 		changeSelection( pDlg->getResultSet(), pSet );
1860 		updateControls();
1861 	}
1862 
1863 	delete pDlg;
1864 }
1865 
1866 void CustomAnimationPane::onChangeCurrentPage()
1867 {
1868 	if( mxView.is() ) try
1869 	{
1870 		Reference< XDrawPage > xNewPage( mxView->getCurrentPage() );
1871 		if( xNewPage != mxCurrentPage )
1872 		{
1873 			mxCurrentPage = xNewPage;
1874 			SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
1875 			if( pPage )
1876 			{
1877 				mpMainSequence = pPage->getMainSequence();
1878 				mpCustomAnimationList->update( mpMainSequence );
1879 			}
1880 			updateControls();
1881 		}
1882 	}
1883 	catch( Exception& )
1884 	{
1885 		DBG_ERROR( "sd::CustomAnimationPane::onChangeCurrentPage(), exception catched!" );
1886 	}
1887 }
1888 
1889 bool getTextSelection( const Any& rSelection, Reference< XShape >& xShape, std::list< sal_Int16 >& rParaList )
1890 {
1891 	Reference< XTextRange > xSelectedText;
1892 	rSelection >>= xSelectedText;
1893 	if( xSelectedText.is() ) try
1894 	{
1895 		xShape.set( xSelectedText->getText(), UNO_QUERY_THROW );
1896 
1897 		Reference< XTextRangeCompare > xTextRangeCompare( xShape, UNO_QUERY_THROW );
1898 		Reference< XEnumerationAccess > xParaEnumAccess( xShape, UNO_QUERY_THROW );
1899 		Reference< XEnumeration > xParaEnum( xParaEnumAccess->createEnumeration(), UNO_QUERY_THROW );
1900 		Reference< XTextRange > xRange;
1901 		Reference< XTextRange > xStart( xSelectedText->getStart() );
1902 		Reference< XTextRange > xEnd( xSelectedText->getEnd() );
1903 
1904 		if( xTextRangeCompare->compareRegionEnds( xStart, xEnd ) < 0 )
1905 		{
1906 			Reference< XTextRange > xTemp( xStart );
1907 			xStart = xEnd;
1908 			xEnd = xTemp;
1909 		}
1910 
1911 		sal_Int16 nPara = 0;
1912 		while( xParaEnum->hasMoreElements() )
1913 		{
1914 			xParaEnum->nextElement() >>= xRange;
1915 
1916 			// break if start of selection is prior to end of current paragraph
1917 			if( xRange.is() && (xTextRangeCompare->compareRegionEnds( xStart, xRange ) >= 0 ) )
1918 				break;
1919 
1920 			nPara++;
1921 		}
1922 
1923 		while( xRange.is() )
1924 		{
1925 			if( xRange.is() && xRange->getString().getLength() )
1926 				rParaList.push_back( nPara );
1927 
1928 			// break if end of selection is before or at end of current paragraph
1929 			if( xRange.is() && xTextRangeCompare->compareRegionEnds( xEnd, xRange ) >= 0 )
1930 				break;
1931 
1932 			nPara++;
1933 
1934 			if( xParaEnum->hasMoreElements() )
1935 				xParaEnum->nextElement() >>= xRange;
1936 			else
1937 				xRange.clear();
1938 		}
1939 
1940 		return true;
1941 	}
1942 	catch( Exception& e )
1943 	{
1944 		(void)e;
1945 		DBG_ERROR( "sd::CustomAnimationPane::getTextSelection(), exception cought!" );
1946 	}
1947 
1948 	return false;
1949 }
1950 
1951 void CustomAnimationPane::onChange( bool bCreate )
1952 {
1953 	bool bHasText = true;
1954 
1955 	// first create vector of targets for dialog preview
1956 	std::vector< Any > aTargets;
1957 	OUString sPresetId;
1958 	double fDuration = 2.0f;
1959 
1960 	if( bCreate )
1961 	{
1962 		// gather shapes from the selection
1963 		Reference< XSelectionSupplier >  xSel( mxView, UNO_QUERY_THROW );
1964 		maViewSelection = xSel->getSelection();
1965 
1966 		if( maViewSelection.getValueType() == ::getCppuType((const Reference< XShapes >*)0) )
1967 		{
1968 			Reference< XIndexAccess > xShapes;
1969 			maViewSelection >>= xShapes;
1970 
1971 			sal_Int32 nCount = xShapes->getCount();
1972 			sal_Int32 nIndex;
1973 			for( nIndex = 0; nIndex < nCount; nIndex++ )
1974 			{
1975 				Any aTarget( xShapes->getByIndex( nIndex ) );
1976 				aTargets.push_back( aTarget );
1977 				if( bHasText )
1978 				{
1979 					Reference< XText > xText;
1980 					aTarget >>= xText;
1981 					if( !xText.is() || xText->getString().getLength() == 0 )
1982 						bHasText = false;
1983 				}
1984 			}
1985 		}
1986 		else if ( maViewSelection.getValueType() == ::getCppuType((const Reference< XShape >*)0) )
1987 		{
1988 			aTargets.push_back( maViewSelection );
1989 			Reference< XText > xText;
1990 			maViewSelection >>= xText;
1991 			if( !xText.is() || xText->getString().getLength() == 0 )
1992 				bHasText = false;
1993 		}
1994 		else if ( maViewSelection.getValueType() == ::getCppuType((const Reference< XTextCursor >*)0) )
1995 		{
1996 			Reference< XShape > xShape;
1997 			std::list< sal_Int16 > aParaList;
1998 			if( getTextSelection( maViewSelection, xShape, aParaList ) )
1999 			{
2000 				ParagraphTarget aParaTarget;
2001 				aParaTarget.Shape = xShape;
2002 
2003 				std::list< sal_Int16 >::iterator aIter( aParaList.begin() );
2004 				for( ; aIter != aParaList.end(); aIter++ )
2005 				{
2006 					aParaTarget.Paragraph = (*aIter);
2007 					aTargets.push_back( makeAny( aParaTarget ) );
2008    				}
2009 			}
2010 		}
2011 		else
2012 		{
2013 			DBG_ERROR("sd::CustomAnimationPane::onChange(), unknown view selection!" );
2014 			return;
2015 		}
2016 	}
2017 	else
2018 	{
2019 		// get selected effect
2020 		EffectSequence::iterator aIter( maListSelection.begin() );
2021 		const EffectSequence::iterator aEnd( maListSelection.end() );
2022 		while( aIter != aEnd )
2023 		{
2024 			if( !bHasText || !(*aIter)->hasText() )
2025 				bHasText = false;
2026 
2027 			if( sPresetId.getLength() == 0 )
2028 			{
2029 				sPresetId = (*aIter)->getPresetId();
2030 				fDuration = (*aIter)->getDuration();
2031 			}
2032 
2033 			aTargets.push_back( (*aIter++)->getTarget() );
2034 		}
2035 	}
2036 
2037 	CustomAnimationCreateDialog* pDlg = new CustomAnimationCreateDialog( this, this, aTargets, bHasText, sPresetId, fDuration );
2038 	if( pDlg->Execute() )
2039 	{
2040 		addUndo();
2041 		fDuration = pDlg->getSelectedDuration();
2042 		CustomAnimationPresetPtr pDescriptor = pDlg->getSelectedPreset();
2043 		if( pDescriptor.get() )
2044 		{
2045 			if( bCreate )
2046 			{
2047 				mpCustomAnimationList->SelectAll( sal_False );
2048 
2049 				// gather shapes from the selection
2050 				std::vector< Any >::iterator aIter( aTargets.begin() );
2051 				const std::vector< Any >::iterator aEnd( aTargets.end() );
2052 				bool bFirst = true;
2053 				for( ; aIter != aEnd; aIter++ )
2054 				{
2055 					CustomAnimationEffectPtr pCreated = mpMainSequence->append( pDescriptor, (*aIter), fDuration );
2056 
2057 					// if only one shape with text and no fill or outline is selected, animate only by first level paragraphs
2058 					if( bHasText && (aTargets.size() == 1) )
2059 					{
2060 						Reference< XShape > xShape( (*aIter), UNO_QUERY );
2061 						if( xShape.is() && !hasVisibleShape( xShape ) )
2062 						{
2063 							mpMainSequence->createTextGroup( pCreated, 1, -1.0, sal_False, sal_False );
2064 						}
2065 					}
2066 
2067 					if( bFirst )
2068 						bFirst = false;
2069 					else
2070 						pCreated->setNodeType( EffectNodeType::WITH_PREVIOUS );
2071 
2072 					if( pCreated.get() )
2073 					{
2074 						mpCustomAnimationList->select( pCreated );
2075 					}
2076 				}
2077 			}
2078 			else
2079 			{
2080 				MainSequenceRebuildGuard aGuard( mpMainSequence );
2081 
2082 				// get selected effect
2083 				EffectSequence::iterator aIter( maListSelection.begin() );
2084 				const EffectSequence::iterator aEnd( maListSelection.end() );
2085 				while( aIter != aEnd )
2086 				{
2087 					CustomAnimationEffectPtr pEffect = (*aIter++);
2088 
2089 					EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
2090 					if( !pEffectSequence )
2091 						pEffectSequence = mpMainSequence.get();
2092 
2093 					pEffectSequence->replace( pEffect, pDescriptor, fDuration );
2094 				}
2095 			}
2096 		}
2097 		else
2098 		{
2099 			PathKind eKind = pDlg->getCreatePathKind();
2100 			if( eKind != NONE )
2101 				createPath( eKind, aTargets, fDuration );
2102 		}
2103 		mrBase.GetDocShell()->SetModified();
2104 	}
2105 
2106 	delete pDlg;
2107 
2108 	updateControls();
2109 
2110 	// stop running preview from dialog
2111 	SlideShow::Stop( mrBase );
2112 }
2113 
2114 void CustomAnimationPane::createPath( PathKind eKind, std::vector< Any >& rTargets, double fDuration)
2115 {
2116 	sal_uInt16 nSID = 0;
2117 
2118 	switch( eKind )
2119 	{
2120 	case CURVE:		nSID = SID_DRAW_BEZIER_NOFILL; break;
2121 	case POLYGON:	nSID = SID_DRAW_POLYGON_NOFILL; break;
2122 	case FREEFORM:	nSID = SID_DRAW_FREELINE_NOFILL; break;
2123 	default: break;
2124 	}
2125 
2126 	if( nSID )
2127 	{
2128 		DrawViewShell* pViewShell = dynamic_cast< DrawViewShell* >(
2129 		    FrameworkHelper::Instance(mrBase)->GetViewShell(FrameworkHelper::msCenterPaneURL).get());
2130 
2131 		if( pViewShell )
2132 		{
2133 			DrawView* pView = pViewShell->GetDrawView();
2134 			if( pView )
2135 				pView->UnmarkAllObj();
2136 
2137 			std::vector< Any > aTargets( 1, Any( fDuration ) );
2138 			aTargets.insert( aTargets.end(), rTargets.begin(), rTargets.end() );
2139 			Sequence< Any > aTargetSequence( comphelper::containerToSequence( aTargets ) );
2140 			const SfxUnoAnyItem aItem( SID_ADD_MOTION_PATH, Any( aTargetSequence ) );
2141 			pViewShell->GetViewFrame()->GetDispatcher()->Execute( nSID, SFX_CALLMODE_ASYNCHRON, &aItem, 0 );
2142 		}
2143 	}
2144 }
2145 
2146 void CustomAnimationPane::onRemove()
2147 {
2148 	if( !maListSelection.empty() )
2149 	{
2150 		addUndo();
2151 
2152 		MainSequenceRebuildGuard aGuard( mpMainSequence );
2153 
2154 		EffectSequence aList( maListSelection );
2155 
2156 		EffectSequence::iterator aIter( aList.begin() );
2157 		const EffectSequence::iterator aEnd( aList.end() );
2158 		while( aIter != aEnd )
2159 		{
2160 			CustomAnimationEffectPtr pEffect = (*aIter++);
2161 			if( pEffect->getEffectSequence() )
2162 				pEffect->getEffectSequence()->remove( pEffect );
2163 		}
2164 
2165 		maListSelection.clear();
2166 		mrBase.GetDocShell()->SetModified();
2167 	}
2168 }
2169 
2170 void CustomAnimationPane::remove( CustomAnimationEffectPtr& pEffect )
2171 {
2172 	if( pEffect->getEffectSequence() )
2173 	{
2174 		addUndo();
2175 		pEffect->getEffectSequence()->remove( pEffect );
2176 		mrBase.GetDocShell()->SetModified();
2177 	}
2178 }
2179 
2180 void CustomAnimationPane::onChangeStart()
2181 {
2182 	if( mpLBStart->GetSelectEntryCount() == 1 )
2183 	{
2184 		sal_Int16 nNodeType;
2185 		sal_uInt16 nPos= mpLBStart->GetSelectEntryPos();
2186 		switch( nPos )
2187 		{
2188 		case 0:	nNodeType = EffectNodeType::ON_CLICK; break;
2189 		case 1:	nNodeType = EffectNodeType::WITH_PREVIOUS; break;
2190 		case 2:	nNodeType = EffectNodeType::AFTER_PREVIOUS; break;
2191 		default:
2192 			return;
2193 		}
2194 
2195 		onChangeStart( nNodeType );
2196 	}
2197 }
2198 
2199 void CustomAnimationPane::onChangeStart( sal_Int16 nNodeType )
2200 {
2201 	addUndo();
2202 
2203 	MainSequenceRebuildGuard aGuard( mpMainSequence );
2204 
2205 	bool bNeedRebuild = false;
2206 
2207 	EffectSequence::iterator aIter( maListSelection.begin() );
2208 	const EffectSequence::iterator aEnd( maListSelection.end() );
2209 	while( aIter != aEnd )
2210 	{
2211 		CustomAnimationEffectPtr pEffect = (*aIter++);
2212 		if( pEffect->getNodeType() != nNodeType )
2213 		{
2214 			pEffect->setNodeType( nNodeType );
2215 			bNeedRebuild = true;
2216 		}
2217 	}
2218 
2219 	if( bNeedRebuild )
2220 	{
2221 		mpMainSequence->rebuild();
2222 		updateControls();
2223 		mrBase.GetDocShell()->SetModified();
2224 	}
2225 }
2226 
2227 void CustomAnimationPane::onChangeProperty()
2228 {
2229 	if( mpLBProperty->getSubControl() )
2230 	{
2231 		addUndo();
2232 
2233 		MainSequenceRebuildGuard aGuard( mpMainSequence );
2234 
2235 		const Any aValue( mpLBProperty->getSubControl()->getValue() );
2236 
2237 		bool bNeedUpdate = false;
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 
2246 			if( setProperty1Value( mnPropertyType, pEffect, aValue ) )
2247 				bNeedUpdate = true;
2248 		}
2249 
2250 		if( bNeedUpdate )
2251 		{
2252 			mpMainSequence->rebuild();
2253 			updateControls();
2254 			mrBase.GetDocShell()->SetModified();
2255 		}
2256 
2257 		onPreview( false );
2258 	}
2259 }
2260 
2261 void CustomAnimationPane::onChangeSpeed()
2262 {
2263 	if( mpCBSpeed->GetSelectEntryCount() == 1 )
2264 	{
2265 		addUndo();
2266 
2267 		MainSequenceRebuildGuard aGuard( mpMainSequence );
2268 
2269 		double fDuration;
2270 
2271 		sal_uInt16 nPos= mpCBSpeed->GetSelectEntryPos();
2272 
2273 		switch( nPos )
2274 		{
2275 		case 0: fDuration = 5.0; break;
2276 		case 1: fDuration = 3.0; break;
2277 		case 2: fDuration = 2.0; break;
2278 		case 3: fDuration = 1.0; break;
2279 		case 4: fDuration = 0.5; break;
2280 		default:
2281 			return;
2282 		}
2283 
2284 		// change selected effect
2285 		EffectSequence::iterator aIter( maListSelection.begin() );
2286 		const EffectSequence::iterator aEnd( maListSelection.end() );
2287 		while( aIter != aEnd )
2288 		{
2289 			CustomAnimationEffectPtr pEffect = (*aIter++);
2290 			pEffect->setDuration( fDuration );
2291 		}
2292 
2293 		mpMainSequence->rebuild();
2294 		updateControls();
2295 		mrBase.GetDocShell()->SetModified();
2296 
2297 		onPreview( false );
2298 	}
2299 }
2300 
2301 /// this link is called when the property box is modified by the user
2302 IMPL_LINK( CustomAnimationPane, implPropertyHdl, Control*, EMPTYARG )
2303 {
2304 	onChangeProperty();
2305 	return 0;
2306 }
2307 
2308 /// this link is called when one of the controls is modified
2309 IMPL_LINK( CustomAnimationPane, implControlHdl, Control*, pControl )
2310 {
2311 	if( pControl == mpPBAddEffect )
2312 		onChange(true);
2313 	else if( pControl == mpPBChangeEffect )
2314 		onChange(false);
2315 	else if( pControl == mpPBRemoveEffect )
2316 		onRemove();
2317 	else if( pControl == mpLBStart )
2318 		onChangeStart();
2319 	else if( pControl == mpCBSpeed )
2320 		onChangeSpeed();
2321 	else if( pControl == mpPBPropertyMore )
2322 		showOptions();
2323 	else if( pControl == mpPBMoveUp )
2324 		moveSelection( true );
2325 	else if( pControl == mpPBMoveDown )
2326 		moveSelection( false );
2327 	else if( pControl == mpPBPlay )
2328 		onPreview( true );
2329 	else if( pControl == mpPBSlideShow )
2330 	{
2331 		mrBase.StartPresentation();
2332 	}
2333 	else if( pControl == mpCBAutoPreview )
2334 	{
2335 		SdOptions* pOptions = SD_MOD()->GetSdOptions(DOCUMENT_TYPE_IMPRESS);
2336 		pOptions->SetPreviewChangedEffects( mpCBAutoPreview->IsChecked() ? sal_True : sal_False );
2337 	}
2338 
2339 	updateControls();
2340 
2341 	return 0;
2342 }
2343 
2344 IMPL_LINK(CustomAnimationPane, lateInitCallback, Timer*, EMPTYARG )
2345 {
2346     // Call getPresets() to initiate the (expensive) construction of the
2347     // presets list.
2348     getPresets();
2349 
2350     // update selection and control states
2351     onSelectionChanged();
2352 
2353     return 0;
2354 }
2355 
2356 void CustomAnimationPane::moveSelection( bool bUp )
2357 {
2358 	if( maListSelection.empty() )
2359 		return;
2360 
2361 	EffectSequenceHelper* pSequence = maListSelection.front()->getEffectSequence();
2362 	if( pSequence == 0 )
2363 		return;
2364 
2365 	addUndo();
2366 
2367 	bool bChanged = false;
2368 
2369 	MainSequenceRebuildGuard aGuard( mpMainSequence );
2370 	EffectSequence& rEffectSequence = pSequence->getSequence();
2371 
2372 	if( bUp )
2373 	{
2374 		EffectSequence::iterator aIter( maListSelection.begin() );
2375 		const EffectSequence::iterator aEnd( maListSelection.end() );
2376 
2377 		while( aIter != aEnd )
2378 		{
2379 			CustomAnimationEffectPtr pEffect = (*aIter++);
2380 
2381 			EffectSequence::iterator aEffectPos( pSequence->find( pEffect ) );
2382 			if( aEffectPos != rEffectSequence.end() )
2383 			{
2384 				EffectSequence::iterator aInsertPos( rEffectSequence.erase( aEffectPos ) );
2385 
2386 				if( aInsertPos != rEffectSequence.begin() )
2387 				{
2388 					aInsertPos--;
2389 					while( (aInsertPos != rEffectSequence.begin()) && !mpCustomAnimationList->isExpanded(*aInsertPos))
2390 						aInsertPos--;
2391 
2392 					rEffectSequence.insert( aInsertPos, pEffect );
2393 				}
2394 				else
2395 				{
2396 					rEffectSequence.push_front( pEffect );
2397 				}
2398 				bChanged = true;
2399 			}
2400 		}
2401 	}
2402 	else
2403 	{
2404 		EffectSequence::reverse_iterator aIter( maListSelection.rbegin() );
2405 		const EffectSequence::reverse_iterator aEnd( maListSelection.rend() );
2406 
2407 		while( aIter != aEnd )
2408 		{
2409 			CustomAnimationEffectPtr pEffect = (*aIter++);
2410 
2411 			EffectSequence::iterator aEffectPos( pSequence->find( pEffect ) );
2412 			if( aEffectPos != rEffectSequence.end() )
2413 			{
2414 				EffectSequence::iterator aInsertPos( rEffectSequence.erase( aEffectPos ) );
2415 
2416 				if( aInsertPos != rEffectSequence.end() )
2417 				{
2418 					aInsertPos++;
2419 					while( (aInsertPos != rEffectSequence.end()) && !mpCustomAnimationList->isExpanded(*aInsertPos))
2420 						aInsertPos++;
2421 
2422 					rEffectSequence.insert( aInsertPos, pEffect );
2423 				}
2424 				else
2425 				{
2426 					rEffectSequence.push_back( pEffect );
2427 				}
2428 				bChanged = true;
2429 			}
2430 		}
2431 	}
2432 
2433 	if( bChanged )
2434 	{
2435 		mpMainSequence->rebuild();
2436 		updateControls();
2437 		mrBase.GetDocShell()->SetModified();
2438 	}
2439 }
2440 
2441 void CustomAnimationPane::onPreview( bool bForcePreview )
2442 {
2443 	if( !bForcePreview && !mpCBAutoPreview->IsChecked() )
2444 		return;
2445 
2446 	if( maListSelection.empty() )
2447 	{
2448 		rtl::Reference< MotionPathTag > xMotionPathTag;
2449 		MotionPathTagVector::iterator aIter;
2450 		for( aIter = maMotionPathTags.begin(); aIter != maMotionPathTags.end(); aIter++ )
2451 		{
2452 			if( (*aIter)->isSelected() )
2453 			{
2454 				xMotionPathTag = (*aIter);
2455 				break;
2456 			}
2457 		}
2458 
2459 		if( xMotionPathTag.is() )
2460 		{
2461 			MainSequencePtr pSequence( new MainSequence() );
2462 			pSequence->append( xMotionPathTag->getEffect()->clone() );
2463 			preview( pSequence->getRootNode() );
2464 		}
2465 		else
2466 		{
2467 			Reference< XAnimationNodeSupplier > xNodeSupplier( mxCurrentPage, UNO_QUERY );
2468 			if( !xNodeSupplier.is() )
2469 				return;
2470 
2471 			preview( xNodeSupplier->getAnimationNode() );
2472 		}
2473 	}
2474 	else
2475 	{
2476 		MainSequencePtr pSequence( new MainSequence() );
2477 
2478 		EffectSequence::iterator aIter( maListSelection.begin() );
2479 		const EffectSequence::iterator aEnd( maListSelection.end() );
2480 
2481 		while( aIter != aEnd )
2482 		{
2483 			CustomAnimationEffectPtr pEffect = (*aIter++);
2484 			pSequence->append( pEffect->clone() );
2485 		}
2486 
2487 		preview( pSequence->getRootNode() );
2488 	}
2489 }
2490 
2491 void CustomAnimationPane::preview( const Reference< XAnimationNode >& xAnimationNode )
2492 {
2493 	Reference< XTimeContainer > xRoot(::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer"))), UNO_QUERY);
2494 	if( xRoot.is() )
2495 	{
2496 		Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
2497 		aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
2498 		aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::TIMING_ROOT;
2499 		xRoot->setUserData( aUserData );
2500 		xRoot->appendChild( xAnimationNode );
2501 
2502 		Reference< XAnimationNode > xNode( xRoot, UNO_QUERY );
2503 		SlideShow::StartPreview( mrBase, mxCurrentPage, xNode );
2504 	}
2505 }
2506 
2507 
2508 // ICustomAnimationListController
2509 void CustomAnimationPane::onSelect()
2510 {
2511 	maListSelection = mpCustomAnimationList->getSelection();
2512 	updateControls();
2513 	markShapesFromSelectedEffects();
2514 }
2515 
2516 
2517 
2518 
2519 const CustomAnimationPresets& CustomAnimationPane::getPresets (void)
2520 {
2521     if (mpCustomAnimationPresets == NULL)
2522         mpCustomAnimationPresets = &CustomAnimationPresets::getCustomAnimationPresets();
2523     return *mpCustomAnimationPresets;
2524 }
2525 
2526 
2527 
2528 void CustomAnimationPane::markShapesFromSelectedEffects()
2529 {
2530 	if( !maSelectionLock.isLocked() )
2531 	{
2532 		ScopeLockGuard aGuard( maSelectionLock );
2533 		DrawViewShell* pViewShell = dynamic_cast< DrawViewShell* >(
2534 			FrameworkHelper::Instance(mrBase)->GetViewShell(FrameworkHelper::msCenterPaneURL).get());
2535 		DrawView* pView = pViewShell ? pViewShell->GetDrawView() : NULL;
2536 
2537 		if( pView )
2538 		{
2539 			pView->UnmarkAllObj();
2540 			EffectSequence::iterator aIter( maListSelection.begin() );
2541 			const EffectSequence::iterator aEnd( maListSelection.end() );
2542 			while( aIter != aEnd )
2543 			{
2544 				CustomAnimationEffectPtr pEffect = (*aIter++);
2545 
2546 				Reference< XShape > xShape( pEffect->getTargetShape() );
2547 				SdrObject* pObj = GetSdrObjectFromXShape( xShape );
2548 				if( pObj )
2549 					pView->MarkObj(pObj, pView->GetSdrPageView(), sal_False, sal_False);
2550 			}
2551 		}
2552 	}
2553 }
2554 
2555 
2556 void CustomAnimationPane::updatePathFromMotionPathTag( const rtl::Reference< MotionPathTag >& xTag )
2557 {
2558 	MainSequenceRebuildGuard aGuard( mpMainSequence );
2559 	if( xTag.is() )
2560 	{
2561 		SdrPathObj* pPathObj = xTag->getPathObj();
2562 		CustomAnimationEffectPtr pEffect = xTag->getEffect();
2563 		if( (pPathObj != 0) && pEffect.get() != 0 )
2564 		{
2565 			::svl::IUndoManager* pManager = mrBase.GetDocShell()->GetUndoManager();
2566 			if( pManager )
2567 			{
2568 				SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
2569 				if( pPage )
2570 					pManager->AddUndoAction( new UndoAnimationPath( mrBase.GetDocShell()->GetDoc(), pPage, pEffect->getNode() ) );
2571 			}
2572 
2573 			pEffect->updatePathFromSdrPathObj( *pPathObj );
2574 		}
2575 	}
2576 }
2577 
2578 // ====================================================================
2579 
2580 ::Window * createCustomAnimationPanel( ::Window* pParent, ViewShellBase& rBase )
2581 {
2582 	DialogListBox* pWindow = 0;
2583 
2584 	DrawDocShell* pDocSh = rBase.GetDocShell();
2585 	if( pDocSh )
2586 	{
2587 		pWindow = new DialogListBox( pParent, WB_CLIPCHILDREN|WB_TABSTOP|WB_AUTOHSCROLL );
2588 		const Size aMinSize( pWindow->LogicToPixel( Size( 80, 256 ), MAP_APPFONT ) );
2589         pWindow->SetSizePixel(aMinSize);
2590         pWindow->SetBackground(Wallpaper(Color(COL_BLUE)));
2591 
2592 		::Window* pPaneWindow = new CustomAnimationPane( pWindow, rBase, aMinSize );
2593 		pWindow->SetChildWindow( pPaneWindow, aMinSize );
2594 		pWindow->SetText( pPaneWindow->GetText() );
2595 	}
2596 
2597 	return pWindow;
2598 }
2599 
2600 
2601 
2602 
2603 sal_Int32 getCustomAnimationPanelMinimumHeight (::Window* pDialog)
2604 {
2605     if (pDialog != NULL)
2606 		return pDialog->LogicToPixel(Size( 80, 256 ), MAP_APPFONT).Height();
2607     else
2608         return 0;
2609 }
2610 
2611 }
2612