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