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 : #ifndef INCLUDED_SD_INC_CUSTOMANIMATIONEFFECT_HXX
21 : #define INCLUDED_SD_INC_CUSTOMANIMATIONEFFECT_HXX
22 :
23 : #include <com/sun/star/animations/XAnimationNode.hpp>
24 : #include <com/sun/star/animations/XTimeContainer.hpp>
25 : #include <com/sun/star/animations/XAudio.hpp>
26 : #include <com/sun/star/drawing/XShape.hpp>
27 : #include <com/sun/star/util/XChangesListener.hpp>
28 :
29 : #include <boost/shared_ptr.hpp>
30 :
31 : #include <vcl/timer.hxx>
32 :
33 : #include <sddllapi.h>
34 :
35 : #include <list>
36 : #include <map>
37 :
38 : class SdrPathObj;
39 :
40 : namespace sd {
41 :
42 :
43 :
44 : enum EValue { VALUE_FROM, VALUE_TO, VALUE_BY, VALUE_FIRST, VALUE_LAST };
45 :
46 : class CustomAnimationEffect;
47 :
48 : class CustomAnimationPreset;
49 : typedef boost::shared_ptr< CustomAnimationPreset > CustomAnimationPresetPtr;
50 :
51 : typedef boost::shared_ptr< CustomAnimationEffect > CustomAnimationEffectPtr;
52 :
53 : typedef std::list< CustomAnimationEffectPtr > EffectSequence;
54 :
55 : class EffectSequenceHelper;
56 :
57 : class CustomAnimationEffect
58 : {
59 : friend class MainSequence;
60 : friend class EffectSequenceHelper;
61 :
62 : public:
63 : SD_DLLPUBLIC CustomAnimationEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode );
64 : SD_DLLPUBLIC virtual ~CustomAnimationEffect();
65 :
66 0 : const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& getNode() const { return mxNode; }
67 : void setNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode );
68 : void replaceNode( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode );
69 :
70 : CustomAnimationEffectPtr clone() const;
71 :
72 : // attributes
73 0 : const OUString& getPresetId() const { return maPresetId; }
74 0 : const OUString& getPresetSubType() const { return maPresetSubType; }
75 0 : const OUString& getProperty() const { return maProperty; }
76 :
77 0 : sal_Int16 getPresetClass() const { return mnPresetClass; }
78 : void setPresetClass( sal_Int16 nPresetClass );
79 :
80 0 : sal_Int16 getNodeType() const { return mnNodeType; }
81 : SD_DLLPUBLIC void setNodeType( sal_Int16 nNodeType );
82 :
83 : ::com::sun::star::uno::Any getRepeatCount() const;
84 : void setRepeatCount( const ::com::sun::star::uno::Any& rRepeatCount );
85 :
86 : ::com::sun::star::uno::Any getEnd() const;
87 : void setEnd( const ::com::sun::star::uno::Any& rEnd );
88 :
89 : sal_Int16 getFill() const;
90 : void setFill( sal_Int16 nFill );
91 :
92 0 : double getBegin() const { return mfBegin; }
93 : SD_DLLPUBLIC void setBegin( double fBegin );
94 :
95 0 : double getDuration() const { return mfDuration; }
96 : SD_DLLPUBLIC void setDuration( double fDuration );
97 :
98 0 : double getAbsoluteDuration() const { return mfAbsoluteDuration; }
99 :
100 : const OUString& getName() const { return maName; }
101 : void setName( const OUString& rName ) { maName = rName; }
102 :
103 0 : sal_Int16 getIterateType() const { return mnIterateType; }
104 : SD_DLLPUBLIC void setIterateType( sal_Int16 nIterateType );
105 :
106 0 : double getIterateInterval() const { return mfIterateInterval; }
107 : SD_DLLPUBLIC void setIterateInterval( double fIterateInterval );
108 :
109 0 : ::com::sun::star::uno::Any getTarget() const { return maTarget; }
110 : SD_DLLPUBLIC void setTarget( const ::com::sun::star::uno::Any& rTarget );
111 :
112 0 : sal_Bool hasAfterEffect() const { return mbHasAfterEffect; }
113 0 : void setHasAfterEffect( sal_Bool bHasAfterEffect ) { mbHasAfterEffect = bHasAfterEffect; }
114 :
115 0 : ::com::sun::star::uno::Any getDimColor() const { return maDimColor; }
116 0 : void setDimColor( ::com::sun::star::uno::Any aDimColor ) { maDimColor = aDimColor; }
117 :
118 0 : bool IsAfterEffectOnNext() const { return mbAfterEffectOnNextEffect; }
119 0 : void setAfterEffectOnNext( bool bOnNextEffect ) { mbAfterEffectOnNextEffect = bOnNextEffect; }
120 :
121 0 : sal_Int32 getParaDepth() const { return mnParaDepth; }
122 :
123 0 : sal_Bool hasText() const { return mbHasText; }
124 :
125 0 : sal_Int16 getCommand() const { return mnCommand; }
126 :
127 0 : double getAcceleration() const { return mfAcceleration; }
128 : void setAcceleration( double fAcceleration );
129 :
130 0 : double getDecelerate() const { return mfDecelerate; }
131 : void setDecelerate( double fDecelerate );
132 :
133 0 : sal_Bool getAutoReverse() const { return mbAutoReverse; }
134 : void setAutoReverse( sal_Bool bAutoReverse );
135 :
136 : ::com::sun::star::uno::Any getProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue );
137 : bool setProperty( sal_Int32 nNodeType, const OUString& rAttributeName, EValue eValue, const ::com::sun::star::uno::Any& rValue );
138 :
139 : ::com::sun::star::uno::Any getTransformationProperty( sal_Int32 nTransformType, EValue eValue );
140 : bool setTransformationProperty( sal_Int32 nTransformType, EValue eValue, const ::com::sun::star::uno::Any& rValue );
141 :
142 : ::com::sun::star::uno::Any getColor( sal_Int32 nIndex );
143 : void setColor( sal_Int32 nIndex, const ::com::sun::star::uno::Any& rColor );
144 :
145 : ::com::sun::star::uno::Any getRotation();
146 : void setRotation( const ::com::sun::star::uno::Any& rRotation );
147 :
148 0 : sal_Int32 getGroupId() const { return mnGroupId; }
149 : void setGroupId( sal_Int32 nGroupId );
150 :
151 0 : sal_Int16 getTargetSubItem() const { return mnTargetSubItem; }
152 : SD_DLLPUBLIC void setTargetSubItem( sal_Int16 nSubItem );
153 :
154 : OUString getPath() const;
155 : void setPath( const OUString& rPath );
156 :
157 : bool checkForText();
158 : bool calculateIterateDuration();
159 :
160 : void setAudio( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAudio >& xAudio );
161 : bool getStopAudio() const;
162 : SD_DLLPUBLIC void setStopAudio();
163 : SD_DLLPUBLIC void createAudio( const ::com::sun::star::uno::Any& rSource, double fVolume = 1.0 );
164 : void removeAudio();
165 0 : const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAudio >& getAudio() const { return mxAudio; }
166 :
167 0 : EffectSequenceHelper* getEffectSequence() const { return mpEffectSequence; }
168 :
169 : // helper
170 : ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode > createAfterEffectNode() const throw (com::sun::star::uno::Exception);
171 : ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > getTargetShape() const;
172 :
173 : // static helpers
174 : static sal_Int32 get_node_type( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode );
175 : static sal_Int32 getNumberOfSubitems( const ::com::sun::star::uno::Any& aTarget, sal_Int16 nIterateType );
176 :
177 : SdrPathObj* createSdrPathObjFromPath();
178 : void updateSdrPathObjFromPath( SdrPathObj& rPathObj );
179 : void updatePathFromSdrPathObj( const SdrPathObj& rPathObj );
180 :
181 : protected:
182 0 : void setEffectSequence( EffectSequenceHelper* pSequence ) { mpEffectSequence = pSequence; }
183 :
184 : private:
185 : sal_Int16 mnNodeType;
186 : OUString maPresetId;
187 : OUString maPresetSubType;
188 : OUString maProperty;
189 : sal_Int16 mnPresetClass;
190 : double mfBegin;
191 : double mfDuration; // this is the maximum duration of the subeffects
192 : double mfAbsoluteDuration; // this is the maximum duration of the subeffects including possible iterations
193 : sal_Int32 mnGroupId;
194 : sal_Int16 mnIterateType;
195 : double mfIterateInterval;
196 : sal_Int32 mnParaDepth;
197 : sal_Bool mbHasText;
198 : double mfAcceleration;
199 : double mfDecelerate;
200 : sal_Bool mbAutoReverse;
201 : sal_Int16 mnTargetSubItem;
202 : sal_Int16 mnCommand;
203 :
204 : EffectSequenceHelper* mpEffectSequence;
205 :
206 : OUString maName;
207 :
208 : ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode > mxNode;
209 : ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAudio > mxAudio;
210 : ::com::sun::star::uno::Any maTarget;
211 :
212 : sal_Bool mbHasAfterEffect;
213 : ::com::sun::star::uno::Any maDimColor;
214 : bool mbAfterEffectOnNextEffect;
215 : };
216 :
217 : struct stl_CustomAnimationEffect_search_node_predict
218 : {
219 : stl_CustomAnimationEffect_search_node_predict( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xSearchNode );
220 : bool operator()( CustomAnimationEffectPtr pEffect ) const;
221 : const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& mxSearchNode;
222 : };
223 :
224 : enum ESequenceHint { EFFECT_EDITED, EFFECT_REMOVED, EFFECT_ADDED };
225 :
226 : /** this listener is implemented by UI components to track changes in the animation core */
227 0 : class ISequenceListener
228 : {
229 : public:
230 : virtual void notify_change() = 0;
231 :
232 : protected:
233 0 : ~ISequenceListener() {}
234 : };
235 :
236 : /** this class keeps track of a group of animations that build up
237 : a text animation for a single shape */
238 0 : class CustomAnimationTextGroup
239 : {
240 : friend class EffectSequenceHelper;
241 :
242 : public:
243 : CustomAnimationTextGroup( const ::com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& rTarget, sal_Int32 nGroupId );
244 :
245 : void reset();
246 : void addEffect( CustomAnimationEffectPtr& pEffect );
247 :
248 : const ::com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& getTarget() const { return maTarget; }
249 0 : const EffectSequence& getEffects() const { return maEffects; }
250 :
251 : /* -1: as single object, 0: all at once, n > 0: by n Th paragraph */
252 0 : sal_Int32 getTextGrouping() const { return mnTextGrouping; }
253 :
254 0 : sal_Bool getAnimateForm() const { return mbAnimateForm; }
255 0 : sal_Bool getTextReverse() const { return mbTextReverse; }
256 0 : double getTextGroupingAuto() const { return mfGroupingAuto; }
257 :
258 : private:
259 : EffectSequence maEffects;
260 : ::com::sun::star::uno::Reference< com::sun::star::drawing::XShape > maTarget;
261 :
262 : enum { PARA_LEVELS = 5 };
263 :
264 : sal_Int32 mnTextGrouping;
265 : sal_Bool mbAnimateForm;
266 : sal_Bool mbTextReverse;
267 : double mfGroupingAuto;
268 : sal_Int32 mnLastPara;
269 : sal_Int8 mnDepthFlags[PARA_LEVELS];
270 : sal_Int32 mnGroupId;
271 : };
272 :
273 : typedef boost::shared_ptr< CustomAnimationTextGroup > CustomAnimationTextGroupPtr;
274 : typedef std::map< sal_Int32, CustomAnimationTextGroupPtr > CustomAnimationTextGroupMap;
275 :
276 : class EffectSequenceHelper
277 : {
278 : friend class MainSequence;
279 :
280 : public:
281 : EffectSequenceHelper();
282 : EffectSequenceHelper( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XTimeContainer >& xSequenceRoot );
283 : virtual ~EffectSequenceHelper();
284 :
285 : virtual ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode > getRootNode();
286 :
287 : CustomAnimationEffectPtr append( const CustomAnimationPresetPtr& pDescriptor, const ::com::sun::star::uno::Any& rTarget, double fDuration = -1.0 );
288 : CustomAnimationEffectPtr append( const SdrPathObj& rPathObj, const ::com::sun::star::uno::Any& rTarget, double fDuration = -1.0 );
289 : SD_DLLPUBLIC void append( const CustomAnimationEffectPtr& pEffect );
290 : void insert( EffectSequence::iterator& rPos, const CustomAnimationEffectPtr& pEffect );
291 : void replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pDescriptor, double fDuration = -1.0 );
292 : void replace( const CustomAnimationEffectPtr& pEffect, const CustomAnimationPresetPtr& pDescriptor, const OUString& rPresetSubType, double fDuration = -1.0 );
293 : void remove( const CustomAnimationEffectPtr& pEffect );
294 :
295 : void create( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode );
296 : void createEffectsequence( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode );
297 : void processAfterEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode );
298 : void createEffects( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode );
299 :
300 0 : sal_Int32 getCount() const { return sal::static_int_cast< sal_Int32 >( maEffects.size() ); }
301 :
302 : virtual CustomAnimationEffectPtr findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const;
303 :
304 : virtual bool disposeShape( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape );
305 : virtual void insertTextRange( const com::sun::star::uno::Any& aTarget );
306 : virtual void disposeTextRange( const com::sun::star::uno::Any& aTarget );
307 : virtual bool hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape );
308 : virtual void onTextChanged( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape );
309 :
310 : /** this must be called if effects from this sequence are changed.
311 : the method will call the registered listeners */
312 : void update( const CustomAnimationEffectPtr& pEffect );
313 :
314 : /** this method rebuilds the animation nodes */
315 : virtual void rebuild();
316 :
317 0 : EffectSequence::iterator getBegin() { return maEffects.begin(); }
318 0 : EffectSequence::iterator getEnd() { return maEffects.end(); }
319 : EffectSequence::iterator find( const CustomAnimationEffectPtr& pEffect );
320 :
321 0 : EffectSequence& getSequence() { return maEffects; }
322 :
323 : void addListener( ISequenceListener* pListener );
324 : void removeListener( ISequenceListener* pListener );
325 :
326 : // text group methods
327 :
328 : CustomAnimationTextGroupPtr findGroup( sal_Int32 nGroupId );
329 : SD_DLLPUBLIC CustomAnimationTextGroupPtr createTextGroup( CustomAnimationEffectPtr pEffect, sal_Int32 nTextGrouping, double fTextGroupingAuto, sal_Bool bAnimateForm, sal_Bool bTextReverse );
330 : void setTextGrouping( CustomAnimationTextGroupPtr pTextGroup, sal_Int32 nTextGrouping );
331 : void setAnimateForm( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bAnimateForm );
332 : void setTextGroupingAuto( CustomAnimationTextGroupPtr pTextGroup, double fTextGroupingAuto );
333 : void setTextReverse( CustomAnimationTextGroupPtr pTextGroup, sal_Bool bAnimateForm );
334 :
335 0 : sal_Int32 getSequenceType() const { return mnSequenceType; }
336 :
337 0 : ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > getTriggerShape() const { return mxEventSource; }
338 0 : void setTriggerShape( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xTrigger ) { mxEventSource = xTrigger; }
339 :
340 : virtual sal_Int32 getOffsetFromEffect( const CustomAnimationEffectPtr& xEffect ) const;
341 : virtual CustomAnimationEffectPtr getEffectFromOffset( sal_Int32 nOffset ) const;
342 :
343 : protected:
344 : virtual void implRebuild();
345 : virtual void reset();
346 :
347 : void createTextGroupParagraphEffects( CustomAnimationTextGroupPtr pTextGroup, CustomAnimationEffectPtr pEffect, bool bUsed );
348 :
349 : void notify_listeners();
350 :
351 : void updateTextGroups();
352 :
353 : protected:
354 : ::com::sun::star::uno::Reference< ::com::sun::star::animations::XTimeContainer > mxSequenceRoot;
355 : EffectSequence maEffects;
356 : std::list< ISequenceListener* > maListeners;
357 : CustomAnimationTextGroupMap maGroupMap;
358 : sal_Int32 mnSequenceType;
359 : ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > mxEventSource;
360 : };
361 :
362 : class MainSequence;
363 :
364 0 : class InteractiveSequence : public EffectSequenceHelper
365 : {
366 : friend class MainSequence;
367 : friend class MainSequenceChangeGuard;
368 :
369 : public:
370 : InteractiveSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XTimeContainer >& xSequenceRoot, MainSequence* pMainSequence );
371 :
372 : /** this method rebuilds the animation nodes */
373 : virtual void rebuild() SAL_OVERRIDE;
374 :
375 : private:
376 : virtual void implRebuild() SAL_OVERRIDE;
377 :
378 : MainSequence* mpMainSequence;
379 : };
380 :
381 : typedef boost::shared_ptr< InteractiveSequence > InteractiveSequencePtr;
382 : typedef std::list< InteractiveSequencePtr > InteractiveSequenceList;
383 :
384 : class MainSequence : public EffectSequenceHelper, public ISequenceListener
385 : {
386 : friend class UndoAnimation;
387 : friend class MainSequenceRebuildGuard;
388 : friend class MainSequenceChangeGuard;
389 :
390 : public:
391 : MainSequence();
392 : MainSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xTimingRootNode );
393 : virtual ~MainSequence();
394 :
395 : virtual ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode > getRootNode() SAL_OVERRIDE;
396 : void reset( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xTimingRootNode );
397 :
398 : /** this method rebuilds the animation nodes */
399 : virtual void rebuild() SAL_OVERRIDE;
400 :
401 : virtual CustomAnimationEffectPtr findEffect( const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >& xNode ) const SAL_OVERRIDE;
402 :
403 : virtual bool disposeShape( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape ) SAL_OVERRIDE;
404 : virtual void insertTextRange( const com::sun::star::uno::Any& aTarget ) SAL_OVERRIDE;
405 : virtual void disposeTextRange( const com::sun::star::uno::Any& aTarget ) SAL_OVERRIDE;
406 : virtual bool hasEffect( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape ) SAL_OVERRIDE;
407 : virtual void onTextChanged( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape ) SAL_OVERRIDE;
408 :
409 0 : const InteractiveSequenceList& getInteractiveSequenceList() const { return maInteractiveSequenceList; }
410 :
411 : virtual void notify_change() SAL_OVERRIDE;
412 :
413 : bool setTrigger( const CustomAnimationEffectPtr& pEffect, const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xTriggerShape );
414 :
415 : /** starts a timer that recreates the internal structure from the API core after 1 second */
416 : void startRecreateTimer();
417 :
418 : /** starts a timer that rebuilds the API core from the internal structure after 1 second */
419 : void startRebuildTimer();
420 :
421 : virtual sal_Int32 getOffsetFromEffect( const CustomAnimationEffectPtr& xEffect ) const SAL_OVERRIDE;
422 : virtual CustomAnimationEffectPtr getEffectFromOffset( sal_Int32 nOffset ) const SAL_OVERRIDE;
423 :
424 : protected:
425 : /** permits rebuilds until unlockRebuilds() is called. All rebuild calls during a locked sequence are
426 : process after unlockRebuilds() call. lockRebuilds() and unlockRebuilds() calls can be nested. */
427 : void lockRebuilds();
428 : void unlockRebuilds();
429 :
430 : DECL_LINK(onTimerHdl, void *);
431 :
432 : virtual void implRebuild() SAL_OVERRIDE;
433 :
434 : void init();
435 :
436 : void createMainSequence();
437 : virtual void reset() SAL_OVERRIDE;
438 :
439 : InteractiveSequencePtr createInteractiveSequence( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >& xShape );
440 :
441 : InteractiveSequenceList maInteractiveSequenceList;
442 :
443 : ::com::sun::star::uno::Reference< ::com::sun::star::util::XChangesListener > mxChangesListener;
444 : ::com::sun::star::uno::Reference< ::com::sun::star::animations::XTimeContainer > mxTimingRootNode;
445 : Timer maTimer;
446 : bool mbTimerMode;
447 : bool mbRebuilding;
448 :
449 : long mnRebuildLockGuard;
450 : bool mbPendingRebuildRequest;
451 : sal_Int32 mbIgnoreChanges;
452 : };
453 :
454 : typedef boost::shared_ptr< MainSequence > MainSequencePtr;
455 :
456 : class MainSequenceRebuildGuard
457 : {
458 : public:
459 : MainSequenceRebuildGuard( const MainSequencePtr& pMainSequence );
460 : ~MainSequenceRebuildGuard();
461 :
462 : private:
463 : MainSequencePtr mpMainSequence;
464 : };
465 :
466 : }
467 :
468 : #endif // INCLUDED_SD_INC_CUSTOMANIMATIONEFFECT_HXX
469 :
470 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|