1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <com/sun/star/animations/XTimeContainer.hpp>
22 #include <com/sun/star/presentation/ParagraphTarget.hpp>
23 #include <com/sun/star/animations/AnimationFill.hpp>
24 #include <com/sun/star/animations/XAnimate.hpp>
25 #include <com/sun/star/animations/AnimationRestart.hpp>
26 #include <com/sun/star/animations/ParallelTimeContainer.hpp>
27 #include <com/sun/star/lang/XServiceInfo.hpp>
28 #include <com/sun/star/lang/XInitialization.hpp>
29 #include <com/sun/star/container/XEnumerationAccess.hpp>
30 #include <com/sun/star/util/XCloneable.hpp>
31 #include <comphelper/processfactory.hxx>
33 #include <cppuhelper/implbase5.hxx>
34 #include <osl/mutex.hxx>
35 #include "CustomAnimationPreset.hxx"
40 using ::com::sun::star::uno::Reference
;
41 using ::com::sun::star::uno::RuntimeException
;
42 using ::com::sun::star::uno::Exception
;
43 using ::com::sun::star::uno::Sequence
;
44 using ::com::sun::star::uno::Any
;
45 using ::com::sun::star::uno::UNO_QUERY
;
46 using ::com::sun::star::uno::XInterface
;
47 using ::com::sun::star::lang::NoSupportException
;
48 using ::com::sun::star::beans::NamedValue
;
49 using ::com::sun::star::lang::IllegalArgumentException
;
50 using ::com::sun::star::container::NoSuchElementException
;
51 using ::com::sun::star::container::ElementExistException
;
52 using ::com::sun::star::lang::WrappedTargetException
;
53 using ::com::sun::star::container::XEnumeration
;
54 using ::com::sun::star::container::XEnumerationAccess
;
55 using ::com::sun::star::util::XCloneable
;
56 using ::com::sun::star::lang::XServiceInfo
;
57 using ::com::sun::star::lang::XInitialization
;
58 using ::com::sun::star::uno::Type
;
59 using ::com::sun::star::uno::XWeak
;
60 using ::com::sun::star::lang::XMultiServiceFactory
;
61 using ::com::sun::star::presentation::ParagraphTarget
;
62 using ::com::sun::star::drawing::XShape
;
64 using namespace ::com::sun::star::animations
;
68 typedef ::cppu::WeakImplHelper5
< XTimeContainer
, XEnumerationAccess
, XCloneable
, XServiceInfo
, XInitialization
> RandomAnimationNodeBase
;
69 class RandomAnimationNode
: public RandomAnimationNodeBase
72 RandomAnimationNode( const RandomAnimationNode
& rNode
);
73 RandomAnimationNode( sal_Int16 nPresetClass
);
74 RandomAnimationNode();
76 void init( sal_Int16 nPresetClass
);
79 void SAL_CALL
initialize( const Sequence
< Any
>& aArguments
) throw (Exception
, RuntimeException
);
82 Reference
< XInterface
> SAL_CALL
getParent( ) throw (RuntimeException
);
83 void SAL_CALL
setParent( const Reference
< XInterface
>& Parent
) throw (NoSupportException
, RuntimeException
);
86 virtual Reference
< XCloneable
> SAL_CALL
createClone() throw (RuntimeException
);
89 OUString SAL_CALL
getImplementationName() throw();
90 Sequence
< OUString
> SAL_CALL
getSupportedServiceNames(void) throw();
91 sal_Bool SAL_CALL
supportsService(const OUString
& ServiceName
) throw();
94 ::sal_Int16 SAL_CALL
getType() throw (RuntimeException
);
95 Any SAL_CALL
getBegin() throw (RuntimeException
);
96 void SAL_CALL
setBegin( const Any
& _begin
) throw (RuntimeException
);
97 Any SAL_CALL
getDuration() throw (RuntimeException
);
98 void SAL_CALL
setDuration( const Any
& _duration
) throw (RuntimeException
);
99 Any SAL_CALL
getEnd() throw (RuntimeException
);
100 void SAL_CALL
setEnd( const Any
& _end
) throw (RuntimeException
);
101 Any SAL_CALL
getEndSync() throw (RuntimeException
);
102 void SAL_CALL
setEndSync( const Any
& _endsync
) throw (RuntimeException
);
103 Any SAL_CALL
getRepeatCount() throw (RuntimeException
);
104 void SAL_CALL
setRepeatCount( const Any
& _repeatcount
) throw (RuntimeException
);
105 Any SAL_CALL
getRepeatDuration() throw (RuntimeException
);
106 void SAL_CALL
setRepeatDuration( const Any
& _repeatduration
) throw (RuntimeException
);
107 ::sal_Int16 SAL_CALL
getFill() throw (RuntimeException
);
108 void SAL_CALL
setFill( ::sal_Int16 _fill
) throw (RuntimeException
);
109 ::sal_Int16 SAL_CALL
getFillDefault() throw (RuntimeException
);
110 void SAL_CALL
setFillDefault( ::sal_Int16 _filldefault
) throw (RuntimeException
);
111 ::sal_Int16 SAL_CALL
getRestart() throw (RuntimeException
);
112 void SAL_CALL
setRestart( ::sal_Int16 _restart
) throw (RuntimeException
);
113 ::sal_Int16 SAL_CALL
getRestartDefault() throw (RuntimeException
);
114 void SAL_CALL
setRestartDefault( ::sal_Int16 _restartdefault
) throw (RuntimeException
);
115 double SAL_CALL
getAcceleration() throw (RuntimeException
);
116 void SAL_CALL
setAcceleration( double _acceleration
) throw (RuntimeException
);
117 double SAL_CALL
getDecelerate() throw (RuntimeException
);
118 void SAL_CALL
setDecelerate( double _decelerate
) throw (RuntimeException
);
119 ::sal_Bool SAL_CALL
getAutoReverse() throw (RuntimeException
);
120 void SAL_CALL
setAutoReverse( ::sal_Bool _autoreverse
) throw (RuntimeException
);
121 Sequence
< NamedValue
> SAL_CALL
getUserData() throw (RuntimeException
);
122 void SAL_CALL
setUserData( const Sequence
< NamedValue
>& _userdata
) throw (RuntimeException
);
125 virtual Type SAL_CALL
getElementType() throw (RuntimeException
);
126 virtual sal_Bool SAL_CALL
hasElements() throw (RuntimeException
);
128 // XEnumerationAccess
129 virtual Reference
< XEnumeration
> SAL_CALL
createEnumeration() throw (RuntimeException
);
132 Reference
< XAnimationNode
> SAL_CALL
insertBefore( const Reference
< XAnimationNode
>& newChild
, const Reference
< XAnimationNode
>& refChild
) throw (IllegalArgumentException
, NoSuchElementException
, ElementExistException
, WrappedTargetException
, RuntimeException
);
133 Reference
< XAnimationNode
> SAL_CALL
insertAfter( const Reference
< XAnimationNode
>& newChild
, const Reference
< XAnimationNode
>& refChild
) throw (IllegalArgumentException
, NoSuchElementException
, ElementExistException
, WrappedTargetException
, RuntimeException
);
134 Reference
< XAnimationNode
> SAL_CALL
replaceChild( const Reference
< XAnimationNode
>& newChild
, const Reference
< XAnimationNode
>& oldChild
) throw (IllegalArgumentException
, NoSuchElementException
, ElementExistException
, WrappedTargetException
, RuntimeException
);
135 Reference
< XAnimationNode
> SAL_CALL
removeChild( const Reference
< XAnimationNode
>& oldChild
) throw (IllegalArgumentException
, NoSuchElementException
, WrappedTargetException
, RuntimeException
);
136 Reference
< XAnimationNode
> SAL_CALL
appendChild( const Reference
< XAnimationNode
>& newChild
) throw (IllegalArgumentException
, ElementExistException
, WrappedTargetException
, RuntimeException
);
139 // our first, last and only protection from mutli-threads!
142 sal_Int16 mnPresetClass
;
143 Reference
< XInterface
> mxParent
;
145 Any maBegin
, maDuration
, maEnd
, maEndSync
, maRepeatCount
, maRepeatDuration
, maTarget
;
146 sal_Int16 mnFill
, mnFillDefault
, mnRestart
, mnRestartDefault
;
147 double mfAcceleration
, mfDecelerate
;
148 sal_Bool mbAutoReverse
;
149 Sequence
< NamedValue
> maUserData
;
151 Reference
< XAnimate
> mxFirstNode
;
154 // --------------------------------------------------------------------
156 static const sal_Char
* pSN1
= "com.sun.star.animations.ParallelTimeContainer";
157 static const sal_Char
* pSN2
= "com.sun.star.comp.sd.RandomAnimationNode";
159 // --------------------------------------------------------------------
161 SD_DLLPUBLIC Reference
< XInterface
> RandomAnimationNode_createInstance( sal_Int16 nPresetClass
)
163 Reference
< XInterface
> xInt( static_cast<XWeak
*>( new RandomAnimationNode( nPresetClass
) ) );
167 // --------------------------------------------------------------------
169 Reference
< XInterface
> SAL_CALL
RandomNode_createInstance( const Reference
< XMultiServiceFactory
> & )
171 Reference
< XInterface
> xInt( static_cast<XWeak
*>( new RandomAnimationNode() ) );
175 // --------------------------------------------------------------------
177 OUString
RandomNode__getImplementationName() throw( RuntimeException
)
179 return OUString( "sd::RandomAnimationNode" ) ;
182 // --------------------------------------------------------------------
184 Sequence
< OUString
> SAL_CALL
RandomNode_getSupportedServiceNames() throw( RuntimeException
)
186 static const OUString
aSN2( OUString::createFromAscii( pSN2
) );
187 Sequence
< OUString
> aSeq( &aSN2
, 1 );
191 // --------------------------------------------------------------------
193 RandomAnimationNode::RandomAnimationNode( const RandomAnimationNode
& rNode
)
194 : RandomAnimationNodeBase(),
195 mnPresetClass( rNode
.mnPresetClass
),
196 maBegin( rNode
.maBegin
),
197 maDuration( rNode
.maDuration
),
198 maEnd( rNode
.maEnd
),
199 maEndSync( rNode
.maEndSync
),
200 maRepeatCount( rNode
.maRepeatCount
),
201 maRepeatDuration( rNode
.maRepeatDuration
),
202 maTarget( rNode
.maTarget
),
203 mnFill( rNode
.mnFill
),
204 mnFillDefault( rNode
.mnFillDefault
),
205 mnRestart( rNode
.mnRestart
),
206 mnRestartDefault( rNode
.mnRestartDefault
),
207 mfAcceleration( rNode
.mfAcceleration
),
208 mfDecelerate( rNode
.mfDecelerate
),
209 mbAutoReverse( rNode
.mbAutoReverse
),
210 maUserData( rNode
.maUserData
)
214 // --------------------------------------------------------------------
216 RandomAnimationNode::RandomAnimationNode( sal_Int16 nPresetClass
)
218 init( nPresetClass
);
221 RandomAnimationNode::RandomAnimationNode()
226 void RandomAnimationNode::init( sal_Int16 nPresetClass
)
228 mnPresetClass
= nPresetClass
;
229 mnFill
= AnimationFill::DEFAULT
;
230 mnFillDefault
= AnimationFill::INHERIT
;
231 mnRestart
= AnimationRestart::DEFAULT
;
232 mnRestartDefault
= AnimationRestart::INHERIT
;
233 mfAcceleration
= 0.0;
235 mbAutoReverse
= sal_False
;
238 // --------------------------------------------------------------------
241 void SAL_CALL
RandomAnimationNode::initialize( const Sequence
< Any
>& aArguments
) throw (Exception
, RuntimeException
)
243 if( aArguments
.getLength() != 1 )
244 throw IllegalArgumentException();
246 if( aArguments
[0].getValueType() == ::getCppuType((const sal_Int16
*)0) )
248 aArguments
[0] >>= mnPresetClass
;
250 else if( aArguments
[0].getValueType() != ::getCppuType((const ParagraphTarget
*)0) )
252 Reference
< XShape
> xShape
;
253 aArguments
[0] >>= xShape
;
255 throw IllegalArgumentException();
257 maTarget
= aArguments
[0];
260 // --------------------------------------------------------------------
263 sal_Int16 SAL_CALL
RandomAnimationNode::getType() throw (RuntimeException
)
265 Guard
< Mutex
> aGuard( maMutex
);
266 return ::com::sun::star::animations::AnimationNodeType::PAR
;
269 // --------------------------------------------------------------------
272 Any SAL_CALL
RandomAnimationNode::getBegin() throw (RuntimeException
)
274 Guard
< Mutex
> aGuard( maMutex
);
278 // --------------------------------------------------------------------
281 void SAL_CALL
RandomAnimationNode::setBegin( const Any
& _begin
) throw (RuntimeException
)
283 Guard
< Mutex
> aGuard( maMutex
);
287 // --------------------------------------------------------------------
290 Any SAL_CALL
RandomAnimationNode::getDuration() throw (RuntimeException
)
292 Guard
< Mutex
> aGuard( maMutex
);
296 // --------------------------------------------------------------------
299 void SAL_CALL
RandomAnimationNode::setDuration( const Any
& _duration
) throw (RuntimeException
)
301 Guard
< Mutex
> aGuard( maMutex
);
302 maDuration
= _duration
;
305 // --------------------------------------------------------------------
308 Any SAL_CALL
RandomAnimationNode::getEnd() throw (RuntimeException
)
310 Guard
< Mutex
> aGuard( maMutex
);
314 // --------------------------------------------------------------------
317 void SAL_CALL
RandomAnimationNode::setEnd( const Any
& _end
) throw (RuntimeException
)
319 Guard
< Mutex
> aGuard( maMutex
);
323 // --------------------------------------------------------------------
326 Any SAL_CALL
RandomAnimationNode::getEndSync() throw (RuntimeException
)
328 Guard
< Mutex
> aGuard( maMutex
);
332 // --------------------------------------------------------------------
335 void SAL_CALL
RandomAnimationNode::setEndSync( const Any
& _endsync
) throw (RuntimeException
)
337 Guard
< Mutex
> aGuard( maMutex
);
338 maEndSync
= _endsync
;
341 // --------------------------------------------------------------------
344 Any SAL_CALL
RandomAnimationNode::getRepeatCount() throw (RuntimeException
)
346 Guard
< Mutex
> aGuard( maMutex
);
347 return maRepeatCount
;
350 // --------------------------------------------------------------------
353 void SAL_CALL
RandomAnimationNode::setRepeatCount( const Any
& _repeatcount
) throw (RuntimeException
)
355 Guard
< Mutex
> aGuard( maMutex
);
356 maRepeatCount
= _repeatcount
;
359 // --------------------------------------------------------------------
362 Any SAL_CALL
RandomAnimationNode::getRepeatDuration() throw (RuntimeException
)
364 Guard
< Mutex
> aGuard( maMutex
);
365 return maRepeatDuration
;
368 // --------------------------------------------------------------------
371 void SAL_CALL
RandomAnimationNode::setRepeatDuration( const Any
& _repeatduration
) throw (RuntimeException
)
373 Guard
< Mutex
> aGuard( maMutex
);
374 maRepeatDuration
= _repeatduration
;
377 // --------------------------------------------------------------------
380 sal_Int16 SAL_CALL
RandomAnimationNode::getFill() throw (RuntimeException
)
382 Guard
< Mutex
> aGuard( maMutex
);
386 // --------------------------------------------------------------------
389 void SAL_CALL
RandomAnimationNode::setFill( sal_Int16 _fill
) throw (RuntimeException
)
391 Guard
< Mutex
> aGuard( maMutex
);
395 // --------------------------------------------------------------------
398 sal_Int16 SAL_CALL
RandomAnimationNode::getFillDefault() throw (RuntimeException
)
400 Guard
< Mutex
> aGuard( maMutex
);
401 return mnFillDefault
;
404 // --------------------------------------------------------------------
407 void SAL_CALL
RandomAnimationNode::setFillDefault( sal_Int16 _filldefault
) throw (RuntimeException
)
409 Guard
< Mutex
> aGuard( maMutex
);
410 mnFillDefault
= _filldefault
;
413 // --------------------------------------------------------------------
416 sal_Int16 SAL_CALL
RandomAnimationNode::getRestart() throw (RuntimeException
)
418 Guard
< Mutex
> aGuard( maMutex
);
422 // --------------------------------------------------------------------
425 void SAL_CALL
RandomAnimationNode::setRestart( sal_Int16 _restart
) throw (RuntimeException
)
427 Guard
< Mutex
> aGuard( maMutex
);
428 mnRestart
= _restart
;
431 // --------------------------------------------------------------------
434 sal_Int16 SAL_CALL
RandomAnimationNode::getRestartDefault() throw (RuntimeException
)
436 Guard
< Mutex
> aGuard( maMutex
);
437 return mnRestartDefault
;
440 // --------------------------------------------------------------------
443 void SAL_CALL
RandomAnimationNode::setRestartDefault( sal_Int16 _restartdefault
) throw (RuntimeException
)
445 Guard
< Mutex
> aGuard( maMutex
);
446 mnRestartDefault
= _restartdefault
;
449 // --------------------------------------------------------------------
452 double SAL_CALL
RandomAnimationNode::getAcceleration() throw (RuntimeException
)
454 Guard
< Mutex
> aGuard( maMutex
);
455 return mfAcceleration
;
458 // --------------------------------------------------------------------
461 void SAL_CALL
RandomAnimationNode::setAcceleration( double _acceleration
) throw (RuntimeException
)
463 Guard
< Mutex
> aGuard( maMutex
);
464 mfAcceleration
= _acceleration
;
467 // --------------------------------------------------------------------
470 double SAL_CALL
RandomAnimationNode::getDecelerate() throw (RuntimeException
)
472 Guard
< Mutex
> aGuard( maMutex
);
476 // --------------------------------------------------------------------
479 void SAL_CALL
RandomAnimationNode::setDecelerate( double _decelerate
) throw (RuntimeException
)
481 Guard
< Mutex
> aGuard( maMutex
);
482 mfDecelerate
= _decelerate
;
485 // --------------------------------------------------------------------
488 sal_Bool SAL_CALL
RandomAnimationNode::getAutoReverse() throw (RuntimeException
)
490 Guard
< Mutex
> aGuard( maMutex
);
491 return mbAutoReverse
;
494 // --------------------------------------------------------------------
497 void SAL_CALL
RandomAnimationNode::setAutoReverse( sal_Bool _autoreverse
) throw (RuntimeException
)
499 Guard
< Mutex
> aGuard( maMutex
);
500 mbAutoReverse
= _autoreverse
;
503 // --------------------------------------------------------------------
505 Sequence
< NamedValue
> SAL_CALL
RandomAnimationNode::getUserData() throw (RuntimeException
)
507 Guard
< Mutex
> aGuard( maMutex
);
511 // --------------------------------------------------------------------
513 void SAL_CALL
RandomAnimationNode::setUserData( const Sequence
< NamedValue
>& _userdata
) throw (RuntimeException
)
515 Guard
< Mutex
> aGuard( maMutex
);
516 maUserData
= _userdata
;
519 // --------------------------------------------------------------------
522 Reference
< XInterface
> SAL_CALL
RandomAnimationNode::getParent() throw (RuntimeException
)
524 Guard
< Mutex
> aGuard( maMutex
);
528 // --------------------------------------------------------------------
531 void SAL_CALL
RandomAnimationNode::setParent( const Reference
< XInterface
>& Parent
) throw (NoSupportException
, RuntimeException
)
533 Guard
< Mutex
> aGuard( maMutex
);
537 // --------------------------------------------------------------------
540 Reference
< XCloneable
> SAL_CALL
RandomAnimationNode::createClone() throw (RuntimeException
)
542 Reference
< XCloneable
> xNewNode( new RandomAnimationNode( *this ) );
546 // --------------------------------------------------------------------
549 Type SAL_CALL
RandomAnimationNode::getElementType() throw (RuntimeException
)
551 return ::getCppuType((const Reference
< XAnimationNode
>*)0);
554 // --------------------------------------------------------------------
557 sal_Bool SAL_CALL
RandomAnimationNode::hasElements() throw (RuntimeException
)
562 // --------------------------------------------------------------------
564 // XEnumerationAccess
565 Reference
< XEnumeration
> SAL_CALL
RandomAnimationNode::createEnumeration()
566 throw (RuntimeException
)
568 Guard
< Mutex
> aGuard( maMutex
);
570 if( !maTarget
.hasValue() && mxFirstNode
.is() )
572 Any
aTarget( mxFirstNode
->getTarget() );
573 if( aTarget
.hasValue() )
580 Reference
< XEnumeration
> xEnum
;
582 Reference
< XEnumerationAccess
> aEnumAccess( CustomAnimationPresets::getCustomAnimationPresets().getRandomPreset( mnPresetClass
), UNO_QUERY
);
584 if( aEnumAccess
.is() )
586 Reference
< XEnumeration
> xEnumeration( aEnumAccess
->createEnumeration(), UNO_QUERY
);
587 if( xEnumeration
.is() )
589 while( xEnumeration
->hasMoreElements() )
591 Reference
< XAnimate
> xAnimate( xEnumeration
->nextElement(), UNO_QUERY
);
593 xAnimate
->setTarget( maTarget
);
596 xEnum
= aEnumAccess
->createEnumeration();
600 // no presets? give empty node!
601 Reference
< XParallelTimeContainer
> xTimeContainer
= ParallelTimeContainer::create( comphelper::getProcessComponentContext() );
602 xEnum
= xTimeContainer
->createEnumeration();
608 // --------------------------------------------------------------------
612 Reference
< XAnimationNode
> SAL_CALL
RandomAnimationNode::insertBefore( const Reference
< XAnimationNode
>& newChild
, const Reference
< XAnimationNode
>& )
613 throw (IllegalArgumentException
, NoSuchElementException
, ElementExistException
, WrappedTargetException
, RuntimeException
)
615 return appendChild( newChild
);
618 // --------------------------------------------------------------------
621 Reference
< XAnimationNode
> SAL_CALL
RandomAnimationNode::insertAfter( const Reference
< XAnimationNode
>& newChild
, const Reference
< XAnimationNode
>& )
622 throw (IllegalArgumentException
, NoSuchElementException
, ElementExistException
, WrappedTargetException
, RuntimeException
)
624 return appendChild( newChild
);
627 // --------------------------------------------------------------------
630 Reference
< XAnimationNode
> SAL_CALL
RandomAnimationNode::replaceChild( const Reference
< XAnimationNode
>& newChild
, const Reference
< XAnimationNode
>& )
631 throw( IllegalArgumentException
, NoSuchElementException
, ElementExistException
, WrappedTargetException
, RuntimeException
)
633 return appendChild( newChild
);
636 // --------------------------------------------------------------------
639 Reference
< XAnimationNode
> SAL_CALL
RandomAnimationNode::removeChild( const Reference
< XAnimationNode
>& oldChild
)
640 throw(IllegalArgumentException
, NoSuchElementException
, WrappedTargetException
, RuntimeException
)
645 // --------------------------------------------------------------------
648 Reference
< XAnimationNode
> SAL_CALL
RandomAnimationNode::appendChild( const Reference
< XAnimationNode
>& newChild
)
649 throw(IllegalArgumentException
, ElementExistException
, WrappedTargetException
, RuntimeException
)
651 Reference
< XAnimate
> xAnimate( newChild
, UNO_QUERY
);
654 Any
aTarget( xAnimate
->getTarget() );
655 if( aTarget
.hasValue() )
659 if( !maTarget
.hasValue() && !mxFirstNode
.is() )
660 mxFirstNode
= xAnimate
;
666 OUString
RandomAnimationNode::getImplementationName() throw()
668 return RandomNode__getImplementationName();
672 sal_Bool
RandomAnimationNode::supportsService(const OUString
& ServiceName
) throw()
674 return ServiceName
.equalsAscii( pSN1
) || ServiceName
.equalsAscii( pSN2
);
678 Sequence
< OUString
> RandomAnimationNode::getSupportedServiceNames(void) throw()
680 return RandomNode_getSupportedServiceNames();
685 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */