Files
core/sc/source/ui/docshell/docsh4.cxx
Darshan-upadhyay1110 5114b8edea feat(sc): Add UNO command for page orientation in Calc
Implements UNO command support for setting Calc page orientation (Portrait/Landscape)
via '.uno:Orientation' with a direct boolean parameter.

- Reuses existing SID_ATTR_PAGE_ORIENTATION.
- Uses SfxBoolItem parameter for orientation.
- Provides API for programmatic orientation control

Change-Id: I55bf9a16a0c97aa6d0d242cdfc7771b210eab47b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187590
Reviewed-by: Szymon Kłos <szymon.klos@collabora.com>
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
(cherry picked from commit 427de88f76)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188753
Tested-by: Jenkins
2025-08-08 08:21:27 +02:00

3110 lines
125 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <config_features.h>
#include <com/sun/star/frame/Desktop.hpp>
#include <scitems.hxx>
#include <editeng/flstitem.hxx>
#include <sfx2/fcontnr.hxx>
#include <sfx2/infobar.hxx>
#include <sfx2/objface.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/sfxresid.hxx>
#include <sfx2/strings.hrc>
#include <svtools/ehdl.hxx>
#include <svtools/langtab.hxx>
#include <basic/sbxcore.hxx>
#include <basic/sberrors.hxx>
#include <svtools/sfxecode.hxx>
#include <svx/ofaitem.hxx>
#include <svx/svdograf.hxx>
#include <svl/stritem.hxx>
#include <svl/whiter.hxx>
#include <vcl/stdtext.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <svx/dataaccessdescriptor.hxx>
#include <svx/drawitem.hxx>
#include <svx/fmshell.hxx>
#include <svx/pageitem.hxx>
#include <editeng/sizeitem.hxx>
#include <sfx2/passwd.hxx>
#include <sfx2/filedlghelper.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/sfxdlg.hxx>
#include <svl/PasswordHelper.hxx>
#include <svl/documentlockfile.hxx>
#include <svl/sharecontrolfile.hxx>
#include <tools/json_writer.hxx>
#include <unotools/securityoptions.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <sal/log.hxx>
#include <unotools/charclass.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <o3tl/string_view.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/propertyvalue.hxx>
#include <docuno.hxx>
#include <docsh.hxx>
#include "docshimp.hxx"
#include <docfunc.hxx>
#include <scres.hrc>
#include <strings.hrc>
#include <stlsheet.hxx>
#include <stlpool.hxx>
#include <appoptio.hxx>
#include <globstr.hrc>
#include <global.hxx>
#include <dbdocfun.hxx>
#include <printfun.hxx>
#include <viewdata.hxx>
#include <tabvwsh.hxx>
#include <impex.hxx>
#include <undodat.hxx>
#include <undocell.hxx>
#include <inputhdl.hxx>
#include <dbdata.hxx>
#include <servobj.hxx>
#include <rangenam.hxx>
#include <scmod.hxx>
#include <chgviset.hxx>
#include <reffact.hxx>
#include <chartlis.hxx>
#include <chartpos.hxx>
#include <tablink.hxx>
#include <drwlayer.hxx>
#include <docoptio.hxx>
#include <undostyl.hxx>
#include <rangeseq.hxx>
#include <chgtrack.hxx>
#include <com/sun/star/document/UpdateDocMode.hpp>
#include <scresid.hxx>
#include <scabstdlg.hxx>
#include <sharedocdlg.hxx>
#include <conditio.hxx>
#include <sheetevents.hxx>
#include <formulacell.hxx>
#include <documentlinkmgr.hxx>
#include <memory>
#include <sfx2/notebookbar/SfxNotebookBar.hxx>
#include <helpids.h>
#include <editeng/eeitem.hxx>
#include <editeng/langitem.hxx>
#include <editeng/urlfieldhelper.hxx>
#include <officecfg/Office/Common.hxx>
#include <svx/xdef.hxx>
using namespace ::com::sun::star;
void ScDocShell::SetInitialLinkUpdate( const SfxMedium* pMed )
{
if (pMed)
{
const SfxUInt16Item* pUpdateDocItem = pMed->GetItemSet().GetItem(SID_UPDATEDOCMODE, false);
m_nCanUpdate = pUpdateDocItem ? pUpdateDocItem->GetValue() : css::document::UpdateDocMode::NO_UPDATE;
}
// GetLinkUpdateModeState() evaluates m_nCanUpdate so that must have
// been set first. Do not override an already forbidden LinkUpdate (the
// default is allow).
comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = getEmbeddedObjectContainer();
if (rEmbeddedObjectContainer.getUserAllowsLinkUpdate())
{
// For anything else than LM_ALWAYS we need user confirmation.
rEmbeddedObjectContainer.setUserAllowsLinkUpdate( GetLinkUpdateModeState() == LM_ALWAYS);
}
}
ScLkUpdMode ScDocShell::GetLinkUpdateModeState() const
{
ScLkUpdMode nSet;
if (m_nCanUpdate == css::document::UpdateDocMode::NO_UPDATE)
nSet = LM_NEVER;
else if (m_nCanUpdate == css::document::UpdateDocMode::FULL_UPDATE)
nSet = LM_ALWAYS;
else
{
nSet = GetDocument().GetLinkMode();
if (nSet == LM_UNKNOWN)
{
ScAppOptions aAppOptions = ScModule::get()->GetAppOptions();
nSet = aAppOptions.GetLinkMode();
}
}
if (nSet != LM_NEVER
&& (SvtSecurityOptions::isUntrustedReferer(
GetMedium() == nullptr ? OUString() : GetMedium()->GetName())
|| (IsDocShared() && SvtSecurityOptions::isUntrustedReferer(GetSharedFileURL()))))
{
nSet = LM_NEVER;
}
else if (nSet == LM_ALWAYS
&& !(SvtSecurityOptions::isTrustedLocationUriForUpdatingLinks(
GetMedium() == nullptr ? OUString() : GetMedium()->GetName())
|| (IsDocShared()
&& SvtSecurityOptions::isTrustedLocationUriForUpdatingLinks(
GetSharedFileURL()))))
{
nSet = LM_ON_DEMAND;
}
if (m_nCanUpdate == css::document::UpdateDocMode::QUIET_UPDATE
&& nSet == LM_ON_DEMAND)
{
nSet = LM_NEVER;
}
return nSet;
}
void ScDocShell::AllowLinkUpdate()
{
m_pDocument->SetLinkFormulaNeedingCheck(false);
getEmbeddedObjectContainer().setUserAllowsLinkUpdate(true);
}
void ScDocShell::ReloadAllLinks()
{
AllowLinkUpdate();
ReloadTabLinks();
weld::Window *pDialogParent = GetActiveDialogParent();
m_pDocument->UpdateExternalRefLinks(pDialogParent);
bool bAnyDde = m_pDocument->GetDocLinkManager().updateDdeOrOleOrWebServiceLinks(pDialogParent);
if (bAnyDde)
{
// calculate formulas and paint like in the TrackTimeHdl
m_pDocument->TrackFormulas();
Broadcast(SfxHint(SfxHintId::ScDataChanged));
// Should FID_DATACHANGED become asynchronous some time
// (e.g., with Invalidate at Window), an update needs to be forced here.
}
m_pDocument->UpdateAreaLinks();
}
IMPL_LINK( ScDocShell, ReloadAllLinksHdl, weld::Button&, rButton, void )
{
ScDocument& rDoc = GetDocument();
if (rDoc.HasLinkFormulaNeedingCheck() && rDoc.GetDocLinkManager().hasExternalRefLinks())
{
// If we have WEBSERVICE/Dde link and other external links in the document, it might indicate some
// exfiltration attempt, add *another* warning about this on top of the "Security Warning"
// shown in the infobar before they got here.
std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(&rButton,
VclMessageType::Warning, VclButtonsType::YesNo,
ScResId(STR_TRUST_DOCUMENT_WARNING)));
xQueryBox->set_secondary_text(ScResId(STR_WEBSERVICE_WITH_LINKS_WARNING));
xQueryBox->set_default_response(RET_NO);
if (xQueryBox->run() != RET_YES)
return;
}
ReloadAllLinks();
ScTabViewShell* pViewSh = GetBestViewShell();
SfxViewFrame* pViewFrame = pViewSh ? pViewSh->GetFrame() : nullptr;
if (pViewFrame)
pViewFrame->RemoveInfoBar(u"enablecontent");
SAL_WARN_IF(!pViewFrame, "sc", "expected there to be a ViewFrame");
}
namespace
{
class LinkHelp
{
public:
DECL_STATIC_LINK(LinkHelp, DispatchHelpLinksHdl, weld::Button&, void);
};
}
IMPL_STATIC_LINK(LinkHelp, DispatchHelpLinksHdl, weld::Button&, rBtn, void)
{
if (Help* pHelp = Application::GetHelp())
pHelp->Start(HID_UPDATE_LINK_WARNING, &rBtn);
}
void ScDocShell::Execute( SfxRequest& rReq )
{
const SfxItemSet* pReqArgs = rReq.GetArgs();
SfxBindings* pBindings = GetViewBindings();
bool bUndo (m_pDocument->IsUndoEnabled());
sal_uInt16 nSlot = rReq.GetSlot();
switch ( nSlot )
{
case SID_SC_SETTEXT:
{
const SfxPoolItem* pColItem;
const SfxPoolItem* pRowItem;
const SfxPoolItem* pTabItem;
const SfxPoolItem* pTextItem;
if( pReqArgs && pReqArgs->HasItem( FN_PARAM_1, &pColItem ) &&
pReqArgs->HasItem( FN_PARAM_2, &pRowItem ) &&
pReqArgs->HasItem( FN_PARAM_3, &pTabItem ) &&
pReqArgs->HasItem( SID_SC_SETTEXT, &pTextItem ) )
{
// parameters are 1-based !!!
SCCOL nCol = static_cast<const SfxInt16Item*>(pColItem)->GetValue() - 1;
SCROW nRow = static_cast<const SfxInt32Item*>(pRowItem)->GetValue() - 1;
SCTAB nTab = static_cast<const SfxInt16Item*>(pTabItem)->GetValue() - 1;
SCTAB nTabCount = m_pDocument->GetTableCount();
if ( m_pDocument->ValidCol(nCol) && m_pDocument->ValidRow(nRow) && ValidTab(nTab,nTabCount) )
{
if ( m_pDocument->IsBlockEditable( nTab, nCol,nRow, nCol, nRow ) )
{
OUString aVal = static_cast<const SfxStringItem*>(pTextItem)->GetValue();
m_pDocument->SetString( nCol, nRow, nTab, aVal );
PostPaintCell( nCol, nRow, nTab );
SetDocumentModified();
rReq.Done();
break;
}
else // protected cell
{
#if HAVE_FEATURE_SCRIPTING
SbxBase::SetError( ERRCODE_BASIC_BAD_PARAMETER ); //! which error ?
#endif
break;
}
}
}
#if HAVE_FEATURE_SCRIPTING
SbxBase::SetError( ERRCODE_BASIC_NO_OBJECT );
#endif
}
break;
case SID_SBA_IMPORT:
{
if (pReqArgs)
{
const SfxPoolItem* pItem;
svx::ODataAccessDescriptor aDesc;
if ( pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
{
uno::Any aAny = static_cast<const SfxUnoAnyItem*>(pItem)->GetValue();
uno::Sequence<beans::PropertyValue> aProperties;
if ( aAny >>= aProperties )
aDesc.initializeFrom( aProperties );
}
OUString sTarget;
if ( pReqArgs->GetItemState( FN_PARAM_1, true, &pItem ) == SfxItemState::SET )
sTarget = static_cast<const SfxStringItem*>(pItem)->GetValue();
bool bIsNewArea = true; // Default sal_True (no inquiry)
if ( pReqArgs->GetItemState( FN_PARAM_2, true, &pItem ) == SfxItemState::SET )
bIsNewArea = static_cast<const SfxBoolItem*>(pItem)->GetValue();
// if necessary, create new database area
bool bMakeArea = false;
if (bIsNewArea)
{
ScDBCollection* pDBColl = m_pDocument->GetDBCollection();
if ( !pDBColl || !pDBColl->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(sTarget)) )
{
ScAddress aPos;
if ( aPos.Parse( sTarget, *m_pDocument, m_pDocument->GetAddressConvention() ) & ScRefFlags::VALID )
{
bMakeArea = true;
if (bUndo)
{
OUString aStrImport = ScResId( STR_UNDO_IMPORTDATA );
ViewShellId nViewShellId(-1);
if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
nViewShellId = pViewSh->GetViewShellId();
GetUndoManager()->EnterListAction( aStrImport, aStrImport, 0, nViewShellId );
}
ScDBData* pDBData = GetDBData( ScRange(aPos), SC_DB_IMPORT, ScGetDBSelection::Keep );
assert(pDBData && "Cannot create DB data");
sTarget = pDBData->GetName();
}
}
}
// inquire, before old DB range gets overwritten
bool bDo = true;
if (!bIsNewArea)
{
OUString aTemplate = ScResId( STR_IMPORT_REPLACE );
OUString aMessage = o3tl::getToken(aTemplate, 0, '#' )
+ sTarget
+ o3tl::getToken(aTemplate, 1, '#' );
std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
VclMessageType::Question, VclButtonsType::YesNo,
aMessage));
xQueryBox->set_default_response(RET_YES);
bDo = xQueryBox->run() == RET_YES;
}
if (bDo)
{
ScDBDocFunc(*this).UpdateImport( sTarget, aDesc );
rReq.Done();
// UpdateImport also updates the internal operations
}
else
rReq.Ignore();
if ( bMakeArea && bUndo)
GetUndoManager()->LeaveListAction();
}
else
{
OSL_FAIL( "arguments expected" );
}
}
break;
case SID_CHART_SOURCE:
case SID_CHART_ADDSOURCE:
ExecuteChartSource(rReq);
break;
case FID_AUTO_CALC:
{
bool bNewVal;
const SfxPoolItem* pItem;
if ( pReqArgs && SfxItemState::SET == pReqArgs->GetItemState( nSlot, true, &pItem ) )
bNewVal = static_cast<const SfxBoolItem*>(pItem)->GetValue();
else
bNewVal = !m_pDocument->GetAutoCalc(); // Toggle for menu
m_pDocument->SetAutoCalc( bNewVal );
SetDocumentModified();
if (pBindings)
{
pBindings->Invalidate( FID_AUTO_CALC );
}
rReq.AppendItem( SfxBoolItem( FID_AUTO_CALC, bNewVal ) );
rReq.Done();
}
break;
case SID_OPEN_HYPERLINK:
{
ScViewData* pViewData = GetViewData();
if ( !pViewData )
{
rReq.Ignore();
break;
}
if (ScModule::get()->IsEditMode())
{
if (EditView* pEditView = pViewData->GetEditView(pViewData->GetActivePart()))
{
const SvxFieldItem* pFieldItem = pEditView->GetFieldAtSelection(/*bAlsoCheckBeforeCursor=*/true);
const SvxFieldData* pField = pFieldItem ? pFieldItem->GetField() : nullptr;
if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
{
ScGlobal::OpenURL(pURLField->GetURL(), pURLField->GetTargetFrame(), true);
rReq.Done();
break;
}
}
}
else
{
if (ScGridWindow* pWin = pViewData->GetActiveWin())
{
std::vector<UrlData> vUrls = pWin->GetEditUrls(pViewData->GetCurPos());
if (!vUrls.empty())
{
for (UrlData& data : vUrls)
{
ScGlobal::OpenURL(data.aUrl, data.aTarget, true);
}
rReq.Done();
break;
}
}
}
rReq.Ignore();
}
break;
case FID_RECALC:
DoRecalc( rReq.IsAPI() );
rReq.Done();
break;
case FID_HARD_RECALC:
DoHardRecalc();
rReq.Done();
break;
case SID_UPDATETABLINKS:
{
ScLkUpdMode nSet = GetLinkUpdateModeState();
if (nSet == LM_ALWAYS)
{
ReloadAllLinks();
rReq.Done();
}
else if (nSet == LM_NEVER)
{
getEmbeddedObjectContainer().setUserAllowsLinkUpdate(false);
rReq.Ignore();
}
else if (nSet == LM_ON_DEMAND)
{
ScTabViewShell* pViewSh = GetBestViewShell();
SfxViewFrame* pViewFrame = pViewSh ? pViewSh->GetFrame() : nullptr;
if (pViewFrame)
{
pViewFrame->RemoveInfoBar(u"enablecontent");
auto pInfoBar = pViewFrame->AppendInfoBar(u"enablecontent"_ustr, SfxResId(RID_SECURITY_WARNING_TITLE),
ScResId(STR_RELOAD_TABLES), InfobarType::WARNING);
if (pInfoBar)
{
weld::Button& rHelpBtn = pInfoBar->addButton();
rHelpBtn.set_label(GetStandardText(StandardButtonType::Help).replaceFirst("~", ""));
rHelpBtn.connect_clicked(LINK(nullptr, LinkHelp, DispatchHelpLinksHdl));
weld::Button& rBtn = pInfoBar->addButton();
rBtn.set_label(ScResId(STR_ENABLE_CONTENT));
rBtn.set_tooltip_text(ScResId(STR_ENABLE_CONTENT_TOOLTIP));
rBtn.connect_clicked(LINK(this, ScDocShell, ReloadAllLinksHdl));
// when active content is disabled the "Allow updating" button has no functionality.
if (officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
{
rBtn.set_tooltip_text(ScResId(STR_ENABLE_CONTENT_TOOLTIP_DISABLED));
rBtn.set_sensitive(false);
}
}
}
rReq.Done();
}
}
break;
case SID_REIMPORT_AFTER_LOAD:
{
// Is called after loading if there are DB areas with omitted data
bool bDone = false;
ScDBCollection* pDBColl = m_pDocument->GetDBCollection();
if ((m_nCanUpdate != css::document::UpdateDocMode::NO_UPDATE) &&
(m_nCanUpdate != css::document::UpdateDocMode::QUIET_UPDATE))
{
ScRange aRange;
ScTabViewShell* pViewSh = GetBestViewShell();
OSL_ENSURE(pViewSh,"SID_REIMPORT_AFTER_LOAD: no View");
if (pViewSh && pDBColl)
{
std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetActiveDialogParent(),
VclMessageType::Question, VclButtonsType::YesNo,
ScResId(STR_REIMPORT_AFTER_LOAD)));
xQueryBox->set_default_response(RET_YES);
if (xQueryBox->run() == RET_YES)
{
ScDBCollection::NamedDBs& rDBs = pDBColl->getNamedDBs();
for (const auto& rxDB : rDBs)
{
ScDBData& rDBData = *rxDB;
if ( rDBData.IsStripData() &&
rDBData.HasImportParam() && !rDBData.HasImportSelection() )
{
rDBData.GetArea(aRange);
pViewSh->MarkRange(aRange);
// Import and internal operations like SID_REFRESH_DBAREA
// (inquiry for import not needed here)
ScImportParam aImportParam;
rDBData.GetImportParam( aImportParam );
bool bContinue = pViewSh->ImportData( aImportParam );
rDBData.SetImportParam( aImportParam );
// mark (size may have changed)
rDBData.GetArea(aRange);
pViewSh->MarkRange(aRange);
if ( bContinue ) // error at import -> abort
{
// internal operations, if some where saved
if ( rDBData.HasQueryParam() || rDBData.HasSortParam() ||
rDBData.HasSubTotalParam() )
pViewSh->RepeatDB();
// pivot tables, which have the range as source data
RefreshPivotTables(aRange);
}
}
}
bDone = true;
}
}
}
if ( !bDone && pDBColl )
{
// if not, but then update the dependent formulas
//! also for individual ranges, which cannot be updated
m_pDocument->CalcAll(); //! only for the dependent
PostDataChanged();
}
if (bDone)
rReq.Done();
else
rReq.Ignore();
}
break;
case SID_ATTR_PAGE_ORIENTATION: // .uno:Orientation
{
const SfxBoolItem* pBool = rReq.GetArg<SfxBoolItem>(SID_ATTR_PAGE_ORIENTATION);
if (!pBool) // nothing supplied -> do nothing
{
rReq.Done();
break;
}
ScViewData* pViewData = GetViewData();
if (!pViewData)
break;
ScDocument& rDoc = GetDocument();
const SCTAB nTab = pViewData->GetTabNo();
// obtain the page-styles ItemSet
OUString aStyleName = rDoc.GetPageStyle(nTab);
ScStyleSheetPool* pPagePool = rDoc.GetStyleSheetPool();
if (!pPagePool)
break;
SfxStyleSheetBase* pStyle = pPagePool->Find(aStyleName, SfxStyleFamily::Page);
if (!pStyle)
break;
SfxItemSet& rSet = pStyle->GetItemSet();
const SvxPageItem& rOldPageItem = rSet.Get(ATTR_PAGE);
const SvxSizeItem& rOldSizeItem = rSet.Get(ATTR_PAGE_SIZE);
bool bDesiredLandscape = pBool->GetValue();
bool bCurrentLandscape = rOldPageItem.IsLandscape();
if (bDesiredLandscape == bCurrentLandscape) // already correct
{
rReq.Done();
break;
}
// apply the change: flip orientation and swap paper size
SvxPageItem aNewPageItem(ATTR_PAGE);
aNewPageItem.SetLandscape(bDesiredLandscape);
Size aOld = rOldSizeItem.GetSize();
Size aNew(aOld.Height(), aOld.Width()); // swap W/H
SvxSizeItem aNewSizeItem(ATTR_PAGE_SIZE, aNew);
rSet.Put(aNewPageItem);
rSet.Put(aNewSizeItem);
SetDocumentModified();
PostPaintGridAll(); // repaint sheet
if (pBindings) {
pBindings->Invalidate(SID_ATTR_PAGE_ORIENTATION);
pBindings->Invalidate(SID_ATTR_PAGE_SIZE);
}
rReq.Done();
}
break;
case SID_AUTO_STYLE:
OSL_FAIL("use ScAutoStyleHint instead of SID_AUTO_STYLE");
break;
case SID_GET_COLORLIST:
{
const SvxColorListItem* pColItem = GetItem(SID_COLOR_TABLE);
const XColorListRef& pList = pColItem->GetColorList();
rReq.SetReturnValue(OfaXColorListItem(SID_GET_COLORLIST, pList));
}
break;
case FID_CHG_RECORD:
{
ScDocument& rDoc = GetDocument();
// get argument (recorded macro)
const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(FID_CHG_RECORD);
bool bDo = true;
// desired state
ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
bool bActivateTracking = (pChangeTrack == nullptr); // toggle
if ( pItem )
bActivateTracking = pItem->GetValue(); // from argument
if ( !bActivateTracking )
{
if ( !pItem )
{
// no dialog on playing the macro
std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
VclMessageType::Warning, VclButtonsType::YesNo,
ScResId(STR_END_REDLINING)));
xWarn->set_default_response(RET_NO);
bDo = (xWarn->run() == RET_YES );
}
if ( bDo )
{
if (pChangeTrack)
{
if ( pChangeTrack->IsProtected() )
bDo = ExecuteChangeProtectionDialog();
}
if ( bDo )
{
rDoc.EndChangeTracking();
PostPaintGridAll();
}
}
}
else
{
rDoc.StartChangeTracking();
ScChangeViewSettings aChangeViewSet;
aChangeViewSet.SetShowChanges(true);
rDoc.SetChangeViewSettings(aChangeViewSet);
}
if ( bDo )
{
UpdateAcceptChangesDialog();
// invalidate slots
if (pBindings)
pBindings->InvalidateAll(false);
if ( !pItem )
rReq.AppendItem( SfxBoolItem( FID_CHG_RECORD, bActivateTracking ) );
rReq.Done();
}
else
rReq.Ignore();
}
break;
case SID_CHG_PROTECT :
{
if ( ExecuteChangeProtectionDialog() )
{
rReq.Done();
SetDocumentModified();
}
else
rReq.Ignore();
}
break;
case SID_DOCUMENT_MERGE:
case SID_DOCUMENT_COMPARE:
{
bool bDo = true;
ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
if ( pChangeTrack && !m_pImpl->bIgnoreLostRedliningWarning )
{
if ( nSlot == SID_DOCUMENT_COMPARE )
{ //! old changes trace will be lost
std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
VclMessageType::Warning, VclButtonsType::YesNo,
ScResId(STR_END_REDLINING)));
xWarn->set_default_response(RET_NO);
if (xWarn->run() == RET_YES)
bDo = ExecuteChangeProtectionDialog( true );
else
bDo = false;
}
else // merge might reject some actions
bDo = ExecuteChangeProtectionDialog( true );
}
if ( !bDo )
{
rReq.Ignore();
break;
}
SfxApplication* pApp = SfxGetpApp();
const SfxPoolItem* pItem;
const SfxStringItem* pFileNameItem(nullptr);
SfxMedium* pMed = nullptr;
if (pReqArgs)
pFileNameItem = pReqArgs->GetItemIfSet(SID_FILE_NAME);
if (pFileNameItem)
{
OUString aFileName = pFileNameItem->GetValue();
OUString aFilterName;
if (const SfxStringItem* pFilterItem = pReqArgs->GetItemIfSet(SID_FILTER_NAME))
{
aFilterName = pFilterItem->GetValue();
}
OUString aOptions;
if (const SfxStringItem* pOptionsItem = pReqArgs->GetItemIfSet(SID_FILE_FILTEROPTIONS))
{
aOptions = pOptionsItem->GetValue();
}
short nVersion = 0;
const SfxInt16Item* pInt16Item(nullptr);
if (pReqArgs->GetItemState(SID_VERSION, true, &pItem) == SfxItemState::SET)
pInt16Item = dynamic_cast<const SfxInt16Item*>(pItem);
if (pInt16Item)
{
nVersion = pInt16Item->GetValue();
}
// no filter specified -> detection
if (aFilterName.isEmpty())
ScDocumentLoader::GetFilterName( aFileName, aFilterName, aOptions, true, false );
// filter name from dialog contains application prefix,
// GetFilter needs name without the prefix.
ScDocumentLoader::RemoveAppPrefix( aFilterName );
std::shared_ptr<const SfxFilter> pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName( aFilterName );
auto pSet = std::make_shared<SfxAllItemSet>( pApp->GetPool() );
if (!aOptions.isEmpty())
pSet->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, aOptions ) );
if ( nVersion != 0 )
pSet->Put( SfxInt16Item( SID_VERSION, nVersion ) );
pMed = new SfxMedium( aFileName, StreamMode::STD_READ, std::move(pFilter), std::move(pSet) );
}
else
{
const sfx2::DocumentInserter::Mode mode { nSlot==SID_DOCUMENT_COMPARE
? sfx2::DocumentInserter::Mode::Compare
: sfx2::DocumentInserter::Mode::Merge};
// start file dialog asynchronous
m_pImpl->bIgnoreLostRedliningWarning = true;
m_pImpl->pRequest.reset(new SfxRequest( rReq ));
m_pImpl->pDocInserter.reset();
ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
weld::Window* pParent = pViewSh ? pViewSh->GetFrameWeld() : nullptr;
m_pImpl->pDocInserter.reset( new ::sfx2::DocumentInserter(pParent,
ScDocShell::Factory().GetFactoryName(), mode ) );
m_pImpl->pDocInserter->StartExecuteModal( LINK( this, ScDocShell, DialogClosedHdl ) );
return ;
}
// now execute in earnest...
SfxErrorContext aEc( ERRCTX_SFX_OPENDOC, pMed->GetName() );
// pOtherDocSh->DoClose() will be called explicitly later, but it is still more safe to use SfxObjectShellLock here
rtl::Reference<ScDocShell> pOtherDocSh = new ScDocShell;
pOtherDocSh->DoLoad( pMed );
ErrCodeMsg nErr = pOtherDocSh->GetErrorCode();
if (nErr)
ErrorHandler::HandleError( nErr ); // also warnings
if ( !pOtherDocSh->GetErrorIgnoreWarning() ) // only errors
{
bool bHadTrack = ( m_pDocument->GetChangeTrack() != nullptr );
#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
sal_uLong nStart = 0;
if ( nSlot == SID_DOCUMENT_MERGE && pChangeTrack )
{
nStart = pChangeTrack->GetActionMax() + 1;
}
#endif
if ( nSlot == SID_DOCUMENT_COMPARE )
CompareDocument( pOtherDocSh->GetDocument() );
else
MergeDocument( pOtherDocSh->GetDocument() );
// show "accept changes" dialog
//! get view for this document!
if ( !IsDocShared() )
{
SfxViewFrame* pViewFrm = SfxViewFrame::Current();
if ( pViewFrm )
{
pViewFrm->ShowChildWindow( ScAcceptChgDlgWrapper::GetChildWindowId() ); //@51669
}
if ( pBindings )
{
pBindings->Invalidate( FID_CHG_ACCEPT );
}
}
rReq.SetReturnValue( SfxInt32Item( TypedWhichId<SfxInt32Item>(nSlot), 0 ) ); //! ???????
rReq.Done();
if (!bHadTrack) // newly turned on -> show as well
{
ScChangeViewSettings* pOldSet = m_pDocument->GetChangeViewSettings();
if ( !pOldSet || !pOldSet->ShowChanges() )
{
ScChangeViewSettings aChangeViewSet;
aChangeViewSet.SetShowChanges(true);
m_pDocument->SetChangeViewSettings(aChangeViewSet);
}
}
#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
else if ( nSlot == SID_DOCUMENT_MERGE && IsDocShared() && pChangeTrack )
{
sal_uLong nEnd = pChangeTrack->GetActionMax();
if ( nEnd >= nStart )
{
// only show changes from merged document
ScChangeViewSettings aChangeViewSet;
aChangeViewSet.SetShowChanges( true );
aChangeViewSet.SetShowAccepted( true );
aChangeViewSet.SetHasActionRange();
aChangeViewSet.SetTheActionRange( nStart, nEnd );
m_pDocument->SetChangeViewSettings( aChangeViewSet );
// update view
PostPaintExtras();
PostPaintGridAll();
}
}
#endif
}
pOtherDocSh->DoClose(); // delete happens with the Ref
}
break;
case SID_DELETE_SCENARIO:
if (pReqArgs)
{
const SfxPoolItem* pItem;
if ( pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
{
if (const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>(pItem))
{
const OUString& aName = pStringItem->GetValue();
SCTAB nTab;
if (m_pDocument->GetTable( aName, nTab ))
{
// move DeleteTable from viewfunc to docfunc!
ScTabViewShell* pSh = GetBestViewShell();
if ( pSh )
{
//! omit SetTabNo in DeleteTable?
SCTAB nDispTab = pSh->GetViewData().GetTabNo();
pSh->DeleteTable( nTab );
pSh->SetTabNo(nDispTab);
rReq.Done();
}
}
}
}
}
break;
case SID_EDIT_SCENARIO:
{
const SfxPoolItem* pItem;
if ( pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
{
if (const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>(pItem))
{
OUString aName = pStringItem->GetValue();
SCTAB nTab;
if (m_pDocument->GetTable( aName, nTab ))
{
if (m_pDocument->IsScenario(nTab))
{
OUString aComment;
Color aColor;
ScScenarioFlags nFlags;
m_pDocument->GetScenarioData( nTab, aComment, aColor, nFlags );
// Determine if the Sheet that the Scenario was created on
// is protected. But first we need to find that Sheet.
// Rewind back to the actual sheet.
SCTAB nActualTab = nTab;
do
{
nActualTab--;
}
while(m_pDocument->IsScenario(nActualTab));
bool bSheetProtected = m_pDocument->IsTabProtected(nActualTab);
ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
ScopedVclPtr<AbstractScNewScenarioDlg> pNewDlg(pFact->CreateScNewScenarioDlg(GetActiveDialogParent(), aName, true, bSheetProtected));
pNewDlg->SetScenarioData( aName, aComment, aColor, nFlags );
if ( pNewDlg->Execute() == RET_OK )
{
pNewDlg->GetScenarioData( aName, aComment, aColor, nFlags );
ModifyScenario( nTab, aName, aComment, aColor, nFlags );
rReq.Done();
}
}
}
}
}
}
break;
case SID_ATTR_YEAR2000 :
{
const SfxPoolItem* pItem;
if ( pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
{
if (const SfxUInt16Item* pInt16Item = dynamic_cast<const SfxUInt16Item*>(pItem))
{
sal_uInt16 nY2k = pInt16Item->GetValue();
// set always to DocOptions, so that it is also saved for S050
// (and all inquiries run up until now on it as well).
// SetDocOptions propagates that to the NumberFormatter
ScDocOptions aDocOpt( m_pDocument->GetDocOptions() );
aDocOpt.SetYear2000( nY2k );
m_pDocument->SetDocOptions( aDocOpt );
// the FormShell shall notice it as well
ScTabViewShell* pSh = GetBestViewShell();
if ( pSh )
{
FmFormShell* pFSh = pSh->GetFormShell();
if ( pFSh )
pFSh->SetY2KState( nY2k );
}
}
}
}
break;
#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
case SID_SHARE_DOC:
{
ScViewData* pViewData = GetViewData();
if ( !pViewData )
{
rReq.Ignore();
break;
}
weld::Window* pWin = GetActiveDialogParent();
ScShareDocumentDlg aDlg(pWin, *pViewData);
if (aDlg.run() == RET_OK)
{
bool bSetShared = aDlg.IsShareDocumentChecked();
if ( bSetShared != IsDocShared() )
{
if ( bSetShared )
{
bool bContinue = true;
if ( HasName() )
{
std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pWin,
VclMessageType::Question, VclButtonsType::YesNo,
ScResId(STR_DOC_WILLBESAVED)));
xQueryBox->set_default_response(RET_YES);
if (xQueryBox->run() == RET_NO)
{
bContinue = false;
}
}
if ( bContinue )
{
EnableSharedSettings( true );
ScModule* mod = ScModule::get();
mod->SetInSharedDocSaving(true);
if ( !SwitchToShared( true, true ) )
{
// TODO/LATER: what should be done in case the switch has failed?
// for example in case the user has cancelled the saveAs operation
}
mod->SetInSharedDocSaving(false);
InvalidateName();
GetUndoManager()->Clear();
ScTabView* pTabView = pViewData->GetView();
if ( pTabView )
{
pTabView->UpdateLayerLocks();
}
}
}
else
{
uno::Reference< frame::XModel > xModel;
try
{
// load shared file
xModel.set( LoadSharedDocument(), uno::UNO_SET_THROW );
uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY_THROW );
// check if shared flag is set in shared file
bool bShared = false;
ScModelObj* pDocObj = comphelper::getFromUnoTunnel<ScModelObj>( xModel );
if ( pDocObj )
{
ScDocShell* pDocShell = dynamic_cast< ScDocShell* >( pDocObj->GetEmbeddedObject() );
if ( pDocShell )
{
bShared = pDocShell->HasSharedXMLFlagSet();
}
}
// #i87870# check if shared status was disabled and enabled again
bool bOwnEntry = false;
try
{
::svt::ShareControlFile aControlFile( GetSharedFileURL() );
bOwnEntry = aControlFile.HasOwnEntry();
}
catch ( uno::Exception& )
{
}
if ( bShared && bOwnEntry )
{
uno::Reference< frame::XStorable > xStorable( xModel, uno::UNO_QUERY_THROW );
if ( xStorable->isReadonly() )
{
xCloseable->close( true );
OUString aUserName( ScResId( STR_UNKNOWN_USER ) );
try
{
::svt::DocumentLockFile aLockFile( GetSharedFileURL() );
LockFileEntry aData = aLockFile.GetLockData();
if ( !aData[LockFileComponent::OOOUSERNAME].isEmpty() )
{
aUserName = aData[LockFileComponent::OOOUSERNAME];
}
else if ( !aData[LockFileComponent::SYSUSERNAME].isEmpty() )
{
aUserName = aData[LockFileComponent::SYSUSERNAME];
}
}
catch ( uno::Exception& )
{
}
OUString aMessage( ScResId( STR_FILE_LOCKED_TRY_LATER ) );
aMessage = aMessage.replaceFirst( "%1", aUserName );
std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(pWin,
VclMessageType::Warning, VclButtonsType::Ok,
aMessage));
xWarn->run();
}
else
{
std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(pWin,
VclMessageType::Warning, VclButtonsType::YesNo,
ScResId(STR_DOC_DISABLESHARED)));
xWarn->set_default_response(RET_YES);
if (xWarn->run() == RET_YES)
{
xCloseable->close( true );
if ( !SwitchToShared( false, true ) )
{
// TODO/LATER: what should be done in case the switch has failed?
// for example in case the user has cancelled the saveAs operation
}
EnableSharedSettings( false );
// Do *not* use dispatch mechanism in this place - we don't want others (extensions etc.) to intercept this.
GetModel()->store();
ScTabView* pTabView = pViewData->GetView();
if ( pTabView )
{
pTabView->UpdateLayerLocks();
}
}
else
{
xCloseable->close( true );
}
}
}
else
{
xCloseable->close( true );
std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(pWin,
VclMessageType::Warning, VclButtonsType::Ok,
ScResId(STR_DOC_NOLONGERSHARED)));
xWarn->run();
}
}
catch ( uno::Exception& )
{
TOOLS_WARN_EXCEPTION( "sc", "SID_SHARE_DOC" );
ScModule::get()->SetInSharedDocSaving(false);
try
{
uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW );
xClose->close( true );
}
catch ( uno::Exception& )
{
}
}
}
}
}
rReq.Done();
}
break;
#endif
case SID_OPEN_CALC:
{
ScViewData* pViewData = GetViewData();
if (pViewData)
{
SfxStringItem aApp(SID_DOC_SERVICE, u"com.sun.star.sheet.SpreadsheetDocument"_ustr);
SfxStringItem aTarget(SID_TARGETNAME, u"_blank"_ustr);
pViewData->GetDispatcher().ExecuteList(
SID_OPENDOC, SfxCallMode::API|SfxCallMode::SYNCHRON,
{ &aApp, &aTarget });
}
}
break;
case SID_NOTEBOOKBAR:
{
const SfxStringItem* pFile = rReq.GetArg<SfxStringItem>( SID_NOTEBOOKBAR );
if ( pBindings && sfx2::SfxNotebookBar::IsActive() )
sfx2::SfxNotebookBar::ExecMethod(*pBindings, pFile ? pFile->GetValue() : u""_ustr);
else if ( pBindings )
sfx2::SfxNotebookBar::CloseMethod(*pBindings);
}
break;
case SID_LANGUAGE_STATUS:
{
OUString aLangText;
const SfxStringItem* pItem = rReq.GetArg<SfxStringItem>(nSlot);
if ( pItem )
aLangText = pItem->GetValue();
if ( !aLangText.isEmpty() )
{
LanguageType eLang, eLatin, eCjk, eCtl;
static constexpr OUString aSelectionLangPrefix(u"Current_"_ustr);
static constexpr OUString aParagraphLangPrefix(u"Paragraph_"_ustr);
static constexpr OUString aDocLangPrefix(u"Default_"_ustr);
bool bSelection = false;
bool bParagraph = false;
ScDocument& rDoc = GetDocument();
rDoc.GetLanguage( eLatin, eCjk, eCtl );
sal_Int32 nPos = 0;
if ( aLangText == "*" )
{
if (ScTabViewShell* pSh = GetBestViewShell())
{
pSh->ExecuteCellFormatDlg(rReq, u"font"_ustr);
pBindings->Invalidate(SID_LANGUAGE_STATUS);
}
}
else if ( (nPos = aLangText.indexOf(aDocLangPrefix)) != -1 )
{
aLangText = aLangText.replaceAt(nPos, aDocLangPrefix.getLength(), u"");
if ( aLangText == "LANGUAGE_NONE" )
{
eLang = LANGUAGE_NONE;
rDoc.SetLanguage( eLang, eCjk, eCtl );
}
else if ( aLangText == "RESET_LANGUAGES" )
{
ScModule::GetSpellSettings(eLang, eCjk, eCtl);
rDoc.SetLanguage(eLang, eCjk, eCtl);
}
else
{
eLang = SvtLanguageTable::GetLanguageType( aLangText );
if ( eLang != LANGUAGE_DONTKNOW && SvtLanguageOptions::GetScriptTypeOfLanguage(eLang) == SvtScriptType::LATIN )
{
rDoc.SetLanguage( eLang, eCjk, eCtl );
}
else
{
eLang = eLatin;
}
}
}
else if (-1 != (nPos = aLangText.indexOf( aSelectionLangPrefix )))
{
bSelection = true;
aLangText = aLangText.replaceAt( nPos, aSelectionLangPrefix.getLength(), u"" );
}
else if (-1 != (nPos = aLangText.indexOf( aParagraphLangPrefix )))
{
bParagraph = true;
aLangText = aLangText.replaceAt( nPos, aParagraphLangPrefix.getLength(), u"" );
}
if (bSelection)
{
ScTabViewShell* pViewShell = GetBestViewShell();
if (pViewShell)
{
const ScPatternAttr* pSelAttrs = pViewShell->GetSelectionPattern();
if (pSelAttrs)
{
const SfxItemSet& rOldSet = pSelAttrs->GetItemSet();
SfxItemPool* pItemPool = rOldSet.GetPool();
auto pNewSet = std::make_shared<SfxItemSet>(*pItemPool);
if (aLangText == "LANGUAGE_NONE")
{
pNewSet->Put(SvxLanguageItem(LANGUAGE_NONE,
pItemPool->GetWhichIDFromSlotID(SID_ATTR_CHAR_LANGUAGE)));
pNewSet->Put(SvxLanguageItem(LANGUAGE_NONE,
pItemPool->GetWhichIDFromSlotID(SID_ATTR_CHAR_CJK_LANGUAGE)));
pNewSet->Put(SvxLanguageItem(LANGUAGE_NONE,
pItemPool->GetWhichIDFromSlotID(SID_ATTR_CHAR_CTL_LANGUAGE)));
}
else
{
const LanguageType nLangType = SvtLanguageTable::GetLanguageType(aLangText);
const SvtScriptType nScriptType =
SvtLanguageOptions::GetScriptTypeOfLanguage(nLangType);
if (nScriptType == SvtScriptType::LATIN)
pNewSet->Put(SvxLanguageItem(nLangType,
pItemPool->GetWhichIDFromSlotID(SID_ATTR_CHAR_LANGUAGE)));
if (nScriptType == SvtScriptType::COMPLEX)
pNewSet->Put(SvxLanguageItem(nLangType,
pItemPool->GetWhichIDFromSlotID(SID_ATTR_CHAR_CTL_LANGUAGE)));
if (nScriptType == SvtScriptType::ASIAN)
pNewSet->Put(SvxLanguageItem(nLangType,
pItemPool->GetWhichIDFromSlotID(SID_ATTR_CHAR_CJK_LANGUAGE)));
}
pViewShell->ApplyAttributes(*pNewSet, rOldSet);
pBindings->Invalidate(SID_LANGUAGE_STATUS);
}
}
}
else if (bParagraph)
{
ScViewData* pViewData = GetViewData();
if (!pViewData)
return;
EditView* pEditView = pViewData->GetEditView(pViewData->GetActivePart());
if (!pEditView)
return;
const LanguageType nLangToUse = SvtLanguageTable::GetLanguageType( aLangText );
SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( nLangToUse );
SfxItemSet aAttrs = pEditView->getEditEngine().GetEmptyItemSet();
if (nScriptType == SvtScriptType::LATIN)
aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE ) );
if (nScriptType == SvtScriptType::COMPLEX)
aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CTL ) );
if (nScriptType == SvtScriptType::ASIAN)
aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CJK ) );
ESelection aOldSel;
if (bParagraph)
{
ESelection aSel = pEditView->GetSelection();
aOldSel = aSel;
aSel.start.nIndex = 0;
aSel.end.nIndex = EE_TEXTPOS_MAX;
pEditView->SetSelection( aSel );
}
pEditView->SetAttribs( aAttrs );
if (bParagraph)
pEditView->SetSelection( aOldSel );
}
else if ( eLang != eLatin )
{
if ( ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell() )
{
ScInputHandler* pInputHandler = ScModule::get()->GetInputHdl(pViewSh);
if ( pInputHandler )
pInputHandler->UpdateSpellSettings();
pViewSh->UpdateDrawTextOutliner();
}
SetDocumentModified();
Broadcast(SfxHint(SfxHintId::LanguageChanged));
PostPaintGridAll();
}
}
}
break;
case SID_SPELLCHECK_IGNORE_ALL:
{
ScViewData* pViewData = GetViewData();
if (!pViewData)
return;
EditView* pEditView = pViewData->GetEditView(pViewData->GetActivePart());
if (!pEditView)
return;
OUString sIgnoreText;
const SfxStringItem* pItem2 = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
if (pItem2)
sIgnoreText = pItem2->GetValue();
if(sIgnoreText == "Spelling")
{
ESelection aOldSel = pEditView->GetSelection();
pEditView->SpellIgnoreWord();
pEditView->SetSelection( aOldSel );
}
}
break;
case SID_SPELLCHECK_APPLY_SUGGESTION:
{
ScViewData* pViewData = GetViewData();
if (!pViewData)
return;
EditView* pEditView = pViewData->GetEditView(pViewData->GetActivePart());
if (!pEditView)
return;
OUString sApplyText;
const SfxStringItem* pItem2 = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
if (pItem2)
sApplyText = pItem2->GetValue();
static constexpr OUString sSpellingRule(u"Spelling_"_ustr);
sal_Int32 nPos = 0;
if(-1 != (nPos = sApplyText.indexOf( sSpellingRule )))
{
sApplyText = sApplyText.replaceAt(nPos, sSpellingRule.getLength(), u"");
pEditView->InsertText( sApplyText );
}
}
break;
case SID_REFRESH_VIEW:
{
PostPaintGridAll();
}
break;
case SID_PROTECTPOS:
case SID_PROTECTSIZE:
{
ScTabViewShell* pViewShell = GetBestViewShell();
if (!pViewShell)
return;
ScDrawView* pScDrawView = pViewShell->GetViewData().GetScDrawView();
if (!pScDrawView)
return;
const SdrMarkList& rMarkList = pScDrawView->GetMarkedObjectList();
assert ( rMarkList.GetMarkCount() == 1 );
SdrObject* pGraphicObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
if (nSlot == SID_PROTECTSIZE)
pGraphicObj->SetResizeProtect(!pGraphicObj->IsResizeProtect());
else
pGraphicObj->SetMoveProtect(!pGraphicObj->IsMoveProtect());
}
break;
default:
{
// small (?) hack -> forwarding of the slots to TabViewShell
ScTabViewShell* pSh = GetBestViewShell();
if ( pSh )
pSh->Execute( rReq );
#if HAVE_FEATURE_SCRIPTING
else
SbxBase::SetError( ERRCODE_BASIC_NO_ACTIVE_OBJECT );
#endif
}
}
}
void UpdateAcceptChangesDialog()
{
// update "accept changes" dialog
//! notify all views
SfxViewFrame* pViewFrm = SfxViewFrame::Current();
if ( pViewFrm && pViewFrm->HasChildWindow( FID_CHG_ACCEPT ) )
{
SfxChildWindow* pChild = pViewFrm->GetChildWindow( FID_CHG_ACCEPT );
if ( pChild )
static_cast<ScAcceptChgDlgWrapper*>(pChild)->ReInitDlg();
}
}
void ScDocShell::ExecuteChartSource(SfxRequest& rReq)
{
const SfxItemSet* pReqArgs = rReq.GetArgs();
sal_uInt16 nSlot = rReq.GetSlot();
bool bUndo (m_pDocument->IsUndoEnabled());
if (!pReqArgs)
{
OSL_FAIL("SID_CHART_SOURCE without arguments");
return;
}
ScDocument& rDoc = GetDocument();
const SfxPoolItem* pItem;
OUString aChartName, aRangeName;
ScRange aSingleRange;
ScRangeListRef aRangeListRef;
bool bMultiRange = false;
bool bColHeaders = true;
bool bRowHeaders = true;
bool bColInit = false;
bool bRowInit = false;
bool bAddRange = (nSlot == SID_CHART_ADDSOURCE);
if( const SfxStringItem* pChartItem = pReqArgs->GetItemIfSet( SID_CHART_NAME ) )
aChartName = pChartItem->GetValue();
if( const SfxStringItem* pChartItem = pReqArgs->GetItemIfSet( SID_CHART_SOURCE ) )
aRangeName = pChartItem->GetValue();
if( pReqArgs->HasItem( FN_PARAM_1, &pItem ) )
{
bColHeaders = static_cast<const SfxBoolItem*>(pItem)->GetValue();
bColInit = true;
}
if( pReqArgs->HasItem( FN_PARAM_2, &pItem ) )
{
bRowHeaders = static_cast<const SfxBoolItem*>(pItem)->GetValue();
bRowInit = true;
}
ScAddress::Details aDetails(rDoc.GetAddressConvention(), 0, 0);
bool bValid = (aSingleRange.ParseAny(aRangeName, rDoc, aDetails) & ScRefFlags::VALID) != ScRefFlags::ZERO;
if (!bValid)
{
aRangeListRef = new ScRangeList;
aRangeListRef->Parse( aRangeName, rDoc, rDoc.GetAddressConvention());
if ( !aRangeListRef->empty() )
{
bMultiRange = true;
aSingleRange = aRangeListRef->front(); // for header
bValid = true;
}
else
aRangeListRef.clear();
}
ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
if (!pViewSh || !bValid || aChartName.isEmpty() )
{
OSL_FAIL("UpdateChartArea: no ViewShell or wrong data");
rReq.Done();
return;
}
weld::Window* pParent = pViewSh->GetFrameWeld();
SCCOL nCol1 = aSingleRange.aStart.Col();
SCROW nRow1 = aSingleRange.aStart.Row();
SCCOL nCol2 = aSingleRange.aEnd.Col();
SCROW nRow2 = aSingleRange.aEnd.Row();
SCTAB nTab = aSingleRange.aStart.Tab();
//! limit always or not at all ???
if (!bMultiRange)
m_pDocument->LimitChartArea( nTab, nCol1,nRow1, nCol2,nRow2 );
// Dialog for column/row headers
if ( !bAddRange && ( !bColInit || !bRowInit ) )
{
ScChartPositioner aChartPositioner( *m_pDocument, nTab, nCol1,nRow1, nCol2,nRow2 );
if (!bColInit)
bColHeaders = aChartPositioner.HasColHeaders();
if (!bRowInit)
bRowHeaders = aChartPositioner.HasRowHeaders();
auto xRequest = std::make_shared<SfxRequest>(rReq);
rReq.Ignore(); // the 'old' request is not relevant any more
ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
VclPtr<AbstractScColRowLabelDlg> pDlg(pFact->CreateScColRowLabelDlg(pParent, bRowHeaders, bColHeaders));
pDlg->StartExecuteAsync(
[this, pDlg, xRequest=std::move(xRequest), bUndo, bMultiRange,
aChartName, aRangeListRef=std::move(aRangeListRef), bAddRange,
nCol1, nRow1, nCol2, nRow2, nTab] (sal_Int32 nResult)->void
{
if (nResult == RET_OK)
{
bool bColHeaders2 = pDlg->IsRow();
bool bRowHeaders2 = pDlg->IsCol();
xRequest->AppendItem(SfxBoolItem(FN_PARAM_1, bColHeaders2));
xRequest->AppendItem(SfxBoolItem(FN_PARAM_2, bRowHeaders2));
ExecuteChartSourcePost(bUndo, bMultiRange,
aChartName, aRangeListRef, bColHeaders2, bRowHeaders2, bAddRange,
nCol1, nRow1, nCol2, nRow2, nTab);
}
pDlg->disposeOnce();
xRequest->Done();
}
);
}
else
{
ExecuteChartSourcePost(bUndo, bMultiRange,
aChartName, aRangeListRef, bColHeaders, bRowHeaders, bAddRange,
nCol1, nRow1,nCol2, nRow2, nTab);
rReq.Done();
}
}
void ScDocShell::ExecuteChartSourcePost(bool bUndo, bool bMultiRange,
const OUString& rChartName, const ScRangeListRef& rRangeListRef,
bool bColHeaders, bool bRowHeaders, bool bAddRange,
SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab )
{
if (bMultiRange)
{
if (bUndo)
{
GetUndoManager()->AddUndoAction(
std::make_unique<ScUndoChartData>( *this, rChartName, rRangeListRef,
bColHeaders, bRowHeaders, bAddRange ) );
}
m_pDocument->UpdateChartArea( rChartName, rRangeListRef,
bColHeaders, bRowHeaders, bAddRange );
}
else
{
ScRange aNewRange( nCol1,nRow1,nTab, nCol2,nRow2,nTab );
if (bUndo)
{
GetUndoManager()->AddUndoAction(
std::make_unique<ScUndoChartData>( *this, rChartName, aNewRange,
bColHeaders, bRowHeaders, bAddRange ) );
}
m_pDocument->UpdateChartArea( rChartName, aNewRange,
bColHeaders, bRowHeaders, bAddRange );
}
}
bool ScDocShell::ExecuteChangeProtectionDialog( bool bJustQueryIfProtected )
{
bool bDone = false;
ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
if ( pChangeTrack )
{
bool bProtected = pChangeTrack->IsProtected();
if ( bJustQueryIfProtected && !bProtected )
return true;
OUString aTitle( ScResId( bProtected ? SCSTR_CHG_UNPROTECT : SCSTR_CHG_PROTECT ) );
OUString aText( ScResId( SCSTR_PASSWORD ) );
OUString aPassword;
weld::Window* pWin = ScDocShell::GetActiveDialogParent();
SfxPasswordDialog aDlg(pWin, &aText);
aDlg.set_title(aTitle);
aDlg.SetMinLen(1);
aDlg.set_help_id(GetStaticInterface()->GetSlot(SID_CHG_PROTECT)->GetCommand());
aDlg.SetEditHelpId( HID_CHG_PROTECT );
if ( !bProtected )
aDlg.ShowExtras(SfxShowExtras::CONFIRM);
if (aDlg.run() == RET_OK)
aPassword = aDlg.GetPassword();
if (!aPassword.isEmpty())
{
if ( bProtected )
{
if ( SvPasswordHelper::CompareHashPassword(pChangeTrack->GetProtection(), aPassword) )
{
if ( bJustQueryIfProtected )
bDone = true;
else
pChangeTrack->SetProtection( {} );
}
else
{
std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pWin,
VclMessageType::Info, VclButtonsType::Ok,
ScResId(SCSTR_WRONGPASSWORD)));
xInfoBox->run();
}
}
else
{
css::uno::Sequence< sal_Int8 > aPass;
SvPasswordHelper::GetHashPassword( aPass, aPassword );
pChangeTrack->SetProtection( aPass );
}
if ( bProtected != pChangeTrack->IsProtected() )
{
UpdateAcceptChangesDialog();
bDone = true;
}
}
}
else if ( bJustQueryIfProtected )
bDone = true;
return bDone;
}
void ScDocShell::DoRecalc( bool bApi )
{
if (m_pDocument->IsInDocShellRecalc())
{
SAL_WARN("sc","ScDocShell::DoRecalc tries re-entering while in Recalc; probably Forms->BASIC->Dispatcher.");
return;
}
ScDocShellRecalcGuard aGuard(*m_pDocument);
bool bDone = false;
ScTabViewShell* pSh = GetBestViewShell();
ScInputHandler* pHdl = (pSh ? ScModule::get()->GetInputHdl(pSh) : nullptr);
if ( pSh )
{
if ( pHdl && pHdl->IsInputMode() && pHdl->IsFormulaMode() && !bApi )
{
pHdl->FormulaPreview(); // partial result as QuickHelp
bDone = true;
}
else
{
ScTabView::UpdateInputLine(); // InputEnterHandler
pSh->UpdateInputHandler();
}
}
if (bDone) // otherwise re-calculate document
return;
weld::WaitObject aWaitObj( GetActiveDialogParent() );
if ( pHdl )
{
// tdf97897 set current cell to Dirty to force recalculation of cell
ScFormulaCell* pFC = m_pDocument->GetFormulaCell( pHdl->GetCursorPos());
if (pFC)
pFC->SetDirty();
}
m_pDocument->CalcFormulaTree();
if ( pSh )
pSh->UpdateCharts(true);
m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
// If there are charts, then paint everything, so that PostDataChanged
// and the charts do not come one after the other and parts are painted twice.
ScChartListenerCollection* pCharts = m_pDocument->GetChartListenerCollection();
if ( pCharts && pCharts->hasListeners() )
PostPaintGridAll();
else
PostDataChanged();
}
void ScDocShell::DoHardRecalc()
{
if (m_pDocument->IsInDocShellRecalc())
{
SAL_WARN("sc","ScDocShell::DoHardRecalc tries re-entering while in Recalc; probably Forms->BASIC->Dispatcher.");
return;
}
auto start = std::chrono::steady_clock::now();
ScDocShellRecalcGuard aGuard(*m_pDocument);
weld::WaitObject aWaitObj( GetActiveDialogParent() );
ScTabViewShell* pSh = GetBestViewShell();
if ( pSh )
{
ScTabView::UpdateInputLine(); // InputEnterHandler
pSh->UpdateInputHandler();
}
m_pDocument->CalcAll();
GetDocFunc().DetectiveRefresh(); // creates own Undo
if ( pSh )
pSh->UpdateCharts(true);
// set notification flags for "calculate" event (used in SfxHintId::DataChanged broadcast)
// (might check for the presence of any formulas on each sheet)
SCTAB nTabCount = m_pDocument->GetTableCount();
if (m_pDocument->HasAnySheetEventScript( ScSheetEventId::CALCULATE, true )) // search also for VBA handler
for (SCTAB nTab=0; nTab<nTabCount; nTab++)
m_pDocument->SetCalcNotification(nTab);
// CalcAll doesn't broadcast value changes, so SfxHintId::ScCalcAll is broadcasted globally
// in addition to SfxHintId::DataChanged.
m_pDocument->BroadcastUno( SfxHint( SfxHintId::ScCalcAll ) );
m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
// use hard recalc also to disable stream-copying of all sheets
// (somewhat consistent with charts)
for (SCTAB nTab=0; nTab<nTabCount; nTab++)
m_pDocument->SetStreamValid(nTab, false);
PostPaintGridAll();
auto end = std::chrono::steady_clock::now();
SAL_INFO("sc.timing", "ScDocShell::DoHardRecalc(): took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms");
}
void ScDocShell::DoAutoStyle( const ScRange& rRange, const OUString& rStyle )
{
ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
ScStyleSheet* pStyleSheet = pStylePool->FindAutoStyle(rStyle);
if (!pStyleSheet)
return;
OSL_ENSURE(rRange.aStart.Tab() == rRange.aEnd.Tab(),
"DoAutoStyle with several tables");
SCTAB nTab = rRange.aStart.Tab();
SCCOL nStartCol = rRange.aStart.Col();
SCROW nStartRow = rRange.aStart.Row();
SCCOL nEndCol = rRange.aEnd.Col();
SCROW nEndRow = rRange.aEnd.Row();
m_pDocument->ApplyStyleAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, *pStyleSheet );
m_pDocument->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab );
PostPaint( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, PaintPartFlags::Grid );
}
void ScDocShell::NotifyStyle( const SfxStyleSheetHint& rHint )
{
SfxHintId nId = rHint.GetId();
const SfxStyleSheetBase* pStyle = rHint.GetStyleSheet();
if (!pStyle)
return;
if ( pStyle->GetFamily() == SfxStyleFamily::Page )
{
if ( nId == SfxHintId::StyleSheetModified || nId == SfxHintId::StyleSheetModifiedExtended )
{
ScDocShellModificator aModificator( *this );
const OUString& aNewName = pStyle->GetName();
OUString aOldName = aNewName;
if ( nId == SfxHintId::StyleSheetModifiedExtended )
{
const SfxStyleSheetModifiedHint& rExtendedHint = static_cast<const SfxStyleSheetModifiedHint&>(rHint); // name changed?
aOldName = rExtendedHint.GetOldName();
}
if ( aNewName != aOldName )
m_pDocument->RenamePageStyleInUse( aOldName, aNewName );
SCTAB nTabCount = m_pDocument->GetTableCount();
for (SCTAB nTab=0; nTab<nTabCount; nTab++)
if (m_pDocument->GetPageStyle(nTab) == aNewName) // already adjusted to new
{
m_pDocument->PageStyleModified( nTab, aNewName );
ScPrintFunc aPrintFunc( *this, GetPrinter(), nTab );
aPrintFunc.UpdatePages();
}
aModificator.SetDocumentModified();
if (nId == SfxHintId::StyleSheetModifiedExtended)
{
SfxBindings* pBindings = GetViewBindings();
if (pBindings)
{
pBindings->Invalidate( SID_STATUS_PAGESTYLE );
pBindings->Invalidate( SID_STYLE_FAMILY4 );
pBindings->Invalidate( FID_RESET_PRINTZOOM );
pBindings->Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT );
pBindings->Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT );
}
}
}
}
else if ( pStyle->GetFamily() == SfxStyleFamily::Para )
{
if (nId == SfxHintId::StyleSheetModifiedExtended)
{
const SfxStyleSheetModifiedHint& rExtendedHint = static_cast<const SfxStyleSheetModifiedHint&>(rHint);
const OUString& aNewName = pStyle->GetName();
const OUString& aOldName = rExtendedHint.GetOldName();
if ( aNewName != aOldName )
{
for(SCTAB i = 0; i < m_pDocument->GetTableCount(); ++i)
{
ScConditionalFormatList* pList = m_pDocument->GetCondFormList(i);
if (pList)
pList->RenameCellStyle( aOldName,aNewName );
}
}
}
}
// everything else goes via slots...
}
// like in printfun.cxx
#define ZOOM_MIN 10
void ScDocShell::SetPrintZoom( SCTAB nTab, sal_uInt16 nScale, sal_uInt16 nPages )
{
OUString aStyleName = m_pDocument->GetPageStyle( nTab );
ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Page );
OSL_ENSURE( pStyleSheet, "PageStyle not found" );
if ( !pStyleSheet )
return;
ScDocShellModificator aModificator( *this );
SfxItemSet& rSet = pStyleSheet->GetItemSet();
const bool bUndo(m_pDocument->IsUndoEnabled());
if (bUndo)
{
sal_uInt16 nOldScale = rSet.Get(ATTR_PAGE_SCALE).GetValue();
sal_uInt16 nOldPages = rSet.Get(ATTR_PAGE_SCALETOPAGES).GetValue();
GetUndoManager()->AddUndoAction( std::make_unique<ScUndoPrintZoom>(
*this, nTab, nOldScale, nOldPages, nScale, nPages ) );
}
rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALE, nScale ) );
rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, nPages ) );
ScPrintFunc aPrintFunc( *this, GetPrinter(), nTab );
aPrintFunc.UpdatePages();
aModificator.SetDocumentModified();
SfxBindings* pBindings = GetViewBindings();
if (pBindings)
pBindings->Invalidate( FID_RESET_PRINTZOOM );
}
bool ScDocShell::AdjustPrintZoom( const ScRange& rRange )
{
bool bChange = false;
SCTAB nTab = rRange.aStart.Tab();
OUString aStyleName = m_pDocument->GetPageStyle( nTab );
ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Page );
OSL_ENSURE( pStyleSheet, "PageStyle not found" );
if ( pStyleSheet )
{
SfxItemSet& rSet = pStyleSheet->GetItemSet();
bool bHeaders = rSet.Get(ATTR_PAGE_HEADERS).GetValue();
sal_uInt16 nOldScale = rSet.Get(ATTR_PAGE_SCALE).GetValue();
sal_uInt16 nOldPages = rSet.Get(ATTR_PAGE_SCALETOPAGES).GetValue();
std::optional<ScRange> oRepeatCol = m_pDocument->GetRepeatColRange( nTab );
std::optional<ScRange> oRepeatRow = m_pDocument->GetRepeatRowRange( nTab );
// calculate needed scaling for selection
sal_uInt16 nNewScale = nOldScale;
tools::Long nBlkTwipsX = 0;
if (bHeaders)
nBlkTwipsX += PRINT_HEADER_WIDTH;
SCCOL nStartCol = rRange.aStart.Col();
SCCOL nEndCol = rRange.aEnd.Col();
if ( oRepeatCol && nStartCol >= oRepeatCol->aStart.Col() )
{
for (SCCOL i=oRepeatCol->aStart.Col(); i<=oRepeatCol->aEnd.Col(); i++ )
nBlkTwipsX += m_pDocument->GetColWidth( i, nTab );
if ( nStartCol <= oRepeatCol->aEnd.Col() )
nStartCol = oRepeatCol->aEnd.Col() + 1;
}
// legacy compilers' own scope for i
{
for ( SCCOL i=nStartCol; i<=nEndCol; i++ )
nBlkTwipsX += m_pDocument->GetColWidth( i, nTab );
}
tools::Long nBlkTwipsY = 0;
if (bHeaders)
nBlkTwipsY += PRINT_HEADER_HEIGHT;
SCROW nStartRow = rRange.aStart.Row();
SCROW nEndRow = rRange.aEnd.Row();
if ( oRepeatRow && nStartRow >= oRepeatRow->aStart.Row() )
{
nBlkTwipsY += m_pDocument->GetRowHeight( oRepeatRow->aStart.Row(),
oRepeatRow->aEnd.Row(), nTab );
if ( nStartRow <= oRepeatRow->aEnd.Row() )
nStartRow = oRepeatRow->aEnd.Row() + 1;
}
nBlkTwipsY += m_pDocument->GetRowHeight( nStartRow, nEndRow, nTab );
Size aPhysPage;
tools::Long nHdr, nFtr;
ScPrintFunc aOldPrFunc( *this, GetPrinter(), nTab );
aOldPrFunc.GetScaleData( aPhysPage, nHdr, nFtr );
nBlkTwipsY += nHdr + nFtr;
if ( nBlkTwipsX == 0 ) // hidden columns/rows may lead to 0
nBlkTwipsX = 1;
if ( nBlkTwipsY == 0 )
nBlkTwipsY = 1;
tools::Long nNeeded = std::min( aPhysPage.Width() * 100 / nBlkTwipsX,
aPhysPage.Height() * 100 / nBlkTwipsY );
if ( nNeeded < ZOOM_MIN )
nNeeded = ZOOM_MIN; // boundary
if ( nNeeded < static_cast<tools::Long>(nNewScale) )
nNewScale = static_cast<sal_uInt16>(nNeeded);
bChange = ( nNewScale != nOldScale || nOldPages != 0 );
if ( bChange )
SetPrintZoom( nTab, nNewScale, 0 );
}
return bChange;
}
void ScDocShell::PageStyleModified( std::u16string_view rStyleName, bool bApi )
{
ScDocShellModificator aModificator( *this );
SCTAB nTabCount = m_pDocument->GetTableCount();
SCTAB nUseTab = MAXTAB+1;
for (SCTAB nTab=0; nTab<nTabCount && nUseTab>MAXTAB; nTab++)
if ( m_pDocument->GetPageStyle(nTab) == rStyleName &&
( !bApi || m_pDocument->GetPageSize(nTab).Width() ) )
nUseTab = nTab;
// at bApi only if breaks already shown
if (ValidTab(nUseTab)) // not used -> nothing to do
{
bool bWarn = false;
ScPrintFunc aPrintFunc( *this, GetPrinter(), nUseTab ); //! cope without CountPages
if (!aPrintFunc.UpdatePages()) // sets breaks on all tabs
bWarn = true;
if (bWarn && !bApi)
{
weld::Window* pWin = GetActiveDialogParent();
weld::WaitObject aWaitOff(pWin);
std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pWin,
VclMessageType::Info, VclButtonsType::Ok,
ScResId(STR_PRINT_INVALID_AREA)));
xInfoBox->run();
}
}
aModificator.SetDocumentModified();
SfxBindings* pBindings = GetViewBindings();
if (pBindings)
{
pBindings->Invalidate( FID_RESET_PRINTZOOM );
pBindings->Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT );
pBindings->Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT );
}
}
void ScDocShell::ExecutePageStyle( const SfxViewShell& rCaller,
SfxRequest& rReq,
SCTAB nCurTab )
{
const SfxItemSet* pReqArgs = rReq.GetArgs();
switch ( rReq.GetSlot() )
{
case SID_STATUS_PAGESTYLE: // click on StatusBar control
case SID_FORMATPAGE:
{
if ( pReqArgs == nullptr )
{
OUString aOldName = m_pDocument->GetPageStyle( nCurTab );
ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
SfxStyleSheetBase* pStyleSheet
= pStylePool->Find( aOldName, SfxStyleFamily::Page );
OSL_ENSURE( pStyleSheet, "PageStyle not found! :-/" );
if ( pStyleSheet )
{
auto xOldData = std::make_shared<ScStyleSaveData>();
const bool bUndo(m_pDocument->IsUndoEnabled());
if (bUndo)
xOldData->InitFromStyle(pStyleSheet);
SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
rStyleSet.MergeRange( XATTR_FILL_FIRST, XATTR_FILL_LAST );
ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
VclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateScStyleDlg(GetActiveDialogParent(), *pStyleSheet, true));
auto xRequest = std::make_shared<SfxRequest>(rReq);
rReq.Ignore(); // the 'old' request is not relevant any more
pDlg->StartExecuteAsync([this, pDlg, xRequest=std::move(xRequest), pStyleSheet,
xOldData=std::move(xOldData), aOldName, &rStyleSet,
nCurTab, &rCaller, bUndo](sal_Int32 nResult) {
if ( nResult == RET_OK )
{
const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
weld::WaitObject aWait( GetActiveDialogParent() );
OUString aNewName = pStyleSheet->GetName();
if ( aNewName != aOldName &&
m_pDocument->RenamePageStyleInUse( aOldName, aNewName ) )
{
SfxBindings* pBindings = GetViewBindings();
if (pBindings)
{
pBindings->Invalidate( SID_STATUS_PAGESTYLE );
pBindings->Invalidate( FID_RESET_PRINTZOOM );
}
}
if ( pOutSet )
m_pDocument->ModifyStyleSheet( *pStyleSheet, *pOutSet );
// memorizing for GetState():
GetPageOnFromPageStyleSet( &rStyleSet, nCurTab, m_bHeaderOn, m_bFooterOn );
rCaller.GetViewFrame().GetBindings().Invalidate( SID_HFEDIT );
ScStyleSaveData aNewData;
aNewData.InitFromStyle( pStyleSheet );
if (bUndo)
{
GetUndoManager()->AddUndoAction(
std::make_unique<ScUndoModifyStyle>( *this, SfxStyleFamily::Page,
*xOldData, aNewData ) );
}
PageStyleModified( aNewName, false );
xRequest->Done();
}
pDlg->disposeOnce();
});
}
}
}
break;
case SID_HFEDIT:
{
if ( pReqArgs == nullptr )
{
OUString aStr( m_pDocument->GetPageStyle( nCurTab ) );
ScStyleSheetPool* pStylePool
= m_pDocument->GetStyleSheetPool();
SfxStyleSheetBase* pStyleSheet
= pStylePool->Find( aStr, SfxStyleFamily::Page );
OSL_ENSURE( pStyleSheet, "PageStyle not found! :-/" );
if ( pStyleSheet )
{
SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
SvxPageUsage eUsage = rStyleSet.Get( ATTR_PAGE ).GetPageUsage();
bool bShareHeader = rStyleSet
.Get(ATTR_PAGE_HEADERSET)
.GetItemSet()
.Get(ATTR_PAGE_SHARED)
.GetValue();
bool bShareFooter = rStyleSet
.Get(ATTR_PAGE_FOOTERSET)
.GetItemSet()
.Get(ATTR_PAGE_SHARED)
.GetValue();
sal_uInt16 nResId = 0;
switch ( eUsage )
{
case SvxPageUsage::Left:
case SvxPageUsage::Right:
{
if ( m_bHeaderOn && m_bFooterOn )
nResId = RID_SCDLG_HFEDIT;
else if ( SvxPageUsage::Right == eUsage )
{
if ( !m_bHeaderOn && m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_RIGHTFOOTER;
else if ( m_bHeaderOn && !m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_RIGHTHEADER;
}
else
{
// #69193a# respect "shared" setting
if ( !m_bHeaderOn && m_bFooterOn )
nResId = bShareFooter ?
RID_SCDLG_HFEDIT_RIGHTFOOTER :
RID_SCDLG_HFEDIT_LEFTFOOTER;
else if ( m_bHeaderOn && !m_bFooterOn )
nResId = bShareHeader ?
RID_SCDLG_HFEDIT_RIGHTHEADER :
RID_SCDLG_HFEDIT_LEFTHEADER;
}
}
break;
case SvxPageUsage::Mirror:
case SvxPageUsage::All:
default:
{
if ( !bShareHeader && !bShareFooter )
{
if ( m_bHeaderOn && m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_ALL;
else if ( !m_bHeaderOn && m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_FOOTER;
else if ( m_bHeaderOn && !m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_HEADER;
}
else if ( bShareHeader && bShareFooter )
{
if ( m_bHeaderOn && m_bFooterOn )
nResId = RID_SCDLG_HFEDIT;
else
{
if ( !m_bHeaderOn && m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_RIGHTFOOTER;
else if ( m_bHeaderOn && !m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_RIGHTHEADER;
}
}
else if ( !bShareHeader && bShareFooter )
{
if ( m_bHeaderOn && m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_SFTR;
else if ( !m_bHeaderOn && m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_RIGHTFOOTER;
else if ( m_bHeaderOn && !m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_HEADER;
}
else if ( bShareHeader && !bShareFooter )
{
if ( m_bHeaderOn && m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_SHDR;
else if ( !m_bHeaderOn && m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_FOOTER;
else if ( m_bHeaderOn && !m_bFooterOn )
nResId = RID_SCDLG_HFEDIT_RIGHTHEADER;
}
}
}
ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
VclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateScHFEditDlg(
GetActiveDialogParent(),
rStyleSet,
aStr,
nResId));
auto xRequest = std::make_shared<SfxRequest>(rReq);
rReq.Ignore(); // the 'old' request is not relevant any more
pDlg->StartExecuteAsync([this, pDlg, pStyleSheet, xRequest=std::move(xRequest)](sal_Int32 nResult){
if ( nResult == RET_OK )
{
const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
if ( pOutSet )
m_pDocument->ModifyStyleSheet( *pStyleSheet, *pOutSet );
SetDocumentModified();
xRequest->Done();
}
pDlg->disposeOnce();
});
}
}
}
break;
default:
break;
}
}
void ScDocShell::GetStatePageStyle( SfxItemSet& rSet,
SCTAB nCurTab )
{
SfxWhichIter aIter(rSet);
sal_uInt16 nWhich = aIter.FirstWhich();
while ( nWhich )
{
switch (nWhich)
{
case SID_STATUS_PAGESTYLE:
rSet.Put( SfxStringItem( nWhich, m_pDocument->GetPageStyle( nCurTab ) ) );
break;
case SID_HFEDIT:
{
OUString aStr = m_pDocument->GetPageStyle( nCurTab );
ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStr, SfxStyleFamily::Page );
OSL_ENSURE( pStyleSheet, "PageStyle not found! :-/" );
if ( pStyleSheet )
{
SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
GetPageOnFromPageStyleSet( &rStyleSet, nCurTab, m_bHeaderOn, m_bFooterOn );
if ( !m_bHeaderOn && !m_bFooterOn )
rSet.DisableItem( nWhich );
}
}
break;
}
nWhich = aIter.NextWhich();
}
}
void ScDocShell::GetState( SfxItemSet &rSet )
{
bool bTabView = GetBestViewShell() != nullptr;
SfxWhichIter aIter(rSet);
for (sal_uInt16 nWhich = aIter.FirstWhich(); nWhich; nWhich = aIter.NextWhich())
{
if (!bTabView)
{
rSet.DisableItem(nWhich);
continue;
}
switch (nWhich)
{
case FID_AUTO_CALC:
if ( m_pDocument->GetHardRecalcState() != ScDocument::HardRecalcState::OFF )
rSet.DisableItem( nWhich );
else
rSet.Put( SfxBoolItem( nWhich, m_pDocument->GetAutoCalc() ) );
break;
case FID_CHG_RECORD:
if ( IsDocShared() )
rSet.DisableItem( nWhich );
else
rSet.Put( SfxBoolItem( nWhich,
m_pDocument->GetChangeTrack() != nullptr ) );
break;
case SID_CHG_PROTECT:
{
ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
if ( pChangeTrack && !IsDocShared() )
rSet.Put( SfxBoolItem( nWhich,
pChangeTrack->IsProtected() ) );
else
rSet.DisableItem( nWhich );
}
break;
case SID_DOCUMENT_COMPARE:
{
if ( IsDocShared() )
{
rSet.DisableItem( nWhich );
}
}
break;
// When a formula is edited, FID_RECALC must be enabled in any case. Recalc for
// the doc was disabled once because of a bug if AutoCalc was on, but is now
// always enabled because of another bug.
case SID_TABLES_COUNT:
rSet.Put( SfxInt16Item( nWhich, m_pDocument->GetTableCount() ) );
break;
case SID_ATTR_YEAR2000 :
rSet.Put( SfxUInt16Item( nWhich,
m_pDocument->GetDocOptions().GetYear2000() ) );
break;
case SID_SHARE_DOC:
{
if ( IsReadOnly() || GetObjectShell()->isExportLocked() )
{
rSet.DisableItem( nWhich );
}
}
break;
case SID_ATTR_PAGE_ORIENTATION:
{
ScViewData* pViewData = GetViewData();
if (pViewData)
{
ScDocument& rDoc = GetDocument();
const SCTAB nTab = pViewData->GetTabNo();
OUString aStyleName = rDoc.GetPageStyle(nTab);
ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
if (pStylePool)
{
SfxStyleSheetBase* pStyleSheet
= pStylePool->Find(aStyleName, SfxStyleFamily::Page);
if (pStyleSheet)
{
const SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
rSet.Put(rStyleSet.Get(ATTR_PAGE));
}
}
}
}
break;
case SID_OPEN_HYPERLINK:
{
ScViewData* pViewData = GetViewData();
if (!pViewData)
{
rSet.DisableItem(nWhich);
break;
}
if (ScModule::get()->IsEditMode())
{
if (EditView* pEditView = pViewData->GetEditView(pViewData->GetActivePart()))
if (!URLFieldHelper::IsCursorAtURLField(*pEditView, true))
rSet.DisableItem(nWhich);
}
else
{
if (ScGridWindow* pWin = pViewData->GetActiveWin())
{
std::vector<UrlData> vUrls = pWin->GetEditUrls(pViewData->GetCurPos());
if (vUrls.empty())
rSet.DisableItem(nWhich);
}
}
}
break;
case SID_ATTR_CHAR_FONTLIST:
rSet.Put( SvxFontListItem( m_pImpl->pFontList.get(), nWhich ) );
break;
case SID_NOTEBOOKBAR:
{
if (SfxBindings* pBindings = GetViewBindings())
{
bool bVisible = sfx2::SfxNotebookBar::StateMethod(*pBindings,
u"modules/scalc/ui/");
rSet.Put( SfxBoolItem( SID_NOTEBOOKBAR, bVisible ) );
}
}
break;
case SID_LANGUAGE_STATUS:
{
OUString sLanguage;
sal_uInt16 nLangWhich = 0;
LanguageType eLatin = LANGUAGE_DONTKNOW, eCjk = LANGUAGE_DONTKNOW,
eCtl = LANGUAGE_DONTKNOW;
if (comphelper::LibreOfficeKit::isActive())
{
GetDocument().GetLanguage( eLatin, eCjk, eCtl );
sLanguage = SvtLanguageTable::GetLanguageString(eLatin);
if (eLatin == LANGUAGE_NONE)
sLanguage += ";-";
else
sLanguage += ";" + LanguageTag(eLatin).getBcp47(false);
}
else if (ScTabViewShell* pViewShell = GetBestViewShell())
{
ScMarkData aMark = pViewShell->GetViewData().GetMarkData();
SCCOL nCol = pViewShell->GetViewData().GetCurX();
SCROW nRow = pViewShell->GetViewData().GetCurY();
SCTAB nTab = pViewShell->GetViewData().GetTabNo();
aMark.SetMarkArea(ScRange(nCol, nRow, nTab));
const ScPatternAttr* pSelAttrs = GetDocument().GetSelectionPattern(aMark);
if (pSelAttrs)
{
const SfxItemSet& rItemSet = pSelAttrs->GetItemSet();
nLangWhich = rItemSet.GetPool()->GetWhichIDFromSlotID(SID_ATTR_CHAR_LANGUAGE);
if (SfxItemState::SET == rItemSet.GetItemState(nLangWhich))
eLatin = static_cast<const SvxLanguageItem&>(rItemSet.Get(nLangWhich)).GetLanguage();
nLangWhich = rItemSet.GetPool()->GetWhichIDFromSlotID(SID_ATTR_CHAR_CJK_LANGUAGE);
if (SfxItemState::SET == rItemSet.GetItemState(nLangWhich))
eCjk = static_cast<const SvxLanguageItem&>(rItemSet.Get(nLangWhich)).GetLanguage();
nLangWhich = rItemSet.GetPool()->GetWhichIDFromSlotID(SID_ATTR_CHAR_CTL_LANGUAGE);
if (SfxItemState::SET == rItemSet.GetItemState(nLangWhich))
eCtl = static_cast<const SvxLanguageItem&>(rItemSet.Get(nLangWhich)).GetLanguage();
if (eLatin != LANGUAGE_DONTKNOW)
sLanguage = SvtLanguageTable::GetLanguageString(eLatin);
else if (eCjk != LANGUAGE_DONTKNOW)
sLanguage = SvtLanguageTable::GetLanguageString(eCjk);
else if (eCtl != LANGUAGE_DONTKNOW)
sLanguage = SvtLanguageTable::GetLanguageString(eCtl);
if (sLanguage.isEmpty())
{
GetDocument().GetLanguage(eLatin, eCjk, eCtl);
sLanguage = SvtLanguageTable::GetLanguageString(eLatin);
}
}
}
rSet.Put(SfxStringItem(nWhich, sLanguage));
}
break;
case SID_PROTECTPOS:
case SID_PROTECTSIZE:
{
ScViewData* pViewData = GetViewData();
if (pViewData)
{
const ScDrawView* pDrView = pViewData->GetScDrawView();
const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
if ( rMarkList.GetMarkCount() == 1 )
{
const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
const SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
if ( nSdrObjKind == SdrObjKind::Graphic )
{
if (nWhich == SID_PROTECTSIZE)
{
rSet.Put(SfxBoolItem(nWhich, pObj->IsResizeProtect()));
if (pObj->IsMoveProtect())
rSet.DisableItem( nWhich );
}
else
rSet.Put(SfxBoolItem(nWhich, pObj->IsMoveProtect()));
break;
}
}
}
rSet.DisableItem( nWhich );
}
break;
default:
{
}
break;
}
}
}
void ScDocShell::Draw( OutputDevice* pDev, const JobSetup & /* rSetup */, sal_uInt16 nAspect, bool /*bOutputToWindow*/ )
{
SCTAB nVisTab = m_pDocument->GetVisibleTab();
if (!m_pDocument->HasTable(nVisTab))
return;
vcl::text::ComplexTextLayoutFlags nOldLayoutMode = pDev->GetLayoutMode();
pDev->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::Default ); // even if it's the same, to get the metafile action
if ( nAspect == ASPECT_THUMBNAIL )
{
tools::Rectangle aBoundRect = GetVisArea( ASPECT_THUMBNAIL );
ScViewData aTmpData( *this, nullptr );
aTmpData.SetTabNo(nVisTab);
SnapVisArea( aBoundRect );
aTmpData.SetScreen( aBoundRect );
ScPrintFunc::DrawToDev( *m_pDocument, pDev, 1.0, aBoundRect, aTmpData, true );
}
else
{
tools::Rectangle aOldArea = SfxObjectShell::GetVisArea();
tools::Rectangle aNewArea = aOldArea;
ScViewData aTmpData( *this, nullptr );
aTmpData.SetTabNo(nVisTab);
SnapVisArea( aNewArea );
if ( aNewArea != aOldArea && (m_pDocument->GetPosLeft() > 0 || m_pDocument->GetPosTop() > 0) )
SfxObjectShell::SetVisArea( aNewArea );
aTmpData.SetScreen( aNewArea );
ScPrintFunc::DrawToDev( *m_pDocument, pDev, 1.0, aNewArea, aTmpData, true );
}
pDev->SetLayoutMode( nOldLayoutMode );
}
tools::Rectangle ScDocShell::GetVisArea( sal_uInt16 nAspect ) const
{
SfxObjectCreateMode eShellMode = GetCreateMode();
if ( eShellMode == SfxObjectCreateMode::ORGANIZER )
{
// without contents we also don't know how large are the contents;
// return empty rectangle, it will then be calculated after the loading
return tools::Rectangle();
}
if( nAspect == ASPECT_THUMBNAIL )
{
SCTAB nVisTab = m_pDocument->GetVisibleTab();
if (!m_pDocument->HasTable(nVisTab))
{
nVisTab = 0;
const_cast<ScDocShell*>(this)->m_pDocument->SetVisibleTab(nVisTab);
}
Size aSize = m_pDocument->GetPageSize(nVisTab);
const tools::Long SC_PREVIEW_SIZE_X = 10000;
const tools::Long SC_PREVIEW_SIZE_Y = 12400;
tools::Rectangle aArea( 0,0, SC_PREVIEW_SIZE_X, SC_PREVIEW_SIZE_Y);
if (aSize.Width() > aSize.Height())
{
aArea.SetRight( SC_PREVIEW_SIZE_Y );
aArea.SetBottom( SC_PREVIEW_SIZE_X );
}
bool bNegativePage = m_pDocument->IsNegativePage( m_pDocument->GetVisibleTab() );
if ( bNegativePage )
ScDrawLayer::MirrorRectRTL( aArea );
SnapVisArea( aArea );
return aArea;
}
else if( nAspect == ASPECT_CONTENT && eShellMode != SfxObjectCreateMode::EMBEDDED )
{
// fetch visarea like after loading
SCTAB nVisTab = m_pDocument->GetVisibleTab();
if (!m_pDocument->HasTable(nVisTab))
{
nVisTab = 0;
const_cast<ScDocShell*>(this)->m_pDocument->SetVisibleTab(nVisTab);
}
SCCOL nStartCol;
SCROW nStartRow;
m_pDocument->GetDataStart( nVisTab, nStartCol, nStartRow );
SCCOL nEndCol;
SCROW nEndRow;
m_pDocument->GetPrintArea( nVisTab, nEndCol, nEndRow );
if (nStartCol>nEndCol)
nStartCol = nEndCol;
if (nStartRow>nEndRow)
nStartRow = nEndRow;
tools::Rectangle aNewArea = m_pDocument
->GetMMRect( nStartCol,nStartRow, nEndCol,nEndRow, nVisTab );
return aNewArea;
}
else
return SfxObjectShell::GetVisArea( nAspect );
}
namespace {
[[nodiscard]]
tools::Long SnapHorizontal( const ScDocument& rDoc, SCTAB nTab, tools::Long nVal, SCCOL& rStartCol )
{
SCCOL nCol = 0;
tools::Long nTwips = o3tl::convert(nVal, o3tl::Length::mm100, o3tl::Length::twip);
tools::Long nSnap = 0;
while ( nCol<rDoc.MaxCol() )
{
tools::Long nAdd = rDoc.GetColWidth(nCol, nTab);
if ( nSnap + nAdd/2 < nTwips || nCol < rStartCol )
{
nSnap += nAdd;
++nCol;
}
else
break;
}
nVal = o3tl::convert(nSnap, o3tl::Length::twip, o3tl::Length::mm100);
rStartCol = nCol;
return nVal;
}
[[nodiscard]]
tools::Long SnapVertical( const ScDocument& rDoc, SCTAB nTab, tools::Long nVal, SCROW& rStartRow )
{
SCROW nRow = 0;
tools::Long nTwips = o3tl::convert(nVal, o3tl::Length::mm100, o3tl::Length::twip);
tools::Long nSnap = 0;
bool bFound = false;
for (SCROW i = nRow; i <= rDoc.MaxRow(); ++i)
{
SCROW nLastRow;
if (rDoc.RowHidden(i, nTab, nullptr, &nLastRow))
{
i = nLastRow;
continue;
}
nRow = i;
tools::Long nAdd = rDoc.GetRowHeight(i, nTab);
if ( nSnap + nAdd/2 < nTwips || nRow < rStartRow )
{
nSnap += nAdd;
++nRow;
}
else
{
bFound = true;
break;
}
}
if (!bFound)
nRow = rDoc.MaxRow(); // all hidden down to the bottom
nVal = o3tl::convert(nSnap, o3tl::Length::twip, o3tl::Length::mm100);
rStartRow = nRow;
return nVal;
}
}
void ScDocShell::SnapVisArea( tools::Rectangle& rRect ) const
{
SCTAB nTab = m_pDocument->GetVisibleTab();
tools::Long nOrigTop = rRect.Top();
tools::Long nOrigLeft = rRect.Left();
bool bNegativePage = m_pDocument->IsNegativePage( nTab );
if ( bNegativePage )
ScDrawLayer::MirrorRectRTL( rRect ); // calculate with positive (LTR) values
SCCOL nCol = m_pDocument->GetPosLeft();
tools::Long nSetLeft = SnapHorizontal( *m_pDocument, nTab, rRect.Left(), nCol );
rRect.SetLeft( nSetLeft );
++nCol; // at least one column
tools::Long nCorrectionLeft = (nOrigLeft == 0 && nCol > 0) ? nSetLeft : 0; // initial correction
rRect.SetRight( SnapHorizontal( *m_pDocument, nTab, rRect.Right() + nCorrectionLeft, nCol ));
SCROW nRow = m_pDocument->GetPosTop();
tools::Long nSetTop = SnapVertical( *m_pDocument, nTab, rRect.Top(), nRow );
rRect.SetTop( nSetTop );
++nRow; // at least one row
tools::Long nCorrectionTop = (nOrigTop == 0 && nRow > 0) ? nSetTop : 0; // initial correction
rRect.SetBottom( SnapVertical( *m_pDocument, nTab, rRect.Bottom() + nCorrectionTop, nRow ));
if ( bNegativePage )
ScDrawLayer::MirrorRectRTL( rRect ); // back to real rectangle
}
void ScDocShell::GetPageOnFromPageStyleSet( const SfxItemSet* pStyleSet,
SCTAB nCurTab,
bool& rbHeader,
bool& rbFooter )
{
if ( !pStyleSet )
{
ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
SfxStyleSheetBase* pStyleSheet = pStylePool->
Find( m_pDocument->GetPageStyle( nCurTab ),
SfxStyleFamily::Page );
OSL_ENSURE( pStyleSheet, "PageStyle not found! :-/" );
if ( pStyleSheet )
pStyleSet = &pStyleSheet->GetItemSet();
else
rbHeader = rbFooter = false;
}
OSL_ENSURE( pStyleSet, "PageStyle-Set not found! :-(" );
if (!pStyleSet)
return;
const SvxSetItem* pSetItem = nullptr;
const SfxItemSet* pSet = nullptr;
pSetItem = &pStyleSet->Get( ATTR_PAGE_HEADERSET );
pSet = &pSetItem->GetItemSet();
rbHeader = pSet->Get(ATTR_PAGE_ON).GetValue();
pSetItem = &pStyleSet->Get( ATTR_PAGE_FOOTERSET );
pSet = &pSetItem->GetItemSet();
rbFooter = pSet->Get(ATTR_PAGE_ON).GetValue();
}
#if defined(_WIN32)
bool ScDocShell::DdeGetData( const OUString& rItem,
const OUString& rMimeType,
css::uno::Any & rValue )
{
SotClipboardFormatId eFormatId = SotExchange::GetFormatIdFromMimeType( rMimeType );
if (SotClipboardFormatId::STRING == eFormatId || SotClipboardFormatId::STRING_TSVC == eFormatId)
{
if( rItem.equalsIgnoreAsciiCase( "Format" ) )
{
OString aFmtByte(OUStringToOString(m_aDdeTextFmt,
osl_getThreadTextEncoding()));
rValue <<= css::uno::Sequence< sal_Int8 >(
reinterpret_cast<const sal_Int8*>(aFmtByte.getStr()),
aFmtByte.getLength() + 1 );
return true;
}
ScImportExport aObj( *m_pDocument, rItem );
if ( !aObj.IsRef() )
return false; // invalid range
if( m_aDdeTextFmt[0] == 'F' )
aObj.SetFormulas( true );
if( m_aDdeTextFmt == "SYLK" ||
m_aDdeTextFmt == "FSYLK" )
{
OString aData;
if( aObj.ExportByteString( aData, osl_getThreadTextEncoding(),
SotClipboardFormatId::SYLK ) )
{
rValue <<= css::uno::Sequence< sal_Int8 >(
reinterpret_cast<const sal_Int8*>(aData.getStr()),
aData.getLength() + 1 );
return true;
}
else
return false;
}
if( m_aDdeTextFmt == "CSV" ||
m_aDdeTextFmt == "FCSV" )
aObj.SetSeparator( ',' );
aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, 0, false ) );
return aObj.ExportData( rMimeType, rValue );
}
ScImportExport aObj( *m_pDocument, rItem );
aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, 0, false ) );
return aObj.IsRef() && aObj.ExportData( rMimeType, rValue );
}
bool ScDocShell::DdeSetData( const OUString& rItem,
const OUString& rMimeType,
const css::uno::Any & rValue )
{
SotClipboardFormatId eFormatId = SotExchange::GetFormatIdFromMimeType( rMimeType );
if (SotClipboardFormatId::STRING == eFormatId || SotClipboardFormatId::STRING_TSVC == eFormatId)
{
if( rItem.equalsIgnoreAsciiCase( "Format" ) )
{
if ( ScByteSequenceToString::GetString( m_aDdeTextFmt, rValue ) )
{
m_aDdeTextFmt = m_aDdeTextFmt.toAsciiUpperCase();
return true;
}
return false;
}
ScImportExport aObj( *m_pDocument, rItem );
if( m_aDdeTextFmt[0] == 'F' )
aObj.SetFormulas( true );
if( m_aDdeTextFmt == "SYLK" ||
m_aDdeTextFmt == "FSYLK" )
{
OUString aData;
if ( ScByteSequenceToString::GetString( aData, rValue ) )
{
return aObj.ImportString( aData, SotClipboardFormatId::SYLK );
}
return false;
}
if( m_aDdeTextFmt == "CSV" ||
m_aDdeTextFmt == "FCSV" )
aObj.SetSeparator( ',' );
OSL_ENSURE( false, "Implementation is missing" );
return false;
}
/*ScImportExport aObj( aDocument, rItem );
return aObj.IsRef() && ScImportExport::ImportData( rMimeType, rValue );*/
OSL_ENSURE( false, "Implementation is missing" );
return false;
}
#endif
::sfx2::SvLinkSource* ScDocShell::DdeCreateLinkSource( const OUString& rItem )
{
if (officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
return nullptr;
// only check for valid item string - range is parsed again in ScServerObject ctor
// named range?
OUString aPos = rItem;
ScRangeName* pRange = m_pDocument->GetRangeName();
if( pRange )
{
const ScRangeData* pData = pRange->findByUpperName(ScGlobal::getCharClass().uppercase(aPos));
if (pData)
{
if( pData->HasType( ScRangeData::Type::RefArea )
|| pData->HasType( ScRangeData::Type::AbsArea )
|| pData->HasType( ScRangeData::Type::AbsPos ) )
aPos = pData->GetSymbol(); // continue with the name's contents
}
}
// Address in DDE function must be always parsed as CONV_OOO so that it
// would always work regardless of current address conversion. We do this
// because the address item in a DDE entry is *not* normalized when saved
// into ODF.
ScRange aRange;
bool bValid = ( (aRange.Parse(aPos, *m_pDocument, formula::FormulaGrammar::CONV_OOO ) & ScRefFlags::VALID) ||
(aRange.aStart.Parse(aPos, *m_pDocument, formula::FormulaGrammar::CONV_OOO) & ScRefFlags::VALID) );
ScServerObject* pObj = nullptr; // NULL = error
if ( bValid )
pObj = new ScServerObject( this, rItem );
// GetLinkManager()->InsertServer() is in the ScServerObject ctor
return pObj;
}
void ScDocShell::LOKCommentNotify(LOKCommentNotificationType nType, const ScDocument& rDocument, const ScAddress& rPos, const ScPostIt* pNote)
{
if ( !rDocument.IsDocVisible() || // don't want callbacks until document load
!comphelper::LibreOfficeKit::isActive() ||
comphelper::LibreOfficeKit::isTiledAnnotations() )
return;
tools::JsonWriter aAnnotation;
{
auto commentNode = aAnnotation.startNode("comment");
aAnnotation.put("action", (nType == LOKCommentNotificationType::Add ? "Add" :
(nType == LOKCommentNotificationType::Remove ? "Remove" :
(nType == LOKCommentNotificationType::Modify ? "Modify" : "???"))));
assert(pNote);
aAnnotation.put("id", pNote->GetId());
aAnnotation.put("tab", rPos.Tab());
if (nType != LOKCommentNotificationType::Remove)
{
aAnnotation.put("author", pNote->GetAuthor());
aAnnotation.put("dateTime", pNote->GetDate());
aAnnotation.put("text", pNote->GetText());
// Calculating the cell cursor position
ScViewData* pViewData = GetViewData();
if (pViewData && pViewData->GetActiveWin())
aAnnotation.put("cellRange", ScPostIt::NoteRangeToJsonString(rDocument, rPos));
}
}
OString aPayload = aAnnotation.finishAndGetAsOString();
ScViewData* pViewData = GetViewData();
SfxViewShell* pThisViewShell = ( pViewData ? pViewData->GetViewShell() : nullptr );
SfxViewShell* pViewShell = SfxViewShell::GetFirst();
while (pViewShell)
{
if (pThisViewShell == nullptr || pViewShell->GetDocId() == pThisViewShell->GetDocId())
pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT, aPayload);
pViewShell = SfxViewShell::GetNext(*pViewShell);
}
}
ScViewData* ScDocShell::GetViewData()
{
SfxViewShell* pCur = SfxViewShell::Current();
ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( pCur );
return pViewSh ? &pViewSh->GetViewData() : nullptr;
}
SCTAB ScDocShell::GetCurTab()
{
//! this must be made non-static and use a ViewShell from this document!
ScViewData* pViewData = GetViewData();
return pViewData ? pViewData->GetTabNo() : static_cast<SCTAB>(0);
}
ScTabViewShell* ScDocShell::GetBestViewShell( bool bOnlyVisible )
{
ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
// wrong Doc?
if( pViewSh && &pViewSh->GetViewData().GetDocShell() != this )
pViewSh = nullptr;
if( !pViewSh )
{
// 1. find ViewShell
SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this, bOnlyVisible );
if( pFrame )
{
SfxViewShell* p = pFrame->GetViewShell();
pViewSh = dynamic_cast< ScTabViewShell *>( p );
}
}
return pViewSh;
}
SfxBindings* ScDocShell::GetViewBindings()
{
// used to invalidate slots after changes to this document
SfxViewShell* pViewSh = GetBestViewShell();
if (pViewSh)
return &pViewSh->GetViewFrame().GetBindings();
else
return nullptr;
}
ScDocShell* ScDocShell::GetShellByNum( sal_uInt16 nDocNo ) // static
{
ScDocShell* pFound = nullptr;
SfxObjectShell* pShell = SfxObjectShell::GetFirst();
sal_uInt16 nShellCnt = 0;
while ( pShell && !pFound )
{
if ( auto pDocSh = dynamic_cast<ScDocShell*>(pShell) )
{
if ( nShellCnt == nDocNo )
pFound = pDocSh;
else
++nShellCnt;
}
pShell = SfxObjectShell::GetNext( *pShell );
}
return pFound;
}
IMPL_LINK( ScDocShell, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void )
{
assert( _pFileDlg && "ScDocShell::DialogClosedHdl(): no file dialog");
OSL_ENSURE( m_pImpl->pDocInserter, "ScDocShell::DialogClosedHdl(): no document inserter" );
if ( ERRCODE_NONE == _pFileDlg->GetError() )
{
sal_uInt16 nSlot = m_pImpl->pRequest->GetSlot();
std::unique_ptr<SfxMedium> pMed = m_pImpl->pDocInserter->CreateMedium();
// #i87094# If a .odt was selected pMed is NULL.
if (pMed)
{
m_pImpl->pRequest->AppendItem( SfxStringItem( SID_FILE_NAME, pMed->GetName() ) );
if ( SID_DOCUMENT_COMPARE == nSlot )
{
if ( pMed->GetFilter() )
m_pImpl->pRequest->AppendItem(
SfxStringItem( SID_FILTER_NAME, pMed->GetFilter()->GetFilterName() ) );
OUString sOptions = ScDocumentLoader::GetOptions( *pMed );
if ( !sOptions.isEmpty() )
m_pImpl->pRequest->AppendItem( SfxStringItem( SID_FILE_FILTEROPTIONS, sOptions ) );
}
const SfxPoolItem* pItem = nullptr;
const SfxInt16Item* pInt16Item(nullptr);
if (pMed->GetItemSet().GetItemState(SID_VERSION, true, &pItem) == SfxItemState::SET)
{
pInt16Item = dynamic_cast<const SfxInt16Item*>(pItem);
}
if (pInt16Item)
{
m_pImpl->pRequest->AppendItem( *pItem );
}
Execute( *(m_pImpl->pRequest) );
}
}
m_pImpl->bIgnoreLostRedliningWarning = false;
}
#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
void ScDocShell::EnableSharedSettings( bool bEnable )
{
SetDocumentModified();
if ( bEnable )
{
m_pDocument->EndChangeTracking();
m_pDocument->StartChangeTracking();
// hide accept or reject changes dialog
sal_uInt16 nId = ScAcceptChgDlgWrapper::GetChildWindowId();
SfxViewFrame* pViewFrame = SfxViewFrame::Current();
if ( pViewFrame && pViewFrame->HasChildWindow( nId ) )
{
pViewFrame->ToggleChildWindow( nId );
SfxBindings* pBindings = GetViewBindings();
if ( pBindings )
{
pBindings->Invalidate( FID_CHG_ACCEPT );
}
}
}
else
{
m_pDocument->EndChangeTracking();
}
ScChangeViewSettings aChangeViewSet;
aChangeViewSet.SetShowChanges( false );
m_pDocument->SetChangeViewSettings( aChangeViewSet );
}
uno::Reference< frame::XModel > ScDocShell::LoadSharedDocument()
{
uno::Reference< frame::XModel > xModel;
ScModule* mod = ScModule::get();
try
{
mod->SetInSharedDocLoading(true);
uno::Reference< frame::XDesktop2 > xLoader = frame::Desktop::create( ::comphelper::getProcessComponentContext() );
uno::Sequence aArgs{ comphelper::makePropertyValue(u"Hidden"_ustr, true) };
if ( GetMedium() )
{
const SfxStringItem* pPasswordItem = GetMedium()->GetItemSet().GetItem(SID_PASSWORD, false);
if ( pPasswordItem && !pPasswordItem->GetValue().isEmpty() )
{
aArgs.realloc( 2 );
auto pArgs = aArgs.getArray();
pArgs[1].Name = "Password";
pArgs[1].Value <<= pPasswordItem->GetValue();
}
const SfxUnoAnyItem* pEncryptionItem = GetMedium()->GetItemSet().GetItem(SID_ENCRYPTIONDATA, false);
if (pEncryptionItem)
{
aArgs.realloc(aArgs.getLength() + 1);
auto pArgs = aArgs.getArray();
pArgs[aArgs.getLength() - 1].Name = "EncryptionData";
pArgs[aArgs.getLength() - 1].Value = pEncryptionItem->GetValue();
}
}
xModel.set(
xLoader->loadComponentFromURL( GetSharedFileURL(), u"_blank"_ustr, 0, aArgs ),
uno::UNO_QUERY_THROW );
mod->SetInSharedDocLoading(false);
}
catch ( uno::Exception& )
{
OSL_FAIL( "ScDocShell::LoadSharedDocument(): caught exception" );
mod->SetInSharedDocLoading(false);
try
{
uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW );
xClose->close( true );
return uno::Reference< frame::XModel >();
}
catch ( uno::Exception& )
{
return uno::Reference< frame::XModel >();
}
}
return xModel;
}
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */