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