xref: /core/sc/source/ui/view/tabvwsh4.cxx (revision 4cfa840e)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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 <sal/config.h>
21 
22 #include <formdata.hxx>
23 
24 #include <sfx2/app.hxx>
25 #include <svx/dialogs.hrc>
26 #include <svx/extrusionbar.hxx>
27 #include <svx/fontworkbar.hxx>
28 #include <editeng/borderline.hxx>
29 #include <svx/fmshell.hxx>
30 #include <svx/sidebar/ContextChangeEventMultiplexer.hxx>
31 #include <sfx2/printer.hxx>
32 #include <sfx2/dispatch.hxx>
33 #include <sfx2/ipclient.hxx>
34 #include <tools/urlobj.hxx>
35 #include <sfx2/docfile.hxx>
36 #include <tools/svborder.hxx>
37 
38 #include <IAnyRefDialog.hxx>
39 #include <tabvwsh.hxx>
40 #include <sc.hrc>
41 #include <globstr.hrc>
42 #include <docsh.hxx>
43 #include <scmod.hxx>
44 #include <appoptio.hxx>
45 #include <drawsh.hxx>
46 #include <drformsh.hxx>
47 #include <editsh.hxx>
48 #include <pivotsh.hxx>
49 #include <auditsh.hxx>
50 #include <drtxtob.hxx>
51 #include <inputhdl.hxx>
52 #include <editutil.hxx>
53 #include <inputopt.hxx>
54 #include <inputwin.hxx>
55 #include <dbdata.hxx>
56 #include <reffact.hxx>
57 #include <viewuno.hxx>
58 #include <dispuno.hxx>
59 #include <chgtrack.hxx>
60 #include <cellsh.hxx>
61 #include <oleobjsh.hxx>
62 #include <chartsh.hxx>
63 #include <graphsh.hxx>
64 #include <mediash.hxx>
65 #include <pgbrksh.hxx>
66 #include <dpobject.hxx>
67 #include <prevwsh.hxx>
68 #include <scextopt.hxx>
69 #include <drawview.hxx>
70 #include <fupoor.hxx>
71 #include <navsett.hxx>
72 #include <scabstdlg.hxx>
73 #include <externalrefmgr.hxx>
74 #include <defaultsoptions.hxx>
75 #include <markdata.hxx>
76 #include <preview.hxx>
77 #include <docoptio.hxx>
78 #include <documentlinkmgr.hxx>
79 #include <gridwin.hxx>
80 
81 #include <com/sun/star/document/XDocumentProperties.hpp>
82 #include <sfx2/lokhelper.hxx>
83 #include <comphelper/flagguard.hxx>
84 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
85 #include <comphelper/lok.hxx>
86 #include <sfx2/sidebar/SidebarController.hxx>
87 
88 using namespace com::sun::star;
89 using namespace sfx2::sidebar;
90 
91 namespace {
92 
93 bool inChartContext(const ScTabViewShell* pViewShell)
94 {
95     SidebarController* pSidebar = SidebarController::GetSidebarControllerForView(pViewShell);
96     if (pSidebar)
97         return pSidebar->hasChartContextCurrently();
98 
99     return false;
100 }
101 
102 } // anonymous namespace
103 
104 void ScTabViewShell::Activate(bool bMDI)
105 {
106     SfxViewShell::Activate(bMDI);
107     bIsActive = true;
108     // here no GrabFocus, otherwise there will be problems when something is edited inplace!
109 
110     if ( bMDI )
111     {
112         // for input row (ClearCache)
113         ScModule* pScMod = SC_MOD();
114         pScMod->ViewShellChanged(/*bStopEditing=*/ !comphelper::LibreOfficeKit::isActive());
115 
116         ActivateView( true, bFirstActivate );
117 
118         // update AutoCorrect, if Writer has newly created this
119         UpdateDrawTextOutliner();
120 
121         // RegisterNewTargetNames does not exist anymore
122 
123         SfxViewFrame* pThisFrame  = GetViewFrame();
124         if ( mpInputHandler && pThisFrame->HasChildWindow(FID_INPUTLINE_STATUS) )
125         {
126             // actually only required for Reload (last version):
127             // The InputWindow remains, but the View along with the InputHandler is newly created,
128             // that is why the InputHandler must be set at the InputWindow.
129             SfxChildWindow* pChild = pThisFrame->GetChildWindow(FID_INPUTLINE_STATUS);
130             if (pChild)
131             {
132                 ScInputWindow* pWin = static_cast<ScInputWindow*>(pChild->GetWindow());
133                 if (pWin && pWin->IsVisible())
134                 {
135 
136                     ScInputHandler* pOldHdl=pWin->GetInputHandler();
137 
138                     SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
139                     while ( pSh!=nullptr && pOldHdl!=nullptr)
140                     {
141                         // Hmm, what if pSh is a shell for a different document? But as this code
142                         // does not seem to be LibreOfficeKit-specific, probably that doesn't
143                         // happen, because having multiple documents open simultaneously has of
144                         // course not been a problem at all in traditional desktop LibreOffice.
145                         // (Unlike in a LibreOfficeKit-based process where it has been a problem.)
146                         if (static_cast<ScTabViewShell*>(pSh)->GetInputHandler() == pOldHdl)
147                         {
148                             pOldHdl->ResetDelayTimer();
149                             break;
150                         }
151                         pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
152                     }
153 
154                     pWin->SetInputHandler( mpInputHandler.get() );
155                 }
156             }
157         }
158 
159         UpdateInputHandler( /*bForce=*/ true, /*bStopEditing=*/ !comphelper::LibreOfficeKit::isActive() );
160 
161         if ( bFirstActivate )
162         {
163             SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScNavigatorUpdateAll ) );
164             bFirstActivate = false;
165 
166             // ReadExtOptions (view settings from Excel import) must also be done
167             // after the ctor, because of the potential calls to Window::Show.
168             // Even after a bugfix (Window::Show no longer notifies the access
169             // bridge, it's done in ImplSetReallyVisible), there are problems if Window::Show
170             // is called during the ViewShell ctor and reschedules asynchronous calls
171             // (for example from the FmFormShell ctor).
172             ScExtDocOptions* pExtOpt = GetViewData().GetDocument().GetExtDocOptions();
173             if ( pExtOpt && pExtOpt->IsChanged() )
174             {
175                 GetViewData().ReadExtOptions(*pExtOpt);        // Excel view settings
176                 SetTabNo( GetViewData().GetTabNo(), true );
177                 pExtOpt->SetChanged( false );
178             }
179         }
180 
181         pScActiveViewShell = this;
182 
183         ScInputHandler* pHdl = pScMod->GetInputHdl(this);
184         if (pHdl)
185         {
186             pHdl->SetRefScale( GetViewData().GetZoomX(), GetViewData().GetZoomY() );
187         }
188 
189         // update change dialog
190 
191         if ( pThisFrame->HasChildWindow(FID_CHG_ACCEPT) )
192         {
193             SfxChildWindow* pChild = pThisFrame->GetChildWindow(FID_CHG_ACCEPT);
194             if (pChild)
195             {
196                 static_cast<ScAcceptChgDlgWrapper*>(pChild)->ReInitDlg();
197             }
198         }
199 
200         if(pScMod->IsRefDialogOpen())
201         {
202             sal_uInt16 nModRefDlgId=pScMod->GetCurRefDlgId();
203             SfxChildWindow* pChildWnd = pThisFrame->GetChildWindow( nModRefDlgId );
204             if ( pChildWnd )
205             {
206                 if (auto pController = pChildWnd->GetController())
207                 {
208                     IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pController.get());
209                     if (pRefDlg)
210                         pRefDlg->ViewShellChanged();
211                 }
212             }
213         }
214     }
215 
216     //  don't call CheckSelectionTransfer here - activating a view should not change the
217     //  primary selection (may be happening just because the mouse was moved over the window)
218 
219     if (!inChartContext(this))
220     {
221         ContextChangeEventMultiplexer::NotifyContextChange(
222             GetController(),
223             vcl::EnumContext::Context::Default);
224     }
225 }
226 
227 void ScTabViewShell::Deactivate(bool bMDI)
228 {
229     HideTip();
230 
231     ScDocument& rDoc = GetViewData().GetDocument();
232 
233     ScChangeTrack* pChanges = rDoc.GetChangeTrack();
234 
235     if(pChanges!=nullptr)
236     {
237         Link<ScChangeTrack&,void> aLink;
238         pChanges->SetModifiedLink(aLink);
239     }
240 
241     SfxViewShell::Deactivate(bMDI);
242     bIsActive = false;
243     ScInputHandler* pHdl = SC_MOD()->GetInputHdl(this);
244 
245     if( bMDI && !comphelper::LibreOfficeKit::isActive())
246     {
247         //  during shell deactivation, shells must not be switched, or the loop
248         //  through the shell stack (in SfxDispatcher::DoDeactivate_Impl) will not work
249         bool bOldDontSwitch = bDontSwitch;
250         bDontSwitch = true;
251 
252         ActivateView( false, false );
253 
254         if ( GetViewFrame()->GetFrame().IsInPlace() ) // inplace
255             GetViewData().GetDocShell()->UpdateOle(GetViewData(), true);
256 
257         if ( pHdl )
258             pHdl->NotifyChange( nullptr, true ); // timer-delayed due to document switching
259 
260         if (pScActiveViewShell == this)
261             pScActiveViewShell = nullptr;
262 
263         bDontSwitch = bOldDontSwitch;
264     }
265     else
266     {
267         HideNoteMarker();           // note marker
268 
269         if ( pHdl )
270             pHdl->HideTip();        // Hide formula auto input tip
271     }
272 }
273 
274 void ScTabViewShell::SetActive()
275 {
276     // SFX-View would like to activate itself, since then magical things would happen
277     // (eg else the designer may crash)
278     ActiveGrabFocus();
279 }
280 
281 bool ScTabViewShell::PrepareClose(bool bUI)
282 {
283     comphelper::FlagRestorationGuard aFlagGuard(bInPrepareClose, true);
284 
285     // Call EnterHandler even in formula mode here,
286     // so a formula change in an embedded object isn't lost
287     // (ScDocShell::PrepareClose isn't called then).
288     ScInputHandler* pHdl = SC_MOD()->GetInputHdl( this );
289     if ( pHdl && pHdl->IsInputMode() )
290     {
291         pHdl->EnterHandler();
292     }
293 
294     // draw text edit mode must be closed
295     FuPoor* pPoor = GetDrawFuncPtr();
296     if (pPoor && IsDrawTextShell())
297     {
298         // "clean" end of text edit, including note handling, subshells and draw func switching,
299         // as in FuDraw and ScTabView::DrawDeselectAll
300         GetViewData().GetDispatcher().Execute( pPoor->GetSlotID(), SfxCallMode::SLOT | SfxCallMode::RECORD );
301     }
302     ScDrawView* pDrView = GetScDrawView();
303     if ( pDrView )
304     {
305         // force end of text edit, to be safe
306         // ScEndTextEdit must always be used, to ensure correct UndoManager
307         pDrView->ScEndTextEdit();
308     }
309 
310     if ( pFormShell )
311     {
312         bool bRet = pFormShell->PrepareClose(bUI);
313         if (!bRet)
314             return bRet;
315     }
316     return SfxViewShell::PrepareClose(bUI);
317 }
318 
319 // calculate zoom for in-place
320 // from the ratio of VisArea and window size of GridWin
321 
322 void ScTabViewShell::UpdateOleZoom()
323 {
324     ScDocShell* pDocSh = GetViewData().GetDocShell();
325     if ( pDocSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
326     {
327         //TODO/LATER: is there a difference between the two GetVisArea methods?
328         Size aObjSize = static_cast<const SfxObjectShell*>(pDocSh)->GetVisArea().GetSize();
329         if ( !aObjSize.IsEmpty() )
330         {
331             vcl::Window* pWin = GetActiveWin();
332             Size aWinHMM = pWin->PixelToLogic(pWin->GetOutputSizePixel(), MapMode(MapUnit::Map100thMM));
333             SetZoomFactor( Fraction( aWinHMM.Width(),aObjSize.Width() ),
334                             Fraction( aWinHMM.Height(),aObjSize.Height() ) );
335         }
336     }
337 }
338 
339 void ScTabViewShell::InnerResizePixel( const Point &rOfs, const Size &rSize, bool inplaceEditModeChange )
340 {
341     Size aNewSize( rSize );
342     if ( GetViewFrame()->GetFrame().IsInPlace() )
343     {
344         SvBorder aBorder;
345         GetBorderSize( aBorder, rSize );
346         SetBorderPixel( aBorder );
347 
348         Size aObjSize = GetObjectShell()->GetVisArea().GetSize();
349 
350         Size aSize( rSize );
351         aSize.AdjustWidth( -(aBorder.Left() + aBorder.Right()) );
352         aSize.AdjustHeight( -(aBorder.Top() + aBorder.Bottom()) );
353 
354         if ( !aObjSize.IsEmpty() )
355         {
356             Size aLogicSize = GetWindow()->PixelToLogic(aSize, MapMode(MapUnit::Map100thMM));
357             SfxViewShell::SetZoomFactor( Fraction( aLogicSize.Width(),aObjSize.Width() ),
358                             Fraction( aLogicSize.Height(),aObjSize.Height() ) );
359         }
360 
361         Point aPos( rOfs );
362         aPos.AdjustX(aBorder.Left() );
363         aPos.AdjustY(aBorder.Top() );
364         GetWindow()->SetPosSizePixel( aPos, aSize );
365     }
366     else
367     {
368         SvBorder aBorder;
369         GetBorderSize( aBorder, rSize );
370         SetBorderPixel( aBorder );
371         aNewSize.AdjustWidth(aBorder.Left() + aBorder.Right() );
372         aNewSize.AdjustHeight(aBorder.Top() + aBorder.Bottom() );
373     }
374 
375     DoResize( rOfs, aNewSize, true );                   // rSize = size of gridwin
376 
377     UpdateOleZoom();                                    // calculate zoom for in-place
378 
379     if (!inplaceEditModeChange)
380     {
381         GetViewData().GetDocShell()->SetDocumentModified();
382     }
383 }
384 
385 void ScTabViewShell::OuterResizePixel( const Point &rOfs, const Size &rSize )
386 {
387     SvBorder aBorder;
388     GetBorderSize( aBorder, rSize );
389     SetBorderPixel( aBorder );
390 
391     DoResize( rOfs, rSize );                    // position and size of tabview as passed
392 
393     // ForceMove as replacement for Sfx-Move mechanism
394     // (aWinPos must be kept current, so that ForceMove works for Ole deactivation)
395 
396     ForceMove();
397 }
398 
399 void ScTabViewShell::SetZoomFactor( const Fraction &rZoomX, const Fraction &rZoomY )
400 {
401     // for OLE...
402 
403     Fraction aFrac20( 1,5 );
404     Fraction aFrac400( 4,1 );
405 
406     Fraction aNewX( rZoomX );
407     if ( aNewX < aFrac20 )
408         aNewX = aFrac20;
409     if ( aNewX > aFrac400 )
410         aNewX = aFrac400;
411     Fraction aNewY( rZoomY );
412     if ( aNewY < aFrac20 )
413         aNewY = aFrac20;
414     if ( aNewY > aFrac400 )
415         aNewY = aFrac400;
416 
417     GetViewData().UpdateScreenZoom( aNewX, aNewY );
418     SetZoom( aNewX, aNewY, true );
419 
420     PaintGrid();
421     PaintTop();
422     PaintLeft();
423 
424     SfxViewShell::SetZoomFactor( rZoomX, rZoomY );
425 }
426 
427 void ScTabViewShell::QueryObjAreaPixel( tools::Rectangle& rRect ) const
428 {
429     // adjust to entire cells (in 1/100 mm)
430 
431     Size aPixelSize = rRect.GetSize();
432     vcl::Window* pWin = const_cast<ScTabViewShell*>(this)->GetActiveWin();
433     Size aLogicSize = pWin->PixelToLogic( aPixelSize );
434 
435     const ScViewData& rViewData = GetViewData();
436     ScDocument& rDoc = rViewData.GetDocument();
437     ScSplitPos ePos = rViewData.GetActivePart();
438     SCCOL nCol = rViewData.GetPosX(WhichH(ePos));
439     SCROW nRow = rViewData.GetPosY(WhichV(ePos));
440     SCTAB nTab = rViewData.GetTabNo();
441     bool bNegativePage = rDoc.IsNegativePage( nTab );
442 
443     tools::Rectangle aLogicRect = rDoc.GetMMRect( nCol, nRow, nCol, nRow, nTab );
444     if ( bNegativePage )
445     {
446         // use right edge of aLogicRect, and aLogicSize
447         aLogicRect.SetLeft( aLogicRect.Right() - aLogicSize.Width() + 1 );    // Right() is set below
448     }
449     aLogicRect.SetSize( aLogicSize );
450 
451     rViewData.GetDocShell()->SnapVisArea( aLogicRect );
452 
453     rRect.SetSize( pWin->LogicToPixel( aLogicRect.GetSize() ) );
454 }
455 
456 void ScTabViewShell::Move()
457 {
458     Point aNewPos = GetViewFrame()->GetWindow().OutputToScreenPixel(Point());
459 
460     if (aNewPos != aWinPos)
461     {
462         StopMarking();
463         aWinPos = aNewPos;
464     }
465 }
466 
467 void ScTabViewShell::ShowCursor(bool /* bOn */)
468 {
469 /*!!!   ShowCursor is not called as a pair as in gridwin.
470         here the CursorLockCount for Gridwin must be set directly to 0
471 
472     if (bOn)
473         ShowAllCursors();
474     else
475         HideAllCursors();
476 */
477 }
478 
479 void ScTabViewShell::WriteUserData(OUString& rData, bool /* bBrowse */)
480 {
481     GetViewData().WriteUserData(rData);
482 }
483 
484 void ScTabViewShell::WriteUserDataSequence (uno::Sequence < beans::PropertyValue >& rSettings )
485 {
486     GetViewData().WriteUserDataSequence(rSettings);
487 }
488 
489 void ScTabViewShell::ReadUserData(const OUString& rData, bool /* bBrowse */)
490 {
491     if ( !GetViewData().GetDocShell()->IsPreview() )
492         DoReadUserData( rData );
493 }
494 
495 void ScTabViewShell::ReadUserDataSequence (const uno::Sequence < beans::PropertyValue >& rSettings )
496 {
497     if ( !GetViewData().GetDocShell()->IsPreview() )
498         DoReadUserDataSequence( rSettings );
499 }
500 
501 void ScTabViewShell::DoReadUserDataSequence( const uno::Sequence < beans::PropertyValue >& rSettings )
502 {
503     vcl::Window* pOldWin = GetActiveWin();
504     bool bFocus = pOldWin && pOldWin->HasFocus();
505 
506     GetViewData().ReadUserDataSequence(rSettings);
507     SetTabNo( GetViewData().GetTabNo(), true );
508 
509     if ( GetViewData().IsPagebreakMode() )
510         SetCurSubShell( GetCurObjectSelectionType(), true );
511 
512     vcl::Window* pNewWin = GetActiveWin();
513     if (pNewWin && pNewWin != pOldWin)
514     {
515         SetWindow( pNewWin );       //! is this ViewShell always active???
516         if (bFocus)
517             pNewWin->GrabFocus();
518         WindowChanged();            // drawing layer (for instance #56771#)
519     }
520 
521     if (GetViewData().GetHSplitMode() == SC_SPLIT_FIX ||
522         GetViewData().GetVSplitMode() == SC_SPLIT_FIX)
523     {
524         InvalidateSplit();
525     }
526 
527     ZoomChanged();
528 
529     TestHintWindow();
530 
531     //! if ViewData has more tables than document, remove tables in ViewData
532 }
533 
534 // DoReadUserData is also called from ctor when switching from print preview
535 
536 void ScTabViewShell::DoReadUserData( const OUString& rData )
537 {
538     vcl::Window* pOldWin = GetActiveWin();
539     bool bFocus = pOldWin && pOldWin->HasFocus();
540 
541     GetViewData().ReadUserData(rData);
542     SetTabNo( GetViewData().GetTabNo(), true );
543 
544     if ( GetViewData().IsPagebreakMode() )
545         SetCurSubShell( GetCurObjectSelectionType(), true );
546 
547     vcl::Window* pNewWin = GetActiveWin();
548     if (pNewWin && pNewWin != pOldWin)
549     {
550         SetWindow( pNewWin );       //! is this ViewShell always active???
551         if (bFocus)
552             pNewWin->GrabFocus();
553         WindowChanged();            // drawing layer (for instance #56771#)
554     }
555 
556     if (GetViewData().GetHSplitMode() == SC_SPLIT_FIX ||
557         GetViewData().GetVSplitMode() == SC_SPLIT_FIX)
558     {
559         InvalidateSplit();
560     }
561 
562     ZoomChanged();
563 
564     TestHintWindow();
565 
566     //! if ViewData has more tables than document, remove tables in ViewData
567 }
568 
569 void ScTabViewShell::UpdateDrawShell()
570 {
571     // Called after user interaction that may delete the selected drawing object.
572     // Remove DrawShell if nothing is selected.
573 
574     SdrView* pDrView = GetScDrawView();
575     if ( pDrView && !pDrView->AreObjectsMarked() && !IsDrawSelMode() )
576         SetDrawShell( false );
577 }
578 
579 void ScTabViewShell::SetDrawShellOrSub()
580 {
581     bActiveDrawSh = true;
582 
583     if(bActiveDrawFormSh)
584     {
585         SetCurSubShell(OST_DrawForm);
586     }
587     else if(bActiveGraphicSh)
588     {
589         SetCurSubShell(OST_Graphic);
590     }
591     else if(bActiveMediaSh)
592     {
593         SetCurSubShell(OST_Media);
594     }
595     else if(bActiveChartSh)
596     {
597         SetCurSubShell(OST_Chart);
598     }
599     else if(bActiveOleObjectSh)
600     {
601         SetCurSubShell(OST_OleObject);
602     }
603     else
604     {
605         SetCurSubShell(OST_Drawing, true /* force: different toolbars are
606                                             visible concerning shape type
607                                             and shape state */);
608     }
609 }
610 
611 void ScTabViewShell::SetDrawShell( bool bActive )
612 {
613     if(bActive)
614     {
615         SetCurSubShell(OST_Drawing, true /* force: different toolbars are
616                                             visible concerning shape type
617                                             and shape state */);
618     }
619     else
620     {
621         if(bActiveDrawFormSh || bActiveDrawSh ||
622             bActiveGraphicSh || bActiveMediaSh || bActiveOleObjectSh||
623             bActiveChartSh || bActiveDrawTextSh)
624         {
625             SetCurSubShell(OST_Cell);
626         }
627         bActiveDrawFormSh=false;
628         bActiveGraphicSh=false;
629         bActiveMediaSh=false;
630         bActiveOleObjectSh=false;
631         bActiveChartSh=false;
632     }
633 
634     bool bWasDraw = bActiveDrawSh || bActiveDrawTextSh;
635 
636     bActiveDrawSh = bActive;
637     bActiveDrawTextSh = false;
638 
639     if ( !bActive )
640     {
641         ResetDrawDragMode();        // switch off Mirror / Rotate
642 
643         if (bWasDraw && (GetViewData().GetHSplitMode() == SC_SPLIT_FIX ||
644                          GetViewData().GetVSplitMode() == SC_SPLIT_FIX))
645         {
646             // adjust active part to cursor, etc.
647             MoveCursorAbs( GetViewData().GetCurX(), GetViewData().GetCurY(),
648                             SC_FOLLOW_NONE, false, false, true );
649         }
650     }
651 }
652 
653 void ScTabViewShell::SetDrawTextShell( bool bActive )
654 {
655     bActiveDrawTextSh = bActive;
656     if ( bActive )
657     {
658         bActiveDrawFormSh=false;
659         bActiveGraphicSh=false;
660         bActiveMediaSh=false;
661         bActiveOleObjectSh=false;
662         bActiveChartSh=false;
663         bActiveDrawSh = false;
664         SetCurSubShell(OST_DrawText);
665     }
666     else
667         SetCurSubShell(OST_Cell);
668 
669 }
670 
671 void ScTabViewShell::SetPivotShell( bool bActive )
672 {
673     //  SetPivotShell is called from CursorPosChanged every time
674     //  -> don't change anything except switching between cell and pivot shell
675 
676     if (eCurOST != OST_Pivot && eCurOST != OST_Cell)
677         return;
678 
679     if ( bActive )
680     {
681         bActiveDrawTextSh = bActiveDrawSh = false;
682         bActiveDrawFormSh=false;
683         bActiveGraphicSh=false;
684         bActiveMediaSh=false;
685         bActiveOleObjectSh=false;
686         bActiveChartSh=false;
687         SetCurSubShell(OST_Pivot);
688     }
689     else
690         SetCurSubShell(OST_Cell);
691 }
692 
693 void ScTabViewShell::SetAuditShell( bool bActive )
694 {
695     if ( bActive )
696     {
697         bActiveDrawTextSh = bActiveDrawSh = false;
698         bActiveDrawFormSh=false;
699         bActiveGraphicSh=false;
700         bActiveMediaSh=false;
701         bActiveOleObjectSh=false;
702         bActiveChartSh=false;
703         SetCurSubShell(OST_Auditing);
704     }
705     else
706         SetCurSubShell(OST_Cell);
707 }
708 
709 void ScTabViewShell::SetDrawFormShell( bool bActive )
710 {
711     bActiveDrawFormSh = bActive;
712 
713     if(bActiveDrawFormSh)
714         SetCurSubShell(OST_DrawForm);
715 }
716 void ScTabViewShell::SetChartShell( bool bActive )
717 {
718     bActiveChartSh = bActive;
719 
720     if(bActiveChartSh)
721         SetCurSubShell(OST_Chart);
722 }
723 
724 void ScTabViewShell::SetGraphicShell( bool bActive )
725 {
726     bActiveGraphicSh = bActive;
727 
728     if(bActiveGraphicSh)
729         SetCurSubShell(OST_Graphic);
730 }
731 
732 void ScTabViewShell::SetMediaShell( bool bActive )
733 {
734     bActiveMediaSh = bActive;
735 
736     if(bActiveMediaSh)
737         SetCurSubShell(OST_Media);
738 }
739 
740 void ScTabViewShell::SetOleObjectShell( bool bActive )
741 {
742     bActiveOleObjectSh = bActive;
743 
744     if(bActiveOleObjectSh)
745         SetCurSubShell(OST_OleObject);
746     else
747         SetCurSubShell(OST_Cell);
748 }
749 
750 void ScTabViewShell::SetEditShell(EditView* pView, bool bActive )
751 {
752     if(bActive)
753     {
754         if (pEditShell)
755             pEditShell->SetEditView( pView );
756         else
757             pEditShell.reset( new ScEditShell(pView, GetViewData()) );
758 
759         SetCurSubShell(OST_Editing);
760     }
761     else if(bActiveEditSh)
762     {
763         SetCurSubShell(OST_Cell);
764     }
765     bActiveEditSh = bActive;
766 }
767 
768 void ScTabViewShell::SetCurSubShell(ObjectSelectionType eOST, bool bForce)
769 {
770     ScViewData& rViewData   = GetViewData();
771     ScDocShell* pDocSh      = rViewData.GetDocShell();
772 
773     if(bDontSwitch) return;
774 
775     if(!pCellShell) // is anyway always used
776     {
777         pCellShell.reset(new ScCellShell(GetViewData(), GetFrameWin()));
778         pCellShell->SetRepeatTarget( &aTarget );
779     }
780 
781     bool bPgBrk = rViewData.IsPagebreakMode();
782 
783     if(bPgBrk && !pPageBreakShell)
784     {
785         pPageBreakShell.reset( new ScPageBreakShell( this ) );
786         pPageBreakShell->SetRepeatTarget( &aTarget );
787     }
788 
789     if ( !(eOST!=eCurOST || bForce) )
790         return;
791 
792     bool bCellBrush = false;    // "format paint brush" allowed for cells
793     bool bDrawBrush = false;    // "format paint brush" allowed for drawing objects
794 
795     if(eCurOST!=OST_NONE) RemoveSubShell();
796 
797     if (pFormShell && !bFormShellAtTop)
798         AddSubShell(*pFormShell);               // add below own subshells
799 
800     switch(eOST)
801     {
802         case    OST_Cell:
803         {
804             AddSubShell(*pCellShell);
805             if(bPgBrk) AddSubShell(*pPageBreakShell);
806             bCellBrush = true;
807         }
808         break;
809         case    OST_Editing:
810         {
811             AddSubShell(*pCellShell);
812             if(bPgBrk) AddSubShell(*pPageBreakShell);
813 
814             if(pEditShell)
815             {
816                 AddSubShell(*pEditShell);
817             }
818         }
819         break;
820         case    OST_DrawText:
821         {
822             if ( !pDrawTextShell )
823             {
824                 pDocSh->MakeDrawLayer();
825                 pDrawTextShell.reset( new ScDrawTextObjectBar(GetViewData()) );
826             }
827             AddSubShell(*pDrawTextShell);
828         }
829         break;
830         case    OST_Drawing:
831         {
832             if (svx::checkForSelectedCustomShapes(
833                         GetScDrawView(), true /* bOnlyExtruded */ )) {
834                 if (pExtrusionBarShell == nullptr)
835                     pExtrusionBarShell.reset( new svx::ExtrusionBar(this) );
836                 AddSubShell( *pExtrusionBarShell );
837             }
838 
839             if (svx::checkForSelectedFontWork(
840                         GetScDrawView() )) {
841                 if (pFontworkBarShell == nullptr)
842                     pFontworkBarShell.reset( new svx::FontworkBar(this) );
843                 AddSubShell( *pFontworkBarShell );
844             }
845 
846             if ( !pDrawShell )
847             {
848                 pDocSh->MakeDrawLayer();
849                 pDrawShell.reset(new ScDrawShell(GetViewData()));
850                 pDrawShell->SetRepeatTarget( &aTarget );
851             }
852             AddSubShell(*pDrawShell);
853             bDrawBrush = true;
854         }
855         break;
856 
857         case    OST_DrawForm:
858         {
859             if ( !pDrawFormShell )
860             {
861                 pDocSh->MakeDrawLayer();
862                 pDrawFormShell.reset( new ScDrawFormShell(GetViewData()) );
863                 pDrawFormShell->SetRepeatTarget( &aTarget );
864             }
865             AddSubShell(*pDrawFormShell);
866             bDrawBrush = true;
867         }
868         break;
869 
870         case    OST_Chart:
871         {
872             if ( !pChartShell )
873             {
874                 pDocSh->MakeDrawLayer();
875                 pChartShell.reset( new ScChartShell(GetViewData()) );
876                 pChartShell->SetRepeatTarget( &aTarget );
877             }
878             AddSubShell(*pChartShell);
879             bDrawBrush = true;
880         }
881         break;
882 
883         case    OST_OleObject:
884         {
885             if ( !pOleObjectShell )
886             {
887                 pDocSh->MakeDrawLayer();
888                 pOleObjectShell.reset( new ScOleObjectShell(GetViewData()) );
889                 pOleObjectShell->SetRepeatTarget( &aTarget );
890             }
891             AddSubShell(*pOleObjectShell);
892             bDrawBrush = true;
893         }
894         break;
895 
896         case    OST_Graphic:
897         {
898             if ( !pGraphicShell)
899             {
900                 pDocSh->MakeDrawLayer();
901                 pGraphicShell.reset( new ScGraphicShell(GetViewData()) );
902                 pGraphicShell->SetRepeatTarget( &aTarget );
903             }
904             AddSubShell(*pGraphicShell);
905             bDrawBrush = true;
906         }
907         break;
908 
909         case    OST_Media:
910         {
911             if ( !pMediaShell)
912             {
913                 pDocSh->MakeDrawLayer();
914                 pMediaShell.reset( new ScMediaShell(GetViewData()) );
915                 pMediaShell->SetRepeatTarget( &aTarget );
916             }
917             AddSubShell(*pMediaShell);
918         }
919         break;
920 
921         case    OST_Pivot:
922         {
923             AddSubShell(*pCellShell);
924             if(bPgBrk) AddSubShell(*pPageBreakShell);
925 
926             if ( !pPivotShell )
927             {
928                 pPivotShell.reset( new ScPivotShell( this ) );
929                 pPivotShell->SetRepeatTarget( &aTarget );
930             }
931             AddSubShell(*pPivotShell);
932             bCellBrush = true;
933         }
934         break;
935         case    OST_Auditing:
936         {
937             AddSubShell(*pCellShell);
938             if(bPgBrk) AddSubShell(*pPageBreakShell);
939 
940             if ( !pAuditingShell )
941             {
942                 pDocSh->MakeDrawLayer();    // the waiting time rather now as on the click
943 
944                 pAuditingShell.reset( new ScAuditingShell(GetViewData()) );
945                 pAuditingShell->SetRepeatTarget( &aTarget );
946             }
947             AddSubShell(*pAuditingShell);
948             bCellBrush = true;
949         }
950         break;
951         default:
952         OSL_FAIL("wrong shell requested");
953         break;
954     }
955 
956     if (pFormShell && bFormShellAtTop)
957         AddSubShell(*pFormShell);               // add on top of own subshells
958 
959     eCurOST=eOST;
960 
961     // abort "format paint brush" when switching to an incompatible shell
962     if ( ( GetBrushDocument() && !bCellBrush ) || ( GetDrawBrushSet() && !bDrawBrush ) )
963         ResetBrushDocument();
964 }
965 
966 void ScTabViewShell::SetFormShellAtTop( bool bSet )
967 {
968     if ( pFormShell && !bSet )
969         pFormShell->ForgetActiveControl();      // let the FormShell know it no longer has the focus
970 
971     if ( bFormShellAtTop != bSet )
972     {
973         bFormShellAtTop = bSet;
974         SetCurSubShell( GetCurObjectSelectionType(), true );
975     }
976 }
977 
978 IMPL_LINK_NOARG(ScTabViewShell, FormControlActivated, LinkParamNone*, void)
979 {
980     // a form control got the focus, so the form shell has to be on top
981     SetFormShellAtTop( true );
982 }
983 
984 // GetMySubShell / SetMySubShell: simulate old behavior,
985 // so that there is only one SubShell (only within the 5 own SubShells)
986 
987 SfxShell* ScTabViewShell::GetMySubShell() const
988 {
989     //  GetSubShell() was const before, and GetSubShell(sal_uInt16) should also be const...
990 
991     sal_uInt16 nPos = 0;
992     SfxShell* pSub = const_cast<ScTabViewShell*>(this)->GetSubShell(nPos);
993     while (pSub)
994     {
995         if ( pSub == pDrawShell.get()  || pSub == pDrawTextShell.get() || pSub == pEditShell.get() ||
996              pSub == pPivotShell.get() || pSub == pAuditingShell.get() || pSub == pDrawFormShell.get() ||
997              pSub == pCellShell.get()  || pSub == pOleObjectShell.get() || pSub == pChartShell.get() ||
998              pSub == pGraphicShell.get() || pSub == pMediaShell.get() || pSub == pPageBreakShell.get())
999             return pSub;    // found
1000 
1001         pSub = const_cast<ScTabViewShell*>(this)->GetSubShell(++nPos);
1002     }
1003     return nullptr;        // none from mine present
1004 }
1005 
1006 bool ScTabViewShell::IsDrawTextShell() const
1007 {
1008     return ( pDrawTextShell && ( GetMySubShell() == pDrawTextShell.get() ) );
1009 }
1010 
1011 bool ScTabViewShell::IsAuditShell() const
1012 {
1013     return ( pAuditingShell && ( GetMySubShell() == pAuditingShell.get() ) );
1014 }
1015 
1016 void ScTabViewShell::SetDrawTextUndo( SfxUndoManager* pNewUndoMgr )
1017 {
1018     // Default: undo manager for DocShell
1019     if (!pNewUndoMgr)
1020         pNewUndoMgr = GetViewData().GetDocShell()->GetUndoManager();
1021 
1022     if (pDrawTextShell)
1023     {
1024         pDrawTextShell->SetUndoManager(pNewUndoMgr);
1025         ScDocShell* pDocSh = GetViewData().GetDocShell();
1026         if ( pNewUndoMgr == pDocSh->GetUndoManager() &&
1027              !pDocSh->GetDocument().IsUndoEnabled() )
1028         {
1029             pNewUndoMgr->SetMaxUndoActionCount( 0 );
1030         }
1031     }
1032     else
1033     {
1034         OSL_FAIL("SetDrawTextUndo without DrawTextShell");
1035     }
1036 }
1037 
1038 ScTabViewShell* ScTabViewShell::GetActiveViewShell()
1039 {
1040     return dynamic_cast< ScTabViewShell *>( Current() );
1041 }
1042 
1043 SfxPrinter* ScTabViewShell::GetPrinter( bool bCreate )
1044 {
1045     // printer is always present (is created for the FontList already on start-up)
1046     return GetViewData().GetDocShell()->GetPrinter(bCreate);
1047 }
1048 
1049 sal_uInt16 ScTabViewShell::SetPrinter( SfxPrinter *pNewPrinter, SfxPrinterChangeFlags nDiffFlags )
1050 {
1051     return GetViewData().GetDocShell()->SetPrinter( pNewPrinter, nDiffFlags );
1052 }
1053 
1054 bool ScTabViewShell::HasPrintOptionsPage() const
1055 {
1056     return true;
1057 }
1058 
1059 std::unique_ptr<SfxTabPage> ScTabViewShell::CreatePrintOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rOptions )
1060 {
1061     ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
1062     ::CreateTabPage ScTpPrintOptionsCreate = pFact->GetTabPageCreatorFunc(RID_SC_TP_PRINT);
1063     if ( ScTpPrintOptionsCreate )
1064         return ScTpPrintOptionsCreate(pPage, pController, &rOptions);
1065     return nullptr;
1066 }
1067 
1068 void ScTabViewShell::StopEditShell()
1069 {
1070     if ( pEditShell != nullptr && !bDontSwitch )
1071         SetEditShell(nullptr, false );
1072 }
1073 
1074 // close handler to ensure function of dialog:
1075 
1076 IMPL_LINK_NOARG(ScTabViewShell, SimpleRefClose, const OUString*, void)
1077 {
1078     SfxInPlaceClient* pClient = GetIPClient();
1079     if ( pClient && pClient->IsObjectInPlaceActive() )
1080     {
1081         // If range selection was started with an active embedded object,
1082         // switch back to original sheet (while the dialog is still open).
1083 
1084         SetTabNo( GetViewData().GetRefTabNo() );
1085     }
1086 
1087     ScSimpleRefDlgWrapper::SetAutoReOpen( true );
1088 }
1089 
1090 // handlers to call UNO listeners:
1091 
1092 static ScTabViewObj* lcl_GetViewObj( const ScTabViewShell& rShell )
1093 {
1094     ScTabViewObj* pRet = nullptr;
1095     SfxViewFrame* pViewFrame = rShell.GetViewFrame();
1096     if (pViewFrame)
1097     {
1098         SfxFrame& rFrame = pViewFrame->GetFrame();
1099         uno::Reference<frame::XController> xController = rFrame.GetController();
1100         if (xController.is())
1101             pRet = comphelper::getFromUnoTunnel<ScTabViewObj>( xController );
1102     }
1103     return pRet;
1104 }
1105 
1106 IMPL_LINK( ScTabViewShell, SimpleRefDone, const OUString&, aResult, void )
1107 {
1108     ScTabViewObj* pImpObj = lcl_GetViewObj( *this );
1109     if ( pImpObj )
1110         pImpObj->RangeSelDone( aResult );
1111 }
1112 
1113 IMPL_LINK( ScTabViewShell, SimpleRefAborted, const OUString&, rResult, void )
1114 {
1115     ScTabViewObj* pImpObj = lcl_GetViewObj( *this );
1116     if ( pImpObj )
1117         pImpObj->RangeSelAborted( rResult );
1118 }
1119 
1120 IMPL_LINK( ScTabViewShell, SimpleRefChange, const OUString&, rResult, void )
1121 {
1122     ScTabViewObj* pImpObj = lcl_GetViewObj( *this );
1123     if ( pImpObj )
1124         pImpObj->RangeSelChanged( rResult );
1125 }
1126 
1127 void ScTabViewShell::StartSimpleRefDialog(
1128             const OUString& rTitle, const OUString& rInitVal,
1129             bool bCloseOnButtonUp, bool bSingleCell, bool bMultiSelection )
1130 {
1131     SfxViewFrame* pViewFrm = GetViewFrame();
1132 
1133     if ( GetActiveViewShell() != this )
1134     {
1135         // #i18833# / #i34499# The API method can be called for a view that's not active.
1136         // Then the view has to be activated first, the same way as in Execute for SID_CURRENTDOC.
1137         // Can't use GrabFocus here, because it needs to take effect immediately.
1138 
1139         pViewFrm->GetFrame().Appear();
1140     }
1141 
1142     sal_uInt16 nId = ScSimpleRefDlgWrapper::GetChildWindowId();
1143 
1144     SC_MOD()->SetRefDialog( nId, true, pViewFrm );
1145 
1146     ScSimpleRefDlgWrapper* pWnd = static_cast<ScSimpleRefDlgWrapper*>(pViewFrm->GetChildWindow( nId ));
1147     if (!pWnd)
1148         return;
1149 
1150     pWnd->SetCloseHdl( LINK( this, ScTabViewShell, SimpleRefClose ) );
1151     pWnd->SetUnoLinks( LINK( this, ScTabViewShell, SimpleRefDone ),
1152                        LINK( this, ScTabViewShell, SimpleRefAborted ),
1153                        LINK( this, ScTabViewShell, SimpleRefChange ) );
1154     pWnd->SetRefString( rInitVal );
1155     pWnd->SetFlags( bCloseOnButtonUp, bSingleCell, bMultiSelection );
1156     ScSimpleRefDlgWrapper::SetAutoReOpen( false );
1157     if (auto xWin = pWnd->GetController())
1158         xWin->set_title(rTitle);
1159     pWnd->StartRefInput();
1160 }
1161 
1162 void ScTabViewShell::StopSimpleRefDialog()
1163 {
1164     SfxViewFrame* pViewFrm = GetViewFrame();
1165     sal_uInt16 nId = ScSimpleRefDlgWrapper::GetChildWindowId();
1166 
1167     ScSimpleRefDlgWrapper* pWnd = static_cast<ScSimpleRefDlgWrapper*>(pViewFrm->GetChildWindow( nId ));
1168     if (pWnd)
1169     {
1170         if (auto pWin = pWnd->GetController())
1171             pWin->response(RET_CLOSE);
1172     }
1173 }
1174 
1175 bool ScTabViewShell::TabKeyInput(const KeyEvent& rKEvt)
1176 {
1177     ScModule* pScMod = SC_MOD();
1178 
1179     SfxViewFrame* pThisFrame = GetViewFrame();
1180     if ( pThisFrame->GetChildWindow( SID_OPENDLG_FUNCTION ) )
1181         return false;
1182 
1183     vcl::KeyCode aCode = rKEvt.GetKeyCode();
1184     bool bShift     = aCode.IsShift();
1185     bool bControl   = aCode.IsMod1();
1186     bool bAlt       = aCode.IsMod2();
1187     sal_uInt16 nCode    = aCode.GetCode();
1188     bool bUsed      = false;
1189     bool bInPlace   = pScMod->IsEditMode();     // Editengine gets all
1190     bool bAnyEdit   = pScMod->IsInputMode();    // only characters & backspace
1191     bool bDraw      = IsDrawTextEdit();
1192 
1193     HideNoteMarker();   // note marker
1194 
1195     // don't do extra HideCursor/ShowCursor calls if EnterHandler will switch to a different sheet
1196     bool bOnRefSheet = ( GetViewData().GetRefTabNo() == GetViewData().GetTabNo() );
1197     bool bHideCursor = ( ( nCode == KEY_RETURN && bInPlace ) || nCode == KEY_TAB ) && bOnRefSheet;
1198 
1199     if (bHideCursor)
1200         HideAllCursors();
1201 
1202     ScDocument& rDoc = GetViewData().GetDocument();
1203     rDoc.KeyInput();    // TimerDelays etc.
1204 
1205     if( bInPlace )
1206     {
1207         bUsed = pScMod->InputKeyEvent( rKEvt );         // input
1208         if( !bUsed )
1209             bUsed = SfxViewShell::KeyInput( rKEvt );    // accelerators
1210     }
1211     else if( bAnyEdit )
1212     {
1213         bool bIsType = false;
1214         sal_uInt16 nModi = aCode.GetModifier();
1215         sal_uInt16 nGroup = aCode.GetGroup();
1216 
1217         if ( nGroup == KEYGROUP_NUM || nGroup == KEYGROUP_ALPHA || nGroup == 0 )
1218             if ( !bControl && !bAlt )
1219                 bIsType = true;
1220 
1221         if ( nGroup == KEYGROUP_MISC )
1222             switch ( nCode )
1223             {
1224                 case KEY_RETURN:
1225                     bIsType = bControl && !bAlt;        // Control, Shift-Control-Return
1226                     if ( !bIsType && nModi == 0 )
1227                     {
1228                         // Does the Input Handler also want a simple Return?
1229 
1230                         ScInputHandler* pHdl = pScMod->GetInputHdl(this);
1231                         bIsType = pHdl && pHdl->TakesReturn();
1232                     }
1233                     break;
1234                 case KEY_SPACE:
1235                     bIsType = !bControl && !bAlt;       // without modifier or Shift-Space
1236                     break;
1237                 case KEY_ESCAPE:
1238                     bIsType = (nModi == 0); // only without modifier
1239                     break;
1240                 default:
1241                     bIsType = true;
1242             }
1243         else if (nCode == KEY_RIGHT && !bControl && !bShift && !bAlt)
1244         {
1245             ScInputHandler* pHdl = pScMod->GetInputHdl(this);
1246             bIsType = pHdl && pHdl->HasPartialComplete();
1247         }
1248 
1249         if( bIsType )
1250             bUsed = pScMod->InputKeyEvent( rKEvt );     // input
1251 
1252         if( !bUsed )
1253             bUsed = SfxViewShell::KeyInput( rKEvt );    // accelerators
1254 
1255         if ( !bUsed && !bIsType && nCode != KEY_RETURN )    // input once again afterwards
1256             bUsed = pScMod->InputKeyEvent( rKEvt );
1257     }
1258     else
1259     {
1260         // special case: copy/cut for multiselect  -> error message
1261         //  (Slot is disabled, so SfxViewShell::KeyInput would be swallowed without a comment)
1262         KeyFuncType eFunc = aCode.GetFunction();
1263         if ( eFunc == KeyFuncType::CUT )
1264         {
1265             ScRange aDummy;
1266             ScMarkType eMarkType = GetViewData().GetSimpleArea( aDummy );
1267             if (eMarkType != SC_MARK_SIMPLE)
1268             {
1269                 ErrorMessage(STR_NOMULTISELECT);
1270                 bUsed = true;
1271             }
1272         }
1273         if (!bUsed)
1274             bUsed = SfxViewShell::KeyInput( rKEvt );    // accelerators
1275 
1276         //  during inplace editing, some slots are handled by the
1277         //  container app and are executed during Window::KeyInput.
1278         //  -> don't pass keys to input handler that would be used there
1279         //  but should call slots instead.
1280         bool bParent = ( GetViewFrame()->GetFrame().IsInPlace() && eFunc != KeyFuncType::DONTKNOW );
1281 
1282         if( !bUsed && !bDraw && nCode != KEY_RETURN && !bParent )
1283             bUsed = pScMod->InputKeyEvent( rKEvt, true );       // input
1284     }
1285 
1286     if (!bInPlace && !bUsed && !bDraw)
1287     {
1288         switch (nCode)
1289         {
1290             case KEY_RETURN:
1291                 {
1292                     bool bNormal = !bControl && !bAlt;
1293                     if ( !bAnyEdit && bNormal )
1294                     {
1295                         // Depending on options, Enter switches to edit mode.
1296                         const ScInputOptions& rOpt = pScMod->GetInputOptions();
1297                         if ( rOpt.GetEnterEdit() )
1298                         {
1299                             pScMod->SetInputMode( SC_INPUT_TABLE );
1300                             bUsed = true;
1301                         }
1302                     }
1303 
1304                     bool bEditReturn = bControl && !bShift;         // pass on to edit engine
1305                     if ( !bUsed && !bEditReturn )
1306                     {
1307                         if ( bOnRefSheet )
1308                             HideAllCursors();
1309 
1310                         ScEnterMode nMode = ScEnterMode::NORMAL;
1311                         if ( bShift && bControl )
1312                             nMode = ScEnterMode::MATRIX;
1313                         else if ( bAlt )
1314                             nMode = ScEnterMode::BLOCK;
1315                         pScMod->InputEnterHandler(nMode);
1316 
1317                         if (nMode == ScEnterMode::NORMAL)
1318                         {
1319                             if( bShift )
1320                                 GetViewData().GetDispatcher().Execute( SID_CURSORENTERUP,
1321                                             SfxCallMode::SLOT | SfxCallMode::RECORD );
1322                             else
1323                                 GetViewData().GetDispatcher().Execute( SID_CURSORENTERDOWN,
1324                                             SfxCallMode::SLOT | SfxCallMode::RECORD );
1325                         }
1326                         else
1327                             UpdateInputHandler(true);
1328 
1329                         if ( bOnRefSheet )
1330                             ShowAllCursors();
1331 
1332                         // here no UpdateInputHandler, since during reference input on another
1333                         // document this ViewShell is not the one that is used for input.
1334 
1335                         bUsed = true;
1336                     }
1337                 }
1338                 break;
1339         }
1340     }
1341 
1342     // hard-code Alt-Cursor key, since Alt is not configurable
1343 
1344     if ( !bUsed && bAlt && !bControl )
1345     {
1346         sal_uInt16 nSlotId = 0;
1347         switch (nCode)
1348         {
1349             case KEY_UP:
1350                 ModifyCellSize( DIR_TOP, bShift );
1351                 bUsed = true;
1352                 break;
1353             case KEY_DOWN:
1354                 ModifyCellSize( DIR_BOTTOM, bShift );
1355                 bUsed = true;
1356                 break;
1357             case KEY_LEFT:
1358                 ModifyCellSize( DIR_LEFT, bShift );
1359                 bUsed = true;
1360                 break;
1361             case KEY_RIGHT:
1362                 ModifyCellSize( DIR_RIGHT, bShift );
1363                 bUsed = true;
1364                 break;
1365             case KEY_PAGEUP:
1366                 nSlotId = bShift ? SID_CURSORPAGELEFT_SEL : SID_CURSORPAGELEFT_;
1367                 break;
1368             case KEY_PAGEDOWN:
1369                 nSlotId = bShift ? SID_CURSORPAGERIGHT_SEL : SID_CURSORPAGERIGHT_;
1370                 break;
1371             case KEY_EQUAL:
1372             {
1373                 // #tdf39302: Use "Alt + =" for autosum
1374                 if ( !bAnyEdit ) // Ignore shortcut if currently editing a cell
1375                 {
1376                     ScInputHandler* pHdl = pScMod->GetInputHdl(this);
1377                     if ( pHdl )
1378                     {
1379                         ScInputWindow* pWin = pHdl->GetInputWindow();
1380                         if ( pWin )
1381                         {
1382                             bool bRangeFinder = false;
1383                             bool bSubTotal = false;
1384                             pWin->AutoSum( bRangeFinder, bSubTotal, ocSum );
1385                         }
1386                     }
1387 
1388                     bUsed = true;
1389                     break;
1390                 }
1391             }
1392         }
1393         if ( nSlotId )
1394         {
1395             GetViewData().GetDispatcher().Execute( nSlotId, SfxCallMode::SLOT | SfxCallMode::RECORD );
1396             bUsed = true;
1397         }
1398     }
1399 
1400     // use Ctrl+Alt+Shift+arrow keys to move the cursor in cells
1401     // while keeping the last selection
1402     if ( !bUsed && bAlt && bControl && bShift)
1403     {
1404         sal_uInt16 nSlotId = 0;
1405         switch (nCode)
1406         {
1407             case KEY_UP:
1408                 nSlotId = SID_CURSORUP;
1409                 break;
1410             case KEY_DOWN:
1411                 nSlotId = SID_CURSORDOWN;
1412                 break;
1413             case KEY_LEFT:
1414                 nSlotId = SID_CURSORLEFT;
1415                 break;
1416             case KEY_RIGHT:
1417                 nSlotId = SID_CURSORRIGHT;
1418                 break;
1419             case KEY_PAGEUP:
1420                 nSlotId = SID_CURSORPAGEUP;
1421                 break;
1422             case KEY_PAGEDOWN:
1423                 nSlotId = SID_CURSORPAGEDOWN;
1424                 break;
1425             case KEY_HOME:
1426                 nSlotId = SID_CURSORHOME;
1427                 break;
1428             case KEY_END:
1429                 nSlotId = SID_CURSOREND;
1430                 break;
1431             default:
1432                 nSlotId = 0;
1433                 break;
1434         }
1435         if ( nSlotId )
1436         {
1437             sal_uInt16 nMode = GetLockedModifiers();
1438             LockModifiers(KEY_MOD1);
1439             GetViewData().GetDispatcher().Execute( nSlotId, SfxCallMode::SLOT | SfxCallMode::RECORD );
1440             LockModifiers(nMode);
1441             bUsed = true;
1442         }
1443     }
1444     if (bHideCursor)
1445         ShowAllCursors();
1446 
1447     return bUsed;
1448 }
1449 
1450 bool ScTabViewShell::SfxKeyInput(const KeyEvent& rKeyEvent)
1451 {
1452     return SfxViewShell::KeyInput( rKeyEvent );
1453 }
1454 
1455 bool ScTabViewShell::KeyInput( const KeyEvent &rKeyEvent )
1456 {
1457     return TabKeyInput( rKeyEvent );
1458 }
1459 
1460 void ScTabViewShell::Construct( TriState nForceDesignMode )
1461 {
1462     SfxApplication* pSfxApp  = SfxGetpApp();
1463     ScDocShell* pDocSh = GetViewData().GetDocShell();
1464     ScDocument& rDoc = pDocSh->GetDocument();
1465     bReadOnly = pDocSh->IsReadOnly();
1466     bIsActive = false;
1467 
1468     EnableAutoSpell(rDoc.GetDocOptions().IsAutoSpell());
1469 
1470     SetName("View"); // for SBX
1471     Color aColBlack( COL_BLACK );
1472     SetPool( &SC_MOD()->GetPool() );
1473     SetWindow( GetActiveWin() );
1474 
1475     pCurFrameLine.reset( new ::editeng::SvxBorderLine(&aColBlack, 20, SvxBorderLineStyle::SOLID) );
1476     StartListening(*GetViewData().GetDocShell(), DuplicateHandling::Prevent);
1477     StartListening(*GetViewFrame(), DuplicateHandling::Prevent);
1478     StartListening(*pSfxApp, DuplicateHandling::Prevent); // #i62045# #i62046# application is needed for Calc's own hints
1479 
1480     SfxViewFrame* pFirst = SfxViewFrame::GetFirst(pDocSh);
1481     bool bFirstView = !pFirst
1482           || (pFirst == GetViewFrame() && !SfxViewFrame::GetNext(*pFirst,pDocSh));
1483 
1484     if ( pDocSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
1485     {
1486         //TODO/LATER: is there a difference between the two GetVisArea methods?
1487         tools::Rectangle aVisArea = static_cast<const SfxObjectShell*>(pDocSh)->GetVisArea();
1488 
1489         SCTAB nVisTab = rDoc.GetVisibleTab();
1490         if (!rDoc.HasTable(nVisTab))
1491         {
1492             nVisTab = 0;
1493             rDoc.SetVisibleTab(nVisTab);
1494         }
1495         SetTabNo( nVisTab );
1496         bool bNegativePage = rDoc.IsNegativePage( nVisTab );
1497         // show the right cells
1498         GetViewData().SetScreenPos( bNegativePage ? aVisArea.TopRight() : aVisArea.TopLeft() );
1499 
1500         if ( GetViewFrame()->GetFrame().IsInPlace() )                         // inplace
1501         {
1502             pDocSh->SetInplace( true );             // already initiated like this
1503             if (rDoc.IsEmbedded())
1504                 rDoc.ResetEmbedded();              // no blue mark
1505         }
1506         else if ( bFirstView )
1507         {
1508             pDocSh->SetInplace( false );
1509             GetViewData().RefreshZoom();           // recalculate PPT
1510             if (!rDoc.IsEmbedded())
1511                 rDoc.SetEmbedded( rDoc.GetVisibleTab(), aVisArea );                  // mark VisArea
1512         }
1513     }
1514 
1515     // ViewInputHandler
1516     // Each task now has its own InputWindow,
1517     // therefore either should each task get its own InputHandler,
1518     // or the InputWindow should create its own InputHandler
1519     // (then always search via InputWindow and only if not found
1520     // use the InputHandler of the App).
1521     // As an intermediate solution each View gets its own InputHandler,
1522     // which only yields problems if two Views are in one task window.
1523     mpInputHandler.reset(new ScInputHandler);
1524 
1525     // old version:
1526     //  if ( !GetViewFrame()->ISA(SfxTopViewFrame) )        // OLE or Plug-In
1527     //      pInputHandler = new ScInputHandler;
1528 
1529             // create FormShell before MakeDrawView, so that DrawView can be registered at the
1530             // FormShell in every case
1531             // the FormShell is pushed in the first activate
1532     pFormShell.reset( new FmFormShell(this) );
1533     pFormShell->SetControlActivationHandler( LINK( this, ScTabViewShell, FormControlActivated ) );
1534 
1535             // DrawView must not be created in TabView - ctor,
1536             // if the ViewShell is not yet constructed...
1537     if (rDoc.GetDrawLayer())
1538         MakeDrawView( nForceDesignMode );
1539     ViewOptionsHasChanged(false, false);   // possibly also creates DrawView
1540 
1541     SfxUndoManager* pMgr = pDocSh->GetUndoManager();
1542     SetUndoManager( pMgr );
1543     pFormShell->SetUndoManager( pMgr );
1544     if ( !rDoc.IsUndoEnabled() )
1545     {
1546         pMgr->SetMaxUndoActionCount( 0 );
1547     }
1548     SetRepeatTarget( &aTarget );
1549     pFormShell->SetRepeatTarget( &aTarget );
1550 
1551     if ( bFirstView )   // first view?
1552     {
1553         rDoc.SetDocVisible( true );        // used when creating new sheets
1554         if ( pDocSh->IsEmpty() )
1555         {
1556             // set first sheet's RTL flag (following will already be initialized because of SetDocVisible)
1557             rDoc.SetLayoutRTL( 0, ScGlobal::IsSystemRTL() );
1558 
1559             // append additional sheets (not for OLE object)
1560             if ( pDocSh->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
1561             {
1562                 // Get the customized initial tab count
1563                 const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
1564                 SCTAB nInitTabCount = rOpt.GetInitTabCount();
1565 
1566                 for (SCTAB i=1; i<nInitTabCount; i++)
1567                     rDoc.MakeTable(i,false);
1568             }
1569 
1570             pDocSh->SetEmpty( false );          // #i6232# make sure this is done only once
1571         }
1572 
1573         // ReadExtOptions is now in Activate
1574 
1575         // link update no nesting
1576         if ( pDocSh->GetCreateMode() != SfxObjectCreateMode::INTERNAL &&
1577              pDocSh->IsUpdateEnabled() )  // #105575#; update only in the first creation of the ViewShell
1578         {
1579             // Check if there are any external data.
1580             bool bLink = rDoc.GetExternalRefManager()->hasExternalData();
1581             if (!bLink)
1582             {
1583                 // #i100042# sheet links can still exist independently from external formula references
1584                 SCTAB nTabCount = rDoc.GetTableCount();
1585                 for (SCTAB i=0; i<nTabCount && !bLink; i++)
1586                     if (rDoc.IsLinked(i))
1587                         bLink = true;
1588             }
1589             if (!bLink)
1590             {
1591                 const sc::DocumentLinkManager& rMgr = rDoc.GetDocLinkManager();
1592                 if (rDoc.HasLinkFormulaNeedingCheck() || rDoc.HasAreaLinks() || rMgr.hasDdeOrOleOrWebServiceLinks())
1593                     bLink = true;
1594             }
1595             if (bLink)
1596             {
1597                 if ( !pFirst )
1598                     pFirst = GetViewFrame();
1599 
1600                 if(SC_MOD()->GetCurRefDlgId()==0)
1601                 {
1602                         pFirst->GetDispatcher()->Execute( SID_UPDATETABLINKS,
1603                                             SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
1604                 }
1605             }
1606             else
1607             {
1608                 // No links yet, but loading an existing document may have
1609                 // disabled link update but there's no "Allow updating" infobar
1610                 // that could enable it again. So in order to enable the user
1611                 // to add formulas with external references allow link updates
1612                 // again.
1613                 pDocSh->AllowLinkUpdate();
1614             }
1615 
1616             bool bReImport = false;                             // update imported data
1617             ScDBCollection* pDBColl = rDoc.GetDBCollection();
1618             if ( pDBColl )
1619             {
1620                 const ScDBCollection::NamedDBs& rDBs = pDBColl->getNamedDBs();
1621                 bReImport = std::any_of(rDBs.begin(), rDBs.end(),
1622                     [](const std::unique_ptr<ScDBData>& rxDB) { return rxDB->IsStripData() && rxDB->HasImportParam() && !rxDB->HasImportSelection(); });
1623             }
1624             if (bReImport)
1625             {
1626                 if ( !pFirst )
1627                     pFirst = GetViewFrame();
1628                 if(SC_MOD()->GetCurRefDlgId()==0)
1629                 {
1630                     pFirst->GetDispatcher()->Execute( SID_REIMPORT_AFTER_LOAD,
1631                                             SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
1632                 }
1633             }
1634         }
1635     }
1636 
1637     UpdateAutoFillMark();
1638 
1639     // ScDispatchProviderInterceptor registers itself in ctor
1640     xDisProvInterceptor = new ScDispatchProviderInterceptor( this );
1641 
1642     bFirstActivate = true; // delay NavigatorUpdate until Activate()
1643 
1644     // #105575#; update only in the first creation of the ViewShell
1645     pDocSh->SetUpdateEnabled(false);
1646 
1647     if ( GetViewFrame()->GetFrame().IsInPlace() )
1648         UpdateHeaderWidth(); // The inplace activation requires headers to be calculated
1649 
1650     SvBorder aBorder;
1651     GetBorderSize( aBorder, Size() );
1652     SetBorderPixel( aBorder );
1653 }
1654 
1655 ScTabViewShell::ScTabViewShell( SfxViewFrame* pViewFrame,
1656                                 SfxViewShell* pOldSh ) :
1657     SfxViewShell( pViewFrame, SfxViewShellFlags::HAS_PRINTOPTIONS ),
1658     ScDBFunc( &pViewFrame->GetWindow(), static_cast<ScDocShell&>(*pViewFrame->GetObjectShell()), this ),
1659     eCurOST(OST_NONE),
1660     nDrawSfxId(0),
1661     aTarget(this),
1662     bActiveDrawSh(false),
1663     bActiveDrawTextSh(false),
1664     bActiveDrawFormSh(false),
1665     bActiveOleObjectSh(false),
1666     bActiveChartSh(false),
1667     bActiveGraphicSh(false),
1668     bActiveMediaSh(false),
1669     bFormShellAtTop(false),
1670     bDontSwitch(false),
1671     bInFormatDialog(false),
1672     bReadOnly(false),
1673     bForceFocusOnCurCell(false),
1674     bInPrepareClose(false),
1675     bInDispose(false),
1676     nCurRefDlgId(0),
1677     mbInSwitch(false)
1678 {
1679     const ScAppOptions& rAppOpt = SC_MOD()->GetAppOptions();
1680 
1681     //  if switching back from print preview,
1682     //  restore the view settings that were active when creating the preview
1683     //  ReadUserData must not happen from ctor, because the view's edit window
1684     //  has to be shown by the sfx. ReadUserData is deferred until the first Activate call.
1685     //  old DesignMode state from form layer must be restored, too
1686 
1687     TriState nForceDesignMode = TRISTATE_INDET;
1688     if ( auto pPreviewShell = dynamic_cast<ScPreviewShell*>( pOldSh) )
1689     {
1690         nForceDesignMode = pPreviewShell->GetSourceDesignMode();
1691         ScPreview* p = pPreviewShell->GetPreview();
1692         if (p)
1693             GetViewData().GetMarkData().SetSelectedTabs(p->GetSelectedTabs());
1694     }
1695 
1696     Construct( nForceDesignMode );
1697 
1698     // make Controller known to SFX
1699     new ScTabViewObj( this );
1700 
1701     // Resolves: tdf#53899 if there is no controller, register the above
1702     // ScTabViewObj as the current controller for the duration of the first
1703     // round of calculations triggered here by SetZoom. That way any StarBasic
1704     // macros triggered while the document is loading have a CurrentController
1705     // available to them.
1706     bool bInstalledScTabViewObjAsTempController = false;
1707     uno::Reference<frame::XController> xCurrentController(GetViewData().GetDocShell()->GetModel()->getCurrentController());
1708     if (!xCurrentController)
1709     {
1710         //GetController here returns the ScTabViewObj above
1711         GetViewData().GetDocShell()->GetModel()->setCurrentController(GetController());
1712         bInstalledScTabViewObjAsTempController = true;
1713     }
1714     xCurrentController.clear();
1715 
1716     if ( GetViewData().GetDocShell()->IsPreview() )
1717     {
1718         //  preview for template dialog: always show whole page
1719         SetZoomType( SvxZoomType::WHOLEPAGE, true );    // zoom value is recalculated at next Resize
1720     }
1721     else
1722     {
1723         Fraction aFract( rAppOpt.GetZoom(), 100 );
1724         SetZoom( aFract, aFract, true );
1725         SetZoomType( rAppOpt.GetZoomType(), true );
1726     }
1727 
1728     SetCurSubShell(OST_Cell);
1729     SvBorder aBorder;
1730     GetBorderSize( aBorder, Size() );
1731     SetBorderPixel( aBorder );
1732 
1733     MakeDrawLayer();
1734 
1735     //put things back as we found them
1736     if (bInstalledScTabViewObjAsTempController)
1737         GetViewData().GetDocShell()->GetModel()->setCurrentController(nullptr);
1738 
1739     // formula mode in online is not usable in collaborative mode,
1740     // this is a workaround for disabling formula mode in online
1741     // when there is more than a single view
1742     if (!comphelper::LibreOfficeKit::isActive())
1743         return;
1744 
1745     SfxViewShell* pViewShell = SfxViewShell::GetFirst();
1746     // have we already one view ?
1747     if (!pViewShell)
1748         return;
1749 
1750     // this view is not yet visible at this stage, so we look for not visible views, too, for this same document
1751     SfxViewShell* pViewShell2 = pViewShell;
1752     do
1753     {
1754         pViewShell2 = SfxViewShell::GetNext(*pViewShell2, /*only visible shells*/ false);
1755     } while (pViewShell2 && pViewShell2->GetDocId() != pViewShell->GetDocId());
1756     // if the second view is not this one, it means that there is
1757     // already more than one active view and so the formula mode
1758     // has already been disabled
1759     if (pViewShell2 && pViewShell2 == this)
1760     {
1761         ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
1762         assert(pTabViewShell);
1763         ScInputHandler* pInputHdl = pTabViewShell->GetInputHandler();
1764         if (pInputHdl && pInputHdl->IsFormulaMode())
1765         {
1766             pInputHdl->SetMode(SC_INPUT_NONE);
1767         }
1768     }
1769 }
1770 
1771 ScTabViewShell::~ScTabViewShell()
1772 {
1773     bInDispose = true;
1774 
1775     // Notify other LOK views that we are going away.
1776     SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", "false");
1777     SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "");
1778     SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY");
1779     SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", "EMPTY");
1780 
1781     // all to NULL, in case the TabView-dtor tries to access them
1782     //! (should not really! ??!?!)
1783     if (mpInputHandler)
1784     {
1785         mpInputHandler->SetDocumentDisposing(true);
1786     }
1787 
1788     ScDocShell* pDocSh = GetViewData().GetDocShell();
1789     EndListening(*pDocSh);
1790     EndListening(*GetViewFrame());
1791     EndListening(*SfxGetpApp());           // #i62045# #i62046# needed now - SfxViewShell no longer does it
1792 
1793     SC_MOD()->ViewShellGone(this);
1794 
1795     RemoveSubShell();           // all
1796     SetWindow(nullptr);
1797 
1798     // need kill editview or we will touch the editengine after it has been freed by the ScInputHandler
1799     KillEditView(true);
1800 
1801     pFontworkBarShell.reset();
1802     pExtrusionBarShell.reset();
1803     pCellShell.reset();
1804     pPageBreakShell.reset();
1805     pDrawShell.reset();
1806     pDrawFormShell.reset();
1807     pOleObjectShell.reset();
1808     pChartShell.reset();
1809     pGraphicShell.reset();
1810     pMediaShell.reset();
1811     pDrawTextShell.reset();
1812     pEditShell.reset();
1813     pPivotShell.reset();
1814     pAuditingShell.reset();
1815     pCurFrameLine.reset();
1816     mpFormEditData.reset();
1817     mpInputHandler.reset();
1818     pDialogDPObject.reset();
1819     pNavSettings.reset();
1820 
1821     pFormShell.reset();
1822     pAccessibilityBroadcaster.reset();
1823 }
1824 
1825 void ScTabViewShell::SetDialogDPObject( std::unique_ptr<ScDPObject> pObj )
1826 {
1827     pDialogDPObject = std::move(pObj);
1828 }
1829 
1830 void ScTabViewShell::FillFieldData( ScHeaderFieldData& rData )
1831 {
1832     ScDocShell* pDocShell = GetViewData().GetDocShell();
1833     ScDocument& rDoc = pDocShell->GetDocument();
1834     SCTAB nTab = GetViewData().GetTabNo();
1835     OUString aTmp;
1836     rDoc.GetName(nTab, aTmp);
1837     rData.aTabName = aTmp;
1838 
1839     if( pDocShell->getDocProperties()->getTitle().getLength() != 0 )
1840         rData.aTitle = pDocShell->getDocProperties()->getTitle();
1841     else
1842         rData.aTitle = pDocShell->GetTitle();
1843 
1844     const INetURLObject& rURLObj = pDocShell->GetMedium()->GetURLObject();
1845     rData.aLongDocName  = rURLObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
1846     if ( !rData.aLongDocName.isEmpty() )
1847         rData.aShortDocName = rURLObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
1848     else
1849         rData.aShortDocName = rData.aLongDocName = rData.aTitle;
1850     rData.nPageNo       = 1;
1851     rData.nTotalPages   = 99;
1852 
1853     // eNumType is known by the dialog
1854 }
1855 
1856 ScNavigatorSettings* ScTabViewShell::GetNavigatorSettings()
1857 {
1858     if( !pNavSettings )
1859         pNavSettings.reset(new ScNavigatorSettings);
1860     return pNavSettings.get();
1861 }
1862 
1863 tools::Rectangle ScTabViewShell::getLOKVisibleArea() const
1864 {
1865     return GetViewData().getLOKVisibleArea();
1866 }
1867 
1868 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1869