    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * This file incorporates work covered by the following license notice:
     *
     *   Licensed to the Apache Software Foundation (ASF) under one or more
     *   contributor license agreements. See the NOTICE file distributed
     *   with this work for additional information regarding copyright
     *   ownership. The ASF licenses this file to you under the Apache
     *   License, Version 2.0 (the "License"); you may not use this file
     *   except in compliance with the License. You may obtain a copy of
     *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
     */

    #include <sal/config.h>

    #include <scitems.hxx>
    #include <editeng/eeitem.hxx>

    #include <sfx2/app.hxx>
    #include <svx/dialogs.hrc>
    #include <svx/extrusionbar.hxx>
    #include <svx/fontworkbar.hxx>
    #include <editeng/boxitem.hxx>
    #include <svx/fmpage.hxx>
    #include <svx/fmshell.hxx>
    #include <editeng/sizeitem.hxx>
    #include <svx/sidebar/ContextChangeEventMultiplexer.hxx>
    #include <sfx2/request.hxx>
    #include <sfx2/printer.hxx>
    #include <sfx2/dispatch.hxx>
    #include <svl/whiter.hxx>
    #include <unotools/moduleoptions.hxx>
    #include <tools/urlobj.hxx>
    #include <sfx2/docfile.hxx>
    #include <o3tl/make_unique.hxx>

    #include <tabvwsh.hxx>
    #include <sc.hrc>
    #include <globstr.hrc>
    #include <stlpool.hxx>
    #include <stlsheet.hxx>
    #include <docsh.hxx>
    #include <scmod.hxx>
    #include <appoptio.hxx>
    #include <rangeutl.hxx>
    #include <printfun.hxx>
    #include <drawsh.hxx>
    #include <drformsh.hxx>
    #include <editsh.hxx>
    #include <pivotsh.hxx>
    #include <auditsh.hxx>
    #include <drtxtob.hxx>
    #include <inputhdl.hxx>
    #include <editutil.hxx>
    #include <inputopt.hxx>
    #include <inputwin.hxx>
    #include <dbdata.hxx>
    #include <reffact.hxx>
    #include <viewuno.hxx>
    #include <dispuno.hxx>
    #include <anyrefdg.hxx>
    #include <chgtrack.hxx>
    #include <cellsh.hxx>
    #include <oleobjsh.hxx>
    #include <chartsh.hxx>
    #include <graphsh.hxx>
    #include <mediash.hxx>
    #include <pgbrksh.hxx>
    #include <dpobject.hxx>
    #include <prevwsh.hxx>
    #include <tpprint.hxx>
    #include <scextopt.hxx>
    #include <printopt.hxx>
    #include <drawview.hxx>
    #include <fupoor.hxx>
    #include <navsett.hxx>
    #include <scabstdlg.hxx>
    #include <externalrefmgr.hxx>
    #include <defaultsoptions.hxx>
    #include <markdata.hxx>
    #include <preview.hxx>
    #include <docoptio.hxx>
    #include <documentlinkmgr.hxx>
    #include <gridwin.hxx>

    #include <com/sun/star/document/XDocumentProperties.hpp>
    #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
    #include <com/sun/star/chart2/XCoordinateSystem.hpp>
    #include <com/sun/star/chart2/XChartTypeContainer.hpp>
    #include <com/sun/star/chart2/XChartType.hpp>
    #include <sfx2/lokhelper.hxx>
    #include <comphelper/flagguard.hxx>
    #include <LibreOfficeKit/LibreOfficeKitEnums.h>
    #include <comphelper/lok.hxx>

    using namespace com::sun::star;

    void ScTabViewShell::Activate(bool bMDI)
    {
        SfxViewShell::Activate(bMDI);
        bIsActive = true;
        // here no GrabFocus, otherwise there will be problems when something is edited inplace!

        if ( bMDI )
        {
            // for input row (ClearCache)
            ScModule* pScMod = SC_MOD();
            pScMod->ViewShellChanged(/*bStopEditing=*/ !comphelper::LibreOfficeKit::isActive());

            ActivateView( true, bFirstActivate );

            // update AutoCorrect, if Writer has newly created this
            UpdateDrawTextOutliner();

            // RegisterNewTargetNames does not exist anymore

            SfxViewFrame* pThisFrame  = GetViewFrame();
            if ( mpInputHandler && pThisFrame->HasChildWindow(FID_INPUTLINE_STATUS) )
            {
                // actually only required for Reload (last version):
                // The InputWindow remains, but the View along with the InputHandler is newly created,
                // that is why the InputHandler must be set at the InputWindow.
                SfxChildWindow* pChild = pThisFrame->GetChildWindow(FID_INPUTLINE_STATUS);
                if (pChild)
                {
                    ScInputWindow* pWin = static_cast<ScInputWindow*>(pChild->GetWindow());
                    if (pWin && pWin->IsVisible())
                    {

                        ScInputHandler* pOldHdl=pWin->GetInputHandler();

                        SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
                        while ( pSh!=nullptr && pOldHdl!=nullptr)
                        {
                            if (static_cast<ScTabViewShell*>(pSh)->GetInputHandler() == pOldHdl)
                            {
                                pOldHdl->ResetDelayTimer();
                                break;
                            }
                            pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
                        }

                        pWin->SetInputHandler( mpInputHandler.get() );
                    }
                }
            }

            UpdateInputHandler( /*bForce=*/ true, /*bStopEditing=*/ !comphelper::LibreOfficeKit::isActive() );

            if ( bFirstActivate )
            {
                SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScNavigatorUpdateAll ) );
                bFirstActivate = false;

                // ReadExtOptions (view settings from Excel import) must also be done
                // after the ctor, because of the potential calls to Window::Show.
                // Even after a bugfix (Window::Show no longer notifies the access
                // bridge, it's done in ImplSetReallyVisible), there are problems if Window::Show
                // is called during the ViewShell ctor and reschedules asynchronous calls
                // (for example from the FmFormShell ctor).
                ScExtDocOptions* pExtOpt = GetViewData().GetDocument()->GetExtDocOptions();
                if ( pExtOpt && pExtOpt->IsChanged() )
                {
                    GetViewData().ReadExtOptions(*pExtOpt);        // Excel view settings
                    SetTabNo( GetViewData().GetTabNo(), true );
                    pExtOpt->SetChanged( false );
                }
            }

            pScActiveViewShell = this;

            ScInputHandler* pHdl = pScMod->GetInputHdl(this);
            if (pHdl)
            {
                pHdl->SetRefScale( GetViewData().GetZoomX(), GetViewData().GetZoomY() );
            }

            // update change dialog

            if ( pThisFrame->HasChildWindow(FID_CHG_ACCEPT) )
            {
                SfxChildWindow* pChild = pThisFrame->GetChildWindow(FID_CHG_ACCEPT);
                if (pChild)
                {
                    static_cast<ScAcceptChgDlgWrapper*>(pChild)->ReInitDlg();
                }
            }

            if(pScMod->IsRefDialogOpen())
            {
                sal_uInt16 nModRefDlgId=pScMod->GetCurRefDlgId();
                SfxChildWindow* pChildWnd = pThisFrame->GetChildWindow( nModRefDlgId );
                if ( pChildWnd )
                {
                    IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetWindow());
                    assert(pRefDlg);
                    if(pRefDlg)
                    {
                        pRefDlg->ViewShellChanged();
                    }
                }
            }
        }

        //  don't call CheckSelectionTransfer here - activating a view should not change the
        //  primary selection (may be happening just because the mouse was moved over the window)

        ContextChangeEventMultiplexer::NotifyContextChange(
            GetController(),
            vcl::EnumContext::Context::Default);
    }

    void ScTabViewShell::Deactivate(bool bMDI)
    {
        HideTip();

        ScDocument* pDoc=GetViewData().GetDocument();

        ScChangeTrack* pChanges=pDoc->GetChangeTrack();

        if(pChanges!=nullptr)
        {
            Link<ScChangeTrack&,void> aLink;
            pChanges->SetModifiedLink(aLink);
        }

        SfxViewShell::Deactivate(bMDI);
        bIsActive = false;
        ScInputHandler* pHdl = SC_MOD()->GetInputHdl(this);

        if( bMDI && !comphelper::LibreOfficeKit::isActive())
        {
            //  during shell deactivation, shells must not be switched, or the loop
            //  through the shell stack (in SfxDispatcher::DoDeactivate_Impl) will not work
            bool bOldDontSwitch = bDontSwitch;
            bDontSwitch = true;

            ActivateView( false, false );

            if ( GetViewFrame()->GetFrame().IsInPlace() ) // inplace
                GetViewData().GetDocShell()->UpdateOle(&GetViewData(), true);

            if ( pHdl )
                pHdl->NotifyChange( nullptr, true ); // timer-delayed due to document switching

            if (pScActiveViewShell == this)
                pScActiveViewShell = nullptr;

            bDontSwitch = bOldDontSwitch;
        }
        else
        {
            HideNoteMarker();           // note marker

            if ( pHdl )
                pHdl->HideTip();        // Hide formula auto input tip
        }
    }

    void ScTabViewShell::SetActive()
    {
        // SFX-View would like to activate itself, since then magical things would happen
        // (eg else the designer may crash)
        ActiveGrabFocus();
    }

    bool ScTabViewShell::PrepareClose(bool bUI)
    {
        comphelper::FlagRestorationGuard aFlagGuard(bInPrepareClose, true);

        // Call EnterHandler even in formula mode here,
        // so a formula change in an embedded object isn't lost
        // (ScDocShell::PrepareClose isn't called then).
        ScInputHandler* pHdl = SC_MOD()->GetInputHdl( this );
        if ( pHdl && pHdl->IsInputMode() )
        {
            pHdl->EnterHandler();
        }

        // draw text edit mode must be closed
        FuPoor* pPoor = GetDrawFuncPtr();
        if (pPoor && IsDrawTextShell())
        {
            // "clean" end of text edit, including note handling, subshells and draw func switching,
            // as in FuDraw and ScTabView::DrawDeselectAll
            GetViewData().GetDispatcher().Execute( pPoor->GetSlotID(), SfxCallMode::SLOT | SfxCallMode::RECORD );
        }
        ScDrawView* pDrView = GetScDrawView();
        if ( pDrView )
        {
            // force end of text edit, to be safe
            // ScEndTextEdit must always be used, to ensure correct UndoManager
            pDrView->ScEndTextEdit();
        }

        if ( pFormShell )
        {
            bool bRet = pFormShell->PrepareClose(bUI);
            if (!bRet)
                return bRet;
        }
        return SfxViewShell::PrepareClose(bUI);
    }

    // calculate zoom for in-place
    // from the ratio of VisArea and window size of GridWin

    void ScTabViewShell::UpdateOleZoom()
    {
        ScDocShell* pDocSh = GetViewData().GetDocShell();
        if ( pDocSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
        {
            //TODO/LATER: is there a difference between the two GetVisArea methods?
            Size aObjSize = static_cast<const SfxObjectShell*>(pDocSh)->GetVisArea().GetSize();
            if ( aObjSize.Width() > 0 && aObjSize.Height() > 0 )
            {
                vcl::Window* pWin = GetActiveWin();
                Size aWinHMM = pWin->PixelToLogic(pWin->GetOutputSizePixel(), MapMode(MapUnit::Map100thMM));
                SetZoomFactor( Fraction( aWinHMM.Width(),aObjSize.Width() ),
                                Fraction( aWinHMM.Height(),aObjSize.Height() ) );
            }
        }
    }

    void ScTabViewShell::InnerResizePixel( const Point &rOfs, const Size &rSize, bool inplaceEditModeChange )
    {
        Size aNewSize( rSize );
        if ( GetViewFrame()->GetFrame().IsInPlace() )
        {
            SvBorder aBorder;
               GetBorderSize( aBorder, rSize );
            SetBorderPixel( aBorder );

            Size aObjSize = GetObjectShell()->GetVisArea().GetSize();

              Size aSize( rSize );
            aSize.AdjustWidth( -(aBorder.Left() + aBorder.Right()) );
            aSize.AdjustHeight( -(aBorder.Top() + aBorder.Bottom()) );

            if ( aObjSize.Width() > 0 && aObjSize.Height() > 0 )
            {
                Size aLogicSize = GetWindow()->PixelToLogic(aSize, MapMode(MapUnit::Map100thMM));
                SfxViewShell::SetZoomFactor( Fraction( aLogicSize.Width(),aObjSize.Width() ),
                                Fraction( aLogicSize.Height(),aObjSize.Height() ) );
            }

            Point aPos( rOfs );
            aPos.AdjustX(aBorder.Left() );
            aPos.AdjustY(aBorder.Top() );
            GetWindow()->SetPosSizePixel( aPos, aSize );
        }
        else
        {
            SvBorder aBorder;
            GetBorderSize( aBorder, rSize );
            SetBorderPixel( aBorder );
            aNewSize.AdjustWidth(aBorder.Left() + aBorder.Right() );
            aNewSize.AdjustHeight(aBorder.Top() + aBorder.Bottom() );
        }

        DoResize( rOfs, aNewSize, true );                   // rSize = size of gridwin

        UpdateOleZoom();                                    // calculate zoom for in-place

        if (!inplaceEditModeChange)
        {
            GetViewData().GetDocShell()->SetDocumentModified();
        }
    }

    void ScTabViewShell::OuterResizePixel( const Point &rOfs, const Size &rSize )
    {
        SvBorder aBorder;
        GetBorderSize( aBorder, rSize );
        SetBorderPixel( aBorder );

        DoResize( rOfs, rSize );                    // position and size of tabview as passed

        // ForceMove as replacement for Sfx-Move mechanism
        // (aWinPos must be kept current, so that ForceMove works for Ole deactivation)

        ForceMove();
    }

    void ScTabViewShell::SetZoomFactor( const Fraction &rZoomX, const Fraction &rZoomY )
    {
        // for OLE...

        Fraction aFrac20( 1,5 );
        Fraction aFrac400( 4,1 );

        Fraction aNewX( rZoomX );
        if ( aNewX < aFrac20 )
            aNewX = aFrac20;
        if ( aNewX > aFrac400 )
            aNewX = aFrac400;
        Fraction aNewY( rZoomY );
        if ( aNewY < aFrac20 )
            aNewY = aFrac20;
        if ( aNewY > aFrac400 )
            aNewY = aFrac400;

        GetViewData().UpdateScreenZoom( aNewX, aNewY );
        SetZoom( aNewX, aNewY, true );

        PaintGrid();
        PaintTop();
        PaintLeft();

        SfxViewShell::SetZoomFactor( rZoomX, rZoomY );
    }

    void ScTabViewShell::QueryObjAreaPixel( tools::Rectangle& rRect ) const
    {
        // adjust to entire cells (in 1/100 mm)

        Size aPixelSize = rRect.GetSize();
        vcl::Window* pWin = const_cast<ScTabViewShell*>(this)->GetActiveWin();
        Size aLogicSize = pWin->PixelToLogic( aPixelSize );

        const ScViewData& rViewData = GetViewData();
        ScDocument* pDoc = rViewData.GetDocument();
        ScSplitPos ePos = rViewData.GetActivePart();
        SCCOL nCol = rViewData.GetPosX(WhichH(ePos));
        SCROW nRow = rViewData.GetPosY(WhichV(ePos));
        SCTAB nTab = rViewData.GetTabNo();
        bool bNegativePage = pDoc->IsNegativePage( nTab );

        tools::Rectangle aLogicRect = pDoc->GetMMRect( nCol, nRow, nCol, nRow, nTab );
        if ( bNegativePage )
        {
            // use right edge of aLogicRect, and aLogicSize
            aLogicRect.SetLeft( aLogicRect.Right() - aLogicSize.Width() + 1 );    // Right() is set below
        }
        aLogicRect.SetSize( aLogicSize );

        rViewData.GetDocShell()->SnapVisArea( aLogicRect );

        rRect.SetSize( pWin->LogicToPixel( aLogicRect.GetSize() ) );
    }

    void ScTabViewShell::Move()
    {
        Point aNewPos = GetViewFrame()->GetWindow().OutputToScreenPixel(Point());

        if (aNewPos != aWinPos)
        {
            StopMarking();
            aWinPos = aNewPos;
        }
    }

    void ScTabViewShell::ShowCursor(bool /* bOn */)
    {
    /*!!!   ShowCursor is not called as a pair as in gridwin.
            here the CursorLockCount for Gridwin must be set directly to 0

        if (bOn)
            ShowAllCursors();
        else
            HideAllCursors();
    */
    }

    void ScTabViewShell::WriteUserData(OUString& rData, bool /* bBrowse */)
    {
        GetViewData().WriteUserData(rData);
    }

    void ScTabViewShell::WriteUserDataSequence (uno::Sequence < beans::PropertyValue >& rSettings )
    {
        GetViewData().WriteUserDataSequence(rSettings);
    }

    void ScTabViewShell::ReadUserData(const OUString& rData, bool /* bBrowse */)
    {
        if ( !GetViewData().GetDocShell()->IsPreview() )
            DoReadUserData( rData );
    }

    void ScTabViewShell::ReadUserDataSequence (const uno::Sequence < beans::PropertyValue >& rSettings )
    {
        if ( !GetViewData().GetDocShell()->IsPreview() )
            DoReadUserDataSequence( rSettings );
    }

    void ScTabViewShell::DoReadUserDataSequence( const uno::Sequence < beans::PropertyValue >& rSettings )
    {
        vcl::Window* pOldWin = GetActiveWin();
        bool bFocus = pOldWin && pOldWin->HasFocus();

        GetViewData().ReadUserDataSequence(rSettings);
        SetTabNo( GetViewData().GetTabNo(), true );

        if ( GetViewData().IsPagebreakMode() )
            SetCurSubShell( GetCurObjectSelectionType(), true );

        vcl::Window* pNewWin = GetActiveWin();
        if (pNewWin && pNewWin != pOldWin)
        {
            SetWindow( pNewWin );       //! is this ViewShell always active???
            if (bFocus)
                pNewWin->GrabFocus();
            WindowChanged();            // drawing layer (for instance #56771#)
        }

        if (GetViewData().GetHSplitMode() == SC_SPLIT_FIX ||
            GetViewData().GetVSplitMode() == SC_SPLIT_FIX)
        {
            InvalidateSplit();
        }

        ZoomChanged();

        TestHintWindow();

        //! if ViewData has more tables than document, remove tables in ViewData
    }

    // DoReadUserData is also called from ctor when switching from print preview

    void ScTabViewShell::DoReadUserData( const OUString& rData )
    {
        vcl::Window* pOldWin = GetActiveWin();
        bool bFocus = pOldWin && pOldWin->HasFocus();

        GetViewData().ReadUserData(rData);
        SetTabNo( GetViewData().GetTabNo(), true );

        if ( GetViewData().IsPagebreakMode() )
            SetCurSubShell( GetCurObjectSelectionType(), true );

        vcl::Window* pNewWin = GetActiveWin();
        if (pNewWin && pNewWin != pOldWin)
        {
            SetWindow( pNewWin );       //! is this ViewShell always active???
            if (bFocus)
                pNewWin->GrabFocus();
            WindowChanged();            // drawing layer (for instance #56771#)
        }

        if (GetViewData().GetHSplitMode() == SC_SPLIT_FIX ||
            GetViewData().GetVSplitMode() == SC_SPLIT_FIX)
        {
            InvalidateSplit();
        }

        ZoomChanged();

        TestHintWindow();

        //! if ViewData has more tables than document, remove tables in ViewData
    }

    void ScTabViewShell::UpdateDrawShell()
    {
        // Called after user interaction that may delete the selected drawing object.
        // Remove DrawShell if nothing is selected.

        SdrView* pDrView = GetSdrView();
        if ( pDrView && !pDrView->AreObjectsMarked() && !IsDrawSelMode() )
            SetDrawShell( false );
    }

    void ScTabViewShell::SetDrawShellOrSub()
    {
        bActiveDrawSh = true;

        if(bActiveDrawFormSh)
        {
            SetCurSubShell(OST_DrawForm);
        }
        else if(bActiveGraphicSh)
        {
            SetCurSubShell(OST_Graphic);
        }
        else if(bActiveMediaSh)
        {
            SetCurSubShell(OST_Media);
        }
        else if(bActiveChartSh)
        {
            SetCurSubShell(OST_Chart);
        }
        else if(bActiveOleObjectSh)
        {
            SetCurSubShell(OST_OleObject);
        }
        else
        {
            SetCurSubShell(OST_Drawing, true /* force: different toolbars are
                                                visible concerning shape type
                                                and shape state */);
        }
    }

    void ScTabViewShell::SetDrawShell( bool bActive )
    {
        if(bActive)
        {
            SetCurSubShell(OST_Drawing, true /* force: different toolbars are
                                                visible concerning shape type
                                                and shape state */);
        }
        else
        {
            if(bActiveDrawFormSh || bActiveDrawSh ||
                bActiveGraphicSh || bActiveMediaSh || bActiveOleObjectSh||
                bActiveChartSh || bActiveDrawTextSh)
            {
                SetCurSubShell(OST_Cell);
            }
            bActiveDrawFormSh=false;
            bActiveGraphicSh=false;
            bActiveMediaSh=false;
            bActiveOleObjectSh=false;
            bActiveChartSh=false;
        }

        bool bWasDraw = bActiveDrawSh || bActiveDrawTextSh;

        bActiveDrawSh = bActive;
        bActiveDrawTextSh = false;

        if ( !bActive )
        {
            ResetDrawDragMode();        // switch off Mirror / Rotate

            if (bWasDraw && (GetViewData().GetHSplitMode() == SC_SPLIT_FIX ||
                             GetViewData().GetVSplitMode() == SC_SPLIT_FIX))
            {
                // adjust active part to cursor, etc.
                MoveCursorAbs( GetViewData().GetCurX(), GetViewData().GetCurY(),
                                SC_FOLLOW_NONE, false, false, true );
            }
        }
    }

    void ScTabViewShell::SetDrawTextShell( bool bActive )
    {
        bActiveDrawTextSh = bActive;
        if ( bActive )
        {
            bActiveDrawFormSh=false;
            bActiveGraphicSh=false;
            bActiveMediaSh=false;
            bActiveOleObjectSh=false;
            bActiveChartSh=false;
            bActiveDrawSh = false;
            SetCurSubShell(OST_DrawText);
        }
        else
            SetCurSubShell(OST_Cell);

    }

    void ScTabViewShell::SetPivotShell( bool bActive )
    {
        //  SetPivotShell is called from CursorPosChanged every time
        //  -> don't change anything except switching between cell and pivot shell

        if ( eCurOST == OST_Pivot || eCurOST == OST_Cell )
        {
            if ( bActive )
            {
                bActiveDrawTextSh = bActiveDrawSh = false;
                bActiveDrawFormSh=false;
                bActiveGraphicSh=false;
                bActiveMediaSh=false;
                bActiveOleObjectSh=false;
                bActiveChartSh=false;
                SetCurSubShell(OST_Pivot);
            }
            else
                SetCurSubShell(OST_Cell);
        }
    }

    void ScTabViewShell::SetAuditShell( bool bActive )
    {
        if ( bActive )
        {
            bActiveDrawTextSh = bActiveDrawSh = false;
            bActiveDrawFormSh=false;
            bActiveGraphicSh=false;
            bActiveMediaSh=false;
            bActiveOleObjectSh=false;
            bActiveChartSh=false;
            SetCurSubShell(OST_Auditing);
        }
        else
            SetCurSubShell(OST_Cell);
    }

    void ScTabViewShell::SetDrawFormShell( bool bActive )
    {
        bActiveDrawFormSh = bActive;

        if(bActiveDrawFormSh)
            SetCurSubShell(OST_DrawForm);
    }
    void ScTabViewShell::SetChartShell( bool bActive )
    {
        bActiveChartSh = bActive;

        if(bActiveChartSh)
            SetCurSubShell(OST_Chart);
    }

    void ScTabViewShell::SetGraphicShell( bool bActive )
    {
        bActiveGraphicSh = bActive;

        if(bActiveGraphicSh)
            SetCurSubShell(OST_Graphic);
    }

    void ScTabViewShell::SetMediaShell( bool bActive )
    {
        bActiveMediaSh = bActive;

        if(bActiveMediaSh)
            SetCurSubShell(OST_Media);
    }

    void ScTabViewShell::SetOleObjectShell( bool bActive )
    {
        bActiveOleObjectSh = bActive;

        if(bActiveOleObjectSh)
            SetCurSubShell(OST_OleObject);
        else
            SetCurSubShell(OST_Cell);
    }

    void ScTabViewShell::SetEditShell(EditView* pView, bool bActive )
    {
        if(bActive)
        {
            if (pEditShell)
                pEditShell->SetEditView( pView );
            else
                pEditShell.reset( new ScEditShell( pView, &GetViewData() ) );

            SetCurSubShell(OST_Editing);
        }
        else if(bActiveEditSh)
        {
            SetCurSubShell(OST_Cell);
        }
        bActiveEditSh = bActive;
    }

    void ScTabViewShell::SetCurSubShell(ObjectSelectionType eOST, bool bForce)
    {
        ScViewData& rViewData   = GetViewData();
        ScDocShell* pDocSh      = rViewData.GetDocShell();

        if(bDontSwitch) return;

        if(!pCellShell) // is anyway always used
        {
            pCellShell.reset( new ScCellShell( &GetViewData(), GetFrameWin() ) );
            pCellShell->SetRepeatTarget( &aTarget );
        }

        bool bPgBrk = rViewData.IsPagebreakMode();

        if(bPgBrk && !pPageBreakShell)
        {
            pPageBreakShell.reset( new ScPageBreakShell( this ) );
            pPageBreakShell->SetRepeatTarget( &aTarget );
        }

        if ( eOST!=eCurOST || bForce )
        {
            bool bCellBrush = false;    // "format paint brush" allowed for cells
            bool bDrawBrush = false;    // "format paint brush" allowed for drawing objects

            if(eCurOST!=OST_NONE) RemoveSubShell();

            if (pFormShell && !bFormShellAtTop)
                AddSubShell(*pFormShell);               // add below own subshells

            switch(eOST)
            {
                case    OST_Cell:
                {
                    AddSubShell(*pCellShell);
                    if(bPgBrk) AddSubShell(*pPageBreakShell);
                    bCellBrush = true;
                }
                break;
                case    OST_Editing:
                {
                    AddSubShell(*pCellShell);
                    if(bPgBrk) AddSubShell(*pPageBreakShell);

                    if(pEditShell)
                    {
                        AddSubShell(*pEditShell);
                    }
                }
                break;
                case    OST_DrawText:
                {
                    if ( !pDrawTextShell )
                    {
                        pDocSh->MakeDrawLayer();
                        pDrawTextShell.reset( new ScDrawTextObjectBar( &GetViewData() ) );
                    }
                    AddSubShell(*pDrawTextShell);
                }
                break;
                case    OST_Drawing:
                {
                    if (svx::checkForSelectedCustomShapes(
                                GetScDrawView(), true /* bOnlyExtruded */ )) {
                        if (pExtrusionBarShell == nullptr)
                            pExtrusionBarShell.reset( new svx::ExtrusionBar(this) );
                        AddSubShell( *pExtrusionBarShell );
                    }
                    sal_uInt32 nCheckStatus = 0;
                    if (svx::checkForSelectedFontWork(
                                GetScDrawView(), nCheckStatus )) {
                        if (pFontworkBarShell == nullptr)
                            pFontworkBarShell.reset( new svx::FontworkBar(this) );
                        AddSubShell( *pFontworkBarShell );
                    }

                    if ( !pDrawShell )
                    {
                        pDocSh->MakeDrawLayer();
                        pDrawShell.reset( new ScDrawShell( &GetViewData() ) );
                        pDrawShell->SetRepeatTarget( &aTarget );
                    }
                    AddSubShell(*pDrawShell);
                    bDrawBrush = true;
                }
                break;

                case    OST_DrawForm:
                {
                    if ( !pDrawFormShell )
                    {
                        pDocSh->MakeDrawLayer();
                        pDrawFormShell.reset( new ScDrawFormShell( &GetViewData() ) );
                        pDrawFormShell->SetRepeatTarget( &aTarget );
                    }
                    AddSubShell(*pDrawFormShell);
                    bDrawBrush = true;
                }
                break;

                case    OST_Chart:
                {
                    if ( !pChartShell )
                    {
                        pDocSh->MakeDrawLayer();
                        pChartShell.reset( new ScChartShell( &GetViewData() ) );
                        pChartShell->SetRepeatTarget( &aTarget );
                    }
                    AddSubShell(*pChartShell);
                    bDrawBrush = true;
                }
                break;

                case    OST_OleObject:
                {
                    if ( !pOleObjectShell )
                    {
                        pDocSh->MakeDrawLayer();
                        pOleObjectShell.reset( new ScOleObjectShell( &GetViewData() ) );
                        pOleObjectShell->SetRepeatTarget( &aTarget );
                    }
                    AddSubShell(*pOleObjectShell);
                    bDrawBrush = true;
                }
                break;

                case    OST_Graphic:
                {
                    if ( !pGraphicShell)
                    {
                        pDocSh->MakeDrawLayer();
                        pGraphicShell.reset( new ScGraphicShell( &GetViewData() ) );
                        pGraphicShell->SetRepeatTarget( &aTarget );
                    }
                    AddSubShell(*pGraphicShell);
                    bDrawBrush = true;
                }
                break;

                case    OST_Media:
                {
                    if ( !pMediaShell)
                    {
                        pDocSh->MakeDrawLayer();
                        pMediaShell.reset( new ScMediaShell( &GetViewData() ) );
                        pMediaShell->SetRepeatTarget( &aTarget );
                    }
                    AddSubShell(*pMediaShell);
                }
                break;

                case    OST_Pivot:
                {
                    AddSubShell(*pCellShell);
                    if(bPgBrk) AddSubShell(*pPageBreakShell);

                    if ( !pPivotShell )
                    {
                        pPivotShell.reset( new ScPivotShell( this ) );
                        pPivotShell->SetRepeatTarget( &aTarget );
                    }
                    AddSubShell(*pPivotShell);
                    bCellBrush = true;
                }
                break;
                case    OST_Auditing:
                {
                    AddSubShell(*pCellShell);
                    if(bPgBrk) AddSubShell(*pPageBreakShell);

                    if ( !pAuditingShell )
                    {
                        pDocSh->MakeDrawLayer();    // the waiting time rather now as on the click

                        pAuditingShell.reset( new ScAuditingShell( &GetViewData() ) );
                        pAuditingShell->SetRepeatTarget( &aTarget );
                    }
                    AddSubShell(*pAuditingShell);
                    bCellBrush = true;
                }
                break;
                default:
                OSL_FAIL("wrong shell requested");
                break;
            }

            if (pFormShell && bFormShellAtTop)
                AddSubShell(*pFormShell);               // add on top of own subshells

            eCurOST=eOST;

            // abort "format paint brush" when switching to an incompatible shell
            if ( ( GetBrushDocument() && !bCellBrush ) || ( GetDrawBrushSet() && !bDrawBrush ) )
                ResetBrushDocument();
        }
    }

    void ScTabViewShell::SetFormShellAtTop( bool bSet )
    {
        if ( pFormShell && !bSet )
            pFormShell->ForgetActiveControl();      // let the FormShell know it no longer has the focus

        if ( bFormShellAtTop != bSet )
        {
            bFormShellAtTop = bSet;
            SetCurSubShell( GetCurObjectSelectionType(), true );
        }
    }

    IMPL_LINK_NOARG(ScTabViewShell, FormControlActivated, LinkParamNone*, void)
    {
        // a form control got the focus, so the form shell has to be on top
        SetFormShellAtTop( true );
    }

    // GetMySubShell / SetMySubShell: simulate old behavior,
    // so that there is only one SubShell (only within the 5 own SubShells)

    SfxShell* ScTabViewShell::GetMySubShell() const
    {
        //  GetSubShell() was const before, and GetSubShell(sal_uInt16) should also be const...

        sal_uInt16 nPos = 0;
        SfxShell* pSub = const_cast<ScTabViewShell*>(this)->GetSubShell(nPos);
        while (pSub)
        {
            if ( pSub == pDrawShell.get()  || pSub == pDrawTextShell.get() || pSub == pEditShell.get() ||
                 pSub == pPivotShell.get() || pSub == pAuditingShell.get() || pSub == pDrawFormShell.get() ||
                 pSub == pCellShell.get()  || pSub == pOleObjectShell.get() || pSub == pChartShell.get() ||
                 pSub == pGraphicShell.get() || pSub == pMediaShell.get() || pSub == pPageBreakShell.get())
                return pSub;    // found

            pSub = const_cast<ScTabViewShell*>(this)->GetSubShell(++nPos);
        }
        return nullptr;        // none from mine present
    }

    bool ScTabViewShell::IsDrawTextShell() const
    {
        return ( pDrawTextShell && ( GetMySubShell() == pDrawTextShell.get() ) );
    }

    bool ScTabViewShell::IsAuditShell() const
    {
        return ( pAuditingShell && ( GetMySubShell() == pAuditingShell.get() ) );
    }

    void ScTabViewShell::SetDrawTextUndo( SfxUndoManager* pNewUndoMgr )
    {
        // Default: undo manager for DocShell
        if (!pNewUndoMgr)
            pNewUndoMgr = GetViewData().GetDocShell()->GetUndoManager();

        if (pDrawTextShell)
        {
            pDrawTextShell->SetUndoManager(pNewUndoMgr);
            ScDocShell* pDocSh = GetViewData().GetDocShell();
            if ( pNewUndoMgr == pDocSh->GetUndoManager() &&
                 !pDocSh->GetDocument().IsUndoEnabled() )
            {
                pNewUndoMgr->SetMaxUndoActionCount( 0 );
            }
        }
        else
        {
            OSL_FAIL("SetDrawTextUndo without DrawTextShell");
        }
    }

    ScTabViewShell* ScTabViewShell::GetActiveViewShell()
    {
        return dynamic_cast< ScTabViewShell *>( Current() );
    }

    SfxPrinter* ScTabViewShell::GetPrinter( bool bCreate )
    {
        // printer is always present (is created for the FontList already on start-up)
        return GetViewData().GetDocShell()->GetPrinter(bCreate);
    }

    sal_uInt16 ScTabViewShell::SetPrinter( SfxPrinter *pNewPrinter, SfxPrinterChangeFlags nDiffFlags )
    {
        return GetViewData().GetDocShell()->SetPrinter( pNewPrinter, nDiffFlags );
    }

    bool ScTabViewShell::HasPrintOptionsPage() const
    {
        return true;
    }

    VclPtr<SfxTabPage> ScTabViewShell::CreatePrintOptionsPage(TabPageParent pParent, const SfxItemSet &rOptions )
    {
        ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
        ::CreateTabPage ScTpPrintOptionsCreate = pFact->GetTabPageCreatorFunc(RID_SC_TP_PRINT);
        if ( ScTpPrintOptionsCreate )
            return ScTpPrintOptionsCreate(pParent, &rOptions);
        return VclPtr<SfxTabPage>();
    }

    void ScTabViewShell::StopEditShell()
    {
        if ( pEditShell != nullptr && !bDontSwitch )
            SetEditShell(nullptr, false );
    }

    // close handler to ensure function of dialog:

    IMPL_LINK_NOARG(ScTabViewShell, SimpleRefClose, const OUString*, void)
    {
        SfxInPlaceClient* pClient = GetIPClient();
        if ( pClient && pClient->IsObjectInPlaceActive() )
        {
            // If range selection was started with an active embedded object,
            // switch back to original sheet (while the dialog is still open).

            SetTabNo( GetViewData().GetRefTabNo() );
        }

        ScSimpleRefDlgWrapper::SetAutoReOpen( true );
    }

    // handlers to call UNO listeners:

    static ScTabViewObj* lcl_GetViewObj( const ScTabViewShell& rShell )
    {
        ScTabViewObj* pRet = nullptr;
        SfxViewFrame* pViewFrame = rShell.GetViewFrame();
        if (pViewFrame)
        {
            SfxFrame& rFrame = pViewFrame->GetFrame();
            uno::Reference<frame::XController> xController = rFrame.GetController();
            if (xController.is())
                pRet = ScTabViewObj::getImplementation( xController );
        }
        return pRet;
    }

    IMPL_LINK( ScTabViewShell, SimpleRefDone, const OUString&, aResult, void )
    {
        ScTabViewObj* pImpObj = lcl_GetViewObj( *this );
        if ( pImpObj )
            pImpObj->RangeSelDone( aResult );
    }

    IMPL_LINK( ScTabViewShell, SimpleRefAborted, const OUString&, rResult, void )
    {
        ScTabViewObj* pImpObj = lcl_GetViewObj( *this );
        if ( pImpObj )
            pImpObj->RangeSelAborted( rResult );
    }

    IMPL_LINK( ScTabViewShell, SimpleRefChange, const OUString&, rResult, void )
    {
        ScTabViewObj* pImpObj = lcl_GetViewObj( *this );
        if ( pImpObj )
            pImpObj->RangeSelChanged( rResult );
    }

    void ScTabViewShell::StartSimpleRefDialog(
                const OUString& rTitle, const OUString& rInitVal,
                bool bCloseOnButtonUp, bool bSingleCell, bool bMultiSelection )
    {
        SfxViewFrame* pViewFrm = GetViewFrame();

        if ( GetActiveViewShell() != this )
        {
            // #i18833# / #i34499# The API method can be called for a view that's not active.
            // Then the view has to be activated first, the same way as in Execute for SID_CURRENTDOC.
            // Can't use GrabFocus here, because it needs to take effect immediately.

            pViewFrm->GetFrame().Appear();
        }

        sal_uInt16 nId = ScSimpleRefDlgWrapper::GetChildWindowId();

        SC_MOD()->SetRefDialog( nId, true, pViewFrm );

        ScSimpleRefDlgWrapper* pWnd = static_cast<ScSimpleRefDlgWrapper*>(pViewFrm->GetChildWindow( nId ));
        if (pWnd)
        {
            pWnd->SetCloseHdl( LINK( this, ScTabViewShell, SimpleRefClose ) );
            pWnd->SetUnoLinks( LINK( this, ScTabViewShell, SimpleRefDone ),
                               LINK( this, ScTabViewShell, SimpleRefAborted ),
                               LINK( this, ScTabViewShell, SimpleRefChange ) );
            pWnd->SetRefString( rInitVal );
            pWnd->SetFlags( bCloseOnButtonUp, bSingleCell, bMultiSelection );
            ScSimpleRefDlgWrapper::SetAutoReOpen( false );
            vcl::Window* pWin = pWnd->GetWindow();
            pWin->SetText( rTitle );
            pWnd->StartRefInput();
        }
    }

    void ScTabViewShell::StopSimpleRefDialog()
    {
        SfxViewFrame* pViewFrm = GetViewFrame();
        sal_uInt16 nId = ScSimpleRefDlgWrapper::GetChildWindowId();

        ScSimpleRefDlgWrapper* pWnd = static_cast<ScSimpleRefDlgWrapper*>(pViewFrm->GetChildWindow( nId ));
        if (pWnd)
        {
            vcl::Window* pWin = pWnd->GetWindow();
            if (pWin && pWin->IsSystemWindow())
                static_cast<SystemWindow*>(pWin)->Close();     // calls abort handler
        }
    }

    bool ScTabViewShell::TabKeyInput(const KeyEvent& rKEvt)
    {
        ScModule* pScMod = SC_MOD();

        SfxViewFrame* pThisFrame = GetViewFrame();
        if ( pThisFrame->GetChildWindow( SID_OPENDLG_FUNCTION ) )
            return false;

        vcl::KeyCode aCode = rKEvt.GetKeyCode();
        bool bShift     = aCode.IsShift();
        bool bControl   = aCode.IsMod1();
        bool bAlt       = aCode.IsMod2();
        sal_uInt16 nCode    = aCode.GetCode();
        bool bUsed      = false;
        bool bInPlace   = pScMod->IsEditMode();     // Editengine gets all
        bool bAnyEdit   = pScMod->IsInputMode();    // only characters & backspace
        bool bDraw      = IsDrawTextEdit();

        HideNoteMarker();   // note marker

        // don't do extra HideCursor/ShowCursor calls if EnterHandler will switch to a different sheet
        bool bOnRefSheet = ( GetViewData().GetRefTabNo() == GetViewData().GetTabNo() );
        bool bHideCursor = ( ( nCode == KEY_RETURN && bInPlace ) || nCode == KEY_TAB ) && bOnRefSheet;

        if (bHideCursor)
            HideAllCursors();

        ScDocument* pDoc = GetViewData().GetDocument();
        if ( pDoc )
            pDoc->KeyInput();    // TimerDelays etc.

        if( bInPlace )
        {
            bUsed = pScMod->InputKeyEvent( rKEvt );         // input
            if( !bUsed )
                bUsed = SfxViewShell::KeyInput( rKEvt );    // accelerators
        }
        else if( bAnyEdit )
        {
            bool bIsType = false;
            sal_uInt16 nModi = aCode.GetModifier();
            sal_uInt16 nGroup = aCode.GetGroup();

            if ( nGroup == KEYGROUP_NUM || nGroup == KEYGROUP_ALPHA || nGroup == 0 )
                if ( !bControl && !bAlt )
                    bIsType = true;

            if ( nGroup == KEYGROUP_MISC )
                switch ( nCode )
                {
                    case KEY_RETURN:
                        bIsType = bControl && !bAlt;        // Control, Shift-Control-Return
                        if ( !bIsType && nModi == 0 )
                        {
                            // Does the Input Handler also want a simple Return?

                            ScInputHandler* pHdl = pScMod->GetInputHdl(this);
                            bIsType = pHdl && pHdl->TakesReturn();
                        }
                        break;
                    case KEY_SPACE:
                        bIsType = !bControl && !bAlt;       // without modifier or Shift-Space
                        break;
                    case KEY_ESCAPE:
                        bIsType = (nModi == 0); // only without modifier
                        break;
                    default:
                        bIsType = true;
                }

            if( bIsType )
                bUsed = pScMod->InputKeyEvent( rKEvt );     // input

            if( !bUsed )
                bUsed = SfxViewShell::KeyInput( rKEvt );    // accelerators

            if ( !bUsed && !bIsType && nCode != KEY_RETURN )    // input once again afterwards
                bUsed = pScMod->InputKeyEvent( rKEvt );
        }
        else
        {
            // special case: copy/cut for multiselect  -> error message
            //  (Slot is disabled, so SfxViewShell::KeyInput would be swallowed without a comment)
            KeyFuncType eFunc = aCode.GetFunction();
            if ( eFunc == KeyFuncType::CUT )
            {
                ScRange aDummy;
                ScMarkType eMarkType = GetViewData().GetSimpleArea( aDummy );
                if (eMarkType != SC_MARK_SIMPLE)
                {
                    ErrorMessage(STR_NOMULTISELECT);
                    bUsed = true;
                }
            }
            if (!bUsed)
                bUsed = SfxViewShell::KeyInput( rKEvt );    // accelerators

            //  during inplace editing, some slots are handled by the
            //  container app and are executed during Window::KeyInput.
            //  -> don't pass keys to input handler that would be used there
            //  but should call slots instead.
            bool bParent = ( GetViewFrame()->GetFrame().IsInPlace() && eFunc != KeyFuncType::DONTKNOW );

            if( !bUsed && !bDraw && nCode != KEY_RETURN && !bParent )
                bUsed = pScMod->InputKeyEvent( rKEvt, true );       // input
        }

        if (!bInPlace && !bUsed && !bDraw)
        {
            switch (nCode)
            {
                case KEY_RETURN:
                    {
                        bool bNormal = !bControl && !bAlt;
                        if ( !bAnyEdit && bNormal )
                        {
                            // Depending on options, Enter switches to edit mode.
                            const ScInputOptions& rOpt = pScMod->GetInputOptions();
                            if ( rOpt.GetEnterEdit() )
                            {
                                pScMod->SetInputMode( SC_INPUT_TABLE );
                                bUsed = true;
                            }
                        }

                        bool bEditReturn = bControl && !bShift;         // pass on to edit engine
                        if ( !bUsed && !bEditReturn )
                        {
                            if ( bOnRefSheet )
                                HideAllCursors();

                            ScEnterMode nMode = ScEnterMode::NORMAL;
                            if ( bShift && bControl )
                                nMode = ScEnterMode::MATRIX;
                            else if ( bAlt )
                                nMode = ScEnterMode::BLOCK;
                            pScMod->InputEnterHandler(nMode);

                            if (nMode == ScEnterMode::NORMAL)
                            {
                                if( bShift )
                                    GetViewData().GetDispatcher().Execute( SID_CURSORENTERUP,
                                                SfxCallMode::SLOT | SfxCallMode::RECORD );
                                else
                                    GetViewData().GetDispatcher().Execute( SID_CURSORENTERDOWN,
                                                SfxCallMode::SLOT | SfxCallMode::RECORD );
                            }
                            else
                                UpdateInputHandler(true);

                            if ( bOnRefSheet )
                                ShowAllCursors();

                            // here no UpdateInputHandler, since during reference input on another
                            // document this ViewShell is not the one that is used for input.

                            bUsed = true;
                        }
                    }
                    break;
            }
        }

        // hard-code Alt-Cursor key, since Alt is not configurable

        if ( !bUsed && bAlt && !bControl )
        {
            sal_uInt16 nSlotId = 0;
            switch (nCode)
            {
                case KEY_UP:
                    ModifyCellSize( DIR_TOP, bShift );
                    bUsed = true;
                    break;
                case KEY_DOWN:
                    ModifyCellSize( DIR_BOTTOM, bShift );
                    bUsed = true;
                    break;
                case KEY_LEFT:
                    ModifyCellSize( DIR_LEFT, bShift );
                    bUsed = true;
                    break;
                case KEY_RIGHT:
                    ModifyCellSize( DIR_RIGHT, bShift );
                    bUsed = true;
                    break;
                case KEY_PAGEUP:
                    nSlotId = bShift ? SID_CURSORPAGELEFT_SEL : SID_CURSORPAGELEFT_;
                    break;
                case KEY_PAGEDOWN:
                    nSlotId = bShift ? SID_CURSORPAGERIGHT_SEL : SID_CURSORPAGERIGHT_;
                    break;
            }
            if ( nSlotId )
            {
                GetViewData().GetDispatcher().Execute( nSlotId, SfxCallMode::SLOT | SfxCallMode::RECORD );
                bUsed = true;
            }
        }

        // use Ctrl+Alt+Shift+arrow keys to move the cursor in cells
        // while keeping the last selection
        if ( !bUsed && bAlt && bControl && bShift)
        {
            sal_uInt16 nSlotId = 0;
            switch (nCode)
            {
                case KEY_UP:
                    nSlotId = SID_CURSORUP;
                    break;
                case KEY_DOWN:
                    nSlotId = SID_CURSORDOWN;
                    break;
                case KEY_LEFT:
                    nSlotId = SID_CURSORLEFT;
                    break;
                case KEY_RIGHT:
                    nSlotId = SID_CURSORRIGHT;
                    break;
                case KEY_PAGEUP:
                    nSlotId = SID_CURSORPAGEUP;
                    break;
                case KEY_PAGEDOWN:
                    nSlotId = SID_CURSORPAGEDOWN;
                    break;
                case KEY_HOME:
                    nSlotId = SID_CURSORHOME;
                    break;
                case KEY_END:
                    nSlotId = SID_CURSOREND;
                    break;
                default:
                    nSlotId = 0;
                    break;
            }
            if ( nSlotId )
            {
                sal_uInt16 nMode = GetLockedModifiers();
                LockModifiers(KEY_MOD1);
                GetViewData().GetDispatcher().Execute( nSlotId, SfxCallMode::SLOT | SfxCallMode::RECORD );
                LockModifiers(nMode);
                bUsed = true;
            }
        }
        if (bHideCursor)
            ShowAllCursors();

        return bUsed;
    }

    bool ScTabViewShell::SfxKeyInput(const KeyEvent& rKeyEvent)
    {
        return SfxViewShell::KeyInput( rKeyEvent );
    }

    bool ScTabViewShell::KeyInput( const KeyEvent &rKeyEvent )
    {
        return TabKeyInput( rKeyEvent );
    }

    void ScTabViewShell::Construct( TriState nForceDesignMode )
    {
        SfxApplication* pSfxApp  = SfxGetpApp();
        ScDocShell* pDocSh = GetViewData().GetDocShell();
        ScDocument& rDoc = pDocSh->GetDocument();
        bReadOnly = pDocSh->IsReadOnly();
        bIsActive = false;

        EnableAutoSpell(rDoc.GetDocOptions().IsAutoSpell());

        SetName("View"); // for SBX
        Color aColBlack( COL_BLACK );
        SetPool( &SC_MOD()->GetPool() );
        SetWindow( GetActiveWin() );

        pCurFrameLine.reset( new ::editeng::SvxBorderLine(&aColBlack, 20, SvxBorderLineStyle::SOLID) );
        pPivotSource.reset( new ScArea );
        StartListening(*GetViewData().GetDocShell(), DuplicateHandling::Prevent);
        StartListening(*GetViewFrame(), DuplicateHandling::Prevent);
        StartListening(*pSfxApp, DuplicateHandling::Prevent); // #i62045# #i62046# application is needed for Calc's own hints

        SfxViewFrame* pFirst = SfxViewFrame::GetFirst(pDocSh);
        bool bFirstView = !pFirst
              || (pFirst == GetViewFrame() && !SfxViewFrame::GetNext(*pFirst,pDocSh));

        if ( pDocSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
        {
            //TODO/LATER: is there a difference between the two GetVisArea methods?
            tools::Rectangle aVisArea = static_cast<const SfxObjectShell*>(pDocSh)->GetVisArea();

            SCTAB nVisTab = rDoc.GetVisibleTab();
            if (!rDoc.HasTable(nVisTab))
            {
                nVisTab = 0;
                rDoc.SetVisibleTab(nVisTab);
            }
            SetTabNo( nVisTab );
            bool bNegativePage = rDoc.IsNegativePage( nVisTab );
            // show the right cells
            GetViewData().SetScreenPos( bNegativePage ? aVisArea.TopRight() : aVisArea.TopLeft() );

            if ( GetViewFrame()->GetFrame().IsInPlace() )                         // inplace
            {
                pDocSh->SetInplace( true );             // already initiated like this
                if (rDoc.IsEmbedded())
                    rDoc.ResetEmbedded();              // no blue mark
            }
            else if ( bFirstView )
            {
                pDocSh->SetInplace( false );
                GetViewData().RefreshZoom();           // recalculate PPT
                if (!rDoc.IsEmbedded())
                    rDoc.SetEmbedded( rDoc.GetVisibleTab(), aVisArea );                  // mark VisArea
            }
        }

        // ViewInputHandler
        // Each task now has its own InputWindow,
        // therefore either should each task get its own InputHandler,
        // or the InputWindow should create its own InputHandler
        // (then always search via InputWindow and only if not found
        // use the InputHandler of the App).
        // As an intermediate solution each View gets its own InputHandler,
        // which only yields problems if two Views are in one task window.
        mpInputHandler.reset(new ScInputHandler);

        // old version:
        //  if ( !GetViewFrame()->ISA(SfxTopViewFrame) )        // OLE or Plug-In
        //      pInputHandler = new ScInputHandler;

                // create FormShell before MakeDrawView, so that DrawView can be registered at the
                // FormShell in every case
                // the FormShell is pushed in the first activate
        pFormShell.reset( new FmFormShell(this) );
        pFormShell->SetControlActivationHandler( LINK( this, ScTabViewShell, FormControlActivated ) );

                // DrawView must not be created in TabView - ctor,
                // if the ViewShell is not yet constructed...
        if (rDoc.GetDrawLayer())
            MakeDrawView( nForceDesignMode );
        ViewOptionsHasChanged(false, false);   // possibly also creates DrawView

        SfxUndoManager* pMgr = pDocSh->GetUndoManager();
        SetUndoManager( pMgr );
        pFormShell->SetUndoManager( pMgr );
        if ( !rDoc.IsUndoEnabled() )
        {
            pMgr->SetMaxUndoActionCount( 0 );
        }
        SetRepeatTarget( &aTarget );
        pFormShell->SetRepeatTarget( &aTarget );

        if ( bFirstView )   // first view?
        {
            rDoc.SetDocVisible( true );        // used when creating new sheets
            if ( pDocSh->IsEmpty() )
            {
                // set first sheet's RTL flag (following will already be initialized because of SetDocVisible)
                rDoc.SetLayoutRTL( 0, ScGlobal::IsSystemRTL() );

                // append additional sheets (not for OLE object)
                if ( pDocSh->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
                {
                    // Get the customized initial tab count
                    const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
                    SCTAB nInitTabCount = rOpt.GetInitTabCount();

                    for (SCTAB i=1; i<nInitTabCount; i++)
                        rDoc.MakeTable(i,false);
                }

                pDocSh->SetEmpty( false );          // #i6232# make sure this is done only once
            }

            // ReadExtOptions is now in Activate

            // link update no nesting
            if ( pDocSh->GetCreateMode() != SfxObjectCreateMode::INTERNAL &&
                 pDocSh->IsUpdateEnabled() )  // #105575#; update only in the first creation of the ViewShell
            {
                // Check if there are any external data.
                bool bLink = rDoc.GetExternalRefManager()->hasExternalData();
                if (!bLink)
                {
                    // #i100042# sheet links can still exist independently from external formula references
                    SCTAB nTabCount = rDoc.GetTableCount();
                    for (SCTAB i=0; i<nTabCount && !bLink; i++)
                        if (rDoc.IsLinked(i))
                            bLink = true;
                }
                if (!bLink)
                {
                    const sc::DocumentLinkManager& rMgr = rDoc.GetDocLinkManager();
                    if (rDoc.HasLinkFormulaNeedingCheck() || rDoc.HasAreaLinks() || rMgr.hasDdeOrOleOrWebServiceLinks())
                        bLink = true;
                }
                if (bLink)
                {
                    if ( !pFirst )
                        pFirst = GetViewFrame();

                    if(SC_MOD()->GetCurRefDlgId()==0)
                    {
                            pFirst->GetDispatcher()->Execute( SID_UPDATETABLINKS,
                                                SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
                    }
                }

                bool bReImport = false;                             // update imported data
                ScDBCollection* pDBColl = rDoc.GetDBCollection();
                if ( pDBColl )
                {
                    const ScDBCollection::NamedDBs& rDBs = pDBColl->getNamedDBs();
                    ScDBCollection::NamedDBs::const_iterator itr = rDBs.begin(), itrEnd = rDBs.end();
                    for (; itr != itrEnd; ++itr)
                    {
                        if ((*itr)->IsStripData() && (*itr)->HasImportParam()
                            && !(*itr)->HasImportSelection())
                        {
                            bReImport = true;
                            break;
                        }
                    }
                }
                if (bReImport)
                {
                    if ( !pFirst )
                        pFirst = GetViewFrame();
                    if(SC_MOD()->GetCurRefDlgId()==0)
                    {
                        pFirst->GetDispatcher()->Execute( SID_REIMPORT_AFTER_LOAD,
                                                SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
                    }
                }
            }
        }

        UpdateAutoFillMark();

        // ScDispatchProviderInterceptor registers itself in ctor
        xDisProvInterceptor = new ScDispatchProviderInterceptor( this );

        bFirstActivate = true; // delay NavigatorUpdate until Activate()

        // #105575#; update only in the first creation of the ViewShell
        pDocSh->SetUpdateEnabled(false);

        if ( GetViewFrame()->GetFrame().IsInPlace() )
            UpdateHeaderWidth(); // The inplace activation requires headers to be calculated

        SvBorder aBorder;
        GetBorderSize( aBorder, Size() );
        SetBorderPixel( aBorder );
    }

    ScTabViewShell::ScTabViewShell( SfxViewFrame* pViewFrame,
                                    SfxViewShell* pOldSh ) :
        SfxViewShell( pViewFrame, SfxViewShellFlags::HAS_PRINTOPTIONS ),
        ScDBFunc( &pViewFrame->GetWindow(), static_cast<ScDocShell&>(*pViewFrame->GetObjectShell()), this ),
        eCurOST(OST_NONE),
        nDrawSfxId(0),
        aTarget(this),
        bActiveDrawSh(false),
        bActiveDrawTextSh(false),
        bActiveDrawFormSh(false),
        bActiveOleObjectSh(false),
        bActiveChartSh(false),
        bActiveGraphicSh(false),
        bActiveMediaSh(false),
        bFormShellAtTop(false),
        bDontSwitch(false),
        bInFormatDialog(false),
        bReadOnly(false),
        bForceFocusOnCurCell(false),
        bInPrepareClose(false),
        bInDispose(false),
        nCurRefDlgId(0),
        mbInSwitch(false)
    {
        const ScAppOptions& rAppOpt = SC_MOD()->GetAppOptions();

        //  if switching back from print preview,
        //  restore the view settings that were active when creating the preview
        //  ReadUserData must not happen from ctor, because the view's edit window
        //  has to be shown by the sfx. ReadUserData is deferred until the first Activate call.
        //  old DesignMode state from form layer must be restored, too

        TriState nForceDesignMode = TRISTATE_INDET;
        if ( auto pPreviewShell = dynamic_cast<ScPreviewShell*>( pOldSh) )
        {
            nForceDesignMode = pPreviewShell->GetSourceDesignMode();
            ScPreview* p = pPreviewShell->GetPreview();
            if (p)
                GetViewData().GetMarkData().SetSelectedTabs(p->GetSelectedTabs());
        }

        Construct( nForceDesignMode );

        // make Controller known to SFX
        new ScTabViewObj( this );

        // Resolves: tdf#53899 if there is no controller, register the above
        // ScTabViewObj as the current controller for the duration of the first
        // round of calculations triggered here by SetZoom. That way any StarBasic
        // macros triggered while the document is loading have a CurrentController
        // available to them.
        bool bInstalledScTabViewObjAsTempController = false;
        uno::Reference<frame::XController> xCurrentController(GetViewData().GetDocShell()->GetModel()->getCurrentController());
        if (!xCurrentController.get())
        {
            //GetController here returns the ScTabViewObj above
            GetViewData().GetDocShell()->GetModel()->setCurrentController(GetController());
            bInstalledScTabViewObjAsTempController = true;
        }
        xCurrentController.clear();

        if ( GetViewData().GetDocShell()->IsPreview() )
        {
            //  preview for template dialog: always show whole page
            SetZoomType( SvxZoomType::WHOLEPAGE, true );    // zoom value is recalculated at next Resize
        }
        else
        {
            Fraction aFract( rAppOpt.GetZoom(), 100 );
            SetZoom( aFract, aFract, true );
            SetZoomType( rAppOpt.GetZoomType(), true );
        }

        SetCurSubShell(OST_Cell);
        SvBorder aBorder;
        GetBorderSize( aBorder, Size() );
        SetBorderPixel( aBorder );

        MakeDrawLayer();

        //put things back as we found them
        if (bInstalledScTabViewObjAsTempController)
            GetViewData().GetDocShell()->GetModel()->setCurrentController(nullptr);

        // formula mode in online is not usable in collaborative mode,
        // this is a workaround for disabling formula mode in online
        // when there is more than a single view
        if (comphelper::LibreOfficeKit::isActive())
        {
            SfxViewShell* pViewShell = SfxViewShell::GetFirst();
            // have we already one view ?
            if (pViewShell)
            {
                // this view is not yet visible at this stage, so we look for not visible views, too
                SfxViewShell* pViewShell2 = SfxViewShell::GetNext(*pViewShell, /*only visible shells*/ false);
                // if the second view is not this one, it means that there is
                // already more than one active view and so the formula mode
                // has already been disabled
                if (pViewShell2 && pViewShell2 == this)
                {
                    ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
                    ScInputHandler* pInputHdl = pTabViewShell->GetInputHandler();
                    if (pInputHdl && pInputHdl->IsFormulaMode())
                    {
                        pInputHdl->SetMode(SC_INPUT_NONE);
                    }
                }
            }
        }
    }

    ScTabViewShell::~ScTabViewShell()
    {
        bInDispose = true;

        // Notify other LOK views that we are going away.
        SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", "false");
        SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "");
        SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY");
        SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", "EMPTY");

        // all to NULL, in case the TabView-dtor tries to access them
        //! (should not really! ??!?!)
        if (mpInputHandler)
        {
            mpInputHandler->SetDocumentDisposing(true);
            // We end edit mode, before destroying the input handler and the edit engine
            // and before end listening (in order to call ScTabViewShell::KillEditView())
            mpInputHandler->EnterHandler();
        }

        ScDocShell* pDocSh = GetViewData().GetDocShell();
        EndListening(*pDocSh);
        EndListening(*GetViewFrame());
        EndListening(*SfxGetpApp());           // #i62045# #i62046# needed now - SfxViewShell no longer does it

        SC_MOD()->ViewShellGone(this);

        RemoveSubShell();           // all
        SetWindow(nullptr);

        pFontworkBarShell.reset();
        pExtrusionBarShell.reset();
        pCellShell.reset();
        pPageBreakShell.reset();
        pDrawShell.reset();
        pDrawFormShell.reset();
        pOleObjectShell.reset();
        pChartShell.reset();
        pGraphicShell.reset();
        pMediaShell.reset();
        pDrawTextShell.reset();
        pEditShell.reset();
        pPivotShell.reset();
        pAuditingShell.reset();
        pCurFrameLine.reset();
        mpInputHandler.reset();
        pPivotSource.reset();
        pDialogDPObject.reset();
        pNavSettings.reset();

        pFormShell.reset();
        pAccessibilityBroadcaster.reset();
    }

    void ScTabViewShell::SetDialogDPObject( std::unique_ptr<ScDPObject> pObj )
    {
        pDialogDPObject = std::move(pObj);
    }

    void ScTabViewShell::FillFieldData( ScHeaderFieldData& rData )
    {
        ScDocShell* pDocShell = GetViewData().GetDocShell();
        ScDocument& rDoc = pDocShell->GetDocument();
        SCTAB nTab = GetViewData().GetTabNo();
        OUString aTmp;
        rDoc.GetName(nTab, aTmp);
        rData.aTabName = aTmp;

        if( pDocShell->getDocProperties()->getTitle().getLength() != 0 )
            rData.aTitle = pDocShell->getDocProperties()->getTitle();
        else
            rData.aTitle = pDocShell->GetTitle();

        const INetURLObject& rURLObj = pDocShell->GetMedium()->GetURLObject();
        rData.aLongDocName  = rURLObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
        if ( !rData.aLongDocName.isEmpty() )
            rData.aShortDocName = rURLObj.GetName( INetURLObject::DecodeMechanism::Unambiguous );
        else
            rData.aShortDocName = rData.aLongDocName = rData.aTitle;
        rData.nPageNo       = 1;
        rData.nTotalPages   = 99;

        // eNumType is known by the dialog
    }

    ScNavigatorSettings* ScTabViewShell::GetNavigatorSettings()
    {
        if( !pNavSettings )
            pNavSettings.reset(new ScNavigatorSettings);
        return pNavSettings.get();
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V522 There might be dereferencing of a potential null pointer 'pTabViewShell'.