update credits
[LibreOffice.git] / sw / inc / viewsh.hxx
blob72d7c4839c0cc5d74e8d370bb748582aa2fa9df7
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 SW_VIEWSH_HXX
20 #define SW_VIEWSH_HXX
22 #include <com/sun/star/embed/XClassifiedObject.hpp>
23 #include <com/sun/star/embed/XEmbeddedObject.hpp>
24 #include <tools/rtti.hxx>
25 #include "swdllapi.h"
26 #include <swtypes.hxx>
27 #include <ring.hxx>
28 #include <swrect.hxx>
29 #include <boost/shared_ptr.hpp> // swmod 080115
30 #include <stack>
31 #include <vcl/mapmod.hxx>
32 #include <vcl/print.hxx>
34 namespace com { namespace sun { namespace star { namespace accessibility {
35 class XAccessible; } } } }
37 class SfxObjectShellRef;
38 class SwDoc;
39 class IDocumentSettingAccess;
40 class IDocumentDeviceAccess;
41 class IDocumentMarkAccess;
42 class IDocumentDrawModelAccess;
43 class IDocumentRedlineAccess;
44 class IDocumentLayoutAccess;
45 class IDocumentFieldsAccess;
46 class IDocumentContentOperations;
47 class IDocumentStylePoolAccess;
48 class IDocumentStatistics;
49 class IDocumentUndoRedo;
50 class IDocumentListItems;
51 class IDocumentOutlineNodes;
52 class SfxPrinter;
53 class SfxProgress;
54 class SwRootFrm;
55 class SwNodes;
56 class SdrView;
57 class SfxItemPool;
58 class SfxViewShell;
59 class SwViewOption;
60 class SwViewImp;
61 class SwPrintData;
62 class SwPagePreViewPrtData;
63 class Window;
64 class OutputDevice;
65 class SwLayIdle;
66 struct ShellResource;
67 class SwRegionRects;
68 class SwFrm;
69 class SvtAccessibilityOptions;
70 class SwPagePreviewLayout;
71 class SwTxtFrm;
72 class BitmapEx;
74 struct SwAccessibilityOptions;
75 class Region;
76 class SwPostItMgr;
77 class SdrPaintWindow;
78 class SwAccessibleMap;
80 namespace vcl
82 class OldStylePrintAdaptor;
85 enum FrameControlType
87 PageBreak,
88 Header,
89 Footer
92 // Define for flags needed in ctor or layers below.
93 // Currently the PreView flag is needed for DrawPage.
94 #define VSHELLFLAG_ISPREVIEW ((long)0x1)
95 #define VSHELLFLAG_SHARELAYOUT ((long)0x2)//swmod 080125 flag
96 typedef boost::shared_ptr<SwRootFrm> SwRootFrmPtr;
98 class SW_DLLPUBLIC ViewShell : public Ring
100 friend void SetOutDev( ViewShell *pSh, OutputDevice *pOut );
101 friend void SetOutDevAndWin( ViewShell *pSh, OutputDevice *pOut,
102 Window *pWin, sal_uInt16 nZoom );
104 friend class SwViewImp;
105 friend class SwLayIdle;
107 // For setting visible area for page preview paint.
108 friend class SwPagePreviewLayout;
111 // Set SwVisArea in order to enable clean formatting before printing.
112 friend void SetSwVisArea( ViewShell *pSh, const SwRect &, sal_Bool bPDFExport = sal_False );
114 static BitmapEx* mpReplaceBmp; ///< replaced display of still loaded images
115 static BitmapEx* mpErrorBmp; ///< error display of missed images
117 static sal_Bool mbLstAct; // sal_True if EndAction of last Shell
118 // i.e. if the EndActions of the other
119 // Shells on the document are through.
121 Point maPrtOffst; // Ofst for Printer,
122 // non-printable margin.
123 Size maBrowseBorder; // Border for frame documents.
124 SwRect maInvalidRect;
126 SfxViewShell *mpSfxViewShell;
127 SwViewImp *mpImp; // Core-internals of ViewShell.
128 // The pointer is never 0.
130 Window *mpWin; ///< = 0 during printing or pdf export
131 OutputDevice *mpOut; ///< Window, Printer, VirtDev, ...
132 OutputDevice* mpTmpRef; // Temporariy reference device. Is used
133 // during (printer depending) prospect
134 // and page preview printing
135 // (because a scaling has to be set at
136 // the original printer)
138 SwViewOption *mpOpt;
139 SwAccessibilityOptions* mpAccOptions;
142 sal_Bool mbDocSizeChgd :1; // For DocChgNotify(): Announce new DocSize
143 // at EndAction to DocMDI.
144 sal_Bool mbPaintWorks :1; // Normal Painting if sal_True,
145 // remember Paint if sal_False.
146 sal_Bool mbPaintInProgress :1; // Block any double paint.
147 sal_Bool mbViewLocked :1; // Lock visible range;
148 // in this case MakeVisible is ineffectual.
149 sal_Bool mbInEndAction :1; // Avoid problems, cf. viewsh.cxx.
150 sal_Bool mbPreView :1; // If sal_True it is a PreView-ViewShell.
151 sal_Bool mbFrameView :1; // If sal_True it is a (HTML-)Frame.
152 sal_Bool mbEnableSmooth :1; // Disable SmoothScroll, e.g. for drag
153 // of scrollbars.
154 sal_Bool mbEndActionByVirDev:1; // Paints from EndAction always via virtual device
155 // (e.g. when browsing).
156 bool mbShowHeaderSeparator:1; ///< Flag to say that we are showing the header control
157 bool mbShowFooterSeparator:1; ///< Flag to say that we are showing the footer control
158 bool mbHeaderFooterEdit:1; ///< Flag to say that we are editing header or footer (according to the bShow(Header|Footer)Separator above)
160 // boolean, indicating that class in in constructor.
161 bool mbInConstructor:1;
163 SdrPaintWindow* mpTargetPaintWindow;
164 OutputDevice* mpBufferedOut;
166 SwRootFrmPtr mpLayout;
168 // Initialization; called by the diverse constructors.
169 SW_DLLPRIVATE void Init( const SwViewOption *pNewOpt );
171 inline void ResetInvalidRect();
173 SW_DLLPRIVATE void Reformat(); // Invalidates complete Layout (ApplyViewOption).
175 SW_DLLPRIVATE void PaintDesktop( const SwRect & ); // Collect values for painting of desktop
176 // and calling.
177 // PaintDesktop split. This pars is also used by PreViewPage.
178 SW_DLLPRIVATE void _PaintDesktop( const SwRegionRects &rRegion );
180 SW_DLLPRIVATE sal_Bool CheckInvalidForPaint( const SwRect & ); // Direct Paint or rather
181 // trigger an action.
183 SW_DLLPRIVATE void PrepareForPrint( const SwPrintData &rOptions );
185 SW_DLLPRIVATE void ImplApplyViewOptions( const SwViewOption &rOpt );
187 protected:
188 static ShellResource* mpShellRes; ///< Resources for the Shell.
189 static Window* mpCareWindow; ///< Avoid this window.
191 SwRect maVisArea; ///< The modern version of VisArea.
192 SwDoc *mpDoc; ///< The document; never 0.
194 sal_uInt16 mnStartAction; ///< != 0 if at least one ::com::sun::star::chaos::Action is active.
195 sal_uInt16 mnLockPaint; ///< != 0 if Paint is locked.
197 public:
198 TYPEINFO();
200 SwViewImp *Imp() { return mpImp; }
201 const SwViewImp *Imp() const { return mpImp; }
203 const SwNodes& GetNodes() const;
205 // After change of printer; by Doc.
206 void InitPrt( OutputDevice *pOutDev );
208 // Bracketing of actions belonging together.
209 inline void StartAction();
210 void ImplStartAction();
211 inline void EndAction( const sal_Bool bIdleEnd = sal_False );
212 void ImplEndAction( const sal_Bool bIdleEnd = sal_False );
213 sal_uInt16 ActionCount() const { return mnStartAction; }
214 sal_Bool ActionPend() const { return mnStartAction != 0; }
215 sal_Bool IsInEndAction() const { return mbInEndAction; }
217 void SetEndActionByVirDev( sal_Bool b ) { mbEndActionByVirDev = b; }
218 sal_Bool IsEndActionByVirDev() { return mbEndActionByVirDev; }
220 // The ActionCount for all Shells is temporarily set to zero and then
221 // restored at the RootFrame via UNO.
222 void SetRestoreActions(sal_uInt16 nSet);
223 sal_uInt16 GetRestoreActions() const;
225 inline sal_Bool HasInvalidRect() const { return maInvalidRect.HasArea(); }
226 void ChgHyphenation() { Reformat(); }
227 void ChgNumberDigits();
229 sal_Bool AddPaintRect( const SwRect &rRect );
231 void InvalidateWindows( const SwRect &rRect );
233 //////////////////////////////////////////////////////////////////////////////
234 // #i72754# set of Pre/PostPaints with lock counter and initial target OutDev
235 protected:
236 std::stack<Region> mPrePostPaintRegions; // acts also as a lock counter (empty == not locked)
237 OutputDevice* mpPrePostOutDev;
238 MapMode maPrePostMapMode;
239 public:
240 void PrePaint();
241 void DLPrePaint2(const Region& rRegion);
242 void DLPostPaint2(bool bPaintFormLayer);
243 const MapMode& getPrePostMapMode() const { return maPrePostMapMode; }
244 //////////////////////////////////////////////////////////////////////////////
246 virtual void Paint(const Rectangle &rRect);
247 sal_Bool IsPaintInProgress() const { return mbPaintInProgress; }
248 bool IsDrawingLayerPaintInProgress() const { return !mPrePostPaintRegions.empty(); }
250 // Notification that visible area has been changed.
251 // VisArea is reset, after that scrolling takes place.
252 // The passed rect is situated on pixel borders
253 // in order to avoid pixel errors when scrolling.
254 virtual void VisPortChgd( const SwRect & );
255 sal_Bool SmoothScroll( long lXDiff, long lYDiff, const Rectangle* );//Browser
256 void EnableSmooth( sal_Bool b ) { mbEnableSmooth = b; }
258 const SwRect& VisArea() const { return maVisArea; }
260 // If necessary scroll until passed Rect is situated in visible sector.
261 void MakeVisible( const SwRect & );
263 // At nearest occasion pass new document size to UI.
264 void SizeChgNotify();
265 void UISizeNotify(); // Passing of current size.
267 Point GetPagePos( sal_uInt16 nPageNum ) const;
269 sal_uInt16 GetNumPages(); // Ask count of current pages from layout.
270 sal_Bool IsDummyPage( sal_uInt16 nPageNum ) const; // An empty page?
272 // Invalidate first visible page for all Shells in ring.
273 void SetFirstVisPageInvalid();
275 SwRootFrm *GetLayout() const;// swmod 080116
276 sal_Bool IsNewLayout() const; // Has Layout been loaded or created?
278 Size GetDocSize() const; // Get document size.
280 void CalcLayout(); // Force complete formatting of layout.
282 sal_uInt16 GetPageCount() const;
284 const Size GetPageSize( sal_uInt16 nPageNum, bool bSkipEmptyPages ) const;
286 inline SwDoc *GetDoc() const { return mpDoc; } //Never 0.
288 /** Provides access to the document setting interface
290 const IDocumentSettingAccess* getIDocumentSettingAccess() const;
291 IDocumentSettingAccess* getIDocumentSettingAccess();
293 /** Provides access to the document device interface
295 const IDocumentDeviceAccess* getIDocumentDeviceAccess() const;
296 IDocumentDeviceAccess* getIDocumentDeviceAccess();
298 /** Provides access to the document bookmark interface
300 const IDocumentMarkAccess* getIDocumentMarkAccess() const;
301 IDocumentMarkAccess* getIDocumentMarkAccess();
303 /** Provides access to the document draw model interface
305 const IDocumentDrawModelAccess* getIDocumentDrawModelAccess() const;
306 IDocumentDrawModelAccess* getIDocumentDrawModelAccess();
308 /** Provides access to the document redline interface
310 const IDocumentRedlineAccess* getIDocumentRedlineAccess() const;
311 IDocumentRedlineAccess* getIDocumentRedlineAccess();
313 /** Provides access to the document layout interface
315 const IDocumentLayoutAccess* getIDocumentLayoutAccess() const;
316 IDocumentLayoutAccess* getIDocumentLayoutAccess();
318 /** Provides access to the content operations interface
320 IDocumentContentOperations* getIDocumentContentOperations();
322 /** Provides access to the document style pool interface
324 IDocumentStylePoolAccess* getIDocumentStylePoolAccess();
326 /** Provides access to the document statistics interface
328 const IDocumentStatistics* getIDocumentStatistics() const;
330 /** Provides access to the document undo/redo interface
332 IDocumentUndoRedo const& GetIDocumentUndoRedo() const;
333 IDocumentUndoRedo & GetIDocumentUndoRedo();
335 const IDocumentListItems* getIDocumentListItemsAccess() const;
336 const IDocumentOutlineNodes* getIDocumentOutlineNodesAccess() const;
338 // 1. GetRefDev: Either the printer or the virtual device from the doc
339 // 2. GetWin: Available if we not printing
340 // 3. GetOut: Printer, Window or Virtual device
341 OutputDevice& GetRefDev() const;
342 inline Window* GetWin() const { return mpWin; }
343 inline OutputDevice* GetOut() const { return mpOut; }
345 static inline sal_Bool IsLstEndAction() { return ViewShell::mbLstAct; }
347 // Change of all page descriptors.
348 void ChgAllPageOrientation( sal_uInt16 eOri );
349 void ChgAllPageSize( Size &rSz );
351 // Printing of one page.
352 // bIsPDFExport == true is: do PDF Export (no printing!)
353 sal_Bool PrintOrPDFExport( OutputDevice *pOutDev,
354 SwPrintData const& rPrintData,
355 sal_Int32 nRenderer /* offset in vector of pages to print */ );
357 // Printing of one brochure page.
358 void PrintProspect( OutputDevice *pOutDev, const SwPrintData &rPrintData,
359 sal_Int32 nRenderer /* offset in vector of page pairs for prospect printing */ );
361 // Printing for OLE 2.0.
362 static void PrtOle2( SwDoc *pDoc, const SwViewOption *pOpt, const SwPrintData& rOptions,
363 OutputDevice* pOleOut, const Rectangle& rRect );
365 // Fill temporary doc with selected text for Print or PDF export.
366 SwDoc * FillPrtDoc( SwDoc* pPrtDoc, const SfxPrinter* pPrt );
368 // Called internally for Shell. Formats pages.
369 void CalcPagesForPrint( sal_uInt16 nMax );
371 // All about fields.
372 void UpdateFlds(sal_Bool bCloseDB = sal_False);
373 sal_Bool IsAnyFieldInDoc() const;
374 // Update all charts, for that exists any table.
375 void UpdateAllCharts();
376 sal_Bool HasCharts() const;
378 // DOCUMENT COMPATIBILITY FLAGS START
380 // Add or maximize paragraph spacing?
381 void SetParaSpaceMax( bool bNew );
383 // Add or maximize paragraph spacing?
384 void SetParaSpaceMaxAtPages( bool bNew );
386 // Compatible behaviour of tabs.
387 void SetTabCompat( bool bNew );
389 // Font metric attribute "External Leading" should be considered.
390 void SetAddExtLeading( bool bNew );
392 // Formatting by virtual device or printer.
393 void SetUseVirDev( bool nNew );
395 // Adding paragraph and table spacing at bottom
396 // of table cells.
397 void SetAddParaSpacingToTableCells( bool _bAddParaSpacingToTableCells );
399 // Former formatting of text lines with
400 // proportional line spacing or not.
401 void SetUseFormerLineSpacing( bool _bUseFormerLineSpacing );
403 // Former object positioning.
404 void SetUseFormerObjectPositioning( bool _bUseFormerObjPos );
406 void SetConsiderWrapOnObjPos( bool _bConsiderWrapOnObjPos );
408 void SetUseFormerTextWrapping( bool _bUseFormerTextWrapping );
410 void SetDoNotJustifyLinesWithManualBreak( bool _bDoNotJustifyLinesWithManualBreak );
412 // DOCUMENT COMPATIBILITY FLAGS END
414 // Calls Idle-formatter of Layout.
415 void LayoutIdle();
417 inline const SwViewOption *GetViewOptions() const { return mpOpt; }
418 virtual void ApplyViewOptions( const SwViewOption &rOpt );
419 void SetUIOptions( const SwViewOption &rOpt );
420 virtual void SetReadonlyOption(sal_Bool bSet); // Set readonly-bit of ViewOptions.
421 void SetPDFExportOption(sal_Bool bSet); // Set/reset PDF export mode.
422 void SetPrtFormatOption(sal_Bool bSet); // Set PrtFormat-Bit of ViewOptions.
423 void SetReadonlySelectionOption(sal_Bool bSet); // Change the selection mode in readonly docs.
425 const SwAccessibilityOptions* GetAccessibilityOptions() const { return mpAccOptions;}
427 static void SetShellRes( ShellResource* pRes ) { mpShellRes = pRes; }
428 static ShellResource* GetShellRes();
430 static void SetCareWin( Window* pNew );
431 static Window* GetCareWin(ViewShell& rVSh)
432 { return mpCareWindow ? mpCareWindow : CareChildWin(rVSh); }
433 static Window* CareChildWin(ViewShell& rVSh);
435 inline SfxViewShell *GetSfxViewShell() { return mpSfxViewShell; }
436 inline void SetSfxViewShell(SfxViewShell *pNew) { mpSfxViewShell = pNew; }
438 // Selection of Draw ::com::sun::star::script::Engine has been changed.
439 virtual void DrawSelChanged();
441 SwPagePreviewLayout* PagePreviewLayout();
443 /** adjust view options for page preview
445 Because page preview should show the document as it is printed -
446 page preview is print preview -, the view options are adjusted to the
447 same as for printing.
449 @param _rPrintOptions
450 input parameter - constant reference to print options, to which the
451 view option will be adjusted.
453 void AdjustOptionsForPagePreview( SwPrintData const& rPrintOptions );
455 sal_Bool IsViewLocked() const { return mbViewLocked; }
456 void LockView( sal_Bool b ) { mbViewLocked = b; }
458 inline void LockPaint();
459 void ImplLockPaint();
460 inline void UnlockPaint( sal_Bool bVirDev = sal_False );
461 void ImplUnlockPaint( sal_Bool bVirDev );
462 sal_Bool IsPaintLocked() const { return mnLockPaint != 0; }
464 // Get/set DrawView and PageView.
465 sal_Bool HasDrawView() const;
466 void MakeDrawView();
468 // DrawView may be used at UI.
469 SdrView *GetDrawView();
470 const SdrView *GetDrawView() const { return ((ViewShell*)this)->GetDrawView(); }
472 // Take care that MarkList is up-to-date in any case (Bug 57153).
473 SdrView *GetDrawViewWithValidMarkList();
475 // Query attribute pool.
476 inline const SfxItemPool& GetAttrPool() const;
477 SfxItemPool& GetAttrPool();
479 sal_Bool IsPreView() const { return mbPreView; }
481 sal_Bool IsFrameView() const { return mbFrameView; }
482 void SetFrameView( const Size& rBrowseBorder )
483 { mbFrameView = sal_True; maBrowseBorder = rBrowseBorder; }
485 // Makes the necessary invalidations:
486 // If BrowseMode has changed bBrowseChgd == sal_True
487 // or bBrowseChgd == sal_False in BrowseMode
488 // if proportions have changed.
489 void CheckBrowseView( sal_Bool bBrowseChgd );
491 const Size& GetBrowseBorder() const;
492 sal_Int32 GetBrowseWidth() const;
493 void SetBrowseBorder( const Size& rNew );
495 ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible();
497 ::com::sun::star::uno::Reference<
498 ::com::sun::star::accessibility::XAccessible >
499 CreateAccessiblePreview();
501 void ShowPreViewSelection( sal_uInt16 nSelPage );
502 void InvalidateAccessibleFocus();
504 // Apply Accessiblity options.
505 void ApplyAccessiblityOptions(SvtAccessibilityOptions& rAccessibilityOptions);
507 /** invalidate CONTENT_FLOWS_FROM/_TO relation for paragraphs
509 @author OD
511 @param _pFromTxtFrm
512 input parameter - paragraph frame, for which the relation CONTENT_FLOWS_FROM
513 has to be invalidated.
514 If NULL, no CONTENT_FLOWS_FROM relation has to be invalidated
516 @param _pToTxtFrm
517 input parameter - paragraph frame, for which the relation CONTENT_FLOWS_TO
518 has to be invalidated.
519 If NULL, no CONTENT_FLOWS_TO relation has to be invalidated
521 void InvalidateAccessibleParaFlowRelation( const SwTxtFrm* _pFromTxtFrm,
522 const SwTxtFrm* _pToTxtFrm );
524 /** invalidate text selection for paragraphs
526 @author OD
528 void InvalidateAccessibleParaTextSelection();
530 /** invalidate attributes for paragraphs and paragraph's characters
532 usage also for changes of the attributes of
533 paragraph's characters.
535 @author OD
537 @param rTxtFrm
538 input parameter - paragraph frame, whose attributes have changed
540 void InvalidateAccessibleParaAttrs( const SwTxtFrm& rTxtFrm );
542 SwAccessibleMap* GetAccessibleMap();
544 ViewShell( ViewShell&, Window *pWin = 0, OutputDevice *pOut = 0,
545 long nFlags = 0 );
546 ViewShell( SwDoc& rDoc, Window *pWin,
547 const SwViewOption *pOpt = 0, OutputDevice *pOut = 0,
548 long nFlags = 0 );
549 virtual ~ViewShell();
551 sal_Int32 GetPageNumAndSetOffsetForPDF( OutputDevice& rOut, const SwRect& rRect ) const;
553 inline bool IsInConstructor() const { return mbInConstructor; }
555 static const BitmapEx& GetReplacementBitmap( bool bIsErrorState );
556 static void DeleteReplacementBitmaps();
558 const SwPostItMgr* GetPostItMgr() const { return (const_cast<ViewShell*>(this))->GetPostItMgr(); }
559 SwPostItMgr* GetPostItMgr();
561 /// Acts both for headers / footers, depending on the bShow(Header|Footer)Separator flags
562 void ToggleHeaderFooterEdit();
563 /// Acts both for headers / footers, depending on the bShow(Header|Footer)Separator flags
564 bool IsHeaderFooterEdit() const { return mbHeaderFooterEdit; }
565 bool IsShowHeaderFooterSeparator( FrameControlType eControl ) { return (eControl == Header)? mbShowHeaderSeparator: mbShowFooterSeparator; }
566 virtual void SetShowHeaderFooterSeparator( FrameControlType eControl, bool bShow ) { if ( eControl == Header ) mbShowHeaderSeparator = bShow; else mbShowFooterSeparator = bShow; }
569 //---- class CurrShell manages global ShellPointer -------------------
571 class CurrShell
573 public:
574 ViewShell *pPrev;
575 SwRootFrm *pRoot;
577 CurrShell( ViewShell *pNew );
578 ~CurrShell();
581 inline void ViewShell::ResetInvalidRect()
583 maInvalidRect.Clear();
586 inline void ViewShell::StartAction()
588 if ( !mnStartAction++ )
589 ImplStartAction();
591 inline void ViewShell::EndAction( const sal_Bool bIdleEnd )
593 if( 0 == (mnStartAction - 1) )
594 ImplEndAction( bIdleEnd );
595 --mnStartAction;
598 inline void ViewShell::LockPaint()
600 if ( !mnLockPaint++ )
601 ImplLockPaint();
603 inline void ViewShell::UnlockPaint( sal_Bool bVirDev )
605 if ( 0 == --mnLockPaint )
606 ImplUnlockPaint( bVirDev );
608 inline const SfxItemPool& ViewShell::GetAttrPool() const
610 return ((ViewShell*)this)->GetAttrPool();
615 #endif // SW_VIEWSH_HXX
617 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */