fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / writerfilter / source / dmapper / PropertyMap.hxx
blobfb4e4ad53abf36f56e13809d991a2134edcc96ae
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
19 #ifndef INCLUDED_DMAPPER_PROPERTYMAP_HXX
20 #define INCLUDED_DMAPPER_PROPERTYMAP_HXX
22 #include <rtl/ustring.hxx>
23 #include <com/sun/star/uno/Sequence.hxx>
24 #include <com/sun/star/beans/PropertyValue.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/uno/Any.h>
27 #include "PropertyIds.hxx"
28 #include <boost/shared_ptr.hpp>
29 #include <map>
30 #include <vector>
32 #include <resourcemodel/TagLogger.hxx>
34 namespace com{namespace sun{namespace star{
35 namespace beans{
36 struct PropertyValue;
38 namespace container{
39 class XNameContainer;
41 namespace lang{
42 class XMultiServiceFactory;
44 namespace text{
45 class XTextRange;
46 class XTextColumns;
47 class XFootnote;
49 namespace table{
50 struct BorderLine2;
52 }}}
54 namespace writerfilter {
55 namespace dmapper{
56 class DomainMapper_Impl;
58 enum BorderPosition
60 BORDER_LEFT,
61 BORDER_RIGHT,
62 BORDER_TOP,
63 BORDER_BOTTOM
67 struct PropertyDefinition
69 PropertyIds eId;
70 bool bIsTextProperty;
72 PropertyDefinition( PropertyIds _eId, bool _bIsTextProperty ) :
73 eId( _eId ),
74 bIsTextProperty( _bIsTextProperty ){}
76 bool operator== (const PropertyDefinition& rDef) const
77 { return rDef.eId == eId; }
78 bool operator< (const PropertyDefinition& rDef) const
79 { return eId < rDef.eId; }
81 typedef std::map < PropertyDefinition, ::com::sun::star::uno::Any > _PropertyMap;
82 class PropertyMap : public _PropertyMap
84 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > m_aValues;
85 //marks context as footnote context - ::text( ) events contain either the footnote character or can be ignored
86 //depending on sprmCSymbol
87 sal_Unicode m_cFootnoteSymbol; // 0 == invalid
88 sal_Int32 m_nFootnoteFontId; // negative values are invalid ids
89 OUString m_sFootnoteFontName;
90 ::com::sun::star::uno::Reference< ::com::sun::star::text::XFootnote > m_xFootnote;
92 protected:
93 void Invalidate()
95 if(m_aValues.getLength())
96 m_aValues.realloc( 0 );
99 public:
100 PropertyMap();
101 virtual ~PropertyMap();
103 ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > GetPropertyValues();
104 bool hasEmptyPropertyValues() const {return !m_aValues.getLength();}
105 /** Add property, usually overwrites already available attributes. It shouldn't overwrite in case of default attributes
107 void Insert( PropertyIds eId, bool bIsTextProperty, const ::com::sun::star::uno::Any& rAny, bool bOverwrite = true );
108 void InsertProps(const boost::shared_ptr<PropertyMap> pMap);
110 const ::com::sun::star::uno::Reference< ::com::sun::star::text::XFootnote>& GetFootnote() const;
111 void SetFootnote( ::com::sun::star::uno::Reference< ::com::sun::star::text::XFootnote> xF ) { m_xFootnote = xF; }
113 sal_Unicode GetFootnoteSymbol() const { return m_cFootnoteSymbol;}
114 void SetFootnoteSymbol(sal_Unicode cSet) { m_cFootnoteSymbol = cSet;}
116 sal_Int32 GetFootnoteFontId() const { return m_nFootnoteFontId;}
117 void SetFootnoteFontId(sal_Int32 nSet) { m_nFootnoteFontId = nSet;}
119 const OUString& GetFootnoteFontName() const { return m_sFootnoteFontName;}
120 void SetFootnoteFontName( const OUString& rSet ) { m_sFootnoteFontName = rSet;}
122 virtual void insertTableProperties( const PropertyMap* );
124 #if OSL_DEBUG_LEVEL > 1
125 virtual void dumpXml( const TagLogger::Pointer_t pLogger ) const;
126 #endif
129 typedef boost::shared_ptr<PropertyMap> PropertyMapPtr;
133 class SectionPropertyMap : public PropertyMap
135 //--> debug
136 sal_Int32 nSectionNumber;
137 //<-- debug
138 //'temporarily' the section page settings are imported as page styles
139 // empty strings mark page settings as not yet imported
141 bool m_bIsFirstSection;
142 ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > m_xStartingRange;
144 OUString m_sFirstPageStyleName;
145 OUString m_sFollowPageStyleName;
146 ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > m_aFirstPageStyle;
147 ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > m_aFollowPageStyle;
149 ::com::sun::star::table::BorderLine2* m_pBorderLines[4];
150 sal_Int32 m_nBorderDistances[4];
151 sal_Int32 m_nBorderParams;
152 bool m_bBorderShadows[4];
154 bool m_bTitlePage;
155 sal_Int16 m_nColumnCount;
156 sal_Int32 m_nColumnDistance;
157 ::std::vector< sal_Int32 > m_aColWidth;
158 ::std::vector< sal_Int32 > m_aColDistance;
160 bool m_bSeparatorLineIsOn;
161 bool m_bEvenlySpaced;
162 bool m_bIsLandscape;
164 bool m_bPageNoRestart;
165 sal_Int32 m_nPageNumber;
166 sal_Int32 m_nBreakType;
167 sal_Int32 m_nPaperBin;
168 sal_Int32 m_nFirstPaperBin;
170 sal_Int32 m_nLeftMargin;
171 sal_Int32 m_nRightMargin;
172 sal_Int32 m_nTopMargin;
173 sal_Int32 m_nBottomMargin;
174 sal_Int32 m_nHeaderTop;
175 sal_Int32 m_nHeaderBottom;
177 sal_Int32 m_nDzaGutter;
178 bool m_bGutterRTL;
179 bool m_bSFBiDi;
181 sal_Int32 m_nGridType;
182 sal_Int32 m_nGridLinePitch;
183 sal_Int32 m_nDxtCharSpace;
185 //line numbering
186 sal_Int32 m_nLnnMod;
187 sal_Int32 m_nLnc;
188 sal_Int32 m_ndxaLnn;
189 sal_Int32 m_nLnnMin;
191 void _ApplyProperties( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xStyle );
192 ::com::sun::star::uno::Reference< com::sun::star::text::XTextColumns > ApplyColumnProperties(
193 ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xFollowPageStyle );
194 void CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl );
195 void PrepareHeaderFooterProperties( bool bFirstPage );
196 bool HasHeader( bool bFirstPage ) const;
197 bool HasFooter( bool bFirstPage ) const;
199 void SetBorderDistance( ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xStyle,
200 PropertyIds eMarginId, PropertyIds eDistId, sal_Int32 nDistance, sal_Int32 nOffsetFrom, sal_uInt32 nLineWidth );
202 public:
203 explicit SectionPropertyMap(bool bIsFirstSection);
204 ~SectionPropertyMap();
206 enum PageType
208 PAGE_FIRST,
209 PAGE_LEFT,
210 PAGE_RIGHT
213 void SetStart( const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange >& xRange )
215 m_xStartingRange = xRange;
218 ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > GetPageStyle(
219 const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& xStyles,
220 const ::com::sun::star::uno::Reference < ::com::sun::star::lang::XMultiServiceFactory >& xTextFactory,
221 bool bFirst );
223 void SetBorder( BorderPosition ePos, sal_Int32 nLineDistance, const ::com::sun::star::table::BorderLine2& rBorderLine, bool bShadow );
224 void SetBorderParams( sal_Int32 nSet ) { m_nBorderParams = nSet; }
226 void SetColumnCount( sal_Int16 nCount ) { m_nColumnCount = nCount; }
227 void SetColumnDistance( sal_Int32 nDist ) { m_nColumnDistance = nDist; }
228 void AppendColumnWidth( sal_Int32 nWidth ) { m_aColWidth.push_back( nWidth ); }
229 void AppendColumnSpacing( sal_Int32 nDist ) {m_aColDistance.push_back( nDist ); }
231 void SetTitlePage( bool bSet ) { m_bTitlePage = bSet; }
232 void SetSeparatorLine( bool bSet ) { m_bSeparatorLineIsOn = bSet; }
233 void SetEvenlySpaced( bool bSet ) { m_bEvenlySpaced = bSet; }
234 void SetLandscape( bool bSet ) { m_bIsLandscape = bSet; }
235 void SetPageNoRestart( bool bSet ) { m_bPageNoRestart = bSet; }
236 void SetPageNumber( sal_Int32 nSet ) { m_nPageNumber = nSet; }
237 void SetBreakType( sal_Int32 nSet ) { m_nBreakType = nSet; }
238 sal_Int32 GetBreakType( ) { return m_nBreakType; }
239 void SetPaperBin( sal_Int32 nSet );
240 void SetFirstPaperBin( sal_Int32 nSet );
242 void SetLeftMargin( sal_Int32 nSet ) { m_nLeftMargin = nSet; }
243 sal_Int32 GetLeftMargin() { return m_nLeftMargin; }
244 void SetRightMargin( sal_Int32 nSet ) { m_nRightMargin = nSet; }
245 sal_Int32 GetRightMargin() { return m_nRightMargin; }
246 void SetTopMargin( sal_Int32 nSet ) { m_nTopMargin = nSet; }
247 void SetBottomMargin( sal_Int32 nSet ) { m_nBottomMargin = nSet; }
248 void SetHeaderTop( sal_Int32 nSet ) { m_nHeaderTop = nSet; }
249 void SetHeaderBottom( sal_Int32 nSet ) { m_nHeaderBottom = nSet; }
250 sal_Int32 GetPageWidth();
252 void SetGutterRTL( bool bSet ) { m_bGutterRTL = bSet;}
253 void SetDzaGutter( sal_Int32 nSet ) {m_nDzaGutter = nSet; }
254 void SetSFBiDi( bool bSet ) { m_bSFBiDi = bSet;}
256 void SetGridType(sal_Int32 nSet) { m_nGridType = nSet; }
257 void SetGridLinePitch( sal_Int32 nSet ) { m_nGridLinePitch = nSet; }
258 void SetDxtCharSpace( sal_Int32 nSet ) { m_nDxtCharSpace = nSet; }
260 void SetLnnMod( sal_Int32 nValue ) { m_nLnnMod = nValue; }
261 void SetLnc( sal_Int32 nValue ) { m_nLnc = nValue; }
262 void SetdxaLnn( sal_Int32 nValue ) { m_ndxaLnn = nValue; }
263 void SetLnnMin( sal_Int32 nValue ) { m_nLnnMin = nValue; }
265 //determine which style gets the borders
266 void ApplyBorderToPageStyles(
267 const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >& xStyles,
268 const ::com::sun::star::uno::Reference < ::com::sun::star::lang::XMultiServiceFactory >& xTextFactory,
269 sal_Int32 nValue );
271 void CloseSectionGroup( DomainMapper_Impl& rDM_Impl );
272 /// Handling of margins, header and footer for any kind of sections breaks.
273 void HandleMarginsHeaderFooter(DomainMapper_Impl& rDM_Impl);
275 typedef boost::shared_ptr<SectionPropertyMap> SectionPropertyMapPtr;
279 class ParagraphProperties
281 bool m_bFrameMode;
282 sal_Int32 m_nDropCap; //drop, margin ST_DropCap
283 sal_Int32 m_nLines; //number of lines of the drop cap
284 sal_Int32 m_w; //width
285 sal_Int32 m_h; //height
286 sal_Int32 m_nWrap; // from ST_Wrap around, auto, none, notBeside, through, tight
287 sal_Int32 m_hAnchor; // page, from ST_HAnchor margin, page, text
288 sal_Int32 m_vAnchor; // around from ST_VAnchor margin, page, text
289 sal_Int32 m_x; //x-position
290 bool m_bxValid;
291 sal_Int32 m_y; //y-position
292 bool m_byValid;
293 sal_Int32 m_hSpace; //frame padding h
294 sal_Int32 m_vSpace; //frame padding v
295 sal_Int32 m_hRule; // from ST_HeightRule exact, atLeast, auto
296 sal_Int32 m_xAlign; // from ST_XAlign center, inside, left, outside, right
297 sal_Int32 m_yAlign; // from ST_YAlign bottom, center, inline, inside, outside, top
298 bool m_bAnchorLock;
300 sal_Int8 m_nDropCapLength; //number of characters
302 OUString m_sParaStyleName;
304 ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > m_xStartingRange; //start of a frame
305 ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > m_xEndingRange; //end of the frame
307 public:
308 ParagraphProperties();
309 ParagraphProperties(const ParagraphProperties&);
310 ~ParagraphProperties();
312 int operator==(const ParagraphProperties&); //does not compare the starting/ending range, m_sParaStyleName and m_nDropCapLength
314 void SetFrameMode( bool set = true ) { m_bFrameMode = set; }
315 bool IsFrameMode()const { return m_bFrameMode; }
317 void SetDropCap( sal_Int32 nSet ) { m_nDropCap = nSet; }
318 sal_Int32 GetDropCap()const { return m_nDropCap; }
320 void SetLines( sal_Int32 nSet ) { m_nLines = nSet; }
321 sal_Int32 GetLines() const { return m_nLines; }
323 void Setw( sal_Int32 nSet ) { m_w = nSet; }
324 sal_Int32 Getw() const { return m_w; }
326 void Seth( sal_Int32 nSet ) { m_h = nSet; }
327 sal_Int32 Geth() const { return m_h; }
329 void SetWrap( sal_Int32 nSet ) { m_nWrap = nSet; }
330 sal_Int32 GetWrap() const { return m_nWrap; }
332 void SethAnchor( sal_Int32 nSet ) { m_hAnchor = nSet; }
333 sal_Int32 GethAnchor() const { return m_hAnchor;}
335 void SetvAnchor( sal_Int32 nSet ) { m_vAnchor = nSet; }
336 sal_Int32 GetvAnchor() const { return m_vAnchor; }
338 void Setx( sal_Int32 nSet ) { m_x = nSet; m_bxValid = true;}
339 sal_Int32 Getx() const { return m_x; }
340 bool IsxValid() const {return m_bxValid;}
342 void Sety( sal_Int32 nSet ) { m_y = nSet; m_byValid = true;}
343 sal_Int32 Gety()const { return m_y; }
344 bool IsyValid() const {return m_byValid;}
346 void SethSpace( sal_Int32 nSet ) { m_hSpace = nSet; }
347 sal_Int32 GethSpace()const { return m_hSpace; }
349 void SetvSpace( sal_Int32 nSet ) { m_vSpace = nSet; }
350 sal_Int32 GetvSpace()const { return m_vSpace; }
352 void SethRule( sal_Int32 nSet ) { m_hRule = nSet; }
353 sal_Int32 GethRule() const { return m_hRule; }
355 void SetxAlign( sal_Int32 nSet ) { m_xAlign = nSet; }
356 sal_Int32 GetxAlign()const { return m_xAlign; }
358 void SetyAlign( sal_Int32 nSet ) { m_yAlign = nSet; }
359 sal_Int32 GetyAlign()const { return m_yAlign; }
361 void SetAnchorLock( bool bSet ) {m_bAnchorLock = bSet; }
363 sal_Int8 GetDropCapLength() const { return m_nDropCapLength;}
364 void SetDropCapLength(sal_Int8 nSet) { m_nDropCapLength = nSet;}
366 ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > GetStartingRange() const { return m_xStartingRange; }
367 void SetStartingRange( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > xSet ) { m_xStartingRange = xSet; }
369 ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > GetEndingRange() const { return m_xEndingRange; }
370 void SetEndingRange( ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > xSet ) { m_xEndingRange = xSet; }
372 void SetParaStyleName( const OUString& rSet ) { m_sParaStyleName = rSet;}
373 const OUString& GetParaStyleName() const { return m_sParaStyleName;}
375 void ResetFrameProperties();
377 typedef boost::shared_ptr<ParagraphProperties> ParagraphPropertiesPtr;
378 /*-------------------------------------------------------------------------
379 property map of a stylesheet
380 -----------------------------------------------------------------------*/
382 #define WW_OUTLINE_MAX sal_Int16( 9 )
383 #define WW_OUTLINE_MIN sal_Int16( 0 )
385 class StyleSheetPropertyMap : public PropertyMap, public ParagraphProperties
388 //special table style properties
389 sal_Int32 mnCT_Spacing_line;
390 sal_Int32 mnCT_Spacing_lineRule;
392 OUString msCT_Fonts_ascii;
393 bool mbCT_TrPrBase_tblHeader;
394 sal_Int32 mnCT_TrPrBase_jc;
395 sal_Int32 mnCT_TcPrBase_vAlign;
397 sal_Int32 mnCT_TblWidth_w;
398 sal_Int32 mnCT_TblWidth_type;
400 bool mbCT_Spacing_lineSet;
401 bool mbCT_Spacing_lineRuleSet;
403 bool mbCT_TrPrBase_tblHeaderSet;
404 bool mbCT_TrPrBase_jcSet;
405 bool mbCT_TcPrBase_vAlignSet;
407 bool mbCT_TblWidth_wSet;
408 bool mbCT_TblWidth_typeSet;
410 sal_Int32 mnListId;
411 sal_Int16 mnListLevel;
413 sal_Int16 mnOutlineLevel;
415 sal_Int32 mnNumId;
416 public:
417 explicit StyleSheetPropertyMap();
418 ~StyleSheetPropertyMap();
420 void SetCT_Spacing_line( sal_Int32 nSet )
421 {mnCT_Spacing_line = nSet; mbCT_Spacing_lineSet = true; }
422 void SetCT_Spacing_lineRule( sal_Int32 nSet )
423 {mnCT_Spacing_lineRule = nSet; mbCT_Spacing_lineRuleSet = true; }
425 void SetCT_Fonts_ascii( const OUString& rSet )
426 {msCT_Fonts_ascii = rSet; }
427 void SetCT_TrPrBase_tblHeader( bool bSet )
428 {mbCT_TrPrBase_tblHeader = bSet; mbCT_TrPrBase_tblHeaderSet = true; }
429 void SetCT_TrPrBase_jc( sal_Int32 nSet )
430 {mnCT_TrPrBase_jc = nSet; mbCT_TrPrBase_jcSet = true; }
431 void SetCT_TcPrBase_vAlign( sal_Int32 nSet )
432 {mnCT_TcPrBase_vAlign = nSet; mbCT_TcPrBase_vAlignSet = true; }
434 void SetCT_TblWidth_w( sal_Int32 nSet )
435 { mnCT_TblWidth_w = nSet; mbCT_TblWidth_wSet = true; }
436 void SetCT_TblWidth_type( sal_Int32 nSet )
437 {mnCT_TblWidth_type = nSet; mbCT_TblWidth_typeSet = true; }
439 bool GetCT_Spacing_line( sal_Int32& rToFill) const
441 if( mbCT_Spacing_lineSet )
442 rToFill = mnCT_Spacing_line;
443 return mbCT_Spacing_lineSet;
445 bool GetCT_Spacing_lineRule(sal_Int32& rToFill) const
447 if( mbCT_Spacing_lineRuleSet )
448 rToFill = mnCT_Spacing_lineRule;
449 return mbCT_Spacing_lineRuleSet;
452 bool GetCT_Fonts_ascii(OUString& rToFill) const
454 if( msCT_Fonts_ascii.getLength() > 0 )
455 rToFill = msCT_Fonts_ascii;
456 return msCT_Fonts_ascii.getLength() > 0;
458 bool GetCT_TrPrBase_tblHeader(bool& rToFill) const
460 if( mbCT_TrPrBase_tblHeaderSet )
461 rToFill = mbCT_TrPrBase_tblHeader;
462 return mbCT_TrPrBase_tblHeaderSet;
464 bool GetCT_TrPrBase_jc( sal_Int32& rToFill)const
466 if( mbCT_TrPrBase_jcSet )
467 rToFill = mnCT_TrPrBase_jc;
468 return mbCT_TrPrBase_jcSet;
470 bool GetCT_TcPrBase_vAlign( sal_Int32& rToFill)const
472 if( mbCT_TcPrBase_vAlignSet )
473 rToFill = mnCT_TcPrBase_vAlign;
474 return mbCT_TcPrBase_vAlignSet;
476 sal_Int32 GetListId() const { return mnListId; }
477 void SetListId(sal_Int32 nId) { mnListId = nId; }
479 sal_Int16 GetListLevel() const { return mnListLevel; }
480 void SetListLevel(sal_Int16 nLevel) { mnListLevel = nLevel; }
482 sal_Int16 GetOutlineLevel() const { return mnOutlineLevel; }
483 void SetOutlineLevel(sal_Int16 nLevel)
485 if ( nLevel < WW_OUTLINE_MAX )
486 mnOutlineLevel = nLevel;
489 sal_Int32 GetNumId() const { return mnNumId; }
490 void SetNumId(sal_Int32 nId) { mnNumId = nId; }
494 class ParagraphPropertyMap : public PropertyMap, public ParagraphProperties
496 public:
497 explicit ParagraphPropertyMap();
498 ~ParagraphPropertyMap();
503 class TablePropertyMap : public PropertyMap
505 public:
506 enum TablePropertyMapTarget
508 TablePropertyMapTarget_START,
509 CELL_MAR_LEFT = TablePropertyMapTarget_START,
510 CELL_MAR_RIGHT,
511 CELL_MAR_TOP,
512 CELL_MAR_BOTTOM,
513 TABLE_WIDTH,
514 TABLE_WIDTH_TYPE,
515 GAP_HALF,
516 LEFT_MARGIN,
517 HORI_ORIENT,
518 TablePropertyMapTarget_MAX
520 private:
521 struct ValidValue
523 sal_Int32 nValue;
524 bool bValid;
525 ValidValue() :
526 nValue( 0 ),
527 bValid( false ){}
529 ValidValue m_aValidValues[TablePropertyMapTarget_MAX];
531 public:
532 explicit TablePropertyMap();
533 ~TablePropertyMap();
535 bool getValue( TablePropertyMapTarget eWhich, sal_Int32& nFill );
536 void setValue( TablePropertyMapTarget eWhich, sal_Int32 nSet );
538 virtual void insertTableProperties( const PropertyMap* );
540 typedef boost::shared_ptr<TablePropertyMap> TablePropertyMapPtr;
541 } //namespace dmapper
542 } //namespace writerfilter
543 #endif
545 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */