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