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