diff options
Diffstat (limited to '')
-rw-r--r-- | sc/source/ui/view/tabvwsh4.cxx | 1942 |
1 files changed, 1942 insertions, 0 deletions
diff --git a/sc/source/ui/view/tabvwsh4.cxx b/sc/source/ui/view/tabvwsh4.cxx new file mode 100644 index 000000000..edf1c5c3e --- /dev/null +++ b/sc/source/ui/view/tabvwsh4.cxx @@ -0,0 +1,1942 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 <formdata.hxx> + +#include <sfx2/app.hxx> +#include <svx/dialogs.hrc> +#include <svx/extrusionbar.hxx> +#include <svx/fontworkbar.hxx> +#include <editeng/borderline.hxx> +#include <svx/fmshell.hxx> +#include <svx/sidebar/ContextChangeEventMultiplexer.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/ipclient.hxx> +#include <tools/urlobj.hxx> +#include <sfx2/docfile.hxx> +#include <tools/svborder.hxx> + +#include <IAnyRefDialog.hxx> +#include <tabvwsh.hxx> +#include <sc.hrc> +#include <globstr.hrc> +#include <docsh.hxx> +#include <scmod.hxx> +#include <appoptio.hxx> +#include <drawsh.hxx> +#include <drformsh.hxx> +#include <editsh.hxx> +#include <pivotsh.hxx> +#include <SparklineShell.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 <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 <scextopt.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 <sfx2/lokhelper.hxx> +#include <comphelper/flagguard.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <comphelper/lok.hxx> +#include <sfx2/sidebar/SidebarController.hxx> + +using namespace com::sun::star; +using namespace sfx2::sidebar; + +namespace { + +bool inChartContext(const ScTabViewShell* pViewShell) +{ + SidebarController* pSidebar = SidebarController::GetSidebarControllerForView(pViewShell); + if (pSidebar) + return pSidebar->hasChartContextCurrently(); + + return false; +} + +} // anonymous namespace + +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()) + { + pWin->NumLinesChanged(); // tdf#150664 + ScInputHandler* pOldHdl=pWin->GetInputHandler(); + + SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> ); + while ( pSh!=nullptr && pOldHdl!=nullptr) + { + // Hmm, what if pSh is a shell for a different document? But as this code + // does not seem to be LibreOfficeKit-specific, probably that doesn't + // happen, because having multiple documents open simultaneously has of + // course not been a problem at all in traditional desktop LibreOffice. + // (Unlike in a LibreOfficeKit-based process where it has been a problem.) + 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 ) + { + if (auto pController = pChildWnd->GetController()) + { + IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pController.get()); + 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) + + if (!inChartContext(this)) + { + ContextChangeEventMultiplexer::NotifyContextChange( + GetController(), + vcl::EnumContext::Context::Default); + } +} + +void ScTabViewShell::Deactivate(bool bMDI) +{ + HideTip(); + + ScDocument& rDoc = GetViewData().GetDocument(); + + ScChangeTrack* pChanges = rDoc.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.IsEmpty() ) + { + 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.IsEmpty() ) + { + 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& rDoc = rViewData.GetDocument(); + ScSplitPos ePos = rViewData.GetActivePart(); + SCCOL nCol = rViewData.GetPosX(WhichH(ePos)); + SCROW nRow = rViewData.GetPosY(WhichV(ePos)); + SCTAB nTab = rViewData.GetTabNo(); + bool bNegativePage = rDoc.IsNegativePage( nTab ); + + tools::Rectangle aLogicRect = rDoc.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( std::u16string_view 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 = GetScDrawView(); + 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) + return; + + if ( bActive ) + { + bActiveDrawTextSh = bActiveDrawSh = false; + bActiveDrawFormSh=false; + bActiveGraphicSh=false; + bActiveMediaSh=false; + bActiveOleObjectSh=false; + bActiveChartSh=false; + SetCurSubShell(OST_Pivot); + } + else + SetCurSubShell(OST_Cell); +} + +void ScTabViewShell::SetSparklineShell(bool bActive) +{ + if (eCurOST != OST_Sparkline && eCurOST != OST_Cell) + return; + + if (bActive) + { + bActiveDrawTextSh = bActiveDrawSh = false; + bActiveDrawFormSh=false; + bActiveGraphicSh=false; + bActiveMediaSh=false; + bActiveOleObjectSh=false; + bActiveChartSh=false; + SetCurSubShell(OST_Sparkline); + } + 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) ) + return; + + 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 ); + } + + if (svx::checkForSelectedFontWork( + GetScDrawView() )) { + 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; + case OST_Sparkline: + { + AddSubShell(*pCellShell); + if(bPgBrk) AddSubShell(*pPageBreakShell); + + if (!m_pSparklineShell) + { + m_pSparklineShell.reset(new sc::SparklineShell(this)); + m_pSparklineShell->SetRepeatTarget(&aTarget); + } + AddSubShell(*m_pSparklineShell); + 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() || + pSub == m_pSparklineShell.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; +} + +std::unique_ptr<SfxTabPage> ScTabViewShell::CreatePrintOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rOptions ) +{ + ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); + ::CreateTabPage ScTpPrintOptionsCreate = pFact->GetTabPageCreatorFunc(RID_SC_TP_PRINT); + if ( ScTpPrintOptionsCreate ) + return ScTpPrintOptionsCreate(pPage, pController, &rOptions); + return nullptr; +} + +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 = comphelper::getFromUnoTunnel<ScTabViewObj>( 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) + return; + + 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 ); + if (auto xWin = pWnd->GetController()) + xWin->set_title(rTitle); + pWnd->StartRefInput(); +} + +void ScTabViewShell::StopSimpleRefDialog() +{ + SfxViewFrame* pViewFrm = GetViewFrame(); + sal_uInt16 nId = ScSimpleRefDlgWrapper::GetChildWindowId(); + + ScSimpleRefDlgWrapper* pWnd = static_cast<ScSimpleRefDlgWrapper*>(pViewFrm->GetChildWindow( nId )); + if (pWnd) + { + if (auto pWin = pWnd->GetController()) + pWin->response(RET_CLOSE); + } +} + +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& rDoc = GetViewData().GetDocument(); + rDoc.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; + } + else if (nCode == KEY_RIGHT && !bControl && !bShift && !bAlt) + { + ScInputHandler* pHdl = pScMod->GetInputHdl(this); + bIsType = pHdl && pHdl->HasPartialComplete(); + } + + 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; + case KEY_EQUAL: + { + // #tdf39302: Use "Alt + =" for autosum + if ( !bAnyEdit ) // Ignore shortcut if currently editing a cell + { + ScInputHandler* pHdl = pScMod->GetInputHdl(this); + if ( pHdl ) + { + ScInputWindow* pWin = pHdl->GetInputWindow(); + if ( pWin ) + { + bool bRangeFinder = false; + bool bSubTotal = false; + pWin->AutoSum( bRangeFinder, bSubTotal, ocSum ); + } + } + + bUsed = true; + 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) ); + 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 ); + } + } + else + { + // No links yet, but loading an existing document may have + // disabled link update but there's no "Allow updating" infobar + // that could enable it again. So in order to enable the user + // to add formulas with external references allow link updates + // again. + pDocSh->AllowLinkUpdate(); + } + + bool bReImport = false; // update imported data + ScDBCollection* pDBColl = rDoc.GetDBCollection(); + if ( pDBColl ) + { + const ScDBCollection::NamedDBs& rDBs = pDBColl->getNamedDBs(); + bReImport = std::any_of(rDBs.begin(), rDBs.end(), + [](const std::unique_ptr<ScDBData>& rxDB) { return rxDB->IsStripData() && rxDB->HasImportParam() && !rxDB->HasImportSelection(); }); + } + 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), + m_pDragData(new ScDragData) +{ + 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) + { + //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()) + return; + + SfxViewShell* pViewShell = SfxViewShell::GetFirst(); + // have we already one view ? + if (!pViewShell) + return; + + // this view is not yet visible at this stage, so we look for not visible views, too, for this same document + SfxViewShell* pViewShell2 = pViewShell; + do + { + pViewShell2 = SfxViewShell::GetNext(*pViewShell2, /*only visible shells*/ false); + } while (pViewShell2 && pViewShell2->GetDocId() != pViewShell->GetDocId()); + // 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); + assert(pTabViewShell); + 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); + } + + 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); + + // need kill editview or we will touch the editengine after it has been freed by the ScInputHandler + KillEditView(true); + + 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(); + m_pSparklineShell.reset(); + pAuditingShell.reset(); + pCurFrameLine.reset(); + mpFormEditData.reset(); + mpInputHandler.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.GetLastName(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(); +} + +tools::Rectangle ScTabViewShell::getLOKVisibleArea() const +{ + return GetViewData().getLOKVisibleArea(); +} + +void ScTabViewShell::SetDragObject(ScTransferObj* pCellObj, ScDrawTransferObj* pDrawObj) +{ + ResetDragObject(); + m_pDragData->pCellTransfer = pCellObj; + m_pDragData->pDrawTransfer = pDrawObj; +} + +void ScTabViewShell::ResetDragObject() +{ + m_pDragData->pCellTransfer = nullptr; + m_pDragData->pDrawTransfer = nullptr; + m_pDragData->pJumpLocalDoc = nullptr; + m_pDragData->aLinkDoc.clear(); + m_pDragData->aLinkTable.clear(); + m_pDragData->aLinkArea.clear(); + m_pDragData->aJumpTarget.clear(); + m_pDragData->aJumpText.clear(); +} + +void ScTabViewShell::SetDragLink(const OUString& rDoc, const OUString& rTab, const OUString& rArea) +{ + ResetDragObject(); + m_pDragData->aLinkDoc = rDoc; + m_pDragData->aLinkTable = rTab; + m_pDragData->aLinkArea = rArea; +} + +void ScTabViewShell::SetDragJump(ScDocument* pLocalDoc, const OUString& rTarget, const OUString& rText) +{ + ResetDragObject(); + m_pDragData->pJumpLocalDoc = pLocalDoc; + m_pDragData->aJumpTarget = rTarget; + m_pDragData->aJumpText = rText; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |