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 <svx/fmshell.hxx>
21 #include <svx/svdobj.hxx>
22 #include <svx/svdocapt.hxx>
23 #include <svx/svdoutl.hxx>
24 #include <sfx2/bindings.hxx>
25 #include <sfx2/dispatch.hxx>
26 #include <sfx2/lokhelper.hxx>
27 #include <sfx2/objsh.hxx>
28 #include <sfx2/viewfrm.hxx>
29 #include <osl/diagnose.h>
30 
31 #include <tabview.hxx>
32 #include <tabvwsh.hxx>
33 #include <document.hxx>
34 #include <gridwin.hxx>
35 #include <olinewin.hxx>
36 #include <tabsplit.hxx>
37 #include <colrowba.hxx>
38 #include <tabcont.hxx>
39 #include <sc.hrc>
40 #include <pagedata.hxx>
41 #include <hiranges.hxx>
42 #include <drawview.hxx>
43 #include <drwlayer.hxx>
44 #include <fusel.hxx>
45 #include <seltrans.hxx>
46 #include <scmod.hxx>
47 #include <docsh.hxx>
48 #include <viewuno.hxx>
49 #include <postit.hxx>
50 #include <spellcheckcontext.hxx>
51 
52 #include <vcl/settings.hxx>
53 
54 #include <comphelper/lok.hxx>
55 #include <officecfg/Office/Calc.hxx>
56 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
57 
58 using namespace com::sun::star;
59 
Init()60 void ScTabView::Init()
61 {
62     /*  RTL layout of the view windows is done manually, because it depends on
63         the sheet orientation, not the UI setting. Note: controls that are
64         already constructed (e.g. scroll bars) have the RTL setting of the GUI.
65         Eventually this has to be disabled manually (see below). */
66     pFrameWin->EnableRTL( false );
67 
68     sal_uInt16 i;
69 
70     mbInlineWithScrollbar = officecfg::Office::Calc::Layout::Other::TabbarInlineWithScrollbar::get();
71 
72     aScrollTimer.SetTimeout(10);
73     aScrollTimer.SetInvokeHandler( LINK( this, ScTabView, TimerHdl ) );
74 
75     for (i=0; i<4; i++)
76         pGridWin[i] = nullptr;
77     pGridWin[SC_SPLIT_BOTTOMLEFT] = VclPtr<ScGridWindow>::Create( pFrameWin, aViewData, SC_SPLIT_BOTTOMLEFT );
78 
79     pSelEngine.reset( new ScViewSelectionEngine( pGridWin[SC_SPLIT_BOTTOMLEFT], this,
80                                                 SC_SPLIT_BOTTOMLEFT ) );
81     aFunctionSet.SetSelectionEngine( pSelEngine.get() );
82 
83     pHdrSelEng.reset( new ScHeaderSelectionEngine( pFrameWin, &aHdrFunc ) );
84 
85     pColBar[SC_SPLIT_LEFT] = VclPtr<ScColBar>::Create( pFrameWin, SC_SPLIT_LEFT,
86                                                        &aHdrFunc, pHdrSelEng.get(), this );
87     pColBar[SC_SPLIT_RIGHT] = nullptr;
88     pRowBar[SC_SPLIT_BOTTOM] = VclPtr<ScRowBar>::Create( pFrameWin, SC_SPLIT_BOTTOM,
89                                                          &aHdrFunc, pHdrSelEng.get(), this );
90     pRowBar[SC_SPLIT_TOP] = nullptr;
91     for (i=0; i<2; i++)
92         pColOutline[i] = pRowOutline[i] = nullptr;
93 
94     pHSplitter = VclPtr<ScTabSplitter>::Create( pFrameWin, WinBits( WB_HSCROLL ), &aViewData );
95     pVSplitter = VclPtr<ScTabSplitter>::Create( pFrameWin, WinBits( WB_VSCROLL ), &aViewData );
96 
97     // SSA: override default keyboard step size to allow snap to row/column
98     pHSplitter->SetKeyboardStepSize( 1 );
99     pVSplitter->SetKeyboardStepSize( 1 );
100 
101     pTabControl = VclPtr<ScTabControl>::Create(pFrameWin, &aViewData);
102     if (mbInlineWithScrollbar)
103         pTabControl->SetStyle(pTabControl->GetStyle() | WB_SIZEABLE);
104 
105     /*  #i97900# The tab control has to remain in RTL mode if GUI is RTL, this
106         is needed to draw the 3D effect correctly. The base TabBar implements
107         mirroring independent from the GUI direction. Have to set RTL mode
108         explicitly because the parent frame window is already RTL disabled. */
109     pTabControl->EnableRTL( AllSettings::GetLayoutRTL() );
110 
111     InitScrollBar( *aHScrollLeft,    aViewData.GetDocument().MaxCol()+1 );
112     InitScrollBar( *aHScrollRight,   aViewData.GetDocument().MaxCol()+1 );
113     InitScrollBar( *aVScrollTop,     aViewData.GetDocument().MaxRow()+1 );
114     InitScrollBar( *aVScrollBottom,  aViewData.GetDocument().MaxRow()+1 );
115     /*  #i97900# scrollbars remain in correct RTL mode, needed mirroring etc.
116         is now handled correctly at the respective places. */
117 
118     //  Don't show anything here, because still in wrong order
119     //  Show is received from UpdateShow during first resize
120     //      pTabControl, pGridWin, aHScrollLeft, aVScrollBottom,
121     //      aCornerButton, aScrollBarBox, pHSplitter, pVSplitter
122 
123     //      fragment
124 
125     pHSplitter->SetSplitHdl( LINK( this, ScTabView, SplitHdl ) );
126     pVSplitter->SetSplitHdl( LINK( this, ScTabView, SplitHdl ) );
127 
128     //  UpdateShow is done during resize or a copy of an existing view from ctor
129 
130     pDrawActual = nullptr;
131     pDrawOld = nullptr;
132 
133     //  DrawView cannot be create in the TabView - ctor
134     //  when the ViewShell isn't constructed yet...
135     //  The also applies to ViewOptionsHasChanged()
136 
137     TestHintWindow();
138 }
139 
~ScTabView()140 ScTabView::~ScTabView()
141 {
142     sal_uInt16 i;
143 
144     //  remove selection object
145     ScModule* pScMod = SC_MOD();
146     ScSelectionTransferObj* pOld = pScMod->GetSelectionTransfer();
147     if ( pOld && pOld->GetView() == this )
148     {
149         pOld->ForgetView();
150         pScMod->SetSelectionTransfer( nullptr );
151         TransferableHelper::ClearPrimarySelection();       // may delete pOld
152     }
153 
154     pBrushDocument.reset();
155     pDrawBrushSet.reset();
156 
157     pPageBreakData.reset();
158 
159     delete pDrawActual;
160     pDrawActual = nullptr;
161     delete pDrawOld;
162     pDrawOld = nullptr;
163 
164     if (comphelper::LibreOfficeKit::isActive())
165     {
166         ScTabViewShell* pThisViewShell = GetViewData().GetViewShell();
167 
168         auto lRemoveWindows =
169                 [pThisViewShell] (ScTabViewShell* pOtherViewShell)
170                 {
171                     ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
172                     for (int k = 0; k < 4; ++k)
173                     {
174                         if (rOtherViewData.HasEditView(static_cast<ScSplitPos>(k)))
175                             pThisViewShell->RemoveWindowFromForeignEditView(pOtherViewShell, static_cast<ScSplitPos>(k));
176                     }
177                 };
178 
179         SfxLokHelper::forEachOtherView(pThisViewShell, lRemoveWindows);
180     }
181 
182     aViewData.KillEditView();           // as long as GridWins still exist
183 
184     if (pDrawView)
185     {
186         for (i=0; i<4; i++)
187             if (pGridWin[i])
188             {
189                 pDrawView->DeleteWindowFromPaintView(pGridWin[i]->GetOutDev());
190             }
191 
192         pDrawView->HideSdrPage();
193         pDrawView.reset();
194     }
195 
196     pSelEngine.reset();
197 
198     if (mpSpellCheckCxt)
199         mpSpellCheckCxt->dispose();
200     mpSpellCheckCxt.reset();
201 
202     mxInputHintOO.reset();
203     for (i=0; i<4; i++)
204         pGridWin[i].disposeAndClear();
205 
206     pHdrSelEng.reset();
207 
208     for (i=0; i<2; i++)
209     {
210         pColBar[i].disposeAndClear();
211         pRowBar[i].disposeAndClear();
212         pColOutline[i].disposeAndClear();
213         pRowOutline[i].disposeAndClear();
214     }
215 
216     aScrollBarBox.disposeAndClear();
217     aCornerButton.disposeAndClear();
218     aTopButton.disposeAndClear();
219     aHScrollLeft.disposeAndClear();
220     aHScrollRight.disposeAndClear();
221     aVScrollTop.disposeAndClear();
222     aVScrollBottom.disposeAndClear();
223 
224     pHSplitter.disposeAndClear();
225     pVSplitter.disposeAndClear();
226     pTabControl.disposeAndClear();
227 }
228 
MakeDrawView(TriState nForceDesignMode)229 void ScTabView::MakeDrawView( TriState nForceDesignMode )
230 {
231     if (pDrawView)
232         return;
233 
234     ScDrawLayer* pLayer = aViewData.GetDocument().GetDrawLayer();
235     OSL_ENSURE(pLayer, "Where is the Draw Layer ??");
236 
237     sal_uInt16 i;
238     pDrawView.reset( new ScDrawView( pGridWin[SC_SPLIT_BOTTOMLEFT]->GetOutDev(), &aViewData ) );
239     for (i=0; i<4; i++)
240         if (pGridWin[i])
241         {
242             if ( SC_SPLIT_BOTTOMLEFT != static_cast<ScSplitPos>(i) )
243                 pDrawView->AddWindowToPaintView(pGridWin[i]->GetOutDev(), nullptr);
244         }
245     pDrawView->RecalcScale();
246     for (i=0; i<4; i++)
247         if (pGridWin[i])
248         {
249             pGridWin[i]->SetMapMode(pGridWin[i]->GetDrawMapMode());
250 
251             pGridWin[i]->PaintImmediately(); // because of Invalidate in DrawView ctor (ShowPage),
252                                              // so that immediately can be drawn
253         }
254     SfxRequest aSfxRequest(SID_OBJECT_SELECT, SfxCallMode::SLOT, aViewData.GetViewShell()->GetPool());
255     SetDrawFuncPtr(new FuSelection(*aViewData.GetViewShell(), GetActiveWin(), pDrawView.get(),
256                                    pLayer,aSfxRequest));
257 
258     //  used when switching back from page preview: restore saved design mode state
259     //  (otherwise, keep the default from the draw view ctor)
260     if ( nForceDesignMode != TRISTATE_INDET )
261         pDrawView->SetDesignMode( nForceDesignMode != TRISTATE_FALSE );
262 
263     //  register at FormShell
264     FmFormShell* pFormSh = aViewData.GetViewShell()->GetFormShell();
265     if (pFormSh)
266         pFormSh->SetView(pDrawView.get());
267 
268     if (aViewData.GetViewShell()->HasAccessibilityObjects())
269         aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccMakeDrawLayer));
270 }
271 
DoAddWin(ScGridWindow * pWin)272 void ScTabView::DoAddWin( ScGridWindow* pWin )
273 {
274     if (pDrawView)
275     {
276         pDrawView->AddWindowToPaintView(pWin->GetOutDev(), nullptr);
277         pWin->DrawLayerCreated();
278     }
279     pWin->SetAutoSpellContext(mpSpellCheckCxt);
280 }
281 
TabChanged(bool bSameTabButMoved)282 void ScTabView::TabChanged( bool bSameTabButMoved )
283 {
284     if (pDrawView)
285     {
286         DrawDeselectAll();      // end also text edit mode
287 
288         SCTAB nTab = aViewData.GetTabNo();
289         pDrawView->HideSdrPage();
290         pDrawView->ShowSdrPage(pDrawView->GetModel()->GetPage(nTab));
291 
292         UpdateLayerLocks();
293 
294         pDrawView->RecalcScale();
295         pDrawView->UpdateWorkArea();    // PageSize is different per page
296     }
297 
298     SfxBindings& rBindings = aViewData.GetBindings();
299 
300     //  There is no easy way to invalidate all slots of the FormShell
301     //  (for disabled slots on protected tables), therefore simply everything...
302     rBindings.InvalidateAll(false);
303 
304     if (aViewData.GetViewShell()->HasAccessibilityObjects())
305     {
306         SfxHint aAccHint(SfxHintId::ScAccTableChanged);
307         aViewData.GetViewShell()->BroadcastAccessibility(aAccHint);
308     }
309 
310     // notification for XActivationBroadcaster
311     SfxViewFrame* pViewFrame = aViewData.GetViewShell()->GetViewFrame();
312     if (pViewFrame)
313     {
314         uno::Reference<frame::XController> xController = pViewFrame->GetFrame().GetController();
315         if (xController.is())
316         {
317             ScTabViewObj* pImp = comphelper::getUnoTunnelImplementation<ScTabViewObj>( xController );
318             if (pImp)
319                 pImp->SheetChanged( bSameTabButMoved );
320         }
321     }
322 
323     for (int i = 0; i < 4; i++)
324     {
325         if (pGridWin[i])
326         {
327             pGridWin[i]->initiatePageBreaks();
328             // Trigger calculating page breaks only once.
329             break;
330         }
331     }
332 
333     if (!comphelper::LibreOfficeKit::isActive())
334         return;
335 
336     ScDocShell* pDocSh = GetViewData().GetDocShell();
337     ScModelObj* pModelObj = pDocSh ? comphelper::getUnoTunnelImplementation<ScModelObj>( pDocSh->GetModel()) : nullptr;
338 
339     if (!pModelObj)
340         return;
341 
342     Size aDocSize = pModelObj->getDocumentSize();
343     std::stringstream ss;
344     ss << aDocSize.Width() << ", " << aDocSize.Height();
345     OString sRect = ss.str().c_str();
346     ScTabViewShell* pViewShell = aViewData.GetViewShell();
347 
348     // Invalidate first
349     tools::Rectangle aRectangle(0, 0, 1000000000, 1000000000);
350     OString sPayload = aRectangle.toString() + ", " + OString::number(aViewData.GetTabNo());
351     pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_TILES, sPayload.getStr());
352 
353     ScModelObj* pModel = comphelper::getUnoTunnelImplementation<ScModelObj>(pViewShell->GetCurrentDocument());
354     SfxLokHelper::notifyDocumentSizeChanged(pViewShell, sRect, pModel, false);
355 }
356 
UpdateLayerLocks()357 void ScTabView::UpdateLayerLocks()
358 {
359     if (!pDrawView)
360         return;
361 
362     SCTAB nTab = aViewData.GetTabNo();
363     bool bEx = aViewData.GetViewShell()->IsDrawSelMode();
364     bool bProt = aViewData.GetDocument().IsTabProtected( nTab ) ||
365                  aViewData.GetSfxDocShell()->IsReadOnly();
366     bool bShared = aViewData.GetDocShell()->IsDocShared();
367 
368     SdrLayer* pLayer;
369     SdrLayerAdmin& rAdmin = pDrawView->GetModel()->GetLayerAdmin();
370     pLayer = rAdmin.GetLayerPerID(SC_LAYER_BACK);
371     if (pLayer)
372         pDrawView->SetLayerLocked( pLayer->GetName(), bProt || !bEx || bShared );
373     pLayer = rAdmin.GetLayerPerID(SC_LAYER_INTERN);
374     if (pLayer)
375         pDrawView->SetLayerLocked( pLayer->GetName() );
376     pLayer = rAdmin.GetLayerPerID(SC_LAYER_FRONT);
377     if (pLayer)
378         pDrawView->SetLayerLocked( pLayer->GetName(), bProt || bShared );
379     pLayer = rAdmin.GetLayerPerID(SC_LAYER_CONTROLS);
380     if (pLayer)
381         pDrawView->SetLayerLocked( pLayer->GetName(), bProt || bShared );
382     pLayer = rAdmin.GetLayerPerID(SC_LAYER_HIDDEN);
383     if (pLayer)
384     {
385         pDrawView->SetLayerLocked( pLayer->GetName(), bProt || bShared );
386         pDrawView->SetLayerVisible( pLayer->GetName(), false);
387     }
388 }
389 
DrawDeselectAll()390 void ScTabView::DrawDeselectAll()
391 {
392     if (!pDrawView)
393         return;
394 
395     ScTabViewShell* pViewSh = aViewData.GetViewShell();
396     if ( pDrawActual &&
397         ( pViewSh->IsDrawTextShell() || pDrawActual->GetSlotID() == SID_DRAW_NOTEEDIT ) )
398     {
399         // end text edit (as if escape pressed, in FuDraw)
400         aViewData.GetDispatcher().Execute( pDrawActual->GetSlotID(),
401                                     SfxCallMode::SLOT | SfxCallMode::RECORD );
402     }
403 
404     pDrawView->ScEndTextEdit();
405     pDrawView->UnmarkAll();
406 
407     if (!pViewSh->IsDrawSelMode())
408         pViewSh->SetDrawShell( false );
409 }
410 
IsDrawTextEdit() const411 bool ScTabView::IsDrawTextEdit() const
412 {
413     if (pDrawView)
414         return pDrawView->IsTextEdit();
415     else
416         return false;
417 }
418 
GetZoomType() const419 SvxZoomType ScTabView::GetZoomType() const
420 {
421     return aViewData.GetZoomType();
422 }
423 
SetZoomType(SvxZoomType eNew,bool bAll)424 void ScTabView::SetZoomType( SvxZoomType eNew, bool bAll )
425 {
426     aViewData.SetZoomType( eNew, bAll );
427 }
428 
SetZoom(const Fraction & rNewX,const Fraction & rNewY,bool bAll)429 void ScTabView::SetZoom( const Fraction& rNewX, const Fraction& rNewY, bool bAll )
430 {
431     aViewData.SetZoom( rNewX, rNewY, bAll );
432     if (pDrawView)
433         pDrawView->RecalcScale();
434     ZoomChanged();
435 }
436 
RefreshZoom()437 void ScTabView::RefreshZoom()
438 {
439     aViewData.RefreshZoom();
440     if (pDrawView)
441         pDrawView->RecalcScale();
442     ZoomChanged();
443 }
444 
SetPagebreakMode(bool bSet)445 void ScTabView::SetPagebreakMode( bool bSet )
446 {
447     aViewData.SetPagebreakMode(bSet);
448     if (pDrawView)
449         pDrawView->RecalcScale();
450     ZoomChanged();
451 }
452 
ResetDrawDragMode()453 void ScTabView::ResetDrawDragMode()
454 {
455     if (pDrawView)
456         pDrawView->SetDragMode( SdrDragMode::Move );
457 }
458 
ViewOptionsHasChanged(bool bHScrollChanged,bool bGraphicsChanged)459 void ScTabView::ViewOptionsHasChanged( bool bHScrollChanged, bool bGraphicsChanged )
460 {
461     //  create DrawView when grid should be displayed
462     if ( !pDrawView && aViewData.GetOptions().GetGridOptions().GetGridVisible() )
463         MakeDrawLayer();
464 
465     if (pDrawView)
466         pDrawView->UpdateUserViewOptions();
467 
468     if (bGraphicsChanged)
469         DrawEnableAnim(true);   // DrawEnableAnim checks the options state
470 
471     // if TabBar is set to visible, make sure its size is not 0
472     bool bGrow = ( aViewData.IsTabMode() && pTabControl->GetSizePixel().Width() <= 0 );
473 
474     // if ScrollBar is set to visible, TabBar must make room
475     bool bShrink = ( bHScrollChanged && aViewData.IsTabMode() && aViewData.IsHScrollMode() &&
476                      pTabControl->GetSizePixel().Width() > SC_TABBAR_DEFWIDTH );
477 
478     if ( bGrow || bShrink )
479     {
480         Size aSize = pTabControl->GetSizePixel();
481         aSize.setWidth( SC_TABBAR_DEFWIDTH );             // initial size
482         pTabControl->SetSizePixel(aSize);               // DoResize is called later...
483     }
484 }
485 
486 // helper function against including the drawing layer
487 
DrawMarkListHasChanged()488 void ScTabView::DrawMarkListHasChanged()
489 {
490     if ( pDrawView )
491         pDrawView->MarkListHasChanged();
492 }
493 
UpdateAnchorHandles()494 void ScTabView::UpdateAnchorHandles()
495 {
496     if ( pDrawView )
497         pDrawView->AdjustMarkHdl();
498 }
499 
UpdateIMap(SdrObject * pObj)500 void ScTabView::UpdateIMap( SdrObject* pObj )
501 {
502     if ( pDrawView )
503         pDrawView->UpdateIMap( pObj );
504 }
505 
DrawEnableAnim(bool bSet)506 void ScTabView::DrawEnableAnim(bool bSet)
507 {
508     sal_uInt16 i;
509     if ( !pDrawView )
510         return;
511 
512     //  don't start animations if display of graphics is disabled
513     //  graphics are controlled by VOBJ_TYPE_OLE
514     if ( bSet && aViewData.GetOptions().GetObjMode(VOBJ_TYPE_OLE) == VOBJ_MODE_SHOW )
515     {
516         if ( !pDrawView->IsAnimationEnabled() )
517         {
518             pDrawView->SetAnimationEnabled();
519 
520             //  animated GIFs must be restarted:
521             ScDocument& rDoc = aViewData.GetDocument();
522             for (i=0; i<4; i++)
523                 if ( pGridWin[i] && pGridWin[i]->IsVisible() )
524                     rDoc.StartAnimations( aViewData.GetTabNo() );
525         }
526     }
527     else
528     {
529         pDrawView->SetAnimationEnabled(false);
530     }
531 }
532 
UpdateDrawTextOutliner()533 void ScTabView::UpdateDrawTextOutliner()
534 {
535     if ( pDrawView )
536     {
537         Outliner* pOL = pDrawView->GetTextEditOutliner();
538         if (pOL)
539             aViewData.UpdateOutlinerFlags( *pOL );
540     }
541 }
542 
DigitLanguageChanged()543 void ScTabView::DigitLanguageChanged()
544 {
545     LanguageType eNewLang = SC_MOD()->GetOptDigitLanguage();
546     for (VclPtr<ScGridWindow> & pWin : pGridWin)
547         if ( pWin )
548             pWin->GetOutDev()->SetDigitLanguage( eNewLang );
549 }
550 
ScrollToObject(const SdrObject * pDrawObj)551 void ScTabView::ScrollToObject( const SdrObject* pDrawObj )
552 {
553     if ( pDrawObj )
554     {
555         // #i118524# use the BoundRect, this defines the visible area
556         MakeVisible(pDrawObj->GetCurrentBoundRect());
557     }
558 }
559 
MakeVisible(const tools::Rectangle & rHMMRect)560 void ScTabView::MakeVisible( const tools::Rectangle& rHMMRect )
561 {
562     vcl::Window* pWin = GetActiveWin();
563     Size aWinSize = pWin->GetOutputSizePixel();
564     SCTAB nTab = aViewData.GetTabNo();
565 
566     tools::Rectangle aRect = pWin->LogicToPixel( rHMMRect );
567 
568     tools::Long nScrollX=0, nScrollY=0;        // pixel
569 
570     if ( aRect.Right() >= aWinSize.Width() )                // right out
571     {
572         nScrollX = aRect.Right() - aWinSize.Width() + 1;    // right border visible
573         if ( aRect.Left() < nScrollX )
574             nScrollX = aRect.Left();                        // left visible (if too big)
575     }
576     if ( aRect.Bottom() >= aWinSize.Height() )              // bottom out
577     {
578         nScrollY = aRect.Bottom() - aWinSize.Height() + 1;  // bottom border visible
579         if ( aRect.Top() < nScrollY )
580             nScrollY = aRect.Top();                         // top visible (if too big)
581     }
582 
583     if ( aRect.Left() < 0 )             // left out
584         nScrollX = aRect.Left();        // left border visible
585     if ( aRect.Top() < 0 )              // top out
586         nScrollY = aRect.Top();         // top border visible
587 
588     if (!(nScrollX || nScrollY))
589         return;
590 
591     ScDocument& rDoc = aViewData.GetDocument();
592     if ( rDoc.IsNegativePage( nTab ) )
593         nScrollX = -nScrollX;
594 
595     double nPPTX = aViewData.GetPPTX();
596     double nPPTY = aViewData.GetPPTY();
597     ScSplitPos eWhich = aViewData.GetActivePart();
598     SCCOL nPosX = aViewData.GetPosX(WhichH(eWhich));
599     SCROW nPosY = aViewData.GetPosY(WhichV(eWhich));
600 
601     tools::Long nLinesX=0, nLinesY=0;      // columns/rows - scroll at least nScrollX/Y
602 
603     if (nScrollX > 0)
604         while (nScrollX > 0 && nPosX < rDoc.MaxCol())
605         {
606             nScrollX -= static_cast<tools::Long>( rDoc.GetColWidth(nPosX, nTab) * nPPTX );
607             ++nPosX;
608             ++nLinesX;
609         }
610     else if (nScrollX < 0)
611         while (nScrollX < 0 && nPosX > 0)
612         {
613             --nPosX;
614             nScrollX += static_cast<tools::Long>( rDoc.GetColWidth(nPosX, nTab) * nPPTX );
615             --nLinesX;
616         }
617 
618     if (nScrollY > 0)
619         while (nScrollY > 0 && nPosY < rDoc.MaxRow())
620         {
621             nScrollY -= static_cast<tools::Long>( rDoc.GetRowHeight(nPosY, nTab) * nPPTY );
622             ++nPosY;
623             ++nLinesY;
624         }
625     else if (nScrollY < 0)
626         while (nScrollY < 0 && nPosY > 0)
627         {
628             --nPosY;
629             nScrollY += static_cast<tools::Long>( rDoc.GetRowHeight(nPosY, nTab) * nPPTY );
630             --nLinesY;
631         }
632 
633     ScrollLines( nLinesX, nLinesY );                    // execute
634 }
635 
SetBrushDocument(ScDocumentUniquePtr pNew,bool bLock)636 void ScTabView::SetBrushDocument( ScDocumentUniquePtr pNew, bool bLock )
637 {
638     pDrawBrushSet.reset();
639     pBrushDocument = std::move(pNew);
640 
641     bLockPaintBrush = bLock;
642 
643     aViewData.GetBindings().Invalidate(SID_FORMATPAINTBRUSH);
644 }
645 
SetDrawBrushSet(std::unique_ptr<SfxItemSet> pNew,bool bLock)646 void ScTabView::SetDrawBrushSet( std::unique_ptr<SfxItemSet> pNew, bool bLock )
647 {
648     pBrushDocument.reset();
649     pDrawBrushSet = std::move(pNew);
650 
651     bLockPaintBrush = bLock;
652 
653     aViewData.GetBindings().Invalidate(SID_FORMATPAINTBRUSH);
654 }
655 
ResetBrushDocument()656 void ScTabView::ResetBrushDocument()
657 {
658     if ( HasPaintBrush() )
659     {
660         SetBrushDocument( nullptr, false );
661         SetActivePointer( aViewData.IsThemedCursor() ? PointerStyle::FatCross : PointerStyle::Arrow ); // switch pointers also when ended with escape key
662     }
663 }
664 
OnLOKNoteStateChanged(const ScPostIt * pNote)665 void ScTabView::OnLOKNoteStateChanged(const ScPostIt* pNote)
666 {
667     if (!comphelper::LibreOfficeKit::isActive())
668         return;
669 
670     const SdrCaptionObj* pCaption = pNote->GetCaption();
671     if (!pCaption) return;
672 
673     tools::Rectangle aRect = pCaption->GetLogicRect();
674     basegfx::B2DRange aTailRange = pCaption->getTailPolygon().getB2DRange();
675     tools::Rectangle aTailRect(aTailRange.getMinX(), aTailRange.getMinY(),
676                         aTailRange.getMaxX(), aTailRange.getMaxY());
677     aRect.Union( aTailRect );
678 
679     // This is a temporary workaround: sometime in tiled rendering mode
680     // the tip of the note arrow is misplaced by a fixed offset.
681     // The value used below is enough to get the tile, where the arrow tip is
682     // placed, invalidated.
683     const int nBorderSize = 200;
684     tools::Rectangle aInvalidRect = aRect;
685     aInvalidRect.AdjustLeft( -nBorderSize );
686     aInvalidRect.AdjustRight( nBorderSize );
687     aInvalidRect.AdjustTop( -nBorderSize );
688     aInvalidRect.AdjustBottom( nBorderSize );
689 
690     SfxViewShell* pCurrentViewShell = SfxViewShell::Current();
691     SfxViewShell* pViewShell = SfxViewShell::GetFirst();
692     while (pViewShell)
693     {
694         ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
695         if (pTabViewShell && pViewShell->GetDocId() == pCurrentViewShell->GetDocId())
696         {
697             for (auto& pWin: pTabViewShell->pGridWin)
698             {
699                 if (pWin && pWin->IsVisible())
700                 {
701                     pWin->Invalidate(aInvalidRect);
702                 }
703             }
704         }
705         pViewShell = SfxViewShell::GetNext(*pViewShell);
706     }
707 }
708 
709 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
710