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