xref: /trunk/main/sd/source/ui/animations/CustomAnimationList.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sd.hxx"
30 #include <com/sun/star/drawing/XShapes.hpp>
31 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
32 #include <com/sun/star/presentation/EffectNodeType.hpp>
33 #include <com/sun/star/presentation/ParagraphTarget.hpp>
34 #include <com/sun/star/container/XEnumerationAccess.hpp>
35 #include <com/sun/star/animations/XIterateContainer.hpp>
36 #include <com/sun/star/presentation/EffectPresetClass.hpp>
37 #include <com/sun/star/presentation/EffectCommands.hpp>
38 #include <com/sun/star/text/XTextRange.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/drawing/XDrawPage.hpp>
41 #include <svx/ShapeTypeHandler.hxx>
42 #include "CustomAnimationList.hxx"
43 #ifndef _SD_CUSTOMANIMATIONPANE_HRC
44 #include "CustomAnimationPane.hrc"
45 #endif
46 #ifndef _SD_CUSTOMANIMATION_HRC
47 #include "CustomAnimation.hrc"
48 #endif
49 #include "CustomAnimationPreset.hxx"
50 #include <svtools/treelist.hxx>
51 #include <vcl/svapp.hxx>
52 #include "sdresid.hxx"
53 
54 #include "res_bmp.hrc"
55 #include "glob.hrc"
56 
57 #include <algorithm>
58 
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::animations;
61 using namespace ::com::sun::star::presentation;
62 
63 using ::rtl::OUString;
64 using ::com::sun::star::uno::UNO_QUERY;
65 using ::com::sun::star::uno::UNO_QUERY_THROW;
66 using ::com::sun::star::uno::Any;
67 using ::com::sun::star::uno::Sequence;
68 using ::com::sun::star::uno::Reference;
69 using ::com::sun::star::uno::Exception;
70 using ::com::sun::star::uno::XInterface;
71 using ::com::sun::star::text::XTextRange;
72 using ::com::sun::star::drawing::XShape;
73 using ::com::sun::star::drawing::XShapes;
74 using ::com::sun::star::drawing::XDrawPage;
75 using ::com::sun::star::container::XChild;
76 using ::com::sun::star::container::XIndexAccess;
77 using ::com::sun::star::container::XEnumerationAccess;
78 using ::com::sun::star::container::XEnumeration;
79 using ::com::sun::star::beans::XPropertySet;
80 using ::com::sun::star::beans::XPropertySetInfo;
81 using ::accessibility::ShapeTypeHandler;
82 
83 namespace sd {
84 
85 // go recursivly through all shapes in the given XShapes collection and return true as soon as the
86 // given shape is found. nIndex is incremented for each shape with the same shape type as the given
87 // shape is found until the given shape is found.
88 static bool getShapeIndex(  const Reference< XShapes >& xShapes, const Reference< XShape >& xShape, sal_Int32& nIndex )
89 {
90     const sal_Int32 nCount = xShapes->getCount();
91     sal_Int32 n;
92     for( n = 0; n < nCount; n++ )
93     {
94         Reference< XShape > xChild;
95         xShapes->getByIndex( n ) >>= xChild;
96         if( xChild == xShape )
97             return true;
98 
99         if( xChild->getShapeType() == xShape->getShapeType() )
100             nIndex++;
101 
102         Reference< XShapes > xChildContainer( xChild, UNO_QUERY );
103         if( xChildContainer.is() )
104         {
105             if( getShapeIndex( xChildContainer, xShape, nIndex ) )
106                 return true;
107         }
108     }
109 
110     return false;
111 }
112 
113 // returns the index of the shape type from the given shape
114 static sal_Int32 getShapeIndex( const Reference< XShape >& xShape )
115 {
116     Reference< XChild > xChild( xShape, UNO_QUERY );
117     Reference< XShapes > xPage;
118 
119     while( xChild.is() && !xPage.is() )
120     {
121         Reference< XInterface > x( xChild->getParent() );
122         xChild = Reference< XChild >::query( x );
123         Reference< XDrawPage > xTestPage( x, UNO_QUERY );
124         if( xTestPage.is() )
125             xPage = Reference< XShapes >::query( x );
126     }
127 
128     sal_Int32 nIndex = 1;
129 
130     if( xPage.is() && getShapeIndex( xPage, xShape, nIndex ) )
131         return nIndex;
132     else
133         return -1;
134 }
135 
136 OUString getShapeDescription( const Reference< XShape >& xShape, bool bWithText = true )
137 {
138     OUString aDescription;
139     Reference< XPropertySet > xSet( xShape, UNO_QUERY );
140     if( xSet.is() )
141     {
142         Reference< XPropertySetInfo > xInfo( xSet->getPropertySetInfo() );
143         const OUString aPropName( RTL_CONSTASCII_USTRINGPARAM("UINameSingular") );
144         if( xInfo->hasPropertyByName( aPropName ) )
145             xSet->getPropertyValue( aPropName ) >>= aDescription;
146     }
147 
148     aDescription += OUString( RTL_CONSTASCII_USTRINGPARAM(" "));
149     aDescription += OUString::valueOf( getShapeIndex( xShape ) );
150 
151     if( bWithText )
152     {
153         Reference< XTextRange > xText( xShape, UNO_QUERY );
154         if( xText.is() )
155         {
156             OUString aText( xText->getString() );
157             if( aText.getLength() )
158             {
159                 aDescription += OUString(RTL_CONSTASCII_USTRINGPARAM(": "));
160 
161                 aText = aText.replace( (sal_Unicode)'\n', (sal_Unicode)' ' );
162                 aText = aText.replace( (sal_Unicode)'\r', (sal_Unicode)' ' );
163 
164                 aDescription += aText;
165             }
166         }
167     }
168     return aDescription;
169 }
170 
171 static OUString getDescription( const Any& rTarget, bool bWithText = true )
172 {
173     OUString aDescription;
174 
175     if( rTarget.getValueType() == ::getCppuType((const ParagraphTarget*)0) )
176     {
177         ParagraphTarget aParaTarget;
178         rTarget >>= aParaTarget;
179 
180         Reference< XEnumerationAccess > xText( aParaTarget.Shape, UNO_QUERY_THROW );
181         Reference< XEnumeration > xEnumeration( xText->createEnumeration(), UNO_QUERY_THROW );
182         sal_Int32 nPara = aParaTarget.Paragraph;
183 
184         while( xEnumeration->hasMoreElements() && nPara )
185         {
186             xEnumeration->nextElement();
187             nPara--;
188         }
189 
190         DBG_ASSERT( xEnumeration->hasMoreElements(), "sd::CustomAnimationEffect::prepareText(), paragraph out of range!" );
191 
192         if( xEnumeration->hasMoreElements() )
193         {
194             Reference< XTextRange > xParagraph;
195             xEnumeration->nextElement() >>= xParagraph;
196 
197             if( xParagraph.is() )
198                 aDescription = xParagraph->getString();
199         }
200     }
201     else
202     {
203         Reference< XShape > xShape;
204         rTarget >>= xShape;
205         if( xShape.is() )
206             aDescription = getShapeDescription( xShape, bWithText );
207     }
208 
209     return aDescription;
210 }
211 
212 // ====================================================================
213 
214 class CustomAnimationListEntryItem : public SvLBoxString
215 {
216 public:
217                     CustomAnimationListEntryItem( SvLBoxEntry*,sal_uInt16 nFlags, OUString aDescription, CustomAnimationEffectPtr pEffect, CustomAnimationList* pParent  );
218     virtual         ~CustomAnimationListEntryItem();
219     void            InitViewData( SvLBox*,SvLBoxEntry*,SvViewDataItem* );
220     void            Paint( const Point&, SvLBox& rDev, sal_uInt16 nFlags,SvLBoxEntry* );
221     SvLBoxItem*     Create() const;
222     void            Clone( SvLBoxItem* pSource );
223 
224 private:
225     CustomAnimationList* mpParent;
226     OUString        maDescription;
227     CustomAnimationEffectPtr mpEffect;
228 };
229 
230 // --------------------------------------------------------------------
231 
232 CustomAnimationListEntryItem::CustomAnimationListEntryItem( SvLBoxEntry* pEntry, sal_uInt16 nFlags, OUString aDescription, CustomAnimationEffectPtr pEffect, CustomAnimationList* pParent  )
233 : SvLBoxString( pEntry, nFlags, aDescription )
234 , mpParent( pParent )
235 , maDescription( aDescription )
236 , mpEffect(pEffect)
237 {
238 }
239 
240 // --------------------------------------------------------------------
241 
242 CustomAnimationListEntryItem::~CustomAnimationListEntryItem()
243 {
244 }
245 
246 // --------------------------------------------------------------------
247 
248 void CustomAnimationListEntryItem::InitViewData( SvLBox* pView, SvLBoxEntry* pEntry, SvViewDataItem* pViewData )
249 {
250     if( !pViewData )
251         pViewData = pView->GetViewDataItem( pEntry, this );
252 
253     Size aSize(pView->GetTextWidth( maDescription ) + 2 * 19, pView->GetTextHeight() );
254     if( aSize.Height() < 19 )
255         aSize.Height() = 19;
256     pViewData->aSize = aSize;
257 }
258 
259 // --------------------------------------------------------------------
260 
261 void CustomAnimationListEntryItem::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16, SvLBoxEntry* pEntry )
262 {
263     const bool bHighContrast = Application::GetSettings().GetStyleSettings().GetHighContrastMode();
264 
265     SvViewDataItem* pViewData = mpParent->GetViewDataItem( pEntry, this );
266 
267     Point aPos( rPos );
268     Size aSize( pViewData->aSize );
269 
270     sal_Int16 nNodeType = mpEffect->getNodeType();
271     if( nNodeType == EffectNodeType::ON_CLICK )
272     {
273         rDev.DrawImage( aPos, mpParent->getImage( IMG_CUSTOMANIMATION_ON_CLICK, bHighContrast ) );
274     }
275     else if( nNodeType == EffectNodeType::AFTER_PREVIOUS )
276     {
277         rDev.DrawImage( aPos, mpParent->getImage( IMG_CUSTOMANIMATION_AFTER_PREVIOUS, bHighContrast ) );
278     }
279 
280     aPos.X() += 19;
281 
282     sal_uInt16 nImage;
283     switch( mpEffect->getPresetClass() )
284     {
285     case EffectPresetClass::ENTRANCE:   nImage = IMG_CUSTOMANIMATION_ENTRANCE_EFFECT; break;
286     case EffectPresetClass::EXIT:       nImage =  IMG_CUSTOMANIMATION_EXIT_EFFECT; break;
287     case EffectPresetClass::EMPHASIS:   nImage =  IMG_CUSTOMANIMATION_EMPHASIS_EFFECT; break;
288     case EffectPresetClass::MOTIONPATH: nImage = IMG_CUSTOMANIMATION_MOTION_PATH; break;
289     case EffectPresetClass::OLEACTION:  nImage = IMG_CUSTOMANIMATION_OLE; break;
290     case EffectPresetClass::MEDIACALL:
291         switch( mpEffect->getCommand() )
292         {
293         case EffectCommands::TOGGLEPAUSE:   nImage = IMG_CUSTOMANIMATION_MEDIA_PAUSE; break;
294         case EffectCommands::STOP:          nImage = IMG_CUSTOMANIMATION_MEDIA_STOP; break;
295         case EffectCommands::PLAY:
296         default:                            nImage = IMG_CUSTOMANIMATION_MEDIA_PLAY; break;
297         }
298         break;
299     default:                            nImage = 0xffff;
300     }
301 
302     if( nImage != 0xffff )
303     {
304         const Image& rImage = mpParent->getImage( nImage, bHighContrast );
305         Point aImagePos( aPos );
306         aImagePos.Y() += ( aSize.Height() - rImage.GetSizePixel().Height() ) >> 1;
307         rDev.DrawImage( aImagePos, rImage );
308     }
309 
310     aPos.X() += 19;
311     aPos.Y() += ( aSize.Height() - rDev.GetTextHeight()) >> 1;
312 
313     rDev.DrawText( aPos, rDev.GetEllipsisString( maDescription, rDev.GetOutputSizePixel().Width() - aPos.X() ) );
314 }
315 
316 // --------------------------------------------------------------------
317 
318 SvLBoxItem* CustomAnimationListEntryItem::Create() const
319 {
320     return NULL;
321 }
322 
323 // --------------------------------------------------------------------
324 
325 void CustomAnimationListEntryItem::Clone( SvLBoxItem* )
326 {
327 }
328 
329 // ====================================================================
330 
331 class CustomAnimationListEntry : public SvLBoxEntry
332 {
333 public:
334     CustomAnimationListEntry();
335     CustomAnimationListEntry( CustomAnimationEffectPtr pEffect );
336     virtual ~CustomAnimationListEntry();
337 
338     CustomAnimationEffectPtr getEffect() const { return mpEffect; }
339 
340 private:
341     CustomAnimationEffectPtr mpEffect;
342 };
343 
344 // --------------------------------------------------------------------
345 
346 CustomAnimationListEntry::CustomAnimationListEntry()
347 {
348 }
349 
350 // --------------------------------------------------------------------
351 
352 CustomAnimationListEntry::CustomAnimationListEntry( CustomAnimationEffectPtr pEffect )
353 : mpEffect( pEffect )
354 {
355 }
356 
357 // --------------------------------------------------------------------
358 
359 CustomAnimationListEntry::~CustomAnimationListEntry()
360 {
361 }
362 
363 // ====================================================================
364 
365 class CustomAnimationTriggerEntryItem : public SvLBoxString
366 {
367 public:
368                     CustomAnimationTriggerEntryItem( SvLBoxEntry*,sal_uInt16 nFlags, OUString aDescription, CustomAnimationList* pParent  );
369     virtual         ~CustomAnimationTriggerEntryItem();
370     virtual sal_uInt16  IsA();
371     void            InitViewData( SvLBox*,SvLBoxEntry*,SvViewDataItem* );
372     void            Paint( const Point&, SvLBox& rDev, sal_uInt16 nFlags,SvLBoxEntry* );
373     SvLBoxItem*     Create() const;
374     void            Clone( SvLBoxItem* pSource );
375 
376 private:
377     CustomAnimationList* mpParent;
378     OUString        maDescription;
379 };
380 
381 // --------------------------------------------------------------------
382 
383 CustomAnimationTriggerEntryItem::CustomAnimationTriggerEntryItem( SvLBoxEntry* pEntry, sal_uInt16 nFlags, OUString aDescription, CustomAnimationList* pParent  )
384 : SvLBoxString( pEntry, nFlags, aDescription ), mpParent( pParent ), maDescription( aDescription )
385 {
386 }
387 
388 // --------------------------------------------------------------------
389 
390 CustomAnimationTriggerEntryItem::~CustomAnimationTriggerEntryItem()
391 {
392 }
393 
394 // --------------------------------------------------------------------
395 
396 sal_uInt16 CustomAnimationTriggerEntryItem::IsA()
397 {
398     return (sal_uInt16)-1;
399 }
400 
401 // --------------------------------------------------------------------
402 
403 void CustomAnimationTriggerEntryItem::InitViewData( SvLBox* pView, SvLBoxEntry* pEntry, SvViewDataItem* pViewData )
404 {
405     if( !pViewData )
406         pViewData = pView->GetViewDataItem( pEntry, this );
407 
408     Size aSize(pView->GetTextWidth( maDescription ) + 2 * 19, pView->GetTextHeight() );
409     if( aSize.Height() < 19 )
410         aSize.Height() = 19;
411     pViewData->aSize = aSize;
412 
413 /*
414         SvViewData* pViewData = pView->GetViewData( pEntry );
415         if( pViewData )
416             pViewData->SetSelectable(false);
417 */
418 }
419 
420 // --------------------------------------------------------------------
421 
422 void CustomAnimationTriggerEntryItem::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16, SvLBoxEntry* )
423 {
424     Size aSize( rDev.GetOutputSizePixel().Width(), static_cast< SvTreeListBox* >(&rDev)->GetEntryHeight() );
425 
426     Point aPos( 0, rPos.Y() );
427 
428     Rectangle aOutRect( aPos, aSize );
429 
430     // fill the background
431     Color aColor (rDev.GetSettings().GetStyleSettings().GetDialogColor());
432 
433     rDev.Push();
434     rDev.SetFillColor (aColor);
435     rDev.SetLineColor ();
436     rDev.DrawRect(aOutRect);
437 
438     // Erase the four corner pixels to make the rectangle appear rounded.
439     rDev.SetLineColor( rDev.GetSettings().GetStyleSettings().GetWindowColor());
440     rDev.DrawPixel( aOutRect.TopLeft());
441     rDev.DrawPixel( Point(aOutRect.Right(), aOutRect.Top()));
442     rDev.DrawPixel( Point(aOutRect.Left(), aOutRect.Bottom()));
443     rDev.DrawPixel( Point(aOutRect.Right(), aOutRect.Bottom()));
444 
445     // draw the category title
446 
447     int nVertBorder = (( aSize.Height() - rDev.GetTextHeight()) >> 1);
448     int nHorzBorder = rDev.LogicToPixel( Size( 3, 3 ), MAP_APPFONT ).Width();
449 
450     aOutRect.nLeft += nHorzBorder;
451     aOutRect.nRight -= nHorzBorder;
452     aOutRect.nTop += nVertBorder;
453     aOutRect.nBottom -= nVertBorder;
454 
455     rDev.DrawText (aOutRect, rDev.GetEllipsisString( maDescription, aOutRect.GetWidth() ) );
456     rDev.Pop();
457 }
458 
459 // --------------------------------------------------------------------
460 
461 SvLBoxItem* CustomAnimationTriggerEntryItem::Create() const
462 {
463     return NULL;
464 }
465 
466 // --------------------------------------------------------------------
467 
468 void CustomAnimationTriggerEntryItem::Clone( SvLBoxItem* )
469 {
470 }
471 
472 // ====================================================================
473 
474 CustomAnimationList::CustomAnimationList( ::Window* pParent, const ResId& rResId, ICustomAnimationListController* pController )
475 :   SvTreeListBox( pParent, rResId )
476 ,   mbIgnorePaint( false )
477 ,   mpController( pController )
478 ,   mpLastParentEntry(0)
479 {
480     SetStyle( GetStyle() | WB_TABSTOP | WB_BORDER | WB_HASLINES | WB_HASBUTTONS | WB_HASBUTTONSATROOT );
481 
482     EnableContextMenuHandling();
483     SetSelectionMode( MULTIPLE_SELECTION );
484     SetIndent(16);
485     SetNodeDefaultImages();
486 }
487 
488 // --------------------------------------------------------------------
489 
490 const Image&  CustomAnimationList::getImage( sal_uInt16 nId, bool bHighContrast )
491 {
492     DBG_ASSERT( (nId >= IMG_CUSTOMANIMATION_ON_CLICK) && (nId <= IMG_CUSTOMANIMATION_MEDIA_STOP), "sd::CustomAnimationList::getImage(), illegal index!" );
493 
494     if( bHighContrast )
495         nId += 1;
496 
497     Image& rImage = maImages[nId - IMG_CUSTOMANIMATION_ON_CLICK];
498 
499     // load on demand
500     if( rImage.GetSizePixel().Width() == 0 )
501         rImage = Image(SdResId( nId ) );
502 
503     return rImage;
504 }
505 
506 // --------------------------------------------------------------------
507 
508 CustomAnimationList::~CustomAnimationList()
509 {
510     if( mpMainSequence.get() )
511         mpMainSequence->removeListener( this );
512 
513     clear();
514 }
515 
516 // --------------------------------------------------------------------
517 
518 void CustomAnimationList::KeyInput( const KeyEvent& rKEvt )
519 {
520     const int nKeyCode = rKEvt.GetKeyCode().GetCode();
521     switch( nKeyCode )
522     {
523         case KEY_DELETE:    mpController->onContextMenu( CM_REMOVE ); return;
524         case KEY_INSERT:    mpController->onContextMenu( CM_CREATE ); return;
525         case KEY_SPACE:
526             {
527                 const Point aPos;
528                 const CommandEvent aCEvt( aPos, COMMAND_CONTEXTMENU );
529                 Command( aCEvt );
530                 return;
531             }
532 
533     }
534 
535     ::SvTreeListBox::KeyInput( rKEvt );
536 }
537 
538 // --------------------------------------------------------------------
539 
540 /** selects or deselects the given effect.
541     Selections of other effects are not changed */
542 void CustomAnimationList::select( CustomAnimationEffectPtr pEffect, bool bSelect /* = true */ )
543 {
544     CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(First());
545     while( pEntry )
546     {
547         if( pEntry->getEffect() == pEffect )
548         {
549             Select( pEntry, bSelect );
550             break;
551         }
552         pEntry = static_cast< CustomAnimationListEntry* >(Next( pEntry ));
553     }
554 
555     if( !pEntry && bSelect )
556     {
557         append( pEffect );
558         select( pEffect );
559     }
560 }
561 
562 // --------------------------------------------------------------------
563 
564 void CustomAnimationList::clear()
565 {
566     Clear();
567 
568     mpLastParentEntry = 0;
569     mxLastTargetShape = 0;
570 }
571 
572 // --------------------------------------------------------------------
573 
574 void CustomAnimationList::update( MainSequencePtr pMainSequence )
575 {
576     if( mpMainSequence.get() )
577         mpMainSequence->removeListener( this );
578 
579     mpMainSequence = pMainSequence;
580     update();
581 
582     if( mpMainSequence.get() )
583         mpMainSequence->addListener( this );
584 }
585 
586 // --------------------------------------------------------------------
587 
588 struct stl_append_effect_func : public std::unary_function<CustomAnimationEffectPtr, void>
589 {
590     stl_append_effect_func( CustomAnimationList& rList ) : mrList( rList ) {}
591     void operator()(CustomAnimationEffectPtr pEffect);
592     CustomAnimationList& mrList;
593 };
594 
595 void stl_append_effect_func::operator()(CustomAnimationEffectPtr pEffect)
596 {
597     mrList.append( pEffect );
598 }
599 // --------------------------------------------------------------------
600 
601 void CustomAnimationList::update()
602 {
603     mbIgnorePaint = true;
604 
605     CustomAnimationListEntry* pEntry = 0;
606 
607     std::list< CustomAnimationEffectPtr > aExpanded;
608     std::list< CustomAnimationEffectPtr > aSelected;
609 
610     CustomAnimationEffectPtr pFirstVisibleEffect;
611 
612     if( mpMainSequence.get() )
613     {
614         // save selection and expand states
615         pEntry = static_cast<CustomAnimationListEntry*>(FirstVisible());
616         if( pEntry )
617             pFirstVisibleEffect = pEntry->getEffect();
618 
619         pEntry = static_cast<CustomAnimationListEntry*>(First());
620 
621         while( pEntry )
622         {
623             CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
624             if( pEffect.get() )
625             {
626                 if( IsExpanded( pEntry ) )
627                     aExpanded.push_back( pEffect );
628 
629                 if( IsSelected( pEntry ) )
630                     aSelected.push_back( pEffect );
631             }
632 
633             pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
634         }
635     }
636 
637     // rebuild list
638     clear();
639     if( mpMainSequence.get() )
640     {
641         std::for_each( mpMainSequence->getBegin(), mpMainSequence->getEnd(), stl_append_effect_func( *this ) );
642         mpLastParentEntry = 0;
643 
644         const InteractiveSequenceList& rISL = mpMainSequence->getInteractiveSequenceList();
645 
646         InteractiveSequenceList::const_iterator aIter( rISL.begin() );
647         const InteractiveSequenceList::const_iterator aEnd( rISL.end() );
648         while( aIter != aEnd )
649         {
650             InteractiveSequencePtr pIS( (*aIter++) );
651 
652             Reference< XShape > xShape( pIS->getTriggerShape() );
653             if( xShape.is() )
654             {
655                 SvLBoxEntry* pLBoxEntry = new CustomAnimationListEntry;
656                 pLBoxEntry->AddItem( new SvLBoxContextBmp( pLBoxEntry, 0, Image(), Image(), 0));
657                 OUString aDescription = String( SdResId( STR_CUSTOMANIMATION_TRIGGER ) );
658                 aDescription += OUString( RTL_CONSTASCII_USTRINGPARAM(": ") );
659                 aDescription += getShapeDescription( xShape, false );
660                 pLBoxEntry->AddItem( new CustomAnimationTriggerEntryItem( pLBoxEntry, 0, aDescription, this ) );
661                 Insert( pLBoxEntry );
662                 SvViewData* pViewData = GetViewData( pLBoxEntry );
663                 if( pViewData )
664                     pViewData->SetSelectable(false);
665 
666                 std::for_each( pIS->getBegin(), pIS->getEnd(), stl_append_effect_func( *this ) );
667                 mpLastParentEntry = 0;
668             }
669         }
670 
671         // restore selection and expand states
672         pEntry = static_cast<CustomAnimationListEntry*>(First());
673 
674         while( pEntry )
675         {
676             CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
677             if( pEffect.get() )
678             {
679                 if( std::find( aExpanded.begin(), aExpanded.end(), pEffect ) != aExpanded.end() )
680                     Expand( pEntry );
681 
682                 if( std::find( aSelected.begin(), aSelected.end(), pEffect ) != aSelected.end() )
683                     Select( pEntry );
684 
685                 if( pFirstVisibleEffect == pEffect )
686                     MakeVisible( pEntry );
687             }
688 
689             pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
690         }
691     }
692 
693     mbIgnorePaint = false;
694     Invalidate();
695 }
696 
697 // --------------------------------------------------------------------
698 
699 /*
700 void CustomAnimationList::update( CustomAnimationEffectPtr pEffect )
701 {
702     SvLBoxEntry* pEntry = First();
703     while( pEntry )
704     {
705         if( static_cast< CustomAnimationEffectPtr * >( pEntry->GetUserData() )->get() == pEffect.get() )
706         {
707             CustomAnimationPresetsPtr pPresets = mpController->getPresets();
708             const CustomAnimationPresetPtr pPreset = pPresets->getEffectDescriptor( pEffect->getPresetId() );
709             if( pPreset.get() )
710                 pEffect->setName( pPresets->getUINameForPresetId( pPreset->getPresetId() ) );
711             else
712                 pEffect->setName( pEffect->getPresetId() );
713             break;
714         }
715         pEntry = Next( pEntry );
716     }
717 
718     Invalidate();
719 }
720 */
721 
722 // --------------------------------------------------------------------
723 
724 void CustomAnimationList::append( CustomAnimationEffectPtr pEffect )
725 {
726     // create a ui description
727     OUString aDescription;
728 
729     Any aTarget( pEffect->getTarget() );
730     if( aTarget.hasValue() ) try
731     {
732         aDescription = getDescription( aTarget, pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_BACKGROUND );
733 
734         SvLBoxEntry* pParentEntry = 0;
735 
736         Reference< XShape > xTargetShape( pEffect->getTargetShape() );
737         sal_Int32 nGroupId = pEffect->getGroupId();
738 
739         // if this effect has the same target and group-id as the last root effect,
740         // the last root effect is also this effects parent
741         if( mpLastParentEntry && (nGroupId != -1) && (mxLastTargetShape == xTargetShape) && (mnLastGroupId == nGroupId) )
742             pParentEntry = mpLastParentEntry;
743 
744         // create an entry for the effect
745         SvLBoxEntry* pEntry = new CustomAnimationListEntry( pEffect );
746 
747         pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), 0));
748         pEntry->AddItem( new CustomAnimationListEntryItem( pEntry, 0, aDescription, pEffect, this ) );
749 
750         if( pParentEntry )
751         {
752             // add a subentry
753             Insert( pEntry, pParentEntry );
754         }
755         else
756         {
757             // add a root entry
758             Insert( pEntry );
759 
760             // and the new root entry becomes the possible next group header
761             mxLastTargetShape = xTargetShape;
762             mnLastGroupId = nGroupId;
763             mpLastParentEntry = pEntry;
764         }
765     }
766     catch( Exception& e )
767     {
768         (void)e;
769         DBG_ERROR("sd::CustomAnimationList::append(), exception catched!" );
770     }
771 }
772 
773 // --------------------------------------------------------------------
774 
775 /*
776 void CustomAnimationList::remove( CustomAnimationEffectPtr pEffect )
777 {
778     SvLBoxEntry* pEntry = First();
779     while( pEntry )
780     {
781         if( static_cast< CustomAnimationEffectPtr * >( pEntry->GetUserData() )->get() == pEffect.get() )
782         {
783             GetModel()->Remove( pEntry );
784             if( pEntry == mpLastParentEntry )
785             {
786                 mpLastParentEntry = 0;
787                 mxLastTargetShape = 0;
788             }
789             break;
790         }
791         pEntry = Next( pEntry );
792     }
793 
794     Invalidate();
795 }
796 */
797 
798 // --------------------------------------------------------------------
799 
800 void selectShape( SvTreeListBox* pTreeList, Reference< XShape > xShape )
801 {
802     CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(pTreeList->First());
803     while( pEntry )
804     {
805         CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
806         if( pEffect.get() )
807         {
808             if( pEffect->getTarget() == xShape )
809                 pTreeList->Select( pEntry );
810         }
811 
812         pEntry = static_cast< CustomAnimationListEntry* >(pTreeList->Next( pEntry ));
813     }
814 }
815 
816 // --------------------------------------------------------------------
817 
818 void CustomAnimationList::onSelectionChanged( Any aSelection )
819 {
820     try
821     {
822         SelectAll(sal_False);
823 
824         if( aSelection.hasValue() )
825         {
826             Reference< XIndexAccess > xShapes( aSelection, UNO_QUERY );
827             if( xShapes.is() )
828             {
829                 sal_Int32 nCount = xShapes->getCount();
830                 sal_Int32 nIndex;
831                 for( nIndex = 0; nIndex < nCount; nIndex++ )
832                 {
833                     Reference< XShape > xShape( xShapes->getByIndex( nIndex ), UNO_QUERY );
834                     if( xShape.is() )
835                         selectShape( this, xShape );
836                 }
837             }
838             else
839             {
840                 Reference< XShape > xShape( aSelection, UNO_QUERY );
841                 if( xShape.is() )
842                     selectShape( this, xShape );
843             }
844         }
845 
846         SelectHdl();
847     }
848     catch( Exception& )
849     {
850         DBG_ERROR( "sd::CustomAnimationList::onSelectionChanged(), Exception catched!" );
851     }
852 }
853 
854 // --------------------------------------------------------------------
855 
856 void CustomAnimationList::SelectHdl()
857 {
858     SvTreeListBox::SelectHdl();
859     mpController->onSelect();
860 }
861 
862 // --------------------------------------------------------------------
863 
864 bool CustomAnimationList::isExpanded( const CustomAnimationEffectPtr& pEffect ) const
865 {
866     CustomAnimationListEntry* pEntry = static_cast<CustomAnimationListEntry*>(First());
867 
868     while( pEntry )
869     {
870         if( pEntry->getEffect() == pEffect )
871             break;
872 
873         pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
874     }
875 
876     if( pEntry )
877         pEntry = static_cast<CustomAnimationListEntry*>(GetParent( pEntry ));
878 
879     return (pEntry == 0) || IsExpanded( pEntry );
880 }
881 
882 // --------------------------------------------------------------------
883 EffectSequence CustomAnimationList::getSelection() const
884 {
885     EffectSequence aSelection;
886 
887     CustomAnimationListEntry* pEntry = dynamic_cast< CustomAnimationListEntry* >(FirstSelected());
888     while( pEntry )
889     {
890         CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
891         if( pEffect.get() )
892             aSelection.push_back( pEffect );
893 
894         // if the selected effect is not expanded and has children
895         // we say that the children are automaticly selected
896         if( !IsExpanded( pEntry ) )
897         {
898             CustomAnimationListEntry* pChild = dynamic_cast< CustomAnimationListEntry* >( FirstChild( pEntry ) );
899             while( pChild )
900             {
901                 if( !IsSelected( pChild ) )
902                 {
903                     CustomAnimationEffectPtr pChildEffect( pChild->getEffect() );
904                     if( pChildEffect.get() )
905                         aSelection.push_back( pChildEffect );
906                 }
907 
908                 pChild = dynamic_cast< CustomAnimationListEntry* >(  NextSibling( pChild ) );
909             }
910         }
911 
912         pEntry = static_cast< CustomAnimationListEntry* >(NextSelected( pEntry ));
913     }
914 
915     return aSelection;
916 }
917 
918 // --------------------------------------------------------------------
919 
920 sal_Bool CustomAnimationList::DoubleClickHdl()
921 {
922     mpController->onDoubleClick();
923     return false;
924 }
925 
926 // --------------------------------------------------------------------
927 
928 PopupMenu* CustomAnimationList::CreateContextMenu()
929 {
930     PopupMenu* pMenu = new PopupMenu(SdResId( RID_EFFECT_CONTEXTMENU ));
931 
932     sal_Int16 nNodeType = -1;
933     sal_Int16 nEntries = 0;
934 
935     CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(FirstSelected());
936     while( pEntry )
937     {
938         nEntries++;
939         CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
940         if( pEffect.get() )
941         {
942             if( nNodeType == -1 )
943             {
944                 nNodeType = pEffect->getNodeType();
945             }
946             else
947             {
948                 if( nNodeType != pEffect->getNodeType() )
949                 {
950                     nNodeType = -1;
951                     break;
952                 }
953             }
954         }
955 
956         pEntry = static_cast< CustomAnimationListEntry* >(NextSelected( pEntry ));
957     }
958 
959     pMenu->CheckItem( CM_WITH_CLICK, nNodeType == EffectNodeType::ON_CLICK );
960     pMenu->CheckItem( CM_WITH_PREVIOUS, nNodeType == EffectNodeType::WITH_PREVIOUS );
961     pMenu->CheckItem( CM_AFTER_PREVIOUS, nNodeType == EffectNodeType::AFTER_PREVIOUS );
962     pMenu->EnableItem( CM_OPTIONS, nEntries == 1 );
963     pMenu->EnableItem( CM_DURATION, nEntries == 1 );
964 
965     return pMenu;
966 }
967 
968 // --------------------------------------------------------------------
969 
970 void CustomAnimationList::ExcecuteContextMenuAction( sal_uInt16 nSelectedPopupEntry )
971 {
972     mpController->onContextMenu( nSelectedPopupEntry );
973 }
974 
975 // --------------------------------------------------------------------
976 
977 void CustomAnimationList::SetTabs()
978 {
979     SvTreeListBox::SetTabs();
980 }
981 
982 // --------------------------------------------------------------------
983 
984 void CustomAnimationList::notify_change()
985 {
986     update();
987     mpController->onSelect();
988 }
989 
990 void CustomAnimationList::Paint( const Rectangle& rRect )
991 {
992     if( mbIgnorePaint )
993         return;
994 
995     SvTreeListBox::Paint( rRect );
996 
997     // draw help text if list box is still empty
998     if( First() == 0 )
999     {
1000         Color aOldColor( GetTextColor() );
1001         SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
1002         ::Point aOffset( LogicToPixel( Point( 6, 6 ), MAP_APPFONT ) );
1003 
1004         Rectangle aRect( Point( 0,0 ), GetOutputSizePixel() );
1005 
1006         aRect.Left() += aOffset.X();
1007         aRect.Top() += aOffset.Y();
1008         aRect.Right() -= aOffset.X();
1009         aRect.Bottom() -= aOffset.Y();
1010 
1011         DrawText( aRect, String( SdResId( STR_CUSTOMANIMATION_LIST_HELPTEXT ) ),
1012             TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK | TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER );
1013 
1014         SetTextColor( aOldColor );
1015     }
1016 }
1017 
1018 }
1019