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 "CustomAnimation.hrc"
34 : #include "CustomAnimationPreset.hxx"
35 : #include <vcl/svapp.hxx>
36 : #include <vcl/settings.hxx>
37 :
38 : #include "sdresid.hxx"
39 :
40 : #include "svtools/svlbitm.hxx"
41 : #include "svtools/treelistentry.hxx"
42 : #include "svtools/viewdataentry.hxx"
43 :
44 : #include "res_bmp.hrc"
45 : #include "glob.hrc"
46 :
47 : #include <algorithm>
48 :
49 : using namespace ::com::sun::star;
50 : using namespace ::com::sun::star::animations;
51 : using namespace ::com::sun::star::presentation;
52 :
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 )
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::number( 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() == ::cppu::UnoType<ParagraphTarget>::get() )
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 : class CustomAnimationListEntryItem : public SvLBoxString
202 : {
203 : public:
204 : CustomAnimationListEntryItem( SvTreeListEntry*,sal_uInt16 nFlags, const OUString& aDescription, CustomAnimationEffectPtr pEffect, CustomAnimationList* pParent );
205 : virtual ~CustomAnimationListEntryItem();
206 : void InitViewData( SvTreeListBox*,SvTreeListEntry*,SvViewDataItem* ) SAL_OVERRIDE;
207 : SvLBoxItem* Create() const SAL_OVERRIDE;
208 : void Clone( SvLBoxItem* pSource ) SAL_OVERRIDE;
209 :
210 : virtual void Paint(
211 : const Point&, SvTreeListBox& rDev, const SvViewDataEntry* pView,const SvTreeListEntry* pEntry) SAL_OVERRIDE;
212 : private:
213 : CustomAnimationList* mpParent;
214 : OUString maDescription;
215 : CustomAnimationEffectPtr mpEffect;
216 : };
217 :
218 0 : CustomAnimationListEntryItem::CustomAnimationListEntryItem( SvTreeListEntry* pEntry, sal_uInt16 nFlags, const OUString& aDescription, CustomAnimationEffectPtr pEffect, CustomAnimationList* pParent )
219 : : SvLBoxString( pEntry, nFlags, aDescription )
220 : , mpParent( pParent )
221 : , maDescription( aDescription )
222 0 : , mpEffect(pEffect)
223 : {
224 0 : }
225 :
226 0 : CustomAnimationListEntryItem::~CustomAnimationListEntryItem()
227 : {
228 0 : }
229 :
230 0 : void CustomAnimationListEntryItem::InitViewData( SvTreeListBox* pView, SvTreeListEntry* pEntry, SvViewDataItem* pViewData )
231 : {
232 0 : if( !pViewData )
233 0 : pViewData = pView->GetViewDataItem( pEntry, this );
234 :
235 0 : Size aSize(pView->GetTextWidth( maDescription ) + 2 * 19, pView->GetTextHeight() );
236 0 : if( aSize.Height() < 19 )
237 0 : aSize.Height() = 19;
238 0 : pViewData->maSize = aSize;
239 0 : }
240 :
241 0 : void CustomAnimationListEntryItem::Paint(
242 : const Point& rPos, SvTreeListBox& rDev, const SvViewDataEntry* /*pView*/, const SvTreeListEntry* pEntry)
243 : {
244 :
245 0 : const SvViewDataItem* pViewData = mpParent->GetViewDataItem( pEntry, this );
246 :
247 0 : Point aPos( rPos );
248 0 : Size aSize( pViewData->maSize );
249 :
250 0 : sal_Int16 nNodeType = mpEffect->getNodeType();
251 0 : if( nNodeType == EffectNodeType::ON_CLICK )
252 : {
253 0 : rDev.DrawImage( aPos, mpParent->getImage( IMG_CUSTOMANIMATION_ON_CLICK ) );
254 : }
255 0 : else if( nNodeType == EffectNodeType::AFTER_PREVIOUS )
256 : {
257 0 : rDev.DrawImage( aPos, mpParent->getImage( IMG_CUSTOMANIMATION_AFTER_PREVIOUS ) );
258 : }
259 :
260 0 : aPos.X() += 19;
261 :
262 : sal_uInt16 nImage;
263 0 : switch( mpEffect->getPresetClass() )
264 : {
265 0 : case EffectPresetClass::ENTRANCE: nImage = IMG_CUSTOMANIMATION_ENTRANCE_EFFECT; break;
266 0 : case EffectPresetClass::EXIT: nImage = IMG_CUSTOMANIMATION_EXIT_EFFECT; break;
267 0 : case EffectPresetClass::EMPHASIS: nImage = IMG_CUSTOMANIMATION_EMPHASIS_EFFECT; break;
268 0 : case EffectPresetClass::MOTIONPATH: nImage = IMG_CUSTOMANIMATION_MOTION_PATH; break;
269 0 : case EffectPresetClass::OLEACTION: nImage = IMG_CUSTOMANIMATION_OLE; break;
270 : case EffectPresetClass::MEDIACALL:
271 0 : switch( mpEffect->getCommand() )
272 : {
273 0 : case EffectCommands::TOGGLEPAUSE: nImage = IMG_CUSTOMANIMATION_MEDIA_PAUSE; break;
274 0 : case EffectCommands::STOP: nImage = IMG_CUSTOMANIMATION_MEDIA_STOP; break;
275 : case EffectCommands::PLAY:
276 0 : default: nImage = IMG_CUSTOMANIMATION_MEDIA_PLAY; break;
277 : }
278 0 : break;
279 0 : default: nImage = 0xffff;
280 : }
281 :
282 0 : if( nImage != 0xffff )
283 : {
284 0 : const Image& rImage = mpParent->getImage( nImage );
285 0 : Point aImagePos( aPos );
286 0 : aImagePos.Y() += ( aSize.Height() - rImage.GetSizePixel().Height() ) >> 1;
287 0 : rDev.DrawImage( aImagePos, rImage );
288 : }
289 :
290 0 : aPos.X() += 19;
291 0 : aPos.Y() += ( aSize.Height() - rDev.GetTextHeight()) >> 1;
292 :
293 0 : rDev.DrawText( aPos, rDev.GetEllipsisString( maDescription, rDev.GetOutputSizePixel().Width() - aPos.X() ) );
294 0 : }
295 :
296 0 : SvLBoxItem* CustomAnimationListEntryItem::Create() const
297 : {
298 0 : return NULL;
299 : }
300 :
301 0 : void CustomAnimationListEntryItem::Clone( SvLBoxItem* )
302 : {
303 0 : }
304 :
305 : class CustomAnimationListEntry : public SvTreeListEntry
306 : {
307 : public:
308 : CustomAnimationListEntry();
309 : CustomAnimationListEntry( CustomAnimationEffectPtr pEffect );
310 : virtual ~CustomAnimationListEntry();
311 :
312 0 : CustomAnimationEffectPtr getEffect() const { return mpEffect; }
313 :
314 : private:
315 : CustomAnimationEffectPtr mpEffect;
316 : };
317 :
318 0 : CustomAnimationListEntry::CustomAnimationListEntry()
319 : {
320 0 : }
321 :
322 0 : CustomAnimationListEntry::CustomAnimationListEntry( CustomAnimationEffectPtr pEffect )
323 0 : : mpEffect( pEffect )
324 : {
325 0 : }
326 :
327 0 : CustomAnimationListEntry::~CustomAnimationListEntry()
328 : {
329 0 : }
330 :
331 : class CustomAnimationTriggerEntryItem : public SvLBoxString
332 : {
333 : public:
334 : CustomAnimationTriggerEntryItem( SvTreeListEntry*,sal_uInt16 nFlags, const OUString& aDescription );
335 : virtual ~CustomAnimationTriggerEntryItem();
336 : void InitViewData( SvTreeListBox*,SvTreeListEntry*,SvViewDataItem* ) SAL_OVERRIDE;
337 : SvLBoxItem* Create() const SAL_OVERRIDE;
338 : void Clone( SvLBoxItem* pSource ) SAL_OVERRIDE;
339 : virtual void Paint(
340 : const Point& rPos, SvTreeListBox& rOutDev, const SvViewDataEntry* pView, const SvTreeListEntry* pEntry) SAL_OVERRIDE;
341 :
342 : private:
343 : OUString maDescription;
344 : };
345 :
346 0 : CustomAnimationTriggerEntryItem::CustomAnimationTriggerEntryItem( SvTreeListEntry* pEntry, sal_uInt16 nFlags, const OUString& aDescription )
347 0 : : SvLBoxString( pEntry, nFlags, aDescription ), maDescription( aDescription )
348 : {
349 0 : }
350 :
351 0 : CustomAnimationTriggerEntryItem::~CustomAnimationTriggerEntryItem()
352 : {
353 0 : }
354 :
355 0 : void CustomAnimationTriggerEntryItem::InitViewData( SvTreeListBox* pView, SvTreeListEntry* pEntry, SvViewDataItem* pViewData )
356 : {
357 0 : if( !pViewData )
358 0 : pViewData = pView->GetViewDataItem( pEntry, this );
359 :
360 0 : Size aSize(pView->GetTextWidth( maDescription ) + 2 * 19, pView->GetTextHeight() );
361 0 : if( aSize.Height() < 19 )
362 0 : aSize.Height() = 19;
363 0 : pViewData->maSize = aSize;
364 0 : }
365 :
366 0 : void CustomAnimationTriggerEntryItem::Paint(
367 : const Point& rPos, SvTreeListBox& rDev, const SvViewDataEntry* /*pView*/, const SvTreeListEntry* /*pEntry*/)
368 : {
369 0 : Size aSize( rDev.GetOutputSizePixel().Width(), static_cast< SvTreeListBox* >(&rDev)->GetEntryHeight() );
370 :
371 0 : Point aPos( 0, rPos.Y() );
372 :
373 0 : Rectangle aOutRect( aPos, aSize );
374 :
375 : // fill the background
376 0 : Color aColor (rDev.GetSettings().GetStyleSettings().GetDialogColor());
377 :
378 0 : rDev.Push();
379 0 : rDev.SetFillColor (aColor);
380 0 : rDev.SetLineColor ();
381 0 : rDev.DrawRect(aOutRect);
382 :
383 : // Erase the four corner pixels to make the rectangle appear rounded.
384 0 : rDev.SetLineColor( rDev.GetSettings().GetStyleSettings().GetWindowColor());
385 0 : rDev.DrawPixel( aOutRect.TopLeft());
386 0 : rDev.DrawPixel( Point(aOutRect.Right(), aOutRect.Top()));
387 0 : rDev.DrawPixel( Point(aOutRect.Left(), aOutRect.Bottom()));
388 0 : rDev.DrawPixel( Point(aOutRect.Right(), aOutRect.Bottom()));
389 :
390 : // draw the category title
391 :
392 0 : int nVertBorder = (( aSize.Height() - rDev.GetTextHeight()) >> 1);
393 0 : int nHorzBorder = rDev.LogicToPixel( Size( 3, 3 ), MAP_APPFONT ).Width();
394 :
395 0 : aOutRect.Left() += nHorzBorder;
396 0 : aOutRect.Right() -= nHorzBorder;
397 0 : aOutRect.Top() += nVertBorder;
398 0 : aOutRect.Bottom() -= nVertBorder;
399 :
400 0 : rDev.DrawText (aOutRect, rDev.GetEllipsisString( maDescription, aOutRect.GetWidth() ) );
401 0 : rDev.Pop();
402 0 : }
403 :
404 0 : SvLBoxItem* CustomAnimationTriggerEntryItem::Create() const
405 : {
406 0 : return NULL;
407 : }
408 :
409 0 : void CustomAnimationTriggerEntryItem::Clone( SvLBoxItem* )
410 : {
411 0 : }
412 :
413 0 : CustomAnimationList::CustomAnimationList( vcl::Window* pParent )
414 : : SvTreeListBox( pParent, WB_TABSTOP | WB_BORDER | WB_HASLINES | WB_HASBUTTONS | WB_HASBUTTONSATROOT )
415 : , mbIgnorePaint(false)
416 : , mpController(0)
417 : , mnLastGroupId(0)
418 0 : , mpLastParentEntry(0)
419 : {
420 :
421 0 : EnableContextMenuHandling();
422 0 : SetSelectionMode( MULTIPLE_SELECTION );
423 0 : SetOptimalImageIndent();
424 0 : SetNodeDefaultImages();
425 0 : }
426 :
427 0 : extern "C" SAL_DLLPUBLIC_EXPORT vcl::Window* SAL_CALL makeCustomAnimationList( vcl::Window *pParent )
428 : {
429 0 : return new CustomAnimationList( pParent );
430 : }
431 :
432 0 : const Image& CustomAnimationList::getImage( sal_uInt16 nId )
433 : {
434 : DBG_ASSERT( (nId >= IMG_CUSTOMANIMATION_ON_CLICK) && (nId <= IMG_CUSTOMANIMATION_MEDIA_STOP), "sd::CustomAnimationList::getImage(), illegal index!" );
435 :
436 0 : Image& rImage = maImages[nId - IMG_CUSTOMANIMATION_ON_CLICK];
437 :
438 : // load on demand
439 0 : if( rImage.GetSizePixel().Width() == 0 )
440 0 : rImage = Image(SdResId( nId ) );
441 :
442 0 : return rImage;
443 : }
444 :
445 0 : CustomAnimationList::~CustomAnimationList()
446 : {
447 0 : if( mpMainSequence.get() )
448 0 : mpMainSequence->removeListener( this );
449 :
450 0 : clear();
451 0 : }
452 :
453 0 : void CustomAnimationList::KeyInput( const KeyEvent& rKEvt )
454 : {
455 0 : const int nKeyCode = rKEvt.GetKeyCode().GetCode();
456 0 : switch( nKeyCode )
457 : {
458 0 : case KEY_DELETE: mpController->onContextMenu( CM_REMOVE ); return;
459 0 : case KEY_INSERT: mpController->onContextMenu( CM_CREATE ); return;
460 : case KEY_SPACE:
461 : {
462 0 : const Point aPos;
463 0 : const CommandEvent aCEvt( aPos, COMMAND_CONTEXTMENU );
464 0 : Command( aCEvt );
465 0 : return;
466 : }
467 :
468 : }
469 :
470 0 : ::SvTreeListBox::KeyInput( rKEvt );
471 : }
472 :
473 : /** selects or deselects the given effect.
474 : Selections of other effects are not changed */
475 0 : void CustomAnimationList::select( CustomAnimationEffectPtr pEffect, bool bSelect /* = true */ )
476 : {
477 0 : CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(First());
478 0 : while( pEntry )
479 : {
480 0 : if( pEntry->getEffect() == pEffect )
481 : {
482 0 : Select( pEntry, bSelect );
483 0 : MakeVisible( pEntry );
484 0 : break;
485 : }
486 0 : pEntry = static_cast< CustomAnimationListEntry* >(Next( pEntry ));
487 : }
488 :
489 0 : if( !pEntry && bSelect )
490 : {
491 0 : append( pEffect );
492 0 : select( pEffect );
493 : }
494 0 : }
495 :
496 0 : void CustomAnimationList::clear()
497 : {
498 0 : Clear();
499 :
500 0 : mpLastParentEntry = 0;
501 0 : mxLastTargetShape = 0;
502 0 : }
503 :
504 0 : void CustomAnimationList::update( MainSequencePtr pMainSequence )
505 : {
506 0 : if( mpMainSequence.get() )
507 0 : mpMainSequence->removeListener( this );
508 :
509 0 : mpMainSequence = pMainSequence;
510 0 : update();
511 :
512 0 : if( mpMainSequence.get() )
513 0 : mpMainSequence->addListener( this );
514 0 : }
515 :
516 : struct stl_append_effect_func : public std::unary_function<CustomAnimationEffectPtr, void>
517 : {
518 0 : stl_append_effect_func( CustomAnimationList& rList ) : mrList( rList ) {}
519 : void operator()(CustomAnimationEffectPtr pEffect);
520 : CustomAnimationList& mrList;
521 : };
522 :
523 0 : void stl_append_effect_func::operator()(CustomAnimationEffectPtr pEffect)
524 : {
525 0 : mrList.append( pEffect );
526 0 : }
527 :
528 0 : void CustomAnimationList::update()
529 : {
530 0 : mbIgnorePaint = true;
531 0 : SetUpdateMode( false );
532 :
533 0 : CustomAnimationListEntry* pEntry = 0;
534 :
535 0 : std::list< CustomAnimationEffectPtr > aExpanded;
536 0 : std::list< CustomAnimationEffectPtr > aSelected;
537 :
538 0 : CustomAnimationEffectPtr pFirstSelEffect;
539 0 : CustomAnimationEffectPtr pLastSelEffect;
540 0 : long nFirstVis = -1;
541 0 : long nLastVis = -1;
542 0 : long nFirstSelOld = -1;
543 0 : long nLastSelOld = -1;
544 0 : bool bMoved = false;
545 0 : bool bMovedUp = false;
546 0 : bool bMovedDown = false;
547 :
548 0 : if( mpMainSequence.get() )
549 : {
550 : // save scroll position
551 0 : pEntry = static_cast<CustomAnimationListEntry*>(GetFirstEntryInView());
552 0 : if( pEntry )
553 0 : nFirstVis = GetAbsPos( pEntry );
554 :
555 0 : pEntry = static_cast<CustomAnimationListEntry*>(GetLastEntryInView());
556 0 : if( pEntry )
557 0 : nLastVis = GetAbsPos( pEntry );
558 :
559 0 : pEntry = static_cast<CustomAnimationListEntry*>(FirstSelected());
560 0 : if( pEntry )
561 : {
562 0 : pFirstSelEffect = pEntry->getEffect();
563 0 : nFirstSelOld = GetAbsPos( pEntry );
564 : }
565 :
566 0 : pEntry = static_cast<CustomAnimationListEntry*>(LastSelected());
567 0 : if( pEntry )
568 : {
569 0 : pLastSelEffect = pEntry->getEffect();
570 0 : nLastSelOld = GetAbsPos( pEntry );
571 : }
572 :
573 : // save selection and expand states
574 0 : pEntry = static_cast<CustomAnimationListEntry*>(First());
575 :
576 0 : while( pEntry )
577 : {
578 0 : CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
579 0 : if( pEffect.get() )
580 : {
581 0 : if( IsExpanded( pEntry ) )
582 0 : aExpanded.push_back( pEffect );
583 :
584 0 : if( IsSelected( pEntry ) )
585 0 : aSelected.push_back( pEffect );
586 : }
587 :
588 0 : pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
589 0 : }
590 : }
591 :
592 : // rebuild list
593 0 : clear();
594 0 : if( mpMainSequence.get() )
595 : {
596 0 : long nFirstSelNew = -1;
597 0 : long nLastSelNew = -1;
598 0 : std::for_each( mpMainSequence->getBegin(), mpMainSequence->getEnd(), stl_append_effect_func( *this ) );
599 0 : mpLastParentEntry = 0;
600 :
601 0 : const InteractiveSequenceList& rISL = mpMainSequence->getInteractiveSequenceList();
602 :
603 0 : InteractiveSequenceList::const_iterator aIter( rISL.begin() );
604 0 : const InteractiveSequenceList::const_iterator aEnd( rISL.end() );
605 0 : while( aIter != aEnd )
606 : {
607 0 : InteractiveSequencePtr pIS( (*aIter++) );
608 :
609 0 : Reference< XShape > xShape( pIS->getTriggerShape() );
610 0 : if( xShape.is() )
611 : {
612 0 : SvTreeListEntry* pLBoxEntry = new CustomAnimationListEntry;
613 0 : pLBoxEntry->AddItem( new SvLBoxContextBmp( pLBoxEntry, 0, Image(), Image(), false));
614 0 : OUString aDescription = SD_RESSTR(STR_CUSTOMANIMATION_TRIGGER);
615 0 : aDescription += ": ";
616 0 : aDescription += getShapeDescription( xShape, false );
617 0 : pLBoxEntry->AddItem( new CustomAnimationTriggerEntryItem( pLBoxEntry, 0, aDescription ) );
618 0 : Insert( pLBoxEntry );
619 0 : SvViewDataEntry* pViewData = GetViewData( pLBoxEntry );
620 0 : if( pViewData )
621 0 : pViewData->SetSelectable(false);
622 :
623 0 : std::for_each( pIS->getBegin(), pIS->getEnd(), stl_append_effect_func( *this ) );
624 0 : mpLastParentEntry = 0;
625 : }
626 0 : }
627 :
628 : // restore selection and expand states
629 0 : pEntry = static_cast<CustomAnimationListEntry*>(First());
630 :
631 0 : while( pEntry )
632 : {
633 0 : CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
634 0 : if( pEffect.get() )
635 : {
636 0 : if( std::find( aExpanded.begin(), aExpanded.end(), pEffect ) != aExpanded.end() )
637 0 : Expand( pEntry );
638 :
639 0 : if( std::find( aSelected.begin(), aSelected.end(), pEffect ) != aSelected.end() )
640 0 : Select( pEntry );
641 :
642 0 : if( pEffect == pFirstSelEffect )
643 0 : nFirstSelNew = GetAbsPos( pEntry );
644 :
645 0 : if( pEffect == pLastSelEffect )
646 0 : nLastSelNew = GetAbsPos( pEntry );
647 : }
648 :
649 0 : pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
650 0 : }
651 :
652 : // Scroll to a selected entry, depending on where the selection moved.
653 0 : bMoved = nFirstSelNew != nFirstSelOld;
654 0 : bMovedUp = nFirstSelNew < nFirstSelOld;
655 0 : bMovedDown = nFirstSelNew > nFirstSelOld;
656 :
657 0 : if( bMoved && nLastSelOld < nFirstVis && nLastSelNew < nFirstVis )
658 : {
659 : // The selection is above the visible area.
660 : // Scroll up to show the last few selected entries.
661 0 : if( nLastSelNew - (nLastVis - nFirstVis) > nFirstSelNew)
662 : {
663 : // The entries in the selection range can't fit in view.
664 : // Scroll so the last selected entry is last in view.
665 0 : ScrollToAbsPos( nLastSelNew - (nLastVis - nFirstVis) );
666 : }
667 : else
668 0 : ScrollToAbsPos( nFirstSelNew );
669 : }
670 0 : else if( bMoved && nFirstSelOld > nLastVis && nFirstSelNew > nLastVis )
671 : {
672 : // The selection is below the visible area.
673 : // Scroll down to the first few selected entries.
674 0 : ScrollToAbsPos( nFirstSelNew );
675 : }
676 0 : else if( bMovedUp && nFirstSelOld <= nFirstVis )
677 : {
678 : // A visible entry has moved up out of view; scroll up one.
679 0 : ScrollToAbsPos( nFirstVis - 1 );
680 : }
681 0 : else if( bMovedDown && nLastSelOld >= nLastVis )
682 : {
683 : // An entry has moved down out of view; scroll down one.
684 0 : ScrollToAbsPos( nFirstVis + 1 );
685 : }
686 0 : else if ( nFirstVis != -1 )
687 : {
688 : // The selection is still in view, or it hasn't moved.
689 0 : ScrollToAbsPos( nFirstVis );
690 : }
691 : }
692 :
693 0 : mbIgnorePaint = false;
694 0 : SetUpdateMode( true );
695 0 : Invalidate();
696 0 : }
697 :
698 0 : void CustomAnimationList::append( CustomAnimationEffectPtr pEffect )
699 : {
700 : // create a ui description
701 0 : OUString aDescription;
702 :
703 0 : Any aTarget( pEffect->getTarget() );
704 0 : if( aTarget.hasValue() ) try
705 : {
706 0 : aDescription = getDescription( aTarget, pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_BACKGROUND );
707 :
708 0 : SvTreeListEntry* pParentEntry = 0;
709 :
710 0 : Reference< XShape > xTargetShape( pEffect->getTargetShape() );
711 0 : sal_Int32 nGroupId = pEffect->getGroupId();
712 :
713 : // if this effect has the same target and group-id as the last root effect,
714 : // the last root effect is also this effects parent
715 0 : if( mpLastParentEntry && (nGroupId != -1) && (mxLastTargetShape == xTargetShape) && (mnLastGroupId == nGroupId) )
716 0 : pParentEntry = mpLastParentEntry;
717 :
718 : // create an entry for the effect
719 0 : SvTreeListEntry* pEntry = new CustomAnimationListEntry( pEffect );
720 :
721 0 : pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), false));
722 0 : pEntry->AddItem( new CustomAnimationListEntryItem( pEntry, 0, aDescription, pEffect, this ) );
723 :
724 0 : if( pParentEntry )
725 : {
726 : // add a subentry
727 0 : Insert( pEntry, pParentEntry );
728 : }
729 : else
730 : {
731 : // add a root entry
732 0 : Insert( pEntry );
733 :
734 : // and the new root entry becomes the possible next group header
735 0 : mxLastTargetShape = xTargetShape;
736 0 : mnLastGroupId = nGroupId;
737 0 : mpLastParentEntry = pEntry;
738 0 : }
739 : }
740 0 : catch( Exception& )
741 : {
742 : OSL_FAIL("sd::CustomAnimationList::append(), exception caught!" );
743 0 : }
744 0 : }
745 :
746 0 : void selectShape( SvTreeListBox* pTreeList, Reference< XShape > xShape )
747 : {
748 0 : CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(pTreeList->First());
749 0 : while( pEntry )
750 : {
751 0 : CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
752 0 : if( pEffect.get() )
753 : {
754 0 : if( pEffect->getTarget() == xShape )
755 0 : pTreeList->Select( pEntry );
756 : }
757 :
758 0 : pEntry = static_cast< CustomAnimationListEntry* >(pTreeList->Next( pEntry ));
759 0 : }
760 0 : }
761 :
762 0 : void CustomAnimationList::onSelectionChanged( Any aSelection )
763 : {
764 : try
765 : {
766 0 : SelectAll(false);
767 :
768 0 : if( aSelection.hasValue() )
769 : {
770 0 : Reference< XIndexAccess > xShapes( aSelection, UNO_QUERY );
771 0 : if( xShapes.is() )
772 : {
773 0 : sal_Int32 nCount = xShapes->getCount();
774 : sal_Int32 nIndex;
775 0 : for( nIndex = 0; nIndex < nCount; nIndex++ )
776 : {
777 0 : Reference< XShape > xShape( xShapes->getByIndex( nIndex ), UNO_QUERY );
778 0 : if( xShape.is() )
779 0 : selectShape( this, xShape );
780 0 : }
781 : }
782 : else
783 : {
784 0 : Reference< XShape > xShape( aSelection, UNO_QUERY );
785 0 : if( xShape.is() )
786 0 : selectShape( this, xShape );
787 0 : }
788 : }
789 :
790 0 : SelectHdl();
791 : }
792 0 : catch( Exception& )
793 : {
794 : OSL_FAIL( "sd::CustomAnimationList::onSelectionChanged(), Exception caught!" );
795 : }
796 0 : }
797 :
798 0 : void CustomAnimationList::SelectHdl()
799 : {
800 0 : if( mbIgnorePaint )
801 0 : return;
802 0 : SvTreeListBox::SelectHdl();
803 0 : mpController->onSelect();
804 : }
805 :
806 0 : bool CustomAnimationList::isExpanded( const CustomAnimationEffectPtr& pEffect ) const
807 : {
808 0 : CustomAnimationListEntry* pEntry = static_cast<CustomAnimationListEntry*>(First());
809 :
810 0 : while( pEntry )
811 : {
812 0 : if( pEntry->getEffect() == pEffect )
813 0 : break;
814 :
815 0 : pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
816 : }
817 :
818 0 : if( pEntry )
819 0 : pEntry = static_cast<CustomAnimationListEntry*>(GetParent( pEntry ));
820 :
821 0 : return (pEntry == 0) || IsExpanded( pEntry );
822 : }
823 :
824 0 : EffectSequence CustomAnimationList::getSelection() const
825 : {
826 0 : EffectSequence aSelection;
827 :
828 0 : CustomAnimationListEntry* pEntry = dynamic_cast< CustomAnimationListEntry* >(FirstSelected());
829 0 : while( pEntry )
830 : {
831 0 : CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
832 0 : if( pEffect.get() )
833 0 : aSelection.push_back( pEffect );
834 :
835 : // if the selected effect is not expanded and has children
836 : // we say that the children are automatically selected
837 0 : if( !IsExpanded( pEntry ) )
838 : {
839 0 : CustomAnimationListEntry* pChild = dynamic_cast< CustomAnimationListEntry* >( FirstChild( pEntry ) );
840 0 : while( pChild )
841 : {
842 0 : if( !IsSelected( pChild ) )
843 : {
844 0 : CustomAnimationEffectPtr pChildEffect( pChild->getEffect() );
845 0 : if( pChildEffect.get() )
846 0 : aSelection.push_back( pChildEffect );
847 : }
848 :
849 0 : pChild = dynamic_cast< CustomAnimationListEntry* >( NextSibling( pChild ) );
850 : }
851 : }
852 :
853 0 : pEntry = static_cast< CustomAnimationListEntry* >(NextSelected( pEntry ));
854 0 : }
855 :
856 0 : return aSelection;
857 : }
858 :
859 0 : bool CustomAnimationList::DoubleClickHdl()
860 : {
861 0 : mpController->onDoubleClick();
862 0 : return false;
863 : }
864 :
865 0 : PopupMenu* CustomAnimationList::CreateContextMenu()
866 : {
867 0 : PopupMenu* pMenu = new PopupMenu(SdResId( RID_EFFECT_CONTEXTMENU ));
868 :
869 0 : sal_Int16 nNodeType = -1;
870 0 : sal_Int16 nEntries = 0;
871 :
872 0 : CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(FirstSelected());
873 0 : while( pEntry )
874 : {
875 0 : nEntries++;
876 0 : CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
877 0 : if( pEffect.get() )
878 : {
879 0 : if( nNodeType == -1 )
880 : {
881 0 : nNodeType = pEffect->getNodeType();
882 : }
883 : else
884 : {
885 0 : if( nNodeType != pEffect->getNodeType() )
886 : {
887 0 : nNodeType = -1;
888 0 : break;
889 : }
890 : }
891 : }
892 :
893 0 : pEntry = static_cast< CustomAnimationListEntry* >(NextSelected( pEntry ));
894 0 : }
895 :
896 0 : pMenu->CheckItem( CM_WITH_CLICK, nNodeType == EffectNodeType::ON_CLICK );
897 0 : pMenu->CheckItem( CM_WITH_PREVIOUS, nNodeType == EffectNodeType::WITH_PREVIOUS );
898 0 : pMenu->CheckItem( CM_AFTER_PREVIOUS, nNodeType == EffectNodeType::AFTER_PREVIOUS );
899 0 : pMenu->EnableItem( CM_OPTIONS, nEntries == 1 );
900 0 : pMenu->EnableItem( CM_DURATION, nEntries == 1 );
901 :
902 0 : return pMenu;
903 : }
904 :
905 0 : void CustomAnimationList::ExcecuteContextMenuAction( sal_uInt16 nSelectedPopupEntry )
906 : {
907 0 : mpController->onContextMenu( nSelectedPopupEntry );
908 0 : }
909 :
910 0 : void CustomAnimationList::SetTabs()
911 : {
912 0 : SvTreeListBox::SetTabs();
913 0 : }
914 :
915 0 : void CustomAnimationList::notify_change()
916 : {
917 0 : update();
918 0 : mpController->onSelect();
919 0 : }
920 :
921 0 : void CustomAnimationList::Paint( const Rectangle& rRect )
922 : {
923 0 : if( mbIgnorePaint )
924 0 : return;
925 :
926 0 : SvTreeListBox::Paint( rRect );
927 :
928 : // draw help text if list box is still empty
929 0 : if( First() == 0 )
930 : {
931 0 : Color aOldColor( GetTextColor() );
932 0 : SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
933 0 : ::Point aOffset( LogicToPixel( Point( 6, 6 ), MAP_APPFONT ) );
934 :
935 0 : Rectangle aRect( Point( 0,0 ), GetOutputSizePixel() );
936 :
937 0 : aRect.Left() += aOffset.X();
938 0 : aRect.Top() += aOffset.Y();
939 0 : aRect.Right() -= aOffset.X();
940 0 : aRect.Bottom() -= aOffset.Y();
941 :
942 : DrawText( aRect, SD_RESSTR(STR_CUSTOMANIMATION_LIST_HELPTEXT),
943 0 : TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK | TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER );
944 :
945 0 : SetTextColor( aOldColor );
946 : }
947 : }
948 :
949 114 : }
950 :
951 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|