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