/src/libreoffice/sc/source/ui/view/tabview.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #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> |
31 | | |
32 | | #include <pagedata.hxx> |
33 | | #include <printfun.hxx> |
34 | | #include <tabview.hxx> |
35 | | #include <tabvwsh.hxx> |
36 | | #include <document.hxx> |
37 | | #include <gridwin.hxx> |
38 | | #include <olinewin.hxx> |
39 | | #include <olinetab.hxx> |
40 | | #include <tabsplit.hxx> |
41 | | #include <colrowba.hxx> |
42 | | #include <tabcont.hxx> |
43 | | #include <scmod.hxx> |
44 | | #include <sc.hrc> |
45 | | #include <strings.hrc> |
46 | | #include <globstr.hrc> |
47 | | #include <scresid.hxx> |
48 | | #include <drawview.hxx> |
49 | | #include <docsh.hxx> |
50 | | #include <viewuno.hxx> |
51 | | #include <appoptio.hxx> |
52 | | #include <attrib.hxx> |
53 | | #include <spellcheckcontext.hxx> |
54 | | #include <comphelper/lok.hxx> |
55 | | #include <sfx2/lokhelper.hxx> |
56 | | #include <osl/diagnose.h> |
57 | | |
58 | | #include <boost/property_tree/ptree.hpp> |
59 | | #include <boost/property_tree/json_parser.hpp> |
60 | | |
61 | | #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> |
62 | | |
63 | | #include <algorithm> |
64 | | |
65 | | #include <basegfx/utils/zoomtools.hxx> |
66 | | |
67 | 0 | #define SPLIT_MARGIN 30 |
68 | 0 | #define SPLIT_HANDLE_SIZE 5 |
69 | | constexpr sal_Int32 TAB_HEIGHT_MARGIN = 10; |
70 | | |
71 | 0 | #define SC_ICONSIZE 36 |
72 | | |
73 | 0 | #define SC_SCROLLBAR_MIN 30 |
74 | 0 | #define SC_TABBAR_MIN 6 |
75 | | |
76 | | using namespace ::com::sun::star; |
77 | | |
78 | | // Corner-Button |
79 | | |
80 | | ScCornerButton::ScCornerButton( vcl::Window* pParent, ScViewData& rData ) : |
81 | 0 | Window( pParent, WinBits( 0 ) ), |
82 | 0 | rViewData( rData ) |
83 | 0 | { |
84 | 0 | ScCornerButton::EnableRTL( false ); |
85 | 0 | SetQuickHelpText(ScResId(SCSTR_QHELP_SELECT_ALL_CELLS)); |
86 | 0 | } Unexecuted instantiation: ScCornerButton::ScCornerButton(vcl::Window*, ScViewData&) Unexecuted instantiation: ScCornerButton::ScCornerButton(vcl::Window*, ScViewData&) |
87 | | |
88 | | ScCornerButton::~ScCornerButton() |
89 | 0 | { |
90 | 0 | } |
91 | | |
92 | | void ScCornerButton::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) |
93 | 0 | { |
94 | 0 | const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); |
95 | 0 | SetBackground(rStyleSettings.GetFaceColor()); |
96 | |
|
97 | 0 | Size aSize(GetOutputSizePixel()); |
98 | 0 | tools::Long nPosX = aSize.Width() - 1; |
99 | 0 | tools::Long nPosY = aSize.Height() - 1; |
100 | |
|
101 | 0 | Window::Paint(rRenderContext, rRect); |
102 | |
|
103 | 0 | bool bLayoutRTL = rViewData.GetDocument().IsLayoutRTL( rViewData.CurrentTabForData() ); |
104 | 0 | tools::Long nDarkX = bLayoutRTL ? 0 : nPosX; |
105 | | |
106 | | // both buttons have the same look now - only dark right/bottom lines |
107 | 0 | rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); |
108 | 0 | rRenderContext.DrawLine(Point(0, nPosY), Point(nPosX, nPosY)); |
109 | 0 | rRenderContext.DrawLine(Point(nDarkX, 0), Point(nDarkX, nPosY)); |
110 | 0 | } |
111 | | |
112 | | void ScCornerButton::StateChanged( StateChangedType nType ) |
113 | 0 | { |
114 | 0 | Window::StateChanged( nType ); |
115 | |
|
116 | 0 | const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); |
117 | 0 | SetBackground( rStyleSettings.GetFaceColor() ); |
118 | 0 | Invalidate(); |
119 | 0 | } |
120 | | |
121 | | void ScCornerButton::DataChanged( const DataChangedEvent& rDCEvt ) |
122 | 0 | { |
123 | 0 | Window::DataChanged( rDCEvt ); |
124 | |
|
125 | 0 | const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); |
126 | 0 | SetBackground( rStyleSettings.GetFaceColor() ); |
127 | 0 | Invalidate(); |
128 | 0 | } |
129 | | |
130 | | void ScCornerButton::Resize() |
131 | 0 | { |
132 | 0 | Invalidate(); |
133 | 0 | } |
134 | | |
135 | | void ScCornerButton::MouseButtonDown( const MouseEvent& rMEvt ) |
136 | 0 | { |
137 | 0 | ScModule* pScMod = ScModule::get(); |
138 | 0 | bool bDisable = pScMod->IsFormulaMode() || pScMod->IsModalMode(); |
139 | 0 | if (!bDisable) |
140 | 0 | { |
141 | 0 | ScTabViewShell* pViewSh = rViewData.GetViewShell(); |
142 | 0 | pViewSh->SetActive(); // Appear and SetViewFrame |
143 | | // tdf#84694 - deselect draw objects before selecting the entire sheet |
144 | 0 | pViewSh->DrawDeselectAll(); |
145 | 0 | pViewSh->ActiveGrabFocus(); |
146 | |
|
147 | 0 | bool bControl = rMEvt.IsMod1(); |
148 | 0 | pViewSh->SelectAll( bControl ); |
149 | 0 | } |
150 | 0 | } |
151 | | namespace |
152 | | { |
153 | | |
154 | | bool lcl_HasColOutline( const ScViewData& rViewData ) |
155 | 0 | { |
156 | 0 | const ScOutlineTable* pTable = rViewData.GetDocument().GetOutlineTable(rViewData.CurrentTabForData()); |
157 | 0 | if (pTable) |
158 | 0 | { |
159 | 0 | const ScOutlineArray& rArray = pTable->GetColArray(); |
160 | 0 | if ( rArray.GetDepth() > 0 ) |
161 | 0 | return true; |
162 | 0 | } |
163 | 0 | return false; |
164 | 0 | } |
165 | | |
166 | | bool lcl_HasRowOutline( const ScViewData& rViewData ) |
167 | 0 | { |
168 | 0 | const ScOutlineTable* pTable = rViewData.GetDocument().GetOutlineTable(rViewData.CurrentTabForData()); |
169 | 0 | if (pTable) |
170 | 0 | { |
171 | 0 | const ScOutlineArray& rArray = pTable->GetRowArray(); |
172 | 0 | if ( rArray.GetDepth() > 0 ) |
173 | 0 | return true; |
174 | 0 | } |
175 | 0 | return false; |
176 | 0 | } |
177 | | |
178 | | } // anonymous namespace |
179 | | |
180 | | ScTabView::ScTabView( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) : |
181 | 0 | pFrameWin( pParent ), |
182 | 0 | aViewData( rDocSh, pViewShell ), |
183 | 0 | aFunctionSet( aViewData ), |
184 | 0 | aHdrFunc( aViewData ), |
185 | 0 | aVScrollTop( VclPtr<ScrollAdaptor>::Create( pFrameWin, false ) ), |
186 | 0 | aVScrollBottom( VclPtr<ScrollAdaptor>::Create( pFrameWin, false ) ), |
187 | 0 | aHScrollLeft( VclPtr<ScrollAdaptor>::Create( pFrameWin, true ) ), |
188 | 0 | aHScrollRight( VclPtr<ScrollAdaptor>::Create( pFrameWin, true ) ), |
189 | 0 | aCornerButton( VclPtr<ScCornerButton>::Create( pFrameWin, aViewData ) ), |
190 | 0 | aTopButton( VclPtr<ScCornerButton>::Create( pFrameWin, aViewData ) ), |
191 | 0 | aScrollTimer("ScTabView aScrollTimer"), |
192 | 0 | pTimerWindow( nullptr ), |
193 | 0 | aExtraEditViewManager( pViewShell, pGridWin ), |
194 | 0 | nTipVisible( nullptr ), |
195 | 0 | nTipAlign( QuickHelpFlags::NONE ), |
196 | 0 | nPrevDragPos( 0 ), |
197 | 0 | meBlockMode(None), |
198 | 0 | meHighlightBlockMode(None), |
199 | 0 | nBlockStartX( 0 ), |
200 | 0 | nBlockStartXOrig( 0 ), |
201 | 0 | nBlockEndX( 0 ), |
202 | 0 | nBlockStartY( 0 ), |
203 | 0 | nBlockStartYOrig( 0 ), |
204 | 0 | nBlockEndY( 0 ), |
205 | 0 | nBlockStartZ( 0 ), |
206 | 0 | nBlockEndZ( 0 ), |
207 | 0 | nOldCurX( 0 ), |
208 | 0 | nOldCurY( 0 ), |
209 | 0 | mfPendingTabBarWidth( -1.0 ), |
210 | 0 | mnLOKStartHeaderRow( -2 ), |
211 | 0 | mnLOKEndHeaderRow( -1 ), |
212 | 0 | mnLOKStartHeaderCol( -2 ), |
213 | 0 | mnLOKEndHeaderCol( -1 ), |
214 | 0 | bMinimized( false ), |
215 | 0 | bInUpdateHeader( false ), |
216 | 0 | bInActivatePart( false ), |
217 | 0 | bInZoomUpdate( false ), |
218 | 0 | bMoveIsShift( false ), |
219 | 0 | bDrawSelMode( false ), |
220 | 0 | bLockPaintBrush( false ), |
221 | 0 | bDragging( false ), |
222 | 0 | bBlockNeg( false ), |
223 | 0 | bBlockCols( false ), |
224 | 0 | bBlockRows( false ), |
225 | 0 | mbInlineWithScrollbar( false ) |
226 | 0 | { |
227 | | // copy settings of existing shell for this document |
228 | 0 | if (ScTabViewShell* pExistingViewShell = rDocSh.GetBestViewShell()) |
229 | 0 | { |
230 | 0 | aViewRenderingData = pExistingViewShell->GetViewRenderingData(); |
231 | 0 | EnableAutoSpell(pExistingViewShell->IsAutoSpell()); |
232 | 0 | } |
233 | 0 | Init(); |
234 | 0 | } |
235 | | |
236 | | void ScTabView::InitScrollBar(ScrollAdaptor& rScrollBar, tools::Long nMaxVal, const Link<weld::Scrollbar&, void>& rLink) |
237 | 0 | { |
238 | 0 | rScrollBar.SetRange( Range( 0, nMaxVal ) ); |
239 | 0 | rScrollBar.SetLineSize( 1 ); |
240 | 0 | rScrollBar.SetPageSize( 1 ); // is queried separately |
241 | 0 | rScrollBar.SetVisibleSize( 10 ); // is reset by Resize |
242 | |
|
243 | 0 | rScrollBar.SetScrollHdl(rLink); |
244 | 0 | rScrollBar.SetMouseReleaseHdl(LINK(this, ScTabView, EndScrollHdl)); |
245 | |
|
246 | 0 | rScrollBar.EnableRTL( aViewData.GetDocument().IsLayoutRTL( aViewData.CurrentTabForData() ) ); |
247 | | |
248 | | // Related: tdf#155266 Eliminate delayed scrollbar redrawing when swiping |
249 | | // By default, the layout idle timer in the InterimWindowItem class |
250 | | // is set to TaskPriority::RESIZE. That is too high of a priority as |
251 | | // it appears that other timers are drawing after the scrollbar has been |
252 | | // redrawn. |
253 | | // As a result, when swiping, the content moves fluidly but the scrollbar |
254 | | // thumb does not move until after swiping stops or pauses. Then, after a |
255 | | // short lag, the scrollbar thumb finally "jumps" to the expected |
256 | | // position. |
257 | | // So, to fix this scrollbar "stickiness" when swiping, setting the |
258 | | // priority to TaskPriority::POST_PAINT causes the scrollbar to be |
259 | | // redrawn after any competing timers. |
260 | 0 | rScrollBar.SetPriority(TaskPriority::POST_PAINT); |
261 | 0 | } |
262 | | |
263 | | // Scroll-Timer |
264 | | void ScTabView::SetTimer( ScGridWindow* pWin, const MouseEvent& rMEvt ) |
265 | 0 | { |
266 | 0 | pTimerWindow = pWin; |
267 | 0 | aTimerMEvt = rMEvt; |
268 | 0 | aScrollTimer.Start(); |
269 | 0 | } |
270 | | |
271 | | void ScTabView::ResetTimer() |
272 | 0 | { |
273 | 0 | aScrollTimer.Stop(); |
274 | 0 | pTimerWindow = nullptr; |
275 | 0 | } |
276 | | |
277 | | IMPL_LINK_NOARG(ScTabView, TimerHdl, Timer *, void) |
278 | 0 | { |
279 | 0 | if (pTimerWindow) |
280 | 0 | pTimerWindow->MouseMove( aTimerMEvt ); |
281 | 0 | } |
282 | | |
283 | | // --- Resize --------------------------------------------------------------------- |
284 | | |
285 | | static void lcl_SetPosSize( vcl::Window& rWindow, const Point& rPos, const Size& rSize, |
286 | | tools::Long nTotalWidth, bool bLayoutRTL ) |
287 | 0 | { |
288 | 0 | Point aNewPos = rPos; |
289 | 0 | if ( bLayoutRTL ) |
290 | 0 | { |
291 | 0 | aNewPos.setX( nTotalWidth - rPos.X() - rSize.Width() ); |
292 | 0 | if ( aNewPos == rWindow.GetPosPixel() && rSize.Width() != rWindow.GetSizePixel().Width() ) |
293 | 0 | { |
294 | | // Document windows are manually painted right-to-left, so they need to |
295 | | // be repainted if the size changes. |
296 | 0 | rWindow.Invalidate(); |
297 | 0 | } |
298 | 0 | } |
299 | 0 | rWindow.SetPosSizePixel( aNewPos, rSize ); |
300 | 0 | } |
301 | | |
302 | | void ScTabView::DoResize( const Point& rOffset, const Size& rSize, bool bInner ) |
303 | 0 | { |
304 | 0 | HideListBox(); |
305 | |
|
306 | 0 | bool bHasHint = HasHintWindow(); |
307 | 0 | if (bHasHint) |
308 | 0 | RemoveHintWindow(); |
309 | |
|
310 | 0 | bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.CurrentTabForData() ); |
311 | 0 | tools::Long nTotalWidth = rSize.Width(); |
312 | 0 | if ( bLayoutRTL ) |
313 | 0 | nTotalWidth += 2*rOffset.X(); |
314 | |
|
315 | 0 | bool bVScroll = aViewData.IsVScrollMode(); |
316 | 0 | bool bHScroll = aViewData.IsHScrollMode(); |
317 | 0 | bool bTabControl = aViewData.IsTabMode(); |
318 | 0 | bool bHeaders = aViewData.IsHeaderMode(); |
319 | 0 | bool bOutlMode = aViewData.IsOutlineMode(); |
320 | 0 | bool bHOutline = bOutlMode && lcl_HasColOutline(aViewData); |
321 | 0 | bool bVOutline = bOutlMode && lcl_HasRowOutline(aViewData); |
322 | |
|
323 | 0 | if ( aViewData.GetDocShell()->IsPreview() ) |
324 | 0 | bHScroll = bVScroll = bTabControl = bHeaders = bHOutline = bVOutline = false; |
325 | |
|
326 | 0 | tools::Long nBarX = 0; |
327 | 0 | tools::Long nBarY = 0; |
328 | 0 | tools::Long nOutlineX = 0; |
329 | 0 | tools::Long nOutlineY = 0; |
330 | 0 | tools::Long nOutPosX; |
331 | 0 | tools::Long nOutPosY; |
332 | |
|
333 | 0 | tools::Long nPosX = rOffset.X(); |
334 | 0 | tools::Long nPosY = rOffset.Y(); |
335 | 0 | tools::Long nSizeX = rSize.Width(); |
336 | 0 | tools::Long nSizeY = rSize.Height(); |
337 | |
|
338 | 0 | bMinimized = ( nSizeX<=SC_ICONSIZE || nSizeY<=SC_ICONSIZE ); |
339 | 0 | if ( bMinimized ) |
340 | 0 | return; |
341 | | |
342 | 0 | float fScaleFactor = pFrameWin->GetDPIScaleFactor(); |
343 | |
|
344 | 0 | tools::Long nSplitSizeX = SPLIT_HANDLE_SIZE * fScaleFactor; |
345 | 0 | if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX ) |
346 | 0 | nSplitSizeX = 1; |
347 | 0 | tools::Long nSplitSizeY = SPLIT_HANDLE_SIZE * fScaleFactor; |
348 | 0 | if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX ) |
349 | 0 | nSplitSizeY = 1; |
350 | |
|
351 | 0 | aBorderPos = rOffset; |
352 | 0 | aFrameSize = rSize; |
353 | |
|
354 | 0 | const StyleSettings& rStyleSettings = pFrameWin->GetSettings().GetStyleSettings(); |
355 | | |
356 | |
|
357 | 0 | Size aFontSize = rStyleSettings.GetTabFont().GetFontSize(); |
358 | 0 | #ifndef MACOSX // already in pixels on macOS: a point conversion would inflate the tab bar |
359 | 0 | MapMode aPtMapMode(MapUnit::MapPoint); |
360 | 0 | aFontSize = pFrameWin->LogicToPixel(aFontSize, aPtMapMode); |
361 | 0 | #endif |
362 | 0 | sal_Int32 nTabHeight = aFontSize.Height() + TAB_HEIGHT_MARGIN; |
363 | |
|
364 | 0 | if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE ) |
365 | 0 | { |
366 | 0 | if ( aViewData.GetHSplitPos() > nSizeX - SPLIT_MARGIN ) |
367 | 0 | { |
368 | 0 | aViewData.SetHSplitMode( SC_SPLIT_NONE ); |
369 | 0 | if ( WhichH( aViewData.GetActivePart() ) == SC_SPLIT_RIGHT ) |
370 | 0 | ActivatePart( SC_SPLIT_BOTTOMLEFT ); |
371 | 0 | InvalidateSplit(); |
372 | 0 | } |
373 | 0 | } |
374 | 0 | if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE ) |
375 | 0 | { |
376 | 0 | if ( aViewData.GetVSplitPos() > nSizeY - SPLIT_MARGIN ) |
377 | 0 | { |
378 | 0 | aViewData.SetVSplitMode( SC_SPLIT_NONE ); |
379 | 0 | if ( WhichV( aViewData.GetActivePart() ) == SC_SPLIT_TOP ) |
380 | 0 | ActivatePart( SC_SPLIT_BOTTOMLEFT ); |
381 | 0 | InvalidateSplit(); |
382 | 0 | } |
383 | 0 | } |
384 | |
|
385 | 0 | UpdateShow(); |
386 | |
|
387 | 0 | if (bHScroll || bVScroll) // Scrollbars horizontal or vertical |
388 | 0 | { |
389 | 0 | tools::Long nScrollBarSize = rStyleSettings.GetScrollBarSize(); |
390 | 0 | if (bVScroll) |
391 | 0 | { |
392 | 0 | nBarX = nScrollBarSize; |
393 | 0 | nSizeX -= nBarX; |
394 | 0 | } |
395 | 0 | if (bHScroll) |
396 | 0 | { |
397 | 0 | nBarY = nTabHeight; |
398 | |
|
399 | 0 | if (!mbInlineWithScrollbar) |
400 | 0 | nBarY += nScrollBarSize; |
401 | |
|
402 | 0 | nSizeY -= nBarY; |
403 | |
|
404 | 0 | tools::Long nSizeLt = 0; // left scroll bar |
405 | 0 | tools::Long nSizeRt = 0; // right scroll bar |
406 | 0 | tools::Long nSizeSp = 0; // splitter |
407 | |
|
408 | 0 | switch (aViewData.GetHSplitMode()) |
409 | 0 | { |
410 | 0 | case SC_SPLIT_NONE: |
411 | 0 | nSizeSp = nSplitSizeX; |
412 | 0 | nSizeLt = nSizeX - nSizeSp; // Convert the corner |
413 | 0 | break; |
414 | 0 | case SC_SPLIT_NORMAL: |
415 | 0 | nSizeSp = nSplitSizeX; |
416 | 0 | nSizeLt = aViewData.GetHSplitPos(); |
417 | 0 | break; |
418 | 0 | case SC_SPLIT_FIX: |
419 | 0 | nSizeSp = 0; |
420 | 0 | nSizeLt = 0; |
421 | 0 | break; |
422 | 0 | } |
423 | 0 | nSizeRt = nSizeX - nSizeLt - nSizeSp; |
424 | |
|
425 | 0 | tools::Long nTabSize = 0; |
426 | |
|
427 | 0 | if (bTabControl) |
428 | 0 | { |
429 | | // pending relative tab bar width from extended document options |
430 | 0 | if( mfPendingTabBarWidth >= 0.0 ) |
431 | 0 | { |
432 | 0 | SetRelTabBarWidth( mfPendingTabBarWidth ); |
433 | 0 | mfPendingTabBarWidth = -1.0; |
434 | 0 | } |
435 | |
|
436 | 0 | if (mbInlineWithScrollbar) |
437 | 0 | { |
438 | 0 | nTabSize = pTabControl->GetSizePixel().Width(); |
439 | |
|
440 | 0 | if ( aViewData.GetHSplitMode() != SC_SPLIT_FIX ) // left Scrollbar |
441 | 0 | { |
442 | 0 | if (nTabSize > nSizeLt-SC_SCROLLBAR_MIN) |
443 | 0 | nTabSize = nSizeLt-SC_SCROLLBAR_MIN; |
444 | 0 | if (nTabSize < SC_TABBAR_MIN) |
445 | 0 | nTabSize = SC_TABBAR_MIN; |
446 | 0 | nSizeLt -= nTabSize; |
447 | 0 | } |
448 | 0 | else // right Scrollbar |
449 | 0 | { |
450 | 0 | if (nTabSize > nSizeRt-SC_SCROLLBAR_MIN) |
451 | 0 | nTabSize = nSizeRt-SC_SCROLLBAR_MIN; |
452 | 0 | if (nTabSize < SC_TABBAR_MIN) |
453 | 0 | nTabSize = SC_TABBAR_MIN; |
454 | 0 | nSizeRt -= nTabSize; |
455 | 0 | } |
456 | 0 | } |
457 | 0 | } |
458 | |
|
459 | 0 | if (mbInlineWithScrollbar) |
460 | 0 | { |
461 | 0 | Point aTabPoint(nPosX, nPosY + nSizeY); |
462 | 0 | Size aTabSize(nTabSize, nBarY); |
463 | 0 | lcl_SetPosSize(*pTabControl, aTabPoint, aTabSize, nTotalWidth, bLayoutRTL); |
464 | 0 | pTabControl->SetSheetLayoutRTL(bLayoutRTL); |
465 | |
|
466 | 0 | Point aHScrollLeftPoint(nPosX + nTabSize, nPosY + nSizeY); |
467 | 0 | Size aHScrollLeftSize(nSizeLt, nBarY); |
468 | 0 | lcl_SetPosSize(*aHScrollLeft, aHScrollLeftPoint, aHScrollLeftSize, nTotalWidth, bLayoutRTL); |
469 | |
|
470 | 0 | Point aHSplitterPoint(nPosX + nTabSize + nSizeLt, nPosY + nSizeY); |
471 | 0 | Size aHSplitterSize(nSizeSp, nBarY); |
472 | 0 | lcl_SetPosSize(*pHSplitter, aHSplitterPoint, aHSplitterSize, nTotalWidth, bLayoutRTL); |
473 | |
|
474 | 0 | Point aHScrollRightPoint(nPosX + nTabSize + nSizeLt + nSizeSp, nPosY + nSizeY); |
475 | 0 | Size aHScrollRightSize(nSizeRt, nBarY); |
476 | 0 | lcl_SetPosSize(*aHScrollRight, aHScrollRightPoint, aHScrollRightSize, nTotalWidth, bLayoutRTL); |
477 | 0 | } |
478 | 0 | else |
479 | 0 | { |
480 | 0 | Point aTabPoint(nPosX, nPosY + nSizeY + nScrollBarSize); |
481 | 0 | Size aTabSize(nSizeX, nTabHeight); |
482 | 0 | lcl_SetPosSize(*pTabControl, aTabPoint, aTabSize, nTotalWidth, bLayoutRTL); |
483 | 0 | pTabControl->SetSheetLayoutRTL(bLayoutRTL); |
484 | |
|
485 | 0 | Point aHScrollLeftPoint(nPosX, nPosY + nSizeY); |
486 | 0 | Size aHScrollLeftSize(nSizeLt, nScrollBarSize); |
487 | 0 | lcl_SetPosSize(*aHScrollLeft, aHScrollLeftPoint, aHScrollLeftSize, nTotalWidth, bLayoutRTL); |
488 | |
|
489 | 0 | Point aHSplitterPoint(nPosX + nSizeLt, nPosY + nSizeY); |
490 | 0 | Size aHSplitterSize(nSizeSp, nScrollBarSize); |
491 | 0 | lcl_SetPosSize(*pHSplitter, aHSplitterPoint, aHSplitterSize, nTotalWidth, bLayoutRTL); |
492 | |
|
493 | 0 | Point aHScrollRightPoint(nPosX + nSizeLt + nSizeSp, nPosY + nSizeY); |
494 | 0 | Size aHScrollRightSize(nSizeRt, nScrollBarSize); |
495 | 0 | lcl_SetPosSize(*aHScrollRight, aHScrollRightPoint, aHScrollRightSize, nTotalWidth, bLayoutRTL); |
496 | 0 | } |
497 | | // SetDragRectPixel is done below |
498 | 0 | } |
499 | | |
500 | 0 | if (bVScroll) |
501 | 0 | { |
502 | 0 | tools::Long nSizeUp = 0; // upper scroll bar |
503 | 0 | tools::Long nSizeSp = 0; // splitter |
504 | 0 | tools::Long nSizeDn; // lower scroll bar |
505 | |
|
506 | 0 | switch (aViewData.GetVSplitMode()) |
507 | 0 | { |
508 | 0 | case SC_SPLIT_NONE: |
509 | 0 | nSizeUp = 0; |
510 | 0 | nSizeSp = nSplitSizeY; |
511 | 0 | break; |
512 | 0 | case SC_SPLIT_NORMAL: |
513 | 0 | nSizeUp = aViewData.GetVSplitPos(); |
514 | 0 | nSizeSp = nSplitSizeY; |
515 | 0 | break; |
516 | 0 | case SC_SPLIT_FIX: |
517 | 0 | nSizeUp = 0; |
518 | 0 | nSizeSp = 0; |
519 | 0 | break; |
520 | 0 | } |
521 | 0 | nSizeDn = nSizeY - nSizeUp - nSizeSp; |
522 | |
|
523 | 0 | lcl_SetPosSize( *aVScrollTop, Point(nPosX + nSizeX, nPosY), |
524 | 0 | Size(nBarX, nSizeUp), nTotalWidth, bLayoutRTL ); |
525 | 0 | lcl_SetPosSize( *pVSplitter, Point( nPosX + nSizeX, nPosY+nSizeUp ), |
526 | 0 | Size( nBarX, nSizeSp ), nTotalWidth, bLayoutRTL ); |
527 | 0 | lcl_SetPosSize( *aVScrollBottom, Point(nPosX + nSizeX, |
528 | 0 | nPosY + nSizeUp + nSizeSp), |
529 | 0 | Size(nBarX, nSizeDn), nTotalWidth, bLayoutRTL ); |
530 | | |
531 | | // SetDragRectPixel is done below |
532 | 0 | } |
533 | 0 | } |
534 | | |
535 | | // SetDragRectPixel also without Scrollbars etc., when already split |
536 | 0 | if ( bHScroll || aViewData.GetHSplitMode() != SC_SPLIT_NONE ) |
537 | 0 | pHSplitter->SetDragRectPixel( |
538 | 0 | tools::Rectangle( nPosX, nPosY, nPosX+nSizeX, nPosY+nSizeY ), pFrameWin ); |
539 | 0 | if ( bVScroll || aViewData.GetVSplitMode() != SC_SPLIT_NONE ) |
540 | 0 | pVSplitter->SetDragRectPixel( |
541 | 0 | tools::Rectangle( nPosX, nPosY, nPosX+nSizeX, nPosY+nSizeY ), pFrameWin ); |
542 | |
|
543 | 0 | if (bTabControl && ! bHScroll ) |
544 | 0 | { |
545 | 0 | nBarY = aHScrollLeft->GetSizePixel().Height(); |
546 | |
|
547 | 0 | tools::Long nSize1 = nSizeX; |
548 | |
|
549 | 0 | tools::Long nTabSize = nSize1; |
550 | 0 | if (nTabSize < 0) nTabSize = 0; |
551 | |
|
552 | 0 | lcl_SetPosSize( *pTabControl, Point(nPosX, nPosY+nSizeY-nBarY), |
553 | 0 | Size(nTabSize, nBarY), nTotalWidth, bLayoutRTL ); |
554 | 0 | nSizeY -= nBarY; |
555 | |
|
556 | 0 | if( bVScroll ) |
557 | 0 | { |
558 | 0 | Size aVScrSize = aVScrollBottom->GetSizePixel(); |
559 | 0 | aVScrSize.AdjustHeight( -nBarY ); |
560 | 0 | aVScrollBottom->SetSizePixel( aVScrSize ); |
561 | 0 | } |
562 | 0 | } |
563 | |
|
564 | 0 | nOutPosX = nPosX; |
565 | 0 | nOutPosY = nPosY; |
566 | | |
567 | | // Outline-Controls |
568 | 0 | if (bVOutline && pRowOutline[SC_SPLIT_BOTTOM]) |
569 | 0 | { |
570 | 0 | nOutlineX = pRowOutline[SC_SPLIT_BOTTOM]->GetDepthSize(); |
571 | 0 | nSizeX -= nOutlineX; |
572 | 0 | nPosX += nOutlineX; |
573 | 0 | } |
574 | 0 | if (bHOutline && pColOutline[SC_SPLIT_LEFT]) |
575 | 0 | { |
576 | 0 | nOutlineY = pColOutline[SC_SPLIT_LEFT]->GetDepthSize(); |
577 | 0 | nSizeY -= nOutlineY; |
578 | 0 | nPosY += nOutlineY; |
579 | 0 | } |
580 | |
|
581 | 0 | if (bHeaders) // column/row header |
582 | 0 | { |
583 | 0 | nBarX = pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width(); |
584 | 0 | nBarY = pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height(); |
585 | 0 | nSizeX -= nBarX; |
586 | 0 | nSizeY -= nBarY; |
587 | 0 | nPosX += nBarX; |
588 | 0 | nPosY += nBarY; |
589 | 0 | } |
590 | 0 | else |
591 | 0 | nBarX = nBarY = 0; |
592 | | |
593 | | // evaluate splitter |
594 | |
|
595 | 0 | tools::Long nLeftSize = nSizeX; |
596 | 0 | tools::Long nRightSize = 0; |
597 | 0 | tools::Long nTopSize = 0; |
598 | 0 | tools::Long nBottomSize = nSizeY; |
599 | 0 | tools::Long nSplitPosX = nPosX; |
600 | 0 | tools::Long nSplitPosY = nPosY; |
601 | |
|
602 | 0 | if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE ) |
603 | 0 | { |
604 | 0 | tools::Long nSplitHeight = rSize.Height(); |
605 | 0 | if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX ) |
606 | 0 | { |
607 | | // Do not allow freeze splitter to overlap scroll bar/tab bar |
608 | 0 | if ( bHScroll ) |
609 | 0 | nSplitHeight -= aHScrollLeft->GetSizePixel().Height(); |
610 | 0 | else if ( bTabControl && pTabControl ) |
611 | 0 | nSplitHeight -= pTabControl->GetSizePixel().Height(); |
612 | 0 | } |
613 | 0 | nSplitPosX = aViewData.GetHSplitPos(); |
614 | 0 | lcl_SetPosSize( *pHSplitter, |
615 | 0 | Point(nSplitPosX, nOutPosY), |
616 | 0 | Size(nSplitSizeX, nSplitHeight - nTabHeight), nTotalWidth, bLayoutRTL); |
617 | 0 | nLeftSize = nSplitPosX - nPosX; |
618 | 0 | nSplitPosX += nSplitSizeX; |
619 | 0 | nRightSize = nSizeX - nLeftSize - nSplitSizeX; |
620 | 0 | } |
621 | 0 | if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE ) |
622 | 0 | { |
623 | 0 | tools::Long nSplitWidth = rSize.Width(); |
624 | 0 | if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX && bVScroll ) |
625 | 0 | nSplitWidth -= aVScrollBottom->GetSizePixel().Width(); |
626 | 0 | nSplitPosY = aViewData.GetVSplitPos(); |
627 | 0 | lcl_SetPosSize( *pVSplitter, |
628 | 0 | Point( nOutPosX, nSplitPosY ), Size( nSplitWidth, nSplitSizeY ), nTotalWidth, bLayoutRTL ); |
629 | 0 | nTopSize = nSplitPosY - nPosY; |
630 | 0 | nSplitPosY += nSplitSizeY; |
631 | 0 | nBottomSize = nSizeY - nTopSize - nSplitSizeY; |
632 | 0 | } |
633 | | |
634 | | // ShowHide for pColOutline / pRowOutline happens in UpdateShow |
635 | |
|
636 | 0 | if (bHOutline) // Outline-Controls |
637 | 0 | { |
638 | 0 | if (pColOutline[SC_SPLIT_LEFT]) |
639 | 0 | { |
640 | 0 | pColOutline[SC_SPLIT_LEFT]->SetHeaderSize( nBarX ); |
641 | 0 | lcl_SetPosSize( *pColOutline[SC_SPLIT_LEFT], |
642 | 0 | Point(nPosX-nBarX,nOutPosY), Size(nLeftSize+nBarX,nOutlineY), nTotalWidth, bLayoutRTL ); |
643 | 0 | } |
644 | 0 | if (pColOutline[SC_SPLIT_RIGHT]) |
645 | 0 | { |
646 | 0 | pColOutline[SC_SPLIT_RIGHT]->SetHeaderSize( 0 ); // always call to update RTL flag |
647 | 0 | lcl_SetPosSize( *pColOutline[SC_SPLIT_RIGHT], |
648 | 0 | Point(nSplitPosX,nOutPosY), Size(nRightSize,nOutlineY), nTotalWidth, bLayoutRTL ); |
649 | 0 | } |
650 | 0 | } |
651 | 0 | if (bVOutline) |
652 | 0 | { |
653 | 0 | if (nTopSize) |
654 | 0 | { |
655 | 0 | if (pRowOutline[SC_SPLIT_TOP] && pRowOutline[SC_SPLIT_BOTTOM]) |
656 | 0 | { |
657 | 0 | pRowOutline[SC_SPLIT_TOP]->SetHeaderSize( nBarY ); |
658 | 0 | lcl_SetPosSize( *pRowOutline[SC_SPLIT_TOP], |
659 | 0 | Point(nOutPosX,nPosY-nBarY), Size(nOutlineX,nTopSize+nBarY), nTotalWidth, bLayoutRTL ); |
660 | 0 | pRowOutline[SC_SPLIT_BOTTOM]->SetHeaderSize( 0 ); |
661 | 0 | lcl_SetPosSize( *pRowOutline[SC_SPLIT_BOTTOM], |
662 | 0 | Point(nOutPosX,nSplitPosY), Size(nOutlineX,nBottomSize), nTotalWidth, bLayoutRTL ); |
663 | 0 | } |
664 | 0 | } |
665 | 0 | else if (pRowOutline[SC_SPLIT_BOTTOM]) |
666 | 0 | { |
667 | 0 | pRowOutline[SC_SPLIT_BOTTOM]->SetHeaderSize( nBarY ); |
668 | 0 | lcl_SetPosSize( *pRowOutline[SC_SPLIT_BOTTOM], |
669 | 0 | Point(nOutPosX,nSplitPosY-nBarY), Size(nOutlineX,nBottomSize+nBarY), nTotalWidth, bLayoutRTL ); |
670 | 0 | } |
671 | 0 | } |
672 | 0 | if (bHOutline && bVOutline) |
673 | 0 | { |
674 | 0 | lcl_SetPosSize( *aTopButton, Point(nOutPosX,nOutPosY), Size(nOutlineX,nOutlineY), nTotalWidth, bLayoutRTL ); |
675 | 0 | aTopButton->Show(); |
676 | 0 | } |
677 | 0 | else |
678 | 0 | aTopButton->Hide(); |
679 | |
|
680 | 0 | if (bHeaders) // column/row header |
681 | 0 | { |
682 | 0 | lcl_SetPosSize( *pColBar[SC_SPLIT_LEFT], |
683 | 0 | Point(nPosX,nPosY-nBarY), Size(nLeftSize,nBarY), nTotalWidth, bLayoutRTL ); |
684 | 0 | if (pColBar[SC_SPLIT_RIGHT]) |
685 | 0 | lcl_SetPosSize( *pColBar[SC_SPLIT_RIGHT], |
686 | 0 | Point(nSplitPosX,nPosY-nBarY), Size(nRightSize,nBarY), nTotalWidth, bLayoutRTL ); |
687 | |
|
688 | 0 | if (pRowBar[SC_SPLIT_TOP]) |
689 | 0 | lcl_SetPosSize( *pRowBar[SC_SPLIT_TOP], |
690 | 0 | Point(nPosX-nBarX,nPosY), Size(nBarX,nTopSize), nTotalWidth, bLayoutRTL ); |
691 | 0 | lcl_SetPosSize( *pRowBar[SC_SPLIT_BOTTOM], |
692 | 0 | Point(nPosX-nBarX,nSplitPosY), Size(nBarX,nBottomSize), nTotalWidth, bLayoutRTL ); |
693 | |
|
694 | 0 | lcl_SetPosSize( *aCornerButton, Point(nPosX-nBarX,nPosY-nBarY), Size(nBarX,nBarY), nTotalWidth, bLayoutRTL ); |
695 | 0 | aCornerButton->Show(); |
696 | 0 | pColBar[SC_SPLIT_LEFT]->Show(); |
697 | 0 | pRowBar[SC_SPLIT_BOTTOM]->Show(); |
698 | 0 | } |
699 | 0 | else |
700 | 0 | { |
701 | 0 | aCornerButton->Hide(); |
702 | 0 | pColBar[SC_SPLIT_LEFT]->Hide(); // always here |
703 | 0 | pRowBar[SC_SPLIT_BOTTOM]->Hide(); |
704 | 0 | } |
705 | | |
706 | | // Grid-Windows |
707 | |
|
708 | 0 | if (bInner) |
709 | 0 | { |
710 | 0 | tools::Long nInnerPosX = bLayoutRTL ? ( nTotalWidth - nPosX - nLeftSize ) : nPosX; |
711 | 0 | pGridWin[SC_SPLIT_BOTTOMLEFT]->SetPosPixel( Point(nInnerPosX,nSplitPosY) ); |
712 | 0 | } |
713 | 0 | else |
714 | 0 | { |
715 | 0 | lcl_SetPosSize( *pGridWin[SC_SPLIT_BOTTOMLEFT], |
716 | 0 | Point(nPosX,nSplitPosY), Size(nLeftSize,nBottomSize), nTotalWidth, bLayoutRTL ); |
717 | 0 | if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE ) |
718 | 0 | lcl_SetPosSize( *pGridWin[SC_SPLIT_BOTTOMRIGHT], |
719 | 0 | Point(nSplitPosX,nSplitPosY), Size(nRightSize,nBottomSize), nTotalWidth, bLayoutRTL ); |
720 | 0 | if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE ) |
721 | 0 | lcl_SetPosSize( *pGridWin[SC_SPLIT_TOPLEFT], |
722 | 0 | Point(nPosX,nPosY), Size(nLeftSize,nTopSize), nTotalWidth, bLayoutRTL ); |
723 | 0 | if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE && aViewData.GetVSplitMode() != SC_SPLIT_NONE ) |
724 | 0 | lcl_SetPosSize( *pGridWin[SC_SPLIT_TOPRIGHT], |
725 | 0 | Point(nSplitPosX,nPosY), Size(nRightSize,nTopSize), nTotalWidth, bLayoutRTL ); |
726 | 0 | } |
727 | | |
728 | | // update scroll bars |
729 | |
|
730 | 0 | if (!bInUpdateHeader) |
731 | 0 | { |
732 | 0 | UpdateScrollBars(); // don't reset scroll bars when scrolling |
733 | 0 | UpdateHeaderWidth(); |
734 | |
|
735 | 0 | InterpretVisible(); // have everything calculated before painting |
736 | 0 | } |
737 | |
|
738 | 0 | if (bHasHint) |
739 | 0 | TestHintWindow(); // reposition |
740 | |
|
741 | 0 | UpdateVarZoom(); // update variable zoom types (after resizing GridWindows) |
742 | |
|
743 | 0 | if (aViewData.GetViewShell()->HasAccessibilityObjects()) |
744 | 0 | aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccWindowResized)); |
745 | 0 | } |
746 | | |
747 | | void ScTabView::UpdateVarZoom() |
748 | 0 | { |
749 | | // update variable zoom types |
750 | |
|
751 | 0 | SvxZoomType eZoomType = GetZoomType(); |
752 | 0 | if (eZoomType == SvxZoomType::PERCENT || bInZoomUpdate) |
753 | 0 | return; |
754 | | |
755 | 0 | bInZoomUpdate = true; |
756 | 0 | double fOldX = GetViewData().GetZoomX(); |
757 | 0 | double fOldY = GetViewData().GetZoomY(); |
758 | 0 | tools::Long nOldPercent = tools::Long(fOldY * 100); |
759 | 0 | sal_uInt16 nNewZoom = CalcZoom( eZoomType, static_cast<sal_uInt16>(nOldPercent) ); |
760 | 0 | double fNew = double(nNewZoom) / 100; |
761 | |
|
762 | 0 | if ( fNew != fOldX || fNew != fOldY ) |
763 | 0 | { |
764 | 0 | SetZoom( fNew, fNew, false ); // always separately per sheet |
765 | 0 | PaintGrid(); |
766 | 0 | PaintTop(); |
767 | 0 | PaintLeft(); |
768 | 0 | aViewData.GetViewShell()->GetViewFrame().GetBindings().Invalidate( SID_ATTR_ZOOM ); |
769 | 0 | aViewData.GetViewShell()->GetViewFrame().GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER ); |
770 | 0 | aViewData.GetBindings().Invalidate(SID_ZOOM_IN); |
771 | 0 | aViewData.GetBindings().Invalidate(SID_ZOOM_OUT); |
772 | 0 | } |
773 | 0 | bInZoomUpdate = false; |
774 | 0 | } |
775 | | |
776 | | void ScTabView::UpdateFixPos() |
777 | 0 | { |
778 | 0 | bool bResize = false; |
779 | 0 | if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX ) |
780 | 0 | if (aViewData.UpdateFixX()) |
781 | 0 | bResize = true; |
782 | 0 | if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX ) |
783 | 0 | if (aViewData.UpdateFixY()) |
784 | 0 | bResize = true; |
785 | 0 | if (bResize) |
786 | 0 | RepeatResize(false); |
787 | 0 | } |
788 | | |
789 | | void ScTabView::RepeatResize( bool bUpdateFix ) |
790 | 0 | { |
791 | 0 | if ( bUpdateFix ) |
792 | 0 | { |
793 | 0 | ScSplitMode eHSplit = aViewData.GetHSplitMode(); |
794 | 0 | ScSplitMode eVSplit = aViewData.GetVSplitMode(); |
795 | | |
796 | | // #i46796# UpdateFixX / UpdateFixY uses GetGridOffset, which requires the |
797 | | // outline windows to be available. So UpdateShow has to be called before |
798 | | // (also called from DoResize). |
799 | 0 | if ( eHSplit == SC_SPLIT_FIX || eVSplit == SC_SPLIT_FIX ) |
800 | 0 | UpdateShow(); |
801 | |
|
802 | 0 | if ( eHSplit == SC_SPLIT_FIX ) |
803 | 0 | aViewData.UpdateFixX(); |
804 | 0 | if ( eVSplit == SC_SPLIT_FIX ) |
805 | 0 | aViewData.UpdateFixY(); |
806 | 0 | } |
807 | |
|
808 | 0 | DoResize( aBorderPos, aFrameSize ); |
809 | | |
810 | | //! border must be reset ??? |
811 | 0 | } |
812 | | |
813 | | void ScTabView::GetBorderSize( SvBorder& rBorder, const Size& /* rSize */ ) |
814 | 0 | { |
815 | 0 | bool bScrollBars = aViewData.IsVScrollMode(); |
816 | 0 | bool bHeaders = aViewData.IsHeaderMode(); |
817 | 0 | bool bOutlMode = aViewData.IsOutlineMode(); |
818 | 0 | bool bHOutline = bOutlMode && lcl_HasColOutline(aViewData); |
819 | 0 | bool bVOutline = bOutlMode && lcl_HasRowOutline(aViewData); |
820 | 0 | bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.CurrentTabForData() ); |
821 | |
|
822 | 0 | rBorder = SvBorder(); |
823 | |
|
824 | 0 | if (bScrollBars) // Scrollbars horizontal or vertical |
825 | 0 | { |
826 | 0 | rBorder.Right() += aVScrollBottom->GetSizePixel().Width(); |
827 | 0 | rBorder.Bottom() += aHScrollLeft->GetSizePixel().Height(); |
828 | 0 | } |
829 | | |
830 | | // Outline-Controls |
831 | 0 | if (bVOutline && pRowOutline[SC_SPLIT_BOTTOM]) |
832 | 0 | rBorder.Left() += pRowOutline[SC_SPLIT_BOTTOM]->GetDepthSize(); |
833 | 0 | if (bHOutline && pColOutline[SC_SPLIT_LEFT]) |
834 | 0 | rBorder.Top() += pColOutline[SC_SPLIT_LEFT]->GetDepthSize(); |
835 | |
|
836 | 0 | if (bHeaders) // column/row headers |
837 | 0 | { |
838 | 0 | rBorder.Left() += pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width(); |
839 | 0 | rBorder.Top() += pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height(); |
840 | 0 | } |
841 | |
|
842 | 0 | if ( bLayoutRTL ) |
843 | 0 | ::std::swap( rBorder.Left(), rBorder.Right() ); |
844 | 0 | } |
845 | | |
846 | | IMPL_LINK_NOARG(ScTabView, TabBarResize, TabBar*, void) |
847 | 0 | { |
848 | 0 | if (!aViewData.IsHScrollMode()) |
849 | 0 | return; |
850 | | |
851 | 0 | tools::Long nSize = pTabControl->GetSplitSize(); |
852 | |
|
853 | 0 | if (aViewData.GetHSplitMode() != SC_SPLIT_FIX) |
854 | 0 | { |
855 | 0 | tools::Long nMax = pHSplitter->GetPosPixel().X(); |
856 | 0 | if( pTabControl->IsEffectiveRTL() ) |
857 | 0 | nMax = pFrameWin->GetSizePixel().Width() - nMax; |
858 | 0 | --nMax; |
859 | 0 | if (nSize>nMax) nSize = nMax; |
860 | 0 | } |
861 | |
|
862 | 0 | if ( nSize != pTabControl->GetSizePixel().Width() ) |
863 | 0 | { |
864 | 0 | pTabControl->SetSizePixel( Size( nSize, |
865 | 0 | pTabControl->GetSizePixel().Height() ) ); |
866 | 0 | RepeatResize(); |
867 | 0 | } |
868 | 0 | } |
869 | | |
870 | | void ScTabView::SetTabBarWidth( tools::Long nNewWidth ) |
871 | 0 | { |
872 | 0 | Size aSize = pTabControl->GetSizePixel(); |
873 | |
|
874 | 0 | if ( aSize.Width() != nNewWidth ) |
875 | 0 | { |
876 | 0 | aSize.setWidth( nNewWidth ); |
877 | 0 | pTabControl->SetSizePixel( aSize ); |
878 | 0 | } |
879 | 0 | } |
880 | | |
881 | | void ScTabView::SetRelTabBarWidth( double fRelTabBarWidth ) |
882 | 0 | { |
883 | 0 | if( (0.0 <= fRelTabBarWidth) && (fRelTabBarWidth <= 1.0) ) |
884 | 0 | if( tools::Long nFrameWidth = pFrameWin->GetSizePixel().Width() ) |
885 | 0 | SetTabBarWidth( static_cast< tools::Long >( fRelTabBarWidth * nFrameWidth + 0.5 ) ); |
886 | 0 | } |
887 | | |
888 | | void ScTabView::SetPendingRelTabBarWidth( double fRelTabBarWidth ) |
889 | 0 | { |
890 | 0 | mfPendingTabBarWidth = fRelTabBarWidth; |
891 | 0 | SetRelTabBarWidth( fRelTabBarWidth ); |
892 | 0 | } |
893 | | |
894 | | tools::Long ScTabView::GetTabBarWidth() const |
895 | 0 | { |
896 | 0 | return pTabControl->GetSizePixel().Width(); |
897 | 0 | } |
898 | | |
899 | | double ScTabView::GetRelTabBarWidth() |
900 | 0 | { |
901 | 0 | return 0.5; |
902 | 0 | } |
903 | | |
904 | | ScGridWindow* ScTabView::GetActiveWin() |
905 | 0 | { |
906 | 0 | ScSplitPos ePos = aViewData.GetActivePart(); |
907 | 0 | OSL_ENSURE(pGridWin[ePos],"no active window"); |
908 | 0 | return pGridWin[ePos]; |
909 | 0 | } |
910 | | |
911 | | void ScTabView::SetActivePointer( PointerStyle nPointer ) |
912 | 0 | { |
913 | 0 | for (VclPtr<ScGridWindow> & pWin : pGridWin) |
914 | 0 | if (pWin) |
915 | 0 | pWin->SetPointer( nPointer ); |
916 | 0 | } |
917 | | |
918 | | void ScTabView::ActiveGrabFocus() |
919 | 0 | { |
920 | 0 | ScSplitPos ePos = aViewData.GetActivePart(); |
921 | 0 | if (pGridWin[ePos]) |
922 | 0 | pGridWin[ePos]->GrabFocus(); |
923 | 0 | } |
924 | | |
925 | | ScSplitPos ScTabView::FindWindow( const vcl::Window* pWindow ) const |
926 | 0 | { |
927 | 0 | ScSplitPos eVal = SC_SPLIT_BOTTOMLEFT; // Default |
928 | 0 | for (sal_uInt16 i=0; i<4; i++) |
929 | 0 | if ( pGridWin[i] == pWindow ) |
930 | 0 | eVal = static_cast<ScSplitPos>(i); |
931 | |
|
932 | 0 | return eVal; |
933 | 0 | } |
934 | | |
935 | | Point ScTabView::GetGridOffset() const |
936 | 0 | { |
937 | 0 | Point aPos; |
938 | | |
939 | | // size as in DoResize |
940 | |
|
941 | 0 | bool bHeaders = aViewData.IsHeaderMode(); |
942 | 0 | bool bOutlMode = aViewData.IsOutlineMode(); |
943 | 0 | bool bHOutline = bOutlMode && lcl_HasColOutline(aViewData); |
944 | 0 | bool bVOutline = bOutlMode && lcl_HasRowOutline(aViewData); |
945 | | |
946 | | // Outline-Controls |
947 | 0 | if (bVOutline && pRowOutline[SC_SPLIT_BOTTOM]) |
948 | 0 | aPos.AdjustX(pRowOutline[SC_SPLIT_BOTTOM]->GetDepthSize() ); |
949 | 0 | if (bHOutline && pColOutline[SC_SPLIT_LEFT]) |
950 | 0 | aPos.AdjustY(pColOutline[SC_SPLIT_LEFT]->GetDepthSize() ); |
951 | |
|
952 | 0 | if (bHeaders) // column/row headers |
953 | 0 | { |
954 | 0 | if (pRowBar[SC_SPLIT_BOTTOM]) |
955 | 0 | aPos.AdjustX(pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width() ); |
956 | 0 | if (pColBar[SC_SPLIT_LEFT]) |
957 | 0 | aPos.AdjustY(pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height() ); |
958 | 0 | } |
959 | |
|
960 | 0 | return aPos; |
961 | 0 | } |
962 | | |
963 | | // --- Scroll-Bars -------------------------------------------------------- |
964 | | |
965 | | void ScTabView::SetZoomPercentFromCommand(sal_uInt16 nZoomPercent) |
966 | 0 | { |
967 | | // scroll wheel doesn't set the AppOptions default |
968 | |
|
969 | 0 | bool bSyncZoom = ScModule::get()->GetAppOptions().GetSynchronizeZoom(); |
970 | 0 | SetZoomType(SvxZoomType::PERCENT, bSyncZoom); |
971 | 0 | double fFract = double(nZoomPercent) / 100; |
972 | 0 | SetZoom(fFract, fFract, bSyncZoom); |
973 | 0 | PaintGrid(); |
974 | 0 | PaintTop(); |
975 | 0 | PaintLeft(); |
976 | 0 | aViewData.GetBindings().Invalidate( SID_ATTR_ZOOM); |
977 | 0 | aViewData.GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER); |
978 | 0 | aViewData.GetBindings().Invalidate( SID_ZOOM_IN); |
979 | 0 | aViewData.GetBindings().Invalidate( SID_ZOOM_OUT); |
980 | 0 | } |
981 | | |
982 | | bool ScTabView::ScrollCommand( const CommandEvent& rCEvt, ScSplitPos ePos ) |
983 | 0 | { |
984 | 0 | HideNoteOverlay(); |
985 | |
|
986 | 0 | bool bDone = false; |
987 | 0 | const CommandWheelData* pData = rCEvt.GetWheelData(); |
988 | 0 | if (pData && pData->GetMode() == CommandWheelMode::ZOOM) |
989 | 0 | { |
990 | 0 | if ( !aViewData.GetViewShell()->GetViewFrame().GetFrame().IsInPlace() ) |
991 | 0 | { |
992 | | // for ole inplace editing, the scale is defined by the visarea and client size |
993 | | // and can't be changed directly |
994 | |
|
995 | 0 | double fOldY = aViewData.GetZoomY(); |
996 | 0 | sal_uInt16 nOld = static_cast<tools::Long>( fOldY * 100 ); |
997 | 0 | sal_uInt16 nNew; |
998 | 0 | if ( pData->GetDelta() < 0 ) |
999 | 0 | nNew = std::max( MINZOOM, basegfx::zoomtools::zoomOut( nOld )); |
1000 | 0 | else |
1001 | 0 | nNew = std::min( MAXZOOM, basegfx::zoomtools::zoomIn( nOld )); |
1002 | 0 | if ( nNew != nOld ) |
1003 | 0 | { |
1004 | 0 | SetZoomPercentFromCommand(nNew); |
1005 | 0 | } |
1006 | |
|
1007 | 0 | bDone = true; |
1008 | 0 | } |
1009 | 0 | } |
1010 | 0 | else |
1011 | 0 | { |
1012 | 0 | ScHSplitPos eHPos = WhichH(ePos); |
1013 | 0 | ScVSplitPos eVPos = WhichV(ePos); |
1014 | 0 | ScrollAdaptor* pHScroll = ( eHPos == SC_SPLIT_LEFT ) ? aHScrollLeft.get() : aHScrollRight.get(); |
1015 | 0 | ScrollAdaptor* pVScroll = ( eVPos == SC_SPLIT_TOP ) ? aVScrollTop.get() : aVScrollBottom.get(); |
1016 | 0 | if ( pGridWin[ePos] ) |
1017 | 0 | bDone = pGridWin[ePos]->HandleScrollCommand( rCEvt, pHScroll, pVScroll ); |
1018 | 0 | } |
1019 | 0 | return bDone; |
1020 | 0 | } |
1021 | | |
1022 | | bool ScTabView::GesturePanCommand(const CommandEvent& rCEvt) |
1023 | 0 | { |
1024 | 0 | HideNoteOverlay(); |
1025 | |
|
1026 | 0 | bool bDone = false; |
1027 | 0 | const CommandGesturePanData* pData = rCEvt.GetGesturePanData(); |
1028 | 0 | if (!pData) |
1029 | 0 | return false; |
1030 | | |
1031 | 0 | if (aViewData.GetViewShell()->GetViewFrame().GetFrame().IsInPlace()) |
1032 | 0 | return false; |
1033 | | |
1034 | 0 | ScSplitPos ePos = aViewData.GetActivePart(); |
1035 | 0 | ScHSplitPos eHPos = WhichH(ePos); |
1036 | 0 | ScVSplitPos eVPos = WhichV(ePos); |
1037 | 0 | ScrollAdaptor* pHScroll = (eHPos == SC_SPLIT_LEFT) ? aHScrollLeft.get() : aHScrollRight.get(); |
1038 | 0 | ScrollAdaptor* pVScroll = (eVPos == SC_SPLIT_TOP) ? aVScrollTop.get() : aVScrollBottom.get(); |
1039 | 0 | if (pGridWin[ePos]) |
1040 | 0 | bDone = pGridWin[ePos]->HandleScrollCommand(rCEvt, pHScroll, pVScroll); |
1041 | |
|
1042 | 0 | return bDone; |
1043 | 0 | } |
1044 | | |
1045 | | bool ScTabView::GestureZoomCommand(const CommandEvent& rCEvt) |
1046 | 0 | { |
1047 | 0 | HideNoteOverlay(); |
1048 | |
|
1049 | 0 | const CommandGestureZoomData* pData = rCEvt.GetGestureZoomData(); |
1050 | 0 | if (!pData) |
1051 | 0 | return false; |
1052 | | |
1053 | 0 | if (aViewData.GetViewShell()->GetViewFrame().GetFrame().IsInPlace()) |
1054 | 0 | return false; |
1055 | | |
1056 | 0 | if (pData->meEventType == GestureEventZoomType::Begin) |
1057 | 0 | { |
1058 | 0 | mfLastZoomScale = pData->mfScaleDelta; |
1059 | 0 | return true; |
1060 | 0 | } |
1061 | | |
1062 | 0 | if (pData->meEventType == GestureEventZoomType::Update) |
1063 | 0 | { |
1064 | 0 | double deltaBetweenEvents = (pData->mfScaleDelta - mfLastZoomScale) / mfLastZoomScale; |
1065 | 0 | mfLastZoomScale = pData->mfScaleDelta; |
1066 | | |
1067 | | // Accumulate fractional zoom to avoid small zoom changes from being ignored |
1068 | 0 | mfAccumulatedZoom += deltaBetweenEvents; |
1069 | 0 | int nZoomChangePercent = mfAccumulatedZoom * 100; |
1070 | 0 | mfAccumulatedZoom -= nZoomChangePercent / 100.0; |
1071 | |
|
1072 | 0 | double fOldY = aViewData.GetZoomY(); |
1073 | 0 | sal_uInt16 nOld = static_cast<tools::Long>(fOldY * 100); |
1074 | 0 | sal_uInt16 nNew = nOld + nZoomChangePercent; |
1075 | 0 | nNew = std::clamp<sal_uInt16>(nNew, MINZOOM, MAXZOOM); |
1076 | |
|
1077 | 0 | if (nNew != nOld) |
1078 | 0 | { |
1079 | 0 | SetZoomPercentFromCommand(nNew); |
1080 | 0 | } |
1081 | |
|
1082 | 0 | return true; |
1083 | 0 | } |
1084 | 0 | return true; |
1085 | 0 | } |
1086 | | |
1087 | | IMPL_LINK_NOARG(ScTabView, HScrollLeftHdl, weld::Scrollbar&, void) |
1088 | 0 | { |
1089 | 0 | ScrollHdl(aHScrollLeft.get()); |
1090 | 0 | } |
1091 | | |
1092 | | IMPL_LINK_NOARG(ScTabView, HScrollRightHdl, weld::Scrollbar&, void) |
1093 | 0 | { |
1094 | 0 | ScrollHdl(aHScrollRight.get()); |
1095 | 0 | } |
1096 | | |
1097 | | IMPL_LINK_NOARG(ScTabView, VScrollTopHdl, weld::Scrollbar&, void) |
1098 | 0 | { |
1099 | 0 | ScrollHdl(aVScrollTop.get()); |
1100 | 0 | } |
1101 | | |
1102 | | IMPL_LINK_NOARG(ScTabView, VScrollBottomHdl, weld::Scrollbar&, void) |
1103 | 0 | { |
1104 | 0 | ScrollHdl(aVScrollBottom.get()); |
1105 | 0 | } |
1106 | | |
1107 | | IMPL_LINK_NOARG(ScTabView, EndScrollHdl, const MouseEvent&, bool) |
1108 | 0 | { |
1109 | 0 | if (bDragging) |
1110 | 0 | { |
1111 | 0 | UpdateScrollBars(); |
1112 | 0 | bDragging = false; |
1113 | 0 | } |
1114 | 0 | return false; |
1115 | 0 | } |
1116 | | |
1117 | | void ScTabView::ScrollHdl(ScrollAdaptor* pScroll) |
1118 | 0 | { |
1119 | 0 | bool bUpdateHorizontalScrollbars = false; |
1120 | |
|
1121 | 0 | bool bHoriz = ( pScroll == aHScrollLeft.get() || pScroll == aHScrollRight.get() ); |
1122 | 0 | tools::Long nViewPos; |
1123 | 0 | if ( bHoriz ) |
1124 | 0 | nViewPos = aViewData.GetPosX( (pScroll == aHScrollLeft.get()) ? |
1125 | 0 | SC_SPLIT_LEFT : SC_SPLIT_RIGHT ); |
1126 | 0 | else |
1127 | 0 | nViewPos = aViewData.GetPosY( (pScroll == aVScrollTop.get()) ? |
1128 | 0 | SC_SPLIT_TOP : SC_SPLIT_BOTTOM ); |
1129 | |
|
1130 | 0 | bool bLayoutRTL = bHoriz && aViewData.GetDocument().IsLayoutRTL( aViewData.CurrentTabForData() ); |
1131 | |
|
1132 | 0 | ScrollType eType = pScroll->GetScrollType(); |
1133 | 0 | if ( eType == ScrollType::Drag ) |
1134 | 0 | { |
1135 | 0 | if (!bDragging) |
1136 | 0 | { |
1137 | 0 | bDragging = true; |
1138 | 0 | nPrevDragPos = nViewPos; |
1139 | 0 | } |
1140 | | |
1141 | | // show scroll position |
1142 | | // (only QuickHelp, there is no entry for it in the status bar) |
1143 | |
|
1144 | 0 | if (Help::IsQuickHelpEnabled()) |
1145 | 0 | { |
1146 | 0 | Size aSize = pScroll->GetSizePixel(); |
1147 | | |
1148 | | /* Convert scrollbar mouse position to screen position. If RTL |
1149 | | mode of scrollbar differs from RTL mode of its parent, then the |
1150 | | direct call to Window::OutputToNormalizedScreenPixel() will |
1151 | | give unusable results, because calculation of screen position |
1152 | | is based on parent orientation and expects equal orientation of |
1153 | | the child position. Need to mirror mouse position before. */ |
1154 | 0 | Point aMousePos = pScroll->GetPointerPosPixel(); |
1155 | 0 | if( pScroll->IsRTLEnabled() != pScroll->GetParent()->IsRTLEnabled() ) |
1156 | 0 | aMousePos.setX( aSize.Width() - aMousePos.X() - 1 ); |
1157 | 0 | aMousePos = pScroll->OutputToNormalizedScreenPixel( aMousePos ); |
1158 | | |
1159 | | // convert top-left position of scrollbar to screen position |
1160 | 0 | Point aPos = pScroll->OutputToNormalizedScreenPixel( Point() ); |
1161 | | |
1162 | | // get scrollbar scroll position for help text (row number/column name) |
1163 | 0 | tools::Long nScrollMin = 0; // simulate RangeMin |
1164 | 0 | if ( aViewData.GetHSplitMode()==SC_SPLIT_FIX && pScroll == aHScrollRight.get() ) |
1165 | 0 | nScrollMin = aViewData.GetFixPosX(); |
1166 | 0 | if ( aViewData.GetVSplitMode()==SC_SPLIT_FIX && pScroll == aVScrollBottom.get() ) |
1167 | 0 | nScrollMin = aViewData.GetFixPosY(); |
1168 | 0 | tools::Long nScrollPos = GetScrollBarPos( *pScroll, bLayoutRTL ) + nScrollMin; |
1169 | |
|
1170 | 0 | OUString aHelpStr; |
1171 | 0 | tools::Rectangle aRect; |
1172 | 0 | QuickHelpFlags nAlign; |
1173 | 0 | if (bHoriz) |
1174 | 0 | { |
1175 | 0 | aHelpStr = ScResId(STR_COLUMN) + |
1176 | 0 | " " + ScColToAlpha(static_cast<SCCOL>(nScrollPos)); |
1177 | |
|
1178 | 0 | aRect.SetLeft( aMousePos.X() ); |
1179 | 0 | aRect.SetTop( aPos.Y() - 4 ); |
1180 | 0 | nAlign = QuickHelpFlags::Bottom|QuickHelpFlags::Center; |
1181 | 0 | } |
1182 | 0 | else |
1183 | 0 | { |
1184 | 0 | aHelpStr = ScResId(STR_ROW) + |
1185 | 0 | " " + OUString::number(nScrollPos + 1); |
1186 | | |
1187 | | // note that bLayoutRTL is always false here, because bLayoutRTL depends on bHoriz |
1188 | | |
1189 | | // show quicktext always inside sheet area |
1190 | 0 | aRect.SetLeft(aPos.X() - 8); |
1191 | 0 | aRect.SetTop( aMousePos.Y() ); |
1192 | 0 | nAlign = QuickHelpFlags::Right | QuickHelpFlags::VCenter; |
1193 | 0 | } |
1194 | 0 | aRect.SetRight( aRect.Left() ); |
1195 | 0 | aRect.SetBottom( aRect.Top() ); |
1196 | |
|
1197 | 0 | Help::ShowQuickHelp(pScroll->GetParent(), aRect, aHelpStr, nAlign); |
1198 | 0 | } |
1199 | 0 | } |
1200 | 0 | else |
1201 | 0 | bDragging = false; |
1202 | |
|
1203 | 0 | if ( bHoriz && bLayoutRTL ) |
1204 | 0 | { |
1205 | | // change scroll type so visible/previous cells calculation below remains the same |
1206 | 0 | switch ( eType ) |
1207 | 0 | { |
1208 | 0 | case ScrollType::LineUp: eType = ScrollType::LineDown; break; |
1209 | 0 | case ScrollType::LineDown: eType = ScrollType::LineUp; break; |
1210 | 0 | case ScrollType::PageUp: eType = ScrollType::PageDown; break; |
1211 | 0 | case ScrollType::PageDown: eType = ScrollType::PageUp; break; |
1212 | 0 | default: |
1213 | 0 | { |
1214 | | // added to avoid warnings |
1215 | 0 | } |
1216 | 0 | } |
1217 | 0 | } |
1218 | | |
1219 | 0 | tools::Long nDelta(0); |
1220 | 0 | switch ( eType ) |
1221 | 0 | { |
1222 | 0 | case ScrollType::LineUp: |
1223 | 0 | nDelta = -1; |
1224 | 0 | break; |
1225 | 0 | case ScrollType::LineDown: |
1226 | 0 | nDelta = 1; |
1227 | 0 | break; |
1228 | 0 | case ScrollType::PageUp: |
1229 | 0 | if ( pScroll == aHScrollLeft.get() ) nDelta = -static_cast<tools::Long>(aViewData.PrevCellsX( SC_SPLIT_LEFT )); |
1230 | 0 | if ( pScroll == aHScrollRight.get() ) nDelta = -static_cast<tools::Long>(aViewData.PrevCellsX( SC_SPLIT_RIGHT )); |
1231 | 0 | if ( pScroll == aVScrollTop.get() ) nDelta = -static_cast<tools::Long>(aViewData.PrevCellsY( SC_SPLIT_TOP )); |
1232 | 0 | if ( pScroll == aVScrollBottom.get() ) nDelta = -static_cast<tools::Long>(aViewData.PrevCellsY( SC_SPLIT_BOTTOM )); |
1233 | 0 | if (nDelta==0) nDelta=-1; |
1234 | 0 | break; |
1235 | 0 | case ScrollType::PageDown: |
1236 | 0 | if ( pScroll == aHScrollLeft.get() ) nDelta = aViewData.VisibleCellsX( SC_SPLIT_LEFT ); |
1237 | 0 | if ( pScroll == aHScrollRight.get() ) nDelta = aViewData.VisibleCellsX( SC_SPLIT_RIGHT ); |
1238 | 0 | if ( pScroll == aVScrollTop.get() ) nDelta = aViewData.VisibleCellsY( SC_SPLIT_TOP ); |
1239 | 0 | if ( pScroll == aVScrollBottom.get() ) nDelta = aViewData.VisibleCellsY( SC_SPLIT_BOTTOM ); |
1240 | 0 | if (nDelta==0) nDelta=1; |
1241 | 0 | break; |
1242 | 0 | default: |
1243 | 0 | { |
1244 | | // only scroll in the correct direction, do not jitter around hidden ranges |
1245 | 0 | tools::Long nScrollMin = 0; // simulate RangeMin |
1246 | 0 | if ( aViewData.GetHSplitMode()==SC_SPLIT_FIX && pScroll == aHScrollRight.get() ) |
1247 | 0 | nScrollMin = aViewData.GetFixPosX(); |
1248 | 0 | if ( aViewData.GetVSplitMode()==SC_SPLIT_FIX && pScroll == aVScrollBottom.get() ) |
1249 | 0 | nScrollMin = aViewData.GetFixPosY(); |
1250 | |
|
1251 | 0 | tools::Long nScrollPos = GetScrollBarPos( *pScroll, bLayoutRTL ) + nScrollMin; |
1252 | 0 | nDelta = nScrollPos - nViewPos; |
1253 | | |
1254 | | // tdf#152406 Disable anti-jitter code for scroll wheel events |
1255 | | // After moving thousands of columns to the right via |
1256 | | // horizontal scroll wheel or trackpad swipe events, most |
1257 | | // vertical scroll wheel or trackpad swipe events will trigger |
1258 | | // the anti-jitter code because nScrollPos and nPrevDragPos |
1259 | | // will be equal and nDelta will be overridden and set to zero. |
1260 | | // So, only use the anti-jitter code for mouse drag events. |
1261 | 0 | if ( eType == ScrollType::Drag ) |
1262 | 0 | { |
1263 | 0 | if ( nScrollPos > nPrevDragPos ) |
1264 | 0 | { |
1265 | 0 | if (nDelta<0) nDelta=0; |
1266 | 0 | } |
1267 | 0 | else if ( nScrollPos < nPrevDragPos ) |
1268 | 0 | { |
1269 | 0 | if (nDelta>0) nDelta=0; |
1270 | 0 | } |
1271 | 0 | else |
1272 | 0 | nDelta = 0; |
1273 | 0 | } |
1274 | 0 | else if ( bHoriz ) |
1275 | 0 | { |
1276 | | // tdf#135478 Reduce sensitivity of horizontal scrollwheel |
1277 | | // Problem: at least on macOS, swipe events are very |
1278 | | // precise. So, when swiping at a slight angle off of |
1279 | | // vertical, swipe events will include a small amount |
1280 | | // of horizontal movement. Since horizontal swipe units |
1281 | | // are measured in cell widths, these small amounts of |
1282 | | // horizontal movement results in shifting many columns |
1283 | | // to the right or left while swiping almost vertically. |
1284 | | // So my hacky fix is to reduce the amount of horizontal |
1285 | | // swipe events to roughly match the "visual distance" |
1286 | | // of vertical swipe events. |
1287 | | // The reduction factor is arbitrary but is set to |
1288 | | // roughly the ratio of default cell width divided by |
1289 | | // default cell height. This hacky fix isn't a perfect |
1290 | | // fix, but hopefully it reduces the amount of |
1291 | | // unexpected horizontal shifting while swiping |
1292 | | // vertically to a tolerable amount for most users. |
1293 | | // Note: the potential downside of doing this is that |
1294 | | // some users might find horizontal swiping to be |
1295 | | // slower than they are used to. If that becomes an |
1296 | | // issue for enough users, the reduction factor may |
1297 | | // need to be lowered to find a good balance point. |
1298 | | #ifdef _WIN32 |
1299 | | static const tools::Long nHScrollReductionFactor = 3; |
1300 | | #else |
1301 | 0 | static const tools::Long nHScrollReductionFactor = 8; |
1302 | 0 | #endif |
1303 | | |
1304 | | // tdf#161945 increase sensitivity for negative horizontal deltas |
1305 | | // A side effect of the anti-jitter code is that it tends |
1306 | | // to reduce the sensitivity of horizontal scroll events |
1307 | | // towards the first column. It is particularly noticeable |
1308 | | // with horizontal scroll events from a scrollwheel when |
1309 | | // the view position is in column B or C. This results in |
1310 | | // a very small delta from the anti-jitter code. |
1311 | | // So, to balance things out, apply a constant adjustment |
1312 | | // factor to increase the sensitivity more for small deltas |
1313 | | // than for large deltas. |
1314 | 0 | static const tools::Long nHScrollNegativeDeltaAdjustmentFactor = -1; |
1315 | 0 | if ( nDelta < 0 ) |
1316 | 0 | nDelta += nHScrollNegativeDeltaAdjustmentFactor; |
1317 | |
|
1318 | 0 | if ( pScroll == aHScrollLeft.get() ) |
1319 | 0 | { |
1320 | 0 | mnPendingaHScrollLeftDelta += nDelta; |
1321 | 0 | nDelta = 0; |
1322 | 0 | if ( abs(mnPendingaHScrollLeftDelta) > nHScrollReductionFactor ) |
1323 | 0 | { |
1324 | 0 | nDelta = mnPendingaHScrollLeftDelta / nHScrollReductionFactor; |
1325 | 0 | mnPendingaHScrollLeftDelta = mnPendingaHScrollLeftDelta % nHScrollReductionFactor; |
1326 | 0 | } |
1327 | 0 | } |
1328 | 0 | else |
1329 | 0 | { |
1330 | 0 | mnPendingaHScrollRightDelta += nDelta; |
1331 | 0 | nDelta = 0; |
1332 | 0 | if ( abs(mnPendingaHScrollRightDelta) > nHScrollReductionFactor ) |
1333 | 0 | { |
1334 | 0 | nDelta = mnPendingaHScrollRightDelta / nHScrollReductionFactor; |
1335 | 0 | mnPendingaHScrollRightDelta = mnPendingaHScrollRightDelta % nHScrollReductionFactor; |
1336 | 0 | } |
1337 | 0 | } |
1338 | |
|
1339 | 0 | bUpdateHorizontalScrollbars = true; |
1340 | 0 | } |
1341 | |
|
1342 | 0 | nPrevDragPos = nScrollPos; |
1343 | 0 | } |
1344 | 0 | break; |
1345 | 0 | } |
1346 | | |
1347 | 0 | if (nDelta) |
1348 | 0 | { |
1349 | 0 | bool bUpdate = ( eType != ScrollType::Drag ); // don't alter the ranges while dragging |
1350 | 0 | if ( bHoriz ) |
1351 | 0 | ScrollX( nDelta, (pScroll == aHScrollLeft.get()) ? SC_SPLIT_LEFT : SC_SPLIT_RIGHT, bUpdate ); |
1352 | 0 | else |
1353 | 0 | ScrollY( nDelta, (pScroll == aVScrollTop.get()) ? SC_SPLIT_TOP : SC_SPLIT_BOTTOM, bUpdate ); |
1354 | 0 | } |
1355 | | |
1356 | | // tdf#161945 update horizontal scrollbar position to match tab view |
1357 | | // While the fix for tdf#135478 reduces the horizontal scroll delta |
1358 | | // applied to the tab view, the horizontal scrollbar is set before |
1359 | | // that with the original delta. As a result, the horizontal scrollbar |
1360 | | // is now mispositioned so update the horizontal scrollbar position |
1361 | | // to match the position of the tab view's visible columns. |
1362 | 0 | if ( bUpdateHorizontalScrollbars ) |
1363 | 0 | UpdateScrollBars( COLUMN_HEADER ); |
1364 | 0 | } |
1365 | | |
1366 | | void ScTabView::ScrollX( tools::Long nDeltaX, ScHSplitPos eWhich, bool bUpdBars ) |
1367 | 0 | { |
1368 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1369 | 0 | SCCOL nOldX = aViewData.GetPosX(eWhich); |
1370 | 0 | SCCOL nNewX = nOldX + static_cast<SCCOL>(nDeltaX); |
1371 | 0 | if ( nNewX < 0 ) |
1372 | 0 | { |
1373 | 0 | nDeltaX -= nNewX; |
1374 | 0 | nNewX = 0; |
1375 | 0 | } |
1376 | 0 | if ( nNewX > rDoc.MaxCol() ) |
1377 | 0 | { |
1378 | 0 | nDeltaX -= nNewX - rDoc.MaxCol(); |
1379 | 0 | nNewX = rDoc.MaxCol(); |
1380 | 0 | } |
1381 | |
|
1382 | 0 | SCCOL nDir = ( nDeltaX > 0 ) ? 1 : -1; |
1383 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1384 | 0 | while ( rDoc.ColHidden(nNewX, nTab) && |
1385 | 0 | nNewX+nDir >= 0 && nNewX+nDir <= rDoc.MaxCol() ) |
1386 | 0 | nNewX = sal::static_int_cast<SCCOL>( nNewX + nDir ); |
1387 | | |
1388 | | // freeze |
1389 | |
|
1390 | 0 | if (aViewData.GetHSplitMode() == SC_SPLIT_FIX) |
1391 | 0 | { |
1392 | 0 | if (eWhich == SC_SPLIT_LEFT) |
1393 | 0 | nNewX = nOldX; // always keep the left part |
1394 | 0 | else |
1395 | 0 | { |
1396 | 0 | SCCOL nFixX = aViewData.GetFixPosX(); |
1397 | 0 | if (nNewX < nFixX) |
1398 | 0 | nNewX = nFixX; |
1399 | 0 | } |
1400 | 0 | } |
1401 | 0 | if (nNewX == nOldX) |
1402 | 0 | return; |
1403 | | |
1404 | 0 | HideAllCursors(); |
1405 | |
|
1406 | 0 | if ( nNewX >= 0 && nNewX <= rDoc.MaxCol() && nDeltaX ) |
1407 | 0 | { |
1408 | 0 | SCCOL nTrackX = std::max( nOldX, nNewX ); |
1409 | | |
1410 | | // with VCL Update() affects all windows at the moment, that is why |
1411 | | // calling Update after scrolling of the GridWindow would possibly |
1412 | | // already have painted the column/row bar with updated position. - |
1413 | | // Therefore call Update once before on column/row bar |
1414 | 0 | if (pColBar[eWhich]) |
1415 | 0 | pColBar[eWhich]->PaintImmediately(); |
1416 | |
|
1417 | 0 | tools::Long nOldPos = aViewData.GetScrPos( nTrackX, 0, eWhich ).X(); |
1418 | 0 | aViewData.SetPosX( eWhich, nNewX ); |
1419 | 0 | tools::Long nDiff = aViewData.GetScrPos( nTrackX, 0, eWhich ).X() - nOldPos; |
1420 | |
|
1421 | 0 | if ( eWhich==SC_SPLIT_LEFT ) |
1422 | 0 | { |
1423 | 0 | pGridWin[SC_SPLIT_BOTTOMLEFT]->ScrollPixel( nDiff, 0 ); |
1424 | 0 | if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE ) |
1425 | 0 | pGridWin[SC_SPLIT_TOPLEFT]->ScrollPixel( nDiff, 0 ); |
1426 | 0 | } |
1427 | 0 | else |
1428 | 0 | { |
1429 | 0 | pGridWin[SC_SPLIT_BOTTOMRIGHT]->ScrollPixel( nDiff, 0 ); |
1430 | 0 | if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE ) |
1431 | 0 | pGridWin[SC_SPLIT_TOPRIGHT]->ScrollPixel( nDiff, 0 ); |
1432 | 0 | } |
1433 | 0 | if (pColBar[eWhich]) { pColBar[eWhich]->Scroll( nDiff,0 ); pColBar[eWhich]->PaintImmediately(); } |
1434 | 0 | if (pColOutline[eWhich]) pColOutline[eWhich]->ScrollPixel( nDiff ); |
1435 | 0 | if (bUpdBars) |
1436 | 0 | UpdateScrollBars(); |
1437 | 0 | } |
1438 | |
|
1439 | 0 | if (nDeltaX==1 || nDeltaX==-1) |
1440 | 0 | pGridWin[aViewData.GetActivePart()]->PaintImmediately(); |
1441 | |
|
1442 | 0 | ShowAllCursors(); |
1443 | |
|
1444 | 0 | SetNewVisArea(); // MapMode must already be set |
1445 | |
|
1446 | 0 | TestHintWindow(); |
1447 | 0 | } |
1448 | | |
1449 | | void ScTabView::ScrollY( tools::Long nDeltaY, ScVSplitPos eWhich, bool bUpdBars ) |
1450 | 0 | { |
1451 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1452 | 0 | SCROW nOldY = aViewData.GetPosY(eWhich); |
1453 | 0 | SCROW nNewY = nOldY + static_cast<SCROW>(nDeltaY); |
1454 | 0 | if ( nNewY < 0 ) |
1455 | 0 | { |
1456 | 0 | nDeltaY -= nNewY; |
1457 | 0 | nNewY = 0; |
1458 | 0 | } |
1459 | 0 | if ( nNewY > rDoc.MaxRow() ) |
1460 | 0 | { |
1461 | 0 | nDeltaY -= nNewY - rDoc.MaxRow(); |
1462 | 0 | nNewY = rDoc.MaxRow(); |
1463 | 0 | } |
1464 | |
|
1465 | 0 | SCROW nDir = ( nDeltaY > 0 ) ? 1 : -1; |
1466 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1467 | 0 | while ( rDoc.RowHidden(nNewY, nTab) && |
1468 | 0 | nNewY+nDir >= 0 && nNewY+nDir <= rDoc.MaxRow() ) |
1469 | 0 | nNewY += nDir; |
1470 | | |
1471 | | // freeze |
1472 | |
|
1473 | 0 | if (aViewData.GetVSplitMode() == SC_SPLIT_FIX) |
1474 | 0 | { |
1475 | 0 | if (eWhich == SC_SPLIT_TOP) |
1476 | 0 | nNewY = nOldY; // always keep the upper part |
1477 | 0 | else |
1478 | 0 | { |
1479 | 0 | SCROW nFixY = aViewData.GetFixPosY(); |
1480 | 0 | if (nNewY < nFixY) |
1481 | 0 | nNewY = nFixY; |
1482 | 0 | } |
1483 | 0 | } |
1484 | 0 | if (nNewY == nOldY) |
1485 | 0 | return; |
1486 | | |
1487 | 0 | HideAllCursors(); |
1488 | |
|
1489 | 0 | if ( nNewY >= 0 && nNewY <= rDoc.MaxRow() && nDeltaY ) |
1490 | 0 | { |
1491 | 0 | SCROW nTrackY = std::max( nOldY, nNewY ); |
1492 | | |
1493 | | // adjust row headers before the actual scrolling, so it does not get painted twice |
1494 | | // PosY may then also not be set yet, pass on new value |
1495 | 0 | SCROW nUNew = nNewY; |
1496 | 0 | UpdateHeaderWidth( &eWhich, &nUNew ); // adjust row headers |
1497 | |
|
1498 | 0 | if (pRowBar[eWhich]) |
1499 | 0 | pRowBar[eWhich]->PaintImmediately(); |
1500 | |
|
1501 | 0 | tools::Long nOldPos = aViewData.GetScrPos( 0, nTrackY, eWhich ).Y(); |
1502 | 0 | aViewData.SetPosY( eWhich, nNewY ); |
1503 | 0 | tools::Long nDiff = aViewData.GetScrPos( 0, nTrackY, eWhich ).Y() - nOldPos; |
1504 | |
|
1505 | 0 | if ( eWhich==SC_SPLIT_TOP ) |
1506 | 0 | { |
1507 | 0 | pGridWin[SC_SPLIT_TOPLEFT]->ScrollPixel( 0, nDiff ); |
1508 | 0 | if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE ) |
1509 | 0 | pGridWin[SC_SPLIT_TOPRIGHT]->ScrollPixel( 0, nDiff ); |
1510 | 0 | } |
1511 | 0 | else |
1512 | 0 | { |
1513 | 0 | pGridWin[SC_SPLIT_BOTTOMLEFT]->ScrollPixel( 0, nDiff ); |
1514 | 0 | if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE ) |
1515 | 0 | pGridWin[SC_SPLIT_BOTTOMRIGHT]->ScrollPixel( 0, nDiff ); |
1516 | 0 | } |
1517 | 0 | if (pRowBar[eWhich]) { pRowBar[eWhich]->Scroll( 0,nDiff ); pRowBar[eWhich]->PaintImmediately(); } |
1518 | 0 | if (pRowOutline[eWhich]) pRowOutline[eWhich]->ScrollPixel( nDiff ); |
1519 | 0 | if (bUpdBars) |
1520 | 0 | UpdateScrollBars(); |
1521 | 0 | } |
1522 | |
|
1523 | 0 | if (nDeltaY==1 || nDeltaY==-1) |
1524 | 0 | pGridWin[aViewData.GetActivePart()]->PaintImmediately(); |
1525 | |
|
1526 | 0 | ShowAllCursors(); |
1527 | |
|
1528 | 0 | SetNewVisArea(); // MapMode must already be set |
1529 | |
|
1530 | 0 | TestHintWindow(); |
1531 | 0 | } |
1532 | | |
1533 | | void ScTabView::ScrollLines( tools::Long nDeltaX, tools::Long nDeltaY ) |
1534 | 0 | { |
1535 | 0 | ScSplitPos eWhich = aViewData.GetActivePart(); |
1536 | 0 | if (nDeltaX) |
1537 | 0 | ScrollX(nDeltaX,WhichH(eWhich)); |
1538 | 0 | if (nDeltaY) |
1539 | 0 | ScrollY(nDeltaY,WhichV(eWhich)); |
1540 | 0 | } |
1541 | | |
1542 | | namespace |
1543 | | { |
1544 | | |
1545 | | SCROW lcl_LastVisible( const ScViewData& rViewData ) |
1546 | 0 | { |
1547 | | // If many rows are hidden at end of the document, |
1548 | | // then there should not be a switch to wide row headers because of this |
1549 | 0 | ScDocument& rDoc = rViewData.GetDocument(); |
1550 | 0 | SCTAB nTab = rViewData.CurrentTabForData(); |
1551 | |
|
1552 | 0 | SCROW nVis = rDoc.MaxRow(); |
1553 | 0 | SCROW startRow; |
1554 | 0 | while ( nVis > 0 && rDoc.GetRowHeight( nVis, nTab, &startRow, nullptr ) == 0 ) |
1555 | 0 | nVis = std::max<SCROW>( startRow - 1, 0 ); |
1556 | 0 | return nVis; |
1557 | 0 | } |
1558 | | |
1559 | | } // anonymous namespace |
1560 | | |
1561 | | void ScTabView::UpdateHeaderWidth( const ScVSplitPos* pWhich, const SCROW* pPosY ) |
1562 | 0 | { |
1563 | 0 | if (!pRowBar[SC_SPLIT_BOTTOM]) |
1564 | 0 | return; |
1565 | | |
1566 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1567 | 0 | SCROW nEndPos = rDoc.MaxRow(); |
1568 | 0 | if ( !aViewData.GetViewShell()->GetViewFrame().GetFrame().IsInPlace() ) |
1569 | 0 | { |
1570 | | // for OLE Inplace always MAXROW |
1571 | |
|
1572 | 0 | if ( pWhich && *pWhich == SC_SPLIT_BOTTOM && pPosY ) |
1573 | 0 | nEndPos = *pPosY; |
1574 | 0 | else |
1575 | 0 | nEndPos = aViewData.GetPosY( SC_SPLIT_BOTTOM ); |
1576 | 0 | nEndPos += aViewData.CellsAtY( nEndPos, 1, SC_SPLIT_BOTTOM ); // VisibleCellsY |
1577 | 0 | if (nEndPos > rDoc.MaxRow()) |
1578 | 0 | nEndPos = lcl_LastVisible( aViewData ); |
1579 | |
|
1580 | 0 | if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE ) |
1581 | 0 | { |
1582 | 0 | SCROW nTopEnd; |
1583 | 0 | if ( pWhich && *pWhich == SC_SPLIT_TOP && pPosY ) |
1584 | 0 | nTopEnd = *pPosY; |
1585 | 0 | else |
1586 | 0 | nTopEnd = aViewData.GetPosY( SC_SPLIT_TOP ); |
1587 | 0 | nTopEnd += aViewData.CellsAtY( nTopEnd, 1, SC_SPLIT_TOP );// VisibleCellsY |
1588 | 0 | if (nTopEnd > rDoc.MaxRow()) |
1589 | 0 | nTopEnd = lcl_LastVisible( aViewData ); |
1590 | |
|
1591 | 0 | if ( nTopEnd > nEndPos ) |
1592 | 0 | nEndPos = nTopEnd; |
1593 | 0 | } |
1594 | 0 | } |
1595 | | |
1596 | | // tdf#148507 - update row header width only on digit changes |
1597 | 0 | tools::Long nWidth = pRowBar[SC_SPLIT_BOTTOM]->GetSmallWidth(); |
1598 | 0 | if (nEndPos >= 999999) |
1599 | 0 | nWidth = pRowBar[SC_SPLIT_BOTTOM]->GetBigWidth(); |
1600 | 0 | else if (nEndPos >= 99999) |
1601 | 0 | nWidth = pRowBar[SC_SPLIT_BOTTOM]->GetLargeWidth(); |
1602 | 0 | else if (nEndPos >= 9999) |
1603 | 0 | nWidth = pRowBar[SC_SPLIT_BOTTOM]->GetMedWidth(); |
1604 | |
|
1605 | 0 | if (nWidth == pRowBar[SC_SPLIT_BOTTOM]->GetWidth() || bInUpdateHeader) |
1606 | 0 | return; |
1607 | | |
1608 | 0 | bInUpdateHeader = true; |
1609 | |
|
1610 | 0 | pRowBar[SC_SPLIT_BOTTOM]->SetWidth( nWidth ); |
1611 | 0 | if (pRowBar[SC_SPLIT_TOP]) |
1612 | 0 | pRowBar[SC_SPLIT_TOP]->SetWidth( nWidth ); |
1613 | |
|
1614 | 0 | RepeatResize(); |
1615 | | |
1616 | | // on VCL there are endless updates (each Update is valid for all windows) |
1617 | | //aCornerButton->Update(); // otherwise this never gets an Update |
1618 | |
|
1619 | 0 | bInUpdateHeader = false; |
1620 | 0 | } |
1621 | | |
1622 | | static void ShowHide( vcl::Window* pWin, bool bShow ) |
1623 | 0 | { |
1624 | 0 | OSL_ENSURE(pWin || !bShow, "window is not present"); |
1625 | 0 | if (pWin) |
1626 | 0 | pWin->Show(bShow); |
1627 | 0 | } |
1628 | | |
1629 | | void ScTabView::UpdateShow() |
1630 | 0 | { |
1631 | 0 | bool bHScrollMode = aViewData.IsHScrollMode(); |
1632 | 0 | bool bVScrollMode = aViewData.IsVScrollMode(); |
1633 | 0 | bool bTabMode = aViewData.IsTabMode(); |
1634 | 0 | bool bOutlMode = aViewData.IsOutlineMode(); |
1635 | 0 | bool bHOutline = bOutlMode && lcl_HasColOutline(aViewData); |
1636 | 0 | bool bVOutline = bOutlMode && lcl_HasRowOutline(aViewData); |
1637 | 0 | bool bHeader = aViewData.IsHeaderMode(); |
1638 | |
|
1639 | 0 | bool bShowH = ( aViewData.GetHSplitMode() != SC_SPLIT_NONE ); |
1640 | 0 | bool bShowV = ( aViewData.GetVSplitMode() != SC_SPLIT_NONE ); |
1641 | |
|
1642 | 0 | if ( aViewData.GetDocShell()->IsPreview() ) |
1643 | 0 | bHScrollMode = bVScrollMode = bTabMode = bHeader = bHOutline = bVOutline = false; |
1644 | | |
1645 | | // create Windows |
1646 | |
|
1647 | 0 | if (bShowH && !pGridWin[SC_SPLIT_BOTTOMRIGHT]) |
1648 | 0 | { |
1649 | 0 | pGridWin[SC_SPLIT_BOTTOMRIGHT] = VclPtr<ScGridWindow>::Create( pFrameWin, aViewData, SC_SPLIT_BOTTOMRIGHT ); |
1650 | 0 | DoAddWin( pGridWin[SC_SPLIT_BOTTOMRIGHT] ); |
1651 | 0 | } |
1652 | 0 | if (bShowV && !pGridWin[SC_SPLIT_TOPLEFT]) |
1653 | 0 | { |
1654 | 0 | pGridWin[SC_SPLIT_TOPLEFT] = VclPtr<ScGridWindow>::Create( pFrameWin, aViewData, SC_SPLIT_TOPLEFT ); |
1655 | 0 | DoAddWin( pGridWin[SC_SPLIT_TOPLEFT] ); |
1656 | 0 | } |
1657 | 0 | if (bShowH && bShowV && !pGridWin[SC_SPLIT_TOPRIGHT]) |
1658 | 0 | { |
1659 | 0 | pGridWin[SC_SPLIT_TOPRIGHT] = VclPtr<ScGridWindow>::Create( pFrameWin, aViewData, SC_SPLIT_TOPRIGHT ); |
1660 | 0 | DoAddWin( pGridWin[SC_SPLIT_TOPRIGHT] ); |
1661 | 0 | } |
1662 | |
|
1663 | 0 | if (bHOutline && !pColOutline[SC_SPLIT_LEFT]) |
1664 | 0 | pColOutline[SC_SPLIT_LEFT] = VclPtr<ScOutlineWindow>::Create( pFrameWin, SC_OUTLINE_HOR, aViewData, SC_SPLIT_BOTTOMLEFT ); |
1665 | 0 | if (bShowH && bHOutline && !pColOutline[SC_SPLIT_RIGHT]) |
1666 | 0 | pColOutline[SC_SPLIT_RIGHT] = VclPtr<ScOutlineWindow>::Create( pFrameWin, SC_OUTLINE_HOR, aViewData, SC_SPLIT_BOTTOMRIGHT ); |
1667 | |
|
1668 | 0 | if (bVOutline && !pRowOutline[SC_SPLIT_BOTTOM]) |
1669 | 0 | pRowOutline[SC_SPLIT_BOTTOM] = VclPtr<ScOutlineWindow>::Create( pFrameWin, SC_OUTLINE_VER, aViewData, SC_SPLIT_BOTTOMLEFT ); |
1670 | 0 | if (bShowV && bVOutline && !pRowOutline[SC_SPLIT_TOP]) |
1671 | 0 | pRowOutline[SC_SPLIT_TOP] = VclPtr<ScOutlineWindow>::Create( pFrameWin, SC_OUTLINE_VER, aViewData, SC_SPLIT_TOPLEFT ); |
1672 | |
|
1673 | 0 | if (bShowH && bHeader && !pColBar[SC_SPLIT_RIGHT]) |
1674 | 0 | pColBar[SC_SPLIT_RIGHT] = VclPtr<ScColBar>::Create( pFrameWin, SC_SPLIT_RIGHT, |
1675 | 0 | &aHdrFunc, pHdrSelEng.get(), this ); |
1676 | 0 | if (bShowV && bHeader && !pRowBar[SC_SPLIT_TOP]) |
1677 | 0 | pRowBar[SC_SPLIT_TOP] = VclPtr<ScRowBar>::Create( pFrameWin, SC_SPLIT_TOP, |
1678 | 0 | &aHdrFunc, pHdrSelEng.get(), this ); |
1679 | | |
1680 | | // show Windows |
1681 | |
|
1682 | 0 | ShowHide( aHScrollLeft.get(), bHScrollMode ); |
1683 | 0 | ShowHide( aHScrollRight.get(), bShowH && bHScrollMode ); |
1684 | 0 | ShowHide( aVScrollBottom.get(), bVScrollMode ); |
1685 | 0 | ShowHide( aVScrollTop.get(), bShowV && bVScrollMode ); |
1686 | |
|
1687 | 0 | ShowHide( pHSplitter, bHScrollMode || bShowH ); // always generated |
1688 | 0 | ShowHide( pVSplitter, bVScrollMode || bShowV ); |
1689 | 0 | ShowHide( pTabControl, bTabMode ); |
1690 | | |
1691 | | // from here dynamically generated |
1692 | |
|
1693 | 0 | ShowHide( pGridWin[SC_SPLIT_BOTTOMRIGHT], bShowH ); |
1694 | 0 | ShowHide( pGridWin[SC_SPLIT_TOPLEFT], bShowV ); |
1695 | 0 | ShowHide( pGridWin[SC_SPLIT_TOPRIGHT], bShowH && bShowV ); |
1696 | |
|
1697 | 0 | ShowHide( pColOutline[SC_SPLIT_LEFT], bHOutline ); |
1698 | 0 | ShowHide( pColOutline[SC_SPLIT_RIGHT], bShowH && bHOutline ); |
1699 | |
|
1700 | 0 | ShowHide( pRowOutline[SC_SPLIT_BOTTOM], bVOutline ); |
1701 | 0 | ShowHide( pRowOutline[SC_SPLIT_TOP], bShowV && bVOutline ); |
1702 | |
|
1703 | 0 | ShowHide( pColBar[SC_SPLIT_RIGHT], bShowH && bHeader ); |
1704 | 0 | ShowHide( pRowBar[SC_SPLIT_TOP], bShowV && bHeader ); |
1705 | | |
1706 | | //! register new Gridwindows |
1707 | 0 | } |
1708 | | |
1709 | | bool ScTabView::UpdateVisibleRange() |
1710 | 0 | { |
1711 | 0 | bool bChanged = false; |
1712 | 0 | for (VclPtr<ScGridWindow> & pWin : pGridWin) |
1713 | 0 | { |
1714 | 0 | if (!pWin || !pWin->IsVisible()) |
1715 | 0 | continue; |
1716 | | |
1717 | 0 | if (pWin->UpdateVisibleRange()) |
1718 | 0 | bChanged = true; |
1719 | 0 | } |
1720 | |
|
1721 | 0 | return bChanged; |
1722 | 0 | } |
1723 | | |
1724 | | // --- Splitter -------------------------------------------------------- |
1725 | | |
1726 | | IMPL_LINK( ScTabView, SplitHdl, Splitter*, pSplitter, void ) |
1727 | 0 | { |
1728 | 0 | if ( pSplitter == pHSplitter ) |
1729 | 0 | DoHSplit( pHSplitter->GetSplitPosPixel() ); |
1730 | 0 | else |
1731 | 0 | DoVSplit( pVSplitter->GetSplitPosPixel() ); |
1732 | |
|
1733 | 0 | if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX || aViewData.GetVSplitMode() == SC_SPLIT_FIX ) |
1734 | 0 | FreezeSplitters( true ); |
1735 | |
|
1736 | 0 | DoResize( aBorderPos, aFrameSize ); |
1737 | 0 | } |
1738 | | |
1739 | | void ScTabView::DoHSplit(tools::Long nSplitPos) |
1740 | 0 | { |
1741 | | // nSplitPos is the real pixel position on the frame window, |
1742 | | // mirroring for RTL has to be done here. |
1743 | |
|
1744 | 0 | bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.CurrentTabForData() ); |
1745 | 0 | if ( bLayoutRTL ) |
1746 | 0 | nSplitPos = pFrameWin->GetOutputSizePixel().Width() - nSplitPos - 1; |
1747 | |
|
1748 | 0 | tools::Long nMinPos; |
1749 | 0 | tools::Long nMaxPos; |
1750 | |
|
1751 | 0 | nMinPos = SPLIT_MARGIN; |
1752 | 0 | if ( pRowBar[SC_SPLIT_BOTTOM] && pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width() >= nMinPos ) |
1753 | 0 | nMinPos = pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width() + 1; |
1754 | 0 | nMaxPos = aFrameSize.Width() - SPLIT_MARGIN; |
1755 | |
|
1756 | 0 | ScSplitMode aOldMode = aViewData.GetHSplitMode(); |
1757 | 0 | ScSplitMode aNewMode = SC_SPLIT_NORMAL; |
1758 | |
|
1759 | 0 | aViewData.SetHSplitPos( nSplitPos ); |
1760 | 0 | if ( nSplitPos < nMinPos || nSplitPos > nMaxPos ) |
1761 | 0 | aNewMode = SC_SPLIT_NONE; |
1762 | |
|
1763 | 0 | aViewData.SetHSplitMode( aNewMode ); |
1764 | |
|
1765 | 0 | if ( aNewMode == aOldMode ) |
1766 | 0 | return; |
1767 | | |
1768 | 0 | UpdateShow(); // before ActivatePart !! |
1769 | |
|
1770 | 0 | if ( aNewMode == SC_SPLIT_NONE ) |
1771 | 0 | { |
1772 | 0 | if (aViewData.GetActivePart() == SC_SPLIT_TOPRIGHT) |
1773 | 0 | ActivatePart( SC_SPLIT_TOPLEFT ); |
1774 | 0 | if (aViewData.GetActivePart() == SC_SPLIT_BOTTOMRIGHT) |
1775 | 0 | ActivatePart( SC_SPLIT_BOTTOMLEFT ); |
1776 | 0 | } |
1777 | 0 | else |
1778 | 0 | { |
1779 | 0 | SCCOL nOldDelta = aViewData.GetPosX( SC_SPLIT_LEFT ); |
1780 | 0 | tools::Long nLeftWidth = nSplitPos - pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width(); |
1781 | 0 | if ( nLeftWidth < 0 ) nLeftWidth = 0; |
1782 | 0 | SCCOL nNewDelta = nOldDelta + aViewData.CellsAtX( nOldDelta, 1, SC_SPLIT_LEFT, nLeftWidth ); |
1783 | |
|
1784 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1785 | 0 | if ( nNewDelta > rDoc.MaxCol() ) |
1786 | 0 | nNewDelta = rDoc.MaxCol(); |
1787 | 0 | aViewData.SetPosX( SC_SPLIT_RIGHT, nNewDelta ); |
1788 | 0 | if ( nNewDelta > aViewData.GetCurX() ) |
1789 | 0 | ActivatePart( (WhichV(aViewData.GetActivePart()) == SC_SPLIT_BOTTOM) ? |
1790 | 0 | SC_SPLIT_BOTTOMLEFT : SC_SPLIT_TOPLEFT ); |
1791 | 0 | else |
1792 | 0 | ActivatePart( (WhichV(aViewData.GetActivePart()) == SC_SPLIT_BOTTOM) ? |
1793 | 0 | SC_SPLIT_BOTTOMRIGHT : SC_SPLIT_TOPRIGHT ); |
1794 | 0 | } |
1795 | | |
1796 | | // Form Layer needs to know the visible part of all windows |
1797 | | // that is why MapMode must already be correct here |
1798 | 0 | SyncGridWindowMapModeFromDrawMapMode(); |
1799 | 0 | SetNewVisArea(); |
1800 | |
|
1801 | 0 | PaintGrid(); |
1802 | 0 | PaintTop(); |
1803 | |
|
1804 | 0 | InvalidateSplit(); |
1805 | 0 | } |
1806 | | |
1807 | | void ScTabView::DoVSplit(tools::Long nSplitPos) |
1808 | 0 | { |
1809 | 0 | tools::Long nMinPos; |
1810 | 0 | tools::Long nMaxPos; |
1811 | 0 | SCROW nOldDelta; |
1812 | |
|
1813 | 0 | nMinPos = SPLIT_MARGIN; |
1814 | 0 | if ( pColBar[SC_SPLIT_LEFT] && pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height() >= nMinPos ) |
1815 | 0 | nMinPos = pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height() + 1; |
1816 | 0 | nMaxPos = aFrameSize.Height() - SPLIT_MARGIN; |
1817 | |
|
1818 | 0 | ScSplitMode aOldMode = aViewData.GetVSplitMode(); |
1819 | 0 | ScSplitMode aNewMode = SC_SPLIT_NORMAL; |
1820 | |
|
1821 | 0 | aViewData.SetVSplitPos( nSplitPos ); |
1822 | 0 | if ( nSplitPos < nMinPos || nSplitPos > nMaxPos ) |
1823 | 0 | aNewMode = SC_SPLIT_NONE; |
1824 | |
|
1825 | 0 | aViewData.SetVSplitMode( aNewMode ); |
1826 | |
|
1827 | 0 | if ( aNewMode == aOldMode ) |
1828 | 0 | return; |
1829 | | |
1830 | 0 | UpdateShow(); // before ActivatePart !! |
1831 | |
|
1832 | 0 | if ( aNewMode == SC_SPLIT_NONE ) |
1833 | 0 | { |
1834 | 0 | nOldDelta = aViewData.GetPosY( SC_SPLIT_TOP ); |
1835 | 0 | aViewData.SetPosY( SC_SPLIT_BOTTOM, nOldDelta ); |
1836 | |
|
1837 | 0 | if (aViewData.GetActivePart() == SC_SPLIT_TOPLEFT) |
1838 | 0 | ActivatePart( SC_SPLIT_BOTTOMLEFT ); |
1839 | 0 | if (aViewData.GetActivePart() == SC_SPLIT_TOPRIGHT) |
1840 | 0 | ActivatePart( SC_SPLIT_BOTTOMRIGHT ); |
1841 | 0 | } |
1842 | 0 | else |
1843 | 0 | { |
1844 | 0 | if ( aOldMode == SC_SPLIT_NONE ) |
1845 | 0 | nOldDelta = aViewData.GetPosY( SC_SPLIT_BOTTOM ); |
1846 | 0 | else |
1847 | 0 | nOldDelta = aViewData.GetPosY( SC_SPLIT_TOP ); |
1848 | |
|
1849 | 0 | aViewData.SetPosY( SC_SPLIT_TOP, nOldDelta ); |
1850 | 0 | tools::Long nTopHeight = nSplitPos - pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height(); |
1851 | 0 | if ( nTopHeight < 0 ) nTopHeight = 0; |
1852 | 0 | SCROW nNewDelta = nOldDelta + aViewData.CellsAtY( nOldDelta, 1, SC_SPLIT_TOP, nTopHeight ); |
1853 | |
|
1854 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1855 | 0 | if ( nNewDelta > rDoc.MaxRow() ) |
1856 | 0 | nNewDelta = rDoc.MaxRow(); |
1857 | 0 | aViewData.SetPosY( SC_SPLIT_BOTTOM, nNewDelta ); |
1858 | 0 | if ( nNewDelta > aViewData.GetCurY() ) |
1859 | 0 | ActivatePart( (WhichH(aViewData.GetActivePart()) == SC_SPLIT_LEFT) ? |
1860 | 0 | SC_SPLIT_TOPLEFT : SC_SPLIT_TOPRIGHT ); |
1861 | 0 | else |
1862 | 0 | ActivatePart( (WhichH(aViewData.GetActivePart()) == SC_SPLIT_LEFT) ? |
1863 | 0 | SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT ); |
1864 | 0 | } |
1865 | | |
1866 | | // Form Layer needs to know the visible part of all windows |
1867 | | // that is why MapMode must already be correct here |
1868 | 0 | SyncGridWindowMapModeFromDrawMapMode(); |
1869 | 0 | SetNewVisArea(); |
1870 | |
|
1871 | 0 | PaintGrid(); |
1872 | 0 | PaintLeft(); |
1873 | |
|
1874 | 0 | InvalidateSplit(); |
1875 | 0 | } |
1876 | | |
1877 | | Point ScTabView::GetInsertPos() const |
1878 | 0 | { |
1879 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1880 | 0 | SCCOL nCol = aViewData.GetCurX(); |
1881 | 0 | SCROW nRow = aViewData.GetCurY(); |
1882 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1883 | 0 | tools::Long nPosX = 0; |
1884 | 0 | for (SCCOL i=0; i<nCol; i++) |
1885 | 0 | nPosX += rDoc.GetColWidth(i,nTab); |
1886 | 0 | nPosX = o3tl::convert(nPosX, o3tl::Length::twip, o3tl::Length::mm100); |
1887 | 0 | if ( rDoc.IsNegativePage( nTab ) ) |
1888 | 0 | nPosX = -nPosX; |
1889 | 0 | tools::Long nPosY = rDoc.GetRowHeight( 0, nRow-1, nTab); |
1890 | 0 | nPosY = o3tl::convert(nPosY, o3tl::Length::twip, o3tl::Length::mm100); |
1891 | 0 | return Point(nPosX,nPosY); |
1892 | 0 | } |
1893 | | |
1894 | | Point ScTabView::GetChartInsertPos( const Size& rSize, const ScRange& rCellRange ) |
1895 | 0 | { |
1896 | 0 | Point aInsertPos; |
1897 | 0 | const tools::Long nBorder = 100; // leave 1mm for border |
1898 | 0 | tools::Long nNeededWidth = rSize.Width() + 2 * nBorder; |
1899 | 0 | tools::Long nNeededHeight = rSize.Height() + 2 * nBorder; |
1900 | | |
1901 | | // use the active window, or lower/right if frozen (as in CalcZoom) |
1902 | 0 | ScSplitPos eUsedPart = aViewData.GetActivePart(); |
1903 | 0 | if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX ) |
1904 | 0 | eUsedPart = (WhichV(eUsedPart)==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT; |
1905 | 0 | if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX ) |
1906 | 0 | eUsedPart = (WhichH(eUsedPart)==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT; |
1907 | |
|
1908 | 0 | ScGridWindow* pWin = pGridWin[eUsedPart].get(); |
1909 | 0 | OSL_ENSURE( pWin, "Window not found" ); |
1910 | 0 | if (pWin) |
1911 | 0 | { |
1912 | 0 | ActivatePart( eUsedPart ); |
1913 | | |
1914 | | // get the visible rectangle in logic units |
1915 | 0 | bool bLOKActive = comphelper::LibreOfficeKit::isActive(); |
1916 | 0 | MapMode aDrawMode = pWin->GetDrawMapMode(); |
1917 | 0 | tools::Rectangle aVisible( |
1918 | 0 | bLOKActive ? |
1919 | 0 | OutputDevice::LogicToLogic( aViewData.getLOKVisibleArea(), MapMode(MapUnit::MapTwip), MapMode(MapUnit::Map100thMM) ) |
1920 | 0 | : pWin->PixelToLogic( tools::Rectangle( Point(0,0), pWin->GetOutputSizePixel() ), aDrawMode ) ); |
1921 | |
|
1922 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
1923 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
1924 | 0 | bool bLayoutRTL = rDoc.IsLayoutRTL( nTab ); |
1925 | 0 | tools::Long nLayoutSign = bLayoutRTL ? -1 : 1; |
1926 | |
|
1927 | 0 | tools::Long nDocX = o3tl::convert(rDoc.GetColOffset(rDoc.MaxCol() + 1, nTab), o3tl::Length::twip, o3tl::Length::mm100) * nLayoutSign; |
1928 | 0 | tools::Long nDocY = o3tl::convert(rDoc.GetRowOffset( rDoc.MaxRow() + 1, nTab ), o3tl::Length::twip, o3tl::Length::mm100); |
1929 | |
|
1930 | 0 | if ( aVisible.Left() * nLayoutSign > nDocX * nLayoutSign ) |
1931 | 0 | aVisible.SetLeft( nDocX ); |
1932 | 0 | if ( aVisible.Right() * nLayoutSign > nDocX * nLayoutSign ) |
1933 | 0 | aVisible.SetRight( nDocX ); |
1934 | 0 | if ( aVisible.Top() > nDocY ) |
1935 | 0 | aVisible.SetTop( nDocY ); |
1936 | 0 | if ( aVisible.Bottom() > nDocY ) |
1937 | 0 | aVisible.SetBottom( nDocY ); |
1938 | | |
1939 | | // get the logic position of the selection |
1940 | |
|
1941 | 0 | tools::Rectangle aSelection = rDoc.GetMMRect( rCellRange.aStart.Col(), rCellRange.aStart.Row(), |
1942 | 0 | rCellRange.aEnd.Col(), rCellRange.aEnd.Row(), nTab ); |
1943 | |
|
1944 | 0 | if (bLOKActive && bLayoutRTL) |
1945 | 0 | { |
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 | 0 | aVisible = tools::Rectangle(-aVisible.Right(), aVisible.Top(), -aVisible.Left(), aVisible.Bottom()); |
1950 | 0 | } |
1951 | |
|
1952 | 0 | tools::Long nLeftSpace = aSelection.Left() - aVisible.Left(); |
1953 | 0 | tools::Long nRightSpace = aVisible.Right() - aSelection.Right(); |
1954 | 0 | tools::Long nTopSpace = aSelection.Top() - aVisible.Top(); |
1955 | 0 | tools::Long nBottomSpace = aVisible.Bottom() - aSelection.Bottom(); |
1956 | |
|
1957 | 0 | bool bFitLeft = ( nLeftSpace >= nNeededWidth ); |
1958 | 0 | bool bFitRight = ( nRightSpace >= nNeededWidth ); |
1959 | |
|
1960 | 0 | if ( bFitLeft || bFitRight ) |
1961 | 0 | { |
1962 | | // first preference: completely left or right of the selection |
1963 | | |
1964 | | // if both fit, prefer left in RTL mode, right otherwise |
1965 | 0 | bool bPutLeft = bFitLeft && ( bLayoutRTL || !bFitRight ); |
1966 | |
|
1967 | 0 | if ( bPutLeft ) |
1968 | 0 | aInsertPos.setX( aSelection.Left() - nNeededWidth ); |
1969 | 0 | else |
1970 | 0 | aInsertPos.setX( aSelection.Right() + 1 ); |
1971 | | |
1972 | | // align with top of selection (is moved again if it doesn't fit) |
1973 | 0 | aInsertPos.setY( std::max( aSelection.Top(), aVisible.Top() ) ); |
1974 | 0 | } |
1975 | 0 | else if ( nTopSpace >= nNeededHeight || nBottomSpace >= nNeededHeight ) |
1976 | 0 | { |
1977 | | // second preference: completely above or below the selection |
1978 | 0 | if ( nBottomSpace > nNeededHeight ) // bottom is preferred |
1979 | 0 | aInsertPos.setY( aSelection.Bottom() + 1 ); |
1980 | 0 | else |
1981 | 0 | aInsertPos.setY( aSelection.Top() - nNeededHeight ); |
1982 | | |
1983 | | // align with (logic) left edge of selection (moved again if it doesn't fit) |
1984 | 0 | if ( bLayoutRTL ) |
1985 | 0 | aInsertPos.setX( std::min( aSelection.Right(), aVisible.Right() ) - nNeededWidth + 1 ); |
1986 | 0 | else |
1987 | 0 | aInsertPos.setX( std::max( aSelection.Left(), aVisible.Left() ) ); |
1988 | 0 | } |
1989 | 0 | else |
1990 | 0 | { |
1991 | | // place to the (logic) right of the selection and move so it fits |
1992 | |
|
1993 | 0 | if ( bLayoutRTL ) |
1994 | 0 | aInsertPos.setX( aSelection.Left() - nNeededWidth ); |
1995 | 0 | else |
1996 | 0 | aInsertPos.setX( aSelection.Right() + 1 ); |
1997 | 0 | aInsertPos.setY( std::max( aSelection.Top(), aVisible.Top() ) ); |
1998 | 0 | } |
1999 | | |
2000 | | // move the position if the object doesn't fit in the screen |
2001 | |
|
2002 | 0 | tools::Rectangle aCompareRect( aInsertPos, Size( nNeededWidth, nNeededHeight ) ); |
2003 | 0 | if ( aCompareRect.Right() > aVisible.Right() ) |
2004 | 0 | aInsertPos.AdjustX( -(aCompareRect.Right() - aVisible.Right()) ); |
2005 | 0 | if ( aCompareRect.Bottom() > aVisible.Bottom() ) |
2006 | 0 | aInsertPos.AdjustY( -(aCompareRect.Bottom() - aVisible.Bottom()) ); |
2007 | |
|
2008 | 0 | if ( aInsertPos.X() < aVisible.Left() ) |
2009 | 0 | aInsertPos.setX( aVisible.Left() ); |
2010 | 0 | if ( aInsertPos.Y() < aVisible.Top() ) |
2011 | 0 | aInsertPos.setY( aVisible.Top() ); |
2012 | | |
2013 | | // nNeededWidth / nNeededHeight includes all borders - move aInsertPos to the |
2014 | | // object position, inside the border |
2015 | |
|
2016 | 0 | aInsertPos.AdjustX(nBorder ); |
2017 | 0 | aInsertPos.AdjustY(nBorder ); |
2018 | 0 | } |
2019 | 0 | return aInsertPos; |
2020 | 0 | } |
2021 | | |
2022 | | Point ScTabView::GetChartDialogPos( const Size& rDialogSize, const tools::Rectangle& rLogicChart ) |
2023 | 0 | { |
2024 | | // rDialogSize must be in pixels, rLogicChart in 1/100 mm. Return value is in pixels. |
2025 | |
|
2026 | 0 | Point aRet; |
2027 | | |
2028 | | // use the active window, or lower/right if frozen (as in CalcZoom) |
2029 | 0 | ScSplitPos eUsedPart = aViewData.GetActivePart(); |
2030 | 0 | if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX ) |
2031 | 0 | eUsedPart = (WhichV(eUsedPart)==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT; |
2032 | 0 | if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX ) |
2033 | 0 | eUsedPart = (WhichH(eUsedPart)==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT; |
2034 | |
|
2035 | 0 | ScGridWindow* pWin = pGridWin[eUsedPart].get(); |
2036 | 0 | OSL_ENSURE( pWin, "Window not found" ); |
2037 | 0 | if (pWin) |
2038 | 0 | { |
2039 | 0 | MapMode aDrawMode = pWin->GetDrawMapMode(); |
2040 | 0 | tools::Rectangle aObjPixel = pWin->LogicToPixel( rLogicChart, aDrawMode ); |
2041 | 0 | AbsoluteScreenPixelRectangle aObjAbs( pWin->OutputToAbsoluteScreenPixel( aObjPixel.TopLeft() ), |
2042 | 0 | pWin->OutputToAbsoluteScreenPixel( aObjPixel.BottomRight() ) ); |
2043 | |
|
2044 | 0 | AbsoluteScreenPixelRectangle aDesktop = pWin->GetDesktopRectPixel(); |
2045 | 0 | Size aSpace = pWin->LogicToPixel( Size(8, 12), MapMode(MapUnit::MapAppFont)); |
2046 | |
|
2047 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
2048 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
2049 | 0 | bool bLayoutRTL = rDoc.IsLayoutRTL( nTab ); |
2050 | |
|
2051 | 0 | bool bCenterHor = false; |
2052 | |
|
2053 | 0 | if ( aDesktop.Bottom() - aObjAbs.Bottom() >= rDialogSize.Height() + aSpace.Height() ) |
2054 | 0 | { |
2055 | | // first preference: below the chart |
2056 | |
|
2057 | 0 | aRet.setY( aObjAbs.Bottom() + aSpace.Height() ); |
2058 | 0 | bCenterHor = true; |
2059 | 0 | } |
2060 | 0 | else if ( aObjAbs.Top() - aDesktop.Top() >= rDialogSize.Height() + aSpace.Height() ) |
2061 | 0 | { |
2062 | | // second preference: above the chart |
2063 | |
|
2064 | 0 | aRet.setY( aObjAbs.Top() - rDialogSize.Height() - aSpace.Height() ); |
2065 | 0 | bCenterHor = true; |
2066 | 0 | } |
2067 | 0 | else |
2068 | 0 | { |
2069 | 0 | bool bFitLeft = ( aObjAbs.Left() - aDesktop.Left() >= rDialogSize.Width() + aSpace.Width() ); |
2070 | 0 | bool bFitRight = ( aDesktop.Right() - aObjAbs.Right() >= rDialogSize.Width() + aSpace.Width() ); |
2071 | |
|
2072 | 0 | if ( bFitLeft || bFitRight ) |
2073 | 0 | { |
2074 | | // if both fit, prefer right in RTL mode, left otherwise |
2075 | 0 | bool bPutRight = bFitRight && ( bLayoutRTL || !bFitLeft ); |
2076 | 0 | if ( bPutRight ) |
2077 | 0 | aRet.setX( aObjAbs.Right() + aSpace.Width() ); |
2078 | 0 | else |
2079 | 0 | aRet.setX( aObjAbs.Left() - rDialogSize.Width() - aSpace.Width() ); |
2080 | | |
2081 | | // center vertically |
2082 | 0 | aRet.setY( aObjAbs.Top() + ( aObjAbs.GetHeight() - rDialogSize.Height() ) / 2 ); |
2083 | 0 | } |
2084 | 0 | else |
2085 | 0 | { |
2086 | | // doesn't fit on any edge - put at the bottom of the screen |
2087 | 0 | aRet.setY( aDesktop.Bottom() - rDialogSize.Height() ); |
2088 | 0 | bCenterHor = true; |
2089 | 0 | } |
2090 | 0 | } |
2091 | 0 | if ( bCenterHor ) |
2092 | 0 | aRet.setX( aObjAbs.Left() + ( aObjAbs.GetWidth() - rDialogSize.Width() ) / 2 ); |
2093 | | |
2094 | | // limit to screen (centering might lead to invalid positions) |
2095 | 0 | if ( aRet.X() + rDialogSize.Width() - 1 > aDesktop.Right() ) |
2096 | 0 | aRet.setX( aDesktop.Right() - rDialogSize.Width() + 1 ); |
2097 | 0 | if ( aRet.X() < aDesktop.Left() ) |
2098 | 0 | aRet.setX( aDesktop.Left() ); |
2099 | 0 | if ( aRet.Y() + rDialogSize.Height() - 1 > aDesktop.Bottom() ) |
2100 | 0 | aRet.setY( aDesktop.Bottom() - rDialogSize.Height() + 1 ); |
2101 | 0 | if ( aRet.Y() < aDesktop.Top() ) |
2102 | 0 | aRet.setY( aDesktop.Top() ); |
2103 | 0 | } |
2104 | |
|
2105 | 0 | return aRet; |
2106 | 0 | } |
2107 | | |
2108 | | void ScTabView::LockModifiers( sal_uInt16 nModifiers ) |
2109 | 0 | { |
2110 | 0 | pSelEngine->LockModifiers( nModifiers ); |
2111 | 0 | pHdrSelEng->LockModifiers( nModifiers ); |
2112 | 0 | } |
2113 | | |
2114 | | sal_uInt16 ScTabView::GetLockedModifiers() const |
2115 | 0 | { |
2116 | 0 | return pSelEngine->GetLockedModifiers(); |
2117 | 0 | } |
2118 | | |
2119 | | Point ScTabView::GetMousePosPixel() |
2120 | 0 | { |
2121 | 0 | Point aPos; |
2122 | 0 | ScGridWindow* pWin = GetActiveWin(); |
2123 | |
|
2124 | 0 | if ( pWin ) |
2125 | 0 | aPos = pWin->GetMousePosPixel(); |
2126 | |
|
2127 | 0 | return aPos; |
2128 | 0 | } |
2129 | | |
2130 | | void ScTabView::FreezeSplitters( bool bFreeze, SplitMethod eSplitMethod, SCCOLROW nFreezeIndex) |
2131 | 0 | { |
2132 | 0 | if ((eSplitMethod == SC_SPLIT_METHOD_COL || eSplitMethod == SC_SPLIT_METHOD_ROW) && nFreezeIndex < 0) |
2133 | 0 | nFreezeIndex = 0; |
2134 | |
|
2135 | 0 | ScSplitMode eOldH = aViewData.GetHSplitMode(); |
2136 | 0 | ScSplitMode eOldV = aViewData.GetVSplitMode(); |
2137 | |
|
2138 | 0 | ScSplitPos ePos = SC_SPLIT_BOTTOMLEFT; |
2139 | 0 | if ( eOldV != SC_SPLIT_NONE ) |
2140 | 0 | ePos = SC_SPLIT_TOPLEFT; |
2141 | 0 | vcl::Window* pWin = pGridWin[ePos]; |
2142 | |
|
2143 | 0 | bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.CurrentTabForData() ); |
2144 | 0 | bool bUpdateFix = false; |
2145 | |
|
2146 | 0 | if ( bFreeze ) |
2147 | 0 | { |
2148 | 0 | Point aWinStart = pWin->GetPosPixel(); |
2149 | 0 | aViewData.GetDocShell()->SetDocumentModified(); |
2150 | |
|
2151 | 0 | Point aSplit; |
2152 | 0 | SCCOL nPosX = 1; |
2153 | 0 | SCROW nPosY = 1; |
2154 | 0 | if (eOldV != SC_SPLIT_NONE || eOldH != SC_SPLIT_NONE) |
2155 | 0 | { |
2156 | 0 | if ( eOldV != SC_SPLIT_NONE && (eSplitMethod == SC_SPLIT_METHOD_ROW || eSplitMethod == SC_SPLIT_METHOD_CURSOR)) |
2157 | 0 | aSplit.setY( aViewData.GetVSplitPos() - aWinStart.Y() ); |
2158 | |
|
2159 | 0 | if ( eOldH != SC_SPLIT_NONE && (eSplitMethod == SC_SPLIT_METHOD_COL || eSplitMethod == SC_SPLIT_METHOD_CURSOR)) |
2160 | 0 | { |
2161 | 0 | tools::Long nSplitPos = aViewData.GetHSplitPos(); |
2162 | 0 | if ( bLayoutRTL ) |
2163 | 0 | nSplitPos = pFrameWin->GetOutputSizePixel().Width() - nSplitPos - 1; |
2164 | 0 | aSplit.setX( nSplitPos - aWinStart.X() ); |
2165 | 0 | } |
2166 | |
|
2167 | 0 | aViewData.GetPosFromPixel( aSplit.X(), aSplit.Y(), ePos, nPosX, nPosY ); |
2168 | 0 | bool bLeft; |
2169 | 0 | bool bTop; |
2170 | 0 | aViewData.GetMouseQuadrant( aSplit, ePos, nPosX, nPosY, bLeft, bTop ); |
2171 | 0 | if (eSplitMethod == SC_SPLIT_METHOD_COL) |
2172 | 0 | nPosX = static_cast<SCCOL>(nFreezeIndex); |
2173 | 0 | else if (!bLeft) |
2174 | 0 | ++nPosX; |
2175 | 0 | if (eSplitMethod == SC_SPLIT_METHOD_ROW) |
2176 | 0 | nPosY = static_cast<SCROW>(nFreezeIndex); |
2177 | 0 | else if (!bTop) |
2178 | 0 | ++nPosY; |
2179 | 0 | } |
2180 | 0 | else |
2181 | 0 | { |
2182 | 0 | switch(eSplitMethod) |
2183 | 0 | { |
2184 | 0 | case SC_SPLIT_METHOD_ROW: |
2185 | 0 | { |
2186 | 0 | nPosX = 0; |
2187 | 0 | nPosY = static_cast<SCROW>(nFreezeIndex); |
2188 | 0 | } |
2189 | 0 | break; |
2190 | 0 | case SC_SPLIT_METHOD_COL: |
2191 | 0 | { |
2192 | 0 | nPosX = static_cast<SCCOL>(nFreezeIndex); |
2193 | 0 | nPosY = 0; |
2194 | 0 | } |
2195 | 0 | break; |
2196 | 0 | case SC_SPLIT_METHOD_CURSOR: |
2197 | 0 | { |
2198 | 0 | nPosX = aViewData.GetCurX(); |
2199 | 0 | nPosY = aViewData.GetCurY(); |
2200 | 0 | } |
2201 | 0 | break; |
2202 | 0 | } |
2203 | 0 | } |
2204 | | |
2205 | 0 | SCROW nTopPos = aViewData.GetPosY(SC_SPLIT_BOTTOM); |
2206 | 0 | SCROW nBottomPos = nPosY; |
2207 | 0 | SCCOL nLeftPos = aViewData.GetPosX(SC_SPLIT_LEFT); |
2208 | 0 | SCCOL nRightPos = nPosX; |
2209 | |
|
2210 | 0 | if (eSplitMethod == SC_SPLIT_METHOD_ROW || eSplitMethod == SC_SPLIT_METHOD_CURSOR) |
2211 | 0 | { |
2212 | 0 | if (eOldV != SC_SPLIT_NONE) |
2213 | 0 | { |
2214 | 0 | nTopPos = aViewData.GetPosY(SC_SPLIT_TOP); |
2215 | 0 | nBottomPos = std::max(aViewData.GetPosY(SC_SPLIT_BOTTOM), nBottomPos); |
2216 | 0 | } |
2217 | 0 | aSplit = aViewData.GetScrPos(nPosX, nPosY, ePos, true); |
2218 | 0 | if (aSplit.Y() > 0) |
2219 | 0 | { |
2220 | 0 | aViewData.SetVSplitMode(SC_SPLIT_FIX); |
2221 | 0 | aViewData.SetVSplitPos(aSplit.Y() + aWinStart.Y()); |
2222 | 0 | aViewData.SetFixPosY(nPosY); |
2223 | |
|
2224 | 0 | aViewData.SetPosY(SC_SPLIT_TOP, nTopPos); |
2225 | 0 | aViewData.SetPosY(SC_SPLIT_BOTTOM, nBottomPos); |
2226 | 0 | } |
2227 | 0 | else if (nPosY == 1 && eSplitMethod == SC_SPLIT_METHOD_ROW) |
2228 | 0 | { |
2229 | | // Freeze first row, but row 1 is not visible on screen now == special handling |
2230 | 0 | aViewData.SetVSplitMode(SC_SPLIT_FIX); |
2231 | 0 | aViewData.SetFixPosY(nPosY); |
2232 | |
|
2233 | 0 | aViewData.SetPosY(SC_SPLIT_TOP, 0); |
2234 | 0 | bUpdateFix = true; |
2235 | 0 | } |
2236 | 0 | else |
2237 | 0 | aViewData.SetVSplitMode(SC_SPLIT_NONE); |
2238 | 0 | } |
2239 | |
|
2240 | 0 | if (eSplitMethod == SC_SPLIT_METHOD_COL || eSplitMethod == SC_SPLIT_METHOD_CURSOR) |
2241 | 0 | { |
2242 | 0 | if (eOldH != SC_SPLIT_NONE) |
2243 | 0 | { |
2244 | 0 | if (aViewData.GetPosX(SC_SPLIT_RIGHT) > nRightPos) |
2245 | 0 | nRightPos = aViewData.GetPosX(SC_SPLIT_RIGHT); |
2246 | 0 | } |
2247 | 0 | aSplit = aViewData.GetScrPos( nPosX, nPosY, ePos, true ); |
2248 | 0 | if (nPosX > aViewData.GetPosX(SC_SPLIT_LEFT)) // (aSplit.X() > 0) doesn't work for RTL |
2249 | 0 | { |
2250 | 0 | tools::Long nSplitPos = aSplit.X() + aWinStart.X(); |
2251 | 0 | if ( bLayoutRTL ) |
2252 | 0 | nSplitPos = pFrameWin->GetOutputSizePixel().Width() - nSplitPos - 1; |
2253 | |
|
2254 | 0 | aViewData.SetHSplitMode( SC_SPLIT_FIX ); |
2255 | 0 | aViewData.SetHSplitPos( nSplitPos ); |
2256 | 0 | aViewData.SetFixPosX( nPosX ); |
2257 | |
|
2258 | 0 | aViewData.SetPosX(SC_SPLIT_LEFT, nLeftPos); |
2259 | 0 | aViewData.SetPosX(SC_SPLIT_RIGHT, nRightPos); |
2260 | 0 | } |
2261 | 0 | else if (nPosX == 1 && eSplitMethod == SC_SPLIT_METHOD_COL) |
2262 | 0 | { |
2263 | | // Freeze first column, but col A is not visible on screen now == special handling |
2264 | 0 | aViewData.SetHSplitMode(SC_SPLIT_FIX); |
2265 | 0 | aViewData.SetFixPosX(nPosX); |
2266 | |
|
2267 | 0 | aViewData.SetPosX(SC_SPLIT_RIGHT, aViewData.GetPosX(SC_SPLIT_LEFT)); |
2268 | 0 | aViewData.SetPosX(SC_SPLIT_LEFT, 0); |
2269 | 0 | bUpdateFix = true; |
2270 | 0 | } |
2271 | 0 | else |
2272 | 0 | aViewData.SetHSplitMode( SC_SPLIT_NONE ); |
2273 | 0 | } |
2274 | 0 | } |
2275 | 0 | else // unfreeze |
2276 | 0 | { |
2277 | 0 | if ( eOldH == SC_SPLIT_FIX ) |
2278 | 0 | aViewData.SetHSplitMode( SC_SPLIT_NORMAL ); |
2279 | 0 | if ( eOldV == SC_SPLIT_FIX ) |
2280 | 0 | aViewData.SetVSplitMode( SC_SPLIT_NORMAL ); |
2281 | 0 | } |
2282 | | |
2283 | | // Form Layer needs to know the visible part of all windows |
2284 | | // that is why MapMode must already be correct here |
2285 | 0 | SyncGridWindowMapModeFromDrawMapMode(); |
2286 | 0 | SetNewVisArea(); |
2287 | |
|
2288 | 0 | RepeatResize(bUpdateFix); |
2289 | |
|
2290 | 0 | UpdateShow(); |
2291 | 0 | PaintLeft(); |
2292 | 0 | PaintTop(); |
2293 | 0 | PaintGrid(); |
2294 | | |
2295 | | // SC_FOLLOW_NONE: only update active part |
2296 | 0 | AlignToCursor( aViewData.GetCurX(), aViewData.GetCurY(), SC_FOLLOW_NONE ); |
2297 | 0 | UpdateAutoFillMark(); |
2298 | |
|
2299 | 0 | InvalidateSplit(); |
2300 | 0 | } |
2301 | | |
2302 | | void ScTabView::RemoveSplit() |
2303 | 0 | { |
2304 | 0 | if (aViewData.GetHSplitMode() == SC_SPLIT_FIX || aViewData.GetVSplitMode() == SC_SPLIT_FIX) |
2305 | 0 | aViewData.GetDocShell()->SetDocumentModified(); |
2306 | 0 | DoHSplit( 0 ); |
2307 | 0 | DoVSplit( 0 ); |
2308 | 0 | RepeatResize(); |
2309 | 0 | } |
2310 | | |
2311 | | void ScTabView::SplitAtCursor() |
2312 | 0 | { |
2313 | 0 | ScSplitPos ePos = SC_SPLIT_BOTTOMLEFT; |
2314 | 0 | if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE ) |
2315 | 0 | ePos = SC_SPLIT_TOPLEFT; |
2316 | 0 | vcl::Window* pWin = pGridWin[ePos]; |
2317 | 0 | Point aWinStart = pWin->GetPosPixel(); |
2318 | |
|
2319 | 0 | SCCOL nPosX = aViewData.GetCurX(); |
2320 | 0 | SCROW nPosY = aViewData.GetCurY(); |
2321 | 0 | Point aSplit = aViewData.GetScrPos( nPosX, nPosY, ePos, true ); |
2322 | 0 | if ( nPosX > 0 ) |
2323 | 0 | DoHSplit( aSplit.X() + aWinStart.X() ); |
2324 | 0 | else |
2325 | 0 | DoHSplit( 0 ); |
2326 | 0 | if ( nPosY > 0 ) |
2327 | 0 | DoVSplit( aSplit.Y() + aWinStart.Y() ); |
2328 | 0 | else |
2329 | 0 | DoVSplit( 0 ); |
2330 | 0 | RepeatResize(); |
2331 | 0 | } |
2332 | | |
2333 | | void ScTabView::SplitAtPixel( const Point& rPixel ) |
2334 | 0 | { |
2335 | | // pixel is relative to the entire View, not to the first GridWin |
2336 | |
|
2337 | 0 | if ( rPixel.X() > 0 ) |
2338 | 0 | DoHSplit( rPixel.X() ); |
2339 | 0 | else |
2340 | 0 | DoHSplit( 0 ); |
2341 | 0 | if ( rPixel.Y() > 0 ) |
2342 | 0 | DoVSplit( rPixel.Y() ); |
2343 | 0 | else |
2344 | 0 | DoVSplit( 0 ); |
2345 | 0 | RepeatResize(); |
2346 | 0 | } |
2347 | | |
2348 | | void ScTabView::InvalidateSplit() |
2349 | 0 | { |
2350 | 0 | SfxBindings& rBindings = aViewData.GetBindings(); |
2351 | 0 | rBindings.Invalidate( SID_WINDOW_SPLIT ); |
2352 | 0 | rBindings.Invalidate( SID_WINDOW_FIX ); |
2353 | 0 | rBindings.Invalidate( SID_WINDOW_FIX_COL ); |
2354 | 0 | rBindings.Invalidate( SID_WINDOW_FIX_ROW ); |
2355 | |
|
2356 | 0 | pHSplitter->SetFixed( aViewData.GetHSplitMode() == SC_SPLIT_FIX ); |
2357 | 0 | pVSplitter->SetFixed( aViewData.GetVSplitMode() == SC_SPLIT_FIX ); |
2358 | 0 | } |
2359 | | |
2360 | | void ScTabView::SetNewVisArea() |
2361 | 0 | { |
2362 | | // Draw-MapMode must be set for Controls when VisAreaChanged |
2363 | | // (also when Edit-MapMode is set instead) |
2364 | 0 | MapMode aOldMode[4]; |
2365 | 0 | MapMode aDrawMode[4]; |
2366 | 0 | sal_uInt16 i; |
2367 | 0 | for (i=0; i<4; i++) |
2368 | 0 | if (pGridWin[i]) |
2369 | 0 | { |
2370 | 0 | aOldMode[i] = pGridWin[i]->GetMapMode(); |
2371 | 0 | aDrawMode[i] = pGridWin[i]->GetDrawMapMode(); |
2372 | 0 | if (aDrawMode[i] != aOldMode[i]) |
2373 | 0 | pGridWin[i]->SetMapMode(aDrawMode[i]); |
2374 | 0 | } |
2375 | |
|
2376 | 0 | vcl::Window* pActive = pGridWin[aViewData.GetActivePart()]; |
2377 | 0 | if (pActive) |
2378 | 0 | aViewData.GetViewShell()->VisAreaChanged(); |
2379 | 0 | if (pDrawView) |
2380 | 0 | pDrawView->VisAreaChanged(nullptr); // no window passed on -> for all windows |
2381 | |
|
2382 | 0 | UpdateAllOverlays(); // #i79909# with drawing MapMode set |
2383 | |
|
2384 | 0 | for (i=0; i<4; i++) |
2385 | 0 | if (pGridWin[i] && aDrawMode[i] != aOldMode[i]) |
2386 | 0 | { |
2387 | 0 | pGridWin[i]->SetMapMode(aOldMode[i]); |
2388 | 0 | } |
2389 | |
|
2390 | 0 | SfxViewFrame& rViewFrame = aViewData.GetViewShell()->GetViewFrame(); |
2391 | 0 | SfxFrame& rFrame = rViewFrame.GetFrame(); |
2392 | 0 | css::uno::Reference<css::frame::XController> xController = rFrame.GetController(); |
2393 | 0 | if (xController.is()) |
2394 | 0 | { |
2395 | 0 | ScTabViewObj* pImp = dynamic_cast<ScTabViewObj*>( xController.get() ); |
2396 | 0 | if (pImp) |
2397 | 0 | pImp->VisAreaChanged(); |
2398 | 0 | } |
2399 | |
|
2400 | 0 | if (GetViewData().HasEditView(GetViewData().GetActivePart())) |
2401 | 0 | { |
2402 | 0 | EditView *pEditView = GetViewData().GetEditView(GetViewData().GetActivePart()); |
2403 | 0 | vcl::Cursor *pInPlaceCrsr = pEditView->GetCursor(); |
2404 | 0 | bool bInPlaceVisCursor = pInPlaceCrsr && pInPlaceCrsr->IsVisible(); |
2405 | |
|
2406 | 0 | if (bInPlaceVisCursor) |
2407 | 0 | pInPlaceCrsr->Hide(); |
2408 | |
|
2409 | 0 | RefeshTextEditOverlay(); |
2410 | |
|
2411 | 0 | if (bInPlaceVisCursor) |
2412 | 0 | pInPlaceCrsr->Show(); |
2413 | 0 | } |
2414 | |
|
2415 | 0 | if (aViewData.GetViewShell()->HasAccessibilityObjects()) |
2416 | 0 | aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccVisAreaChanged)); |
2417 | 0 | } |
2418 | | |
2419 | | bool ScTabView::HasPageFieldDataAtCursor() const |
2420 | 0 | { |
2421 | 0 | ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get(); |
2422 | 0 | SCCOL nCol = aViewData.GetCurX(); |
2423 | 0 | SCROW nRow = aViewData.GetCurY(); |
2424 | 0 | if (pWin) |
2425 | 0 | return pWin->GetDPFieldOrientation( nCol, nRow ) == sheet::DataPilotFieldOrientation_PAGE; |
2426 | | |
2427 | 0 | return false; |
2428 | 0 | } |
2429 | | |
2430 | | void ScTabView::StartDataSelect() |
2431 | 0 | { |
2432 | 0 | ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get(); |
2433 | 0 | SCCOL nCol = aViewData.GetCurX(); |
2434 | 0 | SCROW nRow = aViewData.GetCurY(); |
2435 | |
|
2436 | 0 | if (!pWin) |
2437 | 0 | return; |
2438 | | |
2439 | 0 | switch (pWin->GetDPFieldOrientation(nCol, nRow)) |
2440 | 0 | { |
2441 | 0 | case sheet::DataPilotFieldOrientation_PAGE: |
2442 | | // #i36598# If the cursor is on a page field's data cell, |
2443 | | // no meaningful input is possible anyway, so this function |
2444 | | // can be used to select a page field entry. |
2445 | 0 | pWin->LaunchPageFieldMenu( nCol, nRow ); |
2446 | 0 | return; |
2447 | 0 | case sheet::DataPilotFieldOrientation_COLUMN: |
2448 | 0 | case sheet::DataPilotFieldOrientation_ROW: |
2449 | 0 | pWin->LaunchDPFieldMenu( nCol, nRow ); |
2450 | 0 | return; |
2451 | 0 | default: |
2452 | 0 | ; |
2453 | 0 | } |
2454 | | |
2455 | | // Do autofilter if the current cell has autofilter button. Otherwise do |
2456 | | // a normal data select popup. |
2457 | 0 | const ScMergeFlagAttr& rAttr = |
2458 | 0 | aViewData.GetDocument().GetAttr( |
2459 | 0 | nCol, nRow, aViewData.CurrentTabForData(), ATTR_MERGE_FLAG); |
2460 | |
|
2461 | 0 | if (rAttr.HasAutoFilter()) |
2462 | 0 | pWin->LaunchAutoFilterMenu(nCol, nRow); |
2463 | 0 | else |
2464 | 0 | pWin->LaunchDataSelectMenu(nCol, nRow); |
2465 | 0 | } |
2466 | | |
2467 | | void ScTabView::EnableRefInput(bool bFlag) |
2468 | 0 | { |
2469 | 0 | aHScrollLeft->EnableInput(bFlag); |
2470 | 0 | aHScrollRight->EnableInput(bFlag); |
2471 | 0 | aVScrollBottom->EnableInput(bFlag); |
2472 | 0 | aVScrollTop->EnableInput(bFlag); |
2473 | | |
2474 | | // from here on dynamically created ones |
2475 | |
|
2476 | 0 | if(pTabControl!=nullptr) pTabControl->EnableInput(bFlag); |
2477 | |
|
2478 | 0 | for (auto& p : pGridWin) |
2479 | 0 | if (p) |
2480 | 0 | p->EnableInput(bFlag, false); |
2481 | 0 | for (auto& p : pColBar) |
2482 | 0 | if (p) |
2483 | 0 | p->EnableInput(bFlag, false); |
2484 | 0 | for (auto& p : pRowBar) |
2485 | 0 | if (p) |
2486 | 0 | p->EnableInput(bFlag, false); |
2487 | 0 | } |
2488 | | |
2489 | | void ScTabView::EnableAutoSpell( bool bEnable ) |
2490 | 0 | { |
2491 | 0 | const bool bWasEnabled = IsAutoSpell(); |
2492 | 0 | if (bEnable) |
2493 | 0 | mpSpellCheckCxt = |
2494 | 0 | std::make_shared<sc::SpellCheckContext>(aViewData.GetDocument(), |
2495 | 0 | aViewData.CurrentTabForData()); |
2496 | 0 | else |
2497 | 0 | mpSpellCheckCxt.reset(); |
2498 | |
|
2499 | 0 | for (VclPtr<ScGridWindow> & pWin : pGridWin) |
2500 | 0 | { |
2501 | 0 | if (!pWin) |
2502 | 0 | continue; |
2503 | | |
2504 | 0 | pWin->SetAutoSpellContext(mpSpellCheckCxt); |
2505 | 0 | } |
2506 | |
|
2507 | 0 | if (bWasEnabled != bEnable && comphelper::LibreOfficeKit::isActive()) |
2508 | 0 | { |
2509 | 0 | if (ScTabViewShell* pViewSh = aViewData.GetViewShell()) |
2510 | 0 | { |
2511 | 0 | ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>(pViewSh->GetCurrentDocument()); |
2512 | 0 | SfxLokHelper::notifyViewRenderState(pViewSh, pModel); |
2513 | 0 | } |
2514 | 0 | } |
2515 | 0 | } |
2516 | | |
2517 | | bool ScTabView::IsAutoSpell() const |
2518 | 0 | { |
2519 | 0 | return static_cast<bool>(mpSpellCheckCxt); |
2520 | 0 | } |
2521 | | |
2522 | | void ScTabView::ResetAutoSpell() |
2523 | 0 | { |
2524 | 0 | for (VclPtr<ScGridWindow> & pWin : pGridWin) |
2525 | 0 | { |
2526 | 0 | if (!pWin) |
2527 | 0 | continue; |
2528 | | |
2529 | 0 | pWin->ResetAutoSpell(); |
2530 | 0 | } |
2531 | 0 | } |
2532 | | |
2533 | | void ScTabView::ResetAutoSpellForContentChange() |
2534 | 0 | { |
2535 | 0 | for (VclPtr<ScGridWindow> & pWin : pGridWin) |
2536 | 0 | { |
2537 | 0 | if (!pWin) |
2538 | 0 | continue; |
2539 | | |
2540 | 0 | pWin->ResetAutoSpellForContentChange(); |
2541 | 0 | } |
2542 | 0 | } |
2543 | | |
2544 | | void ScTabView::SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const sc::MisspellRangeResult& rRangeResult ) |
2545 | 0 | { |
2546 | 0 | for (VclPtr<ScGridWindow> & pWin: pGridWin) |
2547 | 0 | { |
2548 | 0 | if (!pWin) |
2549 | 0 | continue; |
2550 | | |
2551 | 0 | pWin->SetAutoSpellData(nPosX, nPosY, rRangeResult); |
2552 | 0 | } |
2553 | 0 | } |
2554 | | |
2555 | | namespace |
2556 | | { |
2557 | | |
2558 | | tools::Long lcl_GetRowHeightPx(const ScViewData &rViewData, SCROW nRow, SCTAB nTab) |
2559 | 0 | { |
2560 | 0 | const sal_uInt16 nSize = rViewData.GetDocument().GetRowHeight(nRow, nTab); |
2561 | 0 | return ScViewData::ToPixel(nSize, rViewData.GetPPTY()); |
2562 | 0 | } |
2563 | | |
2564 | | tools::Long lcl_GetColWidthPx(const ScViewData &rViewData, SCCOL nCol, SCTAB nTab) |
2565 | 0 | { |
2566 | 0 | const sal_uInt16 nSize = rViewData.GetDocument().GetColWidth(nCol, nTab); |
2567 | 0 | return ScViewData::ToPixel(nSize, rViewData.GetPPTX()); |
2568 | 0 | } |
2569 | | |
2570 | | void lcl_getGroupIndexes(const ScOutlineArray& rArray, SCCOLROW nStart, SCCOLROW nEnd, std::vector<size_t>& rGroupIndexes) |
2571 | 0 | { |
2572 | 0 | rGroupIndexes.clear(); |
2573 | 0 | const size_t nGroupDepth = rArray.GetDepth(); |
2574 | 0 | rGroupIndexes.resize(nGroupDepth); |
2575 | | |
2576 | | // Get first group per each level |
2577 | 0 | for (size_t nLevel = 0; nLevel < nGroupDepth; ++nLevel) |
2578 | 0 | { |
2579 | 0 | if (rArray.GetCount(nLevel)) |
2580 | 0 | { |
2581 | | // look for a group inside the [nStartRow+1, nEndRow] range |
2582 | 0 | size_t nIndex; |
2583 | 0 | bool bFound = rArray.GetEntryIndexInRange(nLevel, nStart + 1, nEnd, nIndex); |
2584 | 0 | if (bFound) |
2585 | 0 | { |
2586 | 0 | if (nIndex > 0) |
2587 | 0 | { |
2588 | | // is there a previous group not inside the range |
2589 | | // but anyway intersecting it ? |
2590 | 0 | const ScOutlineEntry* pPrevEntry = rArray.GetEntry(nLevel, nIndex - 1); |
2591 | 0 | if (pPrevEntry && nStart < pPrevEntry->GetEnd()) |
2592 | 0 | { |
2593 | 0 | --nIndex; |
2594 | 0 | } |
2595 | 0 | } |
2596 | 0 | } |
2597 | 0 | else |
2598 | 0 | { |
2599 | | // look for a group which contains nStartRow+1 |
2600 | 0 | bFound = rArray.GetEntryIndex(nLevel, nStart + 1, nIndex); |
2601 | 0 | if (!bFound) |
2602 | 0 | { |
2603 | | // look for a group which contains nEndRow |
2604 | 0 | bFound = rArray.GetEntryIndex(nLevel, nEnd, nIndex); |
2605 | 0 | } |
2606 | 0 | } |
2607 | |
|
2608 | 0 | if (bFound) |
2609 | 0 | { |
2610 | | // skip groups with no visible control |
2611 | 0 | bFound = false; |
2612 | 0 | while (nIndex < rArray.GetCount(nLevel)) |
2613 | 0 | { |
2614 | 0 | const ScOutlineEntry* pEntry = rArray.GetEntry(nLevel, nIndex); |
2615 | 0 | if (pEntry && pEntry->IsVisible()) |
2616 | 0 | { |
2617 | 0 | bFound = true; |
2618 | 0 | break; |
2619 | 0 | } |
2620 | 0 | if (pEntry && pEntry->GetStart() > nEnd) |
2621 | 0 | { |
2622 | 0 | break; |
2623 | 0 | } |
2624 | 0 | ++nIndex; |
2625 | 0 | } |
2626 | 0 | } |
2627 | |
|
2628 | 0 | rGroupIndexes[nLevel] = bFound ? nIndex : -1; |
2629 | 0 | } |
2630 | 0 | } |
2631 | 0 | } |
2632 | | |
2633 | | void lcl_createGroupsData( |
2634 | | SCCOLROW nHeaderIndex, SCCOLROW nEnd, tools::Long nSizePx, tools::Long nTotalPx, |
2635 | | const ScOutlineArray& rArray, std::vector<size_t>& rGroupIndexes, |
2636 | | std::vector<tools::Long>& rGroupStartPositions, OStringBuffer& rGroupsBuffer) |
2637 | 0 | { |
2638 | 0 | const size_t nGroupDepth = rArray.GetDepth(); |
2639 | | // create string data for group controls |
2640 | 0 | for (size_t nLevel = nGroupDepth - 1; nLevel != size_t(-1); --nLevel) |
2641 | 0 | { |
2642 | 0 | size_t nIndex = rGroupIndexes[nLevel]; |
2643 | 0 | if (nIndex == size_t(-1)) |
2644 | 0 | continue; |
2645 | 0 | const ScOutlineEntry* pEntry = rArray.GetEntry(nLevel, nIndex); |
2646 | 0 | if (pEntry) |
2647 | 0 | { |
2648 | 0 | if (nHeaderIndex < pEntry->GetStart()) |
2649 | 0 | { |
2650 | 0 | continue; |
2651 | 0 | } |
2652 | 0 | else if (nHeaderIndex == pEntry->GetStart()) |
2653 | 0 | { |
2654 | 0 | rGroupStartPositions[nLevel] = nTotalPx - nSizePx; |
2655 | 0 | } |
2656 | 0 | else if (nHeaderIndex > pEntry->GetStart() && (nHeaderIndex < nEnd && nHeaderIndex < pEntry->GetEnd())) |
2657 | 0 | { |
2658 | | // for handling group started before the current view range |
2659 | 0 | if (rGroupStartPositions[nLevel] < 0) |
2660 | 0 | rGroupStartPositions[nLevel] *= -1; |
2661 | 0 | break; |
2662 | 0 | } |
2663 | 0 | if (nHeaderIndex == pEntry->GetEnd() || (nHeaderIndex == nEnd && rGroupStartPositions[nLevel] != -1)) |
2664 | 0 | { |
2665 | | // nHeaderIndex is the end col/row of a group or is the last col/row and a group started and not yet ended |
2666 | | |
2667 | | // append a new group control data |
2668 | 0 | auto len = rGroupsBuffer.getLength(); |
2669 | 0 | if (len && rGroupsBuffer[len-1] == '}') |
2670 | 0 | { |
2671 | 0 | rGroupsBuffer.append(", "); |
2672 | 0 | } |
2673 | |
|
2674 | 0 | bool bGroupHidden = pEntry->IsHidden(); |
2675 | |
|
2676 | 0 | rGroupsBuffer.append( |
2677 | 0 | "{ \"level\": " + OString::number(nLevel + 1) + ", " |
2678 | 0 | "\"index\": " + OString::number(nIndex) + ", " |
2679 | 0 | "\"startPos\": " + OString::number(rGroupStartPositions[nLevel]) + ", " |
2680 | 0 | "\"endPos\": " + OString::number(nTotalPx) + ", " |
2681 | 0 | "\"hidden\": " + OString::number(bGroupHidden ? 1 : 0) + " }"); |
2682 | | |
2683 | | // look for the next visible group control at level nLevel |
2684 | 0 | bool bFound = false; |
2685 | 0 | ++nIndex; |
2686 | 0 | while (nIndex < rArray.GetCount(nLevel)) |
2687 | 0 | { |
2688 | 0 | pEntry = rArray.GetEntry(nLevel, nIndex); |
2689 | 0 | if (pEntry && pEntry->IsVisible()) |
2690 | 0 | { |
2691 | 0 | bFound = true; |
2692 | 0 | break; |
2693 | 0 | } |
2694 | 0 | if (pEntry && pEntry->GetStart() > nEnd) |
2695 | 0 | { |
2696 | 0 | break; |
2697 | 0 | } |
2698 | 0 | ++nIndex; |
2699 | 0 | } |
2700 | 0 | rGroupIndexes[nLevel] = bFound ? nIndex : -1; |
2701 | 0 | rGroupStartPositions[nLevel] = -1; |
2702 | 0 | } |
2703 | 0 | } |
2704 | 0 | } |
2705 | 0 | } |
2706 | | |
2707 | | class ScRangeProvider |
2708 | | { |
2709 | | public: |
2710 | | ScRangeProvider(const tools::Rectangle& rArea, bool bInPixels, |
2711 | | ScViewData& rViewData): |
2712 | 0 | mrViewData(rViewData) |
2713 | 0 | { |
2714 | 0 | tools::Rectangle aAreaPx = bInPixels ? rArea : |
2715 | 0 | tools::Rectangle(rArea.Left() * mrViewData.GetPPTX(), |
2716 | 0 | rArea.Top() * mrViewData.GetPPTY(), |
2717 | 0 | rArea.Right() * mrViewData.GetPPTX(), |
2718 | 0 | rArea.Bottom() * mrViewData.GetPPTY()); |
2719 | 0 | calculateBounds(aAreaPx); |
2720 | 0 | } |
2721 | | |
2722 | | const ScRange& getCellRange() const |
2723 | 0 | { |
2724 | 0 | return maRange; |
2725 | 0 | } |
2726 | | |
2727 | | void getColPositions(tools::Long& rStartColPos, tools::Long& rEndColPos) const |
2728 | 0 | { |
2729 | 0 | rStartColPos = maBoundPositions.Left(); |
2730 | 0 | rEndColPos = maBoundPositions.Right(); |
2731 | 0 | } |
2732 | | |
2733 | | void getRowPositions(tools::Long& rStartRowPos, tools::Long& rEndRowPos) const |
2734 | 0 | { |
2735 | 0 | rStartRowPos = maBoundPositions.Top(); |
2736 | 0 | rEndRowPos = maBoundPositions.Bottom(); |
2737 | 0 | } |
2738 | | |
2739 | | private: |
2740 | | void calculateBounds(const tools::Rectangle& rAreaPx) |
2741 | 0 | { |
2742 | 0 | tools::Long nLeftPx = 0, nRightPx = 0; |
2743 | 0 | SCCOLROW nStartCol = -1, nEndCol = -1; |
2744 | 0 | calculateDimensionBounds(rAreaPx.Left(), rAreaPx.Right(), true, |
2745 | 0 | nStartCol, nEndCol, nLeftPx, nRightPx, |
2746 | 0 | mnEnlargeX, mrViewData); |
2747 | 0 | tools::Long nTopPx = 0, nBottomPx = 0; |
2748 | 0 | SCCOLROW nStartRow = -1, nEndRow = -1; |
2749 | 0 | calculateDimensionBounds(rAreaPx.Top(), rAreaPx.Bottom(), false, |
2750 | 0 | nStartRow, nEndRow, nTopPx, nBottomPx, |
2751 | 0 | mnEnlargeY, mrViewData); |
2752 | |
|
2753 | 0 | maRange.aStart.Set(nStartCol, nStartRow, mrViewData.CurrentTabForData()); |
2754 | 0 | maRange.aEnd.Set(nEndCol, nEndRow, mrViewData.CurrentTabForData()); |
2755 | |
|
2756 | 0 | maBoundPositions.SetLeft(nLeftPx); |
2757 | 0 | maBoundPositions.SetRight(nRightPx); |
2758 | 0 | maBoundPositions.SetTop(nTopPx); |
2759 | 0 | maBoundPositions.SetBottom(nBottomPx); |
2760 | 0 | } |
2761 | | |
2762 | | // All positions are in pixels. |
2763 | | static void calculateDimensionBounds(const tools::Long nStartPos, const tools::Long nEndPos, |
2764 | | bool bColumns, SCCOLROW& rStartIndex, |
2765 | | SCCOLROW& rEndIndex, tools::Long& rBoundStart, |
2766 | | tools::Long& rBoundEnd, SCCOLROW nEnlarge, |
2767 | | ScViewData& rViewData) |
2768 | 0 | { |
2769 | 0 | ScPositionHelper& rPosHelper = bColumns ? rViewData.GetLOKWidthHelper() : |
2770 | 0 | rViewData.GetLOKHeightHelper(); |
2771 | 0 | const auto& rStartNearest = rPosHelper.getNearestByPosition(nStartPos); |
2772 | 0 | const auto& rEndNearest = rPosHelper.getNearestByPosition(nEndPos); |
2773 | |
|
2774 | 0 | ScBoundsProvider aBoundsProvider(rViewData, rViewData.CurrentTabForData(), bColumns); |
2775 | 0 | aBoundsProvider.Compute(rStartNearest, rEndNearest, nStartPos, nEndPos); |
2776 | 0 | aBoundsProvider.EnlargeBy(nEnlarge); |
2777 | 0 | if (bColumns) |
2778 | 0 | { |
2779 | 0 | SCCOL nStartCol = -1, nEndCol = -1; |
2780 | 0 | aBoundsProvider.GetStartIndexAndPosition(nStartCol, rBoundStart); |
2781 | 0 | aBoundsProvider.GetEndIndexAndPosition(nEndCol, rBoundEnd); |
2782 | 0 | rStartIndex = nStartCol; |
2783 | 0 | rEndIndex = nEndCol; |
2784 | 0 | } |
2785 | 0 | else |
2786 | 0 | { |
2787 | 0 | SCROW nStartRow = -1, nEndRow = -1; |
2788 | 0 | aBoundsProvider.GetStartIndexAndPosition(nStartRow, rBoundStart); |
2789 | 0 | aBoundsProvider.GetEndIndexAndPosition(nEndRow, rBoundEnd); |
2790 | 0 | rStartIndex = nStartRow; |
2791 | 0 | rEndIndex = nEndRow; |
2792 | 0 | } |
2793 | 0 | } |
2794 | | |
2795 | | private: |
2796 | | |
2797 | | ScRange maRange; |
2798 | | tools::Rectangle maBoundPositions; |
2799 | | ScViewData& mrViewData; |
2800 | | static const SCCOLROW mnEnlargeX = 2; |
2801 | | static const SCCOLROW mnEnlargeY = 2; |
2802 | | }; |
2803 | | |
2804 | | void lcl_ExtendTiledDimension(bool bColumn, const SCCOLROW nEnd, const SCCOLROW nExtra, |
2805 | | ScTabView& rTabView, ScViewData& rViewData) |
2806 | 0 | { |
2807 | 0 | ScDocument& rDoc = rViewData.GetDocument(); |
2808 | | // If we are approaching current max tiled row/col, signal a size changed event |
2809 | | // and invalidate the involved area |
2810 | 0 | SCCOLROW nMaxTiledIndex = bColumn ? rViewData.GetMaxTiledCol() : rViewData.GetMaxTiledRow(); |
2811 | 0 | SCCOLROW nHardLimit = !bColumn ? MAXTILEDROW : rDoc.MaxCol(); |
2812 | |
|
2813 | 0 | if (nMaxTiledIndex >= nHardLimit) |
2814 | 0 | return; |
2815 | | |
2816 | 0 | if (nEnd <= nMaxTiledIndex - nExtra) // No need to extend. |
2817 | 0 | return; |
2818 | | |
2819 | 0 | ScDocShell* pDocSh = rViewData.GetDocShell(); |
2820 | 0 | ScModelObj* pModelObj = pDocSh ? pDocSh->GetModel() : nullptr; |
2821 | 0 | Size aOldSize(0, 0); |
2822 | 0 | if (pModelObj) |
2823 | 0 | aOldSize = pModelObj->getDocumentSize(); |
2824 | |
|
2825 | 0 | SCCOLROW nNewMaxTiledIndex = std::min(std::max(nEnd, nMaxTiledIndex) + nExtra, nHardLimit); |
2826 | |
|
2827 | 0 | if (bColumn) |
2828 | 0 | rViewData.SetMaxTiledCol(nNewMaxTiledIndex); |
2829 | 0 | else |
2830 | 0 | rViewData.SetMaxTiledRow(nNewMaxTiledIndex); |
2831 | |
|
2832 | 0 | Size aNewSize(0, 0); |
2833 | 0 | if (pModelObj) |
2834 | 0 | aNewSize = pModelObj->getDocumentSize(); |
2835 | |
|
2836 | 0 | if (!pDocSh) |
2837 | 0 | return; |
2838 | | |
2839 | 0 | if (pModelObj) |
2840 | 0 | { |
2841 | 0 | ScGridWindow* pGridWindow = rViewData.GetActiveWin(); |
2842 | 0 | if (pGridWindow) |
2843 | 0 | { |
2844 | 0 | Size aNewSizePx(aNewSize.Width() * rViewData.GetPPTX(), aNewSize.Height() * rViewData.GetPPTY()); |
2845 | 0 | if (aNewSizePx != pGridWindow->GetOutputSizePixel()) |
2846 | 0 | pGridWindow->SetOutputSizePixel(aNewSizePx); |
2847 | 0 | } |
2848 | 0 | } |
2849 | |
|
2850 | 0 | if (aOldSize == aNewSize) |
2851 | 0 | return; |
2852 | | |
2853 | | // New area extended to the right/bottom of the sheet after last col/row |
2854 | 0 | tools::Rectangle aNewArea(Point(0, 0), aNewSize); |
2855 | | // excluding overlapping area with aNewArea |
2856 | 0 | if (bColumn) |
2857 | 0 | aNewArea.SetLeft(aOldSize.getWidth()); |
2858 | 0 | else |
2859 | 0 | aNewArea.SetTop(aOldSize.getHeight()); |
2860 | | |
2861 | | // Only invalidate if spreadsheet has extended to the right or bottom |
2862 | 0 | if ((bColumn && aNewArea.getOpenWidth()) || (!bColumn && aNewArea.getOpenHeight())) |
2863 | 0 | { |
2864 | 0 | rTabView.UpdateSelectionOverlay(); |
2865 | 0 | SfxLokHelper::notifyInvalidation(rViewData.GetViewShell(), &aNewArea); |
2866 | 0 | } |
2867 | | |
2868 | | // Provide size in the payload, so clients don't have to query for that. |
2869 | 0 | std::stringstream ss; |
2870 | 0 | ss << aNewSize.Width() << ", " << aNewSize.Height(); |
2871 | 0 | OString sSize( ss.str() ); |
2872 | 0 | ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>( |
2873 | 0 | rViewData.GetViewShell()->GetCurrentDocument()); |
2874 | 0 | SfxLokHelper::notifyDocumentSizeChanged(rViewData.GetViewShell(), sSize, pModel, false); |
2875 | 0 | } |
2876 | | |
2877 | | } // anonymous namespace |
2878 | | |
2879 | | void ScTabView::getRowColumnHeaders(const tools::Rectangle& rRectangle, tools::JsonWriter& rJsonWriter) |
2880 | 0 | { |
2881 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
2882 | |
|
2883 | 0 | if (rRectangle.IsEmpty()) |
2884 | 0 | return; |
2885 | | |
2886 | 0 | bool bRangeHeaderSupport = comphelper::LibreOfficeKit::isRangeHeaders(); |
2887 | |
|
2888 | 0 | rJsonWriter.put("commandName", ".uno:ViewRowColumnHeaders"); |
2889 | |
|
2890 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
2891 | 0 | SCROW nStartRow = -1; |
2892 | 0 | SCROW nEndRow = -1; |
2893 | 0 | tools::Long nStartHeightPx = 0; |
2894 | 0 | SCCOL nStartCol = -1; |
2895 | 0 | SCCOL nEndCol = -1; |
2896 | 0 | tools::Long nStartWidthPx = 0; |
2897 | |
|
2898 | 0 | tools::Rectangle aOldVisArea( |
2899 | 0 | mnLOKStartHeaderCol + 1, mnLOKStartHeaderRow + 1, |
2900 | 0 | mnLOKEndHeaderCol, mnLOKEndHeaderRow); |
2901 | |
|
2902 | 0 | ScRangeProvider aRangeProvider(rRectangle, /* bInPixels */ false, aViewData); |
2903 | 0 | const ScRange& rCellRange = aRangeProvider.getCellRange(); |
2904 | | |
2905 | | /// *** start collecting ROWS *** |
2906 | | |
2907 | | /// 1) compute start and end rows |
2908 | |
|
2909 | 0 | if (rRectangle.Top() < rRectangle.Bottom()) |
2910 | 0 | { |
2911 | 0 | SAL_INFO("sc.lok.header", "Row Header: compute start/end rows."); |
2912 | 0 | tools::Long nEndHeightPx = 0; |
2913 | 0 | nStartRow = rCellRange.aStart.Row(); |
2914 | 0 | nEndRow = rCellRange.aEnd.Row(); |
2915 | 0 | aRangeProvider.getRowPositions(nStartHeightPx, nEndHeightPx); |
2916 | |
|
2917 | 0 | aViewData.GetLOKHeightHelper().removeByIndex(mnLOKStartHeaderRow); |
2918 | 0 | aViewData.GetLOKHeightHelper().removeByIndex(mnLOKEndHeaderRow); |
2919 | 0 | aViewData.GetLOKHeightHelper().insert(nStartRow, nStartHeightPx); |
2920 | 0 | aViewData.GetLOKHeightHelper().insert(nEndRow, nEndHeightPx); |
2921 | |
|
2922 | 0 | mnLOKStartHeaderRow = nStartRow; |
2923 | 0 | mnLOKEndHeaderRow = nEndRow; |
2924 | 0 | } |
2925 | | |
2926 | 0 | sal_Int32 nVisibleRows = nEndRow - nStartRow; |
2927 | 0 | if (nVisibleRows < 25) |
2928 | 0 | nVisibleRows = 25; |
2929 | |
|
2930 | 0 | SAL_INFO("sc.lok.header", "Row Header: visible rows: " << nVisibleRows); |
2931 | | |
2932 | | |
2933 | | // Get row groups |
2934 | | // per each level store the index of the first group intersecting |
2935 | | // [nStartRow, nEndRow] range |
2936 | | |
2937 | 0 | const ScOutlineTable* pTable = rDoc.GetOutlineTable(nTab); |
2938 | 0 | const ScOutlineArray* pRowArray = pTable ? &(pTable->GetRowArray()) : nullptr; |
2939 | 0 | size_t nRowGroupDepth = 0; |
2940 | 0 | std::vector<size_t> aRowGroupIndexes; |
2941 | 0 | if (bRangeHeaderSupport && pTable) |
2942 | 0 | { |
2943 | 0 | nRowGroupDepth = pRowArray->GetDepth(); |
2944 | 0 | lcl_getGroupIndexes(*pRowArray, nStartRow, nEndRow, aRowGroupIndexes); |
2945 | 0 | } |
2946 | | |
2947 | | /// 2) if we are approaching current max tiled row, signal a size changed event |
2948 | | /// and invalidate the involved area |
2949 | 0 | lcl_ExtendTiledDimension(/* bColumn */ false, nEndRow, nVisibleRows, *this, aViewData); |
2950 | | |
2951 | | /// 3) create string data for rows |
2952 | |
|
2953 | 0 | tools::Long nTotalPixels = nStartHeightPx; |
2954 | 0 | tools::Long nPrevSizePx = -1; |
2955 | 0 | OStringBuffer aRowGroupsBuffer = "\"rowGroups\": [\n"; |
2956 | 0 | { |
2957 | 0 | auto rowsNode = rJsonWriter.startArray("rows"); |
2958 | |
|
2959 | 0 | SAL_INFO("sc.lok.header", "Row Header: [create string data for rows]: start row: " |
2960 | 0 | << nStartRow << " start height: " << nTotalPixels); |
2961 | | |
2962 | 0 | if (nStartRow != nEndRow) |
2963 | 0 | { |
2964 | 0 | auto node = rJsonWriter.startStruct(); |
2965 | 0 | rJsonWriter.put("text", nStartRow + 1); |
2966 | 0 | rJsonWriter.put("size", nTotalPixels); |
2967 | 0 | rJsonWriter.put("groupLevels", static_cast<sal_Int64>(nRowGroupDepth)); |
2968 | 0 | } |
2969 | |
|
2970 | 0 | std::vector<tools::Long> aRowGroupStartPositions(nRowGroupDepth, -nTotalPixels); |
2971 | 0 | for (SCROW nRow = nStartRow + 1; nRow <= nEndRow; ++nRow) |
2972 | 0 | { |
2973 | | // nSize will be 0 for hidden rows. |
2974 | 0 | const tools::Long nSizePx = lcl_GetRowHeightPx(aViewData, nRow, nTab); |
2975 | 0 | nTotalPixels += nSizePx; |
2976 | |
|
2977 | 0 | if (bRangeHeaderSupport && nRowGroupDepth > 0) |
2978 | 0 | { |
2979 | 0 | lcl_createGroupsData(nRow, nEndRow, nSizePx, nTotalPixels, |
2980 | 0 | *pRowArray, aRowGroupIndexes, aRowGroupStartPositions, |
2981 | 0 | aRowGroupsBuffer); |
2982 | 0 | } |
2983 | |
|
2984 | 0 | if (bRangeHeaderSupport && nRow < nEndRow && nSizePx == nPrevSizePx) |
2985 | 0 | continue; |
2986 | 0 | nPrevSizePx = nSizePx; |
2987 | |
|
2988 | 0 | auto node = rJsonWriter.startStruct(); |
2989 | 0 | rJsonWriter.put("text", pRowBar[SC_SPLIT_BOTTOM]->GetEntryText(nRow)); |
2990 | 0 | rJsonWriter.put("size", nTotalPixels); |
2991 | 0 | } |
2992 | |
|
2993 | 0 | aRowGroupsBuffer.append("]"); |
2994 | 0 | } |
2995 | 0 | if (nRowGroupDepth > 0) |
2996 | 0 | { |
2997 | 0 | aRowGroupsBuffer.append(",\n"); |
2998 | 0 | rJsonWriter.putRaw(aRowGroupsBuffer); |
2999 | 0 | } |
3000 | | /// end collecting ROWS |
3001 | | |
3002 | | |
3003 | | /// *** start collecting COLS *** |
3004 | | |
3005 | | /// 1) compute start and end columns |
3006 | |
|
3007 | 0 | if (rRectangle.Left() < rRectangle.Right()) |
3008 | 0 | { |
3009 | 0 | SAL_INFO("sc.lok.header", "Column Header: compute start/end columns."); |
3010 | 0 | tools::Long nEndWidthPx = 0; |
3011 | 0 | nStartCol = rCellRange.aStart.Col(); |
3012 | 0 | nEndCol = rCellRange.aEnd.Col(); |
3013 | 0 | aRangeProvider.getColPositions(nStartWidthPx, nEndWidthPx); |
3014 | |
|
3015 | 0 | aViewData.GetLOKWidthHelper().removeByIndex(mnLOKStartHeaderCol); |
3016 | 0 | aViewData.GetLOKWidthHelper().removeByIndex(mnLOKEndHeaderCol); |
3017 | 0 | aViewData.GetLOKWidthHelper().insert(nStartCol, nStartWidthPx); |
3018 | 0 | aViewData.GetLOKWidthHelper().insert(nEndCol, nEndWidthPx); |
3019 | |
|
3020 | 0 | mnLOKStartHeaderCol = nStartCol; |
3021 | 0 | mnLOKEndHeaderCol = nEndCol; |
3022 | 0 | } |
3023 | | |
3024 | 0 | sal_Int32 nVisibleCols = nEndCol - nStartCol; |
3025 | 0 | if (nVisibleCols < 10) |
3026 | 0 | nVisibleCols = 10; |
3027 | | |
3028 | | |
3029 | | // Get column groups |
3030 | | // per each level store the index of the first group intersecting |
3031 | | // [nStartCol, nEndCol] range |
3032 | |
|
3033 | 0 | const ScOutlineArray* pColArray = pTable ? &(pTable->GetColArray()) : nullptr; |
3034 | 0 | size_t nColGroupDepth = 0; |
3035 | 0 | std::vector<size_t> aColGroupIndexes; |
3036 | 0 | if (bRangeHeaderSupport && pTable) |
3037 | 0 | { |
3038 | 0 | nColGroupDepth = pColArray->GetDepth(); |
3039 | 0 | lcl_getGroupIndexes(*pColArray, nStartCol, nEndCol, aColGroupIndexes); |
3040 | 0 | } |
3041 | | |
3042 | | /// 2) if we are approaching current max tiled column, signal a size changed event |
3043 | | /// and invalidate the involved area |
3044 | 0 | lcl_ExtendTiledDimension(/* bColumn */ true, nEndCol, nVisibleCols, *this, aViewData); |
3045 | | |
3046 | | /// 3) create string data for columns |
3047 | 0 | OStringBuffer aColGroupsBuffer = "\"columnGroups\": [\n"; |
3048 | 0 | { |
3049 | 0 | auto columnsNode = rJsonWriter.startArray("columns"); |
3050 | |
|
3051 | 0 | nTotalPixels = nStartWidthPx; |
3052 | 0 | SAL_INFO("sc.lok.header", "Col Header: [create string data for cols]: start col: " |
3053 | 0 | << nStartRow << " start width: " << nTotalPixels); |
3054 | | |
3055 | 0 | if (nStartCol != nEndCol) |
3056 | 0 | { |
3057 | 0 | auto node = rJsonWriter.startStruct(); |
3058 | 0 | rJsonWriter.put("text", static_cast<sal_Int64>(nStartCol) + 1); |
3059 | 0 | rJsonWriter.put("size", nTotalPixels); |
3060 | 0 | rJsonWriter.put("groupLevels", static_cast<sal_Int64>(nColGroupDepth)); |
3061 | 0 | } |
3062 | |
|
3063 | 0 | std::vector<tools::Long> aColGroupStartPositions(nColGroupDepth, -nTotalPixels); |
3064 | 0 | nPrevSizePx = -1; |
3065 | 0 | for (SCCOL nCol = nStartCol + 1; nCol <= nEndCol; ++nCol) |
3066 | 0 | { |
3067 | | // nSize will be 0 for hidden columns. |
3068 | 0 | const tools::Long nSizePx = lcl_GetColWidthPx(aViewData, nCol, nTab); |
3069 | 0 | nTotalPixels += nSizePx; |
3070 | |
|
3071 | 0 | if (bRangeHeaderSupport && nColGroupDepth > 0) |
3072 | 0 | lcl_createGroupsData(nCol, nEndCol, nSizePx, nTotalPixels, |
3073 | 0 | *pColArray, aColGroupIndexes, |
3074 | 0 | aColGroupStartPositions, aColGroupsBuffer); |
3075 | |
|
3076 | 0 | if (bRangeHeaderSupport && nCol < nEndCol && nSizePx == nPrevSizePx) |
3077 | 0 | continue; |
3078 | 0 | nPrevSizePx = nSizePx; |
3079 | |
|
3080 | 0 | OUString aText = bRangeHeaderSupport ? |
3081 | 0 | OUString::number(nCol + 1) : pColBar[SC_SPLIT_LEFT]->GetEntryText(nCol); |
3082 | |
|
3083 | 0 | auto node = rJsonWriter.startStruct(); |
3084 | 0 | rJsonWriter.put("text", aText); |
3085 | 0 | rJsonWriter.put("size", nTotalPixels); |
3086 | 0 | } |
3087 | |
|
3088 | 0 | aColGroupsBuffer.append("]"); |
3089 | 0 | } |
3090 | 0 | if (nColGroupDepth > 0) |
3091 | 0 | { |
3092 | 0 | aColGroupsBuffer.append(",\n"); |
3093 | 0 | rJsonWriter.putRaw(aColGroupsBuffer); |
3094 | 0 | } |
3095 | | /// end collecting COLs |
3096 | |
|
3097 | 0 | vcl::Region aNewVisArea( |
3098 | 0 | tools::Rectangle(mnLOKStartHeaderCol + 1, mnLOKStartHeaderRow + 1, |
3099 | 0 | mnLOKEndHeaderCol, mnLOKEndHeaderRow)); |
3100 | 0 | aNewVisArea.Exclude(aOldVisArea); |
3101 | 0 | tools::Rectangle aChangedArea = aNewVisArea.GetBoundRect(); |
3102 | 0 | if (!aChangedArea.IsEmpty()) |
3103 | 0 | { |
3104 | 0 | UpdateVisibleRange(); |
3105 | 0 | UpdateFormulas(aChangedArea.Left(), aChangedArea.Top(), aChangedArea.Right(), aChangedArea.Bottom()); |
3106 | 0 | } |
3107 | 0 | } |
3108 | | |
3109 | | OString ScTabView::getSheetGeometryData(bool bColumns, bool bRows, bool bSizes, bool bHidden, |
3110 | | bool bFiltered, bool bGroups) |
3111 | 0 | { |
3112 | 0 | ScDocument& rDoc = aViewData.GetDocument(); |
3113 | |
|
3114 | 0 | boost::property_tree::ptree aTree; |
3115 | 0 | aTree.put("commandName", ".uno:SheetGeometryData"); |
3116 | 0 | aTree.put("maxtiledcolumn", rDoc.MaxCol()); |
3117 | 0 | aTree.put("maxtiledrow", MAXTILEDROW); |
3118 | |
|
3119 | 0 | auto getJSONString = [](const boost::property_tree::ptree& rTree) { |
3120 | 0 | std::stringstream aStream; |
3121 | 0 | boost::property_tree::write_json(aStream, rTree); |
3122 | 0 | return aStream.str(); |
3123 | 0 | }; |
3124 | |
|
3125 | 0 | if ((!bSizes && !bHidden && !bFiltered && !bGroups) || |
3126 | 0 | (!bColumns && !bRows)) |
3127 | 0 | { |
3128 | 0 | return OString(getJSONString(aTree)); |
3129 | 0 | } |
3130 | | |
3131 | 0 | struct GeomEntry |
3132 | 0 | { |
3133 | 0 | SheetGeomType eType; |
3134 | 0 | const char* pKey; |
3135 | 0 | bool bEnabled; |
3136 | 0 | }; |
3137 | |
|
3138 | 0 | const GeomEntry aGeomEntries[] = { |
3139 | 0 | { SheetGeomType::SIZES, "sizes", bSizes }, |
3140 | 0 | { SheetGeomType::HIDDEN, "hidden", bHidden }, |
3141 | 0 | { SheetGeomType::FILTERED, "filtered", bFiltered }, |
3142 | 0 | { SheetGeomType::GROUPS, "groups", bGroups } |
3143 | 0 | }; |
3144 | |
|
3145 | 0 | struct DimensionEntry |
3146 | 0 | { |
3147 | 0 | const char* pKey; |
3148 | 0 | bool bDimIsCol; |
3149 | 0 | bool bEnabled; |
3150 | 0 | }; |
3151 | |
|
3152 | 0 | const DimensionEntry aDimEntries[] = { |
3153 | 0 | { "columns", true, bColumns }, |
3154 | 0 | { "rows", false, bRows } |
3155 | 0 | }; |
3156 | |
|
3157 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
3158 | |
|
3159 | 0 | for (const auto& rDimEntry : aDimEntries) |
3160 | 0 | { |
3161 | 0 | if (!rDimEntry.bEnabled) |
3162 | 0 | continue; |
3163 | | |
3164 | 0 | bool bDimIsCol = rDimEntry.bDimIsCol; |
3165 | |
|
3166 | 0 | boost::property_tree::ptree aDimTree; |
3167 | 0 | for (const auto& rGeomEntry : aGeomEntries) |
3168 | 0 | { |
3169 | 0 | if (!rGeomEntry.bEnabled) |
3170 | 0 | continue; |
3171 | | |
3172 | 0 | OString aGeomDataEncoding = rDoc.dumpSheetGeomData(nTab, bDimIsCol, rGeomEntry.eType); |
3173 | | // TODO: Investigate if we can avoid the copy of the 'value' string in put(). |
3174 | 0 | aDimTree.put(rGeomEntry.pKey, aGeomDataEncoding.getStr()); |
3175 | 0 | } |
3176 | |
|
3177 | 0 | aTree.add_child(rDimEntry.pKey, aDimTree); |
3178 | 0 | } |
3179 | |
|
3180 | 0 | return OString(getJSONString(aTree)); |
3181 | 0 | } |
3182 | | |
3183 | | void ScTabView::extendTiledAreaIfNeeded() |
3184 | 0 | { |
3185 | 0 | SAL_INFO("sc.lok.header", |
3186 | 0 | "extendTiledAreaIfNeeded: START: ClientView: ColRange[" |
3187 | 0 | << mnLOKStartHeaderCol << "," << mnLOKEndHeaderCol |
3188 | 0 | << "] RowRange[" << mnLOKStartHeaderRow << "," << mnLOKEndHeaderRow |
3189 | 0 | << "] MaxTiledCol = " << aViewData.GetMaxTiledCol() |
3190 | 0 | << " MaxTiledRow = " << aViewData.GetMaxTiledRow()); |
3191 | | |
3192 | 0 | const tools::Rectangle rVisArea = aViewData.getLOKVisibleArea(); |
3193 | 0 | if (rVisArea.Top() >= rVisArea.Bottom() || |
3194 | 0 | rVisArea.Left() >= rVisArea.Right()) |
3195 | 0 | return; |
3196 | | |
3197 | | // Needed for conditional updating of visible-range/formula. |
3198 | 0 | tools::Rectangle aOldVisCellRange(mnLOKStartHeaderCol + 1, mnLOKStartHeaderRow + 1, |
3199 | 0 | mnLOKEndHeaderCol, mnLOKEndHeaderRow); |
3200 | |
|
3201 | 0 | ScRangeProvider aRangeProvider(rVisArea, /* bInPixels */ false, aViewData); |
3202 | | // Index bounds. |
3203 | 0 | const ScRange& rCellRange = aRangeProvider.getCellRange(); |
3204 | 0 | const SCCOL nStartCol = rCellRange.aStart.Col(); |
3205 | 0 | const SCCOL nEndCol = rCellRange.aEnd.Col(); |
3206 | 0 | const SCROW nStartRow = rCellRange.aStart.Row(); |
3207 | 0 | const SCROW nEndRow = rCellRange.aEnd.Row(); |
3208 | | |
3209 | | // Column/Row positions. |
3210 | 0 | tools::Long nStartColPos, nEndColPos, nStartRowPos, nEndRowPos; |
3211 | 0 | aRangeProvider.getColPositions(nStartColPos, nEndColPos); |
3212 | 0 | aRangeProvider.getRowPositions(nStartRowPos, nEndRowPos); |
3213 | |
|
3214 | 0 | ScPositionHelper& rWidthHelper = aViewData.GetLOKWidthHelper(); |
3215 | 0 | ScPositionHelper& rHeightHelper = aViewData.GetLOKHeightHelper(); |
3216 | | |
3217 | | // Update mnLOKStartHeaderCol and mnLOKEndHeaderCol members. |
3218 | | // These are consulted in some ScGridWindow methods. |
3219 | 0 | if (mnLOKStartHeaderCol != nStartCol) |
3220 | 0 | { |
3221 | 0 | rWidthHelper.removeByIndex(mnLOKStartHeaderCol); |
3222 | 0 | rWidthHelper.insert(nStartCol, nStartColPos); |
3223 | 0 | mnLOKStartHeaderCol = nStartCol; |
3224 | 0 | } |
3225 | |
|
3226 | 0 | if (mnLOKEndHeaderCol != nEndCol) |
3227 | 0 | { |
3228 | 0 | rWidthHelper.removeByIndex(mnLOKEndHeaderCol); |
3229 | 0 | rWidthHelper.insert(nEndCol, nEndColPos); |
3230 | 0 | mnLOKEndHeaderCol = nEndCol; |
3231 | 0 | } |
3232 | | |
3233 | | // Update mnLOKStartHeaderRow and mnLOKEndHeaderRow members. |
3234 | | // These are consulted in some ScGridWindow methods. |
3235 | 0 | if (mnLOKStartHeaderRow != nStartRow) |
3236 | 0 | { |
3237 | 0 | rHeightHelper.removeByIndex(mnLOKStartHeaderRow); |
3238 | 0 | rHeightHelper.insert(nStartRow, nStartRowPos); |
3239 | 0 | mnLOKStartHeaderRow = nStartRow; |
3240 | 0 | } |
3241 | |
|
3242 | 0 | if (mnLOKEndHeaderRow != nEndRow) |
3243 | 0 | { |
3244 | 0 | rHeightHelper.removeByIndex(mnLOKEndHeaderRow); |
3245 | 0 | rHeightHelper.insert(nEndRow, nEndRowPos); |
3246 | 0 | mnLOKEndHeaderRow = nEndRow; |
3247 | 0 | } |
3248 | |
|
3249 | 0 | constexpr SCCOL nMinExtraCols = 10; |
3250 | 0 | SCCOL nExtraCols = std::max<SCCOL>(nMinExtraCols, nEndCol - nStartCol); |
3251 | | // If we are approaching current max tiled column, signal a size changed event |
3252 | | // and invalidate the involved area. |
3253 | 0 | lcl_ExtendTiledDimension(/* bColumn */ true, nEndCol, nExtraCols, *this, aViewData); |
3254 | |
|
3255 | 0 | constexpr SCROW nMinExtraRows = 25; |
3256 | 0 | SCROW nExtraRows = std::max(nMinExtraRows, nEndRow - nStartRow); |
3257 | | // If we are approaching current max tiled row, signal a size changed event |
3258 | | // and invalidate the involved area. |
3259 | 0 | lcl_ExtendTiledDimension(/* bColumn */ false, nEndRow, nExtraRows, *this, aViewData); |
3260 | |
|
3261 | 0 | vcl::Region aNewVisCellRange( |
3262 | 0 | tools::Rectangle(mnLOKStartHeaderCol + 1, mnLOKStartHeaderRow + 1, |
3263 | 0 | mnLOKEndHeaderCol, mnLOKEndHeaderRow)); |
3264 | 0 | aNewVisCellRange.Exclude(aOldVisCellRange); |
3265 | 0 | tools::Rectangle aChangedCellRange = aNewVisCellRange.GetBoundRect(); |
3266 | 0 | if (!aChangedCellRange.IsEmpty()) |
3267 | 0 | { |
3268 | 0 | UpdateVisibleRange(); |
3269 | 0 | UpdateFormulas(aChangedCellRange.Left(), aChangedCellRange.Top(), |
3270 | 0 | aChangedCellRange.Right(), aChangedCellRange.Bottom()); |
3271 | 0 | } |
3272 | |
|
3273 | 0 | SAL_INFO("sc.lok.header", |
3274 | 0 | "extendTiledAreaIfNeeded: END: ClientView: ColRange[" |
3275 | 0 | << mnLOKStartHeaderCol << "," << mnLOKEndHeaderCol |
3276 | 0 | << "] RowRange[" << mnLOKStartHeaderRow << "," << mnLOKEndHeaderRow |
3277 | 0 | << "] MaxTiledCol = " << aViewData.GetMaxTiledCol() |
3278 | 0 | << " MaxTiledRow = " << aViewData.GetMaxTiledRow()); |
3279 | 0 | } |
3280 | | |
3281 | | tools::Long ScTabView::GetCurrentPage() const |
3282 | 0 | { |
3283 | 0 | std::unique_ptr<ScPageBreakData> pTempPageData; |
3284 | 0 | const ScPageBreakData* pPageData = pPageBreakData.get(); |
3285 | |
|
3286 | 0 | if (!pPageData) |
3287 | 0 | { |
3288 | 0 | ScDocShell* pDocSh = aViewData.GetDocShell(); |
3289 | 0 | if (!pDocSh) |
3290 | 0 | return 1; |
3291 | | |
3292 | 0 | ScDocument& rDoc = pDocSh->GetDocument(); |
3293 | 0 | SCTAB nTab = aViewData.CurrentTabForData(); |
3294 | |
|
3295 | 0 | sal_uInt16 nCount = rDoc.GetPrintRangeCount(nTab); |
3296 | 0 | if (!nCount) |
3297 | 0 | nCount = 1; |
3298 | |
|
3299 | 0 | pTempPageData = std::make_unique<ScPageBreakData>(nCount); |
3300 | |
|
3301 | 0 | ScPrintFunc aPrintFunc( |
3302 | 0 | *pDocSh, |
3303 | 0 | pDocSh->GetPrinter(), |
3304 | 0 | nTab, |
3305 | 0 | 0, 0, |
3306 | 0 | nullptr, |
3307 | 0 | nullptr, |
3308 | 0 | pTempPageData.get()); |
3309 | | |
3310 | | // ScPrintFunc fills the PageBreakData in ctor. |
3311 | 0 | if (nCount > 1) |
3312 | 0 | { |
3313 | 0 | aPrintFunc.ResetBreaks(nTab); |
3314 | 0 | pTempPageData->AddPages(); |
3315 | 0 | } |
3316 | |
|
3317 | 0 | pPageData = pTempPageData.get(); |
3318 | 0 | } |
3319 | | |
3320 | 0 | const SCCOL nCurCol = aViewData.GetCurX(); |
3321 | 0 | const SCROW nCurRow = aViewData.GetCurY(); |
3322 | |
|
3323 | 0 | for (size_t nPos = 0; nPos < pPageData->GetCount(); ++nPos) |
3324 | 0 | { |
3325 | 0 | const ScPrintRangeData& rData = pPageData->GetData(nPos); |
3326 | 0 | const ScRange& rRange = rData.GetPrintRange(); |
3327 | |
|
3328 | 0 | if (nCurCol < rRange.aStart.Col() || nCurCol > rRange.aEnd.Col() |
3329 | 0 | || nCurRow < rRange.aStart.Row() || nCurRow > rRange.aEnd.Row()) |
3330 | 0 | continue; |
3331 | | |
3332 | 0 | return rData.GetPageNumber(nCurCol, nCurRow); |
3333 | 0 | } |
3334 | | |
3335 | 0 | return 1; |
3336 | 0 | } |
3337 | | |
3338 | | |
3339 | | |
3340 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |