/* -*- 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 <documentlinkmgr.hxx>
#include <gridwin.hxx>
#include <com/sun/star/document/XDocumentProperties.hpp>
#include <com/sun/star/configuration/theDefaultProvider.hpp>
#include <com/sun/star/sheet/XCellRangeMovement.hpp>
#include <com/sun/star/sheet/XCellRangeData.hpp>
#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
#include <comphelper/processfactory.hxx>
#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 inChartOrMathContext(const ScTabViewShell* pViewShell)
{
SidebarController* pSidebar = SidebarController::GetSidebarControllerForView(pViewShell);
if (pSidebar)
return pSidebar->hasChartOrMathContextCurrently();
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& rThisFrame = GetViewFrame();
if ( mpInputHandler && rThisFrame.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 = rThisFrame.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() );
}
}
}
bool isLOK = comphelper::LibreOfficeKit::isActive();
UpdateInputHandler( /*bForce=*/ !isLOK, /*bStopEditing=*/ !isLOK );
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 ( rThisFrame.HasChildWindow(FID_CHG_ACCEPT) )
{
SfxChildWindow* pChild = rThisFrame.GetChildWindow(FID_CHG_ACCEPT);
if (pChild)
{
static_cast<ScAcceptChgDlgWrapper*>(pChild)->ReInitDlg();
}
}
if(pScMod->IsRefDialogOpen())
{
sal_uInt16 nModRefDlgId=pScMod->GetCurRefDlgId();
SfxChildWindow* pChildWnd = rThisFrame.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 (!inChartOrMathContext(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
// in LOK case this could be triggered on every action from other view (doc_setView)
// we don't want to hide tooltip only because other view did some action
if ( pHdl && !comphelper::LibreOfficeKit::isActive() )
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->GetMarkedObjectList().GetMarkCount() == 0 && !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);
GetViewData().SetEditHighlight(false);
}
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 *>( SfxViewShell::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& rViewFrame = rShell.GetViewFrame();
SfxFrame& rFrame = rViewFrame.GetFrame();
uno::Reference<frame::XController> xController = rFrame.GetController();
if (xController.is())
pRet = dynamic_cast<ScTabViewObj*>( xController.get() );
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& rViewFrm = 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.
rViewFrm.GetFrame().Appear();
}
sal_uInt16 nId = ScSimpleRefDlgWrapper::GetChildWindowId();
SC_MOD()->SetRefDialog( nId, true, &rViewFrm );
ScSimpleRefDlgWrapper* pWnd = static_cast<ScSimpleRefDlgWrapper*>(rViewFrm.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& rViewFrm = GetViewFrame();
sal_uInt16 nId = ScSimpleRefDlgWrapper::GetChildWindowId();
ScSimpleRefDlgWrapper* pWnd = static_cast<ScSimpleRefDlgWrapper*>(rViewFrm.GetChildWindow( nId ));
if (pWnd)
{
if (auto pWin = pWnd->GetController())
pWin->response(RET_CLOSE);
}
}
bool ScTabViewShell::TabKeyInput(const KeyEvent& rKEvt)
{
ScModule* pScMod = SC_MOD();
SfxViewFrame& rThisFrame = GetViewFrame();
if ( rThisFrame.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(ScModule::GetAutoSpellProperty());
SetName(u"View"_ustr); // 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 );
}
class ScViewOptiChangesListener : public cppu::WeakImplHelper<util::XChangesListener>
{
public:
ScViewOptiChangesListener(ScTabViewShell&);
void stopListening();
virtual void SAL_CALL changesOccurred(const util::ChangesEvent& Event) override;
virtual void SAL_CALL disposing(const lang::EventObject& rEvent) override;
private:
ScTabViewShell& mrViewShell;
uno::Reference<util::XChangesNotifier> m_xViewChangesNotifier;
uno::Reference<util::XChangesNotifier> m_xColorSchemeChangesNotifier;
};
void ScViewOptiChangesListener::stopListening()
{
if (m_xViewChangesNotifier)
m_xViewChangesNotifier->removeChangesListener(this);
if (m_xColorSchemeChangesNotifier)
m_xColorSchemeChangesNotifier->removeChangesListener(this);
}
// virtual
void SAL_CALL ScViewOptiChangesListener::changesOccurred(const util::ChangesEvent& rEvent)
{
for (const auto& change : rEvent.Changes)
{
if (OUString sChangedEntry;
(change.Accessor >>= sChangedEntry) && sChangedEntry == "ColumnRowHighlighting")
{
mrViewShell.HighlightOverlay();
break;
}
if (OUString sChangedEntry; (change.Accessor >>= sChangedEntry) && sChangedEntry ==
"ColorSchemes/org.openoffice.Office.UI:ColorScheme['COLOR_SCHEME_LIBREOFFICE_AUTOMATIC']/CalcCellFocus/Color")
{
mrViewShell.GetActiveWin()->UpdateCursorOverlay();
mrViewShell.GetActiveWin()->UpdateAutoFillOverlay();
mrViewShell.GetActiveWin()->UpdateHighlightOverlay();
break;
}
}
}
// virtual
void SAL_CALL ScViewOptiChangesListener::disposing(const lang::EventObject& /* rEvent */)
{
m_xViewChangesNotifier.clear();
m_xColorSchemeChangesNotifier.clear();
}
ScViewOptiChangesListener::ScViewOptiChangesListener(ScTabViewShell& rViewShell)
: mrViewShell(rViewShell)
{
// add a listener for configuration changes (ColumnRowHighlighting Checkbox)
uno::Reference<lang::XMultiServiceFactory> xConfigurationProvider(
configuration::theDefaultProvider::get(comphelper::getProcessComponentContext()));
beans::NamedValue aViewProperty{ u"nodepath"_ustr,
uno::Any(u"/org.openoffice.Office.Calc/Content/Display"_ustr) };
beans::NamedValue aColorSchemeProperty{ u"nodepath"_ustr,
uno::Any(u"/org.openoffice.Office.UI/ColorScheme"_ustr) };
uno::Reference<uno::XInterface> xViewConfigurationAccess
= xConfigurationProvider->createInstanceWithArguments(
u"com.sun.star.configuration.ConfigurationAccess"_ustr, { uno::Any(aViewProperty) });
uno::Reference<uno::XInterface> xColorSchemeConfigurationAccess
= xConfigurationProvider->createInstanceWithArguments(
u"com.sun.star.configuration.ConfigurationAccess"_ustr, { uno::Any(aColorSchemeProperty) });
m_xViewChangesNotifier.set(xViewConfigurationAccess, uno::UNO_QUERY);
m_xColorSchemeChangesNotifier.set(xColorSchemeConfigurationAccess, uno::UNO_QUERY);
if (m_xViewChangesNotifier)
m_xViewChangesNotifier->addChangesListener(this);
if (m_xColorSchemeChangesNotifier)
m_xColorSchemeChangesNotifier->addChangesListener(this);
}
static void lcl_RemoveCells(uno::Reference<sheet::XSpreadsheet>& rSheet, sal_uInt16 nSheet,
sal_uInt32 nStartColumn, sal_uInt32 nStartRow, sal_uInt32 nEndColumn,
sal_uInt32 nEndRow, bool bRows)
{
table::CellRangeAddress aCellRange(nSheet, nStartColumn, nStartRow, nEndColumn, nEndRow);
uno::Reference<sheet::XCellRangeMovement> xCRM(rSheet, uno::UNO_QUERY);
if (xCRM.is())
{
if (bRows)
xCRM->removeRange(aCellRange, sheet::CellDeleteMode_UP);
else
xCRM->removeRange(aCellRange, sheet::CellDeleteMode_LEFT);
}
}
/* For rows (bool bRows), I am passing reference to already existing sequence, and comparing the required
* columns, whereas for columns, I am creating a sequence for each, with only the checked entries
* in the dialog.
*/
static bool lcl_CheckInArray(std::vector<uno::Sequence<uno::Any>>& nUniqueRecords,
const uno::Sequence<uno::Any>& nCurrentRecord,
const std::vector<int>& rSelectedEntries, bool bRows)
{
for (size_t m = 0; m < nUniqueRecords.size(); ++m)
{
bool bIsDuplicate = true;
for (size_t n = 0; n < rSelectedEntries.size(); ++n)
{
// when the first different element is found
int nColumn = (bRows ? rSelectedEntries[n] : n);
if (nUniqueRecords[m][nColumn] != (bRows ? nCurrentRecord[rSelectedEntries[n]] : nCurrentRecord[n]))
{
bIsDuplicate = false;
break;
}
}
if (bIsDuplicate)
return true;
}
return false;
}
uno::Reference<css::sheet::XSpreadsheet> ScTabViewShell::GetRangeWithSheet(css::table::CellRangeAddress& rRangeData, bool& bHasData, bool bHasUnoArguments)
{
// get spreadsheet document model & controller
uno::Reference<frame::XModel> xModel(GetViewData().GetDocShell()->GetModel());
uno::Reference<frame::XController> xController(xModel->getCurrentController());
// spreadsheet's extension of com.sun.star.frame.Controller service
uno::Reference<sheet::XSpreadsheetView> SpreadsheetDocument(xController, uno::UNO_QUERY);
uno::Reference<sheet::XSpreadsheet> ActiveSheet = SpreadsheetDocument->getActiveSheet();
if (!bHasUnoArguments)
{
// get the selection supplier, extract selection in XSheetCellRange
uno::Reference<view::XSelectionSupplier> xSelectionSupplier(SpreadsheetDocument, uno::UNO_QUERY);
uno::Any Selection = xSelectionSupplier->getSelection();
uno::Reference<sheet::XSheetCellRange> SelectedCellRange;
Selection >>= SelectedCellRange;
// Get the Selected Range Address.
uno::Reference<sheet::XCellRangeAddressable> xAddressable( SelectedCellRange, uno::UNO_QUERY);
if (xAddressable.is())
rRangeData = xAddressable->getRangeAddress();
else
{
bHasData = false;
return ActiveSheet;
}
}
SCCOL nStartColumn = rRangeData.StartColumn;
SCCOL nEndColumn = rRangeData.EndColumn;
SCROW nStartRow = rRangeData.StartRow;
SCROW nEndRow = rRangeData.EndRow;
// shrink to intersection of data and selection. If no intersection ==> return
bHasData = GetViewData().GetDocument().ShrinkToDataArea(rRangeData.Sheet, nStartColumn, nStartRow, nEndColumn, nEndRow);
rRangeData.StartColumn = nStartColumn;
rRangeData.StartRow = nStartRow;
rRangeData.EndColumn = nEndColumn;
rRangeData.EndRow = nEndRow;
return ActiveSheet;
}
void ScTabViewShell::ExtendSingleSelection(css::table::CellRangeAddress& rRangeData)
{
SCCOL aStartCol(rRangeData.StartColumn);
SCCOL aEndCol(rRangeData.EndColumn);
SCROW aStartRow(rRangeData.StartRow);
SCROW aEndRow(rRangeData.EndRow);
GetViewData().GetDocument().GetDataArea(rRangeData.Sheet, aStartCol, aStartRow, aEndCol,
aEndRow, true, false);
MarkRange(ScRange(ScAddress(aStartCol, aStartRow, rRangeData.Sheet),
ScAddress(aEndCol, aEndRow, rRangeData.Sheet)));
rRangeData.StartRow = aStartRow;
rRangeData.StartColumn = aStartCol;
rRangeData.EndRow = aEndRow;
rRangeData.EndColumn = aEndCol;
}
/* bool bRemove == false ==> highlight duplicate rows */
void ScTabViewShell::HandleDuplicateRecords(css::uno::Reference<css::sheet::XSpreadsheet> ActiveSheet,
const css::table::CellRangeAddress& aRange, bool bRemove,
bool bIncludesHeaders, bool bDuplicateRows,
const std::vector<int>& rSelectedEntries)
{
if (rSelectedEntries.size() == 0)
{
Unmark();
return;
}
uno::Reference<frame::XModel> xModel(GetViewData().GetDocShell()->GetModel());
uno::Reference<sheet::XSheetCellRange> xSheetRange(
ActiveSheet->getCellRangeByPosition(aRange.StartColumn, aRange.StartRow, aRange.EndColumn, aRange.EndRow),
uno::UNO_QUERY);
uno::Reference<sheet::XCellRangeData> xCellRangeData(xSheetRange, uno::UNO_QUERY);
uno::Sequence<uno::Sequence<uno::Any>> aDataArray = xCellRangeData->getDataArray();
uno::Reference< document::XUndoManagerSupplier > xUndoManager( xModel, uno::UNO_QUERY );
uno::Reference<document::XActionLockable> xLockable(xModel, uno::UNO_QUERY);
uno::Reference<sheet::XCalculatable> xCalculatable(xModel, uno::UNO_QUERY);
bool bAutoCalc = xCalculatable->isAutomaticCalculationEnabled();
comphelper::ScopeGuard aUndoContextGuard(
[&xUndoManager, &xLockable, &xModel, &xCalculatable, &bAutoCalc, &bRemove] {
xUndoManager->getUndoManager()->leaveUndoContext();
if (bRemove)
xCalculatable->enableAutomaticCalculation(bAutoCalc);
xLockable->removeActionLock();
if (xModel->hasControllersLocked())
xModel->unlockControllers();
});
xModel->lockControllers();
xLockable->addActionLock();
if (bRemove)
xCalculatable->enableAutomaticCalculation(true);
xUndoManager->getUndoManager()->enterUndoContext("HandleDuplicateRecords");
bool nModifier = false; // modifier key pressed?
bool bNoDuplicatesForSelection = true;
if (bDuplicateRows)
{
std::vector<uno::Sequence<uno::Any>> aUnionArray;
sal_uInt32 nRow = bIncludesHeaders ? 1 : 0;
sal_uInt32 lRows = aDataArray.getLength();
sal_uInt32 nDeleteCount = 0;
while (nRow < lRows)
{
if (lcl_CheckInArray(aUnionArray, aDataArray[nRow], rSelectedEntries, true))
{
if (bRemove)
{
lcl_RemoveCells(ActiveSheet, aRange.Sheet, aRange.StartColumn,
aRange.StartRow + nRow - nDeleteCount, aRange.EndColumn,
aRange.StartRow + nRow - nDeleteCount, true);
++nDeleteCount;
}
else
{
for (int nCol = aRange.StartColumn; nCol <= aRange.EndColumn; ++nCol)
{
bNoDuplicatesForSelection = false;
DoneBlockMode( nModifier );
nModifier = true;
InitBlockMode( nCol, aRange.StartRow + nRow, aRange.Sheet, false, false);
}
}
}
else
{
aUnionArray.push_back(aDataArray[nRow]);
}
++nRow;
}
}
else
{
std::vector<uno::Sequence<uno::Any>> aUnionArray;
sal_uInt32 nDeleteCount = 0;
sal_uInt32 nColumn = bIncludesHeaders ? 1 : 0;
sal_uInt32 lColumns = aDataArray[0].getLength();
while (nColumn < lColumns)
{
uno::Sequence<uno::Any> aSeq;
aSeq.realloc(rSelectedEntries.size());
for (size_t i = 0; i < rSelectedEntries.size(); ++i)
aSeq.getArray()[i] = aDataArray[rSelectedEntries[i]][nColumn];
if (lcl_CheckInArray(aUnionArray, aSeq, rSelectedEntries, false))
{
if (bRemove)
{
lcl_RemoveCells(ActiveSheet, aRange.Sheet,
aRange.StartColumn + nColumn - nDeleteCount, aRange.StartRow,
aRange.StartColumn + nColumn - nDeleteCount, aRange.EndRow, false);
++nDeleteCount;
}
else
{
for (int nRow = aRange.StartRow; nRow <= aRange.EndRow; ++nRow)
{
bNoDuplicatesForSelection = false;
DoneBlockMode( nModifier );
nModifier = true;
InitBlockMode( aRange.StartColumn + nColumn, nRow, aRange.Sheet, false, false);
}
}
}
else
{
aUnionArray.push_back(aSeq);
}
++nColumn;
}
}
if (bNoDuplicatesForSelection && !bRemove)
Unmark();
}
ScTabViewShell::ScTabViewShell( SfxViewFrame& rViewFrame,
SfxViewShell* pOldSh ) :
SfxViewShell(rViewFrame, SfxViewShellFlags::HAS_PRINTOPTIONS),
ScDBFunc( &rViewFrame.GetWindow(), static_cast<ScDocShell&>(*rViewFrame.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),
bMoveKeepEdit(false),
nCurRefDlgId(0),
mbInSwitch(false),
m_pDragData(new ScDragData),
m_pScCondFormatDlgItem()
{
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);
mChangesListener.set(new ScViewOptiChangesListener(*this));
// 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);
}
}
if (comphelper::LibreOfficeKit::isActive())
{
ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>(GetCurrentDocument());
SfxLokHelper::notifyViewRenderState(this, pModel);
}
}
ScTabViewShell::~ScTabViewShell()
{
bInDispose = true;
mChangesListener->stopListening();
mChangesListener.clear();
// Notify other LOK views that we are going away.
SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", "false"_ostr);
SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", ""_ostr);
SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY"_ostr);
SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", "EMPTY"_ostr);
// 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: */
↑ V522 There might be dereferencing of a potential null pointer 'pTabViewShell'.