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 <scitems.hxx>
21 #include <sfx2/viewfrm.hxx>
22 #include <sfx2/bindings.hxx>
23 #include <vcl/commandevent.hxx>
24 #include <vcl/help.hxx>
25 #include <vcl/settings.hxx>
26 #include <vcl/cursor.hxx>
27 #include <sal/log.hxx>
28 #include <tools/svborder.hxx>
29 #include <tools/json_writer.hxx>
30 #include <o3tl/unit_conversion.hxx>
32 #include <pagedata.hxx>
33 #include <tabview.hxx>
34 #include <tabvwsh.hxx>
35 #include <document.hxx>
36 #include <gridwin.hxx>
37 #include <olinewin.hxx>
38 #include <olinetab.hxx>
39 #include <tabsplit.hxx>
40 #include <colrowba.hxx>
41 #include <tabcont.hxx>
44 #include <strings.hrc>
45 #include <globstr.hrc>
46 #include <scresid.hxx>
47 #include <drawview.hxx>
49 #include <viewuno.hxx>
50 #include <appoptio.hxx>
52 #include <spellcheckcontext.hxx>
53 #include <comphelper/lok.hxx>
54 #include <sfx2/lokhelper.hxx>
55 #include <osl/diagnose.h>
57 #include <boost/property_tree/ptree.hpp>
58 #include <boost/property_tree/json_parser.hpp>
60 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
64 #include <basegfx/utils/zoomtools.hxx>
66 #define SPLIT_MARGIN 30
67 #define SPLIT_HANDLE_SIZE 5
68 constexpr sal_Int32 TAB_HEIGHT_MARGIN
= 10;
70 #define SC_ICONSIZE 36
72 #define SC_SCROLLBAR_MIN 30
73 #define SC_TABBAR_MIN 6
75 using namespace ::com::sun::star
;
79 ScCornerButton::ScCornerButton( vcl::Window
* pParent
, ScViewData
* pData
) :
80 Window( pParent
, WinBits( 0 ) ),
83 ScCornerButton::EnableRTL( false );
84 SetQuickHelpText(ScResId(SCSTR_QHELP_SELECT_ALL_CELLS
));
87 ScCornerButton::~ScCornerButton()
91 void ScCornerButton::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
93 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
94 SetBackground(rStyleSettings
.GetFaceColor());
96 Size
aSize(GetOutputSizePixel());
97 tools::Long nPosX
= aSize
.Width() - 1;
98 tools::Long nPosY
= aSize
.Height() - 1;
100 Window::Paint(rRenderContext
, rRect
);
102 bool bLayoutRTL
= pViewData
->GetDocument().IsLayoutRTL( pViewData
->GetTabNo() );
103 tools::Long nDarkX
= bLayoutRTL
? 0 : nPosX
;
105 // both buttons have the same look now - only dark right/bottom lines
106 rRenderContext
.SetLineColor(rStyleSettings
.GetShadowColor());
107 rRenderContext
.DrawLine(Point(0, nPosY
), Point(nPosX
, nPosY
));
108 rRenderContext
.DrawLine(Point(nDarkX
, 0), Point(nDarkX
, nPosY
));
111 void ScCornerButton::StateChanged( StateChangedType nType
)
113 Window::StateChanged( nType
);
115 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
116 SetBackground( rStyleSettings
.GetFaceColor() );
120 void ScCornerButton::DataChanged( const DataChangedEvent
& rDCEvt
)
122 Window::DataChanged( rDCEvt
);
124 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
125 SetBackground( rStyleSettings
.GetFaceColor() );
129 void ScCornerButton::Resize()
134 void ScCornerButton::MouseButtonDown( const MouseEvent
& rMEvt
)
136 ScModule
* pScMod
= ScModule::get();
137 bool bDisable
= pScMod
->IsFormulaMode() || pScMod
->IsModalMode();
140 ScTabViewShell
* pViewSh
= pViewData
->GetViewShell();
141 pViewSh
->SetActive(); // Appear and SetViewFrame
142 pViewSh
->ActiveGrabFocus();
144 bool bControl
= rMEvt
.IsMod1();
145 pViewSh
->SelectAll( bControl
);
151 bool lcl_HasColOutline( const ScViewData
& rViewData
)
153 const ScOutlineTable
* pTable
= rViewData
.GetDocument().GetOutlineTable(rViewData
.GetTabNo());
156 const ScOutlineArray
& rArray
= pTable
->GetColArray();
157 if ( rArray
.GetDepth() > 0 )
163 bool lcl_HasRowOutline( const ScViewData
& rViewData
)
165 const ScOutlineTable
* pTable
= rViewData
.GetDocument().GetOutlineTable(rViewData
.GetTabNo());
168 const ScOutlineArray
& rArray
= pTable
->GetRowArray();
169 if ( rArray
.GetDepth() > 0 )
175 } // anonymous namespace
177 ScTabView::ScTabView( vcl::Window
* pParent
, ScDocShell
& rDocSh
, ScTabViewShell
* pViewShell
) :
178 pFrameWin( pParent
),
179 aViewData( rDocSh
, pViewShell
),
180 aFunctionSet( &aViewData
),
181 aHdrFunc( &aViewData
),
182 aVScrollTop( VclPtr
<ScrollAdaptor
>::Create( pFrameWin
, false ) ),
183 aVScrollBottom( VclPtr
<ScrollAdaptor
>::Create( pFrameWin
, false ) ),
184 aHScrollLeft( VclPtr
<ScrollAdaptor
>::Create( pFrameWin
, true ) ),
185 aHScrollRight( VclPtr
<ScrollAdaptor
>::Create( pFrameWin
, true ) ),
186 aCornerButton( VclPtr
<ScCornerButton
>::Create( pFrameWin
, &aViewData
) ),
187 aTopButton( VclPtr
<ScCornerButton
>::Create( pFrameWin
, &aViewData
) ),
188 aScrollTimer("ScTabView aScrollTimer"),
189 pTimerWindow( nullptr ),
190 aExtraEditViewManager( pViewShell
, pGridWin
),
191 nTipVisible( nullptr ),
192 nTipAlign( QuickHelpFlags::NONE
),
195 meHighlightBlockMode(None
),
197 nBlockStartXOrig( 0 ),
200 nBlockStartYOrig( 0 ),
206 mfPendingTabBarWidth( -1.0 ),
207 mnLOKStartHeaderRow( -2 ),
208 mnLOKEndHeaderRow( -1 ),
209 mnLOKStartHeaderCol( -2 ),
210 mnLOKEndHeaderCol( -1 ),
212 bInUpdateHeader( false ),
213 bInActivatePart( false ),
214 bInZoomUpdate( false ),
215 bMoveIsShift( false ),
216 bDrawSelMode( false ),
217 bLockPaintBrush( false ),
222 mbInlineWithScrollbar( false )
224 // copy settings of existing shell for this document
225 if (ScTabViewShell
* pExistingViewShell
= rDocSh
.GetBestViewShell())
227 aViewRenderingData
= pExistingViewShell
->GetViewRenderingData();
228 EnableAutoSpell(pExistingViewShell
->IsAutoSpell());
233 void ScTabView::InitScrollBar(ScrollAdaptor
& rScrollBar
, tools::Long nMaxVal
, const Link
<weld::Scrollbar
&, void>& rLink
)
235 rScrollBar
.SetRange( Range( 0, nMaxVal
) );
236 rScrollBar
.SetLineSize( 1 );
237 rScrollBar
.SetPageSize( 1 ); // is queried separately
238 rScrollBar
.SetVisibleSize( 10 ); // is reset by Resize
240 rScrollBar
.SetScrollHdl(rLink
);
241 rScrollBar
.SetMouseReleaseHdl(LINK(this, ScTabView
, EndScrollHdl
));
243 rScrollBar
.EnableRTL( aViewData
.GetDocument().IsLayoutRTL( aViewData
.GetTabNo() ) );
245 // Related: tdf#155266 Eliminate delayed scrollbar redrawing when swiping
246 // By default, the layout idle timer in the InterimWindowItem class
247 // is set to TaskPriority::RESIZE. That is too high of a priority as
248 // it appears that other timers are drawing after the scrollbar has been
250 // As a result, when swiping, the content moves fluidly but the scrollbar
251 // thumb does not move until after swiping stops or pauses. Then, after a
252 // short lag, the scrollbar thumb finally "jumps" to the expected
254 // So, to fix this scrollbar "stickiness" when swiping, setting the
255 // priority to TaskPriority::POST_PAINT causes the scrollbar to be
256 // redrawn after any competing timers.
257 rScrollBar
.SetPriority(TaskPriority::POST_PAINT
);
261 void ScTabView::SetTimer( ScGridWindow
* pWin
, const MouseEvent
& rMEvt
)
265 aScrollTimer
.Start();
268 void ScTabView::ResetTimer()
271 pTimerWindow
= nullptr;
274 IMPL_LINK_NOARG(ScTabView
, TimerHdl
, Timer
*, void)
277 pTimerWindow
->MouseMove( aTimerMEvt
);
280 // --- Resize ---------------------------------------------------------------------
282 static void lcl_SetPosSize( vcl::Window
& rWindow
, const Point
& rPos
, const Size
& rSize
,
283 tools::Long nTotalWidth
, bool bLayoutRTL
)
285 Point aNewPos
= rPos
;
288 aNewPos
.setX( nTotalWidth
- rPos
.X() - rSize
.Width() );
289 if ( aNewPos
== rWindow
.GetPosPixel() && rSize
.Width() != rWindow
.GetSizePixel().Width() )
291 // Document windows are manually painted right-to-left, so they need to
292 // be repainted if the size changes.
293 rWindow
.Invalidate();
296 rWindow
.SetPosSizePixel( aNewPos
, rSize
);
299 void ScTabView::DoResize( const Point
& rOffset
, const Size
& rSize
, bool bInner
)
303 bool bHasHint
= HasHintWindow();
307 bool bLayoutRTL
= aViewData
.GetDocument().IsLayoutRTL( aViewData
.GetTabNo() );
308 tools::Long nTotalWidth
= rSize
.Width();
310 nTotalWidth
+= 2*rOffset
.X();
312 bool bVScroll
= aViewData
.IsVScrollMode();
313 bool bHScroll
= aViewData
.IsHScrollMode();
314 bool bTabControl
= aViewData
.IsTabMode();
315 bool bHeaders
= aViewData
.IsHeaderMode();
316 bool bOutlMode
= aViewData
.IsOutlineMode();
317 bool bHOutline
= bOutlMode
&& lcl_HasColOutline(aViewData
);
318 bool bVOutline
= bOutlMode
&& lcl_HasRowOutline(aViewData
);
320 if ( aViewData
.GetDocShell()->IsPreview() )
321 bHScroll
= bVScroll
= bTabControl
= bHeaders
= bHOutline
= bVOutline
= false;
323 tools::Long nBarX
= 0;
324 tools::Long nBarY
= 0;
325 tools::Long nOutlineX
= 0;
326 tools::Long nOutlineY
= 0;
327 tools::Long nOutPosX
;
328 tools::Long nOutPosY
;
330 tools::Long nPosX
= rOffset
.X();
331 tools::Long nPosY
= rOffset
.Y();
332 tools::Long nSizeX
= rSize
.Width();
333 tools::Long nSizeY
= rSize
.Height();
335 bMinimized
= ( nSizeX
<=SC_ICONSIZE
|| nSizeY
<=SC_ICONSIZE
);
339 float fScaleFactor
= pFrameWin
->GetDPIScaleFactor();
341 tools::Long nSplitSizeX
= SPLIT_HANDLE_SIZE
* fScaleFactor
;
342 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
344 tools::Long nSplitSizeY
= SPLIT_HANDLE_SIZE
* fScaleFactor
;
345 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
348 aBorderPos
= rOffset
;
351 const StyleSettings
& rStyleSettings
= pFrameWin
->GetSettings().GetStyleSettings();
354 Size aFontSize
= rStyleSettings
.GetTabFont().GetFontSize();
355 MapMode
aPtMapMode(MapUnit::MapPoint
);
356 aFontSize
= pFrameWin
->LogicToPixel(aFontSize
, aPtMapMode
);
357 sal_Int32 nTabHeight
= aFontSize
.Height() + TAB_HEIGHT_MARGIN
;
359 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
361 if ( aViewData
.GetHSplitPos() > nSizeX
- SPLIT_MARGIN
)
363 aViewData
.SetHSplitMode( SC_SPLIT_NONE
);
364 if ( WhichH( aViewData
.GetActivePart() ) == SC_SPLIT_RIGHT
)
365 ActivatePart( SC_SPLIT_BOTTOMLEFT
);
369 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
371 if ( aViewData
.GetVSplitPos() > nSizeY
- SPLIT_MARGIN
)
373 aViewData
.SetVSplitMode( SC_SPLIT_NONE
);
374 if ( WhichV( aViewData
.GetActivePart() ) == SC_SPLIT_TOP
)
375 ActivatePart( SC_SPLIT_BOTTOMLEFT
);
382 if (bHScroll
|| bVScroll
) // Scrollbars horizontal or vertical
384 tools::Long nScrollBarSize
= rStyleSettings
.GetScrollBarSize();
387 nBarX
= nScrollBarSize
;
394 if (!mbInlineWithScrollbar
)
395 nBarY
+= nScrollBarSize
;
399 tools::Long nSizeLt
= 0; // left scroll bar
400 tools::Long nSizeRt
= 0; // right scroll bar
401 tools::Long nSizeSp
= 0; // splitter
403 switch (aViewData
.GetHSplitMode())
406 nSizeSp
= nSplitSizeX
;
407 nSizeLt
= nSizeX
- nSizeSp
; // Convert the corner
409 case SC_SPLIT_NORMAL
:
410 nSizeSp
= nSplitSizeX
;
411 nSizeLt
= aViewData
.GetHSplitPos();
418 nSizeRt
= nSizeX
- nSizeLt
- nSizeSp
;
420 tools::Long nTabSize
= 0;
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
, aTabPoint
, aTabSize
, nTotalWidth
, bLayoutRTL
);
459 pTabControl
->SetSheetLayoutRTL(bLayoutRTL
);
461 Point
aHScrollLeftPoint(nPosX
+ nTabSize
, nPosY
+ nSizeY
);
462 Size
aHScrollLeftSize(nSizeLt
, nBarY
);
463 lcl_SetPosSize(*aHScrollLeft
, aHScrollLeftPoint
, aHScrollLeftSize
, nTotalWidth
, bLayoutRTL
);
465 Point
aHSplitterPoint(nPosX
+ nTabSize
+ nSizeLt
, nPosY
+ nSizeY
);
466 Size
aHSplitterSize(nSizeSp
, nBarY
);
467 lcl_SetPosSize(*pHSplitter
, aHSplitterPoint
, aHSplitterSize
, nTotalWidth
, bLayoutRTL
);
469 Point
aHScrollRightPoint(nPosX
+ nTabSize
+ nSizeLt
+ nSizeSp
, nPosY
+ nSizeY
);
470 Size
aHScrollRightSize(nSizeRt
, nBarY
);
471 lcl_SetPosSize(*aHScrollRight
, aHScrollRightPoint
, aHScrollRightSize
, nTotalWidth
, bLayoutRTL
);
475 Point
aTabPoint(nPosX
, nPosY
+ nSizeY
+ nScrollBarSize
);
476 Size
aTabSize(nSizeX
, nTabHeight
);
477 lcl_SetPosSize(*pTabControl
, aTabPoint
, aTabSize
, nTotalWidth
, bLayoutRTL
);
478 pTabControl
->SetSheetLayoutRTL(bLayoutRTL
);
480 Point
aHScrollLeftPoint(nPosX
, nPosY
+ nSizeY
);
481 Size
aHScrollLeftSize(nSizeLt
, nScrollBarSize
);
482 lcl_SetPosSize(*aHScrollLeft
, aHScrollLeftPoint
, aHScrollLeftSize
, nTotalWidth
, bLayoutRTL
);
484 Point
aHSplitterPoint(nPosX
+ nSizeLt
, nPosY
+ nSizeY
);
485 Size
aHSplitterSize(nSizeSp
, nScrollBarSize
);
486 lcl_SetPosSize(*pHSplitter
, aHSplitterPoint
, aHSplitterSize
, nTotalWidth
, bLayoutRTL
);
488 Point
aHScrollRightPoint(nPosX
+ nSizeLt
+ nSizeSp
, nPosY
+ nSizeY
);
489 Size
aHScrollRightSize(nSizeRt
, nScrollBarSize
);
490 lcl_SetPosSize(*aHScrollRight
, aHScrollRightPoint
, aHScrollRightSize
, nTotalWidth
, bLayoutRTL
);
492 // SetDragRectPixel is done below
497 tools::Long nSizeUp
= 0; // upper scroll bar
498 tools::Long nSizeSp
= 0; // splitter
499 tools::Long nSizeDn
; // lower scroll bar
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
, 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
, Point(nPosX
+ nSizeX
,
523 nPosY
+ nSizeUp
+ nSizeSp
),
524 Size(nBarX
, nSizeDn
), nTotalWidth
, bLayoutRTL
);
526 // SetDragRectPixel is done below
530 // SetDragRectPixel also without Scrollbars etc., when already split
531 if ( bHScroll
|| aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
532 pHSplitter
->SetDragRectPixel(
533 tools::Rectangle( nPosX
, nPosY
, nPosX
+nSizeX
, nPosY
+nSizeY
), pFrameWin
);
534 if ( bVScroll
|| aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
535 pVSplitter
->SetDragRectPixel(
536 tools::Rectangle( nPosX
, nPosY
, nPosX
+nSizeX
, nPosY
+nSizeY
), pFrameWin
);
538 if (bTabControl
&& ! bHScroll
)
540 nBarY
= aHScrollLeft
->GetSizePixel().Height();
542 tools::Long nSize1
= nSizeX
;
544 tools::Long nTabSize
= nSize1
;
545 if (nTabSize
< 0) nTabSize
= 0;
547 lcl_SetPosSize( *pTabControl
, Point(nPosX
, nPosY
+nSizeY
-nBarY
),
548 Size(nTabSize
, nBarY
), nTotalWidth
, bLayoutRTL
);
553 Size aVScrSize
= aVScrollBottom
->GetSizePixel();
554 aVScrSize
.AdjustHeight( -nBarY
);
555 aVScrollBottom
->SetSizePixel( aVScrSize
);
563 if (bVOutline
&& pRowOutline
[SC_SPLIT_BOTTOM
])
565 nOutlineX
= pRowOutline
[SC_SPLIT_BOTTOM
]->GetDepthSize();
569 if (bHOutline
&& pColOutline
[SC_SPLIT_LEFT
])
571 nOutlineY
= pColOutline
[SC_SPLIT_LEFT
]->GetDepthSize();
576 if (bHeaders
) // column/row header
578 nBarX
= pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width();
579 nBarY
= pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height();
590 tools::Long nLeftSize
= nSizeX
;
591 tools::Long nRightSize
= 0;
592 tools::Long nTopSize
= 0;
593 tools::Long nBottomSize
= nSizeY
;
594 tools::Long nSplitPosX
= nPosX
;
595 tools::Long nSplitPosY
= nPosY
;
597 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
599 tools::Long nSplitHeight
= rSize
.Height();
600 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
602 // Do not allow freeze splitter to overlap scroll bar/tab bar
604 nSplitHeight
-= aHScrollLeft
->GetSizePixel().Height();
605 else if ( bTabControl
&& pTabControl
)
606 nSplitHeight
-= pTabControl
->GetSizePixel().Height();
608 nSplitPosX
= aViewData
.GetHSplitPos();
609 lcl_SetPosSize( *pHSplitter
,
610 Point(nSplitPosX
, nOutPosY
),
611 Size(nSplitSizeX
, nSplitHeight
- nTabHeight
), nTotalWidth
, bLayoutRTL
);
612 nLeftSize
= nSplitPosX
- nPosX
;
613 nSplitPosX
+= nSplitSizeX
;
614 nRightSize
= nSizeX
- nLeftSize
- nSplitSizeX
;
616 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
618 tools::Long nSplitWidth
= rSize
.Width();
619 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
&& bVScroll
)
620 nSplitWidth
-= aVScrollBottom
->GetSizePixel().Width();
621 nSplitPosY
= aViewData
.GetVSplitPos();
622 lcl_SetPosSize( *pVSplitter
,
623 Point( nOutPosX
, nSplitPosY
), Size( nSplitWidth
, nSplitSizeY
), nTotalWidth
, bLayoutRTL
);
624 nTopSize
= nSplitPosY
- nPosY
;
625 nSplitPosY
+= nSplitSizeY
;
626 nBottomSize
= nSizeY
- nTopSize
- nSplitSizeY
;
629 // ShowHide for pColOutline / pRowOutline happens in UpdateShow
631 if (bHOutline
) // Outline-Controls
633 if (pColOutline
[SC_SPLIT_LEFT
])
635 pColOutline
[SC_SPLIT_LEFT
]->SetHeaderSize( nBarX
);
636 lcl_SetPosSize( *pColOutline
[SC_SPLIT_LEFT
],
637 Point(nPosX
-nBarX
,nOutPosY
), Size(nLeftSize
+nBarX
,nOutlineY
), nTotalWidth
, bLayoutRTL
);
639 if (pColOutline
[SC_SPLIT_RIGHT
])
641 pColOutline
[SC_SPLIT_RIGHT
]->SetHeaderSize( 0 ); // always call to update RTL flag
642 lcl_SetPosSize( *pColOutline
[SC_SPLIT_RIGHT
],
643 Point(nSplitPosX
,nOutPosY
), Size(nRightSize
,nOutlineY
), nTotalWidth
, bLayoutRTL
);
650 if (pRowOutline
[SC_SPLIT_TOP
] && pRowOutline
[SC_SPLIT_BOTTOM
])
652 pRowOutline
[SC_SPLIT_TOP
]->SetHeaderSize( nBarY
);
653 lcl_SetPosSize( *pRowOutline
[SC_SPLIT_TOP
],
654 Point(nOutPosX
,nPosY
-nBarY
), Size(nOutlineX
,nTopSize
+nBarY
), nTotalWidth
, bLayoutRTL
);
655 pRowOutline
[SC_SPLIT_BOTTOM
]->SetHeaderSize( 0 );
656 lcl_SetPosSize( *pRowOutline
[SC_SPLIT_BOTTOM
],
657 Point(nOutPosX
,nSplitPosY
), Size(nOutlineX
,nBottomSize
), nTotalWidth
, bLayoutRTL
);
660 else if (pRowOutline
[SC_SPLIT_BOTTOM
])
662 pRowOutline
[SC_SPLIT_BOTTOM
]->SetHeaderSize( nBarY
);
663 lcl_SetPosSize( *pRowOutline
[SC_SPLIT_BOTTOM
],
664 Point(nOutPosX
,nSplitPosY
-nBarY
), Size(nOutlineX
,nBottomSize
+nBarY
), nTotalWidth
, bLayoutRTL
);
667 if (bHOutline
&& bVOutline
)
669 lcl_SetPosSize( *aTopButton
, Point(nOutPosX
,nOutPosY
), Size(nOutlineX
,nOutlineY
), nTotalWidth
, bLayoutRTL
);
675 if (bHeaders
) // column/row header
677 lcl_SetPosSize( *pColBar
[SC_SPLIT_LEFT
],
678 Point(nPosX
,nPosY
-nBarY
), Size(nLeftSize
,nBarY
), nTotalWidth
, bLayoutRTL
);
679 if (pColBar
[SC_SPLIT_RIGHT
])
680 lcl_SetPosSize( *pColBar
[SC_SPLIT_RIGHT
],
681 Point(nSplitPosX
,nPosY
-nBarY
), Size(nRightSize
,nBarY
), nTotalWidth
, bLayoutRTL
);
683 if (pRowBar
[SC_SPLIT_TOP
])
684 lcl_SetPosSize( *pRowBar
[SC_SPLIT_TOP
],
685 Point(nPosX
-nBarX
,nPosY
), Size(nBarX
,nTopSize
), nTotalWidth
, bLayoutRTL
);
686 lcl_SetPosSize( *pRowBar
[SC_SPLIT_BOTTOM
],
687 Point(nPosX
-nBarX
,nSplitPosY
), Size(nBarX
,nBottomSize
), nTotalWidth
, bLayoutRTL
);
689 lcl_SetPosSize( *aCornerButton
, Point(nPosX
-nBarX
,nPosY
-nBarY
), Size(nBarX
,nBarY
), nTotalWidth
, bLayoutRTL
);
690 aCornerButton
->Show();
691 pColBar
[SC_SPLIT_LEFT
]->Show();
692 pRowBar
[SC_SPLIT_BOTTOM
]->Show();
696 aCornerButton
->Hide();
697 pColBar
[SC_SPLIT_LEFT
]->Hide(); // always here
698 pRowBar
[SC_SPLIT_BOTTOM
]->Hide();
705 tools::Long nInnerPosX
= bLayoutRTL
? ( nTotalWidth
- nPosX
- nLeftSize
) : nPosX
;
706 pGridWin
[SC_SPLIT_BOTTOMLEFT
]->SetPosPixel( Point(nInnerPosX
,nSplitPosY
) );
710 lcl_SetPosSize( *pGridWin
[SC_SPLIT_BOTTOMLEFT
],
711 Point(nPosX
,nSplitPosY
), Size(nLeftSize
,nBottomSize
), nTotalWidth
, bLayoutRTL
);
712 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
713 lcl_SetPosSize( *pGridWin
[SC_SPLIT_BOTTOMRIGHT
],
714 Point(nSplitPosX
,nSplitPosY
), Size(nRightSize
,nBottomSize
), nTotalWidth
, bLayoutRTL
);
715 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
716 lcl_SetPosSize( *pGridWin
[SC_SPLIT_TOPLEFT
],
717 Point(nPosX
,nPosY
), Size(nLeftSize
,nTopSize
), nTotalWidth
, bLayoutRTL
);
718 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
&& aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
719 lcl_SetPosSize( *pGridWin
[SC_SPLIT_TOPRIGHT
],
720 Point(nSplitPosX
,nPosY
), Size(nRightSize
,nTopSize
), nTotalWidth
, bLayoutRTL
);
723 // update scroll bars
725 if (!bInUpdateHeader
)
727 UpdateScrollBars(); // don't reset scroll bars when scrolling
730 InterpretVisible(); // have everything calculated before painting
734 TestHintWindow(); // reposition
736 UpdateVarZoom(); // update variable zoom types (after resizing GridWindows)
738 if (aViewData
.GetViewShell()->HasAccessibilityObjects())
739 aViewData
.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccWindowResized
));
742 void ScTabView::UpdateVarZoom()
744 // update variable zoom types
746 SvxZoomType eZoomType
= GetZoomType();
747 if (eZoomType
== SvxZoomType::PERCENT
|| bInZoomUpdate
)
750 bInZoomUpdate
= true;
751 const Fraction
& rOldX
= GetViewData().GetZoomX();
752 const Fraction
& rOldY
= GetViewData().GetZoomY();
753 tools::Long nOldPercent
= tools::Long(rOldY
* 100);
754 sal_uInt16 nNewZoom
= CalcZoom( eZoomType
, static_cast<sal_uInt16
>(nOldPercent
) );
755 Fraction
aNew( nNewZoom
, 100 );
757 if ( aNew
!= rOldX
|| aNew
!= rOldY
)
759 SetZoom( aNew
, aNew
, false ); // always separately per sheet
763 aViewData
.GetViewShell()->GetViewFrame().GetBindings().Invalidate( SID_ATTR_ZOOM
);
764 aViewData
.GetViewShell()->GetViewFrame().GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER
);
765 aViewData
.GetBindings().Invalidate(SID_ZOOM_IN
);
766 aViewData
.GetBindings().Invalidate(SID_ZOOM_OUT
);
768 bInZoomUpdate
= false;
771 void ScTabView::UpdateFixPos()
773 bool bResize
= false;
774 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
775 if (aViewData
.UpdateFixX())
777 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
778 if (aViewData
.UpdateFixY())
784 void ScTabView::RepeatResize( bool bUpdateFix
)
788 ScSplitMode eHSplit
= aViewData
.GetHSplitMode();
789 ScSplitMode eVSplit
= aViewData
.GetVSplitMode();
791 // #i46796# UpdateFixX / UpdateFixY uses GetGridOffset, which requires the
792 // outline windows to be available. So UpdateShow has to be called before
793 // (also called from DoResize).
794 if ( eHSplit
== SC_SPLIT_FIX
|| eVSplit
== SC_SPLIT_FIX
)
797 if ( eHSplit
== SC_SPLIT_FIX
)
798 aViewData
.UpdateFixX();
799 if ( eVSplit
== SC_SPLIT_FIX
)
800 aViewData
.UpdateFixY();
803 DoResize( aBorderPos
, aFrameSize
);
805 //! border must be reset ???
808 void ScTabView::GetBorderSize( SvBorder
& rBorder
, const Size
& /* rSize */ )
810 bool bScrollBars
= aViewData
.IsVScrollMode();
811 bool bHeaders
= aViewData
.IsHeaderMode();
812 bool bOutlMode
= aViewData
.IsOutlineMode();
813 bool bHOutline
= bOutlMode
&& lcl_HasColOutline(aViewData
);
814 bool bVOutline
= bOutlMode
&& lcl_HasRowOutline(aViewData
);
815 bool bLayoutRTL
= aViewData
.GetDocument().IsLayoutRTL( aViewData
.GetTabNo() );
817 rBorder
= SvBorder();
819 if (bScrollBars
) // Scrollbars horizontal or vertical
821 rBorder
.Right() += aVScrollBottom
->GetSizePixel().Width();
822 rBorder
.Bottom() += aHScrollLeft
->GetSizePixel().Height();
826 if (bVOutline
&& pRowOutline
[SC_SPLIT_BOTTOM
])
827 rBorder
.Left() += pRowOutline
[SC_SPLIT_BOTTOM
]->GetDepthSize();
828 if (bHOutline
&& pColOutline
[SC_SPLIT_LEFT
])
829 rBorder
.Top() += pColOutline
[SC_SPLIT_LEFT
]->GetDepthSize();
831 if (bHeaders
) // column/row headers
833 rBorder
.Left() += pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width();
834 rBorder
.Top() += pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height();
838 ::std::swap( rBorder
.Left(), rBorder
.Right() );
841 IMPL_LINK_NOARG(ScTabView
, TabBarResize
, TabBar
*, void)
843 if (!aViewData
.IsHScrollMode())
846 tools::Long nSize
= pTabControl
->GetSplitSize();
848 if (aViewData
.GetHSplitMode() != SC_SPLIT_FIX
)
850 tools::Long nMax
= pHSplitter
->GetPosPixel().X();
851 if( pTabControl
->IsEffectiveRTL() )
852 nMax
= pFrameWin
->GetSizePixel().Width() - nMax
;
854 if (nSize
>nMax
) nSize
= nMax
;
857 if ( nSize
!= pTabControl
->GetSizePixel().Width() )
859 pTabControl
->SetSizePixel( Size( nSize
,
860 pTabControl
->GetSizePixel().Height() ) );
865 void ScTabView::SetTabBarWidth( tools::Long nNewWidth
)
867 Size aSize
= pTabControl
->GetSizePixel();
869 if ( aSize
.Width() != nNewWidth
)
871 aSize
.setWidth( nNewWidth
);
872 pTabControl
->SetSizePixel( aSize
);
876 void ScTabView::SetRelTabBarWidth( double fRelTabBarWidth
)
878 if( (0.0 <= fRelTabBarWidth
) && (fRelTabBarWidth
<= 1.0) )
879 if( tools::Long nFrameWidth
= pFrameWin
->GetSizePixel().Width() )
880 SetTabBarWidth( static_cast< tools::Long
>( fRelTabBarWidth
* nFrameWidth
+ 0.5 ) );
883 void ScTabView::SetPendingRelTabBarWidth( double fRelTabBarWidth
)
885 mfPendingTabBarWidth
= fRelTabBarWidth
;
886 SetRelTabBarWidth( fRelTabBarWidth
);
889 tools::Long
ScTabView::GetTabBarWidth() const
891 return pTabControl
->GetSizePixel().Width();
894 double ScTabView::GetRelTabBarWidth()
899 ScGridWindow
* ScTabView::GetActiveWin()
901 ScSplitPos ePos
= aViewData
.GetActivePart();
902 OSL_ENSURE(pGridWin
[ePos
],"no active window");
903 return pGridWin
[ePos
];
906 void ScTabView::SetActivePointer( PointerStyle nPointer
)
908 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
910 pWin
->SetPointer( nPointer
);
913 void ScTabView::ActiveGrabFocus()
915 ScSplitPos ePos
= aViewData
.GetActivePart();
917 pGridWin
[ePos
]->GrabFocus();
920 ScSplitPos
ScTabView::FindWindow( const vcl::Window
* pWindow
) const
922 ScSplitPos eVal
= SC_SPLIT_BOTTOMLEFT
; // Default
923 for (sal_uInt16 i
=0; i
<4; i
++)
924 if ( pGridWin
[i
] == pWindow
)
925 eVal
= static_cast<ScSplitPos
>(i
);
930 Point
ScTabView::GetGridOffset() const
934 // size as in DoResize
936 bool bHeaders
= aViewData
.IsHeaderMode();
937 bool bOutlMode
= aViewData
.IsOutlineMode();
938 bool bHOutline
= bOutlMode
&& lcl_HasColOutline(aViewData
);
939 bool bVOutline
= bOutlMode
&& lcl_HasRowOutline(aViewData
);
942 if (bVOutline
&& pRowOutline
[SC_SPLIT_BOTTOM
])
943 aPos
.AdjustX(pRowOutline
[SC_SPLIT_BOTTOM
]->GetDepthSize() );
944 if (bHOutline
&& pColOutline
[SC_SPLIT_LEFT
])
945 aPos
.AdjustY(pColOutline
[SC_SPLIT_LEFT
]->GetDepthSize() );
947 if (bHeaders
) // column/row headers
949 if (pRowBar
[SC_SPLIT_BOTTOM
])
950 aPos
.AdjustX(pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width() );
951 if (pColBar
[SC_SPLIT_LEFT
])
952 aPos
.AdjustY(pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height() );
958 // --- Scroll-Bars --------------------------------------------------------
960 void ScTabView::SetZoomPercentFromCommand(sal_uInt16 nZoomPercent
)
962 // scroll wheel doesn't set the AppOptions default
964 bool bSyncZoom
= ScModule::get()->GetAppOptions().GetSynchronizeZoom();
965 SetZoomType(SvxZoomType::PERCENT
, bSyncZoom
);
966 Fraction
aFract(nZoomPercent
, 100);
967 SetZoom(aFract
, aFract
, bSyncZoom
);
971 aViewData
.GetBindings().Invalidate( SID_ATTR_ZOOM
);
972 aViewData
.GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER
);
973 aViewData
.GetBindings().Invalidate( SID_ZOOM_IN
);
974 aViewData
.GetBindings().Invalidate( SID_ZOOM_OUT
);
977 bool ScTabView::ScrollCommand( const CommandEvent
& rCEvt
, ScSplitPos ePos
)
982 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
983 if (pData
&& pData
->GetMode() == CommandWheelMode::ZOOM
)
985 if ( !aViewData
.GetViewShell()->GetViewFrame().GetFrame().IsInPlace() )
987 // for ole inplace editing, the scale is defined by the visarea and client size
988 // and can't be changed directly
990 const Fraction
& rOldY
= aViewData
.GetZoomY();
991 sal_uInt16 nOld
= static_cast<tools::Long
>( rOldY
* 100 );
993 if ( pData
->GetDelta() < 0 )
994 nNew
= std::max( MINZOOM
, basegfx::zoomtools::zoomOut( nOld
));
996 nNew
= std::min( MAXZOOM
, basegfx::zoomtools::zoomIn( nOld
));
999 SetZoomPercentFromCommand(nNew
);
1007 ScHSplitPos eHPos
= WhichH(ePos
);
1008 ScVSplitPos eVPos
= WhichV(ePos
);
1009 ScrollAdaptor
* pHScroll
= ( eHPos
== SC_SPLIT_LEFT
) ? aHScrollLeft
.get() : aHScrollRight
.get();
1010 ScrollAdaptor
* pVScroll
= ( eVPos
== SC_SPLIT_TOP
) ? aVScrollTop
.get() : aVScrollBottom
.get();
1011 if ( pGridWin
[ePos
] )
1012 bDone
= pGridWin
[ePos
]->HandleScrollCommand( rCEvt
, pHScroll
, pVScroll
);
1017 bool ScTabView::GesturePanCommand(const CommandEvent
& rCEvt
)
1022 const CommandGesturePanData
* pData
= rCEvt
.GetGesturePanData();
1026 if (aViewData
.GetViewShell()->GetViewFrame().GetFrame().IsInPlace())
1029 ScSplitPos ePos
= aViewData
.GetActivePart();
1030 ScHSplitPos eHPos
= WhichH(ePos
);
1031 ScVSplitPos eVPos
= WhichV(ePos
);
1032 ScrollAdaptor
* pHScroll
= (eHPos
== SC_SPLIT_LEFT
) ? aHScrollLeft
.get() : aHScrollRight
.get();
1033 ScrollAdaptor
* pVScroll
= (eVPos
== SC_SPLIT_TOP
) ? aVScrollTop
.get() : aVScrollBottom
.get();
1035 bDone
= pGridWin
[ePos
]->HandleScrollCommand(rCEvt
, pHScroll
, pVScroll
);
1040 bool ScTabView::GestureZoomCommand(const CommandEvent
& rCEvt
)
1044 const CommandGestureZoomData
* pData
= rCEvt
.GetGestureZoomData();
1048 if (aViewData
.GetViewShell()->GetViewFrame().GetFrame().IsInPlace())
1051 if (pData
->meEventType
== GestureEventZoomType::Begin
)
1053 mfLastZoomScale
= pData
->mfScaleDelta
;
1057 if (pData
->meEventType
== GestureEventZoomType::Update
)
1059 double deltaBetweenEvents
= (pData
->mfScaleDelta
- mfLastZoomScale
) / mfLastZoomScale
;
1060 mfLastZoomScale
= pData
->mfScaleDelta
;
1062 // Accumulate fractional zoom to avoid small zoom changes from being ignored
1063 mfAccumulatedZoom
+= deltaBetweenEvents
;
1064 int nZoomChangePercent
= mfAccumulatedZoom
* 100;
1065 mfAccumulatedZoom
-= nZoomChangePercent
/ 100.0;
1067 const Fraction
& rOldY
= aViewData
.GetZoomY();
1068 sal_uInt16 nOld
= static_cast<tools::Long
>(rOldY
* 100);
1069 sal_uInt16 nNew
= nOld
+ nZoomChangePercent
;
1070 nNew
= std::clamp
<sal_uInt16
>(nNew
, MINZOOM
, MAXZOOM
);
1074 SetZoomPercentFromCommand(nNew
);
1082 IMPL_LINK_NOARG(ScTabView
, HScrollLeftHdl
, weld::Scrollbar
&, void)
1084 ScrollHdl(aHScrollLeft
.get());
1087 IMPL_LINK_NOARG(ScTabView
, HScrollRightHdl
, weld::Scrollbar
&, void)
1089 ScrollHdl(aHScrollRight
.get());
1092 IMPL_LINK_NOARG(ScTabView
, VScrollTopHdl
, weld::Scrollbar
&, void)
1094 ScrollHdl(aVScrollTop
.get());
1097 IMPL_LINK_NOARG(ScTabView
, VScrollBottomHdl
, weld::Scrollbar
&, void)
1099 ScrollHdl(aVScrollBottom
.get());
1102 IMPL_LINK_NOARG(ScTabView
, EndScrollHdl
, const MouseEvent
&, bool)
1112 void ScTabView::ScrollHdl(ScrollAdaptor
* pScroll
)
1114 bool bUpdateHorizontalScrollbars
= false;
1116 bool bHoriz
= ( pScroll
== aHScrollLeft
.get() || pScroll
== aHScrollRight
.get() );
1117 tools::Long nViewPos
;
1119 nViewPos
= aViewData
.GetPosX( (pScroll
== aHScrollLeft
.get()) ?
1120 SC_SPLIT_LEFT
: SC_SPLIT_RIGHT
);
1122 nViewPos
= aViewData
.GetPosY( (pScroll
== aVScrollTop
.get()) ?
1123 SC_SPLIT_TOP
: SC_SPLIT_BOTTOM
);
1125 bool bLayoutRTL
= bHoriz
&& aViewData
.GetDocument().IsLayoutRTL( aViewData
.GetTabNo() );
1127 ScrollType eType
= pScroll
->GetScrollType();
1128 if ( eType
== ScrollType::Drag
)
1133 nPrevDragPos
= nViewPos
;
1136 // show scroll position
1137 // (only QuickHelp, there is no entry for it in the status bar)
1139 if (Help::IsQuickHelpEnabled())
1141 Size aSize
= pScroll
->GetSizePixel();
1143 /* Convert scrollbar mouse position to screen position. If RTL
1144 mode of scrollbar differs from RTL mode of its parent, then the
1145 direct call to Window::OutputToNormalizedScreenPixel() will
1146 give unusable results, because calculation of screen position
1147 is based on parent orientation and expects equal orientation of
1148 the child position. Need to mirror mouse position before. */
1149 Point aMousePos
= pScroll
->GetPointerPosPixel();
1150 if( pScroll
->IsRTLEnabled() != pScroll
->GetParent()->IsRTLEnabled() )
1151 aMousePos
.setX( aSize
.Width() - aMousePos
.X() - 1 );
1152 aMousePos
= pScroll
->OutputToNormalizedScreenPixel( aMousePos
);
1154 // convert top-left position of scrollbar to screen position
1155 Point aPos
= pScroll
->OutputToNormalizedScreenPixel( Point() );
1157 // get scrollbar scroll position for help text (row number/column name)
1158 tools::Long nScrollMin
= 0; // simulate RangeMin
1159 if ( aViewData
.GetHSplitMode()==SC_SPLIT_FIX
&& pScroll
== aHScrollRight
.get() )
1160 nScrollMin
= aViewData
.GetFixPosX();
1161 if ( aViewData
.GetVSplitMode()==SC_SPLIT_FIX
&& pScroll
== aVScrollBottom
.get() )
1162 nScrollMin
= aViewData
.GetFixPosY();
1163 tools::Long nScrollPos
= GetScrollBarPos( *pScroll
, bLayoutRTL
) + nScrollMin
;
1166 tools::Rectangle aRect
;
1167 QuickHelpFlags nAlign
;
1170 aHelpStr
= ScResId(STR_COLUMN
) +
1171 " " + ScColToAlpha(static_cast<SCCOL
>(nScrollPos
));
1173 aRect
.SetLeft( aMousePos
.X() );
1174 aRect
.SetTop( aPos
.Y() - 4 );
1175 nAlign
= QuickHelpFlags::Bottom
|QuickHelpFlags::Center
;
1179 aHelpStr
= ScResId(STR_ROW
) +
1180 " " + OUString::number(nScrollPos
+ 1);
1182 // note that bLayoutRTL is always false here, because bLayoutRTL depends on bHoriz
1184 // show quicktext always inside sheet area
1185 aRect
.SetLeft(aPos
.X() - 8);
1186 aRect
.SetTop( aMousePos
.Y() );
1187 nAlign
= QuickHelpFlags::Right
| QuickHelpFlags::VCenter
;
1189 aRect
.SetRight( aRect
.Left() );
1190 aRect
.SetBottom( aRect
.Top() );
1192 Help::ShowQuickHelp(pScroll
->GetParent(), aRect
, aHelpStr
, nAlign
);
1198 if ( bHoriz
&& bLayoutRTL
)
1200 // change scroll type so visible/previous cells calculation below remains the same
1203 case ScrollType::LineUp
: eType
= ScrollType::LineDown
; break;
1204 case ScrollType::LineDown
: eType
= ScrollType::LineUp
; break;
1205 case ScrollType::PageUp
: eType
= ScrollType::PageDown
; break;
1206 case ScrollType::PageDown
: eType
= ScrollType::PageUp
; break;
1209 // added to avoid warnings
1214 tools::Long
nDelta(0);
1217 case ScrollType::LineUp
:
1220 case ScrollType::LineDown
:
1223 case ScrollType::PageUp
:
1224 if ( pScroll
== aHScrollLeft
.get() ) nDelta
= -static_cast<tools::Long
>(aViewData
.PrevCellsX( SC_SPLIT_LEFT
));
1225 if ( pScroll
== aHScrollRight
.get() ) nDelta
= -static_cast<tools::Long
>(aViewData
.PrevCellsX( SC_SPLIT_RIGHT
));
1226 if ( pScroll
== aVScrollTop
.get() ) nDelta
= -static_cast<tools::Long
>(aViewData
.PrevCellsY( SC_SPLIT_TOP
));
1227 if ( pScroll
== aVScrollBottom
.get() ) nDelta
= -static_cast<tools::Long
>(aViewData
.PrevCellsY( SC_SPLIT_BOTTOM
));
1228 if (nDelta
==0) nDelta
=-1;
1230 case ScrollType::PageDown
:
1231 if ( pScroll
== aHScrollLeft
.get() ) nDelta
= aViewData
.VisibleCellsX( SC_SPLIT_LEFT
);
1232 if ( pScroll
== aHScrollRight
.get() ) nDelta
= aViewData
.VisibleCellsX( SC_SPLIT_RIGHT
);
1233 if ( pScroll
== aVScrollTop
.get() ) nDelta
= aViewData
.VisibleCellsY( SC_SPLIT_TOP
);
1234 if ( pScroll
== aVScrollBottom
.get() ) nDelta
= aViewData
.VisibleCellsY( SC_SPLIT_BOTTOM
);
1235 if (nDelta
==0) nDelta
=1;
1239 // only scroll in the correct direction, do not jitter around hidden ranges
1240 tools::Long nScrollMin
= 0; // simulate RangeMin
1241 if ( aViewData
.GetHSplitMode()==SC_SPLIT_FIX
&& pScroll
== aHScrollRight
.get() )
1242 nScrollMin
= aViewData
.GetFixPosX();
1243 if ( aViewData
.GetVSplitMode()==SC_SPLIT_FIX
&& pScroll
== aVScrollBottom
.get() )
1244 nScrollMin
= aViewData
.GetFixPosY();
1246 tools::Long nScrollPos
= GetScrollBarPos( *pScroll
, bLayoutRTL
) + nScrollMin
;
1247 nDelta
= nScrollPos
- nViewPos
;
1249 // tdf#152406 Disable anti-jitter code for scroll wheel events
1250 // After moving thousands of columns to the right via
1251 // horizontal scroll wheel or trackpad swipe events, most
1252 // vertical scroll wheel or trackpad swipe events will trigger
1253 // the anti-jitter code because nScrollPos and nPrevDragPos
1254 // will be equal and nDelta will be overridden and set to zero.
1255 // So, only use the anti-jitter code for mouse drag events.
1256 if ( eType
== ScrollType::Drag
)
1258 if ( nScrollPos
> nPrevDragPos
)
1260 if (nDelta
<0) nDelta
=0;
1262 else if ( nScrollPos
< nPrevDragPos
)
1264 if (nDelta
>0) nDelta
=0;
1271 // tdf#135478 Reduce sensitivity of horizontal scrollwheel
1272 // Problem: at least on macOS, swipe events are very
1273 // precise. So, when swiping at a slight angle off of
1274 // vertical, swipe events will include a small amount
1275 // of horizontal movement. Since horizontal swipe units
1276 // are measured in cell widths, these small amounts of
1277 // horizontal movement results in shifting many columns
1278 // to the right or left while swiping almost vertically.
1279 // So my hacky fix is to reduce the amount of horizontal
1280 // swipe events to roughly match the "visual distance"
1281 // of vertical swipe events.
1282 // The reduction factor is arbitrary but is set to
1283 // roughly the ratio of default cell width divided by
1284 // default cell height. This hacky fix isn't a perfect
1285 // fix, but hopefully it reduces the amount of
1286 // unexpected horizontal shifting while swiping
1287 // vertically to a tolerable amount for most users.
1288 // Note: the potential downside of doing this is that
1289 // some users might find horizontal swiping to be
1290 // slower than they are used to. If that becomes an
1291 // issue for enough users, the reduction factor may
1292 // need to be lowered to find a good balance point.
1294 static const tools::Long nHScrollReductionFactor
= 3;
1296 static const tools::Long nHScrollReductionFactor
= 8;
1299 // tdf#161945 increase sensitivity for negative horizontal deltas
1300 // A side effect of the anti-jitter code is that it tends
1301 // to reduce the sensitivity of horizontal scroll events
1302 // towards the first column. It is particularly noticeable
1303 // with horizontal scroll events from a scrollwheel when
1304 // the view position is in column B or C. This results in
1305 // a very small delta from the anti-jitter code.
1306 // So, to balance things out, apply a constant adjustment
1307 // factor to increase the sensitivity more for small deltas
1308 // than for large deltas.
1309 static const tools::Long nHScrollNegativeDeltaAdjustmentFactor
= -1;
1311 nDelta
+= nHScrollNegativeDeltaAdjustmentFactor
;
1313 if ( pScroll
== aHScrollLeft
.get() )
1315 mnPendingaHScrollLeftDelta
+= nDelta
;
1317 if ( abs(mnPendingaHScrollLeftDelta
) > nHScrollReductionFactor
)
1319 nDelta
= mnPendingaHScrollLeftDelta
/ nHScrollReductionFactor
;
1320 mnPendingaHScrollLeftDelta
= mnPendingaHScrollLeftDelta
% nHScrollReductionFactor
;
1325 mnPendingaHScrollRightDelta
+= nDelta
;
1327 if ( abs(mnPendingaHScrollRightDelta
) > nHScrollReductionFactor
)
1329 nDelta
= mnPendingaHScrollRightDelta
/ nHScrollReductionFactor
;
1330 mnPendingaHScrollRightDelta
= mnPendingaHScrollRightDelta
% nHScrollReductionFactor
;
1334 bUpdateHorizontalScrollbars
= true;
1337 nPrevDragPos
= nScrollPos
;
1344 bool bUpdate
= ( eType
!= ScrollType::Drag
); // don't alter the ranges while dragging
1346 ScrollX( nDelta
, (pScroll
== aHScrollLeft
.get()) ? SC_SPLIT_LEFT
: SC_SPLIT_RIGHT
, bUpdate
);
1348 ScrollY( nDelta
, (pScroll
== aVScrollTop
.get()) ? SC_SPLIT_TOP
: SC_SPLIT_BOTTOM
, bUpdate
);
1351 // tdf#161945 update horizontal scrollbar position to match tab view
1352 // While the fix for tdf#135478 reduces the horizontal scroll delta
1353 // applied to the tab view, the horizontal scrollbar is set before
1354 // that with the original delta. As a result, the horizontal scrollbar
1355 // is now mispositioned so update the horizontal scrollbar position
1356 // to match the position of the tab view's visible columns.
1357 if ( bUpdateHorizontalScrollbars
)
1358 UpdateScrollBars( COLUMN_HEADER
);
1361 void ScTabView::ScrollX( tools::Long nDeltaX
, ScHSplitPos eWhich
, bool bUpdBars
)
1363 ScDocument
& rDoc
= aViewData
.GetDocument();
1364 SCCOL nOldX
= aViewData
.GetPosX(eWhich
);
1365 SCCOL nNewX
= nOldX
+ static_cast<SCCOL
>(nDeltaX
);
1371 if ( nNewX
> rDoc
.MaxCol() )
1373 nDeltaX
-= nNewX
- rDoc
.MaxCol();
1374 nNewX
= rDoc
.MaxCol();
1377 SCCOL nDir
= ( nDeltaX
> 0 ) ? 1 : -1;
1378 SCTAB nTab
= aViewData
.GetTabNo();
1379 while ( rDoc
.ColHidden(nNewX
, nTab
) &&
1380 nNewX
+nDir
>= 0 && nNewX
+nDir
<= rDoc
.MaxCol() )
1381 nNewX
= sal::static_int_cast
<SCCOL
>( nNewX
+ nDir
);
1385 if (aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
1387 if (eWhich
== SC_SPLIT_LEFT
)
1388 nNewX
= nOldX
; // always keep the left part
1391 SCCOL nFixX
= aViewData
.GetFixPosX();
1401 if ( nNewX
>= 0 && nNewX
<= rDoc
.MaxCol() && nDeltaX
)
1403 SCCOL nTrackX
= std::max( nOldX
, nNewX
);
1405 // with VCL Update() affects all windows at the moment, that is why
1406 // calling Update after scrolling of the GridWindow would possibly
1407 // already have painted the column/row bar with updated position. -
1408 // Therefore call Update once before on column/row bar
1409 if (pColBar
[eWhich
])
1410 pColBar
[eWhich
]->PaintImmediately();
1412 tools::Long nOldPos
= aViewData
.GetScrPos( nTrackX
, 0, eWhich
).X();
1413 aViewData
.SetPosX( eWhich
, nNewX
);
1414 tools::Long nDiff
= aViewData
.GetScrPos( nTrackX
, 0, eWhich
).X() - nOldPos
;
1416 if ( eWhich
==SC_SPLIT_LEFT
)
1418 pGridWin
[SC_SPLIT_BOTTOMLEFT
]->ScrollPixel( nDiff
, 0 );
1419 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
1420 pGridWin
[SC_SPLIT_TOPLEFT
]->ScrollPixel( nDiff
, 0 );
1424 pGridWin
[SC_SPLIT_BOTTOMRIGHT
]->ScrollPixel( nDiff
, 0 );
1425 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
1426 pGridWin
[SC_SPLIT_TOPRIGHT
]->ScrollPixel( nDiff
, 0 );
1428 if (pColBar
[eWhich
]) { pColBar
[eWhich
]->Scroll( nDiff
,0 ); pColBar
[eWhich
]->PaintImmediately(); }
1429 if (pColOutline
[eWhich
]) pColOutline
[eWhich
]->ScrollPixel( nDiff
);
1434 if (nDeltaX
==1 || nDeltaX
==-1)
1435 pGridWin
[aViewData
.GetActivePart()]->PaintImmediately();
1439 SetNewVisArea(); // MapMode must already be set
1444 void ScTabView::ScrollY( tools::Long nDeltaY
, ScVSplitPos eWhich
, bool bUpdBars
)
1446 ScDocument
& rDoc
= aViewData
.GetDocument();
1447 SCROW nOldY
= aViewData
.GetPosY(eWhich
);
1448 SCROW nNewY
= nOldY
+ static_cast<SCROW
>(nDeltaY
);
1454 if ( nNewY
> rDoc
.MaxRow() )
1456 nDeltaY
-= nNewY
- rDoc
.MaxRow();
1457 nNewY
= rDoc
.MaxRow();
1460 SCROW nDir
= ( nDeltaY
> 0 ) ? 1 : -1;
1461 SCTAB nTab
= aViewData
.GetTabNo();
1462 while ( rDoc
.RowHidden(nNewY
, nTab
) &&
1463 nNewY
+nDir
>= 0 && nNewY
+nDir
<= rDoc
.MaxRow() )
1468 if (aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
1470 if (eWhich
== SC_SPLIT_TOP
)
1471 nNewY
= nOldY
; // always keep the upper part
1474 SCROW nFixY
= aViewData
.GetFixPosY();
1484 if ( nNewY
>= 0 && nNewY
<= rDoc
.MaxRow() && nDeltaY
)
1486 SCROW nTrackY
= std::max( nOldY
, nNewY
);
1488 // adjust row headers before the actual scrolling, so it does not get painted twice
1489 // PosY may then also not be set yet, pass on new value
1490 SCROW nUNew
= nNewY
;
1491 UpdateHeaderWidth( &eWhich
, &nUNew
); // adjust row headers
1493 if (pRowBar
[eWhich
])
1494 pRowBar
[eWhich
]->PaintImmediately();
1496 tools::Long nOldPos
= aViewData
.GetScrPos( 0, nTrackY
, eWhich
).Y();
1497 aViewData
.SetPosY( eWhich
, nNewY
);
1498 tools::Long nDiff
= aViewData
.GetScrPos( 0, nTrackY
, eWhich
).Y() - nOldPos
;
1500 if ( eWhich
==SC_SPLIT_TOP
)
1502 pGridWin
[SC_SPLIT_TOPLEFT
]->ScrollPixel( 0, nDiff
);
1503 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
1504 pGridWin
[SC_SPLIT_TOPRIGHT
]->ScrollPixel( 0, nDiff
);
1508 pGridWin
[SC_SPLIT_BOTTOMLEFT
]->ScrollPixel( 0, nDiff
);
1509 if ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
)
1510 pGridWin
[SC_SPLIT_BOTTOMRIGHT
]->ScrollPixel( 0, nDiff
);
1512 if (pRowBar
[eWhich
]) { pRowBar
[eWhich
]->Scroll( 0,nDiff
); pRowBar
[eWhich
]->PaintImmediately(); }
1513 if (pRowOutline
[eWhich
]) pRowOutline
[eWhich
]->ScrollPixel( nDiff
);
1518 if (nDeltaY
==1 || nDeltaY
==-1)
1519 pGridWin
[aViewData
.GetActivePart()]->PaintImmediately();
1523 SetNewVisArea(); // MapMode must already be set
1528 void ScTabView::ScrollLines( tools::Long nDeltaX
, tools::Long nDeltaY
)
1530 ScSplitPos eWhich
= aViewData
.GetActivePart();
1532 ScrollX(nDeltaX
,WhichH(eWhich
));
1534 ScrollY(nDeltaY
,WhichV(eWhich
));
1540 SCROW
lcl_LastVisible( const ScViewData
& rViewData
)
1542 // If many rows are hidden at end of the document,
1543 // then there should not be a switch to wide row headers because of this
1544 ScDocument
& rDoc
= rViewData
.GetDocument();
1545 SCTAB nTab
= rViewData
.GetTabNo();
1547 SCROW nVis
= rDoc
.MaxRow();
1549 while ( nVis
> 0 && rDoc
.GetRowHeight( nVis
, nTab
, &startRow
, nullptr ) == 0 )
1550 nVis
= std::max
<SCROW
>( startRow
- 1, 0 );
1554 } // anonymous namespace
1556 void ScTabView::UpdateHeaderWidth( const ScVSplitPos
* pWhich
, const SCROW
* pPosY
)
1558 if (!pRowBar
[SC_SPLIT_BOTTOM
])
1561 ScDocument
& rDoc
= aViewData
.GetDocument();
1562 SCROW nEndPos
= rDoc
.MaxRow();
1563 if ( !aViewData
.GetViewShell()->GetViewFrame().GetFrame().IsInPlace() )
1565 // for OLE Inplace always MAXROW
1567 if ( pWhich
&& *pWhich
== SC_SPLIT_BOTTOM
&& pPosY
)
1570 nEndPos
= aViewData
.GetPosY( SC_SPLIT_BOTTOM
);
1571 nEndPos
+= aViewData
.CellsAtY( nEndPos
, 1, SC_SPLIT_BOTTOM
); // VisibleCellsY
1572 if (nEndPos
> rDoc
.MaxRow())
1573 nEndPos
= lcl_LastVisible( aViewData
);
1575 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
1578 if ( pWhich
&& *pWhich
== SC_SPLIT_TOP
&& pPosY
)
1581 nTopEnd
= aViewData
.GetPosY( SC_SPLIT_TOP
);
1582 nTopEnd
+= aViewData
.CellsAtY( nTopEnd
, 1, SC_SPLIT_TOP
);// VisibleCellsY
1583 if (nTopEnd
> rDoc
.MaxRow())
1584 nTopEnd
= lcl_LastVisible( aViewData
);
1586 if ( nTopEnd
> nEndPos
)
1591 tools::Long nSmall
= pRowBar
[SC_SPLIT_BOTTOM
]->GetSmallWidth();
1592 tools::Long nBig
= pRowBar
[SC_SPLIT_BOTTOM
]->GetBigWidth();
1593 tools::Long nDiff
= nBig
- nSmall
;
1597 else if (nEndPos
<1) // avoid extra step at 0 (when only one row is visible)
1599 tools::Long nWidth
= nBig
- ( 10000 - nEndPos
) * nDiff
/ 10000;
1601 if (nWidth
== pRowBar
[SC_SPLIT_BOTTOM
]->GetWidth() || bInUpdateHeader
)
1604 bInUpdateHeader
= true;
1606 pRowBar
[SC_SPLIT_BOTTOM
]->SetWidth( nWidth
);
1607 if (pRowBar
[SC_SPLIT_TOP
])
1608 pRowBar
[SC_SPLIT_TOP
]->SetWidth( nWidth
);
1612 // on VCL there are endless updates (each Update is valid for all windows)
1613 //aCornerButton->Update(); // otherwise this never gets an Update
1615 bInUpdateHeader
= false;
1618 static void ShowHide( vcl::Window
* pWin
, bool bShow
)
1620 OSL_ENSURE(pWin
|| !bShow
, "window is not present");
1625 void ScTabView::UpdateShow()
1627 bool bHScrollMode
= aViewData
.IsHScrollMode();
1628 bool bVScrollMode
= aViewData
.IsVScrollMode();
1629 bool bTabMode
= aViewData
.IsTabMode();
1630 bool bOutlMode
= aViewData
.IsOutlineMode();
1631 bool bHOutline
= bOutlMode
&& lcl_HasColOutline(aViewData
);
1632 bool bVOutline
= bOutlMode
&& lcl_HasRowOutline(aViewData
);
1633 bool bHeader
= aViewData
.IsHeaderMode();
1635 bool bShowH
= ( aViewData
.GetHSplitMode() != SC_SPLIT_NONE
);
1636 bool bShowV
= ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
);
1638 if ( aViewData
.GetDocShell()->IsPreview() )
1639 bHScrollMode
= bVScrollMode
= bTabMode
= bHeader
= bHOutline
= bVOutline
= false;
1643 if (bShowH
&& !pGridWin
[SC_SPLIT_BOTTOMRIGHT
])
1645 pGridWin
[SC_SPLIT_BOTTOMRIGHT
] = VclPtr
<ScGridWindow
>::Create( pFrameWin
, aViewData
, SC_SPLIT_BOTTOMRIGHT
);
1646 DoAddWin( pGridWin
[SC_SPLIT_BOTTOMRIGHT
] );
1648 if (bShowV
&& !pGridWin
[SC_SPLIT_TOPLEFT
])
1650 pGridWin
[SC_SPLIT_TOPLEFT
] = VclPtr
<ScGridWindow
>::Create( pFrameWin
, aViewData
, SC_SPLIT_TOPLEFT
);
1651 DoAddWin( pGridWin
[SC_SPLIT_TOPLEFT
] );
1653 if (bShowH
&& bShowV
&& !pGridWin
[SC_SPLIT_TOPRIGHT
])
1655 pGridWin
[SC_SPLIT_TOPRIGHT
] = VclPtr
<ScGridWindow
>::Create( pFrameWin
, aViewData
, SC_SPLIT_TOPRIGHT
);
1656 DoAddWin( pGridWin
[SC_SPLIT_TOPRIGHT
] );
1659 if (bHOutline
&& !pColOutline
[SC_SPLIT_LEFT
])
1660 pColOutline
[SC_SPLIT_LEFT
] = VclPtr
<ScOutlineWindow
>::Create( pFrameWin
, SC_OUTLINE_HOR
, &aViewData
, SC_SPLIT_BOTTOMLEFT
);
1661 if (bShowH
&& bHOutline
&& !pColOutline
[SC_SPLIT_RIGHT
])
1662 pColOutline
[SC_SPLIT_RIGHT
] = VclPtr
<ScOutlineWindow
>::Create( pFrameWin
, SC_OUTLINE_HOR
, &aViewData
, SC_SPLIT_BOTTOMRIGHT
);
1664 if (bVOutline
&& !pRowOutline
[SC_SPLIT_BOTTOM
])
1665 pRowOutline
[SC_SPLIT_BOTTOM
] = VclPtr
<ScOutlineWindow
>::Create( pFrameWin
, SC_OUTLINE_VER
, &aViewData
, SC_SPLIT_BOTTOMLEFT
);
1666 if (bShowV
&& bVOutline
&& !pRowOutline
[SC_SPLIT_TOP
])
1667 pRowOutline
[SC_SPLIT_TOP
] = VclPtr
<ScOutlineWindow
>::Create( pFrameWin
, SC_OUTLINE_VER
, &aViewData
, SC_SPLIT_TOPLEFT
);
1669 if (bShowH
&& bHeader
&& !pColBar
[SC_SPLIT_RIGHT
])
1670 pColBar
[SC_SPLIT_RIGHT
] = VclPtr
<ScColBar
>::Create( pFrameWin
, SC_SPLIT_RIGHT
,
1671 &aHdrFunc
, pHdrSelEng
.get(), this );
1672 if (bShowV
&& bHeader
&& !pRowBar
[SC_SPLIT_TOP
])
1673 pRowBar
[SC_SPLIT_TOP
] = VclPtr
<ScRowBar
>::Create( pFrameWin
, SC_SPLIT_TOP
,
1674 &aHdrFunc
, pHdrSelEng
.get(), this );
1678 ShowHide( aHScrollLeft
.get(), bHScrollMode
);
1679 ShowHide( aHScrollRight
.get(), bShowH
&& bHScrollMode
);
1680 ShowHide( aVScrollBottom
.get(), bVScrollMode
);
1681 ShowHide( aVScrollTop
.get(), bShowV
&& bVScrollMode
);
1683 ShowHide( pHSplitter
, bHScrollMode
|| bShowH
); // always generated
1684 ShowHide( pVSplitter
, bVScrollMode
|| bShowV
);
1685 ShowHide( pTabControl
, bTabMode
);
1687 // from here dynamically generated
1689 ShowHide( pGridWin
[SC_SPLIT_BOTTOMRIGHT
], bShowH
);
1690 ShowHide( pGridWin
[SC_SPLIT_TOPLEFT
], bShowV
);
1691 ShowHide( pGridWin
[SC_SPLIT_TOPRIGHT
], bShowH
&& bShowV
);
1693 ShowHide( pColOutline
[SC_SPLIT_LEFT
], bHOutline
);
1694 ShowHide( pColOutline
[SC_SPLIT_RIGHT
], bShowH
&& bHOutline
);
1696 ShowHide( pRowOutline
[SC_SPLIT_BOTTOM
], bVOutline
);
1697 ShowHide( pRowOutline
[SC_SPLIT_TOP
], bShowV
&& bVOutline
);
1699 ShowHide( pColBar
[SC_SPLIT_RIGHT
], bShowH
&& bHeader
);
1700 ShowHide( pRowBar
[SC_SPLIT_TOP
], bShowV
&& bHeader
);
1702 //! register new Gridwindows
1705 bool ScTabView::UpdateVisibleRange()
1707 bool bChanged
= false;
1708 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
1710 if (!pWin
|| !pWin
->IsVisible())
1713 if (pWin
->UpdateVisibleRange())
1720 // --- Splitter --------------------------------------------------------
1722 IMPL_LINK( ScTabView
, SplitHdl
, Splitter
*, pSplitter
, void )
1724 if ( pSplitter
== pHSplitter
)
1725 DoHSplit( pHSplitter
->GetSplitPosPixel() );
1727 DoVSplit( pVSplitter
->GetSplitPosPixel() );
1729 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
|| aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
1730 FreezeSplitters( true );
1732 DoResize( aBorderPos
, aFrameSize
);
1735 void ScTabView::DoHSplit(tools::Long nSplitPos
)
1737 // nSplitPos is the real pixel position on the frame window,
1738 // mirroring for RTL has to be done here.
1740 bool bLayoutRTL
= aViewData
.GetDocument().IsLayoutRTL( aViewData
.GetTabNo() );
1742 nSplitPos
= pFrameWin
->GetOutputSizePixel().Width() - nSplitPos
- 1;
1744 tools::Long nMinPos
;
1745 tools::Long nMaxPos
;
1747 nMinPos
= SPLIT_MARGIN
;
1748 if ( pRowBar
[SC_SPLIT_BOTTOM
] && pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width() >= nMinPos
)
1749 nMinPos
= pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width() + 1;
1750 nMaxPos
= aFrameSize
.Width() - SPLIT_MARGIN
;
1752 ScSplitMode aOldMode
= aViewData
.GetHSplitMode();
1753 ScSplitMode aNewMode
= SC_SPLIT_NORMAL
;
1755 aViewData
.SetHSplitPos( nSplitPos
);
1756 if ( nSplitPos
< nMinPos
|| nSplitPos
> nMaxPos
)
1757 aNewMode
= SC_SPLIT_NONE
;
1759 aViewData
.SetHSplitMode( aNewMode
);
1761 if ( aNewMode
== aOldMode
)
1764 UpdateShow(); // before ActivatePart !!
1766 if ( aNewMode
== SC_SPLIT_NONE
)
1768 if (aViewData
.GetActivePart() == SC_SPLIT_TOPRIGHT
)
1769 ActivatePart( SC_SPLIT_TOPLEFT
);
1770 if (aViewData
.GetActivePart() == SC_SPLIT_BOTTOMRIGHT
)
1771 ActivatePart( SC_SPLIT_BOTTOMLEFT
);
1775 // coverity[ tainted_data_return : FALSE ] version 2023.12.2
1776 SCCOL nOldDelta
= aViewData
.GetPosX( SC_SPLIT_LEFT
);
1777 tools::Long nLeftWidth
= nSplitPos
- pRowBar
[SC_SPLIT_BOTTOM
]->GetSizePixel().Width();
1778 if ( nLeftWidth
< 0 ) nLeftWidth
= 0;
1779 SCCOL nNewDelta
= nOldDelta
+ aViewData
.CellsAtX( nOldDelta
, 1, SC_SPLIT_LEFT
,
1780 static_cast<sal_uInt16
>(nLeftWidth
) );
1781 ScDocument
& rDoc
= aViewData
.GetDocument();
1782 if ( nNewDelta
> rDoc
.MaxCol() )
1783 nNewDelta
= rDoc
.MaxCol();
1784 aViewData
.SetPosX( SC_SPLIT_RIGHT
, nNewDelta
);
1785 if ( nNewDelta
> aViewData
.GetCurX() )
1786 ActivatePart( (WhichV(aViewData
.GetActivePart()) == SC_SPLIT_BOTTOM
) ?
1787 SC_SPLIT_BOTTOMLEFT
: SC_SPLIT_TOPLEFT
);
1789 ActivatePart( (WhichV(aViewData
.GetActivePart()) == SC_SPLIT_BOTTOM
) ?
1790 SC_SPLIT_BOTTOMRIGHT
: SC_SPLIT_TOPRIGHT
);
1793 // Form Layer needs to know the visible part of all windows
1794 // that is why MapMode must already be correct here
1795 SyncGridWindowMapModeFromDrawMapMode();
1804 void ScTabView::DoVSplit(tools::Long nSplitPos
)
1806 tools::Long nMinPos
;
1807 tools::Long nMaxPos
;
1810 nMinPos
= SPLIT_MARGIN
;
1811 if ( pColBar
[SC_SPLIT_LEFT
] && pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height() >= nMinPos
)
1812 nMinPos
= pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height() + 1;
1813 nMaxPos
= aFrameSize
.Height() - SPLIT_MARGIN
;
1815 ScSplitMode aOldMode
= aViewData
.GetVSplitMode();
1816 ScSplitMode aNewMode
= SC_SPLIT_NORMAL
;
1818 aViewData
.SetVSplitPos( nSplitPos
);
1819 if ( nSplitPos
< nMinPos
|| nSplitPos
> nMaxPos
)
1820 aNewMode
= SC_SPLIT_NONE
;
1822 aViewData
.SetVSplitMode( aNewMode
);
1824 if ( aNewMode
== aOldMode
)
1827 UpdateShow(); // before ActivatePart !!
1829 if ( aNewMode
== SC_SPLIT_NONE
)
1831 nOldDelta
= aViewData
.GetPosY( SC_SPLIT_TOP
);
1832 aViewData
.SetPosY( SC_SPLIT_BOTTOM
, nOldDelta
);
1834 if (aViewData
.GetActivePart() == SC_SPLIT_TOPLEFT
)
1835 ActivatePart( SC_SPLIT_BOTTOMLEFT
);
1836 if (aViewData
.GetActivePart() == SC_SPLIT_TOPRIGHT
)
1837 ActivatePart( SC_SPLIT_BOTTOMRIGHT
);
1841 if ( aOldMode
== SC_SPLIT_NONE
)
1843 // coverity[ tainted_data_return : FALSE ] version 2023.12.2
1844 nOldDelta
= aViewData
.GetPosY( SC_SPLIT_BOTTOM
);
1847 nOldDelta
= aViewData
.GetPosY( SC_SPLIT_TOP
);
1849 aViewData
.SetPosY( SC_SPLIT_TOP
, nOldDelta
);
1850 tools::Long nTopHeight
= nSplitPos
- pColBar
[SC_SPLIT_LEFT
]->GetSizePixel().Height();
1851 if ( nTopHeight
< 0 ) nTopHeight
= 0;
1852 SCROW nNewDelta
= nOldDelta
+ aViewData
.CellsAtY( nOldDelta
, 1, SC_SPLIT_TOP
,
1853 static_cast<sal_uInt16
>(nTopHeight
) );
1854 ScDocument
& rDoc
= aViewData
.GetDocument();
1855 if ( nNewDelta
> rDoc
.MaxRow() )
1856 nNewDelta
= rDoc
.MaxRow();
1857 aViewData
.SetPosY( SC_SPLIT_BOTTOM
, nNewDelta
);
1858 if ( nNewDelta
> aViewData
.GetCurY() )
1859 ActivatePart( (WhichH(aViewData
.GetActivePart()) == SC_SPLIT_LEFT
) ?
1860 SC_SPLIT_TOPLEFT
: SC_SPLIT_TOPRIGHT
);
1862 ActivatePart( (WhichH(aViewData
.GetActivePart()) == SC_SPLIT_LEFT
) ?
1863 SC_SPLIT_BOTTOMLEFT
: SC_SPLIT_BOTTOMRIGHT
);
1866 // Form Layer needs to know the visible part of all windows
1867 // that is why MapMode must already be correct here
1868 SyncGridWindowMapModeFromDrawMapMode();
1877 Point
ScTabView::GetInsertPos() const
1879 ScDocument
& rDoc
= aViewData
.GetDocument();
1880 SCCOL nCol
= aViewData
.GetCurX();
1881 SCROW nRow
= aViewData
.GetCurY();
1882 SCTAB nTab
= aViewData
.GetTabNo();
1883 tools::Long nPosX
= 0;
1884 for (SCCOL i
=0; i
<nCol
; i
++)
1885 nPosX
+= rDoc
.GetColWidth(i
,nTab
);
1886 nPosX
= o3tl::convert(nPosX
, o3tl::Length::twip
, o3tl::Length::mm100
);
1887 if ( rDoc
.IsNegativePage( nTab
) )
1889 tools::Long nPosY
= rDoc
.GetRowHeight( 0, nRow
-1, nTab
);
1890 nPosY
= o3tl::convert(nPosY
, o3tl::Length::twip
, o3tl::Length::mm100
);
1891 return Point(nPosX
,nPosY
);
1894 Point
ScTabView::GetChartInsertPos( const Size
& rSize
, const ScRange
& rCellRange
)
1897 const tools::Long nBorder
= 100; // leave 1mm for border
1898 tools::Long nNeededWidth
= rSize
.Width() + 2 * nBorder
;
1899 tools::Long nNeededHeight
= rSize
.Height() + 2 * nBorder
;
1901 // use the active window, or lower/right if frozen (as in CalcZoom)
1902 ScSplitPos eUsedPart
= aViewData
.GetActivePart();
1903 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
1904 eUsedPart
= (WhichV(eUsedPart
)==SC_SPLIT_TOP
) ? SC_SPLIT_TOPRIGHT
: SC_SPLIT_BOTTOMRIGHT
;
1905 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
1906 eUsedPart
= (WhichH(eUsedPart
)==SC_SPLIT_LEFT
) ? SC_SPLIT_BOTTOMLEFT
: SC_SPLIT_BOTTOMRIGHT
;
1908 ScGridWindow
* pWin
= pGridWin
[eUsedPart
].get();
1909 OSL_ENSURE( pWin
, "Window not found" );
1912 ActivatePart( eUsedPart
);
1914 // get the visible rectangle in logic units
1915 bool bLOKActive
= comphelper::LibreOfficeKit::isActive();
1916 MapMode aDrawMode
= pWin
->GetDrawMapMode();
1917 tools::Rectangle
aVisible(
1919 OutputDevice::LogicToLogic( aViewData
.getLOKVisibleArea(), MapMode(MapUnit::MapTwip
), MapMode(MapUnit::Map100thMM
) )
1920 : pWin
->PixelToLogic( tools::Rectangle( Point(0,0), pWin
->GetOutputSizePixel() ), aDrawMode
) );
1922 ScDocument
& rDoc
= aViewData
.GetDocument();
1923 SCTAB nTab
= aViewData
.GetTabNo();
1924 bool bLayoutRTL
= rDoc
.IsLayoutRTL( nTab
);
1925 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
1927 tools::Long nDocX
= o3tl::convert(rDoc
.GetColOffset(rDoc
.MaxCol() + 1, nTab
), o3tl::Length::twip
, o3tl::Length::mm100
) * nLayoutSign
;
1928 tools::Long nDocY
= o3tl::convert(rDoc
.GetRowOffset( rDoc
.MaxRow() + 1, nTab
), o3tl::Length::twip
, o3tl::Length::mm100
);
1930 if ( aVisible
.Left() * nLayoutSign
> nDocX
* nLayoutSign
)
1931 aVisible
.SetLeft( nDocX
);
1932 if ( aVisible
.Right() * nLayoutSign
> nDocX
* nLayoutSign
)
1933 aVisible
.SetRight( nDocX
);
1934 if ( aVisible
.Top() > nDocY
)
1935 aVisible
.SetTop( nDocY
);
1936 if ( aVisible
.Bottom() > nDocY
)
1937 aVisible
.SetBottom( nDocY
);
1939 // get the logic position of the selection
1941 tools::Rectangle aSelection
= rDoc
.GetMMRect( rCellRange
.aStart
.Col(), rCellRange
.aStart
.Row(),
1942 rCellRange
.aEnd
.Col(), rCellRange
.aEnd
.Row(), nTab
);
1944 if (bLOKActive
&& bLayoutRTL
)
1946 // In this case we operate in negative X coordinates. The rectangle aSelection already
1947 // has negative X coordinates. So the x coordinates in the rectangle aVisible(from getLOKVisibleArea)
1948 // need be negated to match.
1949 aVisible
= tools::Rectangle(-aVisible
.Right(), aVisible
.Top(), -aVisible
.Left(), aVisible
.Bottom());
1952 tools::Long nLeftSpace
= aSelection
.Left() - aVisible
.Left();
1953 tools::Long nRightSpace
= aVisible
.Right() - aSelection
.Right();
1954 tools::Long nTopSpace
= aSelection
.Top() - aVisible
.Top();
1955 tools::Long nBottomSpace
= aVisible
.Bottom() - aSelection
.Bottom();
1957 bool bFitLeft
= ( nLeftSpace
>= nNeededWidth
);
1958 bool bFitRight
= ( nRightSpace
>= nNeededWidth
);
1960 if ( bFitLeft
|| bFitRight
)
1962 // first preference: completely left or right of the selection
1964 // if both fit, prefer left in RTL mode, right otherwise
1965 bool bPutLeft
= bFitLeft
&& ( bLayoutRTL
|| !bFitRight
);
1968 aInsertPos
.setX( aSelection
.Left() - nNeededWidth
);
1970 aInsertPos
.setX( aSelection
.Right() + 1 );
1972 // align with top of selection (is moved again if it doesn't fit)
1973 aInsertPos
.setY( std::max( aSelection
.Top(), aVisible
.Top() ) );
1975 else if ( nTopSpace
>= nNeededHeight
|| nBottomSpace
>= nNeededHeight
)
1977 // second preference: completely above or below the selection
1978 if ( nBottomSpace
> nNeededHeight
) // bottom is preferred
1979 aInsertPos
.setY( aSelection
.Bottom() + 1 );
1981 aInsertPos
.setY( aSelection
.Top() - nNeededHeight
);
1983 // align with (logic) left edge of selection (moved again if it doesn't fit)
1985 aInsertPos
.setX( std::min( aSelection
.Right(), aVisible
.Right() ) - nNeededWidth
+ 1 );
1987 aInsertPos
.setX( std::max( aSelection
.Left(), aVisible
.Left() ) );
1991 // place to the (logic) right of the selection and move so it fits
1994 aInsertPos
.setX( aSelection
.Left() - nNeededWidth
);
1996 aInsertPos
.setX( aSelection
.Right() + 1 );
1997 aInsertPos
.setY( std::max( aSelection
.Top(), aVisible
.Top() ) );
2000 // move the position if the object doesn't fit in the screen
2002 tools::Rectangle
aCompareRect( aInsertPos
, Size( nNeededWidth
, nNeededHeight
) );
2003 if ( aCompareRect
.Right() > aVisible
.Right() )
2004 aInsertPos
.AdjustX( -(aCompareRect
.Right() - aVisible
.Right()) );
2005 if ( aCompareRect
.Bottom() > aVisible
.Bottom() )
2006 aInsertPos
.AdjustY( -(aCompareRect
.Bottom() - aVisible
.Bottom()) );
2008 if ( aInsertPos
.X() < aVisible
.Left() )
2009 aInsertPos
.setX( aVisible
.Left() );
2010 if ( aInsertPos
.Y() < aVisible
.Top() )
2011 aInsertPos
.setY( aVisible
.Top() );
2013 // nNeededWidth / nNeededHeight includes all borders - move aInsertPos to the
2014 // object position, inside the border
2016 aInsertPos
.AdjustX(nBorder
);
2017 aInsertPos
.AdjustY(nBorder
);
2022 Point
ScTabView::GetChartDialogPos( const Size
& rDialogSize
, const tools::Rectangle
& rLogicChart
)
2024 // rDialogSize must be in pixels, rLogicChart in 1/100 mm. Return value is in pixels.
2028 // use the active window, or lower/right if frozen (as in CalcZoom)
2029 ScSplitPos eUsedPart
= aViewData
.GetActivePart();
2030 if ( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
)
2031 eUsedPart
= (WhichV(eUsedPart
)==SC_SPLIT_TOP
) ? SC_SPLIT_TOPRIGHT
: SC_SPLIT_BOTTOMRIGHT
;
2032 if ( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
2033 eUsedPart
= (WhichH(eUsedPart
)==SC_SPLIT_LEFT
) ? SC_SPLIT_BOTTOMLEFT
: SC_SPLIT_BOTTOMRIGHT
;
2035 ScGridWindow
* pWin
= pGridWin
[eUsedPart
].get();
2036 OSL_ENSURE( pWin
, "Window not found" );
2039 MapMode aDrawMode
= pWin
->GetDrawMapMode();
2040 tools::Rectangle aObjPixel
= pWin
->LogicToPixel( rLogicChart
, aDrawMode
);
2041 AbsoluteScreenPixelRectangle
aObjAbs( pWin
->OutputToAbsoluteScreenPixel( aObjPixel
.TopLeft() ),
2042 pWin
->OutputToAbsoluteScreenPixel( aObjPixel
.BottomRight() ) );
2044 AbsoluteScreenPixelRectangle aDesktop
= pWin
->GetDesktopRectPixel();
2045 Size aSpace
= pWin
->LogicToPixel( Size(8, 12), MapMode(MapUnit::MapAppFont
));
2047 ScDocument
& rDoc
= aViewData
.GetDocument();
2048 SCTAB nTab
= aViewData
.GetTabNo();
2049 bool bLayoutRTL
= rDoc
.IsLayoutRTL( nTab
);
2051 bool bCenterHor
= false;
2053 if ( aDesktop
.Bottom() - aObjAbs
.Bottom() >= rDialogSize
.Height() + aSpace
.Height() )
2055 // first preference: below the chart
2057 aRet
.setY( aObjAbs
.Bottom() + aSpace
.Height() );
2060 else if ( aObjAbs
.Top() - aDesktop
.Top() >= rDialogSize
.Height() + aSpace
.Height() )
2062 // second preference: above the chart
2064 aRet
.setY( aObjAbs
.Top() - rDialogSize
.Height() - aSpace
.Height() );
2069 bool bFitLeft
= ( aObjAbs
.Left() - aDesktop
.Left() >= rDialogSize
.Width() + aSpace
.Width() );
2070 bool bFitRight
= ( aDesktop
.Right() - aObjAbs
.Right() >= rDialogSize
.Width() + aSpace
.Width() );
2072 if ( bFitLeft
|| bFitRight
)
2074 // if both fit, prefer right in RTL mode, left otherwise
2075 bool bPutRight
= bFitRight
&& ( bLayoutRTL
|| !bFitLeft
);
2077 aRet
.setX( aObjAbs
.Right() + aSpace
.Width() );
2079 aRet
.setX( aObjAbs
.Left() - rDialogSize
.Width() - aSpace
.Width() );
2081 // center vertically
2082 aRet
.setY( aObjAbs
.Top() + ( aObjAbs
.GetHeight() - rDialogSize
.Height() ) / 2 );
2086 // doesn't fit on any edge - put at the bottom of the screen
2087 aRet
.setY( aDesktop
.Bottom() - rDialogSize
.Height() );
2092 aRet
.setX( aObjAbs
.Left() + ( aObjAbs
.GetWidth() - rDialogSize
.Width() ) / 2 );
2094 // limit to screen (centering might lead to invalid positions)
2095 if ( aRet
.X() + rDialogSize
.Width() - 1 > aDesktop
.Right() )
2096 aRet
.setX( aDesktop
.Right() - rDialogSize
.Width() + 1 );
2097 if ( aRet
.X() < aDesktop
.Left() )
2098 aRet
.setX( aDesktop
.Left() );
2099 if ( aRet
.Y() + rDialogSize
.Height() - 1 > aDesktop
.Bottom() )
2100 aRet
.setY( aDesktop
.Bottom() - rDialogSize
.Height() + 1 );
2101 if ( aRet
.Y() < aDesktop
.Top() )
2102 aRet
.setY( aDesktop
.Top() );
2108 void ScTabView::LockModifiers( sal_uInt16 nModifiers
)
2110 pSelEngine
->LockModifiers( nModifiers
);
2111 pHdrSelEng
->LockModifiers( nModifiers
);
2114 sal_uInt16
ScTabView::GetLockedModifiers() const
2116 return pSelEngine
->GetLockedModifiers();
2119 Point
ScTabView::GetMousePosPixel()
2122 ScGridWindow
* pWin
= GetActiveWin();
2125 aPos
= pWin
->GetMousePosPixel();
2130 void ScTabView::FreezeSplitters( bool bFreeze
, SplitMethod eSplitMethod
, SCCOLROW nFreezeIndex
)
2132 if ((eSplitMethod
== SC_SPLIT_METHOD_COL
|| eSplitMethod
== SC_SPLIT_METHOD_ROW
) && nFreezeIndex
< 0)
2135 ScSplitMode eOldH
= aViewData
.GetHSplitMode();
2136 ScSplitMode eOldV
= aViewData
.GetVSplitMode();
2138 ScSplitPos ePos
= SC_SPLIT_BOTTOMLEFT
;
2139 if ( eOldV
!= SC_SPLIT_NONE
)
2140 ePos
= SC_SPLIT_TOPLEFT
;
2141 vcl::Window
* pWin
= pGridWin
[ePos
];
2143 bool bLayoutRTL
= aViewData
.GetDocument().IsLayoutRTL( aViewData
.GetTabNo() );
2144 bool bUpdateFix
= false;
2148 Point aWinStart
= pWin
->GetPosPixel();
2149 aViewData
.GetDocShell()->SetDocumentModified();
2154 if (eOldV
!= SC_SPLIT_NONE
|| eOldH
!= SC_SPLIT_NONE
)
2156 if ( eOldV
!= SC_SPLIT_NONE
&& (eSplitMethod
== SC_SPLIT_METHOD_ROW
|| eSplitMethod
== SC_SPLIT_METHOD_CURSOR
))
2157 aSplit
.setY( aViewData
.GetVSplitPos() - aWinStart
.Y() );
2159 if ( eOldH
!= SC_SPLIT_NONE
&& (eSplitMethod
== SC_SPLIT_METHOD_COL
|| eSplitMethod
== SC_SPLIT_METHOD_CURSOR
))
2161 tools::Long nSplitPos
= aViewData
.GetHSplitPos();
2163 nSplitPos
= pFrameWin
->GetOutputSizePixel().Width() - nSplitPos
- 1;
2164 aSplit
.setX( nSplitPos
- aWinStart
.X() );
2167 aViewData
.GetPosFromPixel( aSplit
.X(), aSplit
.Y(), ePos
, nPosX
, nPosY
);
2170 aViewData
.GetMouseQuadrant( aSplit
, ePos
, nPosX
, nPosY
, bLeft
, bTop
);
2171 if (eSplitMethod
== SC_SPLIT_METHOD_COL
)
2172 nPosX
= static_cast<SCCOL
>(nFreezeIndex
);
2175 if (eSplitMethod
== SC_SPLIT_METHOD_ROW
)
2176 nPosY
= static_cast<SCROW
>(nFreezeIndex
);
2182 switch(eSplitMethod
)
2184 case SC_SPLIT_METHOD_ROW
:
2187 nPosY
= static_cast<SCROW
>(nFreezeIndex
);
2190 case SC_SPLIT_METHOD_COL
:
2192 nPosX
= static_cast<SCCOL
>(nFreezeIndex
);
2196 case SC_SPLIT_METHOD_CURSOR
:
2198 nPosX
= aViewData
.GetCurX();
2199 nPosY
= aViewData
.GetCurY();
2205 SCROW nTopPos
= aViewData
.GetPosY(SC_SPLIT_BOTTOM
);
2206 SCROW nBottomPos
= nPosY
;
2207 SCCOL nLeftPos
= aViewData
.GetPosX(SC_SPLIT_LEFT
);
2208 SCCOL nRightPos
= nPosX
;
2210 if (eSplitMethod
== SC_SPLIT_METHOD_ROW
|| eSplitMethod
== SC_SPLIT_METHOD_CURSOR
)
2212 if (eOldV
!= SC_SPLIT_NONE
)
2214 nTopPos
= aViewData
.GetPosY(SC_SPLIT_TOP
);
2215 nBottomPos
= std::max(aViewData
.GetPosY(SC_SPLIT_BOTTOM
), nBottomPos
);
2217 aSplit
= aViewData
.GetScrPos(nPosX
, nPosY
, ePos
, true);
2220 aViewData
.SetVSplitMode(SC_SPLIT_FIX
);
2221 aViewData
.SetVSplitPos(aSplit
.Y() + aWinStart
.Y());
2222 aViewData
.SetFixPosY(nPosY
);
2224 aViewData
.SetPosY(SC_SPLIT_TOP
, nTopPos
);
2225 aViewData
.SetPosY(SC_SPLIT_BOTTOM
, nBottomPos
);
2227 else if (nPosY
== 1 && eSplitMethod
== SC_SPLIT_METHOD_ROW
)
2229 // Freeze first row, but row 1 is not visible on screen now == special handling
2230 aViewData
.SetVSplitMode(SC_SPLIT_FIX
);
2231 aViewData
.SetFixPosY(nPosY
);
2233 aViewData
.SetPosY(SC_SPLIT_TOP
, 0);
2237 aViewData
.SetVSplitMode(SC_SPLIT_NONE
);
2240 if (eSplitMethod
== SC_SPLIT_METHOD_COL
|| eSplitMethod
== SC_SPLIT_METHOD_CURSOR
)
2242 if (eOldH
!= SC_SPLIT_NONE
)
2244 if (aViewData
.GetPosX(SC_SPLIT_RIGHT
) > nRightPos
)
2245 nRightPos
= aViewData
.GetPosX(SC_SPLIT_RIGHT
);
2247 aSplit
= aViewData
.GetScrPos( nPosX
, nPosY
, ePos
, true );
2248 if (nPosX
> aViewData
.GetPosX(SC_SPLIT_LEFT
)) // (aSplit.X() > 0) doesn't work for RTL
2250 tools::Long nSplitPos
= aSplit
.X() + aWinStart
.X();
2252 nSplitPos
= pFrameWin
->GetOutputSizePixel().Width() - nSplitPos
- 1;
2254 aViewData
.SetHSplitMode( SC_SPLIT_FIX
);
2255 aViewData
.SetHSplitPos( nSplitPos
);
2256 aViewData
.SetFixPosX( nPosX
);
2258 aViewData
.SetPosX(SC_SPLIT_LEFT
, nLeftPos
);
2259 aViewData
.SetPosX(SC_SPLIT_RIGHT
, nRightPos
);
2261 else if (nPosX
== 1 && eSplitMethod
== SC_SPLIT_METHOD_COL
)
2263 // Freeze first column, but col A is not visible on screen now == special handling
2264 aViewData
.SetHSplitMode(SC_SPLIT_FIX
);
2265 aViewData
.SetFixPosX(nPosX
);
2267 aViewData
.SetPosX(SC_SPLIT_RIGHT
, aViewData
.GetPosX(SC_SPLIT_LEFT
));
2268 aViewData
.SetPosX(SC_SPLIT_LEFT
, 0);
2272 aViewData
.SetHSplitMode( SC_SPLIT_NONE
);
2277 if ( eOldH
== SC_SPLIT_FIX
)
2278 aViewData
.SetHSplitMode( SC_SPLIT_NORMAL
);
2279 if ( eOldV
== SC_SPLIT_FIX
)
2280 aViewData
.SetVSplitMode( SC_SPLIT_NORMAL
);
2283 // Form Layer needs to know the visible part of all windows
2284 // that is why MapMode must already be correct here
2285 SyncGridWindowMapModeFromDrawMapMode();
2288 RepeatResize(bUpdateFix
);
2295 // SC_FOLLOW_NONE: only update active part
2296 AlignToCursor( aViewData
.GetCurX(), aViewData
.GetCurY(), SC_FOLLOW_NONE
);
2297 UpdateAutoFillMark();
2302 void ScTabView::RemoveSplit()
2304 if (aViewData
.GetHSplitMode() == SC_SPLIT_FIX
|| aViewData
.GetVSplitMode() == SC_SPLIT_FIX
)
2305 aViewData
.GetDocShell()->SetDocumentModified();
2311 void ScTabView::SplitAtCursor()
2313 ScSplitPos ePos
= SC_SPLIT_BOTTOMLEFT
;
2314 if ( aViewData
.GetVSplitMode() != SC_SPLIT_NONE
)
2315 ePos
= SC_SPLIT_TOPLEFT
;
2316 vcl::Window
* pWin
= pGridWin
[ePos
];
2317 Point aWinStart
= pWin
->GetPosPixel();
2319 SCCOL nPosX
= aViewData
.GetCurX();
2320 SCROW nPosY
= aViewData
.GetCurY();
2321 Point aSplit
= aViewData
.GetScrPos( nPosX
, nPosY
, ePos
, true );
2323 DoHSplit( aSplit
.X() + aWinStart
.X() );
2327 DoVSplit( aSplit
.Y() + aWinStart
.Y() );
2333 void ScTabView::SplitAtPixel( const Point
& rPixel
)
2335 // pixel is relative to the entire View, not to the first GridWin
2337 if ( rPixel
.X() > 0 )
2338 DoHSplit( rPixel
.X() );
2341 if ( rPixel
.Y() > 0 )
2342 DoVSplit( rPixel
.Y() );
2348 void ScTabView::InvalidateSplit()
2350 SfxBindings
& rBindings
= aViewData
.GetBindings();
2351 rBindings
.Invalidate( SID_WINDOW_SPLIT
);
2352 rBindings
.Invalidate( SID_WINDOW_FIX
);
2353 rBindings
.Invalidate( SID_WINDOW_FIX_COL
);
2354 rBindings
.Invalidate( SID_WINDOW_FIX_ROW
);
2356 pHSplitter
->SetFixed( aViewData
.GetHSplitMode() == SC_SPLIT_FIX
);
2357 pVSplitter
->SetFixed( aViewData
.GetVSplitMode() == SC_SPLIT_FIX
);
2360 void ScTabView::SetNewVisArea()
2362 // Draw-MapMode must be set for Controls when VisAreaChanged
2363 // (also when Edit-MapMode is set instead)
2364 MapMode aOldMode
[4];
2365 MapMode aDrawMode
[4];
2370 aOldMode
[i
] = pGridWin
[i
]->GetMapMode();
2371 aDrawMode
[i
] = pGridWin
[i
]->GetDrawMapMode();
2372 if (aDrawMode
[i
] != aOldMode
[i
])
2373 pGridWin
[i
]->SetMapMode(aDrawMode
[i
]);
2376 vcl::Window
* pActive
= pGridWin
[aViewData
.GetActivePart()];
2378 aViewData
.GetViewShell()->VisAreaChanged();
2380 pDrawView
->VisAreaChanged(nullptr); // no window passed on -> for all windows
2382 UpdateAllOverlays(); // #i79909# with drawing MapMode set
2385 if (pGridWin
[i
] && aDrawMode
[i
] != aOldMode
[i
])
2387 pGridWin
[i
]->flushOverlayManager(); // #i79909# flush overlays before switching to edit MapMode
2388 pGridWin
[i
]->SetMapMode(aOldMode
[i
]);
2391 SfxViewFrame
& rViewFrame
= aViewData
.GetViewShell()->GetViewFrame();
2392 SfxFrame
& rFrame
= rViewFrame
.GetFrame();
2393 css::uno::Reference
<css::frame::XController
> xController
= rFrame
.GetController();
2394 if (xController
.is())
2396 ScTabViewObj
* pImp
= dynamic_cast<ScTabViewObj
*>( xController
.get() );
2398 pImp
->VisAreaChanged();
2401 if (GetViewData().HasEditView(GetViewData().GetActivePart()))
2403 EditView
*pEditView
= GetViewData().GetEditView(GetViewData().GetActivePart());
2404 vcl::Cursor
*pInPlaceCrsr
= pEditView
->GetCursor();
2405 bool bInPlaceVisCursor
= pInPlaceCrsr
&& pInPlaceCrsr
->IsVisible();
2407 if (bInPlaceVisCursor
)
2408 pInPlaceCrsr
->Hide();
2410 ScGridWindow
*pGridWindow
= GetViewData().GetActiveWin();
2411 pGridWindow
->DrawEditView(*pGridWindow
->GetOutDev(), pEditView
);
2413 pGridWindow
->flushOverlayManager();
2414 pGridWindow
->GetOutDev()->SetMapMode(GetViewData().GetLogicMode());
2416 if (bInPlaceVisCursor
)
2417 pInPlaceCrsr
->Show();
2420 if (aViewData
.GetViewShell()->HasAccessibilityObjects())
2421 aViewData
.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccVisAreaChanged
));
2424 bool ScTabView::HasPageFieldDataAtCursor() const
2426 ScGridWindow
* pWin
= pGridWin
[aViewData
.GetActivePart()].get();
2427 SCCOL nCol
= aViewData
.GetCurX();
2428 SCROW nRow
= aViewData
.GetCurY();
2430 return pWin
->GetDPFieldOrientation( nCol
, nRow
) == sheet::DataPilotFieldOrientation_PAGE
;
2435 void ScTabView::StartDataSelect()
2437 ScGridWindow
* pWin
= pGridWin
[aViewData
.GetActivePart()].get();
2438 SCCOL nCol
= aViewData
.GetCurX();
2439 SCROW nRow
= aViewData
.GetCurY();
2444 switch (pWin
->GetDPFieldOrientation(nCol
, nRow
))
2446 case sheet::DataPilotFieldOrientation_PAGE
:
2447 // #i36598# If the cursor is on a page field's data cell,
2448 // no meaningful input is possible anyway, so this function
2449 // can be used to select a page field entry.
2450 pWin
->LaunchPageFieldMenu( nCol
, nRow
);
2452 case sheet::DataPilotFieldOrientation_COLUMN
:
2453 case sheet::DataPilotFieldOrientation_ROW
:
2454 pWin
->LaunchDPFieldMenu( nCol
, nRow
);
2460 // Do autofilter if the current cell has autofilter button. Otherwise do
2461 // a normal data select popup.
2462 const ScMergeFlagAttr
* pAttr
=
2463 aViewData
.GetDocument().GetAttr(
2464 nCol
, nRow
, aViewData
.GetTabNo(), ATTR_MERGE_FLAG
);
2466 if (pAttr
->HasAutoFilter())
2467 pWin
->LaunchAutoFilterMenu(nCol
, nRow
);
2469 pWin
->LaunchDataSelectMenu(nCol
, nRow
);
2472 void ScTabView::EnableRefInput(bool bFlag
)
2474 aHScrollLeft
->EnableInput(bFlag
);
2475 aHScrollRight
->EnableInput(bFlag
);
2476 aVScrollBottom
->EnableInput(bFlag
);
2477 aVScrollTop
->EnableInput(bFlag
);
2479 // from here on dynamically created ones
2481 if(pTabControl
!=nullptr) pTabControl
->EnableInput(bFlag
);
2483 for (auto& p
: pGridWin
)
2485 p
->EnableInput(bFlag
, false);
2486 for (auto& p
: pColBar
)
2488 p
->EnableInput(bFlag
, false);
2489 for (auto& p
: pRowBar
)
2491 p
->EnableInput(bFlag
, false);
2494 void ScTabView::EnableAutoSpell( bool bEnable
)
2496 const bool bWasEnabled
= IsAutoSpell();
2499 std::make_shared
<sc::SpellCheckContext
>(&aViewData
.GetDocument(),
2500 aViewData
.GetTabNo());
2502 mpSpellCheckCxt
.reset();
2504 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
2509 pWin
->SetAutoSpellContext(mpSpellCheckCxt
);
2512 if (bWasEnabled
!= bEnable
&& comphelper::LibreOfficeKit::isActive())
2514 if (ScTabViewShell
* pViewSh
= aViewData
.GetViewShell())
2516 ScModelObj
* pModel
= comphelper::getFromUnoTunnel
<ScModelObj
>(pViewSh
->GetCurrentDocument());
2517 SfxLokHelper::notifyViewRenderState(pViewSh
, pModel
);
2522 bool ScTabView::IsAutoSpell() const
2524 return static_cast<bool>(mpSpellCheckCxt
);
2527 void ScTabView::ResetAutoSpell()
2529 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
2534 pWin
->ResetAutoSpell();
2538 void ScTabView::ResetAutoSpellForContentChange()
2540 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
2545 pWin
->ResetAutoSpellForContentChange();
2549 void ScTabView::SetAutoSpellData( SCCOL nPosX
, SCROW nPosY
, const std::vector
<editeng::MisspellRanges
>* pRanges
)
2551 for (VclPtr
<ScGridWindow
> & pWin
: pGridWin
)
2556 pWin
->SetAutoSpellData(nPosX
, nPosY
, pRanges
);
2563 tools::Long
lcl_GetRowHeightPx(const ScViewData
&rViewData
, SCROW nRow
, SCTAB nTab
)
2565 const sal_uInt16 nSize
= rViewData
.GetDocument().GetRowHeight(nRow
, nTab
);
2566 return ScViewData::ToPixel(nSize
, rViewData
.GetPPTY());
2569 tools::Long
lcl_GetColWidthPx(const ScViewData
&rViewData
, SCCOL nCol
, SCTAB nTab
)
2571 const sal_uInt16 nSize
= rViewData
.GetDocument().GetColWidth(nCol
, nTab
);
2572 return ScViewData::ToPixel(nSize
, rViewData
.GetPPTX());
2575 void lcl_getGroupIndexes(const ScOutlineArray
& rArray
, SCCOLROW nStart
, SCCOLROW nEnd
, std::vector
<size_t>& rGroupIndexes
)
2577 rGroupIndexes
.clear();
2578 const size_t nGroupDepth
= rArray
.GetDepth();
2579 rGroupIndexes
.resize(nGroupDepth
);
2581 // Get first group per each level
2582 for (size_t nLevel
= 0; nLevel
< nGroupDepth
; ++nLevel
)
2584 if (rArray
.GetCount(nLevel
))
2586 // look for a group inside the [nStartRow+1, nEndRow] range
2588 bool bFound
= rArray
.GetEntryIndexInRange(nLevel
, nStart
+ 1, nEnd
, nIndex
);
2593 // is there a previous group not inside the range
2594 // but anyway intersecting it ?
2595 const ScOutlineEntry
* pPrevEntry
= rArray
.GetEntry(nLevel
, nIndex
- 1);
2596 if (pPrevEntry
&& nStart
< pPrevEntry
->GetEnd())
2604 // look for a group which contains nStartRow+1
2605 bFound
= rArray
.GetEntryIndex(nLevel
, nStart
+ 1, nIndex
);
2608 // look for a group which contains nEndRow
2609 bFound
= rArray
.GetEntryIndex(nLevel
, nEnd
, nIndex
);
2615 // skip groups with no visible control
2617 while (nIndex
< rArray
.GetCount(nLevel
))
2619 const ScOutlineEntry
* pEntry
= rArray
.GetEntry(nLevel
, nIndex
);
2620 if (pEntry
&& pEntry
->IsVisible())
2625 if (pEntry
&& pEntry
->GetStart() > nEnd
)
2633 rGroupIndexes
[nLevel
] = bFound
? nIndex
: -1;
2638 void lcl_createGroupsData(
2639 SCCOLROW nHeaderIndex
, SCCOLROW nEnd
, tools::Long nSizePx
, tools::Long nTotalPx
,
2640 const ScOutlineArray
& rArray
, std::vector
<size_t>& rGroupIndexes
,
2641 std::vector
<tools::Long
>& rGroupStartPositions
, OStringBuffer
& rGroupsBuffer
)
2643 const size_t nGroupDepth
= rArray
.GetDepth();
2644 // create string data for group controls
2645 for (size_t nLevel
= nGroupDepth
- 1; nLevel
!= size_t(-1); --nLevel
)
2647 size_t nIndex
= rGroupIndexes
[nLevel
];
2648 if (nIndex
== size_t(-1))
2650 const ScOutlineEntry
* pEntry
= rArray
.GetEntry(nLevel
, nIndex
);
2653 if (nHeaderIndex
< pEntry
->GetStart())
2657 else if (nHeaderIndex
== pEntry
->GetStart())
2659 rGroupStartPositions
[nLevel
] = nTotalPx
- nSizePx
;
2661 else if (nHeaderIndex
> pEntry
->GetStart() && (nHeaderIndex
< nEnd
&& nHeaderIndex
< pEntry
->GetEnd()))
2663 // for handling group started before the current view range
2664 if (rGroupStartPositions
[nLevel
] < 0)
2665 rGroupStartPositions
[nLevel
] *= -1;
2668 if (nHeaderIndex
== pEntry
->GetEnd() || (nHeaderIndex
== nEnd
&& rGroupStartPositions
[nLevel
] != -1))
2670 // nHeaderIndex is the end col/row of a group or is the last col/row and a group started and not yet ended
2672 // append a new group control data
2673 auto len
= rGroupsBuffer
.getLength();
2674 if (len
&& rGroupsBuffer
[len
-1] == '}')
2676 rGroupsBuffer
.append(", ");
2679 bool bGroupHidden
= pEntry
->IsHidden();
2681 rGroupsBuffer
.append(
2682 "{ \"level\": " + OString::number(nLevel
+ 1) + ", "
2683 "\"index\": " + OString::number(nIndex
) + ", "
2684 "\"startPos\": " + OString::number(rGroupStartPositions
[nLevel
]) + ", "
2685 "\"endPos\": " + OString::number(nTotalPx
) + ", "
2686 "\"hidden\": " + OString::number(bGroupHidden
? 1 : 0) + " }");
2688 // look for the next visible group control at level nLevel
2689 bool bFound
= false;
2691 while (nIndex
< rArray
.GetCount(nLevel
))
2693 pEntry
= rArray
.GetEntry(nLevel
, nIndex
);
2694 if (pEntry
&& pEntry
->IsVisible())
2699 if (pEntry
&& pEntry
->GetStart() > nEnd
)
2705 rGroupIndexes
[nLevel
] = bFound
? nIndex
: -1;
2706 rGroupStartPositions
[nLevel
] = -1;
2712 class ScRangeProvider
2715 ScRangeProvider(const tools::Rectangle
& rArea
, bool bInPixels
,
2716 ScViewData
& rViewData
):
2717 mrViewData(rViewData
)
2719 tools::Rectangle aAreaPx
= bInPixels
? rArea
:
2720 tools::Rectangle(rArea
.Left() * mrViewData
.GetPPTX(),
2721 rArea
.Top() * mrViewData
.GetPPTY(),
2722 rArea
.Right() * mrViewData
.GetPPTX(),
2723 rArea
.Bottom() * mrViewData
.GetPPTY());
2724 calculateBounds(aAreaPx
);
2727 const ScRange
& getCellRange() const
2732 void getColPositions(tools::Long
& rStartColPos
, tools::Long
& rEndColPos
) const
2734 rStartColPos
= maBoundPositions
.Left();
2735 rEndColPos
= maBoundPositions
.Right();
2738 void getRowPositions(tools::Long
& rStartRowPos
, tools::Long
& rEndRowPos
) const
2740 rStartRowPos
= maBoundPositions
.Top();
2741 rEndRowPos
= maBoundPositions
.Bottom();
2745 void calculateBounds(const tools::Rectangle
& rAreaPx
)
2747 tools::Long nLeftPx
= 0, nRightPx
= 0;
2748 SCCOLROW nStartCol
= -1, nEndCol
= -1;
2749 calculateDimensionBounds(rAreaPx
.Left(), rAreaPx
.Right(), true,
2750 nStartCol
, nEndCol
, nLeftPx
, nRightPx
,
2751 mnEnlargeX
, mrViewData
);
2752 tools::Long nTopPx
= 0, nBottomPx
= 0;
2753 SCCOLROW nStartRow
= -1, nEndRow
= -1;
2754 calculateDimensionBounds(rAreaPx
.Top(), rAreaPx
.Bottom(), false,
2755 nStartRow
, nEndRow
, nTopPx
, nBottomPx
,
2756 mnEnlargeY
, mrViewData
);
2758 maRange
.aStart
.Set(nStartCol
, nStartRow
, mrViewData
.GetTabNo());
2759 maRange
.aEnd
.Set(nEndCol
, nEndRow
, mrViewData
.GetTabNo());
2761 maBoundPositions
.SetLeft(nLeftPx
);
2762 maBoundPositions
.SetRight(nRightPx
);
2763 maBoundPositions
.SetTop(nTopPx
);
2764 maBoundPositions
.SetBottom(nBottomPx
);
2767 // All positions are in pixels.
2768 static void calculateDimensionBounds(const tools::Long nStartPos
, const tools::Long nEndPos
,
2769 bool bColumns
, SCCOLROW
& rStartIndex
,
2770 SCCOLROW
& rEndIndex
, tools::Long
& rBoundStart
,
2771 tools::Long
& rBoundEnd
, SCCOLROW nEnlarge
,
2772 ScViewData
& rViewData
)
2774 ScPositionHelper
& rPosHelper
= bColumns
? rViewData
.GetLOKWidthHelper() :
2775 rViewData
.GetLOKHeightHelper();
2776 const auto& rStartNearest
= rPosHelper
.getNearestByPosition(nStartPos
);
2777 const auto& rEndNearest
= rPosHelper
.getNearestByPosition(nEndPos
);
2779 ScBoundsProvider
aBoundsProvider(rViewData
, rViewData
.GetTabNo(), bColumns
);
2780 aBoundsProvider
.Compute(rStartNearest
, rEndNearest
, nStartPos
, nEndPos
);
2781 aBoundsProvider
.EnlargeBy(nEnlarge
);
2784 SCCOL nStartCol
= -1, nEndCol
= -1;
2785 aBoundsProvider
.GetStartIndexAndPosition(nStartCol
, rBoundStart
);
2786 aBoundsProvider
.GetEndIndexAndPosition(nEndCol
, rBoundEnd
);
2787 rStartIndex
= nStartCol
;
2788 rEndIndex
= nEndCol
;
2792 SCROW nStartRow
= -1, nEndRow
= -1;
2793 aBoundsProvider
.GetStartIndexAndPosition(nStartRow
, rBoundStart
);
2794 aBoundsProvider
.GetEndIndexAndPosition(nEndRow
, rBoundEnd
);
2795 rStartIndex
= nStartRow
;
2796 rEndIndex
= nEndRow
;
2803 tools::Rectangle maBoundPositions
;
2804 ScViewData
& mrViewData
;
2805 static const SCCOLROW mnEnlargeX
= 2;
2806 static const SCCOLROW mnEnlargeY
= 2;
2809 void lcl_ExtendTiledDimension(bool bColumn
, const SCCOLROW nEnd
, const SCCOLROW nExtra
,
2810 ScTabView
& rTabView
, ScViewData
& rViewData
)
2812 ScDocument
& rDoc
= rViewData
.GetDocument();
2813 // If we are approaching current max tiled row/col, signal a size changed event
2814 // and invalidate the involved area
2815 SCCOLROW nMaxTiledIndex
= bColumn
? rViewData
.GetMaxTiledCol() : rViewData
.GetMaxTiledRow();
2816 SCCOLROW nHardLimit
= !bColumn
? MAXTILEDROW
: rDoc
.MaxCol();
2818 if (nMaxTiledIndex
>= nHardLimit
)
2821 if (nEnd
<= nMaxTiledIndex
- nExtra
) // No need to extend.
2824 ScDocShell
* pDocSh
= rViewData
.GetDocShell();
2825 ScModelObj
* pModelObj
= pDocSh
? pDocSh
->GetModel() : nullptr;
2826 Size
aOldSize(0, 0);
2828 aOldSize
= pModelObj
->getDocumentSize();
2830 SCCOLROW nNewMaxTiledIndex
= std::min(std::max(nEnd
, nMaxTiledIndex
) + nExtra
, nHardLimit
);
2833 rViewData
.SetMaxTiledCol(nNewMaxTiledIndex
);
2835 rViewData
.SetMaxTiledRow(nNewMaxTiledIndex
);
2837 Size
aNewSize(0, 0);
2839 aNewSize
= pModelObj
->getDocumentSize();
2846 ScGridWindow
* pGridWindow
= rViewData
.GetActiveWin();
2849 Size
aNewSizePx(aNewSize
.Width() * rViewData
.GetPPTX(), aNewSize
.Height() * rViewData
.GetPPTY());
2850 if (aNewSizePx
!= pGridWindow
->GetOutputSizePixel())
2851 pGridWindow
->SetOutputSizePixel(aNewSizePx
);
2855 if (aOldSize
== aNewSize
)
2858 // New area extended to the right/bottom of the sheet after last col/row
2859 tools::Rectangle
aNewArea(Point(0, 0), aNewSize
);
2860 // excluding overlapping area with aNewArea
2862 aNewArea
.SetLeft(aOldSize
.getWidth());
2864 aNewArea
.SetTop(aOldSize
.getHeight());
2866 // Only invalidate if spreadsheet has extended to the right or bottom
2867 if ((bColumn
&& aNewArea
.getOpenWidth()) || (!bColumn
&& aNewArea
.getOpenHeight()))
2869 rTabView
.UpdateSelectionOverlay();
2870 SfxLokHelper::notifyInvalidation(rViewData
.GetViewShell(), &aNewArea
);
2873 // Provide size in the payload, so clients don't have to query for that.
2874 std::stringstream ss
;
2875 ss
<< aNewSize
.Width() << ", " << aNewSize
.Height();
2876 OString
sSize( ss
.str() );
2877 ScModelObj
* pModel
= comphelper::getFromUnoTunnel
<ScModelObj
>(
2878 rViewData
.GetViewShell()->GetCurrentDocument());
2879 SfxLokHelper::notifyDocumentSizeChanged(rViewData
.GetViewShell(), sSize
, pModel
, false);
2882 } // anonymous namespace
2884 void ScTabView::getRowColumnHeaders(const tools::Rectangle
& rRectangle
, tools::JsonWriter
& rJsonWriter
)
2886 ScDocument
& rDoc
= aViewData
.GetDocument();
2888 if (rRectangle
.IsEmpty())
2891 bool bRangeHeaderSupport
= comphelper::LibreOfficeKit::isRangeHeaders();
2893 rJsonWriter
.put("commandName", ".uno:ViewRowColumnHeaders");
2895 SCTAB nTab
= aViewData
.GetTabNo();
2896 SCROW nStartRow
= -1;
2898 tools::Long nStartHeightPx
= 0;
2899 SCCOL nStartCol
= -1;
2901 tools::Long nStartWidthPx
= 0;
2903 tools::Rectangle
aOldVisArea(
2904 mnLOKStartHeaderCol
+ 1, mnLOKStartHeaderRow
+ 1,
2905 mnLOKEndHeaderCol
, mnLOKEndHeaderRow
);
2907 ScRangeProvider
aRangeProvider(rRectangle
, /* bInPixels */ false, aViewData
);
2908 const ScRange
& rCellRange
= aRangeProvider
.getCellRange();
2910 /// *** start collecting ROWS ***
2912 /// 1) compute start and end rows
2914 if (rRectangle
.Top() < rRectangle
.Bottom())
2916 SAL_INFO("sc.lok.header", "Row Header: compute start/end rows.");
2917 tools::Long nEndHeightPx
= 0;
2918 nStartRow
= rCellRange
.aStart
.Row();
2919 nEndRow
= rCellRange
.aEnd
.Row();
2920 aRangeProvider
.getRowPositions(nStartHeightPx
, nEndHeightPx
);
2922 aViewData
.GetLOKHeightHelper().removeByIndex(mnLOKStartHeaderRow
);
2923 aViewData
.GetLOKHeightHelper().removeByIndex(mnLOKEndHeaderRow
);
2924 aViewData
.GetLOKHeightHelper().insert(nStartRow
, nStartHeightPx
);
2925 aViewData
.GetLOKHeightHelper().insert(nEndRow
, nEndHeightPx
);
2927 mnLOKStartHeaderRow
= nStartRow
;
2928 mnLOKEndHeaderRow
= nEndRow
;
2931 sal_Int32 nVisibleRows
= nEndRow
- nStartRow
;
2932 if (nVisibleRows
< 25)
2935 SAL_INFO("sc.lok.header", "Row Header: visible rows: " << nVisibleRows
);
2939 // per each level store the index of the first group intersecting
2940 // [nStartRow, nEndRow] range
2942 const ScOutlineTable
* pTable
= rDoc
.GetOutlineTable(nTab
);
2943 const ScOutlineArray
* pRowArray
= pTable
? &(pTable
->GetRowArray()) : nullptr;
2944 size_t nRowGroupDepth
= 0;
2945 std::vector
<size_t> aRowGroupIndexes
;
2946 if (bRangeHeaderSupport
&& pTable
)
2948 nRowGroupDepth
= pRowArray
->GetDepth();
2949 lcl_getGroupIndexes(*pRowArray
, nStartRow
, nEndRow
, aRowGroupIndexes
);
2952 /// 2) if we are approaching current max tiled row, signal a size changed event
2953 /// and invalidate the involved area
2954 lcl_ExtendTiledDimension(/* bColumn */ false, nEndRow
, nVisibleRows
, *this, aViewData
);
2956 /// 3) create string data for rows
2958 tools::Long nTotalPixels
= nStartHeightPx
;
2959 tools::Long nPrevSizePx
= -1;
2960 OStringBuffer aRowGroupsBuffer
= "\"rowGroups\": [\n";
2962 auto rowsNode
= rJsonWriter
.startArray("rows");
2964 SAL_INFO("sc.lok.header", "Row Header: [create string data for rows]: start row: "
2965 << nStartRow
<< " start height: " << nTotalPixels
);
2967 if (nStartRow
!= nEndRow
)
2969 auto node
= rJsonWriter
.startStruct();
2970 rJsonWriter
.put("text", nStartRow
+ 1);
2971 rJsonWriter
.put("size", nTotalPixels
);
2972 rJsonWriter
.put("groupLevels", static_cast<sal_Int64
>(nRowGroupDepth
));
2975 std::vector
<tools::Long
> aRowGroupStartPositions(nRowGroupDepth
, -nTotalPixels
);
2976 for (SCROW nRow
= nStartRow
+ 1; nRow
<= nEndRow
; ++nRow
)
2978 // nSize will be 0 for hidden rows.
2979 const tools::Long nSizePx
= lcl_GetRowHeightPx(aViewData
, nRow
, nTab
);
2980 nTotalPixels
+= nSizePx
;
2982 if (bRangeHeaderSupport
&& nRowGroupDepth
> 0)
2984 lcl_createGroupsData(nRow
, nEndRow
, nSizePx
, nTotalPixels
,
2985 *pRowArray
, aRowGroupIndexes
, aRowGroupStartPositions
,
2989 if (bRangeHeaderSupport
&& nRow
< nEndRow
&& nSizePx
== nPrevSizePx
)
2991 nPrevSizePx
= nSizePx
;
2993 auto node
= rJsonWriter
.startStruct();
2994 rJsonWriter
.put("text", pRowBar
[SC_SPLIT_BOTTOM
]->GetEntryText(nRow
));
2995 rJsonWriter
.put("size", nTotalPixels
);
2998 aRowGroupsBuffer
.append("]");
3000 if (nRowGroupDepth
> 0)
3002 aRowGroupsBuffer
.append(",\n");
3003 rJsonWriter
.putRaw(aRowGroupsBuffer
);
3005 /// end collecting ROWS
3008 /// *** start collecting COLS ***
3010 /// 1) compute start and end columns
3012 if (rRectangle
.Left() < rRectangle
.Right())
3014 SAL_INFO("sc.lok.header", "Column Header: compute start/end columns.");
3015 tools::Long nEndWidthPx
= 0;
3016 nStartCol
= rCellRange
.aStart
.Col();
3017 nEndCol
= rCellRange
.aEnd
.Col();
3018 aRangeProvider
.getColPositions(nStartWidthPx
, nEndWidthPx
);
3020 aViewData
.GetLOKWidthHelper().removeByIndex(mnLOKStartHeaderCol
);
3021 aViewData
.GetLOKWidthHelper().removeByIndex(mnLOKEndHeaderCol
);
3022 aViewData
.GetLOKWidthHelper().insert(nStartCol
, nStartWidthPx
);
3023 aViewData
.GetLOKWidthHelper().insert(nEndCol
, nEndWidthPx
);
3025 mnLOKStartHeaderCol
= nStartCol
;
3026 mnLOKEndHeaderCol
= nEndCol
;
3029 sal_Int32 nVisibleCols
= nEndCol
- nStartCol
;
3030 if (nVisibleCols
< 10)
3034 // Get column groups
3035 // per each level store the index of the first group intersecting
3036 // [nStartCol, nEndCol] range
3038 const ScOutlineArray
* pColArray
= pTable
? &(pTable
->GetColArray()) : nullptr;
3039 size_t nColGroupDepth
= 0;
3040 std::vector
<size_t> aColGroupIndexes
;
3041 if (bRangeHeaderSupport
&& pTable
)
3043 nColGroupDepth
= pColArray
->GetDepth();
3044 lcl_getGroupIndexes(*pColArray
, nStartCol
, nEndCol
, aColGroupIndexes
);
3047 /// 2) if we are approaching current max tiled column, signal a size changed event
3048 /// and invalidate the involved area
3049 lcl_ExtendTiledDimension(/* bColumn */ true, nEndCol
, nVisibleCols
, *this, aViewData
);
3051 /// 3) create string data for columns
3052 OStringBuffer aColGroupsBuffer
= "\"columnGroups\": [\n";
3054 auto columnsNode
= rJsonWriter
.startArray("columns");
3056 nTotalPixels
= nStartWidthPx
;
3057 SAL_INFO("sc.lok.header", "Col Header: [create string data for cols]: start col: "
3058 << nStartRow
<< " start width: " << nTotalPixels
);
3060 if (nStartCol
!= nEndCol
)
3062 auto node
= rJsonWriter
.startStruct();
3063 rJsonWriter
.put("text", static_cast<sal_Int64
>(nStartCol
) + 1);
3064 rJsonWriter
.put("size", nTotalPixels
);
3065 rJsonWriter
.put("groupLevels", static_cast<sal_Int64
>(nColGroupDepth
));
3068 std::vector
<tools::Long
> aColGroupStartPositions(nColGroupDepth
, -nTotalPixels
);
3070 for (SCCOL nCol
= nStartCol
+ 1; nCol
<= nEndCol
; ++nCol
)
3072 // nSize will be 0 for hidden columns.
3073 const tools::Long nSizePx
= lcl_GetColWidthPx(aViewData
, nCol
, nTab
);
3074 nTotalPixels
+= nSizePx
;
3076 if (bRangeHeaderSupport
&& nColGroupDepth
> 0)
3077 lcl_createGroupsData(nCol
, nEndCol
, nSizePx
, nTotalPixels
,
3078 *pColArray
, aColGroupIndexes
,
3079 aColGroupStartPositions
, aColGroupsBuffer
);
3081 if (bRangeHeaderSupport
&& nCol
< nEndCol
&& nSizePx
== nPrevSizePx
)
3083 nPrevSizePx
= nSizePx
;
3085 OUString aText
= bRangeHeaderSupport
?
3086 OUString::number(nCol
+ 1) : pColBar
[SC_SPLIT_LEFT
]->GetEntryText(nCol
);
3088 auto node
= rJsonWriter
.startStruct();
3089 rJsonWriter
.put("text", aText
);
3090 rJsonWriter
.put("size", nTotalPixels
);
3093 aColGroupsBuffer
.append("]");
3095 if (nColGroupDepth
> 0)
3097 aColGroupsBuffer
.append(",\n");
3098 rJsonWriter
.putRaw(aColGroupsBuffer
);
3100 /// end collecting COLs
3102 vcl::Region
aNewVisArea(
3103 tools::Rectangle(mnLOKStartHeaderCol
+ 1, mnLOKStartHeaderRow
+ 1,
3104 mnLOKEndHeaderCol
, mnLOKEndHeaderRow
));
3105 aNewVisArea
.Exclude(aOldVisArea
);
3106 tools::Rectangle aChangedArea
= aNewVisArea
.GetBoundRect();
3107 if (!aChangedArea
.IsEmpty())
3109 UpdateVisibleRange();
3110 UpdateFormulas(aChangedArea
.Left(), aChangedArea
.Top(), aChangedArea
.Right(), aChangedArea
.Bottom());
3114 OString
ScTabView::getSheetGeometryData(bool bColumns
, bool bRows
, bool bSizes
, bool bHidden
,
3115 bool bFiltered
, bool bGroups
)
3117 ScDocument
& rDoc
= aViewData
.GetDocument();
3119 boost::property_tree::ptree aTree
;
3120 aTree
.put("commandName", ".uno:SheetGeometryData");
3121 aTree
.put("maxtiledcolumn", rDoc
.MaxCol());
3122 aTree
.put("maxtiledrow", MAXTILEDROW
);
3124 auto getJSONString
= [](const boost::property_tree::ptree
& rTree
) {
3125 std::stringstream aStream
;
3126 boost::property_tree::write_json(aStream
, rTree
);
3127 return aStream
.str();
3130 if ((!bSizes
&& !bHidden
&& !bFiltered
&& !bGroups
) ||
3131 (!bColumns
&& !bRows
))
3133 return OString(getJSONString(aTree
));
3138 SheetGeomType eType
;
3143 const GeomEntry aGeomEntries
[] = {
3144 { SheetGeomType::SIZES
, "sizes", bSizes
},
3145 { SheetGeomType::HIDDEN
, "hidden", bHidden
},
3146 { SheetGeomType::FILTERED
, "filtered", bFiltered
},
3147 { SheetGeomType::GROUPS
, "groups", bGroups
}
3150 struct DimensionEntry
3157 const DimensionEntry aDimEntries
[] = {
3158 { "columns", true, bColumns
},
3159 { "rows", false, bRows
}
3162 SCTAB nTab
= aViewData
.GetTabNo();
3164 for (const auto& rDimEntry
: aDimEntries
)
3166 if (!rDimEntry
.bEnabled
)
3169 bool bDimIsCol
= rDimEntry
.bDimIsCol
;
3171 boost::property_tree::ptree aDimTree
;
3172 for (const auto& rGeomEntry
: aGeomEntries
)
3174 if (!rGeomEntry
.bEnabled
)
3177 OString aGeomDataEncoding
= rDoc
.dumpSheetGeomData(nTab
, bDimIsCol
, rGeomEntry
.eType
);
3178 // TODO: Investigate if we can avoid the copy of the 'value' string in put().
3179 aDimTree
.put(rGeomEntry
.pKey
, aGeomDataEncoding
.getStr());
3182 aTree
.add_child(rDimEntry
.pKey
, aDimTree
);
3185 return OString(getJSONString(aTree
));
3188 void ScTabView::extendTiledAreaIfNeeded()
3190 SAL_INFO("sc.lok.header",
3191 "extendTiledAreaIfNeeded: START: ClientView: ColRange["
3192 << mnLOKStartHeaderCol
<< "," << mnLOKEndHeaderCol
3193 << "] RowRange[" << mnLOKStartHeaderRow
<< "," << mnLOKEndHeaderRow
3194 << "] MaxTiledCol = " << aViewData
.GetMaxTiledCol()
3195 << " MaxTiledRow = " << aViewData
.GetMaxTiledRow());
3197 const tools::Rectangle rVisArea
= aViewData
.getLOKVisibleArea();
3198 if (rVisArea
.Top() >= rVisArea
.Bottom() ||
3199 rVisArea
.Left() >= rVisArea
.Right())
3202 // Needed for conditional updating of visible-range/formula.
3203 tools::Rectangle
aOldVisCellRange(mnLOKStartHeaderCol
+ 1, mnLOKStartHeaderRow
+ 1,
3204 mnLOKEndHeaderCol
, mnLOKEndHeaderRow
);
3206 ScRangeProvider
aRangeProvider(rVisArea
, /* bInPixels */ false, aViewData
);
3208 const ScRange
& rCellRange
= aRangeProvider
.getCellRange();
3209 const SCCOL nStartCol
= rCellRange
.aStart
.Col();
3210 const SCCOL nEndCol
= rCellRange
.aEnd
.Col();
3211 const SCROW nStartRow
= rCellRange
.aStart
.Row();
3212 const SCROW nEndRow
= rCellRange
.aEnd
.Row();
3214 // Column/Row positions.
3215 tools::Long nStartColPos
, nEndColPos
, nStartRowPos
, nEndRowPos
;
3216 aRangeProvider
.getColPositions(nStartColPos
, nEndColPos
);
3217 aRangeProvider
.getRowPositions(nStartRowPos
, nEndRowPos
);
3219 ScPositionHelper
& rWidthHelper
= aViewData
.GetLOKWidthHelper();
3220 ScPositionHelper
& rHeightHelper
= aViewData
.GetLOKHeightHelper();
3222 // Update mnLOKStartHeaderCol and mnLOKEndHeaderCol members.
3223 // These are consulted in some ScGridWindow methods.
3224 if (mnLOKStartHeaderCol
!= nStartCol
)
3226 rWidthHelper
.removeByIndex(mnLOKStartHeaderCol
);
3227 rWidthHelper
.insert(nStartCol
, nStartColPos
);
3228 mnLOKStartHeaderCol
= nStartCol
;
3231 if (mnLOKEndHeaderCol
!= nEndCol
)
3233 rWidthHelper
.removeByIndex(mnLOKEndHeaderCol
);
3234 rWidthHelper
.insert(nEndCol
, nEndColPos
);
3235 mnLOKEndHeaderCol
= nEndCol
;
3238 // Update mnLOKStartHeaderRow and mnLOKEndHeaderRow members.
3239 // These are consulted in some ScGridWindow methods.
3240 if (mnLOKStartHeaderRow
!= nStartRow
)
3242 rHeightHelper
.removeByIndex(mnLOKStartHeaderRow
);
3243 rHeightHelper
.insert(nStartRow
, nStartRowPos
);
3244 mnLOKStartHeaderRow
= nStartRow
;
3247 if (mnLOKEndHeaderRow
!= nEndRow
)
3249 rHeightHelper
.removeByIndex(mnLOKEndHeaderRow
);
3250 rHeightHelper
.insert(nEndRow
, nEndRowPos
);
3251 mnLOKEndHeaderRow
= nEndRow
;
3254 constexpr SCCOL nMinExtraCols
= 10;
3255 SCCOL nExtraCols
= std::max
<SCCOL
>(nMinExtraCols
, nEndCol
- nStartCol
);
3256 // If we are approaching current max tiled column, signal a size changed event
3257 // and invalidate the involved area.
3258 lcl_ExtendTiledDimension(/* bColumn */ true, nEndCol
, nExtraCols
, *this, aViewData
);
3260 constexpr SCROW nMinExtraRows
= 25;
3261 SCROW nExtraRows
= std::max(nMinExtraRows
, nEndRow
- nStartRow
);
3262 // If we are approaching current max tiled row, signal a size changed event
3263 // and invalidate the involved area.
3264 lcl_ExtendTiledDimension(/* bColumn */ false, nEndRow
, nExtraRows
, *this, aViewData
);
3266 vcl::Region
aNewVisCellRange(
3267 tools::Rectangle(mnLOKStartHeaderCol
+ 1, mnLOKStartHeaderRow
+ 1,
3268 mnLOKEndHeaderCol
, mnLOKEndHeaderRow
));
3269 aNewVisCellRange
.Exclude(aOldVisCellRange
);
3270 tools::Rectangle aChangedCellRange
= aNewVisCellRange
.GetBoundRect();
3271 if (!aChangedCellRange
.IsEmpty())
3273 UpdateVisibleRange();
3274 UpdateFormulas(aChangedCellRange
.Left(), aChangedCellRange
.Top(),
3275 aChangedCellRange
.Right(), aChangedCellRange
.Bottom());
3278 SAL_INFO("sc.lok.header",
3279 "extendTiledAreaIfNeeded: END: ClientView: ColRange["
3280 << mnLOKStartHeaderCol
<< "," << mnLOKEndHeaderCol
3281 << "] RowRange[" << mnLOKStartHeaderRow
<< "," << mnLOKEndHeaderRow
3282 << "] MaxTiledCol = " << aViewData
.GetMaxTiledCol()
3283 << " MaxTiledRow = " << aViewData
.GetMaxTiledRow());
3286 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */