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