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 aplied 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->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->getTextGrouping() != nTextGrouping) )
1808 				{
1809 					pEffectSequence->setTextGrouping( pTextGroup, nTextGrouping );
1810 					bChanged = true;
1811 				}
1812 			}
1813 
1814 			if (!bDoSetAnimateFormFirst&&bNeedDoSetAnimateForm)
1815 			{
1816 				pEffectSequence->setAnimateForm( pTextGroup, bAnimateForm );
1817 				bChanged = true;
1818 			}
1819 
1820 			if( bHasTextGroupingAuto )
1821 			{
1822 				if( pTextGroup->getTextGroupingAuto() != fTextGroupingAuto )
1823 				{
1824 					pEffectSequence->setTextGroupingAuto( pTextGroup, fTextGroupingAuto );
1825 					bChanged = true;
1826 				}
1827 			}
1828 
1829 			if( bHasTextReverse )
1830 			{
1831 				if( pTextGroup->getTextReverse() != bTextReverse )
1832 				{
1833 					pEffectSequence->setTextReverse( pTextGroup, bTextReverse );
1834 					bChanged = true;
1835 				}
1836 			}
1837 		}
1838 	}
1839 
1840 	if( bChanged )
1841 	{
1842 		mpMainSequence->rebuild();
1843 		updateControls();
1844 		mrBase.GetDocShell()->SetModified();
1845 	}
1846 }
1847 
1848 void CustomAnimationPane::showOptions( sal_uInt16 nPage /* = 0 */ )
1849 {
1850 	STLPropertySet* pSet = createSelectionSet();
1851 
1852 	CustomAnimationDialog* pDlg = new CustomAnimationDialog( this, pSet, nPage );
1853 	if( pDlg->Execute() )
1854 	{
1855 		addUndo();
1856 		changeSelection( pDlg->getResultSet(), pSet );
1857 		updateControls();
1858 	}
1859 
1860 	delete pDlg;
1861 }
1862 
1863 void CustomAnimationPane::onChangeCurrentPage()
1864 {
1865 	if( mxView.is() ) try
1866 	{
1867 		Reference< XDrawPage > xNewPage( mxView->getCurrentPage() );
1868 		if( xNewPage != mxCurrentPage )
1869 		{
1870 			mxCurrentPage = xNewPage;
1871 			SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
1872 			if( pPage )
1873 			{
1874 				mpMainSequence = pPage->getMainSequence();
1875 				mpCustomAnimationList->update( mpMainSequence );
1876 			}
1877 			updateControls();
1878 		}
1879 	}
1880 	catch( Exception& )
1881 	{
1882 		DBG_ERROR( "sd::CustomAnimationPane::onChangeCurrentPage(), exception catched!" );
1883 	}
1884 }
1885 
1886 bool getTextSelection( const Any& rSelection, Reference< XShape >& xShape, std::list< sal_Int16 >& rParaList )
1887 {
1888 	Reference< XTextRange > xSelectedText;
1889 	rSelection >>= xSelectedText;
1890 	if( xSelectedText.is() ) try
1891 	{
1892 		xShape.set( xSelectedText->getText(), UNO_QUERY_THROW );
1893 
1894 		Reference< XTextRangeCompare > xTextRangeCompare( xShape, UNO_QUERY_THROW );
1895 		Reference< XEnumerationAccess > xParaEnumAccess( xShape, UNO_QUERY_THROW );
1896 		Reference< XEnumeration > xParaEnum( xParaEnumAccess->createEnumeration(), UNO_QUERY_THROW );
1897 		Reference< XTextRange > xRange;
1898 		Reference< XTextRange > xStart( xSelectedText->getStart() );
1899 		Reference< XTextRange > xEnd( xSelectedText->getEnd() );
1900 
1901 		if( xTextRangeCompare->compareRegionEnds( xStart, xEnd ) < 0 )
1902 		{
1903 			Reference< XTextRange > xTemp( xStart );
1904 			xStart = xEnd;
1905 			xEnd = xTemp;
1906 		}
1907 
1908 		sal_Int16 nPara = 0;
1909 		while( xParaEnum->hasMoreElements() )
1910 		{
1911 			xParaEnum->nextElement() >>= xRange;
1912 
1913 			// break if start of selection is prior to end of current paragraph
1914 			if( xRange.is() && (xTextRangeCompare->compareRegionEnds( xStart, xRange ) >= 0 ) )
1915 				break;
1916 
1917 			nPara++;
1918 		}
1919 
1920 		while( xRange.is() )
1921 		{
1922 			if( xRange.is() && xRange->getString().getLength() )
1923 				rParaList.push_back( nPara );
1924 
1925 			// break if end of selection is before or at end of current paragraph
1926 			if( xRange.is() && xTextRangeCompare->compareRegionEnds( xEnd, xRange ) >= 0 )
1927 				break;
1928 
1929 			nPara++;
1930 
1931 			if( xParaEnum->hasMoreElements() )
1932 				xParaEnum->nextElement() >>= xRange;
1933 			else
1934 				xRange.clear();
1935 		}
1936 
1937 		return true;
1938 	}
1939 	catch( Exception& e )
1940 	{
1941 		(void)e;
1942 		DBG_ERROR( "sd::CustomAnimationPane::getTextSelection(), exception cought!" );
1943 	}
1944 
1945 	return false;
1946 }
1947 
1948 void CustomAnimationPane::onChange( bool bCreate )
1949 {
1950 	bool bHasText = true;
1951 
1952 	// first create vector of targets for dialog preview
1953 	std::vector< Any > aTargets;
1954 	OUString sPresetId;
1955 	double fDuration = 2.0f;
1956 
1957 	if( bCreate )
1958 	{
1959 		// gather shapes from the selection
1960 		Reference< XSelectionSupplier >  xSel( mxView, UNO_QUERY_THROW );
1961 		maViewSelection = xSel->getSelection();
1962 
1963 		if( maViewSelection.getValueType() == ::getCppuType((const Reference< XShapes >*)0) )
1964 		{
1965 			Reference< XIndexAccess > xShapes;
1966 			maViewSelection >>= xShapes;
1967 
1968 			sal_Int32 nCount = xShapes->getCount();
1969 			sal_Int32 nIndex;
1970 			for( nIndex = 0; nIndex < nCount; nIndex++ )
1971 			{
1972 				Any aTarget( xShapes->getByIndex( nIndex ) );
1973 				aTargets.push_back( aTarget );
1974 				if( bHasText )
1975 				{
1976 					Reference< XText > xText;
1977 					aTarget >>= xText;
1978 					if( !xText.is() || xText->getString().getLength() == 0 )
1979 						bHasText = false;
1980 				}
1981 			}
1982 		}
1983 		else if ( maViewSelection.getValueType() == ::getCppuType((const Reference< XShape >*)0) )
1984 		{
1985 			aTargets.push_back( maViewSelection );
1986 			Reference< XText > xText;
1987 			maViewSelection >>= xText;
1988 			if( !xText.is() || xText->getString().getLength() == 0 )
1989 				bHasText = false;
1990 		}
1991 		else if ( maViewSelection.getValueType() == ::getCppuType((const Reference< XTextCursor >*)0) )
1992 		{
1993 			Reference< XShape > xShape;
1994 			std::list< sal_Int16 > aParaList;
1995 			if( getTextSelection( maViewSelection, xShape, aParaList ) )
1996 			{
1997 				ParagraphTarget aParaTarget;
1998 				aParaTarget.Shape = xShape;
1999 
2000 				std::list< sal_Int16 >::iterator aIter( aParaList.begin() );
2001 				for( ; aIter != aParaList.end(); aIter++ )
2002 				{
2003 					aParaTarget.Paragraph = (*aIter);
2004 					aTargets.push_back( makeAny( aParaTarget ) );
2005    				}
2006 			}
2007 		}
2008 		else
2009 		{
2010 			DBG_ERROR("sd::CustomAnimationPane::onChange(), unknown view selection!" );
2011 			return;
2012 		}
2013 	}
2014 	else
2015 	{
2016 		// get selected effect
2017 		EffectSequence::iterator aIter( maListSelection.begin() );
2018 		const EffectSequence::iterator aEnd( maListSelection.end() );
2019 		while( aIter != aEnd )
2020 		{
2021 			if( !bHasText || !(*aIter)->hasText() )
2022 				bHasText = false;
2023 
2024 			if( sPresetId.getLength() == 0 )
2025 			{
2026 				sPresetId = (*aIter)->getPresetId();
2027 				fDuration = (*aIter)->getDuration();
2028 			}
2029 
2030 			aTargets.push_back( (*aIter++)->getTarget() );
2031 		}
2032 	}
2033 
2034 	CustomAnimationCreateDialog* pDlg = new CustomAnimationCreateDialog( this, this, aTargets, bHasText, sPresetId, fDuration );
2035 	if( pDlg->Execute() )
2036 	{
2037 		addUndo();
2038 		fDuration = pDlg->getSelectedDuration();
2039 		CustomAnimationPresetPtr pDescriptor = pDlg->getSelectedPreset();
2040 		if( pDescriptor.get() )
2041 		{
2042 			if( bCreate )
2043 			{
2044 				mpCustomAnimationList->SelectAll( sal_False );
2045 
2046 				// gather shapes from the selection
2047 				std::vector< Any >::iterator aIter( aTargets.begin() );
2048 				const std::vector< Any >::iterator aEnd( aTargets.end() );
2049 				bool bFirst = true;
2050 				for( ; aIter != aEnd; aIter++ )
2051 				{
2052 					CustomAnimationEffectPtr pCreated = mpMainSequence->append( pDescriptor, (*aIter), fDuration );
2053 
2054 					// if only one shape with text and no fill or outline is selected, animate only by first level paragraphs
2055 					if( bHasText && (aTargets.size() == 1) )
2056 					{
2057 						Reference< XShape > xShape( (*aIter), UNO_QUERY );
2058 						if( xShape.is() && !hasVisibleShape( xShape ) )
2059 						{
2060 							mpMainSequence->createTextGroup( pCreated, 1, -1.0, sal_False, sal_False );
2061 						}
2062 					}
2063 
2064 					if( bFirst )
2065 						bFirst = false;
2066 					else
2067 						pCreated->setNodeType( EffectNodeType::WITH_PREVIOUS );
2068 
2069 					if( pCreated.get() )
2070 					{
2071 						mpCustomAnimationList->select( pCreated );
2072 					}
2073 				}
2074 			}
2075 			else
2076 			{
2077 				MainSequenceRebuildGuard aGuard( mpMainSequence );
2078 
2079 				// get selected effect
2080 				EffectSequence::iterator aIter( maListSelection.begin() );
2081 				const EffectSequence::iterator aEnd( maListSelection.end() );
2082 				while( aIter != aEnd )
2083 				{
2084 					CustomAnimationEffectPtr pEffect = (*aIter++);
2085 
2086 					EffectSequenceHelper* pEffectSequence = pEffect->getEffectSequence();
2087 					if( !pEffectSequence )
2088 						pEffectSequence = mpMainSequence.get();
2089 
2090 					pEffectSequence->replace( pEffect, pDescriptor, fDuration );
2091 				}
2092 			}
2093 		}
2094 		else
2095 		{
2096 			PathKind eKind = pDlg->getCreatePathKind();
2097 			if( eKind != NONE )
2098 				createPath( eKind, aTargets, fDuration );
2099 		}
2100 		mrBase.GetDocShell()->SetModified();
2101 	}
2102 
2103 	delete pDlg;
2104 
2105 	updateControls();
2106 
2107 	// stop running preview from dialog
2108 	SlideShow::Stop( mrBase );
2109 }
2110 
2111 void CustomAnimationPane::createPath( PathKind eKind, std::vector< Any >& rTargets, double fDuration)
2112 {
2113 	sal_uInt16 nSID = 0;
2114 
2115 	switch( eKind )
2116 	{
2117 	case CURVE:		nSID = SID_DRAW_BEZIER_NOFILL; break;
2118 	case POLYGON:	nSID = SID_DRAW_POLYGON_NOFILL; break;
2119 	case FREEFORM:	nSID = SID_DRAW_FREELINE_NOFILL; break;
2120 	default: break;
2121 	}
2122 
2123 	if( nSID )
2124 	{
2125 		DrawViewShell* pViewShell = dynamic_cast< DrawViewShell* >(
2126 		    FrameworkHelper::Instance(mrBase)->GetViewShell(FrameworkHelper::msCenterPaneURL).get());
2127 
2128 		if( pViewShell )
2129 		{
2130 			DrawView* pView = pViewShell->GetDrawView();
2131 			if( pView )
2132 				pView->UnmarkAllObj();
2133 
2134 			std::vector< Any > aTargets( 1, Any( fDuration ) );
2135 			aTargets.insert( aTargets.end(), rTargets.begin(), rTargets.end() );
2136 			Sequence< Any > aTargetSequence( comphelper::containerToSequence( aTargets ) );
2137 			const SfxUnoAnyItem aItem( SID_ADD_MOTION_PATH, Any( aTargetSequence ) );
2138 			pViewShell->GetViewFrame()->GetDispatcher()->Execute( nSID, SFX_CALLMODE_ASYNCHRON, &aItem, 0 );
2139 		}
2140 	}
2141 }
2142 
2143 void CustomAnimationPane::onRemove()
2144 {
2145 	if( !maListSelection.empty() )
2146 	{
2147 		addUndo();
2148 
2149 		MainSequenceRebuildGuard aGuard( mpMainSequence );
2150 
2151 		EffectSequence aList( maListSelection );
2152 
2153 		EffectSequence::iterator aIter( aList.begin() );
2154 		const EffectSequence::iterator aEnd( aList.end() );
2155 		while( aIter != aEnd )
2156 		{
2157 			CustomAnimationEffectPtr pEffect = (*aIter++);
2158 			if( pEffect->getEffectSequence() )
2159 				pEffect->getEffectSequence()->remove( pEffect );
2160 		}
2161 
2162 		maListSelection.clear();
2163 		mrBase.GetDocShell()->SetModified();
2164 	}
2165 }
2166 
2167 void CustomAnimationPane::remove( CustomAnimationEffectPtr& pEffect )
2168 {
2169 	if( pEffect->getEffectSequence() )
2170 	{
2171 		addUndo();
2172 		pEffect->getEffectSequence()->remove( pEffect );
2173 		mrBase.GetDocShell()->SetModified();
2174 	}
2175 }
2176 
2177 void CustomAnimationPane::onChangeStart()
2178 {
2179 	if( mpLBStart->GetSelectEntryCount() == 1 )
2180 	{
2181 		sal_Int16 nNodeType;
2182 		sal_uInt16 nPos= mpLBStart->GetSelectEntryPos();
2183 		switch( nPos )
2184 		{
2185 		case 0:	nNodeType = EffectNodeType::ON_CLICK; break;
2186 		case 1:	nNodeType = EffectNodeType::WITH_PREVIOUS; break;
2187 		case 2:	nNodeType = EffectNodeType::AFTER_PREVIOUS; break;
2188 		default:
2189 			return;
2190 		}
2191 
2192 		onChangeStart( nNodeType );
2193 	}
2194 }
2195 
2196 void CustomAnimationPane::onChangeStart( sal_Int16 nNodeType )
2197 {
2198 	addUndo();
2199 
2200 	MainSequenceRebuildGuard aGuard( mpMainSequence );
2201 
2202 	bool bNeedRebuild = false;
2203 
2204 	EffectSequence::iterator aIter( maListSelection.begin() );
2205 	const EffectSequence::iterator aEnd( maListSelection.end() );
2206 	while( aIter != aEnd )
2207 	{
2208 		CustomAnimationEffectPtr pEffect = (*aIter++);
2209 		if( pEffect->getNodeType() != nNodeType )
2210 		{
2211 			pEffect->setNodeType( nNodeType );
2212 			bNeedRebuild = true;
2213 		}
2214 	}
2215 
2216 	if( bNeedRebuild )
2217 	{
2218 		mpMainSequence->rebuild();
2219 		updateControls();
2220 		mrBase.GetDocShell()->SetModified();
2221 	}
2222 }
2223 
2224 void CustomAnimationPane::onChangeProperty()
2225 {
2226 	if( mpLBProperty->getSubControl() )
2227 	{
2228 		addUndo();
2229 
2230 		MainSequenceRebuildGuard aGuard( mpMainSequence );
2231 
2232 		const Any aValue( mpLBProperty->getSubControl()->getValue() );
2233 
2234 		bool bNeedUpdate = false;
2235 
2236 		// change selected effect
2237 		EffectSequence::iterator aIter( maListSelection.begin() );
2238 		const EffectSequence::iterator aEnd( maListSelection.end() );
2239 		while( aIter != aEnd )
2240 		{
2241 			CustomAnimationEffectPtr pEffect = (*aIter++);
2242 
2243 			if( setProperty1Value( mnPropertyType, pEffect, aValue ) )
2244 				bNeedUpdate = true;
2245 		}
2246 
2247 		if( bNeedUpdate )
2248 		{
2249 			mpMainSequence->rebuild();
2250 			updateControls();
2251 			mrBase.GetDocShell()->SetModified();
2252 		}
2253 
2254 		onPreview( false );
2255 	}
2256 }
2257 
2258 void CustomAnimationPane::onChangeSpeed()
2259 {
2260 	if( mpCBSpeed->GetSelectEntryCount() == 1 )
2261 	{
2262 		addUndo();
2263 
2264 		MainSequenceRebuildGuard aGuard( mpMainSequence );
2265 
2266 		double fDuration;
2267 
2268 		sal_uInt16 nPos= mpCBSpeed->GetSelectEntryPos();
2269 
2270 		switch( nPos )
2271 		{
2272 		case 0: fDuration = 5.0; break;
2273 		case 1: fDuration = 3.0; break;
2274 		case 2: fDuration = 2.0; break;
2275 		case 3: fDuration = 1.0; break;
2276 		case 4: fDuration = 0.5; break;
2277 		default:
2278 			return;
2279 		}
2280 
2281 		// change selected effect
2282 		EffectSequence::iterator aIter( maListSelection.begin() );
2283 		const EffectSequence::iterator aEnd( maListSelection.end() );
2284 		while( aIter != aEnd )
2285 		{
2286 			CustomAnimationEffectPtr pEffect = (*aIter++);
2287 			pEffect->setDuration( fDuration );
2288 		}
2289 
2290 		mpMainSequence->rebuild();
2291 		updateControls();
2292 		mrBase.GetDocShell()->SetModified();
2293 
2294 		onPreview( false );
2295 	}
2296 }
2297 
2298 /// this link is called when the property box is modified by the user
2299 IMPL_LINK( CustomAnimationPane, implPropertyHdl, Control*, EMPTYARG )
2300 {
2301 	onChangeProperty();
2302 	return 0;
2303 }
2304 
2305 /// this link is called when one of the controls is modified
2306 IMPL_LINK( CustomAnimationPane, implControlHdl, Control*, pControl )
2307 {
2308 	if( pControl == mpPBAddEffect )
2309 		onChange(true);
2310 	else if( pControl == mpPBChangeEffect )
2311 		onChange(false);
2312 	else if( pControl == mpPBRemoveEffect )
2313 		onRemove();
2314 	else if( pControl == mpLBStart )
2315 		onChangeStart();
2316 	else if( pControl == mpCBSpeed )
2317 		onChangeSpeed();
2318 	else if( pControl == mpPBPropertyMore )
2319 		showOptions();
2320 	else if( pControl == mpPBMoveUp )
2321 		moveSelection( true );
2322 	else if( pControl == mpPBMoveDown )
2323 		moveSelection( false );
2324 	else if( pControl == mpPBPlay )
2325 		onPreview( true );
2326 	else if( pControl == mpPBSlideShow )
2327 	{
2328 		mrBase.StartPresentation();
2329 	}
2330 	else if( pControl == mpCBAutoPreview )
2331 	{
2332 		SdOptions* pOptions = SD_MOD()->GetSdOptions(DOCUMENT_TYPE_IMPRESS);
2333 		pOptions->SetPreviewChangedEffects( mpCBAutoPreview->IsChecked() ? sal_True : sal_False );
2334 	}
2335 
2336 	updateControls();
2337 
2338 	return 0;
2339 }
2340 
2341 IMPL_LINK(CustomAnimationPane, lateInitCallback, Timer*, EMPTYARG )
2342 {
2343     // Call getPresets() to initiate the (expensive) construction of the
2344     // presets list.
2345     getPresets();
2346 
2347     // update selection and control states
2348     onSelectionChanged();
2349 
2350     return 0;
2351 }
2352 
2353 void CustomAnimationPane::moveSelection( bool bUp )
2354 {
2355 	if( maListSelection.empty() )
2356 		return;
2357 
2358 	EffectSequenceHelper* pSequence = maListSelection.front()->getEffectSequence();
2359 	if( pSequence == 0 )
2360 		return;
2361 
2362 	addUndo();
2363 
2364 	bool bChanged = false;
2365 
2366 	MainSequenceRebuildGuard aGuard( mpMainSequence );
2367 	EffectSequence& rEffectSequence = pSequence->getSequence();
2368 
2369 	if( bUp )
2370 	{
2371 		EffectSequence::iterator aIter( maListSelection.begin() );
2372 		const EffectSequence::iterator aEnd( maListSelection.end() );
2373 
2374 		while( aIter != aEnd )
2375 		{
2376 			CustomAnimationEffectPtr pEffect = (*aIter++);
2377 
2378 			EffectSequence::iterator aEffectPos( pSequence->find( pEffect ) );
2379 			if( aEffectPos != rEffectSequence.end() )
2380 			{
2381 				EffectSequence::iterator aInsertPos( rEffectSequence.erase( aEffectPos ) );
2382 
2383 				if( aInsertPos != rEffectSequence.begin() )
2384 				{
2385 					aInsertPos--;
2386 					while( (aInsertPos != rEffectSequence.begin()) && !mpCustomAnimationList->isExpanded(*aInsertPos))
2387 						aInsertPos--;
2388 
2389 					rEffectSequence.insert( aInsertPos, pEffect );
2390 				}
2391 				else
2392 				{
2393 					rEffectSequence.push_front( pEffect );
2394 				}
2395 				bChanged = true;
2396 			}
2397 		}
2398 	}
2399 	else
2400 	{
2401 		EffectSequence::reverse_iterator aIter( maListSelection.rbegin() );
2402 		const EffectSequence::reverse_iterator aEnd( maListSelection.rend() );
2403 
2404 		while( aIter != aEnd )
2405 		{
2406 			CustomAnimationEffectPtr pEffect = (*aIter++);
2407 
2408 			EffectSequence::iterator aEffectPos( pSequence->find( pEffect ) );
2409 			if( aEffectPos != rEffectSequence.end() )
2410 			{
2411 				EffectSequence::iterator aInsertPos( rEffectSequence.erase( aEffectPos ) );
2412 
2413 				if( aInsertPos != rEffectSequence.end() )
2414 				{
2415 					aInsertPos++;
2416 					while( (aInsertPos != rEffectSequence.end()) && !mpCustomAnimationList->isExpanded(*aInsertPos))
2417 						aInsertPos++;
2418 
2419 					rEffectSequence.insert( aInsertPos, pEffect );
2420 				}
2421 				else
2422 				{
2423 					rEffectSequence.push_back( pEffect );
2424 				}
2425 				bChanged = true;
2426 			}
2427 		}
2428 	}
2429 
2430 	if( bChanged )
2431 	{
2432 		mpMainSequence->rebuild();
2433 		updateControls();
2434 		mrBase.GetDocShell()->SetModified();
2435 	}
2436 }
2437 
2438 void CustomAnimationPane::onPreview( bool bForcePreview )
2439 {
2440 	if( !bForcePreview && !mpCBAutoPreview->IsChecked() )
2441 		return;
2442 
2443 	if( maListSelection.empty() )
2444 	{
2445 		rtl::Reference< MotionPathTag > xMotionPathTag;
2446 		MotionPathTagVector::iterator aIter;
2447 		for( aIter = maMotionPathTags.begin(); aIter != maMotionPathTags.end(); aIter++ )
2448 		{
2449 			if( (*aIter)->isSelected() )
2450 			{
2451 				xMotionPathTag = (*aIter);
2452 				break;
2453 			}
2454 		}
2455 
2456 		if( xMotionPathTag.is() )
2457 		{
2458 			MainSequencePtr pSequence( new MainSequence() );
2459 			pSequence->append( xMotionPathTag->getEffect()->clone() );
2460 			preview( pSequence->getRootNode() );
2461 		}
2462 		else
2463 		{
2464 			Reference< XAnimationNodeSupplier > xNodeSupplier( mxCurrentPage, UNO_QUERY );
2465 			if( !xNodeSupplier.is() )
2466 				return;
2467 
2468 			preview( xNodeSupplier->getAnimationNode() );
2469 		}
2470 	}
2471 	else
2472 	{
2473 		MainSequencePtr pSequence( new MainSequence() );
2474 
2475 		EffectSequence::iterator aIter( maListSelection.begin() );
2476 		const EffectSequence::iterator aEnd( maListSelection.end() );
2477 
2478 		while( aIter != aEnd )
2479 		{
2480 			CustomAnimationEffectPtr pEffect = (*aIter++);
2481 			pSequence->append( pEffect->clone() );
2482 		}
2483 
2484 		preview( pSequence->getRootNode() );
2485 	}
2486 }
2487 
2488 void CustomAnimationPane::preview( const Reference< XAnimationNode >& xAnimationNode )
2489 {
2490 	Reference< XTimeContainer > xRoot(::comphelper::getProcessServiceFactory()->createInstance(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.animations.ParallelTimeContainer"))), UNO_QUERY);
2491 	if( xRoot.is() )
2492 	{
2493 		Sequence< ::com::sun::star::beans::NamedValue > aUserData( 1 );
2494 		aUserData[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) );
2495 		aUserData[0].Value <<= ::com::sun::star::presentation::EffectNodeType::TIMING_ROOT;
2496 		xRoot->setUserData( aUserData );
2497 		xRoot->appendChild( xAnimationNode );
2498 
2499 		Reference< XAnimationNode > xNode( xRoot, UNO_QUERY );
2500 		SlideShow::StartPreview( mrBase, mxCurrentPage, xNode );
2501 	}
2502 }
2503 
2504 
2505 // ICustomAnimationListController
2506 void CustomAnimationPane::onSelect()
2507 {
2508 	maListSelection = mpCustomAnimationList->getSelection();
2509 	updateControls();
2510 	markShapesFromSelectedEffects();
2511 }
2512 
2513 
2514 
2515 
2516 const CustomAnimationPresets& CustomAnimationPane::getPresets (void)
2517 {
2518     if (mpCustomAnimationPresets == NULL)
2519         mpCustomAnimationPresets = &CustomAnimationPresets::getCustomAnimationPresets();
2520     return *mpCustomAnimationPresets;
2521 }
2522 
2523 
2524 
2525 void CustomAnimationPane::markShapesFromSelectedEffects()
2526 {
2527 	if( !maSelectionLock.isLocked() )
2528 	{
2529 		ScopeLockGuard aGuard( maSelectionLock );
2530 		DrawViewShell* pViewShell = dynamic_cast< DrawViewShell* >(
2531 			FrameworkHelper::Instance(mrBase)->GetViewShell(FrameworkHelper::msCenterPaneURL).get());
2532 		DrawView* pView = pViewShell ? pViewShell->GetDrawView() : NULL;
2533 
2534 		if( pView )
2535 		{
2536 			pView->UnmarkAllObj();
2537 			EffectSequence::iterator aIter( maListSelection.begin() );
2538 			const EffectSequence::iterator aEnd( maListSelection.end() );
2539 			while( aIter != aEnd )
2540 			{
2541 				CustomAnimationEffectPtr pEffect = (*aIter++);
2542 
2543 				Reference< XShape > xShape( pEffect->getTargetShape() );
2544 				SdrObject* pObj = GetSdrObjectFromXShape( xShape );
2545 				if( pObj )
2546 					pView->MarkObj(pObj, pView->GetSdrPageView(), sal_False, sal_False);
2547 			}
2548 		}
2549 	}
2550 }
2551 
2552 
2553 void CustomAnimationPane::updatePathFromMotionPathTag( const rtl::Reference< MotionPathTag >& xTag )
2554 {
2555 	MainSequenceRebuildGuard aGuard( mpMainSequence );
2556 	if( xTag.is() )
2557 	{
2558 		SdrPathObj* pPathObj = xTag->getPathObj();
2559 		CustomAnimationEffectPtr pEffect = xTag->getEffect();
2560 		if( (pPathObj != 0) && pEffect.get() != 0 )
2561 		{
2562 			::svl::IUndoManager* pManager = mrBase.GetDocShell()->GetUndoManager();
2563 			if( pManager )
2564 			{
2565 				SdPage* pPage = SdPage::getImplementation( mxCurrentPage );
2566 				if( pPage )
2567 					pManager->AddUndoAction( new UndoAnimationPath( mrBase.GetDocShell()->GetDoc(), pPage, pEffect->getNode() ) );
2568 			}
2569 
2570 			pEffect->updatePathFromSdrPathObj( *pPathObj );
2571 		}
2572 	}
2573 }
2574 
2575 // ====================================================================
2576 
2577 ::Window * createCustomAnimationPanel( ::Window* pParent, ViewShellBase& rBase )
2578 {
2579 	DialogListBox* pWindow = 0;
2580 
2581 	DrawDocShell* pDocSh = rBase.GetDocShell();
2582 	if( pDocSh )
2583 	{
2584 		pWindow = new DialogListBox( pParent, WB_CLIPCHILDREN|WB_TABSTOP|WB_AUTOHSCROLL );
2585 		const Size aMinSize( pWindow->LogicToPixel( Size( 80, 256 ), MAP_APPFONT ) );
2586         pWindow->SetSizePixel(aMinSize);
2587         pWindow->SetBackground(Wallpaper(Color(COL_BLUE)));
2588 
2589 		::Window* pPaneWindow = new CustomAnimationPane( pWindow, rBase, aMinSize );
2590 		pWindow->SetChildWindow( pPaneWindow, aMinSize );
2591 		pWindow->SetText( pPaneWindow->GetText() );
2592 	}
2593 
2594 	return pWindow;
2595 }
2596 
2597 
2598 
2599 
2600 sal_Int32 getCustomAnimationPanelMinimumHeight (::Window* pDialog)
2601 {
2602     if (pDialog != NULL)
2603 		return pDialog->LogicToPixel(Size( 80, 256 ), MAP_APPFONT).Height();
2604     else
2605         return 0;
2606 }
2607 
2608 }
2609