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 = 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::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() == ::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, const OUString& aDescription, CustomAnimationEffectPtr pEffect, CustomAnimationList* pParent );
207 : virtual ~CustomAnimationListEntryItem();
208 : void InitViewData( SvTreeListBox*,SvTreeListEntry*,SvViewDataItem* ) SAL_OVERRIDE;
209 : SvLBoxItem* Create() const SAL_OVERRIDE;
210 : void Clone( SvLBoxItem* pSource ) SAL_OVERRIDE;
211 :
212 : virtual void Paint(
213 : const Point&, SvTreeListBox& rDev, const SvViewDataEntry* pView,const SvTreeListEntry* pEntry) SAL_OVERRIDE;
214 : private:
215 : CustomAnimationList* mpParent;
216 : OUString maDescription;
217 : CustomAnimationEffectPtr mpEffect;
218 : };
219 :
220 :
221 :
222 0 : CustomAnimationListEntryItem::CustomAnimationListEntryItem( SvTreeListEntry* pEntry, sal_uInt16 nFlags, const 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, const OUString& aDescription );
359 : virtual ~CustomAnimationTriggerEntryItem();
360 : void InitViewData( SvTreeListBox*,SvTreeListEntry*,SvViewDataItem* ) SAL_OVERRIDE;
361 : SvLBoxItem* Create() const SAL_OVERRIDE;
362 : void Clone( SvLBoxItem* pSource ) SAL_OVERRIDE;
363 : virtual void Paint(
364 : const Point& rPos, SvTreeListBox& rOutDev, const SvViewDataEntry* pView, const SvTreeListEntry* pEntry) SAL_OVERRIDE;
365 :
366 : private:
367 : OUString maDescription;
368 : };
369 :
370 :
371 :
372 0 : CustomAnimationTriggerEntryItem::CustomAnimationTriggerEntryItem( SvTreeListEntry* pEntry, sal_uInt16 nFlags, const OUString& aDescription )
373 0 : : SvLBoxString( pEntry, nFlags, aDescription ), maDescription( aDescription )
374 : {
375 0 : }
376 :
377 :
378 :
379 0 : CustomAnimationTriggerEntryItem::~CustomAnimationTriggerEntryItem()
380 : {
381 0 : }
382 :
383 :
384 0 : void CustomAnimationTriggerEntryItem::InitViewData( SvTreeListBox* pView, SvTreeListEntry* pEntry, SvViewDataItem* pViewData )
385 : {
386 0 : if( !pViewData )
387 0 : pViewData = pView->GetViewDataItem( pEntry, this );
388 :
389 0 : Size aSize(pView->GetTextWidth( maDescription ) + 2 * 19, pView->GetTextHeight() );
390 0 : if( aSize.Height() < 19 )
391 0 : aSize.Height() = 19;
392 0 : pViewData->maSize = aSize;
393 0 : }
394 :
395 :
396 :
397 0 : void CustomAnimationTriggerEntryItem::Paint(
398 : const Point& rPos, SvTreeListBox& rDev, const SvViewDataEntry* /*pView*/, const SvTreeListEntry* /*pEntry*/)
399 : {
400 0 : Size aSize( rDev.GetOutputSizePixel().Width(), static_cast< SvTreeListBox* >(&rDev)->GetEntryHeight() );
401 :
402 0 : Point aPos( 0, rPos.Y() );
403 :
404 0 : Rectangle aOutRect( aPos, aSize );
405 :
406 : // fill the background
407 0 : Color aColor (rDev.GetSettings().GetStyleSettings().GetDialogColor());
408 :
409 0 : rDev.Push();
410 0 : rDev.SetFillColor (aColor);
411 0 : rDev.SetLineColor ();
412 0 : rDev.DrawRect(aOutRect);
413 :
414 : // Erase the four corner pixels to make the rectangle appear rounded.
415 0 : rDev.SetLineColor( rDev.GetSettings().GetStyleSettings().GetWindowColor());
416 0 : rDev.DrawPixel( aOutRect.TopLeft());
417 0 : rDev.DrawPixel( Point(aOutRect.Right(), aOutRect.Top()));
418 0 : rDev.DrawPixel( Point(aOutRect.Left(), aOutRect.Bottom()));
419 0 : rDev.DrawPixel( Point(aOutRect.Right(), aOutRect.Bottom()));
420 :
421 : // draw the category title
422 :
423 0 : int nVertBorder = (( aSize.Height() - rDev.GetTextHeight()) >> 1);
424 0 : int nHorzBorder = rDev.LogicToPixel( Size( 3, 3 ), MAP_APPFONT ).Width();
425 :
426 0 : aOutRect.Left() += nHorzBorder;
427 0 : aOutRect.Right() -= nHorzBorder;
428 0 : aOutRect.Top() += nVertBorder;
429 0 : aOutRect.Bottom() -= nVertBorder;
430 :
431 0 : rDev.DrawText (aOutRect, rDev.GetEllipsisString( maDescription, aOutRect.GetWidth() ) );
432 0 : rDev.Pop();
433 0 : }
434 :
435 :
436 :
437 0 : SvLBoxItem* CustomAnimationTriggerEntryItem::Create() const
438 : {
439 0 : return NULL;
440 : }
441 :
442 :
443 :
444 0 : void CustomAnimationTriggerEntryItem::Clone( SvLBoxItem* )
445 : {
446 0 : }
447 :
448 :
449 :
450 0 : CustomAnimationList::CustomAnimationList( ::Window* pParent )
451 : : SvTreeListBox( pParent, WB_TABSTOP | WB_BORDER | WB_HASLINES | WB_HASBUTTONS | WB_HASBUTTONSATROOT )
452 : , mbIgnorePaint(false)
453 : , mpController(0)
454 : , mnLastGroupId(0)
455 0 : , mpLastParentEntry(0)
456 : {
457 :
458 0 : EnableContextMenuHandling();
459 0 : SetSelectionMode( MULTIPLE_SELECTION );
460 0 : SetOptimalImageIndent();
461 0 : SetNodeDefaultImages();
462 0 : }
463 :
464 0 : extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeCustomAnimationList( ::Window *pParent )
465 : {
466 0 : return new CustomAnimationList( pParent );
467 : }
468 :
469 :
470 :
471 0 : const Image& CustomAnimationList::getImage( sal_uInt16 nId )
472 : {
473 : DBG_ASSERT( (nId >= IMG_CUSTOMANIMATION_ON_CLICK) && (nId <= IMG_CUSTOMANIMATION_MEDIA_STOP), "sd::CustomAnimationList::getImage(), illegal index!" );
474 :
475 0 : Image& rImage = maImages[nId - IMG_CUSTOMANIMATION_ON_CLICK];
476 :
477 : // load on demand
478 0 : if( rImage.GetSizePixel().Width() == 0 )
479 0 : rImage = Image(SdResId( nId ) );
480 :
481 0 : return rImage;
482 : }
483 :
484 :
485 :
486 0 : CustomAnimationList::~CustomAnimationList()
487 : {
488 0 : if( mpMainSequence.get() )
489 0 : mpMainSequence->removeListener( this );
490 :
491 0 : clear();
492 0 : }
493 :
494 :
495 :
496 0 : void CustomAnimationList::KeyInput( const KeyEvent& rKEvt )
497 : {
498 0 : const int nKeyCode = rKEvt.GetKeyCode().GetCode();
499 0 : switch( nKeyCode )
500 : {
501 0 : case KEY_DELETE: mpController->onContextMenu( CM_REMOVE ); return;
502 0 : case KEY_INSERT: mpController->onContextMenu( CM_CREATE ); return;
503 : case KEY_SPACE:
504 : {
505 0 : const Point aPos;
506 0 : const CommandEvent aCEvt( aPos, COMMAND_CONTEXTMENU );
507 0 : Command( aCEvt );
508 0 : return;
509 : }
510 :
511 : }
512 :
513 0 : ::SvTreeListBox::KeyInput( rKEvt );
514 : }
515 :
516 :
517 :
518 : /** selects or deselects the given effect.
519 : Selections of other effects are not changed */
520 0 : void CustomAnimationList::select( CustomAnimationEffectPtr pEffect, bool bSelect /* = true */ )
521 : {
522 0 : CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(First());
523 0 : while( pEntry )
524 : {
525 0 : if( pEntry->getEffect() == pEffect )
526 : {
527 0 : Select( pEntry, bSelect );
528 0 : MakeVisible( pEntry );
529 0 : break;
530 : }
531 0 : pEntry = static_cast< CustomAnimationListEntry* >(Next( pEntry ));
532 : }
533 :
534 0 : if( !pEntry && bSelect )
535 : {
536 0 : append( pEffect );
537 0 : select( pEffect );
538 : }
539 0 : }
540 :
541 :
542 :
543 0 : void CustomAnimationList::clear()
544 : {
545 0 : Clear();
546 :
547 0 : mpLastParentEntry = 0;
548 0 : mxLastTargetShape = 0;
549 0 : }
550 :
551 :
552 :
553 0 : void CustomAnimationList::update( MainSequencePtr pMainSequence )
554 : {
555 0 : if( mpMainSequence.get() )
556 0 : mpMainSequence->removeListener( this );
557 :
558 0 : mpMainSequence = pMainSequence;
559 0 : update();
560 :
561 0 : if( mpMainSequence.get() )
562 0 : mpMainSequence->addListener( this );
563 0 : }
564 :
565 :
566 :
567 : struct stl_append_effect_func : public std::unary_function<CustomAnimationEffectPtr, void>
568 : {
569 0 : stl_append_effect_func( CustomAnimationList& rList ) : mrList( rList ) {}
570 : void operator()(CustomAnimationEffectPtr pEffect);
571 : CustomAnimationList& mrList;
572 : };
573 :
574 0 : void stl_append_effect_func::operator()(CustomAnimationEffectPtr pEffect)
575 : {
576 0 : mrList.append( pEffect );
577 0 : }
578 :
579 :
580 0 : void CustomAnimationList::update()
581 : {
582 0 : mbIgnorePaint = true;
583 0 : SetUpdateMode( false );
584 :
585 0 : CustomAnimationListEntry* pEntry = 0;
586 :
587 0 : std::list< CustomAnimationEffectPtr > aExpanded;
588 0 : std::list< CustomAnimationEffectPtr > aSelected;
589 :
590 0 : CustomAnimationEffectPtr pFirstSelEffect;
591 0 : CustomAnimationEffectPtr pLastSelEffect;
592 0 : long nFirstVis = -1;
593 0 : long nLastVis = -1;
594 0 : long nFirstSelOld = -1;
595 0 : long nLastSelOld = -1;
596 0 : bool bMoved = false;
597 0 : bool bMovedUp = false;
598 0 : bool bMovedDown = false;
599 :
600 0 : if( mpMainSequence.get() )
601 : {
602 : // save scroll position
603 0 : pEntry = static_cast<CustomAnimationListEntry*>(GetFirstEntryInView());
604 0 : if( pEntry )
605 0 : nFirstVis = GetAbsPos( pEntry );
606 :
607 0 : pEntry = static_cast<CustomAnimationListEntry*>(GetLastEntryInView());
608 0 : if( pEntry )
609 0 : nLastVis = GetAbsPos( pEntry );
610 :
611 0 : pEntry = static_cast<CustomAnimationListEntry*>(FirstSelected());
612 0 : if( pEntry )
613 : {
614 0 : pFirstSelEffect = pEntry->getEffect();
615 0 : nFirstSelOld = GetAbsPos( pEntry );
616 : }
617 :
618 0 : pEntry = static_cast<CustomAnimationListEntry*>(LastSelected());
619 0 : if( pEntry )
620 : {
621 0 : pLastSelEffect = pEntry->getEffect();
622 0 : nLastSelOld = GetAbsPos( pEntry );
623 : }
624 :
625 : // save selection and expand states
626 0 : pEntry = static_cast<CustomAnimationListEntry*>(First());
627 :
628 0 : while( pEntry )
629 : {
630 0 : CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
631 0 : if( pEffect.get() )
632 : {
633 0 : if( IsExpanded( pEntry ) )
634 0 : aExpanded.push_back( pEffect );
635 :
636 0 : if( IsSelected( pEntry ) )
637 0 : aSelected.push_back( pEffect );
638 : }
639 :
640 0 : pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
641 0 : }
642 : }
643 :
644 : // rebuild list
645 0 : clear();
646 0 : if( mpMainSequence.get() )
647 : {
648 0 : long nFirstSelNew = -1;
649 0 : long nLastSelNew = -1;
650 0 : std::for_each( mpMainSequence->getBegin(), mpMainSequence->getEnd(), stl_append_effect_func( *this ) );
651 0 : mpLastParentEntry = 0;
652 :
653 0 : const InteractiveSequenceList& rISL = mpMainSequence->getInteractiveSequenceList();
654 :
655 0 : InteractiveSequenceList::const_iterator aIter( rISL.begin() );
656 0 : const InteractiveSequenceList::const_iterator aEnd( rISL.end() );
657 0 : while( aIter != aEnd )
658 : {
659 0 : InteractiveSequencePtr pIS( (*aIter++) );
660 :
661 0 : Reference< XShape > xShape( pIS->getTriggerShape() );
662 0 : if( xShape.is() )
663 : {
664 0 : SvTreeListEntry* pLBoxEntry = new CustomAnimationListEntry;
665 0 : pLBoxEntry->AddItem( new SvLBoxContextBmp( pLBoxEntry, 0, Image(), Image(), false));
666 0 : OUString aDescription = SD_RESSTR(STR_CUSTOMANIMATION_TRIGGER);
667 0 : aDescription += ": ";
668 0 : aDescription += getShapeDescription( xShape, false );
669 0 : pLBoxEntry->AddItem( new CustomAnimationTriggerEntryItem( pLBoxEntry, 0, aDescription ) );
670 0 : Insert( pLBoxEntry );
671 0 : SvViewDataEntry* pViewData = GetViewData( pLBoxEntry );
672 0 : if( pViewData )
673 0 : pViewData->SetSelectable(false);
674 :
675 0 : std::for_each( pIS->getBegin(), pIS->getEnd(), stl_append_effect_func( *this ) );
676 0 : mpLastParentEntry = 0;
677 : }
678 0 : }
679 :
680 : // restore selection and expand states
681 0 : pEntry = static_cast<CustomAnimationListEntry*>(First());
682 :
683 0 : while( pEntry )
684 : {
685 0 : CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
686 0 : if( pEffect.get() )
687 : {
688 0 : if( std::find( aExpanded.begin(), aExpanded.end(), pEffect ) != aExpanded.end() )
689 0 : Expand( pEntry );
690 :
691 0 : if( std::find( aSelected.begin(), aSelected.end(), pEffect ) != aSelected.end() )
692 0 : Select( pEntry );
693 :
694 0 : if( pEffect == pFirstSelEffect )
695 0 : nFirstSelNew = GetAbsPos( pEntry );
696 :
697 0 : if( pEffect == pLastSelEffect )
698 0 : nLastSelNew = GetAbsPos( pEntry );
699 : }
700 :
701 0 : pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
702 0 : }
703 :
704 : // Scroll to a selected entry, depending on where the selection moved.
705 0 : bMoved = nFirstSelNew != nFirstSelOld;
706 0 : bMovedUp = nFirstSelNew < nFirstSelOld;
707 0 : bMovedDown = nFirstSelNew > nFirstSelOld;
708 :
709 0 : if( bMoved && nLastSelOld < nFirstVis && nLastSelNew < nFirstVis )
710 : {
711 : // The selection is above the visible area.
712 : // Scroll up to show the last few selected entries.
713 0 : if( nLastSelNew - (nLastVis - nFirstVis) > nFirstSelNew)
714 : {
715 : // The entries in the selection range can't fit in view.
716 : // Scroll so the last selected entry is last in view.
717 0 : ScrollToAbsPos( nLastSelNew - (nLastVis - nFirstVis) );
718 : }
719 : else
720 0 : ScrollToAbsPos( nFirstSelNew );
721 : }
722 0 : else if( bMoved && nFirstSelOld > nLastVis && nFirstSelNew > nLastVis )
723 : {
724 : // The selection is below the visible area.
725 : // Scroll down to the first few selected entries.
726 0 : ScrollToAbsPos( nFirstSelNew );
727 : }
728 0 : else if( bMovedUp && nFirstSelOld <= nFirstVis )
729 : {
730 : // A visible entry has moved up out of view; scroll up one.
731 0 : ScrollToAbsPos( nFirstVis - 1 );
732 : }
733 0 : else if( bMovedDown && nLastSelOld >= nLastVis )
734 : {
735 : // An entry has moved down out of view; scroll down one.
736 0 : ScrollToAbsPos( nFirstVis + 1 );
737 : }
738 0 : else if ( nFirstVis != -1 )
739 : {
740 : // The selection is still in view, or it hasn't moved.
741 0 : ScrollToAbsPos( nFirstVis );
742 : }
743 : }
744 :
745 0 : mbIgnorePaint = false;
746 0 : SetUpdateMode( true );
747 0 : Invalidate();
748 0 : }
749 :
750 :
751 :
752 0 : void CustomAnimationList::append( CustomAnimationEffectPtr pEffect )
753 : {
754 : // create a ui description
755 0 : OUString aDescription;
756 :
757 0 : Any aTarget( pEffect->getTarget() );
758 0 : if( aTarget.hasValue() ) try
759 : {
760 0 : aDescription = getDescription( aTarget, pEffect->getTargetSubItem() != ShapeAnimationSubType::ONLY_BACKGROUND );
761 :
762 0 : SvTreeListEntry* pParentEntry = 0;
763 :
764 0 : Reference< XShape > xTargetShape( pEffect->getTargetShape() );
765 0 : sal_Int32 nGroupId = pEffect->getGroupId();
766 :
767 : // if this effect has the same target and group-id as the last root effect,
768 : // the last root effect is also this effects parent
769 0 : if( mpLastParentEntry && (nGroupId != -1) && (mxLastTargetShape == xTargetShape) && (mnLastGroupId == nGroupId) )
770 0 : pParentEntry = mpLastParentEntry;
771 :
772 : // create an entry for the effect
773 0 : SvTreeListEntry* pEntry = new CustomAnimationListEntry( pEffect );
774 :
775 0 : pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), false));
776 0 : pEntry->AddItem( new CustomAnimationListEntryItem( pEntry, 0, aDescription, pEffect, this ) );
777 :
778 0 : if( pParentEntry )
779 : {
780 : // add a subentry
781 0 : Insert( pEntry, pParentEntry );
782 : }
783 : else
784 : {
785 : // add a root entry
786 0 : Insert( pEntry );
787 :
788 : // and the new root entry becomes the possible next group header
789 0 : mxLastTargetShape = xTargetShape;
790 0 : mnLastGroupId = nGroupId;
791 0 : mpLastParentEntry = pEntry;
792 0 : }
793 : }
794 0 : catch( Exception& )
795 : {
796 : OSL_FAIL("sd::CustomAnimationList::append(), exception caught!" );
797 0 : }
798 0 : }
799 :
800 :
801 :
802 0 : void selectShape( SvTreeListBox* pTreeList, Reference< XShape > xShape )
803 : {
804 0 : CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(pTreeList->First());
805 0 : while( pEntry )
806 : {
807 0 : CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
808 0 : if( pEffect.get() )
809 : {
810 0 : if( pEffect->getTarget() == xShape )
811 0 : pTreeList->Select( pEntry );
812 : }
813 :
814 0 : pEntry = static_cast< CustomAnimationListEntry* >(pTreeList->Next( pEntry ));
815 0 : }
816 0 : }
817 :
818 :
819 :
820 0 : void CustomAnimationList::onSelectionChanged( Any aSelection )
821 : {
822 : try
823 : {
824 0 : SelectAll(false);
825 :
826 0 : if( aSelection.hasValue() )
827 : {
828 0 : Reference< XIndexAccess > xShapes( aSelection, UNO_QUERY );
829 0 : if( xShapes.is() )
830 : {
831 0 : sal_Int32 nCount = xShapes->getCount();
832 : sal_Int32 nIndex;
833 0 : for( nIndex = 0; nIndex < nCount; nIndex++ )
834 : {
835 0 : Reference< XShape > xShape( xShapes->getByIndex( nIndex ), UNO_QUERY );
836 0 : if( xShape.is() )
837 0 : selectShape( this, xShape );
838 0 : }
839 : }
840 : else
841 : {
842 0 : Reference< XShape > xShape( aSelection, UNO_QUERY );
843 0 : if( xShape.is() )
844 0 : selectShape( this, xShape );
845 0 : }
846 : }
847 :
848 0 : SelectHdl();
849 : }
850 0 : catch( Exception& )
851 : {
852 : OSL_FAIL( "sd::CustomAnimationList::onSelectionChanged(), Exception caught!" );
853 : }
854 0 : }
855 :
856 :
857 :
858 0 : void CustomAnimationList::SelectHdl()
859 : {
860 0 : if( mbIgnorePaint )
861 0 : return;
862 0 : SvTreeListBox::SelectHdl();
863 0 : mpController->onSelect();
864 : }
865 :
866 :
867 :
868 0 : bool CustomAnimationList::isExpanded( const CustomAnimationEffectPtr& pEffect ) const
869 : {
870 0 : CustomAnimationListEntry* pEntry = static_cast<CustomAnimationListEntry*>(First());
871 :
872 0 : while( pEntry )
873 : {
874 0 : if( pEntry->getEffect() == pEffect )
875 0 : break;
876 :
877 0 : pEntry = static_cast<CustomAnimationListEntry*>(Next( pEntry ));
878 : }
879 :
880 0 : if( pEntry )
881 0 : pEntry = static_cast<CustomAnimationListEntry*>(GetParent( pEntry ));
882 :
883 0 : return (pEntry == 0) || IsExpanded( pEntry );
884 : }
885 :
886 :
887 0 : EffectSequence CustomAnimationList::getSelection() const
888 : {
889 0 : EffectSequence aSelection;
890 :
891 0 : CustomAnimationListEntry* pEntry = dynamic_cast< CustomAnimationListEntry* >(FirstSelected());
892 0 : while( pEntry )
893 : {
894 0 : CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
895 0 : if( pEffect.get() )
896 0 : aSelection.push_back( pEffect );
897 :
898 : // if the selected effect is not expanded and has children
899 : // we say that the children are automaticly selected
900 0 : if( !IsExpanded( pEntry ) )
901 : {
902 0 : CustomAnimationListEntry* pChild = dynamic_cast< CustomAnimationListEntry* >( FirstChild( pEntry ) );
903 0 : while( pChild )
904 : {
905 0 : if( !IsSelected( pChild ) )
906 : {
907 0 : CustomAnimationEffectPtr pChildEffect( pChild->getEffect() );
908 0 : if( pChildEffect.get() )
909 0 : aSelection.push_back( pChildEffect );
910 : }
911 :
912 0 : pChild = dynamic_cast< CustomAnimationListEntry* >( NextSibling( pChild ) );
913 : }
914 : }
915 :
916 0 : pEntry = static_cast< CustomAnimationListEntry* >(NextSelected( pEntry ));
917 0 : }
918 :
919 0 : return aSelection;
920 : }
921 :
922 :
923 :
924 0 : bool CustomAnimationList::DoubleClickHdl()
925 : {
926 0 : mpController->onDoubleClick();
927 0 : return false;
928 : }
929 :
930 :
931 :
932 0 : PopupMenu* CustomAnimationList::CreateContextMenu()
933 : {
934 0 : PopupMenu* pMenu = new PopupMenu(SdResId( RID_EFFECT_CONTEXTMENU ));
935 :
936 0 : sal_Int16 nNodeType = -1;
937 0 : sal_Int16 nEntries = 0;
938 :
939 0 : CustomAnimationListEntry* pEntry = static_cast< CustomAnimationListEntry* >(FirstSelected());
940 0 : while( pEntry )
941 : {
942 0 : nEntries++;
943 0 : CustomAnimationEffectPtr pEffect( pEntry->getEffect() );
944 0 : if( pEffect.get() )
945 : {
946 0 : if( nNodeType == -1 )
947 : {
948 0 : nNodeType = pEffect->getNodeType();
949 : }
950 : else
951 : {
952 0 : if( nNodeType != pEffect->getNodeType() )
953 : {
954 0 : nNodeType = -1;
955 0 : break;
956 : }
957 : }
958 : }
959 :
960 0 : pEntry = static_cast< CustomAnimationListEntry* >(NextSelected( pEntry ));
961 0 : }
962 :
963 0 : pMenu->CheckItem( CM_WITH_CLICK, nNodeType == EffectNodeType::ON_CLICK );
964 0 : pMenu->CheckItem( CM_WITH_PREVIOUS, nNodeType == EffectNodeType::WITH_PREVIOUS );
965 0 : pMenu->CheckItem( CM_AFTER_PREVIOUS, nNodeType == EffectNodeType::AFTER_PREVIOUS );
966 0 : pMenu->EnableItem( CM_OPTIONS, nEntries == 1 );
967 0 : pMenu->EnableItem( CM_DURATION, nEntries == 1 );
968 :
969 0 : return pMenu;
970 : }
971 :
972 :
973 :
974 0 : void CustomAnimationList::ExcecuteContextMenuAction( sal_uInt16 nSelectedPopupEntry )
975 : {
976 0 : mpController->onContextMenu( nSelectedPopupEntry );
977 0 : }
978 :
979 :
980 :
981 0 : void CustomAnimationList::SetTabs()
982 : {
983 0 : SvTreeListBox::SetTabs();
984 0 : }
985 :
986 :
987 :
988 0 : void CustomAnimationList::notify_change()
989 : {
990 0 : update();
991 0 : mpController->onSelect();
992 0 : }
993 :
994 0 : void CustomAnimationList::Paint( const Rectangle& rRect )
995 : {
996 0 : if( mbIgnorePaint )
997 0 : return;
998 :
999 0 : SvTreeListBox::Paint( rRect );
1000 :
1001 : // draw help text if list box is still empty
1002 0 : if( First() == 0 )
1003 : {
1004 0 : Color aOldColor( GetTextColor() );
1005 0 : SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
1006 0 : ::Point aOffset( LogicToPixel( Point( 6, 6 ), MAP_APPFONT ) );
1007 :
1008 0 : Rectangle aRect( Point( 0,0 ), GetOutputSizePixel() );
1009 :
1010 0 : aRect.Left() += aOffset.X();
1011 0 : aRect.Top() += aOffset.Y();
1012 0 : aRect.Right() -= aOffset.X();
1013 0 : aRect.Bottom() -= aOffset.Y();
1014 :
1015 : DrawText( aRect, SD_RESSTR(STR_CUSTOMANIMATION_LIST_HELPTEXT),
1016 0 : TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK | TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER );
1017 :
1018 0 : SetTextColor( aOldColor );
1019 : }
1020 : }
1021 :
1022 : }
1023 :
1024 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|