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