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 :
21 : #include <toolkit/controls/roadmapcontrol.hxx>
22 : #include <toolkit/helper/unopropertyarrayhelper.hxx>
23 : #include <toolkit/helper/property.hxx>
24 : #include <com/sun/star/awt/XVclWindowPeer.hpp>
25 : #include <osl/diagnose.h>
26 :
27 :
28 : namespace toolkit
29 : {
30 :
31 :
32 : using namespace ::com::sun::star::uno;
33 : using namespace ::com::sun::star::awt;
34 : using namespace ::com::sun::star::lang;
35 : using namespace ::com::sun::star::beans;
36 : using namespace ::com::sun::star::container;
37 :
38 :
39 : // helper
40 :
41 :
42 0 : static void lcl_throwIllegalArgumentException( )
43 : { // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this ....
44 0 : throw IllegalArgumentException();
45 : }
46 :
47 0 : static void lcl_throwIndexOutOfBoundsException( )
48 : { // throwing is expensive (in terms of code size), thus we hope the compiler does not inline this ....
49 0 : throw IndexOutOfBoundsException();
50 : }
51 :
52 :
53 : // = UnoControlRoadmapModel
54 :
55 :
56 0 : UnoControlRoadmapModel::UnoControlRoadmapModel( const Reference< XComponentContext >& i_factory )
57 : :UnoControlRoadmapModel_Base( i_factory )
58 0 : ,maContainerListeners( *this )
59 : {
60 0 : ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR );
61 0 : ImplRegisterProperty( BASEPROPERTY_BORDER );
62 0 : ImplRegisterProperty( BASEPROPERTY_BORDERCOLOR );
63 0 : ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL );
64 0 : ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR );
65 0 : ImplRegisterProperty( BASEPROPERTY_HELPTEXT );
66 0 : ImplRegisterProperty( BASEPROPERTY_HELPURL );
67 0 : ImplRegisterProperty( BASEPROPERTY_IMAGEURL );
68 0 : ImplRegisterProperty( BASEPROPERTY_GRAPHIC );
69 0 : ImplRegisterProperty( BASEPROPERTY_PRINTABLE );
70 0 : ImplRegisterProperty( BASEPROPERTY_COMPLETE );
71 0 : ImplRegisterProperty( BASEPROPERTY_ACTIVATED );
72 0 : ImplRegisterProperty( BASEPROPERTY_CURRENTITEMID );
73 0 : ImplRegisterProperty( BASEPROPERTY_TABSTOP );
74 0 : ImplRegisterProperty( BASEPROPERTY_TEXT );
75 0 : }
76 :
77 :
78 0 : OUString UnoControlRoadmapModel::getServiceName() throw(RuntimeException, std::exception)
79 : {
80 0 : return OUString::createFromAscii( szServiceName_UnoControlRoadmapModel );
81 : }
82 :
83 :
84 :
85 0 : Any UnoControlRoadmapModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const
86 : {
87 0 : Any aReturn;
88 0 : switch (nPropId)
89 : {
90 : case BASEPROPERTY_COMPLETE:
91 0 : aReturn <<= true;
92 0 : break;
93 : case BASEPROPERTY_ACTIVATED:
94 0 : aReturn <<= true;
95 0 : break;
96 : case BASEPROPERTY_CURRENTITEMID:
97 0 : aReturn <<= (sal_Int16) -1;
98 0 : break;
99 : case BASEPROPERTY_TEXT:
100 0 : break;
101 : case BASEPROPERTY_BORDER:
102 0 : aReturn <<= (sal_Int16) 2; // No Border
103 0 : break;
104 : case BASEPROPERTY_DEFAULTCONTROL:
105 0 : aReturn <<= OUString( OUString::createFromAscii( szServiceName_UnoControlRoadmap ) );
106 0 : break;
107 0 : default : aReturn = UnoControlRoadmapModel_Base::ImplGetDefaultValue( nPropId ); break;
108 : }
109 :
110 0 : return aReturn;
111 : }
112 :
113 :
114 0 : Reference< XInterface > SAL_CALL UnoControlRoadmapModel::createInstance( ) throw (Exception, ::com::sun::star::uno::RuntimeException, std::exception)
115 : {
116 0 : ORoadmapEntry* pRoadmapItem = new ORoadmapEntry();
117 0 : Reference< XInterface > xNewRoadmapItem = (::cppu::OWeakObject*)pRoadmapItem;
118 0 : return xNewRoadmapItem;
119 : }
120 :
121 :
122 0 : Reference< XInterface > SAL_CALL UnoControlRoadmapModel::createInstanceWithArguments( const Sequence< Any >& /*aArguments*/ ) throw (Exception, RuntimeException, std::exception)
123 : {
124 : // Todo: implementation of the arguments handling
125 0 : ORoadmapEntry* pRoadmapItem = new ORoadmapEntry();
126 0 : Reference< XInterface > xNewRoadmapItem = (::cppu::OWeakObject*)pRoadmapItem;
127 0 : return xNewRoadmapItem;
128 : }
129 :
130 :
131 0 : IMPLEMENT_FORWARD_XTYPEPROVIDER2( UnoControlRoadmapModel, UnoControlRoadmapModel_Base, UnoControlRoadmapModel_IBase )
132 :
133 :
134 :
135 0 : ::com::sun::star::uno::Any SAL_CALL UnoControlRoadmapModel::queryAggregation( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException, std::exception)
136 : {
137 0 : Any aRet = UnoControlRoadmapModel_Base::queryAggregation( rType );
138 0 : if ( !aRet.hasValue() )
139 0 : aRet = UnoControlRoadmapModel_IBase::queryInterface( rType );
140 0 : return aRet;
141 : }
142 :
143 :
144 :
145 0 : ::cppu::IPropertyArrayHelper& UnoControlRoadmapModel::getInfoHelper()
146 : {
147 : static UnoPropertyArrayHelper* pHelper = NULL;
148 0 : if ( !pHelper )
149 : {
150 0 : Sequence<sal_Int32> aIDs = ImplGetPropertyIds();
151 0 : pHelper = new UnoPropertyArrayHelper( aIDs );
152 : }
153 0 : return *pHelper;
154 : }
155 :
156 :
157 : // beans::XMultiPropertySet
158 :
159 0 : Reference< XPropertySetInfo > UnoControlRoadmapModel::getPropertySetInfo( ) throw(RuntimeException, std::exception)
160 : {
161 0 : static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
162 0 : return xInfo;
163 : }
164 :
165 :
166 0 : sal_Int32 SAL_CALL UnoControlRoadmapModel::getCount() throw(RuntimeException, std::exception)
167 : {
168 0 : return maRoadmapItems.size();
169 : }
170 :
171 0 : Any SAL_CALL UnoControlRoadmapModel::getByIndex( sal_Int32 Index ) throw (IndexOutOfBoundsException, WrappedTargetException, RuntimeException, std::exception )
172 : {
173 0 : if (( Index >= (sal_Int32)maRoadmapItems.size()) || (Index < 0))
174 0 : lcl_throwIndexOutOfBoundsException( );
175 0 : Any aAny;
176 0 : aAny = makeAny( maRoadmapItems.at( Index ));
177 0 : return aAny;
178 : }
179 :
180 :
181 :
182 0 : void UnoControlRoadmapModel::MakeRMItemValidation( sal_Int32 Index, Reference< XInterface > xRoadmapItem )
183 : {
184 0 : if ((Index > (sal_Int32)maRoadmapItems.size()) || ( Index < 0 ) )
185 0 : lcl_throwIndexOutOfBoundsException( );
186 0 : if ( !xRoadmapItem.is() )
187 0 : lcl_throwIllegalArgumentException();
188 0 : Reference< XServiceInfo > xServiceInfo( xRoadmapItem, UNO_QUERY );
189 0 : bool bIsRoadmapItem = xServiceInfo->supportsService("com.sun.star.awt.RoadmapItem");
190 0 : if ( !bIsRoadmapItem )
191 0 : lcl_throwIllegalArgumentException();
192 0 : }
193 :
194 :
195 0 : void UnoControlRoadmapModel::SetRMItemDefaultProperties( const sal_Int32 , Reference< XInterface > xRoadmapItem)
196 : {
197 0 : Any aAny;
198 0 : Reference< XPropertySet > xPropertySet( xRoadmapItem, UNO_QUERY );
199 0 : Reference< XPropertySet > xProps( xRoadmapItem, UNO_QUERY );
200 0 : if ( xProps.is() )
201 : {
202 0 : sal_Int32 LocID = 0;
203 0 : Any aValue = xPropertySet->getPropertyValue("ID");
204 0 : aValue >>= LocID;
205 0 : if (LocID < 0) // index may not be smaller than zero
206 : {
207 0 : aAny <<= GetUniqueID();
208 0 : xPropertySet->setPropertyValue("ID", aAny );
209 0 : }
210 0 : }
211 0 : }
212 :
213 :
214 : // The performance of this method could certainly be improved.
215 : // As long as only vectors with up to 10 elements are
216 : // involved it should be sufficient
217 0 : sal_Int32 UnoControlRoadmapModel::GetUniqueID()
218 : {
219 0 : Any aAny;
220 0 : bool bIncrement = true;
221 0 : sal_Int32 CurID = 0;
222 0 : sal_Int32 n_CurItemID = 0;
223 0 : Reference< XInterface > CurRoadmapItem;
224 0 : while ( bIncrement )
225 : {
226 0 : bIncrement = false;
227 0 : for ( RoadmapItemHolderList::iterator i = maRoadmapItems.begin(); i < maRoadmapItems.end(); ++i )
228 : {
229 0 : CurRoadmapItem = *i;
230 0 : Reference< XPropertySet > xPropertySet( CurRoadmapItem, UNO_QUERY );
231 0 : aAny = xPropertySet->getPropertyValue("ID");
232 0 : aAny >>= n_CurItemID;
233 0 : if (n_CurItemID == CurID)
234 : {
235 0 : bIncrement = true;
236 0 : CurID++;
237 0 : break;
238 : }
239 0 : }
240 : }
241 0 : return CurID;
242 : }
243 :
244 :
245 0 : ContainerEvent UnoControlRoadmapModel::GetContainerEvent(sal_Int32 Index, Reference< XInterface > xRoadmapItem)
246 : {
247 0 : ContainerEvent aEvent;
248 0 : aEvent.Source = *this;
249 0 : aEvent.Element <<= xRoadmapItem;
250 0 : aEvent.Accessor = makeAny(Index);
251 0 : return aEvent;
252 : }
253 :
254 :
255 0 : sal_Int16 UnoControlRoadmapModel::GetCurrentItemID( Reference< XPropertySet > xPropertySet )
256 : {
257 0 : Any aAny = xPropertySet->getPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ) );
258 0 : sal_Int16 n_CurrentItemID = 0;
259 0 : aAny >>= n_CurrentItemID;
260 0 : return n_CurrentItemID;
261 : }
262 :
263 :
264 0 : void SAL_CALL UnoControlRoadmapModel::insertByIndex( const sal_Int32 Index, const Any& _Element)
265 : throw (IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException, std::exception )
266 : {
267 0 : if ( ( Index >= ( (sal_Int32)maRoadmapItems.size() + 1 ) ) || (Index < 0))
268 0 : lcl_throwIndexOutOfBoundsException( );
269 0 : Reference< XInterface > xRoadmapItem;
270 0 : _Element >>= xRoadmapItem;
271 0 : MakeRMItemValidation( Index, xRoadmapItem);
272 0 : SetRMItemDefaultProperties( Index, xRoadmapItem );
273 0 : maRoadmapItems.insert( maRoadmapItems.begin() + Index, xRoadmapItem);
274 0 : ContainerEvent aEvent = GetContainerEvent(Index, xRoadmapItem);
275 0 : maContainerListeners.elementInserted( aEvent );
276 0 : Reference< XPropertySet > xPropertySet( (XAggregation*) (::cppu::OWeakAggObject*)this, UNO_QUERY );
277 0 : sal_Int16 n_CurrentItemID = GetCurrentItemID( xPropertySet );
278 0 : if ( Index <= n_CurrentItemID )
279 : {
280 0 : Any aAny;
281 0 : aAny <<= ( sal_Int16 ) ( n_CurrentItemID + 1 );
282 0 : xPropertySet->setPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ), aAny );
283 0 : }
284 0 : }
285 :
286 :
287 :
288 0 : void SAL_CALL UnoControlRoadmapModel::removeByIndex( sal_Int32 Index)
289 : throw (IndexOutOfBoundsException, WrappedTargetException, RuntimeException, std::exception )
290 : {
291 0 : if (( Index > (sal_Int32)maRoadmapItems.size()) || (Index < 0))
292 0 : lcl_throwIndexOutOfBoundsException( );
293 0 : Reference< XInterface > xRoadmapItem;
294 0 : maRoadmapItems.erase( maRoadmapItems.begin() + Index );
295 0 : ContainerEvent aEvent = GetContainerEvent(Index, xRoadmapItem);
296 0 : maContainerListeners.elementRemoved( aEvent );
297 0 : Reference< XPropertySet > xPropertySet( (XAggregation*) (::cppu::OWeakAggObject*)this, UNO_QUERY );
298 0 : sal_Int16 n_CurrentItemID = GetCurrentItemID( xPropertySet );
299 0 : Any aAny;
300 0 : if ( Index <= n_CurrentItemID )
301 : {
302 0 : if ( n_CurrentItemID >= (sal_Int32)maRoadmapItems.size() )
303 : {
304 : n_CurrentItemID = sal::static_int_cast< sal_Int16 >(
305 0 : maRoadmapItems.size()-1);
306 0 : if ( n_CurrentItemID < 0 )
307 0 : return;
308 0 : aAny <<= n_CurrentItemID;
309 : }
310 0 : else if (Index == n_CurrentItemID)
311 0 : aAny <<= ( sal_Int16 ) -1;
312 0 : else if( Index < n_CurrentItemID)
313 0 : aAny <<= ( sal_Int16 ) ( n_CurrentItemID - 1 );
314 0 : xPropertySet->setPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ), aAny );
315 0 : }
316 : }
317 :
318 :
319 0 : void SAL_CALL UnoControlRoadmapModel::replaceByIndex( const sal_Int32 Index, const Any& _Element)
320 : throw (IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException, std::exception )
321 : {
322 0 : Reference< XInterface > xRoadmapItem;
323 0 : _Element >>= xRoadmapItem;
324 0 : MakeRMItemValidation( Index, xRoadmapItem);
325 0 : SetRMItemDefaultProperties( Index, xRoadmapItem );
326 0 : maRoadmapItems.erase( maRoadmapItems.begin() + Index );
327 0 : maRoadmapItems.insert( maRoadmapItems.begin() + Index, xRoadmapItem); //push_back( xRoadmapItem );
328 0 : ContainerEvent aEvent = GetContainerEvent(Index, xRoadmapItem);
329 0 : maContainerListeners.elementReplaced( aEvent );
330 0 : }
331 :
332 :
333 0 : Type SAL_CALL UnoControlRoadmapModel::getElementType() throw(RuntimeException, std::exception)
334 : {
335 0 : Type aType = getCppuType( ( Reference< XPropertySet>* ) NULL );
336 0 : return aType;
337 : }
338 :
339 :
340 0 : sal_Bool SAL_CALL UnoControlRoadmapModel::hasElements() throw(RuntimeException, std::exception)
341 : {
342 0 : return !maRoadmapItems.empty();
343 : }
344 :
345 :
346 0 : void SAL_CALL UnoControlRoadmapModel::addContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XContainerListener >& xListener ) throw (::com::sun::star::uno::RuntimeException, std::exception)
347 : {
348 0 : maContainerListeners.addInterface( xListener );
349 0 : }
350 :
351 0 : void SAL_CALL UnoControlRoadmapModel::removeContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::container::XContainerListener >& xListener ) throw (::com::sun::star::uno::RuntimeException, std::exception)
352 : {
353 0 : maContainerListeners.removeInterface( xListener );
354 0 : }
355 :
356 :
357 : // = UnoRoadmapControl
358 :
359 :
360 0 : UnoRoadmapControl::UnoRoadmapControl()
361 : :UnoControlRoadmap_Base()
362 0 : ,maItemListeners( *this )
363 : {
364 0 : }
365 :
366 0 : IMPLEMENT_FORWARD_XTYPEPROVIDER2( UnoRoadmapControl, UnoControlRoadmap_Base, UnoControlRoadmap_IBase )
367 0 : IMPLEMENT_FORWARD_XINTERFACE2( UnoRoadmapControl, UnoControlRoadmap_Base, UnoControlRoadmap_IBase )
368 :
369 :
370 0 : sal_Bool SAL_CALL UnoRoadmapControl::setModel(const Reference< XControlModel >& _rModel) throw ( RuntimeException, std::exception )
371 : {
372 :
373 :
374 0 : Reference< XContainer > xC( getModel(), UNO_QUERY );
375 0 : if ( xC.is() )
376 0 : xC->removeContainerListener( this );
377 :
378 0 : bool bReturn = UnoControlBase::setModel( _rModel );
379 :
380 0 : xC = xC.query( getModel());
381 0 : if ( xC.is() )
382 0 : xC->addContainerListener( this );
383 :
384 0 : return bReturn;
385 : }
386 :
387 :
388 :
389 0 : OUString UnoRoadmapControl::GetComponentServiceName()
390 : {
391 0 : return OUString("Roadmap");
392 : }
393 :
394 :
395 :
396 0 : void UnoRoadmapControl::dispose() throw(RuntimeException, std::exception)
397 : {
398 0 : EventObject aEvt;
399 0 : aEvt.Source = (::cppu::OWeakObject*)this;
400 0 : maItemListeners.disposeAndClear( aEvt );
401 0 : UnoControl::dispose();
402 0 : }
403 :
404 :
405 :
406 0 : void UnoRoadmapControl::elementInserted( const ContainerEvent& rEvent )throw(RuntimeException, std::exception)
407 : {
408 0 : Reference< XInterface > xRoadmapItem;
409 0 : rEvent.Element >>= xRoadmapItem;
410 0 : Reference< XPropertySet > xRoadmapPropertySet( xRoadmapItem, UNO_QUERY );
411 0 : if ( xRoadmapPropertySet.is() )
412 0 : xRoadmapPropertySet->addPropertyChangeListener( OUString(), this );
413 :
414 0 : Reference< XContainerListener > xPeer(getPeer(), UNO_QUERY);
415 0 : if ( xPeer.is() )
416 : {
417 0 : xPeer->elementInserted( rEvent );
418 0 : Reference < XPropertySet > xPropertySet( xPeer, UNO_QUERY );
419 0 : if ( xPropertySet.is() )
420 0 : xPropertySet->addPropertyChangeListener( OUString(), this );
421 0 : }
422 0 : }
423 :
424 :
425 0 : void UnoRoadmapControl::elementRemoved( const ContainerEvent& rEvent )throw(RuntimeException, std::exception)
426 : {
427 0 : Reference< XContainerListener > xPeer(getPeer(), UNO_QUERY);
428 0 : if ( xPeer.is() )
429 0 : xPeer->elementRemoved( rEvent );
430 0 : Reference< XInterface > xRoadmapItem;
431 0 : rEvent.Element >>= xRoadmapItem;
432 0 : Reference< XPropertySet > xPropertySet( xRoadmapItem, UNO_QUERY );
433 0 : if ( xPropertySet.is() )
434 0 : xPropertySet->removePropertyChangeListener( OUString(), this );
435 0 : }
436 :
437 :
438 0 : void UnoRoadmapControl::elementReplaced( const ContainerEvent& rEvent )throw(RuntimeException, std::exception)
439 : {
440 0 : Reference< XContainerListener > xPeer(getPeer(), UNO_QUERY);
441 0 : if ( xPeer.is() )
442 0 : xPeer->elementReplaced( rEvent );
443 0 : }
444 :
445 :
446 0 : void SAL_CALL UnoRoadmapControl::itemStateChanged( const ItemEvent& rEvent ) throw (RuntimeException, std::exception)
447 : {
448 0 : sal_Int16 CurItemIndex = sal::static_int_cast< sal_Int16 >(rEvent.ItemId);
449 0 : Any aAny;
450 0 : aAny <<= CurItemIndex;
451 0 : Reference< XControlModel > xModel( getModel( ), UNO_QUERY );
452 0 : Reference< XPropertySet > xPropertySet( xModel, UNO_QUERY );
453 0 : xPropertySet->setPropertyValue( GetPropertyName( BASEPROPERTY_CURRENTITEMID ), aAny );
454 0 : if ( maItemListeners.getLength() )
455 0 : maItemListeners.itemStateChanged( rEvent );
456 0 : }
457 :
458 :
459 0 : void SAL_CALL UnoRoadmapControl::addItemListener( const Reference< XItemListener >& l ) throw (RuntimeException, std::exception)
460 : {
461 0 : maItemListeners.addInterface( l );
462 0 : if( getPeer().is() && maItemListeners.getLength() == 1 )
463 : {
464 0 : Reference < XItemEventBroadcaster > xRoadmap( getPeer(), UNO_QUERY );
465 0 : xRoadmap->addItemListener( this );
466 : }
467 0 : }
468 :
469 :
470 0 : void SAL_CALL UnoRoadmapControl::removeItemListener( const Reference< XItemListener >& l ) throw (RuntimeException, std::exception)
471 : {
472 0 : if( getPeer().is() && maItemListeners.getLength() == 1 )
473 : {
474 0 : Reference < XItemEventBroadcaster > xRoadmap( getPeer(), UNO_QUERY );
475 0 : xRoadmap->removeItemListener( this );
476 : }
477 :
478 0 : maItemListeners.removeInterface( l );
479 0 : }
480 :
481 :
482 0 : void SAL_CALL UnoRoadmapControl::propertyChange( const PropertyChangeEvent& evt ) throw (RuntimeException, std::exception)
483 : {
484 0 : Reference< XPropertyChangeListener > xPeer(getPeer(), UNO_QUERY);
485 0 : if ( xPeer.is() )
486 0 : xPeer->propertyChange( evt );
487 0 : }
488 :
489 : }
490 :
491 : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
492 0 : stardiv_Toolkit_UnoControlRoadmapModel_get_implementation(
493 : css::uno::XComponentContext *context,
494 : css::uno::Sequence<css::uno::Any> const &)
495 : {
496 0 : return cppu::acquire(new toolkit::UnoControlRoadmapModel(context));
497 : }
498 :
499 : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
500 0 : stardiv_Toolkit_UnoRoadmapControl_get_implementation(
501 : css::uno::XComponentContext *,
502 : css::uno::Sequence<css::uno::Any> const &)
503 : {
504 0 : return cppu::acquire(new toolkit::UnoRoadmapControl());
505 : }
506 :
507 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|