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