summaryrefslogtreecommitdiffstats
path: root/sc/source/ui/unoobj/docuno.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/unoobj/docuno.cxx')
-rw-r--r--sc/source/ui/unoobj/docuno.cxx4984
1 files changed, 4984 insertions, 0 deletions
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
new file mode 100644
index 0000000000..c906f39336
--- /dev/null
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -0,0 +1,4984 @@
+/* -*- 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_feature_opencl.h>
+
+#include <scitems.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/memberids.h>
+#include <editeng/outliner.hxx>
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <svx/fmview.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svxids.hrc>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/propertysequence.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <officecfg/Office/Calc.hxx>
+#include <svl/numuno.hxx>
+#include <svl/hint.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/unopage.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
+#include <vcl/print.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/json_writer.hxx>
+#include <tools/multisel.hxx>
+#include <tools/UnitConversion.hxx>
+#include <toolkit/awt/vclxdevice.hxx>
+
+#include <float.h>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/util/XTheme.hpp>
+#include <com/sun/star/sheet/XNamedRanges.hpp>
+#include <com/sun/star/sheet/XLabelRanges.hpp>
+#include <com/sun/star/sheet/XSelectedSheetsSupplier.hpp>
+#include <com/sun/star/sheet/XUnnamedDatabaseRanges.hpp>
+#include <com/sun/star/i18n/XForbiddenCharacters.hpp>
+#include <com/sun/star/script/XLibraryContainer.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <comphelper/indexedpropertyvalues.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/profilezone.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/string.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#if HAVE_FEATURE_OPENCL
+#include <opencl/platforminfo.hxx>
+#endif
+#include <sfx2/lokhelper.hxx>
+#include <sfx2/lokcomponenthelpers.hxx>
+#include <sfx2/LokControlHandler.hxx>
+#include <docmodel/uno/UnoTheme.hxx>
+#include <docmodel/theme/Theme.hxx>
+
+#include <cellsuno.hxx>
+#include <columnspanset.hxx>
+#include <convuno.hxx>
+#include <datauno.hxx>
+#include <docfunc.hxx>
+#include <docoptio.hxx>
+#include <docsh.hxx>
+#include <docuno.hxx>
+#include <drwlayer.hxx>
+#include <forbiuno.hxx>
+#include <formulagroup.hxx>
+#include <gridwin.hxx>
+#include <hints.hxx>
+#include <inputhdl.hxx>
+#include <inputopt.hxx>
+#include <interpre.hxx>
+#include <linkuno.hxx>
+#include <markdata.hxx>
+#include <miscuno.hxx>
+#include <nameuno.hxx>
+#include <notesuno.hxx>
+#include <optuno.hxx>
+#include <pfuncache.hxx>
+#include <postit.hxx>
+#include <printfun.hxx>
+#include <rangeutl.hxx>
+#include <scmod.hxx>
+#include <scresid.hxx>
+#include <servuno.hxx>
+#include <shapeuno.hxx>
+#include <sheetevents.hxx>
+#include <styleuno.hxx>
+#include <tabvwsh.hxx>
+#include <targuno.hxx>
+#include <unonames.hxx>
+#include <ViewSettingsSequenceDefines.hxx>
+#include <editsh.hxx>
+#include <drawsh.hxx>
+#include <drtxtob.hxx>
+#include <transobj.hxx>
+#include <chgtrack.hxx>
+#include <table.hxx>
+#include <appoptio.hxx>
+#include <formulaopt.hxx>
+
+#include <strings.hrc>
+
+using namespace com::sun::star;
+
+// #i111553# provides the name of the VBA constant for this document type (e.g. 'ThisExcelDoc' for Calc)
+constexpr OUString SC_UNO_VBAGLOBNAME = u"VBAGlobalConstantName"_ustr;
+
+// no Which-ID here, map only for PropertySetInfo
+
+//! rename this, those are no longer only options
+static std::span<const SfxItemPropertyMapEntry> lcl_GetDocOptPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDocOptPropertyMap_Impl[] =
+ {
+ { SC_UNO_APPLYFMDES, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_AREALINKS, 0, cppu::UnoType<sheet::XAreaLinks>::get(), 0, 0},
+ { SC_UNO_AUTOCONTFOC, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_BASICLIBRARIES, 0, cppu::UnoType<script::XLibraryContainer>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_DIALOGLIBRARIES, 0, cppu::UnoType<script::XLibraryContainer>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_VBAGLOBNAME, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_CALCASSHOWN, PROP_UNO_CALCASSHOWN, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_CLOCAL, 0, cppu::UnoType<lang::Locale>::get(), 0, 0},
+ { SC_UNO_CJK_CLOCAL, 0, cppu::UnoType<lang::Locale>::get(), 0, 0},
+ { SC_UNO_CTL_CLOCAL, 0, cppu::UnoType<lang::Locale>::get(), 0, 0},
+ { SC_UNO_COLLABELRNG, 0, cppu::UnoType<sheet::XLabelRanges>::get(), 0, 0},
+ { SC_UNO_DDELINKS, 0, cppu::UnoType<container::XNameAccess>::get(), 0, 0},
+ { SC_UNO_DEFTABSTOP, PROP_UNO_DEFTABSTOP, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_EXTERNALDOCLINKS, 0, cppu::UnoType<sheet::XExternalDocLinks>::get(), 0, 0},
+ { SC_UNO_FORBIDDEN, 0, cppu::UnoType<i18n::XForbiddenCharacters>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_HASDRAWPAGES, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_IGNORECASE, PROP_UNO_IGNORECASE, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ITERENABLED, PROP_UNO_ITERENABLED, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ITERCOUNT, PROP_UNO_ITERCOUNT, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_ITEREPSILON, PROP_UNO_ITEREPSILON, cppu::UnoType<double>::get(), 0, 0},
+ { SC_UNO_LOOKUPLABELS, PROP_UNO_LOOKUPLABELS, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_MATCHWHOLE, PROP_UNO_MATCHWHOLE, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_NAMEDRANGES, 0, cppu::UnoType<sheet::XNamedRanges>::get(), 0, 0},
+ { SC_UNO_THEME, 0, cppu::UnoType<util::XTheme>::get(), 0, 0},
+ { SC_UNO_DATABASERNG, 0, cppu::UnoType<sheet::XDatabaseRanges>::get(), 0, 0},
+ { SC_UNO_NULLDATE, PROP_UNO_NULLDATE, cppu::UnoType<util::Date>::get(), 0, 0},
+ { SC_UNO_ROWLABELRNG, 0, cppu::UnoType<sheet::XLabelRanges>::get(), 0, 0},
+ { SC_UNO_SHEETLINKS, 0, cppu::UnoType<container::XNameAccess>::get(), 0, 0},
+ { SC_UNO_SPELLONLINE, PROP_UNO_SPELLONLINE, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_STANDARDDEC, PROP_UNO_STANDARDDEC, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_REGEXENABLED, PROP_UNO_REGEXENABLED, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_WILDCARDSENABLED, PROP_UNO_WILDCARDSENABLED, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_RUNTIMEUID, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_HASVALIDSIGNATURES, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_ISLOADED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ISUNDOENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_RECORDCHANGES, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ISRECORDCHANGESPROTECTED,0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_ISADJUSTHEIGHTENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ISEXECUTELINKENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ISCHANGEREADONLYENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_REFERENCEDEVICE, 0, cppu::UnoType<awt::XDevice>::get(), beans::PropertyAttribute::READONLY, 0},
+ {u"BuildId"_ustr, 0, ::cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNO_CODENAME, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNO_INTEROPGRABBAG, 0, cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get(), 0, 0},
+ };
+ return aDocOptPropertyMap_Impl;
+}
+
+//! StandardDecimals as property and from NumberFormatter ????????
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetColumnsPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aColumnsPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_MANPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NEWPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLVIS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_OWIDTH, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLWID, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ };
+ return aColumnsPropertyMap_Impl;
+}
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetRowsPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aRowsPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_CELLHGT, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLFILT, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_OHEIGHT, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_MANPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NEWPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLVIS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLBACK, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ // not sorted, not used with SfxItemPropertyMapEntry::GetByName
+ };
+ return aRowsPropertyMap_Impl;
+}
+
+constexpr OUString SCMODELOBJ_SERVICE = u"com.sun.star.sheet.SpreadsheetDocument"_ustr;
+constexpr OUString SCDOCSETTINGS_SERVICE = u"com.sun.star.sheet.SpreadsheetDocumentSettings"_ustr;
+constexpr OUString SCDOC_SERVICE = u"com.sun.star.document.OfficeDocument"_ustr;
+
+SC_SIMPLE_SERVICE_INFO( ScAnnotationsObj, "ScAnnotationsObj", "com.sun.star.sheet.CellAnnotations" )
+SC_SIMPLE_SERVICE_INFO( ScDrawPagesObj, "ScDrawPagesObj", "com.sun.star.drawing.DrawPages" )
+SC_SIMPLE_SERVICE_INFO( ScScenariosObj, "ScScenariosObj", "com.sun.star.sheet.Scenarios" )
+SC_SIMPLE_SERVICE_INFO( ScSpreadsheetSettingsObj, "ScSpreadsheetSettingsObj", "com.sun.star.sheet.SpreadsheetDocumentSettings" )
+SC_SIMPLE_SERVICE_INFO( ScTableColumnsObj, "ScTableColumnsObj", "com.sun.star.table.TableColumns" )
+SC_SIMPLE_SERVICE_INFO( ScTableRowsObj, "ScTableRowsObj", "com.sun.star.table.TableRows" )
+SC_SIMPLE_SERVICE_INFO( ScTableSheetsObj, "ScTableSheetsObj", "com.sun.star.sheet.Spreadsheets" )
+
+class ScPrintUIOptions : public vcl::PrinterOptionsHelper
+{
+public:
+ ScPrintUIOptions();
+ void SetDefaults();
+};
+
+ScPrintUIOptions::ScPrintUIOptions()
+{
+ const ScPrintOptions& rPrintOpt = SC_MOD()->GetPrintOptions();
+ sal_Int32 nContent = rPrintOpt.GetAllSheets() ? 0 : 1;
+ bool bSuppress = rPrintOpt.GetSkipEmpty();
+
+ sal_Int32 nNumProps= 10, nIdx = 0;
+
+ m_aUIProperties.resize(nNumProps);
+
+ // load the writer PrinterOptions into the custom tab
+ m_aUIProperties[nIdx].Name = "OptionsUIFile";
+ m_aUIProperties[nIdx++].Value <<= OUString("modules/scalc/ui/printeroptions.ui");
+
+ // create Section for spreadsheet (results in an extra tab page in dialog)
+ SvtModuleOptions aOpt;
+ OUString aAppGroupname( ScResId( SCSTR_PRINTOPT_PRODNAME ) );
+ aAppGroupname = aAppGroupname.replaceFirst( "%s", aOpt.GetModuleName( SvtModuleOptions::EModule::CALC ) );
+ m_aUIProperties[nIdx++].Value = setGroupControlOpt("tabcontrol-page2", aAppGroupname, OUString());
+
+ // show subgroup for pages
+ m_aUIProperties[nIdx++].Value = setSubgroupControlOpt("pages", ScResId( SCSTR_PRINTOPT_PAGES ), OUString());
+
+ // create a bool option for empty pages
+ m_aUIProperties[nIdx++].Value = setBoolControlOpt("suppressemptypages", ScResId( SCSTR_PRINTOPT_SUPPRESSEMPTY ),
+ ".HelpID:vcl:PrintDialog:IsSuppressEmptyPages:CheckBox",
+ "IsSuppressEmptyPages",
+ bSuppress);
+ // show Subgroup for print content
+ vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt;
+ aPrintRangeOpt.maGroupHint = "PrintRange";
+ m_aUIProperties[nIdx++].Value = setSubgroupControlOpt("printrange", ScResId( SCSTR_PRINTOPT_PAGES ),
+ OUString(),
+ aPrintRangeOpt);
+
+ // create a choice for the content to create
+ uno::Sequence< OUString > aChoices{
+ ScResId( SCSTR_PRINTOPT_ALLSHEETS ),
+ ScResId( SCSTR_PRINTOPT_SELECTEDSHEETS ),
+ ScResId( SCSTR_PRINTOPT_SELECTEDCELLS )};
+ uno::Sequence< OUString > aHelpIds{
+ ".HelpID:vcl:PrintDialog:PrintContent:ListBox"};
+ m_aUIProperties[nIdx++].Value = setChoiceListControlOpt( "printextrabox", OUString(),
+ aHelpIds, "PrintContent",
+ aChoices, nContent );
+
+ // show Subgroup for print range
+ aPrintRangeOpt.mbInternalOnly = true;
+ m_aUIProperties[nIdx++].Value = setSubgroupControlOpt("fromwhich", ScResId( SCSTR_PRINTOPT_FROMWHICH ),
+ OUString(),
+ aPrintRangeOpt);
+
+ // create a choice for the range to print
+ OUString aPrintRangeName( "PrintRange" );
+ aChoices = { ScResId( SCSTR_PRINTOPT_PRINTALLPAGES ), ScResId( SCSTR_PRINTOPT_PRINTPAGES ) };
+ aHelpIds = { ".HelpID:vcl:PrintDialog:PrintRange:RadioButton:0",
+ ".HelpID:vcl:PrintDialog:PrintRange:RadioButton:1" };
+ uno::Sequence< OUString > aWidgetIds{ "rbAllPages", "rbRangePages" };
+ m_aUIProperties[nIdx++].Value = setChoiceRadiosControlOpt(aWidgetIds, OUString(),
+ aHelpIds,
+ aPrintRangeName,
+ aChoices,
+ 0 );
+
+ // create an Edit dependent on "Pages" selected
+ vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt( aPrintRangeName, 1, true );
+ m_aUIProperties[nIdx++].Value = setEditControlOpt("pagerange", OUString(),
+ ".HelpID:vcl:PrintDialog:PageRange:Edit",
+ "PageRange", OUString(), aPageRangeOpt);
+
+ vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintRangeName, 0, true);
+ m_aUIProperties[ nIdx++ ].Value = setChoiceListControlOpt("evenoddbox",
+ OUString(),
+ uno::Sequence<OUString>(),
+ "EvenOdd",
+ uno::Sequence<OUString>(),
+ 0,
+ uno::Sequence< sal_Bool >(),
+ aEvenOddOpt);
+
+ assert(nIdx == nNumProps);
+}
+
+void ScPrintUIOptions::SetDefaults()
+{
+ // re-initialize the default values from print options
+
+ const ScPrintOptions& rPrintOpt = SC_MOD()->GetPrintOptions();
+ sal_Int32 nContent = rPrintOpt.GetAllSheets() ? 0 : 1;
+ bool bSuppress = rPrintOpt.GetSkipEmpty();
+
+ for (beans::PropertyValue & rPropValue : m_aUIProperties)
+ {
+ uno::Sequence<beans::PropertyValue> aUIProp;
+ if ( rPropValue.Value >>= aUIProp )
+ {
+ for (auto& rProp : asNonConstRange(aUIProp))
+ {
+ OUString aName = rProp.Name;
+ if ( aName == "Property" )
+ {
+ beans::PropertyValue aPropertyValue;
+ if ( rProp.Value >>= aPropertyValue )
+ {
+ if ( aPropertyValue.Name == "PrintContent" )
+ {
+ aPropertyValue.Value <<= nContent;
+ rProp.Value <<= aPropertyValue;
+ }
+ else if ( aPropertyValue.Name == "IsSuppressEmptyPages" )
+ {
+ aPropertyValue.Value <<= bSuppress;
+ rProp.Value <<= aPropertyValue;
+ }
+ }
+ }
+ }
+ rPropValue.Value <<= aUIProp;
+ }
+ }
+}
+
+void ScModelObj::CreateAndSet(ScDocShell* pDocSh)
+{
+ if (pDocSh)
+ pDocSh->SetBaseModel( new ScModelObj(pDocSh) );
+}
+
+SdrModel& ScModelObj::getSdrModelFromUnoModel() const
+{
+ ScDocument& rDoc(pDocShell->GetDocument());
+
+ if(!rDoc.GetDrawLayer())
+ {
+ rDoc.InitDrawLayer();
+ }
+
+ return *rDoc.GetDrawLayer(); // TTTT should be reference
+}
+
+ScModelObj::ScModelObj( ScDocShell* pDocSh ) :
+ SfxBaseModel( pDocSh ),
+ aPropSet( lcl_GetDocOptPropertyMap() ),
+ pDocShell( pDocSh ),
+ maChangesListeners( m_aMutex )
+{
+ // pDocShell may be NULL if this is the base of a ScDocOptionsObj
+ if ( pDocShell )
+ {
+ pDocShell->GetDocument().AddUnoObject(*this); // SfxModel is derived from SfxListener
+ }
+}
+
+ScModelObj::~ScModelObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+
+ if (xNumberAgg.is())
+ xNumberAgg->setDelegator(uno::Reference<uno::XInterface>());
+
+ pPrintFuncCache.reset();
+ pPrinterOptions.reset();
+}
+
+uno::Reference< uno::XAggregation> const & ScModelObj::GetFormatter()
+{
+ // pDocShell may be NULL if this is the base of a ScDocOptionsObj
+ if ( !xNumberAgg.is() && pDocShell )
+ {
+ // setDelegator changes RefCount, so we'd better hold the reference ourselves
+ // (directly in m_refCount, so we don't delete ourselves with release())
+ osl_atomic_increment( &m_refCount );
+ // we need a reference to SvNumberFormatsSupplierObj during queryInterface,
+ // otherwise it'll be deleted
+ uno::Reference<util::XNumberFormatsSupplier> xFormatter(
+ new SvNumberFormatsSupplierObj(pDocShell->GetDocument().GetThreadedContext().GetFormatTable() ));
+ {
+ xNumberAgg.set(uno::Reference<uno::XAggregation>( xFormatter, uno::UNO_QUERY ));
+ // extra block to force deletion of the temporary before setDelegator
+ }
+
+ // during setDelegator no additional reference should exist
+ xFormatter = nullptr;
+
+ if (xNumberAgg.is())
+ xNumberAgg->setDelegator( getXWeak() );
+ osl_atomic_decrement( &m_refCount );
+ } // if ( !xNumberAgg.is() )
+ return xNumberAgg;
+}
+
+ScDocument* ScModelObj::GetDocument() const
+{
+ if (pDocShell)
+ return &pDocShell->GetDocument();
+ return nullptr;
+}
+
+SfxObjectShell* ScModelObj::GetEmbeddedObject() const
+{
+ return pDocShell;
+}
+
+void ScModelObj::UpdateAllRowHeights()
+{
+ if (pDocShell)
+ pDocShell->UpdateAllRowHeights();
+}
+
+void ScModelObj::BeforeXMLLoading()
+{
+ if (pDocShell)
+ pDocShell->BeforeXMLLoading();
+}
+
+void ScModelObj::AfterXMLLoading()
+{
+ if (pDocShell)
+ pDocShell->AfterXMLLoading(true);
+}
+
+ScSheetSaveData* ScModelObj::GetSheetSaveData()
+{
+ if (pDocShell)
+ return pDocShell->GetSheetSaveData();
+ return nullptr;
+}
+
+ScFormatSaveData* ScModelObj::GetFormatSaveData()
+{
+ if (pDocShell)
+ return pDocShell->GetFormatSaveData();
+ return nullptr;
+}
+
+void ScModelObj::RepaintRange( const ScRange& rRange )
+{
+ if (pDocShell)
+ pDocShell->PostPaint( rRange, PaintPartFlags::Grid );
+}
+
+void ScModelObj::RepaintRange( const ScRangeList& rRange )
+{
+ if (pDocShell)
+ pDocShell->PostPaint(rRange, PaintPartFlags::Grid, SC_PF_TESTMERGE);
+}
+
+static ScViewData* lcl_getViewMatchingDocZoomTab(const Fraction& rZoomX,
+ const Fraction& rZoomY,
+ const SCTAB nTab,
+ const ViewShellDocId& rDocId)
+{
+ constexpr size_t nMaxIter = 5;
+ size_t nIter = 0;
+ for (SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ pViewShell && nIter < nMaxIter;
+ (pViewShell = SfxViewShell::GetNext(*pViewShell)), ++nIter)
+ {
+ if (pViewShell->GetDocId() != rDocId)
+ continue;
+
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (!pTabViewShell)
+ continue;
+
+ ScViewData& rData = pTabViewShell->GetViewData();
+ if (rData.GetTabNo() == nTab && rData.GetZoomX() == rZoomX && rData.GetZoomY() == rZoomY)
+ return &rData;
+ }
+
+ return nullptr;
+}
+
+void ScModelObj::paintTile( VirtualDevice& rDevice,
+ int nOutputWidth, int nOutputHeight,
+ int nTilePosX, int nTilePosY,
+ tools::Long nTileWidth, tools::Long nTileHeight )
+{
+ ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
+
+ // FIXME: Can this happen? What should we do?
+ if (!pViewShell)
+ return;
+
+ ScViewData* pActiveViewData = &pViewShell->GetViewData();
+ Fraction aFracX(o3tl::toTwips(nOutputWidth, o3tl::Length::px), nTileWidth);
+ Fraction aFracY(o3tl::toTwips(nOutputHeight, o3tl::Length::px), nTileHeight);
+
+ // Try to find a view that matches the tile-zoom requested by iterating over
+ // first few shells. This is to avoid switching of zooms in ScGridWindow::PaintTile
+ // and hence avoid grid-offset recomputation on all shapes which is not cheap.
+ ScViewData* pViewData = lcl_getViewMatchingDocZoomTab(aFracX, aFracY,
+ pActiveViewData->GetTabNo(), pViewShell->GetDocId());
+ if (!pViewData)
+ pViewData = pActiveViewData;
+
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+
+ // update the size of the area we are painting
+ // FIXME we want to use only the minimal necessary size, like the
+ // following; but for the moment there is too many problems with that and
+ // interaction with editeng used for the cell editing
+ //Size aTileSize(nOutputWidth, nOutputHeight);
+ //if (pGridWindow->GetOutputSizePixel() != aTileSize)
+ // pGridWindow->SetOutputSizePixel(Size(nOutputWidth, nOutputHeight));
+ // so instead for now, set the viewport size to document size
+
+ // Fetch the document size and the tiled rendering area together,
+ // because the tiled rendering area is not cheap to compute, and we want
+ // to pass it down to ScGridWindow::PaintFile to avoid computing twice.
+ SCCOL nTiledRenderingAreaEndCol = 0;
+ SCROW nTiledRenderingAreaEndRow = 0;
+ Size aDocSize = getDocumentSize(nTiledRenderingAreaEndCol, nTiledRenderingAreaEndRow);
+
+ pGridWindow->SetOutputSizePixel(Size(aDocSize.Width() * pViewData->GetPPTX(), aDocSize.Height() * pViewData->GetPPTY()));
+
+ pGridWindow->PaintTile( rDevice, nOutputWidth, nOutputHeight,
+ nTilePosX, nTilePosY, nTileWidth, nTileHeight,
+ nTiledRenderingAreaEndCol, nTiledRenderingAreaEndRow );
+
+ // Draw Form controls
+ ScDrawLayer* pDrawLayer = pDocShell->GetDocument().GetDrawLayer();
+ SdrPage* pPage = pDrawLayer->GetPage(sal_uInt16(pViewData->GetTabNo()));
+ SdrView* pDrawView = pViewData->GetViewShell()->GetScDrawView();
+ tools::Rectangle aTileRect(Point(nTilePosX, nTilePosY), Size(nTileWidth, nTileHeight));
+ Size aOutputSize(nOutputWidth, nOutputHeight);
+ LokControlHandler::paintControlTile(pPage, pDrawView, *pGridWindow, rDevice, aOutputSize, aTileRect);
+}
+
+void ScModelObj::setPart( int nPart, bool /*bAllowChangeFocus*/ )
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScTabView* pTabView = pViewData->GetView();
+ if (!pTabView)
+ return;
+
+ if (SdrView* pDrawView = pViewData->GetViewShell()->GetScDrawView())
+ pDrawView->SetNegativeX(comphelper::LibreOfficeKit::isActive() &&
+ pViewData->GetDocument().IsLayoutRTL(nPart));
+
+ pTabView->SelectTabPage(nPart + 1);
+}
+
+int ScModelObj::getParts()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ return rDoc.GetTableCount();
+}
+
+int ScModelObj::getPart()
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ return pViewData ? pViewData->GetViewShell()->getPart() : 0;
+}
+
+OUString ScModelObj::getPartInfo( int nPart )
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return OUString();
+
+ const bool bIsVisible = pViewData->GetDocument().IsVisible(nPart);
+ //FIXME: Implement IsSelected().
+ const bool bIsSelected = false; //pViewData->GetDocument()->IsSelected(nPart);
+ const bool bIsRTLLayout = pViewData->GetDocument().IsLayoutRTL(nPart);
+
+ OUString aPartInfo = "{ \"visible\": \"" +
+ OUString::number(static_cast<unsigned int>(bIsVisible)) +
+ "\", \"selected\": \"" +
+ OUString::number(static_cast<unsigned int>(bIsSelected)) +
+ "\", \"rtllayout\": \"" +
+ OUString::number(static_cast<unsigned int>(bIsRTLLayout)) +
+ "\" }";
+ return aPartInfo;
+}
+
+OUString ScModelObj::getPartName( int nPart )
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return OUString();
+
+ OUString sTabName;
+ pViewData->GetDocument().GetName(nPart, sTabName);
+ return sTabName;
+}
+
+OUString ScModelObj::getPartHash( int nPart )
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return OUString();
+
+ sal_Int64 nHashCode;
+ return (pViewData->GetDocument().GetHashCode(nPart, nHashCode) ? OUString::number(nHashCode) : OUString());
+}
+
+VclPtr<vcl::Window> ScModelObj::getDocWindow()
+{
+ SolarMutexGuard aGuard;
+
+ ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
+
+ // FIXME: Can this happen? What should we do?
+ if (!pViewShell)
+ return VclPtr<vcl::Window>();
+
+ if (VclPtr<vcl::Window> pWindow = SfxLokHelper::getInPlaceDocWindow(pViewShell))
+ return pWindow;
+
+ return pViewShell->GetViewData().GetActiveWin();
+}
+
+Size ScModelObj::getDocumentSize()
+{
+ SCCOL nTiledRenderingAreaEndCol = 0;
+ SCROW nTiledRenderingAreaEndRow = 0;
+ return getDocumentSize(nTiledRenderingAreaEndCol, nTiledRenderingAreaEndRow);
+}
+
+Size ScModelObj::getDocumentSize(SCCOL& rnTiledRenderingAreaEndCol, SCROW& rnTiledRenderingAreaEndRow)
+{
+ Size aSize(10, 10); // minimum size
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return aSize;
+
+ SCTAB nTab = pViewData->GetTabNo();
+ rnTiledRenderingAreaEndCol = 0;
+ rnTiledRenderingAreaEndRow = 0;
+ const ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.GetTiledRenderingArea(nTab, rnTiledRenderingAreaEndCol, rnTiledRenderingAreaEndRow);
+
+ const ScDocument* pThisDoc = &rDoc;
+ const double fPPTX = pViewData->GetPPTX();
+ const double fPPTY = pViewData->GetPPTY();
+
+ auto GetColWidthPx = [pThisDoc, fPPTX, nTab](SCCOL nCol) {
+ const sal_uInt16 nSize = pThisDoc->GetColWidth(nCol, nTab);
+ return ScViewData::ToPixel(nSize, fPPTX);
+ };
+
+ tools::Long nDocWidthPixel = pViewData->GetLOKWidthHelper().computePosition(rnTiledRenderingAreaEndCol, GetColWidthPx);
+ tools::Long nDocHeightPixel = pThisDoc->GetScaledRowHeight(0, rnTiledRenderingAreaEndRow, nTab, fPPTY);
+
+ if (nDocWidthPixel > 0 && nDocHeightPixel > 0)
+ {
+ // convert to twips
+ aSize.setWidth(nDocWidthPixel / fPPTX);
+ aSize.setHeight(nDocHeightPixel / fPPTY);
+ }
+ else
+ {
+ // convert to twips
+ aSize.setWidth(rDoc.GetColWidth(0, rnTiledRenderingAreaEndCol, nTab));
+ aSize.setHeight(rDoc.GetRowHeight(0, rnTiledRenderingAreaEndRow, nTab));
+ }
+
+ return aSize;
+}
+
+Size ScModelObj::getDataArea(long nPart)
+{
+ Size aSize(1, 1);
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData || !pDocShell)
+ return aSize;
+
+ SCTAB nTab = nPart;
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScTable* pTab = rDoc.FetchTable(nTab);
+ if (!pTab)
+ return aSize;
+
+ pTab->GetCellArea(nEndCol, nEndRow);
+ aSize = Size(nEndCol, nEndRow);
+
+ return aSize;
+}
+
+void ScModelObj::postKeyEvent(int nType, int nCharCode, int nKeyCode)
+{
+ SolarMutexGuard aGuard;
+ SfxLokHelper::postKeyEventAsync(getDocWindow(), nType, nCharCode, nKeyCode);
+}
+
+void ScModelObj::postMouseEvent(int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
+{
+ SolarMutexGuard aGuard;
+
+ ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
+
+ // FIXME: Can this happen? What should we do?
+ if (!pViewShell)
+ return;
+
+ ScViewData* pViewData = &pViewShell->GetViewData();
+
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+
+ if (!pGridWindow)
+ return;
+
+ SCTAB nTab = pViewData->GetTabNo();
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ bool bDrawNegativeX = rDoc.IsNegativePage(nTab);
+ if (SfxLokHelper::testInPlaceComponentMouseEventHit(pViewShell, nType, nX, nY, nCount,
+ nButtons, nModifier, pViewData->GetPPTX(),
+ pViewData->GetPPTY(), bDrawNegativeX))
+ return;
+
+ Point aPointTwip(nX, nY);
+
+ // Check if a control is hit
+ Point aPointHMM = o3tl::convert(aPointTwip, o3tl::Length::twip, o3tl::Length::mm100);
+ Point aPointHMMDraw(bDrawNegativeX ? -aPointHMM.X() : aPointHMM.X(), aPointHMM.Y());
+ ScDrawLayer* pDrawLayer = pDocShell->GetDocument().GetDrawLayer();
+ SdrPage* pPage = pDrawLayer->GetPage(sal_uInt16(nTab));
+ SdrView* pDrawView = pViewData->GetViewShell()->GetScDrawView();
+ if (LokControlHandler::postMouseEvent(pPage, pDrawView, *pGridWindow, nType, aPointHMMDraw, nCount, nButtons, nModifier))
+ return;
+
+ if (!pGridWindow->HasChildPathFocus(true))
+ pGridWindow->GrabFocus();
+
+ // Calc operates in pixels...
+ const Point aPosition(nX * pViewData->GetPPTX() + pGridWindow->GetOutOffXPixel(),
+ nY * pViewData->GetPPTY() + pGridWindow->GetOutOffYPixel());
+
+ VclEventId aEvent = VclEventId::NONE;
+ MouseEvent aData(aPosition, nCount, MouseEventModifiers::SIMPLECLICK, nButtons, nModifier);
+ aData.setLogicPosition(aPointHMM);
+ switch (nType)
+ {
+ case LOK_MOUSEEVENT_MOUSEBUTTONDOWN:
+ aEvent = VclEventId::WindowMouseButtonDown;
+ break;
+ case LOK_MOUSEEVENT_MOUSEBUTTONUP:
+ aEvent = VclEventId::WindowMouseButtonUp;
+ break;
+ case LOK_MOUSEEVENT_MOUSEMOVE:
+ aEvent = VclEventId::WindowMouseMove;
+ break;
+ default:
+ break;
+ }
+
+ Application::LOKHandleMouseEvent(aEvent, pGridWindow, &aData);
+}
+
+void ScModelObj::setTextSelection(int nType, int nX, int nY)
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScTabViewShell* pViewShell = pViewData->GetViewShell();
+
+ LokChartHelper aChartHelper(pViewShell);
+ if (aChartHelper.setTextSelection(nType, nX, nY))
+ return;
+
+ ScInputHandler* pInputHandler = SC_MOD()->GetInputHdl(pViewShell);
+ ScDrawView* pDrawView = pViewData->GetScDrawView();
+
+ bool bHandled = false;
+
+ if (pInputHandler && pInputHandler->IsInputMode())
+ {
+ // forwarding to editeng - we are editing the cell content
+ EditView* pTableView = pInputHandler->GetTableView();
+ assert(pTableView);
+
+ Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
+
+ if (pTableView->GetOutputArea().Contains(aPoint))
+ {
+ switch (nType)
+ {
+ case LOK_SETTEXTSELECTION_START:
+ pTableView->SetCursorLogicPosition(aPoint, /*bPoint=*/false, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_END:
+ pTableView->SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_RESET:
+ pTableView->SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/true);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ bHandled = true;
+ }
+ }
+ else if (pDrawView && pDrawView->IsTextEdit())
+ {
+ // forwarding to editeng - we are editing the text in shape
+ OutlinerView* pOutlinerView = pDrawView->GetTextEditOutlinerView();
+ EditView& rEditView = pOutlinerView->GetEditView();
+
+ Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
+ switch (nType)
+ {
+ case LOK_SETTEXTSELECTION_START:
+ rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/false, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_END:
+ rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_RESET:
+ rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/true);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ bHandled = true;
+ }
+
+ if (!bHandled)
+ {
+ // just update the cell selection
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+ if (!pGridWindow)
+ return;
+
+ // move the cell selection handles
+ pGridWindow->SetCellSelectionPixel(nType, nX * pViewData->GetPPTX(), nY * pViewData->GetPPTY());
+ }
+}
+
+uno::Reference<datatransfer::XTransferable> ScModelObj::getSelection()
+{
+ SolarMutexGuard aGuard;
+
+ TransferableDataHelper aDataHelper;
+ uno::Reference<datatransfer::XTransferable> xTransferable;
+
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ {
+ if ( ScEditShell * pShell = dynamic_cast<ScEditShell*>( pViewData->GetViewShell()->GetViewFrame().GetDispatcher()->GetShell(0) ) )
+ xTransferable = pShell->GetEditView()->GetTransferable();
+ else if ( nullptr != dynamic_cast<ScDrawTextObjectBar*>( pViewData->GetViewShell()->GetViewFrame().GetDispatcher()->GetShell(0) ))
+ {
+ ScDrawView* pView = pViewData->GetScDrawView();
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+ if (pOutView)
+ xTransferable = pOutView->GetEditView().GetTransferable();
+ }
+ else if ( ScDrawShell * pDrawShell = dynamic_cast<ScDrawShell*>( pViewData->GetViewShell()->GetViewFrame().GetDispatcher()->GetShell(0) ) )
+ xTransferable = pDrawShell->GetDrawView()->CopyToTransferable();
+ else
+ xTransferable = pViewData->GetViewShell()->CopyToTransferable();
+ }
+
+ if (!xTransferable.is())
+ xTransferable.set( aDataHelper.GetTransferable() );
+
+ return xTransferable;
+}
+
+void ScModelObj::setGraphicSelection(int nType, int nX, int nY)
+{
+ SolarMutexGuard aGuard;
+
+ ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
+
+ // FIXME: Can this happen? What should we do?
+ if (!pViewShell)
+ return;
+
+ ScViewData* pViewData = &pViewShell->GetViewData();
+
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+
+ double fPPTX = pViewData->GetPPTX();
+ double fPPTY = pViewData->GetPPTY();
+
+ pViewShell = pViewData->GetViewShell();
+ LokChartHelper aChartHelper(pViewShell);
+ if (aChartHelper.setGraphicSelection(nType, nX, nY, fPPTX, fPPTY))
+ return;
+
+ int nPixelX = nX * fPPTX;
+ int nPixelY = nY * fPPTY;
+
+ switch (nType)
+ {
+ case LOK_SETGRAPHICSELECTION_START:
+ {
+ MouseEvent aClickEvent(Point(nPixelX, nPixelY), 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
+ pGridWindow->MouseButtonDown(aClickEvent);
+ MouseEvent aMoveEvent(Point(nPixelX, nPixelY), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
+ pGridWindow->MouseMove(aMoveEvent);
+ }
+ break;
+ case LOK_SETGRAPHICSELECTION_END:
+ {
+ MouseEvent aMoveEvent(Point(nPixelX, nPixelY), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
+ pGridWindow->MouseMove(aMoveEvent);
+ MouseEvent aClickEvent(Point(nPixelX, nPixelY), 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
+ pGridWindow->MouseButtonUp(aClickEvent);
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+void ScModelObj::resetSelection()
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScTabViewShell* pViewShell = pViewData->GetViewShell();
+
+ // deselect the shapes & texts
+ ScDrawView* pDrawView = pViewShell->GetScDrawView();
+ if (pDrawView)
+ {
+ pDrawView->ScEndTextEdit();
+ pDrawView->UnmarkAll();
+ }
+ else
+ pViewShell->Unmark();
+
+ // and hide the cell and text selection
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, ""_ostr);
+ SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", ""_ostr);
+}
+
+void ScModelObj::setClipboard(const uno::Reference<datatransfer::clipboard::XClipboard>& xClipboard)
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ pViewData->GetActiveWin()->SetClipboard(xClipboard);
+}
+
+bool ScModelObj::isMimeTypeSupported()
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return false;
+
+
+ TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromSystemClipboard(pViewData->GetActiveWin()));
+ return EditEngine::HasValidData(aDataHelper.GetTransferable());
+}
+
+static void lcl_sendLOKDocumentBackground(const ScViewData* pViewData)
+{
+ ScDocShell* pDocSh = pViewData->GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const ScPatternAttr *pAttr = rDoc.GetDefPattern();
+ const SfxPoolItem& rItem = pAttr->GetItem(ATTR_BACKGROUND);
+ const SvxBrushItem& rBackground = static_cast<const SvxBrushItem&>(rItem);
+ const Color& rColor = rBackground.GetColor();
+
+ ScTabViewShell* pViewShell = pViewData->GetViewShell();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_DOCUMENT_BACKGROUND_COLOR, rColor.AsRGBHexString().toUtf8());
+}
+
+void ScModelObj::setClientZoom(int nTilePixelWidth_, int nTilePixelHeight_, int nTileTwipWidth_, int nTileTwipHeight_)
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ // Currently in LOK clients the doc background cannot be changed, so send this sparingly as possible but for every view.
+ // FIXME: Find a better place to trigger this callback where it would be called just once per view creation.
+ // Doing this in ScTabViewShell init code does not work because callbacks do not work at that point for the first view.
+ lcl_sendLOKDocumentBackground(pViewData);
+
+ const Fraction newZoomX(o3tl::toTwips(nTilePixelWidth_, o3tl::Length::px), nTileTwipWidth_);
+ const Fraction newZoomY(o3tl::toTwips(nTilePixelHeight_, o3tl::Length::px), nTileTwipHeight_);
+
+ double fDeltaPPTX = std::abs(ScGlobal::nScreenPPTX * static_cast<double>(newZoomX) - pViewData->GetPPTX());
+ double fDeltaPPTY = std::abs(ScGlobal::nScreenPPTY * static_cast<double>(newZoomY) - pViewData->GetPPTY());
+ constexpr double fEps = 1E-08;
+
+ if (pViewData->GetZoomX() == newZoomX && pViewData->GetZoomY() == newZoomY && fDeltaPPTX < fEps && fDeltaPPTY < fEps)
+ return;
+
+ pViewData->SetZoom(newZoomX, newZoomY, true);
+
+ // refresh our view's take on other view's cursors & selections
+ pViewData->GetActiveWin()->updateKitOtherCursors();
+ pViewData->GetActiveWin()->updateOtherKitSelections();
+
+ if (ScDrawView* pDrawView = pViewData->GetScDrawView())
+ pDrawView->resetGridOffsetsForAllSdrPageViews();
+}
+
+void ScModelObj::getRowColumnHeaders(const tools::Rectangle& rRectangle, tools::JsonWriter& rJsonWriter)
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScTabView* pTabView = pViewData->GetView();
+ if (!pTabView)
+ return;
+
+ pTabView->getRowColumnHeaders(rRectangle, rJsonWriter);
+}
+
+OString ScModelObj::getSheetGeometryData(bool bColumns, bool bRows, bool bSizes, bool bHidden,
+ bool bFiltered, bool bGroups)
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return ""_ostr;
+
+ ScTabView* pTabView = pViewData->GetView();
+ if (!pTabView)
+ return ""_ostr;
+
+ return pTabView->getSheetGeometryData(bColumns, bRows, bSizes, bHidden, bFiltered, bGroups);
+}
+
+void ScModelObj::getCellCursor(tools::JsonWriter& rJsonWriter)
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+ if (!pGridWindow)
+ return;
+
+ rJsonWriter.put("commandName", ".uno:CellCursor");
+ rJsonWriter.put("commandValues", pGridWindow->getCellCursor());
+}
+
+PointerStyle ScModelObj::getPointer()
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return PointerStyle::Arrow;
+
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+ if (!pGridWindow)
+ return PointerStyle::Arrow;
+
+ return pGridWindow->GetPointer();
+}
+
+void ScModelObj::getTrackedChanges(tools::JsonWriter& rJson)
+{
+ if (pDocShell)
+ {
+ if (ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack())
+ pChangeTrack->GetChangeTrackInfo(rJson);
+ }
+}
+
+void ScModelObj::setClientVisibleArea(const tools::Rectangle& rRectangle)
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ // set the PgUp/PgDown offset
+ pViewData->ForcePageUpDownOffset(rRectangle.GetHeight());
+
+ // Store the visible area so that we can use at places like shape insertion
+ pViewData->setLOKVisibleArea(rRectangle);
+
+ if (comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ {
+ ScTabView* pTabView = pViewData->GetView();
+ if (pTabView)
+ pTabView->extendTiledAreaIfNeeded();
+ }
+}
+
+void ScModelObj::setOutlineState(bool bColumn, int nLevel, int nIndex, bool bHidden)
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScDBFunc* pFunc = pViewData->GetView();
+
+ if (pFunc)
+ pFunc->SetOutlineState(bColumn, nLevel, nIndex, bHidden);
+}
+
+void ScModelObj::getPostIts(tools::JsonWriter& rJsonWriter)
+{
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::vector<sc::NoteEntry> aNotes;
+ rDoc.GetAllNoteEntries(aNotes);
+
+ auto commentsNode = rJsonWriter.startArray("comments");
+ for (const sc::NoteEntry& aNote : aNotes)
+ {
+ auto commentNode = rJsonWriter.startStruct();
+
+ rJsonWriter.put("id", aNote.mpNote->GetId());
+ rJsonWriter.put("tab", aNote.maPos.Tab());
+ rJsonWriter.put("author", aNote.mpNote->GetAuthor());
+ rJsonWriter.put("dateTime", aNote.mpNote->GetDate());
+ rJsonWriter.put("text", aNote.mpNote->GetText());
+
+ // Calculating the cell cursor position
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ {
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+ if (pGridWindow)
+ {
+ rJsonWriter.put("cellRange", ScPostIt::NoteRangeToJsonString(rDoc, aNote.maPos));
+ }
+ }
+ }
+}
+
+OString ScPostIt::NoteRangeToJsonString(const ScDocument& rDoc, const ScAddress& rPos)
+{
+ SCCOL nX(rPos.Col());
+ SCROW nY(rPos.Row());
+ OString aStartCellAddress(OString::number(nX) + " " + OString::number(nY));
+ const ScPatternAttr* pMarkPattern = rDoc.GetPattern(nX, nY, rPos.Tab());
+ if (pMarkPattern && pMarkPattern->GetItemSet().GetItemState(ATTR_MERGE, false) == SfxItemState::SET)
+ {
+ SCCOL nCol = pMarkPattern->GetItem(ATTR_MERGE).GetColMerge();
+ if (nCol > 1)
+ nX += nCol - 1;
+ SCROW nRow = pMarkPattern->GetItem(ATTR_MERGE).GetRowMerge();
+ if (nRow > 1)
+ nY += nRow - 1;
+ }
+ OString aEndCellAddress(OString::number(nX) + " " + OString::number(nY));
+ return aStartCellAddress + " " + aEndCellAddress;
+}
+
+void ScModelObj::getPostItsPos(tools::JsonWriter& rJsonWriter)
+{
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::vector<sc::NoteEntry> aNotes;
+ rDoc.GetAllNoteEntries(aNotes);
+
+ auto commentsNode = rJsonWriter.startArray("commentsPos");
+ for (const sc::NoteEntry& aNote : aNotes)
+ {
+ auto commentNode = rJsonWriter.startStruct();
+
+ rJsonWriter.put("id", aNote.mpNote->GetId());
+ rJsonWriter.put("tab", aNote.maPos.Tab());
+
+ // Calculating the cell cursor position
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ {
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+ if (pGridWindow)
+ {
+ rJsonWriter.put("cellRange", ScPostIt::NoteRangeToJsonString(rDoc, aNote.maPos));
+ }
+ }
+ }
+}
+
+void ScModelObj::completeFunction(const OUString& rFunctionName)
+{
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if (pHdl)
+ {
+ assert(!rFunctionName.isEmpty());
+ pHdl->LOKPasteFunctionData(rFunctionName);
+ }
+}
+
+OString ScModelObj::getViewRenderState(SfxViewShell* pViewShell)
+{
+ OStringBuffer aState;
+ ScViewData* pViewData = nullptr;
+
+ if (pViewShell)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast< ScTabViewShell*>(pViewShell);
+ if (pTabViewShell)
+ pViewData = &pTabViewShell->GetViewData();
+ }
+ else
+ {
+ pViewData = ScDocShell::GetViewData();
+ }
+
+ if (pViewData)
+ {
+ aState.append(';');
+
+ const ScViewOptions& aViewOptions = pViewData->GetOptions();
+ OString aThemeName = OUStringToOString(aViewOptions.GetColorSchemeName(), RTL_TEXTENCODING_UTF8);
+ aState.append(aThemeName);
+ }
+
+ return aState.makeStringAndClear();
+}
+
+void ScModelObj::initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments)
+{
+ SolarMutexGuard aGuard;
+
+ // enable word autocompletion
+ ScAppOptions aAppOptions(SC_MOD()->GetAppOptions());
+ aAppOptions.SetAutoComplete(true);
+ SC_MOD()->SetAppOptions(aAppOptions);
+
+ for (const beans::PropertyValue& rValue : rArguments)
+ {
+ if (rValue.Name == ".uno:SpellOnline" && rValue.Value.has<bool>())
+ {
+ ScDocOptions options = GetDocument()->GetDocOptions();
+ options.SetAutoSpell(rValue.Value.get<bool>());
+ GetDocument()->SetDocOptions(options);
+ }
+ }
+
+ // show us the text exactly
+ ScInputOptions aInputOptions(SC_MOD()->GetInputOptions());
+ aInputOptions.SetTextWysiwyg(true);
+ aInputOptions.SetReplaceCellsWarn(false);
+ SC_MOD()->SetInputOptions(aInputOptions);
+ pDocShell->CalcOutputFactor();
+
+ // when the "This document may contain formatting or content that cannot
+ // be saved..." dialog appears, it is auto-cancelled with tiled rendering,
+ // causing 'Save' being disabled; so let's always save to the original
+ // format
+ auto xChanges = comphelper::ConfigurationChanges::create();
+ officecfg::Office::Common::Save::Document::WarnAlienFormat::set(false, xChanges);
+ xChanges->commit();
+}
+
+uno::Any SAL_CALL ScModelObj::queryInterface( const uno::Type& rType )
+{
+ uno::Any aReturn = ::cppu::queryInterface(rType,
+ static_cast< sheet::XSpreadsheetDocument *>(this),
+ static_cast< document::XActionLockable *>(this),
+ static_cast< sheet::XCalculatable *>(this),
+ static_cast< util::XProtectable *>(this),
+ static_cast< drawing::XDrawPagesSupplier *>(this),
+ static_cast< sheet::XGoalSeek *>(this),
+ static_cast< sheet::XConsolidatable *>(this),
+ static_cast< sheet::XDocumentAuditing *>(this),
+ static_cast< style::XStyleFamiliesSupplier *>(this),
+ static_cast< view::XRenderable *>(this),
+ static_cast< document::XLinkTargetSupplier *>(this),
+ static_cast< beans::XPropertySet *>(this),
+ static_cast< lang::XMultiServiceFactory *>(this),
+ static_cast< lang::XServiceInfo *>(this),
+ static_cast< util::XChangesNotifier *>(this),
+ static_cast< sheet::opencl::XOpenCLSelection *>(this),
+ static_cast< chart2::XDataProviderAccess *>(this));
+ if ( aReturn.hasValue() )
+ return aReturn;
+
+ uno::Any aRet(SfxBaseModel::queryInterface( rType ));
+ if ( !aRet.hasValue()
+ && rType != cppu::UnoType<css::document::XDocumentEventBroadcaster>::get()
+ && rType != cppu::UnoType<css::frame::XController>::get()
+ && rType != cppu::UnoType<css::frame::XFrame>::get()
+ && rType != cppu::UnoType<css::script::XInvocation>::get()
+ && rType != cppu::UnoType<css::beans::XFastPropertySet>::get()
+ && rType != cppu::UnoType<css::awt::XWindow>::get())
+ {
+ GetFormatter();
+ if ( xNumberAgg.is() )
+ aRet = xNumberAgg->queryAggregation( rType );
+ }
+
+ return aRet;
+}
+
+void SAL_CALL ScModelObj::acquire() noexcept
+{
+ SfxBaseModel::acquire();
+}
+
+void SAL_CALL ScModelObj::release() noexcept
+{
+ SfxBaseModel::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScModelObj::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes = [&]()
+ {
+ uno::Sequence<uno::Type> aAggTypes;
+ if ( GetFormatter().is() )
+ {
+ const uno::Type& rProvType = cppu::UnoType<lang::XTypeProvider>::get();
+ uno::Any aNumProv(xNumberAgg->queryAggregation(rProvType));
+ if(auto xNumProv
+ = o3tl::tryAccess<uno::Reference<lang::XTypeProvider>>(aNumProv))
+ {
+ aAggTypes = (*xNumProv)->getTypes();
+ }
+ }
+ return comphelper::concatSequences(
+ SfxBaseModel::getTypes(),
+ aAggTypes,
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XSpreadsheetDocument>::get(),
+ cppu::UnoType<document::XActionLockable>::get(),
+ cppu::UnoType<sheet::XCalculatable>::get(),
+ cppu::UnoType<util::XProtectable>::get(),
+ cppu::UnoType<drawing::XDrawPagesSupplier>::get(),
+ cppu::UnoType<sheet::XGoalSeek>::get(),
+ cppu::UnoType<sheet::XConsolidatable>::get(),
+ cppu::UnoType<sheet::XDocumentAuditing>::get(),
+ cppu::UnoType<style::XStyleFamiliesSupplier>::get(),
+ cppu::UnoType<view::XRenderable>::get(),
+ cppu::UnoType<document::XLinkTargetSupplier>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<lang::XMultiServiceFactory>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<util::XChangesNotifier>::get(),
+ cppu::UnoType<sheet::opencl::XOpenCLSelection>::get(),
+ } );
+ }();
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScModelObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void ScModelObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ // Not interested in reference update hints here
+
+ const SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // has become invalid
+ if (xNumberAgg.is())
+ {
+ SvNumberFormatsSupplierObj* pNumFmt =
+ comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(
+ uno::Reference<util::XNumberFormatsSupplier>(xNumberAgg, uno::UNO_QUERY) );
+ if ( pNumFmt )
+ pNumFmt->SetNumberFormatter( nullptr );
+ }
+
+ pPrintFuncCache.reset(); // must be deleted because it has a pointer to the DocShell
+ m_pPrintState.reset();
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ // cached data for rendering become invalid when contents change
+ // (if a broadcast is added to SetDrawModified, is has to be tested here, too)
+
+ pPrintFuncCache.reset();
+ m_pPrintState.reset();
+
+ // handle "OnCalculate" sheet events (search also for VBA event handlers)
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( rDoc.GetVbaEventProcessor().is() )
+ {
+ // If the VBA event processor is set, HasAnyCalcNotification is much faster than HasAnySheetEventScript
+ if ( rDoc.HasAnyCalcNotification() && rDoc.HasAnySheetEventScript( ScSheetEventId::CALCULATE, true ) )
+ HandleCalculateEvents();
+ }
+ else
+ {
+ if ( rDoc.HasAnySheetEventScript( ScSheetEventId::CALCULATE ) )
+ HandleCalculateEvents();
+ }
+ }
+ }
+
+ // always call parent - SfxBaseModel might need to handle the same hints again
+ SfxBaseModel::Notify( rBC, rHint ); // SfxBaseModel is derived from SfxListener
+}
+
+// XSpreadsheetDocument
+
+uno::Reference<sheet::XSpreadsheets> SAL_CALL ScModelObj::getSheets()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScTableSheetsObj(pDocShell);
+ return nullptr;
+}
+
+css::uno::Reference< ::css::chart2::data::XDataProvider > SAL_CALL ScModelObj::createDataProvider()
+{
+ if (pDocShell)
+ {
+ return css::uno::Reference< ::css::chart2::data::XDataProvider > (
+ ScServiceProvider::MakeInstance(ScServiceProvider::Type::CHDATAPROV, pDocShell), uno::UNO_QUERY);
+ }
+ return nullptr;
+}
+
+// XStyleFamiliesSupplier
+
+uno::Reference<container::XNameAccess> SAL_CALL ScModelObj::getStyleFamilies()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScStyleFamiliesObj(pDocShell);
+ return nullptr;
+}
+
+// XRenderable
+
+static OutputDevice* lcl_GetRenderDevice( const uno::Sequence<beans::PropertyValue>& rOptions )
+{
+ OutputDevice* pRet = nullptr;
+ for (const beans::PropertyValue& rProp : rOptions)
+ {
+ const OUString & rPropName = rProp.Name;
+
+ if (rPropName == SC_UNONAME_RENDERDEV)
+ {
+ uno::Reference<awt::XDevice> xRenderDevice(rProp.Value, uno::UNO_QUERY);
+ if ( xRenderDevice.is() )
+ {
+ VCLXDevice* pDevice = dynamic_cast<VCLXDevice*>( xRenderDevice.get() );
+ if ( pDevice )
+ {
+ pRet = pDevice->GetOutputDevice().get();
+ pRet->SetDigitLanguage( ScModule::GetOptDigitLanguage() );
+ }
+ }
+ }
+ }
+ return pRet;
+}
+
+static bool lcl_ParseTarget( const OUString& rTarget, ScRange& rTargetRange, tools::Rectangle& rTargetRect,
+ bool& rIsSheet, ScDocument& rDoc, SCTAB nSourceTab )
+{
+ // test in same order as in SID_CURRENTCELL execute
+
+ ScAddress aAddress;
+ SCTAB nNameTab;
+ sal_Int32 nNumeric = 0;
+
+ bool bRangeValid = false;
+ bool bRectValid = false;
+
+ if ( rTargetRange.Parse( rTarget, rDoc ) & ScRefFlags::VALID )
+ {
+ bRangeValid = true; // range reference
+ }
+ else if ( aAddress.Parse( rTarget, rDoc ) & ScRefFlags::VALID )
+ {
+ rTargetRange = aAddress;
+ bRangeValid = true; // cell reference
+ }
+ else if ( ScRangeUtil::MakeRangeFromName( rTarget, rDoc, nSourceTab, rTargetRange ) ||
+ ScRangeUtil::MakeRangeFromName( rTarget, rDoc, nSourceTab, rTargetRange, RUTL_DBASE ) )
+ {
+ bRangeValid = true; // named range or database range
+ }
+ else if ( comphelper::string::isdigitAsciiString(rTarget) &&
+ ( nNumeric = rTarget.toInt32() ) > 0 && nNumeric <= rDoc.MaxRow()+1 )
+ {
+ // row number is always mapped to cell A(row) on the same sheet
+ rTargetRange = ScAddress( 0, static_cast<SCROW>(nNumeric-1), nSourceTab ); // target row number is 1-based
+ bRangeValid = true; // row number
+ }
+ else if ( rDoc.GetTable( rTarget, nNameTab ) )
+ {
+ rTargetRange = ScAddress(0,0,nNameTab);
+ bRangeValid = true; // sheet name
+ rIsSheet = true; // needs special handling (first page of the sheet)
+ }
+ else
+ {
+ // look for named drawing object
+
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if ( pDrawLayer )
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB i=0; i<nTabCount && !bRangeValid; i++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(i));
+ OSL_ENSURE(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bRangeValid)
+ {
+ if ( ScDrawLayer::GetVisibleName( pObject ) == rTarget )
+ {
+ rTargetRect = pObject->GetLogicRect(); // 1/100th mm
+ rTargetRange = rDoc.GetRange( i, rTargetRect ); // underlying cells
+ bRangeValid = bRectValid = true; // rectangle is valid
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+ }
+ if ( bRangeValid && !bRectValid )
+ {
+ // get rectangle for cell range
+ rTargetRect = rDoc.GetMMRect( rTargetRange.aStart.Col(), rTargetRange.aStart.Row(),
+ rTargetRange.aEnd.Col(), rTargetRange.aEnd.Row(),
+ rTargetRange.aStart.Tab() );
+ }
+
+ return bRangeValid;
+}
+
+bool ScModelObj::FillRenderMarkData( const uno::Any& aSelection,
+ const uno::Sequence< beans::PropertyValue >& rOptions,
+ ScMarkData& rMark,
+ ScPrintSelectionStatus& rStatus, OUString& rPagesStr,
+ bool& rbRenderToGraphic ) const
+{
+ OSL_ENSURE( !rMark.IsMarked() && !rMark.IsMultiMarked(), "FillRenderMarkData: MarkData must be empty" );
+ OSL_ENSURE( pDocShell, "FillRenderMarkData: DocShell must be set" );
+
+ bool bDone = false;
+
+ uno::Reference<frame::XController> xView;
+
+ // defaults when no options are passed: all sheets, include empty pages
+ bool bSelectedSheetsOnly = false;
+ bool bSuppressEmptyPages = true;
+
+ bool bHasPrintContent = false;
+ sal_Int32 nPrintContent = 0; // all sheets / selected sheets / selected cells
+ sal_Int32 nPrintRange = 0; // all pages / pages
+ sal_Int32 nEOContent = 0; // even pages / odd pages
+ OUString aPageRange; // "pages" edit value
+
+ for( const auto& rOption : rOptions )
+ {
+ if ( rOption.Name == "IsOnlySelectedSheets" )
+ {
+ rOption.Value >>= bSelectedSheetsOnly;
+ }
+ else if ( rOption.Name == "IsSuppressEmptyPages" )
+ {
+ rOption.Value >>= bSuppressEmptyPages;
+ }
+ else if ( rOption.Name == "PageRange" )
+ {
+ rOption.Value >>= aPageRange;
+ }
+ else if ( rOption.Name == "PrintRange" )
+ {
+ rOption.Value >>= nPrintRange;
+ }
+ else if ( rOption.Name == "EvenOdd" )
+ {
+ rOption.Value >>= nEOContent;
+ }
+ else if ( rOption.Name == "PrintContent" )
+ {
+ bHasPrintContent = true;
+ rOption.Value >>= nPrintContent;
+ }
+ else if ( rOption.Name == "View" )
+ {
+ rOption.Value >>= xView;
+ }
+ else if ( rOption.Name == "RenderToGraphic" )
+ {
+ rOption.Value >>= rbRenderToGraphic;
+ }
+ }
+
+ // "Print Content" selection wins over "Selected Sheets" option
+ if ( bHasPrintContent )
+ bSelectedSheetsOnly = ( nPrintContent != 0 );
+
+ uno::Reference<uno::XInterface> xInterface(aSelection, uno::UNO_QUERY);
+ if ( xInterface.is() )
+ {
+ ScCellRangesBase* pSelObj = dynamic_cast<ScCellRangesBase*>( xInterface.get() );
+ uno::Reference< drawing::XShapes > xShapes( xInterface, uno::UNO_QUERY );
+ if ( pSelObj && pSelObj->GetDocShell() == pDocShell )
+ {
+ bool bSheet = ( dynamic_cast<ScTableSheetObj*>( pSelObj ) != nullptr );
+ bool bCursor = pSelObj->IsCursorOnly();
+ const ScRangeList& rRanges = pSelObj->GetRangeList();
+
+ rMark.MarkFromRangeList( rRanges, false );
+ rMark.MarkToSimple();
+
+ if ( rMark.IsMultiMarked() )
+ {
+ // #i115266# copy behavior of old printing:
+ // treat multiple selection like a single selection with the enclosing range
+ const ScRange& aMultiMarkArea = rMark.GetMultiMarkArea();
+ rMark.ResetMark();
+ rMark.SetMarkArea( aMultiMarkArea );
+ }
+
+ if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ // a sheet object is treated like an empty selection: print the used area of the sheet
+
+ if ( bCursor || bSheet ) // nothing selected -> use whole tables
+ {
+ rMark.ResetMark(); // doesn't change table selection
+ rStatus.SetMode( ScPrintSelectionMode::Cursor );
+ }
+ else
+ rStatus.SetMode( ScPrintSelectionMode::Range );
+
+ rStatus.SetRanges( rRanges );
+ bDone = true;
+ }
+ // multi selection isn't supported
+ }
+ else if( xShapes.is() )
+ {
+ //print a selected ole object
+ // multi selection isn't supported yet
+ uno::Reference< drawing::XShape > xShape( xShapes->getByIndex(0), uno::UNO_QUERY );
+ SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape );
+ if( pSdrObj && pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ tools::Rectangle aObjRect = pSdrObj->GetCurrentBoundRect();
+ SCTAB nCurrentTab = ScDocShell::GetCurTab();
+ ScRange aRange = rDoc.GetRange( nCurrentTab, aObjRect );
+ rMark.SetMarkArea( aRange );
+
+ if( rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ rStatus.SetMode( ScPrintSelectionMode::RangeExclusivelyOleAndDrawObjects );
+ bDone = true;
+ }
+ }
+ }
+ else if ( comphelper::getFromUnoTunnel<ScModelObj>( xInterface ) == this )
+ {
+ // render the whole document
+ // -> no selection, all sheets
+
+ SCTAB nTabCount = pDocShell->GetDocument().GetTableCount();
+ for (SCTAB nTab = 0; nTab < nTabCount; nTab++)
+ rMark.SelectTable( nTab, true );
+ rStatus.SetMode( ScPrintSelectionMode::Document );
+ bDone = true;
+ }
+ // other selection types aren't supported
+ }
+
+ // restrict to selected sheets if a view is available
+ uno::Reference<sheet::XSelectedSheetsSupplier> xSelectedSheets(xView, uno::UNO_QUERY);
+ if (bSelectedSheetsOnly && pDocShell && xSelectedSheets.is())
+ {
+ const uno::Sequence<sal_Int32> aSelected = xSelectedSheets->getSelectedSheets();
+ ScMarkData::MarkedTabsType aSelectedTabs;
+ SCTAB nMaxTab = pDocShell->GetDocument().GetTableCount() -1;
+ for (const auto& rSelected : aSelected)
+ {
+ SCTAB nSelected = static_cast<SCTAB>(rSelected);
+ if (ValidTab(nSelected, nMaxTab))
+ aSelectedTabs.insert(nSelected);
+ }
+ rMark.SetSelectedTabs(aSelectedTabs);
+ }
+
+ ScPrintOptions aNewOptions;
+ aNewOptions.SetSkipEmpty( bSuppressEmptyPages );
+ aNewOptions.SetAllSheets( !bSelectedSheetsOnly );
+ rStatus.SetOptions( aNewOptions );
+
+ // "PrintRange" enables (1) or disables (0) the "PageRange" edit
+ if ( nPrintRange == 1 )
+ rPagesStr = aPageRange;
+ else
+ rPagesStr.clear();
+
+ return bDone;
+}
+
+sal_Int32 SAL_CALL ScModelObj::getRendererCount(const uno::Any& aSelection,
+ const uno::Sequence<beans::PropertyValue>& rOptions)
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ {
+ throw lang::DisposedException( OUString(),
+ static_cast< sheet::XSpreadsheetDocument* >(this) );
+ }
+
+ ScMarkData aMark(GetDocument()->GetSheetLimits());
+ ScPrintSelectionStatus aStatus;
+ OUString aPagesStr;
+ bool bRenderToGraphic = false;
+ if ( !FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr, bRenderToGraphic ) )
+ return 0;
+
+ // The same ScPrintFuncCache object in pPrintFuncCache is used as long as
+ // the same selection is used (aStatus) and the document isn't changed
+ // (pPrintFuncCache is cleared in Notify handler)
+
+ if ( !pPrintFuncCache || !pPrintFuncCache->IsSameSelection( aStatus ) )
+ {
+ pPrintFuncCache.reset(new ScPrintFuncCache( pDocShell, aMark, aStatus ));
+ }
+ sal_Int32 nPages = pPrintFuncCache->GetPageCount();
+
+ m_pPrintState.reset();
+ maValidPages.clear();
+
+ sal_Int32 nContent = 0;
+ sal_Int32 nEOContent = 0;
+ bool bSinglePageSheets = false;
+ for ( const auto& rValue : rOptions)
+ {
+ if ( rValue.Name == "PrintRange" )
+ {
+ rValue.Value >>= nContent;
+ }
+ else if ( rValue.Name == "SinglePageSheets" )
+ {
+ rValue.Value >>= bSinglePageSheets;
+ }
+ else if ( rValue.Name == "EvenOdd" )
+ {
+ rValue.Value >>= nEOContent;
+ }
+ }
+
+ if (bSinglePageSheets)
+ {
+ return pDocShell->GetDocument().GetTableCount();
+ }
+
+ bool bIsPrintEvenPages = (nEOContent != 1 && nContent == 0) || nContent != 0;
+ bool bIsPrintOddPages = (nEOContent != 2 && nContent == 0) || nContent != 0;
+
+ for ( sal_Int32 nPage = 1; nPage <= nPages; nPage++ )
+ {
+ if ( (bIsPrintEvenPages && IsOnEvenPage( nPage )) || (bIsPrintOddPages && !IsOnEvenPage( nPage )) )
+ maValidPages.push_back( nPage );
+ }
+
+ sal_Int32 nSelectCount = static_cast<sal_Int32>( maValidPages.size() );
+
+ if ( nEOContent == 1 || nEOContent == 2 ) // even pages / odd pages
+ return nSelectCount;
+
+ if ( !aPagesStr.isEmpty() )
+ {
+ StringRangeEnumerator aRangeEnum( aPagesStr, 0, nPages-1 );
+ nSelectCount = aRangeEnum.size();
+ }
+ return (nSelectCount > 0) ? nSelectCount : 1;
+}
+
+static sal_Int32 lcl_GetRendererNum( sal_Int32 nSelRenderer, std::u16string_view rPagesStr, sal_Int32 nTotalPages )
+{
+ if ( rPagesStr.empty() )
+ return nSelRenderer;
+
+ StringRangeEnumerator aRangeEnum( rPagesStr, 0, nTotalPages-1 );
+ StringRangeEnumerator::Iterator aIter = aRangeEnum.begin();
+ StringRangeEnumerator::Iterator aEnd = aRangeEnum.end();
+ for ( ; nSelRenderer > 0 && aIter != aEnd; --nSelRenderer )
+ ++aIter;
+
+ return *aIter; // returns -1 if reached the end
+}
+
+static bool lcl_renderSelectionToGraphic( bool bRenderToGraphic, const ScPrintSelectionStatus& rStatus )
+{
+ return bRenderToGraphic && rStatus.GetMode() == ScPrintSelectionMode::Range;
+}
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScModelObj::getRenderer( sal_Int32 nSelRenderer,
+ const uno::Any& aSelection, const uno::Sequence<beans::PropertyValue>& rOptions )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ {
+ throw lang::DisposedException( OUString(),
+ static_cast< sheet::XSpreadsheetDocument* >(this) );
+ }
+
+ ScMarkData aMark(pDocShell->GetDocument().GetSheetLimits());
+ ScPrintSelectionStatus aStatus;
+ OUString aPagesStr;
+ // #i115266# if FillRenderMarkData fails, keep nTotalPages at 0, but still handle getRenderer(0) below
+ tools::Long nTotalPages = 0;
+ bool bRenderToGraphic = false;
+ bool bSinglePageSheets = false;
+ if ( FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr, bRenderToGraphic ) )
+ {
+ if ( !pPrintFuncCache || !pPrintFuncCache->IsSameSelection( aStatus ) )
+ {
+ pPrintFuncCache.reset(new ScPrintFuncCache( pDocShell, aMark, aStatus ));
+ }
+ nTotalPages = pPrintFuncCache->GetPageCount();
+ }
+
+ for ( const auto& rValue : rOptions)
+ {
+ if ( rValue.Name == "SinglePageSheets" )
+ {
+ rValue.Value >>= bSinglePageSheets;
+ break;
+ }
+ }
+
+ if (bSinglePageSheets)
+ nTotalPages = pDocShell->GetDocument().GetTableCount();
+
+ sal_Int32 nRenderer = lcl_GetRendererNum( nSelRenderer, aPagesStr, nTotalPages );
+
+ if ( nRenderer < 0 )
+ {
+ if ( nSelRenderer != 0 )
+ throw lang::IllegalArgumentException();
+
+ // getRenderer(0) is used to query the settings, so it must always return something
+
+ awt::Size aPageSize;
+ if (lcl_renderSelectionToGraphic( bRenderToGraphic, aStatus))
+ {
+ assert( aMark.IsMarked());
+ const ScRange& aRange = aMark.GetMarkArea();
+ tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
+ aPageSize.Width = aMMRect.GetWidth();
+ aPageSize.Height = aMMRect.GetHeight();
+ }
+ else
+ {
+ SCTAB const nCurTab = 0; //! use current sheet from view?
+ ScPrintFunc aDefaultFunc( pDocShell, pDocShell->GetPrinter(), nCurTab );
+ Size aTwips = aDefaultFunc.GetPageSize();
+ aPageSize.Width = convertTwipToMm100(aTwips.Width());
+ aPageSize.Height = convertTwipToMm100(aTwips.Height());
+ }
+
+ uno::Sequence<beans::PropertyValue> aSequence( comphelper::InitPropertySequence({
+ { SC_UNONAME_PAGESIZE, uno::Any(aPageSize) }
+ }));
+
+ if( ! pPrinterOptions )
+ pPrinterOptions.reset(new ScPrintUIOptions);
+ else
+ pPrinterOptions->SetDefaults();
+ pPrinterOptions->appendPrintUIOptions( aSequence );
+ return aSequence;
+
+ }
+
+ // printer is used as device (just for page layout), draw view is not needed
+
+ SCTAB nTab;
+ if (bSinglePageSheets)
+ nTab = nSelRenderer;
+ else if ( !maValidPages.empty() )
+ nTab = pPrintFuncCache->GetTabForPage( maValidPages.at( nRenderer )-1 );
+ else
+ nTab = pPrintFuncCache->GetTabForPage( nRenderer );
+
+
+ ScRange aRange;
+ const ScRange* pSelRange = nullptr;
+ if ( bSinglePageSheets )
+ {
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ const ScDocument* pDocument = &pDocShell->GetDocument();
+ pDocument->GetDataStart( nTab, nStartCol, nStartRow );
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ pDocument->GetPrintArea( nTab, nEndCol, nEndRow );
+
+ aRange.aStart = ScAddress(nStartCol, nStartRow, nTab);
+ aRange.aEnd = ScAddress(nEndCol, nEndRow, nTab);
+
+ table::CellRangeAddress aRangeAddress( nTab,
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row() );
+ tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
+
+ const awt::Size aPageSize(aMMRect.GetWidth(), aMMRect.GetHeight());
+ const awt::Point aCalcPagePos(aMMRect.Left(), aMMRect.Top());
+
+ uno::Sequence<beans::PropertyValue> aSequence
+ {
+ comphelper::makePropertyValue(SC_UNONAME_PAGESIZE, aPageSize),
+ // #i111158# all positions are relative to the whole page, including non-printable area
+ comphelper::makePropertyValue(SC_UNONAME_INC_NP_AREA, true),
+ comphelper::makePropertyValue(SC_UNONAME_SOURCERANGE, aRangeAddress),
+ comphelper::makePropertyValue(SC_UNONAME_CALCPAGESIZE, aPageSize), // TODO aPageSize too ?
+ comphelper::makePropertyValue(SC_UNONAME_CALCPAGEPOS, aCalcPagePos)
+ };
+
+ if( ! pPrinterOptions )
+ pPrinterOptions.reset(new ScPrintUIOptions);
+ else
+ pPrinterOptions->SetDefaults();
+ pPrinterOptions->appendPrintUIOptions( aSequence );
+ return aSequence;
+ }
+ else if ( aMark.IsMarked() )
+ {
+ aRange = aMark.GetMarkArea();
+ pSelRange = &aRange;
+ }
+
+ awt::Size aPageSize;
+ bool bWasCellRange = false;
+ ScRange aCellRange;
+ if (lcl_renderSelectionToGraphic( bRenderToGraphic, aStatus))
+ {
+ bWasCellRange = true;
+ aCellRange = aRange;
+ tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
+ aPageSize.Width = aMMRect.GetWidth();
+ aPageSize.Height = aMMRect.GetHeight();
+ }
+ else
+ {
+ std::unique_ptr<ScPrintFunc, o3tl::default_delete<ScPrintFunc>> pPrintFunc;
+ if (m_pPrintState && m_pPrintState->nPrintTab == nTab)
+ pPrintFunc.reset(new ScPrintFunc(pDocShell, pDocShell->GetPrinter(), *m_pPrintState, &aStatus.GetOptions()));
+ else
+ pPrintFunc.reset(new ScPrintFunc(pDocShell, pDocShell->GetPrinter(), nTab,
+ pPrintFuncCache->GetFirstAttr(nTab), nTotalPages, pSelRange, &aStatus.GetOptions()));
+ pPrintFunc->SetRenderFlag( true );
+
+ sal_Int32 nContent = 0;
+ sal_Int32 nEOContent = 0;
+ for ( const auto& rValue : rOptions)
+ {
+ if ( rValue.Name == "PrintRange" )
+ {
+ rValue.Value >>= nContent;
+ }
+ else if ( rValue.Name == "EvenOdd" )
+ {
+ rValue.Value >>= nEOContent;
+ }
+ }
+
+ MultiSelection aPage;
+ aPage.SetTotalRange( Range(0,RANGE_MAX) );
+
+ bool bOddOrEven = (nContent == 0 && nEOContent == 1) || (nContent == 1 && nEOContent == 2); // even pages or odd pages
+ // tdf#127682 when odd/even allow nRenderer of 0 even when maValidPages is empty
+ // to allow PrinterController::abortJob to spool an empty page as part of
+ // its abort procedure
+ if (bOddOrEven && !maValidPages.empty())
+ aPage.Select( maValidPages.at(nRenderer) );
+ else
+ aPage.Select( nRenderer+1 );
+
+ tools::Long nDisplayStart = pPrintFuncCache->GetDisplayStart( nTab );
+ tools::Long nTabStart = pPrintFuncCache->GetTabStart( nTab );
+
+ (void)pPrintFunc->DoPrint( aPage, nTabStart, nDisplayStart, false, nullptr );
+
+ bWasCellRange = pPrintFunc->GetLastSourceRange( aCellRange );
+ Size aTwips = pPrintFunc->GetPageSize();
+
+ if (!m_pPrintState)
+ {
+ m_pPrintState.reset(new ScPrintState());
+ pPrintFunc->GetPrintState(*m_pPrintState, true);
+ }
+
+ aPageSize.Width = convertTwipToMm100(aTwips.Width());
+ aPageSize.Height = convertTwipToMm100(aTwips.Height());
+ }
+
+ tools::Long nPropCount = bWasCellRange ? 5 : 4;
+ uno::Sequence<beans::PropertyValue> aSequence(nPropCount);
+ beans::PropertyValue* pArray = aSequence.getArray();
+ pArray[0].Name = SC_UNONAME_PAGESIZE;
+ pArray[0].Value <<= aPageSize;
+ // #i111158# all positions are relative to the whole page, including non-printable area
+ pArray[1].Name = SC_UNONAME_INC_NP_AREA;
+ pArray[1].Value <<= true;
+ if ( bWasCellRange )
+ {
+ table::CellRangeAddress aRangeAddress( nTab,
+ aCellRange.aStart.Col(), aCellRange.aStart.Row(),
+ aCellRange.aEnd.Col(), aCellRange.aEnd.Row() );
+ tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
+ aCellRange.aStart.Col(), aCellRange.aStart.Row(),
+ aCellRange.aEnd.Col(), aCellRange.aEnd.Row(), aCellRange.aStart.Tab()));
+
+ const awt::Size aCalcPageSize(aMMRect.GetWidth(), aMMRect.GetHeight());
+ const awt::Point aCalcPagePos(aMMRect.Left(), aMMRect.Top());
+
+ pArray[2].Name = SC_UNONAME_SOURCERANGE;
+ pArray[2].Value <<= aRangeAddress;
+ pArray[3].Name = SC_UNONAME_CALCPAGESIZE;
+ pArray[3].Value <<= aCalcPageSize;
+ pArray[4].Name = SC_UNONAME_CALCPAGEPOS;
+ pArray[4].Value <<= aCalcPagePos;
+ }
+
+ if( ! pPrinterOptions )
+ pPrinterOptions.reset(new ScPrintUIOptions);
+ else
+ pPrinterOptions->SetDefaults();
+ pPrinterOptions->appendPrintUIOptions( aSequence );
+ return aSequence;
+}
+
+void SAL_CALL ScModelObj::render( sal_Int32 nSelRenderer, const uno::Any& aSelection,
+ const uno::Sequence<beans::PropertyValue>& rOptions )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ {
+ throw lang::DisposedException( OUString(),
+ static_cast< sheet::XSpreadsheetDocument* >(this) );
+ }
+
+ ScMarkData aMark(pDocShell->GetDocument().GetSheetLimits());
+ ScPrintSelectionStatus aStatus;
+ OUString aPagesStr;
+ bool bRenderToGraphic = false;
+ bool bSinglePageSheets = false;
+ if ( !FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr, bRenderToGraphic ) )
+ throw lang::IllegalArgumentException();
+
+ if ( !pPrintFuncCache || !pPrintFuncCache->IsSameSelection( aStatus ) )
+ {
+ pPrintFuncCache.reset(new ScPrintFuncCache( pDocShell, aMark, aStatus ));
+ }
+ tools::Long nTotalPages = pPrintFuncCache->GetPageCount();
+
+ for ( const auto& rValue : rOptions)
+ {
+ if ( rValue.Name == "SinglePageSheets" )
+ {
+ rValue.Value >>= bSinglePageSheets;
+ break;
+ }
+ }
+
+ if (bSinglePageSheets)
+ nTotalPages = pDocShell->GetDocument().GetTableCount();
+
+ sal_Int32 nRenderer = lcl_GetRendererNum( nSelRenderer, aPagesStr, nTotalPages );
+ if ( nRenderer < 0 )
+ throw lang::IllegalArgumentException();
+
+ OutputDevice* pDev = lcl_GetRenderDevice( rOptions );
+ if ( !pDev )
+ throw lang::IllegalArgumentException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScRange aRange;
+ const ScRange* pSelRange = nullptr;
+ if ( bSinglePageSheets )
+ {
+ awt::Size aPageSize;
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ rDoc.GetDataStart( nSelRenderer, nStartCol, nStartRow );
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ rDoc.GetPrintArea( nSelRenderer, nEndCol, nEndRow );
+
+ aRange.aStart = ScAddress(nStartCol, nStartRow, nSelRenderer);
+ aRange.aEnd = ScAddress(nEndCol, nEndRow, nSelRenderer);
+
+ tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
+
+ aPageSize.Width = aMMRect.GetWidth();
+ aPageSize.Height = aMMRect.GetHeight();
+
+ //Set visible tab
+ SCTAB nVisTab = rDoc.GetVisibleTab();
+ if (nVisTab != nSelRenderer)
+ {
+ nVisTab = nSelRenderer;
+ rDoc.SetVisibleTab(nVisTab);
+ }
+
+ pDocShell->DoDraw(pDev, Point(0,0), Size(aPageSize.Width, aPageSize.Height), JobSetup());
+
+ return;
+ }
+ else if ( aMark.IsMarked() )
+ {
+ aRange = aMark.GetMarkArea();
+ pSelRange = &aRange;
+ }
+
+ if (lcl_renderSelectionToGraphic( bRenderToGraphic, aStatus))
+ {
+ // Similar to as in and when calling ScTransferObj::PaintToDev()
+
+ tools::Rectangle aBound( Point(), pDev->GetOutputSize());
+
+ ScViewData aViewData(rDoc);
+
+ aViewData.SetTabNo( aRange.aStart.Tab() );
+ aViewData.SetScreen( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() );
+
+ const double nPrintFactor = 1.0; /* XXX: currently (2017-08-28) is not evaluated */
+ // The bMetaFile argument maybe could be
+ // pDev->GetConnectMetaFile() != nullptr
+ // but for some yet unknown reason does not draw cell content if true.
+ ScPrintFunc::DrawToDev( rDoc, pDev, nPrintFactor, aBound, &aViewData, false /*bMetaFile*/ );
+
+ return;
+ }
+
+ struct DrawViewKeeper
+ {
+ std::unique_ptr<FmFormView> mpDrawView;
+ DrawViewKeeper() {}
+ ~DrawViewKeeper()
+ {
+ if (mpDrawView)
+ {
+ mpDrawView->HideSdrPage();
+ mpDrawView.reset();
+ }
+ }
+ } aDrawViewKeeper;
+
+ SCTAB nTab;
+ if ( !maValidPages.empty() )
+ nTab = pPrintFuncCache->GetTabForPage( maValidPages.at( nRenderer )-1 );
+ else
+ nTab = pPrintFuncCache->GetTabForPage( nRenderer );
+
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+
+ if( pModel )
+ {
+ aDrawViewKeeper.mpDrawView.reset( new FmFormView(
+ *pModel,
+ pDev) );
+ aDrawViewKeeper.mpDrawView->ShowSdrPage(aDrawViewKeeper.mpDrawView->GetModel().GetPage(nTab));
+ aDrawViewKeeper.mpDrawView->SetPrintPreview();
+ }
+
+ // to increase performance, ScPrintState might be used here for subsequent
+ // pages of the same sheet
+
+
+ std::unique_ptr<ScPrintFunc, o3tl::default_delete<ScPrintFunc>> pPrintFunc;
+ if (m_pPrintState && m_pPrintState->nPrintTab == nTab
+ && ! pSelRange) // tdf#120161 use selection to set required printed area
+ pPrintFunc.reset(new ScPrintFunc(pDev, pDocShell, *m_pPrintState, &aStatus.GetOptions()));
+ else
+ pPrintFunc.reset(new ScPrintFunc(pDev, pDocShell, nTab, pPrintFuncCache->GetFirstAttr(nTab), nTotalPages, pSelRange, &aStatus.GetOptions()));
+
+ pPrintFunc->SetDrawView( aDrawViewKeeper.mpDrawView.get() );
+ pPrintFunc->SetRenderFlag( true );
+ if( aStatus.GetMode() == ScPrintSelectionMode::RangeExclusivelyOleAndDrawObjects )
+ pPrintFunc->SetExclusivelyDrawOleAndDrawObjects();
+
+ sal_Int32 nContent = 0;
+ sal_Int32 nEOContent = 0;
+ for ( const auto& rValue : rOptions)
+ {
+ if ( rValue.Name == "PrintRange" )
+ {
+ rValue.Value >>= nContent;
+ }
+ else if ( rValue.Name == "EvenOdd" )
+ {
+ rValue.Value >>= nEOContent;
+ }
+ }
+
+ MultiSelection aPage;
+ aPage.SetTotalRange( Range(0,RANGE_MAX) );
+
+ bool bOddOrEven = (nContent == 0 && nEOContent == 1) || (nContent == 0 && nEOContent == 2); // even pages or odd pages
+ // tdf#127682 when odd/even allow nRenderer of 0 even when maValidPages is empty
+ // to allow PrinterController::abortJob to spool an empty page as part of
+ // its abort procedure
+ if (bOddOrEven && !maValidPages.empty())
+ aPage.Select( maValidPages.at( nRenderer ) );
+ else
+ aPage.Select( nRenderer+1 );
+
+ tools::Long nDisplayStart = pPrintFuncCache->GetDisplayStart( nTab );
+ tools::Long nTabStart = pPrintFuncCache->GetTabStart( nTab );
+
+ vcl::PDFExtOutDevData* pPDFData = dynamic_cast< vcl::PDFExtOutDevData* >(pDev->GetExtOutDevData() );
+ if ( nRenderer == nTabStart )
+ {
+ if (pPDFData)
+ {
+ css::lang::Locale const docLocale(Application::GetSettings().GetLanguageTag().getLocale());
+ pPDFData->SetDocumentLocale(docLocale);
+ }
+
+ // first page of a sheet: add outline item for the sheet name
+
+ if ( pPDFData && pPDFData->GetIsExportBookmarks() )
+ {
+ // the sheet starts at the top of the page
+ tools::Rectangle aArea( pDev->PixelToLogic( tools::Rectangle( 0,0,0,0 ) ) );
+ sal_Int32 nDestID = pPDFData->CreateDest( aArea );
+ OUString aTabName;
+ rDoc.GetName( nTab, aTabName );
+ // top-level
+ pPDFData->CreateOutlineItem( -1/*nParent*/, aTabName, nDestID );
+ }
+ // #i56629# add the named destination stuff
+ if( pPDFData && pPDFData->GetIsExportNamedDestinations() )
+ {
+ tools::Rectangle aArea( pDev->PixelToLogic( tools::Rectangle( 0,0,0,0 ) ) );
+ OUString aTabName;
+ rDoc.GetName( nTab, aTabName );
+ //need the PDF page number here
+ pPDFData->CreateNamedDest( aTabName, aArea );
+ }
+ }
+
+ (void)pPrintFunc->DoPrint( aPage, nTabStart, nDisplayStart, true, nullptr );
+
+ if (!m_pPrintState)
+ {
+ m_pPrintState.reset(new ScPrintState());
+ pPrintFunc->GetPrintState(*m_pPrintState, true);
+ }
+
+ // resolve the hyperlinks for PDF export
+
+ if ( !pPDFData || pPDFData->GetBookmarks().empty() )
+ return;
+
+ // iterate over the hyperlinks that were output for this page
+
+ std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFData->GetBookmarks();
+ for ( const auto& rBookmark : rBookmarks )
+ {
+ OUString aBookmark = rBookmark.aBookmark;
+ if ( aBookmark.toChar() == '#' )
+ {
+ // try to resolve internal link
+
+ OUString aTarget( aBookmark.copy( 1 ) );
+
+ ScRange aTargetRange;
+ tools::Rectangle aTargetRect; // 1/100th mm
+ bool bIsSheet = false;
+ bool bValid = lcl_ParseTarget( aTarget, aTargetRange, aTargetRect, bIsSheet, rDoc, nTab );
+
+ if ( bValid )
+ {
+ sal_Int32 nPage = -1;
+ tools::Rectangle aArea;
+ if ( bIsSheet )
+ {
+ // Get first page for sheet (if nothing from that sheet is printed,
+ // this page can show a different sheet)
+ nPage = pPrintFuncCache->GetTabStart( aTargetRange.aStart.Tab() );
+ aArea = pDev->PixelToLogic( tools::Rectangle( 0,0,0,0 ) );
+ }
+ else
+ {
+ pPrintFuncCache->InitLocations( aMark, pDev ); // does nothing if already initialized
+
+ ScPrintPageLocation aLocation;
+ if ( pPrintFuncCache->FindLocation( aTargetRange.aStart, aLocation ) )
+ {
+ nPage = aLocation.nPage;
+
+ // get the rectangle of the page's cell range in 1/100th mm
+ ScRange aLocRange = aLocation.aCellRange;
+ tools::Rectangle aLocationMM = rDoc.GetMMRect(
+ aLocRange.aStart.Col(), aLocRange.aStart.Row(),
+ aLocRange.aEnd.Col(), aLocRange.aEnd.Row(),
+ aLocRange.aStart.Tab() );
+ tools::Rectangle aLocationPixel = aLocation.aRectangle;
+
+ // Scale and move the target rectangle from aLocationMM to aLocationPixel,
+ // to get the target rectangle in pixels.
+ assert(aLocationPixel.GetWidth() != 0 && aLocationPixel.GetHeight() != 0);
+
+ Fraction aScaleX( aLocationPixel.GetWidth(), aLocationMM.GetWidth() );
+ Fraction aScaleY( aLocationPixel.GetHeight(), aLocationMM.GetHeight() );
+
+ tools::Long nX1 = aLocationPixel.Left() + static_cast<tools::Long>( Fraction( aTargetRect.Left() - aLocationMM.Left(), 1 ) * aScaleX );
+ tools::Long nX2 = aLocationPixel.Left() + static_cast<tools::Long>( Fraction( aTargetRect.Right() - aLocationMM.Left(), 1 ) * aScaleX );
+ tools::Long nY1 = aLocationPixel.Top() + static_cast<tools::Long>( Fraction( aTargetRect.Top() - aLocationMM.Top(), 1 ) * aScaleY );
+ tools::Long nY2 = aLocationPixel.Top() + static_cast<tools::Long>( Fraction( aTargetRect.Bottom() - aLocationMM.Top(), 1 ) * aScaleY );
+
+ if ( nX1 > aLocationPixel.Right() ) nX1 = aLocationPixel.Right();
+ if ( nX2 > aLocationPixel.Right() ) nX2 = aLocationPixel.Right();
+ if ( nY1 > aLocationPixel.Bottom() ) nY1 = aLocationPixel.Bottom();
+ if ( nY2 > aLocationPixel.Bottom() ) nY2 = aLocationPixel.Bottom();
+
+ // The link target area is interpreted using the device's MapMode at
+ // the time of the CreateDest call, so PixelToLogic can be used here,
+ // regardless of the MapMode that is actually selected.
+ aArea = pDev->PixelToLogic( tools::Rectangle( nX1, nY1, nX2, nY2 ) );
+ }
+ }
+
+ if ( nPage >= 0 )
+ pPDFData->SetLinkDest( rBookmark.nLinkId, pPDFData->CreateDest( aArea, nPage ) );
+ }
+ }
+ else
+ {
+ // external link, use as-is
+ pPDFData->SetLinkURL( rBookmark.nLinkId, aBookmark );
+ }
+ }
+ rBookmarks.clear();
+}
+
+// XLinkTargetSupplier
+
+uno::Reference<container::XNameAccess> SAL_CALL ScModelObj::getLinks()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScLinkTargetTypesObj(pDocShell);
+ return nullptr;
+}
+
+// XActionLockable
+
+sal_Bool SAL_CALL ScModelObj::isActionLocked()
+{
+ SolarMutexGuard aGuard;
+ bool bLocked = false;
+ if (pDocShell)
+ bLocked = ( pDocShell->GetLockCount() != 0 );
+ return bLocked;
+}
+
+void SAL_CALL ScModelObj::addActionLock()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ pDocShell->LockDocument();
+}
+
+void SAL_CALL ScModelObj::removeActionLock()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ pDocShell->UnlockDocument();
+}
+
+void SAL_CALL ScModelObj::setActionLocks( sal_Int16 nLock )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ pDocShell->SetLockCount(nLock);
+}
+
+sal_Int16 SAL_CALL ScModelObj::resetActionLocks()
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nRet = 0;
+ if (pDocShell)
+ {
+ nRet = pDocShell->GetLockCount();
+ pDocShell->SetLockCount(0);
+ }
+ return nRet;
+}
+
+void SAL_CALL ScModelObj::lockControllers()
+{
+ SolarMutexGuard aGuard;
+ SfxBaseModel::lockControllers();
+ if (pDocShell)
+ pDocShell->LockPaint();
+}
+
+void SAL_CALL ScModelObj::unlockControllers()
+{
+ SolarMutexGuard aGuard;
+ if (hasControllersLocked())
+ {
+ SfxBaseModel::unlockControllers();
+ if (pDocShell)
+ pDocShell->UnlockPaint();
+ }
+}
+
+// XCalculate
+
+void SAL_CALL ScModelObj::calculate()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ comphelper::ProfileZone aZone("calculate");
+ pDocShell->DoRecalc(true);
+ }
+ else
+ {
+ OSL_FAIL("no DocShell"); //! throw exception?
+ }
+}
+
+void SAL_CALL ScModelObj::calculateAll()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ comphelper::ProfileZone aZone("calculateAll");
+ pDocShell->DoHardRecalc();
+ }
+ else
+ {
+ OSL_FAIL("no DocShell"); //! throw exception?
+ }
+}
+
+sal_Bool SAL_CALL ScModelObj::isAutomaticCalculationEnabled()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return pDocShell->GetDocument().GetAutoCalc();
+
+ OSL_FAIL("no DocShell"); //! throw exception?
+ return false;
+}
+
+void SAL_CALL ScModelObj::enableAutomaticCalculation( sal_Bool bEnabledIn )
+{
+ bool bEnabled(bEnabledIn);
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( rDoc.GetAutoCalc() != bEnabled )
+ {
+ rDoc.SetAutoCalc( bEnabled );
+ pDocShell->SetDocumentModified();
+ }
+ }
+ else
+ {
+ OSL_FAIL("no DocShell"); //! throw exception?
+ }
+}
+
+// XProtectable
+
+void SAL_CALL ScModelObj::protect( const OUString& aPassword )
+{
+ SolarMutexGuard aGuard;
+ // #i108245# if already protected, don't change anything
+ if ( pDocShell && !pDocShell->GetDocument().IsDocProtected() )
+ {
+ pDocShell->GetDocFunc().Protect( TABLEID_DOC, aPassword );
+ }
+}
+
+void SAL_CALL ScModelObj::unprotect( const OUString& aPassword )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ bool bDone = pDocShell->GetDocFunc().Unprotect( TABLEID_DOC, aPassword, true );
+ if (!bDone)
+ throw lang::IllegalArgumentException();
+ }
+}
+
+sal_Bool SAL_CALL ScModelObj::isProtected()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return pDocShell->GetDocument().IsDocProtected();
+
+ OSL_FAIL("no DocShell"); //! throw exception?
+ return false;
+}
+
+// XDrawPagesSupplier
+
+uno::Reference<drawing::XDrawPages> SAL_CALL ScModelObj::getDrawPages()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScDrawPagesObj(pDocShell);
+
+ OSL_FAIL("no DocShell"); //! throw exception?
+ return nullptr;
+}
+
+// XGoalSeek
+
+sheet::GoalResult SAL_CALL ScModelObj::seekGoal(
+ const table::CellAddress& aFormulaPosition,
+ const table::CellAddress& aVariablePosition,
+ const OUString& aGoalValue )
+{
+ SolarMutexGuard aGuard;
+ sheet::GoalResult aResult;
+ aResult.Divergence = DBL_MAX; // not found
+ if (pDocShell)
+ {
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+ ScDocument& rDoc = pDocShell->GetDocument();
+ double fValue = 0.0;
+ bool bFound = rDoc.Solver(
+ static_cast<SCCOL>(aFormulaPosition.Column), static_cast<SCROW>(aFormulaPosition.Row), aFormulaPosition.Sheet,
+ static_cast<SCCOL>(aVariablePosition.Column), static_cast<SCROW>(aVariablePosition.Row), aVariablePosition.Sheet,
+ aGoalValue, fValue );
+ aResult.Result = fValue;
+ if (bFound)
+ aResult.Divergence = 0.0; //! this is a lie
+ }
+ return aResult;
+}
+
+// XConsolidatable
+
+uno::Reference<sheet::XConsolidationDescriptor> SAL_CALL ScModelObj::createConsolidationDescriptor(
+ sal_Bool bEmpty )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<ScConsolidationDescriptor> pNew = new ScConsolidationDescriptor;
+ if ( pDocShell && !bEmpty )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScConsolidateParam* pParam = rDoc.GetConsolidateDlgData();
+ if (pParam)
+ pNew->SetParam( *pParam );
+ }
+ return pNew;
+}
+
+void SAL_CALL ScModelObj::consolidate(
+ const uno::Reference<sheet::XConsolidationDescriptor>& xDescriptor )
+{
+ SolarMutexGuard aGuard;
+ // in theory, this could also be a different object, so use only
+ // public XConsolidationDescriptor interface to copy the data into
+ // ScConsolidationDescriptor object
+ //! but if this already is ScConsolidationDescriptor, do it directly via getImplementation?
+
+ rtl::Reference< ScConsolidationDescriptor > xImpl(new ScConsolidationDescriptor);
+ xImpl->setFunction( xDescriptor->getFunction() );
+ xImpl->setSources( xDescriptor->getSources() );
+ xImpl->setStartOutputPosition( xDescriptor->getStartOutputPosition() );
+ xImpl->setUseColumnHeaders( xDescriptor->getUseColumnHeaders() );
+ xImpl->setUseRowHeaders( xDescriptor->getUseRowHeaders() );
+ xImpl->setInsertLinks( xDescriptor->getInsertLinks() );
+
+ if (pDocShell)
+ {
+ const ScConsolidateParam& rParam = xImpl->GetParam();
+ pDocShell->DoConsolidate( rParam );
+ pDocShell->GetDocument().SetConsolidateDlgData( std::unique_ptr<ScConsolidateParam>(new ScConsolidateParam(rParam)) );
+ }
+}
+
+// XDocumentAuditing
+
+void SAL_CALL ScModelObj::refreshArrows()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ pDocShell->GetDocFunc().DetectiveRefresh();
+}
+
+// XViewDataSupplier
+uno::Reference< container::XIndexAccess > SAL_CALL ScModelObj::getViewData( )
+{
+ uno::Reference < container::XIndexAccess > xRet( SfxBaseModel::getViewData() );
+
+ if( !xRet.is() )
+ {
+ SolarMutexGuard aGuard;
+ if (pDocShell && pDocShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED)
+ {
+ rtl::Reference< comphelper::IndexedPropertyValuesContainer > xCont = new comphelper::IndexedPropertyValuesContainer();
+ xRet = xCont;
+
+ OUString sName;
+ pDocShell->GetDocument().GetName( pDocShell->GetDocument().GetVisibleTab(), sName );
+ SCCOL nPosLeft = pDocShell->GetDocument().GetPosLeft();
+ SCROW nPosTop = pDocShell->GetDocument().GetPosTop();
+ uno::Sequence< beans::PropertyValue > aSeq{
+ comphelper::makePropertyValue(SC_ACTIVETABLE, sName),
+ comphelper::makePropertyValue(SC_POSITIONLEFT, nPosLeft),
+ comphelper::makePropertyValue(SC_POSITIONTOP, nPosTop)
+ };
+ xCont->insertByIndex( 0, uno::Any( aSeq ) );
+ }
+ }
+
+ return xRet;
+}
+
+// XPropertySet (Doc-Options)
+//! provide them also to the application?
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScModelObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScModelObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScDocOptions& rOldOpt = rDoc.GetDocOptions();
+ ScDocOptions aNewOpt = rOldOpt;
+ // Don't recalculate while loading XML, when the formula text is stored
+ // Recalculation after loading is handled separately.
+ bool bHardRecalc = !rDoc.IsImportingXML();
+
+ bool bOpt = ScDocOptionsHelper::setPropertyValue( aNewOpt, aPropSet.getPropertyMap(), aPropertyName, aValue );
+ if (bOpt)
+ {
+ // done...
+ if ( aPropertyName == SC_UNO_IGNORECASE ||
+ aPropertyName == SC_UNONAME_REGEXP ||
+ aPropertyName == SC_UNONAME_WILDCARDS ||
+ aPropertyName == SC_UNO_LOOKUPLABELS )
+ bHardRecalc = false;
+ }
+ else if ( aPropertyName == SC_UNONAME_CLOCAL )
+ {
+ lang::Locale aLocale;
+ if ( aValue >>= aLocale )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+ eLatin = ScUnoConversion::GetLanguage(aLocale);
+ rDoc.SetLanguage( eLatin, eCjk, eCtl );
+ }
+ }
+ else if ( aPropertyName == SC_UNO_CODENAME )
+ {
+ OUString sCodeName;
+ if ( aValue >>= sCodeName )
+ rDoc.SetCodeName( sCodeName );
+ }
+ else if ( aPropertyName == SC_UNO_CJK_CLOCAL )
+ {
+ lang::Locale aLocale;
+ if ( aValue >>= aLocale )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+ eCjk = ScUnoConversion::GetLanguage(aLocale);
+ rDoc.SetLanguage( eLatin, eCjk, eCtl );
+ }
+ }
+ else if ( aPropertyName == SC_UNO_CTL_CLOCAL )
+ {
+ lang::Locale aLocale;
+ if ( aValue >>= aLocale )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+ eCtl = ScUnoConversion::GetLanguage(aLocale);
+ rDoc.SetLanguage( eLatin, eCjk, eCtl );
+ }
+ }
+ else if ( aPropertyName == SC_UNO_APPLYFMDES )
+ {
+ // model is created if not there
+ ScDrawLayer* pModel = pDocShell->MakeDrawLayer();
+ pModel->SetOpenInDesignMode( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+
+ SfxBindings* pBindings = pDocShell->GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_FM_OPEN_READONLY );
+ }
+ else if ( aPropertyName == SC_UNO_AUTOCONTFOC )
+ {
+ // model is created if not there
+ ScDrawLayer* pModel = pDocShell->MakeDrawLayer();
+ pModel->SetAutoControlFocus( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+
+ SfxBindings* pBindings = pDocShell->GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_FM_AUTOCONTROLFOCUS );
+ }
+ else if ( aPropertyName == SC_UNO_ISLOADED )
+ {
+ pDocShell->SetEmpty( !ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ }
+ else if ( aPropertyName == SC_UNO_ISUNDOENABLED )
+ {
+ bool bUndoEnabled = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ rDoc.EnableUndo( bUndoEnabled );
+ pDocShell->GetUndoManager()->SetMaxUndoActionCount(
+ bUndoEnabled
+ ? officecfg::Office::Common::Undo::Steps::get() : 0);
+ }
+ else if ( aPropertyName == SC_UNO_RECORDCHANGES )
+ {
+ bool bRecordChangesEnabled = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+
+ bool bChangeAllowed = true;
+ if (!bRecordChangesEnabled)
+ bChangeAllowed = !pDocShell->HasChangeRecordProtection();
+
+ if (bChangeAllowed)
+ pDocShell->SetChangeRecording(bRecordChangesEnabled);
+ }
+ else if ( aPropertyName == SC_UNO_ISADJUSTHEIGHTENABLED )
+ {
+ if( ScUnoHelpFunctions::GetBoolFromAny( aValue ) )
+ rDoc.UnlockAdjustHeight();
+ else
+ rDoc.LockAdjustHeight();
+ }
+ else if ( aPropertyName == SC_UNO_ISEXECUTELINKENABLED )
+ {
+ rDoc.EnableExecuteLink( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ }
+ else if ( aPropertyName == SC_UNO_ISCHANGEREADONLYENABLED )
+ {
+ rDoc.EnableChangeReadOnly( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ }
+ else if ( aPropertyName == "BuildId" )
+ {
+ aValue >>= maBuildId;
+ }
+ else if ( aPropertyName == "SavedObject" ) // set from chart after saving
+ {
+ OUString aObjName;
+ aValue >>= aObjName;
+ if ( !aObjName.isEmpty() )
+ rDoc.RestoreChartListener( aObjName );
+ }
+ else if ( aPropertyName == SC_UNO_INTEROPGRABBAG )
+ {
+ setGrabBagItem(aValue);
+ }
+ else if (aPropertyName == SC_UNO_THEME)
+ {
+ SdrModel& rSdrModel = getSdrModelFromUnoModel();
+ uno::Reference<util::XTheme> xTheme;
+ if (aValue >>= xTheme)
+ {
+ auto& rUnoTheme = dynamic_cast<UnoTheme&>(*xTheme);
+ rSdrModel.setTheme(rUnoTheme.getTheme());
+ }
+ }
+
+ if ( aNewOpt != rOldOpt )
+ {
+ rDoc.SetDocOptions( aNewOpt );
+ //! Recalc only for options that need it?
+ if ( bHardRecalc )
+ pDocShell->DoHardRecalc();
+ pDocShell->SetDocumentModified();
+ }
+}
+
+uno::Any SAL_CALL ScModelObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScDocOptions& rOpt = rDoc.GetDocOptions();
+ aRet = ScDocOptionsHelper::getPropertyValue( rOpt, aPropSet.getPropertyMap(), aPropertyName );
+ if ( aRet.hasValue() )
+ {
+ // done...
+ }
+ else if ( aPropertyName == SC_UNONAME_CLOCAL )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+
+ lang::Locale aLocale;
+ ScUnoConversion::FillLocale( aLocale, eLatin );
+ aRet <<= aLocale;
+ }
+ else if ( aPropertyName == SC_UNO_CODENAME )
+ {
+ aRet <<= rDoc.GetCodeName();
+ }
+
+ else if ( aPropertyName == SC_UNO_CJK_CLOCAL )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+
+ lang::Locale aLocale;
+ ScUnoConversion::FillLocale( aLocale, eCjk );
+ aRet <<= aLocale;
+ }
+ else if ( aPropertyName == SC_UNO_CTL_CLOCAL )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+
+ lang::Locale aLocale;
+ ScUnoConversion::FillLocale( aLocale, eCtl );
+ aRet <<= aLocale;
+ }
+ else if ( aPropertyName == SC_UNO_NAMEDRANGES )
+ {
+ aRet <<= uno::Reference<sheet::XNamedRanges>(new ScGlobalNamedRangesObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_DATABASERNG )
+ {
+ aRet <<= uno::Reference<sheet::XDatabaseRanges>(new ScDatabaseRangesObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_UNNAMEDDBRNG )
+ {
+ aRet <<= uno::Reference<sheet::XUnnamedDatabaseRanges>(new ScUnnamedDatabaseRangesObj(pDocShell));
+ }
+ else if ( aPropertyName == SC_UNO_COLLABELRNG )
+ {
+ aRet <<= uno::Reference<sheet::XLabelRanges>(new ScLabelRangesObj( pDocShell, true ));
+ }
+ else if ( aPropertyName == SC_UNO_ROWLABELRNG )
+ {
+ aRet <<= uno::Reference<sheet::XLabelRanges>(new ScLabelRangesObj( pDocShell, false ));
+ }
+ else if ( aPropertyName == SC_UNO_AREALINKS )
+ {
+ aRet <<= uno::Reference<sheet::XAreaLinks>(new ScAreaLinksObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_DDELINKS )
+ {
+ aRet <<= uno::Reference<container::XNameAccess>(new ScDDELinksObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_EXTERNALDOCLINKS )
+ {
+ aRet <<= uno::Reference<sheet::XExternalDocLinks>(new ScExternalDocLinksObj(pDocShell));
+ }
+ else if ( aPropertyName == SC_UNO_SHEETLINKS )
+ {
+ aRet <<= uno::Reference<container::XNameAccess>(new ScSheetLinksObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_APPLYFMDES )
+ {
+ // default for no model is TRUE
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ bool bOpenInDesign = pModel == nullptr || pModel->GetOpenInDesignMode();
+ aRet <<= bOpenInDesign;
+ }
+ else if ( aPropertyName == SC_UNO_AUTOCONTFOC )
+ {
+ // default for no model is FALSE
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ bool bAutoControlFocus = pModel && pModel->GetAutoControlFocus();
+ aRet <<= bAutoControlFocus;
+ }
+ else if ( aPropertyName == SC_UNO_FORBIDDEN )
+ {
+ aRet <<= uno::Reference<i18n::XForbiddenCharacters>(new ScForbiddenCharsObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_HASDRAWPAGES )
+ {
+ aRet <<= (pDocShell->GetDocument().GetDrawLayer() != nullptr);
+ }
+ else if ( aPropertyName == SC_UNO_BASICLIBRARIES )
+ {
+ aRet <<= pDocShell->GetBasicContainer();
+ }
+ else if ( aPropertyName == SC_UNO_DIALOGLIBRARIES )
+ {
+ aRet <<= pDocShell->GetDialogContainer();
+ }
+ else if ( aPropertyName == SC_UNO_VBAGLOBNAME )
+ {
+ /* #i111553# This property provides the name of the constant that
+ will be used to store this model in the global Basic manager.
+ That constant will be equivalent to 'ThisComponent' but for
+ each application, so e.g. a 'ThisExcelDoc' and a 'ThisWordDoc'
+ constant can co-exist, as required by VBA. */
+ aRet <<= OUString( "ThisExcelDoc" );
+ }
+ else if ( aPropertyName == SC_UNO_RUNTIMEUID )
+ {
+ aRet <<= getRuntimeUID();
+ }
+ else if ( aPropertyName == SC_UNO_HASVALIDSIGNATURES )
+ {
+ aRet <<= hasValidSignatures();
+ }
+ else if ( aPropertyName == SC_UNO_ISLOADED )
+ {
+ aRet <<= !pDocShell->IsEmpty();
+ }
+ else if ( aPropertyName == SC_UNO_ISUNDOENABLED )
+ {
+ aRet <<= rDoc.IsUndoEnabled();
+ }
+ else if ( aPropertyName == SC_UNO_RECORDCHANGES )
+ {
+ aRet <<= pDocShell->IsChangeRecording();
+ }
+ else if ( aPropertyName == SC_UNO_ISRECORDCHANGESPROTECTED )
+ {
+ aRet <<= pDocShell->HasChangeRecordProtection();
+ }
+ else if ( aPropertyName == SC_UNO_ISADJUSTHEIGHTENABLED )
+ {
+ aRet <<= !( rDoc.IsAdjustHeightLocked() );
+ }
+ else if ( aPropertyName == SC_UNO_ISEXECUTELINKENABLED )
+ {
+ aRet <<= rDoc.IsExecuteLinkEnabled();
+ }
+ else if ( aPropertyName == SC_UNO_ISCHANGEREADONLYENABLED )
+ {
+ aRet <<= rDoc.IsChangeReadOnlyEnabled();
+ }
+ else if ( aPropertyName == SC_UNO_REFERENCEDEVICE )
+ {
+ rtl::Reference<VCLXDevice> pXDev = new VCLXDevice();
+ pXDev->SetOutputDevice( rDoc.GetRefDevice() );
+ aRet <<= uno::Reference< awt::XDevice >( pXDev );
+ }
+ else if ( aPropertyName == "BuildId" )
+ {
+ aRet <<= maBuildId;
+ }
+ else if ( aPropertyName == "InternalDocument" )
+ {
+ aRet <<= (pDocShell->GetCreateMode() == SfxObjectCreateMode::INTERNAL);
+ }
+ else if ( aPropertyName == SC_UNO_INTEROPGRABBAG )
+ {
+ getGrabBagItem(aRet);
+ }
+ else if (aPropertyName == SC_UNO_THEME)
+ {
+ SdrModel& rSdrModel = getSdrModelFromUnoModel();
+ css::uno::Reference<css::util::XTheme> xTheme;
+ auto pTheme = rSdrModel.getTheme();
+ if (pTheme)
+ xTheme = model::theme::createXTheme(pTheme);
+ aRet <<= xTheme;
+ }
+ }
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScModelObj )
+
+// XMultiServiceFactory
+
+css::uno::Reference<css::uno::XInterface> ScModelObj::create(
+ OUString const & aServiceSpecifier,
+ css::uno::Sequence<css::uno::Any> const * arguments)
+{
+ using ServiceType = ScServiceProvider::Type;
+
+ uno::Reference<uno::XInterface> xRet;
+ ServiceType nType = ScServiceProvider::GetProviderType(aServiceSpecifier);
+ if ( nType != ServiceType::INVALID )
+ {
+ // drawing layer tables must be kept as long as the model is alive
+ // return stored instance if already set
+ switch ( nType )
+ {
+ case ServiceType::GRADTAB: xRet.set(xDrawGradTab); break;
+ case ServiceType::HATCHTAB: xRet.set(xDrawHatchTab); break;
+ case ServiceType::BITMAPTAB: xRet.set(xDrawBitmapTab); break;
+ case ServiceType::TRGRADTAB: xRet.set(xDrawTrGradTab); break;
+ case ServiceType::MARKERTAB: xRet.set(xDrawMarkerTab); break;
+ case ServiceType::DASHTAB: xRet.set(xDrawDashTab); break;
+ case ServiceType::CHDATAPROV: xRet.set(xChartDataProv); break;
+ case ServiceType::VBAOBJECTPROVIDER: xRet.set(xObjProvider); break;
+ default: break;
+ }
+
+ // #i64497# If a chart is in a temporary document during clipboard paste,
+ // there should be no data provider, so that own data is used
+ bool bCreate =
+ ( nType != ServiceType::CHDATAPROV ||
+ ( pDocShell->GetCreateMode() != SfxObjectCreateMode::INTERNAL ));
+ // this should never happen, i.e. the temporary document should never be
+ // loaded, because this unlinks the data
+ assert(bCreate);
+
+ if ( !xRet.is() && bCreate )
+ {
+ xRet.set(ScServiceProvider::MakeInstance( nType, pDocShell ));
+
+ // store created instance
+ switch ( nType )
+ {
+ case ServiceType::GRADTAB: xDrawGradTab.set(xRet); break;
+ case ServiceType::HATCHTAB: xDrawHatchTab.set(xRet); break;
+ case ServiceType::BITMAPTAB: xDrawBitmapTab.set(xRet); break;
+ case ServiceType::TRGRADTAB: xDrawTrGradTab.set(xRet); break;
+ case ServiceType::MARKERTAB: xDrawMarkerTab.set(xRet); break;
+ case ServiceType::DASHTAB: xDrawDashTab.set(xRet); break;
+ case ServiceType::CHDATAPROV: xChartDataProv.set(xRet); break;
+ case ServiceType::VBAOBJECTPROVIDER: xObjProvider.set(xRet); break;
+ default: break;
+ }
+ }
+ }
+ else
+ {
+ // we offload everything we don't know to SvxFmMSFactory,
+ // it'll throw exception if this isn't okay ...
+
+ try
+ {
+ xRet = arguments == nullptr
+ ? SvxFmMSFactory::createInstance(aServiceSpecifier)
+ : SvxFmMSFactory::createInstanceWithArguments(
+ aServiceSpecifier, *arguments);
+ // extra block to force deletion of the temporary before ScShapeObj ctor (setDelegator)
+ }
+ catch ( lang::ServiceNotRegisteredException & )
+ {
+ }
+
+ // if the drawing factory created a shape, a ScShapeObj has to be used
+ // to support own properties like ImageMap:
+
+ uno::Reference<drawing::XShape> xShape( xRet, uno::UNO_QUERY );
+ if ( xShape.is() )
+ {
+ xRet.clear(); // for aggregation, xShape must be the object's only ref
+ new ScShapeObj( xShape ); // aggregates object and modifies xShape
+ xRet.set(xShape);
+ }
+ }
+ return xRet;
+}
+
+uno::Reference<uno::XInterface> SAL_CALL ScModelObj::createInstance(
+ const OUString& aServiceSpecifier )
+{
+ SolarMutexGuard aGuard;
+ return create(aServiceSpecifier, nullptr);
+}
+
+uno::Reference<uno::XInterface> SAL_CALL ScModelObj::createInstanceWithArguments(
+ const OUString& ServiceSpecifier,
+ const uno::Sequence<uno::Any>& aArgs )
+{
+ //! distinguish between own services and those of drawing layer?
+
+ SolarMutexGuard aGuard;
+ uno::Reference<uno::XInterface> xInt(create(ServiceSpecifier, &aArgs));
+
+ if ( aArgs.hasElements() )
+ {
+ // used only for cell value binding so far - it can be initialized after creating
+
+ uno::Reference<lang::XInitialization> xInit( xInt, uno::UNO_QUERY );
+ if ( xInit.is() )
+ xInit->initialize( aArgs );
+ }
+
+ return xInt;
+}
+
+uno::Sequence<OUString> SAL_CALL ScModelObj::getAvailableServiceNames()
+{
+ SolarMutexGuard aGuard;
+
+ return comphelper::concatSequences( ScServiceProvider::GetAllServiceNames(),
+ SvxFmMSFactory::getAvailableServiceNames() );
+}
+
+// XServiceInfo
+OUString SAL_CALL ScModelObj::getImplementationName()
+{
+ return "ScModelObj";
+ /* // Matching the .component information:
+ return OUString( "com.sun.star.comp.Calc.SpreadsheetDocument" );
+ */
+}
+
+sal_Bool SAL_CALL ScModelObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScModelObj::getSupportedServiceNames()
+{
+ return {SCMODELOBJ_SERVICE, SCDOCSETTINGS_SERVICE, SCDOC_SERVICE};
+}
+
+// XUnoTunnel
+
+sal_Int64 SAL_CALL ScModelObj::getSomething(
+ const uno::Sequence<sal_Int8 >& rId )
+{
+ if ( comphelper::isUnoTunnelId<ScModelObj>(rId) )
+ {
+ return comphelper::getSomething_cast(this);
+ }
+
+ if ( comphelper::isUnoTunnelId<SfxObjectShell>(rId) )
+ {
+ return comphelper::getSomething_cast(pDocShell);
+ }
+
+ // aggregated number formats supplier has XUnoTunnel, too
+ // interface from aggregated object must be obtained via queryAggregation
+
+ sal_Int64 nRet = SfxBaseModel::getSomething( rId );
+ if ( nRet )
+ return nRet;
+
+ if ( GetFormatter().is() )
+ {
+ const uno::Type& rTunnelType = cppu::UnoType<lang::XUnoTunnel>::get();
+ uno::Any aNumTunnel(xNumberAgg->queryAggregation(rTunnelType));
+ if(auto xTunnelAgg = o3tl::tryAccess<uno::Reference<lang::XUnoTunnel>>(
+ aNumTunnel))
+ {
+ return (*xTunnelAgg)->getSomething( rId );
+ }
+ }
+
+ return 0;
+}
+
+const uno::Sequence<sal_Int8>& ScModelObj::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theScModelObjUnoTunnelId;
+ return theScModelObjUnoTunnelId.getSeq();
+}
+
+// XChangesNotifier
+
+void ScModelObj::addChangesListener( const uno::Reference< util::XChangesListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+ maChangesListeners.addInterface( aListener );
+}
+
+void ScModelObj::removeChangesListener( const uno::Reference< util::XChangesListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+ maChangesListeners.removeInterface( aListener );
+}
+
+bool ScModelObj::HasChangesListeners() const
+{
+ if ( maChangesListeners.getLength() > 0 )
+ return true;
+
+ // "change" event set in any sheet?
+ return pDocShell && pDocShell->GetDocument().HasAnySheetEventScript(ScSheetEventId::CHANGE);
+}
+
+namespace
+{
+
+void lcl_dataAreaInvalidation(ScModelObj* pModel,
+ const ScRangeList& rRanges,
+ bool bInvalidateDataArea, bool bExtendDataArea)
+{
+ size_t nRangeCount = rRanges.size();
+
+ for ( size_t nIndex = 0; nIndex < nRangeCount; ++nIndex )
+ {
+ ScRange const & rRange = rRanges[ nIndex ];
+ ScAddress const & rEnd = rRange.aEnd;
+ SCTAB nTab = rEnd.Tab();
+
+ bool bAreaExtended = false;
+
+ if (bExtendDataArea)
+ {
+ const Size aCurrentDataArea = pModel->getDataArea( nTab );
+
+ SCCOL nLastCol = aCurrentDataArea.Width();
+ SCROW nLastRow = aCurrentDataArea.Height();
+
+ bAreaExtended = rEnd.Col() > nLastCol || rEnd.Row() > nLastRow;
+ }
+
+ bool bInvalidate = bAreaExtended || bInvalidateDataArea;
+ if ( bInvalidate )
+ {
+ if ( comphelper::LibreOfficeKit::isActive() )
+ SfxLokHelper::notifyPartSizeChangedAllViews( pModel, nTab );
+ }
+ }
+}
+
+};
+
+void ScModelObj::NotifyChanges( const OUString& rOperation, const ScRangeList& rRanges,
+ const uno::Sequence< beans::PropertyValue >& rProperties )
+{
+ OUString aOperation = rOperation;
+ bool bIsDataAreaInvalidateType = aOperation == "data-area-invalidate";
+ bool bIsDataAreaExtendType = aOperation == "data-area-extend";
+
+ bool bInvalidateDataArea = bIsDataAreaInvalidateType
+ || HelperNotifyChanges::isDataAreaInvalidateType(aOperation);
+ bool bExtendDataArea = bIsDataAreaExtendType || aOperation == "cell-change";
+
+ if ( pDocShell )
+ {
+ lcl_dataAreaInvalidation(this, rRanges, bInvalidateDataArea, bExtendDataArea);
+
+ // check if we were called only to update data area
+ if (bIsDataAreaInvalidateType || bIsDataAreaExtendType)
+ return;
+
+ // backward-compatibility Operation conversion
+ // FIXME: make sure it can be passed
+ if (rOperation == "delete-content" || rOperation == "undo"
+ || rOperation == "redo" || rOperation == "paste")
+ aOperation = "cell-change";
+ }
+
+ if ( pDocShell && HasChangesListeners() )
+ {
+ util::ChangesEvent aEvent;
+ aEvent.Source.set(getXWeak());
+ aEvent.Base <<= aEvent.Source;
+
+ size_t nRangeCount = rRanges.size();
+ aEvent.Changes.realloc( static_cast< sal_Int32 >( nRangeCount ) );
+ auto pChanges = aEvent.Changes.getArray();
+ for ( size_t nIndex = 0; nIndex < nRangeCount; ++nIndex )
+ {
+ uno::Reference< table::XCellRange > xRangeObj;
+
+ ScRange const & rRange = rRanges[ nIndex ];
+ if ( rRange.aStart == rRange.aEnd )
+ {
+ xRangeObj.set( new ScCellObj( pDocShell, rRange.aStart ) );
+ }
+ else
+ {
+ xRangeObj.set( new ScCellRangeObj( pDocShell, rRange ) );
+ }
+
+ util::ElementChange& rChange = pChanges[ static_cast< sal_Int32 >( nIndex ) ];
+ rChange.Accessor <<= aOperation;
+ rChange.Element <<= rProperties;
+ rChange.ReplacedElement <<= xRangeObj;
+ }
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter( maChangesListeners );
+ while ( aIter.hasMoreElements() )
+ {
+ try
+ {
+ aIter.next()->changesOccurred( aEvent );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ }
+
+ // handle sheet events
+ //! separate method with ScMarkData? Then change HasChangesListeners back.
+ if ( !(aOperation == "cell-change" && pDocShell) )
+ return;
+
+ ScMarkData aMarkData(pDocShell->GetDocument().GetSheetLimits());
+ aMarkData.MarkFromRangeList( rRanges, false );
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (const SCTAB& nTab : aMarkData)
+ {
+ if (nTab >= nTabCount)
+ break;
+ const ScSheetEvents* pEvents = rDoc.GetSheetEvents(nTab);
+ if (pEvents)
+ {
+ const OUString* pScript = pEvents->GetScript(ScSheetEventId::CHANGE);
+ if (pScript)
+ {
+ ScRangeList aTabRanges; // collect ranges on this sheet
+ size_t nRangeCount = rRanges.size();
+ for ( size_t nIndex = 0; nIndex < nRangeCount; ++nIndex )
+ {
+ ScRange const & rRange = rRanges[ nIndex ];
+ if ( rRange.aStart.Tab() == nTab )
+ aTabRanges.push_back( rRange );
+ }
+ size_t nTabRangeCount = aTabRanges.size();
+ if ( nTabRangeCount > 0 )
+ {
+ uno::Reference<uno::XInterface> xTarget;
+ if ( nTabRangeCount == 1 )
+ {
+ ScRange const & rRange = aTabRanges[ 0 ];
+ if ( rRange.aStart == rRange.aEnd )
+ xTarget.set( cppu::getXWeak( new ScCellObj( pDocShell, rRange.aStart ) ) );
+ else
+ xTarget.set( cppu::getXWeak( new ScCellRangeObj( pDocShell, rRange ) ) );
+ }
+ else
+ xTarget.set( cppu::getXWeak( new ScCellRangesObj( pDocShell, aTabRanges ) ) );
+
+ uno::Sequence<uno::Any> aParams{ uno::Any(xTarget) };
+
+ uno::Any aRet;
+ uno::Sequence<sal_Int16> aOutArgsIndex;
+ uno::Sequence<uno::Any> aOutArgs;
+
+ /*ErrCode eRet =*/ pDocShell->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
+ }
+ }
+ }
+ }
+}
+
+void ScModelObj::HandleCalculateEvents()
+{
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ // don't call events before the document is visible
+ // (might also set a flag on SfxEventHintId::LoadFinished and only disable while loading)
+ if ( rDoc.IsDocVisible() )
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab = 0; nTab < nTabCount; nTab++)
+ {
+ if (rDoc.HasCalcNotification(nTab))
+ {
+ if (const ScSheetEvents* pEvents = rDoc.GetSheetEvents( nTab ))
+ {
+ if (const OUString* pScript = pEvents->GetScript(ScSheetEventId::CALCULATE))
+ {
+ uno::Any aRet;
+ uno::Sequence<uno::Any> aParams;
+ uno::Sequence<sal_Int16> aOutArgsIndex;
+ uno::Sequence<uno::Any> aOutArgs;
+ pDocShell->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
+ }
+ }
+
+ try
+ {
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( rDoc.GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ uno::Sequence< uno::Any > aArgs{ uno::Any(nTab) };
+ xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( ScSheetEventId::CALCULATE ), aArgs );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ }
+ }
+ rDoc.ResetCalcNotifications();
+}
+
+// XOpenCLSelection
+
+sal_Bool ScModelObj::isOpenCLEnabled()
+{
+ return ScCalcConfig::isOpenCLEnabled();
+}
+
+void ScModelObj::enableOpenCL(sal_Bool bEnable)
+{
+ if (ScCalcConfig::isOpenCLEnabled() == static_cast<bool>(bEnable))
+ return;
+ if (ScCalcConfig::getForceCalculationType() != ForceCalculationNone)
+ return;
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::UseOpenCL::set(bEnable, batch);
+ batch->commit();
+
+ ScCalcConfig aConfig = ScInterpreter::GetGlobalConfig();
+ if (bEnable)
+ aConfig.setOpenCLConfigToDefault();
+ ScInterpreter::SetGlobalConfig(aConfig);
+
+#if HAVE_FEATURE_OPENCL
+ sc::FormulaGroupInterpreter::switchOpenCLDevice(u"", true);
+#endif
+
+ ScDocument* pDoc = GetDocument();
+ pDoc->CheckVectorizationState();
+
+}
+
+void ScModelObj::enableAutomaticDeviceSelection(sal_Bool bForce)
+{
+ ScCalcConfig aConfig = ScInterpreter::GetGlobalConfig();
+ aConfig.mbOpenCLAutoSelect = true;
+ ScInterpreter::SetGlobalConfig(aConfig);
+ ScFormulaOptions aOptions = SC_MOD()->GetFormulaOptions();
+ aOptions.SetCalcConfig(aConfig);
+ SC_MOD()->SetFormulaOptions(aOptions);
+#if !HAVE_FEATURE_OPENCL
+ (void) bForce;
+#else
+ sc::FormulaGroupInterpreter::switchOpenCLDevice(u"", true, bForce);
+#endif
+}
+
+void ScModelObj::disableAutomaticDeviceSelection()
+{
+ ScCalcConfig aConfig = ScInterpreter::GetGlobalConfig();
+ aConfig.mbOpenCLAutoSelect = false;
+ ScInterpreter::SetGlobalConfig(aConfig);
+ ScFormulaOptions aOptions = SC_MOD()->GetFormulaOptions();
+ aOptions.SetCalcConfig(aConfig);
+ SC_MOD()->SetFormulaOptions(aOptions);
+}
+
+void ScModelObj::selectOpenCLDevice( sal_Int32 nPlatform, sal_Int32 nDevice )
+{
+ if(nPlatform < 0 || nDevice < 0)
+ throw uno::RuntimeException();
+
+#if !HAVE_FEATURE_OPENCL
+ throw uno::RuntimeException();
+#else
+ std::vector<OpenCLPlatformInfo> aPlatformInfo;
+ sc::FormulaGroupInterpreter::fillOpenCLInfo(aPlatformInfo);
+ if(o3tl::make_unsigned(nPlatform) >= aPlatformInfo.size())
+ throw uno::RuntimeException();
+
+ if(o3tl::make_unsigned(nDevice) >= aPlatformInfo[nPlatform].maDevices.size())
+ throw uno::RuntimeException();
+
+ OUString aDeviceString = aPlatformInfo[nPlatform].maVendor + " " + aPlatformInfo[nPlatform].maDevices[nDevice].maName;
+ sc::FormulaGroupInterpreter::switchOpenCLDevice(aDeviceString, false);
+#endif
+}
+
+sal_Int32 ScModelObj::getPlatformID()
+{
+#if !HAVE_FEATURE_OPENCL
+ return -1;
+#else
+ sal_Int32 nPlatformId;
+ sal_Int32 nDeviceId;
+ sc::FormulaGroupInterpreter::getOpenCLDeviceInfo(nDeviceId, nPlatformId);
+ return nPlatformId;
+#endif
+}
+
+sal_Int32 ScModelObj::getDeviceID()
+{
+#if !HAVE_FEATURE_OPENCL
+ return -1;
+#else
+ sal_Int32 nPlatformId;
+ sal_Int32 nDeviceId;
+ sc::FormulaGroupInterpreter::getOpenCLDeviceInfo(nDeviceId, nPlatformId);
+ return nDeviceId;
+#endif
+}
+
+uno::Sequence< sheet::opencl::OpenCLPlatform > ScModelObj::getOpenCLPlatforms()
+{
+#if !HAVE_FEATURE_OPENCL
+ return uno::Sequence<sheet::opencl::OpenCLPlatform>();
+#else
+ std::vector<OpenCLPlatformInfo> aPlatformInfo;
+ sc::FormulaGroupInterpreter::fillOpenCLInfo(aPlatformInfo);
+
+ uno::Sequence<sheet::opencl::OpenCLPlatform> aRet(aPlatformInfo.size());
+ auto aRetRange = asNonConstRange(aRet);
+ for(size_t i = 0; i < aPlatformInfo.size(); ++i)
+ {
+ aRetRange[i].Name = aPlatformInfo[i].maName;
+ aRetRange[i].Vendor = aPlatformInfo[i].maVendor;
+
+ aRetRange[i].Devices.realloc(aPlatformInfo[i].maDevices.size());
+ auto pDevices = aRetRange[i].Devices.getArray();
+ for(size_t j = 0; j < aPlatformInfo[i].maDevices.size(); ++j)
+ {
+ const OpenCLDeviceInfo& rDevice = aPlatformInfo[i].maDevices[j];
+ pDevices[j].Name = rDevice.maName;
+ pDevices[j].Vendor = rDevice.maVendor;
+ pDevices[j].Driver = rDevice.maDriver;
+ }
+ }
+
+ return aRet;
+#endif
+}
+
+namespace {
+
+/// @throws css::uno::RuntimeException
+void setOpcodeSubsetTest(bool bFlag)
+{
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Calc::Formula::Calculation::OpenCLSubsetOnly::set(bFlag, batch);
+ batch->commit();
+}
+
+}
+
+void ScModelObj::enableOpcodeSubsetTest()
+{
+ setOpcodeSubsetTest(true);
+}
+
+void ScModelObj::disableOpcodeSubsetTest()
+{
+ setOpcodeSubsetTest(false);
+}
+
+sal_Bool ScModelObj::isOpcodeSubsetTested()
+{
+ return officecfg::Office::Calc::Formula::Calculation::OpenCLSubsetOnly::get();
+}
+
+void ScModelObj::setFormulaCellNumberLimit( sal_Int32 number )
+{
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::set(number, batch);
+ batch->commit();
+}
+
+sal_Int32 ScModelObj::getFormulaCellNumberLimit()
+{
+ return officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::get();
+}
+
+ScDrawPagesObj::ScDrawPagesObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDrawPagesObj::~ScDrawPagesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDrawPagesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // we don't care about update of references here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+uno::Reference<drawing::XDrawPage> ScDrawPagesObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
+{
+ if (pDocShell)
+ {
+ ScDrawLayer* pDrawLayer = pDocShell->MakeDrawLayer();
+ OSL_ENSURE(pDrawLayer,"Cannot create Draw-Layer");
+ if ( pDrawLayer && nIndex >= 0 && nIndex < pDocShell->GetDocument().GetTableCount() )
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nIndex));
+ OSL_ENSURE(pPage,"Draw-Page not found");
+ if (pPage)
+ {
+ return uno::Reference<drawing::XDrawPage> (pPage->getUnoPage(), uno::UNO_QUERY);
+ }
+ }
+ }
+ return nullptr;
+}
+
+// XDrawPages
+
+uno::Reference<drawing::XDrawPage> SAL_CALL ScDrawPagesObj::insertNewByIndex( sal_Int32 nPos )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<drawing::XDrawPage> xRet;
+ if (pDocShell)
+ {
+ OUString aNewName;
+ pDocShell->GetDocument().CreateValidTabName(aNewName);
+ if ( pDocShell->GetDocFunc().InsertTable( static_cast<SCTAB>(nPos),
+ aNewName, true, true ) )
+ xRet.set(GetObjectByIndex_Impl( nPos ));
+ }
+ return xRet;
+}
+
+void SAL_CALL ScDrawPagesObj::remove( const uno::Reference<drawing::XDrawPage>& xPage )
+{
+ SolarMutexGuard aGuard;
+ SvxDrawPage* pImp = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
+ if ( pDocShell && pImp )
+ {
+ SdrPage* pPage = pImp->GetSdrPage();
+ if (pPage)
+ {
+ SCTAB nPageNum = static_cast<SCTAB>(pPage->GetPageNum());
+ pDocShell->GetDocFunc().DeleteTable( nPageNum, true );
+ }
+ }
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDrawPagesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return pDocShell->GetDocument().GetTableCount();
+ return 0;
+}
+
+uno::Any SAL_CALL ScDrawPagesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<drawing::XDrawPage> xPage(GetObjectByIndex_Impl(nIndex));
+ if (!xPage.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xPage);
+}
+
+uno::Type SAL_CALL ScDrawPagesObj::getElementType()
+{
+ return cppu::UnoType<drawing::XDrawPage>::get();
+}
+
+sal_Bool SAL_CALL ScDrawPagesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+ScTableSheetsObj::ScTableSheetsObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScTableSheetsObj::~ScTableSheetsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScTableSheetsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // we don't care about update of references here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XSpreadsheets
+
+rtl::Reference<ScTableSheetObj> ScTableSheetsObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
+{
+ if ( pDocShell && nIndex >= 0 && nIndex < pDocShell->GetDocument().GetTableCount() )
+ return new ScTableSheetObj( pDocShell, static_cast<SCTAB>(nIndex) );
+
+ return nullptr;
+}
+
+rtl::Reference<ScTableSheetObj> ScTableSheetsObj::GetObjectByName_Impl(const OUString& aName) const
+{
+ if (pDocShell)
+ {
+ SCTAB nIndex;
+ if ( pDocShell->GetDocument().GetTable( aName, nIndex ) )
+ return new ScTableSheetObj( pDocShell, nIndex );
+ }
+ return nullptr;
+}
+
+void SAL_CALL ScTableSheetsObj::insertNewByName( const OUString& aName, sal_Int16 nPosition )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ bDone = pDocShell->GetDocFunc().InsertTable( nPosition, aName, true, true );
+ }
+ if (!bDone)
+ throw uno::RuntimeException("ScTableSheetsObj::insertNewByName(): Illegal object name or bad index. Duplicate name?"); // no other exceptions specified
+}
+
+void SAL_CALL ScTableSheetsObj::moveByName( const OUString& aName, sal_Int16 nDestination )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ SCTAB nSource;
+ if ( pDocShell->GetDocument().GetTable( aName, nSource ) )
+ bDone = pDocShell->MoveTable( nSource, nDestination, false, true );
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScTableSheetsObj::copyByName( const OUString& aName,
+ const OUString& aCopy, sal_Int16 nDestination )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ SCTAB nSource;
+ if ( pDocShell->GetDocument().GetTable( aName, nSource ) )
+ {
+ bDone = pDocShell->MoveTable( nSource, nDestination, true, true );
+ if (bDone)
+ {
+ // #i92477# any index past the last sheet means "append" in MoveTable
+ SCTAB nResultTab = static_cast<SCTAB>(nDestination);
+ SCTAB nTabCount = pDocShell->GetDocument().GetTableCount(); // count after copying
+ if (nResultTab >= nTabCount)
+ nResultTab = nTabCount - 1;
+
+ bDone = pDocShell->GetDocFunc().RenameTable( nResultTab, aCopy,
+ true, true );
+ }
+ }
+ }
+ if (!bDone)
+ throw uno::RuntimeException("ScTableSheetsObj::copyByName(): Illegal object name or bad index. Duplicate name?"); // no other exceptions specified
+}
+
+void SAL_CALL ScTableSheetsObj::insertByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ bool bIllArg = false;
+
+ //! Type of aElement can be some specific interface instead of XInterface
+
+ if ( pDocShell )
+ {
+ uno::Reference<uno::XInterface> xInterface(aElement, uno::UNO_QUERY);
+ if ( xInterface.is() )
+ {
+ ScTableSheetObj* pSheetObj = dynamic_cast<ScTableSheetObj*>( xInterface.get() );
+ if ( pSheetObj && !pSheetObj->GetDocShell() ) // not inserted yet?
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nDummy;
+ if ( rDoc.GetTable( aName, nDummy ) )
+ {
+ // name already exists
+ throw container::ElementExistException();
+ }
+ SCTAB nPosition = rDoc.GetTableCount();
+ bDone = pDocShell->GetDocFunc().InsertTable( nPosition, aName,
+ true, true );
+ if (bDone)
+ pSheetObj->InitInsertSheet( pDocShell, nPosition );
+ // set document and new range in the object
+ }
+ else
+ bIllArg = true;
+ }
+ else
+ bIllArg = true;
+ }
+
+ if (!bDone)
+ {
+ if (bIllArg)
+ throw lang::IllegalArgumentException();
+ else
+ throw uno::RuntimeException(); // ElementExistException is handled above
+ }
+}
+
+void SAL_CALL ScTableSheetsObj::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ bool bIllArg = false;
+
+ //! Type of aElement can be some specific interface instead of XInterface
+
+ if ( pDocShell )
+ {
+ uno::Reference<uno::XInterface> xInterface(aElement, uno::UNO_QUERY);
+ if ( xInterface.is() )
+ {
+ ScTableSheetObj* pSheetObj = dynamic_cast<ScTableSheetObj*>( xInterface.get() );
+ if ( pSheetObj && !pSheetObj->GetDocShell() ) // not inserted yet?
+ {
+ SCTAB nPosition;
+ if ( !pDocShell->GetDocument().GetTable( aName, nPosition ) )
+ {
+ // not found
+ throw container::NoSuchElementException();
+ }
+
+ if ( pDocShell->GetDocFunc().DeleteTable( nPosition, true ) )
+ {
+ // InsertTable can't really go wrong now
+ bDone = pDocShell->GetDocFunc().InsertTable( nPosition, aName, true, true );
+ if (bDone)
+ pSheetObj->InitInsertSheet( pDocShell, nPosition );
+ }
+
+ }
+ else
+ bIllArg = true;
+ }
+ else
+ bIllArg = true;
+ }
+
+ if (!bDone)
+ {
+ if (bIllArg)
+ throw lang::IllegalArgumentException();
+ else
+ throw uno::RuntimeException(); // NoSuchElementException is handled above
+ }
+}
+
+void SAL_CALL ScTableSheetsObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ SCTAB nIndex;
+ if ( !pDocShell->GetDocument().GetTable( aName, nIndex ) )
+ throw container::NoSuchElementException(); // not found
+ bDone = pDocShell->GetDocFunc().DeleteTable( nIndex, true );
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException(); // NoSuchElementException is handled above
+}
+
+sal_Int32 ScTableSheetsObj::importSheet(
+ const uno::Reference < sheet::XSpreadsheetDocument > & xDocSrc,
+ const OUString& srcName, const sal_Int32 nDestPosition )
+{
+ //pDocShell is the destination
+ ScDocument& rDocDest = pDocShell->GetDocument();
+
+ // Source document docShell
+ if ( !xDocSrc.is() )
+ throw uno::RuntimeException();
+ ScModelObj* pObj = comphelper::getFromUnoTunnel<ScModelObj>(xDocSrc);
+ ScDocShell* pDocShellSrc = static_cast<ScDocShell*>(pObj->GetEmbeddedObject());
+
+ // SourceSheet Position and does srcName exists ?
+ SCTAB nIndexSrc;
+ if ( !pDocShellSrc->GetDocument().GetTable( srcName, nIndexSrc ) )
+ throw lang::IllegalArgumentException();
+
+ // Check the validity of destination index.
+ SCTAB nCount = rDocDest.GetTableCount();
+ SCTAB nIndexDest = static_cast<SCTAB>(nDestPosition);
+ if (nIndexDest > nCount || nIndexDest < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ // Transfer Tab
+ pDocShell->TransferTab(
+ *pDocShellSrc, nIndexSrc, nIndexDest, true/*bInsertNew*/, true/*bNotifyAndPaint*/ );
+
+ return nIndexDest;
+}
+
+// XCellRangesAccess
+
+uno::Reference< table::XCell > SAL_CALL ScTableSheetsObj::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow, sal_Int32 nSheet )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<ScTableSheetObj> xSheet = GetObjectByIndex_Impl(static_cast<sal_uInt16>(nSheet));
+ if (! xSheet.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return xSheet->getCellByPosition(nColumn, nRow);
+}
+
+uno::Reference< table::XCellRange > SAL_CALL ScTableSheetsObj::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom, sal_Int32 nSheet )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<ScTableSheetObj> xSheet = GetObjectByIndex_Impl(static_cast<sal_uInt16>(nSheet));
+ if (! xSheet.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return xSheet->getCellRangeByPosition(nLeft, nTop, nRight, nBottom);
+}
+
+uno::Sequence < uno::Reference< table::XCellRange > > SAL_CALL ScTableSheetsObj::getCellRangesByName( const OUString& aRange )
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence < uno::Reference < table::XCellRange > > xRet;
+
+ ScRangeList aRangeList;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (!ScRangeStringConverter::GetRangeListFromString( aRangeList, aRange, rDoc, ::formula::FormulaGrammar::CONV_OOO, ';' ))
+ throw lang::IllegalArgumentException();
+
+ size_t nCount = aRangeList.size();
+ if (!nCount)
+ throw lang::IllegalArgumentException();
+
+ xRet.realloc(nCount);
+ auto pRet = xRet.getArray();
+ for( size_t nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ const ScRange & rRange = aRangeList[ nIndex ];
+ pRet[nIndex] = new ScCellRangeObj(pDocShell, rRange);
+ }
+
+ return xRet;
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScTableSheetsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.SpreadsheetsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScTableSheetsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return pDocShell->GetDocument().GetTableCount();
+ return 0;
+}
+
+uno::Any SAL_CALL ScTableSheetsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XSpreadsheet> xSheet(GetObjectByIndex_Impl(nIndex));
+ if (!xSheet.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xSheet);
+
+// return uno::Any();
+}
+
+uno::Type SAL_CALL ScTableSheetsObj::getElementType()
+{
+ return cppu::UnoType<sheet::XSpreadsheet>::get();
+}
+
+sal_Bool SAL_CALL ScTableSheetsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XNameAccess
+
+uno::Any SAL_CALL ScTableSheetsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XSpreadsheet> xSheet(GetObjectByName_Impl(aName));
+ if (!xSheet.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xSheet);
+}
+
+uno::Sequence<OUString> SAL_CALL ScTableSheetsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nCount = rDoc.GetTableCount();
+ OUString aName;
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ for (SCTAB i=0; i<nCount; i++)
+ {
+ rDoc.GetName( i, aName );
+ pAry[i] = aName;
+ }
+ return aSeq;
+ }
+ return uno::Sequence<OUString>();
+}
+
+sal_Bool SAL_CALL ScTableSheetsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ SCTAB nIndex;
+ if ( pDocShell->GetDocument().GetTable( aName, nIndex ) )
+ return true;
+ }
+ return false;
+}
+
+ScTableColumnsObj::ScTableColumnsObj(ScDocShell* pDocSh, SCTAB nT, SCCOL nSC, SCCOL nEC) :
+ pDocShell( pDocSh ),
+ nTab ( nT ),
+ nStartCol( nSC ),
+ nEndCol ( nEC )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScTableColumnsObj::~ScTableColumnsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScTableColumnsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! update of references for sheet and its start/end
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XTableColumns
+
+rtl::Reference<ScTableColumnObj> ScTableColumnsObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
+{
+ SCCOL nCol = static_cast<SCCOL>(nIndex) + nStartCol;
+ if ( pDocShell && nCol <= nEndCol )
+ return new ScTableColumnObj( pDocShell, nCol, nTab );
+
+ return nullptr; // wrong index
+}
+
+rtl::Reference<ScTableColumnObj> ScTableColumnsObj::GetObjectByName_Impl(std::u16string_view aName) const
+{
+ SCCOL nCol = 0;
+ if (pDocShell && ::AlphaToCol(pDocShell->GetDocument(), nCol, aName))
+ if (nCol >= nStartCol && nCol <= nEndCol)
+ return new ScTableColumnObj( pDocShell, nCol, nTab );
+
+ return nullptr;
+}
+
+void SAL_CALL ScTableColumnsObj::insertByIndex( sal_Int32 nPosition, sal_Int32 nCount )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if ( pDocShell )
+ {
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ if ( nCount > 0 && nPosition >= 0 && nStartCol+nPosition <= nEndCol &&
+ nStartCol+nPosition+nCount-1 <= rDoc.MaxCol() )
+ {
+ ScRange aRange( static_cast<SCCOL>(nStartCol+nPosition), 0, nTab,
+ static_cast<SCCOL>(nStartCol+nPosition+nCount-1), rDoc.MaxRow(), nTab );
+ bDone = pDocShell->GetDocFunc().InsertCells( aRange, nullptr, INS_INSCOLS_BEFORE, true, true );
+ }
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScTableColumnsObj::removeByIndex( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ // the range to be deleted has to lie within the object
+ if ( pDocShell )
+ {
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ if ( nCount > 0 && nIndex >= 0 && nStartCol+nIndex+nCount-1 <= nEndCol )
+ {
+ ScRange aRange( static_cast<SCCOL>(nStartCol+nIndex), 0, nTab,
+ static_cast<SCCOL>(nStartCol+nIndex+nCount-1), rDoc.MaxRow(), nTab );
+ bDone = pDocShell->GetDocFunc().DeleteCells( aRange, nullptr, DelCellCmd::Cols, true );
+ }
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScTableColumnsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.table.TableColumnsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScTableColumnsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return nEndCol - nStartCol + 1;
+}
+
+uno::Any SAL_CALL ScTableColumnsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XCellRange> xColumn(GetObjectByIndex_Impl(nIndex));
+ if (!xColumn.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xColumn);
+
+}
+
+uno::Type SAL_CALL ScTableColumnsObj::getElementType()
+{
+ return cppu::UnoType<table::XCellRange>::get();
+}
+
+sal_Bool SAL_CALL ScTableColumnsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Any SAL_CALL ScTableColumnsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XCellRange> xColumn(GetObjectByName_Impl(aName));
+ if (!xColumn.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xColumn);
+}
+
+uno::Sequence<OUString> SAL_CALL ScTableColumnsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ SCCOL nCount = nEndCol - nStartCol + 1;
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ for (SCCOL i=0; i<nCount; i++)
+ pAry[i] = ::ScColToAlpha( nStartCol + i );
+
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScTableColumnsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ SCCOL nCol = 0;
+ if (pDocShell && ::AlphaToCol(pDocShell->GetDocument(), nCol, aName))
+ if (nCol >= nStartCol && nCol <= nEndCol)
+ return true;
+
+ return false; // not found
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableColumnsObj::getPropertySetInfo()
+{
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( lcl_GetColumnsPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScTableColumnsObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ throw uno::RuntimeException();
+
+ std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(nStartCol,nEndCol));
+ ScDocFunc& rFunc = pDocShell->GetDocFunc();
+
+ if ( aPropertyName == SC_UNONAME_CELLWID )
+ {
+ sal_Int32 nNewWidth = 0;
+ if ( aValue >>= nNewWidth )
+ rFunc.SetWidthOrHeight(
+ true, aColArr, nTab, SC_SIZE_ORIGINAL, o3tl::toTwips(nNewWidth, o3tl::Length::mm100), true, true);
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLVIS )
+ {
+ bool bVis = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ ScSizeMode eMode = bVis ? SC_SIZE_SHOW : SC_SIZE_DIRECT;
+ rFunc.SetWidthOrHeight(true, aColArr, nTab, eMode, 0, true, true);
+ // SC_SIZE_DIRECT with size 0: hide
+ }
+ else if ( aPropertyName == SC_UNONAME_OWIDTH )
+ {
+ bool bOpt = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bOpt)
+ rFunc.SetWidthOrHeight(
+ true, aColArr, nTab, SC_SIZE_OPTIMAL, STD_EXTRA_WIDTH, true, true);
+ // sal_False for columns currently has no effect
+ }
+ else if ( aPropertyName == SC_UNONAME_NEWPAGE || aPropertyName == SC_UNONAME_MANPAGE )
+ {
+ //! single function to set/remove all breaks?
+ bool bSet = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
+ if (bSet)
+ rFunc.InsertPageBreak( true, ScAddress(nCol,0,nTab), true, true );
+ else
+ rFunc.RemovePageBreak( true, ScAddress(nCol,0,nTab), true, true );
+ }
+}
+
+uno::Any SAL_CALL ScTableColumnsObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ uno::Any aAny;
+
+ //! loop over all columns for current state?
+
+ if ( aPropertyName == SC_UNONAME_CELLWID )
+ {
+ // for hidden column, return original height
+ sal_uInt16 nWidth = rDoc.GetOriginalWidth( nStartCol, nTab );
+ aAny <<= static_cast<sal_Int32>(convertTwipToMm100(nWidth));
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLVIS )
+ {
+ bool bVis = !rDoc.ColHidden(nStartCol, nTab);
+ aAny <<= bVis;
+ }
+ else if ( aPropertyName == SC_UNONAME_OWIDTH )
+ {
+ bool bOpt = !(rDoc.GetColFlags( nStartCol, nTab ) & CRFlags::ManualSize);
+ aAny <<= bOpt;
+ }
+ else if ( aPropertyName == SC_UNONAME_NEWPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasColBreak(nStartCol, nTab);
+ aAny <<= (nBreak != ScBreakType::NONE);
+ }
+ else if ( aPropertyName == SC_UNONAME_MANPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasColBreak(nStartCol, nTab);
+ aAny <<= bool(nBreak & ScBreakType::Manual);
+ }
+
+ return aAny;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScTableColumnsObj )
+
+ScTableRowsObj::ScTableRowsObj(ScDocShell* pDocSh, SCTAB nT, SCROW nSR, SCROW nER) :
+ pDocShell( pDocSh ),
+ nTab ( nT ),
+ nStartRow( nSR ),
+ nEndRow ( nER )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScTableRowsObj::~ScTableRowsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScTableRowsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! update of references for sheet and its start/end
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XTableRows
+
+rtl::Reference<ScTableRowObj> ScTableRowsObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
+{
+ SCROW nRow = static_cast<SCROW>(nIndex) + nStartRow;
+ if ( pDocShell && nRow <= nEndRow )
+ return new ScTableRowObj( pDocShell, nRow, nTab );
+
+ return nullptr; // wrong index
+}
+
+void SAL_CALL ScTableRowsObj::insertByIndex( sal_Int32 nPosition, sal_Int32 nCount )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if ( pDocShell )
+ {
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ if ( nCount > 0 && nPosition >= 0 && nStartRow+nPosition <= nEndRow &&
+ nStartRow+nPosition+nCount-1 <= rDoc.MaxRow() )
+ {
+ ScRange aRange( 0, static_cast<SCROW>(nStartRow+nPosition), nTab,
+ rDoc.MaxCol(), static_cast<SCROW>(nStartRow+nPosition+nCount-1), nTab );
+ bDone = pDocShell->GetDocFunc().InsertCells( aRange, nullptr, INS_INSROWS_BEFORE, true, true );
+ }
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScTableRowsObj::removeByIndex( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ // the range to be deleted has to lie within the object
+ if ( pDocShell && nCount > 0 && nIndex >= 0 && nStartRow+nIndex+nCount-1 <= nEndRow )
+ {
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ ScRange aRange( 0, static_cast<SCROW>(nStartRow+nIndex), nTab,
+ rDoc.MaxCol(), static_cast<SCROW>(nStartRow+nIndex+nCount-1), nTab );
+ bDone = pDocShell->GetDocFunc().DeleteCells( aRange, nullptr, DelCellCmd::Rows, true );
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScTableRowsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.table.TableRowsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScTableRowsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return nEndRow - nStartRow + 1;
+}
+
+uno::Any SAL_CALL ScTableRowsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XCellRange> xRow(GetObjectByIndex_Impl(nIndex));
+ if (!xRow.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRow);
+}
+
+uno::Type SAL_CALL ScTableRowsObj::getElementType()
+{
+ return cppu::UnoType<table::XCellRange>::get();
+}
+
+sal_Bool SAL_CALL ScTableRowsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableRowsObj::getPropertySetInfo()
+{
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( lcl_GetRowsPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScTableRowsObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ throw uno::RuntimeException();
+
+ ScDocFunc& rFunc = pDocShell->GetDocFunc();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::vector<sc::ColRowSpan> aRowArr(1, sc::ColRowSpan(nStartRow,nEndRow));
+
+ if ( aPropertyName == SC_UNONAME_OHEIGHT )
+ {
+ sal_Int32 nNewHeight = 0;
+ if ( rDoc.IsImportingXML() && ( aValue >>= nNewHeight ) )
+ {
+ // used to set the stored row height for rows with optimal height when loading.
+
+ // TODO: It's probably cleaner to use a different property name
+ // for this.
+ rDoc.SetRowHeightOnly( nStartRow, nEndRow, nTab, o3tl::toTwips(nNewHeight, o3tl::Length::mm100) );
+ }
+ else
+ {
+ bool bOpt = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bOpt)
+ rFunc.SetWidthOrHeight(false, aRowArr, nTab, SC_SIZE_OPTIMAL, 0, true, true);
+ else
+ {
+ //! manually set old heights again?
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLHGT )
+ {
+ sal_Int32 nNewHeight = 0;
+ if ( aValue >>= nNewHeight )
+ {
+ if (rDoc.IsImportingXML())
+ {
+ // TODO: This is a band-aid fix. Eventually we need to
+ // re-work ods' style import to get it to set styles to
+ // ScDocument directly.
+ rDoc.SetRowHeightOnly( nStartRow, nEndRow, nTab, o3tl::toTwips(nNewHeight, o3tl::Length::mm100) );
+ rDoc.SetManualHeight( nStartRow, nEndRow, nTab, true );
+ }
+ else
+ rFunc.SetWidthOrHeight(
+ false, aRowArr, nTab, SC_SIZE_ORIGINAL, o3tl::toTwips(nNewHeight, o3tl::Length::mm100), true, true);
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLVIS )
+ {
+ bool bVis = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ ScSizeMode eMode = bVis ? SC_SIZE_SHOW : SC_SIZE_DIRECT;
+ rFunc.SetWidthOrHeight(false, aRowArr, nTab, eMode, 0, true, true);
+ // SC_SIZE_DIRECT with size 0: hide
+ }
+ else if ( aPropertyName == SC_UNONAME_VISFLAG )
+ {
+ // #i116460# Shortcut to only set the flag, without drawing layer update etc.
+ // Should only be used from import filters.
+ rDoc.SetRowHidden(nStartRow, nEndRow, nTab, !ScUnoHelpFunctions::GetBoolFromAny( aValue ));
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLFILT )
+ {
+ //! undo etc.
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ rDoc.SetRowFiltered(nStartRow, nEndRow, nTab, true);
+ else
+ rDoc.SetRowFiltered(nStartRow, nEndRow, nTab, false);
+ }
+ else if ( aPropertyName == SC_UNONAME_NEWPAGE || aPropertyName == SC_UNONAME_MANPAGE )
+ {
+ //! single function to set/remove all breaks?
+ bool bSet = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
+ if (bSet)
+ rFunc.InsertPageBreak( false, ScAddress(0,nRow,nTab), true, true );
+ else
+ rFunc.RemovePageBreak( false, ScAddress(0,nRow,nTab), true, true );
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLBACK || aPropertyName == SC_UNONAME_CELLTRAN )
+ {
+ // #i57867# Background color is specified for row styles in the file format,
+ // so it has to be supported along with the row properties (import only).
+
+ // Use ScCellRangeObj to set the property for all cells in the rows
+ // (this means, the "row attribute" must be set before individual cell attributes).
+
+ ScRange aRange( 0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab );
+ uno::Reference<beans::XPropertySet> xRangeObj = new ScCellRangeObj( pDocShell, aRange );
+ xRangeObj->setPropertyValue( aPropertyName, aValue );
+ }
+}
+
+uno::Any SAL_CALL ScTableRowsObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ uno::Any aAny;
+
+ //! loop over all rows for current state?
+
+ if ( aPropertyName == SC_UNONAME_CELLHGT )
+ {
+ // for hidden row, return original height
+ sal_uInt16 nHeight = rDoc.GetOriginalHeight( nStartRow, nTab );
+ aAny <<= static_cast<sal_Int32>(convertTwipToMm100(nHeight));
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLVIS )
+ {
+ SCROW nLastRow;
+ bool bVis = !rDoc.RowHidden(nStartRow, nTab, nullptr, &nLastRow);
+ aAny <<= bVis;
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLFILT )
+ {
+ bool bVis = rDoc.RowFiltered(nStartRow, nTab);
+ aAny <<= bVis;
+ }
+ else if ( aPropertyName == SC_UNONAME_OHEIGHT )
+ {
+ bool bOpt = !(rDoc.GetRowFlags( nStartRow, nTab ) & CRFlags::ManualSize);
+ aAny <<= bOpt;
+ }
+ else if ( aPropertyName == SC_UNONAME_NEWPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasRowBreak(nStartRow, nTab);
+ aAny <<= (nBreak != ScBreakType::NONE);
+ }
+ else if ( aPropertyName == SC_UNONAME_MANPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasRowBreak(nStartRow, nTab);
+ aAny <<= bool(nBreak & ScBreakType::Manual);
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLBACK || aPropertyName == SC_UNONAME_CELLTRAN )
+ {
+ // Use ScCellRangeObj to get the property from the cell range
+ // (for completeness only, this is not used by the XML filter).
+
+ ScRange aRange( 0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab );
+ uno::Reference<beans::XPropertySet> xRangeObj = new ScCellRangeObj( pDocShell, aRange );
+ aAny = xRangeObj->getPropertyValue( aPropertyName );
+ }
+
+ return aAny;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScTableRowsObj )
+
+ScSpreadsheetSettingsObj::~ScSpreadsheetSettingsObj()
+{
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSpreadsheetSettingsObj::getPropertySetInfo()
+{
+ return nullptr;
+}
+
+void SAL_CALL ScSpreadsheetSettingsObj::setPropertyValue(
+ const OUString& /* aPropertyName */, const uno::Any& /* aValue */ )
+{
+}
+
+uno::Any SAL_CALL ScSpreadsheetSettingsObj::getPropertyValue( const OUString& /* aPropertyName */ )
+{
+ return uno::Any();
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSpreadsheetSettingsObj )
+
+ScAnnotationsObj::ScAnnotationsObj(ScDocShell* pDocSh, SCTAB nT) :
+ pDocShell( pDocSh ),
+ nTab( nT )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScAnnotationsObj::~ScAnnotationsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScAnnotationsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! adjust nTab when updating references!!!
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+bool ScAnnotationsObj::GetAddressByIndex_Impl( sal_Int32 nIndex, ScAddress& rPos ) const
+{
+ if (!pDocShell)
+ return false;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rPos = rDoc.GetNotePosition(nIndex, nTab);
+ return rPos.IsValid();
+}
+
+rtl::Reference<ScAnnotationObj> ScAnnotationsObj::GetObjectByIndex_Impl( sal_Int32 nIndex ) const
+{
+ if (pDocShell)
+ {
+ ScAddress aPos;
+ if ( GetAddressByIndex_Impl( nIndex, aPos ) )
+ return new ScAnnotationObj( pDocShell, aPos );
+ }
+ return nullptr;
+}
+
+// XSheetAnnotations
+
+void SAL_CALL ScAnnotationsObj::insertNew(
+ const table::CellAddress& aPosition, const OUString& rText )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ OSL_ENSURE( aPosition.Sheet == nTab, "addAnnotation with a wrong Sheet" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ pDocShell->GetDocFunc().ReplaceNote( aPos, rText, nullptr, nullptr, true );
+ }
+}
+
+void SAL_CALL ScAnnotationsObj::removeByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScAddress aPos;
+ if ( GetAddressByIndex_Impl( nIndex, aPos ) )
+ {
+ ScMarkData aMarkData(pDocShell->GetDocument().GetSheetLimits());
+ aMarkData.SelectTable( aPos.Tab(), true );
+ aMarkData.SetMultiMarkArea( ScRange(aPos) );
+
+ pDocShell->GetDocFunc().DeleteContents( aMarkData, InsertDeleteFlags::NOTE, true, true );
+ }
+ }
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScAnnotationsObj::createEnumeration()
+{
+ //! iterate directly (more efficiently)?
+
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.CellAnnotationsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScAnnotationsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nCount = 0;
+ if (pDocShell)
+ {
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ for (SCCOL nCol : rDoc.GetAllocatedColumnsRange(nTab, 0, rDoc.MaxCol()))
+ nCount += rDoc.GetNoteCount(nTab, nCol);
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL ScAnnotationsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XSheetAnnotation> xAnnotation(GetObjectByIndex_Impl(nIndex));
+ if (!xAnnotation.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xAnnotation);
+}
+
+uno::Type SAL_CALL ScAnnotationsObj::getElementType()
+{
+ return cppu::UnoType<sheet::XSheetAnnotation>::get();
+}
+
+sal_Bool SAL_CALL ScAnnotationsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+ScScenariosObj::ScScenariosObj(ScDocShell* pDocSh, SCTAB nT) :
+ pDocShell( pDocSh ),
+ nTab ( nT )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScScenariosObj::~ScScenariosObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScScenariosObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! update of references for sheet and its start/end
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XScenarios
+
+bool ScScenariosObj::GetScenarioIndex_Impl( std::u16string_view rName, SCTAB& rIndex )
+{
+ //! Case-insensitive ????
+
+ if ( pDocShell )
+ {
+ OUString aTabName;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nCount = static_cast<SCTAB>(getCount());
+ for (SCTAB i=0; i<nCount; i++)
+ if (rDoc.GetName( nTab+i+1, aTabName ))
+ if (aTabName == rName)
+ {
+ rIndex = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+rtl::Reference<ScTableSheetObj> ScScenariosObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
+{
+ sal_uInt16 nCount = static_cast<sal_uInt16>(getCount());
+ if ( pDocShell && nIndex >= 0 && nIndex < nCount )
+ return new ScTableSheetObj( pDocShell, nTab+static_cast<SCTAB>(nIndex)+1 );
+
+ return nullptr; // no document or wrong index
+}
+
+rtl::Reference<ScTableSheetObj> ScScenariosObj::GetObjectByName_Impl(std::u16string_view aName)
+{
+ SCTAB nIndex;
+ if ( pDocShell && GetScenarioIndex_Impl( aName, nIndex ) )
+ return new ScTableSheetObj( pDocShell, nTab+nIndex+1 );
+
+ return nullptr; // not found
+}
+
+void SAL_CALL ScScenariosObj::addNewByName( const OUString& aName,
+ const uno::Sequence<table::CellRangeAddress>& aRanges,
+ const OUString& aComment )
+{
+ SolarMutexGuard aGuard;
+ if ( !pDocShell )
+ return;
+
+ ScMarkData aMarkData(pDocShell->GetDocument().GetSheetLimits());
+ aMarkData.SelectTable( nTab, true );
+
+ for (const table::CellRangeAddress& rRange : aRanges)
+ {
+ OSL_ENSURE( rRange.Sheet == nTab, "addScenario with a wrong Tab" );
+ ScRange aRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), nTab,
+ static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), nTab );
+
+ aMarkData.SetMultiMarkArea( aRange );
+ }
+
+ ScScenarioFlags const nFlags = ScScenarioFlags::ShowFrame | ScScenarioFlags::PrintFrame
+ | ScScenarioFlags::TwoWay | ScScenarioFlags::Protected;
+
+ pDocShell->MakeScenario( nTab, aName, aComment, COL_LIGHTGRAY, nFlags, aMarkData );
+}
+
+void SAL_CALL ScScenariosObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ SCTAB nIndex;
+ if ( pDocShell && GetScenarioIndex_Impl( aName, nIndex ) )
+ pDocShell->GetDocFunc().DeleteTable( nTab+nIndex+1, true );
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScScenariosObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.ScenariosEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScScenariosObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ SCTAB nCount = 0;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (!rDoc.IsScenario(nTab))
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCTAB nNext = nTab + 1;
+ while (nNext < nTabCount && rDoc.IsScenario(nNext))
+ {
+ ++nCount;
+ ++nNext;
+ }
+ }
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL ScScenariosObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XScenario> xScen(GetObjectByIndex_Impl(nIndex));
+ if (!xScen.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xScen);
+}
+
+uno::Type SAL_CALL ScScenariosObj::getElementType()
+{
+ return cppu::UnoType<sheet::XScenario>::get();
+}
+
+sal_Bool SAL_CALL ScScenariosObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Any SAL_CALL ScScenariosObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XScenario> xScen(GetObjectByName_Impl(aName));
+ if (!xScen.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xScen);
+}
+
+uno::Sequence<OUString> SAL_CALL ScScenariosObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ SCTAB nCount = static_cast<SCTAB>(getCount());
+ uno::Sequence<OUString> aSeq(nCount);
+
+ if ( pDocShell ) // otherwise Count = 0
+ {
+ OUString aTabName;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OUString* pAry = aSeq.getArray();
+ for (SCTAB i=0; i<nCount; i++)
+ if (rDoc.GetName( nTab+i+1, aTabName ))
+ pAry[i] = aTabName;
+ }
+
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScScenariosObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ SCTAB nIndex;
+ return GetScenarioIndex_Impl( aName, nIndex );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */