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 .
20 #include <vcl/svapp.hxx>
22 #include "scitems.hxx"
23 #include <sfx2/viewfrm.hxx>
24 #include <sfx2/bindings.hxx>
25 #include <vcl/help.hxx>
26 #include <vcl/settings.hxx>
28 #include "tabview.hxx"
29 #include "tabvwsh.hxx"
30 #include "document.hxx"
31 #include "gridwin.hxx"
32 #include "olinewin.hxx"
33 #include "olinetab.hxx"
34 #include "tabsplit.hxx"
35 #include "colrowba.hxx"
36 #include "tabcont.hxx"
39 #include "viewutil.hxx"
40 #include "globstr.hrc"
41 #include "drawview.hxx"
43 #include "viewuno.hxx"
44 #include "AccessibilityHints.hxx"
45 #include "appoptio.hxx"
47 #include "hintwin.hxx"
49 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
54 #include <basegfx/tools/zoomtools.hxx>
56 #define SPLIT_MARGIN 30
57 #define SPLIT_HANDLE_SIZE 5
58 #define WIDTH_MARGIN 5
60 #define SC_ICONSIZE 36
62 #define SC_SCROLLBAR_MIN 30
63 #define SC_TABBAR_MIN 6
65 using namespace ::com::sun::star
;
69 ScCornerButton::ScCornerButton( vcl::Window
* pParent
, ScViewData
* pData
, bool bAdditional
) :
70 Window( pParent
, WinBits( 0 ) ),
77 ScCornerButton::~ScCornerButton()
81 void ScCornerButton::Paint(vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
)
83 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
84 SetBackground(rStyleSettings
.GetFaceColor());
86 Size
aSize(GetOutputSizePixel());
87 long nPosX
= aSize
.Width() - 1;
88 long nPosY
= aSize
.Height() - 1;
90 Window::Paint(rRenderContext
, rRect
);
92 bool bLayoutRTL
= pViewData
->GetDocument()->IsLayoutRTL( pViewData
->GetTabNo() );
93 long nDarkX
= bLayoutRTL
? 0 : nPosX
;
97 // match the shaded look of column/row headers
99 Color
aFace(rStyleSettings
.GetFaceColor());
100 Color
aWhite(COL_WHITE
);
101 Color
aCenter(aFace
);
102 aCenter
.Merge(aWhite
, 0xd0); // lighten up a bit
103 Color
aOuter(aFace
);
104 aOuter
.Merge(aWhite
, 0xa0); // lighten up more
106 long nCenterX
= (aSize
.Width() / 2) - 1;
107 long nCenterY
= (aSize
.Height() / 2) - 1;
109 rRenderContext
.SetLineColor();
110 rRenderContext
.SetFillColor(aCenter
);
111 rRenderContext
.DrawRect(Rectangle(nCenterX
, nCenterY
, nCenterX
, nPosY
));
112 rRenderContext
.DrawRect(Rectangle(nCenterX
, nCenterY
, nDarkX
, nCenterY
));
113 rRenderContext
.SetFillColor(aOuter
);
114 rRenderContext
.DrawRect(Rectangle(0, 0, nPosX
, nCenterY
- 1));
116 rRenderContext
.DrawRect(Rectangle(nCenterX
+ 1, nCenterY
, nPosX
, nPosY
));
118 rRenderContext
.DrawRect(Rectangle(0, nCenterY
, nCenterX
- 1, nPosY
));
121 // both buttons have the same look now - only dark right/bottom lines
122 rRenderContext
.SetLineColor(rStyleSettings
.GetDarkShadowColor());
123 rRenderContext
.DrawLine(Point(0, nPosY
), Point(nPosX
, nPosY
));
124 rRenderContext
.DrawLine(Point(nDarkX
, 0), Point(nDarkX
, nPosY
));
127 void ScCornerButton::StateChanged( StateChangedType nType
)
129 Window::StateChanged( nType
);
131 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
132 SetBackground( rStyleSettings
.GetFaceColor() );
136 void ScCornerButton::DataChanged( const DataChangedEvent
& rDCEvt
)
138 Window::DataChanged( rDCEvt
);
140 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
141 SetBackground( rStyleSettings
.GetFaceColor() );
145 void ScCornerButton::Resize()
150 void ScCornerButton::MouseButtonDown( const MouseEvent
& rMEvt
)
152 ScModule
* pScMod
= SC_MOD();
153 bool bDisable
= pScMod
->IsFormulaMode() || pScMod
->IsModalMode();
156 ScTabViewShell
* pViewSh
= pViewData
->GetViewShell();
157 pViewSh
->SetActive(); // Appear und SetViewFrame
158 pViewSh
->ActiveGrabFocus();
160 bool bControl
= rMEvt
.IsMod1();
161 pViewSh
->SelectAll( bControl
);
167 bool lcl_HasColOutline( const ScViewData
& rViewData
)
169 const ScOutlineTable
* pTable
= rViewData
.GetDocument()->GetOutlineTable(rViewData
.GetTabNo());
172 const ScOutlineArray
& rArray
= pTable
->GetColArray();
173 if ( rArray
.GetDepth() > 0 )
179 bool lcl_HasRowOutline( const ScViewData
& rViewData
)
181 const ScOutlineTable
* pTable
= rViewData
.GetDocument()->GetOutlineTable(rViewData
.GetTabNo());
184 const ScOutlineArray
& rArray
= pTable
->GetRowArray();
185 if ( rArray
.GetDepth() > 0 )
191 } // anonymous namespace
193 ScTabView::ScTabView( vcl::Window
* pParent
, ScDocShell
& rDocSh
, ScTabViewShell
* pViewShell
) :
194 pFrameWin( pParent
),
195 aViewData( &rDocSh
, pViewShell
),
197 aFunctionSet( &aViewData
),
199 aHdrFunc( &aViewData
),
201 aVScrollTop( VclPtr
<ScrollBar
>::Create( pFrameWin
, WinBits( WB_VSCROLL
| WB_DRAG
) ) ),
202 aVScrollBottom( VclPtr
<ScrollBar
>::Create( pFrameWin
, WinBits( WB_VSCROLL
| WB_DRAG
) ) ),
203 aHScrollLeft( VclPtr
<ScrollBar
>::Create( pFrameWin
, WinBits( WB_HSCROLL
| WB_DRAG
) ) ),
204 aHScrollRight( VclPtr
<ScrollBar
>::Create( pFrameWin
, WinBits( WB_HSCROLL
| WB_DRAG
) ) ),
205 aCornerButton( VclPtr
<ScCornerButton
>::Create( pFrameWin
, &aViewData
, false ) ),
206 aTopButton( VclPtr
<ScCornerButton
>::Create( pFrameWin
, &aViewData
, true ) ),
207 aScrollBarBox( VclPtr
<ScrollBarBox
>::Create( pFrameWin
, WB_SIZEABLE
) ),
208 mpInputHintWindow( NULL
),
209 pPageBreakData( NULL
),
210 pBrushDocument( NULL
),
211 pDrawBrushSet( NULL
),
212 pTimerWindow( NULL
),
217 nBlockStartXOrig( 0 ),
220 nBlockStartYOrig( 0 ),
226 mfPendingTabBarWidth( -1.0 ),
228 bInUpdateHeader( false ),
229 bInActivatePart( false ),
230 bInZoomUpdate( false ),
231 bMoveIsShift( false ),
232 bDrawSelMode( false ),
233 bLockPaintBrush( false ),
238 mbInlineWithScrollbar( false )
243 void ScTabView::InitScrollBar( ScrollBar
& rScrollBar
, long nMaxVal
)
245 rScrollBar
.SetRange( Range( 0, nMaxVal
) );
246 rScrollBar
.SetLineSize( 1 );
247 rScrollBar
.SetPageSize( 1 ); // wird getrennt abgefragt
248 rScrollBar
.SetVisibleSize( 10 ); // wird bei Resize neu gesetzt
250 rScrollBar
.SetScrollHdl( LINK(this, ScTabView
, ScrollHdl
) );
251 rScrollBar
.SetEndScrollHdl( LINK(this, ScTabView
, EndScrollHdl
) );
253 rScrollBar
.EnableRTL( aViewData
.GetDocument()->IsLayoutRTL( aViewData
.GetTabNo() ) );
258 void ScTabView::SetTimer( ScGridWindow
* pWin
, const MouseEvent
& rMEvt
)
262 aScrollTimer
.Start();
265 void ScTabView::ResetTimer()
271 IMPL_LINK_NOARG_TYPED(ScTabView
, TimerHdl
, Timer
*, void)
274 pTimerWindow
->MouseMove( aTimerMEvt
);
277 // --- Resize ---------------------------------------------------------------------
279 static void lcl_SetPosSize( vcl::Window
& rWindow
, const Point
& rPos
, const Size
& rSize
,
280 long nTotalWidth
, bool bLayoutRTL
)
282 Point aNewPos
= rPos
;
285 aNewPos
.X() = nTotalWidth
- rPos
.X() - rSize
.Width();
286 if ( aNewPos
== rWindow
.GetPosPixel() && rSize
.Width() != rWindow
.GetSizePixel().Width() )
288 // Document windows are manually painted right-to-left, so they need to
289 // be repainted if the size changes.
290 rWindow
.Invalidate();
293 rWindow
.SetPosSizePixel( aNewPos
, rSize
);
296 void ScTabView::DoResize( const Point
& rOffset
, const Size
& rSize
, bool bInner
)
300 bool bHasHint
= HasHintWindow();
304 bool bLayoutRTL
= aViewData
.GetDocument()->IsLayoutRTL( aViewData
.GetTabNo() );
305 long nTotalWidth
= rSize
.Width();
307 nTotalWidth
+= 2*rOffset
.X();
309 bool bVScroll
= aViewData
.IsVScrollMode();
310 bool bHScroll
= aViewData
.IsHScrollMode();
311 bool bTabControl
= aViewData
.IsTabMode();
312 bool bHeaders
= aViewData
.IsHeaderMode();
313 bool bOutlMode
= aViewData
.IsOutlineMode();
314 bool bHOutline
= bOutlMode
&& lcl_HasColOutline(aViewData
);
315 bool bVOutline
= bOutlMode
&& lcl_HasRowOutline(aViewData
);
317 if ( aViewData
.GetDocShell()->IsPreview() )
318 bHScroll
= bVScroll
= bTabControl
= bHeaders
= bOutlMode
= bHOutline
= bVOutline
= false;
327 long nPosX
= rOffset
.X();
328 long nPosY
= rOffset
.Y();
329 long nSizeX
= rSize
.Width();
330 long nSizeY
= rSize
.Height();
332 bMinimized
= ( nSizeX
<=SC_ICONSIZE
|| nSizeY
<=SC_ICONSIZE
);
336 sal_Int32 aScaleFactor
= pFrameWin
->GetDPIScaleFactor();
338 long nSplitSizeX
= SPLIT_HANDLE_SIZE
* aScaleFactor
;
339 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
341 long nSplitSizeY
= SPLIT_HANDLE_SIZE
* aScaleFactor
;
342 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
345 aBorderPos
= rOffset
;
348 const StyleSettings
& rStyleSettings
= pFrameWin
->GetSettings().GetStyleSettings();
350 sal_Int32 nTabWidth
= pFrameWin
->GetFont().GetHeight() + WIDTH_MARGIN
;
352 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
354 if ( aViewData
.GetHSplitPos() > nSizeX
- SPLIT_MARGIN
)
356 aViewData
.SetHSplitMode( SC_SPLIT_NONE
);
357 if ( WhichH( aViewData
.GetActivePart() ) == SC_SPLIT_RIGHT
)
358 ActivatePart( SC_SPLIT_BOTTOMLEFT
);
362 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
364 if ( aViewData
.GetVSplitPos() > nSizeY
- SPLIT_MARGIN
)
366 aViewData
.SetVSplitMode( SC_SPLIT_NONE
);
367 if ( WhichV( aViewData
.GetActivePart() ) == SC_SPLIT_TOP
)
368 ActivatePart( SC_SPLIT_BOTTOMLEFT
);
375 if (bHScroll
|| bVScroll
) // Scrollbars horizontal oder vertikal
377 long nScrollBarSize
= rStyleSettings
.GetScrollBarSize();
380 nBarX
= nScrollBarSize
;
387 if (!mbInlineWithScrollbar
)
388 nBarY
+= nScrollBarSize
;
393 // window at the bottom right
394 lcl_SetPosSize( *aScrollBarBox
.get(), Point( nPosX
+nSizeX
, nPosY
+nSizeY
), Size( nBarX
, nBarY
),
395 nTotalWidth
, bLayoutRTL
);
397 if (bHScroll
) // Scrollbars horizontal
399 long nSizeLt
= 0; // left scroll bar
400 long nSizeRt
= 0; // right scroll bar
401 long nSizeSp
= 0; // splitter
403 switch (aViewData
.GetHSplitMode())
406 nSizeSp
= nSplitSizeX
;
407 nSizeLt
= nSizeX
- nSizeSp
; // Covert the corner
409 case SC_SPLIT_NORMAL
:
410 nSizeSp
= nSplitSizeX
;
411 nSizeLt
= aViewData
.GetHSplitPos();
418 nSizeRt
= nSizeX
- nSizeLt
- nSizeSp
;
424 // pending relative tab bar width from extended document options
425 if( mfPendingTabBarWidth
>= 0.0 )
427 SetRelTabBarWidth( mfPendingTabBarWidth
);
428 mfPendingTabBarWidth
= -1.0;
431 if (mbInlineWithScrollbar
)
433 nTabSize
= pTabControl
->GetSizePixel().Width();
435 if ( aViewData
.GetHSplitMode() != SC_SPLIT_FIX
) // left Scrollbar
437 if (nTabSize
> nSizeLt
-SC_SCROLLBAR_MIN
)
438 nTabSize
= nSizeLt
-SC_SCROLLBAR_MIN
;
439 if (nTabSize
< SC_TABBAR_MIN
)
440 nTabSize
= SC_TABBAR_MIN
;
443 else // right Scrollbar
445 if (nTabSize
> nSizeRt
-SC_SCROLLBAR_MIN
)
446 nTabSize
= nSizeRt
-SC_SCROLLBAR_MIN
;
447 if (nTabSize
< SC_TABBAR_MIN
)
448 nTabSize
= SC_TABBAR_MIN
;
454 if (mbInlineWithScrollbar
)
456 Point
aTabPoint(nPosX
, nPosY
+ nSizeY
);
457 Size
aTabSize(nTabSize
, nBarY
);
458 lcl_SetPosSize(*pTabControl
.get(), aTabPoint
, aTabSize
, nTotalWidth
, bLayoutRTL
);
459 pTabControl
->SetSheetLayoutRTL(bLayoutRTL
);
461 Point
aHScrollLeftPoint(nPosX
+ nTabSize
, nPosY
+ nSizeY
);
462 Size
aHScrollLeftSize(nSizeLt
, nBarY
);
463 lcl_SetPosSize(*aHScrollLeft
.get(), aHScrollLeftPoint
, aHScrollLeftSize
, nTotalWidth
, bLayoutRTL
);
465 Point
aHSplitterPoint(nPosX
+ nTabSize
+ nSizeLt
, nPosY
+ nSizeY
);
466 Size
aHSplitterSize(nSizeSp
, nBarY
);
467 lcl_SetPosSize(*pHSplitter
.get(), aHSplitterPoint
, aHSplitterSize
, nTotalWidth
, bLayoutRTL
);
469 Point
aHScrollRightPoint(nPosX
+ nTabSize
+ nSizeLt
+ nSizeSp
, nPosY
+ nSizeY
);
470 Size
aHScrollRightSize(nSizeRt
, nBarY
);
471 lcl_SetPosSize(*aHScrollRight
.get(), aHScrollRightPoint
, aHScrollRightSize
, nTotalWidth
, bLayoutRTL
);
475 Point
aTabPoint(nPosX
, nPosY
+ nSizeY
+ nScrollBarSize
);
476 Size
aTabSize(nSizeX
, nTabWidth
);
477 lcl_SetPosSize(*pTabControl
.get(), aTabPoint
, aTabSize
, nTotalWidth
, bLayoutRTL
);
478 pTabControl
->SetSheetLayoutRTL(bLayoutRTL
);
480 Point
aHScrollLeftPoint(nPosX
, nPosY
+ nSizeY
);
481 Size
aHScrollLeftSize(nSizeLt
, nScrollBarSize
);
482 lcl_SetPosSize(*aHScrollLeft
.get(), aHScrollLeftPoint
, aHScrollLeftSize
, nTotalWidth
, bLayoutRTL
);
484 Point
aHSplitterPoint(nPosX
+ nSizeLt
, nPosY
+ nSizeY
);
485 Size
aHSplitterSize(nSizeSp
, nScrollBarSize
);
486 lcl_SetPosSize(*pHSplitter
.get(), aHSplitterPoint
, aHSplitterSize
, nTotalWidth
, bLayoutRTL
);
488 Point
aHScrollRightPoint(nPosX
+ nSizeLt
+ nSizeSp
, nPosY
+ nSizeY
);
489 Size
aHScrollRightSize(nSizeRt
, nScrollBarSize
);
490 lcl_SetPosSize(*aHScrollRight
.get(), aHScrollRightPoint
, aHScrollRightSize
, nTotalWidth
, bLayoutRTL
);
492 // SetDragRectPixel is done below
497 long nSizeUp
= 0; // upper scroll bar
498 long nSizeSp
= 0; // splitter
499 long nSizeDn
; // unterer Scrollbar
501 switch (aViewData
.GetVSplitMode())
505 nSizeSp
= nSplitSizeY
;
507 case SC_SPLIT_NORMAL
:
508 nSizeUp
= aViewData
.GetVSplitPos();
509 nSizeSp
= nSplitSizeY
;
516 nSizeDn
= nSizeY
- nSizeUp
- nSizeSp
;
518 lcl_SetPosSize( *aVScrollTop
.get(), Point(nPosX
+ nSizeX
, nPosY
),
519 Size(nBarX
, nSizeUp
), nTotalWidth
, bLayoutRTL
);
520 lcl_SetPosSize( *pVSplitter
, Point( nPosX
+ nSizeX
, nPosY
+nSizeUp
),
521 Size( nBarX
, nSizeSp
), nTotalWidth
, bLayoutRTL
);
522 lcl_SetPosSize( *aVScrollBottom
.get(), Point(nPosX
+ nSizeX
,
523 nPosY
+ nSizeUp
+ nSizeSp
),
524 Size(nBarX
, nSizeDn
), nTotalWidth
, bLayoutRTL
);
526 // SetDragRectPixel is done below
530 // SetDragRectPixel auch ohne Scrollbars etc., wenn schon gesplittet ist
531 if ( bHScroll
|| aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
532 pHSplitter
->SetDragRectPixel(
533 Rectangle( nPosX
, nPosY
, nPosX
+nSizeX
, nPosY
+nSizeY
), pFrameWin
);
534 if ( bVScroll
|| aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
535 pVSplitter
->SetDragRectPixel(
536 Rectangle( nPosX
, nPosY
, nPosX
+nSizeX
, nPosY
+nSizeY
), pFrameWin
);
538 if (bTabControl
&& ! bHScroll
)
540 nBarY
= aHScrollLeft
->GetSizePixel().Height();
541 nBarX
= aVScrollBottom
->GetSizePixel().Width();
543 long nSize1
= nSizeX
;
545 long nTabSize
= nSize1
;
546 if (nTabSize
< 0) nTabSize
= 0;
548 lcl_SetPosSize( *pTabControl
.get(), Point(nPosX
, nPosY
+nSizeY
-nBarY
),
549 Size(nTabSize
, nBarY
), nTotalWidth
, bLayoutRTL
);
551 lcl_SetPosSize( *aScrollBarBox
.get(), Point( nPosX
+nSizeX
, nPosY
+nSizeY
), Size( nBarX
, nBarY
),
552 nTotalWidth
, bLayoutRTL
);
556 Size aVScrSize
= aVScrollBottom
->GetSizePixel();
557 aVScrSize
.Height() -= nBarY
;
558 aVScrollBottom
->SetSizePixel( aVScrSize
);
566 if (bVOutline
&& pRowOutline
[SC_SPLIT_BOTTOM
])
568 nOutlineX
= pRowOutline
[SC_SPLIT_BOTTOM
]->GetDepthSize();
572 if (bHOutline
&& pColOutline
[SC_SPLIT_LEFT
])
574 nOutlineY
= pColOutline
[SC_SPLIT_LEFT
]->GetDepthSize();
579 if (bHeaders
) // Spalten/Zeilen-Header
581 nBarX
= pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width();
582 nBarY
= pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height();
591 // Splitter auswerten
593 long nLeftSize
= nSizeX
;
596 long nBottomSize
= nSizeY
;
597 long nSplitPosX
= nPosX
;
598 long nSplitPosY
= nPosY
;
600 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
602 long nSplitHeight
= rSize
.Height();
603 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
605 // Fixier-Splitter nicht mit Scrollbar/TabBar ueberlappen lassen
607 nSplitHeight
-= aHScrollLeft
->GetSizePixel().Height();
608 else if ( bTabControl
&& pTabControl
)
609 nSplitHeight
-= pTabControl
->GetSizePixel().Height();
611 nSplitPosX
= aViewData
.GetHSplitPos();
612 lcl_SetPosSize( *pHSplitter
,
613 Point(nSplitPosX
, nOutPosY
),
614 Size( nSplitSizeX
, nSplitHeight
- nTabWidth
), nTotalWidth
, bLayoutRTL
);
615 nLeftSize
= nSplitPosX
- nPosX
;
616 nSplitPosX
+= nSplitSizeX
;
617 nRightSize
= nSizeX
- nLeftSize
- nSplitSizeX
;
619 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
621 long nSplitWidth
= rSize
.Width();
622 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
&& bVScroll
)
623 nSplitWidth
-= aVScrollBottom
->GetSizePixel().Width();
624 nSplitPosY
= aViewData
.GetVSplitPos();
625 lcl_SetPosSize( *pVSplitter
,
626 Point( nOutPosX
, nSplitPosY
), Size( nSplitWidth
, nSplitSizeY
), nTotalWidth
, bLayoutRTL
);
627 nTopSize
= nSplitPosY
- nPosY
;
628 nSplitPosY
+= nSplitSizeY
;
629 nBottomSize
= nSizeY
- nTopSize
- nSplitSizeY
;
632 // ShowHide fuer pColOutline / pRowOutline passiert in UpdateShow
634 if (bHOutline
) // Outline-Controls
636 if (pColOutline
[SC_SPLIT_LEFT
])
638 pColOutline
[SC_SPLIT_LEFT
]->SetHeaderSize( nBarX
);
639 lcl_SetPosSize( *pColOutline
[SC_SPLIT_LEFT
],
640 Point(nPosX
-nBarX
,nOutPosY
), Size(nLeftSize
+nBarX
,nOutlineY
), nTotalWidth
, bLayoutRTL
);
642 if (pColOutline
[SC_SPLIT_RIGHT
])
644 pColOutline
[SC_SPLIT_RIGHT
]->SetHeaderSize( 0 ); // always call to update RTL flag
645 lcl_SetPosSize( *pColOutline
[SC_SPLIT_RIGHT
],
646 Point(nSplitPosX
,nOutPosY
), Size(nRightSize
,nOutlineY
), nTotalWidth
, bLayoutRTL
);
653 if (pRowOutline
[SC_SPLIT_TOP
] && pRowOutline
[SC_SPLIT_BOTTOM
])
655 pRowOutline
[SC_SPLIT_TOP
]->SetHeaderSize( nBarY
);
656 lcl_SetPosSize( *pRowOutline
[SC_SPLIT_TOP
],
657 Point(nOutPosX
,nPosY
-nBarY
), Size(nOutlineX
,nTopSize
+nBarY
), nTotalWidth
, bLayoutRTL
);
658 pRowOutline
[SC_SPLIT_BOTTOM
]->SetHeaderSize( 0 );
659 lcl_SetPosSize( *pRowOutline
[SC_SPLIT_BOTTOM
],
660 Point(nOutPosX
,nSplitPosY
), Size(nOutlineX
,nBottomSize
), nTotalWidth
, bLayoutRTL
);
663 else if (pRowOutline
[SC_SPLIT_BOTTOM
])
665 pRowOutline
[SC_SPLIT_BOTTOM
]->SetHeaderSize( nBarY
);
666 lcl_SetPosSize( *pRowOutline
[SC_SPLIT_BOTTOM
],
667 Point(nOutPosX
,nSplitPosY
-nBarY
), Size(nOutlineX
,nBottomSize
+nBarY
), nTotalWidth
, bLayoutRTL
);
670 if (bHOutline
&& bVOutline
)
672 lcl_SetPosSize( *aTopButton
.get(), Point(nOutPosX
,nOutPosY
), Size(nOutlineX
,nOutlineY
), nTotalWidth
, bLayoutRTL
);
678 if (bHeaders
) // Spalten/Zeilen-Header
680 lcl_SetPosSize( *pColBar
[SC_SPLIT_LEFT
],
681 Point(nPosX
,nPosY
-nBarY
), Size(nLeftSize
,nBarY
), nTotalWidth
, bLayoutRTL
);
682 if (pColBar
[SC_SPLIT_RIGHT
])
683 lcl_SetPosSize( *pColBar
[SC_SPLIT_RIGHT
],
684 Point(nSplitPosX
,nPosY
-nBarY
), Size(nRightSize
,nBarY
), nTotalWidth
, bLayoutRTL
);
686 if (pRowBar
[SC_SPLIT_TOP
])
687 lcl_SetPosSize( *pRowBar
[SC_SPLIT_TOP
],
688 Point(nPosX
-nBarX
,nPosY
), Size(nBarX
,nTopSize
), nTotalWidth
, bLayoutRTL
);
689 lcl_SetPosSize( *pRowBar
[SC_SPLIT_BOTTOM
],
690 Point(nPosX
-nBarX
,nSplitPosY
), Size(nBarX
,nBottomSize
), nTotalWidth
, bLayoutRTL
);
692 lcl_SetPosSize( *aCornerButton
.get(), Point(nPosX
-nBarX
,nPosY
-nBarY
), Size(nBarX
,nBarY
), nTotalWidth
, bLayoutRTL
);
693 aCornerButton
->Show();
694 pColBar
[SC_SPLIT_LEFT
]->Show();
695 pRowBar
[SC_SPLIT_BOTTOM
]->Show();
699 aCornerButton
->Hide();
700 pColBar
[SC_SPLIT_LEFT
]->Hide(); // immer da
701 pRowBar
[SC_SPLIT_BOTTOM
]->Hide();
708 long nInnerPosX
= bLayoutRTL
? ( nTotalWidth
- nPosX
- nLeftSize
) : nPosX
;
709 pGridWin
[SC_SPLIT_BOTTOMLEFT
]->SetPosPixel( Point(nInnerPosX
,nSplitPosY
) );
713 lcl_SetPosSize( *pGridWin
[SC_SPLIT_BOTTOMLEFT
],
714 Point(nPosX
,nSplitPosY
), Size(nLeftSize
,nBottomSize
), nTotalWidth
, bLayoutRTL
);
715 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
716 lcl_SetPosSize( *pGridWin
[SC_SPLIT_BOTTOMRIGHT
],
717 Point(nSplitPosX
,nSplitPosY
), Size(nRightSize
,nBottomSize
), nTotalWidth
, bLayoutRTL
);
718 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
719 lcl_SetPosSize( *pGridWin
[SC_SPLIT_TOPLEFT
],
720 Point(nPosX
,nPosY
), Size(nLeftSize
,nTopSize
), nTotalWidth
, bLayoutRTL
);
721 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
&& aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
722 lcl_SetPosSize( *pGridWin
[SC_SPLIT_TOPRIGHT
],
723 Point(nSplitPosX
,nPosY
), Size(nRightSize
,nTopSize
), nTotalWidth
, bLayoutRTL
);
726 // Scrollbars updaten
728 if (!bInUpdateHeader
)
730 UpdateScrollBars(); // Scrollbars nicht beim Scrollen neu setzen
733 InterpretVisible(); // have everything calculated before painting
737 TestHintWindow(); // neu positionieren
739 UpdateVarZoom(); // update variable zoom types (after resizing GridWindows)
741 if (aViewData
.GetViewShell()->HasAccessibilityObjects())
742 aViewData
.GetViewShell()->BroadcastAccessibility(SfxSimpleHint(SC_HINT_ACC_WINDOWRESIZED
));
745 void ScTabView::UpdateVarZoom()
747 // update variable zoom types
749 SvxZoomType eZoomType
= GetZoomType();
750 if ( eZoomType
!= SvxZoomType::PERCENT
&& !bInZoomUpdate
)
752 bInZoomUpdate
= true;
753 const Fraction
& rOldX
= GetViewData().GetZoomX();
754 const Fraction
& rOldY
= GetViewData().GetZoomY();
755 long nOldPercent
= ( rOldY
.GetNumerator() * 100 ) / rOldY
.GetDenominator();
756 sal_uInt16 nNewZoom
= CalcZoom( eZoomType
, (sal_uInt16
)nOldPercent
);
757 Fraction
aNew( nNewZoom
, 100 );
759 if ( aNew
!= rOldX
|| aNew
!= rOldY
)
761 SetZoom( aNew
, aNew
, false ); // always separately per sheet
765 aViewData
.GetViewShell()->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM
);
766 aViewData
.GetViewShell()->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER
);
768 bInZoomUpdate
= false;
772 void ScTabView::UpdateFixPos()
774 bool bResize
= false;
775 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
776 if (aViewData
.UpdateFixX())
778 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
779 if (aViewData
.UpdateFixY())
785 void ScTabView::RepeatResize( bool bUpdateFix
)
789 ScSplitMode eHSplit
= aViewData
.GetHSplitMode();
790 ScSplitMode eVSplit
= aViewData
.GetVSplitMode();
792 // #i46796# UpdateFixX / UpdateFixY uses GetGridOffset, which requires the
793 // outline windows to be available. So UpdateShow has to be called before
794 // (also called from DoResize).
795 if ( eHSplit
== SC_SPLIT_FIX
|| eVSplit
== SC_SPLIT_FIX
)
798 if ( eHSplit
== SC_SPLIT_FIX
)
799 aViewData
.UpdateFixX();
800 if ( eVSplit
== SC_SPLIT_FIX
)
801 aViewData
.UpdateFixY();
804 DoResize( aBorderPos
, aFrameSize
);
806 //! Border muss neu gesetzt werden ???
809 void ScTabView::GetBorderSize( SvBorder
& rBorder
, const Size
& /* rSize */ )
811 bool bScrollBars
= aViewData
.IsVScrollMode();
812 bool bHeaders
= aViewData
.IsHeaderMode();
813 bool bOutlMode
= aViewData
.IsOutlineMode();
814 bool bHOutline
= bOutlMode
&& lcl_HasColOutline(aViewData
);
815 bool bVOutline
= bOutlMode
&& lcl_HasRowOutline(aViewData
);
816 bool bLayoutRTL
= aViewData
.GetDocument()->IsLayoutRTL( aViewData
.GetTabNo() );
818 rBorder
= SvBorder();
820 if (bScrollBars
) // Scrollbars horizontal oder vertikal
822 rBorder
.Right() += aVScrollBottom
->GetSizePixel().Width();
823 rBorder
.Bottom() += aHScrollLeft
->GetSizePixel().Height();
827 if (bVOutline
&& pRowOutline
[SC_SPLIT_BOTTOM
])
828 rBorder
.Left() += pRowOutline
[SC_SPLIT_BOTTOM
]->GetDepthSize();
829 if (bHOutline
&& pColOutline
[SC_SPLIT_LEFT
])
830 rBorder
.Top() += pColOutline
[SC_SPLIT_LEFT
]->GetDepthSize();
832 if (bHeaders
) // Spalten/Zeilen-Header
834 rBorder
.Left() += pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width();
835 rBorder
.Top() += pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height();
839 ::std::swap( rBorder
.Left(), rBorder
.Right() );
842 IMPL_LINK_NOARG(ScTabView
, TabBarResize
)
844 if (aViewData
.IsHScrollMode())
846 const long nOverlap
= 0; // ScrollBar::GetWindowOverlapPixel();
847 long nSize
= pTabControl
->GetSplitSize();
849 if (aViewData
.GetHSplitMode() != SC_SPLIT_FIX
)
851 long nMax
= pHSplitter
->GetPosPixel().X();
852 if( pTabControl
->IsEffectiveRTL() )
853 nMax
= pFrameWin
->GetSizePixel().Width() - nMax
;
855 if (nSize
>nMax
) nSize
= nMax
;
858 if ( nSize
!= pTabControl
->GetSizePixel().Width() )
860 pTabControl
->SetSizePixel( Size( nSize
+nOverlap
,
861 pTabControl
->GetSizePixel().Height() ) );
869 void ScTabView::SetTabBarWidth( long nNewWidth
)
871 Size aSize
= pTabControl
->GetSizePixel();
873 if ( aSize
.Width() != nNewWidth
)
875 aSize
.Width() = nNewWidth
;
876 pTabControl
->SetSizePixel( aSize
);
880 void ScTabView::SetRelTabBarWidth( double fRelTabBarWidth
)
882 if( (0.0 <= fRelTabBarWidth
) && (fRelTabBarWidth
<= 1.0) )
883 if( long nFrameWidth
= pFrameWin
->GetSizePixel().Width() )
884 SetTabBarWidth( static_cast< long >( fRelTabBarWidth
* nFrameWidth
+ 0.5 ) );
887 void ScTabView::SetPendingRelTabBarWidth( double fRelTabBarWidth
)
889 mfPendingTabBarWidth
= fRelTabBarWidth
;
890 SetRelTabBarWidth( fRelTabBarWidth
);
893 long ScTabView::GetTabBarWidth() const
895 return pTabControl
->GetSizePixel().Width();
898 double ScTabView::GetRelTabBarWidth() const
900 if( long nFrameWidth
= pFrameWin
->GetSizePixel().Width() )
901 return static_cast< double >( GetTabBarWidth() ) / nFrameWidth
;
905 ScGridWindow
* ScTabView::GetActiveWin()
907 ScSplitPos ePos
= aViewData
.GetActivePart();
908 OSL_ENSURE(pGridWin
[ePos
],"kein aktives Fenster");
909 return pGridWin
[ePos
];
912 void ScTabView::SetActivePointer( const Pointer
& rPointer
)
914 for (sal_uInt16 i
=0; i
<4; i
++)
916 pGridWin
[i
]->SetPointer( rPointer
);
919 void ScTabView::ActiveGrabFocus()
921 ScSplitPos ePos
= aViewData
.GetActivePart();
923 pGridWin
[ePos
]->GrabFocus();
926 ScSplitPos
ScTabView::FindWindow( vcl::Window
* pWindow
) const
928 ScSplitPos eVal
= SC_SPLIT_BOTTOMLEFT
; // Default
929 for (sal_uInt16 i
=0; i
<4; i
++)
930 if ( pGridWin
[i
] == pWindow
)
931 eVal
= (ScSplitPos
) i
;
936 Point
ScTabView::GetGridOffset() const
940 // Groessen hier wie in DoResize
942 bool bHeaders
= aViewData
.IsHeaderMode();
943 bool bOutlMode
= aViewData
.IsOutlineMode();
944 bool bHOutline
= bOutlMode
&& lcl_HasColOutline(aViewData
);
945 bool bVOutline
= bOutlMode
&& lcl_HasRowOutline(aViewData
);
948 if (bVOutline
&& pRowOutline
[SC_SPLIT_BOTTOM
])
949 aPos
.X() += pRowOutline
[SC_SPLIT_BOTTOM
]->GetDepthSize();
950 if (bHOutline
&& pColOutline
[SC_SPLIT_LEFT
])
951 aPos
.Y() += pColOutline
[SC_SPLIT_LEFT
]->GetDepthSize();
953 if (bHeaders
) // Spalten/Zeilen-Header
955 if (pRowBar
[SC_SPLIT_BOTTOM
])
956 aPos
.X() += pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width();
957 if (pColBar
[SC_SPLIT_LEFT
])
958 aPos
.Y() += pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height();
964 // --- Scroll-Bars --------------------------------------------------------
966 bool ScTabView::ScrollCommand( const CommandEvent
& rCEvt
, ScSplitPos ePos
)
971 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
972 if ( pData
&& (pData
->GetMode() == CommandWheelMode::ZOOM
||
973 pData
->GetMode() == CommandWheelMode::ZOOM_SCALE
) )
975 if ( !aViewData
.GetViewShell()->GetViewFrame()->GetFrame().IsInPlace() )
977 // for ole inplace editing, the scale is defined by the visarea and client size
978 // and can't be changed directly
980 const Fraction
& rOldY
= aViewData
.GetZoomY();
981 long nOld
= (long)(( rOldY
.GetNumerator() * 100 ) / rOldY
.GetDenominator());
983 if ( pData
->GetMode() == CommandWheelMode::ZOOM_SCALE
)
985 nNew
= 100 * (long) ((nOld
/ 100.0) * (pData
->GetDelta() / 100.0));
988 if ( pData
->GetDelta() < 0 )
989 nNew
= std::max( (long) MINZOOM
, basegfx::zoomtools::zoomOut( nOld
));
991 nNew
= std::min( (long) MAXZOOM
, basegfx::zoomtools::zoomIn( nOld
));
995 // scroll wheel doesn't set the AppOptions default
997 bool bSyncZoom
= SC_MOD()->GetAppOptions().GetSynchronizeZoom();
998 SetZoomType( SvxZoomType::PERCENT
, bSyncZoom
);
999 Fraction
aFract( nNew
, 100 );
1000 SetZoom( aFract
, aFract
, bSyncZoom
);
1004 aViewData
.GetBindings().Invalidate( SID_ATTR_ZOOM
);
1005 aViewData
.GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER
);
1013 ScHSplitPos eHPos
= WhichH(ePos
);
1014 ScVSplitPos eVPos
= WhichV(ePos
);
1015 ScrollBar
* pHScroll
= ( eHPos
== SC_SPLIT_LEFT
) ? aHScrollLeft
.get() : aHScrollRight
.get();
1016 ScrollBar
* pVScroll
= ( eVPos
== SC_SPLIT_TOP
) ? aVScrollTop
.get() : aVScrollBottom
.get();
1017 if ( pGridWin
[ePos
] )
1018 bDone
= pGridWin
[ePos
]->HandleScrollCommand( rCEvt
, pHScroll
, pVScroll
);
1023 IMPL_LINK_NOARG(ScTabView
, EndScrollHdl
)
1033 IMPL_LINK( ScTabView
, ScrollHdl
, ScrollBar
*, pScroll
)
1035 bool bHoriz
= ( pScroll
== aHScrollLeft
.get() || pScroll
== aHScrollRight
.get() );
1038 nViewPos
= aViewData
.GetPosX( (pScroll
== aHScrollLeft
.get()) ?
1039 SC_SPLIT_LEFT
: SC_SPLIT_RIGHT
);
1041 nViewPos
= aViewData
.GetPosY( (pScroll
== aVScrollTop
.get()) ?
1042 SC_SPLIT_TOP
: SC_SPLIT_BOTTOM
);
1044 bool bLayoutRTL
= aViewData
.GetDocument()->IsLayoutRTL( aViewData
.GetTabNo() );
1046 ScrollType eType
= pScroll
->GetType();
1047 if ( eType
== SCROLL_DRAG
)
1052 nPrevDragPos
= nViewPos
;
1055 // Scroll-Position anzeigen
1056 // (nur QuickHelp, in der Statuszeile gibt es keinen Eintrag dafuer)
1058 if (Help::IsQuickHelpEnabled())
1060 Size aSize
= pScroll
->GetSizePixel();
1062 /* Convert scrollbar mouse position to screen position. If RTL
1063 mode of scrollbar differs from RTL mode of its parent, then the
1064 direct call to Window::OutputToNormalizedScreenPixel() will
1065 give unusable results, because calcualtion of screen position
1066 is based on parent orientation and expects equal orientation of
1067 the child position. Need to mirror mouse position before. */
1068 Point aMousePos
= pScroll
->GetPointerPosPixel();
1069 if( pScroll
->IsRTLEnabled() != pScroll
->GetParent()->IsRTLEnabled() )
1070 aMousePos
.X() = aSize
.Width() - aMousePos
.X() - 1;
1071 aMousePos
= pScroll
->OutputToNormalizedScreenPixel( aMousePos
);
1073 // convert top-left position of scrollbar to screen position
1074 Point aPos
= pScroll
->OutputToNormalizedScreenPixel( Point() );
1076 // get scrollbar scroll position for help text (row number/column name)
1077 long nScrollMin
= 0; // RangeMin simulieren
1078 if ( aViewData
.GetHSplitMode()==SC_SPLIT_FIX
&& pScroll
== aHScrollRight
.get() )
1079 nScrollMin
= aViewData
.GetFixPosX();
1080 if ( aViewData
.GetVSplitMode()==SC_SPLIT_FIX
&& pScroll
== aVScrollBottom
.get() )
1081 nScrollMin
= aViewData
.GetFixPosY();
1082 long nScrollPos
= GetScrollBarPos( *pScroll
) + nScrollMin
;
1086 QuickHelpFlags nAlign
;
1089 aHelpStr
= ScGlobal::GetRscString(STR_COLUMN
) +
1090 " " + ScColToAlpha((SCCOL
) nScrollPos
);
1092 aRect
.Left() = aMousePos
.X();
1093 aRect
.Top() = aPos
.Y() - 4;
1094 nAlign
= QuickHelpFlags::Bottom
|QuickHelpFlags::Center
;
1098 aHelpStr
= ScGlobal::GetRscString(STR_ROW
) +
1099 " " + OUString::number(nScrollPos
+ 1);
1101 // show quicktext always inside sheet area
1102 aRect
.Left() = bLayoutRTL
? (aPos
.X() + aSize
.Width() + 8) : (aPos
.X() - 8);
1103 aRect
.Top() = aMousePos
.Y();
1104 nAlign
= (bLayoutRTL
? QuickHelpFlags::Left
: QuickHelpFlags::Right
) | QuickHelpFlags::VCenter
;
1106 aRect
.Right() = aRect
.Left();
1107 aRect
.Bottom() = aRect
.Top();
1109 Help::ShowQuickHelp(pScroll
->GetParent(), aRect
, aHelpStr
, nAlign
);
1113 long nDelta
= pScroll
->GetDelta();
1119 case SCROLL_LINEDOWN
:
1123 if ( pScroll
== aHScrollLeft
.get() ) nDelta
= -(long) aViewData
.PrevCellsX( SC_SPLIT_LEFT
);
1124 if ( pScroll
== aHScrollRight
.get() ) nDelta
= -(long) aViewData
.PrevCellsX( SC_SPLIT_RIGHT
);
1125 if ( pScroll
== aVScrollTop
.get() ) nDelta
= -(long) aViewData
.PrevCellsY( SC_SPLIT_TOP
);
1126 if ( pScroll
== aVScrollBottom
.get() ) nDelta
= -(long) aViewData
.PrevCellsY( SC_SPLIT_BOTTOM
);
1127 if (nDelta
==0) nDelta
=-1;
1129 case SCROLL_PAGEDOWN
:
1130 if ( pScroll
== aHScrollLeft
.get() ) nDelta
= aViewData
.VisibleCellsX( SC_SPLIT_LEFT
);
1131 if ( pScroll
== aHScrollRight
.get() ) nDelta
= aViewData
.VisibleCellsX( SC_SPLIT_RIGHT
);
1132 if ( pScroll
== aVScrollTop
.get() ) nDelta
= aViewData
.VisibleCellsY( SC_SPLIT_TOP
);
1133 if ( pScroll
== aVScrollBottom
.get() ) nDelta
= aViewData
.VisibleCellsY( SC_SPLIT_BOTTOM
);
1134 if (nDelta
==0) nDelta
=1;
1138 // nur in die richtige Richtung scrollen, nicht um ausgeblendete
1139 // Bereiche herumzittern
1141 long nScrollMin
= 0; // RangeMin simulieren
1142 if ( aViewData
.GetHSplitMode()==SC_SPLIT_FIX
&& pScroll
== aHScrollRight
.get() )
1143 nScrollMin
= aViewData
.GetFixPosX();
1144 if ( aViewData
.GetVSplitMode()==SC_SPLIT_FIX
&& pScroll
== aVScrollBottom
.get() )
1145 nScrollMin
= aViewData
.GetFixPosY();
1147 long nScrollPos
= GetScrollBarPos( *pScroll
) + nScrollMin
;
1148 nDelta
= nScrollPos
- nViewPos
;
1149 if ( nScrollPos
> nPrevDragPos
)
1151 if (nDelta
<0) nDelta
=0;
1153 else if ( nScrollPos
< nPrevDragPos
)
1155 if (nDelta
>0) nDelta
=0;
1159 nPrevDragPos
= nScrollPos
;
1164 // added to avoid warnings
1170 bool bUpdate
= ( eType
!= SCROLL_DRAG
); // bei Drag die Ranges nicht aendern
1172 ScrollX( nDelta
, (pScroll
== aHScrollLeft
.get()) ? SC_SPLIT_LEFT
: SC_SPLIT_RIGHT
, bUpdate
);
1174 ScrollY( nDelta
, (pScroll
== aVScrollTop
.get()) ? SC_SPLIT_TOP
: SC_SPLIT_BOTTOM
, bUpdate
);
1180 void ScTabView::ScrollX( long nDeltaX
, ScHSplitPos eWhich
, bool bUpdBars
)
1182 SCCOL nOldX
= aViewData
.GetPosX(eWhich
);
1183 SCsCOL nNewX
= static_cast<SCsCOL
>(nOldX
) + static_cast<SCsCOL
>(nDeltaX
);
1189 if ( nNewX
> MAXCOL
)
1191 nDeltaX
-= nNewX
- MAXCOL
;
1195 SCsCOL nDir
= ( nDeltaX
> 0 ) ? 1 : -1;
1196 ScDocument
* pDoc
= aViewData
.GetDocument();
1197 SCTAB nTab
= aViewData
.GetTabNo();
1198 while ( pDoc
->ColHidden(nNewX
, nTab
) &&
1199 nNewX
+nDir
>= 0 && nNewX
+nDir
<= MAXCOL
)
1200 nNewX
= sal::static_int_cast
<SCsCOL
>( nNewX
+ nDir
);
1204 if (aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
1206 if (eWhich
== SC_SPLIT_LEFT
)
1207 nNewX
= static_cast<SCsCOL
>(nOldX
); // links immer stehenlassen
1210 SCsCOL nFixX
= static_cast<SCsCOL
>(aViewData
.GetFixPosX());
1215 if (nNewX
== static_cast<SCsCOL
>(nOldX
))
1220 if ( nNewX
>= 0 && nNewX
<= MAXCOL
&& nDeltaX
)
1222 SCCOL nTrackX
= std::max( nOldX
, static_cast<SCCOL
>(nNewX
) );
1224 // Mit VCL wirkt Update() im Moment immer auf alle Fenster, beim Update
1225 // nach dem Scrollen des GridWindow's wuerde darum der Col-/RowBar evtl.
1226 // mit schon geaenderter Pos. gepainted werden -
1227 // darum vorher einmal Update am Col-/RowBar
1229 if (pColBar
[eWhich
])
1230 pColBar
[eWhich
]->Update();
1232 long nOldPos
= aViewData
.GetScrPos( nTrackX
, 0, eWhich
).X();
1233 aViewData
.SetPosX( eWhich
, static_cast<SCCOL
>(nNewX
) );
1234 long nDiff
= aViewData
.GetScrPos( nTrackX
, 0, eWhich
).X() - nOldPos
;
1236 if ( eWhich
==SC_SPLIT_LEFT
)
1238 pGridWin
[SC_SPLIT_BOTTOMLEFT
]->ScrollPixel( nDiff
, 0 );
1239 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
1240 pGridWin
[SC_SPLIT_TOPLEFT
]->ScrollPixel( nDiff
, 0 );
1244 pGridWin
[SC_SPLIT_BOTTOMRIGHT
]->ScrollPixel( nDiff
, 0 );
1245 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
1246 pGridWin
[SC_SPLIT_TOPRIGHT
]->ScrollPixel( nDiff
, 0 );
1248 if (pColBar
[eWhich
]) { pColBar
[eWhich
]->Scroll( nDiff
,0 ); pColBar
[eWhich
]->Update(); }
1249 if (pColOutline
[eWhich
]) pColOutline
[eWhich
]->ScrollPixel( nDiff
);
1254 if (nDeltaX
==1 || nDeltaX
==-1)
1255 pGridWin
[aViewData
.GetActivePart()]->Update();
1259 SetNewVisArea(); // MapMode muss schon gesetzt sein
1264 void ScTabView::ScrollY( long nDeltaY
, ScVSplitPos eWhich
, bool bUpdBars
)
1266 SCROW nOldY
= aViewData
.GetPosY(eWhich
);
1267 SCsROW nNewY
= static_cast<SCsROW
>(nOldY
) + static_cast<SCsROW
>(nDeltaY
);
1273 if ( nNewY
> MAXROW
)
1275 nDeltaY
-= nNewY
- MAXROW
;
1279 SCsROW nDir
= ( nDeltaY
> 0 ) ? 1 : -1;
1280 ScDocument
* pDoc
= aViewData
.GetDocument();
1281 SCTAB nTab
= aViewData
.GetTabNo();
1282 while ( pDoc
->RowHidden(nNewY
, nTab
) &&
1283 nNewY
+nDir
>= 0 && nNewY
+nDir
<= MAXROW
)
1288 if (aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
1290 if (eWhich
== SC_SPLIT_TOP
)
1291 nNewY
= static_cast<SCsROW
>(nOldY
); // oben immer stehenlassen
1294 SCsROW nFixY
= static_cast<SCsROW
>(aViewData
.GetFixPosY());
1299 if (nNewY
== static_cast<SCsROW
>(nOldY
))
1304 if ( nNewY
>= 0 && nNewY
<= MAXROW
&& nDeltaY
)
1306 SCROW nTrackY
= std::max( nOldY
, static_cast<SCROW
>(nNewY
) );
1308 // Zeilenkoepfe anpassen vor dem eigentlichen Scrolling, damit nicht
1309 // doppelt gepainted werden muss
1310 // PosY darf dann auch noch nicht umgesetzt sein, neuen Wert uebergeben
1311 SCROW nUNew
= static_cast<SCROW
>(nNewY
);
1312 UpdateHeaderWidth( &eWhich
, &nUNew
); // Zeilenkoepfe anpassen
1314 if (pRowBar
[eWhich
])
1315 pRowBar
[eWhich
]->Update();
1317 long nOldPos
= aViewData
.GetScrPos( 0, nTrackY
, eWhich
).Y();
1318 aViewData
.SetPosY( eWhich
, static_cast<SCROW
>(nNewY
) );
1319 long nDiff
= aViewData
.GetScrPos( 0, nTrackY
, eWhich
).Y() - nOldPos
;
1321 if ( eWhich
==SC_SPLIT_TOP
)
1323 pGridWin
[SC_SPLIT_TOPLEFT
]->ScrollPixel( 0, nDiff
);
1324 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
1325 pGridWin
[SC_SPLIT_TOPRIGHT
]->ScrollPixel( 0, nDiff
);
1329 pGridWin
[SC_SPLIT_BOTTOMLEFT
]->ScrollPixel( 0, nDiff
);
1330 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
1331 pGridWin
[SC_SPLIT_BOTTOMRIGHT
]->ScrollPixel( 0, nDiff
);
1333 if (pRowBar
[eWhich
]) { pRowBar
[eWhich
]->Scroll( 0,nDiff
); pRowBar
[eWhich
]->Update(); }
1334 if (pRowOutline
[eWhich
]) pRowOutline
[eWhich
]->ScrollPixel( nDiff
);
1339 if (nDeltaY
==1 || nDeltaY
==-1)
1340 pGridWin
[aViewData
.GetActivePart()]->Update();
1344 SetNewVisArea(); // MapMode muss schon gesetzt sein
1349 void ScTabView::ScrollLines( long nDeltaX
, long nDeltaY
)
1351 ScSplitPos eWhich
= aViewData
.GetActivePart();
1353 ScrollX(nDeltaX
,WhichH(eWhich
));
1355 ScrollY(nDeltaY
,WhichV(eWhich
));
1361 SCROW
lcl_LastVisible( ScViewData
& rViewData
)
1363 // wenn am Dokumentende viele Zeilen ausgeblendet sind (welcher Trottel macht sowas?),
1364 // soll dadurch nicht auf breite Zeilenkoepfe geschaltet werden
1365 //! als Member ans Dokument ???
1367 ScDocument
* pDoc
= rViewData
.GetDocument();
1368 SCTAB nTab
= rViewData
.GetTabNo();
1370 SCROW nVis
= MAXROW
;
1371 while ( nVis
> 0 && pDoc
->GetRowHeight( nVis
, nTab
) == 0 )
1376 } // anonymous namespace
1378 void ScTabView::UpdateHeaderWidth( const ScVSplitPos
* pWhich
, const SCROW
* pPosY
)
1380 if ( !pRowBar
[SC_SPLIT_BOTTOM
] || MAXROW
< 10000 )
1383 SCROW nEndPos
= MAXROW
;
1384 if ( !aViewData
.GetViewShell()->GetViewFrame()->GetFrame().IsInPlace() )
1386 // fuer OLE Inplace immer MAXROW
1388 if ( pWhich
&& *pWhich
== SC_SPLIT_BOTTOM
&& pPosY
)
1391 nEndPos
= aViewData
.GetPosY( SC_SPLIT_BOTTOM
);
1392 nEndPos
+= aViewData
.CellsAtY( nEndPos
, 1, SC_SPLIT_BOTTOM
, SC_SIZE_NONE
); // VisibleCellsY
1393 if (nEndPos
> MAXROW
)
1394 nEndPos
= lcl_LastVisible( aViewData
);
1396 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
1399 if ( pWhich
&& *pWhich
== SC_SPLIT_TOP
&& pPosY
)
1402 nTopEnd
= aViewData
.GetPosY( SC_SPLIT_TOP
);
1403 nTopEnd
+= aViewData
.CellsAtY( nTopEnd
, 1, SC_SPLIT_TOP
, SC_SIZE_NONE
);// VisibleCellsY
1404 if (nTopEnd
> MAXROW
)
1405 nTopEnd
= lcl_LastVisible( aViewData
);
1407 if ( nTopEnd
> nEndPos
)
1412 long nSmall
= pRowBar
[SC_SPLIT_BOTTOM
]->GetSmallWidth();
1413 long nBig
= pRowBar
[SC_SPLIT_BOTTOM
]->GetBigWidth();
1414 long nDiff
= nBig
- nSmall
;
1418 else if (nEndPos
<1) // avoid extra step at 0 (when only one row is visible)
1420 long nWidth
= nBig
- ( 10000 - nEndPos
) * nDiff
/ 10000;
1422 if ( nWidth
!= pRowBar
[SC_SPLIT_BOTTOM
]->GetWidth() && !bInUpdateHeader
)
1424 bInUpdateHeader
= true;
1426 pRowBar
[SC_SPLIT_BOTTOM
]->SetWidth( nWidth
);
1427 if (pRowBar
[SC_SPLIT_TOP
])
1428 pRowBar
[SC_SPLIT_TOP
]->SetWidth( nWidth
);
1432 // auf VCL gibt's Update ohne Ende (jedes Update gilt fuer alle Fenster)
1433 //aCornerButton->Update(); // der bekommt sonst nie ein Update
1435 bInUpdateHeader
= false;
1439 inline void ShowHide( vcl::Window
* pWin
, bool bShow
)
1441 OSL_ENSURE(pWin
|| !bShow
, "Fenster ist nicht da");
1446 void ScTabView::UpdateShow()
1448 bool bHScrollMode
= aViewData
.IsHScrollMode();
1449 bool bVScrollMode
= aViewData
.IsVScrollMode();
1450 bool bTabMode
= aViewData
.IsTabMode();
1451 bool bOutlMode
= aViewData
.IsOutlineMode();
1452 bool bHOutline
= bOutlMode
&& lcl_HasColOutline(aViewData
);
1453 bool bVOutline
= bOutlMode
&& lcl_HasRowOutline(aViewData
);
1454 bool bHeader
= aViewData
.IsHeaderMode();
1456 bool bShowH
= ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
);
1457 bool bShowV
= ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
);
1459 if ( aViewData
.GetDocShell()->IsPreview() )
1460 bHScrollMode
= bVScrollMode
= bTabMode
= bHeader
= bOutlMode
= bHOutline
= bVOutline
= false;
1464 if (bShowH
&& !pGridWin
[SC_SPLIT_BOTTOMRIGHT
])
1466 pGridWin
[SC_SPLIT_BOTTOMRIGHT
] = VclPtr
<ScGridWindow
>::Create( pFrameWin
, &aViewData
, SC_SPLIT_BOTTOMRIGHT
);
1467 DoAddWin( pGridWin
[SC_SPLIT_BOTTOMRIGHT
] );
1469 if (bShowV
&& !pGridWin
[SC_SPLIT_TOPLEFT
])
1471 pGridWin
[SC_SPLIT_TOPLEFT
] = VclPtr
<ScGridWindow
>::Create( pFrameWin
, &aViewData
, SC_SPLIT_TOPLEFT
);
1472 DoAddWin( pGridWin
[SC_SPLIT_TOPLEFT
] );
1474 if (bShowH
&& bShowV
&& !pGridWin
[SC_SPLIT_TOPRIGHT
])
1476 pGridWin
[SC_SPLIT_TOPRIGHT
] = VclPtr
<ScGridWindow
>::Create( pFrameWin
, &aViewData
, SC_SPLIT_TOPRIGHT
);
1477 DoAddWin( pGridWin
[SC_SPLIT_TOPRIGHT
] );
1480 if (bHOutline
&& !pColOutline
[SC_SPLIT_LEFT
])
1481 pColOutline
[SC_SPLIT_LEFT
] = VclPtr
<ScOutlineWindow
>::Create( pFrameWin
, SC_OUTLINE_HOR
, &aViewData
, SC_SPLIT_BOTTOMLEFT
);
1482 if (bShowH
&& bHOutline
&& !pColOutline
[SC_SPLIT_RIGHT
])
1483 pColOutline
[SC_SPLIT_RIGHT
] = VclPtr
<ScOutlineWindow
>::Create( pFrameWin
, SC_OUTLINE_HOR
, &aViewData
, SC_SPLIT_BOTTOMRIGHT
);
1485 if (bVOutline
&& !pRowOutline
[SC_SPLIT_BOTTOM
])
1486 pRowOutline
[SC_SPLIT_BOTTOM
] = VclPtr
<ScOutlineWindow
>::Create( pFrameWin
, SC_OUTLINE_VER
, &aViewData
, SC_SPLIT_BOTTOMLEFT
);
1487 if (bShowV
&& bVOutline
&& !pRowOutline
[SC_SPLIT_TOP
])
1488 pRowOutline
[SC_SPLIT_TOP
] = VclPtr
<ScOutlineWindow
>::Create( pFrameWin
, SC_OUTLINE_VER
, &aViewData
, SC_SPLIT_TOPLEFT
);
1490 if (bShowH
&& bHeader
&& !pColBar
[SC_SPLIT_RIGHT
])
1491 pColBar
[SC_SPLIT_RIGHT
] = VclPtr
<ScColBar
>::Create( pFrameWin
, &aViewData
, SC_SPLIT_RIGHT
,
1492 &aHdrFunc
, pHdrSelEng
);
1493 if (bShowV
&& bHeader
&& !pRowBar
[SC_SPLIT_TOP
])
1494 pRowBar
[SC_SPLIT_TOP
] = VclPtr
<ScRowBar
>::Create( pFrameWin
, &aViewData
, SC_SPLIT_TOP
,
1495 &aHdrFunc
, pHdrSelEng
);
1499 ShowHide( aHScrollLeft
.get(), bHScrollMode
);
1500 ShowHide( aHScrollRight
.get(), bShowH
&& bHScrollMode
);
1501 ShowHide( aVScrollBottom
.get(), bVScrollMode
);
1502 ShowHide( aVScrollTop
.get(), bShowV
&& bVScrollMode
);
1503 ShowHide( aScrollBarBox
.get(), bVScrollMode
|| bHScrollMode
);
1505 ShowHide( pHSplitter
, bHScrollMode
|| bShowH
); // immer angelegt
1506 ShowHide( pVSplitter
, bVScrollMode
|| bShowV
);
1507 ShowHide( pTabControl
, bTabMode
);
1509 // ab hier dynamisch angelegte
1511 ShowHide( pGridWin
[SC_SPLIT_BOTTOMRIGHT
], bShowH
);
1512 ShowHide( pGridWin
[SC_SPLIT_TOPLEFT
], bShowV
);
1513 ShowHide( pGridWin
[SC_SPLIT_TOPRIGHT
], bShowH
&& bShowV
);
1515 ShowHide( pColOutline
[SC_SPLIT_LEFT
], bHOutline
);
1516 ShowHide( pColOutline
[SC_SPLIT_RIGHT
], bShowH
&& bHOutline
);
1518 ShowHide( pRowOutline
[SC_SPLIT_BOTTOM
], bVOutline
);
1519 ShowHide( pRowOutline
[SC_SPLIT_TOP
], bShowV
&& bVOutline
);
1521 ShowHide( pColBar
[SC_SPLIT_RIGHT
], bShowH
&& bHeader
);
1522 ShowHide( pRowBar
[SC_SPLIT_TOP
], bShowV
&& bHeader
);
1524 //! neue Gridwindows eintragen
1527 bool ScTabView::UpdateVisibleRange()
1529 bool bChanged
= false;
1530 for (int i
= 0; i
< 4; ++i
)
1532 if (!pGridWin
[i
] || !pGridWin
[i
]->IsVisible())
1535 if (pGridWin
[i
]->UpdateVisibleRange())
1542 // --- Splitter --------------------------------------------------------
1544 IMPL_LINK( ScTabView
, SplitHdl
, Splitter
*, pSplitter
)
1546 if ( pSplitter
== pHSplitter
)
1547 DoHSplit( pHSplitter
->GetSplitPosPixel() );
1549 DoVSplit( pVSplitter
->GetSplitPosPixel() );
1551 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
|| aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
1552 FreezeSplitters( true );
1554 DoResize( aBorderPos
, aFrameSize
);
1559 void ScTabView::DoHSplit(long nSplitPos
)
1561 // nSplitPos is the real pixel position on the frame window,
1562 // mirroring for RTL has to be done here.
1564 bool bLayoutRTL
= aViewData
.GetDocument()->IsLayoutRTL( aViewData
.GetTabNo() );
1566 nSplitPos
= pFrameWin
->GetOutputSizePixel().Width() - nSplitPos
- 1;
1573 nMinPos
= SPLIT_MARGIN
;
1574 if ( pRowBar
[SC_SPLIT_BOTTOM
] && pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width() >= nMinPos
)
1575 nMinPos
= pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width() + 1;
1576 nMaxPos
= aFrameSize
.Width() - SPLIT_MARGIN
;
1578 ScSplitMode aOldMode
= aViewData
.GetHSplitMode();
1579 ScSplitMode aNewMode
= SC_SPLIT_NORMAL
;
1581 aViewData
.SetHSplitPos( nSplitPos
);
1582 if ( nSplitPos
< nMinPos
|| nSplitPos
> nMaxPos
)
1583 aNewMode
= SC_SPLIT_NONE
;
1585 aViewData
.SetHSplitMode( aNewMode
);
1587 if ( aNewMode
!= aOldMode
)
1589 UpdateShow(); // vor ActivatePart !!
1591 if ( aNewMode
== SC_SPLIT_NONE
)
1593 if (aViewData
.GetActivePart() == SC_SPLIT_TOPRIGHT
)
1594 ActivatePart( SC_SPLIT_TOPLEFT
);
1595 if (aViewData
.GetActivePart() == SC_SPLIT_BOTTOMRIGHT
)
1596 ActivatePart( SC_SPLIT_BOTTOMLEFT
);
1600 nOldDelta
= aViewData
.GetPosX( SC_SPLIT_LEFT
);
1601 long nLeftWidth
= nSplitPos
- pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width();
1602 if ( nLeftWidth
< 0 ) nLeftWidth
= 0;
1603 nNewDelta
= nOldDelta
+ aViewData
.CellsAtX( nOldDelta
, 1, SC_SPLIT_LEFT
,
1604 (sal_uInt16
) nLeftWidth
);
1605 if ( nNewDelta
> MAXCOL
)
1607 aViewData
.SetPosX( SC_SPLIT_RIGHT
, nNewDelta
);
1608 if ( nNewDelta
> aViewData
.GetCurX() )
1609 ActivatePart( (WhichV(aViewData
.GetActivePart()) == SC_SPLIT_BOTTOM
) ?
1610 SC_SPLIT_BOTTOMLEFT
: SC_SPLIT_TOPLEFT
);
1612 ActivatePart( (WhichV(aViewData
.GetActivePart()) == SC_SPLIT_BOTTOM
) ?
1613 SC_SPLIT_BOTTOMRIGHT
: SC_SPLIT_TOPRIGHT
);
1616 // Form-Layer muss den sichtbaren Ausschnitt aller Fenster kennen
1617 // dafuer muss hier schon der MapMode stimmen
1618 for (sal_uInt16 i
=0; i
<4; i
++)
1620 pGridWin
[i
]->SetMapMode( pGridWin
[i
]->GetDrawMapMode() );
1630 void ScTabView::DoVSplit(long nSplitPos
)
1637 nMinPos
= SPLIT_MARGIN
;
1638 if ( pColBar
[SC_SPLIT_LEFT
] && pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height() >= nMinPos
)
1639 nMinPos
= pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height() + 1;
1640 nMaxPos
= aFrameSize
.Height() - SPLIT_MARGIN
;
1642 ScSplitMode aOldMode
= aViewData
.GetVSplitMode();
1643 ScSplitMode aNewMode
= SC_SPLIT_NORMAL
;
1645 aViewData
.SetVSplitPos( nSplitPos
);
1646 if ( nSplitPos
< nMinPos
|| nSplitPos
> nMaxPos
)
1647 aNewMode
= SC_SPLIT_NONE
;
1649 aViewData
.SetVSplitMode( aNewMode
);
1651 if ( aNewMode
!= aOldMode
)
1653 UpdateShow(); // vor ActivatePart !!
1655 if ( aNewMode
== SC_SPLIT_NONE
)
1657 nOldDelta
= aViewData
.GetPosY( SC_SPLIT_TOP
);
1658 aViewData
.SetPosY( SC_SPLIT_BOTTOM
, nOldDelta
);
1660 if (aViewData
.GetActivePart() == SC_SPLIT_TOPLEFT
)
1661 ActivatePart( SC_SPLIT_BOTTOMLEFT
);
1662 if (aViewData
.GetActivePart() == SC_SPLIT_TOPRIGHT
)
1663 ActivatePart( SC_SPLIT_BOTTOMRIGHT
);
1667 if ( aOldMode
== SC_SPLIT_NONE
)
1668 nOldDelta
= aViewData
.GetPosY( SC_SPLIT_BOTTOM
);
1670 nOldDelta
= aViewData
.GetPosY( SC_SPLIT_TOP
);
1672 aViewData
.SetPosY( SC_SPLIT_TOP
, nOldDelta
);
1673 long nTopHeight
= nSplitPos
- pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height();
1674 if ( nTopHeight
< 0 ) nTopHeight
= 0;
1675 nNewDelta
= nOldDelta
+ aViewData
.CellsAtY( nOldDelta
, 1, SC_SPLIT_TOP
,
1676 (sal_uInt16
) nTopHeight
);
1677 if ( nNewDelta
> MAXROW
)
1679 aViewData
.SetPosY( SC_SPLIT_BOTTOM
, nNewDelta
);
1680 if ( nNewDelta
> aViewData
.GetCurY() )
1681 ActivatePart( (WhichH(aViewData
.GetActivePart()) == SC_SPLIT_LEFT
) ?
1682 SC_SPLIT_TOPLEFT
: SC_SPLIT_TOPRIGHT
);
1684 ActivatePart( (WhichH(aViewData
.GetActivePart()) == SC_SPLIT_LEFT
) ?
1685 SC_SPLIT_BOTTOMLEFT
: SC_SPLIT_BOTTOMRIGHT
);
1688 // Form-Layer muss den sichtbaren Ausschnitt aller Fenster kennen
1689 // dafuer muss hier schon der MapMode stimmen
1690 for (sal_uInt16 i
=0; i
<4; i
++)
1692 pGridWin
[i
]->SetMapMode( pGridWin
[i
]->GetDrawMapMode() );
1702 Point
ScTabView::GetInsertPos()
1704 ScDocument
* pDoc
= aViewData
.GetDocument();
1705 SCCOL nCol
= aViewData
.GetCurX();
1706 SCROW nRow
= aViewData
.GetCurY();
1707 SCTAB nTab
= aViewData
.GetTabNo();
1709 for (SCCOL i
=0; i
<nCol
; i
++)
1710 nPosX
+= pDoc
->GetColWidth(i
,nTab
);
1711 nPosX
= (long)(nPosX
* HMM_PER_TWIPS
);
1712 if ( pDoc
->IsNegativePage( nTab
) )
1714 long nPosY
= (long) pDoc
->GetRowHeight( 0, nRow
-1, nTab
);
1715 nPosY
= (long)(nPosY
* HMM_PER_TWIPS
);
1716 return Point(nPosX
,nPosY
);
1719 Point
ScTabView::GetChartInsertPos( const Size
& rSize
, const ScRange
& rCellRange
)
1722 const long nBorder
= 100; // leave 1mm for border
1723 long nNeededWidth
= rSize
.Width() + 2 * nBorder
;
1724 long nNeededHeight
= rSize
.Height() + 2 * nBorder
;
1726 // use the active window, or lower/right if frozen (as in CalcZoom)
1727 ScSplitPos eUsedPart
= aViewData
.GetActivePart();
1728 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
1729 eUsedPart
= (WhichV(eUsedPart
)==SC_SPLIT_TOP
) ? SC_SPLIT_TOPRIGHT
: SC_SPLIT_BOTTOMRIGHT
;
1730 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
1731 eUsedPart
= (WhichH(eUsedPart
)==SC_SPLIT_LEFT
) ? SC_SPLIT_BOTTOMLEFT
: SC_SPLIT_BOTTOMRIGHT
;
1733 ScGridWindow
* pWin
= pGridWin
[eUsedPart
];
1734 OSL_ENSURE( pWin
, "Window not found" );
1737 ActivatePart( eUsedPart
);
1739 // get the visible rectangle in logic units
1741 MapMode aDrawMode
= pWin
->GetDrawMapMode();
1742 Rectangle
aVisible( pWin
->PixelToLogic( Rectangle( Point(0,0), pWin
->GetOutputSizePixel() ), aDrawMode
) );
1744 ScDocument
* pDoc
= aViewData
.GetDocument();
1745 SCTAB nTab
= aViewData
.GetTabNo();
1746 bool bLayoutRTL
= pDoc
->IsLayoutRTL( nTab
);
1747 long nLayoutSign
= bLayoutRTL
? -1 : 1;
1749 long nDocX
= (long)( (double) pDoc
->GetColOffset( MAXCOL
+ 1, nTab
) * HMM_PER_TWIPS
) * nLayoutSign
;
1750 long nDocY
= (long)( (double) pDoc
->GetRowOffset( MAXROW
+ 1, nTab
) * HMM_PER_TWIPS
);
1752 if ( aVisible
.Left() * nLayoutSign
> nDocX
* nLayoutSign
)
1753 aVisible
.Left() = nDocX
;
1754 if ( aVisible
.Right() * nLayoutSign
> nDocX
* nLayoutSign
)
1755 aVisible
.Right() = nDocX
;
1756 if ( aVisible
.Top() > nDocY
)
1757 aVisible
.Top() = nDocY
;
1758 if ( aVisible
.Bottom() > nDocY
)
1759 aVisible
.Bottom() = nDocY
;
1761 // get the logic position of the selection
1763 Rectangle aSelection
= pDoc
->GetMMRect( rCellRange
.aStart
.Col(), rCellRange
.aStart
.Row(),
1764 rCellRange
.aEnd
.Col(), rCellRange
.aEnd
.Row(), nTab
);
1766 long nLeftSpace
= aSelection
.Left() - aVisible
.Left();
1767 long nRightSpace
= aVisible
.Right() - aSelection
.Right();
1768 long nTopSpace
= aSelection
.Top() - aVisible
.Top();
1769 long nBottomSpace
= aVisible
.Bottom() - aSelection
.Bottom();
1771 bool bFitLeft
= ( nLeftSpace
>= nNeededWidth
);
1772 bool bFitRight
= ( nRightSpace
>= nNeededWidth
);
1774 if ( bFitLeft
|| bFitRight
)
1776 // first preference: completely left or right of the selection
1778 // if both fit, prefer left in RTL mode, right otherwise
1779 bool bPutLeft
= bFitLeft
&& ( bLayoutRTL
|| !bFitRight
);
1782 aInsertPos
.X() = aSelection
.Left() - nNeededWidth
;
1784 aInsertPos
.X() = aSelection
.Right() + 1;
1786 // align with top of selection (is moved again if it doesn't fit)
1787 aInsertPos
.Y() = std::max( aSelection
.Top(), aVisible
.Top() );
1789 else if ( nTopSpace
>= nNeededHeight
|| nBottomSpace
>= nNeededHeight
)
1791 // second preference: completely above or below the selection
1793 if ( nBottomSpace
> nNeededHeight
) // bottom is preferred
1794 aInsertPos
.Y() = aSelection
.Bottom() + 1;
1796 aInsertPos
.Y() = aSelection
.Top() - nNeededHeight
;
1798 // align with (logic) left edge of selection (moved again if it doesn't fit)
1800 aInsertPos
.X() = std::min( aSelection
.Right(), aVisible
.Right() ) - nNeededWidth
+ 1;
1802 aInsertPos
.X() = std::max( aSelection
.Left(), aVisible
.Left() );
1806 // place to the (logic) right of the selection and move so it fits
1809 aInsertPos
.X() = aSelection
.Left() - nNeededWidth
;
1811 aInsertPos
.X() = aSelection
.Right() + 1;
1812 aInsertPos
.Y() = std::max( aSelection
.Top(), aVisible
.Top() );
1815 // move the position if the object doesn't fit in the screen
1817 Rectangle
aCompareRect( aInsertPos
, Size( nNeededWidth
, nNeededHeight
) );
1818 if ( aCompareRect
.Right() > aVisible
.Right() )
1819 aInsertPos
.X() -= aCompareRect
.Right() - aVisible
.Right();
1820 if ( aCompareRect
.Bottom() > aVisible
.Bottom() )
1821 aInsertPos
.Y() -= aCompareRect
.Bottom() - aVisible
.Bottom();
1823 if ( aInsertPos
.X() < aVisible
.Left() )
1824 aInsertPos
.X() = aVisible
.Left();
1825 if ( aInsertPos
.Y() < aVisible
.Top() )
1826 aInsertPos
.Y() = aVisible
.Top();
1828 // nNeededWidth / nNeededHeight includes all borders - move aInsertPos to the
1829 // object position, inside the border
1831 aInsertPos
.X() += nBorder
;
1832 aInsertPos
.Y() += nBorder
;
1837 Point
ScTabView::GetChartDialogPos( const Size
& rDialogSize
, const Rectangle
& rLogicChart
)
1839 // rDialogSize must be in pixels, rLogicChart in 1/100 mm. Return value is in pixels.
1843 // use the active window, or lower/right if frozen (as in CalcZoom)
1844 ScSplitPos eUsedPart
= aViewData
.GetActivePart();
1845 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
1846 eUsedPart
= (WhichV(eUsedPart
)==SC_SPLIT_TOP
) ? SC_SPLIT_TOPRIGHT
: SC_SPLIT_BOTTOMRIGHT
;
1847 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
1848 eUsedPart
= (WhichH(eUsedPart
)==SC_SPLIT_LEFT
) ? SC_SPLIT_BOTTOMLEFT
: SC_SPLIT_BOTTOMRIGHT
;
1850 ScGridWindow
* pWin
= pGridWin
[eUsedPart
];
1851 OSL_ENSURE( pWin
, "Window not found" );
1854 MapMode aDrawMode
= pWin
->GetDrawMapMode();
1855 Rectangle aObjPixel
= pWin
->LogicToPixel( rLogicChart
, aDrawMode
);
1856 Rectangle
aObjAbs( pWin
->OutputToAbsoluteScreenPixel( aObjPixel
.TopLeft() ),
1857 pWin
->OutputToAbsoluteScreenPixel( aObjPixel
.BottomRight() ) );
1859 Rectangle aDesktop
= pWin
->GetDesktopRectPixel();
1860 Size aSpace
= pWin
->LogicToPixel( Size( 8, 12 ), MAP_APPFONT
);
1862 ScDocument
* pDoc
= aViewData
.GetDocument();
1863 SCTAB nTab
= aViewData
.GetTabNo();
1864 bool bLayoutRTL
= pDoc
->IsLayoutRTL( nTab
);
1866 bool bCenterHor
= false;
1868 if ( aDesktop
.Bottom() - aObjAbs
.Bottom() >= rDialogSize
.Height() + aSpace
.Height() )
1870 // first preference: below the chart
1872 aRet
.Y() = aObjAbs
.Bottom() + aSpace
.Height();
1875 else if ( aObjAbs
.Top() - aDesktop
.Top() >= rDialogSize
.Height() + aSpace
.Height() )
1877 // second preference: above the chart
1879 aRet
.Y() = aObjAbs
.Top() - rDialogSize
.Height() - aSpace
.Height();
1884 bool bFitLeft
= ( aObjAbs
.Left() - aDesktop
.Left() >= rDialogSize
.Width() + aSpace
.Width() );
1885 bool bFitRight
= ( aDesktop
.Right() - aObjAbs
.Right() >= rDialogSize
.Width() + aSpace
.Width() );
1887 if ( bFitLeft
|| bFitRight
)
1889 // if both fit, prefer right in RTL mode, left otherwise
1890 bool bPutRight
= bFitRight
&& ( bLayoutRTL
|| !bFitLeft
);
1892 aRet
.X() = aObjAbs
.Right() + aSpace
.Width();
1894 aRet
.X() = aObjAbs
.Left() - rDialogSize
.Width() - aSpace
.Width();
1896 // center vertically
1897 aRet
.Y() = aObjAbs
.Top() + ( aObjAbs
.GetHeight() - rDialogSize
.Height() ) / 2;
1901 // doesn't fit on any edge - put at the bottom of the screen
1902 aRet
.Y() = aDesktop
.Bottom() - rDialogSize
.Height();
1907 aRet
.X() = aObjAbs
.Left() + ( aObjAbs
.GetWidth() - rDialogSize
.Width() ) / 2;
1909 // limit to screen (centering might lead to invalid positions)
1910 if ( aRet
.X() + rDialogSize
.Width() - 1 > aDesktop
.Right() )
1911 aRet
.X() = aDesktop
.Right() - rDialogSize
.Width() + 1;
1912 if ( aRet
.X() < aDesktop
.Left() )
1913 aRet
.X() = aDesktop
.Left();
1914 if ( aRet
.Y() + rDialogSize
.Height() - 1 > aDesktop
.Bottom() )
1915 aRet
.Y() = aDesktop
.Bottom() - rDialogSize
.Height() + 1;
1916 if ( aRet
.Y() < aDesktop
.Top() )
1917 aRet
.Y() = aDesktop
.Top();
1923 void ScTabView::LockModifiers( sal_uInt16 nModifiers
)
1925 pSelEngine
->LockModifiers( nModifiers
);
1926 pHdrSelEng
->LockModifiers( nModifiers
);
1929 sal_uInt16
ScTabView::GetLockedModifiers() const
1931 return pSelEngine
->GetLockedModifiers();
1934 Point
ScTabView::GetMousePosPixel()
1937 ScGridWindow
* pWin
= GetActiveWin();
1940 aPos
= pWin
->GetMousePosPixel();
1945 void ScTabView::FreezeSplitters( bool bFreeze
)
1947 ScSplitMode eOldH
= aViewData
.GetHSplitMode();
1948 ScSplitMode eOldV
= aViewData
.GetVSplitMode();
1950 ScSplitPos ePos
= SC_SPLIT_BOTTOMLEFT
;
1951 if ( eOldV
!= SC_SPLIT_NONE
)
1952 ePos
= SC_SPLIT_TOPLEFT
;
1953 vcl::Window
* pWin
= pGridWin
[ePos
];
1955 bool bLayoutRTL
= aViewData
.GetDocument()->IsLayoutRTL( aViewData
.GetTabNo() );
1959 Point aWinStart
= pWin
->GetPosPixel();
1960 aViewData
.GetDocShell()->SetDocumentModified();
1965 if (eOldH
!= SC_SPLIT_NONE
|| eOldV
!= SC_SPLIT_NONE
)
1967 if (eOldH
!= SC_SPLIT_NONE
)
1969 long nSplitPos
= aViewData
.GetHSplitPos();
1971 nSplitPos
= pFrameWin
->GetOutputSizePixel().Width() - nSplitPos
- 1;
1972 aSplit
.X() = nSplitPos
- aWinStart
.X();
1974 if (eOldV
!= SC_SPLIT_NONE
)
1975 aSplit
.Y() = aViewData
.GetVSplitPos() - aWinStart
.Y();
1977 aViewData
.GetPosFromPixel( aSplit
.X(), aSplit
.Y(), ePos
, nPosX
, nPosY
);
1980 aViewData
.GetMouseQuadrant( aSplit
, ePos
, nPosX
, nPosY
, bLeft
, bTop
);
1988 nPosX
= static_cast<SCsCOL
>( aViewData
.GetCurX());
1989 nPosY
= static_cast<SCsROW
>( aViewData
.GetCurY());
1992 SCCOL nLeftPos
= aViewData
.GetPosX(SC_SPLIT_LEFT
);
1993 SCROW nTopPos
= aViewData
.GetPosY(SC_SPLIT_BOTTOM
);
1994 SCCOL nRightPos
= static_cast<SCCOL
>(nPosX
);
1995 SCROW nBottomPos
= static_cast<SCROW
>(nPosY
);
1996 if (eOldH
!= SC_SPLIT_NONE
)
1997 if (aViewData
.GetPosX(SC_SPLIT_RIGHT
) > nRightPos
)
1998 nRightPos
= aViewData
.GetPosX(SC_SPLIT_RIGHT
);
1999 if (eOldV
!= SC_SPLIT_NONE
)
2001 nTopPos
= aViewData
.GetPosY(SC_SPLIT_TOP
);
2002 if (aViewData
.GetPosY(SC_SPLIT_BOTTOM
) > nBottomPos
)
2003 nBottomPos
= aViewData
.GetPosY(SC_SPLIT_BOTTOM
);
2006 aSplit
= aViewData
.GetScrPos( static_cast<SCCOL
>(nPosX
), static_cast<SCROW
>(nPosY
), ePos
, true );
2007 if (nPosX
> aViewData
.GetPosX(SC_SPLIT_LEFT
)) // (aSplit.X() > 0) doesn't work for RTL
2009 long nSplitPos
= aSplit
.X() + aWinStart
.X();
2011 nSplitPos
= pFrameWin
->GetOutputSizePixel().Width() - nSplitPos
- 1;
2013 aViewData
.SetHSplitMode( SC_SPLIT_FIX
);
2014 aViewData
.SetHSplitPos( nSplitPos
);
2015 aViewData
.SetFixPosX( nPosX
);
2017 aViewData
.SetPosX(SC_SPLIT_LEFT
, nLeftPos
);
2018 aViewData
.SetPosX(SC_SPLIT_RIGHT
, nRightPos
);
2021 aViewData
.SetHSplitMode( SC_SPLIT_NONE
);
2024 aViewData
.SetVSplitMode( SC_SPLIT_FIX
);
2025 aViewData
.SetVSplitPos( aSplit
.Y() + aWinStart
.Y() );
2026 aViewData
.SetFixPosY( nPosY
);
2028 aViewData
.SetPosY(SC_SPLIT_TOP
, nTopPos
);
2029 aViewData
.SetPosY(SC_SPLIT_BOTTOM
, nBottomPos
);
2032 aViewData
.SetVSplitMode( SC_SPLIT_NONE
);
2034 else // Fixierung aufheben
2036 if ( eOldH
== SC_SPLIT_FIX
)
2037 aViewData
.SetHSplitMode( SC_SPLIT_NORMAL
);
2038 if ( eOldV
== SC_SPLIT_FIX
)
2039 aViewData
.SetVSplitMode( SC_SPLIT_NORMAL
);
2042 // Form-Layer muss den sichtbaren Ausschnitt aller Fenster kennen
2043 // dafuer muss hier schon der MapMode stimmen
2044 for (sal_uInt16 i
=0; i
<4; i
++)
2046 pGridWin
[i
]->SetMapMode( pGridWin
[i
]->GetDrawMapMode() );
2049 RepeatResize(false);
2056 // SC_FOLLOW_NONE: only update active part
2057 AlignToCursor( aViewData
.GetCurX(), aViewData
.GetCurY(), SC_FOLLOW_NONE
);
2058 UpdateAutoFillMark();
2063 void ScTabView::RemoveSplit()
2070 void ScTabView::SplitAtCursor()
2072 ScSplitPos ePos
= SC_SPLIT_BOTTOMLEFT
;
2073 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
2074 ePos
= SC_SPLIT_TOPLEFT
;
2075 vcl::Window
* pWin
= pGridWin
[ePos
];
2076 Point aWinStart
= pWin
->GetPosPixel();
2078 SCCOL nPosX
= aViewData
.GetCurX();
2079 SCROW nPosY
= aViewData
.GetCurY();
2080 Point aSplit
= aViewData
.GetScrPos( nPosX
, nPosY
, ePos
, true );
2082 DoHSplit( aSplit
.X() + aWinStart
.X() );
2086 DoVSplit( aSplit
.Y() + aWinStart
.Y() );
2092 void ScTabView::SplitAtPixel( const Point
& rPixel
, bool bHor
, bool bVer
)
2094 // Pixel ist auf die ganze View bezogen, nicht auf das erste GridWin
2098 if ( rPixel
.X() > 0 )
2099 DoHSplit( rPixel
.X() );
2105 if ( rPixel
.Y() > 0 )
2106 DoVSplit( rPixel
.Y() );
2113 void ScTabView::InvalidateSplit()
2115 SfxBindings
& rBindings
= aViewData
.GetBindings();
2116 rBindings
.Invalidate( SID_WINDOW_SPLIT
);
2117 rBindings
.Invalidate( SID_WINDOW_FIX
);
2119 pHSplitter
->SetFixed( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
);
2120 pVSplitter
->SetFixed( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
);
2123 void ScTabView::SetNewVisArea()
2125 // fuer die Controls muss bei VisAreaChanged der Draw-MapMode eingestellt sein
2126 // (auch wenn ansonsten der Edit-MapMode gesetzt ist)
2127 MapMode aOldMode
[4];
2128 MapMode aDrawMode
[4];
2133 aOldMode
[i
] = pGridWin
[i
]->GetMapMode();
2134 aDrawMode
[i
] = pGridWin
[i
]->GetDrawMapMode();
2135 if (aDrawMode
[i
] != aOldMode
[i
])
2136 pGridWin
[i
]->SetMapMode(aDrawMode
[i
]);
2139 vcl::Window
* pActive
= pGridWin
[aViewData
.GetActivePart()];
2141 aViewData
.GetViewShell()->VisAreaChanged(
2142 pActive
->PixelToLogic(Rectangle(Point(),pActive
->GetOutputSizePixel())) );
2144 pDrawView
->VisAreaChanged(); // kein Window uebergeben -> alle Fenster
2146 UpdateAllOverlays(); // #i79909# with drawing MapMode set
2149 if (pGridWin
[i
] && aDrawMode
[i
] != aOldMode
[i
])
2151 pGridWin
[i
]->flushOverlayManager(); // #i79909# flush overlays before switching to edit MapMode
2152 pGridWin
[i
]->SetMapMode(aOldMode
[i
]);
2155 SfxViewFrame
* pViewFrame
= aViewData
.GetViewShell()->GetViewFrame();
2158 SfxFrame
& rFrame
= pViewFrame
->GetFrame();
2159 com::sun::star::uno::Reference
<com::sun::star::frame::XController
> xController
= rFrame
.GetController();
2160 if (xController
.is())
2162 ScTabViewObj
* pImp
= ScTabViewObj::getImplementation( xController
);
2164 pImp
->VisAreaChanged();
2167 if (aViewData
.GetViewShell()->HasAccessibilityObjects())
2168 aViewData
.GetViewShell()->BroadcastAccessibility(SfxSimpleHint(SC_HINT_ACC_VISAREACHANGED
));
2171 bool ScTabView::HasPageFieldDataAtCursor() const
2173 ScGridWindow
* pWin
= pGridWin
[aViewData
.GetActivePart()];
2174 SCCOL nCol
= aViewData
.GetCurX();
2175 SCROW nRow
= aViewData
.GetCurY();
2177 return pWin
->GetDPFieldOrientation( nCol
, nRow
) == sheet::DataPilotFieldOrientation_PAGE
;
2182 void ScTabView::StartDataSelect()
2184 ScGridWindow
* pWin
= pGridWin
[aViewData
.GetActivePart()];
2185 SCCOL nCol
= aViewData
.GetCurX();
2186 SCROW nRow
= aViewData
.GetCurY();
2191 switch (pWin
->GetDPFieldOrientation(nCol
, nRow
))
2193 case sheet::DataPilotFieldOrientation_PAGE
:
2194 // #i36598# If the cursor is on a page field's data cell,
2195 // no meaningful input is possible anyway, so this function
2196 // can be used to select a page field entry.
2197 pWin
->LaunchPageFieldMenu( nCol
, nRow
);
2199 case sheet::DataPilotFieldOrientation_COLUMN
:
2200 case sheet::DataPilotFieldOrientation_ROW
:
2201 pWin
->LaunchDPFieldMenu( nCol
, nRow
);
2207 // Do autofilter if the current cell has autofilter button. Otherwise do
2208 // a normal data select popup.
2209 const ScMergeFlagAttr
* pAttr
= static_cast<const ScMergeFlagAttr
*>(
2210 aViewData
.GetDocument()->GetAttr(
2211 nCol
, nRow
, aViewData
.GetTabNo(), ATTR_MERGE_FLAG
));
2213 if (pAttr
->HasAutoFilter())
2214 pWin
->LaunchAutoFilterMenu(nCol
, nRow
);
2216 pWin
->LaunchDataSelectMenu(nCol
, nRow
, true);
2219 void ScTabView::EnableRefInput(bool bFlag
)
2221 aHScrollLeft
->EnableInput(bFlag
);
2222 aHScrollRight
->EnableInput(bFlag
);
2223 aVScrollBottom
->EnableInput(bFlag
);
2224 aVScrollTop
->EnableInput(bFlag
);
2225 aScrollBarBox
->EnableInput(bFlag
);
2227 // ab hier dynamisch angelegte
2229 if(pTabControl
!=nullptr) pTabControl
->EnableInput(bFlag
,true);
2231 if(pGridWin
[SC_SPLIT_BOTTOMLEFT
]!=nullptr)
2232 pGridWin
[SC_SPLIT_BOTTOMLEFT
]->EnableInput(bFlag
,false);
2233 if(pGridWin
[SC_SPLIT_BOTTOMRIGHT
]!=nullptr)
2234 pGridWin
[SC_SPLIT_BOTTOMRIGHT
]->EnableInput(bFlag
,false);
2235 if(pGridWin
[SC_SPLIT_TOPLEFT
]!=nullptr)
2236 pGridWin
[SC_SPLIT_TOPLEFT
]->EnableInput(bFlag
,false);
2237 if(pGridWin
[SC_SPLIT_TOPRIGHT
]!=nullptr)
2238 pGridWin
[SC_SPLIT_TOPRIGHT
]->EnableInput(bFlag
,false);
2239 if(pColBar
[SC_SPLIT_RIGHT
]!=nullptr)
2240 pColBar
[SC_SPLIT_RIGHT
]->EnableInput(bFlag
,false);
2241 if(pRowBar
[SC_SPLIT_TOP
]!=nullptr)
2242 pRowBar
[SC_SPLIT_TOP
]->EnableInput(bFlag
,false);
2245 void ScTabView::SetInRefMode( bool bRefMode
)
2247 if(pGridWin
[SC_SPLIT_BOTTOMLEFT
])
2248 pGridWin
[SC_SPLIT_BOTTOMLEFT
]->SetInRefMode( bRefMode
);
2249 if(pGridWin
[SC_SPLIT_BOTTOMRIGHT
])
2250 pGridWin
[SC_SPLIT_BOTTOMRIGHT
]->SetInRefMode( bRefMode
);
2251 if(pGridWin
[SC_SPLIT_TOPLEFT
])
2252 pGridWin
[SC_SPLIT_TOPLEFT
]->SetInRefMode( bRefMode
);
2253 if(pGridWin
[SC_SPLIT_TOPRIGHT
])
2254 pGridWin
[SC_SPLIT_TOPRIGHT
]->SetInRefMode( bRefMode
);
2257 bool ScTabView::ContinueOnlineSpelling()
2259 bool bChanged
= false;
2260 for (int i
= 0; i
< 4; ++i
)
2262 if (!pGridWin
[i
] || !pGridWin
[i
]->IsVisible())
2265 if (pGridWin
[i
]->ContinueOnlineSpelling())
2272 void ScTabView::EnableAutoSpell( bool bEnable
)
2274 for (int i
= 0; i
< 4; ++i
)
2279 pGridWin
[i
]->EnableAutoSpell(bEnable
);
2283 void ScTabView::ResetAutoSpell()
2285 for (int i
= 0; i
< 4; ++i
)
2290 pGridWin
[i
]->ResetAutoSpell();
2294 void ScTabView::SetAutoSpellData( SCCOL nPosX
, SCROW nPosY
, const std::vector
<editeng::MisspellRanges
>* pRanges
)
2296 for (int i
= 0; i
< 4; ++i
)
2301 pGridWin
[i
]->SetAutoSpellData(nPosX
, nPosY
, pRanges
);
2305 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */