summaryrefslogtreecommitdiffstats
path: root/sc/source/ui/unoobj
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/unoobj')
-rw-r--r--sc/source/ui/unoobj/ChartRangeSelectionListener.cxx71
-rw-r--r--sc/source/ui/unoobj/ChartTools.cxx174
-rw-r--r--sc/source/ui/unoobj/PivotTableDataProvider.cxx906
-rw-r--r--sc/source/ui/unoobj/PivotTableDataSequence.cxx278
-rw-r--r--sc/source/ui/unoobj/PivotTableDataSource.cxx49
-rw-r--r--sc/source/ui/unoobj/TablePivotChart.cxx104
-rw-r--r--sc/source/ui/unoobj/TablePivotCharts.cxx279
-rw-r--r--sc/source/ui/unoobj/addruno.cxx298
-rw-r--r--sc/source/ui/unoobj/afmtuno.cxx718
-rw-r--r--sc/source/ui/unoobj/appluno.cxx619
-rw-r--r--sc/source/ui/unoobj/celllistsource.cxx433
-rw-r--r--sc/source/ui/unoobj/celllistsource.hxx155
-rw-r--r--sc/source/ui/unoobj/cellsuno.cxx9266
-rw-r--r--sc/source/ui/unoobj/cellvaluebinding.cxx576
-rw-r--r--sc/source/ui/unoobj/cellvaluebinding.hxx146
-rw-r--r--sc/source/ui/unoobj/chart2uno.cxx3517
-rw-r--r--sc/source/ui/unoobj/chartuno.cxx739
-rw-r--r--sc/source/ui/unoobj/condformatuno.cxx1899
-rw-r--r--sc/source/ui/unoobj/confuno.cxx661
-rw-r--r--sc/source/ui/unoobj/convuno.cxx46
-rw-r--r--sc/source/ui/unoobj/cursuno.cxx453
-rw-r--r--sc/source/ui/unoobj/dapiuno.cxx3344
-rw-r--r--sc/source/ui/unoobj/datauno.cxx2384
-rw-r--r--sc/source/ui/unoobj/defltuno.cxx334
-rw-r--r--sc/source/ui/unoobj/dispuno.cxx366
-rw-r--r--sc/source/ui/unoobj/docuno.cxx4984
-rw-r--r--sc/source/ui/unoobj/drdefuno.cxx80
-rw-r--r--sc/source/ui/unoobj/editsrc.cxx272
-rw-r--r--sc/source/ui/unoobj/eventuno.cxx174
-rw-r--r--sc/source/ui/unoobj/exceldetect.cxx198
-rw-r--r--sc/source/ui/unoobj/exceldetect.hxx34
-rw-r--r--sc/source/ui/unoobj/fielduno.cxx1289
-rw-r--r--sc/source/ui/unoobj/filtuno.cxx371
-rw-r--r--sc/source/ui/unoobj/fmtuno.cxx913
-rw-r--r--sc/source/ui/unoobj/forbiuno.cxx81
-rw-r--r--sc/source/ui/unoobj/funcuno.cxx653
-rw-r--r--sc/source/ui/unoobj/linkuno.cxx1688
-rw-r--r--sc/source/ui/unoobj/listenercalls.cxx69
-rw-r--r--sc/source/ui/unoobj/miscuno.cxx285
-rw-r--r--sc/source/ui/unoobj/nameuno.cxx1147
-rw-r--r--sc/source/ui/unoobj/notesuno.cxx231
-rw-r--r--sc/source/ui/unoobj/optuno.cxx221
-rw-r--r--sc/source/ui/unoobj/pageuno.cxx60
-rw-r--r--sc/source/ui/unoobj/scdetect.cxx353
-rw-r--r--sc/source/ui/unoobj/scdetect.hxx49
-rw-r--r--sc/source/ui/unoobj/servuno.cxx625
-rw-r--r--sc/source/ui/unoobj/shapeuno.cxx1469
-rw-r--r--sc/source/ui/unoobj/srchuno.cxx195
-rw-r--r--sc/source/ui/unoobj/styleuno.cxx2069
-rw-r--r--sc/source/ui/unoobj/targuno.cxx293
-rw-r--r--sc/source/ui/unoobj/textuno.cxx869
-rw-r--r--sc/source/ui/unoobj/tokenuno.cxx520
-rw-r--r--sc/source/ui/unoobj/unodoc.cxx45
-rw-r--r--sc/source/ui/unoobj/unoreflist.cxx55
-rw-r--r--sc/source/ui/unoobj/viewuno.cxx2220
-rw-r--r--sc/source/ui/unoobj/warnpassword.cxx62
56 files changed, 49389 insertions, 0 deletions
diff --git a/sc/source/ui/unoobj/ChartRangeSelectionListener.cxx b/sc/source/ui/unoobj/ChartRangeSelectionListener.cxx
new file mode 100644
index 0000000000..eae58aee6f
--- /dev/null
+++ b/sc/source/ui/unoobj/ChartRangeSelectionListener.cxx
@@ -0,0 +1,71 @@
+/* -*- 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 <ChartRangeSelectionListener.hxx>
+
+#include <com/sun/star/chart2/data/XRangeHighlighter.hpp>
+
+#include <tabvwsh.hxx>
+#include <unonames.hxx>
+#include <miscuno.hxx>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+SC_SIMPLE_SERVICE_INFO( ScChartRangeSelectionListener, "ScChartRangeSelectionListener",
+ SC_SERVICENAME_CHRANGEHILIGHT )
+
+ScChartRangeSelectionListener::ScChartRangeSelectionListener( ScTabViewShell * pViewShell ) :
+ m_pViewShell( pViewShell )
+{}
+
+ScChartRangeSelectionListener::~ScChartRangeSelectionListener()
+{}
+
+// ____ XModifyListener ____
+void SAL_CALL ScChartRangeSelectionListener::selectionChanged( const lang::EventObject& aEvent )
+{
+ Reference< chart2::data::XRangeHighlighter > xRangeHighlighter( aEvent.Source, uno::UNO_QUERY );
+ if( xRangeHighlighter.is())
+ {
+ Sequence< chart2::data::HighlightedRange > aRanges( xRangeHighlighter->getSelectedRanges());
+
+ // search the view on which the chart is active
+
+ if( m_pViewShell )
+ {
+ m_pViewShell->DoChartSelection( aRanges );
+ }
+ }
+}
+
+// ____ XEventListener ____
+void SAL_CALL ScChartRangeSelectionListener::disposing( const lang::EventObject& /*Source*/ )
+{
+}
+
+// ____ WeakComponentImplHelperBase ____
+void ScChartRangeSelectionListener::disposing(std::unique_lock<std::mutex>&)
+{
+ m_pViewShell = nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/ChartTools.cxx b/sc/source/ui/unoobj/ChartTools.cxx
new file mode 100644
index 0000000000..e9fdc996a3
--- /dev/null
+++ b/sc/source/ui/unoobj/ChartTools.cxx
@@ -0,0 +1,174 @@
+/* -*- 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/.
+ *
+ */
+
+#include <ChartTools.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+
+#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+
+using namespace css;
+
+namespace sc::tools {
+
+namespace {
+
+uno::Reference<chart2::data::XPivotTableDataProvider>
+getPivotTableDataProvider(const SdrOle2Obj* pOleObject)
+{
+ uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider;
+
+ const uno::Reference<embed::XEmbeddedObject>& xObject = pOleObject->GetObjRef();
+ if (xObject.is())
+ {
+ uno::Reference<chart2::XChartDocument> xChartDoc(xObject->getComponent(), uno::UNO_QUERY);
+ if (xChartDoc.is())
+ {
+ xPivotTableDataProvider.set(uno::Reference<chart2::data::XPivotTableDataProvider>(
+ xChartDoc->getDataProvider(), uno::UNO_QUERY));
+ }
+ }
+ return xPivotTableDataProvider;
+}
+
+OUString getAssociatedPivotTableName(const SdrOle2Obj* pOleObject)
+{
+ OUString aPivotTableName;
+ uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider;
+ xPivotTableDataProvider.set(getPivotTableDataProvider(pOleObject));
+ if (xPivotTableDataProvider.is())
+ aPivotTableName = xPivotTableDataProvider->getPivotTableName();
+ return aPivotTableName;
+}
+
+} // end anonymous namespace
+
+ChartIterator::ChartIterator(ScDocShell* pDocShell, SCTAB nTab, ChartSourceType eChartSourceType)
+ : m_eChartSourceType(eChartSourceType)
+{
+ if (!pDocShell)
+ return;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if (!pDrawLayer)
+ return;
+ SdrPage* pPage = pDrawLayer->GetPage(sal_uInt16(nTab));
+ if (!pPage)
+ return;
+ m_oIterator.emplace(pPage, SdrIterMode::DeepNoGroups);
+}
+
+SdrOle2Obj* ChartIterator::next()
+{
+ if (!m_oIterator)
+ return nullptr;
+
+ SdrObject* pObject = m_oIterator->Next();
+ while (pObject)
+ {
+ if (pObject->GetObjIdentifier() == SdrObjKind::OLE2 && ScDocument::IsChart(pObject))
+ {
+ SdrOle2Obj* pOleObject = static_cast<SdrOle2Obj*>(pObject);
+
+ uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider;
+ xPivotTableDataProvider.set(getPivotTableDataProvider(pOleObject));
+
+ if (xPivotTableDataProvider.is() && m_eChartSourceType == ChartSourceType::PIVOT_TABLE)
+ return pOleObject;
+ else if (!xPivotTableDataProvider.is() && m_eChartSourceType == ChartSourceType::CELL_RANGE)
+ return pOleObject;
+ }
+ pObject = m_oIterator->Next();
+ }
+ return nullptr;
+}
+
+SdrOle2Obj* findChartsByName(ScDocShell* pDocShell, SCTAB nTab, std::u16string_view rName, ChartSourceType eChartSourceType)
+{
+ if (!pDocShell)
+ return nullptr;
+
+ ChartIterator aIterator(pDocShell, nTab, eChartSourceType);
+
+ SdrOle2Obj* pObject = aIterator.next();
+ while (pObject)
+ {
+ uno::Reference<embed::XEmbeddedObject> xObject = pObject->GetObjRef();
+ if (xObject.is())
+ {
+ OUString aObjectName = pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName(xObject);
+ if (aObjectName == rName)
+ return pObject;
+ }
+ pObject = aIterator.next();
+ }
+ return nullptr;
+}
+
+SdrOle2Obj* getChartByIndex(ScDocShell* pDocShell, SCTAB nTab, ::tools::Long nIndex, ChartSourceType eChartSourceType)
+{
+ if (!pDocShell)
+ return nullptr;
+
+ ChartIterator aIterator(pDocShell, nTab, eChartSourceType);
+
+ SdrOle2Obj* pObject = aIterator.next();
+ ::tools::Long i = 0;
+ while (pObject)
+ {
+ if (i == nIndex)
+ {
+ return pObject;
+ }
+
+ i++;
+ pObject = aIterator.next();
+ }
+ return nullptr;
+}
+
+std::vector<SdrOle2Obj*> getAllPivotChartsConnectedTo(std::u16string_view sPivotTableName, ScDocShell* pDocShell)
+{
+ std::vector<SdrOle2Obj*> aObjects;
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ ScDrawLayer* pModel = rDocument.GetDrawLayer();
+ if (!pModel)
+ return aObjects;
+
+ sal_uInt16 nPageCount = pModel->GetPageCount();
+ for (sal_uInt16 nPageNo = 0; nPageNo < nPageCount; nPageNo++)
+ {
+ SdrPage* pPage = pModel->GetPage(nPageNo);
+ if (!pPage)
+ continue;
+
+ sc::tools::ChartIterator aIterator(pDocShell, nPageNo, ChartSourceType::PIVOT_TABLE);
+ SdrOle2Obj* pObject = aIterator.next();
+ while (pObject)
+ {
+ if (sPivotTableName == getAssociatedPivotTableName(pObject))
+ {
+ aObjects.push_back(pObject);
+ }
+ pObject = aIterator.next();
+ }
+ }
+ return aObjects;
+}
+
+} // end sc::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/PivotTableDataProvider.cxx b/sc/source/ui/unoobj/PivotTableDataProvider.cxx
new file mode 100644
index 0000000000..e3c800128b
--- /dev/null
+++ b/sc/source/ui/unoobj/PivotTableDataProvider.cxx
@@ -0,0 +1,906 @@
+/* -*- 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/.
+ */
+
+#include <limits>
+#include <memory>
+#include <sal/config.h>
+
+#include <PivotTableDataProvider.hxx>
+#include <PivotTableDataSource.hxx>
+#include <PivotTableDataSequence.hxx>
+
+#include <miscuno.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <unonames.hxx>
+#include <scresid.hxx>
+#include <globstr.hrc>
+#include <strings.hrc>
+#include <dpobject.hxx>
+#include <hints.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/objsh.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+
+#include <com/sun/star/sheet/XDataPilotResults.hpp>
+#include <com/sun/star/sheet/DataResultFlags.hpp>
+
+#include <com/sun/star/sheet/XDimensionsSupplier.hpp>
+#include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
+#include <com/sun/star/sheet/XLevelsSupplier.hpp>
+#include <com/sun/star/sheet/XDataPilotMemberResults.hpp>
+#include <com/sun/star/sheet/MemberResultFlags.hpp>
+#include <com/sun/star/sheet/XMembersSupplier.hpp>
+
+#include <com/sun/star/chart/ChartDataChangeEvent.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+
+#include <unordered_map>
+
+using namespace css;
+
+namespace sc
+{
+namespace
+{
+constexpr OUStringLiteral constIdCategories(u"categories");
+constexpr OUStringLiteral constIdLabel(u"label");
+constexpr OUStringLiteral constIdData(u"data");
+
+std::span<const SfxItemPropertyMapEntry> lcl_GetDataProviderPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_INCLUDEHIDDENCELLS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_USE_INTERNAL_DATA_PROVIDER, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ };
+ return aDataProviderPropertyMap_Impl;
+}
+
+uno::Reference<frame::XModel> lcl_GetXModel(const ScDocument * pDoc)
+{
+ uno::Reference<frame::XModel> xModel;
+ ScDocShell* pObjSh(pDoc ? pDoc->GetDocumentShell() : nullptr);
+ if (pObjSh)
+ xModel.set(pObjSh->GetModel());
+ return xModel;
+}
+
+OUString lcl_identifierForData(sal_Int32 index)
+{
+ return "PT@" + constIdData + " " + OUString::number(index);
+}
+
+OUString lcl_identifierForLabel(sal_Int32 index)
+{
+ return "PT@" + constIdLabel + " " + OUString::number(index);
+}
+
+OUString lcl_identifierForCategories()
+{
+ return "PT@" + constIdCategories;
+}
+
+std::vector<OUString> lcl_getVisiblePageMembers(const uno::Reference<uno::XInterface> & xLevel)
+{
+ std::vector<OUString> aResult;
+ if (!xLevel.is())
+ return aResult;
+
+ uno::Reference<sheet::XMembersSupplier> xMembersSupplier(xLevel, uno::UNO_QUERY);
+ if (!xMembersSupplier.is())
+ return aResult;
+
+ uno::Reference<sheet::XMembersAccess> xMembersAccess = xMembersSupplier->getMembers();
+ if (!xMembersAccess.is())
+ return aResult;
+
+ const css::uno::Sequence<OUString> aMembersNames = xMembersAccess->getElementNames();
+ for (OUString const & rMemberNames : aMembersNames)
+ {
+ uno::Reference<beans::XPropertySet> xProperties(xMembersAccess->getByName(rMemberNames), uno::UNO_QUERY);
+ if (!xProperties.is())
+ continue;
+
+ OUString aCaption = ScUnoHelpFunctions::GetStringProperty(xProperties, SC_UNO_DP_LAYOUTNAME, OUString());
+ if (aCaption.isEmpty())
+ aCaption = rMemberNames;
+
+ bool bVisible = ScUnoHelpFunctions::GetBoolProperty(xProperties, SC_UNO_DP_ISVISIBLE);
+
+ if (bVisible)
+ aResult.push_back(aCaption);
+ }
+
+ return aResult;
+}
+
+} // end anonymous namespace
+
+SC_SIMPLE_SERVICE_INFO(PivotTableDataProvider, "PivotTableDataProvider", SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER)
+
+// DataProvider ==============================================================
+
+PivotTableDataProvider::PivotTableDataProvider(ScDocument& rDoc)
+ : m_pDocument(&rDoc)
+ , m_aPropSet(lcl_GetDataProviderPropertyMap())
+ , m_bIncludeHiddenCells(true)
+ , m_bNeedsUpdate(true)
+ , m_xContext(comphelper::getProcessComponentContext())
+{
+ rDoc.AddUnoObject(*this);
+}
+
+PivotTableDataProvider::~PivotTableDataProvider()
+{
+ SolarMutexGuard g;
+
+ if (m_pDocument)
+ m_pDocument->RemoveUnoObject( *this);
+}
+
+void PivotTableDataProvider::Notify(SfxBroadcaster& /*rBroadcaster*/, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ m_pDocument = nullptr;
+ }
+ else if (m_pDocument)
+ {
+ if (auto pDataPilotHint = dynamic_cast<const ScDataPilotModifiedHint*>(&rHint))
+ {
+ if (pDataPilotHint->GetName() == m_sPivotTableName)
+ {
+ m_bNeedsUpdate = true;
+ for (uno::Reference<util::XModifyListener> const & xListener : m_aValueListeners)
+ {
+ css::chart::ChartDataChangeEvent aEvent(getXWeak(),
+ css::chart::ChartDataChangeType_ALL,
+ 0, 0, 0, 0);
+ xListener->modified(aEvent);
+ }
+ }
+ }
+ }
+}
+
+sal_Bool SAL_CALL PivotTableDataProvider::createDataSourcePossible(const uno::Sequence<beans::PropertyValue>& /*aArguments*/)
+{
+ SolarMutexGuard aGuard;
+ if (!m_pDocument)
+ return false;
+
+ if (m_sPivotTableName.isEmpty())
+ return false;
+
+ ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
+ return bool(pDPCollection->GetByName(m_sPivotTableName));
+}
+
+uno::Reference<chart2::data::XDataSource> SAL_CALL
+ PivotTableDataProvider::createDataSource(const uno::Sequence<beans::PropertyValue>& aArguments)
+{
+ SolarMutexGuard aGuard;
+
+ if (!m_pDocument)
+ throw uno::RuntimeException();
+
+ bool bOrientCol = true;
+ OUString aRangeRepresentation;
+
+ for (beans::PropertyValue const & rProperty : aArguments)
+ {
+ if (rProperty.Name == "DataRowSource")
+ {
+ chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
+ if (!(rProperty.Value >>= eSource))
+ {
+ sal_Int32 nSource(0);
+ if (rProperty.Value >>= nSource)
+ eSource = chart::ChartDataRowSource(nSource);
+ }
+ bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
+ }
+ else if (rProperty.Name == "CellRangeRepresentation")
+ rProperty.Value >>= aRangeRepresentation;
+ }
+
+ uno::Reference<chart2::data::XDataSource> xResult;
+
+ if (aRangeRepresentation == lcl_identifierForCategories())
+ xResult = createCategoriesDataSource(bOrientCol);
+ else
+ xResult = createValuesDataSource();
+
+ return xResult;
+}
+
+uno::Reference<chart2::data::XLabeledDataSequence>
+ PivotTableDataProvider::newLabeledDataSequence()
+{
+ uno::Reference<chart2::data::XLabeledDataSequence> xResult;
+ if (!m_xContext.is())
+ return xResult;
+ xResult.set(chart2::data::LabeledDataSequence::create(m_xContext), uno::UNO_QUERY_THROW);
+ return xResult;
+}
+
+uno::Reference<chart2::data::XDataSource>
+PivotTableDataProvider::createCategoriesDataSource(bool bOrientationIsColumn)
+{
+ if (m_bNeedsUpdate)
+ collectPivotTableData();
+
+ uno::Reference<chart2::data::XDataSource> xDataSource;
+ std::vector<uno::Reference<chart2::data::XLabeledDataSequence>> aLabeledSequences;
+
+ std::vector<std::vector<ValueAndFormat>> const & rCategoriesVector = bOrientationIsColumn ? m_aCategoriesColumnOrientation
+ : m_aCategoriesRowOrientation;
+
+ for (std::vector<ValueAndFormat> const & rCategories : rCategoriesVector)
+ {
+ uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
+ rtl::Reference<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument,
+ lcl_identifierForCategories(), std::vector(rCategories)));
+ pSequence->setRole("categories");
+ xResult->setValues(uno::Reference<chart2::data::XDataSequence>(pSequence));
+
+ aLabeledSequences.push_back(xResult);
+ }
+
+ xDataSource.set(new PivotTableDataSource(std::move(aLabeledSequences)));
+ return xDataSource;
+}
+
+void PivotTableDataProvider::collectPivotTableData()
+{
+ ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
+ ScDPObject* pDPObject = pDPCollection->GetByName(m_sPivotTableName);
+ if (!pDPObject)
+ return;
+
+ m_aCategoriesColumnOrientation.clear();
+ m_aCategoriesRowOrientation.clear();
+ m_aLabels.clear();
+ m_aDataRowVector.clear();
+ m_aColumnFields.clear();
+ m_aRowFields.clear();
+ m_aPageFields.clear();
+ m_aDataFields.clear();
+ m_aFieldOutputDescriptionMap.clear();
+
+ uno::Reference<sheet::XDataPilotResults> xDPResults(pDPObject->GetSource(), uno::UNO_QUERY);
+ if (!xDPResults.is())
+ return;
+ const uno::Sequence<uno::Sequence<sheet::DataResult>> xDataResultsSequence = xDPResults->getResults();
+
+ std::unordered_set<size_t> aValidRowIndex;
+
+ size_t nRowIndex = 0;
+ for (uno::Sequence<sheet::DataResult> const & xDataResults : xDataResultsSequence)
+ {
+ std::vector<ValueAndFormat> aRow;
+ bool bRowEmpty = true;
+ // First pass - collect a row of valid data and track if the row is empty
+ for (sheet::DataResult const & rDataResult : xDataResults)
+ {
+ if (rDataResult.Flags & css::sheet::DataResultFlags::SUBTOTAL)
+ continue;
+ if (rDataResult.Flags == 0 || rDataResult.Flags & css::sheet::DataResultFlags::HASDATA)
+ {
+ aRow.emplace_back(rDataResult.Flags ? rDataResult.Value
+ : std::numeric_limits<double>::quiet_NaN(), 0);
+ if (rDataResult.Flags != 0) // set as valid only if we have data
+ {
+ bRowEmpty = false;
+ // We need to remember all valid (non-empty) row indices
+ aValidRowIndex.insert(nRowIndex);
+ }
+ }
+ }
+ // Second pass: add to collection only non-empty rows
+ if (!bRowEmpty)
+ {
+ size_t nColumnIndex = 0;
+ for (ValueAndFormat const & aValue : aRow)
+ {
+ if (nColumnIndex >= m_aDataRowVector.size())
+ m_aDataRowVector.resize(nColumnIndex + 1);
+ m_aDataRowVector[nColumnIndex].push_back(aValue);
+ nColumnIndex++;
+ }
+ }
+ nRowIndex++;
+ }
+
+ uno::Reference<sheet::XDimensionsSupplier> xDimensionsSupplier(pDPObject->GetSource());
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess(xDimensionsSupplier->getDimensions());
+
+ std::unordered_map<OUString, sal_Int32> aDataFieldNumberFormatMap;
+ std::vector<OUString> aDataFieldNamesVectors;
+
+ std::unordered_map<OUString, OUString> aDataFieldCaptionNames;
+
+ sheet::DataPilotFieldOrientation eDataFieldOrientation = sheet::DataPilotFieldOrientation_HIDDEN;
+
+ for (sal_Int32 nDim = 0; nDim < xDims->getCount(); nDim++)
+ {
+ uno::Reference<uno::XInterface> xDim(xDims->getByIndex(nDim), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xDimProp(xDim, uno::UNO_QUERY);
+ uno::Reference<sheet::XHierarchiesSupplier> xDimSupp(xDim, uno::UNO_QUERY);
+
+ if (!xDimProp.is() || !xDimSupp.is())
+ continue;
+
+ sheet::DataPilotFieldOrientation eDimOrient =
+ ScUnoHelpFunctions::GetEnumProperty(xDimProp, SC_UNO_DP_ORIENTATION,
+ sheet::DataPilotFieldOrientation_HIDDEN);
+
+ if (eDimOrient == sheet::DataPilotFieldOrientation_HIDDEN)
+ continue;
+
+ uno::Reference<container::XIndexAccess> xHierarchies = new ScNameToIndexAccess(xDimSupp->getHierarchies());
+ sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_USEDHIERARCHY);
+ if (nHierarchy >= xHierarchies->getCount())
+ nHierarchy = 0;
+
+ uno::Reference<sheet::XLevelsSupplier> xLevelsSupplier(xHierarchies->getByIndex(nHierarchy),
+ uno::UNO_QUERY);
+
+ if (!xLevelsSupplier.is())
+ continue;
+
+ uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess(xLevelsSupplier->getLevels());
+
+ for (tools::Long nLevel = 0; nLevel < xLevels->getCount(); nLevel++)
+ {
+ uno::Reference<uno::XInterface> xLevel(xLevels->getByIndex(nLevel), uno::UNO_QUERY);
+ uno::Reference<container::XNamed> xLevelName(xLevel, uno::UNO_QUERY);
+ uno::Reference<sheet::XDataPilotMemberResults> xLevelResult(xLevel, uno::UNO_QUERY );
+
+ if (xLevelName.is() && xLevelResult.is())
+ {
+ bool bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty(xDimProp, SC_UNO_DP_ISDATALAYOUT);
+ sal_Int32 nDimPos = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_POSITION);
+ sal_Int32 nNumberFormat = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_NUMBERFO);
+ bool bHasHiddenMember = ScUnoHelpFunctions::GetBoolProperty(xDimProp, SC_UNO_DP_HAS_HIDDEN_MEMBER);
+
+ switch (eDimOrient)
+ {
+ case sheet::DataPilotFieldOrientation_COLUMN:
+ {
+ m_aColumnFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
+
+ const uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
+ size_t i = 0;
+ OUString sCaption;
+ OUString sName;
+ for (sheet::MemberResult const & rMember : aSequence)
+ {
+ // Skip grandtotals and subtotals
+ if (rMember.Flags & sheet::MemberResultFlags::SUBTOTAL ||
+ rMember.Flags & sheet::MemberResultFlags::GRANDTOTAL)
+ continue;
+ if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER ||
+ rMember.Flags & sheet::MemberResultFlags::CONTINUE)
+ {
+ if (!(rMember.Flags & sheet::MemberResultFlags::CONTINUE))
+ {
+ sCaption = rMember.Caption;
+ sName = rMember.Name;
+ }
+
+ if (i >= m_aLabels.size())
+ m_aLabels.resize(i + 1);
+
+ if (o3tl::make_unsigned(nDimPos) >= m_aLabels[i].size())
+ m_aLabels[i].resize(nDimPos + 1);
+ m_aLabels[i][nDimPos] = ValueAndFormat(sCaption);
+
+ if (bIsDataLayout)
+ {
+ // Remember data fields to determine the number format of data
+ aDataFieldNamesVectors.push_back(sName);
+ eDataFieldOrientation = sheet::DataPilotFieldOrientation_COLUMN;
+ // Remember the caption name
+ aDataFieldCaptionNames[rMember.Name] = rMember.Caption;
+ }
+ i++;
+ }
+ }
+ }
+ break;
+
+ case sheet::DataPilotFieldOrientation_ROW:
+ {
+ m_aRowFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
+
+ const uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
+
+ size_t i = 0;
+ size_t nEachIndex = 0;
+ std::unique_ptr<ValueAndFormat> pItem;
+
+ for (sheet::MemberResult const & rMember : aSequence)
+ {
+ bool bFound = aValidRowIndex.find(nEachIndex) != aValidRowIndex.end();
+
+ nEachIndex++;
+
+ bool bHasContinueFlag = rMember.Flags & sheet::MemberResultFlags::CONTINUE;
+
+ if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER || bHasContinueFlag)
+ {
+ if (!bHasContinueFlag)
+ {
+ // Chart2 does not use number format for labels, so use the display string.
+ pItem.reset(new ValueAndFormat(rMember.Caption));
+ }
+
+ if (bFound)
+ {
+ assert(pItem && "bHasContinueFlag must be false on this or some preceding element");
+
+ if (i >= m_aCategoriesRowOrientation.size())
+ m_aCategoriesRowOrientation.resize(i + 1);
+
+ if (o3tl::make_unsigned(nDimPos) >= m_aCategoriesColumnOrientation.size())
+ m_aCategoriesColumnOrientation.resize(nDimPos + 1);
+ m_aCategoriesColumnOrientation[nDimPos].push_back(*pItem);
+
+ if (o3tl::make_unsigned(nDimPos) >= m_aCategoriesRowOrientation[i].size())
+ m_aCategoriesRowOrientation[i].resize(nDimPos + 1);
+ m_aCategoriesRowOrientation[i][nDimPos] = *pItem;
+
+ if (bIsDataLayout)
+ {
+ // Remember data fields to determine the number format of data
+ aDataFieldNamesVectors.push_back(rMember.Name);
+ eDataFieldOrientation = sheet::DataPilotFieldOrientation_ROW;
+
+ // Remember the caption name
+ aDataFieldCaptionNames[rMember.Name] = rMember.Caption;
+ }
+
+ // Set to empty so the sub categories are set to empty when they continue
+ pItem.reset(new ValueAndFormat);
+ i++;
+ }
+ }
+ }
+ }
+ break;
+
+ case sheet::DataPilotFieldOrientation_PAGE:
+ {
+ m_aPageFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
+
+ // Resolve filtering
+ OUString aFieldOutputDescription;
+ if (bHasHiddenMember)
+ {
+ std::vector<OUString> aMembers = lcl_getVisiblePageMembers(xLevel);
+
+ if (aMembers.size() == 1)
+ aFieldOutputDescription = aMembers[0];
+ else
+ aFieldOutputDescription = ScResId(SCSTR_MULTIPLE);
+ }
+ else
+ {
+ aFieldOutputDescription = ScResId(SCSTR_ALL);
+ }
+ m_aFieldOutputDescriptionMap[nDim] = aFieldOutputDescription;
+ }
+ break;
+
+ case sheet::DataPilotFieldOrientation_DATA:
+ {
+ aDataFieldNumberFormatMap[xLevelName->getName()] = nNumberFormat;
+ m_aDataFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // Transform the name of data fields
+ for (chart2::data::PivotTableFieldEntry& rDataFields : m_aDataFields)
+ {
+ rDataFields.Name = aDataFieldCaptionNames[rDataFields.Name];
+ }
+
+ // Apply number format to the data
+ if (eDataFieldOrientation == sheet::DataPilotFieldOrientation_ROW)
+ {
+ for (std::vector<ValueAndFormat> & rDataRow : m_aDataRowVector)
+ {
+ size_t i = 0;
+ for (ValueAndFormat & rItem : rDataRow)
+ {
+ OUString sName = aDataFieldNamesVectors[i];
+ sal_Int32 nNumberFormat = aDataFieldNumberFormatMap[sName];
+ rItem.m_nNumberFormat = nNumberFormat;
+ i++;
+ }
+ }
+ }
+ else if (eDataFieldOrientation == sheet::DataPilotFieldOrientation_COLUMN)
+ {
+ size_t i = 0;
+ for (std::vector<ValueAndFormat> & rDataRow : m_aDataRowVector)
+ {
+ OUString sName = aDataFieldNamesVectors[i];
+ sal_Int32 nNumberFormat = aDataFieldNumberFormatMap[sName];
+ for (ValueAndFormat & rItem : rDataRow)
+ {
+ rItem.m_nNumberFormat = nNumberFormat;
+ }
+ i++;
+ }
+ }
+
+ // Sort fields so it respects the order of how it is represented in the pivot table
+
+ auto funcDimensionPositionSortCompare = [] (chart2::data::PivotTableFieldEntry const & entry1,
+ chart2::data::PivotTableFieldEntry const & entry2)
+ {
+ return entry1.DimensionPositionIndex < entry2.DimensionPositionIndex;
+ };
+
+ std::sort(m_aColumnFields.begin(), m_aColumnFields.end(), funcDimensionPositionSortCompare);
+ std::sort(m_aRowFields.begin(), m_aRowFields.end(), funcDimensionPositionSortCompare);
+ std::sort(m_aPageFields.begin(), m_aPageFields.end(), funcDimensionPositionSortCompare);
+ std::sort(m_aDataFields.begin(), m_aDataFields.end(), funcDimensionPositionSortCompare);
+
+ // Mark that we updated the data
+ m_bNeedsUpdate = false;
+}
+
+uno::Reference<chart2::data::XDataSequence>
+PivotTableDataProvider::assignValuesToDataSequence(size_t nIndex)
+{
+ uno::Reference<chart2::data::XDataSequence> xDataSequence;
+ if (nIndex >= m_aDataRowVector.size())
+ return xDataSequence;
+
+ OUString sDataID = lcl_identifierForData(nIndex);
+
+ std::vector<ValueAndFormat> const & rRowOfData = m_aDataRowVector[nIndex];
+ rtl::Reference<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument, sDataID, std::vector(rRowOfData)));
+ pSequence->setRole("values-y");
+ xDataSequence = pSequence;
+ return xDataSequence;
+}
+
+uno::Reference<chart2::data::XDataSequence>
+PivotTableDataProvider::assignLabelsToDataSequence(size_t nIndex)
+{
+ uno::Reference<chart2::data::XDataSequence> xDataSequence;
+
+ OUString sLabelID = lcl_identifierForLabel(nIndex);
+
+ OUStringBuffer aLabel;
+ bool bFirst = true;
+
+ if (m_aLabels.empty())
+ {
+ aLabel = ScResId(STR_PIVOT_TOTAL);
+ }
+ else if (nIndex < m_aLabels.size())
+ {
+ for (ValueAndFormat const & rItem : m_aLabels[nIndex])
+ {
+ if (bFirst)
+ {
+ aLabel.append(rItem.m_aString);
+ bFirst = false;
+ }
+ else
+ {
+ aLabel.append(" - " + rItem.m_aString);
+ }
+ }
+ }
+
+ std::vector<ValueAndFormat> aLabelVector { ValueAndFormat(aLabel.makeStringAndClear()) };
+
+ rtl::Reference<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument,
+ sLabelID, std::move(aLabelVector)));
+ pSequence->setRole("values-y");
+ xDataSequence = pSequence;
+ return xDataSequence;
+}
+
+css::uno::Reference<css::chart2::data::XDataSequence>
+ PivotTableDataProvider::assignFirstCategoriesToDataSequence()
+{
+ uno::Reference<chart2::data::XDataSequence> xDataSequence;
+
+ if (m_aCategoriesColumnOrientation.empty())
+ return xDataSequence;
+
+ std::vector<ValueAndFormat> const & rCategories = m_aCategoriesColumnOrientation.back();
+
+ rtl::Reference<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument,
+ lcl_identifierForCategories(), std::vector(rCategories)));
+ pSequence->setRole("categories");
+ xDataSequence = pSequence;
+
+ return xDataSequence;
+}
+
+uno::Reference<chart2::data::XDataSource>
+ PivotTableDataProvider::createValuesDataSource()
+{
+ if (m_bNeedsUpdate)
+ collectPivotTableData();
+
+ uno::Reference<chart2::data::XDataSource> xDataSource;
+ std::vector<uno::Reference<chart2::data::XLabeledDataSequence>> aLabeledSequences;
+
+ // Fill first sequence of categories
+ {
+ uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
+ xResult->setValues(assignFirstCategoriesToDataSequence());
+ aLabeledSequences.push_back(xResult);
+ }
+
+ // Fill values and labels
+ {
+ for (size_t i = 0; i < m_aDataRowVector.size(); ++i)
+ {
+ uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
+ xResult->setValues(assignValuesToDataSequence(i));
+ xResult->setLabel(assignLabelsToDataSequence(i));
+ aLabeledSequences.push_back(xResult);
+ }
+ }
+
+ xDataSource.set(new PivotTableDataSource(std::move(aLabeledSequences)));
+ return xDataSource;
+}
+
+
+uno::Sequence<beans::PropertyValue> SAL_CALL PivotTableDataProvider::detectArguments(
+ const uno::Reference<chart2::data::XDataSource> & xDataSource)
+{
+ if (!m_pDocument ||!xDataSource.is())
+ return uno::Sequence<beans::PropertyValue>();
+
+ return comphelper::InitPropertySequence({
+ { "CellRangeRepresentation", uno::Any(OUString("PivotChart")) },
+ { "DataRowSource", uno::Any(chart::ChartDataRowSource_COLUMNS) },
+ { "FirstCellAsLabel", uno::Any(false) },
+ { "HasCategories", uno::Any(true) }
+ });
+}
+
+sal_Bool SAL_CALL PivotTableDataProvider::createDataSequenceByRangeRepresentationPossible(const OUString& /*aRangeRepresentation*/)
+{
+ return false;
+}
+
+uno::Reference<chart2::data::XDataSequence> SAL_CALL
+ PivotTableDataProvider::createDataSequenceByRangeRepresentation(const OUString& /*rRangeRepresentation*/)
+{
+ uno::Reference<chart2::data::XDataSequence> xDataSequence;
+ return xDataSequence;
+}
+
+uno::Reference<chart2::data::XDataSequence> SAL_CALL
+ PivotTableDataProvider::createDataSequenceByValueArray(const OUString& /*aRole*/,
+ const OUString& /*aRangeRepresentation*/,
+ const OUString& /*aRoleQualifier*/)
+{
+ return uno::Reference<chart2::data::XDataSequence>();
+}
+
+uno::Reference<sheet::XRangeSelection> SAL_CALL PivotTableDataProvider::getRangeSelection()
+{
+ uno::Reference<sheet::XRangeSelection> xResult;
+
+ uno::Reference<frame::XModel> xModel(lcl_GetXModel(m_pDocument));
+ if (xModel.is())
+ xResult.set(xModel->getCurrentController(), uno::UNO_QUERY);
+
+ return xResult;
+}
+
+// XPivotTableDataProvider ========================================================
+
+uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getColumnFields()
+{
+ return comphelper::containerToSequence(m_aColumnFields);
+}
+
+uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getRowFields()
+{
+ return comphelper::containerToSequence(m_aRowFields);
+}
+
+uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getPageFields()
+{
+ return comphelper::containerToSequence(m_aPageFields);
+}
+
+uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getDataFields()
+{
+ return comphelper::containerToSequence(m_aDataFields);
+}
+
+OUString PivotTableDataProvider::getPivotTableName()
+{
+ return m_sPivotTableName;
+}
+
+void PivotTableDataProvider::setPivotTableName(const OUString& sPivotTableName)
+{
+ ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
+ ScDPObject* pDPObject = pDPCollection->GetByName(sPivotTableName);
+ if (pDPObject)
+ m_sPivotTableName = sPivotTableName;
+}
+
+sal_Bool PivotTableDataProvider::hasPivotTable()
+{
+ if (m_sPivotTableName.isEmpty())
+ return false;
+
+ ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
+ ScDPObject* pDPObject = pDPCollection->GetByName(m_sPivotTableName);
+
+ if (pDPObject)
+ return true;
+
+ return false;
+}
+
+uno::Reference<chart2::data::XDataSequence>
+ PivotTableDataProvider::createDataSequenceOfValuesByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+
+ if (m_bNeedsUpdate)
+ collectPivotTableData();
+
+ return assignValuesToDataSequence(size_t(nIndex));
+}
+
+uno::Reference<css::chart2::data::XDataSequence>
+ PivotTableDataProvider::createDataSequenceOfLabelsByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+
+ if (m_bNeedsUpdate)
+ collectPivotTableData();
+
+ return assignLabelsToDataSequence(size_t(nIndex));
+}
+
+uno::Reference<css::chart2::data::XDataSequence>
+ PivotTableDataProvider::createDataSequenceOfCategories()
+{
+ SolarMutexGuard aGuard;
+
+ if (m_bNeedsUpdate)
+ collectPivotTableData();
+
+ return assignFirstCategoriesToDataSequence();
+}
+
+OUString PivotTableDataProvider::getFieldOutputDescription(sal_Int32 nDimensionIndex)
+{
+ if (nDimensionIndex < 0)
+ return OUString();
+ return m_aFieldOutputDescriptionMap[size_t(nDimensionIndex)];
+}
+
+// XModifyBroadcaster ========================================================
+
+void SAL_CALL PivotTableDataProvider::addModifyListener(const uno::Reference< util::XModifyListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ m_aValueListeners.emplace_back(aListener);
+}
+
+void SAL_CALL PivotTableDataProvider::removeModifyListener(const uno::Reference<util::XModifyListener>& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ sal_uInt16 nCount = m_aValueListeners.size();
+ for (sal_uInt16 n = nCount; n--;)
+ {
+ uno::Reference<util::XModifyListener>& rObject = m_aValueListeners[n];
+ if (rObject == aListener)
+ {
+ m_aValueListeners.erase(m_aValueListeners.begin() + n);
+ }
+ }
+}
+
+// DataProvider XPropertySet ========================================================
+
+uno::Reference< beans::XPropertySetInfo> SAL_CALL
+ PivotTableDataProvider::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL PivotTableDataProvider::setPropertyValue(const OUString& rPropertyName, const uno::Any& rValue)
+{
+ if (rPropertyName != SC_UNONAME_INCLUDEHIDDENCELLS)
+ throw beans::UnknownPropertyException(rPropertyName);
+
+ if (!(rValue >>= m_bIncludeHiddenCells))
+ throw lang::IllegalArgumentException();
+}
+
+uno::Any SAL_CALL PivotTableDataProvider::getPropertyValue(const OUString& rPropertyName)
+{
+ uno::Any aRet;
+ if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS)
+ aRet <<= m_bIncludeHiddenCells;
+ else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
+ {
+ // This is a read-only property.
+ aRet <<= m_pDocument->PastingDrawFromOtherDoc();
+ }
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+ return aRet;
+}
+
+void SAL_CALL PivotTableDataProvider::addPropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataProvider::removePropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference<beans::XPropertyChangeListener>& /*rListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataProvider::addVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataProvider::removeVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/ )
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/PivotTableDataSequence.cxx b/sc/source/ui/unoobj/PivotTableDataSequence.cxx
new file mode 100644
index 0000000000..dc81d03978
--- /dev/null
+++ b/sc/source/ui/unoobj/PivotTableDataSequence.cxx
@@ -0,0 +1,278 @@
+/* -*- 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/.
+ */
+
+#include <memory>
+#include <PivotTableDataSequence.hxx>
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <utility>
+#include <vcl/svapp.hxx>
+
+#include <miscuno.hxx>
+#include <document.hxx>
+#include <unonames.hxx>
+
+using namespace css;
+
+namespace sc
+{
+
+SC_SIMPLE_SERVICE_INFO( PivotTableDataSequence, "PivotTableDataSequence", "com.sun.star.chart2.data.DataSequence")
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetDataSequencePropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDataSequencePropertyMap_Impl[] =
+ {
+ { SC_UNONAME_HIDDENVALUES, 0, cppu::UnoType<uno::Sequence<sal_Int32>>::get(), 0, 0 },
+ { SC_UNONAME_ROLE, 0, cppu::UnoType<css::chart2::data::DataSequenceRole>::get(), 0, 0 },
+ { SC_UNONAME_INCLUDEHIDDENCELLS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ };
+ return aDataSequencePropertyMap_Impl;
+}
+
+PivotTableDataSequence::PivotTableDataSequence(ScDocument* pDocument, OUString sID,
+ std::vector<ValueAndFormat>&& rData)
+ : m_pDocument(pDocument)
+ , m_aID(std::move(sID))
+ , m_aData(std::move(rData))
+ , m_aPropSet(lcl_GetDataSequencePropertyMap())
+{
+ if (m_pDocument)
+ m_pDocument->AddUnoObject(*this);
+}
+
+PivotTableDataSequence::~PivotTableDataSequence()
+{
+ SolarMutexGuard g;
+
+ if (m_pDocument)
+ m_pDocument->RemoveUnoObject(*this);
+}
+
+void PivotTableDataSequence::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ m_pDocument = nullptr;
+ }
+}
+
+uno::Sequence<uno::Any> SAL_CALL PivotTableDataSequence::getData()
+{
+ SolarMutexGuard aGuard;
+
+ if (!m_pDocument)
+ throw uno::RuntimeException();
+
+ uno::Sequence<uno::Any> aSeq(m_aData.size());
+ auto pSeq = aSeq.getArray();
+
+ size_t i = 0;
+ for (ValueAndFormat const & rItem : m_aData)
+ {
+ if (rItem.m_eType == ValueType::Numeric)
+ pSeq[i] <<= double(rItem.m_fValue);
+ else if (rItem.m_eType == ValueType::String)
+ pSeq[i] <<= rItem.m_aString;
+
+ i++;
+ }
+ return aSeq;
+}
+
+// XNumericalDataSequence --------------------------------------------------
+
+uno::Sequence<double> SAL_CALL PivotTableDataSequence::getNumericalData()
+{
+ SolarMutexGuard aGuard;
+ if (!m_pDocument)
+ throw uno::RuntimeException();
+
+ uno::Sequence<double> aSeq(m_aData.size());
+ auto pSeq = aSeq.getArray();
+
+ size_t i = 0;
+ for (ValueAndFormat const & rItem : m_aData)
+ {
+ pSeq[i] = rItem.m_fValue;
+ i++;
+ }
+ return aSeq;
+}
+
+// XTextualDataSequence --------------------------------------------------
+
+uno::Sequence<OUString> SAL_CALL PivotTableDataSequence::getTextualData()
+{
+ SolarMutexGuard aGuard;
+ if (!m_pDocument)
+ throw uno::RuntimeException();
+
+ uno::Sequence<OUString> aSeq(m_aData.size());
+ auto pSeq = aSeq.getArray();
+
+ size_t i = 0;
+ for (ValueAndFormat const & rItem : m_aData)
+ {
+ if (rItem.m_eType == ValueType::String)
+ pSeq[i] = rItem.m_aString;
+ i++;
+ }
+ return aSeq;
+}
+
+OUString SAL_CALL PivotTableDataSequence::getSourceRangeRepresentation()
+{
+ return m_aID;
+}
+
+uno::Sequence<OUString> SAL_CALL PivotTableDataSequence::generateLabel(chart2::data::LabelOrigin /*eOrigin*/)
+{
+ SolarMutexGuard aGuard;
+ if (!m_pDocument)
+ throw uno::RuntimeException();
+
+ uno::Sequence<OUString> aSeq;
+ return aSeq;
+}
+
+sal_Int32 SAL_CALL PivotTableDataSequence::getNumberFormatKeyByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ if (nIndex == -1 && !m_aData.empty())
+ {
+ return m_aData[0].m_nNumberFormat;
+ }
+ else if (nIndex < 0 && o3tl::make_unsigned(nIndex) >= m_aData.size())
+ {
+ SAL_WARN("sc.ui", "Passed invalid index to getNumberFormatKeyByIndex(). Will return default value '0'.");
+ return 0;
+ }
+ return m_aData[size_t(nIndex)].m_nNumberFormat;
+}
+
+// XCloneable ================================================================
+
+uno::Reference<util::XCloneable> SAL_CALL PivotTableDataSequence::createClone()
+{
+ SolarMutexGuard aGuard;
+
+ rtl::Reference<PivotTableDataSequence> pClone(new PivotTableDataSequence(m_pDocument, m_aID, std::vector(m_aData)));
+ pClone->setRole(m_aRole);
+
+ return pClone;
+}
+
+// XModifyBroadcaster ========================================================
+
+void SAL_CALL PivotTableDataSequence::addModifyListener(const uno::Reference<util::XModifyListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+ m_aValueListeners.emplace_back(aListener);
+}
+
+void SAL_CALL PivotTableDataSequence::removeModifyListener(const uno::Reference<util::XModifyListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ sal_uInt16 nCount = m_aValueListeners.size();
+ for (sal_uInt16 n = nCount; n--; )
+ {
+ uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
+ if (rObj == aListener)
+ {
+ m_aValueListeners.erase(m_aValueListeners.begin() + n);
+ }
+ }
+}
+
+// DataSequence XPropertySet -------------------------------------------------
+
+uno::Reference< beans::XPropertySetInfo> SAL_CALL PivotTableDataSequence::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef = new SfxItemPropertySetInfo(m_aPropSet.getPropertyMap());
+ return aRef;
+}
+
+void SAL_CALL PivotTableDataSequence::setPropertyValue(const OUString& rPropertyName, const uno::Any& rValue)
+{
+ if (rPropertyName == SC_UNONAME_ROLE)
+ {
+ if (!(rValue >>= m_aRole))
+ throw lang::IllegalArgumentException();
+ }
+ else if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS
+ || rPropertyName == SC_UNONAME_HIDDENVALUES
+ || rPropertyName == SC_UNONAME_TIME_BASED
+ || rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
+ {}
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+}
+
+uno::Any SAL_CALL PivotTableDataSequence::getPropertyValue(const OUString& rPropertyName)
+{
+ uno::Any aReturn;
+ if (rPropertyName == SC_UNONAME_ROLE)
+ aReturn <<= m_aRole;
+ else if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS)
+ aReturn <<= false;
+ else if (rPropertyName == SC_UNONAME_HIDDENVALUES)
+ {
+ css::uno::Sequence<sal_Int32> aHiddenValues;
+ aReturn <<= aHiddenValues;
+ }
+ else if (rPropertyName == SC_UNONAME_TIME_BASED)
+ {
+ aReturn <<= false;
+ }
+ else if (rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
+ {
+ aReturn <<= false;
+ }
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+ return aReturn;
+}
+
+void SAL_CALL PivotTableDataSequence::addPropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataSequence::removePropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataSequence::addVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataSequence::removeVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/PivotTableDataSource.cxx b/sc/source/ui/unoobj/PivotTableDataSource.cxx
new file mode 100644
index 0000000000..5c47f0d127
--- /dev/null
+++ b/sc/source/ui/unoobj/PivotTableDataSource.cxx
@@ -0,0 +1,49 @@
+/* -*- 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/.
+ */
+
+#include <PivotTableDataSource.hxx>
+
+#include <sal/config.h>
+
+#include <miscuno.hxx>
+
+#include <comphelper/sequence.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace css;
+
+namespace sc
+{
+
+SC_SIMPLE_SERVICE_INFO(PivotTableDataSource, "PivotTableDataSource", "com.sun.star.chart2.data.DataSource")
+
+PivotTableDataSource::PivotTableDataSource(std::vector<css::uno::Reference<css::chart2::data::XLabeledDataSequence>>&& xLabeledSequence)
+ : m_xLabeledSequence(std::move(xLabeledSequence))
+{
+}
+
+PivotTableDataSource::~PivotTableDataSource()
+{
+}
+
+void PivotTableDataSource::Notify(SfxBroadcaster& /*rBroadcaster*/, const SfxHint& /*rHint*/)
+{
+}
+
+uno::Sequence<uno::Reference<chart2::data::XLabeledDataSequence>> SAL_CALL
+ PivotTableDataSource::getDataSequences()
+{
+ SolarMutexGuard aGuard;
+
+ return comphelper::containerToSequence(m_xLabeledSequence);
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/TablePivotChart.cxx b/sc/source/ui/unoobj/TablePivotChart.cxx
new file mode 100644
index 0000000000..107d6d5baa
--- /dev/null
+++ b/sc/source/ui/unoobj/TablePivotChart.cxx
@@ -0,0 +1,104 @@
+/* -*- 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/.
+ */
+
+#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <svx/svdoole2.hxx>
+#include <svtools/embedhlp.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+
+#include <miscuno.hxx>
+#include <docsh.hxx>
+
+#include <TablePivotChart.hxx>
+#include <ChartTools.hxx>
+
+using namespace css;
+
+namespace sc
+{
+
+SC_SIMPLE_SERVICE_INFO(TablePivotChart, "TablePivotChart", "com.sun.star.table.TablePivotChart")
+
+TablePivotChart::TablePivotChart(ScDocShell* pDocShell, SCTAB nTab, OUString aName)
+ : m_pDocShell(pDocShell)
+ , m_nTab(nTab)
+ , m_aChartName(std::move(aName))
+{
+ if (m_pDocShell)
+ m_pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+TablePivotChart::~TablePivotChart()
+{
+ SolarMutexGuard aGuard;
+
+ if (m_pDocShell)
+ m_pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void TablePivotChart::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ m_pDocShell = nullptr;
+}
+
+// XEmbeddedObjectSupplier
+
+uno::Reference<lang::XComponent> SAL_CALL TablePivotChart::getEmbeddedObject()
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* pObject = sc::tools::findChartsByName(m_pDocShell, m_nTab, m_aChartName, sc::tools::ChartSourceType::PIVOT_TABLE);
+ if (pObject && svt::EmbeddedObjectRef::TryRunningState(pObject->GetObjRef()))
+ return uno::Reference<lang::XComponent>(pObject->GetObjRef()->getComponent(), uno::UNO_QUERY);
+ return nullptr;
+}
+
+// XNamed
+
+OUString SAL_CALL TablePivotChart::getName()
+{
+ return m_aChartName;
+}
+
+void SAL_CALL TablePivotChart::setName(OUString const & /* aName */)
+{
+ throw uno::RuntimeException(); // name cannot be changed
+}
+
+// XTablePivotChart
+
+OUString SAL_CALL TablePivotChart::getPivotTableName()
+{
+ SolarMutexGuard aGuard;
+
+ SdrOle2Obj* pObject = sc::tools::findChartsByName(m_pDocShell, m_nTab, m_aChartName, sc::tools::ChartSourceType::PIVOT_TABLE);
+ if (!pObject)
+ return OUString();
+
+ uno::Reference<embed::XEmbeddedObject> xObject = pObject->GetObjRef();
+ if (!xObject.is())
+ return OUString();
+
+ uno::Reference<chart2::XChartDocument> xChartDoc(xObject->getComponent(), uno::UNO_QUERY);
+ if (!xChartDoc.is())
+ return OUString();
+
+ uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xChartDoc->getDataProvider(), uno::UNO_QUERY);
+ if (!xPivotTableDataProvider.is())
+ return OUString();
+
+ return xPivotTableDataProvider->getPivotTableName();
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/TablePivotCharts.cxx b/sc/source/ui/unoobj/TablePivotCharts.cxx
new file mode 100644
index 0000000000..f69a8298c3
--- /dev/null
+++ b/sc/source/ui/unoobj/TablePivotCharts.cxx
@@ -0,0 +1,279 @@
+/* -*- 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/.
+ */
+
+#include <memory>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/chart2/data/XDataReceiver.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include <tools/gen.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdundo.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/classids.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/globname.hxx>
+#include <svtools/embedhlp.hxx>
+#include <comphelper/sequence.hxx>
+#include <vcl/svapp.hxx>
+
+#include <TablePivotChart.hxx>
+#include <TablePivotCharts.hxx>
+#include <PivotTableDataProvider.hxx>
+#include <ChartTools.hxx>
+
+#include <miscuno.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+
+using namespace css;
+
+namespace sc
+{
+
+SC_SIMPLE_SERVICE_INFO(TablePivotCharts, "TablePivotCharts", "com.sun.star.table.TablePivotCharts")
+
+TablePivotCharts::TablePivotCharts(ScDocShell* pDocShell, SCTAB nTab)
+ : m_pDocShell(pDocShell)
+ , m_nTab(nTab)
+{
+ m_pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+TablePivotCharts::~TablePivotCharts()
+{
+ SolarMutexGuard aGuard;
+
+ if (m_pDocShell)
+ m_pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void TablePivotCharts::Notify(SfxBroadcaster& /*rBroadcaster*/, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ m_pDocShell = nullptr;
+}
+
+// XTablePivotCharts
+void SAL_CALL TablePivotCharts::addNewByName(OUString const & rName,
+ const awt::Rectangle& aRect,
+ OUString const & rDataPilotName)
+{
+ SolarMutexGuard aGuard;
+
+ if (!m_pDocShell)
+ return;
+
+ ScDocument& rDoc = m_pDocShell->GetDocument();
+ ScDrawLayer* pModel = m_pDocShell->MakeDrawLayer();
+ SdrPage* pPage = pModel->GetPage(sal_uInt16(m_nTab));
+ if (!pPage)
+ return;
+
+ // chart can't be inserted if any ole object with that name exists on any table
+ // (empty string: generate valid name)
+
+ OUString aName = rName;
+ SCTAB nDummy;
+ if (!aName.isEmpty() && pModel->GetNamedObject(aName, SdrObjKind::OLE2, nDummy))
+ {
+ // object exists - only RuntimeException is specified
+ throw uno::RuntimeException();
+ }
+
+ uno::Reference<embed::XEmbeddedObject> xObject;
+
+ if (SvtModuleOptions().IsChart())
+ xObject = m_pDocShell->GetEmbeddedObjectContainer().CreateEmbeddedObject(SvGlobalName(SO3_SCH_CLASSID).GetByteSequence(), aName);
+
+ if (!xObject.is())
+ return;
+
+ Point aRectPos(aRect.X, aRect.Y);
+ bool bLayoutRTL = rDoc.IsLayoutRTL(m_nTab);
+ if ((aRectPos.X() < 0 && !bLayoutRTL) || (aRectPos.X() > 0 && bLayoutRTL))
+ aRectPos.setX( 0 );
+
+ if (aRectPos.Y() < 0)
+ aRectPos.setY( 0 );
+
+ Size aRectSize(aRect.Width, aRect.Height);
+ if (aRectSize.Width() <= 0)
+ aRectSize.setWidth( 5000 ); // default size
+
+ if (aRectSize.Height() <= 0)
+ aRectSize.setHeight( 5000 );
+
+ ::tools::Rectangle aInsRect(aRectPos, aRectSize);
+
+ sal_Int64 nAspect(embed::Aspects::MSOLE_CONTENT);
+ MapUnit aMapUnit(VCLUnoHelper::UnoEmbed2VCLMapUnit(xObject->getMapUnit(nAspect)));
+ Size aSize(aInsRect.GetSize());
+ aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aMapUnit));
+ awt::Size aAwtSize;
+ aAwtSize.Width = aSize.Width();
+ aAwtSize.Height = aSize.Height();
+
+ rtl::Reference<sc::PivotTableDataProvider> pPivotTableDataProvider(new sc::PivotTableDataProvider(rDoc));
+ pPivotTableDataProvider->setPivotTableName(rDataPilotName);
+
+ uno::Reference<chart2::data::XDataProvider> xDataProvider(pPivotTableDataProvider);
+
+ uno::Reference<chart2::data::XDataReceiver> xReceiver;
+
+ if (xObject.is())
+ xReceiver.set(xObject->getComponent(), uno::UNO_QUERY);
+
+ if (xReceiver.is())
+ {
+ xReceiver->attachDataProvider(xDataProvider);
+
+ uno::Reference<util::XNumberFormatsSupplier> xNumberFormatsSupplier(cppu::getXWeak(m_pDocShell->GetModel()), uno::UNO_QUERY);
+ xReceiver->attachNumberFormatsSupplier(xNumberFormatsSupplier);
+
+ uno::Sequence<beans::PropertyValue> aArgs( comphelper::InitPropertySequence({
+ { "CellRangeRepresentation", uno::Any(rDataPilotName) },
+ { "HasCategories", uno::Any(true) },
+ { "DataRowSource", uno::Any(chart::ChartDataRowSource_COLUMNS) }
+ }));
+ xReceiver->setArguments(aArgs);
+ }
+
+ rtl::Reference<SdrOle2Obj> pObject = new SdrOle2Obj(
+ *pModel,
+ svt::EmbeddedObjectRef(xObject, embed::Aspects::MSOLE_CONTENT),
+ aName,
+ aInsRect);
+
+ if (xObject.is())
+ xObject->setVisualAreaSize(nAspect, aAwtSize);
+
+ pPage->InsertObject(pObject.get());
+ pModel->AddUndo(std::make_unique<SdrUndoInsertObj>(*pObject));
+}
+
+void SAL_CALL TablePivotCharts::removeByName(const OUString& rName)
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* pObject = sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE);
+ if (pObject)
+ {
+ ScDocument& rDoc = m_pDocShell->GetDocument();
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ SdrPage* pPage = pModel->GetPage(sal_uInt16(m_nTab));
+ pModel->AddUndo(std::make_unique<SdrUndoDelObj>(*pObject));
+ pPage->RemoveObject(pObject->GetOrdNum());
+ }
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL TablePivotCharts::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nCount = 0;
+
+ if (!m_pDocShell)
+ return nCount;
+
+ sc::tools::ChartIterator aIterator(m_pDocShell, m_nTab, sc::tools::ChartSourceType::PIVOT_TABLE);
+
+ SdrOle2Obj* pOleObject = aIterator.next();
+ while (pOleObject)
+ {
+ if (pOleObject->GetObjRef().is())
+ nCount++;
+ pOleObject = aIterator.next();
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL TablePivotCharts::getByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* pObject = sc::tools::getChartByIndex(m_pDocShell, m_nTab, nIndex,
+ sc::tools::ChartSourceType::PIVOT_TABLE);
+ if (!pObject)
+ throw lang::IndexOutOfBoundsException();
+
+ OUString aName;
+ uno::Reference<embed::XEmbeddedObject> xObject = pObject->GetObjRef();
+ if (xObject.is())
+ aName = m_pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName(xObject);
+
+ if (aName.isEmpty())
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Reference<table::XTablePivotChart> xChart(new TablePivotChart(m_pDocShell, m_nTab, aName));
+ if (!xChart.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xChart);
+}
+
+uno::Type SAL_CALL TablePivotCharts::getElementType()
+{
+ return cppu::UnoType<table::XTablePivotChart>::get();
+}
+
+sal_Bool SAL_CALL TablePivotCharts::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return getCount() != 0;
+}
+
+uno::Any SAL_CALL TablePivotCharts::getByName(OUString const & rName)
+{
+ SolarMutexGuard aGuard;
+
+ if (!sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE))
+ throw container::NoSuchElementException();
+
+ uno::Reference<table::XTablePivotChart> xChart(new TablePivotChart(m_pDocShell, m_nTab, rName));
+ if (!xChart.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xChart);
+}
+
+uno::Sequence<OUString> SAL_CALL TablePivotCharts::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ std::vector<OUString> aElements;
+ sc::tools::ChartIterator aIterator(m_pDocShell, m_nTab, sc::tools::ChartSourceType::PIVOT_TABLE);
+
+ SdrOle2Obj* pOleObject = aIterator.next();
+ while (pOleObject)
+ {
+ uno::Reference<embed::XEmbeddedObject> xObject = pOleObject->GetObjRef();
+ if (xObject.is())
+ {
+ OUString aName = m_pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName(xObject);
+ aElements.push_back(aName);
+ }
+ pOleObject = aIterator.next();
+ }
+ return comphelper::containerToSequence(aElements);
+}
+
+sal_Bool SAL_CALL TablePivotCharts::hasByName(OUString const & rName)
+{
+ SolarMutexGuard aGuard;
+
+ return sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE) != nullptr;
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/addruno.cxx b/sc/source/ui/unoobj/addruno.cxx
new file mode 100644
index 0000000000..7a1c2b8b80
--- /dev/null
+++ b/sc/source/ui/unoobj/addruno.cxx
@@ -0,0 +1,298 @@
+/* -*- 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 <com/sun/star/table/CellAddress.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <svl/itemprop.hxx>
+#include <vcl/svapp.hxx>
+
+#include <docsh.hxx>
+#include <unonames.hxx>
+#include <miscuno.hxx>
+#include <convuno.hxx>
+#include <addruno.hxx>
+
+using namespace com::sun::star;
+
+ScAddressConversionObj::ScAddressConversionObj(ScDocShell* pDocSh, bool _bIsRange) :
+ pDocShell( pDocSh ),
+ nRefSheet( 0 ),
+ bIsRange( _bIsRange )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScAddressConversionObj::~ScAddressConversionObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScAddressConversionObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // invalid
+ }
+}
+
+bool ScAddressConversionObj::ParseUIString( const OUString& rUIString, ::formula::FormulaGrammar::AddressConvention eConv )
+{
+ if (!pDocShell)
+ return false;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bSuccess = false;
+ if ( bIsRange )
+ {
+ ScRefFlags nResult = aRange.ParseAny( rUIString, rDoc, eConv );
+ if ( nResult & ScRefFlags::VALID )
+ {
+ if ( ( nResult & ScRefFlags::TAB_3D ) == ScRefFlags::ZERO )
+ aRange.aStart.SetTab( static_cast<SCTAB>(nRefSheet) );
+ if ( ( nResult & ScRefFlags::TAB2_3D ) == ScRefFlags::ZERO )
+ aRange.aEnd.SetTab( aRange.aStart.Tab() );
+ // different sheets are not supported in CellRangeAddress
+ if ( aRange.aStart.Tab() == aRange.aEnd.Tab() )
+ bSuccess = true;
+ }
+ }
+ else
+ {
+ ScRefFlags nResult = aRange.aStart.Parse( rUIString, rDoc, eConv );
+ if ( nResult & ScRefFlags::VALID )
+ {
+ if ( ( nResult & ScRefFlags::TAB_3D ) == ScRefFlags::ZERO )
+ aRange.aStart.SetTab( static_cast<SCTAB>(nRefSheet) );
+ bSuccess = true;
+ }
+ }
+ return bSuccess;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAddressConversionObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+
+ if ( bIsRange )
+ {
+ static const SfxItemPropertyMapEntry aPropertyMap[] =
+ {
+ { SC_UNONAME_ADDRESS, 0, cppu::UnoType<table::CellRangeAddress>::get(), 0, 0 },
+ { SC_UNONAME_PERSREPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_XLA1REPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_REFSHEET, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_UIREPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_XLA1REPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ };
+ static uno::Reference<beans::XPropertySetInfo> aRef(new SfxItemPropertySetInfo( aPropertyMap ));
+ return aRef;
+ }
+ else
+ {
+ static const SfxItemPropertyMapEntry aPropertyMap[] =
+ {
+ { SC_UNONAME_ADDRESS, 0, cppu::UnoType<table::CellAddress>::get(), 0, 0 },
+ { SC_UNONAME_PERSREPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_XLA1REPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_REFSHEET, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_UIREPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_XLA1REPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ };
+ static uno::Reference<beans::XPropertySetInfo> aRef(new SfxItemPropertySetInfo( aPropertyMap ));
+ return aRef;
+ }
+}
+
+void SAL_CALL ScAddressConversionObj::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
+{
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ bool bSuccess = false;
+ if ( aPropertyName == SC_UNONAME_ADDRESS )
+ {
+ // read the cell/range address from API struct
+ if ( bIsRange )
+ {
+ table::CellRangeAddress aRangeAddress;
+ if ( aValue >>= aRangeAddress )
+ {
+ ScUnoConversion::FillScRange( aRange, aRangeAddress );
+ bSuccess = true;
+ }
+ }
+ else
+ {
+ table::CellAddress aCellAddress;
+ if ( aValue >>= aCellAddress )
+ {
+ ScUnoConversion::FillScAddress( aRange.aStart, aCellAddress );
+ bSuccess = true;
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_REFSHEET )
+ {
+ // set the reference sheet
+ sal_Int32 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ {
+ nRefSheet = nIntVal;
+ bSuccess = true;
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_UIREPR )
+ {
+ // parse the UI representation string
+ OUString sRepresentation;
+ if (aValue >>= sRepresentation)
+ {
+ bSuccess = ParseUIString( sRepresentation );
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_PERSREPR || aPropertyName == SC_UNONAME_XLA1REPR )
+ {
+ ::formula::FormulaGrammar::AddressConvention eConv = aPropertyName == SC_UNONAME_XLA1REPR ?
+ ::formula::FormulaGrammar::CONV_XL_A1 : ::formula::FormulaGrammar::CONV_OOO;
+
+ // parse the file format string
+ OUString sRepresentation;
+ if (aValue >>= sRepresentation)
+ {
+ OUString aUIString(sRepresentation);
+
+ // cell or range: strip a single "." at the start
+ if ( aUIString[0]== '.' )
+ aUIString = aUIString.copy( 1 );
+
+ if ( bIsRange )
+ {
+ // range: also strip a "." after the last colon
+ sal_Int32 nColon = aUIString.lastIndexOf( ':' );
+ if ( nColon >= 0 && nColon < aUIString.getLength() - 1 &&
+ aUIString[nColon+1] == '.' )
+ aUIString = aUIString.replaceAt( nColon+1, 1, u"" );
+ }
+
+ // parse the rest like a UI string
+ bSuccess = ParseUIString( aUIString, eConv );
+ }
+ }
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ if ( !bSuccess )
+ throw lang::IllegalArgumentException();
+}
+
+uno::Any SAL_CALL ScAddressConversionObj::getPropertyValue( const OUString& aPropertyName )
+{
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ uno::Any aRet;
+
+ if ( aPropertyName == SC_UNONAME_ADDRESS )
+ {
+ if ( bIsRange )
+ {
+ table::CellRangeAddress aRangeAddress;
+ ScUnoConversion::FillApiRange( aRangeAddress, aRange );
+ aRet <<= aRangeAddress;
+ }
+ else
+ {
+ table::CellAddress aCellAddress;
+ ScUnoConversion::FillApiAddress( aCellAddress, aRange.aStart );
+ aRet <<= aCellAddress;
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_REFSHEET )
+ {
+ aRet <<= nRefSheet;
+ }
+ else if ( aPropertyName == SC_UNONAME_UIREPR )
+ {
+ // generate UI representation string - include sheet only if different from ref sheet
+ OUString aFormatStr;
+ ScRefFlags nFlags = ScRefFlags::VALID;
+ if ( aRange.aStart.Tab() != nRefSheet )
+ nFlags |= ScRefFlags::TAB_3D;
+ if ( bIsRange )
+ aFormatStr = aRange.Format(rDoc, nFlags);
+ else
+ aFormatStr = aRange.aStart.Format(nFlags, &rDoc);
+ aRet <<= aFormatStr;
+ }
+ else if ( aPropertyName == SC_UNONAME_PERSREPR || aPropertyName == SC_UNONAME_XLA1REPR )
+ {
+ ::formula::FormulaGrammar::AddressConvention eConv = aPropertyName == SC_UNONAME_XLA1REPR ?
+ ::formula::FormulaGrammar::CONV_XL_A1 : ::formula::FormulaGrammar::CONV_OOO;
+
+ // generate file format string - always include sheet
+ OUString aFormatStr(aRange.aStart.Format(ScRefFlags::VALID | ScRefFlags::TAB_3D, &rDoc, eConv));
+ if ( bIsRange )
+ {
+ // manually concatenate range so both parts always have the sheet name
+ aFormatStr += ":";
+ ScRefFlags nFlags = ScRefFlags::VALID;
+ if( eConv != ::formula::FormulaGrammar::CONV_XL_A1 )
+ nFlags |= ScRefFlags::TAB_3D;
+ OUString aSecond(aRange.aEnd.Format(nFlags, &rDoc, eConv));
+ aFormatStr += aSecond ;
+ }
+ aRet <<= aFormatStr;
+ }
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAddressConversionObj )
+
+// lang::XServiceInfo
+
+OUString SAL_CALL ScAddressConversionObj::getImplementationName()
+{
+ return "ScAddressConversionObj";
+}
+
+sal_Bool SAL_CALL ScAddressConversionObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScAddressConversionObj::getSupportedServiceNames()
+{
+ if (bIsRange)
+ return {SC_SERVICENAME_RANGEADDRESS};
+ else
+ return {SC_SERVICENAME_CELLADDRESS};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/afmtuno.cxx b/sc/source/ui/unoobj/afmtuno.cxx
new file mode 100644
index 0000000000..fce07d2b96
--- /dev/null
+++ b/sc/source/ui/unoobj/afmtuno.cxx
@@ -0,0 +1,718 @@
+/* -*- 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 <scitems.hxx>
+#include <editeng/memberids.h>
+#include <osl/diagnose.h>
+#include <svl/poolitem.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <svx/unomid.hxx>
+#include <unowids.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/table/CellHoriJustify.hpp>
+#include <com/sun/star/table/CellOrientation.hpp>
+#include <com/sun/star/table/TableBorder2.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+
+#include <attrib.hxx>
+#include <afmtuno.hxx>
+#include <miscuno.hxx>
+#include <autoform.hxx>
+#include <scdll.hxx>
+#include <unonames.hxx>
+#include <cellsuno.hxx>
+
+using namespace ::com::sun::star;
+
+// an AutoFormat has always 16 entries
+#define SC_AF_FIELD_COUNT 16
+
+// AutoFormat map only for PropertySetInfo without Which-IDs
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetAutoFormatMap()
+{
+ static const SfxItemPropertyMapEntry aAutoFormatMap_Impl[] =
+ {
+ { SC_UNONAME_INCBACK, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_INCBORD, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_INCFONT, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_INCJUST, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_INCNUM, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_INCWIDTH, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ };
+ return aAutoFormatMap_Impl;
+}
+
+//! number format (String/Language) ??? (in XNumberFormat only ReadOnly)
+//! table::TableBorder ??!?
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetAutoFieldMap()
+{
+ static const SfxItemPropertyMapEntry aAutoFieldMap_Impl[] =
+ {
+ { SC_UNONAME_CELLBACK, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ { SC_UNONAME_CCOLOR, ATTR_FONT_COLOR, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT, cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CFONT, ATTR_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, ::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT, ::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT, ::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, ::cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, ::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE, ::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE, ::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, ::cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, ::cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE, ::cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, ::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT, ::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT, ::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, ::cppu::UnoType<table::CellHoriJustify>::get(), 0, 0 },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, ::cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ };
+ return aAutoFieldMap_Impl;
+}
+
+constexpr OUString SCAUTOFORMATSOBJ_SERVICE = u"com.sun.star.sheet.TableAutoFormats"_ustr;
+
+SC_SIMPLE_SERVICE_INFO( ScAutoFormatFieldObj, "ScAutoFormatFieldObj", "com.sun.star.sheet.TableAutoFormatField" )
+SC_SIMPLE_SERVICE_INFO( ScAutoFormatObj, "ScAutoFormatObj", "com.sun.star.sheet.TableAutoFormat" )
+SC_SIMPLE_SERVICE_INFO( ScAutoFormatsObj, "stardiv.StarCalc.ScAutoFormatsObj", SCAUTOFORMATSOBJ_SERVICE )
+
+static bool lcl_FindAutoFormatIndex( const ScAutoFormat& rFormats, std::u16string_view rName, sal_uInt16& rOutIndex )
+{
+ ScAutoFormat::const_iterator itBeg = rFormats.begin(), itEnd = rFormats.end();
+ for (ScAutoFormat::const_iterator it = itBeg; it != itEnd; ++it)
+ {
+ const ScAutoFormatData *const pEntry = it->second.get();
+ const OUString& aEntryName = pEntry->GetName();
+ if ( aEntryName == rName )
+ {
+ size_t nPos = std::distance(itBeg, it);
+ rOutIndex = nPos;
+ return true;
+ }
+ }
+ return false;
+}
+
+ScAutoFormatsObj::ScAutoFormatsObj()
+{
+ //! This object should only exist once and it must be known to Auto-Format-Data,
+ //! so that changes can be broadcasted
+}
+
+ScAutoFormatsObj::~ScAutoFormatsObj()
+{
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ScAutoFormatsObj_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScAutoFormatsObj);
+}
+
+// XTableAutoFormats
+
+rtl::Reference<ScAutoFormatObj> ScAutoFormatsObj::GetObjectByIndex_Impl(sal_uInt16 nIndex)
+{
+ if (nIndex < ScGlobal::GetOrCreateAutoFormat()->size())
+ return new ScAutoFormatObj(nIndex);
+
+ return nullptr; // wrong index
+}
+
+rtl::Reference<ScAutoFormatObj> ScAutoFormatsObj::GetObjectByName_Impl(std::u16string_view aName)
+{
+ sal_uInt16 nIndex;
+ if (lcl_FindAutoFormatIndex(
+ *ScGlobal::GetOrCreateAutoFormat(), aName, nIndex ))
+ return GetObjectByIndex_Impl(nIndex);
+ return nullptr;
+}
+
+// container::XNameContainer
+
+void SAL_CALL ScAutoFormatsObj::insertByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ // Reflection need not be uno::XInterface, can be any interface...
+ uno::Reference< uno::XInterface > xInterface(aElement, uno::UNO_QUERY);
+ if ( xInterface.is() )
+ {
+ ScAutoFormatObj* pFormatObj = dynamic_cast<ScAutoFormatObj*>( xInterface.get() );
+ if ( pFormatObj && !pFormatObj->IsInserted() )
+ {
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+
+ sal_uInt16 nDummy;
+ if (lcl_FindAutoFormatIndex( *pFormats, aName, nDummy ))
+ {
+ throw container::ElementExistException();
+ }
+
+ std::unique_ptr<ScAutoFormatData> pNew(new ScAutoFormatData());
+ pNew->SetName( aName );
+
+ if (pFormats->insert(std::move(pNew)) != pFormats->end())
+ {
+ //! notify to other objects
+ pFormats->Save();
+
+ sal_uInt16 nNewIndex;
+ if (lcl_FindAutoFormatIndex( *pFormats, aName, nNewIndex ))
+ {
+ pFormatObj->InitFormat( nNewIndex ); // can be used now
+ bDone = true;
+ }
+ }
+ else
+ {
+ OSL_FAIL("AutoFormat could not be inserted");
+ throw uno::RuntimeException();
+ }
+ }
+ }
+
+ if (!bDone)
+ {
+ // other errors are handled above
+ throw lang::IllegalArgumentException();
+ }
+}
+
+void SAL_CALL ScAutoFormatsObj::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ //! combine?
+ removeByName( aName );
+ insertByName( aName, aElement );
+}
+
+void SAL_CALL ScAutoFormatsObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+
+ ScAutoFormat::iterator it = pFormats->find(aName);
+ if (it == pFormats->end())
+ {
+ throw container::NoSuchElementException();
+ }
+ pFormats->erase(it);
+
+ //! notify to other objects
+ pFormats->Save(); // save immediately
+
+}
+
+// container::XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScAutoFormatsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.TableAutoFormatEnumeration");
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScAutoFormatsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return ScGlobal::GetOrCreateAutoFormat()->size();
+}
+
+uno::Any SAL_CALL ScAutoFormatsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XNamed > xFormat(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if (!xFormat.is())
+ throw lang::IndexOutOfBoundsException();
+ return uno::Any(xFormat);
+}
+
+uno::Type SAL_CALL ScAutoFormatsObj::getElementType()
+{
+ return cppu::UnoType<container::XNamed>::get(); // must match getByIndex
+}
+
+sal_Bool SAL_CALL ScAutoFormatsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// container::XNameAccess
+
+uno::Any SAL_CALL ScAutoFormatsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XNamed > xFormat(GetObjectByName_Impl(aName));
+ if (!xFormat.is())
+ throw container::NoSuchElementException();
+ return uno::Any(xFormat);
+}
+
+uno::Sequence<OUString> SAL_CALL ScAutoFormatsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ uno::Sequence<OUString> aSeq(pFormats->size());
+ OUString* pAry = aSeq.getArray();
+ size_t i = 0;
+ for (const auto& rEntry : *pFormats)
+ {
+ pAry[i] = rEntry.second->GetName();
+ ++i;
+ }
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScAutoFormatsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nDummy;
+ return lcl_FindAutoFormatIndex(
+ *ScGlobal::GetOrCreateAutoFormat(), aName, nDummy );
+}
+
+ScAutoFormatObj::ScAutoFormatObj(sal_uInt16 nIndex) :
+ aPropSet( lcl_GetAutoFormatMap() ),
+ nFormatIndex( nIndex )
+{
+}
+
+ScAutoFormatObj::~ScAutoFormatObj()
+{
+ // If an AutoFormat object is released, then eventually changes are saved
+ // so that they become visible in e.g Writer
+
+ if (IsInserted())
+ {
+ ScAutoFormat* pFormats = ScGlobal::GetAutoFormat();
+ if ( pFormats && pFormats->IsSaveLater() )
+ pFormats->Save();
+
+ // Save() resets flag SaveLater
+ }
+}
+
+void ScAutoFormatObj::InitFormat( sal_uInt16 nNewIndex )
+{
+ OSL_ENSURE( nFormatIndex == SC_AFMTOBJ_INVALID, "ScAutoFormatObj::InitFormat is multiple" );
+ nFormatIndex = nNewIndex;
+}
+
+// XTableAutoFormat
+
+rtl::Reference<ScAutoFormatFieldObj> ScAutoFormatObj::GetObjectByIndex_Impl(sal_uInt16 nIndex)
+{
+ if ( IsInserted() && nIndex < SC_AF_FIELD_COUNT )
+ return new ScAutoFormatFieldObj( nFormatIndex, nIndex );
+
+ return nullptr;
+}
+
+// container::XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScAutoFormatObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.TableAutoFormatEnumeration");
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScAutoFormatObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if (IsInserted())
+ return SC_AF_FIELD_COUNT; // always 16 elements
+ else
+ return 0;
+}
+
+uno::Any SAL_CALL ScAutoFormatObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+
+ if ( nIndex < 0 || nIndex >= getCount() )
+ throw lang::IndexOutOfBoundsException();
+
+ if (IsInserted())
+ return uno::Any(uno::Reference< beans::XPropertySet >(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex))));
+ return uno::Any();
+}
+
+uno::Type SAL_CALL ScAutoFormatObj::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get(); // must match getByIndex
+}
+
+sal_Bool SAL_CALL ScAutoFormatObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// container::XNamed
+
+OUString SAL_CALL ScAutoFormatObj::getName()
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ if (IsInserted() && nFormatIndex < pFormats->size())
+ return pFormats->findByIndex(nFormatIndex)->GetName();
+
+ return OUString();
+}
+
+void SAL_CALL ScAutoFormatObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+
+ sal_uInt16 nDummy;
+ if (!IsInserted() || nFormatIndex >= pFormats->size() ||
+ lcl_FindAutoFormatIndex( *pFormats, aNewName, nDummy ))
+ {
+ // not inserted or name exists
+ throw uno::RuntimeException();
+ }
+
+ ScAutoFormat::iterator it = pFormats->begin();
+ std::advance(it, nFormatIndex);
+ ScAutoFormatData *const pData = it->second.get();
+ OSL_ENSURE(pData,"AutoFormat data not available");
+
+ std::unique_ptr<ScAutoFormatData> pNew(new ScAutoFormatData(*pData));
+ pNew->SetName( aNewName );
+
+ pFormats->erase(it);
+ it = pFormats->insert(std::move(pNew));
+ if (it != pFormats->end())
+ {
+ ScAutoFormat::iterator itBeg = pFormats->begin();
+ nFormatIndex = std::distance(itBeg, it);
+
+ //! notify to other objects
+ pFormats->SetSaveLater(true);
+ }
+ else
+ {
+ OSL_FAIL("AutoFormat could not be inserted");
+ nFormatIndex = 0; //! old index invalid
+ }
+}
+
+// beans::XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAutoFormatObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScAutoFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ if (!(IsInserted() && nFormatIndex < pFormats->size()))
+ return;
+
+ ScAutoFormatData* pData = pFormats->findByIndex(nFormatIndex);
+ OSL_ENSURE(pData,"AutoFormat data not available");
+
+ bool bBool = false;
+ if (aPropertyName == SC_UNONAME_INCBACK && (aValue >>= bBool))
+ pData->SetIncludeBackground( bBool );
+ else if (aPropertyName == SC_UNONAME_INCBORD && (aValue >>= bBool))
+ pData->SetIncludeFrame( bBool );
+ else if (aPropertyName == SC_UNONAME_INCFONT && (aValue >>= bBool))
+ pData->SetIncludeFont( bBool );
+ else if (aPropertyName == SC_UNONAME_INCJUST && (aValue >>= bBool))
+ pData->SetIncludeJustify( bBool );
+ else if (aPropertyName == SC_UNONAME_INCNUM && (aValue >>= bBool))
+ pData->SetIncludeValueFormat( bBool );
+ else if (aPropertyName == SC_UNONAME_INCWIDTH && (aValue >>= bBool))
+ pData->SetIncludeWidthHeight( bBool );
+
+ // else error
+
+ //! notify to other objects
+ pFormats->SetSaveLater(true);
+}
+
+uno::Any SAL_CALL ScAutoFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aAny;
+
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ if (IsInserted() && nFormatIndex < pFormats->size())
+ {
+ ScAutoFormatData* pData = pFormats->findByIndex(nFormatIndex);
+ OSL_ENSURE(pData,"AutoFormat data not available");
+
+ bool bValue;
+ bool bError = false;
+
+ if (aPropertyName == SC_UNONAME_INCBACK)
+ bValue = pData->GetIncludeBackground();
+ else if (aPropertyName == SC_UNONAME_INCBORD)
+ bValue = pData->GetIncludeFrame();
+ else if (aPropertyName == SC_UNONAME_INCFONT)
+ bValue = pData->GetIncludeFont();
+ else if (aPropertyName == SC_UNONAME_INCJUST)
+ bValue = pData->GetIncludeJustify();
+ else if (aPropertyName == SC_UNONAME_INCNUM)
+ bValue = pData->GetIncludeValueFormat();
+ else if (aPropertyName == SC_UNONAME_INCWIDTH)
+ bValue = pData->GetIncludeWidthHeight();
+ else
+ bError = true; // unknown property
+
+ if (!bError)
+ aAny <<= bValue;
+ }
+
+ return aAny;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAutoFormatObj )
+
+ScAutoFormatFieldObj::ScAutoFormatFieldObj(sal_uInt16 nFormat, sal_uInt16 nField) :
+ aPropSet( lcl_GetAutoFieldMap() ),
+ nFormatIndex( nFormat ),
+ nFieldIndex( nField )
+{
+}
+
+ScAutoFormatFieldObj::~ScAutoFormatFieldObj()
+{
+}
+
+// beans::XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAutoFormatFieldObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScAutoFormatFieldObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ const SfxItemPropertyMapEntry* pEntry =
+ aPropSet.getPropertyMap().getByName( aPropertyName );
+
+ if ( !(pEntry && pEntry->nWID && nFormatIndex < pFormats->size()) )
+ return;
+
+ ScAutoFormatData* pData = pFormats->findByIndex(nFormatIndex);
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ if( const SfxPoolItem* pItem = pData->GetItem( nFieldIndex, pEntry->nWID ) )
+ {
+ bool bDone = false;
+
+ switch( pEntry->nWID )
+ {
+ case ATTR_STACKED:
+ {
+ table::CellOrientation eOrient;
+ if( aValue >>= eOrient )
+ {
+ switch( eOrient )
+ {
+ case table::CellOrientation_STANDARD:
+ pData->PutItem( nFieldIndex, ScVerticalStackCell( false ) );
+ break;
+ case table::CellOrientation_TOPBOTTOM:
+ pData->PutItem( nFieldIndex, ScVerticalStackCell( false ) );
+ pData->PutItem( nFieldIndex, ScRotateValueItem( 27000_deg100 ) );
+ break;
+ case table::CellOrientation_BOTTOMTOP:
+ pData->PutItem( nFieldIndex, ScVerticalStackCell( false ) );
+ pData->PutItem( nFieldIndex, ScRotateValueItem( 9000_deg100 ) );
+ break;
+ case table::CellOrientation_STACKED:
+ pData->PutItem( nFieldIndex, ScVerticalStackCell( true ) );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ bDone = true;
+ }
+ }
+ break;
+ default:
+ std::unique_ptr<SfxPoolItem> pNewItem(pItem->Clone());
+ bDone = pNewItem->PutValue( aValue, pEntry->nMemberId );
+ if (bDone)
+ pData->PutItem( nFieldIndex, *pNewItem );
+ }
+
+ if (bDone)
+ //! Notify to other objects?
+ pFormats->SetSaveLater(true);
+ }
+ }
+ else
+ {
+ switch (pEntry->nWID)
+ {
+ case SC_WID_UNO_TBLBORD:
+ {
+ table::TableBorder aBorder;
+ if ( aValue >>= aBorder ) // empty = nothing to do
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder );
+ pData->PutItem( nFieldIndex, aOuter );
+
+ //! Notify for other objects?
+ pFormats->SetSaveLater(true);
+ }
+ }
+ break;
+ case SC_WID_UNO_TBLBORD2:
+ {
+ table::TableBorder2 aBorder2;
+ if ( aValue >>= aBorder2 ) // empty = nothing to do
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder2 );
+ pData->PutItem( nFieldIndex, aOuter );
+
+ //! Notify for other objects?
+ pFormats->SetSaveLater(true);
+ }
+ }
+ break;
+ }
+ }
+}
+
+uno::Any SAL_CALL ScAutoFormatFieldObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aVal;
+
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ const SfxItemPropertyMapEntry* pEntry =
+ aPropSet.getPropertyMap().getByName( aPropertyName );
+
+ if ( pEntry && pEntry->nWID && nFormatIndex < pFormats->size() )
+ {
+ const ScAutoFormatData* pData = pFormats->findByIndex(nFormatIndex);
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ if( const SfxPoolItem* pItem = pData->GetItem( nFieldIndex, pEntry->nWID ) )
+ {
+ switch( pEntry->nWID )
+ {
+ case ATTR_STACKED:
+ {
+ const ScRotateValueItem* pRotItem = pData->GetItem( nFieldIndex, ATTR_ROTATE_VALUE );
+ Degree100 nRot = pRotItem ? pRotItem->GetValue() : 0_deg100;
+ bool bStacked = static_cast<const ScVerticalStackCell*>(pItem)->GetValue();
+ SvxOrientationItem( nRot, bStacked, TypedWhichId<SvxOrientationItem>(0) ).QueryValue( aVal );
+ }
+ break;
+ default:
+ pItem->QueryValue( aVal, pEntry->nMemberId );
+ }
+ }
+ }
+ else
+ {
+ switch (pEntry->nWID)
+ {
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ {
+ const SfxPoolItem* pItem = pData->GetItem(nFieldIndex, ATTR_BORDER);
+ if (pItem)
+ {
+ SvxBoxItem aOuter(*static_cast<const SvxBoxItem*>(pItem));
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+
+ if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
+ ScHelperFunctions::AssignTableBorder2ToAny( aVal, aOuter, aInner);
+ else
+ ScHelperFunctions::AssignTableBorderToAny( aVal, aOuter, aInner);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return aVal;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAutoFormatFieldObj )
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/appluno.cxx b/sc/source/ui/unoobj/appluno.cxx
new file mode 100644
index 0000000000..3b12dc9da7
--- /dev/null
+++ b/sc/source/ui/unoobj/appluno.cxx
@@ -0,0 +1,619 @@
+/* -*- 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 <appluno.hxx>
+#include <sal/types.h>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <formula/funcvarargs.h>
+
+#include <vcl/svapp.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/sfxmodelfactory.hxx>
+#include <miscuno.hxx>
+#include <scmod.hxx>
+#include <appoptio.hxx>
+#include <inputopt.hxx>
+#include <printopt.hxx>
+#include <userlist.hxx>
+#include <scdll.hxx>
+#include <unonames.hxx>
+#include <funcdesc.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/sheet/FunctionArgument.hpp>
+#include <memory>
+
+using namespace com::sun::star;
+
+// Special value for zoom
+//! somewhere central
+#define SC_ZOOMVAL_OPTIMAL (-1)
+#define SC_ZOOMVAL_WHOLEPAGE (-2)
+#define SC_ZOOMVAL_PAGEWIDTH (-3)
+
+// Number of PropertyValues in a function description
+#define SC_FUNCDESC_PROPCOUNT 5
+
+// everything without Which-ID, map only for PropertySetInfo
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetSettingsPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aSettingsPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_DOAUTOCP, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ENTERED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_EXPREF, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_EXTFMT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_LINKUPD, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_MARKHDR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_METRIC, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_MOVEDIR, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_MOVESEL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_PRALLSH, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_PREMPTY, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_RANGEFIN, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_SCALE, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_STBFUNC, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_ULISTS, 0, cppu::UnoType<uno::Sequence<OUString>>::get(), 0, 0},
+ { SC_UNONAME_PRMETRICS,0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_USETABCOL,0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_REPLWARN, 0, cppu::UnoType<bool>::get(), 0, 0},
+ };
+ return aSettingsPropertyMap_Impl;
+}
+
+constexpr OUString SCFUNCTIONLISTOBJ_SERVICE = u"com.sun.star.sheet.FunctionDescriptions"_ustr;
+constexpr OUString SCRECENTFUNCTIONSOBJ_SERVICE = u"com.sun.star.sheet.RecentFunctions"_ustr;
+constexpr OUString SCSPREADSHEETSETTINGS_SERVICE = u"com.sun.star.sheet.GlobalSheetSettings"_ustr;
+
+SC_SIMPLE_SERVICE_INFO( ScFunctionListObj, "stardiv.StarCalc.ScFunctionListObj", SCFUNCTIONLISTOBJ_SERVICE )
+SC_SIMPLE_SERVICE_INFO( ScRecentFunctionsObj, "stardiv.StarCalc.ScRecentFunctionsObj", SCRECENTFUNCTIONSOBJ_SERVICE )
+SC_SIMPLE_SERVICE_INFO( ScSpreadsheetSettings, "stardiv.StarCalc.ScSpreadsheetSettings", SCSPREADSHEETSETTINGS_SERVICE )
+
+
+ScSpreadsheetSettings::ScSpreadsheetSettings() :
+ aPropSet( lcl_GetSettingsPropertyMap() )
+{
+}
+
+ScSpreadsheetSettings::~ScSpreadsheetSettings()
+{
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_ScSpreadsheetSettings_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScSpreadsheetSettings());
+}
+
+
+bool ScSpreadsheetSettings::getPropertyBool(const OUString& aPropertyName)
+{
+ uno::Any any = getPropertyValue(aPropertyName);
+ bool b = false;
+ any >>= b;
+ return b;
+}
+
+sal_Int16 ScSpreadsheetSettings::getPropertyInt16(const OUString& aPropertyName)
+{
+ uno::Any any = getPropertyValue(aPropertyName);
+ sal_Int16 b = 0;
+ any >>= b;
+ return b;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSpreadsheetSettings::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScSpreadsheetSettings::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ ScModule* pScMod = SC_MOD();
+ ScAppOptions aAppOpt(pScMod->GetAppOptions());
+ ScInputOptions aInpOpt(pScMod->GetInputOptions());
+ bool bSaveApp = false;
+ bool bSaveInp = false;
+ // print options aren't loaded until needed
+
+ if (aPropertyName == SC_UNONAME_DOAUTOCP)
+ {
+ aAppOpt.SetAutoComplete( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveApp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_ENTERED)
+ {
+ aInpOpt.SetEnterEdit( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_EXPREF)
+ {
+ aInpOpt.SetExpandRefs( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_EXTFMT)
+ {
+ aInpOpt.SetExtendFormat( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_LINKUPD)
+ {
+ // XXX NOTE: this is not css::document::Settings property
+ // LinkUpdateMode but css::sheet::XGlobalSheetSettings attribute
+ // LinkUpdateMode.
+ sal_Int16 n;
+ if (!(aValue >>= n) || n < 0 || n >= ScLkUpdMode::LM_UNKNOWN)
+ {
+ throw css::lang::IllegalArgumentException(
+ ("LinkUpdateMode property value must be a SHORT with a value in the range of 0--2"
+ " as documented for css::sheet::XGlobalSheetSettings attribute LinkUpdateMode"),
+ css::uno::Reference<css::uno::XInterface>(), -1);
+ }
+ aAppOpt.SetLinkMode( static_cast<ScLkUpdMode>(n) );
+ bSaveApp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_MARKHDR)
+ {
+ aInpOpt.SetMarkHeader( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_MOVESEL)
+ {
+ aInpOpt.SetMoveSelection( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_RANGEFIN)
+ {
+ aInpOpt.SetRangeFinder( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_USETABCOL)
+ {
+ aInpOpt.SetUseTabCol( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_PRMETRICS)
+ {
+ aInpOpt.SetTextWysiwyg( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_REPLWARN)
+ {
+ aInpOpt.SetReplaceCellsWarn( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_METRIC)
+ {
+ aAppOpt.SetAppMetric( static_cast<FieldUnit>(ScUnoHelpFunctions::GetInt16FromAny( aValue )) );
+ bSaveApp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_MOVEDIR)
+ {
+ aInpOpt.SetMoveDir( ScUnoHelpFunctions::GetInt16FromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_SCALE)
+ {
+ short nVal = ScUnoHelpFunctions::GetInt16FromAny( aValue );
+ if ( nVal < 0 )
+ {
+ SvxZoomType eType = SvxZoomType::PERCENT;
+ switch (nVal)
+ {
+ case SC_ZOOMVAL_OPTIMAL: eType = SvxZoomType::OPTIMAL; break;
+ case SC_ZOOMVAL_WHOLEPAGE: eType = SvxZoomType::WHOLEPAGE; break;
+ case SC_ZOOMVAL_PAGEWIDTH: eType = SvxZoomType::PAGEWIDTH; break;
+ }
+ aAppOpt.SetZoomType( eType );
+ }
+ else if ( nVal >= MINZOOM && nVal <= MAXZOOM )
+ {
+ aAppOpt.SetZoom( nVal );
+ aAppOpt.SetZoomType( SvxZoomType::PERCENT );
+ }
+ bSaveApp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_STBFUNC)
+ {
+ aAppOpt.SetStatusFunc( ScUnoHelpFunctions::GetInt16FromAny( aValue ) );
+ bSaveApp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_ULISTS)
+ {
+ ScUserList* pUserList = ScGlobal::GetUserList();
+ uno::Sequence<OUString> aSeq;
+ if ( pUserList && ( aValue >>= aSeq ) )
+ {
+ // directly change the active list
+ // ScGlobal::SetUseTabCol does not do much else
+
+ pUserList->clear();
+ for (const OUString& aEntry : std::as_const(aSeq))
+ {
+ pUserList->emplace_back(aEntry);
+ }
+ bSaveApp = true; // List with App-Options are saved
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_PRALLSH)
+ {
+ ScPrintOptions aPrintOpt(pScMod->GetPrintOptions());
+ aPrintOpt.SetAllSheets( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ pScMod->SetPrintOptions( aPrintOpt );
+ }
+ else if (aPropertyName == SC_UNONAME_PREMPTY)
+ {
+ ScPrintOptions aPrintOpt(pScMod->GetPrintOptions());
+ aPrintOpt.SetSkipEmpty( !ScUnoHelpFunctions::GetBoolFromAny( aValue ) ); // reversed
+ pScMod->SetPrintOptions( aPrintOpt );
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScPrintOptions ) ); // update previews
+ }
+
+ if ( bSaveApp )
+ pScMod->SetAppOptions( aAppOpt );
+ if ( bSaveInp )
+ pScMod->SetInputOptions( aInpOpt );
+}
+
+uno::Any SAL_CALL ScSpreadsheetSettings::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ ScModule* pScMod = SC_MOD();
+ ScAppOptions aAppOpt = pScMod->GetAppOptions();
+ const ScInputOptions& aInpOpt = pScMod->GetInputOptions();
+ // print options aren't loaded until needed
+
+ if (aPropertyName == SC_UNONAME_DOAUTOCP) aRet <<= aAppOpt.GetAutoComplete();
+ else if (aPropertyName == SC_UNONAME_ENTERED ) aRet <<= aInpOpt.GetEnterEdit();
+ else if (aPropertyName == SC_UNONAME_EXPREF ) aRet <<= aInpOpt.GetExpandRefs();
+ else if (aPropertyName == SC_UNONAME_EXTFMT ) aRet <<= aInpOpt.GetExtendFormat();
+ else if (aPropertyName == SC_UNONAME_LINKUPD ) aRet <<= static_cast<sal_Int16>(aAppOpt.GetLinkMode());
+ else if (aPropertyName == SC_UNONAME_MARKHDR ) aRet <<= aInpOpt.GetMarkHeader();
+ else if (aPropertyName == SC_UNONAME_MOVESEL ) aRet <<= aInpOpt.GetMoveSelection();
+ else if (aPropertyName == SC_UNONAME_RANGEFIN ) aRet <<= aInpOpt.GetRangeFinder();
+ else if (aPropertyName == SC_UNONAME_USETABCOL ) aRet <<= aInpOpt.GetUseTabCol();
+ else if (aPropertyName == SC_UNONAME_PRMETRICS ) aRet <<= aInpOpt.GetTextWysiwyg();
+ else if (aPropertyName == SC_UNONAME_REPLWARN ) aRet <<= aInpOpt.GetReplaceCellsWarn();
+ else if (aPropertyName == SC_UNONAME_METRIC ) aRet <<= static_cast<sal_Int16>(aAppOpt.GetAppMetric());
+ else if (aPropertyName == SC_UNONAME_MOVEDIR ) aRet <<= static_cast<sal_Int16>(aInpOpt.GetMoveDir());
+ else if (aPropertyName == SC_UNONAME_STBFUNC ) aRet <<= static_cast<sal_Int16>(aAppOpt.GetStatusFunc());
+ else if (aPropertyName == SC_UNONAME_SCALE )
+ {
+ sal_Int16 nZoomVal = 0;
+ switch ( aAppOpt.GetZoomType() )
+ {
+ case SvxZoomType::PERCENT: nZoomVal = aAppOpt.GetZoom(); break;
+ case SvxZoomType::OPTIMAL: nZoomVal = SC_ZOOMVAL_OPTIMAL; break;
+ case SvxZoomType::WHOLEPAGE: nZoomVal = SC_ZOOMVAL_WHOLEPAGE; break;
+ case SvxZoomType::PAGEWIDTH: nZoomVal = SC_ZOOMVAL_PAGEWIDTH; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ aRet <<= nZoomVal;
+ }
+ else if (aPropertyName == SC_UNONAME_ULISTS )
+ {
+ ScUserList* pUserList = ScGlobal::GetUserList();
+ if (pUserList)
+ {
+ size_t nCount = pUserList->size();
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ OUString aEntry((*pUserList)[i].GetString());
+ pAry[i] = aEntry;
+ }
+ aRet <<= aSeq;
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_PRALLSH )
+ aRet <<= pScMod->GetPrintOptions().GetAllSheets();
+ else if (aPropertyName == SC_UNONAME_PREMPTY )
+ aRet <<= !pScMod->GetPrintOptions().GetSkipEmpty(); // reversed
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSpreadsheetSettings )
+
+ScRecentFunctionsObj::ScRecentFunctionsObj()
+{
+}
+
+ScRecentFunctionsObj::~ScRecentFunctionsObj()
+{
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ScRecentFunctionsObj_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScRecentFunctionsObj());
+}
+
+// XRecentFunctions
+
+uno::Sequence<sal_Int32> SAL_CALL ScRecentFunctionsObj::getRecentFunctionIds()
+{
+ SolarMutexGuard aGuard;
+ const ScAppOptions& rOpt = SC_MOD()->GetAppOptions();
+ sal_uInt16 nCount = rOpt.GetLRUFuncListCount();
+ const sal_uInt16* pFuncs = rOpt.GetLRUFuncList();
+ if (pFuncs)
+ {
+ uno::Sequence<sal_Int32> aSeq(nCount);
+ sal_Int32* pAry = aSeq.getArray();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ pAry[i] = pFuncs[i];
+ return aSeq;
+ }
+ return {};
+}
+
+void SAL_CALL ScRecentFunctionsObj::setRecentFunctionIds(
+ const uno::Sequence<sal_Int32>& aRecentFunctionIds )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = static_cast<sal_uInt16>(std::min( aRecentFunctionIds.getLength(), sal_Int32(LRU_MAX) ));
+ const sal_Int32* pAry = aRecentFunctionIds.getConstArray();
+
+ std::unique_ptr<sal_uInt16[]> pFuncs(nCount ? new sal_uInt16[nCount] : nullptr);
+ for (sal_uInt16 i=0; i<nCount; i++)
+ pFuncs[i] = static_cast<sal_uInt16>(pAry[i]); //! check for valid values?
+
+ ScModule* pScMod = SC_MOD();
+ ScAppOptions aNewOpts(pScMod->GetAppOptions());
+ aNewOpts.SetLRUFuncList(pFuncs.get(), nCount);
+ pScMod->SetAppOptions(aNewOpts);
+}
+
+sal_Int32 SAL_CALL ScRecentFunctionsObj::getMaxRecentFunctions()
+{
+ return LRU_MAX;
+}
+
+ScFunctionListObj::ScFunctionListObj()
+{
+}
+
+ScFunctionListObj::~ScFunctionListObj()
+{
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ScFunctionListObj_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScFunctionListObj());
+}
+
+static void lcl_FillSequence( uno::Sequence<beans::PropertyValue>& rSequence, const ScFuncDesc& rDesc )
+{
+ rDesc.initArgumentInfo(); // full argument info is needed
+
+ OSL_ENSURE( rSequence.getLength() == SC_FUNCDESC_PROPCOUNT, "Wrong count" );
+
+ beans::PropertyValue* pArray = rSequence.getArray();
+
+ pArray[0].Name = SC_UNONAME_ID;
+ pArray[0].Value <<= static_cast<sal_Int32>(rDesc.nFIndex);
+
+ pArray[1].Name = SC_UNONAME_CATEGORY;
+ pArray[1].Value <<= static_cast<sal_Int32>(rDesc.nCategory);
+
+ pArray[2].Name = SC_UNONAME_NAME;
+ if (rDesc.mxFuncName)
+ pArray[2].Value <<= *rDesc.mxFuncName;
+
+ pArray[3].Name = SC_UNONAME_DESCRIPTION;
+ if (rDesc.mxFuncDesc)
+ pArray[3].Value <<= *rDesc.mxFuncDesc;
+
+ pArray[4].Name = SC_UNONAME_ARGUMENTS;
+ if (rDesc.maDefArgNames.empty() || rDesc.maDefArgDescs.empty() || !rDesc.pDefArgFlags)
+ return;
+
+ sal_uInt16 nCount = rDesc.nArgCount;
+ if (nCount >= PAIRED_VAR_ARGS)
+ nCount -= PAIRED_VAR_ARGS - 2;
+ else if (nCount >= VAR_ARGS)
+ nCount -= VAR_ARGS - 1;
+ sal_uInt16 nSeqCount = rDesc.GetSuppressedArgCount();
+ if (nSeqCount >= PAIRED_VAR_ARGS)
+ nSeqCount -= PAIRED_VAR_ARGS - 2;
+ else if (nSeqCount >= VAR_ARGS)
+ nSeqCount -= VAR_ARGS - 1;
+
+ if (!nSeqCount)
+ return;
+
+ uno::Sequence<sheet::FunctionArgument> aArgSeq(nSeqCount);
+ sheet::FunctionArgument* pArgAry = aArgSeq.getArray();
+ for (sal_uInt16 i=0, j=0; i<nCount; i++)
+ {
+ sheet::FunctionArgument aArgument;
+ aArgument.Name = rDesc.maDefArgNames[i];
+ aArgument.Description = rDesc.maDefArgDescs[i];
+ aArgument.IsOptional = rDesc.pDefArgFlags[i].bOptional;
+ pArgAry[j++] = aArgument;
+ }
+ pArray[4].Value <<= aArgSeq;
+}
+
+// XFunctionDescriptions
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScFunctionListObj::getById( sal_Int32 nId )
+{
+ SolarMutexGuard aGuard;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( !pFuncList )
+ throw uno::RuntimeException(); // should not happen
+
+ sal_uInt16 nCount = static_cast<sal_uInt16>(pFuncList->GetCount());
+ for (sal_uInt16 nIndex=0; nIndex<nCount; nIndex++)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(nIndex);
+ if ( pDesc && pDesc->nFIndex == nId )
+ {
+ uno::Sequence<beans::PropertyValue> aSeq( SC_FUNCDESC_PROPCOUNT );
+ lcl_FillSequence( aSeq, *pDesc );
+ return aSeq;
+ }
+ }
+
+ throw lang::IllegalArgumentException(); // not found
+}
+
+// XNameAccess
+
+uno::Any SAL_CALL ScFunctionListObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( !pFuncList )
+ throw uno::RuntimeException(); // should not happen
+
+ sal_uInt16 nCount = static_cast<sal_uInt16>(pFuncList->GetCount());
+ for (sal_uInt16 nIndex=0; nIndex<nCount; nIndex++)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(nIndex);
+ //! Case-insensitive???
+ if ( pDesc && pDesc->mxFuncName && aName == *pDesc->mxFuncName )
+ {
+ uno::Sequence<beans::PropertyValue> aSeq( SC_FUNCDESC_PROPCOUNT );
+ lcl_FillSequence( aSeq, *pDesc );
+ return uno::Any(aSeq);
+ }
+ }
+
+ throw container::NoSuchElementException(); // not found
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScFunctionListObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nCount = 0;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( pFuncList )
+ nCount = static_cast<sal_Int32>(pFuncList->GetCount());
+ return nCount;
+}
+
+uno::Any SAL_CALL ScFunctionListObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( !pFuncList )
+ throw uno::RuntimeException(); // should not happen
+
+ if ( nIndex >= 0 && o3tl::make_unsigned(nIndex) < pFuncList->GetCount() )
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(nIndex);
+ if ( pDesc )
+ {
+ uno::Sequence<beans::PropertyValue> aSeq( SC_FUNCDESC_PROPCOUNT );
+ lcl_FillSequence( aSeq, *pDesc );
+ return uno::Any(aSeq);
+ }
+ }
+
+ throw lang::IndexOutOfBoundsException(); // illegal index
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScFunctionListObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.FunctionDescriptionEnumeration");
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScFunctionListObj::getElementType()
+{
+ return cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get();
+}
+
+sal_Bool SAL_CALL ScFunctionListObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() > 0 );
+}
+
+uno::Sequence<OUString> SAL_CALL ScFunctionListObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( pFuncList )
+ {
+ sal_uInt32 nCount = pFuncList->GetCount();
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(nIndex);
+ if ( pDesc && pDesc->mxFuncName )
+ pAry[nIndex] = *pDesc->mxFuncName;
+ }
+ return aSeq;
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScFunctionListObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( pFuncList )
+ {
+ sal_uInt32 nCount = pFuncList->GetCount();
+ for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(nIndex);
+ //! Case-insensitive???
+ if ( pDesc && pDesc->mxFuncName && aName == *pDesc->mxFuncName )
+ return true;
+ }
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/celllistsource.cxx b/sc/source/ui/unoobj/celllistsource.cxx
new file mode 100644
index 0000000000..bca1e0a695
--- /dev/null
+++ b/sc/source/ui/unoobj/celllistsource.cxx
@@ -0,0 +1,433 @@
+/* -*- 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 "celllistsource.hxx"
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/NotInitializedException.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/FormulaResult.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+namespace calc
+{
+
+#define PROP_HANDLE_RANGE_ADDRESS 1
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::table;
+ using namespace ::com::sun::star::text;
+ using namespace ::com::sun::star::sheet;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::form::binding;
+
+ OCellListSource::OCellListSource( const Reference< XSpreadsheetDocument >& _rxDocument )
+ :OCellListSource_Base( m_aMutex )
+ ,OCellListSource_PBase( OCellListSource_Base::rBHelper )
+ ,m_xDocument( _rxDocument )
+ ,m_aListEntryListeners( m_aMutex )
+ ,m_bInitialized( false )
+ {
+ OSL_PRECOND( m_xDocument.is(), "OCellListSource::OCellListSource: invalid document!" );
+
+ // register our property at the base class
+ registerPropertyNoMember(
+ "CellRange",
+ PROP_HANDLE_RANGE_ADDRESS,
+ PropertyAttribute::BOUND | PropertyAttribute::READONLY,
+ cppu::UnoType<CellRangeAddress>::get(),
+ css::uno::Any(CellRangeAddress())
+ );
+ }
+
+ OCellListSource::~OCellListSource( )
+ {
+ if ( !OCellListSource_Base::rBHelper.bDisposed )
+ {
+ acquire(); // prevent duplicate dtor
+ dispose();
+ }
+ }
+
+ IMPLEMENT_FORWARD_XINTERFACE2( OCellListSource, OCellListSource_Base, OCellListSource_PBase )
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCellListSource, OCellListSource_Base, OCellListSource_PBase )
+
+ void SAL_CALL OCellListSource::disposing()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference<XModifyBroadcaster> xBroadcaster( m_xRange, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->removeModifyListener( this );
+ }
+
+ EventObject aDisposeEvent( *this );
+ m_aListEntryListeners.disposeAndClear( aDisposeEvent );
+
+ WeakComponentImplHelperBase::disposing();
+
+ // TODO: clean up here whatever you need to clean up (e.g. revoking listeners etc.)
+ }
+
+ Reference< XPropertySetInfo > SAL_CALL OCellListSource::getPropertySetInfo( )
+ {
+ return createPropertySetInfo( getInfoHelper() ) ;
+ }
+
+ ::cppu::IPropertyArrayHelper& SAL_CALL OCellListSource::getInfoHelper()
+ {
+ return *OCellListSource_PABase::getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* OCellListSource::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper(aProps);
+ }
+
+ void SAL_CALL OCellListSource::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
+ {
+ OSL_ENSURE( _nHandle == PROP_HANDLE_RANGE_ADDRESS, "OCellListSource::getFastPropertyValue: invalid handle!" );
+ // we only have this one property...
+
+ _rValue <<= getRangeAddress( );
+ }
+
+ void OCellListSource::checkDisposed( ) const
+ {
+ if ( OCellListSource_Base::rBHelper.bInDispose || OCellListSource_Base::rBHelper.bDisposed )
+ throw DisposedException();
+ // TODO: is it worth having an error message here?
+ }
+
+ void OCellListSource::checkInitialized()
+ {
+ if ( !m_bInitialized )
+ throw NotInitializedException("CellListSource is not initialized", getXWeak());
+ }
+
+ OUString SAL_CALL OCellListSource::getImplementationName( )
+ {
+ return "com.sun.star.comp.sheet.OCellListSource";
+ }
+
+ sal_Bool SAL_CALL OCellListSource::supportsService( const OUString& _rServiceName )
+ {
+ return cppu::supportsService(this, _rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL OCellListSource::getSupportedServiceNames( )
+ {
+ return {"com.sun.star.table.CellRangeListSource",
+ "com.sun.star.form.binding.ListEntrySource"};
+ }
+
+ CellRangeAddress OCellListSource::getRangeAddress( ) const
+ {
+ OSL_PRECOND( m_xRange.is(), "OCellListSource::getRangeAddress: invalid range!" );
+
+ CellRangeAddress aAddress;
+ Reference< XCellRangeAddressable > xRangeAddress( m_xRange, UNO_QUERY );
+ if ( xRangeAddress.is() )
+ aAddress = xRangeAddress->getRangeAddress( );
+ return aAddress;
+ }
+
+ OUString OCellListSource::getCellTextContent_noCheck( sal_Int32 _nRangeRelativeRow, css::uno::Any* pAny )
+ {
+ OUString sText;
+
+ OSL_PRECOND( m_xRange.is(), "OCellListSource::getRangeAddress: invalid range!" );
+
+ if (!m_xRange.is())
+ return sText;
+
+ Reference< XCell > xCell( m_xRange->getCellByPosition( 0, _nRangeRelativeRow ));
+ if (!xCell.is())
+ {
+ if (pAny)
+ *pAny <<= sText;
+ return sText;
+ }
+
+ Reference< XTextRange > xCellText;
+ xCellText.set( xCell, UNO_QUERY);
+
+ if (xCellText.is())
+ sText = xCellText->getString(); // formatted output string
+
+ if (pAny)
+ {
+ switch (xCell->getType())
+ {
+ case CellContentType_VALUE:
+ *pAny <<= xCell->getValue();
+ break;
+ case CellContentType_TEXT:
+ *pAny <<= sText;
+ break;
+ case CellContentType_FORMULA:
+ if (xCell->getError())
+ *pAny <<= sText; // Err:... or #...!
+ else
+ {
+ Reference< XPropertySet > xProp( xCell, UNO_QUERY);
+ if (xProp.is())
+ {
+ sal_Int32 nResultType;
+ if ((xProp->getPropertyValue("FormulaResultType2") >>= nResultType) &&
+ nResultType == FormulaResult::VALUE)
+ *pAny <<= xCell->getValue();
+ else
+ *pAny <<= sText;
+ }
+ }
+ break;
+ case CellContentType_EMPTY:
+ *pAny <<= OUString();
+ break;
+ default:
+ ; // nothing, if actually occurred it would result in #N/A being displayed if selected
+ }
+ }
+
+ return sText;
+ }
+
+ sal_Int32 SAL_CALL OCellListSource::getListEntryCount( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ CellRangeAddress aAddress( getRangeAddress( ) );
+ return aAddress.EndRow - aAddress.StartRow + 1;
+ }
+
+ OUString SAL_CALL OCellListSource::getListEntry( sal_Int32 _nPosition )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ if ( _nPosition >= getListEntryCount() )
+ throw IndexOutOfBoundsException();
+
+ return getCellTextContent_noCheck( _nPosition, nullptr );
+ }
+
+ Sequence< OUString > SAL_CALL OCellListSource::getAllListEntries( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ Sequence< OUString > aAllEntries( getListEntryCount() );
+ OUString* pAllEntries = aAllEntries.getArray();
+ for ( sal_Int32 i = 0; i < aAllEntries.getLength(); ++i )
+ {
+ *pAllEntries++ = getCellTextContent_noCheck( i, nullptr );
+ }
+
+ return aAllEntries;
+ }
+
+ Sequence< OUString > SAL_CALL OCellListSource::getAllListEntriesTyped( Sequence< Any >& rDataValues )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ const sal_Int32 nCount = getListEntryCount();
+ Sequence< OUString > aAllEntries( nCount );
+ rDataValues = Sequence< Any >( nCount );
+ OUString* pAllEntries = aAllEntries.getArray();
+ Any* pDataValues = rDataValues.getArray();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ *pAllEntries++ = getCellTextContent_noCheck( i, pDataValues++ );
+ }
+
+ return aAllEntries;
+ }
+
+ void SAL_CALL OCellListSource::addListEntryListener( const Reference< XListEntryListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ if ( !_rxListener.is() )
+ throw NullPointerException();
+
+ m_aListEntryListeners.addInterface( _rxListener );
+ }
+
+ void SAL_CALL OCellListSource::removeListEntryListener( const Reference< XListEntryListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ if ( !_rxListener.is() )
+ throw NullPointerException();
+
+ m_aListEntryListeners.removeInterface( _rxListener );
+ }
+
+ void SAL_CALL OCellListSource::modified( const EventObject& /* aEvent */ )
+ {
+ notifyModified();
+ }
+
+ void OCellListSource::notifyModified()
+ {
+ EventObject aEvent;
+ aEvent.Source.set(*this);
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter( m_aListEntryListeners );
+ while ( aIter.hasMoreElements() )
+ {
+ try
+ {
+ aIter.next()->allEntriesChanged( aEvent );
+ }
+ catch( const RuntimeException& )
+ {
+ // silent this
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "OCellListSource::notifyModified: caught a (non-runtime) exception!" );
+ }
+ }
+
+ }
+
+ void SAL_CALL OCellListSource::disposing( const EventObject& aEvent )
+ {
+ Reference<XInterface> xRangeInt( m_xRange, UNO_QUERY );
+ if ( xRangeInt == aEvent.Source )
+ {
+ // release references to range object
+ m_xRange.clear();
+ }
+ }
+
+ void SAL_CALL OCellListSource::initialize( const Sequence< Any >& _rArguments )
+ {
+ if ( m_bInitialized )
+ throw RuntimeException("CellListSource is already initialized", getXWeak());
+
+ // get the cell address
+ CellRangeAddress aRangeAddress;
+ bool bFoundAddress = false;
+
+ for ( const Any& rArg : _rArguments )
+ {
+ NamedValue aValue;
+ if ( rArg >>= aValue )
+ {
+ if ( aValue.Name == "CellRange" )
+ {
+ if ( aValue.Value >>= aRangeAddress )
+ {
+ bFoundAddress = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !bFoundAddress )
+ throw RuntimeException("Cell not found", getXWeak());
+
+ // determine the range we're bound to
+ try
+ {
+ if ( m_xDocument.is() )
+ {
+ // first the sheets collection
+ Reference< XIndexAccess > xSheets(m_xDocument->getSheets( ), UNO_QUERY);
+ OSL_ENSURE( xSheets.is(), "OCellListSource::initialize: could not retrieve the sheets!" );
+
+ if ( xSheets.is() )
+ {
+ // the concrete sheet
+ Reference< XCellRange > xSheet(xSheets->getByIndex( aRangeAddress.Sheet ), UNO_QUERY);
+ OSL_ENSURE( xSheet.is(), "OCellListSource::initialize: NULL sheet, but no exception!" );
+
+ // the concrete cell
+ if ( xSheet.is() )
+ {
+ m_xRange.set(xSheet->getCellRangeByPosition(
+ aRangeAddress.StartColumn, aRangeAddress.StartRow,
+ aRangeAddress.EndColumn, aRangeAddress.EndRow));
+ OSL_ENSURE( Reference< XCellRangeAddressable >( m_xRange, UNO_QUERY ).is(), "OCellListSource::initialize: either NULL range, or cell without address access!" );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "OCellListSource::initialize: caught an exception while retrieving the cell object!" );
+ }
+
+ if ( !m_xRange.is() )
+ throw RuntimeException("Failed to retrieve cell range", getXWeak());
+
+ Reference<XModifyBroadcaster> xBroadcaster( m_xRange, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->addModifyListener( this );
+ }
+
+ // TODO: add as XEventListener to the cell range, so we get notified when it dies,
+ // and can dispose ourself then
+
+ // TODO: somehow add as listener so we get notified when the address of the cell range changes
+ // We need to forward this as change in our CellRange property to our property change listeners
+
+ // TODO: somehow add as listener to the cells in the range, so that we get notified
+ // when their content changes. We need to forward this to our list entry listeners then
+
+ // TODO: somehow add as listener so that we get notified of insertions and removals of rows in our
+ // range. In this case, we need to fire a change in our CellRange property, and additionally
+ // notify our XListEntryListeners
+
+ m_bInitialized = true;
+ }
+
+} // namespace calc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/celllistsource.hxx b/sc/source/ui/unoobj/celllistsource.hxx
new file mode 100644
index 0000000000..c919c18ec2
--- /dev/null
+++ b/sc/source/ui/unoobj/celllistsource.hxx
@@ -0,0 +1,155 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/form/binding/XListEntryTypedSource.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+
+namespace com::sun::star::sheet { class XSpreadsheetDocument; }
+namespace com::sun::star::table { class XCellRange; }
+
+namespace calc
+{
+
+ //= OCellListSource
+
+ class OCellListSource;
+ // the base for our interfaces
+ typedef ::cppu::WeakComponentImplHelper < css::form::binding::XListEntryTypedSource
+ , css::util::XModifyListener
+ , css::lang::XServiceInfo
+ , css::lang::XInitialization
+ > OCellListSource_Base;
+ // the base for the property handling
+ typedef ::comphelper::OPropertyContainer OCellListSource_PBase;
+ // the second base for property handling
+ typedef ::comphelper::OPropertyArrayUsageHelper< OCellListSource >
+ OCellListSource_PABase;
+
+ class OCellListSource :public ::cppu::BaseMutex
+ ,public OCellListSource_Base // order matters! before OCellListSource_PBase, so rBHelper gets initialized
+ ,public OCellListSource_PBase
+ ,public OCellListSource_PABase
+ {
+ private:
+ css::uno::Reference< css::sheet::XSpreadsheetDocument >
+ m_xDocument; /// the document where our cell lives
+ css::uno::Reference< css::table::XCellRange >
+ m_xRange; /// the range of cells we're bound to
+ ::comphelper::OInterfaceContainerHelper3<css::form::binding::XListEntryListener>
+ m_aListEntryListeners; /// our listeners
+ bool m_bInitialized; /// has XInitialization::initialize been called?
+
+ public:
+ explicit OCellListSource(
+ const css::uno::Reference< css::sheet::XSpreadsheetDocument >& _rxDocument
+ );
+
+ using OCellListSource_PBase::getFastPropertyValue;
+
+ protected:
+ virtual ~OCellListSource( ) override;
+
+ protected:
+ // XInterface
+ DECLARE_XINTERFACE()
+
+ // XTypeProvider
+ DECLARE_XTYPEPROVIDER()
+
+ // XListEntrySource
+ virtual sal_Int32 SAL_CALL getListEntryCount( ) override;
+ virtual OUString SAL_CALL getListEntry( sal_Int32 Position ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getAllListEntries( ) override;
+ virtual void SAL_CALL addListEntryListener( const css::uno::Reference< css::form::binding::XListEntryListener >& Listener ) override;
+ virtual void SAL_CALL removeListEntryListener( const css::uno::Reference< css::form::binding::XListEntryListener >& Listener ) override;
+
+ // XListEntryTypedSource
+ virtual css::uno::Sequence< OUString > SAL_CALL getAllListEntriesTyped( css::uno::Sequence< css::uno::Any >& rDataValues ) override;
+
+ // OComponentHelper/XComponent
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& _rValue, sal_Int32 _nHandle ) const override;
+
+ // ::comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // XModifyListener
+ virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ private:
+ void checkDisposed( ) const;
+ void checkInitialized();
+
+ /** retrieves the actual address of our cell range
+ @precond
+ our m_xRange is not <NULL/>
+ */
+ css::table::CellRangeAddress
+ getRangeAddress( ) const;
+
+ /** retrieves the text of a cell within our range
+ @param _nRangeRelativeRow
+ the relative row index of the cell within our range
+ @param pAny
+ if not <NULL/> then the underlying data value is returned in the Any
+ @precond
+ our m_xRange is not <NULL/>
+ */
+ OUString
+ getCellTextContent_noCheck(
+ sal_Int32 _nRangeRelativeRow,
+ css::uno::Any* pAny
+ );
+
+ void notifyModified();
+
+ private:
+ OCellListSource( const OCellListSource& ) = delete;
+ OCellListSource& operator=( const OCellListSource& ) = delete;
+ };
+
+} // namespace calc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx
new file mode 100644
index 0000000000..3325b0bbcf
--- /dev/null
+++ b/sc/source/ui/unoobj/cellsuno.cxx
@@ -0,0 +1,9266 @@
+/* -*- 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 <scitems.hxx>
+#include <editeng/eeitem.hxx>
+#include <o3tl/safeint.hxx>
+#include <svx/svdpool.hxx>
+
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <svx/algitem.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/unoipset.hxx>
+#include <editeng/langitem.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <svl/numformat.hxx>
+#include <svl/srchitem.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <svx/unomid.hxx>
+#include <editeng/unoprnms.hxx>
+#include <editeng/unotext.hxx>
+#include <svx/svdpage.hxx>
+#include <sfx2/bindings.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <float.h>
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <tools/UnitConversion.hxx>
+
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/util/CellProtection.hpp>
+#include <com/sun/star/table/CellHoriJustify.hpp>
+#include <com/sun/star/table/CellOrientation.hpp>
+#include <com/sun/star/table/ShadowFormat.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/table/TableBorder2.hpp>
+#include <com/sun/star/sheet/CellFlags.hpp>
+#include <com/sun/star/sheet/FormulaResult.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/beans/TolerantPropertySetResultType.hpp>
+#include <com/sun/star/beans/SetPropertyTolerantFailed.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/textfield/Type.hpp>
+#include <com/sun/star/sheet/XConditionalFormats.hpp>
+#include <com/sun/star/util/XComplexColor.hpp>
+
+#include <autoform.hxx>
+#include <cellvalue.hxx>
+#include <cellmergeoption.hxx>
+#include <cellsuno.hxx>
+#include <cursuno.hxx>
+#include <textuno.hxx>
+#include <editsrc.hxx>
+#include <notesuno.hxx>
+#include <fielduno.hxx>
+#include <docuno.hxx>
+#include <datauno.hxx>
+#include <dapiuno.hxx>
+#include <chartuno.hxx>
+#include <fmtuno.hxx>
+#include <miscuno.hxx>
+#include <convuno.hxx>
+#include <srchuno.hxx>
+#include <nameuno.hxx>
+#include <targuno.hxx>
+#include <tokenuno.hxx>
+#include <eventuno.hxx>
+#include <docsh.hxx>
+#include <markdata.hxx>
+#include <patattr.hxx>
+#include <docpool.hxx>
+#include <docfunc.hxx>
+#include <dbdocfun.hxx>
+#include <olinefun.hxx>
+#include <hints.hxx>
+#include <formulacell.hxx>
+#include <undotab.hxx>
+#include <undoblk.hxx>
+#include <stlsheet.hxx>
+#include <dbdata.hxx>
+#include <attrib.hxx>
+#include <chartarr.hxx>
+#include <chartlis.hxx>
+#include <drwlayer.hxx>
+#include <printfun.hxx>
+#include <prnsave.hxx>
+#include <tablink.hxx>
+#include <dociter.hxx>
+#include <rangeutl.hxx>
+#include <conditio.hxx>
+#include <validat.hxx>
+#include <sc.hrc>
+#include <cellform.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <unonames.hxx>
+#include <styleuno.hxx>
+#include <rangeseq.hxx>
+#include <unowids.hxx>
+#include <paramisc.hxx>
+#include <queryentry.hxx>
+#include <formula/errorcodes.hxx>
+#include <unoreflist.hxx>
+#include <formula/grammar.hxx>
+#include <editeng/escapementitem.hxx>
+#include <stringutil.hxx>
+#include <formulaiter.hxx>
+#include <tokenarray.hxx>
+#include <stylehelper.hxx>
+#include <dputil.hxx>
+#include <sortparam.hxx>
+#include <condformatuno.hxx>
+#include <TablePivotCharts.hxx>
+#include <table.hxx>
+#include <refundo.hxx>
+#include <columnspanset.hxx>
+#include <CommonProperties.hxx>
+
+#include <memory>
+
+using namespace com::sun::star;
+
+// The names in the maps must be sorted according to strcmp!
+//! Instead of Which-ID 0 use special IDs and do not compare via names!
+
+// Left/Right/Top/BottomBorder are mapped directly to the core items,
+// not collected/applied to the borders of a range -> ATTR_BORDER can be used directly
+
+static const SfxItemPropertySet* lcl_GetCellsPropertySet()
+{
+ static const SfxItemPropertyMapEntry aCellsPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ CELL_BORDER_PROPERTIES
+ CELL_BACKGROUND_COLOR_PROPERTIES
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ CHAR_COLOR_PROPERTIES
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_HYPERLINK, ATTR_HYPERLINK, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_FORMATID, SC_WID_UNO_FORMATID, cppu::UnoType<sal_uInt64>::get(), 0, 0 },
+ };
+ static SfxItemPropertySet aCellsPropertySet( aCellsPropertyMap_Impl );
+ return &aCellsPropertySet;
+}
+
+// CellRange contains all entries from Cells, plus its own entries
+// with Which-ID 0 (those are needed only for getPropertySetInfo).
+
+static const SfxItemPropertySet* lcl_GetRangePropertySet()
+{
+ static const SfxItemPropertyMapEntry aRangePropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ CELL_BORDER_PROPERTIES
+ CELL_BACKGROUND_COLOR_PROPERTIES
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ CHAR_COLOR_PROPERTIES
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_FORMATID, SC_WID_UNO_FORMATID, cppu::UnoType<sal_uInt64>::get(), 0, 0 },
+ };
+ static SfxItemPropertySet aRangePropertySet( aRangePropertyMap_Impl );
+ return &aRangePropertySet;
+}
+
+// Cell contains entries from CellRange, plus its own entries
+// with Which-ID 0 (those are needed only for getPropertySetInfo).
+
+static const SfxItemPropertySet* lcl_GetCellPropertySet()
+{
+ static const SfxItemPropertyMapEntry aCellPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ CELL_BORDER_PROPERTIES
+ CELL_BACKGROUND_COLOR_PROPERTIES
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ CHAR_COLOR_PROPERTIES
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_FORMLOC, SC_WID_UNO_FORMLOC, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_FORMRT, SC_WID_UNO_FORMRT, cppu::UnoType<table::CellContentType>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_CELLCONTENTTYPE, SC_WID_UNO_CELLCONTENTTYPE, cppu::UnoType<table::CellContentType>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_FORMRT2, SC_WID_UNO_FORMRT2, cppu::UnoType<sal_Int32>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { UNO_NAME_EDIT_CHAR_ESCAPEMENT, EE_CHAR_ESCAPEMENT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_HYPERLINK, ATTR_HYPERLINK, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_FORMATID, SC_WID_UNO_FORMATID, cppu::UnoType<sal_uInt64>::get(), 0, 0 },
+ };
+ static SfxItemPropertySet aCellPropertySet( aCellPropertyMap_Impl );
+ return &aCellPropertySet;
+}
+
+// Column and Row contain all entries from CellRange, plus its own entries
+// with Which-ID 0 (those are needed only for getPropertySetInfo).
+
+static const SfxItemPropertySet* lcl_GetColumnPropertySet()
+{
+ static const SfxItemPropertyMapEntry aColumnPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ CELL_BORDER_PROPERTIES
+ CELL_BACKGROUND_COLOR_PROPERTIES
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ CHAR_COLOR_PROPERTIES
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_MANPAGE, SC_WID_UNO_MANPAGE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NEWPAGE, SC_WID_UNO_NEWPAGE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLVIS, SC_WID_UNO_CELLVIS, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_OWIDTH, SC_WID_UNO_OWIDTH, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLWID, SC_WID_UNO_CELLWID, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ };
+ static SfxItemPropertySet aColumnPropertySet( aColumnPropertyMap_Impl );
+ return &aColumnPropertySet;
+}
+
+static const SfxItemPropertySet* lcl_GetRowPropertySet()
+{
+ static const SfxItemPropertyMapEntry aRowPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ CELL_BORDER_PROPERTIES
+ CELL_BACKGROUND_COLOR_PROPERTIES
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ CHAR_COLOR_PROPERTIES
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CELLHGT, SC_WID_UNO_CELLHGT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_CELLFILT, SC_WID_UNO_CELLFILT,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_MANPAGE, SC_WID_UNO_MANPAGE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NEWPAGE, SC_WID_UNO_NEWPAGE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLVIS, SC_WID_UNO_CELLVIS, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_OHEIGHT, SC_WID_UNO_OHEIGHT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ };
+ static SfxItemPropertySet aRowPropertySet( aRowPropertyMap_Impl );
+ return &aRowPropertySet;
+}
+
+static const SfxItemPropertySet* lcl_GetSheetPropertySet()
+{
+ static const SfxItemPropertyMapEntry aSheetPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_AUTOPRINT,SC_WID_UNO_AUTOPRINT,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_BORDCOL, SC_WID_UNO_BORDCOL, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ CELL_BORDER_PROPERTIES
+ CELL_BACKGROUND_COLOR_PROPERTIES
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ CHAR_COLOR_PROPERTIES
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_COPYBACK, SC_WID_UNO_COPYBACK,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_COPYFORM, SC_WID_UNO_COPYFORM,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_COPYSTYL, SC_WID_UNO_COPYSTYL,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ISACTIVE, SC_WID_UNO_ISACTIVE,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLVIS, SC_WID_UNO_CELLVIS, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_LINKDISPBIT, SC_WID_UNO_LINKDISPBIT,cppu::UnoType<awt::XBitmap>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_LINKDISPNAME, SC_WID_UNO_LINKDISPNAME,cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PAGESTL, SC_WID_UNO_PAGESTL, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_PRINTBORD,SC_WID_UNO_PRINTBORD,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PROTECT, SC_WID_UNO_PROTECT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHOWBORD, SC_WID_UNO_SHOWBORD,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TABLAYOUT,SC_WID_UNO_TABLAYOUT,cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_CONDFORMAT, SC_WID_UNO_CONDFORMAT, cppu::UnoType<sheet::XConditionalFormats>::get(), 0, 0},
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_TABCOLOR, SC_WID_UNO_TABCOLOR, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNO_CODENAME, SC_WID_UNO_CODENAME, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNO_NAMEDRANGES, SC_WID_UNO_NAMES, cppu::UnoType<sheet::XNamedRanges>::get(), 0, 0 },
+ };
+ static SfxItemPropertySet aSheetPropertySet( aSheetPropertyMap_Impl );
+ return &aSheetPropertySet;
+}
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetEditPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aEditPropertyMap_Impl[] =
+ {
+ SVX_UNOEDIT_CHAR_PROPERTIES,
+ SVX_UNOEDIT_FONT_PROPERTIES,
+ SVX_UNOEDIT_PARA_PROPERTIES,
+ SVX_UNOEDIT_NUMBERING_PROPERTY, // for completeness of service ParagraphProperties
+ { SC_UNONAME_TEXTUSER, EE_CHAR_XMLATTRIBS, cppu::UnoType<container::XNameContainer>::get(), 0, 0},
+ { SC_UNONAME_USERDEF, EE_PARA_XMLATTRIBS, cppu::UnoType<container::XNameContainer>::get(), 0, 0},
+ };
+ return aEditPropertyMap_Impl;
+}
+static const SvxItemPropertySet* lcl_GetEditPropertySet()
+{
+ static SvxItemPropertySet aEditPropertySet( lcl_GetEditPropertyMap(), SdrObject::GetGlobalDrawObjectItemPool() );
+ return &aEditPropertySet;
+}
+
+constexpr OUString SCCHARPROPERTIES_SERVICE = u"com.sun.star.style.CharacterProperties"_ustr;
+constexpr OUString SCPARAPROPERTIES_SERVICE = u"com.sun.star.style.ParagraphProperties"_ustr;
+constexpr OUString SCCELLPROPERTIES_SERVICE = u"com.sun.star.table.CellProperties"_ustr;
+constexpr OUString SCCELLRANGE_SERVICE = u"com.sun.star.table.CellRange"_ustr;
+constexpr OUString SCCELL_SERVICE = u"com.sun.star.table.Cell"_ustr;
+constexpr OUString SCSHEETCELLRANGES_SERVICE = u"com.sun.star.sheet.SheetCellRanges"_ustr;
+constexpr OUString SCSHEETCELLRANGE_SERVICE = u"com.sun.star.sheet.SheetCellRange"_ustr;
+constexpr OUString SCSPREADSHEET_SERVICE = u"com.sun.star.sheet.Spreadsheet"_ustr;
+constexpr OUString SCSHEETCELL_SERVICE = u"com.sun.star.sheet.SheetCell"_ustr;
+
+SC_SIMPLE_SERVICE_INFO( ScCellFormatsEnumeration, "ScCellFormatsEnumeration", "com.sun.star.sheet.CellFormatRangesEnumeration" )
+SC_SIMPLE_SERVICE_INFO( ScCellFormatsObj, "ScCellFormatsObj", "com.sun.star.sheet.CellFormatRanges" )
+SC_SIMPLE_SERVICE_INFO( ScUniqueCellFormatsEnumeration, "ScUniqueCellFormatsEnumeration", "com.sun.star.sheet.UniqueCellFormatRangesEnumeration" )
+SC_SIMPLE_SERVICE_INFO( ScUniqueCellFormatsObj, "ScUniqueCellFormatsObj", "com.sun.star.sheet.UniqueCellFormatRanges" )
+SC_SIMPLE_SERVICE_INFO( ScCellRangesBase, "ScCellRangesBase", "stardiv.unknown" )
+SC_SIMPLE_SERVICE_INFO( ScCellsEnumeration, "ScCellsEnumeration", "com.sun.star.sheet.CellsEnumeration" )
+SC_SIMPLE_SERVICE_INFO( ScCellsObj, "ScCellsObj", "com.sun.star.sheet.Cells" )
+SC_SIMPLE_SERVICE_INFO( ScTableColumnObj, "ScTableColumnObj", "com.sun.star.table.TableColumn" )
+SC_SIMPLE_SERVICE_INFO( ScTableRowObj, "ScTableRowObj", "com.sun.star.table.TableRow" )
+
+//! move ScLinkListener into another file !!!
+
+ScLinkListener::~ScLinkListener()
+{
+}
+
+void ScLinkListener::Notify( const SfxHint& rHint )
+{
+ aLink.Call( rHint );
+}
+
+static void lcl_CopyProperties( beans::XPropertySet& rDest, beans::XPropertySet& rSource )
+{
+ uno::Reference<beans::XPropertySetInfo> xInfo(rSource.getPropertySetInfo());
+ if (xInfo.is())
+ {
+ const uno::Sequence<beans::Property> aSeq(xInfo->getProperties());
+ for (const beans::Property& rProp : aSeq)
+ {
+ OUString aName(rProp.Name);
+ rDest.setPropertyValue( aName, rSource.getPropertyValue( aName ) );
+ }
+ }
+}
+
+static SCTAB lcl_FirstTab( const ScRangeList& rRanges )
+{
+ if (rRanges.empty())
+ throw std::out_of_range("empty range");
+ const ScRange & rFirst = rRanges[0];
+ return rFirst.aStart.Tab();
+}
+
+static bool lcl_WholeSheet( const ScDocument& rDoc, const ScRangeList& rRanges )
+{
+ if ( rRanges.size() == 1 )
+ {
+ const ScRange & rRange = rRanges[0];
+ if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
+ rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
+ return true;
+ }
+ return false;
+}
+
+namespace {
+template<typename BorderLineType>
+const ::editeng::SvxBorderLine* lcl_getBorderLine(
+ ::editeng::SvxBorderLine& rLine, const BorderLineType& rStruct )
+{
+ // Convert from 1/100mm to Twips.
+ if (!SvxBoxItem::LineToSvxLine( rStruct, rLine, true))
+ return nullptr;
+
+ if ( rLine.GetOutWidth() || rLine.GetInWidth() || rLine.GetDistance() )
+ return &rLine;
+ else
+ return nullptr;
+}
+}
+
+const ::editeng::SvxBorderLine* ScHelperFunctions::GetBorderLine(
+ ::editeng::SvxBorderLine& rLine, const table::BorderLine& rStruct )
+{
+ return lcl_getBorderLine( rLine, rStruct);
+}
+
+const ::editeng::SvxBorderLine* ScHelperFunctions::GetBorderLine(
+ ::editeng::SvxBorderLine& rLine, const table::BorderLine2& rStruct )
+{
+ return lcl_getBorderLine( rLine, rStruct);
+}
+
+namespace {
+template<typename TableBorderType>
+void lcl_fillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const TableBorderType& rBorder )
+{
+ ::editeng::SvxBorderLine aLine;
+ rOuter.SetAllDistances(o3tl::toTwips(rBorder.Distance, o3tl::Length::mm100));
+ rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.TopLine ), SvxBoxItemLine::TOP );
+ rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.BottomLine ), SvxBoxItemLine::BOTTOM );
+ rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.LeftLine ), SvxBoxItemLine::LEFT );
+ rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.RightLine ), SvxBoxItemLine::RIGHT );
+ rInner.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.HorizontalLine ), SvxBoxInfoItemLine::HORI );
+ rInner.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.VerticalLine ), SvxBoxInfoItemLine::VERT );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::TOP, rBorder.IsTopLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, rBorder.IsBottomLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, rBorder.IsLeftLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, rBorder.IsRightLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::HORI, rBorder.IsHorizontalLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::VERT, rBorder.IsVerticalLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE, rBorder.IsDistanceValid );
+ rInner.SetTable( true );
+}
+}
+
+void ScHelperFunctions::FillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const table::TableBorder& rBorder )
+{
+ lcl_fillBoxItems( rOuter, rInner, rBorder);
+}
+
+void ScHelperFunctions::FillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const table::TableBorder2& rBorder )
+{
+ lcl_fillBoxItems( rOuter, rInner, rBorder);
+}
+
+void ScHelperFunctions::FillBorderLine( table::BorderLine& rStruct, const ::editeng::SvxBorderLine* pLine )
+{
+ // Convert from Twips to 1/100mm.
+ rStruct = SvxBoxItem::SvxLineToLine( pLine, true);
+}
+
+void ScHelperFunctions::FillBorderLine( table::BorderLine2& rStruct, const ::editeng::SvxBorderLine* pLine )
+{
+ rStruct = SvxBoxItem::SvxLineToLine( pLine, true);
+}
+
+namespace {
+template<typename TableBorderItem>
+void lcl_fillTableBorder( TableBorderItem& rBorder, const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner,
+ bool bInvalidateHorVerDist )
+{
+ ScHelperFunctions::FillBorderLine( rBorder.TopLine, rOuter.GetTop() );
+ ScHelperFunctions::FillBorderLine( rBorder.BottomLine, rOuter.GetBottom() );
+ ScHelperFunctions::FillBorderLine( rBorder.LeftLine, rOuter.GetLeft() );
+ ScHelperFunctions::FillBorderLine( rBorder.RightLine, rOuter.GetRight() );
+ ScHelperFunctions::FillBorderLine( rBorder.HorizontalLine, rInner.GetHori() );
+ ScHelperFunctions::FillBorderLine( rBorder.VerticalLine, rInner.GetVert() );
+
+ rBorder.Distance = rOuter.GetSmallestDistance();
+ rBorder.IsTopLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::TOP);
+ rBorder.IsBottomLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
+ rBorder.IsLeftLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::LEFT);
+ rBorder.IsRightLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::RIGHT);
+ rBorder.IsHorizontalLineValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::HORI);
+ rBorder.IsVerticalLineValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::VERT);
+ rBorder.IsDistanceValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
+}
+}
+
+void ScHelperFunctions::AssignTableBorderToAny( uno::Any& rAny,
+ const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner, bool bInvalidateHorVerDist )
+{
+ table::TableBorder aBorder;
+ lcl_fillTableBorder( aBorder, rOuter, rInner, bInvalidateHorVerDist);
+ rAny <<= aBorder;
+}
+
+void ScHelperFunctions::AssignTableBorder2ToAny( uno::Any& rAny,
+ const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner, bool bInvalidateHorVerDist )
+{
+ table::TableBorder2 aBorder;
+ lcl_fillTableBorder( aBorder, rOuter, rInner, bInvalidateHorVerDist);
+ rAny <<= aBorder;
+}
+
+//! move lcl_ApplyBorder to docfunc !
+
+void ScHelperFunctions::ApplyBorder( ScDocShell* pDocShell, const ScRangeList& rRanges,
+ const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+ ScDocumentUniquePtr pUndoDoc;
+ if (bUndo)
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ size_t nCount = rRanges.size();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ ScRange const & rRange = rRanges[ i ];
+ SCTAB nTab = rRange.aStart.Tab();
+
+ if (bUndo)
+ {
+ if ( i==0 )
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ else
+ pUndoDoc->AddUndoTab( nTab, nTab );
+ rDoc.CopyToDocument(rRange, InsertDeleteFlags::ATTRIB, false, *pUndoDoc);
+ }
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SetMarkArea( rRange );
+ aMark.SelectTable( nTab, true );
+
+ rDoc.ApplySelectionFrame(aMark, rOuter, &rInner);
+ // don't need RowHeight if there is only a border
+ }
+
+ if (bUndo)
+ {
+ pDocShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoBorder>( pDocShell, rRanges, std::move(pUndoDoc), rOuter, rInner ) );
+ }
+
+ for (size_t i = 0; i < nCount; ++i )
+ pDocShell->PostPaint( rRanges[ i ], PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ pDocShell->SetDocumentModified();
+}
+
+//! move lcl_PutDataArray to docfunc?
+//! merge loop with ScFunctionAccess::callFunction
+
+static bool lcl_PutDataArray( ScDocShell& rDocShell, const ScRange& rRange,
+ const uno::Sequence< uno::Sequence<uno::Any> >& aData )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
+ SCTAB nTab = rRange.aStart.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ if ( !rDoc.IsBlockEditable( nTab, nStartCol,nStartRow, nEndCol,nEndRow ) )
+ {
+ //! error message
+ return false;
+ }
+
+ sal_Int32 nCols = 0;
+ sal_Int32 nRows = aData.getLength();
+ if ( nRows )
+ nCols = aData[0].getLength();
+
+ if ( nCols != nEndCol-nStartCol+1 || nRows != nEndRow-nStartRow+1 )
+ {
+ //! error message?
+ return false;
+ }
+
+ ScDocumentUniquePtr pUndoDoc;
+ if ( bUndo )
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ rDoc.CopyToDocument(rRange, InsertDeleteFlags::CONTENTS|InsertDeleteFlags::NOCAPTIONS, false, *pUndoDoc);
+ }
+
+ rDoc.DeleteAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS );
+
+ bool bError = false;
+ SCROW nDocRow = nStartRow;
+ for (const uno::Sequence<uno::Any>& rColSeq : aData)
+ {
+ if ( rColSeq.getLength() == nCols )
+ {
+ SCCOL nDocCol = nStartCol;
+ for (const uno::Any& rElement : rColSeq)
+ {
+ ScAddress aPos(nDocCol, nDocRow, nTab);
+
+ switch( rElement.getValueTypeClass() )
+ {
+ case uno::TypeClass_VOID:
+ {
+ // void = "no value"
+ rDoc.SetError( nDocCol, nDocRow, nTab, FormulaError::NotAvailable );
+ }
+ break;
+
+ // #87871# accept integer types because Basic passes a floating point
+ // variable as byte, short or long if it's an integer number.
+ case uno::TypeClass_BYTE:
+ case uno::TypeClass_SHORT:
+ case uno::TypeClass_UNSIGNED_SHORT:
+ case uno::TypeClass_LONG:
+ case uno::TypeClass_UNSIGNED_LONG:
+ case uno::TypeClass_FLOAT:
+ case uno::TypeClass_DOUBLE:
+ {
+ double fVal(0.0);
+ rElement >>= fVal;
+ rDoc.SetValue(aPos, fVal);
+ }
+ break;
+
+ case uno::TypeClass_STRING:
+ {
+ OUString aUStr;
+ rElement >>= aUStr;
+ if ( !aUStr.isEmpty() )
+ {
+ // tdf#146454 - check for a multiline string since setting an edit
+ // or string cell is in magnitudes slower than setting a plain string
+ if (ScStringUtil::isMultiline(aUStr))
+ {
+ rEngine.SetTextCurrentDefaults(aUStr);
+ rDoc.SetEditText(aPos, rEngine.CreateTextObject());
+ }
+ else
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(aPos, aUStr, &aParam);
+ }
+ }
+ }
+ break;
+
+ // accept Sequence<FormulaToken> for formula cells
+ case uno::TypeClass_SEQUENCE:
+ {
+ uno::Sequence< sheet::FormulaToken > aTokens;
+ if ( rElement >>= aTokens )
+ {
+ ScTokenArray aTokenArray(rDoc);
+ ScTokenConversion::ConvertToTokenArray( rDoc, aTokenArray, aTokens );
+ rDoc.SetFormula(aPos, aTokenArray);
+ }
+ else
+ bError = true;
+ }
+ break;
+
+ default:
+ bError = true; // invalid type
+ }
+ ++nDocCol;
+ }
+ }
+ else
+ bError = true; // wrong size
+
+ ++nDocRow;
+ }
+
+ bool bHeight = rDocShell.AdjustRowHeight( nStartRow, nEndRow, nTab );
+
+ if ( pUndoDoc )
+ {
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ aDestMark.SelectOneTable( nTab );
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoPaste>(
+ &rDocShell, ScRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab),
+ aDestMark, std::move(pUndoDoc), nullptr, InsertDeleteFlags::CONTENTS, nullptr, false));
+ }
+
+ if (!bHeight)
+ rDocShell.PostPaint( rRange, PaintPartFlags::Grid ); // AdjustRowHeight may have painted already
+
+ rDocShell.SetDocumentModified();
+
+ return !bError;
+}
+
+static bool lcl_PutFormulaArray( ScDocShell& rDocShell, const ScRange& rRange,
+ const uno::Sequence< uno::Sequence<OUString> >& aData,
+ const formula::FormulaGrammar::Grammar eGrammar )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SCTAB nTab = rRange.aStart.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ if ( !rDoc.IsBlockEditable( nTab, nStartCol,nStartRow, nEndCol,nEndRow ) )
+ {
+ //! error message
+ return false;
+ }
+
+ sal_Int32 nCols = 0;
+ sal_Int32 nRows = aData.getLength();
+ if ( nRows )
+ nCols = aData[0].getLength();
+
+ if ( nCols != nEndCol-nStartCol+1 || nRows != nEndRow-nStartRow+1 )
+ {
+ //! error message?
+ return false;
+ }
+
+ ScDocumentUniquePtr pUndoDoc;
+ if ( bUndo )
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ rDoc.CopyToDocument(rRange, InsertDeleteFlags::CONTENTS, false, *pUndoDoc);
+ }
+
+ rDoc.DeleteAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS );
+
+ bool bError = false;
+ SCROW nDocRow = nStartRow;
+ for (const uno::Sequence<OUString>& rColSeq : aData)
+ {
+ if ( rColSeq.getLength() == nCols )
+ {
+ SCCOL nDocCol = nStartCol;
+ for (const OUString& aText : rColSeq)
+ {
+ ScAddress aPos( nDocCol, nDocRow, nTab );
+
+ ScInputStringType aRes =
+ ScStringUtil::parseInputString(
+ *rDoc.GetFormatTable(), aText, LANGUAGE_ENGLISH_US);
+ switch (aRes.meType)
+ {
+ case ScInputStringType::Formula:
+ rDoc.SetFormula(aPos, aRes.maText, eGrammar);
+ break;
+ case ScInputStringType::Number:
+ rDoc.SetValue(aPos, aRes.mfValue);
+ break;
+ case ScInputStringType::Text:
+ rDoc.SetTextCell(aPos, aRes.maText);
+ break;
+ default:
+ ;
+ }
+
+ ++nDocCol;
+ }
+ }
+ else
+ bError = true; // wrong size
+
+ ++nDocRow;
+ }
+
+ bool bHeight = rDocShell.AdjustRowHeight( nStartRow, nEndRow, nTab );
+
+ if ( pUndoDoc )
+ {
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ aDestMark.SelectOneTable( nTab );
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoPaste>( &rDocShell,
+ ScRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab), aDestMark,
+ std::move(pUndoDoc), nullptr, InsertDeleteFlags::CONTENTS, nullptr, false));
+ }
+
+ if (!bHeight)
+ rDocShell.PostPaint( rRange, PaintPartFlags::Grid ); // AdjustRowHeight may have painted already
+
+ rDocShell.SetDocumentModified();
+
+ return !bError;
+}
+
+// used in ScCellRangeObj::getFormulaArray and ScCellObj::GetInputString_Impl
+static OUString lcl_GetInputString( ScDocument& rDoc, const ScAddress& rPos, bool bEnglish )
+{
+ ScRefCellValue aCell(rDoc, rPos);
+ if (aCell.isEmpty())
+ return OUString();
+
+ OUString aVal;
+
+ CellType eType = aCell.getType();
+ if (eType == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pForm = aCell.getFormula();
+ return pForm->GetFormula( formula::FormulaGrammar::mapAPItoGrammar( bEnglish, false));
+ }
+
+ SvNumberFormatter* pFormatter = bEnglish ? ScGlobal::GetEnglishFormatter() :
+ rDoc.GetFormatTable();
+ // Since the English formatter was constructed with
+ // LANGUAGE_ENGLISH_US the "General" format has index key 0,
+ // we don't have to query.
+ sal_uInt32 nNumFmt = bEnglish ? 0 : rDoc.GetNumberFormat(rPos);
+
+ if (eType == CELLTYPE_EDIT)
+ {
+ // GetString on EditCell turns breaks into spaces,
+ // but we need the breaks here
+ const EditTextObject* pData = aCell.getEditText();
+ if (pData)
+ {
+ EditEngine& rEngine = rDoc.GetEditEngine();
+ rEngine.SetText(*pData);
+ aVal = rEngine.GetText();
+ }
+ }
+ else
+ aVal = ScCellFormat::GetInputString(aCell, nNumFmt, *pFormatter, rDoc);
+
+ // if applicable, prepend ' like in ScTabViewShell::UpdateInputHandler
+ if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
+ {
+ double fDummy;
+ OUString aTempString = aVal;
+ bool bIsNumberFormat(pFormatter->IsNumberFormat(aTempString, nNumFmt, fDummy));
+ if ( bIsNumberFormat )
+ aTempString = "'" + aTempString;
+ else if ( aTempString.startsWith("'") )
+ {
+ // if the string starts with a "'", add another one because setFormula
+ // strips one (like text input, except for "text" number formats)
+ if ( bEnglish || ( pFormatter->GetType(nNumFmt) != SvNumFormatType::TEXT ) )
+ aTempString = "'" + aTempString;
+ }
+ aVal = aTempString;
+ }
+ return aVal;
+}
+
+ScCellRangesBase::ScCellRangesBase(ScDocShell* pDocSh, const ScRange& rR) :
+ pPropSet(lcl_GetCellsPropertySet()),
+ pDocShell( pDocSh ),
+ nObjectId( 0 ),
+ bChartColAsHdr( false ),
+ bChartRowAsHdr( false ),
+ bCursorOnly( false ),
+ bGotDataChangedHint( false ),
+ aValueListeners( 0 )
+{
+ ScRange aCellRange(rR);
+ aCellRange.PutInOrder();
+ aRanges.push_back( aCellRange );
+
+ if (pDocShell) // Null if created with createInstance
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.AddUnoObject(*this);
+ nObjectId = rDoc.GetNewUnoId();
+ }
+}
+
+ScCellRangesBase::ScCellRangesBase(ScDocShell* pDocSh, ScRangeList aR) :
+ pPropSet(lcl_GetCellsPropertySet()),
+ pDocShell( pDocSh ),
+ aRanges(std::move( aR )),
+ nObjectId( 0 ),
+ bChartColAsHdr( false ),
+ bChartRowAsHdr( false ),
+ bCursorOnly( false ),
+ bGotDataChangedHint( false ),
+ aValueListeners( 0 )
+{
+ if (pDocShell) // Null if created with createInstance
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.AddUnoObject(*this);
+ nObjectId = rDoc.GetNewUnoId();
+ }
+}
+
+ScCellRangesBase::~ScCellRangesBase()
+{
+ SolarMutexGuard g;
+
+ // call RemoveUnoObject first, so no notification can happen
+ // during ForgetCurrentAttrs
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+
+ ForgetCurrentAttrs();
+ ForgetMarkData();
+
+ pValueListener.reset();
+
+ //! unregister XChartDataChangeEventListener ??
+ //! (ChartCollection will then hold this object as well!)
+}
+
+void ScCellRangesBase::ForgetCurrentAttrs()
+{
+ pCurrentFlat.reset();
+ pCurrentDeep.reset();
+ moCurrentDataSet.reset();
+ moNoDfltCurrentDataSet.reset();
+
+ // #i62483# pMarkData can remain unchanged, is deleted only if the range changes (RefChanged)
+}
+
+void ScCellRangesBase::ForgetMarkData()
+{
+ pMarkData.reset();
+}
+
+const ScPatternAttr* ScCellRangesBase::GetCurrentAttrsFlat()
+{
+ // get and cache direct cell attributes for this object's range
+
+ if ( !pCurrentFlat && pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pCurrentFlat = rDoc.CreateSelectionPattern( *GetMarkData(), false );
+ }
+ return pCurrentFlat.get();
+}
+
+const ScPatternAttr* ScCellRangesBase::GetCurrentAttrsDeep()
+{
+ // get and cache cell attributes (incl. styles) for this object's range
+
+ if ( !pCurrentDeep && pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pCurrentDeep = rDoc.CreateSelectionPattern( *GetMarkData() );
+ }
+ return pCurrentDeep.get();
+}
+
+SfxItemSet* ScCellRangesBase::GetCurrentDataSet(bool bNoDflt)
+{
+ if(!moCurrentDataSet)
+ {
+ const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
+ if ( pPattern )
+ {
+ // replace Dontcare with Default, so that we always have a reflection
+ moCurrentDataSet.emplace( pPattern->GetItemSet() );
+ moNoDfltCurrentDataSet.emplace( pPattern->GetItemSet() );
+ moCurrentDataSet->ClearInvalidItems();
+ }
+ }
+ if (bNoDflt)
+ {
+ if (moNoDfltCurrentDataSet)
+ return &*moNoDfltCurrentDataSet;
+ }
+ else
+ {
+ if (moCurrentDataSet)
+ return &*moCurrentDataSet;
+ }
+ return nullptr;
+}
+
+const ScMarkData* ScCellRangesBase::GetMarkData()
+{
+ if (!pMarkData)
+ {
+ pMarkData.reset( new ScMarkData(GetDocument()->GetSheetLimits(), aRanges) );
+ }
+ return pMarkData.get();
+}
+
+void ScCellRangesBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::Dying )
+ {
+ // if the document dies, must reset to avoid crash in dtor!
+ ForgetCurrentAttrs();
+ pDocShell = nullptr; // invalid
+
+ // fdo#72695: if UNO object is already dead, don't revive it with event
+ if ( m_refCount > 0 && !aValueListeners.empty() )
+ {
+ // dispose listeners
+
+ lang::EventObject aEvent;
+ aEvent.Source = getXWeak();
+ for (uno::Reference<util::XModifyListener> & xValueListener : aValueListeners)
+ xValueListener->disposing( aEvent );
+
+ aValueListeners.clear();
+
+ // The listeners can't have the last ref to this, as it's still held
+ // by the DocShell.
+ }
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ // document content changed -> forget cached attributes
+ ForgetCurrentAttrs();
+
+ if ( bGotDataChangedHint && pDocShell )
+ {
+ // This object was notified of content changes, so one call
+ // for each listener is generated now.
+ // The calls can't be executed directly because the document's
+ // UNO broadcaster list must not be modified.
+ // Instead, add to the document's list of listener calls,
+ // which will be executed directly after the broadcast of
+ // SfxHintId::DataChanged.
+
+ lang::EventObject aEvent;
+ aEvent.Source = getXWeak();
+
+ // the EventObject holds a Ref to this object until after the listener calls
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (const uno::Reference<util::XModifyListener> & xValueListener : aValueListeners)
+ rDoc.AddUnoListenerCall( xValueListener, aEvent );
+
+ bGotDataChangedHint = false;
+ }
+ }
+ else if ( nId == SfxHintId::ScCalcAll )
+ {
+ // broadcast from DoHardRecalc - set bGotDataChangedHint
+ // (SfxHintId::DataChanged follows separately)
+
+ if ( !aValueListeners.empty() )
+ bGotDataChangedHint = true;
+ }
+ else if ( auto pRefHint = dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::unique_ptr<ScRangeList> pUndoRanges;
+ if ( rDoc.HasUnoRefUndo() )
+ pUndoRanges.reset(new ScRangeList( aRanges ));
+
+ if ( aRanges.UpdateReference( pRefHint->GetMode(), &rDoc, pRefHint->GetRange(),
+ pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() ) )
+ {
+ if ( pRefHint->GetMode() == URM_INSDEL
+ && aRanges.size() == 1
+ && dynamic_cast<ScTableSheetObj*>(this)
+ )
+ {
+ // #101755#; the range size of a sheet does not change
+ ScRange & rR = aRanges.front();
+ rR.aStart.SetCol(0);
+ rR.aStart.SetRow(0);
+ rR.aEnd.SetCol(rDoc.MaxCol());
+ rR.aEnd.SetRow(rDoc.MaxRow());
+ }
+ RefChanged();
+
+ // any change of the range address is broadcast to value (modify) listeners
+ if ( !aValueListeners.empty() )
+ bGotDataChangedHint = true;
+
+ if ( pUndoRanges )
+ rDoc.AddUnoRefChange( nObjectId, *pUndoRanges );
+ }
+ }
+ else if ( auto pUndoHint = dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
+ {
+ if ( pUndoHint->GetObjectId() == nObjectId )
+ {
+ // restore ranges from hint
+
+ aRanges = pUndoHint->GetRanges();
+
+ RefChanged();
+ if ( !aValueListeners.empty() )
+ bGotDataChangedHint = true; // need to broadcast the undo, too
+ }
+ }
+}
+
+void ScCellRangesBase::RefChanged()
+{
+ //! adjust XChartDataChangeEventListener
+
+ if ( pValueListener && !aValueListeners.empty() )
+ {
+ pValueListener->EndListeningAll();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
+ rDoc.StartListeningArea( aRanges[ i ], false, pValueListener.get() );
+ }
+
+ ForgetCurrentAttrs();
+ ForgetMarkData();
+}
+
+ScDocument* ScCellRangesBase::GetDocument() const
+{
+ if (pDocShell)
+ return &pDocShell->GetDocument();
+ else
+ return nullptr;
+}
+
+void ScCellRangesBase::InitInsertRange(ScDocShell* pDocSh, const ScRange& rR)
+{
+ if ( pDocShell || !pDocSh )
+ return;
+
+ pDocShell = pDocSh;
+
+ ScRange aCellRange(rR);
+ aCellRange.PutInOrder();
+ aRanges.RemoveAll();
+ aRanges.push_back( aCellRange );
+
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ RefChanged(); // adjust range in range object
+}
+
+void ScCellRangesBase::AddRange(const ScRange& rRange, const bool bMergeRanges)
+{
+ if (bMergeRanges)
+ aRanges.Join(rRange);
+ else
+ aRanges.push_back(rRange);
+ RefChanged();
+}
+
+void ScCellRangesBase::SetNewRange(const ScRange& rNew)
+{
+ ScRange aCellRange(rNew);
+ aCellRange.PutInOrder();
+
+ aRanges.RemoveAll();
+ aRanges.push_back( aCellRange );
+ RefChanged();
+}
+
+void ScCellRangesBase::SetNewRanges(const ScRangeList& rNew)
+{
+ aRanges = rNew;
+ RefChanged();
+}
+
+void ScCellRangesBase::SetCursorOnly( bool bSet )
+{
+ // set for a selection object that is created from the cursor position
+ // without anything selected (may contain several sheets)
+
+ bCursorOnly = bSet;
+}
+
+void ScCellRangesBase::PaintGridRanges_Impl( )
+{
+ for (size_t i = 0, nCount = aRanges.size(); i < nCount; ++i)
+ pDocShell->PostPaint( aRanges[ i ], PaintPartFlags::Grid );
+}
+
+// XSheetOperation
+
+double SAL_CALL ScCellRangesBase::computeFunction( sheet::GeneralFunction nFunction )
+{
+ SolarMutexGuard aGuard;
+ ScMarkData aMark(*GetMarkData());
+ aMark.MarkToSimple();
+ if (!aMark.IsMarked())
+ aMark.SetMarkNegative(true); // so we can enter dummy position
+
+ ScAddress aDummy; // if not marked, ignored if it is negative
+ double fVal;
+ ScSubTotalFunc eFunc = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(nFunction));
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( !rDoc.GetSelectionFunction( eFunc, aDummy, aMark, fVal ) )
+ {
+ throw uno::RuntimeException(); //! own exception?
+ }
+
+ return fVal;
+}
+
+void SAL_CALL ScCellRangesBase::clearContents( sal_Int32 nContentFlags )
+{
+ SolarMutexGuard aGuard;
+ if ( !aRanges.empty() )
+ {
+ // only for clearContents: EDITATTR is only used if no contents are deleted
+ InsertDeleteFlags nDelFlags = static_cast<InsertDeleteFlags>(nContentFlags) & InsertDeleteFlags::ALL;
+ if ( ( nDelFlags & InsertDeleteFlags::EDITATTR ) && ( nDelFlags & InsertDeleteFlags::CONTENTS ) == InsertDeleteFlags::NONE )
+ nDelFlags |= InsertDeleteFlags::EDITATTR;
+
+ pDocShell->GetDocFunc().DeleteContents( *GetMarkData(), nDelFlags, true, true );
+ }
+ // otherwise nothing to do
+}
+
+// XPropertyState
+
+const SfxItemPropertyMap& ScCellRangesBase::GetItemPropertyMap()
+{
+ return pPropSet->getPropertyMap();
+}
+
+static void lcl_GetPropertyWhich( const SfxItemPropertyMapEntry* pEntry,
+ sal_uInt16& rItemWhich )
+{
+ // Which-ID of the affected items also when the item can't handle
+ // the property by itself
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ rItemWhich = pEntry->nWID;
+ else
+ switch ( pEntry->nWID )
+ {
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ rItemWhich = ATTR_BORDER;
+ break;
+ case SC_WID_UNO_CONDFMT:
+ case SC_WID_UNO_CONDLOC:
+ case SC_WID_UNO_CONDXML:
+ rItemWhich = ATTR_CONDITIONAL;
+ break;
+ case SC_WID_UNO_VALIDAT:
+ case SC_WID_UNO_VALILOC:
+ case SC_WID_UNO_VALIXML:
+ rItemWhich = ATTR_VALIDDATA;
+ break;
+ }
+
+}
+
+beans::PropertyState ScCellRangesBase::GetOnePropertyState( sal_uInt16 nItemWhich, const SfxItemPropertyMapEntry* pEntry )
+{
+ beans::PropertyState eRet = beans::PropertyState_DIRECT_VALUE;
+ if ( nItemWhich ) // item wid (from map or special case)
+ {
+ // For items that contain several properties (like background),
+ // "ambiguous" is returned too often here
+
+ // for PropertyState, don't look at styles
+ const ScPatternAttr* pPattern = GetCurrentAttrsFlat();
+ if ( pPattern )
+ {
+ SfxItemState eState = pPattern->GetItemSet().GetItemState( nItemWhich, false );
+
+ if ( nItemWhich == ATTR_VALUE_FORMAT && eState == SfxItemState::DEFAULT )
+ eState = pPattern->GetItemSet().GetItemState( ATTR_LANGUAGE_FORMAT, false );
+
+ if ( eState == SfxItemState::SET )
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ else if ( eState == SfxItemState::DEFAULT )
+ eRet = beans::PropertyState_DEFAULT_VALUE;
+ else if ( eState == SfxItemState::DONTCARE )
+ eRet = beans::PropertyState_AMBIGUOUS_VALUE;
+ else
+ {
+ OSL_FAIL("unknown ItemState");
+ }
+ }
+ }
+ else if ( pEntry )
+ {
+ if ( pEntry->nWID == SC_WID_UNO_CHCOLHDR || pEntry->nWID == SC_WID_UNO_CHROWHDR || pEntry->nWID == SC_WID_UNO_ABSNAME )
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ else if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
+ {
+ // a style is always set, there's no default state
+ const ScStyleSheet* pStyle = pDocShell->GetDocument().GetSelectionStyle(*GetMarkData());
+ if (pStyle)
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ else
+ eRet = beans::PropertyState_AMBIGUOUS_VALUE;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_NUMRULES )
+ eRet = beans::PropertyState_DEFAULT_VALUE; // numbering rules are always default
+ }
+ return eRet;
+}
+
+beans::PropertyState SAL_CALL ScCellRangesBase::getPropertyState( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ if ( aRanges.empty() )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMap& rMap = GetItemPropertyMap(); // from derived class
+ sal_uInt16 nItemWhich = 0;
+ const SfxItemPropertyMapEntry* pEntry = rMap.getByName( aPropertyName );
+ lcl_GetPropertyWhich( pEntry, nItemWhich );
+ return GetOnePropertyState( nItemWhich, pEntry );
+}
+
+uno::Sequence<beans::PropertyState> SAL_CALL ScCellRangesBase::getPropertyStates(
+ const uno::Sequence<OUString>& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+
+ uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength());
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.getArray(),
+ [this, &rPropertyMap](const auto& rName) -> beans::PropertyState {
+ sal_uInt16 nItemWhich = 0;
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( rName );
+ lcl_GetPropertyWhich( pEntry, nItemWhich );
+ return GetOnePropertyState(nItemWhich, pEntry);
+ });
+ return aRet;
+}
+
+void SAL_CALL ScCellRangesBase::setPropertyToDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ if ( !pDocShell )
+ return;
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ sal_uInt16 nItemWhich = 0;
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ lcl_GetPropertyWhich( pEntry, nItemWhich );
+ if ( nItemWhich ) // item wid (from map or special case)
+ {
+ if ( !aRanges.empty() ) // empty = nothing to do
+ {
+ //! for items that have multiple properties (e.g. background)
+ //! too much will be reset
+ //! for ATTR_ROTATE_VALUE, reset ATTR_ORIENTATION as well?
+
+ sal_uInt16 aWIDs[3];
+ aWIDs[0] = nItemWhich;
+ if ( nItemWhich == ATTR_VALUE_FORMAT )
+ {
+ aWIDs[1] = ATTR_LANGUAGE_FORMAT; // language for number formats
+ aWIDs[2] = 0;
+ }
+ else
+ aWIDs[1] = 0;
+ pDocShell->GetDocFunc().ClearItems( *GetMarkData(), aWIDs, true );
+ }
+ }
+ else if ( pEntry )
+ {
+ if ( pEntry->nWID == SC_WID_UNO_CHCOLHDR )
+ bChartColAsHdr = false;
+ else if ( pEntry->nWID == SC_WID_UNO_CHROWHDR )
+ bChartRowAsHdr = false;
+ else if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
+ {
+ OUString aStyleName( ScResId( STR_STYLENAME_STANDARD ) );
+ pDocShell->GetDocFunc().ApplyStyle( *GetMarkData(), aStyleName, true );
+ }
+ }
+}
+
+uno::Any SAL_CALL ScCellRangesBase::getPropertyDefault( const OUString& aPropertyName )
+{
+ //! bundle with getPropertyValue
+
+ SolarMutexGuard aGuard;
+ uno::Any aAny;
+
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( pEntry )
+ {
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ const ScPatternAttr* pPattern = rDoc.GetDefPattern();
+ if ( pPattern )
+ {
+ const SfxItemSet& rSet = pPattern->GetItemSet();
+
+ switch ( pEntry->nWID ) // for item-specific handling
+ {
+ case ATTR_VALUE_FORMAT:
+ // default has no language set
+ aAny <<= static_cast<sal_Int32>( static_cast<const SfxUInt32Item&>(rSet.Get(pEntry->nWID)).GetValue() );
+ break;
+ case ATTR_INDENT:
+ aAny <<= static_cast<sal_Int16>( convertTwipToMm100(static_cast<const ScIndentItem&>(
+ rSet.Get(pEntry->nWID)).GetValue()) );
+ break;
+ default:
+ pPropSet->getPropertyValue(aPropertyName, rSet, aAny);
+ }
+ }
+ }
+ else
+ switch ( pEntry->nWID )
+ {
+ case SC_WID_UNO_CHCOLHDR:
+ case SC_WID_UNO_CHROWHDR:
+ aAny <<= false;
+ break;
+ case SC_WID_UNO_CELLSTYL:
+ aAny <<= ScStyleNameConversion::DisplayToProgrammaticName(
+ ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Para );
+ break;
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ {
+ const ScPatternAttr* pPattern = rDoc.GetDefPattern();
+ if ( pPattern )
+ {
+ if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
+ ScHelperFunctions::AssignTableBorder2ToAny( aAny,
+ pPattern->GetItem(ATTR_BORDER),
+ pPattern->GetItem(ATTR_BORDER_INNER) );
+ else
+ ScHelperFunctions::AssignTableBorderToAny( aAny,
+ pPattern->GetItem(ATTR_BORDER),
+ pPattern->GetItem(ATTR_BORDER_INNER) );
+ }
+ }
+ break;
+ case SC_WID_UNO_CONDFMT:
+ case SC_WID_UNO_CONDLOC:
+ case SC_WID_UNO_CONDXML:
+ {
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ rDoc.GetStorageGrammar() :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+
+ aAny <<= uno::Reference<sheet::XSheetConditionalEntries>(
+ new ScTableConditionalFormat( &rDoc, 0, aRanges[0].aStart.Tab(), eGrammar ));
+ }
+ break;
+ case SC_WID_UNO_VALIDAT:
+ case SC_WID_UNO_VALILOC:
+ case SC_WID_UNO_VALIXML:
+ {
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ rDoc.GetStorageGrammar() :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+
+ aAny <<= uno::Reference<beans::XPropertySet>(
+ new ScTableValidationObj( rDoc, 0, eGrammar ));
+ }
+ break;
+ case SC_WID_UNO_NUMRULES:
+ {
+ aAny <<= ScStyleObj::CreateEmptyNumberingRules();
+ }
+ break;
+ }
+ }
+ }
+
+ return aAny;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCellRangesBase::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pPropSet->getPropertyMap() ));
+ return aRef;
+}
+
+static void lcl_SetCellProperty( const SfxItemPropertyMapEntry& rEntry, const uno::Any& rValue,
+ ScPatternAttr& rPattern, const ScDocument &rDoc,
+ sal_uInt16& rFirstItemId, sal_uInt16& rSecondItemId )
+{
+ rFirstItemId = rEntry.nWID;
+ rSecondItemId = 0;
+
+ SfxItemSet& rSet = rPattern.GetItemSet();
+ switch ( rEntry.nWID )
+ {
+ case ATTR_VALUE_FORMAT:
+ {
+ // language for number formats
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ sal_uLong nOldFormat = rSet.Get( ATTR_VALUE_FORMAT ).GetValue();
+ LanguageType eOldLang = rSet.Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
+ nOldFormat = pFormatter->GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
+
+ sal_Int32 nIntVal = 0;
+ if ( !(rValue >>= nIntVal) )
+ throw lang::IllegalArgumentException();
+
+ sal_uLong nNewFormat = static_cast<sal_uLong>(nIntVal);
+ rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
+
+ const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
+ LanguageType eNewLang =
+ pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
+ if ( eNewLang != eOldLang && eNewLang != LANGUAGE_DONTKNOW )
+ {
+ rSet.Put( SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
+
+ // if only language is changed,
+ // don't touch number format attribute
+ sal_uLong nNewMod = nNewFormat % SV_COUNTRY_LANGUAGE_OFFSET;
+ if ( nNewMod == ( nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET ) &&
+ nNewMod <= SV_MAX_COUNT_STANDARD_FORMATS )
+ {
+ rFirstItemId = 0; // don't use ATTR_VALUE_FORMAT value
+ }
+
+ rSecondItemId = ATTR_LANGUAGE_FORMAT;
+ }
+
+ }
+ break;
+ case ATTR_INDENT:
+ {
+ sal_Int16 nIntVal = 0;
+ if ( !(rValue >>= nIntVal) )
+ throw lang::IllegalArgumentException();
+
+ rSet.Put(ScIndentItem(o3tl::toTwips(nIntVal, o3tl::Length::mm100)));
+
+ }
+ break;
+ case ATTR_ROTATE_VALUE:
+ {
+ sal_Int32 nRotVal = 0;
+ if ( !(rValue >>= nRotVal) )
+ throw lang::IllegalArgumentException();
+
+ // stored value is always between 0 and 360 deg.
+ nRotVal %= 36000;
+ if ( nRotVal < 0 )
+ nRotVal += 36000;
+
+ rSet.Put( ScRotateValueItem( Degree100(nRotVal) ) );
+
+ }
+ break;
+ case ATTR_STACKED:
+ {
+ table::CellOrientation eOrient;
+ if( rValue >>= eOrient )
+ {
+ switch( eOrient )
+ {
+ case table::CellOrientation_STANDARD:
+ rSet.Put( ScVerticalStackCell( false ) );
+ break;
+ case table::CellOrientation_TOPBOTTOM:
+ rSet.Put( ScVerticalStackCell( false ) );
+ rSet.Put( ScRotateValueItem( 27000_deg100 ) );
+ rSecondItemId = ATTR_ROTATE_VALUE;
+ break;
+ case table::CellOrientation_BOTTOMTOP:
+ rSet.Put( ScVerticalStackCell( false ) );
+ rSet.Put( ScRotateValueItem( 9000_deg100 ) );
+ rSecondItemId = ATTR_ROTATE_VALUE;
+ break;
+ case table::CellOrientation_STACKED:
+ rSet.Put( ScVerticalStackCell( true ) );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ break;
+ default:
+ {
+ lcl_GetCellsPropertySet()->setPropertyValue(rEntry, rValue, rSet);
+ }
+ }
+}
+
+void SAL_CALL ScCellRangesBase::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell || aRanges.empty() )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ SetOnePropertyValue( pEntry, aValue );
+}
+
+void ScCellRangesBase::SetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue )
+{
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ if ( !aRanges.empty() ) // empty = nothing to do
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // For parts of compound items with multiple properties (e.g. background)
+ // the old item has to be first fetched from the document.
+ //! But we can't recognize this case here
+ //! -> an extra flag in PropertyMap entry, or something like that???
+ //! fetch the item directly from its position in the range?
+ // ClearInvalidItems, so that in any case we have an item with the correct type
+
+ ScPatternAttr aPattern( *GetCurrentAttrsDeep() );
+ SfxItemSet& rSet = aPattern.GetItemSet();
+ rSet.ClearInvalidItems();
+
+ sal_uInt16 nFirstItem, nSecondItem;
+ lcl_SetCellProperty( *pEntry, aValue, aPattern, rDoc, nFirstItem, nSecondItem );
+
+ for (sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; nWhich++)
+ if ( nWhich != nFirstItem && nWhich != nSecondItem )
+ rSet.ClearItem(nWhich);
+
+ pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), aPattern, true );
+ }
+ }
+ else // implemented here
+ switch ( pEntry->nWID )
+ {
+ case EE_CHAR_ESCAPEMENT: // Specifically for xlsx import
+ {
+ sal_Int32 nValue = 0;
+ aValue >>= nValue;
+ if (nValue)
+ {
+ for (size_t i = 0, n = aRanges.size(); i < n; ++i)
+ {
+ ScRange const & rRange = aRanges[i];
+
+ /* TODO: Iterate through the range */
+ ScAddress aAddr = rRange.aStart;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRefCellValue aCell(rDoc, aAddr);
+
+ OUString aStr = aCell.getString(&rDoc);
+ EditEngine aEngine( rDoc.GetEnginePool() );
+ aEngine.SetEditTextObjectPool(rDoc.GetEditPool());
+
+ /* EE_CHAR_ESCAPEMENT seems to be set on the cell _only_ when
+ * there are no other attribs for the cell.
+ * So, it is safe to overwrite the complete attribute set.
+ * If there is a need - getting CellType and processing
+ * the attributes could be considered.
+ */
+ SfxItemSet aAttr = aEngine.GetEmptyItemSet();
+ aEngine.SetText(aStr);
+ if( nValue < 0 ) // Subscript
+ aAttr.Put( SvxEscapementItem( SvxEscapement::Subscript, EE_CHAR_ESCAPEMENT ) );
+ else // Superscript
+ aAttr.Put( SvxEscapementItem( SvxEscapement::Superscript, EE_CHAR_ESCAPEMENT ) );
+ aEngine.QuickSetAttribs(aAttr, ESelection(0, 0, 0, aStr.getLength()));
+
+ // The cell will own the text object instance.
+ rDoc.SetEditText(aRanges[0].aStart, aEngine.CreateTextObject());
+ }
+ }
+ }
+ break;
+ case SC_WID_UNO_CHCOLHDR:
+ // chart header flags are set for this object, not stored with document
+ bChartColAsHdr = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ break;
+ case SC_WID_UNO_CHROWHDR:
+ bChartRowAsHdr = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ break;
+ case SC_WID_UNO_CELLSTYL:
+ {
+ OUString aStrVal;
+ aValue >>= aStrVal;
+ OUString aString(ScStyleNameConversion::ProgrammaticToDisplayName(
+ aStrVal, SfxStyleFamily::Para ));
+ pDocShell->GetDocFunc().ApplyStyle( *GetMarkData(), aString, true );
+ }
+ break;
+ case SC_WID_UNO_TBLBORD:
+ {
+ table::TableBorder aBorder;
+ if ( !aRanges.empty() && ( aValue >>= aBorder ) ) // empty = nothing to do
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder );
+
+ ScHelperFunctions::ApplyBorder( pDocShell, aRanges, aOuter, aInner ); //! docfunc
+ }
+ }
+ break;
+ case SC_WID_UNO_TBLBORD2:
+ {
+ table::TableBorder2 aBorder2;
+ if ( !aRanges.empty() && ( aValue >>= aBorder2 ) ) // empty = nothing to do
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder2 );
+
+ ScHelperFunctions::ApplyBorder( pDocShell, aRanges, aOuter, aInner ); //! docfunc
+ }
+ }
+ break;
+ case SC_WID_UNO_CONDFMT:
+ case SC_WID_UNO_CONDLOC:
+ case SC_WID_UNO_CONDXML:
+ {
+ uno::Reference<sheet::XSheetConditionalEntries> xInterface(aValue, uno::UNO_QUERY);
+ if ( !aRanges.empty() && xInterface.is() ) // empty = nothing to do
+ {
+ ScTableConditionalFormat* pFormat =
+ dynamic_cast<ScTableConditionalFormat*>( xInterface.get() );
+ if (pFormat)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ formula::FormulaGrammar::GRAM_UNSPECIFIED :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+
+ SCTAB nTab = aRanges.front().aStart.Tab();
+ // To remove conditional formats for all cells in aRanges we need to:
+ // Remove conditional format data from cells' attributes
+ rDoc.RemoveCondFormatData( aRanges, nTab, 0 );
+ // And also remove ranges from conditional formats list
+ for (size_t i = 0; i < aRanges.size(); ++i)
+ {
+ rDoc.GetCondFormList( aRanges[i].aStart.Tab() )->DeleteArea(
+ aRanges[i].aStart.Col(), aRanges[i].aStart.Row(),
+ aRanges[i].aEnd.Col(), aRanges[i].aEnd.Row() );
+ }
+
+ // Then we can apply new conditional format if there is one
+ if (pFormat->getCount())
+ {
+ auto pNew = std::make_unique<ScConditionalFormat>( 0, &rDoc ); // Index will be set on inserting
+ pFormat->FillFormat( *pNew, rDoc, eGrammar );
+ pNew->SetRange( aRanges );
+ pDocShell->GetDocFunc().ReplaceConditionalFormat( 0, std::move(pNew), nTab, aRanges );
+ }
+
+ // and repaint
+ for (size_t i = 0; i < aRanges.size(); ++i)
+ pDocShell->PostPaint(aRanges[i], PaintPartFlags::Grid);
+ pDocShell->SetDocumentModified();
+ }
+ }
+ }
+ break;
+ case SC_WID_UNO_VALIDAT:
+ case SC_WID_UNO_VALILOC:
+ case SC_WID_UNO_VALIXML:
+ {
+ uno::Reference<beans::XPropertySet> xInterface(aValue, uno::UNO_QUERY);
+ if ( !aRanges.empty() && xInterface.is() ) // empty = nothing to do
+ {
+ ScTableValidationObj* pValidObj =
+ dynamic_cast<ScTableValidationObj*>( xInterface.get() );
+ if (pValidObj)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ formula::FormulaGrammar::GRAM_UNSPECIFIED :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+
+ std::unique_ptr<ScValidationData> pNewData(
+ pValidObj->CreateValidationData( rDoc, eGrammar ));
+ sal_uInt32 nIndex = rDoc.AddValidationEntry( *pNewData );
+ pNewData.reset();
+
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nIndex ) );
+ pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), aPattern, true );
+ }
+ }
+ }
+ break;
+ // SC_WID_UNO_NUMRULES is ignored...
+ }
+}
+
+uno::Any SAL_CALL ScCellRangesBase::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell || aRanges.empty() )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+ GetOnePropertyValue( pEntry, aAny );
+ return aAny;
+}
+
+void ScCellRangesBase::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ SfxItemSet* pDataSet = GetCurrentDataSet();
+ if ( pDataSet )
+ {
+ switch ( pEntry->nWID ) // for special handling of items
+ {
+ case ATTR_VALUE_FORMAT:
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ sal_uLong nOldFormat =
+ pDataSet->Get( ATTR_VALUE_FORMAT ).GetValue();
+ LanguageType eOldLang =
+ pDataSet->Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
+ nOldFormat = rDoc.GetFormatTable()->
+ GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
+ rAny <<= static_cast<sal_Int32>(nOldFormat);
+ }
+ break;
+ case ATTR_INDENT:
+ rAny <<= static_cast<sal_Int16>( convertTwipToMm100(static_cast<const ScIndentItem&>(
+ pDataSet->Get(pEntry->nWID)).GetValue()) );
+ break;
+ case ATTR_STACKED:
+ {
+ Degree100 nRot = pDataSet->Get(ATTR_ROTATE_VALUE).GetValue();
+ bool bStacked = static_cast<const ScVerticalStackCell&>(pDataSet->Get(pEntry->nWID)).GetValue();
+ SvxOrientationItem( nRot, bStacked, TypedWhichId<SvxOrientationItem>(0) ).QueryValue( rAny );
+ }
+ break;
+ default:
+ pPropSet->getPropertyValue(*pEntry, *pDataSet, rAny);
+ }
+ }
+ }
+ else // implemented here
+ switch ( pEntry->nWID )
+ {
+ case SC_WID_UNO_CHCOLHDR:
+ rAny <<= bChartColAsHdr;
+ break;
+ case SC_WID_UNO_CHROWHDR:
+ rAny <<= bChartRowAsHdr;
+ break;
+ case SC_WID_UNO_CELLSTYL:
+ {
+ OUString aStyleName;
+ const ScStyleSheet* pStyle = pDocShell->GetDocument().GetSelectionStyle(*GetMarkData());
+ if (pStyle)
+ aStyleName = pStyle->GetName();
+ rAny <<= ScStyleNameConversion::DisplayToProgrammaticName(
+ aStyleName, SfxStyleFamily::Para );
+ }
+ break;
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ {
+ //! loop through all ranges
+ if ( !aRanges.empty() )
+ {
+ const ScRange & rFirst = aRanges[ 0 ];
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SetMarkArea( rFirst );
+ aMark.SelectTable( rFirst.aStart.Tab(), true );
+ rDoc.GetSelectionFrame( aMark, aOuter, aInner );
+
+ if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
+ ScHelperFunctions::AssignTableBorder2ToAny( rAny, aOuter, aInner);
+ else
+ ScHelperFunctions::AssignTableBorderToAny( rAny, aOuter, aInner);
+ }
+ }
+ break;
+ case SC_WID_UNO_CONDFMT:
+ case SC_WID_UNO_CONDLOC:
+ case SC_WID_UNO_CONDXML:
+ {
+ const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
+ if ( pPattern )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ rDoc.GetStorageGrammar() :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+ const ScCondFormatIndexes& rIndex =
+ pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
+ sal_uLong nIndex = 0;
+ if(!rIndex.empty())
+ nIndex = rIndex[0];
+ rAny <<= uno::Reference<sheet::XSheetConditionalEntries>(
+ new ScTableConditionalFormat( &rDoc, nIndex, aRanges.front().aStart.Tab(), eGrammar ));
+ }
+ }
+ break;
+ case SC_WID_UNO_VALIDAT:
+ case SC_WID_UNO_VALILOC:
+ case SC_WID_UNO_VALIXML:
+ {
+ const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
+ if ( pPattern )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ rDoc.GetStorageGrammar() :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+ sal_uLong nIndex =
+ pPattern->GetItem(ATTR_VALIDDATA).GetValue();
+ rAny <<= uno::Reference<beans::XPropertySet>(
+ new ScTableValidationObj( rDoc, nIndex, eGrammar ));
+ }
+ }
+ break;
+ case SC_WID_UNO_NUMRULES:
+ {
+ // always return empty numbering rules object
+ rAny <<= ScStyleObj::CreateEmptyNumberingRules();
+ }
+ break;
+ case SC_WID_UNO_ABSNAME:
+ {
+ OUString sRet;
+ aRanges.Format(sRet, ScRefFlags::RANGE_ABS_3D, pDocShell->GetDocument());
+ rAny <<= sRet;
+ }
+ break;
+ case SC_WID_UNO_FORMATID:
+ {
+ const ScPatternAttr* pPattern = GetCurrentAttrsFlat();
+ rAny <<= pPattern->GetPAKey();
+ }
+ break;
+ }
+}
+
+void SAL_CALL ScCellRangesBase::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SolarMutexGuard aGuard;
+ if ( aRanges.empty() )
+ throw uno::RuntimeException();
+
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellRangesBase::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SolarMutexGuard aGuard;
+ if ( aRanges.empty() )
+ throw uno::RuntimeException();
+
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellRangesBase::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellRangesBase::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ OSL_FAIL("not implemented");
+}
+
+// XMultiPropertySet
+
+void SAL_CALL ScCellRangesBase::setPropertyValues( const uno::Sequence< OUString >& aPropertyNames,
+ const uno::Sequence< uno::Any >& aValues )
+{
+ SolarMutexGuard aGuard;
+
+ sal_Int32 nCount(aPropertyNames.getLength());
+ sal_Int32 nValues(aValues.getLength());
+ if (nCount != nValues)
+ throw lang::IllegalArgumentException();
+
+ if ( !(pDocShell && nCount) )
+ return;
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ const OUString* pNames = aPropertyNames.getConstArray();
+ const uno::Any* pValues = aValues.getConstArray();
+
+ std::unique_ptr<const SfxItemPropertyMapEntry*[]> pEntryArray(new const SfxItemPropertyMapEntry*[nCount]);
+
+ sal_Int32 i;
+ for(i = 0; i < nCount; i++)
+ {
+ // first loop: find all properties in map, but handle only CellStyle
+ // (CellStyle must be set before any other cell properties)
+
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( pNames[i] );
+ pEntryArray[i] = pEntry;
+ if (pEntry)
+ {
+ if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
+ {
+ try
+ {
+ SetOnePropertyValue( pEntry, pValues[i] );
+ }
+ catch ( lang::IllegalArgumentException& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "exception when setting cell style"); // not supposed to happen
+ }
+ }
+ }
+ }
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::unique_ptr<ScPatternAttr> pOldPattern;
+ std::unique_ptr<ScPatternAttr> pNewPattern;
+
+ for(i = 0; i < nCount; i++)
+ {
+ // second loop: handle other properties
+
+ const SfxItemPropertyMapEntry* pEntry = pEntryArray[i];
+ if ( pEntry )
+ {
+ if ( IsScItemWid( pEntry->nWID ) ) // can be handled by SfxItemPropertySet
+ {
+ if ( !pOldPattern )
+ {
+ pOldPattern.reset(new ScPatternAttr( *GetCurrentAttrsDeep() ));
+ pOldPattern->GetItemSet().ClearInvalidItems();
+ pNewPattern.reset(new ScPatternAttr( rDoc.GetPool() ));
+ }
+
+ // collect items in pNewPattern, apply with one call after the loop
+
+ sal_uInt16 nFirstItem, nSecondItem;
+ lcl_SetCellProperty( *pEntry, pValues[i], *pOldPattern, rDoc, nFirstItem, nSecondItem );
+
+ // put only affected items into new set
+ if ( nFirstItem )
+ pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nFirstItem ) );
+ if ( nSecondItem )
+ pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nSecondItem ) );
+ }
+ else if ( pEntry->nWID != SC_WID_UNO_CELLSTYL ) // CellStyle is handled above
+ {
+ // call virtual method to set a single property
+ SetOnePropertyValue( pEntry, pValues[i] );
+ }
+ }
+ }
+
+ if ( pNewPattern && !aRanges.empty() )
+ pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), *pNewPattern, true );
+}
+
+uno::Sequence<uno::Any> SAL_CALL ScCellRangesBase::getPropertyValues(
+ const uno::Sequence< OUString >& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+
+ uno::Sequence<uno::Any> aRet(aPropertyNames.getLength());
+ uno::Any* pProperties = aRet.getArray();
+ for(sal_Int32 i = 0; i < aPropertyNames.getLength(); i++)
+ {
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
+ GetOnePropertyValue( pEntry, pProperties[i] );
+ }
+ return aRet;
+}
+
+void SAL_CALL ScCellRangesBase::addPropertiesChangeListener( const uno::Sequence< OUString >& /* aPropertyNames */,
+ const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellRangesBase::removePropertiesChangeListener( const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellRangesBase::firePropertiesChangeEvent( const uno::Sequence< OUString >& /* aPropertyNames */,
+ const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+IMPL_LINK( ScCellRangesBase, ValueListenerHdl, const SfxHint&, rHint, void )
+{
+ if ( pDocShell && (rHint.GetId() == SfxHintId::ScDataChanged))
+ {
+ // This may be called several times for a single change, if several formulas
+ // in the range are notified. So only a flag is set that is checked when
+ // SfxHintId::DataChanged is received.
+
+ bGotDataChangedHint = true;
+ }
+}
+
+// XTolerantMultiPropertySet
+uno::Sequence< beans::SetPropertyTolerantFailed > SAL_CALL ScCellRangesBase::setPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames,
+ const uno::Sequence< uno::Any >& aValues )
+{
+ SolarMutexGuard aGuard;
+
+ sal_Int32 nCount(aPropertyNames.getLength());
+ sal_Int32 nValues(aValues.getLength());
+ if (nCount != nValues)
+ throw lang::IllegalArgumentException();
+
+ if ( pDocShell && nCount )
+ {
+ uno::Sequence < beans::SetPropertyTolerantFailed > aReturns(nCount);
+ beans::SetPropertyTolerantFailed* pReturns = aReturns.getArray();
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ const OUString* pNames = aPropertyNames.getConstArray();
+ const uno::Any* pValues = aValues.getConstArray();
+
+ std::unique_ptr<const SfxItemPropertyMapEntry*[]> pMapArray(new const SfxItemPropertyMapEntry*[nCount]);
+
+ sal_Int32 i;
+ for(i = 0; i < nCount; i++)
+ {
+ // first loop: find all properties in map, but handle only CellStyle
+ // (CellStyle must be set before any other cell properties)
+
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( pNames[i] );
+ pMapArray[i] = pEntry;
+ if (pEntry)
+ {
+ if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
+ {
+ try
+ {
+ SetOnePropertyValue( pEntry, pValues[i] );
+ }
+ catch ( lang::IllegalArgumentException& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "exception when setting cell style"); // not supposed to happen
+ }
+ }
+ }
+ }
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::unique_ptr<ScPatternAttr> pOldPattern;
+ std::unique_ptr<ScPatternAttr> pNewPattern;
+
+ sal_Int32 nFailed(0);
+ for(i = 0; i < nCount; i++)
+ {
+ // second loop: handle other properties
+
+ const SfxItemPropertyMapEntry* pEntry = pMapArray[i];
+ if ( pEntry && ((pEntry->nFlags & beans::PropertyAttribute::READONLY) == 0))
+ {
+ if ( IsScItemWid( pEntry->nWID ) ) // can be handled by SfxItemPropertySet
+ {
+ if ( !pOldPattern )
+ {
+ pOldPattern.reset(new ScPatternAttr( *GetCurrentAttrsDeep() ));
+ pOldPattern->GetItemSet().ClearInvalidItems();
+ pNewPattern.reset(new ScPatternAttr( rDoc.GetPool() ));
+ }
+
+ // collect items in pNewPattern, apply with one call after the loop
+ try
+ {
+ sal_uInt16 nFirstItem, nSecondItem;
+ lcl_SetCellProperty( *pEntry, pValues[i], *pOldPattern, rDoc, nFirstItem, nSecondItem );
+
+ // put only affected items into new set
+ if ( nFirstItem )
+ pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nFirstItem ) );
+ if ( nSecondItem )
+ pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nSecondItem ) );
+ }
+ catch ( lang::IllegalArgumentException& )
+ {
+ pReturns[nFailed].Name = pNames[i];
+ pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT;
+ }
+ }
+ else if ( pEntry->nWID != SC_WID_UNO_CELLSTYL ) // CellStyle is handled above
+ {
+ // call virtual method to set a single property
+ try
+ {
+ SetOnePropertyValue( pEntry, pValues[i] );
+ }
+ catch ( lang::IllegalArgumentException& )
+ {
+ pReturns[nFailed].Name = pNames[i];
+ pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT;
+ }
+ }
+ }
+ else
+ {
+ pReturns[nFailed].Name = pNames[i];
+ if (pEntry)
+ pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::PROPERTY_VETO;
+ else
+ pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
+ }
+ }
+
+ if ( pNewPattern && !aRanges.empty() )
+ pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), *pNewPattern, true );
+
+ aReturns.realloc(nFailed);
+
+ return aReturns;
+ }
+ return uno::Sequence < beans::SetPropertyTolerantFailed >();
+}
+
+uno::Sequence< beans::GetPropertyTolerantResult > SAL_CALL ScCellRangesBase::getPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+
+ sal_Int32 nCount(aPropertyNames.getLength());
+ uno::Sequence < beans::GetPropertyTolerantResult > aReturns(nCount);
+ beans::GetPropertyTolerantResult* pReturns = aReturns.getArray();
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+
+ for(sal_Int32 i = 0; i < nCount; i++)
+ {
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
+ if (!pEntry)
+ {
+ pReturns[i].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
+ }
+ else
+ {
+ sal_uInt16 nItemWhich = 0;
+ lcl_GetPropertyWhich( pEntry, nItemWhich );
+ pReturns[i].State = GetOnePropertyState( nItemWhich, pEntry );
+ GetOnePropertyValue( pEntry, pReturns[i].Value );
+ pReturns[i].Result = beans::TolerantPropertySetResultType::SUCCESS;
+ }
+ }
+ return aReturns;
+}
+
+uno::Sequence< beans::GetDirectPropertyTolerantResult > SAL_CALL ScCellRangesBase::getDirectPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+
+ sal_Int32 nCount(aPropertyNames.getLength());
+ uno::Sequence < beans::GetDirectPropertyTolerantResult > aReturns(nCount);
+ beans::GetDirectPropertyTolerantResult* pReturns = aReturns.getArray();
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+
+ sal_Int32 j = 0;
+ for(sal_Int32 i = 0; i < nCount; i++)
+ {
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
+ if (!pEntry)
+ {
+ pReturns[i].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
+ }
+ else
+ {
+ sal_uInt16 nItemWhich = 0;
+ lcl_GetPropertyWhich( pEntry, nItemWhich );
+ pReturns[j].State = GetOnePropertyState( nItemWhich, pEntry );
+ if (pReturns[j].State == beans::PropertyState_DIRECT_VALUE)
+ {
+ GetOnePropertyValue( pEntry, pReturns[j].Value );
+ pReturns[j].Result = beans::TolerantPropertySetResultType::SUCCESS;
+ pReturns[j].Name = aPropertyNames[i];
+ ++j;
+ }
+ }
+ }
+ if (j < nCount)
+ aReturns.realloc(j);
+ return aReturns;
+}
+
+// XIndent
+
+void SAL_CALL ScCellRangesBase::decrementIndent()
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell && !aRanges.empty() )
+ {
+ //#97041#; put only MultiMarked ScMarkData in ChangeIndent
+ ScMarkData aMarkData(*GetMarkData());
+ aMarkData.MarkToMulti();
+ pDocShell->GetDocFunc().ChangeIndent( aMarkData, false, true );
+ }
+}
+
+void SAL_CALL ScCellRangesBase::incrementIndent()
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell && !aRanges.empty() )
+ {
+ //#97041#; put only MultiMarked ScMarkData in ChangeIndent
+ ScMarkData aMarkData(*GetMarkData());
+ aMarkData.MarkToMulti();
+ pDocShell->GetDocFunc().ChangeIndent( aMarkData, true, true );
+ }
+}
+
+// XChartData
+
+std::unique_ptr<ScMemChart> ScCellRangesBase::CreateMemChart_Impl() const
+{
+ if ( pDocShell && !aRanges.empty() )
+ {
+ ScRangeListRef xChartRanges;
+ if ( aRanges.size() == 1 )
+ {
+ // set useful table limit (only occupied data area)
+ // (only here - Listeners are registered for the whole area)
+ //! check immediately if a ScTableSheetObj?
+
+ const ScDocument & rDoc = pDocShell->GetDocument();
+ const ScRange & rRange = aRanges[0];
+ if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
+ rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
+ {
+ SCTAB nTab = rRange.aStart.Tab();
+
+ SCCOL nStartX;
+ SCROW nStartY; // Get start
+ if (!pDocShell->GetDocument().GetDataStart( nTab, nStartX, nStartY ))
+ {
+ nStartX = 0;
+ nStartY = 0;
+ }
+
+ SCCOL nEndX;
+ SCROW nEndY; // Get end
+ if (!pDocShell->GetDocument().GetTableArea( nTab, nEndX, nEndY ))
+ {
+ nEndX = 0;
+ nEndY = 0;
+ }
+
+ xChartRanges = new ScRangeList( ScRange( nStartX, nStartY, nTab, nEndX, nEndY, nTab ) );
+ }
+ }
+ if (!xChartRanges.is()) // otherwise take Ranges directly
+ xChartRanges = new ScRangeList(aRanges);
+ ScChartArray aArr( pDocShell->GetDocument(), xChartRanges );
+
+ // RowAsHdr = ColHeaders and vice versa
+ aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr );
+
+ return aArr.CreateMemChart();
+ }
+ return nullptr;
+}
+
+uno::Sequence< uno::Sequence<double> > SAL_CALL ScCellRangesBase::getData()
+{
+ SolarMutexGuard aGuard;
+ std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
+ if ( pMemChart )
+ {
+ sal_Int32 nColCount = pMemChart->GetColCount();
+ sal_Int32 nRowCount = static_cast<sal_Int32>(pMemChart->GetRowCount());
+
+ uno::Sequence< uno::Sequence<double> > aRowSeq( nRowCount );
+ uno::Sequence<double>* pRowAry = aRowSeq.getArray();
+ for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<double> aColSeq( nColCount );
+ double* pColAry = aColSeq.getArray();
+ for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
+ pColAry[nCol] = pMemChart->GetData( nCol, nRow );
+
+ pRowAry[nRow] = aColSeq;
+ }
+
+ return aRowSeq;
+ }
+
+ return {};
+}
+
+ScRangeListRef ScCellRangesBase::GetLimitedChartRanges_Impl( sal_Int32 nDataColumns, sal_Int32 nDataRows ) const
+{
+ if ( aRanges.size() == 1 )
+ {
+ const ScDocument & rDoc = pDocShell->GetDocument();
+ const ScRange & rRange = aRanges[0];
+ if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
+ rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
+ {
+ // if aRanges is a complete sheet, limit to given size
+
+ SCTAB nTab = rRange.aStart.Tab();
+
+ sal_Int32 nEndColumn = nDataColumns - 1 + ( bChartColAsHdr ? 1 : 0 );
+ if ( nEndColumn < 0 )
+ nEndColumn = 0;
+ if ( nEndColumn > rDoc.MaxCol() )
+ nEndColumn = rDoc.MaxCol();
+
+ sal_Int32 nEndRow = nDataRows - 1 + ( bChartRowAsHdr ? 1 : 0 );
+ if ( nEndRow < 0 )
+ nEndRow = 0;
+ if ( nEndRow > rDoc.MaxRow() )
+ nEndRow = rDoc.MaxRow();
+
+ ScRangeListRef xChartRanges = new ScRangeList( ScRange( 0, 0, nTab, static_cast<SCCOL>(nEndColumn), static_cast<SCROW>(nEndRow), nTab ) );
+ return xChartRanges;
+ }
+ }
+
+ return new ScRangeList(aRanges); // as-is
+}
+
+void SAL_CALL ScCellRangesBase::setData( const uno::Sequence< uno::Sequence<double> >& aData )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ sal_Int32 nRowCount = aData.getLength();
+ sal_Int32 nColCount = nRowCount ? aData[0].getLength() : 0;
+ ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( nColCount, nRowCount );
+ if ( pDocShell && xChartRanges.is() )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChartArray aArr( rDoc, xChartRanges );
+ aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
+ const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
+ if (pPosMap)
+ {
+ if ( pPosMap->GetColCount() == static_cast<SCCOL>(nColCount) &&
+ pPosMap->GetRowCount() == static_cast<SCROW>(nRowCount) )
+ {
+ for (sal_Int32 nRow=0; nRow<nRowCount; nRow++)
+ {
+ const uno::Sequence<double>& rRowSeq = aData[nRow];
+ const double* pArray = rRowSeq.getConstArray();
+ nColCount = rRowSeq.getLength();
+ for (sal_Int32 nCol=0; nCol<nColCount; nCol++)
+ {
+ const ScAddress* pPos = pPosMap->GetPosition(
+ sal::static_int_cast<SCCOL>(nCol),
+ sal::static_int_cast<SCROW>(nRow) );
+ if (pPos)
+ {
+ double fVal = pArray[nCol];
+ if ( fVal == DBL_MIN )
+ rDoc.SetEmptyCell(*pPos);
+ else
+ rDoc.SetValue(*pPos, pArray[nCol]);
+ }
+ }
+ }
+
+ //! undo
+ PaintGridRanges_Impl();
+ pDocShell->SetDocumentModified();
+ ForceChartListener_Impl(); // call listeners for this object synchronously
+ bDone = true;
+ }
+ }
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException();
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellRangesBase::getRowDescriptions()
+{
+ SolarMutexGuard aGuard;
+ std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
+ if ( pMemChart )
+ {
+ sal_Int32 nRowCount = static_cast<sal_Int32>(pMemChart->GetRowCount());
+ uno::Sequence<OUString> aSeq( nRowCount );
+ OUString* pAry = aSeq.getArray();
+ for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
+ pAry[nRow] = pMemChart->GetRowText(nRow);
+
+ return aSeq;
+ }
+ return {};
+}
+
+void SAL_CALL ScCellRangesBase::setRowDescriptions(
+ const uno::Sequence<OUString>& aRowDescriptions )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if ( bChartColAsHdr )
+ {
+ sal_Int32 nRowCount = aRowDescriptions.getLength();
+ ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( 1, nRowCount );
+ if ( pDocShell && xChartRanges.is() )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChartArray aArr( rDoc, xChartRanges );
+ aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
+ const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
+ if (pPosMap)
+ {
+ if ( pPosMap->GetRowCount() == static_cast<SCROW>(nRowCount) )
+ {
+ const OUString* pArray = aRowDescriptions.getConstArray();
+ for (sal_Int32 nRow=0; nRow<nRowCount; nRow++)
+ {
+ const ScAddress* pPos = pPosMap->GetRowHeaderPosition(
+ static_cast<SCSIZE>(nRow) );
+ if (pPos)
+ {
+ const OUString& aStr = pArray[nRow];
+ if (aStr.isEmpty())
+ rDoc.SetEmptyCell(*pPos);
+ else
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(*pPos, aStr, &aParam);
+ }
+ }
+ }
+
+ //! undo
+ PaintGridRanges_Impl();
+ pDocShell->SetDocumentModified();
+ ForceChartListener_Impl(); // call listeners for this object synchronously
+ bDone = true;
+ }
+ }
+ }
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException();
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellRangesBase::getColumnDescriptions()
+{
+ SolarMutexGuard aGuard;
+ std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
+ if ( pMemChart )
+ {
+ sal_Int32 nColCount = pMemChart->GetColCount();
+ uno::Sequence<OUString> aSeq( nColCount );
+ OUString* pAry = aSeq.getArray();
+ for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
+ pAry[nCol] = pMemChart->GetColText(nCol);
+
+ return aSeq;
+ }
+ return {};
+}
+
+void SAL_CALL ScCellRangesBase::setColumnDescriptions(
+ const uno::Sequence<OUString>& aColumnDescriptions )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if ( bChartRowAsHdr )
+ {
+ sal_Int32 nColCount = aColumnDescriptions.getLength();
+ ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( nColCount, 1 );
+ if ( pDocShell && xChartRanges.is() )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChartArray aArr( rDoc, xChartRanges );
+ aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
+ const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
+ if (pPosMap)
+ {
+ if ( pPosMap->GetColCount() == static_cast<SCCOL>(nColCount) )
+ {
+ const OUString* pArray = aColumnDescriptions.getConstArray();
+ for (sal_Int32 nCol=0; nCol<nColCount; nCol++)
+ {
+ const ScAddress* pPos = pPosMap->GetColHeaderPosition(
+ sal::static_int_cast<SCCOL>(nCol) );
+ if (pPos)
+ {
+ const OUString& aStr = pArray[nCol];
+ if (aStr.isEmpty())
+ rDoc.SetEmptyCell(*pPos);
+ else
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(*pPos, aStr, &aParam);
+ }
+ }
+ }
+
+ //! undo
+ PaintGridRanges_Impl();
+ pDocShell->SetDocumentModified();
+ ForceChartListener_Impl(); // call listeners for this object synchronously
+ bDone = true;
+ }
+ }
+ }
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException();
+}
+
+void ScCellRangesBase::ForceChartListener_Impl()
+{
+ // call Update immediately so the caller to setData etc. can
+ // recognize the listener call
+
+ if (!pDocShell)
+ return;
+
+ ScChartListenerCollection* pColl = pDocShell->GetDocument().GetChartListenerCollection();
+ if (!pColl)
+ return;
+
+ ScChartListenerCollection::ListenersType& rListeners = pColl->getListeners();
+ for (auto const& it : rListeners)
+ {
+ ScChartListener *const p = it.second.get();
+ assert(p);
+ if (p->GetUnoSource() == static_cast<chart::XChartData*>(this) && p->IsDirty())
+ p->Update();
+ }
+}
+
+void SAL_CALL ScCellRangesBase::addChartDataChangeEventListener( const uno::Reference<
+ chart::XChartDataChangeEventListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+ if ( !pDocShell || aRanges.empty() )
+ return;
+
+ //! test for duplicates ?
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangeListRef aRangesRef( new ScRangeList(aRanges) );
+ ScChartListenerCollection* pColl = rDoc.GetChartListenerCollection();
+ OUString aName = pColl->getUniqueName(u"__Uno");
+ if (aName.isEmpty())
+ // failed to create unique name.
+ return;
+
+ ScChartListener* pListener = new ScChartListener( aName, rDoc, aRangesRef );
+ pListener->SetUno( aListener, this );
+ pColl->insert( pListener );
+ pListener->StartListeningTo();
+}
+
+void SAL_CALL ScCellRangesBase::removeChartDataChangeEventListener( const uno::Reference<
+ chart::XChartDataChangeEventListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell && !aRanges.empty() )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChartListenerCollection* pColl = rDoc.GetChartListenerCollection();
+ pColl->FreeUno( aListener, this );
+ }
+}
+
+double SAL_CALL ScCellRangesBase::getNotANumber()
+{
+ // use DBL_MIN in ScChartArray, because Chart wants it so
+ return DBL_MIN;
+}
+
+sal_Bool SAL_CALL ScCellRangesBase::isNotANumber( double nNumber )
+{
+ // use DBL_MIN in ScChartArray, because Chart wants it so
+ return (nNumber == DBL_MIN);
+}
+
+// XModifyBroadcaster
+
+void SAL_CALL ScCellRangesBase::addModifyListener(const uno::Reference<util::XModifyListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+ if ( aRanges.empty() )
+ throw uno::RuntimeException();
+
+ aValueListeners.emplace_back( aListener );
+
+ if ( aValueListeners.size() == 1 )
+ {
+ if (!pValueListener)
+ pValueListener.reset( new ScLinkListener( LINK( this, ScCellRangesBase, ValueListenerHdl ) ) );
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for ( size_t i = 0, nCount = aRanges.size(); i < nCount; i++)
+ rDoc.StartListeningArea( aRanges[ i ], false, pValueListener.get() );
+
+ acquire(); // don't lose this object (one ref for all listeners)
+ }
+}
+
+void SAL_CALL ScCellRangesBase::removeModifyListener( const uno::Reference<util::XModifyListener>& aListener )
+{
+
+ SolarMutexGuard aGuard;
+ if ( aRanges.empty() )
+ throw uno::RuntimeException();
+
+ rtl::Reference<ScCellRangesBase> xSelfHold(this); // in case the listeners have the last ref
+
+ sal_uInt16 nCount = aValueListeners.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ {
+ uno::Reference<util::XModifyListener>& rObj = aValueListeners[n];
+ if ( rObj == aListener )
+ {
+ aValueListeners.erase( aValueListeners.begin() + n );
+
+ if ( aValueListeners.empty() )
+ {
+ if (pValueListener)
+ pValueListener->EndListeningAll();
+
+ release(); // release the ref for the listeners
+ }
+
+ break;
+ }
+ }
+}
+
+// XCellRangesQuery
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryVisibleCells()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ //! Separate for all tables, if markings separated per table
+ SCTAB nTab = lcl_FirstTab(aRanges);
+
+ ScMarkData aMarkData(*GetMarkData());
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCCOL nCol = 0, nLastCol;
+ while (nCol <= rDoc.MaxCol())
+ {
+ if (rDoc.ColHidden(nCol, nTab, nullptr, &nLastCol))
+ // hidden columns. Deselect them.
+ aMarkData.SetMultiMarkArea(ScRange(nCol, 0, nTab, nLastCol, rDoc.MaxRow(), nTab), false);
+
+ nCol = nLastCol + 1;
+ }
+
+ SCROW nRow = 0, nLastRow;
+ while (nRow <= rDoc.MaxRow())
+ {
+ if (rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow))
+ // These rows are hidden. Deselect them.
+ aMarkData.SetMultiMarkArea(ScRange(0, nRow, nTab, rDoc.MaxCol(), nLastRow, nTab), false);
+
+ nRow = nLastRow + 1;
+ }
+
+ ScRangeList aNewRanges;
+ aMarkData.FillRangeListWithMarks( &aNewRanges, false );
+ return new ScCellRangesObj( pDocShell, aNewRanges );
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryEmptyCells()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScMarkData aMarkData(*GetMarkData());
+
+ // mark occupied cells
+ for (size_t i = 0, nCount = aRanges.size(); i < nCount; ++i)
+ {
+ ScRange const & rRange = aRanges[ i ];
+
+ ScCellIterator aIter(rDoc, rRange);
+ for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
+ {
+ // notes count as non-empty
+ if (!aIter.isEmpty())
+ aMarkData.SetMultiMarkArea(aIter.GetPos(), false);
+ }
+ }
+
+ ScRangeList aNewRanges;
+ // IsMultiMarked is not enough (will not be reset during deselecting)
+ //if (aMarkData.HasAnyMultiMarks()) // #i20044# should be set for all empty range
+ aMarkData.FillRangeListWithMarks( &aNewRanges, false );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryContentCells(
+ sal_Int16 nContentFlags )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+
+ // select matching cells
+ for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
+ {
+ ScRange const & rRange = aRanges[ i ];
+
+ ScCellIterator aIter(rDoc, rRange);
+ for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
+ {
+ bool bAdd = false;
+ switch (aIter.getType())
+ {
+ case CELLTYPE_STRING:
+ if ( nContentFlags & sheet::CellFlags::STRING )
+ bAdd = true;
+ break;
+ case CELLTYPE_EDIT:
+ if ( (nContentFlags & sheet::CellFlags::STRING) || (nContentFlags & sheet::CellFlags::FORMATTED) )
+ bAdd = true;
+ break;
+ case CELLTYPE_FORMULA:
+ if ( nContentFlags & sheet::CellFlags::FORMULA )
+ bAdd = true;
+ break;
+ case CELLTYPE_VALUE:
+ if ( (nContentFlags & (sheet::CellFlags::VALUE|sheet::CellFlags::DATETIME))
+ == (sheet::CellFlags::VALUE|sheet::CellFlags::DATETIME) )
+ bAdd = true;
+ else
+ {
+ // date/time identification
+
+ sal_uLong nIndex = static_cast<sal_uLong>(rDoc.GetAttr(
+ aIter.GetPos(), ATTR_VALUE_FORMAT)->GetValue());
+ SvNumFormatType nTyp = rDoc.GetFormatTable()->GetType(nIndex);
+ if ((nTyp == SvNumFormatType::DATE) || (nTyp == SvNumFormatType::TIME) ||
+ (nTyp == SvNumFormatType::DATETIME))
+ {
+ if ( nContentFlags & sheet::CellFlags::DATETIME )
+ bAdd = true;
+ }
+ else
+ {
+ if ( nContentFlags & sheet::CellFlags::VALUE )
+ bAdd = true;
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (bAdd)
+ aMarkData.SetMultiMarkArea(aIter.GetPos());
+ }
+ }
+
+ if (nContentFlags & sheet::CellFlags::ANNOTATION)
+ {
+ std::vector<sc::NoteEntry> aNotes;
+ rDoc.GetNotesInRange(aRanges, aNotes);
+
+ for (const auto& i : aNotes)
+ {
+ aMarkData.SetMultiMarkArea(i.maPos);
+ }
+ }
+
+ ScRangeList aNewRanges;
+ if (aMarkData.IsMultiMarked())
+ aMarkData.FillRangeListWithMarks( &aNewRanges, false );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryFormulaCells(
+ sal_Int32 nResultFlags )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+
+ // select matching cells
+ for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
+ {
+ ScRange const & rRange = aRanges[ i ];
+
+ ScCellIterator aIter(rDoc, rRange);
+ for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
+ {
+ if (aIter.getType() == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = aIter.getFormulaCell();
+ bool bAdd = false;
+ if (pFCell->GetErrCode() != FormulaError::NONE)
+ {
+ if ( nResultFlags & sheet::FormulaResult::ERROR )
+ bAdd = true;
+ }
+ else if (pFCell->IsValue())
+ {
+ if ( nResultFlags & sheet::FormulaResult::VALUE )
+ bAdd = true;
+ }
+ else // String
+ {
+ if ( nResultFlags & sheet::FormulaResult::STRING )
+ bAdd = true;
+ }
+
+ if (bAdd)
+ aMarkData.SetMultiMarkArea(aIter.GetPos());
+ }
+ }
+ }
+
+ ScRangeList aNewRanges;
+ if (aMarkData.IsMultiMarked())
+ aMarkData.FillRangeListWithMarks( &aNewRanges, false );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges> ScCellRangesBase::QueryDifferences_Impl(
+ const table::CellAddress& aCompare, bool bColumnDiff)
+{
+ if (pDocShell)
+ {
+ size_t nRangeCount = aRanges.size();
+ size_t i;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+
+ SCCOLROW nCmpPos = bColumnDiff ? static_cast<SCCOLROW>(aCompare.Row) : static_cast<SCCOLROW>(aCompare.Column);
+
+ // first select everything, where at all something is in the comparison column
+ // (in the second step the selection is cancelled for equal cells)
+
+ SCTAB nTab = lcl_FirstTab(aRanges); //! for all tables, if markings per table
+ ScRange aCmpRange, aCellRange;
+ if (bColumnDiff)
+ aCmpRange = ScRange( 0,nCmpPos,nTab, rDoc.MaxCol(),nCmpPos,nTab );
+ else
+ aCmpRange = ScRange( static_cast<SCCOL>(nCmpPos),0,nTab, static_cast<SCCOL>(nCmpPos),rDoc.MaxRow(),nTab );
+ ScCellIterator aCmpIter(rDoc, aCmpRange);
+ for (bool bHasCell = aCmpIter.first(); bHasCell; bHasCell = aCmpIter.next())
+ {
+ SCCOLROW nCellPos = bColumnDiff ? static_cast<SCCOLROW>(aCmpIter.GetPos().Col()) : static_cast<SCCOLROW>(aCmpIter.GetPos().Row());
+ if (bColumnDiff)
+ aCellRange = ScRange( static_cast<SCCOL>(nCellPos),0,nTab,
+ static_cast<SCCOL>(nCellPos),rDoc.MaxRow(),nTab );
+ else
+ aCellRange = ScRange( 0,nCellPos,nTab, rDoc.MaxCol(),nCellPos,nTab );
+
+ for (i=0; i<nRangeCount; i++)
+ {
+ ScRange aRange( aRanges[ i ] );
+ if ( aRange.Intersects( aCellRange ) )
+ {
+ if (bColumnDiff)
+ {
+ aRange.aStart.SetCol(static_cast<SCCOL>(nCellPos));
+ aRange.aEnd.SetCol(static_cast<SCCOL>(nCellPos));
+ }
+ else
+ {
+ aRange.aStart.SetRow(nCellPos);
+ aRange.aEnd.SetRow(nCellPos);
+ }
+ aMarkData.SetMultiMarkArea( aRange );
+ }
+ }
+ }
+
+ // compare all not empty cells with the comparison column and accordingly
+ // select or cancel
+
+ ScAddress aCmpAddr;
+ for (i=0; i<nRangeCount; i++)
+ {
+ ScRange const & rRange = aRanges[ i ];
+
+ ScCellIterator aIter( rDoc, rRange );
+ for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
+ {
+ if (bColumnDiff)
+ aCmpAddr = ScAddress( aIter.GetPos().Col(), nCmpPos, aIter.GetPos().Tab() );
+ else
+ aCmpAddr = ScAddress( static_cast<SCCOL>(nCmpPos), aIter.GetPos().Row(), aIter.GetPos().Tab() );
+
+ ScRange aOneRange(aIter.GetPos());
+ if (!aIter.equalsWithoutFormat(aCmpAddr))
+ aMarkData.SetMultiMarkArea( aOneRange );
+ else
+ aMarkData.SetMultiMarkArea( aOneRange, false ); // deselect
+ }
+ }
+
+ ScRangeList aNewRanges;
+ if (aMarkData.IsMultiMarked())
+ aMarkData.FillRangeListWithMarks( &aNewRanges, false );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
+ }
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges > SAL_CALL ScCellRangesBase::queryColumnDifferences(
+ const table::CellAddress& aCompare )
+{
+ SolarMutexGuard aGuard;
+ return QueryDifferences_Impl( aCompare, true );
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryRowDifferences(
+ const table::CellAddress& aCompare )
+{
+ SolarMutexGuard aGuard;
+ return QueryDifferences_Impl( aCompare, false );
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryIntersection(
+ const table::CellRangeAddress& aRange )
+{
+ SolarMutexGuard aGuard;
+ ScRange aMask( static_cast<SCCOL>(aRange.StartColumn), static_cast<SCROW>(aRange.StartRow), aRange.Sheet,
+ static_cast<SCCOL>(aRange.EndColumn), static_cast<SCROW>(aRange.EndRow), aRange.Sheet );
+
+ ScRangeList aNew;
+ for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
+ {
+ ScRange aTemp( aRanges[ i ] );
+ if ( aTemp.Intersects( aMask ) )
+ aNew.Join( ScRange( std::max( aTemp.aStart.Col(), aMask.aStart.Col() ),
+ std::max( aTemp.aStart.Row(), aMask.aStart.Row() ),
+ std::max( aTemp.aStart.Tab(), aMask.aStart.Tab() ),
+ std::min( aTemp.aEnd.Col(), aMask.aEnd.Col() ),
+ std::min( aTemp.aEnd.Row(), aMask.aEnd.Row() ),
+ std::min( aTemp.aEnd.Tab(), aMask.aEnd.Tab() ) ) );
+ }
+
+ return new ScCellRangesObj( pDocShell, aNew ); // can be empty
+}
+
+// XFormulaQuery
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryPrecedents(
+ sal_Bool bRecursive )
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScRangeList aNewRanges(aRanges);
+ bool bFound;
+ do
+ {
+ bFound = false;
+
+ // aMarkData uses aNewRanges, not aRanges, so GetMarkData can't be used
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+ aMarkData.MarkFromRangeList( aNewRanges, false );
+
+ for (size_t nR = 0, nCount = aNewRanges.size(); nR<nCount; ++nR)
+ {
+ ScRange const & rRange = aNewRanges[ nR];
+ ScCellIterator aIter(rDoc, rRange);
+ for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
+ {
+ if (aIter.getType() != CELLTYPE_FORMULA)
+ continue;
+
+ ScDetectiveRefIter aRefIter(rDoc, aIter.getFormulaCell());
+ ScRange aRefRange;
+ while ( aRefIter.GetNextRef( aRefRange) )
+ {
+ if ( bRecursive && !bFound && !aMarkData.IsAllMarked( aRefRange ) )
+ bFound = true;
+ aMarkData.SetMultiMarkArea(aRefRange);
+ }
+ }
+ }
+
+ aMarkData.FillRangeListWithMarks( &aNewRanges, true );
+ }
+ while ( bRecursive && bFound );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges );
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryDependents(
+ sal_Bool bRecursive )
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScRangeList aNewRanges(aRanges);
+ bool bFound;
+ do
+ {
+ bFound = false;
+
+ // aMarkData uses aNewRanges, not aRanges, so GetMarkData can't be used
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+ aMarkData.MarkFromRangeList( aNewRanges, false );
+
+ SCTAB nTab = lcl_FirstTab(aNewRanges); //! all tables
+
+ ScCellIterator aCellIter( rDoc, ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab) );
+ for (bool bHasCell = aCellIter.first(); bHasCell; bHasCell = aCellIter.next())
+ {
+ if (aCellIter.getType() != CELLTYPE_FORMULA)
+ continue;
+
+ bool bMark = false;
+ ScDetectiveRefIter aIter(rDoc, aCellIter.getFormulaCell());
+ ScRange aRefRange;
+ while ( aIter.GetNextRef( aRefRange) && !bMark )
+ {
+ size_t nRangesCount = aNewRanges.size();
+ for (size_t nR = 0; nR < nRangesCount; ++nR)
+ {
+ ScRange const & rRange = aNewRanges[ nR ];
+ if (rRange.Intersects(aRefRange))
+ {
+ bMark = true; // depending on part of Range
+ break;
+ }
+ }
+ }
+ if (bMark)
+ {
+ ScRange aCellRange(aCellIter.GetPos());
+ if ( bRecursive && !bFound && !aMarkData.IsAllMarked( aCellRange ) )
+ bFound = true;
+ aMarkData.SetMultiMarkArea(aCellRange);
+ }
+ }
+
+ aMarkData.FillRangeListWithMarks( &aNewRanges, true );
+ }
+ while ( bRecursive && bFound );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges );
+ }
+
+ return nullptr;
+}
+
+// XSearchable
+
+uno::Reference<util::XSearchDescriptor> SAL_CALL ScCellRangesBase::createSearchDescriptor()
+{
+ return new ScCellSearchObj;
+}
+
+uno::Reference<container::XIndexAccess> SAL_CALL ScCellRangesBase::findAll(
+ const uno::Reference<util::XSearchDescriptor>& xDesc )
+{
+ SolarMutexGuard aGuard;
+ // should we return Null if nothing is found(?)
+ uno::Reference<container::XIndexAccess> xRet;
+ if ( pDocShell && xDesc.is() )
+ {
+ ScCellSearchObj* pSearch = dynamic_cast<ScCellSearchObj*>( xDesc.get() );
+ if (pSearch)
+ {
+ SvxSearchItem* pSearchItem = pSearch->GetSearchItem();
+ if (pSearchItem)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pSearchItem->SetCommand( SvxSearchCmd::FIND_ALL );
+ // always only within this object
+ pSearchItem->SetSelection( !lcl_WholeSheet(rDoc, aRanges) );
+
+ ScMarkData aMark(*GetMarkData());
+
+ OUString aDummyUndo;
+ ScRangeList aMatchedRanges;
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+ SCTAB nTab = 0;
+ bool bMatchedRangesWereClamped = false;
+ bool bFound = rDoc.SearchAndReplace(
+ *pSearchItem, nCol, nRow, nTab, aMark, aMatchedRanges, aDummyUndo, nullptr, bMatchedRangesWereClamped);
+ if (bFound)
+ {
+ // on findAll always CellRanges no matter how much has been found
+ xRet.set(new ScCellRangesObj( pDocShell, aMatchedRanges ));
+ }
+ }
+ }
+ }
+ return xRet;
+}
+
+uno::Reference<uno::XInterface> ScCellRangesBase::Find_Impl(
+ const uno::Reference<util::XSearchDescriptor>& xDesc,
+ const ScAddress* pLastPos )
+{
+ uno::Reference<uno::XInterface> xRet;
+ if ( pDocShell && xDesc.is() )
+ {
+ ScCellSearchObj* pSearch = dynamic_cast<ScCellSearchObj*>( xDesc.get() );
+ if (pSearch)
+ {
+ SvxSearchItem* pSearchItem = pSearch->GetSearchItem();
+ if (pSearchItem)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pSearchItem->SetCommand( SvxSearchCmd::FIND );
+ // only always in this object
+ pSearchItem->SetSelection( !lcl_WholeSheet(rDoc, aRanges) );
+
+ ScMarkData aMark(*GetMarkData());
+
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ if (pLastPos)
+ pLastPos->GetVars( nCol, nRow, nTab );
+ else
+ {
+ nTab = lcl_FirstTab(aRanges); //! multiple sheets?
+ rDoc.GetSearchAndReplaceStart( *pSearchItem, nCol, nRow );
+ }
+
+ OUString aDummyUndo;
+ ScRangeList aMatchedRanges;
+ bool bMatchedRangesWereClamped;
+ bool bFound = rDoc.SearchAndReplace(
+ *pSearchItem, nCol, nRow, nTab, aMark, aMatchedRanges, aDummyUndo, nullptr, bMatchedRangesWereClamped);
+ if (bFound)
+ {
+ ScAddress aFoundPos( nCol, nRow, nTab );
+ xRet.set(cppu::getXWeak(new ScCellObj( pDocShell, aFoundPos )));
+ }
+ }
+ }
+ }
+ return xRet;
+}
+
+uno::Reference<uno::XInterface> SAL_CALL ScCellRangesBase::findFirst(
+ const uno::Reference<util::XSearchDescriptor>& xDesc )
+{
+ SolarMutexGuard aGuard;
+ return Find_Impl( xDesc, nullptr );
+}
+
+uno::Reference<uno::XInterface> SAL_CALL ScCellRangesBase::findNext(
+ const uno::Reference<uno::XInterface>& xStartAt,
+ const uno::Reference<util::XSearchDescriptor >& xDesc )
+{
+ SolarMutexGuard aGuard;
+ if ( xStartAt.is() )
+ {
+ ScCellRangesBase* pRangesImp = dynamic_cast<ScCellRangesBase*>( xStartAt.get() );
+ if ( pRangesImp && pRangesImp->GetDocShell() == pDocShell )
+ {
+ const ScRangeList& rStartRanges = pRangesImp->GetRangeList();
+ if ( rStartRanges.size() == 1 )
+ {
+ ScAddress aStartPos = rStartRanges[ 0 ].aStart;
+ return Find_Impl( xDesc, &aStartPos );
+ }
+ }
+ }
+ return nullptr;
+}
+
+// XReplaceable
+
+uno::Reference<util::XReplaceDescriptor> SAL_CALL ScCellRangesBase::createReplaceDescriptor()
+{
+ return new ScCellSearchObj;
+}
+
+sal_Int32 SAL_CALL ScCellRangesBase::replaceAll( const uno::Reference<util::XSearchDescriptor>& xDesc )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt64 nReplaced = 0;
+ if ( pDocShell && xDesc.is() )
+ {
+ ScCellSearchObj* pSearch = dynamic_cast<ScCellSearchObj*>( xDesc.get() );
+ if (pSearch)
+ {
+ SvxSearchItem* pSearchItem = pSearch->GetSearchItem();
+ if (pSearchItem)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+ pSearchItem->SetCommand( SvxSearchCmd::REPLACE_ALL );
+ // only always in this object
+ pSearchItem->SetSelection( !lcl_WholeSheet(rDoc, aRanges) );
+
+ ScMarkData aMark(*GetMarkData());
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ bool bProtected = !pDocShell->IsEditable();
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+ if ( rDoc.IsTabProtected(rTab) )
+ bProtected = true;
+ }
+ if (bProtected)
+ {
+ //! Exception, or what?
+ }
+ else
+ {
+ SCTAB nTab = aMark.GetFirstSelected(); // do not use if SearchAndReplace
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+
+ OUString aUndoStr;
+ ScDocumentUniquePtr pUndoDoc;
+ if (bUndo)
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ }
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+ if (rTab != nTab && bUndo)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ }
+ std::unique_ptr<ScMarkData> pUndoMark;
+ if (bUndo)
+ pUndoMark.reset(new ScMarkData(aMark));
+
+ bool bFound = false;
+ if (bUndo)
+ {
+ ScRangeList aMatchedRanges;
+ bool bMatchedRangesWereClamped;
+ bFound = rDoc.SearchAndReplace(
+ *pSearchItem, nCol, nRow, nTab, aMark, aMatchedRanges, aUndoStr, pUndoDoc.get(), bMatchedRangesWereClamped );
+ }
+ if (bFound)
+ {
+ nReplaced = pUndoDoc->GetCellCount();
+
+ pDocShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoReplace>( pDocShell, *pUndoMark, nCol, nRow, nTab,
+ aUndoStr, std::move(pUndoDoc), pSearchItem ) );
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->SetDocumentModified();
+ }
+ }
+ }
+ }
+ }
+ return nReplaced;
+}
+
+ScCellRangesObj::ScCellRangesObj(ScDocShell* pDocSh, const ScRangeList& rR)
+ : ScCellRangesBase(pDocSh, rR)
+{
+}
+
+ScCellRangesObj::~ScCellRangesObj()
+{
+}
+
+void ScCellRangesObj::RefChanged()
+{
+ ScCellRangesBase::RefChanged();
+}
+
+uno::Any SAL_CALL ScCellRangesObj::queryInterface( const uno::Type& rType )
+{
+ uno::Any aReturn = ::cppu::queryInterface(rType,
+ static_cast<sheet::XSheetCellRangeContainer*>(this),
+ static_cast<sheet::XSheetCellRanges*>(this),
+ static_cast<container::XIndexAccess*>(this),
+ static_cast<container::XElementAccess*>(static_cast<container::XIndexAccess*>(this)),
+ static_cast<container::XEnumerationAccess*>(this),
+ static_cast<container::XNameContainer*>(this),
+ static_cast<container::XNameReplace*>(this),
+ static_cast<container::XNameAccess*>(this));
+ if ( aReturn.hasValue() )
+ return aReturn;
+
+ return ScCellRangesBase::queryInterface( rType );
+}
+
+void SAL_CALL ScCellRangesObj::acquire() noexcept
+{
+ ScCellRangesBase::acquire();
+}
+
+void SAL_CALL ScCellRangesObj::release() noexcept
+{
+ ScCellRangesBase::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScCellRangesObj::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes = comphelper::concatSequences(
+ ScCellRangesBase::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XSheetCellRangeContainer>::get(),
+ cppu::UnoType<container::XNameContainer>::get(),
+ cppu::UnoType<container::XEnumerationAccess>::get()
+ } );
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScCellRangesObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XCellRanges
+
+rtl::Reference<ScCellRangeObj> ScCellRangesObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
+{
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ if ( pDocSh && nIndex >= 0 && nIndex < sal::static_int_cast<sal_Int32>(rRanges.size()) )
+ {
+ ScRange const & rRange = rRanges[ nIndex ];
+ if ( rRange.aStart == rRange.aEnd )
+ return new ScCellObj( pDocSh, rRange.aStart );
+ else
+ return new ScCellRangeObj( pDocSh, rRange );
+ }
+
+ return nullptr; // no DocShell or wrong index
+}
+
+uno::Sequence<table::CellRangeAddress> SAL_CALL ScCellRangesObj::getRangeAddresses()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ size_t nCount = rRanges.size();
+ if ( pDocSh && nCount )
+ {
+ table::CellRangeAddress aRangeAddress;
+ uno::Sequence<table::CellRangeAddress> aSeq(nCount);
+ table::CellRangeAddress* pAry = aSeq.getArray();
+ for ( size_t i=0; i < nCount; i++)
+ {
+ ScUnoConversion::FillApiRange( aRangeAddress, rRanges[ i ] );
+ pAry[i] = aRangeAddress;
+ }
+ return aSeq;
+ }
+
+ return {}; // can be empty
+}
+
+uno::Reference<container::XEnumerationAccess> SAL_CALL ScCellRangesObj::getCells()
+{
+ SolarMutexGuard aGuard;
+
+ // getCells with empty range list is possible (no exception),
+ // the resulting enumeration just has no elements
+ // (same behaviour as a valid range with no cells)
+ // This is handled in ScCellsEnumeration ctor.
+
+ const ScRangeList& rRanges = GetRangeList();
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ return new ScCellsObj( pDocSh, rRanges );
+ return nullptr;
+}
+
+OUString SAL_CALL ScCellRangesObj::getRangeAddressesAsString()
+{
+ SolarMutexGuard aGuard;
+ OUString aString;
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ if (pDocSh)
+ rRanges.Format( aString, ScRefFlags::VALID | ScRefFlags::TAB_3D, pDocSh->GetDocument() );
+ return aString;
+}
+
+// XSheetCellRangeContainer
+
+void SAL_CALL ScCellRangesObj::addRangeAddress( const table::CellRangeAddress& rRange,
+ sal_Bool bMergeRanges )
+{
+ SolarMutexGuard aGuard;
+ ScRange aRange(static_cast<SCCOL>(rRange.StartColumn),
+ static_cast<SCROW>(rRange.StartRow),
+ static_cast<SCTAB>(rRange.Sheet),
+ static_cast<SCCOL>(rRange.EndColumn),
+ static_cast<SCROW>(rRange.EndRow),
+ static_cast<SCTAB>(rRange.Sheet));
+ AddRange(aRange, bMergeRanges);
+}
+
+static void lcl_RemoveNamedEntry( std::vector<ScCellRangesObj::ScNamedEntry>& rNamedEntries, const ScRange& rRange )
+{
+ sal_uInt16 nCount = rNamedEntries.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ if ( rNamedEntries[n].GetRange() == rRange )
+ rNamedEntries.erase( rNamedEntries.begin() + n );
+}
+
+void SAL_CALL ScCellRangesObj::removeRangeAddress( const table::CellRangeAddress& rRange )
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+
+ ScRangeList aSheetRanges;
+ ScRangeList aNotSheetRanges;
+ for (size_t i = 0; i < rRanges.size(); ++i)
+ {
+ if (rRanges[ i].aStart.Tab() == rRange.Sheet)
+ {
+ aSheetRanges.push_back( rRanges[ i ] );
+ }
+ else
+ {
+ aNotSheetRanges.push_back( rRanges[ i ] );
+ }
+ }
+ ScMarkData aMarkData(GetDocument()->GetSheetLimits());
+ aMarkData.MarkFromRangeList( aSheetRanges, false );
+ ScRange aRange(static_cast<SCCOL>(rRange.StartColumn),
+ static_cast<SCROW>(rRange.StartRow),
+ static_cast<SCTAB>(rRange.Sheet),
+ static_cast<SCCOL>(rRange.EndColumn),
+ static_cast<SCROW>(rRange.EndRow),
+ static_cast<SCTAB>(rRange.Sheet));
+ if (aMarkData.GetTableSelect( aRange.aStart.Tab() ))
+ {
+ aMarkData.MarkToMulti();
+ if (!aMarkData.IsAllMarked( aRange ) )
+ throw container::NoSuchElementException();
+
+ aMarkData.SetMultiMarkArea( aRange, false );
+ lcl_RemoveNamedEntry(m_aNamedEntries, aRange);
+
+ }
+ SetNewRanges(aNotSheetRanges);
+ ScRangeList aNew;
+ aMarkData.FillRangeListWithMarks( &aNew, false );
+ for ( size_t j = 0; j < aNew.size(); ++j)
+ {
+ AddRange(aNew[ j ], false);
+ }
+}
+
+void SAL_CALL ScCellRangesObj::addRangeAddresses( const uno::Sequence<table::CellRangeAddress >& rRanges,
+ sal_Bool bMergeRanges )
+{
+ SolarMutexGuard aGuard;
+ for (const table::CellRangeAddress& rRange : rRanges)
+ {
+ ScRange aRange(static_cast<SCCOL>(rRange.StartColumn),
+ static_cast<SCROW>(rRange.StartRow),
+ static_cast<SCTAB>(rRange.Sheet),
+ static_cast<SCCOL>(rRange.EndColumn),
+ static_cast<SCROW>(rRange.EndRow),
+ static_cast<SCTAB>(rRange.Sheet));
+ AddRange(aRange, bMergeRanges);
+ }
+}
+
+void SAL_CALL ScCellRangesObj::removeRangeAddresses( const uno::Sequence<table::CellRangeAddress >& rRangeSeq )
+{
+ // use sometimes a better/faster implementation
+ for (const table::CellRangeAddress& rRange : rRangeSeq)
+ {
+ removeRangeAddress(rRange);
+ }
+}
+
+// XNameContainer
+
+static void lcl_RemoveNamedEntry( std::vector<ScCellRangesObj::ScNamedEntry>& rNamedEntries, std::u16string_view rName )
+{
+ sal_uInt16 nCount = rNamedEntries.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ if ( rNamedEntries[n].GetName() == rName )
+ rNamedEntries.erase( rNamedEntries.begin() + n );
+}
+
+void SAL_CALL ScCellRangesObj::insertByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ bool bDone = false;
+
+ //! Type of aElement can be some specific interface instead of XInterface
+
+ uno::Reference<uno::XInterface> xInterface(aElement, uno::UNO_QUERY);
+ if ( pDocSh && xInterface.is() )
+ {
+ ScCellRangesBase* pRangesImp = dynamic_cast<ScCellRangesBase*>( xInterface.get() );
+ if ( pRangesImp && pRangesImp->GetDocShell() == pDocSh )
+ {
+ // if explicit name is given and already existing, throw exception
+
+ if ( !aName.isEmpty() )
+ {
+ size_t nNamedCount = m_aNamedEntries.size();
+ for (size_t n = 0; n < nNamedCount; n++)
+ {
+ if (m_aNamedEntries[n].GetName() == aName)
+ throw container::ElementExistException();
+ }
+ }
+
+ ScRangeList aNew(GetRangeList());
+ const ScRangeList& rAddRanges = pRangesImp->GetRangeList();
+ size_t nAddCount = rAddRanges.size();
+ for ( size_t i = 0; i < nAddCount; i++ )
+ aNew.Join( rAddRanges[ i ] );
+ SetNewRanges(aNew);
+ bDone = true;
+
+ if ( !aName.isEmpty() && nAddCount == 1 )
+ {
+ // if a name is given, also insert into list of named entries
+ // (only possible for a single range)
+ // name is not in m_aNamedEntries (tested above)
+ m_aNamedEntries.emplace_back( ScNamedEntry{aName, rAddRanges[ 0 ]} );
+ }
+ }
+ }
+
+ if (!bDone)
+ {
+ // invalid element - double names are handled above
+ throw lang::IllegalArgumentException();
+ }
+}
+
+static bool lcl_FindRangeByName( const ScRangeList& rRanges, ScDocShell* pDocSh,
+ std::u16string_view rName, size_t& rIndex )
+{
+ if (pDocSh)
+ {
+ OUString aRangeStr;
+ ScDocument& rDoc = pDocSh->GetDocument();
+ for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
+ {
+ aRangeStr = rRanges[ i ].Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_3D);
+ if ( aRangeStr == rName )
+ {
+ rIndex = i;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool lcl_FindRangeOrEntry( const std::vector<ScCellRangesObj::ScNamedEntry>& rNamedEntries,
+ const ScRangeList& rRanges, ScDocShell* pDocSh,
+ const OUString& rName, ScRange& rFound )
+{
+ // exact range in list?
+
+ size_t nIndex = 0;
+ if ( lcl_FindRangeByName( rRanges, pDocSh, rName, nIndex ) )
+ {
+ rFound = rRanges[ nIndex ];
+ return true;
+ }
+
+ // range contained in selection? (sheet must be specified)
+
+ ScRange aCellRange;
+ ScRefFlags nParse = aCellRange.ParseAny( rName, pDocSh->GetDocument() );
+ if ( (nParse & ( ScRefFlags::VALID | ScRefFlags::TAB_3D ))
+ == ( ScRefFlags::VALID | ScRefFlags::TAB_3D ))
+ {
+ ScMarkData aMarkData(pDocSh->GetDocument().GetSheetLimits());
+ aMarkData.MarkFromRangeList( rRanges, false );
+ if ( aMarkData.IsAllMarked( aCellRange ) )
+ {
+ rFound = aCellRange;
+ return true;
+ }
+ }
+
+ // named entry in this object?
+
+ for (const auto & rNamedEntry : rNamedEntries)
+ if ( rNamedEntry.GetName() == rName )
+ {
+ // test if named entry is contained in rRanges
+
+ const ScRange& rComp = rNamedEntry.GetRange();
+ ScMarkData aMarkData(pDocSh->GetDocument().GetSheetLimits());
+ aMarkData.MarkFromRangeList( rRanges, false );
+ if ( aMarkData.IsAllMarked( rComp ) )
+ {
+ rFound = rComp;
+ return true;
+ }
+ }
+
+ return false; // not found
+}
+
+void SAL_CALL ScCellRangesObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ size_t nIndex = 0;
+ if ( lcl_FindRangeByName( rRanges, pDocSh, aName, nIndex ) )
+ {
+ // skip a single range
+ ScRangeList aNew;
+ for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
+ if (i != nIndex)
+ aNew.push_back( rRanges[ i ] );
+ SetNewRanges(aNew);
+ bDone = true;
+ }
+ else if (pDocSh)
+ {
+ // deselect any ranges (parsed or named entry)
+ ScRangeList aDiff;
+ bool bValid = ( aDiff.Parse( aName, pDocSh->GetDocument() ) & ScRefFlags::VALID )
+ == ScRefFlags::VALID;
+ if (!bValid)
+ {
+ sal_uInt16 nCount = m_aNamedEntries.size();
+ for (sal_uInt16 n=0; n<nCount && !bValid; n++)
+ if (m_aNamedEntries[n].GetName() == aName)
+ {
+ aDiff.RemoveAll();
+ aDiff.push_back(m_aNamedEntries[n].GetRange());
+ bValid = true;
+ }
+ }
+ if ( bValid )
+ {
+ ScMarkData aMarkData(GetDocument()->GetSheetLimits());
+ aMarkData.MarkFromRangeList( rRanges, false );
+
+ for ( size_t i = 0, nDiffCount = aDiff.size(); i < nDiffCount; i++ )
+ {
+ ScRange const & rDiffRange = aDiff[ i ];
+ if (aMarkData.GetTableSelect( rDiffRange.aStart.Tab() ))
+ aMarkData.SetMultiMarkArea( rDiffRange, false );
+ }
+
+ ScRangeList aNew;
+ aMarkData.FillRangeListWithMarks( &aNew, false );
+ SetNewRanges(aNew);
+
+ bDone = true; //! error if range was not selected before?
+ }
+ }
+
+ if (!m_aNamedEntries.empty())
+ lcl_RemoveNamedEntry(m_aNamedEntries, aName);
+
+ if (!bDone)
+ throw container::NoSuchElementException(); // not found
+}
+
+// XNameReplace
+
+void SAL_CALL ScCellRangesObj::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ //! combine?
+ removeByName( aName );
+ insertByName( aName, aElement );
+}
+
+// XNameAccess
+
+uno::Any SAL_CALL ScCellRangesObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ ScRange aRange;
+ if (!lcl_FindRangeOrEntry(m_aNamedEntries, rRanges,
+ pDocSh, aName, aRange))
+ throw container::NoSuchElementException();
+
+ uno::Reference<table::XCellRange> xRange;
+ if ( aRange.aStart == aRange.aEnd )
+ xRange.set(new ScCellObj( pDocSh, aRange.aStart ));
+ else
+ xRange.set(new ScCellRangeObj( pDocSh, aRange ));
+ aRet <<= xRange;
+
+ return aRet;
+}
+
+static bool lcl_FindEntryName( const std::vector<ScCellRangesObj::ScNamedEntry>& rNamedEntries,
+ const ScRange& rRange, OUString& rName )
+{
+ sal_uInt16 nCount = rNamedEntries.size();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if (rNamedEntries[i].GetRange() == rRange)
+ {
+ rName = rNamedEntries[i].GetName();
+ return true;
+ }
+ return false;
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellRangesObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ if (pDocSh)
+ {
+ OUString aRangeStr;
+ ScDocument& rDoc = pDocSh->GetDocument();
+ size_t nCount = rRanges.size();
+
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ for (size_t i=0; i < nCount; i++)
+ {
+ // use given name if for exactly this range, otherwise just format
+ ScRange const & rRange = rRanges[ i ];
+ if (m_aNamedEntries.empty() ||
+ !lcl_FindEntryName(m_aNamedEntries, rRange, aRangeStr))
+ {
+ aRangeStr = rRange.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_3D);
+ }
+ pAry[i] = aRangeStr;
+ }
+ return aSeq;
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScCellRangesObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ ScRange aRange;
+ return lcl_FindRangeOrEntry(m_aNamedEntries, rRanges, pDocSh,
+ aName, aRange);
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScCellRangesObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.SheetCellRangesEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScCellRangesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ return rRanges.size();
+}
+
+uno::Any SAL_CALL ScCellRangesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XCellRange> xRange(GetObjectByIndex_Impl(nIndex));
+ if (!xRange.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRange);
+
+}
+
+uno::Type SAL_CALL ScCellRangesObj::getElementType()
+{
+ return cppu::UnoType<table::XCellRange>::get();
+}
+
+sal_Bool SAL_CALL ScCellRangesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ return !rRanges.empty();
+}
+
+// XServiceInfo
+OUString SAL_CALL ScCellRangesObj::getImplementationName()
+{
+ return "ScCellRangesObj";
+}
+
+sal_Bool SAL_CALL ScCellRangesObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellRangesObj::getSupportedServiceNames()
+{
+ return {SCSHEETCELLRANGES_SERVICE,
+ SCCELLPROPERTIES_SERVICE,
+ SCCHARPROPERTIES_SERVICE,
+ SCPARAPROPERTIES_SERVICE};
+}
+
+uno::Reference<table::XCellRange> ScCellRangeObj::CreateRangeFromDoc( const ScDocument& rDoc, const ScRange& rR )
+{
+ if ( ScDocShell* pDocShell = rDoc.GetDocumentShell() )
+ return new ScCellRangeObj( pDocShell, rR );
+ return nullptr;
+}
+
+ScCellRangeObj::ScCellRangeObj(ScDocShell* pDocSh, const ScRange& rR) :
+ ScCellRangesBase( pDocSh, rR ),
+ pRangePropSet( lcl_GetRangePropertySet() ),
+ aRange( rR )
+{
+ aRange.PutInOrder(); // beginning / end correct
+}
+
+ScCellRangeObj::~ScCellRangeObj()
+{
+}
+
+void ScCellRangeObj::RefChanged()
+{
+ ScCellRangesBase::RefChanged();
+
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE(rRanges.size() == 1, "What ranges ?!?!");
+ if ( !rRanges.empty() )
+ {
+ const ScRange & rFirst = rRanges[0];
+ aRange = rFirst;
+ aRange.PutInOrder();
+ }
+}
+
+uno::Any SAL_CALL ScCellRangeObj::queryInterface( const uno::Type& rType )
+{
+ uno::Any aReturn = ::cppu::queryInterface(rType,
+ static_cast<sheet::XCellRangeAddressable*>(this),
+ static_cast<table::XCellRange*>(this),
+ static_cast<sheet::XSheetCellRange*>(this),
+ static_cast<sheet::XArrayFormulaRange*>(this),
+ static_cast<sheet::XArrayFormulaTokens*>(this),
+ static_cast<sheet::XCellRangeData*>(this),
+ static_cast<sheet::XCellRangeFormula*>(this),
+ static_cast<sheet::XMultipleOperation*>(this),
+ static_cast<util::XMergeable*>(this),
+ static_cast<sheet::XCellSeries*>(this),
+ static_cast<table::XAutoFormattable*>(this),
+ static_cast<util::XSortable*>(this),
+ static_cast<sheet::XSheetFilterableEx*>(this),
+ static_cast<sheet::XSheetFilterable*>(this),
+ static_cast<sheet::XSubTotalCalculatable*>(this),
+ static_cast<table::XColumnRowRange*>(this),
+ static_cast<util::XImportable*>(this),
+ static_cast<sheet::XCellFormatRangesSupplier*>(this),
+ static_cast<sheet::XUniqueCellFormatRangesSupplier*>(this));
+ if ( aReturn.hasValue() )
+ return aReturn;
+
+ return ScCellRangesBase::queryInterface( rType );
+}
+
+void SAL_CALL ScCellRangeObj::acquire() noexcept
+{
+ ScCellRangesBase::acquire();
+}
+
+void SAL_CALL ScCellRangeObj::release() noexcept
+{
+ ScCellRangesBase::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScCellRangeObj::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes = comphelper::concatSequences(
+ ScCellRangesBase::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XCellRangeAddressable>::get(),
+ cppu::UnoType<sheet::XSheetCellRange>::get(),
+ cppu::UnoType<sheet::XArrayFormulaRange>::get(),
+ cppu::UnoType<sheet::XArrayFormulaTokens>::get(),
+ cppu::UnoType<sheet::XCellRangeData>::get(),
+ cppu::UnoType<sheet::XCellRangeFormula>::get(),
+ cppu::UnoType<sheet::XMultipleOperation>::get(),
+ cppu::UnoType<util::XMergeable>::get(),
+ cppu::UnoType<sheet::XCellSeries>::get(),
+ cppu::UnoType<table::XAutoFormattable>::get(),
+ cppu::UnoType<util::XSortable>::get(),
+ cppu::UnoType<sheet::XSheetFilterableEx>::get(),
+ cppu::UnoType<sheet::XSubTotalCalculatable>::get(),
+ cppu::UnoType<table::XColumnRowRange>::get(),
+ cppu::UnoType<util::XImportable>::get(),
+ cppu::UnoType<sheet::XCellFormatRangesSupplier>::get(),
+ cppu::UnoType<sheet::XUniqueCellFormatRangesSupplier>::get()
+ } );
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScCellRangeObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XCellRange
+
+// ColumnCount / RowCount vanished
+//! are used in Writer for tables ???
+
+uno::Reference<table::XCell> ScCellRangeObj::GetCellByPosition_Impl(
+ sal_Int32 nColumn, sal_Int32 nRow )
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ throw uno::RuntimeException();
+
+ if ( nColumn >= 0 && nRow >= 0 )
+ {
+ sal_Int32 nPosX = aRange.aStart.Col() + nColumn;
+ sal_Int32 nPosY = aRange.aStart.Row() + nRow;
+
+ if ( nPosX <= aRange.aEnd.Col() && nPosY <= aRange.aEnd.Row() )
+ {
+ ScAddress aNew( static_cast<SCCOL>(nPosX), static_cast<SCROW>(nPosY), aRange.aStart.Tab() );
+ return new ScCellObj( pDocSh, aNew );
+ }
+ }
+
+ throw lang::IndexOutOfBoundsException();
+}
+
+uno::Reference<table::XCell> SAL_CALL ScCellRangeObj::getCellByPosition(
+ sal_Int32 nColumn, sal_Int32 nRow )
+{
+ SolarMutexGuard aGuard;
+
+ return GetCellByPosition_Impl(nColumn, nRow);
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScCellRangeObj::getCellRangeByPosition(
+ sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+{
+ SolarMutexGuard aGuard;
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ throw uno::RuntimeException();
+
+ if ( nLeft >= 0 && nTop >= 0 && nRight >= 0 && nBottom >= 0 )
+ {
+ sal_Int32 nStartX = aRange.aStart.Col() + nLeft;
+ sal_Int32 nStartY = aRange.aStart.Row() + nTop;
+ sal_Int32 nEndX = aRange.aStart.Col() + nRight;
+ sal_Int32 nEndY = aRange.aStart.Row() + nBottom;
+
+ if ( nStartX <= nEndX && nEndX <= aRange.aEnd.Col() &&
+ nStartY <= nEndY && nEndY <= aRange.aEnd.Row() )
+ {
+ ScRange aNew( static_cast<SCCOL>(nStartX), static_cast<SCROW>(nStartY), aRange.aStart.Tab(),
+ static_cast<SCCOL>(nEndX), static_cast<SCROW>(nEndY), aRange.aEnd.Tab() );
+ return new ScCellRangeObj( pDocSh, aNew );
+ }
+ }
+
+ throw lang::IndexOutOfBoundsException();
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScCellRangeObj::getCellRangeByName(
+ const OUString& aName )
+{
+ return getCellRangeByName( aName, ScAddress::detailsOOOa1 );
+}
+
+uno::Reference<table::XCellRange> ScCellRangeObj::getCellRangeByName(
+ const OUString& aName, const ScAddress::Details& rDetails )
+{
+ // name refers to the whole document (with the range's table as default),
+ // valid only if the range is within this range
+
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = aRange.aStart.Tab();
+
+ ScRange aCellRange;
+ bool bFound = false;
+ ScRefFlags nParse = aCellRange.ParseAny( aName, rDoc, rDetails );
+ if ( nParse & ScRefFlags::VALID )
+ {
+ if ( !(nParse & ScRefFlags::TAB_3D) ) // no sheet specified -> this sheet
+ {
+ aCellRange.aStart.SetTab(nTab);
+ aCellRange.aEnd.SetTab(nTab);
+ }
+ bFound = true;
+ }
+ else
+ {
+ if ( ScRangeUtil::MakeRangeFromName( aName, rDoc, nTab, aCellRange, RUTL_NAMES, rDetails) ||
+ ScRangeUtil::MakeRangeFromName( aName, rDoc, nTab, aCellRange, RUTL_DBASE, rDetails))
+ bFound = true;
+ }
+
+ if (bFound) // valid only if within this object's range
+ {
+ if (!aRange.Contains(aCellRange))
+ bFound = false;
+ }
+
+ if (bFound)
+ {
+ if ( aCellRange.aStart == aCellRange.aEnd )
+ return new ScCellObj( pDocSh, aCellRange.aStart );
+ else
+ return new ScCellRangeObj( pDocSh, aCellRange );
+ }
+ }
+
+ throw uno::RuntimeException();
+}
+
+// XColumnRowRange
+
+uno::Reference<table::XTableColumns> SAL_CALL ScCellRangeObj::getColumns()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ return new ScTableColumnsObj( pDocSh, aRange.aStart.Tab(),
+ aRange.aStart.Col(), aRange.aEnd.Col() );
+
+ OSL_FAIL("Document invalid");
+ return nullptr;
+}
+
+uno::Reference<table::XTableRows> SAL_CALL ScCellRangeObj::getRows()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ return new ScTableRowsObj( pDocSh, aRange.aStart.Tab(),
+ aRange.aStart.Row(), aRange.aEnd.Row() );
+
+ OSL_FAIL("Document invalid");
+ return nullptr;
+}
+
+// XAddressableCellRange
+
+table::CellRangeAddress SAL_CALL ScCellRangeObj::getRangeAddress()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScUnoConversion::FillApiRange( aRet, aRange );
+ return aRet;
+}
+
+// XSheetCellRange
+
+uno::Reference<sheet::XSpreadsheet> SAL_CALL ScCellRangeObj::getSpreadsheet()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ return new ScTableSheetObj( pDocSh, aRange.aStart.Tab() );
+
+ OSL_FAIL("Document invalid");
+ return nullptr;
+}
+
+// XArrayFormulaRange
+
+OUString SAL_CALL ScCellRangeObj::getArrayFormula()
+{
+ SolarMutexGuard aGuard;
+
+ // Matrix formula if clearly part of a matrix (so when start and end of
+ // the block belong to the same matrix) else empty string.
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return OUString();
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScRefCellValue aCell1(rDoc, aRange.aStart);
+ ScRefCellValue aCell2(rDoc, aRange.aEnd);
+ if (aCell1.getType() == CELLTYPE_FORMULA && aCell2.getType() == CELLTYPE_FORMULA)
+ {
+ const ScFormulaCell* pFCell1 = aCell1.getFormula();
+ const ScFormulaCell* pFCell2 = aCell2.getFormula();
+ ScAddress aStart1;
+ ScAddress aStart2;
+ if (pFCell1->GetMatrixOrigin(rDoc, aStart1) && pFCell2->GetMatrixOrigin(rDoc, aStart2))
+ {
+ if (aStart1 == aStart2) // both the same matrix
+ return pFCell1->GetFormula(); // it doesn't matter from which cell
+ }
+ }
+ return OUString();
+}
+
+void ScCellRangeObj::SetArrayFormula_Impl(const OUString& rFormula,
+ const formula::FormulaGrammar::Grammar eGrammar)
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ if ( !rFormula.isEmpty() )
+ {
+ if ( dynamic_cast<ScTableSheetObj*>( this ) )
+ {
+ // don't set array formula for sheet object
+ throw uno::RuntimeException();
+ }
+
+ pDocSh->GetDocFunc().EnterMatrix( aRange, nullptr, nullptr, rFormula, true, true, OUString()/*rFormulaNmsp*/, eGrammar );
+ }
+ else
+ {
+ // empty string -> erase array formula
+ ScMarkData aMark(GetDocument()->GetSheetLimits());
+ aMark.SetMarkArea( aRange );
+ aMark.SelectTable( aRange.aStart.Tab(), true );
+ pDocSh->GetDocFunc().DeleteContents( aMark, InsertDeleteFlags::CONTENTS, true, true );
+ }
+}
+
+void SAL_CALL ScCellRangeObj::setArrayFormula( const OUString& aFormula )
+{
+ SolarMutexGuard aGuard;
+ // GRAM_API for API compatibility.
+ SetArrayFormula_Impl( aFormula, formula::FormulaGrammar::GRAM_API);
+}
+
+// XArrayFormulaTokens
+uno::Sequence<sheet::FormulaToken> SAL_CALL ScCellRangeObj::getArrayTokens()
+{
+ SolarMutexGuard aGuard;
+
+ // same cell logic as in getArrayFormula
+
+ uno::Sequence<sheet::FormulaToken> aSequence;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return aSequence;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScRefCellValue aCell1(rDoc, aRange.aStart);
+ ScRefCellValue aCell2(rDoc, aRange.aEnd);
+ if (aCell1.getType() == CELLTYPE_FORMULA && aCell2.getType() == CELLTYPE_FORMULA)
+ {
+ const ScFormulaCell* pFCell1 = aCell1.getFormula();
+ const ScFormulaCell* pFCell2 = aCell2.getFormula();
+ ScAddress aStart1;
+ ScAddress aStart2;
+ if (pFCell1->GetMatrixOrigin(rDoc, aStart1) && pFCell2->GetMatrixOrigin(rDoc, aStart2))
+ {
+ if (aStart1 == aStart2)
+ {
+ const ScTokenArray* pTokenArray = pFCell1->GetCode();
+ if (pTokenArray)
+ ScTokenConversion::ConvertToTokenSequence(rDoc, aSequence, *pTokenArray);
+ }
+ }
+ }
+
+ return aSequence;
+}
+
+void SAL_CALL ScCellRangeObj::setArrayTokens( const uno::Sequence<sheet::FormulaToken>& rTokens )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ if ( rTokens.hasElements() )
+ {
+ if ( dynamic_cast<ScTableSheetObj*>( this ) )
+ {
+ throw uno::RuntimeException();
+ }
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScTokenArray aTokenArray(rDoc);
+ (void)ScTokenConversion::ConvertToTokenArray( rDoc, aTokenArray, rTokens );
+
+ // Actually GRAM_API is a don't-care here because of the token
+ // array being set, it fits with other API compatibility grammars
+ // though.
+ pDocSh->GetDocFunc().EnterMatrix( aRange, nullptr, &aTokenArray, OUString(), true, true, OUString(), formula::FormulaGrammar::GRAM_API );
+ }
+ else
+ {
+ // empty sequence -> erase array formula
+ ScMarkData aMark(pDocSh->GetDocument().GetSheetLimits());
+ aMark.SetMarkArea( aRange );
+ aMark.SelectTable( aRange.aStart.Tab(), true );
+ pDocSh->GetDocFunc().DeleteContents( aMark, InsertDeleteFlags::CONTENTS, true, true );
+ }
+}
+
+// XCellRangeData
+
+uno::Sequence< uno::Sequence<uno::Any> > SAL_CALL ScCellRangeObj::getDataArray()
+{
+ SolarMutexGuard aGuard;
+
+ if ( dynamic_cast<ScTableSheetObj*>( this ) )
+ {
+ // don't create a data array for the sheet
+ throw uno::RuntimeException();
+ }
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ uno::Any aAny;
+ // bAllowNV = TRUE: errors as void
+ if ( ScRangeToSequence::FillMixedArray( aAny, pDocSh->GetDocument(), aRange, true ) )
+ {
+ uno::Sequence< uno::Sequence<uno::Any> > aSeq;
+ if ( aAny >>= aSeq )
+ return aSeq; // success
+ }
+ }
+
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScCellRangeObj::setDataArray(
+ const uno::Sequence< uno::Sequence<uno::Any> >& aArray )
+{
+ SolarMutexGuard aGuard;
+
+ bool bDone = false;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ //! move lcl_PutDataArray to docfunc?
+ bDone = lcl_PutDataArray( *pDocSh, aRange, aArray );
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// XCellRangeFormula
+
+uno::Sequence< uno::Sequence<OUString> > SAL_CALL ScCellRangeObj::getFormulaArray()
+{
+ SolarMutexGuard aGuard;
+
+ if ( dynamic_cast<ScTableSheetObj*>( this ) )
+ {
+ // don't create a data array for the sheet
+ throw uno::RuntimeException();
+ }
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ SCCOL nColCount = nEndCol + 1 - nStartCol;
+ SCROW nRowCount = nEndRow + 1 - nStartRow;
+ SCTAB nTab = aRange.aStart.Tab();
+
+ uno::Sequence< uno::Sequence<OUString> > aRowSeq( nRowCount );
+ uno::Sequence<OUString>* pRowAry = aRowSeq.getArray();
+ for (SCROW nRowIndex = 0; nRowIndex < nRowCount; nRowIndex++)
+ {
+ uno::Sequence<OUString> aColSeq( nColCount );
+ OUString* pColAry = aColSeq.getArray();
+ for (SCCOL nColIndex = 0; nColIndex < nColCount; nColIndex++)
+ pColAry[nColIndex] = lcl_GetInputString( pDocSh->GetDocument(),
+ ScAddress( nStartCol+nColIndex, nStartRow+nRowIndex, nTab ), true );
+
+ pRowAry[nRowIndex] = aColSeq;
+ }
+
+ return aRowSeq;
+ }
+
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScCellRangeObj::setFormulaArray(
+ const uno::Sequence< uno::Sequence<OUString> >& aArray )
+{
+ SolarMutexGuard aGuard;
+
+ bool bDone = false;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ ScExternalRefManager::ApiGuard aExtRefGuard(pDocSh->GetDocument());
+
+ // GRAM_API for API compatibility.
+ bDone = lcl_PutFormulaArray( *pDocSh, aRange, aArray, formula::FormulaGrammar::GRAM_API );
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// XMultipleOperation
+
+void SAL_CALL ScCellRangeObj::setTableOperation( const table::CellRangeAddress& aFormulaRange,
+ sheet::TableOperationMode nMode,
+ const table::CellAddress& aColumnCell,
+ const table::CellAddress& aRowCell )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ bool bError = false;
+ ScTabOpParam aParam;
+ aParam.aRefFormulaCell = ScRefAddress( static_cast<SCCOL>(aFormulaRange.StartColumn),
+ static_cast<SCROW>(aFormulaRange.StartRow), aFormulaRange.Sheet );
+ aParam.aRefFormulaEnd = ScRefAddress( static_cast<SCCOL>(aFormulaRange.EndColumn),
+ static_cast<SCROW>(aFormulaRange.EndRow), aFormulaRange.Sheet );
+ aParam.aRefRowCell = ScRefAddress( static_cast<SCCOL>(aRowCell.Column),
+ static_cast<SCROW>(aRowCell.Row), aRowCell.Sheet );
+ aParam.aRefColCell = ScRefAddress( static_cast<SCCOL>(aColumnCell.Column),
+ static_cast<SCROW>(aColumnCell.Row), aColumnCell.Sheet );
+
+ switch (nMode)
+ {
+ case sheet::TableOperationMode_COLUMN:
+ aParam.meMode = ScTabOpParam::Column;
+ break;
+ case sheet::TableOperationMode_ROW:
+ aParam.meMode = ScTabOpParam::Row;
+ break;
+ case sheet::TableOperationMode_BOTH:
+ aParam.meMode = ScTabOpParam::Both;
+ break;
+ default:
+ bError = true;
+ }
+
+ if (!bError)
+ pDocSh->GetDocFunc().TabOp( aRange, nullptr, aParam, true, true );
+}
+
+// XMergeable
+
+void SAL_CALL ScCellRangeObj::merge( sal_Bool bMerge )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScCellMergeOption aMergeOption(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), false);
+ aMergeOption.maTabs.insert(aRange.aStart.Tab());
+ if ( bMerge )
+ pDocSh->GetDocFunc().MergeCells( aMergeOption, false, true, true );
+ else
+ pDocSh->GetDocFunc().UnmergeCells( aMergeOption, true, nullptr );
+
+ //! Catch error?
+}
+
+sal_Bool SAL_CALL ScCellRangeObj::getIsMerged()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ return pDocSh && pDocSh->GetDocument().HasAttrib( aRange, HasAttrFlags::Merged );
+}
+
+// XCellSeries
+
+void SAL_CALL ScCellRangeObj::fillSeries( sheet::FillDirection nFillDirection,
+ sheet::FillMode nFillMode, sheet::FillDateMode nFillDateMode,
+ double fStep, double fEndValue )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ bool bError = false;
+
+ FillDir eDir = FILL_TO_BOTTOM;
+ switch (nFillDirection)
+ {
+ case sheet::FillDirection_TO_BOTTOM:
+ eDir = FILL_TO_BOTTOM;
+ break;
+ case sheet::FillDirection_TO_RIGHT:
+ eDir = FILL_TO_RIGHT;
+ break;
+ case sheet::FillDirection_TO_TOP:
+ eDir = FILL_TO_TOP;
+ break;
+ case sheet::FillDirection_TO_LEFT:
+ eDir = FILL_TO_LEFT;
+ break;
+ default:
+ bError = true;
+ }
+
+ FillCmd eCmd = FILL_SIMPLE;
+ switch ( nFillMode )
+ {
+ case sheet::FillMode_SIMPLE:
+ eCmd = FILL_SIMPLE;
+ break;
+ case sheet::FillMode_LINEAR:
+ eCmd = FILL_LINEAR;
+ break;
+ case sheet::FillMode_GROWTH:
+ eCmd = FILL_GROWTH;
+ break;
+ case sheet::FillMode_DATE:
+ eCmd = FILL_DATE;
+ break;
+ case sheet::FillMode_AUTO:
+ eCmd = FILL_AUTO;
+ break;
+ default:
+ bError = true;
+ }
+
+ FillDateCmd eDateCmd = FILL_DAY;
+ switch ( nFillDateMode )
+ {
+ case sheet::FillDateMode_FILL_DATE_DAY:
+ eDateCmd = FILL_DAY;
+ break;
+ case sheet::FillDateMode_FILL_DATE_WEEKDAY:
+ eDateCmd = FILL_WEEKDAY;
+ break;
+ case sheet::FillDateMode_FILL_DATE_MONTH:
+ eDateCmd = FILL_MONTH;
+ break;
+ case sheet::FillDateMode_FILL_DATE_YEAR:
+ eDateCmd = FILL_YEAR;
+ break;
+ default:
+ bError = true;
+ }
+
+ if (!bError)
+ pDocSh->GetDocFunc().FillSeries( aRange, nullptr, eDir, eCmd, eDateCmd,
+ MAXDOUBLE, fStep, fEndValue, true );
+}
+
+void SAL_CALL ScCellRangeObj::fillAuto( sheet::FillDirection nFillDirection,
+ sal_Int32 nSourceCount )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !(pDocSh && nSourceCount) )
+ return;
+
+ ScRange aSourceRange(aRange);
+ SCCOLROW nCount = 0; // "Dest-Count"
+ FillDir eDir = FILL_TO_BOTTOM;
+ bool bError = false;
+ switch (nFillDirection)
+ {
+ case sheet::FillDirection_TO_BOTTOM:
+ aSourceRange.aEnd.SetRow( static_cast<SCROW>( aSourceRange.aStart.Row() + nSourceCount - 1 ) );
+ nCount = aRange.aEnd.Row() - aSourceRange.aEnd.Row();
+ eDir = FILL_TO_BOTTOM;
+ break;
+ case sheet::FillDirection_TO_RIGHT:
+ aSourceRange.aEnd.SetCol( static_cast<SCCOL>( aSourceRange.aStart.Col() + nSourceCount - 1 ) );
+ nCount = aRange.aEnd.Col() - aSourceRange.aEnd.Col();
+ eDir = FILL_TO_RIGHT;
+ break;
+ case sheet::FillDirection_TO_TOP:
+ aSourceRange.aStart.SetRow( static_cast<SCROW>( aSourceRange.aEnd.Row() - nSourceCount + 1 ) );
+ nCount = aSourceRange.aStart.Row() - aRange.aStart.Row();
+ eDir = FILL_TO_TOP;
+ break;
+ case sheet::FillDirection_TO_LEFT:
+ aSourceRange.aStart.SetCol( static_cast<SCCOL>( aSourceRange.aEnd.Col() - nSourceCount + 1 ) );
+ nCount = aSourceRange.aStart.Col() - aRange.aStart.Col();
+ eDir = FILL_TO_LEFT;
+ break;
+ default:
+ bError = true;
+ }
+ const ScDocument& rDoc = pDocSh->GetDocument();
+ if (nCount < 0 || nCount > rDoc.MaxRow()) // overflow
+ bError = true;
+
+ if (!bError)
+ pDocSh->GetDocFunc().FillAuto( aSourceRange, nullptr, eDir, nCount, true );
+}
+
+// XAutoFormattable
+
+void SAL_CALL ScCellRangeObj::autoFormat( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScAutoFormat* pAutoFormat = ScGlobal::GetOrCreateAutoFormat();
+ ScAutoFormat::const_iterator it = pAutoFormat->find(aName);
+ if (it == pAutoFormat->end())
+ throw lang::IllegalArgumentException();
+
+ ScAutoFormat::const_iterator itBeg = pAutoFormat->begin();
+ size_t nIndex = std::distance(itBeg, it);
+ pDocSh->GetDocFunc().AutoFormat(aRange, nullptr, nIndex, true);
+
+ }
+}
+
+// XSortable
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScCellRangeObj::createSortDescriptor()
+{
+ SolarMutexGuard aGuard;
+ ScSortParam aParam;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ // create DB-Area only during execution; API always the exact area
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, ScGetDBSelection::ForceMark );
+ if (pData)
+ {
+ pData->GetSortParam(aParam);
+
+ // SortDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOLROW nFieldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aDBRange.aStart.Col()) :
+ static_cast<SCCOLROW>(aDBRange.aStart.Row());
+ for (sal_uInt16 i=0; i<aParam.GetSortKeyCount(); i++)
+ if ( aParam.maKeyState[i].bDoSort && aParam.maKeyState[i].nField >= nFieldStart )
+ aParam.maKeyState[i].nField -= nFieldStart;
+ }
+ }
+
+ uno::Sequence<beans::PropertyValue> aSeq( ScSortDescriptor::GetPropertyCount() );
+ ScSortDescriptor::FillProperties( aSeq, aParam );
+ return aSeq;
+}
+
+void SAL_CALL ScCellRangeObj::sort( const uno::Sequence<beans::PropertyValue>& aDescriptor )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ sal_uInt16 i;
+ ScSortParam aParam;
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+ if (pData)
+ {
+ // get old settings if not everything is set anew
+ pData->GetSortParam(aParam);
+ SCCOLROW nOldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aRange.aStart.Col()) :
+ static_cast<SCCOLROW>(aRange.aStart.Row());
+ for (i=0; i<aParam.GetSortKeyCount(); i++)
+ if ( aParam.maKeyState[i].bDoSort && aParam.maKeyState[i].nField >= nOldStart )
+ aParam.maKeyState[i].nField -= nOldStart;
+ }
+
+ ScSortDescriptor::FillSortParam( aParam, aDescriptor );
+
+ // SortDescriptor contains the counted fields inside the area
+ // ByRow can be changed during execution of FillSortParam
+ SCCOLROW nFieldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aRange.aStart.Col()) :
+ static_cast<SCCOLROW>(aRange.aStart.Row());
+ SCCOLROW nFieldEnd = aParam.bByRow ?
+ static_cast<SCCOLROW>(aRange.aEnd.Col()) :
+ static_cast<SCCOLROW>(aRange.aEnd.Row());
+ for (i=0; i<aParam.GetSortKeyCount(); i++)
+ {
+ aParam.maKeyState[i].nField += nFieldStart;
+ // tdf#103632 - sanity check poorly behaved macros.
+ if (aParam.maKeyState[i].nField > nFieldEnd)
+ aParam.maKeyState[i].nField = nFieldEnd;
+ }
+
+ SCTAB nTab = aRange.aStart.Tab();
+ aParam.nCol1 = aRange.aStart.Col();
+ aParam.nRow1 = aRange.aStart.Row();
+ aParam.nCol2 = aRange.aEnd.Col();
+ aParam.nRow2 = aRange.aEnd.Row();
+
+ pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+
+ ScDBDocFunc aFunc(*pDocSh); // area must be created
+ (void)aFunc.Sort( nTab, aParam, true, true, true );
+}
+
+// XFilterable
+
+uno::Reference<sheet::XSheetFilterDescriptor> SAL_CALL ScCellRangeObj::createFilterDescriptor(
+ sal_Bool bEmpty )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ rtl::Reference<ScFilterDescriptor> pNew = new ScFilterDescriptor(pDocSh);
+ if ( !bEmpty && pDocSh )
+ {
+ // create DB-Area only during execution; API always the exact area
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, ScGetDBSelection::ForceMark );
+ if (pData)
+ {
+ ScQueryParam aParam;
+ pData->GetQueryParam(aParam);
+ // FilterDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOLROW nFieldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aDBRange.aStart.Col()) :
+ static_cast<SCCOLROW>(aDBRange.aStart.Row());
+ SCSIZE nCount = aParam.GetEntryCount();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if (rEntry.bDoQuery && rEntry.nField >= nFieldStart)
+ rEntry.nField -= nFieldStart;
+ }
+ pNew->SetParam(aParam);
+ }
+ }
+ return pNew;
+}
+
+void SAL_CALL ScCellRangeObj::filter( const uno::Reference<sheet::XSheetFilterDescriptor>& xDescriptor )
+{
+ SolarMutexGuard aGuard;
+
+ if (!xDescriptor.is()) return;
+
+ // This could be theoretically an unknown object, so only use the
+ // public XSheetFilterDescriptor interface to copy the data into a
+ // ScFilterDescriptor object:
+ //! if it already a ScFilterDescriptor is, direct via getImplementation?
+
+ ScDocShell* pDocSh = GetDocShell();
+ rtl::Reference<ScFilterDescriptor> xImpl(new ScFilterDescriptor(pDocSh));
+ uno::Reference< sheet::XSheetFilterDescriptor2 > xDescriptor2( xDescriptor, uno::UNO_QUERY );
+ if ( xDescriptor2.is() )
+ {
+ xImpl->setFilterFields2( xDescriptor2->getFilterFields2() );
+ }
+ else
+ {
+ xImpl->setFilterFields( xDescriptor->getFilterFields() );
+ }
+ // the rest are now properties...
+
+ uno::Reference<beans::XPropertySet> xPropSet( xDescriptor, uno::UNO_QUERY );
+ if (xPropSet.is())
+ lcl_CopyProperties(*xImpl, *xPropSet);
+
+ if (!pDocSh)
+ return;
+
+ ScQueryParam aParam = xImpl->GetParam();
+ // FilterDescriptor contains the counted fields inside the area
+ SCCOLROW nFieldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aRange.aStart.Col()) :
+ static_cast<SCCOLROW>(aRange.aStart.Row());
+ SCSIZE nCount = aParam.GetEntryCount();
+ svl::SharedStringPool& rPool = pDocSh->GetDocument().GetSharedStringPool();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if (rEntry.bDoQuery)
+ {
+ rEntry.nField += nFieldStart;
+ // dialog always shows the string -> must match the value
+ ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ rItems.resize(1);
+ ScQueryEntry::Item& rItem = rItems.front();
+ if (rItem.meType != ScQueryEntry::ByString)
+ {
+ OUString aStr;
+ pDocSh->GetDocument().GetFormatTable()->GetInputLineString(rItem.mfVal, 0, aStr);
+ rItem.maString = rPool.intern(aStr);
+ }
+ }
+ }
+
+ SCTAB nTab = aRange.aStart.Tab();
+ aParam.nCol1 = aRange.aStart.Col();
+ aParam.nRow1 = aRange.aStart.Row();
+ aParam.nCol2 = aRange.aEnd.Col();
+ aParam.nRow2 = aRange.aEnd.Row();
+
+ pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+
+ //! keep source range in filter descriptor
+ //! if created by createFilterDescriptorByObject ???
+
+ ScDBDocFunc aFunc(*pDocSh);
+ aFunc.Query( nTab, aParam, nullptr, true, true ); // area must be created
+}
+
+//! get/setAutoFilter as properties!!!
+
+// XAdvancedFilterSource
+
+uno::Reference<sheet::XSheetFilterDescriptor> SAL_CALL ScCellRangeObj::createFilterDescriptorByObject(
+ const uno::Reference<sheet::XSheetFilterable>& xObject )
+{
+ SolarMutexGuard aGuard;
+
+ // this here is not the area, which will be filtered, instead the area
+ // with the query
+
+ uno::Reference<sheet::XCellRangeAddressable> xAddr( xObject, uno::UNO_QUERY );
+
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh || !xAddr.is() )
+ {
+ OSL_FAIL("no document or no area");
+ return nullptr;
+ }
+
+ //! check if xObject is in the same document
+
+ rtl::Reference<ScFilterDescriptor> pNew(new ScFilterDescriptor(pDocSh)); //! instead from object?
+
+ ScQueryParam aParam = pNew->GetParam();
+ aParam.bHasHeader = true;
+
+ table::CellRangeAddress aDataAddress(xAddr->getRangeAddress());
+ aParam.nCol1 = static_cast<SCCOL>(aDataAddress.StartColumn);
+ aParam.nRow1 = static_cast<SCROW>(aDataAddress.StartRow);
+ aParam.nCol2 = static_cast<SCCOL>(aDataAddress.EndColumn);
+ aParam.nRow2 = static_cast<SCROW>(aDataAddress.EndRow);
+ aParam.nTab = aDataAddress.Sheet;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ if (!rDoc.CreateQueryParam(aRange, aParam))
+ return nullptr;
+
+ // FilterDescriptor contains the counted fields inside the area
+ SCCOLROW nFieldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aDataAddress.StartColumn) :
+ static_cast<SCCOLROW>(aDataAddress.StartRow);
+ SCSIZE nCount = aParam.GetEntryCount();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if (rEntry.bDoQuery && rEntry.nField >= nFieldStart)
+ rEntry.nField -= nFieldStart;
+ }
+
+ pNew->SetParam( aParam );
+ return pNew;
+}
+
+// XSubTotalSource
+
+uno::Reference<sheet::XSubTotalDescriptor> SAL_CALL ScCellRangeObj::createSubTotalDescriptor(
+ sal_Bool bEmpty )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<ScSubTotalDescriptor> pNew = new ScSubTotalDescriptor;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !bEmpty && pDocSh )
+ {
+ // create DB-Area only during execution; API always the exact area
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, ScGetDBSelection::ForceMark );
+ if (pData)
+ {
+ ScSubTotalParam aParam;
+ pData->GetSubTotalParam(aParam);
+ // SubTotalDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOL nFieldStart = aDBRange.aStart.Col();
+ for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
+ {
+ if ( aParam.bGroupActive[i] )
+ {
+ if ( aParam.nField[i] >= nFieldStart )
+ aParam.nField[i] = sal::static_int_cast<SCCOL>( aParam.nField[i] - nFieldStart );
+ for (SCCOL j=0; j<aParam.nSubTotals[i]; j++)
+ if ( aParam.pSubTotals[i][j] >= nFieldStart )
+ aParam.pSubTotals[i][j] = sal::static_int_cast<SCCOL>( aParam.pSubTotals[i][j] - nFieldStart );
+ }
+ }
+ pNew->SetParam(aParam);
+ }
+ }
+ return pNew;
+}
+
+void SAL_CALL ScCellRangeObj::applySubTotals(
+ const uno::Reference<sheet::XSubTotalDescriptor>& xDescriptor,
+ sal_Bool bReplace)
+{
+ SolarMutexGuard aGuard;
+
+ if (!xDescriptor.is()) return;
+
+ ScDocShell* pDocSh = GetDocShell();
+ ScSubTotalDescriptorBase* pImp =
+ dynamic_cast<ScSubTotalDescriptorBase*>( xDescriptor.get() );
+
+ if (!(pDocSh && pImp))
+ return;
+
+ ScSubTotalParam aParam;
+ pImp->GetData(aParam); // virtual method of base class
+
+ // SubTotalDescriptor contains the counted fields inside the area
+ SCCOL nFieldStart = aRange.aStart.Col();
+ for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
+ {
+ if ( aParam.bGroupActive[i] )
+ {
+ aParam.nField[i] = sal::static_int_cast<SCCOL>( aParam.nField[i] + nFieldStart );
+ for (SCCOL j=0; j<aParam.nSubTotals[i]; j++)
+ aParam.pSubTotals[i][j] = sal::static_int_cast<SCCOL>( aParam.pSubTotals[i][j] + nFieldStart );
+ }
+ }
+
+ aParam.bReplace = bReplace;
+
+ SCTAB nTab = aRange.aStart.Tab();
+ aParam.nCol1 = aRange.aStart.Col();
+ aParam.nRow1 = aRange.aStart.Row();
+ aParam.nCol2 = aRange.aEnd.Col();
+ aParam.nRow2 = aRange.aEnd.Row();
+
+ pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+
+ ScDBDocFunc aFunc(*pDocSh);
+ aFunc.DoSubTotals( nTab, aParam, true, true ); // area must be created
+}
+
+void SAL_CALL ScCellRangeObj::removeSubTotals()
+{
+ SolarMutexGuard aGuard;
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ ScSubTotalParam aParam;
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, ScGetDBSelection::ForceMark );
+ if (pData)
+ pData->GetSubTotalParam(aParam); // also keep field entries during remove
+
+ aParam.bRemoveOnly = true;
+
+ SCTAB nTab = aRange.aStart.Tab();
+ aParam.nCol1 = aRange.aStart.Col();
+ aParam.nRow1 = aRange.aStart.Row();
+ aParam.nCol2 = aRange.aEnd.Col();
+ aParam.nRow2 = aRange.aEnd.Row();
+
+ pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+
+ ScDBDocFunc aFunc(*pDocSh);
+ aFunc.DoSubTotals( nTab, aParam, true, true ); // are must be created
+}
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScCellRangeObj::createImportDescriptor( sal_Bool bEmpty )
+{
+ SolarMutexGuard aGuard;
+ ScImportParam aParam;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !bEmpty && pDocSh )
+ {
+ // create DB-Area only during execution; API always the exact area
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, ScGetDBSelection::ForceMark );
+ if (pData)
+ pData->GetImportParam(aParam);
+ }
+
+ uno::Sequence<beans::PropertyValue> aSeq( ScImportDescriptor::GetPropertyCount() );
+ ScImportDescriptor::FillProperties( aSeq, aParam );
+ return aSeq;
+}
+
+void SAL_CALL ScCellRangeObj::doImport( const uno::Sequence<beans::PropertyValue>& aDescriptor )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ ScImportParam aParam;
+ ScImportDescriptor::FillImportParam( aParam, aDescriptor );
+
+ SCTAB nTab = aRange.aStart.Tab();
+ aParam.nCol1 = aRange.aStart.Col();
+ aParam.nRow1 = aRange.aStart.Row();
+ aParam.nCol2 = aRange.aEnd.Col();
+ aParam.nRow2 = aRange.aEnd.Row();
+
+ //! TODO: could we get passed a valid result set by any means?
+
+ pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+
+ ScDBDocFunc aFunc(*pDocSh); // are must be created
+ aFunc.DoImport( nTab, aParam, nullptr ); //! Api-Flag as parameter
+}
+
+// XCellFormatRangesSupplier
+
+uno::Reference<container::XIndexAccess> SAL_CALL ScCellRangeObj::getCellFormatRanges()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScCellFormatsObj( pDocSh, aRange );
+ return nullptr;
+}
+
+// XUniqueCellFormatRangesSupplier
+
+uno::Reference<container::XIndexAccess> SAL_CALL ScCellRangeObj::getUniqueCellFormatRanges()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScUniqueCellFormatsObj( pDocSh, aRange );
+ return nullptr;
+}
+
+// XPropertySet extended for Range-Properties
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCellRangeObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pRangePropSet->getPropertyMap() ));
+ return aRef;
+}
+
+void ScCellRangeObj::SetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue )
+{
+ // Range has only Position and Size in addition to ScCellRangesBase, both are ReadOnly
+ // -> nothing to do here
+
+ ScCellRangesBase::SetOnePropertyValue( pEntry, aValue );
+}
+
+void ScCellRangeObj::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ if ( pEntry->nWID == SC_WID_UNO_POS )
+ {
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ // GetMMRect converts using HMM_PER_TWIPS, like the DrawingLayer
+ tools::Rectangle aMMRect(pDocSh->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab() ));
+ awt::Point aPos( aMMRect.Left(), aMMRect.Top() );
+ rAny <<= aPos;
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_SIZE )
+ {
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ // GetMMRect converts using HMM_PER_TWIPS, like the DrawingLayer
+ tools::Rectangle aMMRect = pDocSh->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab() );
+ Size aSize(aMMRect.GetSize());
+ awt::Size aAwtSize( aSize.Width(), aSize.Height() );
+ rAny <<= aAwtSize;
+ }
+ }
+ else
+ ScCellRangesBase::GetOnePropertyValue( pEntry, rAny );
+}
+
+const SfxItemPropertyMap& ScCellRangeObj::GetItemPropertyMap()
+{
+ return pRangePropSet->getPropertyMap();
+}
+
+// XServiceInfo
+
+OUString SAL_CALL ScCellRangeObj::getImplementationName()
+{
+ return "ScCellRangeObj";
+}
+
+sal_Bool SAL_CALL ScCellRangeObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellRangeObj::getSupportedServiceNames()
+{
+ return {SCSHEETCELLRANGE_SERVICE,
+ SCCELLRANGE_SERVICE,
+ SCCELLPROPERTIES_SERVICE,
+ SCCHARPROPERTIES_SERVICE,
+ SCPARAPROPERTIES_SERVICE};
+}
+
+const SvxItemPropertySet* ScCellObj::GetEditPropertySet()
+{
+ return lcl_GetEditPropertySet();
+}
+
+const SfxItemPropertyMap& ScCellObj::GetCellPropertyMap()
+{
+ return lcl_GetCellPropertySet()->getPropertyMap();
+}
+
+ScCellObj::ScCellObj(ScDocShell* pDocSh, const ScAddress& rP) :
+ ScCellRangeObj( pDocSh, ScRange(rP,rP) ),
+ pCellPropSet( lcl_GetCellPropertySet() ),
+ aCellPos( rP ),
+ nActionLockCount( 0 )
+{
+ // pUnoText is allocated on demand (GetUnoText)
+ // can't be aggregated because getString/setString is handled here
+}
+
+SvxUnoText& ScCellObj::GetUnoText()
+{
+ if (!mxUnoText.is())
+ {
+ mxUnoText.set(new ScCellTextObj(GetDocShell(), aCellPos));
+ if (nActionLockCount)
+ {
+ ScCellEditSource* pEditSource =
+ static_cast<ScCellEditSource*> (mxUnoText->GetEditSource());
+ if (pEditSource)
+ pEditSource->SetDoUpdateData(false);
+ }
+ }
+ return *mxUnoText;
+}
+
+ScCellObj::~ScCellObj()
+{
+}
+
+void ScCellObj::RefChanged()
+{
+ ScCellRangeObj::RefChanged();
+
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE(rRanges.size() == 1, "What ranges ?!?!");
+ if ( !rRanges.empty() )
+ {
+ aCellPos = rRanges[ 0 ].aStart;
+ }
+}
+
+uno::Any SAL_CALL ScCellObj::queryInterface( const uno::Type& rType )
+{
+ uno::Any aReturn = ::cppu::queryInterface(rType,
+ static_cast<table::XCell*>(this),
+ static_cast<table::XCell2*>(this),
+ static_cast<sheet::XFormulaTokens*>(this),
+ static_cast<sheet::XCellAddressable*>(this),
+ static_cast<text::XText*>(this),
+ static_cast<text::XSimpleText*>(this),
+ static_cast<text::XTextRange*>(this),
+ static_cast<container::XEnumerationAccess*>(this),
+ static_cast<container::XElementAccess*>(this),
+ static_cast<sheet::XSheetAnnotationAnchor*>(this),
+ static_cast<text::XTextFieldsSupplier*>(this),
+ static_cast<document::XActionLockable*>(this));
+ if ( aReturn.hasValue() )
+ return aReturn;
+
+ return ScCellRangeObj::queryInterface( rType );
+}
+
+void SAL_CALL ScCellObj::acquire() noexcept
+{
+ ScCellRangeObj::acquire();
+}
+
+void SAL_CALL ScCellObj::release() noexcept
+{
+ ScCellRangeObj::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScCellObj::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes = comphelper::concatSequences(
+ ScCellRangeObj::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<table::XCell>::get(),
+ cppu::UnoType<sheet::XCellAddressable>::get(),
+ cppu::UnoType<text::XText>::get(),
+ cppu::UnoType<container::XEnumerationAccess>::get(),
+ cppu::UnoType<sheet::XSheetAnnotationAnchor>::get(),
+ cppu::UnoType<text::XTextFieldsSupplier>::get(),
+ cppu::UnoType<document::XActionLockable>::get(),
+ cppu::UnoType<sheet::XFormulaTokens>::get(),
+ cppu::UnoType<table::XCell2>::get()
+ } );
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScCellObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// helper methods
+
+OUString ScCellObj::GetInputString_Impl(bool bEnglish) const // for getFormula / FormulaLocal
+{
+ if (GetDocShell())
+ return lcl_GetInputString( GetDocShell()->GetDocument(), aCellPos, bEnglish );
+ return OUString();
+}
+
+OUString ScCellObj::GetOutputString_Impl() const
+{
+ ScDocShell* pDocSh = GetDocShell();
+ OUString aVal;
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScRefCellValue aCell(rDoc, aCellPos);
+
+ aVal = ScCellFormat::GetOutputString(rDoc, aCellPos, aCell);
+ }
+ return aVal;
+}
+
+void ScCellObj::SetString_Impl(const OUString& rString, bool bInterpret, bool bEnglish)
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ // GRAM_API for API compatibility.
+ (void)pDocSh->GetDocFunc().SetCellText(
+ aCellPos, rString, bInterpret, bEnglish, true, formula::FormulaGrammar::GRAM_API );
+ }
+}
+
+double ScCellObj::GetValue_Impl() const
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return pDocSh->GetDocument().GetValue( aCellPos );
+
+ return 0.0;
+}
+
+void ScCellObj::SetValue_Impl(double fValue)
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ pDocSh->GetDocFunc().SetValueCell(aCellPos, fValue, false);
+}
+
+// only for XML import
+
+void ScCellObj::InputEnglishString( const OUString& rText )
+{
+ // This is like a mixture of setFormula and property FormulaLocal:
+ // The cell's number format is checked for "text", a new cell format may be set,
+ // but all parsing is in English.
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ sal_uInt32 nOldFormat = rDoc.GetNumberFormat( aCellPos );
+ if (pFormatter->GetType(nOldFormat) == SvNumFormatType::TEXT)
+ {
+ SetString_Impl(rText, false, false); // text cell
+ return;
+ }
+
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+
+ ScInputStringType aRes =
+ ScStringUtil::parseInputString(*pFormatter, rText, LANGUAGE_ENGLISH_US);
+
+ if (aRes.meType != ScInputStringType::Unknown)
+ {
+ if ((nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && aRes.mnFormatType != SvNumFormatType::ALL)
+ {
+ // apply a format for the recognized type and the old format's language
+ sal_uInt32 nNewFormat = ScGlobal::GetStandardFormat(*pFormatter, nOldFormat, aRes.mnFormatType);
+ if (nNewFormat != nOldFormat)
+ {
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
+ // ATTR_LANGUAGE_FORMAT remains unchanged
+ rFunc.ApplyAttributes( *GetMarkData(), aPattern, true );
+ }
+ }
+ }
+ switch (aRes.meType)
+ {
+ case ScInputStringType::Formula:
+ rFunc.SetFormulaCell(
+ aCellPos,
+ new ScFormulaCell(rDoc, aCellPos, aRes.maText, formula::FormulaGrammar::GRAM_API),
+ false);
+ break;
+ case ScInputStringType::Number:
+ rFunc.SetValueCell(aCellPos, aRes.mfValue, false);
+ break;
+ case ScInputStringType::Text:
+ rFunc.SetStringOrEditCell(aCellPos, aRes.maText, false);
+ break;
+ default:
+ SetString_Impl(rText, false, false); // probably empty string
+ }
+}
+
+// XText
+
+uno::Reference<text::XTextCursor> SAL_CALL ScCellObj::createTextCursor()
+{
+ SolarMutexGuard aGuard;
+ return new ScCellTextCursor( *this );
+}
+
+uno::Reference<text::XTextCursor> SAL_CALL ScCellObj::createTextCursorByRange(
+ const uno::Reference<text::XTextRange>& aTextPosition )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<SvxUnoTextCursor> pCursor = new ScCellTextCursor( *this );
+
+ SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( aTextPosition );
+ if(pRange)
+ pCursor->SetSelection( pRange->GetSelection() );
+ else
+ {
+ ScCellTextCursor* pOther = comphelper::getFromUnoTunnel<ScCellTextCursor>( aTextPosition );
+ if(!pOther)
+ throw uno::RuntimeException();
+
+ pCursor->SetSelection( pOther->GetSelection() );
+
+ }
+
+ return pCursor;
+}
+
+OUString SAL_CALL ScCellObj::getString()
+{
+ SolarMutexGuard aGuard;
+ return GetOutputString_Impl();
+}
+
+void SAL_CALL ScCellObj::setString( const OUString& aText )
+{
+ SolarMutexGuard aGuard;
+ SetString_Impl(aText, false, false); // always text
+
+ // don't create pUnoText here if not there
+ if (mxUnoText.is())
+ mxUnoText->SetSelection(ESelection( 0,0, 0,aText.getLength() ));
+}
+
+void SAL_CALL ScCellObj::insertString( const uno::Reference<text::XTextRange>& xRange,
+ const OUString& aString, sal_Bool bAbsorb )
+{
+ // special handling for ScCellTextCursor is no longer needed,
+ // SvxUnoText::insertString checks for SvxUnoTextRangeBase instead of SvxUnoTextRange
+
+ SolarMutexGuard aGuard;
+ GetUnoText().insertString(xRange, aString, bAbsorb);
+}
+
+void SAL_CALL ScCellObj::insertControlCharacter( const uno::Reference<text::XTextRange>& xRange,
+ sal_Int16 nControlCharacter, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ GetUnoText().insertControlCharacter(xRange, nControlCharacter, bAbsorb);
+}
+
+void SAL_CALL ScCellObj::insertTextContent( const uno::Reference<text::XTextRange >& xRange,
+ const uno::Reference<text::XTextContent >& xContent,
+ sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh && xContent.is() )
+ {
+ ScEditFieldObj* pCellField = dynamic_cast<ScEditFieldObj*>(xContent.get());
+ SvxUnoTextRangeBase* pTextRange = comphelper::getFromUnoTunnel<ScCellTextCursor>( xRange );
+
+ if ( pCellField && !pCellField->IsInserted() && pTextRange )
+ {
+ SvxEditSource* pEditSource = pTextRange->GetEditSource();
+ ESelection aSelection(pTextRange->GetSelection());
+
+ if (!bAbsorb)
+ {
+ // do not replace -> append
+ aSelection.Adjust();
+ aSelection.nStartPara = aSelection.nEndPara;
+ aSelection.nStartPos = aSelection.nEndPos;
+ }
+
+ if (pCellField->GetFieldType() == text::textfield::Type::TABLE)
+ pCellField->setPropertyValue(SC_UNONAME_TABLEPOS, uno::Any(sal_Int32(aCellPos.Tab())));
+
+ SvxFieldItem aItem = pCellField->CreateFieldItem();
+ SvxTextForwarder* pForwarder = pEditSource->GetTextForwarder();
+ pForwarder->QuickInsertField( aItem, aSelection );
+ pEditSource->UpdateData();
+
+ // new selection: a digit
+ aSelection.Adjust();
+ aSelection.nEndPara = aSelection.nStartPara;
+ aSelection.nEndPos = aSelection.nStartPos + 1;
+ uno::Reference<text::XTextRange> xParent(this);
+ pCellField->InitDoc(
+ xParent, std::make_unique<ScCellEditSource>(pDocSh, aCellPos), aSelection);
+
+ // for bAbsorb=FALSE, the new selection must be behind the inserted content
+ // (the xml filter relies on this)
+ if (!bAbsorb)
+ aSelection.nStartPos = aSelection.nEndPos;
+
+ pTextRange->SetSelection( aSelection );
+
+ return;
+ }
+ }
+ GetUnoText().insertTextContent(xRange, xContent, bAbsorb);
+}
+
+void SAL_CALL ScCellObj::removeTextContent( const uno::Reference<text::XTextContent>& xContent )
+{
+ SolarMutexGuard aGuard;
+ if ( xContent.is() )
+ {
+ ScEditFieldObj* pCellField = dynamic_cast<ScEditFieldObj*>(xContent.get());
+ if ( pCellField && pCellField->IsInserted() )
+ {
+ //! Check if field is in this cell
+ pCellField->DeleteField();
+ return;
+ }
+ }
+ GetUnoText().removeTextContent(xContent);
+}
+
+uno::Reference<text::XText> SAL_CALL ScCellObj::getText()
+{
+ return this;
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScCellObj::getStart()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getStart();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScCellObj::getEnd()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getEnd();
+}
+
+uno::Reference<container::XEnumeration> SAL_CALL ScCellObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().createEnumeration();
+}
+
+uno::Type SAL_CALL ScCellObj::getElementType()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getElementType();
+}
+
+sal_Bool SAL_CALL ScCellObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().hasElements();
+}
+
+// XCell
+
+OUString SAL_CALL ScCellObj::getFormula()
+{
+ SolarMutexGuard aGuard;
+ return GetInputString_Impl( true /* English */ );
+}
+
+void SAL_CALL ScCellObj::setFormula( const OUString& aFormula )
+{
+ SolarMutexGuard aGuard;
+ SetString_Impl(aFormula, true, true); // Interpret as English
+}
+
+double SAL_CALL ScCellObj::getValue()
+{
+ SolarMutexGuard aGuard;
+ return GetValue_Impl();
+}
+
+void SAL_CALL ScCellObj::setValue( double nValue )
+{
+ SolarMutexGuard aGuard;
+ SetValue_Impl(nValue);
+}
+
+void SAL_CALL ScCellObj::setFormulaString( const OUString& aFormula)
+{
+ SolarMutexGuard aGuard;
+ ScDocShell *pDocSh = GetDocShell();
+ if( pDocSh )
+ {
+ ScFormulaCell* pCell = new ScFormulaCell( pDocSh->GetDocument(), aCellPos );
+ pCell->SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE );
+ pDocSh->GetDocFunc().SetFormulaCell(aCellPos, pCell, false);
+ }
+}
+void SAL_CALL ScCellObj::setFormulaResult( double nValue )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ ScRefCellValue aCell(pDocSh->GetDocument(), aCellPos);
+ if (aCell.getType() == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pCell = aCell.getFormula();
+ pCell->SetHybridDouble( nValue );
+ pCell->ResetDirty();
+ pCell->SetChanged(false);
+ }
+ }
+}
+
+table::CellContentType SAL_CALL ScCellObj::getType()
+{
+ SolarMutexGuard aGuard;
+ table::CellContentType eRet = table::CellContentType_EMPTY;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ CellType eCalcType = pDocSh->GetDocument().GetCellType( aCellPos );
+ switch (eCalcType)
+ {
+ case CELLTYPE_VALUE:
+ eRet = table::CellContentType_VALUE;
+ break;
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ eRet = table::CellContentType_TEXT;
+ break;
+ case CELLTYPE_FORMULA:
+ eRet = table::CellContentType_FORMULA;
+ break;
+ default:
+ eRet = table::CellContentType_EMPTY;
+ }
+ }
+ else
+ {
+ OSL_FAIL("no DocShell"); //! Exception or so?
+ }
+
+ return eRet;
+}
+
+sal_Int32 ScCellObj::GetResultType_Impl() const
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 eRet = sheet::FormulaResult::STRING;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ if (pDocSh->GetDocument().GetCellType(aCellPos) == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = pDocSh->GetDocument().GetFormulaCell(aCellPos);
+ if (!pFCell)
+ {
+ // should throw instead of default string?
+ }
+ else if (pFCell->GetErrCode() != FormulaError::NONE )
+ {
+ eRet = sheet::FormulaResult::ERROR;
+ }
+ else if (pFCell->IsValue())
+ {
+ eRet = sheet::FormulaResult::VALUE;
+ }
+ else
+ {
+ eRet = sheet::FormulaResult::STRING;
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("no DocShell");
+ }
+
+ return eRet;
+}
+
+table::CellContentType ScCellObj::GetContentType_Impl()
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScRefCellValue aCell(pDocSh->GetDocument(), aCellPos);
+ if (aCell.getType() == CELLTYPE_FORMULA)
+ {
+ bool bValue = aCell.getFormula()->IsValue();
+ return bValue ? table::CellContentType_VALUE : table::CellContentType_TEXT;
+ }
+ }
+ return getType();
+}
+
+sal_Int32 SAL_CALL ScCellObj::getError()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ {
+ OSL_FAIL("no DocShell"); //! Exception or so?
+ return 0;
+ }
+
+ FormulaError nError = FormulaError::NONE;
+ ScRefCellValue aCell(pDocSh->GetDocument(), aCellPos);
+ if (aCell.getType() == CELLTYPE_FORMULA)
+ nError = aCell.getFormula()->GetErrCode();
+
+ return static_cast<sal_Int32>(nError);
+}
+
+// XFormulaTokens
+
+uno::Sequence<sheet::FormulaToken> SAL_CALL ScCellObj::getTokens()
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence<sheet::FormulaToken> aSequence;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return aSequence;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScRefCellValue aCell(rDoc, aCellPos);
+ if (aCell.getType() == CELLTYPE_FORMULA)
+ {
+ ScTokenArray* pTokenArray = aCell.getFormula()->GetCode();
+ if (pTokenArray)
+ ScTokenConversion::ConvertToTokenSequence(rDoc, aSequence, *pTokenArray);
+ }
+ return aSequence;
+}
+
+void SAL_CALL ScCellObj::setTokens( const uno::Sequence<sheet::FormulaToken>& rTokens )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScTokenArray aTokenArray(rDoc);
+ (void)ScTokenConversion::ConvertToTokenArray( rDoc, aTokenArray, rTokens );
+
+ ScFormulaCell* pNewCell = new ScFormulaCell(rDoc, aCellPos, aTokenArray);
+ (void)pDocSh->GetDocFunc().SetFormulaCell(aCellPos, pNewCell, false);
+ }
+}
+
+// XCellAddressable
+
+table::CellAddress SAL_CALL ScCellObj::getCellAddress()
+{
+ SolarMutexGuard aGuard;
+ table::CellAddress aAdr;
+ aAdr.Sheet = aCellPos.Tab();
+ aAdr.Column = aCellPos.Col();
+ aAdr.Row = aCellPos.Row();
+ return aAdr;
+}
+
+// XSheetAnnotationAnchor
+
+uno::Reference<sheet::XSheetAnnotation> SAL_CALL ScCellObj::getAnnotation()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScAnnotationObj( pDocSh, aCellPos );
+
+ OSL_FAIL("getAnnotation without DocShell");
+ return nullptr;
+}
+
+// XFieldTypesSupplier
+
+uno::Reference<container::XEnumerationAccess> SAL_CALL ScCellObj::getTextFields()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ uno::Reference<text::XTextRange> xContent(this);
+ return new ScCellFieldsObj(xContent, pDocSh, aCellPos);
+ }
+
+ return nullptr;
+}
+
+uno::Reference<container::XNameAccess> SAL_CALL ScCellObj::getTextFieldMasters()
+{
+ // there is no such thing in Calc (?)
+ return nullptr;
+}
+
+// XPropertySet extended for Cell-Properties
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCellObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pCellPropSet->getPropertyMap() ));
+ return aRef;
+}
+
+void ScCellObj::SetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue )
+{
+ if ( !pEntry )
+ return;
+
+ if ( pEntry->nWID == SC_WID_UNO_FORMLOC )
+ {
+ OUString aStrVal;
+ aValue >>= aStrVal;
+ SetString_Impl(aStrVal, true, false); // interpret locally
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_FORMRT || pEntry->nWID == SC_WID_UNO_FORMRT2
+ || pEntry->nWID == SC_WID_UNO_CELLCONTENTTYPE )
+ {
+ // Read-Only
+ //! Exception or so...
+ }
+ else
+ ScCellRangeObj::SetOnePropertyValue( pEntry, aValue );
+}
+
+void ScCellObj::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ if ( pEntry->nWID == SC_WID_UNO_FORMLOC )
+ {
+ // sal_False = local
+ rAny <<= GetInputString_Impl(false);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_FORMRT2 )
+ {
+ sal_Int32 eType = GetResultType_Impl();
+ rAny <<= eType;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLCONTENTTYPE || pEntry->nWID == SC_WID_UNO_FORMRT )
+ {
+ table::CellContentType eType = GetContentType_Impl();
+ rAny <<= eType;
+ }
+ else
+ ScCellRangeObj::GetOnePropertyValue(pEntry, rAny);
+}
+
+const SfxItemPropertyMap& ScCellObj::GetItemPropertyMap()
+{
+ return pCellPropSet->getPropertyMap();
+}
+
+// XServiceInfo
+
+OUString SAL_CALL ScCellObj::getImplementationName()
+{
+ return "ScCellObj";
+}
+
+sal_Bool SAL_CALL ScCellObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellObj::getSupportedServiceNames()
+{
+ return {SCSHEETCELL_SERVICE,
+ SCCELL_SERVICE,
+ SCCELLPROPERTIES_SERVICE,
+ SCCHARPROPERTIES_SERVICE,
+ SCPARAPROPERTIES_SERVICE,
+ SCSHEETCELLRANGE_SERVICE,
+ SCCELLRANGE_SERVICE};
+}
+
+// XActionLockable
+
+sal_Bool SAL_CALL ScCellObj::isActionLocked()
+{
+ SolarMutexGuard aGuard;
+ return nActionLockCount != 0;
+}
+
+void SAL_CALL ScCellObj::addActionLock()
+{
+ SolarMutexGuard aGuard;
+ if (!nActionLockCount)
+ {
+ if (mxUnoText.is())
+ {
+ ScCellEditSource* pEditSource =
+ static_cast<ScCellEditSource*> (mxUnoText->GetEditSource());
+ if (pEditSource)
+ pEditSource->SetDoUpdateData(false);
+ }
+ }
+ nActionLockCount++;
+}
+
+void SAL_CALL ScCellObj::removeActionLock()
+{
+ SolarMutexGuard aGuard;
+ if (nActionLockCount <= 0)
+ return;
+
+ nActionLockCount--;
+ if (nActionLockCount)
+ return;
+
+ if (mxUnoText.is())
+ {
+ ScCellEditSource* pEditSource =
+ static_cast<ScCellEditSource*> (mxUnoText->GetEditSource());
+ if (pEditSource)
+ {
+ pEditSource->SetDoUpdateData(true);
+ if (pEditSource->IsDirty())
+ pEditSource->UpdateData();
+ }
+ }
+}
+
+void SAL_CALL ScCellObj::setActionLocks( sal_Int16 nLock )
+{
+ SolarMutexGuard aGuard;
+ if (mxUnoText.is())
+ {
+ ScCellEditSource* pEditSource =
+ static_cast<ScCellEditSource*> (mxUnoText->GetEditSource());
+ if (pEditSource)
+ {
+ pEditSource->SetDoUpdateData(nLock == 0);
+ if ((nActionLockCount > 0) && (nLock == 0) && pEditSource->IsDirty())
+ pEditSource->UpdateData();
+ }
+ }
+ nActionLockCount = nLock;
+}
+
+sal_Int16 SAL_CALL ScCellObj::resetActionLocks()
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nRet(nActionLockCount);
+ if (mxUnoText.is())
+ {
+ ScCellEditSource* pEditSource =
+ static_cast<ScCellEditSource*> (mxUnoText->GetEditSource());
+ if (pEditSource)
+ {
+ pEditSource->SetDoUpdateData(true);
+ if (pEditSource->IsDirty())
+ pEditSource->UpdateData();
+ }
+ }
+ nActionLockCount = 0;
+ return nRet;
+}
+
+static ScRange MaxDocRange(ScDocShell* pDocSh, SCTAB nTab)
+{
+ const SCCOL nMaxcol = pDocSh ? pDocSh->GetDocument().MaxCol() : MAXCOL;
+ const SCROW nMaxRow = pDocSh ? pDocSh->GetDocument().MaxRow() : MAXROW;
+ return ScRange(0, 0, nTab, nMaxcol, nMaxRow, nTab);
+}
+
+ScTableSheetObj::ScTableSheetObj( ScDocShell* pDocSh, SCTAB nTab ) :
+ ScCellRangeObj( pDocSh, MaxDocRange(pDocSh, nTab) ),
+ pSheetPropSet(lcl_GetSheetPropertySet())
+{
+}
+
+ScTableSheetObj::~ScTableSheetObj()
+{
+}
+
+void ScTableSheetObj::InitInsertSheet(ScDocShell* pDocSh, SCTAB nTab)
+{
+ ScDocument& rDoc = pDocSh->GetDocument();
+ InitInsertRange( pDocSh, ScRange(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab) );
+}
+
+uno::Any SAL_CALL ScTableSheetObj::queryInterface( const uno::Type& rType )
+{
+ uno::Any aReturn = ::cppu::queryInterface(rType,
+ static_cast<sheet::XSpreadsheet*>(this),
+ static_cast<container::XNamed*>(this),
+ static_cast<sheet::XSheetPageBreak*>(this),
+ static_cast<sheet::XCellRangeMovement*>(this),
+ static_cast<table::XTableChartsSupplier*>(this),
+ static_cast<sheet::XDataPilotTablesSupplier*>(this),
+ static_cast<sheet::XScenariosSupplier*>(this),
+ static_cast<sheet::XSheetAnnotationsSupplier*>(this),
+ static_cast<drawing::XDrawPageSupplier*>(this),
+ static_cast<sheet::XPrintAreas*>(this),
+ static_cast<sheet::XSheetAuditing*>(this),
+ static_cast<sheet::XSheetOutline*>(this),
+ static_cast<util::XProtectable*>(this),
+ static_cast<sheet::XScenario*>(this),
+ static_cast<sheet::XScenarioEnhanced*>(this),
+ static_cast<sheet::XSheetLinkable*>(this),
+ static_cast<sheet::XExternalSheetName*>(this),
+ static_cast<document::XEventsSupplier*>(this),
+ static_cast<table::XTablePivotChartsSupplier*>(this));
+ if ( aReturn.hasValue() )
+ return aReturn;
+
+ return ScCellRangeObj::queryInterface( rType );
+}
+
+void SAL_CALL ScTableSheetObj::acquire() noexcept
+{
+ ScCellRangeObj::acquire();
+}
+
+void SAL_CALL ScTableSheetObj::release() noexcept
+{
+ ScCellRangeObj::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScTableSheetObj::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes = comphelper::concatSequences(
+ ScCellRangeObj::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XSpreadsheet>::get(),
+ cppu::UnoType<container::XNamed>::get(),
+ cppu::UnoType<sheet::XSheetPageBreak>::get(),
+ cppu::UnoType<sheet::XCellRangeMovement>::get(),
+ cppu::UnoType<table::XTableChartsSupplier>::get(),
+ cppu::UnoType<sheet::XDataPilotTablesSupplier>::get(),
+ cppu::UnoType<sheet::XScenariosSupplier>::get(),
+ cppu::UnoType<sheet::XSheetAnnotationsSupplier>::get(),
+ cppu::UnoType<drawing::XDrawPageSupplier>::get(),
+ cppu::UnoType<sheet::XPrintAreas>::get(),
+ cppu::UnoType<sheet::XSheetAuditing>::get(),
+ cppu::UnoType<sheet::XSheetOutline>::get(),
+ cppu::UnoType<util::XProtectable>::get(),
+ cppu::UnoType<sheet::XScenario>::get(),
+ cppu::UnoType<sheet::XScenarioEnhanced>::get(),
+ cppu::UnoType<sheet::XSheetLinkable>::get(),
+ cppu::UnoType<sheet::XExternalSheetName>::get(),
+ cppu::UnoType<document::XEventsSupplier>::get(),
+ cppu::UnoType<table::XTablePivotChartsSupplier>::get()
+ } );
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScTableSheetObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// Helper functions
+
+SCTAB ScTableSheetObj::GetTab_Impl() const
+{
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE(rRanges.size() == 1, "What ranges ?!?!");
+ if ( !rRanges.empty() )
+ {
+ return rRanges[ 0 ].aStart.Tab();
+ }
+ return 0;
+}
+
+// former XSheet
+
+uno::Reference<table::XTableCharts> SAL_CALL ScTableSheetObj::getCharts()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScChartsObj( pDocSh, GetTab_Impl() );
+
+ OSL_FAIL("no document");
+ return nullptr;
+}
+
+uno::Reference<table::XTablePivotCharts> SAL_CALL ScTableSheetObj::getPivotCharts()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ return new sc::TablePivotCharts(pDocSh, GetTab_Impl());
+
+ OSL_FAIL("no document");
+ return nullptr;
+}
+
+uno::Reference<sheet::XDataPilotTables> SAL_CALL ScTableSheetObj::getDataPilotTables()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScDataPilotTablesObj(*pDocSh, GetTab_Impl());
+
+ OSL_FAIL("no document");
+ return nullptr;
+}
+
+uno::Reference<sheet::XScenarios> SAL_CALL ScTableSheetObj::getScenarios()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+
+ if ( pDocSh )
+ return new ScScenariosObj( pDocSh, GetTab_Impl() );
+
+ OSL_FAIL("no document");
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetAnnotations> SAL_CALL ScTableSheetObj::getAnnotations()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+
+ if ( pDocSh )
+ return new ScAnnotationsObj( pDocSh, GetTab_Impl() );
+
+ OSL_FAIL("no document");
+ return nullptr;
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScTableSheetObj::getCellRangeByName(
+ const OUString& rRange )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getCellRangeByName( rRange );
+}
+
+uno::Reference<sheet::XSheetCellCursor> SAL_CALL ScTableSheetObj::createCursor()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ //! single cell or whole table??????
+ const ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ return new ScCellCursorObj( pDocSh, ScRange( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab ) );
+ }
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellCursor> SAL_CALL ScTableSheetObj::createCursorByRange(
+ const uno::Reference<sheet::XSheetCellRange>& xCellRange )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh && xCellRange.is() )
+ {
+ ScCellRangesBase* pRangesImp = dynamic_cast<ScCellRangesBase*>( xCellRange.get() );
+ if (pRangesImp)
+ {
+ const ScRangeList& rRanges = pRangesImp->GetRangeList();
+ SAL_WARN_IF( rRanges.size() != 1, "sc", "ScTableSheetObj::createCursorByRange: Range? Ranges?");
+ if (rRanges.empty())
+ return nullptr;
+ return new ScCellCursorObj( pDocSh, rRanges[ 0 ] );
+ }
+ }
+ return nullptr;
+}
+
+// XSheetCellRange
+
+uno::Reference<sheet::XSpreadsheet> SAL_CALL ScTableSheetObj::getSpreadsheet()
+{
+ return this; //!???
+}
+
+// XCellRange
+
+uno::Reference<table::XCell> SAL_CALL ScTableSheetObj::getCellByPosition(
+ sal_Int32 nColumn, sal_Int32 nRow )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::GetCellByPosition_Impl(nColumn, nRow);
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScTableSheetObj::getCellRangeByPosition(
+ sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getCellRangeByPosition(nLeft,nTop,nRight,nBottom);
+}
+
+uno::Sequence<sheet::TablePageBreakData> SAL_CALL ScTableSheetObj::getColumnPageBreaks()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ Size aSize(rDoc.GetPageSize( nTab ));
+ if (aSize.Width() && aSize.Height()) // effective size already set?
+ rDoc.UpdatePageBreaks( nTab );
+ else
+ {
+ // update breaks like in ScDocShell::PageStyleModified:
+ ScPrintFunc aPrintFunc( pDocSh, pDocSh->GetPrinter(), nTab );
+ aPrintFunc.UpdatePages();
+ }
+
+ SCCOL nCount = 0;
+ for (SCCOL nCol : rDoc.GetColumnsRange(nTab, 0, rDoc.MaxCol()))
+ if (rDoc.HasColBreak(nCol, nTab) != ScBreakType::NONE)
+ ++nCount;
+
+ sheet::TablePageBreakData aData;
+ uno::Sequence<sheet::TablePageBreakData> aSeq(nCount);
+ sheet::TablePageBreakData* pAry = aSeq.getArray();
+ sal_uInt16 nPos = 0;
+ for (SCCOL nCol : rDoc.GetColumnsRange(nTab, 0, rDoc.MaxCol()))
+ {
+ ScBreakType nBreak = rDoc.HasColBreak(nCol, nTab);
+ if (nBreak != ScBreakType::NONE)
+ {
+ aData.Position = nCol;
+ aData.ManualBreak = bool(nBreak & ScBreakType::Manual);
+ pAry[nPos] = aData;
+ ++nPos;
+ }
+ }
+ return aSeq;
+ }
+ return {};
+}
+
+uno::Sequence<sheet::TablePageBreakData> SAL_CALL ScTableSheetObj::getRowPageBreaks()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ Size aSize(rDoc.GetPageSize( nTab ));
+ if (aSize.Width() && aSize.Height()) // effective size already set?
+ rDoc.UpdatePageBreaks( nTab );
+ else
+ {
+ // update breaks like in ScDocShell::PageStyleModified:
+ ScPrintFunc aPrintFunc( pDocSh, pDocSh->GetPrinter(), nTab );
+ aPrintFunc.UpdatePages();
+ }
+ return rDoc.GetRowBreakData(nTab);
+ }
+ return {};
+}
+
+void SAL_CALL ScTableSheetObj::removeAllManualPageBreaks()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ //! DocFunc function, also for ScViewFunc::RemoveManualBreaks
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bool bUndo (rDoc.IsUndoEnabled());
+ SCTAB nTab = GetTab_Impl();
+
+ if (bUndo)
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ rDoc.CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRemoveBreaks>( pDocSh, nTab, std::move(pUndoDoc) ) );
+ }
+
+ rDoc.RemoveManualBreaks(nTab);
+ rDoc.UpdatePageBreaks(nTab);
+
+ //? UpdatePageBreakData( sal_True );
+ pDocSh->SetDocumentModified();
+ pDocSh->PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab), PaintPartFlags::Grid);
+}
+
+// XNamed
+
+OUString SAL_CALL ScTableSheetObj::getName()
+{
+ SolarMutexGuard aGuard;
+ OUString aName;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ pDocSh->GetDocument().GetName( GetTab_Impl(), aName );
+ return aName;
+}
+
+void SAL_CALL ScTableSheetObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ pDocSh->GetDocFunc().RenameTable( GetTab_Impl(), aNewName, true, true );
+ }
+}
+
+// XDrawPageSupplier
+
+uno::Reference<drawing::XDrawPage> SAL_CALL ScTableSheetObj::getDrawPage()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDrawLayer* pDrawLayer = pDocSh->MakeDrawLayer();
+ OSL_ENSURE(pDrawLayer,"Cannot create Draw-Layer");
+
+ SCTAB nTab = GetTab_Impl();
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage,"Draw-Page not found");
+ if (pPage)
+ return uno::Reference<drawing::XDrawPage> (pPage->getUnoPage(), uno::UNO_QUERY);
+
+ // The DrawPage object will register itself as a Listener at SdrModel
+ // and should receive all action from there
+ }
+ return nullptr;
+}
+
+// XCellMovement
+
+void SAL_CALL ScTableSheetObj::insertCells( const table::CellRangeAddress& rRangeAddress,
+ sheet::CellInsertMode nMode )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ bool bDo = true;
+ InsCellCmd eCmd = INS_NONE;
+ switch (nMode)
+ {
+ case sheet::CellInsertMode_NONE: bDo = false; break;
+ case sheet::CellInsertMode_DOWN: eCmd = INS_CELLSDOWN; break;
+ case sheet::CellInsertMode_RIGHT: eCmd = INS_CELLSRIGHT; break;
+ case sheet::CellInsertMode_ROWS: eCmd = INS_INSROWS_BEFORE; break;
+ case sheet::CellInsertMode_COLUMNS: eCmd = INS_INSCOLS_BEFORE; break;
+ default:
+ OSL_FAIL("insertCells: wrong mode");
+ bDo = false;
+ }
+
+ if (bDo)
+ {
+ OSL_ENSURE( rRangeAddress.Sheet == GetTab_Impl(), "wrong table in CellRangeAddress" );
+ ScRange aScRange;
+ ScUnoConversion::FillScRange( aScRange, rRangeAddress );
+ (void)pDocSh->GetDocFunc().InsertCells( aScRange, nullptr, eCmd, true, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::removeRange( const table::CellRangeAddress& rRangeAddress,
+ sheet::CellDeleteMode nMode )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ bool bDo = true;
+ DelCellCmd eCmd = DelCellCmd::NONE;
+ switch (nMode)
+ {
+ case sheet::CellDeleteMode_NONE: bDo = false; break;
+ case sheet::CellDeleteMode_UP: eCmd = DelCellCmd::CellsUp; break;
+ case sheet::CellDeleteMode_LEFT: eCmd = DelCellCmd::CellsLeft; break;
+ case sheet::CellDeleteMode_ROWS: eCmd = DelCellCmd::Rows; break;
+ case sheet::CellDeleteMode_COLUMNS: eCmd = DelCellCmd::Cols; break;
+ default:
+ OSL_FAIL("deleteCells: wrong mode");
+ bDo = false;
+ }
+
+ if (bDo)
+ {
+ OSL_ENSURE( rRangeAddress.Sheet == GetTab_Impl(), "wrong table in CellRangeAddress" );
+ ScRange aScRange;
+ ScUnoConversion::FillScRange( aScRange, rRangeAddress );
+ (void)pDocSh->GetDocFunc().DeleteCells( aScRange, nullptr, eCmd, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::moveRange( const table::CellAddress& aDestination,
+ const table::CellRangeAddress& aSource )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ OSL_ENSURE( aSource.Sheet == GetTab_Impl(), "wrong table in CellRangeAddress" );
+ ScRange aSourceRange;
+ ScUnoConversion::FillScRange( aSourceRange, aSource );
+ ScAddress aDestPos( static_cast<SCCOL>(aDestination.Column), static_cast<SCROW>(aDestination.Row), aDestination.Sheet );
+ (void)pDocSh->GetDocFunc().MoveBlock( aSourceRange, aDestPos, true, true, true, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::copyRange( const table::CellAddress& aDestination,
+ const table::CellRangeAddress& aSource )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ OSL_ENSURE( aSource.Sheet == GetTab_Impl(), "wrong table in CellRangeAddress" );
+ ScRange aSourceRange;
+ ScUnoConversion::FillScRange( aSourceRange, aSource );
+ ScAddress aDestPos( static_cast<SCCOL>(aDestination.Column), static_cast<SCROW>(aDestination.Row), aDestination.Sheet );
+ (void)pDocSh->GetDocFunc().MoveBlock( aSourceRange, aDestPos, false, true, true, true );
+ }
+}
+
+// XPrintAreas
+
+void ScTableSheetObj::PrintAreaUndo_Impl( std::unique_ptr<ScPrintRangeSaver> pOldRanges )
+{
+ // page break and undo
+ ScDocShell* pDocSh = GetDocShell();
+
+ if(!pDocSh)
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const bool bUndo(rDoc.IsUndoEnabled());
+ const SCTAB nTab(GetTab_Impl());
+
+ if(bUndo)
+ {
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoPrintRange>(
+ pDocSh,
+ nTab,
+ std::move(pOldRanges),
+ rDoc.CreatePrintRangeSaver())); // create new ranges
+ }
+
+ ScPrintFunc(pDocSh, pDocSh->GetPrinter(), nTab).UpdatePages();
+ SfxBindings* pBindings = pDocSh->GetViewBindings();
+
+ if(pBindings)
+ {
+ pBindings->Invalidate(SID_DELETE_PRINTAREA);
+ }
+
+ pDocSh->SetDocumentModified();
+}
+
+uno::Sequence<table::CellRangeAddress> SAL_CALL ScTableSheetObj::getPrintAreas()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ sal_uInt16 nCount = rDoc.GetPrintRangeCount( nTab );
+
+ table::CellRangeAddress aRangeAddress;
+ uno::Sequence<table::CellRangeAddress> aSeq(nCount);
+ table::CellRangeAddress* pAry = aSeq.getArray();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ const ScRange* pRange = rDoc.GetPrintRange( nTab, i );
+ OSL_ENSURE(pRange,"where is the printing area");
+ if (pRange)
+ {
+ ScUnoConversion::FillApiRange( aRangeAddress, *pRange );
+ aRangeAddress.Sheet = nTab; // core does not care about sheet index
+ pAry[i] = aRangeAddress;
+ }
+ }
+ return aSeq;
+ }
+ return uno::Sequence<table::CellRangeAddress>();
+}
+
+void SAL_CALL ScTableSheetObj::setPrintAreas(
+ const uno::Sequence<table::CellRangeAddress>& aPrintAreas )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges;
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ if ( rDoc.IsUndoEnabled() )
+ pOldRanges = rDoc.CreatePrintRangeSaver();
+
+ sal_uInt16 nCount = static_cast<sal_uInt16>(aPrintAreas.getLength());
+ rDoc.ClearPrintRanges( nTab );
+ if (nCount)
+ {
+ ScRange aPrintRange;
+ for (const table::CellRangeAddress& rPrintArea : aPrintAreas)
+ {
+ ScUnoConversion::FillScRange( aPrintRange, rPrintArea );
+ rDoc.AddPrintRange( nTab, aPrintRange );
+ }
+ }
+
+ if ( rDoc.IsUndoEnabled() )
+ PrintAreaUndo_Impl( std::move(pOldRanges) ); // Undo, Page Breaks, Modified etc.
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::getPrintTitleColumns()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ return rDoc.GetRepeatColRange(nTab).has_value();
+ }
+ return false;
+}
+
+void SAL_CALL ScTableSheetObj::setPrintTitleColumns( sal_Bool bPrintTitleColumns )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges = rDoc.CreatePrintRangeSaver();
+
+ if ( bPrintTitleColumns )
+ {
+ if ( !rDoc.GetRepeatColRange( nTab ) ) // do not change existing area
+ {
+ rDoc.SetRepeatColRange( nTab, ScRange( 0, 0, nTab, 0, 0, nTab ) ); // enable
+ }
+ }
+ else
+ rDoc.SetRepeatColRange( nTab, std::nullopt ); // disable
+
+ PrintAreaUndo_Impl( std::move(pOldRanges) ); // undo, page break, modified etc.
+
+ //! save last set area during switch off and recreate during switch on ???
+}
+
+table::CellRangeAddress SAL_CALL ScTableSheetObj::getTitleColumns()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ std::optional<ScRange> oRange = rDoc.GetRepeatColRange(nTab);
+ if (oRange)
+ {
+ ScUnoConversion::FillApiRange( aRet, *oRange );
+ aRet.Sheet = nTab; // core does not care about sheet index
+ }
+ }
+ return aRet;
+}
+
+void SAL_CALL ScTableSheetObj::setTitleColumns( const table::CellRangeAddress& aTitleColumns )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges = rDoc.CreatePrintRangeSaver();
+
+ ScRange aNew;
+ ScUnoConversion::FillScRange( aNew, aTitleColumns );
+ rDoc.SetRepeatColRange( nTab, std::move(aNew) ); // also always enable
+
+ PrintAreaUndo_Impl( std::move(pOldRanges) ); // undo, page breaks, modified etc.
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::getPrintTitleRows()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ return rDoc.GetRepeatRowRange(nTab).has_value();
+ }
+ return false;
+}
+
+void SAL_CALL ScTableSheetObj::setPrintTitleRows( sal_Bool bPrintTitleRows )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges = rDoc.CreatePrintRangeSaver();
+
+ if ( bPrintTitleRows )
+ {
+ if ( !rDoc.GetRepeatRowRange( nTab ) ) // do not change existing area
+ {
+ rDoc.SetRepeatRowRange( nTab, ScRange(0, 0, nTab, 0, 0, nTab) ); // enable
+ }
+ }
+ else
+ rDoc.SetRepeatRowRange( nTab, std::nullopt ); // disable
+
+ PrintAreaUndo_Impl( std::move(pOldRanges) ); // undo, page breaks, modified etc.
+
+ //! save last set area during switch off and recreate during switch on ???
+}
+
+table::CellRangeAddress SAL_CALL ScTableSheetObj::getTitleRows()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ std::optional<ScRange> oRange = rDoc.GetRepeatRowRange(nTab);
+ if (oRange)
+ {
+ ScUnoConversion::FillApiRange( aRet, *oRange );
+ aRet.Sheet = nTab; // core does not care about sheet index
+ }
+ }
+ return aRet;
+}
+
+void SAL_CALL ScTableSheetObj::setTitleRows( const table::CellRangeAddress& aTitleRows )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges = rDoc.CreatePrintRangeSaver();
+
+ ScRange aNew;
+ ScUnoConversion::FillScRange( aNew, aTitleRows );
+ rDoc.SetRepeatRowRange( nTab, std::move(aNew) ); // also always enable
+
+ PrintAreaUndo_Impl( std::move(pOldRanges) ); // Undo, page breaks, modified etc.
+}
+
+// XSheetLinkable
+
+sheet::SheetLinkMode SAL_CALL ScTableSheetObj::getLinkMode()
+{
+ SolarMutexGuard aGuard;
+ sheet::SheetLinkMode eRet = sheet::SheetLinkMode_NONE;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScLinkMode nMode = pDocSh->GetDocument().GetLinkMode( GetTab_Impl() );
+ if ( nMode == ScLinkMode::NORMAL )
+ eRet = sheet::SheetLinkMode_NORMAL;
+ else if ( nMode == ScLinkMode::VALUE )
+ eRet = sheet::SheetLinkMode_VALUE;
+ }
+ return eRet;
+}
+
+void SAL_CALL ScTableSheetObj::setLinkMode( sheet::SheetLinkMode nLinkMode )
+{
+ SolarMutexGuard aGuard;
+
+ //! search for filter and options in old link
+
+ OUString aUrl(getLinkUrl());
+ OUString aSheet(getLinkSheetName());
+
+ link( aUrl, aSheet, "", "", nLinkMode );
+}
+
+OUString SAL_CALL ScTableSheetObj::getLinkUrl()
+{
+ SolarMutexGuard aGuard;
+ OUString aFile;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ aFile = pDocSh->GetDocument().GetLinkDoc( GetTab_Impl() );
+ return aFile;
+}
+
+void SAL_CALL ScTableSheetObj::setLinkUrl( const OUString& aLinkUrl )
+{
+ SolarMutexGuard aGuard;
+
+ //! search for filter and options in old link
+
+ sheet::SheetLinkMode eMode = getLinkMode();
+ OUString aSheet(getLinkSheetName());
+
+ link( aLinkUrl, aSheet, "", "", eMode );
+}
+
+OUString SAL_CALL ScTableSheetObj::getLinkSheetName()
+{
+ SolarMutexGuard aGuard;
+ OUString aSheet;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ aSheet = pDocSh->GetDocument().GetLinkTab( GetTab_Impl() );
+ return aSheet;
+}
+
+void SAL_CALL ScTableSheetObj::setLinkSheetName( const OUString& aLinkSheetName )
+{
+ SolarMutexGuard aGuard;
+
+ //! search for filter and options in old link
+
+ sheet::SheetLinkMode eMode = getLinkMode();
+ OUString aUrl(getLinkUrl());
+
+ link( aUrl, aLinkSheetName, "", "", eMode );
+}
+
+void SAL_CALL ScTableSheetObj::link( const OUString& aUrl, const OUString& aSheetName,
+ const OUString& aFilterName, const OUString& aFilterOptions,
+ sheet::SheetLinkMode nMode )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ OUString aFileString = aUrl;
+ OUString aFilterString = aFilterName;
+ OUString aOptString = aFilterOptions;
+
+ aFileString = ScGlobal::GetAbsDocName( aFileString, pDocSh );
+ if (aFilterString.isEmpty())
+ ScDocumentLoader::GetFilterName( aFileString, aFilterString, aOptString, true, false );
+
+ // remove application prefix from filter name here, so the filter options
+ // aren't reset when the filter name is changed in ScTableLink::DataChanged
+ ScDocumentLoader::RemoveAppPrefix( aFilterString );
+
+ ScLinkMode nLinkMode = ScLinkMode::NONE;
+ if ( nMode == sheet::SheetLinkMode_NORMAL )
+ nLinkMode = ScLinkMode::NORMAL;
+ else if ( nMode == sheet::SheetLinkMode_VALUE )
+ nLinkMode = ScLinkMode::VALUE;
+
+ rDoc.SetLink( nTab, nLinkMode, aFileString, aFilterString, aOptString, aSheetName, 0/*nRefresh*/ );
+
+ pDocSh->UpdateLinks(); // if needed add or delete link
+ SfxBindings* pBindings = pDocSh->GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate(SID_LINKS);
+
+ //! undo of link data on the table
+
+ if ( !(nLinkMode != ScLinkMode::NONE && rDoc.IsExecuteLinkEnabled()) ) // update link
+ return;
+
+ // Always update link also if already exists
+ //! update only on the affected table???
+
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+ sal_uInt16 nCount = pLinkManager->GetLinks().size();
+ for ( sal_uInt16 i=0; i<nCount; i++ )
+ {
+ ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
+ if (auto pTabLink = dynamic_cast<ScTableLink*>( pBase))
+ {
+ if ( aFileString == pTabLink->GetFileName() )
+ pTabLink->Update(); // include Paint&Undo
+
+ //! The file name should only exists once (?)
+ }
+ }
+
+ //! notify ScSheetLinkObj objects!!!
+}
+
+// XSheetAuditing
+
+sal_Bool SAL_CALL ScTableSheetObj::hideDependents( const table::CellAddress& aPosition )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ OSL_ENSURE( aPosition.Sheet == nTab, "wrong table in CellAddress" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ return pDocSh->GetDocFunc().DetectiveDelSucc( aPos );
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::hidePrecedents( const table::CellAddress& aPosition )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ OSL_ENSURE( aPosition.Sheet == nTab, "wrong table in CellAddress" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ return pDocSh->GetDocFunc().DetectiveDelPred( aPos );
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::showDependents( const table::CellAddress& aPosition )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ OSL_ENSURE( aPosition.Sheet == nTab, "wrong table in CellAddress" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ return pDocSh->GetDocFunc().DetectiveAddSucc( aPos );
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::showPrecedents( const table::CellAddress& aPosition )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ OSL_ENSURE( aPosition.Sheet == nTab, "wrong table in CellAddress" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ return pDocSh->GetDocFunc().DetectiveAddPred( aPos );
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::showErrors( const table::CellAddress& aPosition )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ OSL_ENSURE( aPosition.Sheet == nTab, "wrong table in CellAddress" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ return pDocSh->GetDocFunc().DetectiveAddError( aPos );
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::showInvalid()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return pDocSh->GetDocFunc().DetectiveMarkInvalid( GetTab_Impl() );
+ return false;
+}
+
+void SAL_CALL ScTableSheetObj::clearArrows()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ pDocSh->GetDocFunc().DetectiveDelAll( GetTab_Impl() );
+}
+
+// XSheetOutline
+
+void SAL_CALL ScTableSheetObj::group( const table::CellRangeAddress& rGroupRange,
+ table::TableOrientation nOrientation )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ bool bColumns = ( nOrientation == table::TableOrientation_COLUMNS );
+ ScRange aGroupRange;
+ ScUnoConversion::FillScRange( aGroupRange, rGroupRange );
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.MakeOutline( aGroupRange, bColumns, true, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::ungroup( const table::CellRangeAddress& rGroupRange,
+ table::TableOrientation nOrientation )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ bool bColumns = ( nOrientation == table::TableOrientation_COLUMNS );
+ ScRange aGroupRange;
+ ScUnoConversion::FillScRange( aGroupRange, rGroupRange );
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.RemoveOutline( aGroupRange, bColumns, true, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::autoOutline( const table::CellRangeAddress& rCellRange )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScRange aFormulaRange;
+ ScUnoConversion::FillScRange( aFormulaRange, rCellRange );
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.AutoOutline( aFormulaRange, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::clearOutline()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.RemoveAllOutlines( nTab, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::hideDetail( const table::CellRangeAddress& rCellRange )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScRange aMarkRange;
+ ScUnoConversion::FillScRange( aMarkRange, rCellRange );
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.HideMarkedOutlines( aMarkRange, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::showDetail( const table::CellRangeAddress& rCellRange )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScRange aMarkRange;
+ ScUnoConversion::FillScRange( aMarkRange, rCellRange );
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.ShowMarkedOutlines( aMarkRange, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::showLevel( sal_Int16 nLevel, table::TableOrientation nOrientation )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ bool bColumns = ( nOrientation == table::TableOrientation_COLUMNS );
+ SCTAB nTab = GetTab_Impl();
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.SelectLevel( nTab, bColumns, nLevel, true, true );
+ }
+}
+
+// XProtectable
+
+void SAL_CALL ScTableSheetObj::protect( const OUString& aPassword )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ // #i108245# if already protected, don't change anything
+ if ( pDocSh && !pDocSh->GetDocument().IsTabProtected( GetTab_Impl() ) )
+ {
+ pDocSh->GetDocFunc().Protect( GetTab_Impl(), aPassword );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::unprotect( const OUString& aPassword )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ bool bDone = pDocSh->GetDocFunc().Unprotect( GetTab_Impl(), aPassword, true );
+ if (!bDone)
+ throw lang::IllegalArgumentException();
+ }
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::isProtected()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return pDocSh->GetDocument().IsTabProtected( GetTab_Impl() );
+
+ OSL_FAIL("no DocShell"); //! Exception or so?
+ return false;
+}
+
+// XScenario
+
+sal_Bool SAL_CALL ScTableSheetObj::getIsScenario()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return pDocSh->GetDocument().IsScenario( GetTab_Impl() );
+
+ return false;
+}
+
+OUString SAL_CALL ScTableSheetObj::getScenarioComment()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ pDocSh->GetDocument().GetScenarioData( GetTab_Impl(), aComment, aColor, nFlags );
+ return aComment;
+ }
+ return OUString();
+}
+
+void SAL_CALL ScTableSheetObj::setScenarioComment( const OUString& aScenarioComment )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+
+ aComment = aScenarioComment;
+
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+}
+
+void SAL_CALL ScTableSheetObj::addRanges( const uno::Sequence<table::CellRangeAddress>& rScenRanges )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ if (!rDoc.IsScenario(nTab))
+ return;
+
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+ aMarkData.SelectTable( nTab, true );
+
+ for (const table::CellRangeAddress& rRange : rScenRanges)
+ {
+ OSL_ENSURE( rRange.Sheet == nTab, "addRanges with wrong Tab" );
+ ScRange aOneRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), nTab,
+ static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), nTab );
+
+ aMarkData.SetMultiMarkArea( aOneRange );
+ }
+
+ // Scenario ranges are tagged with attribute
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( ScMergeFlagAttr( ScMF::Scenario ) );
+ aPattern.GetItemSet().Put( ScProtectionAttr( true ) );
+ pDocSh->GetDocFunc().ApplyAttributes( aMarkData, aPattern, true );
+}
+
+void SAL_CALL ScTableSheetObj::apply()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ OUString aName;
+ rDoc.GetName( nTab, aName ); // scenario name
+
+ SCTAB nDestTab = nTab;
+ while ( nDestTab > 0 && rDoc.IsScenario(nDestTab) )
+ --nDestTab;
+
+ if ( !rDoc.IsScenario(nDestTab) )
+ pDocSh->UseScenario( nDestTab, aName );
+
+ //! otherwise error or so
+}
+
+// XScenarioEnhanced
+
+uno::Sequence< table::CellRangeAddress > SAL_CALL ScTableSheetObj::getRanges( )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ const ScRangeList* pRangeList = rDoc.GetScenarioRanges(nTab);
+ if (pRangeList)
+ {
+ size_t nCount = pRangeList->size();
+ uno::Sequence< table::CellRangeAddress > aRetRanges( nCount );
+ table::CellRangeAddress* pAry = aRetRanges.getArray();
+ for( size_t nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ const ScRange & rRange = (*pRangeList)[nIndex];
+ pAry->StartColumn = rRange.aStart.Col();
+ pAry->StartRow = rRange.aStart.Row();
+ pAry->EndColumn = rRange.aEnd.Col();
+ pAry->EndRow = rRange.aEnd.Row();
+ pAry->Sheet = rRange.aStart.Tab();
+ ++pAry;
+ }
+ return aRetRanges;
+ }
+ }
+ return uno::Sequence< table::CellRangeAddress > ();
+}
+
+// XExternalSheetName
+
+void ScTableSheetObj::setExternalName( const OUString& aUrl, const OUString& aSheetName )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const SCTAB nTab = GetTab_Impl();
+ const OUString aAbsDocName( ScGlobal::GetAbsDocName( aUrl, pDocSh ) );
+ const OUString aDocTabName( ScGlobal::GetDocTabName( aAbsDocName, aSheetName ) );
+ if ( !rDoc.RenameTab( nTab, aDocTabName, true /*bExternalDocument*/ ) )
+ {
+ throw container::ElementExistException( OUString(), *this );
+ }
+ }
+}
+
+// XEventsSupplier
+
+uno::Reference<container::XNameReplace> SAL_CALL ScTableSheetObj::getEvents()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScSheetEventsObj( pDocSh, GetTab_Impl() );
+
+ return nullptr;
+}
+
+// XPropertySet extended for Sheet-Properties
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableSheetObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pSheetPropSet->getPropertyMap() ));
+ return aRef;
+}
+
+void ScTableSheetObj::SetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue )
+{
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ // for Item WIDs, call ScCellRangesBase directly
+ ScCellRangesBase::SetOnePropertyValue(pEntry, aValue);
+ return;
+ }
+
+ // own properties
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return; //! Exception or so?
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+
+ if ( pEntry->nWID == SC_WID_UNO_PAGESTL )
+ {
+ OUString aStrVal;
+ aValue >>= aStrVal;
+ OUString aNewStr(ScStyleNameConversion::ProgrammaticToDisplayName(
+ aStrVal, SfxStyleFamily::Page ));
+
+ //! Undo? (also if SID_STYLE_APPLY on View)
+
+ if ( rDoc.GetPageStyle( nTab ) != aNewStr )
+ {
+ rDoc.SetPageStyle( nTab, aNewStr );
+ if (!rDoc.IsImportingXML())
+ {
+ ScPrintFunc( pDocSh, pDocSh->GetPrinter(), nTab ).UpdatePages();
+
+ SfxBindings* pBindings = pDocSh->GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( SID_STYLE_FAMILY4 );
+ pBindings->Invalidate( SID_STATUS_PAGESTYLE );
+ pBindings->Invalidate( FID_RESET_PRINTZOOM );
+ pBindings->Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ pBindings->Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT );
+ }
+ }
+ pDocSh->SetDocumentModified();
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLVIS )
+ {
+ bool bVis = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ rFunc.SetTableVisible( nTab, bVis, true );
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_ISACTIVE )
+ {
+ if (rDoc.IsScenario(nTab))
+ rDoc.SetActiveScenario( nTab, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_BORDCOL )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ Color aColor;
+ if (aValue >>= aColor)
+ {
+ OUString aName;
+ OUString aComment;
+ ScScenarioFlags nFlags;
+ Color aTmp;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aTmp, nFlags );
+
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_PROTECT )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (!(nFlags & ScScenarioFlags::Protected))
+ {
+ nFlags |= ScScenarioFlags::Protected;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (nFlags & ScScenarioFlags::Protected)
+ {
+ nFlags &= ~ScScenarioFlags::Protected;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_SHOWBORD )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (!(nFlags & ScScenarioFlags::ShowFrame))
+ {
+ nFlags |= ScScenarioFlags::ShowFrame;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (nFlags & ScScenarioFlags::ShowFrame)
+ {
+ nFlags &= ~ScScenarioFlags::ShowFrame;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_PRINTBORD )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (!(nFlags & ScScenarioFlags::PrintFrame))
+ {
+ nFlags |= ScScenarioFlags::PrintFrame;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (nFlags & ScScenarioFlags::PrintFrame)
+ {
+ nFlags &= ~ScScenarioFlags::PrintFrame;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYBACK )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (!(nFlags & ScScenarioFlags::TwoWay))
+ {
+ nFlags |= ScScenarioFlags::TwoWay;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (nFlags & ScScenarioFlags::TwoWay)
+ {
+ nFlags &= ~ScScenarioFlags::TwoWay;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYSTYL )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (!(nFlags & ScScenarioFlags::Attrib))
+ {
+ nFlags |= ScScenarioFlags::Attrib;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (nFlags & ScScenarioFlags::Attrib)
+ {
+ nFlags &= ~ScScenarioFlags::Attrib;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYFORM )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (nFlags & ScScenarioFlags::Value)
+ {
+ nFlags &= ~ScScenarioFlags::Value;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (!(nFlags & ScScenarioFlags::Value))
+ {
+ nFlags |= ScScenarioFlags::Value;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_TABLAYOUT )
+ {
+ sal_Int16 nValue = 0;
+ if (aValue >>= nValue)
+ {
+ if (nValue == css::text::WritingMode2::RL_TB)
+ rFunc.SetLayoutRTL(nTab, true);
+ else
+ rFunc.SetLayoutRTL(nTab, false);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_AUTOPRINT )
+ {
+ bool bAutoPrint = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bAutoPrint)
+ rDoc.SetPrintEntireSheet( nTab ); // clears all print ranges
+ else
+ {
+ if (rDoc.IsPrintEntireSheet( nTab ))
+ rDoc.ClearPrintRanges( nTab ); // if this flag is true, there are no PrintRanges, so Clear clears only the flag.
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_TABCOLOR )
+ {
+ Color aColor = COL_AUTO;
+ if ( aValue >>= aColor )
+ {
+ if ( rDoc.GetTabBgColor( nTab ) != aColor )
+ rFunc.SetTabBgColor( nTab, aColor, true, true );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CODENAME )
+ {
+ OUString aCodeName;
+ if (aValue >>= aCodeName)
+ {
+ pDocSh->GetDocument().SetCodeName( GetTab_Impl(), aCodeName );
+ }
+ }
+ else if (pEntry->nWID == SC_WID_UNO_CONDFORMAT)
+ {
+ uno::Reference<sheet::XConditionalFormats> xCondFormat;
+ if (aValue >>= xCondFormat)
+ {
+ // how to set the format correctly
+ }
+ }
+ else
+ ScCellRangeObj::SetOnePropertyValue(pEntry, aValue); // base class, no Item WID
+}
+
+void ScTableSheetObj::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry,
+ uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ throw uno::RuntimeException();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ if ( pEntry->nWID == SC_WID_UNO_NAMES )
+ {
+ rAny <<= uno::Reference<sheet::XNamedRanges>(new ScLocalNamedRangesObj(pDocSh, this));
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_PAGESTL )
+ {
+ rAny <<= ScStyleNameConversion::DisplayToProgrammaticName(
+ rDoc.GetPageStyle( nTab ), SfxStyleFamily::Page );
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLVIS )
+ {
+ bool bVis = rDoc.IsVisible( nTab );
+ rAny <<= bVis;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_LINKDISPBIT )
+ {
+ // no target bitmaps for individual entries (would be all equal)
+ // ScLinkTargetTypeObj::SetLinkTargetBitmap( aAny, SC_LINKTARGETTYPE_SHEET );
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_LINKDISPNAME )
+ {
+ // LinkDisplayName for hyperlink dialog
+ rAny <<= getName(); // sheet name
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_ISACTIVE )
+ {
+ if (rDoc.IsScenario(nTab))
+ rAny <<= rDoc.IsActiveScenario( nTab );
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_BORDCOL )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+
+ rAny <<= aColor;
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_PROTECT )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= ((nFlags & ScScenarioFlags::Protected) != ScScenarioFlags::NONE);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_SHOWBORD )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= ((nFlags & ScScenarioFlags::ShowFrame) != ScScenarioFlags::NONE);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_PRINTBORD )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= ((nFlags & ScScenarioFlags::PrintFrame) != ScScenarioFlags::NONE);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYBACK )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= ((nFlags & ScScenarioFlags::TwoWay) != ScScenarioFlags::NONE);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYSTYL )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= ((nFlags & ScScenarioFlags::Attrib) != ScScenarioFlags::NONE);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYFORM )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= !(nFlags & ScScenarioFlags::Value);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_TABLAYOUT )
+ {
+ if (rDoc.IsLayoutRTL(nTab))
+ rAny <<= sal_Int16(css::text::WritingMode2::RL_TB);
+ else
+ rAny <<= sal_Int16(css::text::WritingMode2::LR_TB);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_AUTOPRINT )
+ {
+ bool bAutoPrint = rDoc.IsPrintEntireSheet( nTab );
+ rAny <<= bAutoPrint;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_TABCOLOR )
+ {
+ rAny <<= rDoc.GetTabBgColor(nTab);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CODENAME )
+ {
+ OUString aCodeName;
+ pDocSh->GetDocument().GetCodeName(GetTab_Impl(), aCodeName);
+ rAny <<= aCodeName;
+ }
+ else if (pEntry->nWID == SC_WID_UNO_CONDFORMAT)
+ {
+ rAny <<= uno::Reference<sheet::XConditionalFormats>(new ScCondFormatsObj(pDocSh, nTab));
+ }
+ else
+ ScCellRangeObj::GetOnePropertyValue(pEntry, rAny);
+}
+
+const SfxItemPropertyMap& ScTableSheetObj::GetItemPropertyMap()
+{
+ return pSheetPropSet->getPropertyMap();
+}
+
+// XServiceInfo
+
+OUString SAL_CALL ScTableSheetObj::getImplementationName()
+{
+ return "ScTableSheetObj";
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScTableSheetObj::getSupportedServiceNames()
+{
+ return {SCSPREADSHEET_SERVICE,
+ SCSHEETCELLRANGE_SERVICE,
+ SCCELLRANGE_SERVICE,
+ SCCELLPROPERTIES_SERVICE,
+ SCCHARPROPERTIES_SERVICE,
+ SCPARAPROPERTIES_SERVICE,
+ SCLINKTARGET_SERVICE};
+}
+
+ScTableColumnObj::ScTableColumnObj( ScDocShell* pDocSh, SCCOL nCol, SCTAB nTab ) :
+ ScCellRangeObj( pDocSh, ScRange(nCol,0,nTab, nCol, pDocSh->GetDocument().MaxRow(),nTab) ),
+ pColPropSet(lcl_GetColumnPropertySet())
+{
+}
+
+ScTableColumnObj::~ScTableColumnObj()
+{
+}
+
+uno::Any SAL_CALL ScTableColumnObj::queryInterface( const uno::Type& rType )
+{
+ uno::Any aReturn = ::cppu::queryInterface(rType,
+ static_cast<container::XNamed*>(this));
+ if ( aReturn.hasValue() )
+ return aReturn;
+
+ return ScCellRangeObj::queryInterface( rType );
+}
+
+void SAL_CALL ScTableColumnObj::acquire() noexcept
+{
+ ScCellRangeObj::acquire();
+}
+
+void SAL_CALL ScTableColumnObj::release() noexcept
+{
+ ScCellRangeObj::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScTableColumnObj::getTypes()
+{
+ return comphelper::concatSequences(
+ ScCellRangeObj::getTypes(),
+ uno::Sequence<uno::Type> { cppu::UnoType<container::XNamed>::get() } );
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScTableColumnObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XNamed
+
+OUString SAL_CALL ScTableColumnObj::getName()
+{
+ SolarMutexGuard aGuard;
+
+ const ScRange& rRange = GetRange();
+ OSL_ENSURE(rRange.aStart.Col() == rRange.aEnd.Col(), "too many columns");
+ SCCOL nCol = rRange.aStart.Col();
+
+ return ScColToAlpha( nCol ); // from global.hxx
+}
+
+void SAL_CALL ScTableColumnObj::setName( const OUString& /* aNewName */ )
+{
+ throw uno::RuntimeException(); // read-only
+}
+
+// XPropertySet extended for Column-Properties
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableColumnObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pColPropSet->getPropertyMap() ));
+ return aRef;
+}
+
+void ScTableColumnObj::SetOnePropertyValue(const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue)
+{
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ // for Item WIDs, call ScCellRangesBase directly
+ ScCellRangesBase::SetOnePropertyValue(pEntry, aValue);
+ return;
+ }
+
+ // own properties
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return; //! Exception or so?
+ const ScRange& rRange = GetRange();
+ OSL_ENSURE(rRange.aStart.Col() == rRange.aEnd.Col(), "Too many columns");
+ SCCOL nCol = rRange.aStart.Col();
+ SCTAB nTab = rRange.aStart.Tab();
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+
+ std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(nCol,nCol));
+
+ if ( pEntry->nWID == SC_WID_UNO_CELLWID )
+ {
+ sal_Int32 nNewWidth = 0;
+ if ( aValue >>= nNewWidth )
+ {
+ // property is 1/100mm, column width is twips
+ nNewWidth = o3tl::toTwips(nNewWidth, o3tl::Length::mm100);
+ rFunc.SetWidthOrHeight(
+ true, aColArr, nTab, SC_SIZE_ORIGINAL, nNewWidth, true, true);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_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 will hide
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_OWIDTH )
+ {
+ bool bOpt = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bOpt)
+ rFunc.SetWidthOrHeight(
+ true, aColArr, nTab, SC_SIZE_OPTIMAL, STD_EXTRA_WIDTH, true, true);
+ // sal_False on columns currently without effect
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_NEWPAGE || pEntry->nWID == SC_WID_UNO_MANPAGE )
+ {
+ bool bSet = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bSet)
+ rFunc.InsertPageBreak( true, rRange.aStart, true, true );
+ else
+ rFunc.RemovePageBreak( true, rRange.aStart, true, true );
+ }
+ else
+ ScCellRangeObj::SetOnePropertyValue(pEntry, aValue); // base class, no Item WID
+}
+
+void ScTableColumnObj::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const ScRange& rRange = GetRange();
+ OSL_ENSURE(rRange.aStart.Col() == rRange.aEnd.Col(), "too many columns");
+ SCCOL nCol = rRange.aStart.Col();
+ SCTAB nTab = rRange.aStart.Tab();
+
+ if ( pEntry->nWID == SC_WID_UNO_CELLWID )
+ {
+ // for hidden column, return original height
+ sal_uInt16 nWidth = rDoc.GetOriginalWidth( nCol, nTab );
+ // property is 1/100mm, column width is twips
+ nWidth = static_cast<sal_uInt16>(convertTwipToMm100(nWidth));
+ rAny <<= static_cast<sal_Int32>(nWidth);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLVIS )
+ {
+ bool bHidden = rDoc.ColHidden(nCol, nTab);
+ rAny <<= !bHidden;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_OWIDTH )
+ {
+ //! at the moment always set ??!?!
+ bool bOpt = !(rDoc.GetColFlags( nCol, nTab ) & CRFlags::ManualSize);
+ rAny <<= bOpt;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_NEWPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasColBreak(nCol, nTab);
+ rAny <<= nBreak != ScBreakType::NONE;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_MANPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasColBreak(nCol, nTab);
+ rAny <<= bool(nBreak & ScBreakType::Manual);
+ }
+ else
+ ScCellRangeObj::GetOnePropertyValue(pEntry, rAny);
+}
+
+const SfxItemPropertyMap& ScTableColumnObj::GetItemPropertyMap()
+{
+ return pColPropSet->getPropertyMap();
+}
+
+ScTableRowObj::ScTableRowObj(ScDocShell* pDocSh, SCROW nRow, SCTAB nTab) :
+ ScCellRangeObj( pDocSh, ScRange(0,nRow,nTab, pDocSh->GetDocument().MaxCol(),nRow,nTab) ),
+ pRowPropSet(lcl_GetRowPropertySet())
+{
+}
+
+ScTableRowObj::~ScTableRowObj()
+{
+}
+
+// XPropertySet extended for Row-Properties
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableRowObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pRowPropSet->getPropertyMap() ));
+ return aRef;
+}
+
+void ScTableRowObj::SetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue )
+{
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ // for Item WIDs, call ScCellRangesBase directly
+ ScCellRangesBase::SetOnePropertyValue(pEntry, aValue);
+ return;
+ }
+
+ // own properties
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return; //! Exception or so?
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const ScRange& rRange = GetRange();
+ OSL_ENSURE(rRange.aStart.Row() == rRange.aEnd.Row(), "too many rows");
+ SCROW nRow = rRange.aStart.Row();
+ SCTAB nTab = rRange.aStart.Tab();
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+
+ std::vector<sc::ColRowSpan> aRowArr(1, sc::ColRowSpan(nRow,nRow));
+
+ if ( pEntry->nWID == SC_WID_UNO_CELLHGT )
+ {
+ sal_Int32 nNewHeight = 0;
+ if ( aValue >>= nNewHeight )
+ {
+ // property is 1/100mm, row height is twips
+ nNewHeight = o3tl::toTwips(nNewHeight, o3tl::Length::mm100);
+ rFunc.SetWidthOrHeight(
+ false, aRowArr, nTab, SC_SIZE_ORIGINAL, nNewHeight, true, true);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_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 zero will hide
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLFILT )
+ {
+ bool bFil = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ // SC_SIZE_DIRECT with size zero will hide
+ rDoc.SetRowFiltered(nRow, nRow, nTab, bFil);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_OHEIGHT )
+ {
+ bool bOpt = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bOpt)
+ rFunc.SetWidthOrHeight(false, aRowArr, nTab, SC_SIZE_OPTIMAL, 0, true, true);
+ else
+ {
+ // set current height again manually
+ sal_uInt16 nHeight = rDoc.GetOriginalHeight( nRow, nTab );
+ rFunc.SetWidthOrHeight(false, aRowArr, nTab, SC_SIZE_ORIGINAL, nHeight, true, true);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_NEWPAGE || pEntry->nWID == SC_WID_UNO_MANPAGE )
+ {
+ bool bSet = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bSet)
+ rFunc.InsertPageBreak( false, rRange.aStart, true, true );
+ else
+ rFunc.RemovePageBreak( false, rRange.aStart, true, true );
+ }
+ else
+ ScCellRangeObj::SetOnePropertyValue(pEntry, aValue); // base class, no Item WID
+}
+
+void ScTableRowObj::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ throw uno::RuntimeException();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const ScRange& rRange = GetRange();
+ OSL_ENSURE(rRange.aStart.Row() == rRange.aEnd.Row(), "too many rows");
+ SCROW nRow = rRange.aStart.Row();
+ SCTAB nTab = rRange.aStart.Tab();
+
+ if ( pEntry->nWID == SC_WID_UNO_CELLHGT )
+ {
+ // for hidden row, return original height
+ sal_uInt16 nHeight = rDoc.GetOriginalHeight( nRow, nTab );
+ // property is 1/100mm, row height is twips
+ nHeight = static_cast<sal_uInt16>(convertTwipToMm100(nHeight));
+ rAny <<= static_cast<sal_Int32>(nHeight);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLVIS )
+ {
+ bool bHidden = rDoc.RowHidden(nRow, nTab);
+ rAny <<= !bHidden;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLFILT )
+ {
+ bool bVis = rDoc.RowFiltered(nRow, nTab);
+ rAny <<= bVis;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_OHEIGHT )
+ {
+ bool bOpt = !(rDoc.GetRowFlags( nRow, nTab ) & CRFlags::ManualSize);
+ rAny <<= bOpt;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_NEWPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasRowBreak(nRow, nTab);
+ rAny <<= (nBreak != ScBreakType::NONE);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_MANPAGE )
+ {
+ bool bBreak(rDoc.HasRowBreak(nRow, nTab) & ScBreakType::Manual);
+ rAny <<= bBreak;
+ }
+ else
+ ScCellRangeObj::GetOnePropertyValue(pEntry, rAny);
+}
+
+const SfxItemPropertyMap& ScTableRowObj::GetItemPropertyMap()
+{
+ return pRowPropSet->getPropertyMap();
+}
+
+ScCellsObj::ScCellsObj(ScDocShell* pDocSh, ScRangeList aR) :
+ pDocShell( pDocSh ),
+ aRanges(std::move( aR ))
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScCellsObj::~ScCellsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScCellsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( auto pRefHint = dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ aRanges.UpdateReference( pRefHint->GetMode(), &pDocShell->GetDocument(), pRefHint->GetRange(),
+ pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() );
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScCellsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScCellsEnumeration( pDocShell, aRanges );
+ return nullptr;
+}
+
+uno::Type SAL_CALL ScCellsObj::getElementType()
+{
+ return cppu::UnoType<table::XCell>::get();
+}
+
+sal_Bool SAL_CALL ScCellsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ bool bHas = false;
+ if ( pDocShell )
+ {
+ //! faster if test ourself?
+
+ uno::Reference<container::XEnumeration> xEnum(new ScCellsEnumeration( pDocShell, aRanges ));
+ bHas = xEnum->hasMoreElements();
+ }
+ return bHas;
+}
+
+ScCellsEnumeration::ScCellsEnumeration(ScDocShell* pDocSh, ScRangeList aR) :
+ pDocShell( pDocSh ),
+ aRanges(std::move( aR )),
+ bAtEnd( false )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.AddUnoObject(*this);
+
+ if ( aRanges.empty() )
+ bAtEnd = true;
+ else
+ {
+ SCTAB nTab = aRanges[ 0 ].aStart.Tab();
+ aPos = ScAddress(0,0,nTab);
+ CheckPos_Impl(); // set aPos on first matching cell
+ }
+}
+
+void ScCellsEnumeration::CheckPos_Impl()
+{
+ if (!pDocShell)
+ return;
+
+ bool bFound = false;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRefCellValue aCell(rDoc, aPos);
+ if (!aCell.isEmpty())
+ {
+ if (!pMark)
+ {
+ pMark.reset( new ScMarkData(rDoc.GetSheetLimits()) );
+ pMark->MarkFromRangeList(aRanges, false);
+ pMark->MarkToMulti(); // needed for GetNextMarkedCell
+ }
+ bFound = pMark->IsCellMarked(aPos.Col(), aPos.Row());
+ }
+ if (!bFound)
+ Advance_Impl();
+}
+
+ScCellsEnumeration::~ScCellsEnumeration()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+ pMark.reset();
+}
+
+void ScCellsEnumeration::Advance_Impl()
+{
+ OSL_ENSURE(!bAtEnd,"too much Advance_Impl");
+ if (!pMark)
+ {
+ pMark.reset( new ScMarkData(pDocShell->GetDocument().GetSheetLimits()) );
+ pMark->MarkFromRangeList( aRanges, false );
+ pMark->MarkToMulti(); // needed for GetNextMarkedCell
+ }
+
+ SCCOL nCol = aPos.Col();
+ SCROW nRow = aPos.Row();
+ SCTAB nTab = aPos.Tab();
+ bool bFound = pDocShell->GetDocument().GetNextMarkedCell( nCol, nRow, nTab, *pMark );
+ if (bFound)
+ aPos.Set( nCol, nRow, nTab );
+ else
+ bAtEnd = true; // nothing will follow
+}
+
+void ScCellsEnumeration::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const ScUpdateRefHint* pRefHint = dynamic_cast<const ScUpdateRefHint*>(&rHint);
+ if ( pRefHint )
+ {
+ if (pDocShell)
+ {
+ aRanges.UpdateReference( pRefHint->GetMode(), &pDocShell->GetDocument(), pRefHint->GetRange(),
+ pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() );
+
+ pMark.reset(); // recreate from moved area
+
+ if (!bAtEnd) // adjust aPos
+ {
+ ScRangeList aNew { ScRange(aPos) };
+ aNew.UpdateReference( pRefHint->GetMode(), &pDocShell->GetDocument(), pRefHint->GetRange(),
+ pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() );
+ if (aNew.size()==1)
+ {
+ aPos = aNew[ 0 ].aStart;
+ CheckPos_Impl();
+ }
+ }
+ }
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XEnumeration
+
+sal_Bool SAL_CALL ScCellsEnumeration::hasMoreElements()
+{
+ SolarMutexGuard aGuard;
+ return !bAtEnd;
+}
+
+uno::Any SAL_CALL ScCellsEnumeration::nextElement()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell && !bAtEnd)
+ {
+ // interface must match ScCellsObj::getElementType
+
+ ScAddress aTempPos(aPos);
+ Advance_Impl();
+ return uno::Any(uno::Reference<table::XCell>(new ScCellObj( pDocShell, aTempPos )));
+ }
+
+ throw container::NoSuchElementException(); // no more elements
+}
+
+ScCellFormatsObj::ScCellFormatsObj(ScDocShell* pDocSh, const ScRange& rRange) :
+ pDocShell( pDocSh ),
+ aTotalRange( rRange )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.AddUnoObject(*this);
+
+ OSL_ENSURE( aTotalRange.aStart.Tab() == aTotalRange.aEnd.Tab(), "different tables" );
+}
+
+ScCellFormatsObj::~ScCellFormatsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScCellFormatsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! aTotalRange...
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+rtl::Reference<ScCellRangeObj> ScCellFormatsObj::GetObjectByIndex_Impl(tools::Long nIndex) const
+{
+ //! access the AttrArrays directly !!!!
+
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ tools::Long nPos = 0;
+ ScAttrRectIterator aIter( rDoc, aTotalRange.aStart.Tab(),
+ aTotalRange.aStart.Col(), aTotalRange.aStart.Row(),
+ aTotalRange.aEnd.Col(), aTotalRange.aEnd.Row() );
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ while ( aIter.GetNext( nCol1, nCol2, nRow1, nRow2 ) )
+ {
+ if ( nPos == nIndex )
+ {
+ SCTAB nTab = aTotalRange.aStart.Tab();
+ ScRange aNext( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
+
+ if ( aNext.aStart == aNext.aEnd )
+ return new ScCellObj( pDocShell, aNext.aStart );
+ else
+ return new ScCellRangeObj( pDocShell, aNext );
+ }
+ ++nPos;
+ }
+ }
+ return {};
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScCellFormatsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ //! access the AttrArrays directly !!!!
+
+ tools::Long nCount = 0;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScAttrRectIterator aIter( rDoc, aTotalRange.aStart.Tab(),
+ aTotalRange.aStart.Col(), aTotalRange.aStart.Row(),
+ aTotalRange.aEnd.Col(), aTotalRange.aEnd.Row() );
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ while ( aIter.GetNext( nCol1, nCol2, nRow1, nRow2 ) )
+ ++nCount;
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL ScCellFormatsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<table::XCellRange> xRange(GetObjectByIndex_Impl(nIndex));
+ if (!xRange.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRange);
+
+}
+
+uno::Type SAL_CALL ScCellFormatsObj::getElementType()
+{
+ return cppu::UnoType<table::XCellRange>::get();
+}
+
+sal_Bool SAL_CALL ScCellFormatsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 ); //! always greater then zero ??
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScCellFormatsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScCellFormatsEnumeration( pDocShell, aTotalRange );
+ return nullptr;
+}
+
+ScCellFormatsEnumeration::ScCellFormatsEnumeration(ScDocShell* pDocSh, const ScRange& rRange) :
+ pDocShell( pDocSh ),
+ nTab( rRange.aStart.Tab() ),
+ bAtEnd( false ),
+ bDirty( false )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.AddUnoObject(*this);
+
+ OSL_ENSURE( rRange.aStart.Tab() == rRange.aEnd.Tab(),
+ "CellFormatsEnumeration: different tables" );
+
+ pIter.reset( new ScAttrRectIterator( rDoc, nTab,
+ rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row() ) );
+ Advance_Impl();
+}
+
+ScCellFormatsEnumeration::~ScCellFormatsEnumeration()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScCellFormatsEnumeration::Advance_Impl()
+{
+ OSL_ENSURE(!bAtEnd,"too many Advance_Impl");
+
+ if ( pIter )
+ {
+ if ( bDirty )
+ {
+ pIter->DataChanged(); // new search for AttrArray-Index
+ bDirty = false;
+ }
+
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ if ( pIter->GetNext( nCol1, nCol2, nRow1, nRow2 ) )
+ aNext = ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
+ else
+ bAtEnd = true;
+ }
+ else
+ bAtEnd = true; // document vanished or so
+}
+
+rtl::Reference<ScCellRangeObj> ScCellFormatsEnumeration::NextObject_Impl()
+{
+ rtl::Reference<ScCellRangeObj> pRet;
+ if (pDocShell && !bAtEnd)
+ {
+ if ( aNext.aStart == aNext.aEnd )
+ pRet = new ScCellObj( pDocShell, aNext.aStart );
+ else
+ pRet = new ScCellRangeObj( pDocShell, aNext );
+ Advance_Impl();
+ }
+ return pRet;
+}
+
+void ScCellFormatsEnumeration::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! and now???
+ }
+ else
+ {
+ const SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ pIter.reset();
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ bDirty = true; // AttrArray-Index possibly invalid
+ }
+ }
+}
+
+// XEnumeration
+
+sal_Bool SAL_CALL ScCellFormatsEnumeration::hasMoreElements()
+{
+ SolarMutexGuard aGuard;
+ return !bAtEnd;
+}
+
+uno::Any SAL_CALL ScCellFormatsEnumeration::nextElement()
+{
+ SolarMutexGuard aGuard;
+
+ if ( bAtEnd || !pDocShell )
+ throw container::NoSuchElementException(); // no more elements
+
+ // interface must match ScCellFormatsObj::getElementType
+
+ return uno::Any(uno::Reference<table::XCellRange> (NextObject_Impl()));
+}
+
+ScUniqueCellFormatsObj::~ScUniqueCellFormatsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScUniqueCellFormatsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! aTotalRange...
+ }
+ else
+ {
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr;
+ }
+}
+
+// Fill the list of formats from the document
+
+namespace {
+
+// hash code to access the range lists by ScPatternAttr pointer
+struct ScPatternHashCode
+{
+ size_t operator()( const ScPatternAttr* pPattern ) const
+ {
+ return reinterpret_cast<size_t>(pPattern);
+ }
+};
+
+}
+
+// Hash map to find a range by its start row
+typedef std::unordered_map< SCROW, ScRange > ScRowRangeHashMap;
+
+namespace {
+
+// Hash map entry.
+// The Join method depends on the column-wise order of ScAttrRectIterator
+class ScUniqueFormatsEntry
+{
+ enum EntryState { STATE_EMPTY, STATE_SINGLE, STATE_COMPLEX };
+
+ EntryState eState;
+ ScRange aSingleRange;
+ ScRowRangeHashMap aJoinedRanges; // "active" ranges to be merged
+ std::vector<ScRange> aCompletedRanges; // ranges that will no longer be touched
+ ScRangeListRef aReturnRanges; // result as ScRangeList for further use
+
+public:
+ ScUniqueFormatsEntry() : eState( STATE_EMPTY ) {}
+
+ void Join( const ScRange& rNewRange );
+ const ScRangeList& GetRanges();
+ void Clear() { aReturnRanges.clear(); } // aJoinedRanges and aCompletedRanges are cleared in GetRanges
+};
+
+}
+
+void ScUniqueFormatsEntry::Join( const ScRange& rNewRange )
+{
+ // Special-case handling for single range
+
+ if ( eState == STATE_EMPTY )
+ {
+ aSingleRange = rNewRange;
+ eState = STATE_SINGLE;
+ return;
+ }
+ if ( eState == STATE_SINGLE )
+ {
+ if ( aSingleRange.aStart.Row() == rNewRange.aStart.Row() &&
+ aSingleRange.aEnd.Row() == rNewRange.aEnd.Row() &&
+ aSingleRange.aEnd.Col() + 1 == rNewRange.aStart.Col() )
+ {
+ aSingleRange.aEnd.SetCol( rNewRange.aEnd.Col() );
+ return; // still a single range
+ }
+
+ SCROW nSingleRow = aSingleRange.aStart.Row();
+ aJoinedRanges.emplace( nSingleRow, aSingleRange );
+ eState = STATE_COMPLEX;
+ // continue normally
+ }
+
+ // This is called in the order of ScAttrRectIterator results.
+ // rNewRange can only be joined with an existing entry if it's the same rows, starting in the next column.
+ // If the old entry for the start row extends to a different end row, or ends in a different column, it
+ // can be moved to aCompletedRanges because it can't be joined with following iterator results.
+ // Everything happens within one sheet, so Tab can be ignored.
+
+ SCROW nStartRow = rNewRange.aStart.Row();
+ ScRowRangeHashMap::iterator aIter( aJoinedRanges.find( nStartRow ) ); // find the active entry for the start row
+ if ( aIter != aJoinedRanges.end() )
+ {
+ ScRange& rOldRange = aIter->second;
+ if ( rOldRange.aEnd.Row() == rNewRange.aEnd.Row() &&
+ rOldRange.aEnd.Col() + 1 == rNewRange.aStart.Col() )
+ {
+ // extend existing range
+ rOldRange.aEnd.SetCol( rNewRange.aEnd.Col() );
+ }
+ else
+ {
+ // move old range to aCompletedRanges, keep rNewRange for joining
+ aCompletedRanges.push_back( rOldRange );
+ rOldRange = rNewRange; // replace in hash map
+ }
+ }
+ else
+ {
+ // keep rNewRange for joining
+ aJoinedRanges.emplace( nStartRow, rNewRange );
+ }
+}
+
+const ScRangeList& ScUniqueFormatsEntry::GetRanges()
+{
+ if ( eState == STATE_SINGLE )
+ {
+ aReturnRanges = new ScRangeList( aSingleRange );
+ return *aReturnRanges;
+ }
+
+ // move remaining entries from aJoinedRanges to aCompletedRanges
+
+ for ( const auto& rEntry : aJoinedRanges )
+ aCompletedRanges.push_back( rEntry.second );
+ aJoinedRanges.clear();
+
+ // sort all ranges for a predictable API result
+
+ std::sort( aCompletedRanges.begin(), aCompletedRanges.end() );
+
+ // fill and return ScRangeList
+
+ aReturnRanges = new ScRangeList;
+ aReturnRanges->insert( aReturnRanges->end(), aCompletedRanges.begin(), aCompletedRanges.end() );
+ aCompletedRanges.clear();
+
+ return *aReturnRanges;
+}
+
+namespace {
+
+// function object to sort the range lists by start of first range
+struct ScUniqueFormatsOrder
+{
+ bool operator()( const ScRangeList& rList1, const ScRangeList& rList2 ) const
+ {
+ // all range lists have at least one entry
+ OSL_ENSURE( !rList1.empty() && !rList2.empty(), "ScUniqueFormatsOrder: empty list" );
+
+ // compare start positions using ScAddress comparison operator
+ return ( rList1[ 0 ].aStart < rList2[ 0 ].aStart );
+ }
+};
+
+}
+
+ScUniqueCellFormatsObj::ScUniqueCellFormatsObj(ScDocShell* pDocSh, const ScRange& rTotalRange) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ OSL_ENSURE( rTotalRange.aStart.Tab() == rTotalRange.aEnd.Tab(), "different tables" );
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab = rTotalRange.aStart.Tab();
+ ScAttrRectIterator aIter( rDoc, nTab,
+ rTotalRange.aStart.Col(), rTotalRange.aStart.Row(),
+ rTotalRange.aEnd.Col(), rTotalRange.aEnd.Row() );
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+
+ // Collect the ranges for each format in a hash map, to avoid nested loops
+
+ std::unordered_map< const ScPatternAttr*, ScUniqueFormatsEntry, ScPatternHashCode > aHashMap;
+ while (aIter.GetNext( nCol1, nCol2, nRow1, nRow2 ) )
+ {
+ ScRange aRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
+ const ScPatternAttr* pPattern = rDoc.GetPattern(nCol1, nRow1, nTab);
+ aHashMap[pPattern].Join( aRange );
+ }
+
+ // Fill the vector aRangeLists with the range lists from the hash map
+
+ aRangeLists.reserve( aHashMap.size() );
+ for ( auto& rMapEntry : aHashMap )
+ {
+ ScUniqueFormatsEntry& rEntry = rMapEntry.second;
+ const ScRangeList& rRanges = rEntry.GetRanges();
+ aRangeLists.push_back( rRanges ); // copy ScRangeList
+ rEntry.Clear(); // free memory, don't hold both copies of all ranges
+ }
+
+ // Sort the vector by first range's start position, to avoid random shuffling
+ // due to using the ScPatterAttr pointers
+
+ ::std::sort( aRangeLists.begin(), aRangeLists.end(), ScUniqueFormatsOrder() );
+}
+
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScUniqueCellFormatsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ return aRangeLists.size();
+}
+
+uno::Any SAL_CALL ScUniqueCellFormatsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+
+ if(o3tl::make_unsigned(nIndex) >= aRangeLists.size())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(uno::Reference<sheet::XSheetCellRangeContainer>(new ScCellRangesObj(pDocShell, aRangeLists[nIndex])));
+
+}
+
+uno::Type SAL_CALL ScUniqueCellFormatsObj::getElementType()
+{
+ return cppu::UnoType<sheet::XSheetCellRangeContainer>::get();
+}
+
+sal_Bool SAL_CALL ScUniqueCellFormatsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( !aRangeLists.empty() );
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScUniqueCellFormatsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScUniqueCellFormatsEnumeration( pDocShell, std::vector(aRangeLists) );
+ return nullptr;
+}
+
+ScUniqueCellFormatsEnumeration::ScUniqueCellFormatsEnumeration(ScDocShell* pDocSh, std::vector<ScRangeList>&& rRangeLists) :
+ aRangeLists(std::move(rRangeLists)),
+ pDocShell( pDocSh ),
+ nCurrentPosition(0)
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScUniqueCellFormatsEnumeration::~ScUniqueCellFormatsEnumeration()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScUniqueCellFormatsEnumeration::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! and now ???
+ }
+ else
+ {
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr;
+ }
+}
+
+// XEnumeration
+
+sal_Bool SAL_CALL ScUniqueCellFormatsEnumeration::hasMoreElements()
+{
+ SolarMutexGuard aGuard;
+ return o3tl::make_unsigned(nCurrentPosition) < aRangeLists.size();
+}
+
+uno::Any SAL_CALL ScUniqueCellFormatsEnumeration::nextElement()
+{
+ SolarMutexGuard aGuard;
+
+ if ( !hasMoreElements() || !pDocShell )
+ throw container::NoSuchElementException(); // no more elements
+
+ // interface type must match ScCellFormatsObj::getElementType
+
+ return uno::Any(uno::Reference<sheet::XSheetCellRangeContainer>(new ScCellRangesObj(pDocShell, aRangeLists[nCurrentPosition++])));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/cellvaluebinding.cxx b/sc/source/ui/unoobj/cellvaluebinding.cxx
new file mode 100644
index 0000000000..fd8b43f957
--- /dev/null
+++ b/sc/source/ui/unoobj/cellvaluebinding.cxx
@@ -0,0 +1,576 @@
+/* -*- 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 "cellvaluebinding.hxx"
+#include <rtl/math.hxx>
+#include <com/sun/star/form/binding/IncompatibleTypesException.hpp>
+#include <com/sun/star/lang/NotInitializedException.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/sheet/FormulaResult.hpp>
+#include <com/sun/star/sheet/XCellAddressable.hpp>
+#include <com/sun/star/sheet/XCellRangeData.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+namespace calc
+{
+
+#define PROP_HANDLE_BOUND_CELL 1
+
+ namespace lang = ::com::sun::star::lang;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::table;
+ using namespace ::com::sun::star::text;
+ using namespace ::com::sun::star::sheet;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::form::binding;
+
+ OCellValueBinding::OCellValueBinding( const Reference< XSpreadsheetDocument >& _rxDocument, bool _bListPos )
+ :OCellValueBinding_Base( m_aMutex )
+ ,OCellValueBinding_PBase( OCellValueBinding_Base::rBHelper )
+ ,m_xDocument( _rxDocument )
+ ,m_aModifyListeners( m_aMutex )
+ ,m_bInitialized( false )
+ ,m_bListPos( _bListPos )
+ {
+ // register our property at the base class
+ registerPropertyNoMember(
+ "BoundCell",
+ PROP_HANDLE_BOUND_CELL,
+ PropertyAttribute::BOUND | PropertyAttribute::READONLY,
+ cppu::UnoType<CellAddress>::get(),
+ css::uno::Any(CellAddress())
+ );
+
+ // TODO: implement a ReadOnly property as required by the service,
+ // which probably maps to the cell being locked
+ }
+
+ OCellValueBinding::~OCellValueBinding( )
+ {
+ if ( !OCellValueBinding_Base::rBHelper.bDisposed )
+ {
+ acquire(); // prevent duplicate dtor
+ dispose();
+ }
+ }
+
+ IMPLEMENT_FORWARD_XINTERFACE2( OCellValueBinding, OCellValueBinding_Base, OCellValueBinding_PBase )
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCellValueBinding, OCellValueBinding_Base, OCellValueBinding_PBase )
+
+ void SAL_CALL OCellValueBinding::disposing()
+ {
+ Reference<XModifyBroadcaster> xBroadcaster( m_xCell, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->removeModifyListener( this );
+ }
+
+ WeakComponentImplHelperBase::disposing();
+
+ // TODO: clean up here whatever you need to clean up (e.g. deregister as XEventListener
+ // for the cell)
+ }
+
+ Reference< XPropertySetInfo > SAL_CALL OCellValueBinding::getPropertySetInfo( )
+ {
+ return createPropertySetInfo( getInfoHelper() ) ;
+ }
+
+ ::cppu::IPropertyArrayHelper& SAL_CALL OCellValueBinding::getInfoHelper()
+ {
+ return *OCellValueBinding_PABase::getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* OCellValueBinding::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper(aProps);
+ }
+
+ void SAL_CALL OCellValueBinding::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
+ {
+ OSL_ENSURE( _nHandle == PROP_HANDLE_BOUND_CELL, "OCellValueBinding::getFastPropertyValue: invalid handle!" );
+ // we only have this one property...
+
+ _rValue.clear();
+ Reference< XCellAddressable > xCellAddress( m_xCell, UNO_QUERY );
+ if ( xCellAddress.is() )
+ _rValue <<= xCellAddress->getCellAddress( );
+ }
+
+ Sequence< Type > SAL_CALL OCellValueBinding::getSupportedValueTypes( )
+ {
+ checkDisposed( );
+ checkInitialized( );
+
+ sal_Int32 nCount = m_xCellText.is() ? 3 : m_xCell.is() ? 1 : 0;
+ if ( m_bListPos )
+ ++nCount;
+
+ Sequence< Type > aTypes( nCount );
+ if ( m_xCell.is() )
+ {
+ auto pTypes = aTypes.getArray();
+
+ // an XCell can be used to set/get "double" values
+ pTypes[0] = ::cppu::UnoType<double>::get();
+ if ( m_xCellText.is() )
+ {
+ // an XTextRange can be used to set/get "string" values
+ pTypes[1] = ::cppu::UnoType<OUString>::get();
+ // and additionally, we use it to handle booleans
+ pTypes[2] = ::cppu::UnoType<sal_Bool>::get();
+ }
+
+ // add sal_Int32 only if constructed as ListPositionCellBinding
+ if ( m_bListPos )
+ pTypes[nCount-1] = cppu::UnoType<sal_Int32>::get();
+ }
+
+ return aTypes;
+ }
+
+ sal_Bool SAL_CALL OCellValueBinding::supportsType( const Type& aType )
+ {
+ checkDisposed( );
+ checkInitialized( );
+
+ // look up in our sequence
+ const Sequence< Type > aSupportedTypes( getSupportedValueTypes() );
+ for ( auto const & i : aSupportedTypes )
+ if ( aType == i )
+ return true;
+
+ return false;
+ }
+
+ Any SAL_CALL OCellValueBinding::getValue( const Type& aType )
+ {
+ checkDisposed( );
+ checkInitialized( );
+ checkValueType( aType );
+
+ Any aReturn;
+ switch ( aType.getTypeClass() )
+ {
+ case TypeClass_STRING:
+ OSL_ENSURE( m_xCellText.is(), "OCellValueBinding::getValue: don't have a text!" );
+ if ( m_xCellText.is() )
+ aReturn <<= m_xCellText->getString();
+ else
+ aReturn <<= OUString();
+ break;
+
+ case TypeClass_BOOLEAN:
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" );
+ if ( m_xCell.is() )
+ {
+ // check if the cell has a numeric value (this might go into a helper function):
+
+ bool bHasValue = false;
+ CellContentType eCellType = m_xCell->getType();
+ if ( eCellType == CellContentType_VALUE )
+ bHasValue = true;
+ else if ( eCellType == CellContentType_FORMULA )
+ {
+ // check if the formula result is a value
+ if ( m_xCell->getError() == 0 )
+ {
+ Reference<XPropertySet> xProp( m_xCell, UNO_QUERY );
+ if ( xProp.is() )
+ {
+ sal_Int32 nResultType;
+ if ( (xProp->getPropertyValue("FormulaResultType2") >>= nResultType)
+ && nResultType == FormulaResult::VALUE )
+ bHasValue = true;
+ }
+ }
+ }
+
+ if ( bHasValue )
+ {
+ // 0 is "unchecked", any other value is "checked", regardless of number format
+ double nCellValue = m_xCell->getValue();
+ bool bBoolValue = ( nCellValue != 0.0 );
+ aReturn <<= bBoolValue;
+ }
+ // empty cells, text cells and text or error formula results: leave return value empty
+ }
+ break;
+
+ case TypeClass_DOUBLE:
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" );
+ if ( m_xCell.is() )
+ aReturn <<= m_xCell->getValue();
+ else
+ aReturn <<= double(0);
+ break;
+
+ case TypeClass_LONG:
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" );
+ if ( m_xCell.is() )
+ {
+ // The list position value in the cell is 1-based.
+ // We subtract 1 from any cell value (no special handling for 0 or negative values).
+
+ sal_Int32 nValue = static_cast<sal_Int32>(rtl::math::approxFloor( m_xCell->getValue() ));
+ --nValue;
+
+ aReturn <<= nValue;
+ }
+ else
+ aReturn <<= sal_Int32(0);
+ break;
+
+ default:
+ OSL_FAIL( "OCellValueBinding::getValue: unreachable code!" );
+ // a type other than double and string should never have survived the checkValueType
+ // above
+ }
+ return aReturn;
+ }
+
+ void SAL_CALL OCellValueBinding::setValue( const Any& aValue )
+ {
+ checkDisposed( );
+ checkInitialized( );
+ if ( aValue.hasValue() )
+ checkValueType( aValue.getValueType() );
+
+ switch ( aValue.getValueType().getTypeClass() )
+ {
+ case TypeClass_STRING:
+ {
+ OSL_ENSURE( m_xCellText.is(), "OCellValueBinding::setValue: don't have a text!" );
+
+ OUString sText;
+ aValue >>= sText;
+ if ( m_xCellText.is() )
+ m_xCellText->setString( sText );
+ }
+ break;
+
+ case TypeClass_BOOLEAN:
+ {
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" );
+
+ // boolean is stored as values 0 or 1
+ // TODO: set the number format to boolean if no format is set?
+
+ bool bValue( false );
+ aValue >>= bValue;
+ double nCellValue = bValue ? 1.0 : 0.0;
+
+ if ( m_xCell.is() )
+ m_xCell->setValue( nCellValue );
+
+ setBooleanFormat();
+ }
+ break;
+
+ case TypeClass_DOUBLE:
+ {
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" );
+
+ double nValue = 0;
+ aValue >>= nValue;
+ if ( m_xCell.is() )
+ m_xCell->setValue( nValue );
+ }
+ break;
+
+ case TypeClass_LONG:
+ {
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" );
+
+ sal_Int32 nValue = 0;
+ aValue >>= nValue; // list index from control layer (0-based)
+ ++nValue; // the list position value in the cell is 1-based
+ if ( m_xCell.is() )
+ m_xCell->setValue( nValue );
+ }
+ break;
+
+ case TypeClass_VOID:
+ {
+ // #N/A error value can only be set using XCellRangeData
+
+ Reference<XCellRangeData> xData( m_xCell, UNO_QUERY );
+ OSL_ENSURE( xData.is(), "OCellValueBinding::setValue: don't have XCellRangeData!" );
+ if ( xData.is() )
+ {
+ Sequence<Any> aInner(1); // one empty element
+ Sequence< Sequence<Any> > aOuter( &aInner, 1 ); // one row
+ xData->setDataArray( aOuter );
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL( "OCellValueBinding::setValue: unreachable code!" );
+ // a type other than double and string should never have survived the checkValueType
+ // above
+ }
+ }
+
+ void OCellValueBinding::setBooleanFormat()
+ {
+ // set boolean number format if not already set
+
+ OUString sPropName( "NumberFormat" );
+ Reference<XPropertySet> xCellProp( m_xCell, UNO_QUERY );
+ Reference<XNumberFormatsSupplier> xSupplier( m_xDocument, UNO_QUERY );
+ if ( !(xSupplier.is() && xCellProp.is()) )
+ return;
+
+ Reference<XNumberFormats> xFormats(xSupplier->getNumberFormats());
+ Reference<XNumberFormatTypes> xTypes( xFormats, UNO_QUERY );
+ if ( !xTypes.is() )
+ return;
+
+ lang::Locale aLocale;
+ bool bWasBoolean = false;
+
+ sal_Int32 nOldIndex = ::comphelper::getINT32( xCellProp->getPropertyValue( sPropName ) );
+ Reference<XPropertySet> xOldFormat;
+ try
+ {
+ xOldFormat.set(xFormats->getByKey( nOldIndex ));
+ }
+ catch ( Exception& )
+ {
+ // non-existing format - can happen, use defaults
+ }
+ if ( xOldFormat.is() )
+ {
+ // use the locale of the existing format
+ xOldFormat->getPropertyValue("Locale") >>= aLocale;
+
+ sal_Int16 nOldType = ::comphelper::getINT16(
+ xOldFormat->getPropertyValue("Type") );
+ if ( nOldType & NumberFormat::LOGICAL )
+ bWasBoolean = true;
+ }
+
+ if ( !bWasBoolean )
+ {
+ sal_Int32 nNewIndex = xTypes->getStandardFormat( NumberFormat::LOGICAL, aLocale );
+ xCellProp->setPropertyValue( sPropName, Any( nNewIndex ) );
+ }
+ }
+
+ void OCellValueBinding::checkDisposed( ) const
+ {
+ if ( OCellValueBinding_Base::rBHelper.bInDispose || OCellValueBinding_Base::rBHelper.bDisposed )
+ throw DisposedException();
+ // TODO: is it worth having an error message here?
+ }
+
+ void OCellValueBinding::checkInitialized()
+ {
+ if ( !m_bInitialized )
+ throw NotInitializedException("CellValueBinding is not initialized", getXWeak());
+ }
+
+ void OCellValueBinding::checkValueType( const Type& _rType ) const
+ {
+ OCellValueBinding* pNonConstThis = const_cast< OCellValueBinding* >( this );
+ if ( !pNonConstThis->supportsType( _rType ) )
+ {
+ OUString sMessage = "The given type (" +
+ _rType.getTypeName() +
+ ") is not supported by this binding.";
+ // TODO: localize this error message
+
+ throw IncompatibleTypesException( sMessage, *pNonConstThis );
+ // TODO: alternatively use a type converter service for this?
+ }
+ }
+
+ OUString SAL_CALL OCellValueBinding::getImplementationName( )
+ {
+ return "com.sun.star.comp.sheet.OCellValueBinding";
+ }
+
+ sal_Bool SAL_CALL OCellValueBinding::supportsService( const OUString& _rServiceName )
+ {
+ return cppu::supportsService(this, _rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL OCellValueBinding::getSupportedServiceNames( )
+ {
+ Sequence< OUString > aServices( m_bListPos ? 3 : 2 );
+ auto pServices = aServices.getArray();
+ pServices[ 0 ] = "com.sun.star.table.CellValueBinding";
+ pServices[ 1 ] = "com.sun.star.form.binding.ValueBinding";
+ if ( m_bListPos )
+ pServices[ 2 ] = "com.sun.star.table.ListPositionCellBinding";
+ return aServices;
+ }
+
+ void SAL_CALL OCellValueBinding::addModifyListener( const Reference< XModifyListener >& _rxListener )
+ {
+ if ( _rxListener.is() )
+ m_aModifyListeners.addInterface( _rxListener );
+ }
+
+ void SAL_CALL OCellValueBinding::removeModifyListener( const Reference< XModifyListener >& _rxListener )
+ {
+ if ( _rxListener.is() )
+ m_aModifyListeners.removeInterface( _rxListener );
+ }
+
+ void OCellValueBinding::notifyModified()
+ {
+ EventObject aEvent;
+ aEvent.Source.set(*this);
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter( m_aModifyListeners );
+ while ( aIter.hasMoreElements() )
+ {
+ try
+ {
+ aIter.next()->modified( aEvent );
+ }
+ catch( const RuntimeException& )
+ {
+ // silent this
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "OCellValueBinding::notifyModified: caught a (non-runtime) exception!" );
+ }
+ }
+ }
+
+ void SAL_CALL OCellValueBinding::modified( const EventObject& /* aEvent */ )
+ {
+ notifyModified();
+ }
+
+ void SAL_CALL OCellValueBinding::disposing( const EventObject& aEvent )
+ {
+ Reference<XInterface> xCellInt( m_xCell, UNO_QUERY );
+ if ( xCellInt == aEvent.Source )
+ {
+ // release references to cell object
+ m_xCell.clear();
+ m_xCellText.clear();
+ }
+ }
+
+ void SAL_CALL OCellValueBinding::initialize( const Sequence< Any >& _rArguments )
+ {
+ if ( m_bInitialized )
+ throw RuntimeException("CellValueBinding is already initialized", getXWeak());
+
+ // get the cell address
+ CellAddress aAddress;
+ bool bFoundAddress = false;
+
+ for ( const Any& rArg : _rArguments )
+ {
+ NamedValue aValue;
+ if ( rArg >>= aValue )
+ {
+ if ( aValue.Name == "BoundCell" )
+ {
+ if ( aValue.Value >>= aAddress )
+ {
+ bFoundAddress = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !bFoundAddress )
+ throw RuntimeException("Cell not found", getXWeak());
+
+ // get the cell object
+ try
+ {
+ // first the sheets collection
+ Reference< XIndexAccess > xSheets;
+ if ( m_xDocument.is() )
+ xSheets.set(m_xDocument->getSheets( ), css::uno::UNO_QUERY);
+ OSL_ENSURE( xSheets.is(), "OCellValueBinding::initialize: could not retrieve the sheets!" );
+
+ if ( xSheets.is() )
+ {
+ // the concrete sheet
+ Reference< XCellRange > xSheet(xSheets->getByIndex( aAddress.Sheet ), UNO_QUERY);
+ OSL_ENSURE( xSheet.is(), "OCellValueBinding::initialize: NULL sheet, but no exception!" );
+
+ // the concrete cell
+ if ( xSheet.is() )
+ {
+ m_xCell.set(xSheet->getCellByPosition( aAddress.Column, aAddress.Row ));
+ Reference< XCellAddressable > xAddressAccess( m_xCell, UNO_QUERY );
+ OSL_ENSURE( xAddressAccess.is(), "OCellValueBinding::initialize: either NULL cell, or cell without address access!" );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "OCellValueBinding::initialize: caught an exception while retrieving the cell object!" );
+ }
+
+ if ( !m_xCell.is() )
+ throw RuntimeException("Failed to retrieve cell object", getXWeak());
+
+ m_xCellText.set(m_xCell, css::uno::UNO_QUERY);
+
+ Reference<XModifyBroadcaster> xBroadcaster( m_xCell, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->addModifyListener( this );
+ }
+
+ // TODO: add as XEventListener to the cell, so we get notified when it dies,
+ // and can dispose ourself then
+
+ // TODO: somehow add as listener so we get notified when the address of the cell changes
+ // We need to forward this as change in our BoundCell property to our property change listeners
+
+ // TODO: be an XModifyBroadcaster, so that changes in our cell can be notified
+ // to the BindableValue which is/will be bound to this instance.
+
+ m_bInitialized = true;
+ // TODO: place your code here
+ }
+
+} // namespace calc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/cellvaluebinding.hxx b/sc/source/ui/unoobj/cellvaluebinding.hxx
new file mode 100644
index 0000000000..511303f7ed
--- /dev/null
+++ b/sc/source/ui/unoobj/cellvaluebinding.hxx
@@ -0,0 +1,146 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/form/binding/XValueBinding.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+
+namespace com::sun::star::table { class XCell; }
+namespace com::sun::star::sheet { class XSpreadsheetDocument; }
+namespace com::sun::star::text { class XTextRange; }
+
+namespace calc
+{
+
+ //= OCellValueBinding
+
+ class OCellValueBinding;
+ // the base for our interfaces
+ typedef ::cppu::WeakComponentImplHelper < css::form::binding::XValueBinding
+ , css::lang::XServiceInfo
+ , css::util::XModifyBroadcaster
+ , css::util::XModifyListener
+ , css::lang::XInitialization
+ > OCellValueBinding_Base;
+ // the base for the property handling
+ typedef ::comphelper::OPropertyContainer OCellValueBinding_PBase;
+ // the second base for property handling
+ typedef ::comphelper::OPropertyArrayUsageHelper< OCellValueBinding >
+ OCellValueBinding_PABase;
+
+ class OCellValueBinding :public ::cppu::BaseMutex
+ ,public OCellValueBinding_Base // order matters! before OCellValueBinding_PBase, so rBHelper gets initialized
+ ,public OCellValueBinding_PBase
+ ,public OCellValueBinding_PABase
+ {
+ private:
+ css::uno::Reference< css::sheet::XSpreadsheetDocument >
+ m_xDocument; /// the document where our cell lives
+ css::uno::Reference< css::table::XCell >
+ m_xCell; /// the cell we're bound to, for double value access
+ css::uno::Reference< css::text::XTextRange >
+ m_xCellText; /// the cell we're bound to, for text access
+ ::comphelper::OInterfaceContainerHelper3<css::util::XModifyListener>
+ m_aModifyListeners; /// our modify listeners
+ bool m_bInitialized; /// has XInitialization::initialize been called?
+ bool m_bListPos; /// constructed as ListPositionCellBinding?
+
+ public:
+ OCellValueBinding(
+ const css::uno::Reference< css::sheet::XSpreadsheetDocument >& _rxDocument,
+ bool _bListPos
+ );
+
+ using OCellValueBinding_PBase::getFastPropertyValue;
+
+ protected:
+ virtual ~OCellValueBinding( ) override;
+
+ protected:
+ // XInterface
+ DECLARE_XINTERFACE()
+
+ // XTypeProvider
+ DECLARE_XTYPEPROVIDER()
+
+ // XValueBinding
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getSupportedValueTypes( ) override;
+ virtual sal_Bool SAL_CALL supportsType( const css::uno::Type& aType ) override;
+ virtual css::uno::Any SAL_CALL getValue( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL setValue( const css::uno::Any& aValue ) override;
+
+ // OComponentHelper/XComponent
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& _rValue, sal_Int32 _nHandle ) const override;
+
+ // ::comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+
+ // XModifyListener
+ virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ private:
+ void checkDisposed( ) const;
+ void checkValueType( const css::uno::Type& _rType ) const;
+ void checkInitialized();
+
+ /** notifies our modify listeners
+ @precond
+ our mutex is <em>not</em> locked
+ */
+ void notifyModified();
+
+ void setBooleanFormat();
+
+ private:
+ OCellValueBinding( const OCellValueBinding& ) = delete;
+ OCellValueBinding& operator=( const OCellValueBinding& ) = delete;
+ };
+
+} // namespace calc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/chart2uno.cxx b/sc/source/ui/unoobj/chart2uno.cxx
new file mode 100644
index 0000000000..e20a473f06
--- /dev/null
+++ b/sc/source/ui/unoobj/chart2uno.cxx
@@ -0,0 +1,3517 @@
+/* -*- 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 <memory>
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <algorithm>
+#include <utility>
+
+#include <chart2uno.hxx>
+#include <miscuno.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <formulacell.hxx>
+#include <unonames.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <rangeutl.hxx>
+#include <hints.hxx>
+#include <unoreflist.hxx>
+#include <compiler.hxx>
+#include <reftokenhelper.hxx>
+#include <chartlis.hxx>
+#include <tokenuno.hxx>
+#include <cellvalue.hxx>
+#include <tokenarray.hxx>
+#include <scmatrix.hxx>
+#include <brdcst.hxx>
+#include <mtvelements.hxx>
+
+#include <formula/opcode.hxx>
+#include <o3tl/safeint.hxx>
+#include <svl/numformat.hxx>
+#include <svl/sharedstring.hxx>
+
+#include <sfx2/objsh.hxx>
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/beans/UnknownPropertyException.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <comphelper/extract.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <limits>
+
+SC_SIMPLE_SERVICE_INFO( ScChart2DataProvider, "ScChart2DataProvider",
+ "com.sun.star.chart2.data.DataProvider")
+SC_SIMPLE_SERVICE_INFO( ScChart2DataSource, "ScChart2DataSource",
+ "com.sun.star.chart2.data.DataSource")
+SC_SIMPLE_SERVICE_INFO( ScChart2DataSequence, "ScChart2DataSequence",
+ "com.sun.star.chart2.data.DataSequence")
+
+using namespace ::com::sun::star;
+using namespace ::formula;
+using ::com::sun::star::uno::Sequence;
+using ::std::unique_ptr;
+using ::std::vector;
+using ::std::distance;
+using ::std::shared_ptr;
+
+namespace
+{
+std::span<const SfxItemPropertyMapEntry> lcl_GetDataProviderPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_INCLUDEHIDDENCELLS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_USE_INTERNAL_DATA_PROVIDER, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ };
+ return aDataProviderPropertyMap_Impl;
+}
+
+std::span<const SfxItemPropertyMapEntry> lcl_GetDataSequencePropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDataSequencePropertyMap_Impl[] =
+ {
+ { SC_UNONAME_HIDDENVALUES, 0, cppu::UnoType<uno::Sequence<sal_Int32>>::get(), 0, 0 },
+ { SC_UNONAME_ROLE, 0, cppu::UnoType<css::chart2::data::DataSequenceRole>::get(), 0, 0 },
+ { SC_UNONAME_INCLUDEHIDDENCELLS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ };
+ return aDataSequencePropertyMap_Impl;
+}
+
+struct lcl_appendTableNumber
+{
+ explicit lcl_appendTableNumber( OUStringBuffer & rBuffer ) :
+ m_rBuffer( rBuffer )
+ {}
+ void operator() ( SCTAB nTab )
+ {
+ // there is no append with SCTAB or sal_Int16
+ m_rBuffer.append( static_cast< sal_Int32 >( nTab ));
+ m_rBuffer.append( ' ' );
+ }
+private:
+ OUStringBuffer & m_rBuffer;
+};
+
+OUString lcl_createTableNumberList( const ::std::vector< SCTAB > & rTableVector )
+{
+ OUStringBuffer aBuffer;
+ ::std::for_each( rTableVector.begin(), rTableVector.end(), lcl_appendTableNumber( aBuffer ));
+ // remove last trailing ' '
+ if( !aBuffer.isEmpty() )
+ aBuffer.setLength( aBuffer.getLength() - 1 );
+ return aBuffer.makeStringAndClear();
+}
+
+uno::Reference< frame::XModel > lcl_GetXModel( const ScDocument * pDoc )
+{
+ uno::Reference< frame::XModel > xModel;
+ ScDocShell * pObjSh( pDoc ? pDoc->GetDocumentShell() : nullptr );
+ if( pObjSh )
+ xModel.set( pObjSh->GetModel());
+ return xModel;
+}
+
+struct TokenTable
+{
+ SCROW mnRowCount;
+ SCCOL mnColCount;
+ vector<std::unique_ptr<FormulaToken>> maTokens;
+
+ // noncopyable
+ TokenTable(const TokenTable&) = delete;
+ const TokenTable& operator=(const TokenTable&) = delete;
+
+ TokenTable()
+ : mnRowCount(0)
+ , mnColCount(0)
+ {
+ }
+
+ void init( SCCOL nColCount, SCROW nRowCount )
+ {
+ mnColCount = nColCount;
+ mnRowCount = nRowCount;
+ maTokens.reserve(mnColCount*mnRowCount);
+ }
+ void clear()
+ {
+ for (auto & rToken : maTokens)
+ rToken.reset();
+ }
+
+ void push_back( std::unique_ptr<FormulaToken> pToken )
+ {
+ maTokens.push_back( std::move(pToken) );
+ OSL_ENSURE( maTokens.size()<= o3tl::make_unsigned( mnColCount*mnRowCount ), "too many tokens" );
+ }
+
+ sal_uInt32 getIndex(SCCOL nCol, SCROW nRow) const
+ {
+ OSL_ENSURE( nCol<mnColCount, "wrong column index" );
+ OSL_ENSURE( nRow<mnRowCount, "wrong row index" );
+ sal_uInt32 nRet = static_cast<sal_uInt32>(nCol*mnRowCount + nRow);
+ OSL_ENSURE( maTokens.size()>= o3tl::make_unsigned( mnColCount*mnRowCount ), "too few tokens" );
+ return nRet;
+ }
+
+ vector<ScTokenRef> getColRanges(const ScDocument* pDoc, SCCOL nCol) const;
+ vector<ScTokenRef> getRowRanges(const ScDocument* pDoc, SCROW nRow) const;
+ vector<ScTokenRef> getAllRanges(const ScDocument* pDoc) const;
+};
+
+vector<ScTokenRef> TokenTable::getColRanges(const ScDocument* pDoc, SCCOL nCol) const
+{
+ if (nCol >= mnColCount)
+ return vector<ScTokenRef>();
+ if( mnRowCount<=0 )
+ return vector<ScTokenRef>();
+
+ vector<ScTokenRef> aTokens;
+ sal_uInt32 nLast = getIndex(nCol, mnRowCount-1);
+ for (sal_uInt32 i = getIndex(nCol, 0); i <= nLast; ++i)
+ {
+ FormulaToken* p = maTokens[i].get();
+ if (!p)
+ continue;
+
+ ScTokenRef pCopy(p->Clone());
+ ScRefTokenHelper::join(pDoc, aTokens, pCopy, ScAddress());
+ }
+ return aTokens;
+}
+
+vector<ScTokenRef> TokenTable::getRowRanges(const ScDocument* pDoc, SCROW nRow) const
+{
+ if (nRow >= mnRowCount)
+ return vector<ScTokenRef>();
+ if( mnColCount<=0 )
+ return vector<ScTokenRef>();
+
+ vector<ScTokenRef> aTokens;
+ sal_uInt32 nLast = getIndex(mnColCount-1, nRow);
+ for (sal_uInt32 i = getIndex(0, nRow); i <= nLast; i += mnRowCount)
+ {
+ FormulaToken* p = maTokens[i].get();
+ if (!p)
+ continue;
+
+ ScTokenRef p2(p->Clone());
+ ScRefTokenHelper::join(pDoc, aTokens, p2, ScAddress());
+ }
+ return aTokens;
+}
+
+vector<ScTokenRef> TokenTable::getAllRanges(const ScDocument* pDoc) const
+{
+ vector<ScTokenRef> aTokens;
+ sal_uInt32 nStop = mnColCount*mnRowCount;
+ for (sal_uInt32 i = 0; i < nStop; i++)
+ {
+ FormulaToken* p = maTokens[i].get();
+ if (!p)
+ continue;
+
+ ScTokenRef p2(p->Clone());
+ ScRefTokenHelper::join(pDoc, aTokens, p2, ScAddress());
+ }
+ return aTokens;
+}
+
+typedef std::map<SCROW, std::unique_ptr<FormulaToken>> FormulaTokenMap;
+typedef std::map<sal_uInt32, FormulaTokenMap> FormulaTokenMapMap;
+
+class Chart2PositionMap
+{
+public:
+ Chart2PositionMap(SCCOL nColCount, SCROW nRowCount,
+ bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols,
+ ScDocument* pDoc );
+ ~Chart2PositionMap();
+
+ SCCOL getDataColCount() const { return mnDataColCount; }
+ SCROW getDataRowCount() const { return mnDataRowCount; }
+
+ vector<ScTokenRef> getLeftUpperCornerRanges() const;
+ vector<ScTokenRef> getAllColHeaderRanges() const;
+ vector<ScTokenRef> getAllRowHeaderRanges() const;
+
+ vector<ScTokenRef> getColHeaderRanges(SCCOL nChartCol) const;
+ vector<ScTokenRef> getRowHeaderRanges(SCROW nChartRow) const;
+
+ vector<ScTokenRef> getDataColRanges(SCCOL nCol) const;
+ vector<ScTokenRef> getDataRowRanges(SCROW nRow) const;
+
+private:
+ const ScDocument* mpDoc;
+ SCCOL mnDataColCount;
+ SCROW mnDataRowCount;
+
+ TokenTable maLeftUpperCorner; //nHeaderColCount*nHeaderRowCount
+ TokenTable maColHeaders; //mnDataColCount*nHeaderRowCount
+ TokenTable maRowHeaders; //nHeaderColCount*mnDataRowCount
+ TokenTable maData;//mnDataColCount*mnDataRowCount
+};
+
+Chart2PositionMap::Chart2PositionMap(SCCOL nAllColCount, SCROW nAllRowCount,
+ bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols, ScDocument* pDoc)
+{
+ mpDoc = pDoc;
+ // if bFillRowHeader is true, at least the first column serves as a row header.
+ // If more than one column is pure text all the first pure text columns are used as header.
+ // Likewise, if bFillColumnHeader is true, at least the first row serves as a column header.
+ // If more than one row is pure text all the first pure text rows are used as header.
+
+ SCROW nHeaderRowCount = (bFillColumnHeader && nAllColCount && nAllRowCount) ? 1 : 0;
+ SCCOL nHeaderColCount = (bFillRowHeader && nAllColCount && nAllRowCount) ? 1 : 0;
+
+ if( pDoc && (nHeaderColCount || nHeaderRowCount ) )
+ {
+ //check whether there is more than one text column or row that should be added to the headers
+ SCROW nMaxHeaderRow = nAllRowCount;
+ SCCOL nCol = 0;
+ for (auto it = rCols.begin(); it != rCols.end(); ++it, ++nCol)
+ {
+ // Skip header columns
+ if (nCol < nHeaderColCount)
+ continue;
+
+ const auto& rCol = *it;
+
+ bool bFoundValuesInCol = false;
+ bool bFoundAnythingInCol = false;
+ SCROW nRow = 0;
+ for (auto it2 = rCol.second.begin(); it2 != rCol.second.end(); ++it2, ++nRow)
+ {
+ const auto& rCell = *it2;
+
+ // Skip header rows
+ if (nRow < nHeaderRowCount || !rCell.second)
+ continue;
+
+ ScRange aRange;
+ bool bExternal = false;
+ StackVar eType = rCell.second->GetType();
+ if( eType==svExternal || eType==svExternalSingleRef || eType==svExternalDoubleRef || eType==svExternalName )
+ bExternal = true;//lllll todo correct?
+ ScTokenRef pSharedToken(rCell.second->Clone());
+ ScRefTokenHelper::getRangeFromToken(pDoc, aRange, pSharedToken, ScAddress(), bExternal);
+ SCCOL nCol1=0, nCol2=0;
+ SCROW nRow1=0, nRow2=0;
+ SCTAB nTab1=0, nTab2=0;
+ aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if ( pDoc->HasValueData( nCol1, nRow1, nTab1 ) )
+ {
+ // Found some numeric data
+ bFoundValuesInCol = true;
+ nMaxHeaderRow = std::min(nMaxHeaderRow, nRow);
+ break;
+ }
+ if ( pDoc->HasData( nCol1, nRow1, nTab1 ) )
+ {
+ // Found some other data (non-numeric)
+ bFoundAnythingInCol = true;
+ }
+ else
+ {
+ // If cell is empty, it belongs to data
+ nMaxHeaderRow = std::min(nMaxHeaderRow, nRow);
+ }
+ }
+
+ if (nHeaderColCount && !bFoundValuesInCol && bFoundAnythingInCol && nCol == nHeaderColCount)
+ {
+ // There is no values in row, but some data. And this column is next to header
+ // So lets put it to header
+ nHeaderColCount++;
+ }
+ }
+
+ if (nHeaderRowCount)
+ {
+ nHeaderRowCount = nMaxHeaderRow;
+ }
+ }
+
+ mnDataColCount = nAllColCount - nHeaderColCount;
+ mnDataRowCount = nAllRowCount - nHeaderRowCount;
+
+ maLeftUpperCorner.init(nHeaderColCount,nHeaderRowCount);
+ maColHeaders.init(mnDataColCount,nHeaderRowCount);
+ maRowHeaders.init(nHeaderColCount,mnDataRowCount);
+ maData.init(mnDataColCount,mnDataRowCount);
+
+ FormulaTokenMapMap::iterator it1 = rCols.begin();
+ for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol)
+ {
+ if (it1 != rCols.end())
+ {
+ FormulaTokenMap& rCol = it1->second;
+ FormulaTokenMap::iterator it2 = rCol.begin();
+ for (SCROW nRow = 0; nRow < nAllRowCount; ++nRow)
+ {
+ std::unique_ptr<FormulaToken> pToken;
+ if (it2 != rCol.end())
+ {
+ pToken = std::move(it2->second);
+ ++it2;
+ }
+
+ if( nCol < nHeaderColCount )
+ {
+ if( nRow < nHeaderRowCount )
+ maLeftUpperCorner.push_back(std::move(pToken));
+ else
+ maRowHeaders.push_back(std::move(pToken));
+ }
+ else if( nRow < nHeaderRowCount )
+ maColHeaders.push_back(std::move(pToken));
+ else
+ maData.push_back(std::move(pToken));
+ }
+ ++it1;
+ }
+ }
+}
+
+Chart2PositionMap::~Chart2PositionMap()
+{
+ maLeftUpperCorner.clear();
+ maColHeaders.clear();
+ maRowHeaders.clear();
+ maData.clear();
+}
+
+vector<ScTokenRef> Chart2PositionMap::getLeftUpperCornerRanges() const
+{
+ return maLeftUpperCorner.getAllRanges(mpDoc);
+}
+vector<ScTokenRef> Chart2PositionMap::getAllColHeaderRanges() const
+{
+ return maColHeaders.getAllRanges(mpDoc);
+}
+vector<ScTokenRef> Chart2PositionMap::getAllRowHeaderRanges() const
+{
+ return maRowHeaders.getAllRanges(mpDoc);
+}
+vector<ScTokenRef> Chart2PositionMap::getColHeaderRanges(SCCOL nCol) const
+{
+ return maColHeaders.getColRanges(mpDoc, nCol);
+}
+vector<ScTokenRef> Chart2PositionMap::getRowHeaderRanges(SCROW nRow) const
+{
+ return maRowHeaders.getRowRanges(mpDoc, nRow);
+}
+
+vector<ScTokenRef> Chart2PositionMap::getDataColRanges(SCCOL nCol) const
+{
+ return maData.getColRanges(mpDoc, nCol);
+}
+
+vector<ScTokenRef> Chart2PositionMap::getDataRowRanges(SCROW nRow) const
+{
+ return maData.getRowRanges(mpDoc, nRow);
+}
+
+/**
+ * Designed to be a drop-in replacement for ScChartPositioner, in order to
+ * handle external references.
+ */
+class Chart2Positioner
+{
+ enum GlueType
+ {
+ GLUETYPE_NA,
+ GLUETYPE_NONE,
+ GLUETYPE_COLS,
+ GLUETYPE_ROWS,
+ GLUETYPE_BOTH
+ };
+
+public:
+ Chart2Positioner(const Chart2Positioner&) = delete;
+ const Chart2Positioner& operator=(const Chart2Positioner&) = delete;
+
+ Chart2Positioner(ScDocument* pDoc, const vector<ScTokenRef>& rRefTokens) :
+ mrRefTokens(rRefTokens),
+ meGlue(GLUETYPE_NA),
+ mnStartCol(0),
+ mnStartRow(0),
+ mpDoc(pDoc),
+ mbColHeaders(false),
+ mbRowHeaders(false),
+ mbDummyUpperLeft(false)
+ {
+ }
+
+ void setHeaders(bool bColHeaders, bool bRowHeaders)
+ {
+ mbColHeaders = bColHeaders;
+ mbRowHeaders = bRowHeaders;
+ }
+
+ Chart2PositionMap* getPositionMap()
+ {
+ createPositionMap();
+ return mpPositionMap.get();
+ }
+
+private:
+ void invalidateGlue();
+ void glueState();
+ void calcGlueState(SCCOL nCols, SCROW nRows);
+ void createPositionMap();
+
+private:
+ const vector<ScTokenRef>& mrRefTokens;
+ std::unique_ptr<Chart2PositionMap> mpPositionMap;
+ GlueType meGlue;
+ SCCOL mnStartCol;
+ SCROW mnStartRow;
+ ScDocument* mpDoc;
+ bool mbColHeaders:1;
+ bool mbRowHeaders:1;
+ bool mbDummyUpperLeft:1;
+};
+
+void Chart2Positioner::invalidateGlue()
+{
+ meGlue = GLUETYPE_NA;
+ mpPositionMap.reset();
+}
+
+void Chart2Positioner::glueState()
+{
+ if (meGlue != GLUETYPE_NA)
+ return;
+
+ mbDummyUpperLeft = false;
+ if (mrRefTokens.size() <= 1)
+ {
+ // Source data consists of only one data range.
+ const ScTokenRef& p = mrRefTokens.front();
+ ScComplexRefData aData;
+ if (ScRefTokenHelper::getDoubleRefDataFromToken(aData, p))
+ {
+ if (aData.Ref1.Tab() == aData.Ref2.Tab())
+ meGlue = GLUETYPE_NONE;
+ else
+ meGlue = GLUETYPE_COLS;
+ mnStartCol = aData.Ref1.Col();
+ mnStartRow = aData.Ref1.Row();
+ }
+ else
+ {
+ invalidateGlue();
+ mnStartCol = 0;
+ mnStartRow = 0;
+ }
+ return;
+ }
+
+ ScComplexRefData aData;
+ if (!ScRefTokenHelper::getDoubleRefDataFromToken(aData, mrRefTokens.front()))
+ {
+ SAL_WARN("sc", "Chart2Positioner::glueState getDoubleRefDataFromToken failed");
+ invalidateGlue();
+ mnStartCol = 0;
+ mnStartRow = 0;
+ return;
+ }
+ mnStartCol = aData.Ref1.Col();
+ mnStartRow = aData.Ref1.Row();
+
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ for (const auto& rxToken : mrRefTokens)
+ {
+ ScRefTokenHelper::getDoubleRefDataFromToken(aData, rxToken);
+ SCCOLROW n1 = aData.Ref1.Col();
+ SCCOLROW n2 = aData.Ref2.Col();
+ if (n1 > mpDoc->MaxCol())
+ n1 = mpDoc->MaxCol();
+ if (n2 > mpDoc->MaxCol())
+ n2 = mpDoc->MaxCol();
+ if (n1 < mnStartCol)
+ mnStartCol = static_cast<SCCOL>(n1);
+ if (n2 > nEndCol)
+ nEndCol = static_cast<SCCOL>(n2);
+
+ n1 = aData.Ref1.Row();
+ n2 = aData.Ref2.Row();
+ if (n1 > mpDoc->MaxRow())
+ n1 = mpDoc->MaxRow();
+ if (n2 > mpDoc->MaxRow())
+ n2 = mpDoc->MaxRow();
+
+ if (n1 < mnStartRow)
+ mnStartRow = static_cast<SCROW>(n1);
+ if (n2 > nEndRow)
+ nEndRow = static_cast<SCROW>(n2);
+ }
+
+ if (mnStartCol == nEndCol)
+ {
+ // All source data is in a single column.
+ meGlue = GLUETYPE_ROWS;
+ return;
+ }
+
+ if (mnStartRow == nEndRow)
+ {
+ // All source data is in a single row.
+ meGlue = GLUETYPE_COLS;
+ return;
+ }
+
+ // total column size
+ SCCOL nC = nEndCol - mnStartCol + 1;
+
+ // total row size
+ SCROW nR = nEndRow - mnStartRow + 1;
+
+ // #i103540# prevent invalid vector size
+ if ((nC <= 0) || (nR <= 0))
+ {
+ invalidateGlue();
+ mnStartCol = 0;
+ mnStartRow = 0;
+ return;
+ }
+
+ calcGlueState(nC, nR);
+}
+
+enum State { Hole = 0, Occupied = 1, Free = 2, Glue = 3 };
+
+void Chart2Positioner::calcGlueState(SCCOL nColSize, SCROW nRowSize)
+{
+ // TODO: This code can use some space optimization. Using an array to
+ // store individual cell's states is terribly inefficient esp for large
+ // data ranges; let's use flat_segment_tree to reduce memory usage here.
+
+ sal_uInt32 nCR = static_cast<sal_uInt32>(nColSize*nRowSize);
+
+ vector<State> aCellStates(nCR, Hole);
+
+ // Mark all referenced cells "occupied".
+ for (const auto& rxToken : mrRefTokens)
+ {
+ ScComplexRefData aData;
+ ScRefTokenHelper::getDoubleRefDataFromToken(aData, rxToken);
+ SCCOL nCol1 = aData.Ref1.Col() - mnStartCol;
+ SCCOL nCol2 = aData.Ref2.Col() - mnStartCol;
+ SCROW nRow1 = aData.Ref1.Row() - mnStartRow;
+ SCROW nRow2 = aData.Ref2.Row() - mnStartRow;
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+ {
+ size_t i = nCol*nRowSize + nRow;
+ aCellStates[i] = Occupied;
+ }
+ }
+
+ // If at least one cell in either the first column or first row is empty,
+ // we don't glue at all unless the whole column or row is empty; we expect
+ // all cells in the first column / row to be fully populated. If we have
+ // empty column or row, then we do glue by the column or row,
+ // respectively.
+
+ bool bGlue = true;
+ bool bGlueCols = false;
+ for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol)
+ {
+ for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
+ {
+ size_t i = nCol*nRowSize + nRow;
+ if (aCellStates[i] == Occupied)
+ {
+ if (nCol == 0 || nRow == 0)
+ break;
+
+ bGlue = false;
+ }
+ else
+ aCellStates[i] = Free;
+ }
+ size_t nLast = (nCol+1)*nRowSize - 1; // index for the last cell in the column.
+ if (bGlue && aCellStates[nLast] == Free)
+ {
+ // Whole column is empty.
+ aCellStates[nLast] = Glue;
+ bGlueCols = true;
+ }
+ }
+
+ bool bGlueRows = false;
+ for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
+ {
+ size_t i = nRow;
+ for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol, i += nRowSize)
+ {
+ if (aCellStates[i] == Occupied)
+ {
+ if (nCol == 0 || nRow == 0)
+ break;
+
+ bGlue = false;
+ }
+ else
+ aCellStates[i] = Free;
+ }
+ i = (nColSize-1)*nRowSize + nRow; // index for the row position in the last column.
+ if (bGlue && aCellStates[i] == Free)
+ {
+ // Whole row is empty.
+ aCellStates[i] = Glue;
+ bGlueRows = true;
+ }
+ }
+
+ size_t i = 1;
+ for (sal_uInt32 n = 1; bGlue && n < nCR; ++n, ++i)
+ if (aCellStates[i] == Hole)
+ bGlue = false;
+
+ if (bGlue)
+ {
+ if (bGlueCols && bGlueRows)
+ meGlue = GLUETYPE_BOTH;
+ else if (bGlueRows)
+ meGlue = GLUETYPE_ROWS;
+ else
+ meGlue = GLUETYPE_COLS;
+ if (aCellStates.front() != Occupied)
+ mbDummyUpperLeft = true;
+ }
+ else
+ meGlue = GLUETYPE_NONE;
+}
+
+void Chart2Positioner::createPositionMap()
+{
+ if (meGlue == GLUETYPE_NA && mpPositionMap)
+ mpPositionMap.reset();
+
+ if (mpPositionMap)
+ return;
+
+ glueState();
+
+ bool bNoGlue = (meGlue == GLUETYPE_NONE);
+ FormulaTokenMapMap aCols;
+ SCROW nNoGlueRow = 0;
+ for (const ScTokenRef& pToken : mrRefTokens)
+ {
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
+ svl::SharedString aTabName = svl::SharedString::getEmptyString();
+ if (bExternal)
+ aTabName = pToken->GetString();
+
+ ScComplexRefData aData;
+ if( !ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken) )
+ break;
+ const ScSingleRefData& s = aData.Ref1;
+ const ScSingleRefData& e = aData.Ref2;
+ SCCOL nCol1 = s.Col(), nCol2 = e.Col();
+ SCROW nRow1 = s.Row(), nRow2 = e.Row();
+ SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
+
+ for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
+ {
+ // columns on secondary sheets are appended; we treat them as if
+ // all columns are on the same sheet. TODO: We can't assume that
+ // the column range is 16-bit; remove that restriction.
+ sal_uInt32 nInsCol = (static_cast<sal_uInt32>(nTab) << 16) |
+ (bNoGlue ? 0 : static_cast<sal_uInt32>(nCol1));
+
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol)
+ {
+ FormulaTokenMap& rCol = aCols[nInsCol];
+
+ auto nInsRow = bNoGlue ? nNoGlueRow : nRow1;
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow, ++nInsRow)
+ {
+ ScSingleRefData aCellData;
+ aCellData.InitFlags();
+ aCellData.SetFlag3D(true);
+ aCellData.SetColRel(false);
+ aCellData.SetRowRel(false);
+ aCellData.SetTabRel(false);
+ aCellData.SetAbsCol(nCol);
+ aCellData.SetAbsRow(nRow);
+ aCellData.SetAbsTab(nTab);
+
+ auto& rCell = rCol[nInsRow];
+ if (!rCell)
+ {
+ if (bExternal)
+ rCell.reset(new ScExternalSingleRefToken(nFileId, aTabName, aCellData));
+ else
+ rCell.reset(new ScSingleRefToken(mpDoc->GetSheetLimits(), aCellData));
+ }
+ }
+ }
+ }
+ nNoGlueRow += nRow2 - nRow1 + 1;
+ }
+
+ bool bFillRowHeader = mbRowHeaders;
+ bool bFillColumnHeader = mbColHeaders;
+
+ SCSIZE nAllColCount = static_cast<SCSIZE>(aCols.size());
+ SCSIZE nAllRowCount = 0;
+ if (!aCols.empty())
+ {
+ FormulaTokenMap& rCol = aCols.begin()->second;
+ if (mbDummyUpperLeft)
+ rCol.try_emplace( 0, nullptr ); // dummy for labeling
+ nAllRowCount = static_cast<SCSIZE>(rCol.size());
+ }
+
+ if( nAllColCount!=0 && nAllRowCount!=0 )
+ {
+ if (bNoGlue)
+ {
+ FormulaTokenMap& rFirstCol = aCols.begin()->second;
+ for (const auto& rFirstColEntry : rFirstCol)
+ {
+ SCROW nKey = rFirstColEntry.first;
+ for (auto& rEntry : aCols)
+ {
+ FormulaTokenMap& rCol = rEntry.second;
+ rCol.try_emplace( nKey, nullptr );
+ }
+ }
+ }
+ }
+ mpPositionMap.reset(
+ new Chart2PositionMap(
+ static_cast<SCCOL>(nAllColCount), static_cast<SCROW>(nAllRowCount),
+ bFillRowHeader, bFillColumnHeader, aCols, mpDoc));
+}
+
+/**
+ * Function object to create a range string from a token list.
+ */
+class Tokens2RangeString
+{
+public:
+ Tokens2RangeString(ScDocument& rDoc, FormulaGrammar::Grammar eGram, sal_Unicode cRangeSep) :
+ mpRangeStr(std::make_shared<OUStringBuffer>()),
+ mpDoc(&rDoc),
+ meGrammar(eGram),
+ mcRangeSep(cRangeSep),
+ mbFirst(true)
+ {
+ }
+
+ void operator() (const ScTokenRef& rToken)
+ {
+ ScCompiler aCompiler(*mpDoc, ScAddress(0,0,0), meGrammar);
+ OUString aStr;
+ aCompiler.CreateStringFromToken(aStr, rToken.get());
+ if (mbFirst)
+ mbFirst = false;
+ else
+ mpRangeStr->append(mcRangeSep);
+ mpRangeStr->append(aStr);
+ }
+
+ void getString(OUString& rStr)
+ {
+ rStr = mpRangeStr->makeStringAndClear();
+ }
+
+private:
+ shared_ptr<OUStringBuffer> mpRangeStr;
+ ScDocument* mpDoc;
+ FormulaGrammar::Grammar meGrammar;
+ sal_Unicode mcRangeSep;
+ bool mbFirst;
+};
+
+/**
+ * Function object to convert a list of tokens into a string form suitable
+ * for ODF export. In ODF, a range is expressed as
+ *
+ * (start cell address):(end cell address)
+ *
+ * and each address doesn't include any '$' symbols.
+ */
+class Tokens2RangeStringXML
+{
+public:
+ explicit Tokens2RangeStringXML(ScDocument& rDoc) :
+ mpRangeStr(std::make_shared<OUStringBuffer>()),
+ mpDoc(&rDoc),
+ mbFirst(true)
+ {
+ }
+
+ void operator() (const ScTokenRef& rToken)
+ {
+ if (mbFirst)
+ mbFirst = false;
+ else
+ mpRangeStr->append(mcRangeSep);
+
+ ScTokenRef aStart, aEnd;
+ bool bValidToken = splitRangeToken(*mpDoc, rToken, aStart, aEnd);
+ // Check there is a valid reference in named range
+ if (!bValidToken && rToken->GetType() == svIndex && rToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = mpDoc->FindRangeNameBySheetAndIndex(rToken->GetSheet(), rToken->GetIndex());
+ if (pNameRange->HasReferences())
+ {
+ const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
+ bValidToken = splitRangeToken(*mpDoc, aTempToken, aStart, aEnd);
+ }
+ }
+
+ OSL_ENSURE(bValidToken, "invalid token");
+ if (!bValidToken)
+ return;
+
+ ScCompiler aCompiler(*mpDoc, ScAddress(0,0,0), FormulaGrammar::GRAM_ENGLISH);
+ {
+ OUString aStr;
+ aCompiler.CreateStringFromToken(aStr, aStart.get());
+ mpRangeStr->append(aStr);
+ }
+ mpRangeStr->append(mcAddrSep);
+ {
+ OUString aStr;
+ aCompiler.CreateStringFromToken(aStr, aEnd.get());
+ mpRangeStr->append(aStr);
+ }
+ }
+
+ void getString(OUString& rStr)
+ {
+ rStr = mpRangeStr->makeStringAndClear();
+ }
+
+private:
+ static bool splitRangeToken(const ScDocument& rDoc, const ScTokenRef& pToken, ScTokenRef& rStart, ScTokenRef& rEnd)
+ {
+ ScComplexRefData aData;
+ bool bIsRefToken = ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken);
+ OSL_ENSURE(bIsRefToken, "invalid token");
+ if (!bIsRefToken)
+ return false;
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
+ svl::SharedString aTabName = svl::SharedString::getEmptyString();
+ if (bExternal)
+ aTabName = pToken->GetString();
+
+ // In saving to XML, we don't prepend address with '$'.
+ setRelative(aData.Ref1);
+ setRelative(aData.Ref2);
+
+ // In XML, the range must explicitly specify sheet name.
+ aData.Ref1.SetFlag3D(true);
+ aData.Ref2.SetFlag3D(true);
+
+ if (bExternal)
+ rStart.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref1));
+ else
+ rStart.reset(new ScSingleRefToken(rDoc.GetSheetLimits(), aData.Ref1));
+
+ if (bExternal)
+ rEnd.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref2));
+ else
+ rEnd.reset(new ScSingleRefToken(rDoc.GetSheetLimits(), aData.Ref2));
+ return true;
+ }
+
+ static void setRelative(ScSingleRefData& rData)
+ {
+ rData.SetColRel(true);
+ rData.SetRowRel(true);
+ rData.SetTabRel(true);
+ }
+
+private:
+ shared_ptr<OUStringBuffer> mpRangeStr;
+ ScDocument* mpDoc;
+ static const sal_Unicode mcRangeSep = ' ';
+ static const sal_Unicode mcAddrSep = ':';
+ bool mbFirst;
+};
+
+void lcl_convertTokensToString(OUString& rStr, const vector<ScTokenRef>& rTokens, ScDocument& rDoc)
+{
+ const sal_Unicode cRangeSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ FormulaGrammar::Grammar eGrammar = rDoc.GetGrammar();
+ Tokens2RangeString func(rDoc, eGrammar, cRangeSep);
+ func = ::std::for_each(rTokens.begin(), rTokens.end(), func);
+ func.getString(rStr);
+}
+
+} // anonymous namespace
+
+// DataProvider ==============================================================
+
+ScChart2DataProvider::ScChart2DataProvider( ScDocument* pDoc )
+ : m_pDocument( pDoc)
+ , m_aPropSet(lcl_GetDataProviderPropertyMap())
+ , m_bIncludeHiddenCells( true)
+{
+ if ( m_pDocument )
+ m_pDocument->AddUnoObject( *this);
+}
+
+ScChart2DataProvider::~ScChart2DataProvider()
+{
+ SolarMutexGuard g;
+
+ if ( m_pDocument )
+ m_pDocument->RemoveUnoObject( *this);
+}
+
+void ScChart2DataProvider::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ m_pDocument = nullptr;
+ }
+}
+
+sal_Bool SAL_CALL ScChart2DataProvider::createDataSourcePossible( const uno::Sequence< beans::PropertyValue >& aArguments )
+{
+ SolarMutexGuard aGuard;
+ if( ! m_pDocument )
+ return false;
+
+ OUString aRangeRepresentation;
+ for(const auto& rArgument : aArguments)
+ {
+ if ( rArgument.Name == "CellRangeRepresentation" )
+ {
+ rArgument.Value >>= aRangeRepresentation;
+ }
+ }
+
+ vector<ScTokenRef> aTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ return !aTokens.empty();
+}
+
+namespace
+{
+
+uno::Reference< chart2::data::XLabeledDataSequence > lcl_createLabeledDataSequenceFromTokens(
+ vector< ScTokenRef > && aValueTokens, vector< ScTokenRef > && aLabelTokens,
+ ScDocument* pDoc, bool bIncludeHiddenCells )
+{
+ uno::Reference< chart2::data::XLabeledDataSequence > xResult;
+ bool bHasValues = !aValueTokens.empty();
+ bool bHasLabel = !aLabelTokens.empty();
+ if( bHasValues || bHasLabel )
+ {
+ try
+ {
+ uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ if ( xContext.is() )
+ {
+ xResult.set( chart2::data::LabeledDataSequence::create(xContext), uno::UNO_QUERY_THROW );
+ }
+ if ( bHasValues )
+ {
+ uno::Reference< chart2::data::XDataSequence > xSeq( new ScChart2DataSequence( pDoc, std::move(aValueTokens), bIncludeHiddenCells ) );
+ xResult->setValues( xSeq );
+ }
+ if ( bHasLabel )
+ {
+ //Labels should always include hidden cells, regardless of the bIncludeHiddenCells setting
+ uno::Reference< chart2::data::XDataSequence > xLabelSeq( new ScChart2DataSequence( pDoc, std::move(aLabelTokens), true ) );
+ xResult->setLabel( xLabelSeq );
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ return xResult;
+}
+
+/**
+ * Check the current list of reference tokens, and add the upper left
+ * corner of the minimum range that encloses all ranges if certain
+ * conditions are met.
+ *
+ * @param rRefTokens list of reference tokens
+ *
+ * @return true if the corner was added, false otherwise.
+ */
+bool lcl_addUpperLeftCornerIfMissing(const ScDocument* pDoc, vector<ScTokenRef>& rRefTokens,
+ SCROW nCornerRowCount, SCCOL nCornerColumnCount)
+{
+ using ::std::max;
+ using ::std::min;
+
+ if (rRefTokens.empty())
+ return false;
+
+ SCCOL nMinCol = pDoc->GetSheetLimits().GetMaxColCount();
+ SCROW nMinRow = pDoc->GetSheetLimits().GetMaxRowCount();
+ SCCOL nMaxCol = 0;
+ SCROW nMaxRow = 0;
+ SCTAB nTab = 0;
+
+ sal_uInt16 nFileId = 0;
+ svl::SharedString aExtTabName;
+ bool bExternal = false;
+
+ vector<ScTokenRef>::const_iterator itr = rRefTokens.begin(), itrEnd = rRefTokens.end();
+
+ // Get the first ref token.
+ ScTokenRef pToken = *itr;
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ {
+ const ScSingleRefData& rData = *pToken->GetSingleRef();
+ nMinCol = rData.Col();
+ nMinRow = rData.Row();
+ nMaxCol = rData.Col();
+ nMaxRow = rData.Row();
+ nTab = rData.Tab();
+ }
+ break;
+ case svDoubleRef:
+ {
+ const ScComplexRefData& rData = *pToken->GetDoubleRef();
+ nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
+ nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
+ nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
+ nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
+ nTab = rData.Ref1.Tab();
+ }
+ break;
+ case svExternalSingleRef:
+ {
+ const ScSingleRefData& rData = *pToken->GetSingleRef();
+ nMinCol = rData.Col();
+ nMinRow = rData.Row();
+ nMaxCol = rData.Col();
+ nMaxRow = rData.Row();
+ nTab = rData.Tab();
+ nFileId = pToken->GetIndex();
+ aExtTabName = pToken->GetString();
+ bExternal = true;
+ }
+ break;
+ case svExternalDoubleRef:
+ {
+ const ScComplexRefData& rData = *pToken->GetDoubleRef();
+ nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
+ nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
+ nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
+ nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
+ nTab = rData.Ref1.Tab();
+ nFileId = pToken->GetIndex();
+ aExtTabName = pToken->GetString();
+ bExternal = true;
+ }
+ break;
+ default:
+ ;
+ }
+
+ // Determine the minimum range enclosing all data ranges. Also make sure
+ // that they are all on the same table.
+
+ for (++itr; itr != itrEnd; ++itr)
+ {
+ pToken = *itr;
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ {
+ const ScSingleRefData& rData = *pToken->GetSingleRef();
+
+ nMinCol = min(nMinCol, rData.Col());
+ nMinRow = min(nMinRow, rData.Row());
+ nMaxCol = max(nMaxCol, rData.Col());
+ nMaxRow = max(nMaxRow, rData.Row());
+ if (nTab != rData.Tab() || bExternal)
+ return false;
+ }
+ break;
+ case svDoubleRef:
+ {
+ const ScComplexRefData& rData = *pToken->GetDoubleRef();
+
+ nMinCol = min(nMinCol, rData.Ref1.Col());
+ nMinCol = min(nMinCol, rData.Ref2.Col());
+ nMinRow = min(nMinRow, rData.Ref1.Row());
+ nMinRow = min(nMinRow, rData.Ref2.Row());
+
+ nMaxCol = max(nMaxCol, rData.Ref1.Col());
+ nMaxCol = max(nMaxCol, rData.Ref2.Col());
+ nMaxRow = max(nMaxRow, rData.Ref1.Row());
+ nMaxRow = max(nMaxRow, rData.Ref2.Row());
+
+ if (nTab != rData.Ref1.Tab() || bExternal)
+ return false;
+ }
+ break;
+ case svExternalSingleRef:
+ {
+ if (!bExternal)
+ return false;
+
+ if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
+ return false;
+
+ const ScSingleRefData& rData = *pToken->GetSingleRef();
+
+ nMinCol = min(nMinCol, rData.Col());
+ nMinRow = min(nMinRow, rData.Row());
+ nMaxCol = max(nMaxCol, rData.Col());
+ nMaxRow = max(nMaxRow, rData.Row());
+ }
+ break;
+ case svExternalDoubleRef:
+ {
+ if (!bExternal)
+ return false;
+
+ if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
+ return false;
+
+ const ScComplexRefData& rData = *pToken->GetDoubleRef();
+
+ nMinCol = min(nMinCol, rData.Ref1.Col());
+ nMinCol = min(nMinCol, rData.Ref2.Col());
+ nMinRow = min(nMinRow, rData.Ref1.Row());
+ nMinRow = min(nMinRow, rData.Ref2.Row());
+
+ nMaxCol = max(nMaxCol, rData.Ref1.Col());
+ nMaxCol = max(nMaxCol, rData.Ref2.Col());
+ nMaxRow = max(nMaxRow, rData.Ref1.Row());
+ nMaxRow = max(nMaxRow, rData.Ref2.Row());
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+ const auto & rSheetLimits = pDoc->GetSheetLimits();
+ if (nMinRow >= nMaxRow || nMinCol >= nMaxCol ||
+ nMinRow >= rSheetLimits.GetMaxRowCount() || nMinCol >= rSheetLimits.GetMaxColCount() ||
+ nMaxRow >= rSheetLimits.GetMaxRowCount() || nMaxCol >= rSheetLimits.GetMaxColCount())
+ {
+ // Invalid range. Bail out.
+ return false;
+ }
+
+ // Check if the following conditions are met:
+
+ // 1) The upper-left corner cell is not included.
+ // 2) The three adjacent cells of that corner cell are included.
+
+ bool bRight = false, bBottom = false, bDiagonal = false;
+ for (const auto& rxToken : rRefTokens)
+ {
+ switch (rxToken->GetType())
+ {
+ case svSingleRef:
+ case svExternalSingleRef:
+ {
+ const ScSingleRefData& rData = *rxToken->GetSingleRef();
+ if (rData.Col() == nMinCol && rData.Row() == nMinRow)
+ // The corner cell is contained.
+ return false;
+
+ if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow)
+ bRight = true;
+
+ if (rData.Col() == nMinCol && rData.Row() == nMinRow+nCornerRowCount)
+ bBottom = true;
+
+ if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow+nCornerRowCount)
+ bDiagonal = true;
+ }
+ break;
+ case svDoubleRef:
+ case svExternalDoubleRef:
+ {
+ const ScComplexRefData& rData = *rxToken->GetDoubleRef();
+ const ScSingleRefData& r1 = rData.Ref1;
+ const ScSingleRefData& r2 = rData.Ref2;
+ if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
+ r1.Row() <= nMinRow && nMinRow <= r2.Row())
+ // The corner cell is contained.
+ return false;
+
+ if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
+ r1.Row() <= nMinRow && nMinRow <= r2.Row())
+ bRight = true;
+
+ if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
+ r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
+ bBottom = true;
+
+ if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
+ r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
+ bDiagonal = true;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+ if (!bRight || !bBottom || !bDiagonal)
+ // Not all the adjacent cells are included. Bail out.
+ return false;
+
+ ScSingleRefData aData;
+ aData.InitFlags();
+ aData.SetFlag3D(true);
+ aData.SetAbsCol(nMinCol);
+ aData.SetAbsRow(nMinRow);
+ aData.SetAbsTab(nTab);
+
+ if( nCornerRowCount==1 && nCornerColumnCount==1 )
+ {
+ if (bExternal)
+ {
+ ScTokenRef pCorner(
+ new ScExternalSingleRefToken(nFileId, aExtTabName, aData));
+ ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
+ }
+ else
+ {
+ ScTokenRef pCorner(new ScSingleRefToken(pDoc->GetSheetLimits(), aData));
+ ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
+ }
+ }
+ else
+ {
+ ScSingleRefData aDataEnd(aData);
+ aDataEnd.IncCol(nCornerColumnCount-1);
+ aDataEnd.IncRow(nCornerRowCount-1);
+ ScComplexRefData r;
+ r.Ref1=aData;
+ r.Ref2=aDataEnd;
+ if (bExternal)
+ {
+ ScTokenRef pCorner(
+ new ScExternalDoubleRefToken(nFileId, aExtTabName, r));
+ ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
+ }
+ else
+ {
+ ScTokenRef pCorner(new ScDoubleRefToken(pDoc->GetSheetLimits(), r));
+ ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
+ }
+ }
+
+ return true;
+}
+
+#define SHRINK_RANGE_THRESHOLD 10000
+
+class ShrinkRefTokenToDataRange
+{
+ ScDocument* mpDoc;
+public:
+ explicit ShrinkRefTokenToDataRange(ScDocument* pDoc) : mpDoc(pDoc) {}
+ void operator() (const ScTokenRef& rRef)
+ {
+ if (ScRefTokenHelper::isExternalRef(rRef))
+ return;
+
+ // Don't assume an ScDoubleRefToken if it isn't. It can be at least an
+ // ScSingleRefToken, then there isn't anything to shrink.
+ if (rRef->GetType() != svDoubleRef)
+ return;
+
+ ScComplexRefData& rData = *rRef->GetDoubleRef();
+ ScSingleRefData& s = rData.Ref1;
+ ScSingleRefData& e = rData.Ref2;
+
+ if(abs((e.Col()-s.Col())*(e.Row()-s.Row())) < SHRINK_RANGE_THRESHOLD)
+ return;
+
+ SCCOL nMinCol = mpDoc->MaxCol(), nMaxCol = 0;
+ SCROW nMinRow = mpDoc->MaxRow(), nMaxRow = 0;
+
+ // Determine the smallest range that encompasses the data ranges of all sheets.
+ SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
+ for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
+ {
+ SCCOL nCol1 = 0, nCol2 = mpDoc->MaxCol();
+ SCROW nRow1 = 0, nRow2 = mpDoc->MaxRow();
+ mpDoc->ShrinkToDataArea(nTab, nCol1, nRow1, nCol2, nRow2);
+ nMinCol = std::min(nMinCol, nCol1);
+ nMinRow = std::min(nMinRow, nRow1);
+ nMaxCol = std::max(nMaxCol, nCol2);
+ nMaxRow = std::max(nMaxRow, nRow2);
+ }
+
+ // Shrink range to the data range if applicable.
+ if (s.Col() < nMinCol)
+ s.SetAbsCol(nMinCol);
+ if (s.Row() < nMinRow)
+ s.SetAbsRow(nMinRow);
+ if (e.Col() > nMaxCol)
+ e.SetAbsCol(nMaxCol);
+ if (e.Row() > nMaxRow)
+ e.SetAbsRow(nMaxRow);
+ }
+};
+
+void shrinkToDataRange(ScDocument* pDoc, vector<ScTokenRef>& rRefTokens)
+{
+ std::for_each(rRefTokens.begin(), rRefTokens.end(), ShrinkRefTokenToDataRange(pDoc));
+}
+
+}
+
+uno::Reference< chart2::data::XDataSource> SAL_CALL
+ScChart2DataProvider::createDataSource(
+ const uno::Sequence< beans::PropertyValue >& aArguments )
+{
+ SolarMutexGuard aGuard;
+ if ( ! m_pDocument )
+ throw uno::RuntimeException();
+
+ uno::Reference< chart2::data::XDataSource> xResult;
+ bool bLabel = true;
+ bool bCategories = false;
+ bool bOrientCol = true;
+ OUString aRangeRepresentation;
+ uno::Sequence< sal_Int32 > aSequenceMapping;
+ bool bTimeBased = false;
+ for(const auto& rArgument : aArguments)
+ {
+ if ( rArgument.Name == "DataRowSource" )
+ {
+ chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
+ if( ! (rArgument.Value >>= eSource))
+ {
+ sal_Int32 nSource(0);
+ if( rArgument.Value >>= nSource )
+ eSource = static_cast< chart::ChartDataRowSource >( nSource );
+ }
+ bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
+ }
+ else if ( rArgument.Name == "FirstCellAsLabel" )
+ {
+ bLabel = ::cppu::any2bool(rArgument.Value);
+ }
+ else if ( rArgument.Name == "HasCategories" )
+ {
+ bCategories = ::cppu::any2bool(rArgument.Value);
+ }
+ else if ( rArgument.Name == "CellRangeRepresentation" )
+ {
+ rArgument.Value >>= aRangeRepresentation;
+ }
+ else if ( rArgument.Name == "SequenceMapping" )
+ {
+ rArgument.Value >>= aSequenceMapping;
+ }
+ else if ( rArgument.Name == "TimeBased" )
+ {
+ rArgument.Value >>= bTimeBased;
+ }
+ }
+
+ vector<ScTokenRef> aRefTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ if (aRefTokens.empty())
+ // Invalid range representation. Bail out.
+ throw lang::IllegalArgumentException();
+
+ SCTAB nTimeBasedStart = MAXTAB;
+ SCTAB nTimeBasedEnd = 0;
+ if(bTimeBased)
+ {
+ // limit to first sheet
+ for(const auto& rxToken : aRefTokens)
+ {
+ if (rxToken->GetType() != svDoubleRef)
+ continue;
+
+ ScComplexRefData& rData = *rxToken->GetDoubleRef();
+ ScSingleRefData& s = rData.Ref1;
+ ScSingleRefData& e = rData.Ref2;
+
+ nTimeBasedStart = std::min(nTimeBasedStart, s.Tab());
+ nTimeBasedEnd = std::min(nTimeBasedEnd, e.Tab());
+
+ if(s.Tab() != e.Tab())
+ e.SetAbsTab(s.Tab());
+ }
+ }
+
+ if(!bTimeBased)
+ shrinkToDataRange(m_pDocument, aRefTokens);
+
+ if (bLabel)
+ lcl_addUpperLeftCornerIfMissing(m_pDocument, aRefTokens, 1, 1); //#i90669#
+
+ bool bColHeaders = (bOrientCol ? bLabel : bCategories );
+ bool bRowHeaders = (bOrientCol ? bCategories : bLabel );
+
+ Chart2Positioner aChPositioner(m_pDocument, aRefTokens);
+ aChPositioner.setHeaders(bColHeaders, bRowHeaders);
+
+ const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap();
+ if (!pChartMap)
+ // No chart position map instance. Bail out.
+ return xResult;
+
+ rtl::Reference<ScChart2DataSource> pDS;
+ ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqs;
+
+ // Fill Categories
+ if( bCategories )
+ {
+ vector<ScTokenRef> aValueTokens;
+ if (bOrientCol)
+ aValueTokens = pChartMap->getAllRowHeaderRanges();
+ else
+ aValueTokens = pChartMap->getAllColHeaderRanges();
+
+ vector<ScTokenRef> aLabelTokens(
+ pChartMap->getLeftUpperCornerRanges());
+
+ uno::Reference< chart2::data::XLabeledDataSequence > xCategories = lcl_createLabeledDataSequenceFromTokens(
+ std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
+ if ( xCategories.is() )
+ {
+ aSeqs.push_back( xCategories );
+ }
+ }
+
+ // Fill Series (values and label)
+ sal_Int32 nCount = bOrientCol ? pChartMap->getDataColCount() : pChartMap->getDataRowCount();
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ vector<ScTokenRef> aValueTokens;
+ vector<ScTokenRef> aLabelTokens;
+ if (bOrientCol)
+ {
+ aValueTokens = pChartMap->getDataColRanges(static_cast<SCCOL>(i));
+ aLabelTokens = pChartMap->getColHeaderRanges(static_cast<SCCOL>(i));
+ }
+ else
+ {
+ aValueTokens = pChartMap->getDataRowRanges(static_cast<SCROW>(i));
+ aLabelTokens = pChartMap->getRowHeaderRanges(static_cast<SCROW>(i));
+ }
+ uno::Reference< chart2::data::XLabeledDataSequence > xChartSeries = lcl_createLabeledDataSequenceFromTokens(
+ std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
+ if ( xChartSeries.is() && xChartSeries->getValues().is() && xChartSeries->getValues()->getData().hasElements() )
+ {
+ aSeqs.push_back( xChartSeries );
+ }
+ }
+
+ pDS = new ScChart2DataSource(m_pDocument);
+
+ //reorder labeled sequences according to aSequenceMapping
+ ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqVector;
+ aSeqVector.reserve(aSeqs.size());
+ for (auto const& aSeq : aSeqs)
+ {
+ aSeqVector.push_back(aSeq);
+ }
+
+ for( const sal_Int32 nNewIndex : std::as_const(aSequenceMapping) )
+ {
+ // note: assuming that the values in the sequence mapping are always non-negative
+ ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > >::size_type nOldIndex( static_cast< sal_uInt32 >( nNewIndex ) );
+ if( nOldIndex < aSeqVector.size() )
+ {
+ pDS->AddLabeledSequence( aSeqVector[nOldIndex] );
+ aSeqVector[nOldIndex] = nullptr;
+ }
+ }
+
+ for(const uno::Reference< chart2::data::XLabeledDataSequence >& xSeq : aSeqVector)
+ {
+ if ( xSeq.is() )
+ {
+ pDS->AddLabeledSequence( xSeq );
+ }
+ }
+
+ xResult.set( pDS );
+ return xResult;
+}
+
+namespace
+{
+
+/**
+ * Function object to create a list of table numbers from a token list.
+ */
+class InsertTabNumber
+{
+public:
+ InsertTabNumber() :
+ mpTabNumVector(std::make_shared<vector<SCTAB>>())
+ {
+ }
+
+ void operator() (const ScTokenRef& pToken) const
+ {
+ if (!ScRefTokenHelper::isRef(pToken))
+ return;
+
+ const ScSingleRefData& r = *pToken->GetSingleRef();
+ mpTabNumVector->push_back(r.Tab());
+ }
+
+ void getVector(vector<SCTAB>& rVector)
+ {
+ mpTabNumVector->swap(rVector);
+ }
+private:
+ shared_ptr< vector<SCTAB> > mpTabNumVector;
+};
+
+class RangeAnalyzer
+{
+public:
+ RangeAnalyzer();
+ void initRangeAnalyzer( const ScDocument* pDoc, const vector<ScTokenRef>& rTokens );
+ void analyzeRange( sal_Int32& rnDataInRows, sal_Int32& rnDataInCols,
+ bool& rbRowSourceAmbiguous ) const;
+ bool inSameSingleRow( const RangeAnalyzer& rOther );
+ bool inSameSingleColumn( const RangeAnalyzer& rOther );
+ SCROW getRowCount() const { return mnRowCount; }
+ SCCOL getColumnCount() const { return mnColumnCount; }
+
+private:
+ bool mbEmpty;
+ bool mbAmbiguous;
+ SCROW mnRowCount;
+ SCCOL mnColumnCount;
+
+ SCCOL mnStartColumn;
+ SCROW mnStartRow;
+};
+
+RangeAnalyzer::RangeAnalyzer()
+ : mbEmpty(true)
+ , mbAmbiguous(false)
+ , mnRowCount(0)
+ , mnColumnCount(0)
+ , mnStartColumn(-1)
+ , mnStartRow(-1)
+{
+}
+
+void RangeAnalyzer::initRangeAnalyzer( const ScDocument* pDoc, const vector<ScTokenRef>& rTokens )
+{
+ mnRowCount=0;
+ mnColumnCount=0;
+ mnStartColumn = -1;
+ mnStartRow = -1;
+ mbAmbiguous=false;
+ if( rTokens.empty() )
+ {
+ mbEmpty=true;
+ return;
+ }
+ mbEmpty=false;
+
+ for (const ScTokenRef& aRefToken : rTokens)
+ {
+ StackVar eVar = aRefToken->GetType();
+ if (eVar == svDoubleRef || eVar == svExternalDoubleRef)
+ {
+ const ScComplexRefData& r = *aRefToken->GetDoubleRef();
+ if (r.Ref1.Tab() == r.Ref2.Tab())
+ {
+ mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(r.Ref2.Col() - r.Ref1.Col())+1));
+ mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(r.Ref2.Row() - r.Ref1.Row())+1));
+ if( mnStartColumn == -1 )
+ {
+ mnStartColumn = r.Ref1.Col();
+ mnStartRow = r.Ref1.Row();
+ }
+ else
+ {
+ if (mnStartColumn != r.Ref1.Col() && mnStartRow != r.Ref1.Row())
+ mbAmbiguous=true;
+ }
+ }
+ else
+ mbAmbiguous=true;
+ }
+ else if (eVar == svSingleRef || eVar == svExternalSingleRef)
+ {
+ const ScSingleRefData& r = *aRefToken->GetSingleRef();
+ mnColumnCount = std::max<SCCOL>( mnColumnCount, 1);
+ mnRowCount = std::max<SCROW>( mnRowCount, 1);
+ if( mnStartColumn == -1 )
+ {
+ mnStartColumn = r.Col();
+ mnStartRow = r.Row();
+ }
+ else
+ {
+ if (mnStartColumn != r.Col() && mnStartRow != r.Row())
+ mbAmbiguous=true;
+ }
+ }
+ else if (eVar == svIndex && aRefToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = pDoc->FindRangeNameBySheetAndIndex(aRefToken->GetSheet(), aRefToken->GetIndex());
+ ScRange aRange;
+ if (pNameRange->IsReference(aRange))
+ {
+ mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(aRange.aEnd.Col() - aRange.aStart.Col()) + 1));
+ mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(aRange.aEnd.Row() - aRange.aStart.Row()) + 1));
+ if (mnStartColumn == -1)
+ {
+ mnStartColumn = aRange.aStart.Col();
+ mnStartRow = aRange.aStart.Row();
+ }
+ else
+ {
+ if (mnStartColumn != aRange.aStart.Col() && mnStartRow != aRange.aStart.Row())
+ mbAmbiguous = true;
+ }
+ }
+ else
+ mbAmbiguous = true;
+ }
+ else
+ mbAmbiguous=true;
+ }
+}
+
+void RangeAnalyzer::analyzeRange( sal_Int32& rnDataInRows,
+ sal_Int32& rnDataInCols,
+ bool& rbRowSourceAmbiguous ) const
+{
+ if(!mbEmpty && !mbAmbiguous)
+ {
+ if( mnRowCount==1 && mnColumnCount>1 )
+ ++rnDataInRows;
+ else if( mnColumnCount==1 && mnRowCount>1 )
+ ++rnDataInCols;
+ else if( mnRowCount>1 && mnColumnCount>1 )
+ rbRowSourceAmbiguous = true;
+ }
+ else if( !mbEmpty )
+ rbRowSourceAmbiguous = true;
+}
+
+bool RangeAnalyzer::inSameSingleRow( const RangeAnalyzer& rOther )
+{
+ return mnStartRow==rOther.mnStartRow &&
+ mnRowCount==1 && rOther.mnRowCount==1;
+}
+
+bool RangeAnalyzer::inSameSingleColumn( const RangeAnalyzer& rOther )
+{
+ return mnStartColumn==rOther.mnStartColumn &&
+ mnColumnCount==1 && rOther.mnColumnCount==1;
+}
+
+std::pair<OUString, OUString> constructKey(const uno::Reference< chart2::data::XLabeledDataSequence>& xNew)
+{
+ std::pair<OUString, OUString> aKey;
+ if( xNew->getLabel().is() )
+ aKey.first = xNew->getLabel()->getSourceRangeRepresentation();
+ if( xNew->getValues().is() )
+ aKey.second = xNew->getValues()->getSourceRangeRepresentation();
+ return aKey;
+}
+
+
+} //end anonymous namespace
+
+uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments(
+ const uno::Reference< chart2::data::XDataSource >& xDataSource )
+{
+ ::std::vector< beans::PropertyValue > aResult;
+ bool bRowSourceDetected = false;
+ bool bFirstCellAsLabel = false;
+ bool bHasCategories = false;
+ OUString sRangeRep;
+
+ bool bHasCategoriesLabels = false;
+ vector<ScTokenRef> aAllCategoriesValuesTokens;
+ vector<ScTokenRef> aAllSeriesLabelTokens;
+
+ chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS;
+
+ vector<ScTokenRef> aAllTokens;
+
+ // parse given data source and collect infos
+ {
+ SolarMutexGuard aGuard;
+ OSL_ENSURE( m_pDocument, "No Document -> no detectArguments" );
+ if(!m_pDocument ||!xDataSource.is())
+ return comphelper::containerToSequence( aResult );
+
+ sal_Int32 nDataInRows = 0;
+ sal_Int32 nDataInCols = 0;
+ bool bRowSourceAmbiguous = false;
+
+ const Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences());
+ const sal_Int32 nCount( aSequences.getLength());
+ RangeAnalyzer aPrevLabel,aPrevValues;
+ for( const uno::Reference< chart2::data::XLabeledDataSequence >& xLS : aSequences )
+ {
+ if( xLS.is() )
+ {
+ bool bThisIsCategories = false;
+ if(!bHasCategories)
+ {
+ uno::Reference< beans::XPropertySet > xSeqProp( xLS->getValues(), uno::UNO_QUERY );
+ OUString aRole;
+ if( xSeqProp.is() && (xSeqProp->getPropertyValue("Role") >>= aRole) &&
+ aRole == "categories" )
+ bThisIsCategories = bHasCategories = true;
+ }
+
+ RangeAnalyzer aLabel,aValues;
+ // label
+ uno::Reference< chart2::data::XDataSequence > xLabel( xLS->getLabel());
+ if( xLabel.is())
+ {
+ bFirstCellAsLabel = true;
+ vector<ScTokenRef> aTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aTokens, xLabel->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ aLabel.initRangeAnalyzer(m_pDocument, aTokens);
+ for (const auto& rxToken : aTokens)
+ {
+ if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
+ if (pNameRange->HasReferences())
+ {
+ const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ if(!bThisIsCategories)
+ ScRefTokenHelper::join(m_pDocument, aAllSeriesLabelTokens, rxToken, ScAddress());
+ }
+ if(bThisIsCategories)
+ bHasCategoriesLabels=true;
+ }
+ // values
+ uno::Reference< chart2::data::XDataSequence > xValues( xLS->getValues());
+ if( xValues.is())
+ {
+ vector<ScTokenRef> aTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aTokens, xValues->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ aValues.initRangeAnalyzer(m_pDocument, aTokens);
+ for (const auto& rxToken : aTokens)
+ {
+ if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
+ if (pNameRange->HasReferences())
+ {
+ const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ if(bThisIsCategories)
+ ScRefTokenHelper::join(m_pDocument, aAllCategoriesValuesTokens, rxToken, ScAddress());
+ }
+ }
+ //detect row source
+ if(!bThisIsCategories || nCount==1) //categories might span multiple rows *and* columns, so they should be used for detection only if nothing else is available
+ {
+ if (!bRowSourceAmbiguous)
+ {
+ aValues.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
+ aLabel.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
+ if (nDataInRows > 1 && nDataInCols > 1)
+ bRowSourceAmbiguous = true;
+ else if( !bRowSourceAmbiguous && !nDataInRows && !nDataInCols )
+ {
+ if( aValues.inSameSingleColumn( aLabel ) )
+ nDataInCols++;
+ else if( aValues.inSameSingleRow( aLabel ) )
+ nDataInRows++;
+ else
+ {
+ //#i86188# also detect a single column split into rows correctly
+ if( aValues.inSameSingleColumn( aPrevValues ) )
+ nDataInRows++;
+ else if( aValues.inSameSingleRow( aPrevValues ) )
+ nDataInCols++;
+ else if( aLabel.inSameSingleColumn( aPrevLabel ) )
+ nDataInRows++;
+ else if( aLabel.inSameSingleRow( aPrevLabel ) )
+ nDataInCols++;
+ }
+ }
+ }
+ }
+ aPrevValues=aValues;
+ aPrevLabel=aLabel;
+ }
+ }
+
+ if (!bRowSourceAmbiguous)
+ {
+ bRowSourceDetected = true;
+ eRowSource = ( nDataInCols > 0
+ ? chart::ChartDataRowSource_COLUMNS
+ : chart::ChartDataRowSource_ROWS );
+ }
+ else
+ {
+ // set DataRowSource to the better of the two ambiguities
+ eRowSource = ( nDataInRows > nDataInCols
+ ? chart::ChartDataRowSource_ROWS
+ : chart::ChartDataRowSource_COLUMNS );
+ }
+
+ }
+
+ // TableNumberList
+ {
+ vector<SCTAB> aTableNumVector;
+ InsertTabNumber func;
+ func = ::std::for_each(aAllTokens.begin(), aAllTokens.end(), func);
+ func.getVector(aTableNumVector);
+ aResult.emplace_back( "TableNumberList", -1,
+ uno::Any( lcl_createTableNumberList( aTableNumVector ) ),
+ beans::PropertyState_DIRECT_VALUE );
+ }
+
+ if( bRowSourceDetected )
+ {
+ // DataRowSource (calculated before)
+ aResult.emplace_back( "DataRowSource", -1,
+ uno::Any( eRowSource ), beans::PropertyState_DIRECT_VALUE );
+ // HasCategories
+ aResult.emplace_back( "HasCategories", -1,
+ uno::Any( bHasCategories ), beans::PropertyState_DIRECT_VALUE );
+ // FirstCellAsLabel
+ aResult.emplace_back( "FirstCellAsLabel", -1,
+ uno::Any( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE );
+ }
+
+ // Add the left upper corner to the range if it is missing.
+ if (bRowSourceDetected && bFirstCellAsLabel && bHasCategories && !bHasCategoriesLabels )
+ {
+ RangeAnalyzer aTop,aLeft;
+ if( eRowSource==chart::ChartDataRowSource_COLUMNS )
+ {
+ aTop.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
+ aLeft.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
+ }
+ else
+ {
+ aTop.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
+ aLeft.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
+ }
+ lcl_addUpperLeftCornerIfMissing(m_pDocument, aAllTokens, aTop.getRowCount(), aLeft.getColumnCount());//e.g. #i91212#
+ }
+
+ // Get range string.
+ lcl_convertTokensToString(sRangeRep, aAllTokens, *m_pDocument);
+
+ // add cell range property
+ aResult.emplace_back( "CellRangeRepresentation", -1,
+ uno::Any( sRangeRep ), beans::PropertyState_DIRECT_VALUE );
+
+ //Sequence Mapping
+ bool const bSequencesReordered = true;//todo detect this above or detect this sequence mapping cheaper ...
+ if( bSequencesReordered && bRowSourceDetected )
+ {
+ bool bDifferentIndexes = false;
+
+ std::vector< sal_Int32 > aSequenceMappingVector;
+
+ uno::Reference< chart2::data::XDataSource > xCompareDataSource;
+ try
+ {
+ xCompareDataSource.set( createDataSource( comphelper::containerToSequence( aResult ) ) );
+ }
+ catch( const lang::IllegalArgumentException & )
+ {
+ // creation of data source to compare didn't work, so we cannot
+ // create a sequence mapping
+ }
+
+ if( xDataSource.is() && xCompareDataSource.is() )
+ {
+ const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aOldSequences =
+ xCompareDataSource->getDataSequences();
+ const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aNewSequences =
+ xDataSource->getDataSequences();
+
+ std::map<std::pair<OUString, OUString>,sal_Int32> aOldEntryToIndex;
+ for( sal_Int32 nIndex = 0, n = aOldSequences.getLength(); nIndex < n; nIndex++ )
+ {
+ const uno::Reference< chart2::data::XLabeledDataSequence>& xOld( aOldSequences[nIndex] );
+ if( xOld.is() )
+ {
+ std::pair<OUString, OUString> aKey = constructKey(xOld);
+ aOldEntryToIndex[aKey] = nIndex;
+ }
+ }
+
+ for( sal_Int32 nNewIndex = 0, n = aNewSequences.getLength(); nNewIndex < n; nNewIndex++ )
+ {
+ const uno::Reference< chart2::data::XLabeledDataSequence>& xNew( aNewSequences[nNewIndex] );
+ if( !xNew.is() )
+ continue;
+
+ std::pair<OUString, OUString> aKey = constructKey(xNew);
+ if (aOldEntryToIndex.find(aKey) == aOldEntryToIndex.end())
+ continue;
+
+ sal_Int32 nOldIndex = aOldEntryToIndex[aKey];
+ if( nOldIndex != nNewIndex )
+ bDifferentIndexes = true;
+
+ aSequenceMappingVector.push_back(nOldIndex);
+ }
+ }
+
+ if( bDifferentIndexes && !aSequenceMappingVector.empty() )
+ {
+ aResult.emplace_back( "SequenceMapping", -1,
+ uno::Any( comphelper::containerToSequence(aSequenceMappingVector) )
+ , beans::PropertyState_DIRECT_VALUE );
+ }
+ }
+
+ return comphelper::containerToSequence( aResult );
+}
+
+sal_Bool SAL_CALL ScChart2DataProvider::createDataSequenceByRangeRepresentationPossible( const OUString& aRangeRepresentation )
+{
+ SolarMutexGuard aGuard;
+ if( ! m_pDocument )
+ return false;
+
+ vector<ScTokenRef> aTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ return !aTokens.empty();
+}
+
+uno::Reference< chart2::data::XDataSequence > SAL_CALL
+ ScChart2DataProvider::createDataSequenceByRangeRepresentation(
+ const OUString& aRangeRepresentation )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< chart2::data::XDataSequence > xResult;
+
+ OSL_ENSURE( m_pDocument, "No Document -> no createDataSequenceByRangeRepresentation" );
+ if(!m_pDocument || aRangeRepresentation.isEmpty())
+ return xResult;
+
+ vector<ScTokenRef> aRefTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ if (aRefTokens.empty())
+ return xResult;
+
+ shrinkToDataRange(m_pDocument, aRefTokens);
+
+ xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
+
+ return xResult;
+}
+
+uno::Reference<chart2::data::XDataSequence> SAL_CALL
+ScChart2DataProvider::createDataSequenceByValueArray(
+ const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/,
+ const OUString& /*aRoleQualifier*/ )
+{
+ return uno::Reference<chart2::data::XDataSequence>();
+}
+
+uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRangeSelection()
+{
+ uno::Reference< sheet::XRangeSelection > xResult;
+
+ uno::Reference< frame::XModel > xModel( lcl_GetXModel( m_pDocument ));
+ if( xModel.is())
+ xResult.set( xModel->getCurrentController(), uno::UNO_QUERY );
+
+ return xResult;
+}
+
+sal_Bool SAL_CALL ScChart2DataProvider::createDataSequenceByFormulaTokensPossible(
+ const Sequence<sheet::FormulaToken>& aTokens )
+{
+ if (!aTokens.hasElements())
+ return false;
+
+ ScTokenArray aCode(*m_pDocument);
+ if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
+ return false;
+
+ sal_uInt16 n = aCode.GetLen();
+ if (!n)
+ return false;
+
+ formula::FormulaTokenArrayPlainIterator aIter(aCode);
+ const formula::FormulaToken* pFirst = aIter.First();
+ const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
+ for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
+ {
+ switch (p->GetType())
+ {
+ case svSep:
+ {
+ switch (p->GetOpCode())
+ {
+ case ocSep:
+ // separators are allowed.
+ break;
+ case ocOpen:
+ if (p != pFirst)
+ // open paran is allowed only as the first token.
+ return false;
+ break;
+ case ocClose:
+ if (p != pLast)
+ // close paren is allowed only as the last token.
+ return false;
+ break;
+ default:
+ return false;
+ }
+ }
+ break;
+ case svSingleRef:
+ case svDoubleRef:
+ case svExternalSingleRef:
+ case svExternalDoubleRef:
+ break;
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
+uno::Reference<chart2::data::XDataSequence> SAL_CALL
+ScChart2DataProvider::createDataSequenceByFormulaTokens(
+ const Sequence<sheet::FormulaToken>& aTokens )
+{
+ uno::Reference<chart2::data::XDataSequence> xResult;
+ if (!aTokens.hasElements())
+ return xResult;
+
+ ScTokenArray aCode(*m_pDocument);
+ if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
+ return xResult;
+
+ sal_uInt16 n = aCode.GetLen();
+ if (!n)
+ return xResult;
+
+ vector<ScTokenRef> aRefTokens;
+ formula::FormulaTokenArrayPlainIterator aIter(aCode);
+ const formula::FormulaToken* pFirst = aIter.First();
+ const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
+ for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
+ {
+ switch (p->GetType())
+ {
+ case svSep:
+ {
+ switch (p->GetOpCode())
+ {
+ case ocSep:
+ // separators are allowed.
+ break;
+ case ocOpen:
+ if (p != pFirst)
+ // open paran is allowed only as the first token.
+ throw lang::IllegalArgumentException();
+ break;
+ case ocClose:
+ if (p != pLast)
+ // close paren is allowed only as the last token.
+ throw lang::IllegalArgumentException();
+ break;
+ default:
+ throw lang::IllegalArgumentException();
+ }
+ }
+ break;
+ case svIndex:
+ case svString:
+ case svSingleRef:
+ case svDoubleRef:
+ case svExternalSingleRef:
+ case svExternalDoubleRef:
+ {
+ ScTokenRef pNew(p->Clone());
+ aRefTokens.push_back(pNew);
+ }
+ break;
+ default:
+ throw lang::IllegalArgumentException();
+ }
+ }
+
+ if (aRefTokens.empty())
+ return xResult;
+
+ shrinkToDataRange(m_pDocument, aRefTokens);
+
+ xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
+ return xResult;
+}
+
+// XRangeXMLConversion ---------------------------------------------------
+
+OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const OUString& sRangeRepresentation )
+{
+ OUString aRet;
+ if (!m_pDocument)
+ return aRet;
+
+ if (sRangeRepresentation.isEmpty())
+ // Empty data range is allowed.
+ return aRet;
+
+ vector<ScTokenRef> aRefTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aRefTokens, sRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ if (aRefTokens.empty())
+ {
+ SAL_WARN("sc", "convertRangeToXML throw IllegalArgumentException from input of: " << sRangeRepresentation);
+ throw lang::IllegalArgumentException();
+ }
+
+ Tokens2RangeStringXML converter(*m_pDocument);
+ converter = ::std::for_each(aRefTokens.begin(), aRefTokens.end(), converter);
+ converter.getString(aRet);
+
+ return aRet;
+}
+
+OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const OUString& sXMLRange )
+{
+ if (!m_pDocument)
+ {
+ // #i74062# When loading flat XML, this is called before the referenced sheets are in the document,
+ // so the conversion has to take place directly with the strings, without looking up the sheets.
+
+ OUStringBuffer sRet;
+ sal_Int32 nOffset = 0;
+ while( nOffset >= 0 )
+ {
+ OUString sToken;
+ ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset );
+ if( nOffset >= 0 )
+ {
+ // convert one address (remove dots)
+
+ OUString aUIString(sToken);
+
+ sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0 );
+ if ( nIndex >= 0 && nIndex < aUIString.getLength() - 1 &&
+ aUIString[nIndex + 1] == '.' )
+ aUIString = aUIString.replaceAt( nIndex + 1, 1, u"" );
+
+ if ( aUIString[0] == '.' )
+ aUIString = aUIString.copy( 1 );
+
+ if( !sRet.isEmpty() )
+ sRet.append( ';' );
+ sRet.append( aUIString );
+ }
+ }
+
+ return sRet.makeStringAndClear();
+ }
+
+ OUString aRet;
+ ScRangeStringConverter::GetStringFromXMLRangeString(aRet, sXMLRange, *m_pDocument);
+ return aRet;
+}
+
+// DataProvider XPropertySet -------------------------------------------------
+
+uno::Reference< beans::XPropertySetInfo> SAL_CALL
+ScChart2DataProvider::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL ScChart2DataProvider::setPropertyValue(
+ const OUString& rPropertyName, const uno::Any& rValue)
+{
+ if ( rPropertyName != SC_UNONAME_INCLUDEHIDDENCELLS )
+ throw beans::UnknownPropertyException(rPropertyName);
+
+ if ( !(rValue >>= m_bIncludeHiddenCells))
+ throw lang::IllegalArgumentException();
+
+}
+
+uno::Any SAL_CALL ScChart2DataProvider::getPropertyValue(
+ const OUString& rPropertyName)
+{
+ uno::Any aRet;
+ if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
+ aRet <<= m_bIncludeHiddenCells;
+ else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
+ {
+ // This is a read-only property.
+ aRet <<= m_pDocument->PastingDrawFromOtherDoc();
+ }
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+ return aRet;
+}
+
+void SAL_CALL ScChart2DataProvider::addPropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
+{
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataProvider::removePropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
+{
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataProvider::addVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
+{
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataProvider::removeVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/ )
+{
+ OSL_FAIL( "Not yet implemented" );
+}
+
+// DataSource ================================================================
+
+ScChart2DataSource::ScChart2DataSource( ScDocument* pDoc)
+ : m_pDocument( pDoc)
+{
+ if ( m_pDocument )
+ m_pDocument->AddUnoObject( *this);
+}
+
+ScChart2DataSource::~ScChart2DataSource()
+{
+ SolarMutexGuard g;
+
+ if ( m_pDocument )
+ m_pDocument->RemoveUnoObject( *this);
+}
+
+void ScChart2DataSource::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ m_pDocument = nullptr;
+ }
+}
+
+uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > SAL_CALL
+ScChart2DataSource::getDataSequences()
+{
+ SolarMutexGuard aGuard;
+ return comphelper::containerToSequence(m_aLabeledSequences);
+}
+
+void ScChart2DataSource::AddLabeledSequence(const uno::Reference < chart2::data::XLabeledDataSequence >& xNew)
+{
+ m_aLabeledSequences.push_back(xNew);
+}
+
+// DataSequence ==============================================================
+
+ScChart2DataSequence::Item::Item()
+ : mfValue(std::numeric_limits<double>::quiet_NaN())
+ , mbIsValue(false)
+{
+}
+
+ScChart2DataSequence::HiddenRangeListener::HiddenRangeListener(ScChart2DataSequence& rParent) :
+ mrParent(rParent)
+{
+}
+
+ScChart2DataSequence::HiddenRangeListener::~HiddenRangeListener()
+{
+}
+
+void ScChart2DataSequence::HiddenRangeListener::notify()
+{
+ mrParent.setDataChangedHint(true);
+}
+
+ScChart2DataSequence::ScChart2DataSequence( ScDocument* pDoc,
+ vector<ScTokenRef>&& rTokens,
+ bool bIncludeHiddenCells )
+ : m_xDataArray(new std::vector<Item>)
+ , m_bIncludeHiddenCells( bIncludeHiddenCells)
+ , m_nObjectId( 0 )
+ , m_pDocument( pDoc)
+ , m_aTokens(std::move(rTokens))
+ , m_aPropSet(lcl_GetDataSequencePropertyMap())
+ , m_bGotDataChangedHint(false)
+ , m_bExtDataRebuildQueued(false)
+ , mbTimeBased(false)
+ , mnTimeBasedStart(0)
+ , mnTimeBasedEnd(0)
+ , mnCurrentTab(0)
+{
+ if ( m_pDocument )
+ {
+ m_pDocument->AddUnoObject( *this);
+ m_nObjectId = m_pDocument->GetNewUnoId();
+ }
+ // FIXME: real implementation of identifier and it's mapping to ranges.
+ // Reuse ScChartListener?
+
+ // BM: don't use names of named ranges but the UI range strings
+// String aStr;
+// rRangeList->Format( aStr, ScRefFlags::RANGE_ABS_3D, m_pDocument );
+// m_aIdentifier = aStr;
+
+// m_aIdentifier = "ID_";
+// static sal_Int32 nID = 0;
+// m_aIdentifier += OUString::valueOf( ++nID);
+}
+
+/** called from Clone() */
+ScChart2DataSequence::ScChart2DataSequence(ScDocument* pDoc, const ScChart2DataSequence& r)
+ : m_xDataArray(r.m_xDataArray)
+ , m_aHiddenValues(r.m_aHiddenValues)
+ , m_aRole(r.m_aRole)
+ , m_bIncludeHiddenCells( r.m_bIncludeHiddenCells)
+ , m_nObjectId( 0 )
+ , m_pDocument( pDoc)
+ , m_aPropSet(lcl_GetDataSequencePropertyMap())
+ , m_bGotDataChangedHint(false)
+ , m_bExtDataRebuildQueued(false)
+ , mbTimeBased(false)
+ , mnTimeBasedStart(0)
+ , mnTimeBasedEnd(0)
+ , mnCurrentTab(0)
+{
+ assert(pDoc);
+
+ // Clone tokens.
+ m_aTokens.reserve(r.m_aTokens.size());
+ for (const auto& rxToken : r.m_aTokens)
+ {
+ ScTokenRef p(rxToken->Clone());
+ m_aTokens.push_back(p);
+ }
+
+ m_pDocument->AddUnoObject( *this);
+ m_nObjectId = m_pDocument->GetNewUnoId();
+
+ if (r.m_oRangeIndices)
+ m_oRangeIndices = *r.m_oRangeIndices;
+
+ if (!r.m_pExtRefListener)
+ return;
+
+ // Re-register all external files that the old instance was
+ // listening to.
+
+ ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
+ m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
+ const std::unordered_set<sal_uInt16>& rFileIds = r.m_pExtRefListener->getAllFileIds();
+ for (const auto& rFileId : rFileIds)
+ {
+ pRefMgr->addLinkListener(rFileId, m_pExtRefListener.get());
+ m_pExtRefListener->addFileId(rFileId);
+ }
+}
+
+ScChart2DataSequence::~ScChart2DataSequence()
+{
+ SolarMutexGuard g;
+
+ if ( m_pDocument )
+ {
+ m_pDocument->RemoveUnoObject( *this);
+ if (m_pHiddenListener)
+ {
+ ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
+ if (pCLC)
+ pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
+ }
+ StopListeningToAllExternalRefs();
+ }
+
+ m_pValueListener.reset();
+}
+
+void ScChart2DataSequence::RefChanged()
+{
+ if( !m_pValueListener || m_aValueListeners.empty() )
+ return;
+
+ m_pValueListener->EndListeningAll();
+
+ if( !m_pDocument )
+ return;
+
+ ScChartListenerCollection* pCLC = nullptr;
+ if (m_pHiddenListener)
+ {
+ pCLC = m_pDocument->GetChartListenerCollection();
+ if (pCLC)
+ pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
+ }
+
+ for (const auto& rxToken : m_aTokens)
+ {
+ ScRange aRange;
+ if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
+ continue;
+
+ m_pDocument->StartListeningArea(aRange, false, m_pValueListener.get());
+ if (pCLC)
+ pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
+ }
+}
+
+void ScChart2DataSequence::BuildDataCache()
+{
+ m_bExtDataRebuildQueued = false;
+
+ if (!m_xDataArray->empty())
+ return;
+
+ StopListeningToAllExternalRefs();
+
+ ::std::vector<sal_Int32> aHiddenValues;
+ sal_Int32 nDataCount = 0;
+
+ for (const auto& rxToken : m_aTokens)
+ {
+ if (ScRefTokenHelper::isExternalRef(rxToken))
+ {
+ nDataCount += FillCacheFromExternalRef(rxToken);
+ }
+ else
+ {
+ ScRange aRange;
+ if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
+ continue;
+
+ SCCOL nLastCol = -1;
+ SCROW nLastRow = -1;
+ for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
+ {
+ for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
+ {
+ sc::ColumnBlockPosition hint;
+ m_pDocument->InitColumnBlockPosition( hint, nTab, nCol );
+ for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
+ {
+ if (nRow == aRange.aEnd.Row())
+ {
+ // Excel behavior: if the last row is the totals row, the data
+ // is not added to the chart. If it's not the last row, the data
+ // is added like normal.
+ const auto* pData = m_pDocument->GetDBAtCursor(
+ nCol, nRow, nTab,
+ ScDBDataPortion::AREA
+ );
+ if (pData && pData->HasTotals())
+ {
+ ScRange aTempRange;
+ pData->GetArea(aTempRange);
+ if (aTempRange.aEnd.Row() == nRow)
+ {
+ // Current row is totals row, skip
+ break;
+ }
+ }
+ }
+ bool bColHidden = m_pDocument->ColHidden(nCol, nTab, nullptr, &nLastCol);
+ bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, nullptr, &nLastRow);
+
+ if (bColHidden || bRowHidden)
+ {
+ // hidden cell
+ aHiddenValues.push_back(nDataCount-1);
+
+ if( !m_bIncludeHiddenCells )
+ continue;
+ }
+
+ Item aItem;
+
+ ScAddress aAdr(nCol, nRow, nTab);
+ aItem.maString = m_pDocument->GetString(aAdr);
+
+ ScRefCellValue aCell(*m_pDocument, aAdr, hint);
+ switch (aCell.getType())
+ {
+ case CELLTYPE_VALUE:
+ aItem.mfValue = aCell.getValue();
+ aItem.mbIsValue = true;
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFCell = aCell.getFormula();
+ FormulaError nErr = pFCell->GetErrCode();
+ if (nErr != FormulaError::NONE)
+ break;
+
+ if (pFCell->IsValue())
+ {
+ aItem.mfValue = pFCell->GetValue();
+ aItem.mbIsValue = true;
+ }
+ }
+ break;
+ case CELLTYPE_EDIT:
+ case CELLTYPE_NONE:
+ case CELLTYPE_STRING:
+ default:
+ ; // do nothing
+ }
+
+ aItem.mAddress = ScAddress(nCol, nRow, nTab);
+
+ m_xDataArray->push_back(std::move(aItem));
+ ++nDataCount;
+ }
+ }
+ }
+ }
+ }
+
+ // convert the hidden cell list to sequence.
+ m_aHiddenValues.realloc(aHiddenValues.size());
+ std::copy(
+ aHiddenValues.begin(), aHiddenValues.end(), m_aHiddenValues.getArray());
+
+ // Clear the data series cache when the array is re-built.
+ m_aMixedDataCache.realloc(0);
+}
+
+void ScChart2DataSequence::RebuildDataCache()
+{
+ if (!m_bExtDataRebuildQueued)
+ {
+ m_xDataArray.reset(new std::vector<Item>);
+ m_pDocument->BroadcastUno(ScHint(SfxHintId::ScDataChanged, ScAddress()));
+ m_bExtDataRebuildQueued = true;
+ m_bGotDataChangedHint = true;
+ }
+}
+
+sal_Int32 ScChart2DataSequence::FillCacheFromExternalRef(const ScTokenRef& pToken)
+{
+ ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
+ ScRange aRange;
+ if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, pToken, ScAddress(), true))
+ return 0;
+
+ sal_uInt16 nFileId = pToken->GetIndex();
+ OUString aTabName = pToken->GetString().getString();
+ ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, aTabName, aRange, nullptr);
+ if (!pArray)
+ // no external data exists for this range.
+ return 0;
+
+ // Start listening for this external document.
+ ExternalRefListener* pExtRefListener = GetExtRefListener();
+ pRefMgr->addLinkListener(nFileId, pExtRefListener);
+ pExtRefListener->addFileId(nFileId);
+
+ m_xDataArray.reset(new std::vector<Item>);
+ ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, aTabName, false);
+ sal_Int32 nDataCount = 0;
+ FormulaTokenArrayPlainIterator aIter(*pArray);
+ for (FormulaToken* p = aIter.First(); p; p = aIter.Next())
+ {
+ // Cached external range is always represented as a single
+ // matrix token, although that might change in the future when
+ // we introduce a new token type to store multi-table range
+ // data.
+
+ if (p->GetType() != svMatrix)
+ {
+ OSL_FAIL("Cached array is not a matrix token.");
+ continue;
+ }
+
+ const ScMatrix* pMat = p->GetMatrix();
+ SCSIZE nCSize, nRSize;
+ pMat->GetDimensions(nCSize, nRSize);
+ for (SCSIZE nC = 0; nC < nCSize; ++nC)
+ {
+ for (SCSIZE nR = 0; nR < nRSize; ++nR)
+ {
+ if (pMat->IsValue(nC, nR) || pMat->IsBoolean(nC, nR))
+ {
+ Item aItem;
+
+ aItem.mbIsValue = true;
+ aItem.mfValue = pMat->GetDouble(nC, nR);
+
+ SvNumberFormatter* pFormatter = m_pDocument->GetFormatTable();
+ if (pFormatter)
+ {
+ const double fVal = aItem.mfValue;
+ const Color* pColor = nullptr;
+ sal_uInt32 nFmt = 0;
+ if (pTable)
+ {
+ // Get the correct format index from the cache.
+ SCCOL nCol = aRange.aStart.Col() + static_cast<SCCOL>(nC);
+ SCROW nRow = aRange.aStart.Row() + static_cast<SCROW>(nR);
+ pTable->getCell(nCol, nRow, &nFmt);
+ }
+ pFormatter->GetOutputString(fVal, nFmt, aItem.maString, &pColor);
+ }
+
+ m_xDataArray->push_back(std::move(aItem));
+ ++nDataCount;
+ }
+ else if (pMat->IsStringOrEmpty(nC, nR))
+ {
+ Item aItem;
+
+ aItem.mbIsValue = false;
+ aItem.maString = pMat->GetString(nC, nR).getString();
+
+ m_xDataArray->push_back(std::move(aItem));
+ ++nDataCount;
+ }
+ }
+ }
+ }
+ return nDataCount;
+}
+
+void ScChart2DataSequence::UpdateTokensFromRanges(const ScRangeList& rRanges)
+{
+ if (!m_oRangeIndices)
+ return;
+
+ for ( size_t i = 0, nCount = rRanges.size(); i < nCount; ++i )
+ {
+ ScTokenRef pToken;
+ const ScRange & rRange = rRanges[i];
+
+ ScRefTokenHelper::getTokenFromRange(m_pDocument, pToken, rRange);
+ sal_uInt32 nOrigPos = (*m_oRangeIndices)[i];
+ m_aTokens[nOrigPos] = pToken;
+ }
+
+ RefChanged();
+
+ // any change of the range address is broadcast to value (modify) listeners
+ if ( !m_aValueListeners.empty() )
+ m_bGotDataChangedHint = true;
+}
+
+ScChart2DataSequence::ExternalRefListener* ScChart2DataSequence::GetExtRefListener()
+{
+ if (!m_pExtRefListener)
+ m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
+
+ return m_pExtRefListener.get();
+}
+
+void ScChart2DataSequence::StopListeningToAllExternalRefs()
+{
+ if (!m_pExtRefListener)
+ return;
+
+ const std::unordered_set<sal_uInt16>& rFileIds = m_pExtRefListener->getAllFileIds();
+ ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
+ for (const auto& rFileId : rFileIds)
+ pRefMgr->removeLinkListener(rFileId, m_pExtRefListener.get());
+
+ m_pExtRefListener.reset();
+}
+
+
+void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ // Create a range list from the token list, have the range list
+ // updated, and bring the change back to the token list.
+
+ ScRangeList aRanges;
+ m_oRangeIndices.emplace();
+ vector<ScTokenRef>::const_iterator itrBeg = m_aTokens.begin(), itrEnd = m_aTokens.end();
+ for (vector<ScTokenRef>::const_iterator itr = itrBeg ;itr != itrEnd; ++itr)
+ {
+ if (!ScRefTokenHelper::isExternalRef(*itr))
+ {
+ ScRange aRange;
+ ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, *itr, ScAddress());
+ aRanges.push_back(aRange);
+ sal_uInt32 nPos = distance(itrBeg, itr);
+ m_oRangeIndices->push_back(nPos);
+ }
+ }
+
+ assert(m_oRangeIndices->size() == aRanges.size() &&
+ "range list and range index list have different sizes.");
+
+ unique_ptr<ScRangeList> pUndoRanges;
+ if ( m_pDocument->HasUnoRefUndo() )
+ pUndoRanges.reset(new ScRangeList(aRanges));
+
+ const ScUpdateRefHint& rRef = static_cast<const ScUpdateRefHint&>(rHint);
+ bool bChanged = aRanges.UpdateReference(
+ rRef.GetMode(), m_pDocument, rRef.GetRange(), rRef.GetDx(), rRef.GetDy(), rRef.GetDz());
+
+ if (bChanged)
+ {
+ // TODO: This should be an assert, but tdf#144537 triggers it.
+ SAL_WARN_IF(m_oRangeIndices->size() == aRanges.size(),
+ "sc.ui", "range list and range index list have different sizes after the reference update.");
+
+ // Bring the change back from the range list to the token list.
+ UpdateTokensFromRanges(aRanges);
+
+ if (pUndoRanges)
+ m_pDocument->AddUnoRefChange(m_nObjectId, *pUndoRanges);
+ }
+ }
+ else if ( auto pUndoHint = dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
+ {
+ do
+ {
+ if (pUndoHint->GetObjectId() != m_nObjectId)
+ break;
+
+ // The hint object provides the old ranges. Restore the old state
+ // from these ranges.
+
+ if (!m_oRangeIndices || m_oRangeIndices->empty())
+ {
+ assert(false && " faulty range indices");
+ break;
+ }
+
+ const ScRangeList& rRanges = pUndoHint->GetRanges();
+
+ size_t nCount = rRanges.size();
+ if (nCount != m_oRangeIndices->size())
+ {
+ assert(false && "range count and range index count differ.");
+ break;
+ }
+
+ UpdateTokensFromRanges(rRanges);
+ }
+ while (false);
+ }
+ else
+ {
+ const SfxHintId nId = rHint.GetId();
+ if ( nId ==SfxHintId::Dying )
+ {
+ m_pDocument = nullptr;
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ // delayed broadcast as in ScCellRangesBase
+
+ if ( m_bGotDataChangedHint && m_pDocument )
+ {
+ m_xDataArray.reset(new std::vector<Item>);
+ lang::EventObject aEvent;
+ aEvent.Source = getXWeak();
+
+ if( m_pDocument )
+ {
+ for (const uno::Reference<util::XModifyListener> & xListener: m_aValueListeners)
+ m_pDocument->AddUnoListenerCall( xListener, aEvent );
+ }
+
+ m_bGotDataChangedHint = false;
+ }
+ }
+ else if ( nId == SfxHintId::ScCalcAll )
+ {
+ // broadcast from DoHardRecalc - set m_bGotDataChangedHint
+ // (SfxHintId::DataChanged follows separately)
+
+ if ( !m_aValueListeners.empty() )
+ m_bGotDataChangedHint = true;
+ }
+ else if (nId == SfxHintId::ScClearCache)
+ {
+ // necessary after import
+ m_xDataArray.reset(new std::vector<Item>);
+ }
+ }
+}
+
+IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, const SfxHint&, rHint, void )
+{
+ if ( m_pDocument && (rHint.GetId() == SfxHintId::ScDataChanged) )
+ {
+ // This may be called several times for a single change, if several formulas
+ // in the range are notified. So only a flag is set that is checked when
+ // SfxHintId::DataChanged is received.
+
+ setDataChangedHint(true);
+ }
+}
+
+ScChart2DataSequence::ExternalRefListener::ExternalRefListener(
+ ScChart2DataSequence& rParent, ScDocument* pDoc) :
+ mrParent(rParent),
+ mpDoc(pDoc)
+{
+}
+
+ScChart2DataSequence::ExternalRefListener::~ExternalRefListener()
+{
+ if (!mpDoc || mpDoc->IsInDtorClear())
+ // The document is being destroyed. Do nothing.
+ return;
+
+ // Make sure to remove all pointers to this object.
+ mpDoc->GetExternalRefManager()->removeLinkListener(this);
+}
+
+void ScChart2DataSequence::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
+{
+ switch (eType)
+ {
+ case ScExternalRefManager::LINK_MODIFIED:
+ {
+ if (maFileIds.count(nFileId))
+ // We are listening to this external document.
+ mrParent.RebuildDataCache();
+ }
+ break;
+ case ScExternalRefManager::LINK_BROKEN:
+ maFileIds.erase(nFileId);
+ break;
+ case ScExternalRefManager::OH_NO_WE_ARE_GOING_TO_DIE:
+ mpDoc = nullptr;
+ break;
+ }
+}
+
+void ScChart2DataSequence::ExternalRefListener::addFileId(sal_uInt16 nFileId)
+{
+ maFileIds.insert(nFileId);
+}
+
+uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pDocument)
+ throw uno::RuntimeException();
+
+ BuildDataCache();
+
+ if (!m_aMixedDataCache.hasElements())
+ {
+ // Build a cache for the 1st time...
+
+ sal_Int32 nCount = m_xDataArray->size();
+ m_aMixedDataCache.realloc(nCount);
+ uno::Any* pArr = m_aMixedDataCache.getArray();
+ for (const Item &rItem : *m_xDataArray)
+ {
+ if (rItem.mbIsValue)
+ *pArr <<= rItem.mfValue;
+ else if (rItem.maString.isEmpty())
+ {
+ ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
+ if (aCell.isEmpty())
+ *pArr = uno::Any();
+ else
+ *pArr <<= rItem.maString;
+ }
+ else
+ *pArr <<= rItem.maString;
+ ++pArr;
+ }
+ }
+ return m_aMixedDataCache;
+}
+
+// XNumericalDataSequence --------------------------------------------------
+
+uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pDocument)
+ throw uno::RuntimeException();
+
+ BuildDataCache();
+
+ sal_Int32 nCount = m_xDataArray->size();
+ uno::Sequence<double> aSeq(nCount);
+ double* pArr = aSeq.getArray();
+ for (const Item& rItem : *m_xDataArray)
+ {
+ *pArr = rItem.mbIsValue ? rItem.mfValue : std::numeric_limits<double>::quiet_NaN();
+ ++pArr;
+ }
+
+ return aSeq;
+}
+
+// XTextualDataSequence --------------------------------------------------
+
+uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::getTextualData()
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence<OUString> aSeq;
+ if ( !m_pDocument )
+ throw uno::RuntimeException();
+
+ BuildDataCache();
+
+ sal_Int32 nCount = m_xDataArray->size();
+ if ( nCount > 0 )
+ {
+ aSeq = uno::Sequence<OUString>(nCount);
+ OUString* pArr = aSeq.getArray();
+ for (const Item& rItem : *m_xDataArray)
+ {
+ *pArr = rItem.maString;
+ ++pArr;
+ }
+ }
+ else if ( m_aTokens.front() )
+ {
+ if( m_aTokens.front()->GetType() == svString )
+ {
+ aSeq = uno::Sequence<OUString> { m_aTokens.front()->GetString().getString() };
+ }
+ }
+
+ return aSeq;
+}
+
+OUString SAL_CALL ScChart2DataSequence::getSourceRangeRepresentation()
+{
+ SolarMutexGuard aGuard;
+ OUString aStr;
+ OSL_ENSURE( m_pDocument, "No Document -> no SourceRangeRepresentation" );
+ if (m_pDocument)
+ lcl_convertTokensToString(aStr, m_aTokens, *m_pDocument);
+
+ return aStr;
+}
+
+namespace {
+
+/**
+ * This function object is used to accumulatively count the numbers of
+ * columns and rows in all reference tokens.
+ */
+class AccumulateRangeSize
+{
+public:
+ AccumulateRangeSize(const ScDocument* pDoc) :
+ mpDoc(pDoc), mnCols(0), mnRows(0) {}
+
+ void operator() (const ScTokenRef& pToken)
+ {
+ ScRange r;
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ ScRefTokenHelper::getRangeFromToken(mpDoc, r, pToken, ScAddress(), bExternal);
+ r.PutInOrder();
+ mnCols += r.aEnd.Col() - r.aStart.Col() + 1;
+ mnRows += r.aEnd.Row() - r.aStart.Row() + 1;
+ }
+
+ SCCOL getCols() const { return mnCols; }
+ SCROW getRows() const { return mnRows; }
+private:
+ const ScDocument* mpDoc;
+ SCCOL mnCols;
+ SCROW mnRows;
+};
+
+/**
+ * This function object is used to generate label strings from a list of
+ * reference tokens.
+ */
+class GenerateLabelStrings
+{
+public:
+ GenerateLabelStrings(const ScDocument* pDoc, sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) :
+ mpDoc(pDoc),
+ mpLabels(std::make_shared<Sequence<OUString>>(nSize)),
+ meOrigin(eOrigin),
+ mnCount(0),
+ mbColumn(bColumn) {}
+
+ void operator() (const ScTokenRef& pToken)
+ {
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ ScRange aRange;
+ ScRefTokenHelper::getRangeFromToken(mpDoc, aRange, pToken, ScAddress(), bExternal);
+ OUString* pArr = mpLabels->getArray();
+ if (mbColumn)
+ {
+ for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
+ {
+ if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
+ {
+ OUString aString = ScResId(STR_COLUMN) + " ";
+ ScAddress aPos( nCol, 0, 0 );
+ OUString aColStr(aPos.Format(ScRefFlags::COL_VALID));
+ aString += aColStr;
+ pArr[mnCount] = aString;
+ }
+ else //only indices for categories
+ pArr[mnCount] = OUString::number( mnCount+1 );
+ ++mnCount;
+ }
+ }
+ else
+ {
+ for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
+ {
+ if (meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
+ {
+ OUString aString = ScResId(STR_ROW) +
+ " " + OUString::number( nRow+1 );
+ pArr[mnCount] = aString;
+ }
+ else //only indices for categories
+ pArr[mnCount] = OUString::number( mnCount+1 );
+ ++mnCount;
+ }
+ }
+ }
+
+ const Sequence<OUString>& getLabels() const { return *mpLabels; }
+
+private:
+ const ScDocument* mpDoc;
+ shared_ptr< Sequence<OUString> > mpLabels;
+ chart2::data::LabelOrigin meOrigin;
+ sal_Int32 mnCount;
+ bool mbColumn;
+};
+
+}
+
+uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pDocument)
+ throw uno::RuntimeException();
+
+ // Determine the total size of all ranges.
+ AccumulateRangeSize func(m_pDocument);
+ func = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), func);
+ SCCOL nCols = func.getCols();
+ SCROW nRows = func.getRows();
+
+ // Determine whether this is column-major or row-major.
+ bool bColumn = true;
+ if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
+ (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
+ {
+ if (nRows > nCols)
+ {
+ bColumn = eOrigin == chart2::data::LabelOrigin_SHORT_SIDE;
+ }
+ else if (nCols > nRows)
+ {
+ bColumn = eOrigin != chart2::data::LabelOrigin_SHORT_SIDE;
+ }
+ else
+ return Sequence<OUString>();
+ }
+
+ // Generate label strings based on the info so far.
+ sal_Int32 nCount = bColumn ? nCols : nRows;
+ GenerateLabelStrings genLabels(m_pDocument, nCount, eOrigin, bColumn);
+ genLabels = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), genLabels);
+ Sequence<OUString> aSeq = genLabels.getLabels();
+
+ return aSeq;
+}
+
+namespace {
+
+sal_uInt32 getDisplayNumberFormat(const ScDocument* pDoc, const ScAddress& rPos)
+{
+ sal_uInt32 nFormat = pDoc->GetNumberFormat(rPos); // original format from cell.
+ return nFormat;
+}
+
+}
+
+::sal_Int32 SAL_CALL ScChart2DataSequence::getNumberFormatKeyByIndex( ::sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ BuildDataCache();
+
+ if (nIndex == -1)
+ {
+ // return format of first non-empty cell
+ // TODO: use nicer heuristic
+ for (const Item& rItem : *m_xDataArray)
+ {
+ ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
+ if (!aCell.isEmpty() && aCell.hasNumeric())
+ {
+ return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, rItem.mAddress));
+ }
+ }
+
+ // we could not find a non-empty cell
+ return 0;
+ }
+
+ if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= m_xDataArray->size())
+ {
+ SAL_WARN("sc.ui", "Passed invalid index to getNumberFormatKeyByIndex(). Will return default value '0'.");
+ return 0;
+ }
+
+ return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, m_xDataArray->at(nIndex).mAddress));
+}
+
+// XCloneable ================================================================
+
+uno::Reference< util::XCloneable > SAL_CALL ScChart2DataSequence::createClone()
+{
+ SolarMutexGuard aGuard;
+
+ rtl::Reference<ScChart2DataSequence> p(new ScChart2DataSequence(m_pDocument, *this));
+ return p;
+}
+
+// XModifyBroadcaster ========================================================
+
+void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
+{
+ // like ScCellRangesBase::addModifyListener
+ SolarMutexGuard aGuard;
+ if (m_aTokens.empty())
+ return;
+
+ ScRangeList aRanges;
+ ScRefTokenHelper::getRangeListFromTokens(m_pDocument, aRanges, m_aTokens, ScAddress());
+ m_aValueListeners.emplace_back( aListener );
+
+ if ( m_aValueListeners.size() != 1 )
+ return;
+
+ if (!m_pValueListener)
+ m_pValueListener.reset(new ScLinkListener( LINK( this, ScChart2DataSequence, ValueListenerHdl ) ));
+
+ if (!m_pHiddenListener)
+ m_pHiddenListener.reset(new HiddenRangeListener(*this));
+
+ if( m_pDocument )
+ {
+ ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
+ for (const auto& rxToken : m_aTokens)
+ {
+ ScRange aRange;
+ if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
+ continue;
+
+ m_pDocument->StartListeningArea( aRange, false, m_pValueListener.get() );
+ if (pCLC)
+ pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
+ }
+ }
+
+ acquire(); // don't lose this object (one ref for all listeners)
+}
+
+void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
+{
+ // like ScCellRangesBase::removeModifyListener
+
+ SolarMutexGuard aGuard;
+ if (m_aTokens.empty())
+ return;
+
+ rtl::Reference<ScChart2DataSequence> xSelfHold(this); // in case the listeners have the last ref
+
+ sal_uInt16 nCount = m_aValueListeners.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ {
+ uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
+ if ( rObj == aListener )
+ {
+ m_aValueListeners.erase( m_aValueListeners.begin() + n );
+
+ if ( m_aValueListeners.empty() )
+ {
+ if (m_pValueListener)
+ m_pValueListener->EndListeningAll();
+
+ if (m_pHiddenListener && m_pDocument)
+ {
+ ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
+ if (pCLC)
+ pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
+ }
+
+ release(); // release the ref for the listeners
+ }
+
+ break;
+ }
+ }
+}
+
+// DataSequence XPropertySet -------------------------------------------------
+
+uno::Reference< beans::XPropertySetInfo> SAL_CALL
+ScChart2DataSequence::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL ScChart2DataSequence::setPropertyValue(
+ const OUString& rPropertyName, const uno::Any& rValue)
+{
+ if ( rPropertyName == SC_UNONAME_ROLE )
+ {
+ if ( !(rValue >>= m_aRole))
+ throw lang::IllegalArgumentException();
+ }
+ else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
+ {
+ bool bOldValue = m_bIncludeHiddenCells;
+ if ( !(rValue >>= m_bIncludeHiddenCells))
+ throw lang::IllegalArgumentException();
+ if( bOldValue != m_bIncludeHiddenCells )
+ m_xDataArray.reset(new std::vector<Item>);//data array is dirty now
+ }
+ else if( rPropertyName == "TimeBased" )
+ {
+ bool bTimeBased = mbTimeBased;
+ rValue>>= bTimeBased;
+ mbTimeBased = bTimeBased;
+ }
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+ // TODO: support optional properties
+}
+
+uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue(const OUString& rPropertyName)
+{
+ uno::Any aRet;
+ if ( rPropertyName == SC_UNONAME_ROLE )
+ aRet <<= m_aRole;
+ else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
+ aRet <<= m_bIncludeHiddenCells;
+ else if ( rPropertyName == SC_UNONAME_HIDDENVALUES )
+ {
+ // This property is read-only thus cannot be set externally via
+ // setPropertyValue(...).
+ BuildDataCache();
+ aRet <<= m_aHiddenValues;
+ }
+ else if (rPropertyName == SC_UNONAME_TIME_BASED)
+ {
+ aRet <<= mbTimeBased;
+ }
+ else if (rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
+ {
+ // Read-only property. It returns whether or not the label value is a
+ // direct user input, rather than an indirect reference.
+ bool bHasStringLabel = false;
+ if (m_aTokens.size() == 1)
+ {
+ const formula::FormulaToken& rToken = *m_aTokens[0];
+ bHasStringLabel = rToken.GetType() == formula::svString;
+ }
+ aRet <<= bHasStringLabel;
+ }
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+ // TODO: support optional properties
+ return aRet;
+}
+
+void SAL_CALL ScChart2DataSequence::addPropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
+{
+ // FIXME: real implementation
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataSequence::removePropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
+{
+ // FIXME: real implementation
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataSequence::addVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
+{
+ // FIXME: real implementation
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataSequence::removeVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
+{
+ // FIXME: real implementation
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void ScChart2DataSequence::setDataChangedHint(bool b)
+{
+ m_bGotDataChangedHint = b;
+}
+
+sal_Bool ScChart2DataSequence::switchToNext(sal_Bool bWrap)
+{
+ if(!mbTimeBased)
+ return true;
+
+ if(mnCurrentTab >= mnTimeBasedEnd)
+ {
+ if(bWrap)
+ setToPointInTime(0);
+ return false;
+ }
+
+ for(const auto& rxToken : m_aTokens)
+ {
+ if (rxToken->GetType() != svDoubleRef)
+ continue;
+
+ ScComplexRefData& rData = *rxToken->GetDoubleRef();
+ ScSingleRefData& s = rData.Ref1;
+ ScSingleRefData& e = rData.Ref2;
+
+ s.IncTab(1);
+ e.IncTab(1);
+ }
+
+ ++mnCurrentTab;
+
+ RebuildDataCache();
+
+ return true;
+}
+
+void ScChart2DataSequence::setRange(sal_Int32 nStart, sal_Int32 nEnd)
+{
+ mnTimeBasedStart = nStart;
+ mnTimeBasedEnd = nEnd;
+ mnCurrentTab = mnTimeBasedStart;
+}
+
+sal_Bool ScChart2DataSequence::setToPointInTime(sal_Int32 nPoint)
+{
+ if(nPoint > mnTimeBasedEnd - mnTimeBasedStart)
+ return false;
+
+ SCTAB nTab = mnTimeBasedStart + nPoint;
+ for(const auto& rxToken : m_aTokens)
+ {
+ if (rxToken->GetType() != svDoubleRef)
+ continue;
+
+ ScComplexRefData& rData = *rxToken->GetDoubleRef();
+ ScSingleRefData& s = rData.Ref1;
+ ScSingleRefData& e = rData.Ref2;
+
+ s.SetAbsTab(nTab);
+ e.SetAbsTab(nTab);
+ }
+
+ mnCurrentTab = nTab;
+
+ RebuildDataCache();
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/chartuno.cxx b/sc/source/ui/unoobj/chartuno.cxx
new file mode 100644
index 0000000000..aa0554b27f
--- /dev/null
+++ b/sc/source/ui/unoobj/chartuno.cxx
@@ -0,0 +1,739 @@
+/* -*- 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 <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/chart2/data/XDataReceiver.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+
+#include <osl/diagnose.h>
+#include <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdundo.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <comphelper/classids.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/globname.hxx>
+#include <svtools/embedhlp.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+
+#include <ChartTools.hxx>
+#include <chartuno.hxx>
+#include <miscuno.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <undodat.hxx>
+#include <chartlis.hxx>
+#include <chart2uno.hxx>
+#include <convuno.hxx>
+
+using namespace css;
+
+#define PROP_HANDLE_RELATED_CELLRANGES 1
+
+SC_SIMPLE_SERVICE_INFO( ScChartObj, "ScChartObj", "com.sun.star.table.TableChart" )
+SC_SIMPLE_SERVICE_INFO( ScChartsObj, "ScChartsObj", "com.sun.star.table.TableCharts" )
+
+ScChartsObj::ScChartsObj(ScDocShell* pDocSh, SCTAB nT) :
+ pDocShell( pDocSh ),
+ nTab( nT )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScChartsObj::~ScChartsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScChartsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! update reference
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+rtl::Reference<ScChartObj> ScChartsObj::GetObjectByIndex_Impl(tools::Long nIndex) const
+{
+ if ( pDocShell )
+ {
+ OUString aName;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if (pDrawLayer)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage, "Page not found");
+ if (pPage)
+ {
+ tools::Long nPos = 0;
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 && ScDocument::IsChart(pObject) )
+ {
+ if ( nPos == nIndex )
+ {
+ uno::Reference < embed::XEmbeddedObject > xObj = static_cast<SdrOle2Obj*>(pObject)->GetObjRef();
+ if ( xObj.is() )
+ aName = pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName( xObj );
+ break; // stop searching
+ }
+ ++nPos;
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+
+ if (!aName.isEmpty())
+ return new ScChartObj( pDocShell, nTab, aName );
+ }
+
+ return nullptr;
+}
+
+rtl::Reference<ScChartObj> ScChartsObj::GetObjectByName_Impl(const OUString& aName) const
+{
+ if (sc::tools::findChartsByName(pDocShell, nTab, aName, sc::tools::ChartSourceType::CELL_RANGE))
+ return new ScChartObj( pDocShell, nTab, aName );
+ if (sc::tools::findChartsByName(pDocShell, nTab, aName, sc::tools::ChartSourceType::PIVOT_TABLE))
+ return new ScChartObj( pDocShell, nTab, aName );
+ return nullptr;
+}
+
+// XTableCharts
+
+void SAL_CALL ScChartsObj::addNewByName( const OUString& rName,
+ const awt::Rectangle& aRect,
+ const uno::Sequence<table::CellRangeAddress>& aRanges,
+ sal_Bool bColumnHeaders, sal_Bool bRowHeaders )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDrawLayer* pModel = pDocShell->MakeDrawLayer();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage,"addChart: no Page");
+ if (!pPage)
+ return;
+
+ // chart can't be inserted if any ole object with that name exists on any table
+ // (empty string: generate valid name)
+
+ OUString aName = rName;
+ SCTAB nDummy;
+ if ( !aName.isEmpty() && pModel->GetNamedObject( aName, SdrObjKind::OLE2, nDummy ) )
+ {
+ // object exists - only RuntimeException is specified
+ throw uno::RuntimeException();
+ }
+
+ ScRangeList* pList = new ScRangeList;
+ for (const table::CellRangeAddress& rRange : aRanges)
+ {
+ ScRange aRange( static_cast<SCCOL>(rRange.StartColumn), rRange.StartRow, rRange.Sheet,
+ static_cast<SCCOL>(rRange.EndColumn), rRange.EndRow, rRange.Sheet );
+ pList->push_back( aRange );
+ }
+ ScRangeListRef xNewRanges( pList );
+
+ uno::Reference < embed::XEmbeddedObject > xObj;
+ if ( SvtModuleOptions().IsChart() )
+ xObj = pDocShell->GetEmbeddedObjectContainer().CreateEmbeddedObject( SvGlobalName( SO3_SCH_CLASSID ).GetByteSequence(), aName );
+ if ( !xObj.is() )
+ return;
+
+ // adjust rectangle
+ //! error/exception, if empty/invalid ???
+ Point aRectPos( aRect.X, aRect.Y );
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ if ( ( aRectPos.X() < 0 && !bLayoutRTL ) || ( aRectPos.X() > 0 && bLayoutRTL ) )
+ aRectPos.setX( 0 );
+
+ if (aRectPos.Y() < 0)
+ aRectPos.setY( 0 );
+
+ Size aRectSize( aRect.Width, aRect.Height );
+ if (aRectSize.Width() <= 0)
+ aRectSize.setWidth( 5000 ); // default size
+
+ if (aRectSize.Height() <= 0)
+ aRectSize.setHeight( 5000 );
+ tools::Rectangle aInsRect( aRectPos, aRectSize );
+
+ sal_Int64 nAspect(embed::Aspects::MSOLE_CONTENT);
+ MapUnit aMapUnit(VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) ));
+ Size aSize(aInsRect.GetSize());
+ aSize = OutputDevice::LogicToLogic( aSize, MapMode( MapUnit::Map100thMM ), MapMode( aMapUnit ) );
+ awt::Size aSz;
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+
+ // Calc -> DataProvider
+ uno::Reference< chart2::data::XDataProvider > xDataProvider = new
+ ScChart2DataProvider( &rDoc );
+ // Chart -> DataReceiver
+ uno::Reference< chart2::data::XDataReceiver > xReceiver;
+ if( xObj.is())
+ xReceiver.set( xObj->getComponent(), uno::UNO_QUERY );
+ if( xReceiver.is())
+ {
+ // Range in UI representation.
+ OUString sRangeStr;
+ xNewRanges->Format(sRangeStr, ScRefFlags::RANGE_ABS_3D, rDoc, rDoc.GetAddressConvention());
+
+ // connect
+ if( !sRangeStr.isEmpty() )
+ xReceiver->attachDataProvider( xDataProvider );
+ else
+ sRangeStr = "all";
+
+ uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( cppu::getXWeak(pDocShell->GetModel()), uno::UNO_QUERY );
+ xReceiver->attachNumberFormatsSupplier( xNumberFormatsSupplier );
+
+ // set arguments
+ uno::Sequence< beans::PropertyValue > aArgs{
+ beans::PropertyValue(
+ "CellRangeRepresentation", -1,
+ uno::Any( sRangeStr ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "HasCategories", -1,
+ uno::Any( bRowHeaders ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "FirstCellAsLabel", -1,
+ uno::Any( bColumnHeaders ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "DataRowSource", -1,
+ uno::Any( chart::ChartDataRowSource_COLUMNS ), beans::PropertyState_DIRECT_VALUE )
+ };
+ xReceiver->setArguments( aArgs );
+ }
+
+ ScChartListener* pChartListener =
+ new ScChartListener( aName, rDoc, xNewRanges );
+ rDoc.GetChartListenerCollection()->insert( pChartListener );
+ pChartListener->StartListeningTo();
+
+ rtl::Reference<SdrOle2Obj> pObj = new SdrOle2Obj(
+ *pModel,
+ ::svt::EmbeddedObjectRef(xObj, embed::Aspects::MSOLE_CONTENT),
+ aName,
+ aInsRect);
+
+ // set VisArea
+ if( xObj.is())
+ xObj->setVisualAreaSize( nAspect, aSz );
+
+ // #i121334# This call will change the chart's default background fill from white to transparent.
+ // Add here again if this is wanted (see task description for details)
+ // ChartHelper::AdaptDefaultsForChart( xObj );
+
+ pPage->InsertObject( pObj.get() );
+ pModel->AddUndo( std::make_unique<SdrUndoInsertObj>( *pObj ) );
+}
+
+void SAL_CALL ScChartsObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* pObj = sc::tools::findChartsByName(pDocShell, nTab, aName, sc::tools::ChartSourceType::CELL_RANGE);
+ if (pObj)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.GetChartListenerCollection()->removeByName(aName);
+ ScDrawLayer* pModel = rDoc.GetDrawLayer(); // is not zero
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab)); // is not zero
+
+ pModel->AddUndo( std::make_unique<SdrUndoDelObj>( *pObj ) );
+ pPage->RemoveObject( pObj->GetOrdNum() );
+
+ //! Notify etc.???
+ }
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScChartsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.table.TableChartsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScChartsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nCount = 0;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if (pDrawLayer)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage, "Page not found");
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 && ScDocument::IsChart(pObject) )
+ ++nCount;
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL ScChartsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XTableChart> xChart(GetObjectByIndex_Impl(nIndex));
+ if (!xChart.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xChart);
+}
+
+uno::Type SAL_CALL ScChartsObj::getElementType()
+{
+ return cppu::UnoType<table::XTableChart>::get();
+}
+
+sal_Bool SAL_CALL ScChartsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return getCount() != 0;
+}
+
+uno::Any SAL_CALL ScChartsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XTableChart> xChart(GetObjectByName_Impl(aName));
+ if (!xChart.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xChart);
+}
+
+uno::Sequence<OUString> SAL_CALL ScChartsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ tools::Long nCount = getCount();
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+
+ tools::Long nPos = 0;
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if (pDrawLayer)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage, "Page not found");
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 && ScDocument::IsChart(pObject) )
+ {
+ OUString aName;
+ uno::Reference < embed::XEmbeddedObject > xObj = static_cast<SdrOle2Obj*>(pObject)->GetObjRef();
+ if ( xObj.is() )
+ aName = pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName( xObj );
+
+ OSL_ENSURE(nPos<nCount, "oops, miscounted?");
+ pAry[nPos++] = aName;
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ OSL_ENSURE(nPos==nCount, "hey, miscounted?");
+
+ return aSeq;
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScChartsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* aOle2Obj = sc::tools::findChartsByName(pDocShell, nTab, aName,
+ sc::tools::ChartSourceType::CELL_RANGE);
+ return aOle2Obj != nullptr;
+}
+
+ScChartObj::ScChartObj(ScDocShell* pDocSh, SCTAB nT, OUString aN)
+ :ScChartObj_Base( m_aMutex )
+ ,ScChartObj_PBase( ScChartObj_Base::rBHelper )
+ ,pDocShell( pDocSh )
+ ,nTab( nT )
+ ,aChartName(std::move( aN ))
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ registerPropertyNoMember( "RelatedCellRanges",
+ PROP_HANDLE_RELATED_CELLRANGES, beans::PropertyAttribute::MAYBEVOID,
+ cppu::UnoType<uno::Sequence<table::CellRangeAddress>>::get(),
+ css::uno::Any(uno::Sequence<table::CellRangeAddress>()) );
+}
+
+ScChartObj::~ScChartObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScChartObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! update reference
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+void ScChartObj::GetData_Impl( ScRangeListRef& rRanges, bool& rColHeaders, bool& rRowHeaders ) const
+{
+ bool bFound = false;
+
+ if( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ uno::Reference< chart2::XChartDocument > xChartDoc( rDoc.GetChartByName( aChartName ) );
+ if( xChartDoc.is() )
+ {
+ uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, uno::UNO_QUERY );
+ uno::Reference< chart2::data::XDataProvider > xProvider = xChartDoc->getDataProvider();
+ if( xReceiver.is() && xProvider.is() )
+ {
+ const uno::Sequence< beans::PropertyValue > aArgs( xProvider->detectArguments( xReceiver->getUsedData() ) );
+
+ OUString aRanges;
+ chart::ChartDataRowSource eDataRowSource = chart::ChartDataRowSource_COLUMNS;
+ bool bHasCategories=false;
+ bool bFirstCellAsLabel=false;
+ for (const beans::PropertyValue& rProp : aArgs)
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == "CellRangeRepresentation")
+ rProp.Value >>= aRanges;
+ else if (aPropName == "DataRowSource")
+ eDataRowSource = static_cast<chart::ChartDataRowSource>(ScUnoHelpFunctions::GetEnumFromAny( rProp.Value ));
+ else if (aPropName == "HasCategories")
+ bHasCategories = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == "FirstCellAsLabel")
+ bFirstCellAsLabel = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ }
+
+ if( chart::ChartDataRowSource_COLUMNS == eDataRowSource )
+ {
+ rColHeaders=bFirstCellAsLabel;
+ rRowHeaders=bHasCategories;
+ }
+ else
+ {
+ rColHeaders=bHasCategories;
+ rRowHeaders=bFirstCellAsLabel;
+ }
+ // Range in UI representation.
+ rRanges->Parse( aRanges, rDoc, rDoc.GetAddressConvention());
+ }
+ bFound = true;
+ }
+ }
+ if( !bFound )
+ {
+ rRanges = nullptr;
+ rColHeaders = false;
+ rRowHeaders = false;
+ }
+}
+
+void ScChartObj::Update_Impl( const ScRangeListRef& rRanges, bool bColHeaders, bool bRowHeaders )
+{
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ if (bUndo)
+ {
+ pDocShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoChartData>( pDocShell, aChartName, rRanges, bColHeaders, bRowHeaders, false ) );
+ }
+ rDoc.UpdateChartArea( aChartName, rRanges, bColHeaders, bRowHeaders, false );
+ }
+}
+
+// ::comphelper::OPropertySetHelper
+
+::cppu::IPropertyArrayHelper& ScChartObj::getInfoHelper()
+{
+ return *ScChartObj_PABase::getArrayHelper();
+}
+
+void ScChartObj::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const uno::Any& rValue )
+{
+ switch ( nHandle )
+ {
+ case PROP_HANDLE_RELATED_CELLRANGES:
+ {
+ uno::Sequence< table::CellRangeAddress > aCellRanges;
+ if ( rValue >>= aCellRanges )
+ {
+ ScRangeListRef rRangeList = new ScRangeList();
+ for ( table::CellRangeAddress const & aCellRange : std::as_const(aCellRanges) )
+ {
+ ScRange aRange;
+ ScUnoConversion::FillScRange( aRange, aCellRange );
+ rRangeList->push_back( aRange );
+ }
+ if ( pDocShell )
+ {
+ ScChartListenerCollection* pCollection = pDocShell->GetDocument().GetChartListenerCollection();
+ if ( pCollection )
+ {
+ pCollection->ChangeListening( aChartName, rRangeList );
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void ScChartObj::getFastPropertyValue( uno::Any& rValue, sal_Int32 nHandle ) const
+{
+ switch ( nHandle )
+ {
+ case PROP_HANDLE_RELATED_CELLRANGES:
+ {
+ if (!pDocShell)
+ break;
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScChartListenerCollection* pCollection = rDoc.GetChartListenerCollection();
+ if (!pCollection)
+ break;
+
+ ScChartListener* pListener = pCollection->findByName(aChartName);
+ if (!pListener)
+ break;
+
+ const ScRangeListRef& rRangeList = pListener->GetRangeList();
+ if (!rRangeList.is())
+ break;
+
+ size_t nCount = rRangeList->size();
+ uno::Sequence<table::CellRangeAddress> aCellRanges(nCount);
+ table::CellRangeAddress* pCellRanges = aCellRanges.getArray();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ ScRange const & rRange = (*rRangeList)[i];
+ table::CellRangeAddress aCellRange;
+ ScUnoConversion::FillApiRange(aCellRange, rRange);
+ pCellRanges[i] = aCellRange;
+ }
+ rValue <<= aCellRanges;
+ }
+ break;
+ default:
+ ;
+ }
+}
+
+// ::comphelper::OPropertyArrayUsageHelper
+
+::cppu::IPropertyArrayHelper* ScChartObj::createArrayHelper() const
+{
+ uno::Sequence< beans::Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+}
+
+// XInterface
+
+IMPLEMENT_FORWARD_XINTERFACE2( ScChartObj, ScChartObj_Base, ScChartObj_PBase )
+
+// XTypeProvider
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( ScChartObj, ScChartObj_Base, ScChartObj_PBase )
+
+// XTableChart
+
+sal_Bool SAL_CALL ScChartObj::getHasColumnHeaders()
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xRanges = new ScRangeList;
+ bool bColHeaders, bRowHeaders;
+ GetData_Impl( xRanges, bColHeaders, bRowHeaders );
+ return bColHeaders;
+}
+
+void SAL_CALL ScChartObj::setHasColumnHeaders( sal_Bool bHasColumnHeaders )
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xRanges = new ScRangeList;
+ bool bOldColHeaders, bOldRowHeaders;
+ GetData_Impl( xRanges, bOldColHeaders, bOldRowHeaders );
+ if ( bOldColHeaders != bool(bHasColumnHeaders) )
+ Update_Impl( xRanges, bHasColumnHeaders, bOldRowHeaders );
+}
+
+sal_Bool SAL_CALL ScChartObj::getHasRowHeaders()
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xRanges = new ScRangeList;
+ bool bColHeaders, bRowHeaders;
+ GetData_Impl( xRanges, bColHeaders, bRowHeaders );
+ return bRowHeaders;
+}
+
+void SAL_CALL ScChartObj::setHasRowHeaders( sal_Bool bHasRowHeaders )
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xRanges = new ScRangeList;
+ bool bOldColHeaders, bOldRowHeaders;
+ GetData_Impl( xRanges, bOldColHeaders, bOldRowHeaders );
+ if ( bOldRowHeaders != bool(bHasRowHeaders) )
+ Update_Impl( xRanges, bOldColHeaders, bHasRowHeaders );
+}
+
+uno::Sequence<table::CellRangeAddress> SAL_CALL ScChartObj::getRanges()
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xRanges = new ScRangeList;
+ bool bColHeaders, bRowHeaders;
+ GetData_Impl( xRanges, bColHeaders, bRowHeaders );
+ if ( xRanges.is() )
+ {
+ size_t nCount = xRanges->size();
+
+ table::CellRangeAddress aRangeAddress;
+ uno::Sequence<table::CellRangeAddress> aSeq(nCount);
+ table::CellRangeAddress* pAry = aSeq.getArray();
+ for (size_t i = 0; i < nCount; i++)
+ {
+ ScRange const & rRange = (*xRanges)[i];
+
+ aRangeAddress.Sheet = rRange.aStart.Tab();
+ aRangeAddress.StartColumn = rRange.aStart.Col();
+ aRangeAddress.StartRow = rRange.aStart.Row();
+ aRangeAddress.EndColumn = rRange.aEnd.Col();
+ aRangeAddress.EndRow = rRange.aEnd.Row();
+
+ pAry[i] = aRangeAddress;
+ }
+ return aSeq;
+ }
+
+ OSL_FAIL("ScChartObj::getRanges: no Ranges");
+ return uno::Sequence<table::CellRangeAddress>();
+}
+
+void SAL_CALL ScChartObj::setRanges( const uno::Sequence<table::CellRangeAddress>& aRanges )
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xOldRanges = new ScRangeList;
+ bool bColHeaders, bRowHeaders;
+ GetData_Impl( xOldRanges, bColHeaders, bRowHeaders );
+
+ ScRangeList* pList = new ScRangeList;
+ for (const table::CellRangeAddress& rRange : aRanges)
+ {
+ ScRange aRange( static_cast<SCCOL>(rRange.StartColumn), rRange.StartRow, rRange.Sheet,
+ static_cast<SCCOL>(rRange.EndColumn), rRange.EndRow, rRange.Sheet );
+ pList->push_back( aRange );
+ }
+ ScRangeListRef xNewRanges( pList );
+
+ if ( !xOldRanges.is() || *xOldRanges != *xNewRanges )
+ Update_Impl( xNewRanges, bColHeaders, bRowHeaders );
+}
+
+// XEmbeddedObjectSupplier
+
+uno::Reference<lang::XComponent> SAL_CALL ScChartObj::getEmbeddedObject()
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* pObject = sc::tools::findChartsByName(pDocShell, nTab, aChartName,
+ sc::tools::ChartSourceType::CELL_RANGE);
+ if ( pObject && svt::EmbeddedObjectRef::TryRunningState( pObject->GetObjRef() ) )
+ {
+ //TODO/LATER: is it OK that something is returned for *all* objects, not only own objects?
+ return uno::Reference < lang::XComponent > ( pObject->GetObjRef()->getComponent(), uno::UNO_QUERY );
+ }
+
+ return nullptr;
+}
+
+// XNamed
+
+OUString SAL_CALL ScChartObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return aChartName;
+}
+
+void SAL_CALL ScChartObj::setName( const OUString& /* aName */ )
+{
+ throw uno::RuntimeException(); // name cannot be changed
+}
+
+// XPropertySet
+
+uno::Reference< beans::XPropertySetInfo > ScChartObj::getPropertySetInfo()
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/condformatuno.cxx b/sc/source/ui/unoobj/condformatuno.cxx
new file mode 100644
index 0000000000..945752a3c5
--- /dev/null
+++ b/sc/source/ui/unoobj/condformatuno.cxx
@@ -0,0 +1,1899 @@
+/* -*- 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/.
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+#include <memory>
+#include <condformatuno.hxx>
+
+#include <document.hxx>
+#include <conditio.hxx>
+#include <colorscale.hxx>
+#include <docsh.hxx>
+#include <compiler.hxx>
+#include <tokenarray.hxx>
+
+#include <cellsuno.hxx>
+#include <convuno.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/sheet/DataBarAxis.hpp>
+#include <com/sun/star/sheet/IconSetType.hpp>
+#include <com/sun/star/sheet/ConditionFormatOperator.hpp>
+#include <com/sun/star/sheet/DataBarEntryType.hpp>
+#include <com/sun/star/sheet/ColorScaleEntryType.hpp>
+#include <com/sun/star/sheet/IconSetFormatEntry.hpp>
+#include <com/sun/star/sheet/ConditionEntryType.hpp>
+#include <com/sun/star/sheet/DateType.hpp>
+
+namespace {
+
+enum CondFormatProperties
+{
+ ID,
+ CondFormat_Range
+};
+
+std::span<const SfxItemPropertyMapEntry> getCondFormatPropset()
+{
+ static const SfxItemPropertyMapEntry aCondFormatPropertyMap_Impl[] =
+ {
+ {u"ID"_ustr, ID, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ {u"Range"_ustr, CondFormat_Range, cppu::UnoType<sheet::XSheetCellRanges>::get(), 0, 0},
+ };
+ return aCondFormatPropertyMap_Impl;
+}
+
+enum ConditionEntryProperties
+{
+ StyleName,
+ Formula1,
+ Formula2,
+ Operator
+};
+
+std::span<const SfxItemPropertyMapEntry> getConditionEntryrPropSet()
+{
+ static const SfxItemPropertyMapEntry aConditionEntryPropertyMap_Impl[] =
+ {
+ {u"StyleName"_ustr, StyleName, cppu::UnoType<OUString>::get(), 0, 0},
+ {u"Formula1"_ustr, Formula1, cppu::UnoType<OUString>::get(), 0, 0},
+ {u"Formula2"_ustr, Formula2, cppu::UnoType<OUString>::get(), 0, 0},
+ {u"Operator"_ustr, Operator, cppu::UnoType<decltype(sheet::ConditionFormatOperator::EQUAL)>::get(), 0, 0 },
+ };
+ return aConditionEntryPropertyMap_Impl;
+}
+
+struct ConditionEntryApiMap
+{
+ ScConditionMode eMode;
+ sal_Int32 nApiMode;
+};
+
+ConditionEntryApiMap const aConditionEntryMap[] =
+{
+ {ScConditionMode::Equal, sheet::ConditionFormatOperator::EQUAL},
+ {ScConditionMode::Less, sheet::ConditionFormatOperator::LESS},
+ {ScConditionMode::Greater, sheet::ConditionFormatOperator::GREATER},
+ {ScConditionMode::EqLess, sheet::ConditionFormatOperator::LESS_EQUAL},
+ {ScConditionMode::EqGreater, sheet::ConditionFormatOperator::GREATER_EQUAL},
+ {ScConditionMode::NotEqual, sheet::ConditionFormatOperator::NOT_EQUAL},
+ {ScConditionMode::Between, sheet::ConditionFormatOperator::BETWEEN},
+ {ScConditionMode::NotBetween, sheet::ConditionFormatOperator::NOT_BETWEEN},
+ {ScConditionMode::Duplicate, sheet::ConditionFormatOperator::DUPLICATE},
+ {ScConditionMode::NotDuplicate, sheet::ConditionFormatOperator::UNIQUE},
+ {ScConditionMode::Direct, sheet::ConditionFormatOperator::EXPRESSION},
+ {ScConditionMode::Top10, sheet::ConditionFormatOperator::TOP_N_ELEMENTS},
+ {ScConditionMode::Bottom10, sheet::ConditionFormatOperator::BOTTOM_N_ELEMENTS},
+ {ScConditionMode::TopPercent, sheet::ConditionFormatOperator::TOP_N_PERCENT},
+ {ScConditionMode::BottomPercent, sheet::ConditionFormatOperator::BOTTOM_N_PERCENT},
+ {ScConditionMode::AboveAverage, sheet::ConditionFormatOperator::ABOVE_AVERAGE},
+ {ScConditionMode::BelowAverage, sheet::ConditionFormatOperator::BELOW_AVERAGE},
+ {ScConditionMode::AboveEqualAverage, sheet::ConditionFormatOperator::ABOVE_EQUAL_AVERAGE},
+ {ScConditionMode::BelowEqualAverage, sheet::ConditionFormatOperator::BELOW_EQUAL_AVERAGE},
+ {ScConditionMode::Error, sheet::ConditionFormatOperator::ERROR},
+ {ScConditionMode::NoError, sheet::ConditionFormatOperator::NO_ERROR},
+ {ScConditionMode::BeginsWith, sheet::ConditionFormatOperator::BEGINS_WITH},
+ {ScConditionMode::EndsWith, sheet::ConditionFormatOperator::ENDS_WITH},
+ {ScConditionMode::ContainsText, sheet::ConditionFormatOperator::CONTAINS},
+ {ScConditionMode::NotContainsText, sheet::ConditionFormatOperator::NOT_CONTAINS},
+ {ScConditionMode::NONE, sheet::ConditionFormatOperator::EQUAL},
+};
+
+enum ColorScaleProperties
+{
+ ColorScaleEntries
+};
+
+std::span<const SfxItemPropertyMapEntry> getColorScalePropSet()
+{
+ static const SfxItemPropertyMapEntry aColorScalePropertyMap_Impl[] =
+ {
+ {u"ColorScaleEntries"_ustr, ColorScaleEntries, cppu::UnoType<uno::Sequence< sheet::XColorScaleEntry >>::get(), 0, 0 },
+ };
+ return aColorScalePropertyMap_Impl;
+}
+
+struct ColorScaleEntryTypeApiMap
+{
+ ScColorScaleEntryType eType;
+ sal_Int32 nApiType;
+};
+
+ColorScaleEntryTypeApiMap const aColorScaleEntryTypeMap[] =
+{
+ { COLORSCALE_MIN, sheet::ColorScaleEntryType::COLORSCALE_MIN },
+ { COLORSCALE_MAX, sheet::ColorScaleEntryType::COLORSCALE_MAX },
+ { COLORSCALE_VALUE, sheet::ColorScaleEntryType::COLORSCALE_VALUE },
+ { COLORSCALE_FORMULA, sheet::ColorScaleEntryType::COLORSCALE_FORMULA },
+ { COLORSCALE_PERCENT, sheet::ColorScaleEntryType::COLORSCALE_PERCENT },
+ { COLORSCALE_PERCENTILE, sheet::ColorScaleEntryType::COLORSCALE_PERCENTILE }
+};
+
+enum DataBarProperties
+{
+ AxisPosition,
+ UseGradient,
+ UseNegativeColor,
+ DataBar_ShowValue,
+ DataBar_Color,
+ AxisColor,
+ NegativeColor,
+ DataBarEntries,
+ MinimumLength,
+ MaximumLength
+};
+
+std::span<const SfxItemPropertyMapEntry> getDataBarPropSet()
+{
+ static const SfxItemPropertyMapEntry aDataBarPropertyMap_Impl[] =
+ {
+ {u"AxisPosition"_ustr, AxisPosition, cppu::UnoType<decltype(sheet::DataBarAxis::AXIS_AUTOMATIC)>::get(), 0, 0 },
+ {u"UseGradient"_ustr, UseGradient, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"UseNegativeColor"_ustr, UseNegativeColor, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"ShowValue"_ustr, DataBar_ShowValue, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"Color"_ustr, DataBar_Color, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ {u"AxisColor"_ustr, AxisColor, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ {u"NegativeColor"_ustr, NegativeColor, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ {u"DataBarEntries"_ustr, DataBarEntries, cppu::UnoType<uno::Sequence< sheet::XDataBarEntry >>::get(), 0, 0 },
+ {u"MinimumLength"_ustr, MinimumLength, cppu::UnoType<double>::get(), 0, 0 },
+ {u"MaximumLength"_ustr, MaximumLength, cppu::UnoType<double>::get(), 0, 0 },
+ };
+ return aDataBarPropertyMap_Impl;
+}
+
+struct DataBarAxisApiMap
+{
+ databar::ScAxisPosition ePos;
+ sal_Int32 nApiPos;
+};
+
+DataBarAxisApiMap const aDataBarAxisMap[] =
+{
+ { databar::NONE, sheet::DataBarAxis::AXIS_NONE },
+ { databar::AUTOMATIC, sheet::DataBarAxis::AXIS_AUTOMATIC },
+ { databar::MIDDLE, sheet::DataBarAxis::AXIS_MIDDLE }
+};
+
+struct DataBarEntryTypeApiMap
+{
+ ScColorScaleEntryType eType;
+ sal_Int32 nApiType;
+};
+
+DataBarEntryTypeApiMap const aDataBarEntryTypeMap[] =
+{
+ { COLORSCALE_AUTO, sheet::DataBarEntryType::DATABAR_AUTO },
+ { COLORSCALE_MIN, sheet::DataBarEntryType::DATABAR_MIN },
+ { COLORSCALE_MAX, sheet::DataBarEntryType::DATABAR_MAX },
+ { COLORSCALE_VALUE, sheet::DataBarEntryType::DATABAR_VALUE },
+ { COLORSCALE_FORMULA, sheet::DataBarEntryType::DATABAR_FORMULA },
+ { COLORSCALE_PERCENT, sheet::DataBarEntryType::DATABAR_PERCENT },
+ { COLORSCALE_PERCENTILE, sheet::DataBarEntryType::DATABAR_PERCENTILE }
+};
+
+enum IconSetProperties
+{
+ Icons,
+ Reverse,
+ ShowValue,
+ IconSetEntries
+};
+
+std::span<const SfxItemPropertyMapEntry> getIconSetPropSet()
+{
+ static const SfxItemPropertyMapEntry aIconSetPropertyMap_Impl[] =
+ {
+ {u"Icons"_ustr, Icons, cppu::UnoType<decltype(sheet::IconSetType::ICONSET_3SYMBOLS)>::get(), 0, 0 },
+ {u"Reverse"_ustr, Reverse, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"ShowValue"_ustr, ShowValue, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"IconSetEntries"_ustr, IconSetEntries, cppu::UnoType<uno::Sequence< sheet::XIconSetEntry >>::get(), 0, 0 },
+ };
+ return aIconSetPropertyMap_Impl;
+}
+
+struct IconSetTypeApiMap
+{
+ ScIconSetType eType;
+ sal_Int32 nApiType;
+};
+
+const IconSetTypeApiMap aIconSetApiMap[] =
+{
+ { IconSet_3Arrows, sheet::IconSetType::ICONSET_3ARROWS },
+ { IconSet_3ArrowsGray, sheet::IconSetType::ICONSET_3ARROWS_GRAY },
+ { IconSet_3Flags, sheet::IconSetType::ICONSET_3FLAGS },
+ { IconSet_3TrafficLights1, sheet::IconSetType::ICONSET_3TRAFFICLIGHTS1 },
+ { IconSet_3TrafficLights2, sheet::IconSetType::ICONSET_3TRAFFICLIGHTS2 },
+ { IconSet_3Signs, sheet::IconSetType::ICONSET_3SIGNS },
+ { IconSet_3Symbols, sheet::IconSetType::ICONSET_3SYMBOLS },
+ { IconSet_3Symbols2, sheet::IconSetType::ICONSET_3SYMBOLS2 },
+ { IconSet_3Smilies, sheet::IconSetType::ICONSET_3SMILIES },
+ { IconSet_3ColorSmilies, sheet::IconSetType::ICONSET_3COLOR_SIMILIES },
+ { IconSet_4Arrows, sheet::IconSetType::ICONSET_4ARROWS },
+ { IconSet_4ArrowsGray, sheet::IconSetType::ICONSET_4ARROWS_GRAY },
+ { IconSet_4Rating, sheet::IconSetType::ICONSET_4RATING },
+ { IconSet_4RedToBlack, sheet::IconSetType::ICONSET_4RED_TO_BLACK },
+ { IconSet_4TrafficLights, sheet::IconSetType::ICONSET_4TRAFFICLIGHTS },
+ { IconSet_5Arrows, sheet::IconSetType::ICONSET_5ARROWS },
+ { IconSet_5ArrowsGray, sheet::IconSetType::ICONSET_4ARROWS_GRAY },
+ { IconSet_5Ratings, sheet::IconSetType::ICONSET_5RATINGS },
+ { IconSet_5Quarters, sheet::IconSetType::ICONSET_5QUARTERS },
+};
+
+struct IconSetEntryTypeApiMap
+{
+ ScColorScaleEntryType eType;
+ sal_Int32 nApiType;
+};
+
+IconSetEntryTypeApiMap const aIconSetEntryTypeMap[] =
+{
+ { COLORSCALE_MIN, sheet::IconSetFormatEntry::ICONSET_MIN },
+ { COLORSCALE_VALUE, sheet::IconSetFormatEntry::ICONSET_VALUE },
+ { COLORSCALE_FORMULA, sheet::IconSetFormatEntry::ICONSET_FORMULA },
+ { COLORSCALE_PERCENT, sheet::IconSetFormatEntry::ICONSET_PERCENT },
+ { COLORSCALE_PERCENTILE, sheet::IconSetFormatEntry::ICONSET_PERCENTILE }
+};
+
+enum DateProperties
+{
+ Date_StyleName,
+ DateType
+};
+
+std::span<const SfxItemPropertyMapEntry> getCondDatePropSet()
+{
+ static const SfxItemPropertyMapEntry aCondDatePropertyMap_Impl[] =
+ {
+ {u"StyleName"_ustr, StyleName, cppu::UnoType<OUString>::get(), 0, 0},
+ {u"DateType"_ustr, Icons, cppu::UnoType<decltype(sheet::DateType::TODAY)>::get(), 0, 0 },
+ };
+ return aCondDatePropertyMap_Impl;
+}
+
+struct DateTypeApiMap
+{
+ condformat::ScCondFormatDateType eType;
+ sal_Int32 nApiType;
+};
+
+DateTypeApiMap const aDateTypeApiMap[] =
+{
+ { condformat::TODAY, sheet::DateType::TODAY },
+ { condformat::YESTERDAY, sheet::DateType::YESTERDAY },
+ { condformat::TOMORROW, sheet::DateType::TOMORROW },
+ { condformat::LAST7DAYS, sheet::DateType::LAST7DAYS },
+ { condformat::THISWEEK, sheet::DateType::THISWEEK },
+ { condformat::LASTWEEK, sheet::DateType::LASTWEEK },
+ { condformat::NEXTWEEK, sheet::DateType::NEXTWEEK },
+ { condformat::THISMONTH, sheet::DateType::THISMONTH },
+ { condformat::LASTMONTH, sheet::DateType::LASTMONTH },
+ { condformat::NEXTMONTH, sheet::DateType::NEXTMONTH },
+ { condformat::THISYEAR, sheet::DateType::THISYEAR },
+ { condformat::LASTYEAR, sheet::DateType::LASTYEAR },
+ { condformat::NEXTYEAR, sheet::DateType::NEXTYEAR }
+};
+
+}
+
+ScCondFormatsObj::ScCondFormatsObj(ScDocShell* pDocShell, SCTAB nTab):
+ mnTab(nTab),
+ mpDocShell(pDocShell)
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScCondFormatsObj::~ScCondFormatsObj()
+{
+ if (mpDocShell)
+ mpDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScCondFormatsObj::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ mpDocShell = nullptr;
+ }
+}
+
+sal_Int32 ScCondFormatsObj::createByRange(const uno::Reference< sheet::XSheetCellRanges >& xRanges)
+{
+ SolarMutexGuard aGuard;
+ if (!mpDocShell)
+ throw lang::IllegalArgumentException();
+
+ if (!xRanges.is())
+ throw lang::IllegalArgumentException();
+
+ const uno::Sequence<table::CellRangeAddress> aRanges =
+ xRanges->getRangeAddresses();
+
+ ScRangeList aCoreRange;
+ for (const auto& rRange : aRanges)
+ {
+ ScRange aRange;
+ ScUnoConversion::FillScRange(aRange, rRange);
+ aCoreRange.Join(aRange);
+ }
+
+ if (aCoreRange.empty())
+ throw lang::IllegalArgumentException();
+
+ SCTAB nTab = aCoreRange[0].aStart.Tab();
+
+ auto pNewFormat = std::make_unique<ScConditionalFormat>(0, &mpDocShell->GetDocument());
+ pNewFormat->SetRange(aCoreRange);
+ return mpDocShell->GetDocument().AddCondFormat(std::move(pNewFormat), nTab);
+}
+
+void ScCondFormatsObj::removeByID(const sal_Int32 nID)
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormatList* pFormatList = getCoreObject();
+ pFormatList->erase(nID);
+}
+
+uno::Sequence<uno::Reference<sheet::XConditionalFormat> > ScCondFormatsObj::getConditionalFormats()
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormatList* pFormatList = getCoreObject();
+ size_t n = pFormatList->size();
+ uno::Sequence<uno::Reference<sheet::XConditionalFormat> > aCondFormats(n);
+ std::transform(pFormatList->begin(), pFormatList->end(), aCondFormats.getArray(),
+ [this](const auto& rFormat)
+ { return uno::Reference(new ScCondFormatObj(mpDocShell, this, rFormat->GetKey())); });
+
+ return aCondFormats;
+}
+
+sal_Int32 ScCondFormatsObj::getLength()
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormatList* pFormatList = getCoreObject();
+ return pFormatList->size();
+}
+
+ScConditionalFormatList* ScCondFormatsObj::getCoreObject()
+{
+ if (!mpDocShell)
+ throw uno::RuntimeException();
+
+ ScConditionalFormatList* pList = mpDocShell->GetDocument().GetCondFormList(mnTab);
+ if (!pList)
+ throw uno::RuntimeException();
+
+ return pList;
+}
+
+namespace {
+
+uno::Reference<beans::XPropertySet> createConditionEntry(const ScFormatEntry* pEntry,
+ rtl::Reference<ScCondFormatObj> const & xParent)
+{
+ switch (pEntry->GetType())
+ {
+ case ScFormatEntry::Type::Condition:
+ case ScFormatEntry::Type::ExtCondition:
+ return new ScConditionEntryObj(xParent,
+ static_cast<const ScCondFormatEntry*>(pEntry));
+ break;
+ case ScFormatEntry::Type::Colorscale:
+ return new ScColorScaleFormatObj(xParent,
+ static_cast<const ScColorScaleFormat*>(pEntry));
+ break;
+ case ScFormatEntry::Type::Databar:
+ return new ScDataBarFormatObj(xParent,
+ static_cast<const ScDataBarFormat*>(pEntry));
+ break;
+ case ScFormatEntry::Type::Iconset:
+ return new ScIconSetFormatObj(xParent,
+ static_cast<const ScIconSetFormat*>(pEntry));
+ break;
+ case ScFormatEntry::Type::Date:
+ return new ScCondDateFormatObj(xParent,
+ static_cast<const ScCondDateFormatEntry*>(pEntry));
+ break;
+ default:
+ break;
+ }
+ return uno::Reference<beans::XPropertySet>();
+}
+
+}
+
+ScCondFormatObj::ScCondFormatObj(ScDocShell* pDocShell, rtl::Reference<ScCondFormatsObj> xCondFormats,
+ sal_Int32 nKey):
+ mxCondFormatList(std::move(xCondFormats)),
+ mpDocShell(pDocShell),
+ maPropSet(getCondFormatPropset()),
+ mnKey(nKey)
+{
+}
+
+ScCondFormatObj::~ScCondFormatObj()
+{
+}
+
+ScConditionalFormat* ScCondFormatObj::getCoreObject()
+{
+ ScConditionalFormatList* pList = mxCondFormatList->getCoreObject();
+ ScConditionalFormat* pFormat = pList->GetFormat(mnKey);
+ if (!pFormat)
+ throw uno::RuntimeException();
+
+ return pFormat;
+}
+
+ScDocShell* ScCondFormatObj::getDocShell()
+{
+ return mpDocShell;
+}
+
+void ScCondFormatObj::createEntry(const sal_Int32 nType, const sal_Int32 nPos)
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormat* pFormat = getCoreObject();
+ if (nPos > sal_Int32(pFormat->size()))
+ throw lang::IllegalArgumentException();
+
+ ScFormatEntry* pNewEntry = nullptr;
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ switch (nType)
+ {
+ case sheet::ConditionEntryType::CONDITION:
+ pNewEntry = new ScCondFormatEntry(ScConditionMode::Equal, "", "",
+ rDoc, pFormat->GetRange().GetTopLeftCorner(), "");
+ break;
+ case sheet::ConditionEntryType::COLORSCALE:
+ pNewEntry = new ScColorScaleFormat(&rDoc);
+ static_cast<ScColorScaleFormat*>(pNewEntry)->EnsureSize();
+ break;
+ case sheet::ConditionEntryType::DATABAR:
+ pNewEntry = new ScDataBarFormat(&rDoc);
+ static_cast<ScDataBarFormat*>(pNewEntry)->EnsureSize();
+ break;
+ case sheet::ConditionEntryType::ICONSET:
+ pNewEntry = new ScIconSetFormat(&rDoc);
+ static_cast<ScIconSetFormat*>(pNewEntry)->EnsureSize();
+ break;
+ case sheet::ConditionEntryType::DATE:
+ pNewEntry = new ScCondDateFormatEntry(&rDoc);
+ break;
+ default:
+ SAL_WARN("sc", "unknown conditional format type");
+ throw lang::IllegalArgumentException();
+ }
+
+ pFormat->AddEntry(pNewEntry);
+}
+
+void ScCondFormatObj::removeByIndex(const sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ if (getCoreObject()->size() >= o3tl::make_unsigned(nIndex))
+ throw lang::IllegalArgumentException();
+
+ getCoreObject()->RemoveEntry(nIndex);
+}
+
+uno::Type ScCondFormatObj::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get();
+}
+
+sal_Bool ScCondFormatObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormat* pFormat = getCoreObject();
+ return !pFormat->IsEmpty();
+}
+
+sal_Int32 ScCondFormatObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormat* pFormat = getCoreObject();
+
+ return pFormat->size();
+}
+
+uno::Any ScCondFormatObj::getByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ if (getCoreObject()->size() <= o3tl::make_unsigned(nIndex))
+ throw lang::IllegalArgumentException();
+
+ const ScFormatEntry* pEntry = getCoreObject()->GetEntry(nIndex);
+ uno::Reference<beans::XPropertySet> xCondEntry =
+ createConditionEntry(pEntry, this);
+ return uno::Any(xCondEntry);
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCondFormatObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap()));
+ return aRef;
+}
+
+void SAL_CALL ScCondFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case ID:
+ throw lang::IllegalArgumentException();
+ break;
+ case CondFormat_Range:
+ {
+ uno::Reference<sheet::XSheetCellRanges> xRange;
+ if (aValue >>= xRange)
+ {
+ ScConditionalFormat* pFormat = getCoreObject();
+ const uno::Sequence<table::CellRangeAddress> aRanges =
+ xRange->getRangeAddresses();
+ ScRangeList aTargetRange;
+ for (const auto& rRange : aRanges)
+ {
+ ScRange aRange;
+ ScUnoConversion::FillScRange(aRange, rRange);
+ aTargetRange.Join(aRange);
+ }
+ pFormat->SetRange(aTargetRange);
+ }
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+}
+
+uno::Any SAL_CALL ScCondFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+ switch(pEntry->nWID)
+ {
+ case ID:
+ aAny <<= sal_Int32(getCoreObject()->GetKey());
+ break;
+ case CondFormat_Range:
+ {
+ const ScRangeList& rRange = getCoreObject()->GetRange();
+ uno::Reference<sheet::XSheetCellRanges> xRange;
+ xRange.set(new ScCellRangesObj(mpDocShell, rRange));
+ aAny <<= xRange;
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+ return aAny;
+}
+
+void SAL_CALL ScCondFormatObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondFormatObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondFormatObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondFormatObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+namespace {
+
+bool isObjectStillAlive(const ScConditionalFormat* pFormat, const ScFormatEntry* pEntry)
+{
+ for(size_t i = 0, n= pFormat->size(); i < n; ++i)
+ {
+ if (pFormat->GetEntry(i) == pEntry)
+ return true;
+ }
+ return false;
+}
+
+}
+
+ScConditionEntryObj::ScConditionEntryObj(rtl::Reference<ScCondFormatObj> const & xParent,
+ const ScCondFormatEntry* pFormat):
+ mpDocShell(xParent->getDocShell()),
+ mxParent(xParent),
+ maPropSet(getConditionEntryrPropSet()),
+ mpFormat(pFormat)
+{
+}
+
+ScConditionEntryObj::~ScConditionEntryObj()
+{
+}
+
+ScCondFormatEntry* ScConditionEntryObj::getCoreObject()
+{
+ ScConditionalFormat* pFormat = mxParent->getCoreObject();
+ if (isObjectStillAlive(pFormat, mpFormat))
+ return const_cast<ScCondFormatEntry*>(mpFormat);
+
+ throw lang::IllegalArgumentException();
+}
+
+sal_Int32 ScConditionEntryObj::getType()
+{
+ return sheet::ConditionEntryType::CONDITION;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScConditionEntryObj::getPropertySetInfo()
+{
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScConditionEntryObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case StyleName:
+ {
+ OUString aStyleName;
+ if ((aValue >>= aStyleName) && !aStyleName.isEmpty())
+ getCoreObject()->UpdateStyleName(aStyleName);
+ }
+ break;
+ case Formula1:
+ {
+ OUString aFormula;
+ if ((aValue >>= aFormula) && !aFormula.isEmpty())
+ {
+ ScCompiler aComp(mpDocShell->GetDocument(), getCoreObject()->GetSrcPos());
+ aComp.SetGrammar(mpDocShell->GetDocument().GetGrammar());
+ std::unique_ptr<ScTokenArray> pArr(aComp.CompileString(aFormula));
+ getCoreObject()->SetFormula1(*pArr);
+ }
+ }
+ break;
+ case Formula2:
+ {
+ OUString aFormula;
+ if ((aValue >>= aFormula) && !aFormula.isEmpty())
+ {
+ ScCompiler aComp(mpDocShell->GetDocument(), getCoreObject()->GetSrcPos());
+ aComp.SetGrammar(mpDocShell->GetDocument().GetGrammar());
+ std::unique_ptr<ScTokenArray> pArr(aComp.CompileString(aFormula));
+ getCoreObject()->SetFormula2(*pArr);
+ }
+ }
+ break;
+ case Operator:
+ {
+ sal_Int32 nVal;
+ if (aValue >>= nVal)
+ {
+ for (ConditionEntryApiMap const & rEntry : aConditionEntryMap)
+ {
+ if (rEntry.nApiMode == nVal)
+ {
+ getCoreObject()->SetOperation(rEntry.eMode);
+ break;
+ }
+ }
+ }
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unsupported property");
+ }
+}
+
+uno::Any SAL_CALL ScConditionEntryObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+ switch(pEntry->nWID)
+ {
+ case StyleName:
+ aAny <<= getCoreObject()->GetStyle();
+ break;
+ case Formula1:
+ {
+ ScAddress aCursor = getCoreObject()->GetSrcPos();
+ OUString aFormula = getCoreObject()->GetExpression(aCursor, 0);
+ aAny <<= aFormula;
+ }
+ break;
+ case Formula2:
+ {
+ ScAddress aCursor = getCoreObject()->GetSrcPos();
+ OUString aFormula = getCoreObject()->GetExpression(aCursor, 1);
+ aAny <<= aFormula;
+ }
+ break;
+ case Operator:
+ {
+ ScConditionMode eMode = getCoreObject()->GetOperation();
+ for (ConditionEntryApiMap const & rEntry : aConditionEntryMap)
+ {
+ if (rEntry.eMode == eMode)
+ {
+ aAny <<= rEntry.nApiMode;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unsupported property");
+ }
+ return aAny;
+}
+
+void SAL_CALL ScConditionEntryObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScConditionEntryObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScConditionEntryObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScConditionEntryObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+ScColorScaleFormatObj::ScColorScaleFormatObj(rtl::Reference<ScCondFormatObj> xParent,
+ const ScColorScaleFormat* pFormat):
+ mxParent(std::move(xParent)),
+ maPropSet(getColorScalePropSet()),
+ mpFormat(pFormat)
+{
+}
+
+ScColorScaleFormatObj::~ScColorScaleFormatObj()
+{
+}
+
+ScColorScaleFormat* ScColorScaleFormatObj::getCoreObject()
+{
+ ScConditionalFormat* pFormat = mxParent->getCoreObject();
+ if (isObjectStillAlive(pFormat, mpFormat))
+ return const_cast<ScColorScaleFormat*>(mpFormat);
+
+ throw lang::IllegalArgumentException();
+}
+
+sal_Int32 ScColorScaleFormatObj::getType()
+{
+ return sheet::ConditionEntryType::COLORSCALE;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScColorScaleFormatObj::getPropertySetInfo()
+{
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+namespace {
+
+void setColorScaleEntry(ScColorScaleEntry* pEntry, uno::Reference<sheet::XColorScaleEntry> const & xEntry)
+{
+ ScColorScaleEntryType eType = ScColorScaleEntryType();
+ sal_Int32 nApiType = xEntry->getType();
+ bool bFound = false;
+ for (ColorScaleEntryTypeApiMap const & rEntry : aColorScaleEntryTypeMap)
+ {
+ if (rEntry.nApiType == nApiType)
+ {
+ eType = rEntry.eType;
+ bFound = true;
+ break;
+ }
+ }
+
+ if (!bFound)
+ throw lang::IllegalArgumentException();
+
+ pEntry->SetType(eType);
+ pEntry->SetColor(Color(ColorTransparency, xEntry->getColor()));
+ switch (eType)
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ {
+ double nVal = xEntry->getFormula().toDouble();
+ pEntry->SetValue(nVal);
+ }
+ break;
+ }
+}
+
+}
+
+void SAL_CALL ScColorScaleFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case ColorScaleEntries:
+ {
+ uno::Sequence<uno::Reference<sheet::XColorScaleEntry> > aEntries;
+ if (!(aValue >>= aEntries))
+ throw lang::IllegalArgumentException();
+
+ if (aEntries.getLength() < 2)
+ throw lang::IllegalArgumentException();
+
+ // TODO: we need to make sure that there are enough entries
+ size_t n = size_t(aEntries.getLength());
+ for (size_t i = 0; i < n; ++i)
+ {
+ setColorScaleEntry(getCoreObject()->GetEntry(i), aEntries[i]);
+ }
+
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+}
+
+uno::Any SAL_CALL ScColorScaleFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+
+ switch(pEntry->nWID)
+ {
+ case ColorScaleEntries:
+ {
+ uno::Sequence<uno::Reference<sheet::XColorScaleEntry> > aEntries(getCoreObject()->size());
+ auto aEntriesRange = asNonConstRange(aEntries);
+ for (size_t i = 0; i < getCoreObject()->size(); ++i)
+ {
+ aEntriesRange[i] = new ScColorScaleEntryObj(this, i);
+ }
+ aAny <<= aEntries;
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+
+ return aAny;
+}
+
+void SAL_CALL ScColorScaleFormatObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScColorScaleFormatObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScColorScaleFormatObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScColorScaleFormatObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+ScColorScaleEntryObj::ScColorScaleEntryObj(rtl::Reference<ScColorScaleFormatObj> xParent,
+ size_t nPos):
+ mxParent(std::move(xParent)),
+ mnPos(nPos)
+{
+}
+
+ScColorScaleEntryObj::~ScColorScaleEntryObj()
+{
+}
+
+ScColorScaleEntry* ScColorScaleEntryObj::getCoreObject()
+{
+ ScColorScaleFormat* pFormat = mxParent->getCoreObject();
+ if (pFormat->size() <= mnPos)
+ throw lang::IllegalArgumentException();
+
+ return pFormat->GetEntry(mnPos);
+}
+
+sal_Int32 ScColorScaleEntryObj::getColor()
+{
+ Color aColor = getCoreObject()->GetColor();
+ return sal_Int32(aColor);
+}
+
+void ScColorScaleEntryObj::setColor(sal_Int32 aColor)
+{
+ getCoreObject()->SetColor(Color(ColorTransparency, aColor));
+}
+
+sal_Int32 ScColorScaleEntryObj::getType()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ for (ColorScaleEntryTypeApiMap const & rEntry : aColorScaleEntryTypeMap)
+ {
+ if (rEntry.eType == pEntry->GetType())
+ {
+ return rEntry.nApiType;
+ }
+ }
+
+ throw lang::IllegalArgumentException();
+}
+
+void ScColorScaleEntryObj::setType(sal_Int32 nType)
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ for (ColorScaleEntryTypeApiMap const & rEntry : aColorScaleEntryTypeMap)
+ {
+ if (rEntry.nApiType == nType)
+ {
+ pEntry->SetType(rEntry.eType);
+ return;
+ }
+ }
+ throw lang::IllegalArgumentException();
+}
+
+OUString ScColorScaleEntryObj::getFormula()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ return OUString::number(pEntry->GetValue());
+ }
+
+ return OUString();
+}
+
+void ScColorScaleEntryObj::setFormula(const OUString& rFormula)
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ // pEntry->SetFormula(rFormula);
+ break;
+ default:
+ pEntry->SetValue(rFormula.toDouble());
+ break;
+ }
+}
+
+
+ScDataBarFormatObj::ScDataBarFormatObj(rtl::Reference<ScCondFormatObj> xParent,
+ const ScDataBarFormat* pFormat):
+ mxParent(std::move(xParent)),
+ maPropSet(getDataBarPropSet()),
+ mpFormat(pFormat)
+{
+}
+
+ScDataBarFormatObj::~ScDataBarFormatObj()
+{
+}
+
+ScDataBarFormat* ScDataBarFormatObj::getCoreObject()
+{
+ ScConditionalFormat* pFormat = mxParent->getCoreObject();
+ if (isObjectStillAlive(pFormat, mpFormat))
+ return const_cast<ScDataBarFormat*>(mpFormat);
+
+ throw lang::IllegalArgumentException();
+}
+
+sal_Int32 ScDataBarFormatObj::getType()
+{
+ return sheet::ConditionEntryType::DATABAR;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDataBarFormatObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+namespace {
+
+void setDataBarEntry(ScColorScaleEntry* pEntry, uno::Reference<sheet::XDataBarEntry> const & xEntry)
+{
+ ScColorScaleEntryType eType = ScColorScaleEntryType();
+ sal_Int32 nApiType = xEntry->getType();
+ bool bFound = false;
+ for (DataBarEntryTypeApiMap const & rEntry : aDataBarEntryTypeMap)
+ {
+ if (rEntry.nApiType == nApiType)
+ {
+ eType = rEntry.eType;
+ bFound = true;
+ break;
+ }
+ }
+
+ if (!bFound)
+ throw lang::IllegalArgumentException();
+
+ pEntry->SetType(eType);
+ switch (eType)
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ {
+ double nVal = xEntry->getFormula().toDouble();
+ pEntry->SetValue(nVal);
+ }
+ break;
+ }
+}
+
+}
+
+void SAL_CALL ScDataBarFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case AxisPosition:
+ {
+ sal_Int32 nVal;
+ if (aValue >>= nVal)
+ {
+ for (DataBarAxisApiMap const & rEntry : aDataBarAxisMap)
+ {
+ if (rEntry.nApiPos == nVal)
+ {
+ getCoreObject()->GetDataBarData()->meAxisPosition =
+ rEntry.ePos;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case UseGradient:
+ {
+ bool bUseGradient = true;
+ if (aValue >>= bUseGradient)
+ {
+ getCoreObject()->GetDataBarData()->mbGradient = bUseGradient;
+ }
+ }
+ break;
+ case UseNegativeColor:
+ {
+ bool bUseNegativeColor = false;
+ if (aValue >>= bUseNegativeColor)
+ {
+ getCoreObject()->GetDataBarData()->mbNeg = bUseNegativeColor;
+ if (bUseNegativeColor && !getCoreObject()->GetDataBarData()->mxNegativeColor)
+ {
+ getCoreObject()->GetDataBarData()->mxNegativeColor = COL_AUTO;
+ }
+ }
+ }
+ break;
+ case DataBar_ShowValue:
+ {
+ bool bShowValue = true;
+ if (aValue >>= bShowValue)
+ {
+ getCoreObject()->GetDataBarData()->mbOnlyBar = !bShowValue;
+ }
+ }
+ break;
+ case DataBar_Color:
+ {
+ Color nColor = COL_AUTO;
+ if (aValue >>= nColor)
+ {
+ getCoreObject()->GetDataBarData()->maPositiveColor = nColor;
+ }
+ }
+ break;
+ case AxisColor:
+ {
+ Color nAxisColor = COL_AUTO;
+ if (aValue >>= nAxisColor)
+ {
+ getCoreObject()->GetDataBarData()->maAxisColor = nAxisColor;
+ }
+ }
+ break;
+ case NegativeColor:
+ {
+ Color nNegativeColor = COL_AUTO;
+ if (!(aValue >>= nNegativeColor) || !getCoreObject()->GetDataBarData()->mbNeg)
+ throw lang::IllegalArgumentException();
+
+ getCoreObject()->GetDataBarData()->mxNegativeColor = nNegativeColor;
+
+ }
+ break;
+ case DataBarEntries:
+ {
+ uno::Sequence<uno::Reference<sheet::XDataBarEntry> > aEntries;
+ if (!(aValue >>= aEntries))
+ throw lang::IllegalArgumentException();
+
+ if (aEntries.getLength() != 2)
+ throw lang::IllegalArgumentException();
+
+ setDataBarEntry(getCoreObject()->GetDataBarData()->mpLowerLimit.get(),
+ aEntries[0]);
+ setDataBarEntry(getCoreObject()->GetDataBarData()->mpUpperLimit.get(),
+ aEntries[1]);
+
+ }
+ break;
+ case MinimumLength:
+ {
+ double nLength = 0;
+ if (!(aValue >>= nLength) || nLength >= 100 || nLength < 0)
+ throw lang::IllegalArgumentException();
+ getCoreObject()->GetDataBarData()->mnMinLength = nLength;
+
+ }
+ break;
+ case MaximumLength:
+ {
+ double nLength = 0;
+ if (!(aValue >>= nLength) || nLength > 100 || nLength <= 0)
+ throw lang::IllegalArgumentException();
+ getCoreObject()->GetDataBarData()->mnMaxLength = nLength;
+
+ }
+ break;
+ }
+}
+
+uno::Any SAL_CALL ScDataBarFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+ switch(pEntry->nWID)
+ {
+ case AxisPosition:
+ {
+ databar::ScAxisPosition ePos = getCoreObject()->GetDataBarData()->meAxisPosition;
+ sal_Int32 nApiPos = sheet::DataBarAxis::AXIS_NONE;
+ for (DataBarAxisApiMap const & rEntry : aDataBarAxisMap)
+ {
+ if (rEntry.ePos == ePos)
+ {
+ nApiPos = rEntry.nApiPos;
+ }
+ }
+
+ aAny <<= nApiPos;
+ }
+ break;
+ case UseGradient:
+ {
+ aAny <<= getCoreObject()->GetDataBarData()->mbGradient;
+ }
+ break;
+ case UseNegativeColor:
+ {
+ aAny <<= getCoreObject()->GetDataBarData()->mbNeg;
+ }
+ break;
+ case DataBar_ShowValue:
+ {
+ aAny <<= !getCoreObject()->GetDataBarData()->mbOnlyBar;
+ }
+ break;
+ case DataBar_Color:
+ {
+ aAny <<= getCoreObject()->GetDataBarData()->maPositiveColor;
+ }
+ break;
+ case AxisColor:
+ {
+ aAny <<= getCoreObject()->GetDataBarData()->maAxisColor;
+ }
+ break;
+ case NegativeColor:
+ {
+ if (getCoreObject()->GetDataBarData()->mbNeg && getCoreObject()->GetDataBarData()->mxNegativeColor)
+ {
+ aAny <<= *getCoreObject()->GetDataBarData()->mxNegativeColor;
+ }
+ }
+ break;
+ case DataBarEntries:
+ {
+ uno::Sequence<uno::Reference<sheet::XDataBarEntry> > aEntries
+ {
+ new ScDataBarEntryObj(this, 0),
+ new ScDataBarEntryObj(this, 1)
+ };
+ aAny <<= aEntries;
+ }
+ break;
+ }
+ return aAny;
+}
+
+void SAL_CALL ScDataBarFormatObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScDataBarFormatObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScDataBarFormatObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScDataBarFormatObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+ScDataBarEntryObj::ScDataBarEntryObj(rtl::Reference<ScDataBarFormatObj> xParent,
+ size_t nPos):
+ mxParent(std::move(xParent)),
+ mnPos(nPos)
+{
+}
+
+ScDataBarEntryObj::~ScDataBarEntryObj()
+{
+}
+
+ScColorScaleEntry* ScDataBarEntryObj::getCoreObject()
+{
+ ScDataBarFormat* pFormat = mxParent->getCoreObject();
+ ScColorScaleEntry* pEntry;
+ if (mnPos == 0)
+ pEntry = pFormat->GetDataBarData()->mpLowerLimit.get();
+ else
+ pEntry = pFormat->GetDataBarData()->mpUpperLimit.get();
+
+ return pEntry;
+}
+
+sal_Int32 ScDataBarEntryObj::getType()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ for (DataBarEntryTypeApiMap const & rEntry : aDataBarEntryTypeMap)
+ {
+ if (rEntry.eType == pEntry->GetType())
+ {
+ return rEntry.nApiType;
+ }
+ }
+
+ throw lang::IllegalArgumentException();
+}
+
+void ScDataBarEntryObj::setType(sal_Int32 nType)
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ for (DataBarEntryTypeApiMap const & rEntry : aDataBarEntryTypeMap)
+ {
+ if (rEntry.nApiType == nType)
+ {
+ pEntry->SetType(rEntry.eType);
+ return;
+ }
+ }
+ throw lang::IllegalArgumentException();
+}
+
+OUString ScDataBarEntryObj::getFormula()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ return OUString::number(pEntry->GetValue());
+ }
+
+ return OUString();
+}
+
+void ScDataBarEntryObj::setFormula(const OUString& rFormula)
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ // pEntry->SetFormula(rFormula);
+ break;
+ default:
+ pEntry->SetValue(rFormula.toDouble());
+ break;
+ }
+}
+
+
+ScIconSetFormatObj::ScIconSetFormatObj(rtl::Reference<ScCondFormatObj> xParent,
+ const ScIconSetFormat* pFormat):
+ mxParent(std::move(xParent)),
+ maPropSet(getIconSetPropSet()),
+ mpFormat(pFormat)
+{
+}
+
+ScIconSetFormatObj::~ScIconSetFormatObj()
+{
+}
+
+ScIconSetFormat* ScIconSetFormatObj::getCoreObject()
+{
+ ScConditionalFormat* pFormat = mxParent->getCoreObject();
+ if (isObjectStillAlive(pFormat, mpFormat))
+ return const_cast<ScIconSetFormat*>(mpFormat);
+
+ throw lang::IllegalArgumentException();
+}
+
+sal_Int32 ScIconSetFormatObj::getType()
+{
+ return sheet::ConditionEntryType::ICONSET;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScIconSetFormatObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+namespace {
+
+void setIconSetEntry(ScIconSetFormat* pFormat, uno::Reference<sheet::XIconSetEntry> const & xEntry, size_t nPos)
+{
+ ScIconSetFormatData* pData = pFormat->GetIconSetData();
+ ScColorScaleEntryType eType = ScColorScaleEntryType();
+ sal_Int32 nApiType = xEntry->getType();
+ bool bFound = false;
+ for (IconSetEntryTypeApiMap const & rEntry : aIconSetEntryTypeMap)
+ {
+ if (rEntry.nApiType == nApiType)
+ {
+ eType = rEntry.eType;
+ bFound = true;
+ break;
+ }
+ }
+
+ if (!bFound)
+ throw lang::IllegalArgumentException();
+
+ pData->m_Entries[nPos]->SetType(eType);
+ switch (eType)
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ {
+ double nVal = xEntry->getFormula().toDouble();
+ pData->m_Entries[nPos]->SetValue(nVal);
+ }
+ break;
+ }
+}
+
+}
+
+void SAL_CALL ScIconSetFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case ShowValue:
+ {
+ bool bShowValue = true;
+ aValue >>= bShowValue;
+ getCoreObject()->GetIconSetData()->mbShowValue = bShowValue;
+ }
+ break;
+ case Reverse:
+ {
+ bool bReverse = false;
+ aValue >>= bReverse;
+ getCoreObject()->GetIconSetData()->mbReverse = bReverse;
+ }
+ break;
+ case Icons:
+ {
+ sal_Int32 nApiType = -1;
+ aValue >>= nApiType;
+ ScIconSetType eType = IconSet_3Arrows;
+ bool bFound = false;
+ for (const IconSetTypeApiMap & rEntry : aIconSetApiMap)
+ {
+ if (rEntry.nApiType == nApiType)
+ {
+ eType = rEntry.eType;
+ bFound = true;
+ break;
+ }
+ }
+
+ if (!bFound)
+ {
+ throw lang::IllegalArgumentException();
+ }
+
+ // TODO: we need to make sure that there are enough entries
+ getCoreObject()->GetIconSetData()->eIconSetType = eType;
+ }
+ break;
+ case IconSetEntries:
+ {
+ uno::Sequence<uno::Reference<sheet::XIconSetEntry> > aEntries;
+ if (!(aValue >>= aEntries))
+ throw lang::IllegalArgumentException();
+
+ // TODO: we need to check that the number of entries
+ // corresponds to the icon type
+ sal_Int32 nLength = aEntries.getLength();
+ for (size_t i = 0; i < o3tl::make_unsigned(nLength); ++i)
+ {
+ setIconSetEntry(getCoreObject(), aEntries[i], i);
+ }
+
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+uno::Any SAL_CALL ScIconSetFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+
+ switch(pEntry->nWID)
+ {
+ case ShowValue:
+ aAny <<= getCoreObject()->GetIconSetData()->mbShowValue;
+ break;
+ case Reverse:
+ aAny <<= getCoreObject()->GetIconSetData()->mbReverse;
+ break;
+ case Icons:
+ {
+ ScIconSetType eType = getCoreObject()->GetIconSetData()->eIconSetType;
+ for (const IconSetTypeApiMap & rEntry : aIconSetApiMap)
+ {
+ if (rEntry.eType == eType)
+ {
+ aAny <<= rEntry.nApiType;
+ break;
+ }
+ }
+ }
+ break;
+ case IconSetEntries:
+ {
+ size_t nSize = getCoreObject()->size();
+ uno::Sequence<uno::Reference<sheet::XIconSetEntry> > aEntries(nSize);
+ auto aEntriesRange = asNonConstRange(aEntries);
+ for (size_t i = 0; i < nSize; ++i)
+ {
+ aEntriesRange[i] = new ScIconSetEntryObj(this, i);
+ }
+ aAny <<= aEntries;
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+ return aAny;
+}
+
+void SAL_CALL ScIconSetFormatObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScIconSetFormatObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScIconSetFormatObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScIconSetFormatObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+ScIconSetEntryObj::ScIconSetEntryObj(rtl::Reference<ScIconSetFormatObj> xParent,
+ size_t nPos):
+ mxParent(std::move(xParent)),
+ mnPos(nPos)
+{
+}
+
+ScIconSetEntryObj::~ScIconSetEntryObj()
+{
+}
+
+ScColorScaleEntry* ScIconSetEntryObj::getCoreObject()
+{
+ ScIconSetFormat* pFormat = mxParent->getCoreObject();
+ if (pFormat->GetIconSetData()->m_Entries.size() <= mnPos)
+ throw lang::IllegalArgumentException();
+
+ return pFormat->GetIconSetData()->m_Entries[mnPos].get();
+}
+
+sal_Int32 ScIconSetEntryObj::getType()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ // the first entry always is minimum
+ if (mnPos == 0)
+ return sheet::IconSetFormatEntry::ICONSET_MIN;
+
+ for (IconSetEntryTypeApiMap const & rEntry : aIconSetEntryTypeMap)
+ {
+ if (rEntry.eType == pEntry->GetType())
+ {
+ return rEntry.nApiType;
+ }
+ }
+
+ throw lang::IllegalArgumentException();
+}
+
+void ScIconSetEntryObj::setType(sal_Int32 nType)
+{
+ // first entry is always MIN
+ if (mnPos == 0)
+ return;
+
+ ScColorScaleEntry* pEntry = getCoreObject();
+ for (IconSetEntryTypeApiMap const & rEntry : aIconSetEntryTypeMap)
+ {
+ if (rEntry.nApiType == nType)
+ {
+ pEntry->SetType(rEntry.eType);
+ return;
+ }
+ }
+ throw lang::IllegalArgumentException();
+}
+
+OUString ScIconSetEntryObj::getFormula()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ return OUString::number(pEntry->GetValue());
+ }
+
+ return OUString();
+}
+
+void ScIconSetEntryObj::setFormula(const OUString& rFormula)
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ // pEntry->SetFormula(rFormula);
+ break;
+ default:
+ pEntry->SetValue(rFormula.toDouble());
+ break;
+ }
+}
+
+ScCondDateFormatObj::ScCondDateFormatObj(rtl::Reference<ScCondFormatObj> xParent,
+ const ScCondDateFormatEntry* pFormat):
+ mxParent(std::move(xParent)),
+ maPropSet(getCondDatePropSet()),
+ mpFormat(pFormat)
+{
+}
+
+ScCondDateFormatObj::~ScCondDateFormatObj()
+{
+}
+
+ScCondDateFormatEntry* ScCondDateFormatObj::getCoreObject()
+{
+ ScConditionalFormat* pFormat = mxParent->getCoreObject();
+ if (isObjectStillAlive(pFormat, mpFormat))
+ return const_cast<ScCondDateFormatEntry*>(mpFormat);
+
+ throw lang::IllegalArgumentException();
+}
+
+sal_Int32 ScCondDateFormatObj::getType()
+{
+ return sheet::ConditionEntryType::DATE;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCondDateFormatObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScCondDateFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case Date_StyleName:
+ {
+ OUString aStyleName;
+ if (!(aValue >>= aStyleName))
+ throw lang::IllegalArgumentException();
+
+ getCoreObject()->SetStyleName(aStyleName);
+
+ }
+ break;
+ case DateType:
+ {
+ sal_Int32 nApiType = -1;
+ if (!(aValue >>= nApiType))
+ throw lang::IllegalArgumentException();
+
+ for (DateTypeApiMap const & rEntry : aDateTypeApiMap)
+ {
+ if (rEntry.nApiType == nApiType)
+ {
+ getCoreObject()->SetDateType(rEntry.eType);
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+uno::Any SAL_CALL ScCondDateFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+
+ switch(pEntry->nWID)
+ {
+ case Date_StyleName:
+ {
+ OUString aStyleName = getCoreObject()->GetStyleName();
+ aAny <<= aStyleName;
+ }
+ break;
+ case DateType:
+ {
+ condformat::ScCondFormatDateType eType = getCoreObject()->GetDateType();
+ for (DateTypeApiMap const & rEntry : aDateTypeApiMap)
+ {
+ if (rEntry.eType == eType)
+ {
+ aAny <<= rEntry.nApiType;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+ return aAny;
+}
+
+void SAL_CALL ScCondDateFormatObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondDateFormatObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondDateFormatObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondDateFormatObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/confuno.cxx b/sc/source/ui/unoobj/confuno.cxx
new file mode 100644
index 0000000000..4c69e65645
--- /dev/null
+++ b/sc/source/ui/unoobj/confuno.cxx
@@ -0,0 +1,661 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <utility>
+
+#include <config_features.h>
+
+#include <confuno.hxx>
+#include <unonames.hxx>
+#include <docsh.hxx>
+#include <miscuno.hxx>
+#include <forbiuno.hxx>
+#include <appoptio.hxx>
+#include <viewopti.hxx>
+#include <docpool.hxx>
+#include <sc.hrc>
+#include <scmod.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/document/LinkUpdateModes.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <formula/grammar.hxx>
+#include <sfx2/printer.hxx>
+#include <svl/itemset.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/stream.hxx>
+
+using namespace com::sun::star;
+
+constexpr OUString SCSAVEVERSION = u"SaveVersionOnClose"_ustr;
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetConfigPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aConfigPropertyMap_Impl[] =
+ {
+ { SC_UNO_SHOWZERO, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWNOTES, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWFORMULASMARKS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWGRID, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_GRIDCOLOR, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_SHOWPAGEBR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_LINKUPD, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_COLROWHDR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHEETTABS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_OUTLSYMB, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SNAPTORASTER, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_RASTERVIS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_RASTERRESX, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_RASTERRESY, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_RASTERSUBX, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_RASTERSUBY, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_RASTERSYNC, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_AUTOCALC, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_PRINTERNAME, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNO_PRINTERSETUP, 0, cppu::UnoType<uno::Sequence<sal_Int8>>::get(), 0, 0},
+ { SC_UNO_PRINTERPAPER, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_APPLYDOCINF, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_SAVE_THUMBNAIL, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_FORBIDDEN, 0, cppu::UnoType<i18n::XForbiddenCharacters>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_CHARCOMP, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_ASIANKERN, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SCSAVEVERSION, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_UPDTEMPL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ /*Stampit enable/disable print cancel */
+ { SC_UNO_ALLOWPRINTJOBCANCEL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_LOADREADONLY, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHAREDOC, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_MODIFYPASSWORDINFO, 0, cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get(), 0, 0},
+ { SC_UNO_MODIFYPASSWORDHASH, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_EMBED_FONTS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_EMBED_ONLY_USED_FONTS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_EMBED_FONT_SCRIPT_LATIN, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_EMBED_FONT_SCRIPT_ASIAN, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_EMBED_FONT_SCRIPT_COMPLEX, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_IMAGE_PREFERRED_DPI, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_SYNTAXSTRINGREF, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ };
+ return aConfigPropertyMap_Impl;
+}
+
+ScDocumentConfiguration::ScDocumentConfiguration(ScDocShell* pDocSh)
+ : pDocShell(pDocSh) ,
+ aPropSet ( lcl_GetConfigPropertyMap() )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDocumentConfiguration::~ScDocumentConfiguration()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDocumentConfiguration::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDocumentConfiguration::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScDocumentConfiguration::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if(!pDocShell)
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bUpdateHeights = false;
+
+ ScViewOptions aViewOpt(rDoc.GetViewOptions());
+
+ /*Stampit enable/disable print cancel */
+ if ( aPropertyName == SC_UNO_ALLOWPRINTJOBCANCEL )
+ pDocShell->Stamp_SetPrintCancelState( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ /*Stampit enable/disable print cancel */
+
+ else if ( aPropertyName == SC_UNO_SHOWZERO )
+ aViewOpt.SetOption(VOPT_NULLVALS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWNOTES )
+ aViewOpt.SetOption(VOPT_NOTES, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWFORMULASMARKS )
+ aViewOpt.SetOption(VOPT_FORMULAS_MARKS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWGRID )
+ aViewOpt.SetOption(VOPT_GRID, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_GRIDCOLOR )
+ {
+ Color aColor;
+ if (aValue >>= aColor)
+ aViewOpt.SetGridColor(aColor, OUString());
+ }
+ else if ( aPropertyName == SC_UNO_SHOWPAGEBR )
+ aViewOpt.SetOption(VOPT_PAGEBREAKS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNONAME_LINKUPD )
+ {
+ // XXX NOTE: this is the css::document::Settings property
+ // LinkUpdateMode, not the css::sheet::XGlobalSheetSettings
+ // attribute LinkUpdateMode.
+ sal_Int16 n;
+ if (!(aValue >>= n) || n < css::document::LinkUpdateModes::NEVER ||
+ n > css::document::LinkUpdateModes::GLOBAL_SETTING)
+ {
+ throw css::lang::IllegalArgumentException(
+ ("LinkUpdateMode property value must be a SHORT with a value in"
+ " the range of the css::document::LinkUpdateModes constants"),
+ css::uno::Reference<css::uno::XInterface>(), -1);
+ }
+ ScLkUpdMode eMode;
+ switch (n)
+ {
+ case css::document::LinkUpdateModes::NEVER:
+ eMode = LM_NEVER;
+ break;
+ case css::document::LinkUpdateModes::MANUAL:
+ eMode = LM_ON_DEMAND;
+ break;
+ case css::document::LinkUpdateModes::AUTO:
+ eMode = LM_ALWAYS;
+ break;
+ case css::document::LinkUpdateModes::GLOBAL_SETTING:
+ default:
+ eMode = SC_MOD()->GetAppOptions().GetLinkMode();
+ break;
+ }
+ rDoc.SetLinkMode( eMode );
+ }
+ else if ( aPropertyName == SC_UNO_COLROWHDR )
+ aViewOpt.SetOption(VOPT_HEADER, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHEETTABS )
+ aViewOpt.SetOption(VOPT_TABCONTROLS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_OUTLSYMB )
+ aViewOpt.SetOption(VOPT_OUTLINER, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_AUTOCALC )
+ rDoc.SetAutoCalc( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_PRINTERNAME )
+ {
+ OUString sPrinterName;
+ if ( !(aValue >>= sPrinterName) )
+ throw lang::IllegalArgumentException();
+
+ // #i75610# if the name is empty, do nothing (don't create any printer)
+ if ( !sPrinterName.isEmpty() && pDocShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
+ {
+ SfxPrinter* pPrinter = pDocShell->GetPrinter();
+ if (!pPrinter)
+ throw uno::RuntimeException();
+
+ if (pPrinter->GetName() != sPrinterName)
+ {
+ VclPtrInstance<SfxPrinter> pNewPrinter( pPrinter->GetOptions().Clone(), sPrinterName );
+ if (pNewPrinter->IsKnown())
+ pDocShell->SetPrinter( pNewPrinter, SfxPrinterChangeFlags::PRINTER );
+ else
+ pNewPrinter.disposeAndClear();
+ }
+
+ }
+
+ }
+ else if ( aPropertyName == SC_UNO_PRINTERSETUP )
+ {
+ uno::Sequence<sal_Int8> aSequence;
+ if ( aValue >>= aSequence )
+ {
+ sal_uInt32 nSize = aSequence.getLength();
+ // #i75610# if the sequence is empty, do nothing (don't create any printer)
+ if ( nSize != 0 )
+ {
+ SvMemoryStream aStream (aSequence.getArray(), nSize, StreamMode::READ );
+ aStream.Seek ( STREAM_SEEK_TO_BEGIN );
+ auto pSet = std::make_unique<SfxItemSetFixed
+ <SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN,
+ SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC,
+ SID_PRINT_SELECTEDSHEET, SID_PRINT_SELECTEDSHEET,
+ SID_SCPRINTOPTIONS, SID_SCPRINTOPTIONS>>( *rDoc.GetPool());
+
+ SfxPrinter* pPrinter = pDocShell->GetPrinter();
+ bool bPreferPrinterPapersize = false;
+ if ( pPrinter )
+ bPreferPrinterPapersize = pPrinter->GetPrinterSettingsPreferred();
+
+ VclPtr<SfxPrinter> pTempPrinter = SfxPrinter::Create( aStream, std::move(pSet) );
+ pTempPrinter->SetPrinterSettingsPreferred( bPreferPrinterPapersize );
+ pDocShell->SetPrinter( pTempPrinter );
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNO_PRINTERPAPER )
+ {
+ bool bPreferPrinterPapersize;
+ if( aValue >>= bPreferPrinterPapersize )
+ {
+ if( pDocShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
+ {
+ SfxPrinter *pTempPrinter = pDocShell->GetPrinter( true );
+ if (pTempPrinter)
+ pTempPrinter->SetPrinterSettingsPreferred( bPreferPrinterPapersize );
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNO_APPLYDOCINF )
+ {
+ bool bTmp=true;
+ if ( aValue >>= bTmp )
+ pDocShell->SetUseUserData( bTmp );
+ }
+ else if ( aPropertyName == SC_UNO_SAVE_THUMBNAIL)
+ {
+ bool bTmp = true;
+ if (aValue >>= bTmp)
+ pDocShell->SetUseThumbnailSave( bTmp );
+ }
+ else if ( aPropertyName == SC_UNO_FORBIDDEN )
+ {
+ // read-only - should not be set
+ }
+ else if ( aPropertyName == SC_UNO_CHARCOMP )
+ {
+ // Int16 contains CharacterCompressionType values
+ sal_Int16 nUno = ScUnoHelpFunctions::GetInt16FromAny( aValue );
+ rDoc.SetAsianCompression( static_cast<CharCompressType>(nUno) );
+ bUpdateHeights = true;
+ }
+ else if ( aPropertyName == SC_UNO_ASIANKERN )
+ {
+ rDoc.SetAsianKerning( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bUpdateHeights = true;
+ }
+ else if ( aPropertyName == SCSAVEVERSION )
+ {
+ bool bTmp=false;
+ if ( aValue >>= bTmp )
+ pDocShell->SetSaveVersionOnClose( bTmp );
+ }
+ else if ( aPropertyName == SC_UNO_UPDTEMPL )
+ {
+ bool bTmp=true;
+ if ( aValue >>= bTmp )
+ pDocShell->SetQueryLoadTemplate( bTmp );
+ }
+ else if ( aPropertyName == SC_UNO_LOADREADONLY )
+ {
+ bool bTmp=false;
+ if ( aValue >>= bTmp )
+ pDocShell->SetLoadReadonly( bTmp );
+ }
+ else if ( aPropertyName == SC_UNO_SHAREDOC )
+ {
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+ bool bDocShared = false;
+ if ( aValue >>= bDocShared )
+ {
+ pDocShell->SetSharedXMLFlag( bDocShared );
+ }
+#endif
+ }
+ else if ( aPropertyName == SC_UNO_MODIFYPASSWORDINFO )
+ {
+ uno::Sequence< beans::PropertyValue > aInfo;
+ if ( !( aValue >>= aInfo ) )
+ throw lang::IllegalArgumentException(
+ "Value of type Sequence<PropertyValue> expected!",
+ uno::Reference< uno::XInterface >(),
+ 2 );
+
+ if ( !pDocShell->SetModifyPasswordInfo( aInfo ) )
+ throw beans::PropertyVetoException(
+ "The hash is not allowed to be changed now!" );
+ }
+ else if (aPropertyName == SC_UNO_MODIFYPASSWORDHASH)
+ {
+ sal_Int32 nHash;
+ if (!(aValue >>= nHash))
+ throw lang::IllegalArgumentException("Value of type sal_Int32 expected!",
+ uno::Reference<uno::XInterface>(), 2);
+
+ if (!pDocShell->SetModifyPasswordHash(nHash))
+ throw beans::PropertyVetoException("The hash is not allowed to be changed now!");
+ }
+ else if (aPropertyName == SC_UNO_EMBED_FONTS)
+ {
+ bool bVal = aValue.has<bool>() && aValue.get<bool>();
+ rDoc.SetEmbedFonts(bVal);
+ }
+ else if (aPropertyName == SC_UNO_EMBED_ONLY_USED_FONTS)
+ {
+ bool bVal = aValue.has<bool>() && aValue.get<bool>();
+ rDoc.SetEmbedUsedFontsOnly(bVal);
+ }
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_LATIN)
+ {
+ bool bVal = aValue.has<bool>() && aValue.get<bool>();
+ rDoc.SetEmbedFontScriptLatin(bVal);
+ }
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_ASIAN)
+ {
+ bool bVal = aValue.has<bool>() && aValue.get<bool>();
+ rDoc.SetEmbedFontScriptAsian(bVal);
+ }
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_COMPLEX)
+ {
+ bool bVal = aValue.has<bool>() && aValue.get<bool>();
+ rDoc.SetEmbedFontScriptComplex(bVal);
+ }
+ else if ( aPropertyName == SC_UNO_SYNTAXSTRINGREF )
+ {
+ ScCalcConfig aCalcConfig = rDoc.GetCalcConfig();
+ sal_Int16 nUno = 0;
+
+ if( aValue >>= nUno )
+ {
+ switch (nUno)
+ {
+ case 0: // CONV_OOO
+ case 2: // CONV_XL_A1
+ case 3: // CONV_XL_R1C1
+ case 7: // CONV_A1_XL_A1
+ aCalcConfig.SetStringRefSyntax( static_cast<formula::FormulaGrammar::AddressConvention>( nUno ) );
+ break;
+ default:
+ aCalcConfig.SetStringRefSyntax( formula::FormulaGrammar::CONV_UNSPECIFIED );
+ break;
+
+ }
+ rDoc.SetCalcConfig( aCalcConfig );
+ }
+ }
+ else if (aPropertyName == SC_UNO_IMAGE_PREFERRED_DPI)
+ {
+ if (aValue.has<sal_Int32>())
+ {
+ rDoc.SetImagePreferredDPI(aValue.get<sal_Int32>());
+ }
+ }
+ else
+ {
+ ScGridOptions aGridOpt(aViewOpt.GetGridOptions());
+ if ( aPropertyName == SC_UNO_SNAPTORASTER )
+ aGridOpt.SetUseGridSnap( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_RASTERVIS )
+ aGridOpt.SetGridVisible( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_RASTERRESX )
+ aGridOpt.SetFieldDrawX( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( aValue ) ) );
+ else if ( aPropertyName == SC_UNO_RASTERRESY )
+ aGridOpt.SetFieldDrawY( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( aValue ) ) );
+ else if ( aPropertyName == SC_UNO_RASTERSUBX )
+ aGridOpt.SetFieldDivisionX( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( aValue ) ) );
+ else if ( aPropertyName == SC_UNO_RASTERSUBY )
+ aGridOpt.SetFieldDivisionY( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( aValue ) ) );
+ else if ( aPropertyName == SC_UNO_RASTERSYNC )
+ aGridOpt.SetSynchronize( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+ aViewOpt.SetGridOptions(aGridOpt);
+ }
+ rDoc.SetViewOptions(aViewOpt);
+
+ if ( bUpdateHeights && !rDoc.IsImportingXML() )
+ {
+ // update automatic row heights and repaint
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ if ( !pDocShell->AdjustRowHeight( 0, rDoc.MaxRow(), nTab ) )
+ pDocShell->PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab), PaintPartFlags::Grid);
+ pDocShell->SetDocumentModified();
+ }
+
+}
+
+uno::Any SAL_CALL ScDocumentConfiguration::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if(!pDocShell)
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScViewOptions& aViewOpt = rDoc.GetViewOptions();
+
+ /*Stampit enable/disable print cancel */
+ if ( aPropertyName == SC_UNO_ALLOWPRINTJOBCANCEL )
+ aRet <<= pDocShell->Stamp_GetPrintCancelState();
+ /*Stampit enable/disable print cancel */
+
+ else if ( aPropertyName == SC_UNO_SHOWZERO )
+ aRet <<= aViewOpt.GetOption( VOPT_NULLVALS );
+ else if ( aPropertyName == SC_UNO_SHOWNOTES )
+ aRet <<= aViewOpt.GetOption( VOPT_NOTES );
+ else if ( aPropertyName == SC_UNO_SHOWFORMULASMARKS )
+ aRet <<= aViewOpt.GetOption( VOPT_FORMULAS_MARKS );
+ else if ( aPropertyName == SC_UNO_SHOWGRID )
+ aRet <<= aViewOpt.GetOption( VOPT_GRID );
+ else if ( aPropertyName == SC_UNO_GRIDCOLOR )
+ {
+ OUString aColorName;
+ Color aColor = aViewOpt.GetGridColor(&aColorName);
+ aRet <<= aColor;
+ }
+ else if ( aPropertyName == SC_UNO_SHOWPAGEBR )
+ aRet <<= aViewOpt.GetOption( VOPT_PAGEBREAKS );
+ else if ( aPropertyName == SC_UNONAME_LINKUPD )
+ {
+ sal_Int16 nLUM;
+ switch (rDoc.GetLinkMode())
+ {
+ case LM_ALWAYS:
+ nLUM = css::document::LinkUpdateModes::AUTO;
+ break;
+ case LM_NEVER:
+ nLUM = css::document::LinkUpdateModes::NEVER;
+ break;
+ case LM_ON_DEMAND:
+ nLUM = css::document::LinkUpdateModes::MANUAL;
+ break;
+ case LM_UNKNOWN:
+ default:
+ nLUM = css::document::LinkUpdateModes::GLOBAL_SETTING;
+ break;
+ }
+ aRet <<= nLUM;
+ }
+ else if ( aPropertyName == SC_UNO_COLROWHDR )
+ aRet <<= aViewOpt.GetOption( VOPT_HEADER );
+ else if ( aPropertyName == SC_UNO_SHEETTABS )
+ aRet <<= aViewOpt.GetOption( VOPT_TABCONTROLS );
+ else if ( aPropertyName == SC_UNO_OUTLSYMB )
+ aRet <<= aViewOpt.GetOption( VOPT_OUTLINER );
+ else if ( aPropertyName == SC_UNO_AUTOCALC )
+ aRet <<= rDoc.GetAutoCalc();
+ else if ( aPropertyName == SC_UNO_PRINTERNAME )
+ {
+ // #i75610# don't create the printer, return empty string if no printer created yet
+ // (as in SwXDocumentSettings)
+ SfxPrinter* pPrinter = rDoc.GetPrinter( false );
+ if (pPrinter)
+ aRet <<= pPrinter->GetName();
+ else
+ aRet <<= OUString();
+ }
+ else if ( aPropertyName == SC_UNO_PRINTERSETUP )
+ {
+ // #i75610# don't create the printer, return empty sequence if no printer created yet
+ // (as in SwXDocumentSettings)
+ SfxPrinter* pPrinter = rDoc.GetPrinter( false );
+ if (pPrinter)
+ {
+ SvMemoryStream aStream;
+ pPrinter->Store( aStream );
+ aRet <<= uno::Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aStream.GetData() ),
+ aStream.TellEnd() );
+ }
+ else
+ aRet <<= uno::Sequence<sal_Int8>();
+ }
+ else if ( aPropertyName == SC_UNO_PRINTERPAPER)
+ {
+ SfxPrinter *pTempPrinter = pDocShell->GetPrinter( false );
+ aRet <<= pTempPrinter && pTempPrinter->GetPrinterSettingsPreferred();
+
+ }
+ else if ( aPropertyName == SC_UNO_APPLYDOCINF )
+ aRet <<= pDocShell->IsUseUserData();
+ else if ( aPropertyName == SC_UNO_SAVE_THUMBNAIL )
+ aRet <<= pDocShell->IsUseThumbnailSave();
+ else if ( aPropertyName == SC_UNO_FORBIDDEN )
+ {
+ aRet <<= uno::Reference<i18n::XForbiddenCharacters>(new ScForbiddenCharsObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_CHARCOMP )
+ aRet <<= static_cast<sal_Int16> ( rDoc.GetAsianCompression() );
+ else if ( aPropertyName == SC_UNO_ASIANKERN )
+ aRet <<= rDoc.GetAsianKerning();
+ else if ( aPropertyName == SCSAVEVERSION )
+ aRet <<= pDocShell->IsSaveVersionOnClose();
+ else if ( aPropertyName == SC_UNO_UPDTEMPL )
+ aRet <<= pDocShell->IsQueryLoadTemplate();
+ else if ( aPropertyName == SC_UNO_LOADREADONLY )
+ aRet <<= pDocShell->IsLoadReadonly();
+ else if ( aPropertyName == SC_UNO_SHAREDOC )
+ {
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+ aRet <<= pDocShell->HasSharedXMLFlagSet();
+#endif
+ }
+ else if ( aPropertyName == SC_UNO_MODIFYPASSWORDINFO )
+ aRet <<= pDocShell->GetModifyPasswordInfo();
+ else if (aPropertyName == SC_UNO_MODIFYPASSWORDHASH)
+ aRet <<= pDocShell->GetModifyPasswordHash();
+ else if (aPropertyName == SC_UNO_EMBED_FONTS)
+ aRet <<= rDoc.IsEmbedFonts();
+ else if (aPropertyName == SC_UNO_EMBED_ONLY_USED_FONTS)
+ aRet <<= rDoc.IsEmbedUsedFontsOnly();
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_LATIN)
+ aRet <<= rDoc.IsEmbedFontScriptLatin();
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_ASIAN)
+ aRet <<= rDoc.IsEmbedFontScriptAsian();
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_COMPLEX)
+ aRet <<= rDoc.IsEmbedFontScriptComplex();
+ else if ( aPropertyName == SC_UNO_SYNTAXSTRINGREF )
+ {
+ ScCalcConfig aCalcConfig = rDoc.GetCalcConfig();
+ formula::FormulaGrammar::AddressConvention eConv = aCalcConfig.meStringRefAddressSyntax;
+
+ // don't save "unspecified" string ref syntax ... query formula grammar
+ // and save that instead
+ if( eConv == formula::FormulaGrammar::CONV_UNSPECIFIED)
+ {
+ eConv = rDoc.GetAddressConvention();
+ }
+
+ // write if it has been read|imported or explicitly changed
+ // or if ref syntax isn't what would be native for our file format
+ // i.e. CalcA1 in this case
+ if ( aCalcConfig.mbHasStringRefSyntax ||
+ (eConv != formula::FormulaGrammar::CONV_OOO) )
+ {
+ switch (eConv)
+ {
+ case formula::FormulaGrammar::CONV_OOO:
+ case formula::FormulaGrammar::CONV_XL_A1:
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ case formula::FormulaGrammar::CONV_A1_XL_A1:
+ aRet <<= static_cast<sal_Int16>( eConv );
+ break;
+
+ case formula::FormulaGrammar::CONV_UNSPECIFIED:
+ case formula::FormulaGrammar::CONV_ODF:
+ case formula::FormulaGrammar::CONV_XL_OOX:
+ case formula::FormulaGrammar::CONV_LOTUS_A1:
+ case formula::FormulaGrammar::CONV_LAST:
+ {
+ aRet <<= sal_Int16(9999);
+ break;
+ }
+ }
+ }
+ }
+ else if (aPropertyName == SC_UNO_IMAGE_PREFERRED_DPI)
+ {
+ aRet <<= rDoc.GetImagePreferredDPI();
+ }
+ else
+ {
+ const ScGridOptions& aGridOpt = aViewOpt.GetGridOptions();
+ if ( aPropertyName == SC_UNO_SNAPTORASTER )
+ aRet <<= aGridOpt.GetUseGridSnap();
+ else if ( aPropertyName == SC_UNO_RASTERVIS )
+ aRet <<= aGridOpt.GetGridVisible();
+ else if ( aPropertyName == SC_UNO_RASTERRESX )
+ aRet <<= static_cast<sal_Int32> ( aGridOpt.GetFieldDrawX() );
+ else if ( aPropertyName == SC_UNO_RASTERRESY )
+ aRet <<= static_cast<sal_Int32> ( aGridOpt.GetFieldDrawY() );
+ else if ( aPropertyName == SC_UNO_RASTERSUBX )
+ aRet <<= static_cast<sal_Int32> ( aGridOpt.GetFieldDivisionX() );
+ else if ( aPropertyName == SC_UNO_RASTERSUBY )
+ aRet <<= static_cast<sal_Int32> ( aGridOpt.GetFieldDivisionY() );
+ else if ( aPropertyName == SC_UNO_RASTERSYNC )
+ aRet <<= aGridOpt.GetSynchronize();
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+ }
+
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDocumentConfiguration )
+
+// XServiceInfo
+OUString SAL_CALL ScDocumentConfiguration::getImplementationName()
+{
+ return "ScDocumentConfiguration";
+}
+
+sal_Bool SAL_CALL ScDocumentConfiguration::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScDocumentConfiguration::getSupportedServiceNames()
+{
+ return {"com.sun.star.comp.SpreadsheetSettings",
+ "com.sun.star.document.Settings"};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/convuno.cxx b/sc/source/ui/unoobj/convuno.cxx
new file mode 100644
index 0000000000..d6ce8d9e1f
--- /dev/null
+++ b/sc/source/ui/unoobj/convuno.cxx
@@ -0,0 +1,46 @@
+/* -*- 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 <i18nlangtag/languagetag.hxx>
+
+#include <convuno.hxx>
+
+using namespace com::sun::star;
+
+// everything is static...
+
+LanguageType ScUnoConversion::GetLanguage(const lang::Locale& rLocale)
+{
+ // empty language -> LANGUAGE_SYSTEM
+ if (rLocale.Language.isEmpty())
+ return LANGUAGE_SYSTEM;
+
+ LanguageType eRet = LanguageTag::convertToLanguageType(rLocale, false);
+ if (eRet == LANGUAGE_NONE)
+ eRet = LANGUAGE_SYSTEM; //! or throw an exception?
+
+ return eRet;
+}
+
+void ScUnoConversion::FillLocale(lang::Locale& rLocale, LanguageType eLang)
+{
+ rLocale = LanguageTag::convertToLocale(eLang);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/cursuno.cxx b/sc/source/ui/unoobj/cursuno.cxx
new file mode 100644
index 0000000000..f2b9142f37
--- /dev/null
+++ b/sc/source/ui/unoobj/cursuno.cxx
@@ -0,0 +1,453 @@
+/* -*- 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 <vcl/svapp.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cursuno.hxx>
+#include <cellsuno.hxx>
+#include <docsh.hxx>
+#include <markdata.hxx>
+#include <miscuno.hxx>
+
+using namespace com::sun::star;
+
+constexpr OUString SCSHEETCELLCURSOR_SERVICE = u"com.sun.star.sheet.SheetCellCursor"_ustr;
+constexpr OUString SCCELLCURSOR_SERVICE = u"com.sun.star.table.CellCursor"_ustr;
+
+ScCellCursorObj::ScCellCursorObj(ScDocShell* pDocSh, const ScRange& rR) :
+ ScCellRangeObj( pDocSh, rR )
+{
+}
+
+ScCellCursorObj::~ScCellCursorObj()
+{
+}
+
+uno::Any SAL_CALL ScCellCursorObj::queryInterface( const uno::Type& rType )
+{
+ uno::Any aReturn = ::cppu::queryInterface(rType,
+ static_cast<sheet::XSheetCellCursor*>(this),
+ static_cast<sheet::XUsedAreaCursor*>(this),
+ static_cast<table::XCellCursor*>(this));
+ if ( aReturn.hasValue() )
+ return aReturn;
+
+ return ScCellRangeObj::queryInterface( rType );
+}
+
+void SAL_CALL ScCellCursorObj::acquire() noexcept
+{
+ ScCellRangeObj::acquire();
+}
+
+void SAL_CALL ScCellCursorObj::release() noexcept
+{
+ ScCellRangeObj::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScCellCursorObj::getTypes()
+{
+ return comphelper::concatSequences(
+ ScCellRangeObj::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XSheetCellCursor>::get(),
+ cppu::UnoType<sheet::XUsedAreaCursor>::get(),
+ cppu::UnoType<table::XCellCursor>::get()
+ } );
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScCellCursorObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XSheetCellCursor
+
+void SAL_CALL ScCellCursorObj::collapseToCurrentRegion()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+
+ aOneRange.PutInOrder();
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ SCCOL nStartCol = aOneRange.aStart.Col();
+ SCROW nStartRow = aOneRange.aStart.Row();
+ SCCOL nEndCol = aOneRange.aEnd.Col();
+ SCROW nEndRow = aOneRange.aEnd.Row();
+ SCTAB nTab = aOneRange.aStart.Tab();
+
+ pDocSh->GetDocument().GetDataArea(
+ nTab, nStartCol, nStartRow, nEndCol, nEndRow, true, false );
+
+ ScRange aNew( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
+ SetNewRange( aNew );
+}
+
+void SAL_CALL ScCellCursorObj::collapseToCurrentArray()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+
+ aOneRange.PutInOrder();
+ ScAddress aCursor(aOneRange.aStart); // use the start address of the range
+
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScRange aMatrix;
+
+ // finding the matrix range is now in GetMatrixFormulaRange in the document
+ if ( rDoc.GetMatrixFormulaRange( aCursor, aMatrix ) )
+ {
+ SetNewRange( aMatrix );
+ }
+ }
+ // that's a Bug, that this assertion comes; the API Reference says, that
+ // if there is no Matrix, the Range is left unchanged; they say nothing
+ // about an exception
+ /*if (!bFound)
+ {
+ OSL_FAIL("no matrix");
+ //! Exception, or what?
+ }*/
+}
+
+void SAL_CALL ScCellCursorObj::collapseToMergedArea()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[ 0 ] );
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ rDoc.ExtendOverlapped( aNewRange );
+ rDoc.ExtendMerge( aNewRange ); // after ExtendOverlapped!
+
+ SetNewRange( aNewRange );
+ }
+}
+
+void SAL_CALL ScCellCursorObj::expandToEntireColumns()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[ 0 ] );
+
+ aNewRange.aStart.SetRow( 0 );
+ aNewRange.aEnd.SetRow( GetDocShell()->GetDocument().MaxRow() );
+
+ SetNewRange( aNewRange );
+}
+
+void SAL_CALL ScCellCursorObj::expandToEntireRows()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[ 0 ] );
+
+ aNewRange.aStart.SetCol( 0 );
+ aNewRange.aEnd.SetCol( GetDocShell()->GetDocument().MaxCol() );
+
+ SetNewRange( aNewRange );
+}
+
+void SAL_CALL ScCellCursorObj::collapseToSize( sal_Int32 nColumns, sal_Int32 nRows )
+{
+ SolarMutexGuard aGuard;
+ if ( nColumns <= 0 || nRows <= 0 )
+ {
+ OSL_FAIL("Empty range not allowed");
+ //! and then?
+ }
+ else
+ {
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[ 0 ] );
+
+ aNewRange.PutInOrder(); //! really?
+
+ const auto & rDoc = GetDocShell()->GetDocument();
+ tools::Long nEndX = aNewRange.aStart.Col() + nColumns - 1;
+ tools::Long nEndY = aNewRange.aStart.Row() + nRows - 1;
+ if ( nEndX < 0 ) nEndX = 0;
+ if ( nEndX > rDoc.MaxCol() ) nEndX = rDoc.MaxCol();
+ if ( nEndY < 0 ) nEndY = 0;
+ if ( nEndY > rDoc.MaxRow() ) nEndY = rDoc.MaxRow();
+ //! error/exception or so, if too big/small
+
+ aNewRange.aEnd.SetCol(static_cast<SCCOL>(nEndX));
+ aNewRange.aEnd.SetRow(static_cast<SCROW>(nEndY));
+
+ aNewRange.PutInOrder(); //! really?
+
+ SetNewRange( aNewRange );
+ }
+}
+
+// XUsedAreaCursor
+
+void SAL_CALL ScCellCursorObj::gotoStartOfUsedArea(sal_Bool bExpand)
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[0] );
+ SCTAB nTab = aNewRange.aStart.Tab();
+
+ SCCOL nUsedX = 0; // fetch the beginning
+ SCROW nUsedY = 0;
+ if (!pDocSh->GetDocument().GetDataStart( nTab, nUsedX, nUsedY ))
+ {
+ nUsedX = 0;
+ nUsedY = 0;
+ }
+
+ aNewRange.aStart.SetCol( nUsedX );
+ aNewRange.aStart.SetRow( nUsedY );
+ if (!bExpand)
+ aNewRange.aEnd = aNewRange.aStart;
+ SetNewRange( aNewRange );
+}
+
+void SAL_CALL ScCellCursorObj::gotoEndOfUsedArea( sal_Bool bExpand )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[ 0 ]);
+ SCTAB nTab = aNewRange.aStart.Tab();
+
+ SCCOL nUsedX = 0; // fetch the end
+ SCROW nUsedY = 0;
+ if (!pDocSh->GetDocument().GetTableArea( nTab, nUsedX, nUsedY, true ))
+ {
+ nUsedX = 0;
+ nUsedY = 0;
+ }
+
+ aNewRange.aEnd.SetCol( nUsedX );
+ aNewRange.aEnd.SetRow( nUsedY );
+ if (!bExpand)
+ aNewRange.aStart = aNewRange.aEnd;
+ SetNewRange( aNewRange );
+}
+
+// XCellCursor
+
+void SAL_CALL ScCellCursorObj::gotoStart()
+{
+ // this is similar to collapseToCurrentRegion
+ //! something like gotoEdge with 4 possible directions is needed
+
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ]);
+
+ aOneRange.PutInOrder();
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ SCCOL nStartCol = aOneRange.aStart.Col();
+ SCROW nStartRow = aOneRange.aStart.Row();
+ SCCOL nEndCol = aOneRange.aEnd.Col();
+ SCROW nEndRow = aOneRange.aEnd.Row();
+ SCTAB nTab = aOneRange.aStart.Tab();
+
+ pDocSh->GetDocument().GetDataArea(
+ nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, false );
+
+ ScRange aNew( nStartCol, nStartRow, nTab );
+ SetNewRange( aNew );
+}
+
+void SAL_CALL ScCellCursorObj::gotoEnd()
+{
+ // this is similar to collapseToCurrentRegion
+ //! something like gotoEdge with 4 possible directions is needed
+
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+
+ aOneRange.PutInOrder();
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ SCCOL nStartCol = aOneRange.aStart.Col();
+ SCROW nStartRow = aOneRange.aStart.Row();
+ SCCOL nEndCol = aOneRange.aEnd.Col();
+ SCROW nEndRow = aOneRange.aEnd.Row();
+ SCTAB nTab = aOneRange.aStart.Tab();
+
+ pDocSh->GetDocument().GetDataArea(
+ nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, false );
+
+ ScRange aNew( nEndCol, nEndRow, nTab );
+ SetNewRange( aNew );
+}
+
+void SAL_CALL ScCellCursorObj::gotoNext()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+
+ aOneRange.PutInOrder();
+ ScAddress aCursor(aOneRange.aStart); // always use start of block
+
+ ScMarkData aMark(GetDocument()->GetSheetLimits()); // not used with bMarked=FALSE
+ SCCOL nNewX = aCursor.Col();
+ SCROW nNewY = aCursor.Row();
+ SCTAB nTab = aCursor.Tab();
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ pDocSh->GetDocument().GetNextPos( nNewX,nNewY, nTab, 1,0, false,true, aMark );
+ //! otherwise exception or so
+
+ SetNewRange( ScRange( nNewX, nNewY, nTab ) );
+}
+
+void SAL_CALL ScCellCursorObj::gotoPrevious()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+
+ aOneRange.PutInOrder();
+ ScAddress aCursor(aOneRange.aStart); // always use start of block
+
+ ScMarkData aMark(GetDocument()->GetSheetLimits()); // not used with bMarked=FALSE
+ SCCOL nNewX = aCursor.Col();
+ SCROW nNewY = aCursor.Row();
+ SCTAB nTab = aCursor.Tab();
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ pDocSh->GetDocument().GetNextPos( nNewX,nNewY, nTab, -1,0, false,true, aMark );
+ //! otherwise exception or so
+
+ SetNewRange( ScRange( nNewX, nNewY, nTab ) );
+}
+
+void SAL_CALL ScCellCursorObj::gotoOffset( sal_Int32 nColumnOffset, sal_Int32 nRowOffset )
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+ aOneRange.PutInOrder();
+
+ const auto & rDoc = GetDocShell()->GetDocument();
+ if ( aOneRange.aStart.Col() + nColumnOffset >= 0 &&
+ aOneRange.aEnd.Col() + nColumnOffset <= rDoc.MaxCol() &&
+ aOneRange.aStart.Row() + nRowOffset >= 0 &&
+ aOneRange.aEnd.Row() + nRowOffset <= rDoc.MaxRow() )
+ {
+ ScRange aNew( static_cast<SCCOL>(aOneRange.aStart.Col() + nColumnOffset),
+ static_cast<SCROW>(aOneRange.aStart.Row() + nRowOffset),
+ aOneRange.aStart.Tab(),
+ static_cast<SCCOL>(aOneRange.aEnd.Col() + nColumnOffset),
+ static_cast<SCROW>(aOneRange.aEnd.Row() + nRowOffset),
+ aOneRange.aEnd.Tab() );
+ SetNewRange( aNew );
+ }
+}
+
+// XSheetCellRange
+
+uno::Reference<sheet::XSpreadsheet> SAL_CALL ScCellCursorObj::getSpreadsheet()
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getSpreadsheet();
+}
+
+// XCellRange
+
+uno::Reference<table::XCell> SAL_CALL ScCellCursorObj::getCellByPosition(
+ sal_Int32 nColumn, sal_Int32 nRow )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getCellByPosition(nColumn,nRow);
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByPosition(
+ sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getCellRangeByPosition(nLeft,nTop,nRight,nBottom);
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByName(
+ const OUString& rRange )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getCellRangeByName(rRange);
+}
+
+// XServiceInfo
+
+OUString SAL_CALL ScCellCursorObj::getImplementationName()
+{
+ return "ScCellCursorObj";
+}
+
+sal_Bool SAL_CALL ScCellCursorObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellCursorObj::getSupportedServiceNames()
+{
+ // SheetCellCursor should be first (?)
+ return comphelper::concatSequences<OUString>(
+ { SCSHEETCELLCURSOR_SERVICE, SCCELLCURSOR_SERVICE },
+ ScCellRangeObj::getSupportedServiceNames());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/dapiuno.cxx b/sc/source/ui/unoobj/dapiuno.cxx
new file mode 100644
index 0000000000..f172716c11
--- /dev/null
+++ b/sc/source/ui/unoobj/dapiuno.cxx
@@ -0,0 +1,3344 @@
+/* -*- 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 <algorithm>
+#include <cmath>
+
+#include <o3tl/safeint.hxx>
+#include <svl/hint.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <sal/log.hxx>
+
+#include <dapiuno.hxx>
+#include <datauno.hxx>
+#include <miscuno.hxx>
+#include <convuno.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <rangeutl.hxx>
+#include <dpobject.hxx>
+#include <dpshttab.hxx>
+#include <dpsdbtab.hxx>
+#include <dpsave.hxx>
+#include <dbdocfun.hxx>
+#include <unonames.hxx>
+#include <dpdimsave.hxx>
+#include <hints.hxx>
+#include <dputil.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <generalfunction.hxx>
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sheet/XDimensionsSupplier.hpp>
+#include <com/sun/star/sheet/XLevelsSupplier.hpp>
+#include <com/sun/star/sheet/XMembersAccess.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sheet/DataImportMode.hpp>
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+#include <com/sun/star/sheet/DataPilotOutputRangeType.hpp>
+#include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
+#include <com/sun/star/sheet/GeneralFunction2.hpp>
+
+#include <comphelper/extract.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+using namespace com::sun::star;
+using namespace com::sun::star::sheet;
+
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+
+using ::com::sun::star::container::ElementExistException;
+using ::com::sun::star::container::NoSuchElementException;
+using ::com::sun::star::container::XEnumeration;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNamed;
+
+using ::com::sun::star::beans::UnknownPropertyException;
+using ::com::sun::star::beans::XPropertyChangeListener;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::beans::XPropertySetInfo;
+using ::com::sun::star::beans::XVetoableChangeListener;
+
+using ::com::sun::star::lang::IllegalArgumentException;
+using ::com::sun::star::lang::IndexOutOfBoundsException;
+using ::com::sun::star::lang::NullPointerException;
+
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+
+namespace {
+
+std::span<const SfxItemPropertyMapEntry> lcl_GetDataPilotDescriptorBaseMap()
+{
+ static const SfxItemPropertyMapEntry aDataPilotDescriptorBaseMap_Impl[] =
+ {
+ { SC_UNO_DP_COLGRAND, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_DRILLDOWN, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_GRANDTOTAL_NAME,0,cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0 },
+ { SC_UNO_DP_IGNORE_EMPTYROWS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_IMPORTDESC, 0, cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get(), 0, 0 },
+ { SC_UNO_DP_REPEATEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_ROWGRAND, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_SERVICEARG, 0, cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get(), 0, 0 },
+ { SC_UNO_DP_SHOWFILTER, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_SOURCESERVICE, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ };
+ return aDataPilotDescriptorBaseMap_Impl;
+}
+
+std::span<const SfxItemPropertyMapEntry> lcl_GetDataPilotFieldMap()
+{
+ using namespace ::com::sun::star::beans::PropertyAttribute;
+ static const SfxItemPropertyMapEntry aDataPilotFieldMap_Impl[] =
+ {
+ { SC_UNONAME_AUTOSHOW, 0, cppu::UnoType<DataPilotFieldAutoShowInfo>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_FUNCTION, 0, cppu::UnoType<GeneralFunction>::get(), 0, 0 },
+ { SC_UNONAME_FUNCTION2, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_GROUPINFO, 0, cppu::UnoType<DataPilotFieldGroupInfo>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_HASAUTOSHOW, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_HASLAYOUTINFO,0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_HASREFERENCE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_HASSORTINFO, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_ISGROUP, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_LAYOUTINFO, 0, cppu::UnoType<DataPilotFieldLayoutInfo>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_ORIENT, 0, cppu::UnoType<DataPilotFieldOrientation>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_REFERENCE, 0, cppu::UnoType<DataPilotFieldReference>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_SELPAGE, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_SHOWEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_REPEATITEMLABELS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SORTINFO, 0, cppu::UnoType<DataPilotFieldSortInfo>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_SUBTOTALS, 0, cppu::UnoType<Sequence<GeneralFunction>>::get(), 0, 0 },
+ { SC_UNONAME_SUBTOTALS2, 0, cppu::UnoType<Sequence<sal_Int16>>::get(), 0, 0 },
+ { SC_UNONAME_USESELPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ };
+ return aDataPilotFieldMap_Impl;
+}
+
+std::span<const SfxItemPropertyMapEntry> lcl_GetDataPilotItemMap()
+{
+ static const SfxItemPropertyMapEntry aDataPilotItemMap_Impl[] =
+ {
+ { SC_UNONAME_ISHIDDEN, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_POS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHOWDETAIL, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ };
+ return aDataPilotItemMap_Impl;
+}
+
+bool lclCheckValidDouble( double fValue, bool bAuto )
+{
+ return bAuto || std::isfinite( fValue );
+}
+
+bool lclCheckMinMaxStep( const DataPilotFieldGroupInfo& rInfo )
+{
+ return
+ lclCheckValidDouble( rInfo.Start, rInfo.HasAutoStart ) &&
+ lclCheckValidDouble( rInfo.End, rInfo.HasAutoEnd ) &&
+ (rInfo.HasAutoStart || rInfo.HasAutoEnd || (rInfo.Start <= rInfo.End)) &&
+ lclCheckValidDouble( rInfo.Step, false ) &&
+ (0.0 <= rInfo.Step);
+}
+
+} // namespace
+
+SC_SIMPLE_SERVICE_INFO( ScDataPilotDescriptor, "ScDataPilotDescriptor", "stardiv::one::sheet::DataPilotDescriptor" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldObj, "ScDataPilotFieldObj", "com.sun.star.sheet.DataPilotField" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldsObj, "ScDataPilotFieldsObj", "com.sun.star.sheet.DataPilotFields" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotTableObj, "ScDataPilotTableObj", "com.sun.star.sheet.DataPilotTable" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotTablesObj, "ScDataPilotTablesObj", "com.sun.star.sheet.DataPilotTables" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotItemsObj, "ScDataPilotItemsObj", "com.sun.star.sheet.DataPilotItems" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotItemObj, "ScDataPilotItemObj", "com.sun.star.sheet.DataPilotItem" )
+
+SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupsObj, "ScDataPilotFieldGroupsObj", "com.sun.star.sheet.DataPilotFieldGroups" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupObj, "ScDataPilotFieldGroupObj", "com.sun.star.sheet.DataPilotFieldGroup" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupItemObj, "ScDataPilotFieldGroupItemObj", "com.sun.star.sheet.DataPilotFieldGroupItem" )
+
+// name that is used in the API for the data layout field
+constexpr OUString SC_DATALAYOUT_NAME = u"Data"_ustr;
+
+ScGeneralFunction ScDataPilotConversion::FirstFunc( PivotFunc nBits )
+{
+ if ( nBits & PivotFunc::Sum ) return ScGeneralFunction::SUM;
+ if ( nBits & PivotFunc::Count ) return ScGeneralFunction::COUNT;
+ if ( nBits & PivotFunc::Average ) return ScGeneralFunction::AVERAGE;
+ if ( nBits & PivotFunc::Median ) return ScGeneralFunction::MEDIAN;
+ if ( nBits & PivotFunc::Max ) return ScGeneralFunction::MAX;
+ if ( nBits & PivotFunc::Min ) return ScGeneralFunction::MIN;
+ if ( nBits & PivotFunc::Product ) return ScGeneralFunction::PRODUCT;
+ if ( nBits & PivotFunc::CountNum ) return ScGeneralFunction::COUNTNUMS;
+ if ( nBits & PivotFunc::StdDev ) return ScGeneralFunction::STDEV;
+ if ( nBits & PivotFunc::StdDevP ) return ScGeneralFunction::STDEVP;
+ if ( nBits & PivotFunc::StdVar ) return ScGeneralFunction::VAR;
+ if ( nBits & PivotFunc::StdVarP ) return ScGeneralFunction::VARP;
+ if ( nBits & PivotFunc::Auto ) return ScGeneralFunction::AUTO;
+ return ScGeneralFunction::NONE;
+}
+
+PivotFunc ScDataPilotConversion::FunctionBit( sal_Int16 eFunc )
+{
+ PivotFunc nRet = PivotFunc::NONE; // 0
+ switch (eFunc)
+ {
+ case GeneralFunction2::SUM: nRet = PivotFunc::Sum; break;
+ case GeneralFunction2::COUNT: nRet = PivotFunc::Count; break;
+ case GeneralFunction2::AVERAGE: nRet = PivotFunc::Average; break;
+ case GeneralFunction2::MEDIAN: nRet = PivotFunc::Median; break;
+ case GeneralFunction2::MAX: nRet = PivotFunc::Max; break;
+ case GeneralFunction2::MIN: nRet = PivotFunc::Min; break;
+ case GeneralFunction2::PRODUCT: nRet = PivotFunc::Product; break;
+ case GeneralFunction2::COUNTNUMS: nRet = PivotFunc::CountNum; break;
+ case GeneralFunction2::STDEV: nRet = PivotFunc::StdDev; break;
+ case GeneralFunction2::STDEVP: nRet = PivotFunc::StdDevP; break;
+ case GeneralFunction2::VAR: nRet = PivotFunc::StdVar; break;
+ case GeneralFunction2::VARP: nRet = PivotFunc::StdVarP; break;
+ case GeneralFunction2::AUTO: nRet = PivotFunc::Auto; break;
+ default:
+ {
+ assert(false);
+ }
+ }
+ return nRet;
+}
+
+void ScDataPilotConversion::FillGroupInfo( DataPilotFieldGroupInfo& rInfo, const ScDPNumGroupInfo& rGroupInfo )
+{
+ rInfo.HasDateValues = rGroupInfo.mbDateValues;
+ rInfo.HasAutoStart = rGroupInfo.mbAutoStart;
+ rInfo.Start = rGroupInfo.mfStart;
+ rInfo.HasAutoEnd = rGroupInfo.mbAutoEnd;
+ rInfo.End = rGroupInfo.mfEnd;
+ rInfo.Step = rGroupInfo.mfStep;
+}
+
+static ScDPObject* lcl_GetDPObject( ScDocShell* pDocShell, SCTAB nTab, std::u16string_view rName )
+{
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ {
+ size_t nCount = pColl->GetCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab &&
+ rDPObj.GetName() == rName )
+ return &rDPObj;
+ }
+ }
+ }
+ return nullptr; // not found
+}
+
+static OUString lcl_CreatePivotName( ScDocShell* pDocShell )
+{
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ return pColl->CreateNewName();
+ }
+ return OUString(); // shouldn't happen
+}
+
+static sal_Int32 lcl_GetObjectIndex( ScDPObject* pDPObj, const ScFieldIdentifier& rFieldId )
+{
+ // used for items - nRepeat in identifier can be ignored
+ if ( pDPObj )
+ {
+ sal_Int32 nCount = pDPObj->GetDimCount();
+ for ( sal_Int32 nDim = 0; nDim < nCount; ++nDim )
+ {
+ bool bIsDataLayout = false;
+ OUString aDimName( pDPObj->GetDimName( nDim, bIsDataLayout ) );
+ if ( rFieldId.mbDataLayout ? bIsDataLayout : (aDimName == rFieldId.maFieldName) )
+ return nDim;
+ }
+ }
+ return -1; // none
+}
+
+ScDataPilotTablesObj::ScDataPilotTablesObj(ScDocShell& rDocSh, SCTAB nT) :
+ pDocShell( &rDocSh ),
+ nTab( nT )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDataPilotTablesObj::~ScDataPilotTablesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDataPilotTablesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! update of references
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XDataPilotTables
+
+rtl::Reference<ScDataPilotTableObj> ScDataPilotTablesObj::GetObjectByIndex_Impl( sal_Int32 nIndex )
+{
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ {
+ // count tables on this sheet
+ sal_Int32 nFound = 0;
+ size_t nCount = pColl->GetCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
+ {
+ if ( nFound == nIndex )
+ {
+ return new ScDataPilotTableObj(*pDocShell, nTab, rDPObj.GetName());
+ }
+ ++nFound;
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+rtl::Reference<ScDataPilotTableObj> ScDataPilotTablesObj::GetObjectByName_Impl(const OUString& rName)
+{
+ if (hasByName(rName))
+ return new ScDataPilotTableObj(*pDocShell, nTab, rName);
+ return nullptr;
+}
+
+Reference<XDataPilotDescriptor> SAL_CALL ScDataPilotTablesObj::createDataPilotDescriptor()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScDataPilotDescriptor(*pDocShell);
+ return nullptr;
+}
+
+static bool lcl_IsDuplicated(const Reference<XPropertySet>& rDimProps)
+{
+ try
+ {
+ Any aAny = rDimProps->getPropertyValue( SC_UNO_DP_ORIGINAL );
+ Reference< XNamed > xOriginal( aAny, UNO_QUERY );
+ return xOriginal.is();
+ }
+ catch( Exception& )
+ {
+ }
+ return false;
+}
+
+static OUString lcl_GetOriginalName(const Reference< XNamed >& rDim)
+{
+ Reference< XNamed > xOriginal;
+
+ Reference< XPropertySet > xDimProps(rDim, UNO_QUERY);
+ if ( xDimProps.is() )
+ {
+ try
+ {
+ Any aAny = xDimProps->getPropertyValue(SC_UNO_DP_ORIGINAL);
+ aAny >>= xOriginal;
+ }
+ catch( Exception& )
+ {
+ }
+ }
+
+ if ( !xOriginal.is() )
+ xOriginal = rDim;
+
+ return xOriginal->getName();
+}
+
+void SAL_CALL ScDataPilotTablesObj::insertNewByName( const OUString& aNewName,
+ const CellAddress& aOutputAddress,
+ const Reference<XDataPilotDescriptor>& xDescriptor )
+{
+ SolarMutexGuard aGuard;
+ if (!xDescriptor.is()) return;
+
+ if ( !aNewName.isEmpty() && hasByName( aNewName ) )
+ throw IllegalArgumentException("Name \"" + aNewName + "\" already exists", getXWeak(), 0);
+
+ if (!pDocShell)
+ throw RuntimeException("DocShell is null", getXWeak());
+
+ auto pImp = dynamic_cast<ScDataPilotDescriptorBase*>( xDescriptor.get() );
+ if (!pImp)
+ throw RuntimeException("Failed to get ScDataPilotDescriptor", getXWeak());
+
+ ScDPObject* pNewObj = pImp->GetDPObject();
+ if (!pNewObj)
+ throw RuntimeException("Failed to get DPObject", getXWeak());
+
+ ScRange aOutputRange(static_cast<SCCOL>(aOutputAddress.Column), static_cast<SCROW>(aOutputAddress.Row), static_cast<SCTAB>(aOutputAddress.Sheet),
+ static_cast<SCCOL>(aOutputAddress.Column), static_cast<SCROW>(aOutputAddress.Row), static_cast<SCTAB>(aOutputAddress.Sheet));
+ pNewObj->SetOutRange(aOutputRange);
+ OUString aName = aNewName;
+ if (aName.isEmpty())
+ aName = lcl_CreatePivotName( pDocShell );
+ pNewObj->SetName(aName);
+ OUString aTag = xDescriptor->getTag();
+ pNewObj->SetTag(aTag);
+
+ // todo: handle double fields (for more information see ScDPObject)
+
+ ScDBDocFunc aFunc(*pDocShell);
+ if (!aFunc.CreatePivotTable(*pNewObj, true, true))
+ throw RuntimeException("Failed to create pivot table", getXWeak());
+}
+
+void SAL_CALL ScDataPilotTablesObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject( pDocShell, nTab, aName );
+ if (!pDPObj || !pDocShell)
+ throw RuntimeException(); // no other exceptions specified
+
+ ScDBDocFunc aFunc(*pDocShell);
+ aFunc.RemovePivotTable(*pDPObj, true, true); // remove - incl. undo etc.
+
+}
+
+// XEnumerationAccess
+
+Reference< XEnumeration > SAL_CALL ScDataPilotTablesObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.DataPilotTablesEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDataPilotTablesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ {
+ // count tables on this sheet
+
+ sal_uInt16 nFound = 0;
+ size_t nCount = pColl->GetCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
+ ++nFound;
+ }
+ return nFound;
+ }
+ }
+
+ return 0;
+}
+
+Any SAL_CALL ScDataPilotTablesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ Reference<XDataPilotTable2> xTable(GetObjectByIndex_Impl(nIndex));
+ if (!xTable.is())
+ throw IndexOutOfBoundsException();
+ return Any( xTable );
+}
+
+uno::Type SAL_CALL ScDataPilotTablesObj::getElementType()
+{
+ return cppu::UnoType<XDataPilotTable2>::get();
+}
+
+sal_Bool SAL_CALL ScDataPilotTablesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XNameAccess
+
+Any SAL_CALL ScDataPilotTablesObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ Reference<XDataPilotTable2> xTable(GetObjectByName_Impl(aName));
+ if (!xTable.is())
+ throw NoSuchElementException();
+ return Any( xTable );
+}
+
+Sequence<OUString> SAL_CALL ScDataPilotTablesObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ {
+ // count tables on this sheet
+
+ sal_uInt16 nFound = 0;
+ size_t nCount = pColl->GetCount();
+ size_t i;
+ for (i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
+ ++nFound;
+ }
+
+ sal_uInt16 nPos = 0;
+ Sequence<OUString> aSeq(nFound);
+ OUString* pAry = aSeq.getArray();
+ for (i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
+ pAry[nPos++] = rDPObj.GetName();
+ }
+
+ return aSeq;
+ }
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScDataPilotTablesObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ {
+ size_t nCount = pColl->GetCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab &&
+ rDPObj.GetName() == aName )
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ScDataPilotDescriptorBase::ScDataPilotDescriptorBase(ScDocShell& rDocSh) :
+ maPropSet( lcl_GetDataPilotDescriptorBaseMap() ),
+ pDocShell( &rDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDataPilotDescriptorBase::~ScDataPilotDescriptorBase()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDataPilotDescriptorBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! update of references ?
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XDataPilotDescriptor
+
+CellRangeAddress SAL_CALL ScDataPilotDescriptorBase::getSourceRange()
+{
+ SolarMutexGuard aGuard;
+
+ ScDPObject* pDPObject(GetDPObject());
+ if (!pDPObject)
+ throw RuntimeException("Failed to get DPObject", getXWeak());
+
+ CellRangeAddress aRet;
+ if (pDPObject->IsSheetData())
+ ScUnoConversion::FillApiRange( aRet, pDPObject->GetSheetDesc()->GetSourceRange() );
+ return aRet;
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::setSourceRange( const CellRangeAddress& aSourceRange )
+{
+ SolarMutexGuard aGuard;
+
+ ScDPObject* pDPObject = GetDPObject();
+ if (!pDPObject)
+ throw RuntimeException("Failed to get DPObject", getXWeak());
+
+ ScSheetSourceDesc aSheetDesc(&pDocShell->GetDocument());
+ if (pDPObject->IsSheetData())
+ aSheetDesc = *pDPObject->GetSheetDesc();
+
+ ScRange aRange;
+ ScUnoConversion::FillScRange(aRange, aSourceRange);
+ aSheetDesc.SetSourceRange(aRange);
+ pDPObject->SetSheetDesc( aSheetDesc );
+ SetDPObject( pDPObject );
+}
+
+Reference<XSheetFilterDescriptor> SAL_CALL ScDataPilotDescriptorBase::getFilterDescriptor()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFilterDescriptor( pDocShell, this );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getDataPilotFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getColumnFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_COLUMN );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getRowFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_ROW );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getPageFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_PAGE );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getDataFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_DATA );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getHiddenFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_HIDDEN );
+}
+
+// XPropertySet
+Reference< XPropertySetInfo > SAL_CALL ScDataPilotDescriptorBase::getPropertySetInfo( )
+{
+ SolarMutexGuard aGuard;
+ static Reference<XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObject = GetDPObject();
+ if (!pDPObject)
+ return;
+
+ ScDPSaveData* pOldData = pDPObject->GetSaveData();
+ OSL_ENSURE(pOldData, "Here should be a SaveData");
+ if ( pOldData )
+ {
+ ScDPSaveData aNewData( *pOldData );
+
+ if ( aPropertyName == SC_UNO_DP_COLGRAND )
+ {
+ aNewData.SetColumnGrand(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_IGNORE_EMPTYROWS )
+ {
+ aNewData.SetIgnoreEmptyRows(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_REPEATEMPTY )
+ {
+ aNewData.SetRepeatIfEmpty(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_ROWGRAND )
+ {
+ aNewData.SetRowGrand(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_SHOWFILTER )
+ {
+ aNewData.SetFilterButton(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_DRILLDOWN )
+ {
+ aNewData.SetDrillDown(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_GRANDTOTAL_NAME )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aNewData.SetGrandTotalName(aStrVal);
+ }
+ else if ( aPropertyName == SC_UNO_DP_IMPORTDESC )
+ {
+ uno::Sequence<beans::PropertyValue> aArgSeq;
+ if ( aValue >>= aArgSeq )
+ {
+ ScImportSourceDesc aImportDesc(&pDocShell->GetDocument());
+
+ const ScImportSourceDesc* pOldDesc = pDPObject->GetImportSourceDesc();
+ if (pOldDesc)
+ aImportDesc = *pOldDesc;
+
+ ScImportParam aParam;
+ ScImportDescriptor::FillImportParam( aParam, aArgSeq );
+
+ sheet::DataImportMode nNewType = sheet::DataImportMode_NONE;
+ if ( aParam.bImport )
+ {
+ if ( aParam.bSql )
+ nNewType = sheet::DataImportMode_SQL;
+ else if ( aParam.nType == ScDbQuery )
+ nNewType = sheet::DataImportMode_QUERY;
+ else
+ nNewType = sheet::DataImportMode_TABLE;
+ }
+ aImportDesc.nType = nNewType;
+ aImportDesc.aDBName = aParam.aDBName;
+ aImportDesc.aObject = aParam.aStatement;
+ aImportDesc.bNative = aParam.bNative;
+
+ pDPObject->SetImportDesc( aImportDesc );
+ }
+ }
+ else if ( aPropertyName == SC_UNO_DP_SOURCESERVICE )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ {
+ ScDPServiceDesc aServiceDesc("", "", "", "", "");
+
+ const ScDPServiceDesc* pOldDesc = pDPObject->GetDPServiceDesc();
+ if (pOldDesc)
+ aServiceDesc = *pOldDesc;
+
+ aServiceDesc.aServiceName = aStrVal;
+
+ pDPObject->SetServiceData( aServiceDesc );
+ }
+ }
+ else if ( aPropertyName == SC_UNO_DP_SERVICEARG )
+ {
+ uno::Sequence<beans::PropertyValue> aArgSeq;
+ if ( aValue >>= aArgSeq )
+ {
+ ScDPServiceDesc aServiceDesc("", "", "", "", "");
+
+ const ScDPServiceDesc* pOldDesc = pDPObject->GetDPServiceDesc();
+ if (pOldDesc)
+ aServiceDesc = *pOldDesc;
+
+ OUString aStrVal;
+ for (const beans::PropertyValue& rProp : std::as_const(aArgSeq))
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == SC_UNO_DP_SOURCENAME)
+ {
+ if ( rProp.Value >>= aStrVal )
+ aServiceDesc.aParSource = aStrVal;
+ }
+ else if (aPropName == SC_UNO_DP_OBJECTNAME)
+ {
+ if ( rProp.Value >>= aStrVal )
+ aServiceDesc.aParName = aStrVal;
+ }
+ else if (aPropName == SC_UNO_DP_USERNAME)
+ {
+ if ( rProp.Value >>= aStrVal )
+ aServiceDesc.aParUser = aStrVal;
+ }
+ else if (aPropName == SC_UNO_DP_PASSWORD)
+ {
+ if ( rProp.Value >>= aStrVal )
+ aServiceDesc.aParPass = aStrVal;
+ }
+ }
+
+ pDPObject->SetServiceData( aServiceDesc );
+ }
+ }
+ else
+ throw UnknownPropertyException(aPropertyName);
+
+ pDPObject->SetSaveData( aNewData );
+ }
+
+ SetDPObject(pDPObject);
+}
+
+Any SAL_CALL ScDataPilotDescriptorBase::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ Any aRet;
+
+ ScDPObject* pDPObject(GetDPObject());
+ if (pDPObject)
+ {
+ ScDPSaveData* pOldData = pDPObject->GetSaveData();
+ OSL_ENSURE(pOldData, "Here should be a SaveData");
+ if ( pOldData )
+ {
+ ScDPSaveData aNewData( *pOldData );
+
+ if ( aPropertyName == SC_UNO_DP_COLGRAND )
+ {
+ aRet <<= aNewData.GetColumnGrand();
+ }
+ else if ( aPropertyName == SC_UNO_DP_IGNORE_EMPTYROWS )
+ {
+ aRet <<= aNewData.GetIgnoreEmptyRows();
+ }
+ else if ( aPropertyName == SC_UNO_DP_REPEATEMPTY )
+ {
+ aRet <<= aNewData.GetRepeatIfEmpty();
+ }
+ else if ( aPropertyName == SC_UNO_DP_ROWGRAND )
+ {
+ aRet <<= aNewData.GetRowGrand();
+ }
+ else if ( aPropertyName == SC_UNO_DP_SHOWFILTER )
+ {
+ aRet <<= aNewData.GetFilterButton();
+ }
+ else if ( aPropertyName == SC_UNO_DP_DRILLDOWN )
+ {
+ aRet <<= aNewData.GetDrillDown();
+ }
+ else if ( aPropertyName == SC_UNO_DP_GRANDTOTAL_NAME )
+ {
+ const std::optional<OUString> & pGrandTotalName = aNewData.GetGrandTotalName();
+ if (pGrandTotalName)
+ aRet <<= *pGrandTotalName; // same behavior as in ScDPSource
+ }
+ else if ( aPropertyName == SC_UNO_DP_IMPORTDESC )
+ {
+ const ScImportSourceDesc* pImportDesc = pDPObject->GetImportSourceDesc();
+ if ( pImportDesc )
+ {
+ // fill ScImportParam so ScImportDescriptor::FillProperties can be used
+ ScImportParam aParam;
+ aParam.bImport = ( pImportDesc->nType != sheet::DataImportMode_NONE );
+ aParam.aDBName = pImportDesc->aDBName;
+ aParam.aStatement = pImportDesc->aObject;
+ aParam.bNative = pImportDesc->bNative;
+ aParam.bSql = ( pImportDesc->nType == sheet::DataImportMode_SQL );
+ aParam.nType = static_cast<sal_uInt8>(( pImportDesc->nType == sheet::DataImportMode_QUERY ) ? ScDbQuery : ScDbTable);
+
+ uno::Sequence<beans::PropertyValue> aSeq( ScImportDescriptor::GetPropertyCount() );
+ ScImportDescriptor::FillProperties( aSeq, aParam );
+ aRet <<= aSeq;
+ }
+ else
+ {
+ // empty sequence
+ uno::Sequence<beans::PropertyValue> aEmpty(0);
+ aRet <<= aEmpty;
+ }
+ }
+ else if ( aPropertyName == SC_UNO_DP_SOURCESERVICE )
+ {
+ OUString aServiceName;
+ const ScDPServiceDesc* pServiceDesc = pDPObject->GetDPServiceDesc();
+ if (pServiceDesc)
+ aServiceName = pServiceDesc->aServiceName;
+ aRet <<= aServiceName; // empty string if no ServiceDesc set
+ }
+ else if ( aPropertyName == SC_UNO_DP_SERVICEARG )
+ {
+ const ScDPServiceDesc* pServiceDesc = pDPObject->GetDPServiceDesc();
+ if (pServiceDesc)
+ {
+ uno::Sequence<beans::PropertyValue> aSeq( comphelper::InitPropertySequence({
+ { SC_UNO_DP_SOURCENAME, Any(pServiceDesc->aParSource) },
+ { SC_UNO_DP_OBJECTNAME, Any(pServiceDesc->aParName) },
+ { SC_UNO_DP_USERNAME, Any(pServiceDesc->aParUser) },
+ { SC_UNO_DP_PASSWORD, Any(pServiceDesc->aParPass) }
+ }));
+ aRet <<= aSeq;
+ }
+ else
+ {
+ // empty sequence
+ uno::Sequence<beans::PropertyValue> aEmpty;
+ aRet <<= aEmpty;
+ }
+ }
+ else
+ throw UnknownPropertyException(aPropertyName);
+ }
+ }
+
+ return aRet;
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::addPropertyChangeListener(
+ const OUString& /* aPropertyName */, const Reference<XPropertyChangeListener >& /* xListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::removePropertyChangeListener(
+ const OUString& /* aPropertyName */, const Reference<XPropertyChangeListener >& /* aListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::addVetoableChangeListener(
+ const OUString& /* PropertyName */, const Reference<XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::removeVetoableChangeListener(
+ const OUString& /* PropertyName */, const Reference<XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+// XDataPilotDataLayoutFieldSupplier
+
+Reference< XDataPilotField > SAL_CALL ScDataPilotDescriptorBase::getDataLayoutField()
+{
+ SolarMutexGuard aGuard;
+ if( ScDPObject* pDPObject = GetDPObject() )
+ {
+ if( ScDPSaveData* pSaveData = pDPObject->GetSaveData() )
+ {
+ if( pSaveData->GetDataLayoutDimension() )
+ {
+ ScFieldIdentifier aFieldId( SC_DATALAYOUT_NAME, true );
+ return new ScDataPilotFieldObj( *this, aFieldId );
+ }
+ }
+ }
+ return nullptr;
+}
+
+ScDataPilotTableObj::ScDataPilotTableObj(ScDocShell& rDocSh, SCTAB nT, OUString aN) :
+ ScDataPilotDescriptorBase( rDocSh ),
+ nTab( nT ),
+ aName(std::move( aN )),
+ aModifyListeners( 0 )
+{
+}
+
+ScDataPilotTableObj::~ScDataPilotTableObj()
+{
+}
+
+Any SAL_CALL ScDataPilotTableObj::queryInterface( const uno::Type& rType )
+{
+ // since we manually do resolve the query for XDataPilotTable2
+ // we also need to do the same for XDataPilotTable
+ uno::Any aReturn = ::cppu::queryInterface(rType,
+ static_cast<XDataPilotTable*>(this),
+ static_cast<XDataPilotTable2*>(this),
+ static_cast<XModifyBroadcaster*>(this));
+ if ( aReturn.hasValue() )
+ return aReturn;
+
+ return ScDataPilotDescriptorBase::queryInterface( rType );
+}
+
+void SAL_CALL ScDataPilotTableObj::acquire() noexcept
+{
+ ScDataPilotDescriptorBase::acquire();
+}
+
+void SAL_CALL ScDataPilotTableObj::release() noexcept
+{
+ ScDataPilotDescriptorBase::release();
+}
+
+Sequence< uno::Type > SAL_CALL ScDataPilotTableObj::getTypes()
+{
+ return comphelper::concatSequences(
+ ScDataPilotDescriptorBase::getTypes(),
+ Sequence< uno::Type >
+ {
+ cppu::UnoType<XDataPilotTable2>::get(),
+ cppu::UnoType<XModifyBroadcaster>::get()
+ } );
+}
+
+Sequence<sal_Int8> SAL_CALL ScDataPilotTableObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+ScDPObject* ScDataPilotTableObj::GetDPObject() const
+{
+ return lcl_GetDPObject(GetDocShell(), nTab, aName);
+}
+
+void ScDataPilotTableObj::SetDPObject( ScDPObject* pDPObject )
+{
+ ScDocShell* pDocSh = GetDocShell();
+ ScDPObject* pDPObj = lcl_GetDPObject(pDocSh, nTab, aName);
+ if ( pDPObj && pDocSh )
+ {
+ ScDBDocFunc aFunc(*pDocSh);
+ aFunc.DataPilotUpdate( pDPObj, pDPObject, true, true );
+ }
+}
+
+// "rest of XDataPilotDescriptor"
+
+OUString SAL_CALL ScDataPilotTableObj::getName()
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ return pDPObj->GetName();
+ return OUString();
+}
+
+void SAL_CALL ScDataPilotTableObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ {
+ //! test for existing names !!!
+
+ pDPObj->SetName( aNewName ); //! Undo - DBDocFunc ???
+ aName = aNewName;
+
+ // DataPilotUpdate would do too much (output table is not changed)
+ GetDocShell()->SetDocumentModified();
+ }
+}
+
+OUString SAL_CALL ScDataPilotTableObj::getTag()
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ return pDPObj->GetTag();
+ return OUString();
+}
+
+void SAL_CALL ScDataPilotTableObj::setTag( const OUString& aNewTag )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ {
+ pDPObj->SetTag( aNewTag ); //! Undo - DBDocFunc ???
+
+ // DataPilotUpdate would do too much (output table is not changed)
+ GetDocShell()->SetDocumentModified();
+ }
+}
+
+// XDataPilotTable
+
+CellRangeAddress SAL_CALL ScDataPilotTableObj::getOutputRange()
+{
+ SolarMutexGuard aGuard;
+ CellRangeAddress aRet;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ {
+ ScRange aRange(pDPObj->GetOutRange());
+ aRet.Sheet = aRange.aStart.Tab();
+ aRet.StartColumn = aRange.aStart.Col();
+ aRet.StartRow = aRange.aStart.Row();
+ aRet.EndColumn = aRange.aEnd.Col();
+ aRet.EndRow = aRange.aEnd.Row();
+ }
+ return aRet;
+}
+
+void SAL_CALL ScDataPilotTableObj::refresh()
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ {
+ ScDBDocFunc aFunc(*GetDocShell());
+ aFunc.RefreshPivotTables(pDPObj, true);
+ }
+}
+
+Sequence< Sequence<Any> > SAL_CALL ScDataPilotTableObj::getDrillDownData(const CellAddress& aAddr)
+{
+ SolarMutexGuard aGuard;
+ Sequence< Sequence<Any> > aTabData;
+ ScAddress aAddr2(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet);
+ ScDPObject* pObj = GetDPObject();
+ if (!pObj)
+ throw RuntimeException("Failed to get DPObject", getXWeak());
+
+ pObj->GetDrillDownData(aAddr2, aTabData);
+ return aTabData;
+}
+
+DataPilotTablePositionData SAL_CALL ScDataPilotTableObj::getPositionData(const CellAddress& aAddr)
+{
+ SolarMutexGuard aGuard;
+ DataPilotTablePositionData aPosData;
+ ScAddress aAddr2(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet);
+ ScDPObject* pObj = GetDPObject();
+ if (!pObj)
+ throw RuntimeException("Failed to get DPObject", getXWeak());
+
+ pObj->GetPositionData(aAddr2, aPosData);
+ return aPosData;
+}
+
+void SAL_CALL ScDataPilotTableObj::insertDrillDownSheet(const CellAddress& aAddr)
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = GetDPObject();
+ if (!pDPObj)
+ throw RuntimeException("Failed to get DPObject", getXWeak());
+ ScTabViewShell* pViewSh = GetDocShell()->GetBestViewShell();
+ if (!pViewSh)
+ throw RuntimeException("Failed to get ViewShell", getXWeak());
+
+ Sequence<DataPilotFieldFilter> aFilters;
+ pDPObj->GetDataFieldPositionData(
+ ScAddress(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet), aFilters);
+ pViewSh->ShowDataPilotSourceData(*pDPObj, aFilters);
+}
+
+CellRangeAddress SAL_CALL ScDataPilotTableObj::getOutputRangeByType( sal_Int32 nType )
+{
+ SolarMutexGuard aGuard;
+ if (nType < 0 || nType > DataPilotOutputRangeType::RESULT)
+ throw IllegalArgumentException("nType must be between 0 and " +
+ OUString::number(DataPilotOutputRangeType::RESULT) + ", got " + OUString::number(nType),
+ getXWeak(), 0);
+
+ CellRangeAddress aRet;
+ if (ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName))
+ ScUnoConversion::FillApiRange( aRet, pDPObj->GetOutputRangeByType( nType ) );
+ return aRet;
+}
+
+void SAL_CALL ScDataPilotTableObj::addModifyListener( const uno::Reference<util::XModifyListener>& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ aModifyListeners.emplace_back( aListener );
+
+ if ( aModifyListeners.size() == 1 )
+ {
+ acquire(); // don't lose this object (one ref for all listeners)
+ }
+}
+
+void SAL_CALL ScDataPilotTableObj::removeModifyListener( const uno::Reference<util::XModifyListener>& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ rtl::Reference<ScDataPilotTableObj> xSelfHold(this); // in case the listeners have the last ref
+
+ sal_uInt16 nCount = aModifyListeners.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ {
+ uno::Reference<util::XModifyListener>& rObj = aModifyListeners[n];
+ if ( rObj == aListener )
+ {
+ aModifyListeners.erase( aModifyListeners.begin() + n );
+
+ if ( aModifyListeners.empty() )
+ {
+ release(); // release the ref for the listeners
+ }
+
+ break;
+ }
+ }
+}
+
+void ScDataPilotTableObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if ( auto pDataPilotHint = dynamic_cast<const ScDataPilotModifiedHint*>(&rHint) )
+ {
+ if (pDataPilotHint->GetName() == aName)
+ Refreshed_Impl();
+ }
+ else if ( auto pRefHint = dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ ScRange aRange( 0, 0, nTab );
+ ScRangeList aRanges( aRange );
+ if ( aRanges.UpdateReference( pRefHint->GetMode(), &GetDocShell()->GetDocument(), pRefHint->GetRange(),
+ pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() ) &&
+ aRanges.size() == 1 )
+ {
+ nTab = aRanges.front().aStart.Tab();
+ }
+ }
+
+ ScDataPilotDescriptorBase::Notify( rBC, rHint );
+}
+
+void ScDataPilotTableObj::Refreshed_Impl()
+{
+ lang::EventObject aEvent;
+ aEvent.Source = getXWeak();
+
+ // the EventObject holds a Ref to this object until after the listener calls
+
+ ScDocument& rDoc = GetDocShell()->GetDocument();
+ for (const uno::Reference<util::XModifyListener> & xModifyListener : aModifyListeners)
+ rDoc.AddUnoListenerCall( xModifyListener, aEvent );
+}
+
+ScDataPilotDescriptor::ScDataPilotDescriptor(ScDocShell& rDocSh) :
+ ScDataPilotDescriptorBase( rDocSh ),
+ mpDPObject(new ScDPObject(&rDocSh.GetDocument()))
+{
+ ScDPSaveData aSaveData;
+ // set defaults like in ScPivotParam constructor
+ aSaveData.SetColumnGrand( true );
+ aSaveData.SetRowGrand( true );
+ aSaveData.SetIgnoreEmptyRows( false );
+ aSaveData.SetRepeatIfEmpty( false );
+ mpDPObject->SetSaveData(aSaveData);
+ ScSheetSourceDesc aSheetDesc(&rDocSh.GetDocument());
+ mpDPObject->SetSheetDesc(aSheetDesc);
+}
+
+ScDataPilotDescriptor::~ScDataPilotDescriptor()
+{
+}
+
+ScDPObject* ScDataPilotDescriptor::GetDPObject() const
+{
+ return mpDPObject.get();
+}
+
+void ScDataPilotDescriptor::SetDPObject( ScDPObject* pDPObject )
+{
+ if (mpDPObject.get() != pDPObject)
+ {
+ mpDPObject.reset( pDPObject );
+ OSL_FAIL("replace DPObject should not happen");
+ }
+}
+
+// "rest of XDataPilotDescriptor"
+
+OUString SAL_CALL ScDataPilotDescriptor::getName()
+{
+ SolarMutexGuard aGuard;
+ return mpDPObject->GetName();
+}
+
+void SAL_CALL ScDataPilotDescriptor::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ mpDPObject->SetName( aNewName );
+}
+
+OUString SAL_CALL ScDataPilotDescriptor::getTag()
+{
+ SolarMutexGuard aGuard;
+ return mpDPObject->GetTag();
+}
+
+void SAL_CALL ScDataPilotDescriptor::setTag( const OUString& aNewTag )
+{
+ SolarMutexGuard aGuard;
+ mpDPObject->SetTag( aNewTag );
+}
+
+ScDataPilotChildObjBase::ScDataPilotChildObjBase( ScDataPilotDescriptorBase& rParent ) :
+ mxParent( &rParent )
+{
+}
+
+ScDataPilotChildObjBase::ScDataPilotChildObjBase( ScDataPilotDescriptorBase& rParent, ScFieldIdentifier aFieldId ) :
+ mxParent( &rParent ),
+ maFieldId(std::move( aFieldId ))
+{
+}
+
+ScDataPilotChildObjBase::~ScDataPilotChildObjBase()
+{
+}
+
+ScDPObject* ScDataPilotChildObjBase::GetDPObject() const
+{
+ return mxParent->GetDPObject();
+}
+
+void ScDataPilotChildObjBase::SetDPObject( ScDPObject* pDPObject )
+{
+ mxParent->SetDPObject( pDPObject );
+}
+
+ScDPSaveDimension* ScDataPilotChildObjBase::GetDPDimension( ScDPObject** ppDPObject ) const
+{
+ if( ScDPObject* pDPObj = GetDPObject() )
+ {
+ if( ppDPObject ) *ppDPObject = pDPObj;
+ if( ScDPSaveData* pSaveData = pDPObj->GetSaveData() )
+ {
+ if( maFieldId.mbDataLayout )
+ return pSaveData->GetDataLayoutDimension();
+
+ if( maFieldId.mnFieldIdx == 0 )
+ return pSaveData->GetDimensionByName( maFieldId.maFieldName );
+
+ // find dimension with specified index (search in duplicated dimensions)
+ const ScDPSaveData::DimsType& rDims = pSaveData->GetDimensions();
+
+ sal_Int32 nFoundIdx = 0;
+ for (auto const& it : rDims)
+ {
+ if (it->IsDataLayout())
+ continue;
+
+ OUString aSrcName = ScDPUtil::getSourceDimensionName(it->GetName());
+ if (aSrcName == maFieldId.maFieldName)
+ {
+ if( nFoundIdx == maFieldId.mnFieldIdx )
+ return it.get();
+ ++nFoundIdx;
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+sal_Int32 ScDataPilotChildObjBase::GetMemberCount() const
+{
+ sal_Int32 nRet = 0;
+ Reference<XNameAccess> xMembersNA = GetMembers();
+ if (xMembersNA.is())
+ {
+ Reference< XIndexAccess > xMembersIA( new ScNameToIndexAccess( xMembersNA ) );
+ nRet = xMembersIA->getCount();
+ }
+ return nRet;
+}
+
+Reference< XMembersAccess > ScDataPilotChildObjBase::GetMembers() const
+{
+ Reference< XMembersAccess > xMembersNA;
+ if( ScDPObject* pDPObj = GetDPObject() )
+ pDPObj->GetMembersNA( lcl_GetObjectIndex( pDPObj, maFieldId ), xMembersNA );
+ return xMembersNA;
+}
+
+ScDocShell* ScDataPilotChildObjBase::GetDocShell() const
+{
+ return mxParent->GetDocShell();
+}
+
+ScDataPilotFieldsObj::ScDataPilotFieldsObj( ScDataPilotDescriptorBase& rParent ) :
+ ScDataPilotChildObjBase( rParent )
+{
+}
+
+ScDataPilotFieldsObj::ScDataPilotFieldsObj( ScDataPilotDescriptorBase& rParent, DataPilotFieldOrientation eOrient ) :
+ ScDataPilotChildObjBase( rParent ),
+ maOrient( eOrient )
+{
+}
+
+ScDataPilotFieldsObj::~ScDataPilotFieldsObj()
+{
+}
+
+static sal_Int32 lcl_GetFieldCount( const Reference<XDimensionsSupplier>& rSource, const Any& rOrient )
+{
+ if (!rSource.is())
+ throw NullPointerException();
+
+ sal_Int32 nRet = 0;
+
+ Reference<XNameAccess> xDimsName(rSource->getDimensions());
+ Reference<XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
+ sal_Int32 nIntCount = xIntDims->getCount();
+ for (sal_Int32 i = 0; i < nIntCount; ++i)
+ {
+ Reference<XPropertySet> xDim(xIntDims->getByIndex(i), UNO_QUERY);
+ const bool bMatch = xDim
+ && (rOrient.hasValue()
+ // all fields of the specified orientation, including duplicated
+ ? (xDim->getPropertyValue(SC_UNO_DP_ORIENTATION) == rOrient)
+ // count all non-duplicated fields
+ : !lcl_IsDuplicated(xDim));
+ if (bMatch)
+ ++nRet;
+ }
+
+ return nRet;
+}
+
+static bool lcl_GetFieldDataByIndex( const Reference<XDimensionsSupplier>& rSource,
+ const Any& rOrient, SCSIZE nIndex, ScFieldIdentifier& rFieldId )
+{
+ if (!rSource.is())
+ throw NullPointerException();
+
+ bool bOk = false;
+ SCSIZE nPos = 0;
+ sal_Int32 nDimIndex = 0;
+
+ Reference<XNameAccess> xDimsName(rSource->getDimensions());
+ Reference<XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
+ sal_Int32 nIntCount = xIntDims->getCount();
+ Reference<XPropertySet> xDim;
+ for (sal_Int32 i = 0; i < nIntCount; ++i)
+ {
+ xDim.set(xIntDims->getByIndex(i), UNO_QUERY);
+ const bool bMatch = xDim
+ && (rOrient.hasValue()
+ ? (xDim->getPropertyValue(SC_UNO_DP_ORIENTATION) == rOrient)
+ : !lcl_IsDuplicated(xDim));
+ if (bMatch)
+ {
+ if (nPos == nIndex)
+ {
+ bOk = true;
+ nDimIndex = i;
+ break;
+ }
+ else
+ ++nPos;
+ }
+ }
+
+ if ( bOk )
+ {
+ xDim.set( xIntDims->getByIndex(nDimIndex), UNO_QUERY );
+ Reference<XNamed> xDimName( xDim, UNO_QUERY );
+ if ( xDimName.is() )
+ {
+ OUString sOriginalName( lcl_GetOriginalName( xDimName ) );
+ rFieldId.maFieldName = sOriginalName;
+ rFieldId.mbDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDim,
+ SC_UNO_DP_ISDATALAYOUT );
+
+ sal_Int32 nRepeat = 0;
+ if ( rOrient.hasValue() && lcl_IsDuplicated( xDim ) )
+ {
+ // find the repeat count
+ // (this relies on the original dimension always being before the duplicates)
+
+ Reference<XNamed> xPrevName;
+ for (sal_Int32 i = 0; i < nDimIndex; ++i)
+ {
+ xPrevName.set( xIntDims->getByIndex(i), UNO_QUERY );
+ if ( xPrevName.is() && lcl_GetOriginalName( xPrevName ) == sOriginalName )
+ ++nRepeat;
+ }
+ }
+ rFieldId.mnFieldIdx = nRepeat;
+ }
+ else
+ bOk = false;
+ }
+
+ return bOk;
+}
+
+static bool lcl_GetFieldDataByName( ScDPObject* pDPObj, const OUString& rFieldName, ScFieldIdentifier& rFieldId )
+{
+ // "By name" is always the first match.
+ // The name "Data" always refers to the data layout field.
+ rFieldId.maFieldName = rFieldName;
+ rFieldId.mnFieldIdx = 0;
+ rFieldId.mbDataLayout = rFieldName == SC_DATALAYOUT_NAME;
+
+ pDPObj->GetSource(); // IsDimNameInUse doesn't update source data
+
+ // check if the named field exists (not for data layout)
+ return rFieldId.mbDataLayout || pDPObj->IsDimNameInUse( rFieldName );
+}
+
+// XDataPilotFields
+
+rtl::Reference<ScDataPilotFieldObj> ScDataPilotFieldsObj::GetObjectByIndex_Impl( sal_Int32 nIndex ) const
+{
+ if (ScDPObject* pObj = GetDPObject())
+ {
+ ScFieldIdentifier aFieldId;
+ if (lcl_GetFieldDataByIndex( pObj->GetSource(), maOrient, nIndex, aFieldId ))
+ return new ScDataPilotFieldObj( *mxParent, aFieldId, maOrient );
+ }
+ return nullptr;
+}
+
+rtl::Reference<ScDataPilotFieldObj> ScDataPilotFieldsObj::GetObjectByName_Impl(const OUString& aName) const
+{
+ if (ScDPObject* pDPObj = GetDPObject())
+ {
+ ScFieldIdentifier aFieldId;
+ if (lcl_GetFieldDataByName( pDPObj, aName, aFieldId ))
+ return new ScDataPilotFieldObj( *mxParent, aFieldId, maOrient );
+ }
+ return nullptr;
+}
+
+// XEnumerationAccess
+
+Reference<XEnumeration> SAL_CALL ScDataPilotFieldsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.DataPilotFieldsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDataPilotFieldsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = GetDPObject();
+ return pDPObj ? lcl_GetFieldCount( pDPObj->GetSource(), maOrient ) : 0;
+}
+
+Any SAL_CALL ScDataPilotFieldsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ Reference< XPropertySet > xField( GetObjectByIndex_Impl( nIndex ) );
+ if (!xField.is())
+ throw IndexOutOfBoundsException();
+ return Any( xField );
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScDataPilotFieldsObj::getElementType()
+{
+ return cppu::UnoType<XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XNameAccess
+
+Any SAL_CALL ScDataPilotFieldsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ Reference<XPropertySet> xField(GetObjectByName_Impl(aName));
+ if (!xField.is())
+ throw NoSuchElementException();
+ return Any( xField );
+}
+
+Sequence<OUString> SAL_CALL ScDataPilotFieldsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (ScDPObject* pDPObj = GetDPObject())
+ {
+ Sequence< OUString > aSeq( lcl_GetFieldCount( pDPObj->GetSource(), maOrient ) );
+ OUString* pAry = aSeq.getArray();
+
+ const ScDPSaveData::DimsType& rDimensions = pDPObj->GetSaveData()->GetDimensions();
+ for (auto const& it : rDimensions)
+ {
+ if(maOrient.hasValue() && (it->GetOrientation() == maOrient.get< DataPilotFieldOrientation >()))
+ {
+ *pAry = it->GetName();
+ ++pAry;
+ }
+ }
+ return aSeq;
+ }
+ return Sequence<OUString>();
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ return GetObjectByName_Impl(aName) != nullptr;
+}
+
+ScDataPilotFieldObj::ScDataPilotFieldObj(
+ ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId ) :
+ ScDataPilotChildObjBase( rParent, rFieldId ),
+ maPropSet( lcl_GetDataPilotFieldMap() )
+{
+}
+
+ScDataPilotFieldObj::ScDataPilotFieldObj( ScDataPilotDescriptorBase& rParent,
+ const ScFieldIdentifier& rFieldId, Any aOrient ) :
+ ScDataPilotChildObjBase( rParent, rFieldId ),
+ maPropSet( lcl_GetDataPilotFieldMap() ),
+ maOrient(std::move( aOrient ))
+{
+}
+
+ScDataPilotFieldObj::~ScDataPilotFieldObj()
+{
+}
+
+// XNamed
+
+OUString SAL_CALL ScDataPilotFieldObj::getName()
+{
+ SolarMutexGuard aGuard;
+ OUString aName;
+ if( ScDPSaveDimension* pDim = GetDPDimension() )
+ {
+ if( pDim->IsDataLayout() )
+ aName = SC_DATALAYOUT_NAME;
+ else
+ {
+ const std::optional<OUString> & pLayoutName = pDim->GetLayoutName();
+ if (pLayoutName)
+ aName = *pLayoutName;
+ else
+ aName = pDim->GetName();
+ }
+ }
+ return aName;
+}
+
+void SAL_CALL ScDataPilotFieldObj::setName(const OUString& rName)
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if( pDim && !pDim->IsDataLayout() )
+ {
+ pDim->SetLayoutName(rName);
+ SetDPObject( pDPObj );
+ }
+}
+
+// XPropertySet
+
+Reference<XPropertySetInfo> SAL_CALL ScDataPilotFieldObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static Reference<XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScDataPilotFieldObj::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ if ( aPropertyName == SC_UNONAME_FUNCTION )
+ {
+ // #i109350# use GetEnumFromAny because it also allows sal_Int32
+ ScGeneralFunction eFunction = static_cast<ScGeneralFunction>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
+ setFunction( eFunction );
+ }
+ else if ( aPropertyName == SC_UNONAME_FUNCTION2 )
+ {
+ ScGeneralFunction eFunction = static_cast<ScGeneralFunction>(ScUnoHelpFunctions::GetInt16FromAny( aValue ));
+ setFunction( eFunction );
+ }
+ else if ( aPropertyName == SC_UNONAME_SUBTOTALS )
+ {
+ uno::Sequence<sheet::GeneralFunction> aSeq;
+ if( aValue >>= aSeq)
+ {
+ std::vector< ScGeneralFunction > aSubTotals(aSeq.getLength());
+ std::transform(std::cbegin(aSeq), std::cend(aSeq), aSubTotals.begin(),
+ [](const sheet::GeneralFunction& rValue) -> ScGeneralFunction {
+ const int nValAsInt = static_cast<int>(rValue);
+ return static_cast<ScGeneralFunction>(nValAsInt);
+ });
+ setSubtotals( aSubTotals );
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_SUBTOTALS2 )
+ {
+ Sequence< sal_Int16 > aSeq;
+ if( aValue >>= aSeq )
+ {
+ std::vector< ScGeneralFunction > aSubTotals(aSeq.getLength());
+ std::transform(std::cbegin(aSeq), std::cend(aSeq), aSubTotals.begin(),
+ [](sal_Int16 nValue) -> ScGeneralFunction { return static_cast<ScGeneralFunction>(nValue); });
+ setSubtotals( aSubTotals );
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_ORIENT )
+ {
+ //! test for correct enum type?
+ DataPilotFieldOrientation eOrient = static_cast<DataPilotFieldOrientation>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
+ setOrientation( eOrient );
+ }
+ else if ( aPropertyName == SC_UNONAME_SELPAGE )
+ {
+ OUString sCurrentPage;
+ if (aValue >>= sCurrentPage)
+ setCurrentPage(sCurrentPage);
+ }
+ else if ( aPropertyName == SC_UNONAME_USESELPAGE )
+ {
+ setUseCurrentPage(cppu::any2bool(aValue));
+ }
+ else if ( aPropertyName == SC_UNONAME_HASAUTOSHOW )
+ {
+ if (!cppu::any2bool(aValue))
+ setAutoShowInfo(nullptr);
+ }
+ else if ( aPropertyName == SC_UNONAME_AUTOSHOW )
+ {
+ DataPilotFieldAutoShowInfo aInfo;
+ if (aValue >>= aInfo)
+ setAutoShowInfo(&aInfo);
+ }
+ else if ( aPropertyName == SC_UNONAME_HASLAYOUTINFO )
+ {
+ if (!cppu::any2bool(aValue))
+ setLayoutInfo(nullptr);
+ }
+ else if ( aPropertyName == SC_UNONAME_LAYOUTINFO )
+ {
+ DataPilotFieldLayoutInfo aInfo;
+ if (aValue >>= aInfo)
+ setLayoutInfo(&aInfo);
+ }
+ else if ( aPropertyName == SC_UNONAME_HASREFERENCE )
+ {
+ if (!cppu::any2bool(aValue))
+ setReference(nullptr);
+ }
+ else if ( aPropertyName == SC_UNONAME_REFERENCE )
+ {
+ DataPilotFieldReference aRef;
+ if (aValue >>= aRef)
+ setReference(&aRef);
+ }
+ else if ( aPropertyName == SC_UNONAME_HASSORTINFO )
+ {
+ if (!cppu::any2bool(aValue))
+ setSortInfo(nullptr);
+ }
+ else if ( aPropertyName == SC_UNONAME_SORTINFO )
+ {
+ DataPilotFieldSortInfo aInfo;
+ if (aValue >>= aInfo)
+ setSortInfo(&aInfo);
+ }
+ else if ( aPropertyName == SC_UNONAME_ISGROUP )
+ {
+ if (!cppu::any2bool(aValue))
+ setGroupInfo(nullptr);
+ }
+ else if ( aPropertyName == SC_UNONAME_GROUPINFO )
+ {
+ DataPilotFieldGroupInfo aInfo;
+ if (aValue >>= aInfo)
+ setGroupInfo(&aInfo);
+ }
+ else if ( aPropertyName == SC_UNONAME_SHOWEMPTY )
+ {
+ setShowEmpty(cppu::any2bool(aValue));
+ }
+ else if ( aPropertyName == SC_UNONAME_REPEATITEMLABELS )
+ {
+ setRepeatItemLabels(cppu::any2bool(aValue));
+ }
+ else if (aPropertyName == SC_UNONAME_NAME)
+ {
+ OUString sName;
+ if (aValue >>= sName)
+ setName(sName);
+ }
+}
+
+Any SAL_CALL ScDataPilotFieldObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ Any aRet;
+
+ if ( aPropertyName == SC_UNONAME_FUNCTION )
+ {
+ sheet::GeneralFunction eVal;
+ sal_Int16 nFunction = getFunction();
+ if (nFunction == sheet::GeneralFunction2::MEDIAN)
+ {
+ eVal = sheet::GeneralFunction_NONE;
+ }
+ else
+ {
+ eVal = static_cast<sheet::GeneralFunction>(nFunction);
+ }
+ aRet <<= eVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_FUNCTION2 )
+ aRet <<= getFunction();
+ else if ( aPropertyName == SC_UNONAME_SUBTOTALS )
+ {
+ const uno::Sequence<sal_Int16> aSeq = getSubtotals();
+ uno::Sequence<sheet::GeneralFunction> aNewSeq(aSeq.getLength());
+ std::transform(aSeq.begin(), aSeq.end(), aNewSeq.getArray(),
+ [](sal_Int16 nFunc) -> sheet::GeneralFunction {
+ if (nFunc == sheet::GeneralFunction2::MEDIAN)
+ return sheet::GeneralFunction_NONE;
+ return static_cast<sheet::GeneralFunction>(nFunc);
+ });
+ aRet <<= aNewSeq;
+ }
+ else if ( aPropertyName == SC_UNONAME_SUBTOTALS2 )
+ {
+ aRet <<= getSubtotals();
+ }
+ else if ( aPropertyName == SC_UNONAME_ORIENT )
+ aRet <<= getOrientation();
+ else if ( aPropertyName == SC_UNONAME_SELPAGE )
+ aRet <<= OUString();
+ else if ( aPropertyName == SC_UNONAME_USESELPAGE )
+ aRet <<= false;
+ else if ( aPropertyName == SC_UNONAME_HASAUTOSHOW )
+ aRet <<= (getAutoShowInfo() != nullptr);
+ else if ( aPropertyName == SC_UNONAME_AUTOSHOW )
+ {
+ const DataPilotFieldAutoShowInfo* pInfo = getAutoShowInfo();
+ if (pInfo)
+ aRet <<= *pInfo;
+ }
+ else if ( aPropertyName == SC_UNONAME_HASLAYOUTINFO )
+ aRet <<= (getLayoutInfo() != nullptr);
+ else if ( aPropertyName == SC_UNONAME_LAYOUTINFO )
+ {
+ const DataPilotFieldLayoutInfo* pInfo = getLayoutInfo();
+ if (pInfo)
+ aRet <<= *pInfo;
+ }
+ else if ( aPropertyName == SC_UNONAME_HASREFERENCE )
+ aRet <<= (getReference() != nullptr);
+ else if ( aPropertyName == SC_UNONAME_REFERENCE )
+ {
+ const DataPilotFieldReference* pRef = getReference();
+ if (pRef)
+ aRet <<= *pRef;
+ }
+ else if ( aPropertyName == SC_UNONAME_HASSORTINFO )
+ aRet <<= (getSortInfo() != nullptr);
+ else if ( aPropertyName == SC_UNONAME_SORTINFO )
+ {
+ const DataPilotFieldSortInfo* pInfo = getSortInfo();
+ if (pInfo)
+ aRet <<= *pInfo;
+ }
+ else if ( aPropertyName == SC_UNONAME_ISGROUP )
+ aRet <<= hasGroupInfo();
+ else if ( aPropertyName == SC_UNONAME_GROUPINFO )
+ {
+ aRet <<= getGroupInfo();
+ }
+ else if ( aPropertyName == SC_UNONAME_SHOWEMPTY )
+ aRet <<= getShowEmpty();
+ else if ( aPropertyName == SC_UNONAME_REPEATITEMLABELS )
+ aRet <<= getRepeatItemLabels();
+ else if (aPropertyName == SC_UNONAME_NAME)
+ aRet <<= getName();
+
+ return aRet;
+}
+
+// XDatePilotField
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotFieldObj::getItems()
+{
+ SolarMutexGuard aGuard;
+ if (!mxItems.is())
+ mxItems.set( new ScDataPilotItemsObj( *mxParent, maFieldId ) );
+ return mxItems;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDataPilotFieldObj )
+
+DataPilotFieldOrientation ScDataPilotFieldObj::getOrientation() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim ? pDim->GetOrientation() : DataPilotFieldOrientation_HIDDEN;
+}
+
+void ScDataPilotFieldObj::setOrientation(DataPilotFieldOrientation eNew)
+{
+ SolarMutexGuard aGuard;
+ if (maOrient.hasValue() && (eNew == maOrient.get< DataPilotFieldOrientation >()))
+ return;
+
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if(!pDim)
+ return;
+
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+
+ /* If the field was taken from getDataPilotFields(), don't reset the
+ orientation for an existing use, but create a duplicated field
+ instead (for "Data" orientation only). */
+ if ( !maOrient.hasValue() && !maFieldId.mbDataLayout &&
+ (pDim->GetOrientation() != DataPilotFieldOrientation_HIDDEN) &&
+ (eNew == DataPilotFieldOrientation_DATA) )
+ {
+
+ ScDPSaveDimension* pNewDim = nullptr;
+
+ // look for existing duplicate with orientation "hidden"
+
+ sal_Int32 nFound = 0;
+ const ScDPSaveData::DimsType& rDimensions = pSaveData->GetDimensions();
+ for (auto const& it : rDimensions)
+ {
+ if ( !it->IsDataLayout() && (it->GetName() == maFieldId.maFieldName) )
+ {
+ if ( it->GetOrientation() == DataPilotFieldOrientation_HIDDEN )
+ {
+ pNewDim = it.get(); // use this one
+ break;
+ }
+ else
+ ++nFound; // count existing non-hidden occurrences
+ }
+ }
+
+ if ( !pNewDim ) // if none found, create a new duplicated dimension
+ pNewDim = &pSaveData->DuplicateDimension( *pDim );
+
+ maFieldId.mnFieldIdx = nFound; // keep accessing the new one
+ pDim = pNewDim;
+ }
+
+ pDim->SetOrientation(eNew);
+
+ // move changed field behind all other fields (make it the last field in dimension)
+ pSaveData->SetPosition( pDim, pSaveData->GetDimensions().size() );
+
+ SetDPObject( pDPObj );
+
+ maOrient <<= eNew; // modifying the same object's orientation again doesn't create another duplicate
+}
+
+sal_Int16 ScDataPilotFieldObj::getFunction() const
+{
+ SolarMutexGuard aGuard;
+ sal_Int16 eRet = GeneralFunction2::NONE;
+ if( ScDPSaveDimension* pDim = GetDPDimension() )
+ {
+ if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
+ {
+ // for non-data fields, property Function is the subtotals
+ tools::Long nSubCount = pDim->GetSubTotalsCount();
+ if ( nSubCount > 0 )
+ eRet = static_cast<sal_Int16>(pDim->GetSubTotalFunc(0)); // always use the first one
+ // else keep NONE
+ }
+ else
+ eRet = static_cast<sal_Int16>(pDim->GetFunction());
+ }
+ return eRet;
+}
+
+void ScDataPilotFieldObj::setFunction(ScGeneralFunction eNewFunc)
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if(!pDim)
+ return;
+
+ if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
+ {
+ // for non-data fields, property Function is the subtotals
+ std::vector<ScGeneralFunction> nSubTotalFuncs;
+ if ( eNewFunc != ScGeneralFunction::NONE )
+ {
+ nSubTotalFuncs.push_back( eNewFunc );
+ }
+ pDim->SetSubTotals( std::move(nSubTotalFuncs) );
+ }
+ else
+ pDim->SetFunction( eNewFunc );
+ SetDPObject( pDPObj );
+}
+
+Sequence< sal_Int16 > ScDataPilotFieldObj::getSubtotals() const
+{
+ SolarMutexGuard aGuard;
+ Sequence< sal_Int16 > aRet;
+ if( ScDPSaveDimension* pDim = GetDPDimension() )
+ {
+ if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
+ {
+ // for non-data fields, property Functions is the sequence of subtotals
+ sal_Int32 nCount = static_cast< sal_Int32 >( pDim->GetSubTotalsCount() );
+ if ( nCount > 0 )
+ {
+ aRet.realloc( nCount );
+ auto pRet = aRet.getArray();
+ for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
+ pRet[ nIdx ] = static_cast<sal_Int16>(pDim->GetSubTotalFunc( nIdx ));
+ }
+ }
+ }
+ return aRet;
+}
+
+void ScDataPilotFieldObj::setSubtotals( const std::vector< ScGeneralFunction >& rSubtotals )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if(!pDim)
+ return;
+
+ if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
+ {
+ sal_Int32 nCount = rSubtotals.size();
+ if( nCount == 1 )
+ {
+ // count 1: all values are allowed (including NONE and AUTO)
+ std::vector<ScGeneralFunction> nTmpFuncs;
+ if( rSubtotals[ 0 ] != ScGeneralFunction::NONE )
+ {
+ nTmpFuncs.push_back( rSubtotals[ 0 ] );
+ }
+ pDim->SetSubTotals( std::move(nTmpFuncs) );
+ }
+ else if( nCount > 1 )
+ {
+ // set multiple functions, ignore NONE and AUTO in this case
+ ::std::vector< ScGeneralFunction > aSubt;
+ for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
+ {
+ ScGeneralFunction eFunc = rSubtotals[ nIdx ];
+ if( (eFunc != ScGeneralFunction::NONE) && (eFunc != ScGeneralFunction::AUTO) )
+ {
+ // do not insert functions twice
+ if( ::std::find( aSubt.begin(), aSubt.end(), eFunc ) == aSubt.end() )
+ aSubt.push_back( eFunc );
+ }
+ }
+ // set values from vector to ScDPSaveDimension
+ pDim->SetSubTotals( std::move(aSubt) );
+ }
+ }
+ SetDPObject( pDPObj );
+}
+
+void ScDataPilotFieldObj::setCurrentPage( const OUString& rPage )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetCurrentPage( &rPage );
+ SetDPObject( pDPObj );
+ }
+}
+
+void ScDataPilotFieldObj::setUseCurrentPage( bool bUse )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if(!pDim)
+ return;
+
+ if( bUse )
+ {
+ /* It is somehow useless to set the property "HasSelectedPage" to
+ true, because it is still needed to set an explicit page name. */
+ const OUString aPage;
+ pDim->SetCurrentPage( &aPage );
+ }
+ else
+ pDim->SetCurrentPage( nullptr );
+ SetDPObject( pDPObj );
+}
+
+const DataPilotFieldAutoShowInfo* ScDataPilotFieldObj::getAutoShowInfo() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim ? pDim->GetAutoShowInfo() : nullptr;
+}
+
+void ScDataPilotFieldObj::setAutoShowInfo( const DataPilotFieldAutoShowInfo* pInfo )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetAutoShowInfo( pInfo );
+ SetDPObject( pDPObj );
+ }
+}
+
+const DataPilotFieldLayoutInfo* ScDataPilotFieldObj::getLayoutInfo() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim ? pDim->GetLayoutInfo() : nullptr;
+}
+
+void ScDataPilotFieldObj::setLayoutInfo( const DataPilotFieldLayoutInfo* pInfo )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetLayoutInfo( pInfo );
+ SetDPObject( pDPObj );
+ }
+}
+
+const DataPilotFieldReference* ScDataPilotFieldObj::getReference() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim ? pDim->GetReferenceValue() : nullptr;
+}
+
+void ScDataPilotFieldObj::setReference( const DataPilotFieldReference* pInfo )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetReferenceValue( pInfo );
+ SetDPObject( pDPObj );
+ }
+}
+
+const DataPilotFieldSortInfo* ScDataPilotFieldObj::getSortInfo() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim ? pDim->GetSortInfo() : nullptr;
+}
+
+void ScDataPilotFieldObj::setSortInfo( const DataPilotFieldSortInfo* pInfo )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetSortInfo( pInfo );
+ SetDPObject( pDPObj );
+ }
+}
+
+bool ScDataPilotFieldObj::getShowEmpty() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim && pDim->GetShowEmpty();
+}
+
+void ScDataPilotFieldObj::setShowEmpty( bool bShow )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetShowEmpty( bShow );
+ SetDPObject( pDPObj );
+ }
+}
+
+bool ScDataPilotFieldObj::getRepeatItemLabels() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim && pDim->GetRepeatItemLabels();
+}
+
+void ScDataPilotFieldObj::setRepeatItemLabels( bool bShow )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetRepeatItemLabels( bShow );
+ SetDPObject( pDPObj );
+ }
+}
+
+bool ScDataPilotFieldObj::hasGroupInfo() const
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ if( const ScDPDimensionSaveData* pDimData = pDPObj->GetSaveData()->GetExistingDimensionData() )
+ return pDimData->GetNamedGroupDim( pDim->GetName() ) || pDimData->GetNumGroupDim( pDim->GetName() );
+ return false;
+}
+
+DataPilotFieldGroupInfo ScDataPilotFieldObj::getGroupInfo()
+{
+ SolarMutexGuard aGuard;
+ DataPilotFieldGroupInfo aInfo;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ if( const ScDPDimensionSaveData* pDimData = pDPObj->GetSaveData()->GetExistingDimensionData() )
+ {
+ if( const ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDim( pDim->GetName() ) )
+ {
+ // grouped by ...
+ aInfo.GroupBy = pGroupDim->GetDatePart();
+
+ // find source field
+ try
+ {
+ Reference< XNameAccess > xFields( mxParent->getDataPilotFields(), UNO_QUERY_THROW );
+ aInfo.SourceField.set( xFields->getByName( pGroupDim->GetSourceDimName() ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ }
+
+ ScDataPilotConversion::FillGroupInfo( aInfo, pGroupDim->GetDateInfo() );
+ if( pGroupDim->GetDatePart() == 0 )
+ {
+ // fill vector of group and group member information
+ ScFieldGroups aGroups;
+ for( sal_Int32 nIdx = 0, nCount = pGroupDim->GetGroupCount(); nIdx < nCount; ++nIdx )
+ {
+ const ScDPSaveGroupItem& rGroup = pGroupDim->GetGroupByIndex( nIdx );
+ ScFieldGroup aGroup;
+ aGroup.maName = rGroup.GetGroupName();
+ for( sal_Int32 nMemIdx = 0, nMemCount = rGroup.GetElementCount(); nMemIdx < nMemCount; ++nMemIdx )
+ if (const OUString* pMem = rGroup.GetElementByIndex(nMemIdx))
+ aGroup.maMembers.push_back( *pMem );
+ aGroups.push_back( aGroup );
+ }
+ aInfo.Groups = new ScDataPilotFieldGroupsObj( std::move(aGroups) );
+ }
+ }
+ else if( const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( pDim->GetName() ) )
+ {
+ if (pNumGroupDim->GetDatePart())
+ {
+ ScDataPilotConversion::FillGroupInfo( aInfo, pNumGroupDim->GetDateInfo() );
+ aInfo.GroupBy = pNumGroupDim->GetDatePart();
+ }
+ else
+ {
+ ScDataPilotConversion::FillGroupInfo( aInfo, pNumGroupDim->GetInfo() );
+ }
+ }
+ }
+ }
+ return aInfo;
+}
+
+void ScDataPilotFieldObj::setGroupInfo( const DataPilotFieldGroupInfo* pInfo )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( /*ScDPSaveDimension* pDim =*/ !GetDPDimension( &pDPObj ) )
+ return;
+
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ if( pInfo && lclCheckMinMaxStep( *pInfo ) )
+ {
+ ScDPNumGroupInfo aInfo;
+ aInfo.mbEnable = true;
+ aInfo.mbDateValues = pInfo->HasDateValues;
+ aInfo.mbAutoStart = pInfo->HasAutoStart;
+ aInfo.mbAutoEnd = pInfo->HasAutoEnd;
+ aInfo.mfStart = pInfo->Start;
+ aInfo.mfEnd = pInfo->End;
+ aInfo.mfStep = pInfo->Step;
+ Reference< XNamed > xNamed( pInfo->SourceField, UNO_QUERY );
+ if( xNamed.is() )
+ {
+ ScDPSaveGroupDimension aGroupDim( xNamed->getName(), getName() );
+ if( pInfo->GroupBy )
+ aGroupDim.SetDateInfo(aInfo, pInfo->GroupBy);
+ else
+ {
+ Reference<XIndexAccess> xIndex(pInfo->Groups, UNO_QUERY);
+ if (xIndex.is())
+ {
+ sal_Int32 nCount(xIndex->getCount());
+ for(sal_Int32 i = 0; i < nCount; i++)
+ {
+ Reference<XNamed> xGroupNamed(xIndex->getByIndex(i), UNO_QUERY);
+ if (xGroupNamed.is())
+ {
+ ScDPSaveGroupItem aItem(xGroupNamed->getName());
+ Reference<XIndexAccess> xGroupIndex(xGroupNamed, UNO_QUERY);
+ if (xGroupIndex.is())
+ {
+ sal_Int32 nItemCount(xGroupIndex->getCount());
+ for (sal_Int32 j = 0; j < nItemCount; ++j)
+ {
+ Reference<XNamed> xItemNamed(xGroupIndex->getByIndex(j), UNO_QUERY);
+ if (xItemNamed.is())
+ aItem.AddElement(xItemNamed->getName());
+ }
+ }
+ aGroupDim.AddGroupItem(aItem);
+ }
+ }
+ }
+ }
+
+ // get dimension savedata or create new if none
+ ScDPDimensionSaveData& rDimSaveData = *pSaveData->GetDimensionData();
+ rDimSaveData.ReplaceGroupDimension( aGroupDim );
+ }
+ else // no source field in group info -> numeric group
+ {
+ ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData(); // created if not there
+
+ ScDPSaveNumGroupDimension* pExisting = pDimData->GetNumGroupDimAcc( getName() );
+ if ( pExisting )
+ {
+ if (pInfo->GroupBy)
+ pExisting->SetDateInfo(aInfo, pInfo->GroupBy);
+ // modify existing group dimension
+ pExisting->SetGroupInfo( aInfo );
+ }
+ else if (pInfo->GroupBy)
+ {
+ // create new group dimension
+ ScDPSaveNumGroupDimension aNumGroupDim( getName(), aInfo, pInfo->GroupBy );
+ pDimData->AddNumGroupDimension( aNumGroupDim );
+ }
+ else
+ {
+ // create new group dimension
+ ScDPSaveNumGroupDimension aNumGroupDim( getName(), aInfo );
+ pDimData->AddNumGroupDimension( aNumGroupDim );
+ }
+ }
+ }
+ else // null passed as argument
+ {
+ pSaveData->SetDimensionData( nullptr );
+ }
+
+ pDPObj->SetSaveData( *pSaveData );
+ SetDPObject( pDPObj );
+}
+
+// XDataPilotFieldGrouping
+Reference< XDataPilotField > SAL_CALL ScDataPilotFieldObj::createNameGroup( const Sequence< OUString >& rItems )
+{
+ SolarMutexGuard aGuard;
+
+ if( !rItems.hasElements() )
+ throw IllegalArgumentException("rItems is empty", getXWeak(), 0);
+
+ Reference< XMembersAccess > xMembers = GetMembers();
+ if (!xMembers.is())
+ {
+ SAL_WARN("sc.ui", "Cannot access members of the field object.");
+ throw RuntimeException("Cannot access members of the field object", getXWeak());
+ }
+
+ for (const OUString& aEntryName : rItems)
+ {
+ if (!xMembers->hasByName(aEntryName))
+ {
+ SAL_WARN("sc.ui", "There is no member with that name: " + aEntryName + ".");
+ throw IllegalArgumentException("There is no member with name \"" + aEntryName + "\"", getXWeak(), 0);
+ }
+ }
+
+ Reference< XDataPilotField > xRet;
+ OUString sNewDim;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ const OUString& aDimName = pDim->GetName();
+
+ ScDPSaveData aSaveData = *pDPObj->GetSaveData();
+ ScDPDimensionSaveData* pDimData = aSaveData.GetDimensionData(); // created if not there
+
+ // find original base
+ OUString aBaseDimName( aDimName );
+ const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName );
+ if ( pBaseGroupDim )
+ {
+ // any entry's SourceDimName is the original base
+ aBaseDimName = pBaseGroupDim->GetSourceDimName();
+ }
+
+ // find existing group dimension
+ // (using the selected dim, can be intermediate group dim)
+ ScDPSaveGroupDimension* pGroupDimension = pDimData->GetGroupDimAccForBase( aDimName );
+
+ // remove the selected items from their groups
+ // (empty groups are removed, too)
+ if ( pGroupDimension )
+ {
+ for (const OUString& aEntryName : rItems)
+ {
+ if ( pBaseGroupDim )
+ {
+ // for each selected (intermediate) group, remove all its items
+ // (same logic as for adding, below)
+ const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
+ if ( pBaseGroup )
+ pBaseGroup->RemoveElementsFromGroups( *pGroupDimension ); // remove all elements
+ else
+ pGroupDimension->RemoveFromGroups( aEntryName );
+ }
+ else
+ pGroupDimension->RemoveFromGroups( aEntryName );
+ }
+ }
+
+ std::unique_ptr<ScDPSaveGroupDimension> pNewGroupDim;
+ if ( !pGroupDimension )
+ {
+ // create a new group dimension
+ sNewDim = pDimData->CreateGroupDimName( aBaseDimName, *pDPObj, false, nullptr );
+ pNewGroupDim.reset(new ScDPSaveGroupDimension( aBaseDimName, sNewDim ));
+
+ pGroupDimension = pNewGroupDim.get(); // make changes to the new dim if none existed
+
+ if ( pBaseGroupDim )
+ {
+ // If it's a higher-order group dimension, pre-allocate groups for all
+ // non-selected original groups, so the individual base members aren't
+ // used for automatic groups (this would make the original groups hard
+ // to find).
+ //! Also do this when removing groups?
+ //! Handle this case dynamically with automatic groups?
+
+ tools::Long nGroupCount = pBaseGroupDim->GetGroupCount();
+ for ( tools::Long nGroup = 0; nGroup < nGroupCount; nGroup++ )
+ {
+ const ScDPSaveGroupItem& rBaseGroup = pBaseGroupDim->GetGroupByIndex( nGroup );
+
+ if (comphelper::findValue(rItems, rBaseGroup.GetGroupName()) == -1) //! ignore case?
+ {
+ // add an additional group for each item that is not in the selection
+ ScDPSaveGroupItem aGroup( rBaseGroup.GetGroupName() );
+ aGroup.AddElementsFromGroup( rBaseGroup );
+ pGroupDimension->AddGroupItem( aGroup );
+ }
+ }
+ }
+ }
+ OUString aGroupDimName = pGroupDimension->GetGroupDimName();
+
+ OUString aGroupName = pGroupDimension->CreateGroupName( ScResId(STR_PIVOT_GROUP) );
+ ScDPSaveGroupItem aGroup( aGroupName );
+ for (const OUString& aEntryName : rItems)
+ {
+ if ( pBaseGroupDim )
+ {
+ // for each selected (intermediate) group, add all its items
+ const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
+ if ( pBaseGroup )
+ aGroup.AddElementsFromGroup( *pBaseGroup );
+ else
+ aGroup.AddElement( aEntryName ); // no group found -> automatic group, add the item itself
+ }
+ else
+ aGroup.AddElement( aEntryName ); // no group dimension, add all items directly
+ }
+
+ pGroupDimension->AddGroupItem( aGroup );
+
+ if ( pNewGroupDim )
+ {
+ pDimData->AddGroupDimension( *pNewGroupDim );
+ pNewGroupDim.reset(); // AddGroupDimension copies the object
+ // don't access pGroupDimension after here
+ }
+ pGroupDimension = nullptr;
+
+ // set orientation
+ ScDPSaveDimension* pSaveDimension = aSaveData.GetDimensionByName( aGroupDimName );
+ if ( pSaveDimension->GetOrientation() == DataPilotFieldOrientation_HIDDEN )
+ {
+ ScDPSaveDimension* pOldDimension = aSaveData.GetDimensionByName( aDimName );
+ pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
+ aSaveData.SetPosition( pSaveDimension, 0 ); //! before (immediate) base
+ }
+
+ // apply changes
+ pDPObj->SetSaveData( aSaveData );
+ ScDBDocFunc(*GetDocShell()).RefreshPivotTableGroups(pDPObj);
+ }
+
+ // if new grouping field has been created (on first group), return it
+ if( !sNewDim.isEmpty() )
+ {
+ Reference< XNameAccess > xFields(mxParent->getDataPilotFields(), UNO_QUERY);
+ if (xFields.is())
+ {
+ try
+ {
+ xRet.set(xFields->getByName(sNewDim), UNO_QUERY);
+ SAL_WARN_IF(!xRet.is(), "sc.ui", "there is a name, so there should be also a field");
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ SAL_WARN("sc.ui", "Cannot find field with that name: " + sNewDim + ".");
+ // Avoid throwing exception that's not specified in the method signature.
+ throw css::lang::WrappedTargetRuntimeException(
+ "Cannot find field with name \"" + sNewDim + "\"",
+ getXWeak(), anyEx );
+ }
+ }
+ }
+ return xRet;
+}
+
+Reference < XDataPilotField > SAL_CALL ScDataPilotFieldObj::createDateGroup( const DataPilotFieldGroupInfo& rInfo )
+{
+ SolarMutexGuard aGuard;
+ using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
+
+ if( !rInfo.HasDateValues )
+ throw IllegalArgumentException("HasDateValues is not set", getXWeak(), 0);
+ if( !lclCheckMinMaxStep( rInfo ) )
+ throw IllegalArgumentException("min/max/step", getXWeak(), 0);
+
+ // only a single date flag is allowed
+ if( (rInfo.GroupBy == 0) || (rInfo.GroupBy > YEARS) || ((rInfo.GroupBy & (rInfo.GroupBy - 1)) != 0) )
+ throw IllegalArgumentException("Invalid GroupBy value: " + OUString::number(rInfo.GroupBy), getXWeak(), 0);
+
+ // step must be zero, if something else than DAYS is specified
+ if( rInfo.Step >= ((rInfo.GroupBy == DAYS) ? 32768.0 : 1.0) )
+ throw IllegalArgumentException("Invalid step value: " + OUString::number(rInfo.Step), getXWeak(), 0);
+
+ OUString aGroupDimName;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ ScDPNumGroupInfo aInfo;
+ aInfo.mbEnable = true;
+ aInfo.mbDateValues = (rInfo.GroupBy == DAYS) && (rInfo.Step >= 1.0);
+ aInfo.mbAutoStart = rInfo.HasAutoStart;
+ aInfo.mbAutoEnd = rInfo.HasAutoEnd;
+ aInfo.mfStart = rInfo.Start;
+ aInfo.mfEnd = rInfo.End;
+ aInfo.mfStep = std::trunc( rInfo.Step );
+
+ // create a local copy of the entire save data (will be written back below)
+ ScDPSaveData aSaveData = *pDPObj->GetSaveData();
+ // get or create dimension save data
+ ScDPDimensionSaveData& rDimData = *aSaveData.GetDimensionData();
+
+ // find source dimension name
+ const OUString& rDimName = pDim->GetName();
+ const ScDPSaveGroupDimension* pGroupDim = rDimData.GetNamedGroupDim( rDimName );
+ OUString aSrcDimName = pGroupDim ? pGroupDim->GetSourceDimName() : rDimName;
+
+ // find a group dimension for the base field, or get numeric grouping
+ pGroupDim = rDimData.GetFirstNamedGroupDim( aSrcDimName );
+ const ScDPSaveNumGroupDimension* pNumGroupDim = rDimData.GetNumGroupDim( aSrcDimName );
+
+ // do not group by dates, if named groups or numeric grouping is present
+ bool bHasNamedGrouping = pGroupDim && !pGroupDim->GetDateInfo().mbEnable;
+ bool bHasNumGrouping = pNumGroupDim && pNumGroupDim->GetInfo().mbEnable && !pNumGroupDim->GetInfo().mbDateValues && !pNumGroupDim->GetDateInfo().mbEnable;
+ if( bHasNamedGrouping || bHasNumGrouping )
+ throw IllegalArgumentException();
+
+ if( aInfo.mbDateValues ) // create day ranges grouping
+ {
+ // first remove all named group dimensions
+ while( pGroupDim )
+ {
+ OUString aGroupDimName2 = pGroupDim->GetGroupDimName();
+ // find next group dimension before deleting this group
+ pGroupDim = rDimData.GetNextNamedGroupDim( aGroupDimName2 );
+ // remove from dimension save data
+ rDimData.RemoveGroupDimension( aGroupDimName2 );
+ // also remove save data settings for the dimension that no longer exists
+ aSaveData.RemoveDimensionByName( aGroupDimName2 );
+ }
+ // create or replace the number grouping dimension
+ ScDPSaveNumGroupDimension aNumGroupDim( aSrcDimName, aInfo );
+ rDimData.ReplaceNumGroupDimension( aNumGroupDim );
+ }
+ else // create date grouping
+ {
+ // collect all existing date flags
+ sal_Int32 nDateParts = rDimData.CollectDateParts( aSrcDimName );
+ if( nDateParts == 0 )
+ {
+ // insert numeric group dimension, if no date groups exist yet (or replace day range grouping)
+ ScDPSaveNumGroupDimension aNumGroupDim( aSrcDimName, aInfo, rInfo.GroupBy );
+ rDimData.ReplaceNumGroupDimension( aNumGroupDim );
+ }
+ else if( (nDateParts & rInfo.GroupBy) == 0 ) // do nothing if date field exists already
+ {
+ // create new named group dimension for additional date groups
+ aGroupDimName = rDimData.CreateDateGroupDimName( rInfo.GroupBy, *pDPObj, true, nullptr );
+ ScDPSaveGroupDimension aGroupDim( aSrcDimName, aGroupDimName, aInfo, rInfo.GroupBy );
+ rDimData.AddGroupDimension( aGroupDim );
+
+ // set orientation of new named group dimension
+ ScDPSaveDimension& rSaveDim = *aSaveData.GetDimensionByName( aGroupDimName );
+ if( rSaveDim.GetOrientation() == DataPilotFieldOrientation_HIDDEN )
+ {
+ ScDPSaveDimension& rOldDim = *aSaveData.GetDimensionByName( aSrcDimName );
+ rSaveDim.SetOrientation( rOldDim.GetOrientation() );
+ aSaveData.SetPosition( &rSaveDim, 0 ); //! before (immediate) base
+ }
+ }
+ }
+
+ // apply changes
+ pDPObj->SetSaveData( aSaveData );
+ ScDBDocFunc(*GetDocShell()).RefreshPivotTableGroups(pDPObj);
+ }
+
+ // return the UNO object of the new dimension, after writing back saved data
+ Reference< XDataPilotField > xRet;
+ if( !aGroupDimName.isEmpty() )
+ try
+ {
+ Reference< XNameAccess > xFields( mxParent->getDataPilotFields(), UNO_QUERY_THROW );
+ xRet.set( xFields->getByName( aGroupDimName ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ }
+ return xRet;
+}
+
+namespace {
+
+bool lclExtractGroupMembers( ScFieldGroupMembers& rMembers, const Any& rElement )
+{
+ // allow empty value to create a new group
+ if( !rElement.hasValue() )
+ return true;
+
+ // try to extract a simple sequence of strings
+ Sequence< OUString > aSeq;
+ if( rElement >>= aSeq )
+ {
+ if( aSeq.hasElements() )
+ rMembers.insert( rMembers.end(), std::cbegin(aSeq), std::cend(aSeq) );
+ return true;
+ }
+
+ // try to use XIndexAccess providing objects that support XNamed
+ Reference< XIndexAccess > xItemsIA( rElement, UNO_QUERY );
+ if( xItemsIA.is() )
+ {
+ for( sal_Int32 nIdx = 0, nCount = xItemsIA->getCount(); nIdx < nCount; ++nIdx )
+ {
+ try // getByIndex() should not throw, but we cannot be sure
+ {
+ Reference< XNamed > xItemName( xItemsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
+ rMembers.push_back( xItemName->getName() );
+ }
+ catch( Exception& )
+ {
+ // ignore exceptions, go ahead with next element in the array
+ }
+ }
+ return true;
+ }
+
+ // nothing valid inside the Any -> return false
+ return false;
+}
+
+} // namespace
+
+ScDataPilotFieldGroupsObj::ScDataPilotFieldGroupsObj( ScFieldGroups&& rGroups ) :
+ maGroups( std::move(rGroups) )
+{
+}
+
+ScDataPilotFieldGroupsObj::~ScDataPilotFieldGroupsObj()
+{
+}
+
+// XNameAccess
+
+Any SAL_CALL ScDataPilotFieldGroupsObj::getByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ if( implFindByName( rName ) == maGroups.end() )
+ throw NoSuchElementException();
+ return Any( Reference< XNameAccess >( new ScDataPilotFieldGroupObj( *this, rName ) ) );
+}
+
+Sequence< OUString > SAL_CALL ScDataPilotFieldGroupsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ Sequence< OUString > aSeq;
+ if( !maGroups.empty() )
+ {
+ aSeq.realloc( static_cast< sal_Int32 >( maGroups.size() ) );
+ OUString* pName = aSeq.getArray();
+ for( const auto& rGroup : maGroups )
+ {
+ *pName = rGroup.maName;
+ ++pName;
+ }
+ }
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldGroupsObj::hasByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ return implFindByName( rName ) != maGroups.end();
+}
+
+// XNameReplace
+
+void SAL_CALL ScDataPilotFieldGroupsObj::replaceByName( const OUString& rName, const Any& rElement )
+{
+ SolarMutexGuard aGuard;
+
+ if( rName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", getXWeak(), 0);
+
+ ScFieldGroups::iterator aIt = implFindByName( rName );
+ if( aIt == maGroups.end() )
+ throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
+
+ // read all item names provided by the passed object
+ ScFieldGroupMembers aMembers;
+ if( !lclExtractGroupMembers( aMembers, rElement ) )
+ throw IllegalArgumentException("Invalid element object", getXWeak(), 0);
+
+ // copy and forget, faster than vector assignment
+ aIt->maMembers.swap( aMembers );
+}
+
+// XNameContainer
+
+void SAL_CALL ScDataPilotFieldGroupsObj::insertByName( const OUString& rName, const Any& rElement )
+{
+ SolarMutexGuard aGuard;
+
+ if( rName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", getXWeak(), 0);
+
+ ScFieldGroups::iterator aIt = implFindByName( rName );
+ if( aIt != maGroups.end() )
+ throw ElementExistException("Name \"" + rName + "\" already exists", getXWeak());
+
+ // read all item names provided by the passed object
+ ScFieldGroupMembers aMembers;
+ if( !lclExtractGroupMembers( aMembers, rElement ) )
+ throw IllegalArgumentException("Invalid element object", getXWeak(), 0);
+
+ // create the new entry if no error has been occurred
+ maGroups.emplace_back();
+ ScFieldGroup& rGroup = maGroups.back();
+ rGroup.maName = rName;
+ rGroup.maMembers.swap( aMembers );
+}
+
+void SAL_CALL ScDataPilotFieldGroupsObj::removeByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+
+ if( rName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", getXWeak(), 0);
+
+ ScFieldGroups::iterator aIt = implFindByName( rName );
+ if( aIt == maGroups.end() )
+ throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
+
+ maGroups.erase( aIt );
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDataPilotFieldGroupsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return static_cast< sal_Int32 >( maGroups.size() );
+}
+
+Any SAL_CALL ScDataPilotFieldGroupsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ if ((nIndex < 0) || (o3tl::make_unsigned(nIndex) >= maGroups.size()))
+ throw IndexOutOfBoundsException();
+ return Any( Reference< XNameAccess >( new ScDataPilotFieldGroupObj( *this, maGroups[ nIndex ].maName ) ) );
+}
+
+// XEnumerationAccess
+
+Reference<XEnumeration> SAL_CALL ScDataPilotFieldGroupsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration( this, "com.sun.star.sheet.DataPilotFieldGroupsEnumeration" );
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScDataPilotFieldGroupsObj::getElementType()
+{
+ return cppu::UnoType<XNameAccess>::get();
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldGroupsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return !maGroups.empty();
+}
+
+// implementation
+
+ScFieldGroup& ScDataPilotFieldGroupsObj::getFieldGroup( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ ScFieldGroups::iterator aIt = implFindByName( rName );
+ if( aIt == maGroups.end() )
+ throw RuntimeException("Field Group with name \"" + rName + "\" not found", getXWeak());
+ return *aIt;
+}
+
+void ScDataPilotFieldGroupsObj::renameFieldGroup( const OUString& rOldName, const OUString& rNewName )
+{
+ SolarMutexGuard aGuard;
+ ScFieldGroups::iterator aOldIt = implFindByName( rOldName );
+ ScFieldGroups::iterator aNewIt = implFindByName( rNewName );
+ if( aOldIt == maGroups.end() )
+ throw RuntimeException("Field Group with name \"" + rOldName + "\" not found", getXWeak());
+ // new name must not exist yet
+ if( (aNewIt != maGroups.end()) && (aNewIt != aOldIt) )
+ throw RuntimeException("Field Group with name \"" + rOldName + "\" already exists", getXWeak());
+ aOldIt->maName = rNewName;
+}
+
+ScFieldGroups::iterator ScDataPilotFieldGroupsObj::implFindByName( const OUString& rName )
+{
+ return std::find_if(maGroups.begin(), maGroups.end(),
+ [&rName](const ScFieldGroup& rGroup) { return rGroup.maName == rName; });
+}
+
+namespace {
+
+OUString lclExtractMember( const Any& rElement )
+{
+ if( rElement.has< OUString >() )
+ return rElement.get< OUString >();
+
+ Reference< XNamed > xNamed( rElement, UNO_QUERY );
+ if( xNamed.is() )
+ return xNamed->getName();
+
+ return OUString();
+}
+
+} // namespace
+
+ScDataPilotFieldGroupObj::ScDataPilotFieldGroupObj( ScDataPilotFieldGroupsObj& rParent, OUString aGroupName ) :
+ mxParent( &rParent ),
+ maGroupName(std::move( aGroupName ))
+{
+}
+
+ScDataPilotFieldGroupObj::~ScDataPilotFieldGroupObj()
+{
+}
+
+// XNameAccess
+
+Any SAL_CALL ScDataPilotFieldGroupObj::getByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
+ if( aIt == rMembers.end() )
+ throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
+ return Any( Reference< XNamed >( new ScDataPilotFieldGroupItemObj( *this, *aIt ) ) );
+}
+
+Sequence< OUString > SAL_CALL ScDataPilotFieldGroupObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ return ::comphelper::containerToSequence( mxParent->getFieldGroup( maGroupName ).maMembers );
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldGroupObj::hasByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ return ::std::find( rMembers.begin(), rMembers.end(), rName ) != rMembers.end();
+}
+
+// XNameReplace
+
+void SAL_CALL ScDataPilotFieldGroupObj::replaceByName( const OUString& rName, const Any& rElement )
+{
+ SolarMutexGuard aGuard;
+
+ // it should be possible to quickly rename an item -> accept string or XNamed
+ OUString aNewName = lclExtractMember( rElement );
+ if( rName.isEmpty() || aNewName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", getXWeak(), 0);
+ if( rName == aNewName )
+ return;
+
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ ScFieldGroupMembers::iterator aOldIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
+ ScFieldGroupMembers::iterator aNewIt = ::std::find( rMembers.begin(), rMembers.end(), aNewName );
+ if( aOldIt == rMembers.end() )
+ throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
+ if( aNewIt != rMembers.end() )
+ throw IllegalArgumentException("Name \"" + rName + "\" already exists", getXWeak(), 0);
+ *aOldIt = aNewName;
+}
+
+// XNameContainer
+
+void SAL_CALL ScDataPilotFieldGroupObj::insertByName( const OUString& rName, const Any& /*rElement*/ )
+{
+ SolarMutexGuard aGuard;
+
+ // we will ignore the passed element and just try to insert the name
+ if( rName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", getXWeak(), 0);
+
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
+ if( aIt != rMembers.end() )
+ throw IllegalArgumentException("Name \"" + rName + "\" already exists", getXWeak(), 0);
+ rMembers.push_back( rName );
+}
+
+void SAL_CALL ScDataPilotFieldGroupObj::removeByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+
+ if( rName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", getXWeak(), 0);
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
+ if( aIt == rMembers.end() )
+ throw NoSuchElementException("Name \"" + rName + "\" not found", getXWeak());
+ rMembers.erase( aIt );
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDataPilotFieldGroupObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return static_cast< sal_Int32 >( mxParent->getFieldGroup( maGroupName ).maMembers.size() );
+}
+
+Any SAL_CALL ScDataPilotFieldGroupObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ if ((nIndex < 0) || (o3tl::make_unsigned(nIndex) >= rMembers.size()))
+ throw IndexOutOfBoundsException();
+ return Any( Reference< XNamed >( new ScDataPilotFieldGroupItemObj( *this, rMembers[ nIndex ] ) ) );
+}
+
+// XEnumerationAccess
+
+Reference< XEnumeration > SAL_CALL ScDataPilotFieldGroupObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration( this, "com.sun.star.sheet.DataPilotFieldGroupEnumeration" );
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScDataPilotFieldGroupObj::getElementType()
+{
+ return cppu::UnoType<XNamed>::get();
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldGroupObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return !mxParent->getFieldGroup( maGroupName ).maMembers.empty();
+}
+
+// XNamed
+
+OUString SAL_CALL ScDataPilotFieldGroupObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return maGroupName;
+}
+
+void SAL_CALL ScDataPilotFieldGroupObj::setName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ mxParent->renameFieldGroup( maGroupName, rName );
+ // if call to renameFieldGroup() did not throw, remember the new name
+ maGroupName = rName;
+}
+
+ScDataPilotFieldGroupItemObj::ScDataPilotFieldGroupItemObj( ScDataPilotFieldGroupObj& rParent, OUString aName ) :
+ mxParent( &rParent ),
+ maName(std::move( aName ))
+{
+}
+
+ScDataPilotFieldGroupItemObj::~ScDataPilotFieldGroupItemObj()
+{
+}
+
+// XNamed
+
+OUString SAL_CALL ScDataPilotFieldGroupItemObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return maName;
+}
+
+void SAL_CALL ScDataPilotFieldGroupItemObj::setName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ mxParent->replaceByName( maName, Any( rName ) );
+ // if call to replaceByName() did not throw, remember the new name
+ maName = rName;
+}
+
+ScDataPilotItemsObj::ScDataPilotItemsObj( ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId ) :
+ ScDataPilotChildObjBase( rParent, rFieldId )
+{
+}
+
+ScDataPilotItemsObj::~ScDataPilotItemsObj()
+{
+}
+
+// XDataPilotItems
+
+ScDataPilotItemObj* ScDataPilotItemsObj::GetObjectByIndex_Impl( sal_Int32 nIndex ) const
+{
+ return ((0 <= nIndex) && (nIndex < GetMemberCount())) ?
+ new ScDataPilotItemObj( *mxParent, maFieldId, nIndex ) : nullptr;
+}
+
+// XNameAccess
+
+Any SAL_CALL ScDataPilotItemsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ Reference<XNameAccess> xMembers = GetMembers();
+ if (xMembers.is())
+ {
+ Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
+ sal_Int32 nCount = xMembersIndex->getCount();
+ sal_Int32 nItem = 0;
+ while (nItem < nCount)
+ {
+ Reference<XNamed> xMember(xMembersIndex->getByIndex(nItem), UNO_QUERY);
+ if (xMember.is() && (aName == xMember->getName()))
+ {
+ return Any( Reference< XPropertySet >( GetObjectByIndex_Impl( nItem ) ) );
+ }
+ ++nItem;
+ }
+ throw NoSuchElementException("Name \"" + aName + "\" not found", getXWeak());
+ }
+ return Any();
+}
+
+Sequence<OUString> SAL_CALL ScDataPilotItemsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ Sequence< OUString > aSeq;
+ if( ScDPObject* pDPObj = GetDPObject() )
+ pDPObj->GetMemberNames( lcl_GetObjectIndex( pDPObj, maFieldId ), aSeq );
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScDataPilotItemsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bFound = false;
+ Reference<XNameAccess> xMembers = GetMembers();
+ if (xMembers.is())
+ {
+ Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
+ sal_Int32 nCount = xMembersIndex->getCount();
+ sal_Int32 nItem = 0;
+ while (nItem < nCount && !bFound )
+ {
+ Reference<XNamed> xMember(xMembersIndex->getByIndex(nItem), UNO_QUERY);
+ if (xMember.is() && aName == xMember->getName())
+ bFound = true;
+ else
+ nItem++;
+ }
+ }
+ return bFound;
+}
+
+// XEnumerationAccess
+
+Reference<XEnumeration> SAL_CALL ScDataPilotItemsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.DataPilotItemsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDataPilotItemsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return GetMemberCount();
+}
+
+Any SAL_CALL ScDataPilotItemsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ Reference< XPropertySet > xItem( GetObjectByIndex_Impl( nIndex ) );
+ if (!xItem.is())
+ throw IndexOutOfBoundsException();
+ return Any( xItem );
+}
+
+uno::Type SAL_CALL ScDataPilotItemsObj::getElementType()
+{
+ return cppu::UnoType<XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL ScDataPilotItemsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+ScDataPilotItemObj::ScDataPilotItemObj( ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId, sal_Int32 nIndex ) :
+ ScDataPilotChildObjBase( rParent, rFieldId ),
+ maPropSet( lcl_GetDataPilotItemMap() ),
+ mnIndex( nIndex )
+{
+}
+
+ScDataPilotItemObj::~ScDataPilotItemObj()
+{
+}
+
+ // XNamed
+OUString SAL_CALL ScDataPilotItemObj::getName()
+{
+ SolarMutexGuard aGuard;
+ OUString sRet;
+ Reference<XNameAccess> xMembers = GetMembers();
+ if (xMembers.is())
+ {
+ Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
+ sal_Int32 nCount = xMembersIndex->getCount();
+ if (mnIndex < nCount)
+ {
+ Reference<XNamed> xMember(xMembersIndex->getByIndex(mnIndex), UNO_QUERY);
+ sRet = xMember->getName();
+ }
+ }
+ return sRet;
+}
+
+void SAL_CALL ScDataPilotItemObj::setName( const OUString& /* aName */ )
+{
+}
+
+ // XPropertySet
+Reference< XPropertySetInfo >
+ SAL_CALL ScDataPilotItemObj::getPropertySetInfo( )
+{
+ SolarMutexGuard aGuard;
+ static Reference<XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL ScDataPilotItemObj::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if(!pDim)
+ return;
+
+ Reference<XNameAccess> xMembers = GetMembers();
+ if( !xMembers.is() )
+ return;
+
+ Reference<XIndexAccess> xMembersIndex( new ScNameToIndexAccess( xMembers ) );
+ sal_Int32 nCount = xMembersIndex->getCount();
+ if( mnIndex >= nCount )
+ return;
+
+ Reference<XNamed> xMember(xMembersIndex->getByIndex(mnIndex), UNO_QUERY);
+ OUString sName(xMember->getName());
+ ScDPSaveMember* pMember = pDim->GetMemberByName(sName);
+ if (!pMember)
+ return;
+
+ bool bGetNewIndex = false;
+ if ( aPropertyName == SC_UNONAME_SHOWDETAIL )
+ pMember->SetShowDetails(cppu::any2bool(aValue));
+ else if ( aPropertyName == SC_UNONAME_ISHIDDEN )
+ pMember->SetIsVisible(!cppu::any2bool(aValue));
+ else if ( aPropertyName == SC_UNONAME_POS )
+ {
+ sal_Int32 nNewPos = 0;
+ if ( !( aValue >>= nNewPos ) || nNewPos < 0 || nNewPos >= nCount )
+ throw IllegalArgumentException();
+
+ pDim->SetMemberPosition( sName, nNewPos );
+ // get new effective index (depends on sorting mode, which isn't modified)
+ bGetNewIndex = true;
+
+ }
+ SetDPObject( pDPObj );
+
+ if ( bGetNewIndex ) // after SetDPObject, get the new index
+ {
+ Sequence< OUString > aItemNames = xMembers->getElementNames();
+ sal_Int32 nItemCount = aItemNames.getLength();
+ for (sal_Int32 nItem=0; nItem<nItemCount; ++nItem)
+ if (aItemNames[nItem] == sName)
+ mnIndex = nItem;
+ }
+}
+
+Any SAL_CALL ScDataPilotItemObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ Any aRet;
+ if( ScDPSaveDimension* pDim = GetDPDimension() )
+ {
+ Reference< XNameAccess > xMembers = GetMembers();
+ if( xMembers.is() )
+ {
+ Reference< XIndexAccess > xMembersIndex( new ScNameToIndexAccess( xMembers ) );
+ sal_Int32 nCount = xMembersIndex->getCount();
+ if( mnIndex < nCount )
+ {
+ Reference< XNamed > xMember( xMembersIndex->getByIndex( mnIndex ), UNO_QUERY );
+ OUString sName( xMember->getName() );
+ ScDPSaveMember* pMember = pDim->GetExistingMemberByName( sName );
+ if ( aPropertyName == SC_UNONAME_SHOWDETAIL )
+ {
+ if (pMember && pMember->HasShowDetails())
+ {
+ aRet <<= pMember->GetShowDetails();
+ }
+ else
+ {
+ Reference< XPropertySet > xMemberProps( xMember, UNO_QUERY );
+ if( xMemberProps.is() )
+ aRet = xMemberProps->getPropertyValue( SC_UNO_DP_SHOWDETAILS );
+ else
+ aRet <<= true;
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_ISHIDDEN )
+ {
+ if (pMember && pMember->HasIsVisible())
+ {
+ aRet <<= !pMember->GetIsVisible();
+ }
+ else
+ {
+ Reference< XPropertySet > xMemberProps( xMember, UNO_QUERY );
+ if( xMemberProps.is() )
+ aRet <<= !cppu::any2bool( xMemberProps->getPropertyValue( SC_UNO_DP_ISVISIBLE ) );
+ else
+ aRet <<= false;
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_POS )
+ {
+ aRet <<= mnIndex;
+ }
+ }
+ }
+ }
+ return aRet;
+}
+
+void SAL_CALL ScDataPilotItemObj::addPropertyChangeListener(
+ const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* xListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotItemObj::removePropertyChangeListener(
+ const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* aListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotItemObj::addVetoableChangeListener(
+ const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotItemObj::removeVetoableChangeListener(
+ const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/datauno.cxx b/sc/source/ui/unoobj/datauno.cxx
new file mode 100644
index 0000000000..1bbd661a4f
--- /dev/null
+++ b/sc/source/ui/unoobj/datauno.cxx
@@ -0,0 +1,2384 @@
+/* -*- 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 <datauno.hxx>
+
+#include <svl/hint.hxx>
+#include <svl/numformat.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/util/SortField.hpp>
+#include <com/sun/star/table/TableSortField.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/table/TableOrientation.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <com/sun/star/sheet/DataImportMode.hpp>
+#include <com/sun/star/sheet/FilterFieldType.hpp>
+#include <com/sun/star/sheet/FilterOperator2.hpp>
+#include <com/sun/star/sheet/TableFilterField2.hpp>
+
+#include <dapiuno.hxx>
+#include <cellsuno.hxx>
+#include <miscuno.hxx>
+#include <targuno.hxx>
+#include <rangeutl.hxx>
+#include <dbdata.hxx>
+#include <docsh.hxx>
+#include <dbdocfun.hxx>
+#include <unonames.hxx>
+#include <globalnames.hxx>
+#include <convuno.hxx>
+#include <hints.hxx>
+#include <attrib.hxx>
+#include <dpshttab.hxx>
+#include <queryentry.hxx>
+#include <dputil.hxx>
+#include <sortparam.hxx>
+#include <dpobject.hxx>
+#include <filterentries.hxx>
+
+#include <comphelper/extract.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+
+#include <memory>
+
+using namespace com::sun::star;
+using namespace css::sheet;
+
+// everything without Which-ID, map only for PropertySetInfo
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetSubTotalPropertyMap()
+{
+ // some old property names are for 5.2 compatibility
+
+ static const SfxItemPropertyMapEntry aSubTotalPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_BINDFMT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_CASE, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ENABSORT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ENUSLIST, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_FORMATS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_INSBRK, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ISCASE, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_MAXFLD, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNONAME_SORTASC, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ULIST, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_UINDEX, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNONAME_USINDEX, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ };
+ return aSubTotalPropertyMap_Impl;
+}
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetFilterPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aFilterPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_CONTHDR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_COPYOUT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ISCASE, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_MAXFLD, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNONAME_ORIENT, 0, cppu::UnoType<table::TableOrientation>::get(), 0, 0},
+ { SC_UNONAME_OUTPOS, 0, cppu::UnoType<table::CellAddress>::get(), 0, 0},
+ { SC_UNONAME_SAVEOUT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_SKIPDUP, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_USEREGEX, 0, cppu::UnoType<bool>::get(), 0, 0},
+ };
+ return aFilterPropertyMap_Impl;
+}
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetDBRangePropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDBRangePropertyMap_Impl[] =
+ {
+ { SC_UNONAME_AUTOFLT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_FLTCRT, 0, cppu::UnoType<table::CellRangeAddress>::get(), 0, 0},
+ { SC_UNONAME_FROMSELECT,0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ISUSER, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_KEEPFORM, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_LINKDISPBIT, 0, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_LINKDISPNAME, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_MOVCELLS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_REFPERIOD, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNONAME_STRIPDAT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_TOKENINDEX,0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_USEFLTCRT,0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_TOTALSROW,0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_CONTHDR ,0, cppu::UnoType<bool>::get(), 0, 0},
+ };
+ return aDBRangePropertyMap_Impl;
+}
+
+SC_SIMPLE_SERVICE_INFO( ScConsolidationDescriptor, "ScConsolidationDescriptor", "com.sun.star.sheet.ConsolidationDescriptor" )
+SC_SIMPLE_SERVICE_INFO( ScDatabaseRangesObj, "ScDatabaseRangesObj", "com.sun.star.sheet.DatabaseRanges" )
+SC_SIMPLE_SERVICE_INFO( ScFilterDescriptorBase, "ScFilterDescriptorBase", "com.sun.star.sheet.SheetFilterDescriptor" )
+SC_SIMPLE_SERVICE_INFO( ScSubTotalDescriptorBase, "ScSubTotalDescriptorBase", "com.sun.star.sheet.SubTotalDescriptor" )
+SC_SIMPLE_SERVICE_INFO( ScSubTotalFieldObj, "ScSubTotalFieldObj", "com.sun.star.sheet.SubTotalField" )
+
+sheet::GeneralFunction ScDataUnoConversion::SubTotalToGeneral( ScSubTotalFunc eSubTotal )
+{
+ sheet::GeneralFunction eGeneral;
+ switch (eSubTotal)
+ {
+ case SUBTOTAL_FUNC_NONE: eGeneral = sheet::GeneralFunction_NONE; break;
+ case SUBTOTAL_FUNC_AVE: eGeneral = sheet::GeneralFunction_AVERAGE; break;
+ case SUBTOTAL_FUNC_CNT: eGeneral = sheet::GeneralFunction_COUNTNUMS; break;
+ case SUBTOTAL_FUNC_CNT2: eGeneral = sheet::GeneralFunction_COUNT; break;
+ case SUBTOTAL_FUNC_MAX: eGeneral = sheet::GeneralFunction_MAX; break;
+ case SUBTOTAL_FUNC_MIN: eGeneral = sheet::GeneralFunction_MIN; break;
+ case SUBTOTAL_FUNC_PROD: eGeneral = sheet::GeneralFunction_PRODUCT; break;
+ case SUBTOTAL_FUNC_STD: eGeneral = sheet::GeneralFunction_STDEV; break;
+ case SUBTOTAL_FUNC_STDP: eGeneral = sheet::GeneralFunction_STDEVP; break;
+ case SUBTOTAL_FUNC_SUM: eGeneral = sheet::GeneralFunction_SUM; break;
+ case SUBTOTAL_FUNC_VAR: eGeneral = sheet::GeneralFunction_VAR; break;
+ case SUBTOTAL_FUNC_VARP: eGeneral = sheet::GeneralFunction_VARP; break;
+ default:
+ OSL_FAIL("SubTotalToGeneral: wrong enum");
+ eGeneral = sheet::GeneralFunction_NONE;
+ break;
+ }
+ return eGeneral;
+}
+
+void ScImportDescriptor::FillProperties( uno::Sequence<beans::PropertyValue>& rSeq, const ScImportParam& rParam )
+{
+ OSL_ENSURE( rSeq.getLength() == GetPropertyCount(), "wrong Count" );
+
+ beans::PropertyValue* pArray = rSeq.getArray();
+
+ sheet::DataImportMode eMode = sheet::DataImportMode_NONE;
+ if ( rParam.bImport )
+ {
+ if ( rParam.bSql )
+ eMode = sheet::DataImportMode_SQL;
+ else if ( rParam.nType == ScDbQuery )
+ eMode = sheet::DataImportMode_QUERY;
+ else
+ eMode = sheet::DataImportMode_TABLE; // type always ScDbQuery or ScDbTable
+ }
+
+ svx::ODataAccessDescriptor aDescriptor;
+ aDescriptor.setDataSource(rParam.aDBName);
+ if (aDescriptor.has( svx::DataAccessDescriptorProperty::DataSource ))
+ {
+ pArray[0].Name = SC_UNONAME_DBNAME;
+ pArray[0].Value <<= rParam.aDBName;
+ }
+ else if (aDescriptor.has( svx::DataAccessDescriptorProperty::ConnectionResource ))
+ {
+ pArray[0].Name = SC_UNONAME_CONRES;
+ pArray[0].Value <<= rParam.aDBName;
+ }
+
+ pArray[1].Name = SC_UNONAME_SRCTYPE;
+ pArray[1].Value <<= eMode;
+
+ pArray[2].Name = SC_UNONAME_SRCOBJ;
+ pArray[2].Value <<= rParam.aStatement;
+
+ pArray[3].Name = SC_UNONAME_ISNATIVE;
+ pArray[3].Value <<= rParam.bNative;
+}
+
+void ScImportDescriptor::FillImportParam( ScImportParam& rParam, const uno::Sequence<beans::PropertyValue>& rSeq )
+{
+ OUString aStrVal;
+ for (const beans::PropertyValue& rProp : rSeq)
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == SC_UNONAME_ISNATIVE)
+ rParam.bNative = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_DBNAME)
+ {
+ if ( rProp.Value >>= aStrVal )
+ rParam.aDBName = aStrVal;
+ }
+ else if (aPropName == SC_UNONAME_CONRES)
+ {
+ if ( rProp.Value >>= aStrVal )
+ rParam.aDBName = aStrVal;
+ }
+ else if (aPropName == SC_UNONAME_SRCOBJ)
+ {
+ if ( rProp.Value >>= aStrVal )
+ rParam.aStatement = aStrVal;
+ }
+ else if (aPropName == SC_UNONAME_SRCTYPE)
+ {
+ //! test for correct enum type?
+ sheet::DataImportMode eMode = static_cast<sheet::DataImportMode>(ScUnoHelpFunctions::GetEnumFromAny( rProp.Value ));
+ switch (eMode)
+ {
+ case sheet::DataImportMode_NONE:
+ rParam.bImport = false;
+ break;
+ case sheet::DataImportMode_SQL:
+ rParam.bImport = true;
+ rParam.bSql = true;
+ break;
+ case sheet::DataImportMode_TABLE:
+ rParam.bImport = true;
+ rParam.bSql = false;
+ rParam.nType = ScDbTable;
+ break;
+ case sheet::DataImportMode_QUERY:
+ rParam.bImport = true;
+ rParam.bSql = false;
+ rParam.nType = ScDbQuery;
+ break;
+ default:
+ OSL_FAIL("wrong mode");
+ rParam.bImport = false;
+ }
+ }
+ }
+}
+
+void ScSortDescriptor::FillProperties( uno::Sequence<beans::PropertyValue>& rSeq, const ScSortParam& rParam )
+{
+ OSL_ENSURE( rSeq.getLength() == GetPropertyCount(), "wrong count" );
+
+ beans::PropertyValue* pArray = rSeq.getArray();
+
+ // gather Uno values together
+
+ table::CellAddress aOutPos;
+ aOutPos.Sheet = rParam.nDestTab;
+ aOutPos.Column = rParam.nDestCol;
+ aOutPos.Row = rParam.nDestRow;
+
+ sal_uInt16 nSortCount = 0;
+ while ( nSortCount < rParam.GetSortKeyCount() && rParam.maKeyState[nSortCount].bDoSort )
+ ++nSortCount;
+
+ uno::Sequence<table::TableSortField> aFields(nSortCount);
+ if (nSortCount)
+ {
+ table::TableSortField* pFieldArray = aFields.getArray();
+ for (sal_uInt16 i=0; i<nSortCount; i++)
+ {
+ pFieldArray[i].Field = rParam.maKeyState[i].nField;
+ pFieldArray[i].IsAscending = rParam.maKeyState[i].bAscending;
+ pFieldArray[i].FieldType = table::TableSortFieldType_AUTOMATIC; // always automatic
+ pFieldArray[i].IsCaseSensitive = rParam.bCaseSens;
+ pFieldArray[i].CollatorLocale = rParam.aCollatorLocale;
+ pFieldArray[i].CollatorAlgorithm = rParam.aCollatorAlgorithm;
+ }
+ }
+
+ // fill the sequence
+
+ pArray[0].Name = SC_UNONAME_ISSORTCOLUMNS;
+ pArray[0].Value <<= !rParam.bByRow;
+
+ pArray[1].Name = SC_UNONAME_CONTHDR;
+ pArray[1].Value <<= rParam.bHasHeader;
+
+ pArray[2].Name = SC_UNONAME_MAXFLD;
+ pArray[2].Value <<= static_cast<sal_Int32>( rParam.GetSortKeyCount() );
+
+ pArray[3].Name = SC_UNONAME_SORTFLD;
+ pArray[3].Value <<= aFields;
+
+ pArray[4].Name = SC_UNONAME_BINDFMT;
+ pArray[4].Value <<= rParam.aDataAreaExtras.mbCellFormats;
+
+ pArray[5].Name = SC_UNONAME_COPYOUT;
+ pArray[5].Value <<= !rParam.bInplace;
+
+ pArray[6].Name = SC_UNONAME_OUTPOS;
+ pArray[6].Value <<= aOutPos;
+
+ pArray[7].Name = SC_UNONAME_ISULIST;
+ pArray[7].Value <<= rParam.bUserDef;
+
+ pArray[8].Name = SC_UNONAME_UINDEX;
+ pArray[8].Value <<= static_cast<sal_Int32>( rParam.nUserIndex );
+}
+
+void ScSortDescriptor::FillSortParam( ScSortParam& rParam, const uno::Sequence<beans::PropertyValue>& rSeq )
+{
+ sal_Int32 nSortSize = static_cast<sal_Int32>(rParam.GetSortKeyCount());
+
+ for (const beans::PropertyValue& rProp : rSeq)
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == SC_UNONAME_ORIENT)
+ {
+ //! test for correct enum type?
+ table::TableOrientation eOrient = static_cast<table::TableOrientation>(ScUnoHelpFunctions::GetEnumFromAny( rProp.Value ));
+ rParam.bByRow = ( eOrient != table::TableOrientation_COLUMNS );
+ }
+ else if (aPropName == SC_UNONAME_ISSORTCOLUMNS)
+ {
+ rParam.bByRow = !::cppu::any2bool(rProp.Value);
+ }
+ else if (aPropName == SC_UNONAME_CONTHDR)
+ rParam.bHasHeader = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_MAXFLD)
+ {
+ sal_Int32 nVal;
+ if ( (rProp.Value >>= nVal) && nVal > nSortSize )
+ {
+ //! specify exceptions
+ //! throw lang::IllegalArgumentException();
+ }
+ }
+ else if (aPropName == SC_UNONAME_SORTFLD)
+ {
+ uno::Sequence<util::SortField> aSeq;
+ uno::Sequence<table::TableSortField> aNewSeq;
+ if ( rProp.Value >>= aSeq )
+ {
+ sal_Int32 nCount = aSeq.getLength();
+ sal_Int32 i;
+ if ( nCount > static_cast<sal_Int32>( rParam.GetSortKeyCount() ) )
+ {
+ // tdf#105301 - increase the size of the sorting keys
+ nSortSize = nCount;
+ rParam.maKeyState.resize(nCount);
+ }
+ const util::SortField* pFieldArray = aSeq.getConstArray();
+ for (i=0; i<nCount; i++)
+ {
+ rParam.maKeyState[i].nField = static_cast<SCCOLROW>( pFieldArray[i].Field );
+ rParam.maKeyState[i].bAscending = pFieldArray[i].SortAscending;
+
+ // FieldType is ignored
+ rParam.maKeyState[i].bDoSort = true;
+ }
+ for (i=nCount; i<nSortSize; i++)
+ rParam.maKeyState[i].bDoSort = false;
+ }
+ else if ( rProp.Value >>= aNewSeq )
+ {
+ sal_Int32 nCount = aNewSeq.getLength();
+ sal_Int32 i;
+ if ( nCount > nSortSize )
+ {
+ nCount = nSortSize;
+ rParam.maKeyState.resize(nCount);
+ }
+ const table::TableSortField* pFieldArray = aNewSeq.getConstArray();
+ for (i=0; i<nCount; i++)
+ {
+ rParam.maKeyState[i].nField = static_cast<SCCOLROW>( pFieldArray[i].Field );
+ rParam.maKeyState[i].bAscending = pFieldArray[i].IsAscending;
+
+ // only one is possible, sometime we should make it possible to have different for every entry
+ rParam.bCaseSens = pFieldArray[i].IsCaseSensitive;
+ rParam.aCollatorLocale = pFieldArray[i].CollatorLocale;
+ rParam.aCollatorAlgorithm = pFieldArray[i].CollatorAlgorithm;
+
+ // FieldType is ignored
+ rParam.maKeyState[i].bDoSort = true;
+ }
+ for (i=nCount; i<nSortSize; i++)
+ rParam.maKeyState[i].bDoSort = false;
+ }
+ }
+ else if (aPropName == SC_UNONAME_ISCASE)
+ {
+ rParam.bCaseSens = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ }
+ else if (aPropName == SC_UNONAME_BINDFMT)
+ rParam.aDataAreaExtras.mbCellFormats = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_COPYOUT)
+ rParam.bInplace = !ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_OUTPOS)
+ {
+ table::CellAddress aAddress;
+ if ( rProp.Value >>= aAddress )
+ {
+ rParam.nDestTab = aAddress.Sheet;
+ rParam.nDestCol = static_cast<SCCOL>(aAddress.Column);
+ rParam.nDestRow = static_cast<SCROW>(aAddress.Row);
+ }
+ }
+ else if (aPropName == SC_UNONAME_ISULIST)
+ rParam.bUserDef = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_UINDEX)
+ {
+ sal_Int32 nVal = 0;
+ if ( rProp.Value >>= nVal )
+ rParam.nUserIndex = static_cast<sal_uInt16>(nVal);
+ }
+ else if (aPropName == SC_UNONAME_COLLLOC)
+ {
+ rProp.Value >>= rParam.aCollatorLocale;
+ }
+ else if (aPropName == SC_UNONAME_COLLALG)
+ {
+ OUString sStr;
+ if ( rProp.Value >>= sStr )
+ rParam.aCollatorAlgorithm = sStr;
+ }
+ }
+}
+
+ScSubTotalFieldObj::ScSubTotalFieldObj( ScSubTotalDescriptorBase* pDesc, sal_uInt16 nP ) :
+ xParent( pDesc ),
+ nPos( nP )
+{
+ OSL_ENSURE(pDesc, "ScSubTotalFieldObj: Parent is 0");
+}
+
+ScSubTotalFieldObj::~ScSubTotalFieldObj()
+{
+}
+
+// XSubTotalField
+
+sal_Int32 SAL_CALL ScSubTotalFieldObj::getGroupColumn()
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ xParent->GetData(aParam);
+
+ return aParam.nField[nPos];
+}
+
+void SAL_CALL ScSubTotalFieldObj::setGroupColumn( sal_Int32 nGroupColumn )
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ xParent->GetData(aParam);
+
+ aParam.nField[nPos] = static_cast<SCCOL>(nGroupColumn);
+
+ xParent->PutData(aParam);
+}
+
+uno::Sequence<sheet::SubTotalColumn> SAL_CALL ScSubTotalFieldObj::getSubTotalColumns()
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ xParent->GetData(aParam);
+
+ SCCOL nCount = aParam.nSubTotals[nPos];
+ uno::Sequence<sheet::SubTotalColumn> aSeq(nCount);
+ sheet::SubTotalColumn* pAry = aSeq.getArray();
+ for (SCCOL i=0; i<nCount; i++)
+ {
+ pAry[i].Column = aParam.pSubTotals[nPos][i];
+ pAry[i].Function = ScDataUnoConversion::SubTotalToGeneral(
+ aParam.pFunctions[nPos][i] );
+ }
+ return aSeq;
+}
+
+void SAL_CALL ScSubTotalFieldObj::setSubTotalColumns(
+ const uno::Sequence<sheet::SubTotalColumn>& aSubTotalColumns )
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ xParent->GetData(aParam);
+
+ sal_uInt32 nColCount = aSubTotalColumns.getLength();
+ if ( nColCount <= sal::static_int_cast<sal_uInt32>(SCCOL_MAX) )
+ {
+ SCCOL nCount = static_cast<SCCOL>(nColCount);
+ aParam.nSubTotals[nPos] = nCount;
+ if (nCount != 0)
+ {
+ aParam.pSubTotals[nPos].reset(new SCCOL[nCount]);
+ aParam.pFunctions[nPos].reset(new ScSubTotalFunc[nCount]);
+
+ const sheet::SubTotalColumn* pAry = aSubTotalColumns.getConstArray();
+ for (SCCOL i=0; i<nCount; i++)
+ {
+ aParam.pSubTotals[nPos][i] = static_cast<SCCOL>(pAry[i].Column);
+ aParam.pFunctions[nPos][i] = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(pAry[i].Function));
+ }
+ }
+ else
+ {
+ aParam.pSubTotals[nPos].reset();
+ aParam.pFunctions[nPos].reset();
+ }
+ }
+ //! otherwise exception or so? (too many columns)
+
+ xParent->PutData(aParam);
+}
+
+ScSubTotalDescriptorBase::ScSubTotalDescriptorBase() :
+ aPropSet( lcl_GetSubTotalPropertyMap() )
+{
+}
+
+ScSubTotalDescriptorBase::~ScSubTotalDescriptorBase()
+{
+}
+
+// XSubTotalDescriptor
+
+rtl::Reference<ScSubTotalFieldObj> ScSubTotalDescriptorBase::GetObjectByIndex_Impl(sal_uInt16 nIndex)
+{
+ if ( nIndex < getCount() )
+ return new ScSubTotalFieldObj( this, nIndex );
+ return nullptr;
+}
+
+void SAL_CALL ScSubTotalDescriptorBase::clear()
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ GetData(aParam);
+
+ for (bool & rn : aParam.bGroupActive)
+ rn = false;
+
+ //! notify the field objects???
+
+ PutData(aParam);
+}
+
+void SAL_CALL ScSubTotalDescriptorBase::addNew(
+ const uno::Sequence<sheet::SubTotalColumn>& aSubTotalColumns,
+ sal_Int32 nGroupColumn )
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ GetData(aParam);
+
+ sal_uInt16 nPos = 0;
+ while ( nPos < MAXSUBTOTAL && aParam.bGroupActive[nPos] )
+ ++nPos;
+
+ sal_uInt32 nColCount = aSubTotalColumns.getLength();
+
+ if ( nPos >= MAXSUBTOTAL || nColCount > sal::static_int_cast<sal_uInt32>(SCCOL_MAX) )
+ // too many fields / columns
+ throw uno::RuntimeException(); // no other exceptions specified
+
+ aParam.bGroupActive[nPos] = true;
+ aParam.nField[nPos] = static_cast<SCCOL>(nGroupColumn);
+
+ aParam.pSubTotals[nPos].reset();
+ aParam.pFunctions[nPos].reset();
+
+ SCCOL nCount = static_cast<SCCOL>(nColCount);
+ aParam.nSubTotals[nPos] = nCount;
+ if (nCount != 0)
+ {
+ aParam.pSubTotals[nPos].reset(new SCCOL[nCount]);
+ aParam.pFunctions[nPos].reset(new ScSubTotalFunc[nCount]);
+
+ const sheet::SubTotalColumn* pAry = aSubTotalColumns.getConstArray();
+ for (SCCOL i=0; i<nCount; i++)
+ {
+ aParam.pSubTotals[nPos][i] = static_cast<SCCOL>(pAry[i].Column);
+ aParam.pFunctions[nPos][i] = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(pAry[i].Function));
+ }
+ }
+ else
+ {
+ aParam.pSubTotals[nPos].reset();
+ aParam.pFunctions[nPos].reset();
+ }
+
+ PutData(aParam);
+}
+
+// flags/settings as properties
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScSubTotalDescriptorBase::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.SubTotalFieldsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScSubTotalDescriptorBase::getCount()
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ GetData(aParam);
+
+ sal_uInt16 nCount = 0;
+ while ( nCount < MAXSUBTOTAL && aParam.bGroupActive[nCount] )
+ ++nCount;
+ return nCount;
+}
+
+uno::Any SAL_CALL ScSubTotalDescriptorBase::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XSubTotalField> xField(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if (!xField.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xField);
+}
+
+uno::Type SAL_CALL ScSubTotalDescriptorBase::getElementType()
+{
+ return cppu::UnoType<sheet::XSubTotalField>::get();
+}
+
+sal_Bool SAL_CALL ScSubTotalDescriptorBase::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSubTotalDescriptorBase::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScSubTotalDescriptorBase::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ GetData(aParam);
+
+ // some old property names are for 5.2 compatibility
+
+ if (aPropertyName == SC_UNONAME_CASE || aPropertyName == SC_UNONAME_ISCASE )
+ aParam.bCaseSens = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_FORMATS || aPropertyName == SC_UNONAME_BINDFMT )
+ aParam.bIncludePattern = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_ENABSORT )
+ aParam.bDoSort = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_SORTASC )
+ aParam.bAscending = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_INSBRK )
+ aParam.bPagebreak = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_ULIST || aPropertyName == SC_UNONAME_ENUSLIST )
+ aParam.bUserDef = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_UINDEX || aPropertyName == SC_UNONAME_USINDEX )
+ {
+ sal_Int32 nVal = 0;
+ if ( aValue >>= nVal )
+ aParam.nUserIndex = static_cast<sal_uInt16>(nVal);
+ }
+ else if (aPropertyName == SC_UNONAME_MAXFLD )
+ {
+ sal_Int32 nVal = 0;
+ if ( (aValue >>= nVal) && nVal > sal::static_int_cast<sal_Int32>(MAXSUBTOTAL) )
+ {
+ throw lang::IllegalArgumentException();
+ }
+ }
+
+ PutData(aParam);
+}
+
+uno::Any SAL_CALL ScSubTotalDescriptorBase::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ GetData(aParam);
+
+ uno::Any aRet;
+
+ // some old property names are for 5.2 compatibility
+
+ if (aPropertyName == SC_UNONAME_CASE || aPropertyName == SC_UNONAME_ISCASE )
+ aRet <<= aParam.bCaseSens;
+ else if (aPropertyName == SC_UNONAME_FORMATS || aPropertyName == SC_UNONAME_BINDFMT )
+ aRet <<= aParam.bIncludePattern;
+ else if (aPropertyName == SC_UNONAME_ENABSORT )
+ aRet <<= aParam.bDoSort;
+ else if (aPropertyName == SC_UNONAME_SORTASC )
+ aRet <<= aParam.bAscending;
+ else if (aPropertyName == SC_UNONAME_INSBRK )
+ aRet <<= aParam.bPagebreak;
+ else if (aPropertyName == SC_UNONAME_ULIST || aPropertyName == SC_UNONAME_ENUSLIST )
+ aRet <<= aParam.bUserDef;
+ else if (aPropertyName == SC_UNONAME_UINDEX || aPropertyName == SC_UNONAME_USINDEX )
+ aRet <<= static_cast<sal_Int32>(aParam.nUserIndex);
+ else if (aPropertyName == SC_UNONAME_MAXFLD )
+ aRet <<= sal_Int32(MAXSUBTOTAL);
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSubTotalDescriptorBase )
+
+ScSubTotalDescriptor::ScSubTotalDescriptor()
+{
+}
+
+ScSubTotalDescriptor::~ScSubTotalDescriptor()
+{
+}
+
+void ScSubTotalDescriptor::GetData( ScSubTotalParam& rParam ) const
+{
+ rParam = aStoredParam; // query for interface
+}
+
+void ScSubTotalDescriptor::PutData( const ScSubTotalParam& rParam )
+{
+ aStoredParam = rParam; // set by the interface
+}
+
+void ScSubTotalDescriptor::SetParam( const ScSubTotalParam& rNew )
+{
+ aStoredParam = rNew; // set from outside
+}
+
+ScRangeSubTotalDescriptor::ScRangeSubTotalDescriptor(ScDatabaseRangeObj* pPar) :
+ mxParent(pPar)
+{
+}
+
+ScRangeSubTotalDescriptor::~ScRangeSubTotalDescriptor()
+{
+}
+
+void ScRangeSubTotalDescriptor::GetData( ScSubTotalParam& rParam ) const
+{
+ if (mxParent.is())
+ mxParent->GetSubTotalParam( rParam );
+}
+
+void ScRangeSubTotalDescriptor::PutData( const ScSubTotalParam& rParam )
+{
+ if (mxParent.is())
+ mxParent->SetSubTotalParam( rParam );
+}
+
+ScConsolidationDescriptor::ScConsolidationDescriptor()
+{
+}
+
+ScConsolidationDescriptor::~ScConsolidationDescriptor()
+{
+}
+
+void ScConsolidationDescriptor::SetParam( const ScConsolidateParam& rNew )
+{
+ aParam = rNew;
+}
+
+// XConsolidationDescriptor
+
+sheet::GeneralFunction SAL_CALL ScConsolidationDescriptor::getFunction()
+{
+ SolarMutexGuard aGuard;
+ return ScDataUnoConversion::SubTotalToGeneral(aParam.eFunction);
+}
+
+void SAL_CALL ScConsolidationDescriptor::setFunction( sheet::GeneralFunction nFunction )
+{
+ SolarMutexGuard aGuard;
+ aParam.eFunction = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(nFunction));
+}
+
+uno::Sequence<table::CellRangeAddress> SAL_CALL ScConsolidationDescriptor::getSources()
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = aParam.nDataAreaCount;
+ if (!aParam.pDataAreas)
+ nCount = 0;
+ table::CellRangeAddress aRange;
+ uno::Sequence<table::CellRangeAddress> aSeq(nCount);
+ table::CellRangeAddress* pAry = aSeq.getArray();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ScArea const & rArea = aParam.pDataAreas[i];
+ aRange.Sheet = rArea.nTab;
+ aRange.StartColumn = rArea.nColStart;
+ aRange.StartRow = rArea.nRowStart;
+ aRange.EndColumn = rArea.nColEnd;
+ aRange.EndRow = rArea.nRowEnd;
+ pAry[i] = aRange;
+ }
+ return aSeq;
+}
+
+void SAL_CALL ScConsolidationDescriptor::setSources(
+ const uno::Sequence<table::CellRangeAddress>& aSources )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = static_cast<sal_uInt16>(aSources.getLength());
+ if (nCount)
+ {
+ const table::CellRangeAddress* pAry = aSources.getConstArray();
+ std::unique_ptr<ScArea[]> pNew(new ScArea[nCount]);
+ sal_uInt16 i;
+ for (i=0; i<nCount; i++)
+ pNew[i] = ScArea( pAry[i].Sheet,
+ static_cast<SCCOL>(pAry[i].StartColumn), pAry[i].StartRow,
+ static_cast<SCCOL>(pAry[i].EndColumn), pAry[i].EndRow );
+
+ aParam.SetAreas( std::move(pNew), nCount ); // copy everything
+ }
+ else
+ aParam.ClearDataAreas();
+}
+
+table::CellAddress SAL_CALL ScConsolidationDescriptor::getStartOutputPosition()
+{
+ SolarMutexGuard aGuard;
+ table::CellAddress aPos;
+ aPos.Column = aParam.nCol;
+ aPos.Row = aParam.nRow;
+ aPos.Sheet = aParam.nTab;
+ return aPos;
+}
+
+void SAL_CALL ScConsolidationDescriptor::setStartOutputPosition(
+ const table::CellAddress& aStartOutputPosition )
+{
+ SolarMutexGuard aGuard;
+ aParam.nCol = static_cast<SCCOL>(aStartOutputPosition.Column);
+ aParam.nRow = static_cast<SCROW>(aStartOutputPosition.Row);
+ aParam.nTab = aStartOutputPosition.Sheet;
+}
+
+sal_Bool SAL_CALL ScConsolidationDescriptor::getUseColumnHeaders()
+{
+ SolarMutexGuard aGuard;
+ return aParam.bByCol;
+}
+
+void SAL_CALL ScConsolidationDescriptor::setUseColumnHeaders( sal_Bool bUseColumnHeaders )
+{
+ SolarMutexGuard aGuard;
+ aParam.bByCol = bUseColumnHeaders;
+}
+
+sal_Bool SAL_CALL ScConsolidationDescriptor::getUseRowHeaders()
+{
+ SolarMutexGuard aGuard;
+ return aParam.bByRow;
+}
+
+void SAL_CALL ScConsolidationDescriptor::setUseRowHeaders( sal_Bool bUseRowHeaders )
+{
+ SolarMutexGuard aGuard;
+ aParam.bByRow = bUseRowHeaders;
+}
+
+sal_Bool SAL_CALL ScConsolidationDescriptor::getInsertLinks()
+{
+ SolarMutexGuard aGuard;
+ return aParam.bReferenceData;
+}
+
+void SAL_CALL ScConsolidationDescriptor::setInsertLinks( sal_Bool bInsertLinks )
+{
+ SolarMutexGuard aGuard;
+ aParam.bReferenceData = bInsertLinks;
+}
+
+ScFilterDescriptorBase::ScFilterDescriptorBase(ScDocShell* pDocShell) :
+ aPropSet( lcl_GetFilterPropertyMap() ),
+ pDocSh(pDocShell)
+{
+ if (pDocSh)
+ pDocSh->GetDocument().AddUnoObject(*this);
+}
+
+ScFilterDescriptorBase::~ScFilterDescriptorBase()
+{
+ SolarMutexGuard g;
+
+ if (pDocSh)
+ pDocSh->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScFilterDescriptorBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocSh = nullptr; // invalid
+ }
+}
+
+// XSheetFilterDescriptor and XSheetFilterDescriptor2
+
+uno::Sequence<sheet::TableFilterField> SAL_CALL ScFilterDescriptorBase::getFilterFields()
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ SCSIZE nEntries = aParam.GetEntryCount(); // allocated entries in Param
+ SCSIZE nCount = 0; // active
+ while ( nCount < nEntries &&
+ aParam.GetEntry(nCount).bDoQuery )
+ ++nCount;
+
+ sheet::TableFilterField aField;
+ uno::Sequence<sheet::TableFilterField> aSeq(static_cast<sal_Int32>(nCount));
+ sheet::TableFilterField* pAry = aSeq.getArray();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ const ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if (rEntry.GetQueryItems().empty())
+ continue;
+
+ const ScQueryEntry::Item& rItem = rEntry.GetQueryItems().front();
+
+ aField.Connection = (rEntry.eConnect == SC_AND) ? sheet::FilterConnection_AND :
+ sheet::FilterConnection_OR;
+ aField.Field = rEntry.nField;
+ aField.IsNumeric = rItem.meType != ScQueryEntry::ByString;
+ aField.StringValue = rItem.maString.getString();
+ aField.NumericValue = rItem.mfVal;
+
+ switch (rEntry.eOp) // ScQueryOp
+ {
+ case SC_EQUAL:
+ {
+ aField.Operator = sheet::FilterOperator_EQUAL;
+ if (rEntry.IsQueryByEmpty())
+ {
+ aField.Operator = sheet::FilterOperator_EMPTY;
+ aField.NumericValue = 0;
+ }
+ else if (rEntry.IsQueryByNonEmpty())
+ {
+ aField.Operator = sheet::FilterOperator_NOT_EMPTY;
+ aField.NumericValue = 0;
+ }
+ }
+ break;
+ case SC_LESS: aField.Operator = sheet::FilterOperator_LESS; break;
+ case SC_GREATER: aField.Operator = sheet::FilterOperator_GREATER; break;
+ case SC_LESS_EQUAL: aField.Operator = sheet::FilterOperator_LESS_EQUAL; break;
+ case SC_GREATER_EQUAL: aField.Operator = sheet::FilterOperator_GREATER_EQUAL; break;
+ case SC_NOT_EQUAL: aField.Operator = sheet::FilterOperator_NOT_EQUAL; break;
+ case SC_TOPVAL: aField.Operator = sheet::FilterOperator_TOP_VALUES; break;
+ case SC_BOTVAL: aField.Operator = sheet::FilterOperator_BOTTOM_VALUES; break;
+ case SC_TOPPERC: aField.Operator = sheet::FilterOperator_TOP_PERCENT; break;
+ case SC_BOTPERC: aField.Operator = sheet::FilterOperator_BOTTOM_PERCENT; break;
+ default:
+ OSL_FAIL("wrong filter enum");
+ aField.Operator = sheet::FilterOperator_EMPTY;
+ }
+ pAry[i] = aField;
+ }
+ return aSeq;
+}
+
+namespace {
+
+template<typename T>
+void convertQueryEntryToUno(const ScQueryEntry& rEntry, T& rField)
+{
+ rField.Connection = (rEntry.eConnect == SC_AND) ? sheet::FilterConnection_AND : sheet::FilterConnection_OR;
+ rField.Field = rEntry.nField;
+
+ switch (rEntry.eOp) // ScQueryOp
+ {
+ case SC_EQUAL: rField.Operator = sheet::FilterOperator2::EQUAL; break;
+ case SC_LESS: rField.Operator = sheet::FilterOperator2::LESS; break;
+ case SC_GREATER: rField.Operator = sheet::FilterOperator2::GREATER; break;
+ case SC_LESS_EQUAL: rField.Operator = sheet::FilterOperator2::LESS_EQUAL; break;
+ case SC_GREATER_EQUAL: rField.Operator = sheet::FilterOperator2::GREATER_EQUAL; break;
+ case SC_NOT_EQUAL: rField.Operator = sheet::FilterOperator2::NOT_EQUAL; break;
+ case SC_TOPVAL: rField.Operator = sheet::FilterOperator2::TOP_VALUES; break;
+ case SC_BOTVAL: rField.Operator = sheet::FilterOperator2::BOTTOM_VALUES; break;
+ case SC_TOPPERC: rField.Operator = sheet::FilterOperator2::TOP_PERCENT; break;
+ case SC_BOTPERC: rField.Operator = sheet::FilterOperator2::BOTTOM_PERCENT; break;
+ case SC_CONTAINS: rField.Operator = sheet::FilterOperator2::CONTAINS; break;
+ case SC_DOES_NOT_CONTAIN: rField.Operator = sheet::FilterOperator2::DOES_NOT_CONTAIN; break;
+ case SC_BEGINS_WITH: rField.Operator = sheet::FilterOperator2::BEGINS_WITH; break;
+ case SC_DOES_NOT_BEGIN_WITH: rField.Operator = sheet::FilterOperator2::DOES_NOT_BEGIN_WITH; break;
+ case SC_ENDS_WITH: rField.Operator = sheet::FilterOperator2::ENDS_WITH; break;
+ case SC_DOES_NOT_END_WITH: rField.Operator = sheet::FilterOperator2::DOES_NOT_END_WITH; break;
+ default:
+ OSL_FAIL("Unknown filter operator value.");
+ rField.Operator = sheet::FilterOperator2::EMPTY;
+ }
+}
+
+template<typename T>
+void convertUnoToQueryEntry(const T& rField, ScQueryEntry& rEntry)
+{
+ rEntry.bDoQuery = true;
+ rEntry.eConnect = (rField.Connection == sheet::FilterConnection_AND) ? SC_AND : SC_OR;
+ rEntry.nField = rField.Field;
+
+ switch (rField.Operator) // FilterOperator
+ {
+ case sheet::FilterOperator2::EQUAL: rEntry.eOp = SC_EQUAL; break;
+ case sheet::FilterOperator2::LESS: rEntry.eOp = SC_LESS; break;
+ case sheet::FilterOperator2::GREATER: rEntry.eOp = SC_GREATER; break;
+ case sheet::FilterOperator2::LESS_EQUAL: rEntry.eOp = SC_LESS_EQUAL; break;
+ case sheet::FilterOperator2::GREATER_EQUAL: rEntry.eOp = SC_GREATER_EQUAL; break;
+ case sheet::FilterOperator2::NOT_EQUAL: rEntry.eOp = SC_NOT_EQUAL; break;
+ case sheet::FilterOperator2::TOP_VALUES: rEntry.eOp = SC_TOPVAL; break;
+ case sheet::FilterOperator2::BOTTOM_VALUES: rEntry.eOp = SC_BOTVAL; break;
+ case sheet::FilterOperator2::TOP_PERCENT: rEntry.eOp = SC_TOPPERC; break;
+ case sheet::FilterOperator2::BOTTOM_PERCENT: rEntry.eOp = SC_BOTPERC; break;
+ case sheet::FilterOperator2::CONTAINS: rEntry.eOp = SC_CONTAINS; break;
+ case sheet::FilterOperator2::DOES_NOT_CONTAIN: rEntry.eOp = SC_DOES_NOT_CONTAIN; break;
+ case sheet::FilterOperator2::BEGINS_WITH: rEntry.eOp = SC_BEGINS_WITH; break;
+ case sheet::FilterOperator2::DOES_NOT_BEGIN_WITH: rEntry.eOp = SC_DOES_NOT_BEGIN_WITH;break;
+ case sheet::FilterOperator2::ENDS_WITH: rEntry.eOp = SC_ENDS_WITH; break;
+ case sheet::FilterOperator2::DOES_NOT_END_WITH: rEntry.eOp = SC_DOES_NOT_END_WITH; break;
+ case sheet::FilterOperator2::EMPTY:
+ rEntry.SetQueryByEmpty();
+ break;
+ case sheet::FilterOperator2::NOT_EMPTY:
+ rEntry.SetQueryByNonEmpty();
+ break;
+ default:
+ OSL_FAIL("Unknown filter operator type.");
+ rEntry.eOp = SC_EQUAL;
+ }
+}
+
+void fillQueryParam(
+ ScQueryParam& rParam, ScDocument* pDoc,
+ const uno::Sequence<sheet::TableFilterField2>& aFilterFields)
+{
+ size_t nCount = static_cast<size_t>(aFilterFields.getLength());
+ rParam.Resize(nCount);
+
+ const sheet::TableFilterField2* pAry = aFilterFields.getConstArray();
+ svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ ScQueryEntry& rEntry = rParam.GetEntry(i);
+ convertUnoToQueryEntry(pAry[i], rEntry);
+
+ if (pAry[i].Operator != sheet::FilterOperator2::EMPTY && pAry[i].Operator != sheet::FilterOperator2::NOT_EMPTY)
+ {
+ ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ rItems.resize(1);
+ ScQueryEntry::Item& rItem = rItems.front();
+ rItem.meType = pAry[i].IsNumeric ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
+ rItem.mfVal = pAry[i].NumericValue;
+ rItem.maString = rPool.intern(pAry[i].StringValue);
+
+ if (rItem.meType == ScQueryEntry::ByValue)
+ {
+ OUString aStr;
+ pDoc->GetFormatTable()->GetInputLineString(rItem.mfVal, 0, aStr);
+ rItem.maString = rPool.intern(aStr);
+ }
+ }
+ }
+
+ size_t nParamCount = rParam.GetEntryCount(); // if below eight Param isn't resized
+ for (size_t i = nCount; i < nParamCount; ++i)
+ rParam.GetEntry(i).bDoQuery = false; // reset surplus fields
+}
+
+void fillQueryParam(
+ ScQueryParam& rParam, ScDocument* pDoc,
+ const uno::Sequence<sheet::TableFilterField3>& aFilterFields)
+{
+ size_t nCount = static_cast<size_t>(aFilterFields.getLength());
+ rParam.Resize(nCount);
+
+ svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
+ const sheet::TableFilterField3* pAry = aFilterFields.getConstArray();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ ScQueryEntry& rEntry = rParam.GetEntry(i);
+ convertUnoToQueryEntry(pAry[i], rEntry);
+
+ if (pAry[i].Operator != sheet::FilterOperator2::EMPTY && pAry[i].Operator != sheet::FilterOperator2::NOT_EMPTY)
+ {
+ ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ rItems.clear();
+ const uno::Sequence<sheet::FilterFieldValue>& rVals = pAry[i].Values;
+ for (const auto& rVal : rVals)
+ {
+ ScQueryEntry::Item aItem;
+ switch (rVal.FilterType)
+ {
+ case FilterFieldType::NUMERIC:
+ aItem.meType = ScQueryEntry::ByValue;
+ break;
+ case FilterFieldType::STRING:
+ aItem.meType = ScQueryEntry::ByString;
+ break;
+ case FilterFieldType::DATE:
+ aItem.meType = ScQueryEntry::ByDate;
+ break;
+ case FilterFieldType::TEXT_COLOR:
+ aItem.meType = ScQueryEntry::ByTextColor;
+ break;
+ case FilterFieldType::BACKGROUND_COLOR:
+ aItem.meType = ScQueryEntry::ByBackgroundColor;
+ break;
+ }
+ aItem.mfVal = rVal.NumericValue;
+ aItem.maString = rPool.intern(rVal.StringValue);
+
+ if (aItem.meType == ScQueryEntry::ByValue)
+ {
+ OUString aStr;
+ pDoc->GetFormatTable()->GetInputLineString(aItem.mfVal, 0, aStr);
+ aItem.maString = rPool.intern(aStr);
+ }
+ else if (aItem.meType == ScQueryEntry::ByTextColor
+ || aItem.meType == ScQueryEntry::ByBackgroundColor)
+ {
+ aItem.maColor = Color(ColorTransparency, rVal.ColorValue);
+ }
+
+ // filter all dates starting with the given date filter YYYY or YYYY-MM and filter all datetimes
+ // starting with the given datetime filter YYYY-MM-DD, YYYY-MM-DD HH, or YYYY-MM-DD HH:MM
+ if( aItem.meType == ScQueryEntry::ByDate && aItem.maString.getLength() < 19 )
+ {
+ ScFilterEntries aFilterEntries;
+ pDoc->GetFilterEntries(rEntry.nField, rParam.nRow1, rParam.nTab, aFilterEntries);
+ for( const auto& rFilter : aFilterEntries )
+ {
+ if( rFilter.GetString().startsWith(rVal.StringValue) )
+ {
+ aItem.maString = rPool.intern(rFilter.GetString());
+ rItems.push_back(aItem);
+ }
+ }
+ }
+ else
+ {
+ rItems.push_back(aItem);
+ }
+ }
+ }
+ }
+
+ size_t nParamCount = rParam.GetEntryCount(); // if below eight Param isn't resized
+ for (size_t i = nCount; i < nParamCount; ++i)
+ rParam.GetEntry(i).bDoQuery = false; // reset surplus fields
+}
+
+}
+
+uno::Sequence<sheet::TableFilterField2> SAL_CALL ScFilterDescriptorBase::getFilterFields2()
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ SCSIZE nEntries = aParam.GetEntryCount(); // allocated entries in Param
+ SCSIZE nCount = 0; // active
+ while ( nCount < nEntries &&
+ aParam.GetEntry(nCount).bDoQuery )
+ ++nCount;
+
+ sheet::TableFilterField2 aField;
+ uno::Sequence<sheet::TableFilterField2> aSeq(static_cast<sal_Int32>(nCount));
+ sheet::TableFilterField2* pAry = aSeq.getArray();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ const ScQueryEntry& rEntry = aParam.GetEntry(i);
+ convertQueryEntryToUno(rEntry, aField);
+
+ bool bByEmpty = false;
+ if (aField.Operator == sheet::FilterOperator2::EQUAL)
+ {
+ if (rEntry.IsQueryByEmpty())
+ {
+ aField.Operator = sheet::FilterOperator2::EMPTY;
+ aField.NumericValue = 0;
+ bByEmpty = true;
+ }
+ else if (rEntry.IsQueryByNonEmpty())
+ {
+ aField.Operator = sheet::FilterOperator2::NOT_EMPTY;
+ aField.NumericValue = 0;
+ bByEmpty = true;
+ }
+ }
+
+ if (!bByEmpty && !rEntry.GetQueryItems().empty())
+ {
+ const ScQueryEntry::Item& rItem = rEntry.GetQueryItems().front();
+ aField.IsNumeric = rItem.meType != ScQueryEntry::ByString;
+ aField.StringValue = rItem.maString.getString();
+ aField.NumericValue = rItem.mfVal;
+ }
+
+ pAry[i] = aField;
+ }
+ return aSeq;
+}
+
+uno::Sequence<sheet::TableFilterField3> SAL_CALL ScFilterDescriptorBase::getFilterFields3()
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ SCSIZE nEntries = aParam.GetEntryCount(); // allocated entries in Param
+ SCSIZE nCount = 0; // active
+ while ( nCount < nEntries &&
+ aParam.GetEntry(nCount).bDoQuery )
+ ++nCount;
+
+ sheet::TableFilterField3 aField;
+ uno::Sequence<sheet::TableFilterField3> aSeq(static_cast<sal_Int32>(nCount));
+ sheet::TableFilterField3* pAry = aSeq.getArray();
+ for (SCSIZE i = 0; i < nCount; ++i)
+ {
+ const ScQueryEntry& rEntry = aParam.GetEntry(i);
+ convertQueryEntryToUno(rEntry, aField);
+
+ bool bByEmpty = false;
+ if (aField.Operator == sheet::FilterOperator2::EQUAL)
+ {
+ if (rEntry.IsQueryByEmpty())
+ {
+ aField.Operator = sheet::FilterOperator2::EMPTY;
+ aField.Values.realloc(1);
+ aField.Values.getArray()[0].NumericValue = 0;
+ bByEmpty = true;
+ }
+ else if (rEntry.IsQueryByNonEmpty())
+ {
+ aField.Operator = sheet::FilterOperator2::NOT_EMPTY;
+ aField.Values.realloc(1);
+ aField.Values.getArray()[0].NumericValue = 0;
+ bByEmpty = true;
+ }
+ }
+
+ if (!bByEmpty)
+ {
+ const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ size_t nItemCount = rItems.size();
+ aField.Values.realloc(nItemCount);
+ auto pValues = aField.Values.getArray();
+ size_t j = 0;
+ for (const auto& rItem : rItems)
+ {
+ pValues[j].IsNumeric = rItem.meType != ScQueryEntry::ByString;
+ pValues[j].StringValue = rItem.maString.getString();
+ pValues[j].NumericValue = rItem.mfVal;
+ ++j;
+ }
+ }
+
+ pAry[i] = aField;
+ }
+ return aSeq;
+}
+
+void SAL_CALL ScFilterDescriptorBase::setFilterFields(
+ const uno::Sequence<sheet::TableFilterField>& aFilterFields )
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ SCSIZE nCount = static_cast<SCSIZE>(aFilterFields.getLength());
+ aParam.Resize( nCount );
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
+ const sheet::TableFilterField* pAry = aFilterFields.getConstArray();
+ SCSIZE i;
+ for (i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ rItems.resize(1);
+ ScQueryEntry::Item& rItem = rItems.front();
+ rEntry.bDoQuery = true;
+ rEntry.eConnect = (pAry[i].Connection == sheet::FilterConnection_AND) ? SC_AND : SC_OR;
+ rEntry.nField = pAry[i].Field;
+ rItem.meType = pAry[i].IsNumeric ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
+ rItem.mfVal = pAry[i].NumericValue;
+ rItem.maString = rPool.intern(pAry[i].StringValue);
+
+ if (rItem.meType != ScQueryEntry::ByString)
+ {
+ OUString aStr;
+ rDoc.GetFormatTable()->GetInputLineString(rItem.mfVal, 0, aStr);
+ rItem.maString = rPool.intern(aStr);
+ }
+
+ switch (pAry[i].Operator) // FilterOperator
+ {
+ case sheet::FilterOperator_EQUAL: rEntry.eOp = SC_EQUAL; break;
+ case sheet::FilterOperator_LESS: rEntry.eOp = SC_LESS; break;
+ case sheet::FilterOperator_GREATER: rEntry.eOp = SC_GREATER; break;
+ case sheet::FilterOperator_LESS_EQUAL: rEntry.eOp = SC_LESS_EQUAL; break;
+ case sheet::FilterOperator_GREATER_EQUAL: rEntry.eOp = SC_GREATER_EQUAL; break;
+ case sheet::FilterOperator_NOT_EQUAL: rEntry.eOp = SC_NOT_EQUAL; break;
+ case sheet::FilterOperator_TOP_VALUES: rEntry.eOp = SC_TOPVAL; break;
+ case sheet::FilterOperator_BOTTOM_VALUES: rEntry.eOp = SC_BOTVAL; break;
+ case sheet::FilterOperator_TOP_PERCENT: rEntry.eOp = SC_TOPPERC; break;
+ case sheet::FilterOperator_BOTTOM_PERCENT: rEntry.eOp = SC_BOTPERC; break;
+ case sheet::FilterOperator_EMPTY:
+ rEntry.SetQueryByEmpty();
+ break;
+ case sheet::FilterOperator_NOT_EMPTY:
+ rEntry.SetQueryByNonEmpty();
+ break;
+ default:
+ OSL_FAIL("Wrong query enum");
+ rEntry.eOp = SC_EQUAL;
+ }
+ }
+
+ SCSIZE nParamCount = aParam.GetEntryCount(); // if below eight Param isn't resized
+ for (i=nCount; i<nParamCount; i++)
+ aParam.GetEntry(i).bDoQuery = false; // reset surplus fields
+
+ PutData(aParam);
+}
+
+void SAL_CALL ScFilterDescriptorBase::setFilterFields2(
+ const uno::Sequence<sheet::TableFilterField2>& aFilterFields )
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+ fillQueryParam(aParam, &pDocSh->GetDocument(), aFilterFields);
+ PutData(aParam);
+}
+
+void SAL_CALL ScFilterDescriptorBase::setFilterFields3(
+ const uno::Sequence<sheet::TableFilterField3>& aFilterFields )
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+ fillQueryParam(aParam, &pDocSh->GetDocument(), aFilterFields);
+ PutData(aParam);
+}
+
+// Rest sind Properties
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFilterDescriptorBase::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScFilterDescriptorBase::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ if (aPropertyName == SC_UNONAME_CONTHDR)
+ aParam.bHasHeader = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_COPYOUT)
+ aParam.bInplace = !(ScUnoHelpFunctions::GetBoolFromAny( aValue ));
+ else if (aPropertyName == SC_UNONAME_ISCASE)
+ aParam.bCaseSens = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_MAXFLD)
+ {
+ // silently ignored
+ }
+ else if (aPropertyName == SC_UNONAME_ORIENT)
+ {
+ //! test for correct enum type?
+ table::TableOrientation eOrient = static_cast<table::TableOrientation>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
+ aParam.bByRow = ( eOrient != table::TableOrientation_COLUMNS );
+ }
+ else if (aPropertyName == SC_UNONAME_OUTPOS)
+ {
+ table::CellAddress aAddress;
+ if ( aValue >>= aAddress )
+ {
+ aParam.nDestTab = aAddress.Sheet;
+ aParam.nDestCol = static_cast<SCCOL>(aAddress.Column);
+ aParam.nDestRow = static_cast<SCROW>(aAddress.Row);
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_SAVEOUT)
+ aParam.bDestPers = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_SKIPDUP)
+ aParam.bDuplicate = !(ScUnoHelpFunctions::GetBoolFromAny( aValue ));
+ else if (aPropertyName == SC_UNONAME_USEREGEX)
+ aParam.eSearchType = ScUnoHelpFunctions::GetBoolFromAny( aValue ) ? utl::SearchParam::SearchType::Regexp :
+ utl::SearchParam::SearchType::Normal;
+
+ PutData(aParam);
+}
+
+uno::Any SAL_CALL ScFilterDescriptorBase::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ uno::Any aRet;
+
+ if (aPropertyName == SC_UNONAME_CONTHDR )
+ aRet <<= aParam.bHasHeader;
+ else if (aPropertyName == SC_UNONAME_COPYOUT )
+ aRet <<= !(aParam.bInplace);
+ else if (aPropertyName == SC_UNONAME_ISCASE )
+ aRet <<= aParam.bCaseSens;
+ else if (aPropertyName == SC_UNONAME_MAXFLD )
+ aRet <<= static_cast<sal_Int32>(aParam.GetEntryCount());
+ else if (aPropertyName == SC_UNONAME_ORIENT )
+ {
+ table::TableOrientation eOrient = aParam.bByRow ? table::TableOrientation_ROWS :
+ table::TableOrientation_COLUMNS;
+ aRet <<= eOrient;
+ }
+ else if (aPropertyName == SC_UNONAME_OUTPOS )
+ {
+ table::CellAddress aOutPos;
+ aOutPos.Sheet = aParam.nDestTab;
+ aOutPos.Column = aParam.nDestCol;
+ aOutPos.Row = aParam.nDestRow;
+ aRet <<= aOutPos;
+ }
+ else if (aPropertyName == SC_UNONAME_SAVEOUT )
+ aRet <<= aParam.bDestPers;
+ else if (aPropertyName == SC_UNONAME_SKIPDUP )
+ aRet <<= !(aParam.bDuplicate);
+ else if (aPropertyName == SC_UNONAME_USEREGEX )
+ aRet <<= (aParam.eSearchType == utl::SearchParam::SearchType::Regexp);
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFilterDescriptorBase )
+
+ScFilterDescriptor::ScFilterDescriptor(ScDocShell* pDocShell)
+ :
+ ScFilterDescriptorBase(pDocShell)
+{
+}
+
+ScFilterDescriptor::~ScFilterDescriptor()
+{
+}
+
+void ScFilterDescriptor::GetData( ScQueryParam& rParam ) const
+{
+ rParam = aStoredParam; // query for interface
+}
+
+void ScFilterDescriptor::PutData( const ScQueryParam& rParam )
+{
+ aStoredParam = rParam; // set by the interface
+}
+
+void ScFilterDescriptor::SetParam( const ScQueryParam& rNew )
+{
+ aStoredParam = rNew; // set from outside
+}
+
+ScRangeFilterDescriptor::ScRangeFilterDescriptor(ScDocShell* pDocShell, ScDatabaseRangeObj* pPar) :
+ ScFilterDescriptorBase(pDocShell),
+ mxParent(pPar)
+{
+}
+
+ScRangeFilterDescriptor::~ScRangeFilterDescriptor()
+{
+}
+
+void ScRangeFilterDescriptor::GetData( ScQueryParam& rParam ) const
+{
+ if (mxParent.is())
+ mxParent->GetQueryParam( rParam );
+}
+
+void ScRangeFilterDescriptor::PutData( const ScQueryParam& rParam )
+{
+ if (mxParent.is())
+ mxParent->SetQueryParam( rParam );
+}
+
+ScDataPilotFilterDescriptor::ScDataPilotFilterDescriptor(ScDocShell* pDocShell, ScDataPilotDescriptorBase* pPar) :
+ ScFilterDescriptorBase(pDocShell),
+ mxParent(pPar)
+{
+}
+
+ScDataPilotFilterDescriptor::~ScDataPilotFilterDescriptor()
+{
+}
+
+void ScDataPilotFilterDescriptor::GetData( ScQueryParam& rParam ) const
+{
+ if (mxParent.is())
+ {
+ ScDPObject* pDPObj = mxParent->GetDPObject();
+ if (pDPObj && pDPObj->IsSheetData())
+ rParam = pDPObj->GetSheetDesc()->GetQueryParam();
+ }
+}
+
+void ScDataPilotFilterDescriptor::PutData( const ScQueryParam& rParam )
+{
+ if (!mxParent.is())
+ return;
+
+ ScDPObject* pDPObj = mxParent->GetDPObject();
+ if (pDPObj)
+ {
+ ScSheetSourceDesc aSheetDesc(&mxParent->GetDocShell()->GetDocument());
+ if (pDPObj->IsSheetData())
+ aSheetDesc = *pDPObj->GetSheetDesc();
+ aSheetDesc.SetQueryParam(rParam);
+ pDPObj->SetSheetDesc(aSheetDesc);
+ mxParent->SetDPObject(pDPObj);
+ }
+}
+
+ScDatabaseRangeObj::ScDatabaseRangeObj(ScDocShell* pDocSh, OUString aNm) :
+ pDocShell( pDocSh ),
+ aName(std::move( aNm )),
+ aPropSet( lcl_GetDBRangePropertyMap() ),
+ bIsUnnamed(false),
+ aTab( 0 )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDatabaseRangeObj::ScDatabaseRangeObj(ScDocShell* pDocSh, const SCTAB nTab) :
+ pDocShell( pDocSh ),
+ aName(STR_DB_LOCAL_NONAME),
+ aPropSet( lcl_GetDBRangePropertyMap() ),
+ bIsUnnamed(true),
+ aTab( nTab )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDatabaseRangeObj::~ScDatabaseRangeObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDatabaseRangeObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr;
+ else if ( auto pRefreshHint = dynamic_cast<const ScDBRangeRefreshedHint*>(&rHint) )
+ {
+ ScDBData* pDBData = GetDBData_Impl();
+ ScImportParam aParam;
+ pDBData->GetImportParam(aParam);
+ if (aParam == pRefreshHint->GetImportParam())
+ Refreshed_Impl();
+ }
+}
+
+// Help functions
+
+ScDBData* ScDatabaseRangeObj::GetDBData_Impl() const
+{
+ ScDBData* pRet = nullptr;
+ if (pDocShell)
+ {
+ if (bIsUnnamed)
+ {
+ pRet = pDocShell->GetDocument().GetAnonymousDBData(aTab);
+ }
+ else
+ {
+ ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection();
+ if (pNames)
+ {
+ ScDBData* p = pNames->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(aName));
+ if (p)
+ pRet = p;
+ }
+ }
+ }
+ return pRet;
+}
+
+// XNamed
+
+OUString SAL_CALL ScDatabaseRangeObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return aName;
+}
+
+void SAL_CALL ScDatabaseRangeObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDBDocFunc aFunc(*pDocShell);
+ bool bOk = aFunc.RenameDBRange( aName, aNewName );
+ if (bOk)
+ aName = aNewName;
+ }
+}
+
+// XDatabaseRange
+
+table::CellRangeAddress SAL_CALL ScDatabaseRangeObj::getDataArea()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aAddress;
+ ScDBData* pData = GetDBData_Impl();
+ if (pData)
+ {
+ ScRange aRange;
+ pData->GetArea(aRange);
+ aAddress.Sheet = aRange.aStart.Tab();
+ aAddress.StartColumn = aRange.aStart.Col();
+ aAddress.StartRow = aRange.aStart.Row();
+ aAddress.EndColumn = aRange.aEnd.Col();
+ aAddress.EndRow = aRange.aEnd.Row();
+ }
+ return aAddress;
+}
+
+void SAL_CALL ScDatabaseRangeObj::setDataArea( const table::CellRangeAddress& aDataArea )
+{
+ SolarMutexGuard aGuard;
+ ScDBData* pData = GetDBData_Impl();
+ if ( pDocShell && pData )
+ {
+ ScDBData aNewData( *pData );
+ //! MoveTo ???
+ aNewData.SetArea( aDataArea.Sheet, static_cast<SCCOL>(aDataArea.StartColumn), static_cast<SCROW>(aDataArea.StartRow),
+ static_cast<SCCOL>(aDataArea.EndColumn), static_cast<SCROW>(aDataArea.EndRow) );
+ ScDBDocFunc aFunc(*pDocShell);
+ aFunc.ModifyDBData(aNewData);
+ }
+}
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScDatabaseRangeObj::getSortDescriptor()
+{
+ SolarMutexGuard aGuard;
+ ScSortParam aParam;
+ const ScDBData* pData = GetDBData_Impl();
+ if (pData)
+ {
+ pData->GetSortParam(aParam);
+
+ // SortDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOLROW nFieldStart = aParam.bByRow ? static_cast<SCCOLROW>(aDBRange.aStart.Col()) : static_cast<SCCOLROW>(aDBRange.aStart.Row());
+ for (sal_uInt16 i=0; i<aParam.GetSortKeyCount(); i++)
+ if ( aParam.maKeyState[i].bDoSort && aParam.maKeyState[i].nField >= nFieldStart )
+ aParam.maKeyState[i].nField -= nFieldStart;
+ }
+
+ uno::Sequence<beans::PropertyValue> aSeq( ScSortDescriptor::GetPropertyCount() );
+ ScSortDescriptor::FillProperties( aSeq, aParam );
+ return aSeq;
+}
+
+void ScDatabaseRangeObj::GetQueryParam(ScQueryParam& rQueryParam) const
+{
+ const ScDBData* pData = GetDBData_Impl();
+ if (!pData)
+ return;
+
+ pData->GetQueryParam(rQueryParam);
+
+ // FilterDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOLROW nFieldStart = rQueryParam.bByRow ? static_cast<SCCOLROW>(aDBRange.aStart.Col()) : static_cast<SCCOLROW>(aDBRange.aStart.Row());
+ SCSIZE nCount = rQueryParam.GetEntryCount();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = rQueryParam.GetEntry(i);
+ if (rEntry.bDoQuery && rEntry.nField >= nFieldStart)
+ rEntry.nField -= nFieldStart;
+ }
+}
+
+void ScDatabaseRangeObj::SetQueryParam(const ScQueryParam& rQueryParam)
+{
+ const ScDBData* pData = GetDBData_Impl();
+ if (!pData)
+ return;
+
+ // FilterDescriptor contains the counted fields inside the area
+ ScQueryParam aParam(rQueryParam);
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOLROW nFieldStart = aParam.bByRow ? static_cast<SCCOLROW>(aDBRange.aStart.Col()) : static_cast<SCCOLROW>(aDBRange.aStart.Row());
+
+ SCSIZE nCount = aParam.GetEntryCount();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if (rEntry.bDoQuery)
+ rEntry.nField += nFieldStart;
+ }
+
+ ScDBData aNewData( *pData );
+ aNewData.SetQueryParam(aParam);
+ aNewData.SetHeader(aParam.bHasHeader); // not in ScDBData::SetQueryParam
+ ScDBDocFunc aFunc(*pDocShell);
+ aFunc.ModifyDBData(aNewData);
+}
+
+uno::Reference<sheet::XSheetFilterDescriptor> SAL_CALL ScDatabaseRangeObj::getFilterDescriptor()
+{
+ SolarMutexGuard aGuard;
+ return new ScRangeFilterDescriptor(pDocShell, this);
+}
+
+void ScDatabaseRangeObj::GetSubTotalParam(ScSubTotalParam& rSubTotalParam) const
+{
+ const ScDBData* pData = GetDBData_Impl();
+ if (!pData)
+ return;
+
+ pData->GetSubTotalParam(rSubTotalParam);
+
+ // FilterDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOL nFieldStart = aDBRange.aStart.Col();
+ for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
+ {
+ if ( rSubTotalParam.bGroupActive[i] )
+ {
+ if ( rSubTotalParam.nField[i] >= nFieldStart )
+ rSubTotalParam.nField[i] = sal::static_int_cast<SCCOL>( rSubTotalParam.nField[i] - nFieldStart );
+ for (SCCOL j=0; j<rSubTotalParam.nSubTotals[i]; j++)
+ if ( rSubTotalParam.pSubTotals[i][j] >= nFieldStart )
+ rSubTotalParam.pSubTotals[i][j] =
+ sal::static_int_cast<SCCOL>( rSubTotalParam.pSubTotals[i][j] - nFieldStart );
+ }
+ }
+}
+
+void ScDatabaseRangeObj::SetSubTotalParam(const ScSubTotalParam& rSubTotalParam)
+{
+ const ScDBData* pData = GetDBData_Impl();
+ if (!pData)
+ return;
+
+ // FilterDescriptor contains the counted fields inside the area
+ ScSubTotalParam aParam(rSubTotalParam);
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOL nFieldStart = aDBRange.aStart.Col();
+ for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
+ {
+ if ( aParam.bGroupActive[i] )
+ {
+ aParam.nField[i] = sal::static_int_cast<SCCOL>( aParam.nField[i] + nFieldStart );
+ for (SCCOL j=0; j<aParam.nSubTotals[i]; j++)
+ aParam.pSubTotals[i][j] = sal::static_int_cast<SCCOL>( aParam.pSubTotals[i][j] + nFieldStart );
+ }
+ }
+
+ ScDBData aNewData( *pData );
+ aNewData.SetSubTotalParam(aParam);
+ ScDBDocFunc aFunc(*pDocShell);
+ aFunc.ModifyDBData(aNewData);
+}
+
+uno::Reference<sheet::XSubTotalDescriptor> SAL_CALL ScDatabaseRangeObj::getSubTotalDescriptor()
+{
+ SolarMutexGuard aGuard;
+ return new ScRangeSubTotalDescriptor(this);
+}
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScDatabaseRangeObj::getImportDescriptor()
+{
+ SolarMutexGuard aGuard;
+ ScImportParam aParam;
+ const ScDBData* pData = GetDBData_Impl();
+ if (pData)
+ pData->GetImportParam(aParam);
+
+ uno::Sequence<beans::PropertyValue> aSeq( ScImportDescriptor::GetPropertyCount() );
+ ScImportDescriptor::FillProperties( aSeq, aParam );
+ return aSeq;
+}
+
+// XRefreshable
+
+void SAL_CALL ScDatabaseRangeObj::refresh()
+{
+ SolarMutexGuard aGuard;
+ ScDBData* pData = GetDBData_Impl();
+ if ( !(pDocShell && pData) )
+ return;
+
+ ScDBDocFunc aFunc(*pDocShell);
+
+ // repeat import?
+ bool bContinue = true;
+ ScImportParam aImportParam;
+ pData->GetImportParam( aImportParam );
+ if (aImportParam.bImport && !pData->HasImportSelection())
+ {
+ SCTAB nTab;
+ SCCOL nDummyCol;
+ SCROW nDummyRow;
+ pData->GetArea( nTab, nDummyCol,nDummyRow,nDummyCol,nDummyRow );
+ bContinue = aFunc.DoImport( nTab, aImportParam, nullptr ); //! Api-Flag as parameter
+ }
+
+ // if no error then internal operations (sort, query, subtotal)
+ if (bContinue)
+ aFunc.RepeatDB( pData->GetName(), true, bIsUnnamed, aTab );
+}
+
+void SAL_CALL ScDatabaseRangeObj::addRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRefreshListeners.emplace_back( xListener );
+
+ // hold one additional ref to keep this object alive as long as there are listeners
+ if ( aRefreshListeners.size() == 1 )
+ acquire();
+}
+
+void SAL_CALL ScDatabaseRangeObj::removeRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = aRefreshListeners.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ {
+ uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n];
+ if ( rObj == xListener )
+ {
+ aRefreshListeners.erase( aRefreshListeners.begin() + n );
+ if ( aRefreshListeners.empty() )
+ release(); // release ref for listeners
+ break;
+ }
+ }
+}
+
+void ScDatabaseRangeObj::Refreshed_Impl()
+{
+ lang::EventObject aEvent;
+ aEvent.Source = getXWeak();
+ for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners)
+ xRefreshListener->refreshed( aEvent );
+}
+
+// XCellRangeSource
+
+uno::Reference<table::XCellRange> SAL_CALL ScDatabaseRangeObj::getReferredCells()
+{
+ SolarMutexGuard aGuard;
+ ScDBData* pData = GetDBData_Impl();
+ if ( pData )
+ {
+ //! static function to create ScCellObj/ScCellRange on ScCellRangeObj ???
+ ScRange aRange;
+
+ pData->GetArea(aRange);
+ if ( aRange.aStart == aRange.aEnd )
+ return new ScCellObj( pDocShell, aRange.aStart );
+ else
+ return new ScCellRangeObj( pDocShell, aRange );
+ }
+ return nullptr;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDatabaseRangeObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScDatabaseRangeObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScDBData* pData = GetDBData_Impl();
+ if ( !(pDocShell && pData) )
+ return;
+
+ ScDBData aNewData( *pData );
+ bool bDo = true;
+
+ if ( aPropertyName == SC_UNONAME_KEEPFORM )
+ aNewData.SetKeepFmt( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNONAME_MOVCELLS )
+ aNewData.SetDoSize( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNONAME_STRIPDAT )
+ aNewData.SetStripData( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNONAME_AUTOFLT )
+ {
+ bool bAutoFilter(ScUnoHelpFunctions::GetBoolFromAny( aValue ));
+ aNewData.SetAutoFilter(bAutoFilter);
+ ScRange aRange;
+ aNewData.GetArea(aRange);
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (bAutoFilter)
+ rDoc.ApplyFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab(), ScMF::Auto );
+ else if (!bAutoFilter)
+ rDoc.RemoveFlagsTab(aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab(), ScMF::Auto );
+ ScRange aPaintRange(aRange.aStart, aRange.aEnd);
+ aPaintRange.aEnd.SetRow(aPaintRange.aStart.Row());
+ pDocShell->PostPaint(aPaintRange, PaintPartFlags::Grid);
+ }
+ else if (aPropertyName == SC_UNONAME_USEFLTCRT )
+ {
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ // only here to set bIsAdvanced in ScDBData
+ ScRange aRange;
+ (void)aNewData.GetAdvancedQuerySource(aRange);
+ aNewData.SetAdvancedQuerySource(&aRange);
+ }
+ else
+ aNewData.SetAdvancedQuerySource(nullptr);
+ }
+ else if (aPropertyName == SC_UNONAME_FLTCRT )
+ {
+ table::CellRangeAddress aRange;
+ if (aValue >>= aRange)
+ {
+ ScRange aCoreRange;
+ ScUnoConversion::FillScRange(aCoreRange, aRange);
+
+ aNewData.SetAdvancedQuerySource(&aCoreRange);
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_FROMSELECT )
+ {
+ aNewData.SetImportSelection(::cppu::any2bool(aValue));
+ }
+ else if (aPropertyName == SC_UNONAME_REFPERIOD )
+ {
+ sal_Int32 nRefresh = 0;
+ if (aValue >>= nRefresh)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ aNewData.SetRefreshDelay(nRefresh);
+ if (rDoc.GetDBCollection())
+ {
+ aNewData.SetRefreshHandler( rDoc.GetDBCollection()->GetRefreshHandler() );
+ aNewData.SetRefreshControl( &rDoc.GetRefreshTimerControlAddress() );
+ }
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_CONRES )
+ {
+ }
+ else if ( aPropertyName == SC_UNONAME_TOTALSROW )
+ aNewData.SetTotals( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNONAME_CONTHDR )
+ aNewData.SetHeader( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else
+ bDo = false;
+
+ if (bDo)
+ {
+ ScDBDocFunc aFunc(*pDocShell);
+ aFunc.ModifyDBData(aNewData);
+ }
+}
+
+uno::Any SAL_CALL ScDatabaseRangeObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ ScDBData* pData = GetDBData_Impl();
+ if ( pData )
+ {
+ if ( aPropertyName == SC_UNONAME_KEEPFORM )
+ aRet <<= pData->IsKeepFmt();
+ else if ( aPropertyName == SC_UNONAME_MOVCELLS )
+ aRet <<= pData->IsDoSize();
+ else if ( aPropertyName == SC_UNONAME_STRIPDAT )
+ aRet <<= pData->IsStripData();
+ else if ( aPropertyName == SC_UNONAME_ISUSER )
+ {
+ // all database ranges except "unnamed" are user defined
+ aRet <<= (pData->GetName() != STR_DB_LOCAL_NONAME);
+ }
+ else if ( aPropertyName == SC_UNO_LINKDISPBIT )
+ {
+ // no target bitmaps for individual entries (would be all equal)
+ // ScLinkTargetTypeObj::SetLinkTargetBitmap( aRet, SC_LINKTARGETTYPE_DBAREA );
+ }
+ else if ( aPropertyName == SC_UNO_LINKDISPNAME )
+ aRet <<= aName;
+ else if (aPropertyName == SC_UNONAME_AUTOFLT )
+ {
+ bool bAutoFilter(GetDBData_Impl()->HasAutoFilter());
+
+ aRet <<= bAutoFilter;
+ }
+ else if (aPropertyName == SC_UNONAME_USEFLTCRT )
+ {
+ ScRange aRange;
+ bool bIsAdvancedSource(GetDBData_Impl()->GetAdvancedQuerySource(aRange));
+
+ aRet <<= bIsAdvancedSource;
+ }
+ else if (aPropertyName == SC_UNONAME_FLTCRT )
+ {
+ table::CellRangeAddress aRange;
+ ScRange aCoreRange;
+ if (GetDBData_Impl()->GetAdvancedQuerySource(aCoreRange))
+ ScUnoConversion::FillApiRange(aRange, aCoreRange);
+
+ aRet <<= aRange;
+ }
+ else if (aPropertyName == SC_UNONAME_FROMSELECT )
+ {
+ aRet <<= GetDBData_Impl()->HasImportSelection();
+ }
+ else if (aPropertyName == SC_UNONAME_REFPERIOD )
+ {
+ sal_Int32 nRefresh(GetDBData_Impl()->GetRefreshDelaySeconds());
+ aRet <<= nRefresh;
+ }
+ else if (aPropertyName == SC_UNONAME_CONRES )
+ {
+ }
+ else if (aPropertyName == SC_UNONAME_TOKENINDEX )
+ {
+ // get index for use in formula tokens (read-only)
+ aRet <<= static_cast<sal_Int32>(GetDBData_Impl()->GetIndex());
+ }
+ else if (aPropertyName == SC_UNONAME_TOTALSROW )
+ {
+ bool bTotals(GetDBData_Impl()->HasTotals());
+
+ aRet <<= bTotals;
+ }
+ else if (aPropertyName == SC_UNONAME_CONTHDR )
+ {
+ bool bHeader(GetDBData_Impl()->HasHeader());
+
+ aRet <<= bHeader;
+ }
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDatabaseRangeObj )
+
+// XServiceInfo
+OUString SAL_CALL ScDatabaseRangeObj::getImplementationName()
+{
+ return "ScDatabaseRangeObj";
+}
+
+sal_Bool SAL_CALL ScDatabaseRangeObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScDatabaseRangeObj::getSupportedServiceNames()
+{
+ return {"com.sun.star.sheet.DatabaseRange",
+ SCLINKTARGET_SERVICE};
+}
+
+ScDatabaseRangesObj::ScDatabaseRangesObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDatabaseRangesObj::~ScDatabaseRangesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDatabaseRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XDatabaseRanges
+
+rtl::Reference<ScDatabaseRangeObj> ScDatabaseRangesObj::GetObjectByIndex_Impl(size_t nIndex)
+{
+ if (!pDocShell)
+ return nullptr;
+
+ ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection();
+ if (!pNames)
+ return nullptr;
+
+ const ScDBCollection::NamedDBs& rDBs = pNames->getNamedDBs();
+ if (rDBs.empty() || nIndex >= rDBs.size())
+ return nullptr;
+
+ ScDBCollection::NamedDBs::const_iterator itr = rDBs.begin();
+ ::std::advance(itr, nIndex); // boundary check is done above.
+ return new ScDatabaseRangeObj(pDocShell, (*itr)->GetName());
+}
+
+rtl::Reference<ScDatabaseRangeObj> ScDatabaseRangesObj::GetObjectByName_Impl(const OUString& aName)
+{
+ if ( pDocShell && hasByName(aName) )
+ {
+ return new ScDatabaseRangeObj( pDocShell, aName );
+ }
+ return nullptr;
+}
+
+void SAL_CALL ScDatabaseRangesObj::addNewByName( const OUString& aName,
+ const table::CellRangeAddress& aRange )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ ScDBDocFunc aFunc(*pDocShell);
+
+ ScRange aNameRange( static_cast<SCCOL>(aRange.StartColumn), static_cast<SCROW>(aRange.StartRow), aRange.Sheet,
+ static_cast<SCCOL>(aRange.EndColumn), static_cast<SCROW>(aRange.EndRow), aRange.Sheet );
+ bDone = aFunc.AddDBRange( aName, aNameRange );
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScDatabaseRangesObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ ScDBDocFunc aFunc(*pDocShell);
+ bDone = aFunc.DeleteDBRange( aName );
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScDatabaseRangesObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.DatabaseRangesEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDatabaseRangesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ //! need to omit "unnamed"?
+
+ if (pDocShell)
+ {
+ ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection();
+ if (pNames)
+ return static_cast<sal_Int32>(pNames->getNamedDBs().size());
+ }
+ return 0;
+}
+
+uno::Any SAL_CALL ScDatabaseRangesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ if (nIndex < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Reference<sheet::XDatabaseRange> xRange(GetObjectByIndex_Impl(static_cast<size_t>(nIndex)));
+ if (!xRange.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRange);
+}
+
+uno::Type SAL_CALL ScDatabaseRangesObj::getElementType()
+{
+ return cppu::UnoType<sheet::XDatabaseRange>::get();
+}
+
+sal_Bool SAL_CALL ScDatabaseRangesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XNameAccess
+
+uno::Any SAL_CALL ScDatabaseRangesObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XDatabaseRange> xRange(GetObjectByName_Impl(aName));
+ if (!xRange.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xRange);
+}
+
+uno::Sequence<OUString> SAL_CALL ScDatabaseRangesObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ //! need to omit "unnamed"?
+
+ if (pDocShell)
+ {
+ ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection();
+ if (pNames)
+ {
+ const ScDBCollection::NamedDBs& rDBs = pNames->getNamedDBs();
+ uno::Sequence<OUString> aSeq(rDBs.size());
+ auto aSeqRange = asNonConstRange(aSeq);
+ size_t i = 0;
+ for (const auto& rDB : rDBs)
+ {
+ aSeqRange[i] = rDB->GetName();
+ ++i;
+ }
+
+ return aSeq;
+ }
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScDatabaseRangesObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ //! need to omit "unnamed"?
+
+ if (pDocShell)
+ {
+ ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection();
+ if (pNames)
+ return pNames->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(aName)) != nullptr;
+ }
+ return false;
+}
+
+ScUnnamedDatabaseRangesObj::ScUnnamedDatabaseRangesObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScUnnamedDatabaseRangesObj::~ScUnnamedDatabaseRangesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScUnnamedDatabaseRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XUnnamedDatabaseRanges
+
+void ScUnnamedDatabaseRangesObj::setByTable( const table::CellRangeAddress& aRange )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ if ( pDocShell->GetDocument().GetTableCount() <= aRange.Sheet )
+ throw lang::IndexOutOfBoundsException();
+
+ ScDBDocFunc aFunc(*pDocShell);
+ ScRange aUnnamedRange( static_cast<SCCOL>(aRange.StartColumn), static_cast<SCROW>(aRange.StartRow), aRange.Sheet,
+ static_cast<SCCOL>(aRange.EndColumn), static_cast<SCROW>(aRange.EndRow), aRange.Sheet );
+ bDone = aFunc.AddDBRange( STR_DB_LOCAL_NONAME, aUnnamedRange );
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+uno::Any ScUnnamedDatabaseRangesObj::getByTable( sal_Int32 nTab )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ throw uno::RuntimeException();
+
+ if ( pDocShell->GetDocument().GetTableCount() <= nTab )
+ throw lang::IndexOutOfBoundsException();
+ uno::Reference<sheet::XDatabaseRange> xRange(
+ new ScDatabaseRangeObj(pDocShell, static_cast<SCTAB>(nTab)));
+ if (!xRange.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xRange);
+}
+
+sal_Bool ScUnnamedDatabaseRangesObj::hasByTable( sal_Int32 nTab )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ if (pDocShell->GetDocument().GetTableCount() <= nTab)
+ throw lang::IndexOutOfBoundsException();
+ if (pDocShell->GetDocument().GetAnonymousDBData(static_cast<SCTAB>(nTab)))
+ return true;
+ return false;
+ }
+ else
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/defltuno.cxx b/sc/source/ui/unoobj/defltuno.cxx
new file mode 100644
index 0000000000..516fc8c6c7
--- /dev/null
+++ b/sc/source/ui/unoobj/defltuno.cxx
@@ -0,0 +1,334 @@
+/* -*- 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 <editeng/memberids.h>
+#include <svl/hint.hxx>
+#include <svl/itemprop.hxx>
+#include <vcl/svapp.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+#include <scitems.hxx>
+#include <defltuno.hxx>
+#include <miscuno.hxx>
+#include <docsh.hxx>
+#include <docpool.hxx>
+#include <unonames.hxx>
+#include <docoptio.hxx>
+
+#include <limits>
+
+class SvxFontItem;
+using namespace ::com::sun::star;
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetDocDefaultsMap()
+{
+ static const SfxItemPropertyMapEntry aDocDefaultsMap_Impl[] =
+ {
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_STANDARDDEC, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNO_TABSTOPDIS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ };
+ return aDocDefaultsMap_Impl;
+}
+
+using sc::TwipsToEvenHMM;
+
+SC_SIMPLE_SERVICE_INFO( ScDocDefaultsObj, "ScDocDefaultsObj", "com.sun.star.sheet.Defaults" )
+
+ScDocDefaultsObj::ScDocDefaultsObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh ),
+ aPropertyMap(lcl_GetDocDefaultsMap())
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDocDefaultsObj::~ScDocDefaultsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDocDefaultsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // document gone
+ }
+}
+
+void ScDocDefaultsObj::ItemsChanged()
+{
+ if (pDocShell)
+ {
+ //! if not in XML import, adjust row heights
+ const auto & rDoc = pDocShell->GetDocument();
+ pDocShell->PostPaint(ScRange(0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB), PaintPartFlags::Grid);
+ }
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDocDefaultsObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef = new SfxItemPropertySetInfo(
+ aPropertyMap );
+ return aRef;
+}
+
+void SAL_CALL ScDocDefaultsObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMapEntry* pEntry = aPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+ if(!pEntry->nWID)
+ {
+ if(aPropertyName ==SC_UNO_STANDARDDEC)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDocOptions aDocOpt(rDoc.GetDocOptions());
+ sal_Int16 nValue = 0;
+ if (aValue >>= nValue)
+ {
+ aDocOpt.SetStdPrecision(static_cast<sal_uInt16> (nValue));
+ rDoc.SetDocOptions(aDocOpt);
+ }
+ }
+ else if (aPropertyName == SC_UNO_TABSTOPDIS)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDocOptions aDocOpt(rDoc.GetDocOptions());
+ sal_Int32 nValue = 0;
+ if (aValue >>= nValue)
+ {
+ aDocOpt.SetTabDistance(o3tl::toTwips(nValue, o3tl::Length::mm100));
+ rDoc.SetDocOptions(aDocOpt);
+ }
+ }
+ }
+ else if ( pEntry->nWID == ATTR_FONT_LANGUAGE ||
+ pEntry->nWID == ATTR_CJK_FONT_LANGUAGE ||
+ pEntry->nWID == ATTR_CTL_FONT_LANGUAGE )
+ {
+ // for getPropertyValue the PoolDefaults are sufficient,
+ // but setPropertyValue has to be handled differently
+
+ lang::Locale aLocale;
+ if ( aValue >>= aLocale )
+ {
+ LanguageType eNew;
+ if (!aLocale.Language.isEmpty() || !aLocale.Country.isEmpty())
+ eNew = LanguageTag::convertToLanguageType( aLocale, false);
+ else
+ eNew = LANGUAGE_NONE;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+
+ if ( pEntry->nWID == ATTR_CJK_FONT_LANGUAGE )
+ eCjk = eNew;
+ else if ( pEntry->nWID == ATTR_CTL_FONT_LANGUAGE )
+ eCtl = eNew;
+ else
+ eLatin = eNew;
+
+ rDoc.SetLanguage( eLatin, eCjk, eCtl );
+ }
+ }
+ else
+ {
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ std::unique_ptr<SfxPoolItem> pNewItem(pPool->GetDefaultItem(pEntry->nWID).Clone());
+
+ if( !pNewItem->PutValue( aValue, pEntry->nMemberId ) )
+ throw lang::IllegalArgumentException();
+
+ pPool->SetPoolDefaultItem( *pNewItem );
+
+ ItemsChanged();
+ }
+}
+
+uno::Any SAL_CALL ScDocDefaultsObj::getPropertyValue( const OUString& aPropertyName )
+{
+ // use pool default if set
+
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ uno::Any aRet;
+ const SfxItemPropertyMapEntry* pEntry = aPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ if (!pEntry->nWID)
+ {
+ if(aPropertyName == SC_UNO_STANDARDDEC)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScDocOptions& aDocOpt = rDoc.GetDocOptions();
+ sal_uInt16 nPrec = aDocOpt.GetStdPrecision();
+ // the max value of unsigned 16-bit integer is used as the flag
+ // value for unlimited precision, c.f.
+ // SvNumberFormatter::UNLIMITED_PRECISION.
+ if (nPrec <= ::std::numeric_limits<sal_Int16>::max())
+ aRet <<= static_cast<sal_Int16> (nPrec);
+ }
+ else if (aPropertyName == SC_UNO_TABSTOPDIS)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScDocOptions& aDocOpt = rDoc.GetDocOptions();
+ sal_Int32 nValue (TwipsToEvenHMM(aDocOpt.GetTabDistance()));
+ aRet <<= nValue;
+ }
+ }
+ else
+ {
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ const SfxPoolItem& rItem = pPool->GetDefaultItem( pEntry->nWID );
+ rItem.QueryValue( aRet, pEntry->nMemberId );
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDocDefaultsObj )
+
+// XPropertyState
+
+beans::PropertyState SAL_CALL ScDocDefaultsObj::getPropertyState( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMapEntry* pEntry = aPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ beans::PropertyState eRet = beans::PropertyState_DEFAULT_VALUE;
+
+ sal_uInt16 nWID = pEntry->nWID;
+ if ( nWID == ATTR_FONT || nWID == ATTR_CJK_FONT || nWID == ATTR_CTL_FONT || !nWID )
+ {
+ // static default for font is system-dependent,
+ // so font default is always treated as "direct value".
+
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ }
+ else
+ {
+ // check if pool default is set
+
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ if ( pPool->GetPoolDefaultItem( nWID ) != nullptr )
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ }
+
+ return eRet;
+}
+
+uno::Sequence<beans::PropertyState> SAL_CALL ScDocDefaultsObj::getPropertyStates(
+ const uno::Sequence<OUString>& aPropertyNames )
+{
+ // the simple way: call getPropertyState
+
+ SolarMutexGuard aGuard;
+ uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength());
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.getArray(),
+ [this](const OUString& rName) -> beans::PropertyState { return getPropertyState(rName); });
+ return aRet;
+}
+
+void SAL_CALL ScDocDefaultsObj::setPropertyToDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMapEntry* pEntry = aPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ if (pEntry->nWID)
+ {
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ pPool->ResetPoolDefaultItem( pEntry->nWID );
+
+ ItemsChanged();
+ }
+}
+
+uno::Any SAL_CALL ScDocDefaultsObj::getPropertyDefault( const OUString& aPropertyName )
+{
+ // always use static default
+
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMapEntry* pEntry = aPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aRet;
+ if (pEntry->nWID)
+ {
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ const SfxPoolItem* pItem = pPool->GetItem2Default( pEntry->nWID );
+ if (pItem)
+ pItem->QueryValue( aRet, pEntry->nMemberId );
+ }
+ return aRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/dispuno.cxx b/sc/source/ui/unoobj/dispuno.cxx
new file mode 100644
index 0000000000..536d271d64
--- /dev/null
+++ b/sc/source/ui/unoobj/dispuno.cxx
@@ -0,0 +1,366 @@
+/* -*- 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 <sfx2/viewfrm.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <svl/hint.hxx>
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/frame/XDispatchProviderInterception.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+
+#include <dispuno.hxx>
+#include <tabvwsh.hxx>
+#include <dbdocfun.hxx>
+#include <dbdata.hxx>
+
+using namespace com::sun::star;
+
+const char cURLInsertColumns[] = ".uno:DataSourceBrowser/InsertColumns"; //data into text
+constexpr OUString cURLDocDataSource = u".uno:DataSourceBrowser/DocumentDataSource"_ustr;
+
+static uno::Reference<view::XSelectionSupplier> lcl_GetSelectionSupplier( const SfxViewShell* pViewShell )
+{
+ if ( pViewShell )
+ {
+ SfxViewFrame& rViewFrame = pViewShell->GetViewFrame();
+ return uno::Reference<view::XSelectionSupplier>( rViewFrame.GetFrame().GetController(), uno::UNO_QUERY );
+ }
+ return uno::Reference<view::XSelectionSupplier>();
+}
+
+ScDispatchProviderInterceptor::ScDispatchProviderInterceptor(ScTabViewShell* pViewSh) :
+ pViewShell( pViewSh )
+{
+ if ( !pViewShell )
+ return;
+
+ m_xIntercepted.set(uno::Reference<frame::XDispatchProviderInterception>(pViewShell->GetViewFrame().GetFrame().GetFrameInterface(), uno::UNO_QUERY));
+ if (m_xIntercepted.is())
+ {
+ osl_atomic_increment( &m_refCount );
+
+ m_xIntercepted->registerDispatchProviderInterceptor(
+ static_cast<frame::XDispatchProviderInterceptor*>(this));
+ // this should make us the top-level dispatch-provider for the component, via a call to our
+ // setDispatchProvider we should have got a fallback for requests we (i.e. our master) cannot fulfill
+ uno::Reference<lang::XComponent> xInterceptedComponent(m_xIntercepted, uno::UNO_QUERY);
+ if (xInterceptedComponent.is())
+ xInterceptedComponent->addEventListener(static_cast<lang::XEventListener*>(this));
+
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ StartListening(*pViewShell);
+}
+
+ScDispatchProviderInterceptor::~ScDispatchProviderInterceptor()
+{
+ if (pViewShell)
+ EndListening(*pViewShell);
+}
+
+void ScDispatchProviderInterceptor::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pViewShell = nullptr;
+}
+
+// XDispatchProvider
+
+uno::Reference<frame::XDispatch> SAL_CALL ScDispatchProviderInterceptor::queryDispatch(
+ const util::URL& aURL, const OUString& aTargetFrameName,
+ sal_Int32 nSearchFlags )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<frame::XDispatch> xResult;
+ // create some dispatch ...
+ if ( pViewShell && (
+ aURL.Complete == cURLInsertColumns ||
+ aURL.Complete == cURLDocDataSource ) )
+ {
+ if (!m_xMyDispatch.is())
+ m_xMyDispatch = new ScDispatch( pViewShell );
+ xResult = m_xMyDispatch;
+ }
+
+ // ask our slave provider
+ if (!xResult.is() && m_xSlaveDispatcher.is())
+ xResult = m_xSlaveDispatcher->queryDispatch(aURL, aTargetFrameName, nSearchFlags);
+
+ return xResult;
+}
+
+uno::Sequence< uno::Reference<frame::XDispatch> > SAL_CALL
+ ScDispatchProviderInterceptor::queryDispatches(
+ const uno::Sequence<frame::DispatchDescriptor>& aDescripts )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Sequence< uno::Reference< frame::XDispatch> > aReturn(aDescripts.getLength());
+ std::transform(aDescripts.begin(), aDescripts.end(), aReturn.getArray(),
+ [this](const frame::DispatchDescriptor& rDescr) -> uno::Reference<frame::XDispatch> {
+ return queryDispatch(rDescr.FeatureURL, rDescr.FrameName, rDescr.SearchFlags); });
+ return aReturn;
+}
+
+// XDispatchProviderInterceptor
+
+uno::Reference<frame::XDispatchProvider> SAL_CALL
+ ScDispatchProviderInterceptor::getSlaveDispatchProvider()
+{
+ SolarMutexGuard aGuard;
+ return m_xSlaveDispatcher;
+}
+
+void SAL_CALL ScDispatchProviderInterceptor::setSlaveDispatchProvider(
+ const uno::Reference<frame::XDispatchProvider>& xNewDispatchProvider )
+{
+ SolarMutexGuard aGuard;
+ m_xSlaveDispatcher.set(xNewDispatchProvider);
+}
+
+uno::Reference<frame::XDispatchProvider> SAL_CALL
+ ScDispatchProviderInterceptor::getMasterDispatchProvider()
+{
+ SolarMutexGuard aGuard;
+ return m_xMasterDispatcher;
+}
+
+void SAL_CALL ScDispatchProviderInterceptor::setMasterDispatchProvider(
+ const uno::Reference<frame::XDispatchProvider>& xNewSupplier )
+{
+ SolarMutexGuard aGuard;
+ m_xMasterDispatcher.set(xNewSupplier);
+}
+
+// XEventListener
+
+void SAL_CALL ScDispatchProviderInterceptor::disposing( const lang::EventObject& /* Source */ )
+{
+ SolarMutexGuard aGuard;
+
+ if (m_xIntercepted.is())
+ {
+ m_xIntercepted->releaseDispatchProviderInterceptor(
+ static_cast<frame::XDispatchProviderInterceptor*>(this));
+ uno::Reference<lang::XComponent> xInterceptedComponent(m_xIntercepted, uno::UNO_QUERY);
+ if (xInterceptedComponent.is())
+ xInterceptedComponent->removeEventListener(static_cast<lang::XEventListener*>(this));
+
+ m_xMyDispatch = nullptr;
+ }
+ m_xIntercepted = nullptr;
+}
+
+ScDispatch::ScDispatch(ScTabViewShell* pViewSh) :
+ pViewShell( pViewSh ),
+ bListeningToView( false )
+{
+ if (pViewShell)
+ StartListening(*pViewShell);
+}
+
+ScDispatch::~ScDispatch()
+{
+ if (pViewShell)
+ EndListening(*pViewShell);
+
+ if (bListeningToView && pViewShell)
+ {
+ uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell ));
+ if ( xSupplier.is() )
+ xSupplier->removeSelectionChangeListener(this);
+ }
+}
+
+void ScDispatch::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pViewShell = nullptr;
+}
+
+// XDispatch
+
+void SAL_CALL ScDispatch::dispatch( const util::URL& aURL,
+ const uno::Sequence<beans::PropertyValue>& aArgs )
+{
+ SolarMutexGuard aGuard;
+
+ bool bDone = false;
+ if ( pViewShell && aURL.Complete == cURLInsertColumns )
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScAddress aPos( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
+
+ ScDBDocFunc aFunc( *rViewData.GetDocShell() );
+ aFunc.DoImportUno( aPos, aArgs );
+ bDone = true;
+ }
+ // cURLDocDataSource is never dispatched
+
+ if (!bDone)
+ throw uno::RuntimeException();
+}
+
+static void lcl_FillDataSource( frame::FeatureStateEvent& rEvent, const ScImportParam& rParam )
+{
+ rEvent.IsEnabled = rParam.bImport;
+
+ svx::ODataAccessDescriptor aDescriptor;
+ if ( rParam.bImport )
+ {
+ sal_Int32 nType = rParam.bSql ? sdb::CommandType::COMMAND :
+ ( (rParam.nType == ScDbQuery) ? sdb::CommandType::QUERY :
+ sdb::CommandType::TABLE );
+
+ aDescriptor.setDataSource(rParam.aDBName);
+ aDescriptor[svx::DataAccessDescriptorProperty::Command] <<= rParam.aStatement;
+ aDescriptor[svx::DataAccessDescriptorProperty::CommandType] <<= nType;
+ }
+ else
+ {
+ // descriptor has to be complete anyway
+
+ aDescriptor[svx::DataAccessDescriptorProperty::DataSource] <<= OUString();
+ aDescriptor[svx::DataAccessDescriptorProperty::Command] <<= OUString();
+ aDescriptor[svx::DataAccessDescriptorProperty::CommandType] <<= sal_Int32(sdb::CommandType::TABLE);
+ }
+ rEvent.State <<= aDescriptor.createPropertyValueSequence();
+}
+
+void SAL_CALL ScDispatch::addStatusListener(
+ const uno::Reference<frame::XStatusListener>& xListener,
+ const util::URL& aURL)
+{
+ SolarMutexGuard aGuard;
+
+ if (!pViewShell)
+ throw uno::RuntimeException();
+
+ // initial state
+ frame::FeatureStateEvent aEvent;
+ aEvent.IsEnabled = true;
+ aEvent.Source = getXWeak();
+ aEvent.FeatureURL = aURL;
+
+ if ( aURL.Complete == cURLDocDataSource )
+ {
+ aDataSourceListeners.emplace_back( xListener );
+
+ if (!bListeningToView)
+ {
+ uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell ));
+ if ( xSupplier.is() )
+ xSupplier->addSelectionChangeListener(this);
+ bListeningToView = true;
+ }
+
+ ScDBData* pDBData = pViewShell->GetDBData(false,SC_DB_OLD);
+ if ( pDBData )
+ pDBData->GetImportParam( aLastImport );
+ lcl_FillDataSource( aEvent, aLastImport ); // modifies State, IsEnabled
+ }
+ //! else add to listener for "enabled" changes?
+
+ xListener->statusChanged( aEvent );
+}
+
+void SAL_CALL ScDispatch::removeStatusListener(
+ const uno::Reference<frame::XStatusListener>& xListener,
+ const util::URL& aURL )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aURL.Complete != cURLDocDataSource )
+ return;
+
+ sal_uInt16 nCount = aDataSourceListeners.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ {
+ uno::Reference<frame::XStatusListener>& rObj = aDataSourceListeners[n];
+ if ( rObj == xListener )
+ {
+ aDataSourceListeners.erase( aDataSourceListeners.begin() + n );
+ break;
+ }
+ }
+
+ if ( aDataSourceListeners.empty() && pViewShell )
+ {
+ uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell ));
+ if ( xSupplier.is() )
+ xSupplier->removeSelectionChangeListener(this);
+ bListeningToView = false;
+ }
+}
+
+// XSelectionChangeListener
+
+void SAL_CALL ScDispatch::selectionChanged( const css::lang::EventObject& /* aEvent */ )
+{
+ // currently only called for URL cURLDocDataSource
+
+ if ( !pViewShell )
+ return;
+
+ ScImportParam aNewImport;
+ ScDBData* pDBData = pViewShell->GetDBData(false,SC_DB_OLD);
+ if ( pDBData )
+ pDBData->GetImportParam( aNewImport );
+
+ // notify listeners only if data source has changed
+ if ( !(aNewImport.bImport != aLastImport.bImport ||
+ aNewImport.aDBName != aLastImport.aDBName ||
+ aNewImport.aStatement != aLastImport.aStatement ||
+ aNewImport.bSql != aLastImport.bSql ||
+ aNewImport.nType != aLastImport.nType) )
+ return;
+
+ frame::FeatureStateEvent aEvent;
+ aEvent.Source = getXWeak();
+ aEvent.FeatureURL.Complete = cURLDocDataSource;
+
+ lcl_FillDataSource( aEvent, aNewImport ); // modifies State, IsEnabled
+
+ for (uno::Reference<frame::XStatusListener> & xDataSourceListener : aDataSourceListeners)
+ xDataSourceListener->statusChanged( aEvent );
+
+ aLastImport = aNewImport;
+}
+
+// XEventListener
+
+void SAL_CALL ScDispatch::disposing( const css::lang::EventObject& rSource )
+{
+ uno::Reference<view::XSelectionSupplier> xSupplier(rSource.Source, uno::UNO_QUERY);
+ xSupplier->removeSelectionChangeListener(this);
+ bListeningToView = false;
+
+ lang::EventObject aEvent;
+ aEvent.Source = getXWeak();
+ for (uno::Reference<frame::XStatusListener> & xDataSourceListener : aDataSourceListeners)
+ xDataSourceListener->disposing( aEvent );
+
+ pViewShell = nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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: */
diff --git a/sc/source/ui/unoobj/drdefuno.cxx b/sc/source/ui/unoobj/drdefuno.cxx
new file mode 100644
index 0000000000..fa2387d28b
--- /dev/null
+++ b/sc/source/ui/unoobj/drdefuno.cxx
@@ -0,0 +1,80 @@
+/* -*- 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 <drdefuno.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+
+#include <svx/unoprov.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+
+ScDrawDefaultsObj::ScDrawDefaultsObj(ScDocShell* pDocSh) :
+ SvxUnoDrawPool( nullptr, SvxPropertySetInfoPool::getDrawingDefaults() ),
+ pDocShell( pDocSh )
+{
+ // SvxUnoDrawPool is initialized without model,
+ // draw layer is created on demand in getModelPool
+
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDrawDefaultsObj::~ScDrawDefaultsObj() noexcept
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDrawDefaultsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // document gone
+ }
+}
+
+SfxItemPool* ScDrawDefaultsObj::getModelPool( bool bReadOnly ) noexcept
+{
+ SfxItemPool* pRet = nullptr;
+
+ try
+ {
+ if ( pDocShell )
+ {
+ ScDrawLayer* pModel = bReadOnly ?
+ pDocShell->GetDocument().GetDrawLayer() :
+ pDocShell->MakeDrawLayer();
+ if ( pModel )
+ pRet = &pModel->GetItemPool();
+ }
+ }
+ catch (...)
+ {
+ }
+
+ if ( !pRet )
+ pRet = SvxUnoDrawPool::getModelPool( bReadOnly ); // uses default pool
+
+ return pRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/editsrc.cxx b/sc/source/ui/unoobj/editsrc.cxx
new file mode 100644
index 0000000000..f96f9c0201
--- /dev/null
+++ b/sc/source/ui/unoobj/editsrc.cxx
@@ -0,0 +1,272 @@
+/* -*- 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 <memory>
+#include <sal/config.h>
+
+#include <utility>
+
+#include <editsrc.hxx>
+
+#include <editeng/unofored.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/svdocapt.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/outliner.hxx>
+#include <textuno.hxx>
+#include <editutil.hxx>
+#include <docsh.hxx>
+#include <hints.hxx>
+#include <postit.hxx>
+#include <AccessibleText.hxx>
+
+ScHeaderFooterEditSource::ScHeaderFooterEditSource(ScHeaderFooterTextData& rData) :
+ mrTextData(rData) {}
+
+ScHeaderFooterEditSource::~ScHeaderFooterEditSource() {}
+
+ScEditEngineDefaulter* ScHeaderFooterEditSource::GetEditEngine()
+{
+ return mrTextData.GetEditEngine();
+}
+
+std::unique_ptr<SvxEditSource> ScHeaderFooterEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new ScHeaderFooterEditSource(mrTextData));
+}
+
+SvxTextForwarder* ScHeaderFooterEditSource::GetTextForwarder()
+{
+ return mrTextData.GetTextForwarder();
+}
+
+void ScHeaderFooterEditSource::UpdateData()
+{
+ mrTextData.UpdateData();
+}
+
+ScCellEditSource::ScCellEditSource(ScDocShell* pDocSh, const ScAddress& rP) :
+ pCellTextData(new ScCellTextData(pDocSh, rP)) {}
+
+ScCellEditSource::~ScCellEditSource()
+{
+}
+
+std::unique_ptr<SvxEditSource> ScCellEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new ScCellEditSource(pCellTextData->GetDocShell(), pCellTextData->GetCellPos()));
+}
+
+SvxTextForwarder* ScCellEditSource::GetTextForwarder()
+{
+ return pCellTextData->GetTextForwarder();
+}
+
+void ScCellEditSource::UpdateData()
+{
+ pCellTextData->UpdateData();
+}
+
+void ScCellEditSource::SetDoUpdateData(bool bValue)
+{
+ pCellTextData->SetDoUpdate(bValue);
+}
+
+bool ScCellEditSource::IsDirty() const
+{
+ return pCellTextData->IsDirty();
+}
+
+ScEditEngineDefaulter* ScCellEditSource::GetEditEngine()
+{
+ return pCellTextData->GetEditEngine();
+}
+
+ScAnnotationEditSource::ScAnnotationEditSource(ScDocShell* pDocSh, const ScAddress& rP) :
+ pDocShell( pDocSh ),
+ aCellPos( rP ),
+ bDataValid( false )
+{
+ if (pDocShell)
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScAnnotationEditSource::~ScAnnotationEditSource()
+{
+ SolarMutexGuard aGuard; // needed for EditEngine dtor
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+
+ pForwarder.reset();
+ pEditEngine.reset();
+}
+
+std::unique_ptr<SvxEditSource> ScAnnotationEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new ScAnnotationEditSource( pDocShell, aCellPos ));
+}
+
+SdrObject* ScAnnotationEditSource::GetCaptionObj()
+{
+ ScPostIt* pNote = pDocShell->GetDocument().GetNote(aCellPos);
+ return pNote ? pNote->GetOrCreateCaption( aCellPos ) : nullptr;
+}
+
+SvxTextForwarder* ScAnnotationEditSource::GetTextForwarder()
+{
+ if (!pEditEngine)
+ {
+ // notes don't have fields
+ if ( pDocShell )
+ {
+ pEditEngine.reset( new ScNoteEditEngine( pDocShell->GetDocument().GetNoteEngine() ) );
+ }
+ else
+ {
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->FreezeIdRanges();
+ pEditEngine.reset( new ScEditEngineDefaulter( pEnginePool.get(), true ) );
+ }
+ pForwarder.reset( new SvxEditEngineForwarder(*pEditEngine) );
+ }
+
+ if (bDataValid)
+ return pForwarder.get();
+
+ if ( pDocShell )
+ if ( ScPostIt* pNote = pDocShell->GetDocument().GetNote(aCellPos) )
+ if ( const EditTextObject* pEditObj = pNote->GetEditTextObject() )
+ pEditEngine->SetTextCurrentDefaults( *pEditObj ); // incl. breaks (line, etc.)
+
+ bDataValid = true;
+ return pForwarder.get();
+}
+
+void ScAnnotationEditSource::UpdateData()
+{
+ if ( !(pDocShell && pEditEngine) )
+ return;
+
+ ScDocShellModificator aModificator( *pDocShell );
+
+ if( SdrObject* pObj = GetCaptionObj() )
+ {
+ OutlinerParaObject aOPO( pEditEngine->CreateTextObject() );
+ aOPO.SetOutlinerMode( OutlinerMode::TextObject );
+ pObj->NbcSetOutlinerParaObject( std::move(aOPO) );
+ pObj->ActionChanged();
+ }
+
+ //! Undo !!!
+
+ aModificator.SetDocumentModified();
+
+ // SetDocumentModified will reset bDataValid
+}
+
+void ScAnnotationEditSource::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! reference update
+ }
+ else
+ {
+ const SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+
+ pForwarder.reset();
+ pEditEngine.reset(); // EditEngine uses document's pool
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ bDataValid = false; // text must be retrieved again
+ }
+}
+
+ScSimpleEditSource::ScSimpleEditSource( SvxTextForwarder* pForw ) :
+ pForwarder( pForw )
+{
+ // The same forwarder (and EditEngine) is shared by all children of the same Text object.
+ // Text range and cursor keep a reference to their parent text, so the text object is
+ // always alive and the forwarder is valid as long as there are children.
+}
+
+ScSimpleEditSource::~ScSimpleEditSource()
+{
+}
+
+std::unique_ptr<SvxEditSource> ScSimpleEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new ScSimpleEditSource( pForwarder ));
+}
+
+SvxTextForwarder* ScSimpleEditSource::GetTextForwarder()
+{
+ return pForwarder;
+}
+
+void ScSimpleEditSource::UpdateData()
+{
+ // nothing
+}
+
+ScAccessibilityEditSource::ScAccessibilityEditSource( ::std::unique_ptr < ScAccessibleTextData > && pAccessibleCellTextData )
+ : mpAccessibleTextData(std::move(pAccessibleCellTextData))
+{
+}
+
+ScAccessibilityEditSource::~ScAccessibilityEditSource()
+{
+}
+
+std::unique_ptr<SvxEditSource> ScAccessibilityEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new ScAccessibilityEditSource(::std::unique_ptr < ScAccessibleTextData > (mpAccessibleTextData->Clone())));
+}
+
+SvxTextForwarder* ScAccessibilityEditSource::GetTextForwarder()
+{
+ return mpAccessibleTextData->GetTextForwarder();
+}
+
+SvxViewForwarder* ScAccessibilityEditSource::GetViewForwarder()
+{
+ return mpAccessibleTextData->GetViewForwarder();
+}
+
+SvxEditViewForwarder* ScAccessibilityEditSource::GetEditViewForwarder( bool bCreate )
+{
+ return mpAccessibleTextData->GetEditViewForwarder(bCreate);
+}
+
+void ScAccessibilityEditSource::UpdateData()
+{
+ mpAccessibleTextData->UpdateData();
+}
+
+SfxBroadcaster& ScAccessibilityEditSource::GetBroadcaster() const
+{
+ return mpAccessibleTextData->GetBroadcaster();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/eventuno.cxx b/sc/source/ui/unoobj/eventuno.cxx
new file mode 100644
index 0000000000..88a3876378
--- /dev/null
+++ b/sc/source/ui/unoobj/eventuno.cxx
@@ -0,0 +1,174 @@
+/* -*- 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 <eventuno.hxx>
+#include <miscuno.hxx>
+#include <docsh.hxx>
+#include <sheetevents.hxx>
+#include <unonames.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+
+SC_SIMPLE_SERVICE_INFO( ScSheetEventsObj, "ScSheetEventsObj", "com.sun.star.document.Events" )
+
+ScSheetEventsObj::ScSheetEventsObj(ScDocShell* pDocSh, SCTAB nT) :
+ mpDocShell( pDocSh ),
+ mnTab( nT )
+{
+ mpDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScSheetEventsObj::~ScSheetEventsObj()
+{
+ SolarMutexGuard g;
+
+ if (mpDocShell)
+ mpDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScSheetEventsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! reference update
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ mpDocShell = nullptr;
+ }
+}
+
+static ScSheetEventId lcl_GetEventFromName( std::u16string_view aName )
+{
+ for (sal_Int32 nEvent=0; nEvent<static_cast<sal_Int32>(ScSheetEventId::COUNT); ++nEvent)
+ if ( aName == ScSheetEvents::GetEventName(static_cast<ScSheetEventId>(nEvent)) )
+ return static_cast<ScSheetEventId>(nEvent);
+
+ return ScSheetEventId::NOTFOUND; // not found
+}
+
+// XNameReplace
+
+void SAL_CALL ScSheetEventsObj::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ if (!mpDocShell)
+ throw uno::RuntimeException();
+
+ ScSheetEventId nEvent = lcl_GetEventFromName(aName);
+ if (nEvent == ScSheetEventId::NOTFOUND)
+ throw container::NoSuchElementException();
+
+ std::unique_ptr<ScSheetEvents> pNewEvents(new ScSheetEvents);
+ const ScSheetEvents* pOldEvents = mpDocShell->GetDocument().GetSheetEvents(mnTab);
+ if (pOldEvents)
+ *pNewEvents = *pOldEvents;
+
+ OUString aScript;
+ if ( aElement.hasValue() ) // empty Any -> reset event
+ {
+ uno::Sequence<beans::PropertyValue> aPropSeq;
+ if ( aElement >>= aPropSeq )
+ {
+ for (const beans::PropertyValue& rProp : std::as_const(aPropSeq))
+ {
+ if ( rProp.Name == SC_UNO_EVENTTYPE )
+ {
+ OUString aEventType;
+ if ( rProp.Value >>= aEventType )
+ {
+ // only "Script" is supported
+ if ( aEventType != SC_UNO_SCRIPT )
+ throw lang::IllegalArgumentException();
+ }
+ }
+ else if ( rProp.Name == SC_UNO_SCRIPT )
+ rProp.Value >>= aScript;
+ }
+ }
+ }
+ if (!aScript.isEmpty())
+ pNewEvents->SetScript( nEvent, &aScript );
+ else
+ pNewEvents->SetScript( nEvent, nullptr ); // reset
+
+ mpDocShell->GetDocument().SetSheetEvents( mnTab, std::move(pNewEvents) );
+ mpDocShell->SetDocumentModified();
+}
+
+// XNameAccess
+
+uno::Any SAL_CALL ScSheetEventsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ ScSheetEventId nEvent = lcl_GetEventFromName(aName);
+ if (nEvent == ScSheetEventId::NOTFOUND)
+ throw container::NoSuchElementException();
+
+ const OUString* pScript = nullptr;
+ if (mpDocShell)
+ {
+ const ScSheetEvents* pEvents = mpDocShell->GetDocument().GetSheetEvents(mnTab);
+ if (pEvents)
+ pScript = pEvents->GetScript(nEvent);
+ }
+
+ uno::Any aRet;
+ if (pScript)
+ {
+ uno::Sequence<beans::PropertyValue> aPropSeq( comphelper::InitPropertySequence({
+ { "EventType", uno::Any( OUString("Script") ) },
+ { "Script", uno::Any( *pScript ) }
+ }));
+ aRet <<= aPropSeq;
+ }
+ // empty Any if nothing was set
+ return aRet;
+}
+
+uno::Sequence<OUString> SAL_CALL ScSheetEventsObj::getElementNames()
+{
+ auto aNames = uno::Sequence<OUString>(int(ScSheetEventId::COUNT));
+ auto pNames = aNames.getArray();
+ for (sal_Int32 nEvent=0; nEvent<int(ScSheetEventId::COUNT); ++nEvent)
+ pNames[nEvent] = ScSheetEvents::GetEventName(static_cast<ScSheetEventId>(nEvent));
+ return aNames;
+}
+
+sal_Bool SAL_CALL ScSheetEventsObj::hasByName( const OUString& aName )
+{
+ ScSheetEventId nEvent = lcl_GetEventFromName(aName);
+ return (nEvent != ScSheetEventId::NOTFOUND);
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScSheetEventsObj::getElementType()
+{
+ return cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get();
+}
+
+sal_Bool SAL_CALL ScSheetEventsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ if (mpDocShell)
+ return true;
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/exceldetect.cxx b/sc/source/ui/unoobj/exceldetect.cxx
new file mode 100644
index 0000000000..0c4373356a
--- /dev/null
+++ b/sc/source/ui/unoobj/exceldetect.cxx
@@ -0,0 +1,198 @@
+/* -*- 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/.
+ */
+
+#include "exceldetect.hxx"
+
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <sfx2/docfile.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <sot/storage.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+using namespace com::sun::star;
+using utl::MediaDescriptor;
+
+ScExcelBiffDetect::ScExcelBiffDetect() {}
+ScExcelBiffDetect::~ScExcelBiffDetect() {}
+
+OUString ScExcelBiffDetect::getImplementationName()
+{
+ return "com.sun.star.comp.calc.ExcelBiffFormatDetector";
+}
+
+sal_Bool ScExcelBiffDetect::supportsService( const OUString& aName )
+{
+ return cppu::supportsService(this, aName);
+}
+
+uno::Sequence<OUString> ScExcelBiffDetect::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ExtendedTypeDetection" };
+}
+
+namespace {
+
+bool hasStream(const uno::Reference<io::XInputStream>& xInStream, const OUString& rName)
+{
+ SfxMedium aMedium;
+ aMedium.UseInteractionHandler(false);
+ aMedium.setStreamToLoadFrom(xInStream, true);
+ SvStream* pStream = aMedium.GetInStream();
+ if (!pStream)
+ return false;
+
+ sal_uInt64 const nSize = pStream->TellEnd();
+ pStream->Seek(0);
+
+ if (!nSize)
+ {
+ // 0-size stream. Failed.
+ return false;
+ }
+
+ try
+ {
+ tools::SvRef<SotStorage> xStorage = new SotStorage(pStream, false);
+ if (!xStorage.is() || xStorage->GetError())
+ return false;
+ return xStorage->IsStream(rName);
+ }
+ catch (const css::ucb::ContentCreationException &)
+ {
+ TOOLS_WARN_EXCEPTION("sc", "hasStream");
+ }
+
+ return false;
+}
+
+/**
+ * We detect BIFF 2, 3 and 4 file types together since the only thing that
+ * set them apart is the BOF ID.
+ */
+bool isExcel40(const uno::Reference<io::XInputStream>& xInStream)
+{
+ SfxMedium aMedium;
+ aMedium.UseInteractionHandler(false);
+ aMedium.setStreamToLoadFrom(xInStream, true);
+ SvStream* pStream = aMedium.GetInStream();
+ if (!pStream)
+ return false;
+
+ sal_uInt64 const nSize = pStream->TellEnd();
+ pStream->Seek(0);
+
+ if (nSize < 4)
+ return false;
+
+ sal_uInt16 nBofId, nBofSize;
+ pStream->ReadUInt16( nBofId ).ReadUInt16( nBofSize );
+
+ switch (nBofId)
+ {
+ case 0x0009: // Excel 2.1 worksheet (BIFF 2)
+ case 0x0209: // Excel 3.0 worksheet (BIFF 3)
+ case 0x0409: // Excel 4.0 worksheet (BIFF 4)
+ case 0x0809: // Excel 5.0 worksheet (BIFF 5), some apps create such files (fdo#70100)
+ break;
+ default:
+ return false;
+ }
+
+ if (nBofSize < 4 || 16 < nBofSize)
+ // BOF record must be sized between 4 and 16 for BIFF 2, 3 and 4.
+ return false;
+
+ sal_uInt64 const nPos = pStream->Tell();
+ if (nSize - nPos < nBofSize)
+ // BOF record doesn't have required bytes.
+ return false;
+
+ return true;
+}
+
+bool isTemplate(std::u16string_view rType)
+{
+ return rType.find(u"_VorlageTemplate") != std::u16string_view::npos;
+}
+
+}
+
+OUString ScExcelBiffDetect::detect( uno::Sequence<beans::PropertyValue>& lDescriptor )
+{
+ MediaDescriptor aMediaDesc(lDescriptor);
+ OUString aType;
+ aMediaDesc[MediaDescriptor::PROP_TYPENAME] >>= aType;
+ if (aType.isEmpty())
+ // Type is not given. We can't proceed.
+ return OUString();
+
+ aMediaDesc.addInputStream();
+ uno::Reference<io::XInputStream> xInStream(aMediaDesc[MediaDescriptor::PROP_INPUTSTREAM], uno::UNO_QUERY);
+ if (!xInStream.is())
+ // No input stream.
+ return OUString();
+
+ if (aType == "calc_MS_Excel_97" || aType == "calc_MS_Excel_97_VorlageTemplate")
+ {
+ // See if this stream is an Excel 97/XP/2003 (BIFF8) stream.
+ if (!hasStream(xInStream, "Workbook"))
+ // BIFF8 is expected to contain a stream named "Workbook".
+ return OUString();
+
+ aMediaDesc[MediaDescriptor::PROP_FILTERNAME] <<= isTemplate(aType) ? OUString("MS Excel 97 Vorlage/Template") : OUString("MS Excel 97");
+ }
+
+ else if (aType == "calc_MS_Excel_95" || aType == "calc_MS_Excel_95_VorlageTemplate")
+ {
+ // See if this stream is an Excel 95 (BIFF5) stream.
+ if (!hasStream(xInStream, "Book"))
+ return OUString();
+
+ aMediaDesc[MediaDescriptor::PROP_FILTERNAME] <<= isTemplate(aType) ? OUString("MS Excel 95 Vorlage/Template") : OUString("MS Excel 95");
+ }
+
+ else if (aType == "calc_MS_Excel_5095" || aType == "calc_MS_Excel_5095_VorlageTemplate")
+ {
+ // See if this stream is an Excel 5.0/95 stream.
+ if (!hasStream(xInStream, "Book"))
+ return OUString();
+
+ aMediaDesc[MediaDescriptor::PROP_FILTERNAME] <<= isTemplate(aType) ? OUString("MS Excel 5.0/95 Vorlage/Template") : OUString("MS Excel 5.0/95");
+ }
+
+ else if (aType == "calc_MS_Excel_40" || aType == "calc_MS_Excel_40_VorlageTemplate")
+ {
+ // See if this stream is an Excel 4.0 stream.
+ if (!isExcel40(xInStream))
+ return OUString();
+
+ aMediaDesc[MediaDescriptor::PROP_FILTERNAME] <<= isTemplate(aType) ? OUString("MS Excel 4.0 Vorlage/Template") : OUString("MS Excel 4.0");
+ }
+
+ else
+ // Nothing to detect.
+ return OUString();
+
+ aMediaDesc >> lDescriptor;
+ return aType;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_calc_ExcelBiffFormatDetector_get_implementation(css::uno::XComponentContext* /*context*/,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ScExcelBiffDetect);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/exceldetect.hxx b/sc/source/ui/unoobj/exceldetect.hxx
new file mode 100644
index 0000000000..7189637526
--- /dev/null
+++ b/sc/source/ui/unoobj/exceldetect.hxx
@@ -0,0 +1,34 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/document/XExtendedFilterDetection.hpp>
+
+class ScExcelBiffDetect
+ : public cppu::WeakImplHelper<css::document::XExtendedFilterDetection, css::lang::XServiceInfo>
+{
+public:
+ explicit ScExcelBiffDetect();
+ virtual ~ScExcelBiffDetect() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& aName) override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XExtendedFilterDetection
+ virtual OUString SAL_CALL
+ detect(css::uno::Sequence<css::beans::PropertyValue>& lDescriptor) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/fielduno.cxx b/sc/source/ui/unoobj/fielduno.cxx
new file mode 100644
index 0000000000..bdd3271a8b
--- /dev/null
+++ b/sc/source/ui/unoobj/fielduno.cxx
@@ -0,0 +1,1289 @@
+/* -*- 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 <memory>
+#include <fielduno.hxx>
+#include <textuno.hxx>
+#include <miscuno.hxx>
+#include <docsh.hxx>
+#include <hints.hxx>
+#include <editsrc.hxx>
+#include <unonames.hxx>
+#include <editutil.hxx>
+
+#include <svl/hint.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+
+#include <editeng/eeitem.hxx>
+
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/flditem.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/FilenameDisplayFormat.hpp>
+#include <com/sun/star/text/textfield/Type.hpp>
+
+using namespace com::sun::star;
+
+namespace {
+
+// no Which-ID here, map only for PropertySetInfo
+
+const SfxItemPropertySet* getDateTimePropertySet()
+{
+ static const SfxItemPropertyMapEntry aMapContent[] =
+ {
+ { SC_UNONAME_DATETIME, 0, cppu::UnoType<util::DateTime>::get(), 0, 0 },
+ { SC_UNONAME_ISFIXED, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_ISDATE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NUMFMT, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ };
+ static SfxItemPropertySet aMap(aMapContent);
+ return &aMap;
+}
+
+const SfxItemPropertySet* getEmptyPropertySet()
+{
+ static SfxItemPropertySet aMap({});
+ return &aMap;
+}
+
+const SfxItemPropertySet* lcl_GetURLPropertySet()
+{
+ static const SfxItemPropertyMapEntry aURLPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ANCTYPE, 0, cppu::UnoType<text::TextContentAnchorType>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ANCTYPES, 0, cppu::UnoType<uno::Sequence<text::TextContentAnchorType>>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_REPR, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_TARGET, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_TEXTWRAP, 0, cppu::UnoType<text::WrapTextMode>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_URL, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ };
+ static SfxItemPropertySet aURLPropertySet_Impl( aURLPropertyMap_Impl );
+ return &aURLPropertySet_Impl;
+}
+
+const SfxItemPropertySet* lcl_GetHeaderFieldPropertySet()
+{
+ static const SfxItemPropertyMapEntry aHeaderFieldPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ANCTYPE, 0, cppu::UnoType<text::TextContentAnchorType>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ANCTYPES, 0, cppu::UnoType<uno::Sequence<text::TextContentAnchorType>>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TEXTWRAP, 0, cppu::UnoType<text::WrapTextMode>::get(), beans::PropertyAttribute::READONLY, 0 },
+ };
+ static SfxItemPropertySet aHeaderFieldPropertySet_Impl( aHeaderFieldPropertyMap_Impl );
+ return &aHeaderFieldPropertySet_Impl;
+}
+
+const SfxItemPropertySet* lcl_GetFileFieldPropertySet()
+{
+ static const SfxItemPropertyMapEntry aFileFieldPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ANCTYPE, 0, cppu::UnoType<text::TextContentAnchorType>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ANCTYPES, 0, cppu::UnoType<uno::Sequence<text::TextContentAnchorType>>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_FILEFORM, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_TEXTWRAP, 0, cppu::UnoType<text::WrapTextMode>::get(), beans::PropertyAttribute::READONLY, 0 },
+ };
+ static SfxItemPropertySet aFileFieldPropertySet_Impl( aFileFieldPropertyMap_Impl );
+ return &aFileFieldPropertySet_Impl;
+}
+
+SvxFileFormat lcl_UnoToSvxFileFormat( sal_Int16 nUnoValue )
+{
+ switch( nUnoValue )
+ {
+ case text::FilenameDisplayFormat::FULL: return SvxFileFormat::PathFull;
+ case text::FilenameDisplayFormat::PATH: return SvxFileFormat::PathOnly;
+ case text::FilenameDisplayFormat::NAME: return SvxFileFormat::NameOnly;
+ default:
+ return SvxFileFormat::NameAndExt;
+ }
+}
+
+sal_Int16 lcl_SvxToUnoFileFormat( SvxFileFormat nSvxValue )
+{
+ switch( nSvxValue )
+ {
+ case SvxFileFormat::NameAndExt: return text::FilenameDisplayFormat::NAME_AND_EXT;
+ case SvxFileFormat::PathFull: return text::FilenameDisplayFormat::FULL;
+ case SvxFileFormat::PathOnly: return text::FilenameDisplayFormat::PATH;
+ default:
+ return text::FilenameDisplayFormat::NAME;
+ }
+}
+
+}
+
+SC_SIMPLE_SERVICE_INFO( ScCellFieldsObj, "ScCellFieldsObj", "com.sun.star.text.TextFields" )
+SC_SIMPLE_SERVICE_INFO( ScHeaderFieldsObj, "ScHeaderFieldsObj", "com.sun.star.text.TextFields" )
+
+namespace {
+
+enum ScUnoCollectMode
+{
+ SC_UNO_COLLECT_NONE,
+ SC_UNO_COLLECT_COUNT,
+ SC_UNO_COLLECT_FINDINDEX,
+ SC_UNO_COLLECT_FINDPOS
+};
+
+/**
+ * This class exists solely to allow searching through field items. TODO:
+ * Look into providing the same functionality directly in EditEngine, to
+ * avoid having this class altogether.
+ */
+class ScUnoEditEngine : public ScEditEngineDefaulter
+{
+ ScUnoCollectMode eMode;
+ sal_uInt16 nFieldCount;
+ sal_Int32 mnFieldType;
+ std::unique_ptr<SvxFieldData>
+ pFound; // local copy
+ sal_Int32 nFieldPar;
+ sal_Int32 nFieldPos;
+ sal_uInt16 nFieldIndex;
+
+public:
+ explicit ScUnoEditEngine(ScEditEngineDefaulter* pSource);
+
+ virtual OUString CalcFieldValue( const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos,
+ std::optional<Color>& rTxtColor, std::optional<Color>& rFldColor, std::optional<FontLineStyle>& rFldLineStyle ) override;
+
+ sal_uInt16 CountFields();
+ SvxFieldData* FindByIndex(sal_uInt16 nIndex);
+ SvxFieldData* FindByPos(sal_Int32 nPar, sal_Int32 nPos, sal_Int32 nType);
+
+ sal_Int32 GetFieldPar() const { return nFieldPar; }
+ sal_Int32 GetFieldPos() const { return nFieldPos; }
+};
+
+}
+
+ScUnoEditEngine::ScUnoEditEngine(ScEditEngineDefaulter* pSource)
+ : ScEditEngineDefaulter(*pSource)
+ , eMode(SC_UNO_COLLECT_NONE)
+ , nFieldCount(0)
+ , mnFieldType(text::textfield::Type::UNSPECIFIED)
+ , nFieldPar(0)
+ , nFieldPos(0)
+ , nFieldIndex(0)
+{
+ std::unique_ptr<EditTextObject> pData = pSource->CreateTextObject();
+ SetTextCurrentDefaults( *pData );
+}
+
+OUString ScUnoEditEngine::CalcFieldValue( const SvxFieldItem& rField,
+ sal_Int32 nPara, sal_Int32 nPos, std::optional<Color>& rTxtColor, std::optional<Color>& rFldColor, std::optional<FontLineStyle>& rFldLineStyle )
+{
+ OUString aRet(EditEngine::CalcFieldValue( rField, nPara, nPos, rTxtColor, rFldColor, rFldLineStyle ));
+ if (eMode != SC_UNO_COLLECT_NONE)
+ {
+ const SvxFieldData* pFieldData = rField.GetField();
+ if ( pFieldData )
+ {
+ if (mnFieldType == text::textfield::Type::UNSPECIFIED || pFieldData->GetClassId() == mnFieldType)
+ {
+ if ( eMode == SC_UNO_COLLECT_FINDINDEX && !pFound && nFieldCount == nFieldIndex )
+ {
+ pFound = pFieldData->Clone();
+ nFieldPar = nPara;
+ nFieldPos = nPos;
+ }
+ if ( eMode == SC_UNO_COLLECT_FINDPOS && !pFound &&
+ nPara == nFieldPar && nPos == nFieldPos )
+ {
+ pFound = pFieldData->Clone();
+ nFieldIndex = nFieldCount;
+ }
+ ++nFieldCount;
+ }
+ }
+ }
+ return aRet;
+}
+
+sal_uInt16 ScUnoEditEngine::CountFields()
+{
+ eMode = SC_UNO_COLLECT_COUNT;
+ mnFieldType = text::textfield::Type::UNSPECIFIED;
+ nFieldCount = 0;
+ UpdateFields();
+ eMode = SC_UNO_COLLECT_NONE;
+
+ return nFieldCount;
+}
+
+SvxFieldData* ScUnoEditEngine::FindByIndex(sal_uInt16 nIndex)
+{
+ eMode = SC_UNO_COLLECT_FINDINDEX;
+ nFieldIndex = nIndex;
+ mnFieldType = text::textfield::Type::UNSPECIFIED;
+ nFieldCount = 0;
+ UpdateFields();
+ eMode = SC_UNO_COLLECT_NONE;
+
+ return pFound.get();
+}
+
+SvxFieldData* ScUnoEditEngine::FindByPos(sal_Int32 nPar, sal_Int32 nPos, sal_Int32 nType)
+{
+ eMode = SC_UNO_COLLECT_FINDPOS;
+ nFieldPar = nPar;
+ nFieldPos = nPos;
+ mnFieldType = nType;
+ nFieldCount = 0;
+ UpdateFields();
+ mnFieldType = text::textfield::Type::UNSPECIFIED;
+ eMode = SC_UNO_COLLECT_NONE;
+
+ return pFound.get();
+}
+
+ScCellFieldsObj::ScCellFieldsObj(
+ uno::Reference<text::XTextRange> xContent,
+ ScDocShell* pDocSh, const ScAddress& rPos) :
+ mxContent(std::move(xContent)),
+ pDocShell( pDocSh ),
+ aCellPos( rPos )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ mpEditSource.reset( new ScCellEditSource( pDocShell, aCellPos ) );
+}
+
+ScCellFieldsObj::~ScCellFieldsObj()
+{
+ {
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+
+ mpEditSource.reset();
+ }
+
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+
+ std::unique_lock g(aMutex);
+ if (maRefreshListeners.getLength(g))
+ {
+ lang::EventObject aEvent;
+ aEvent.Source.set(getXWeak());
+ maRefreshListeners.disposeAndClear(g, aEvent);
+ }
+}
+
+void ScCellFieldsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! update of references
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+
+ // EditSource registered itself as a listener
+}
+
+// XIndexAccess (via XTextFields)
+
+uno::Reference<text::XTextField> ScCellFieldsObj::GetObjectByIndex_Impl(sal_Int32 Index) const
+{
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ SvxFieldData* pData = aTempEngine.FindByIndex(static_cast<sal_uInt16>(Index));
+ if (!pData)
+ return uno::Reference<text::XTextField>();
+
+ sal_Int32 nPar = aTempEngine.GetFieldPar();
+ sal_Int32 nPos = aTempEngine.GetFieldPos();
+ ESelection aSelection( nPar, nPos, nPar, nPos+1 ); // Field size is 1 character
+
+ sal_Int32 eType = pData->GetClassId();
+ uno::Reference<text::XTextField> xRet(
+ new ScEditFieldObj(mxContent, std::make_unique<ScCellEditSource>(pDocShell, aCellPos), eType, aSelection));
+ return xRet;
+}
+
+sal_Int32 SAL_CALL ScCellFieldsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ return aTempEngine.CountFields(); // count the fields, we don't care about their type in the cell
+}
+
+uno::Any SAL_CALL ScCellFieldsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<text::XTextField> xField(GetObjectByIndex_Impl(nIndex));
+ if (!xField.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xField);
+}
+
+uno::Type SAL_CALL ScCellFieldsObj::getElementType()
+{
+ return cppu::UnoType<text::XTextField>::get();
+}
+
+sal_Bool SAL_CALL ScCellFieldsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Reference<container::XEnumeration> SAL_CALL ScCellFieldsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.text.TextFieldEnumeration");
+}
+
+void SAL_CALL ScCellFieldsObj::addContainerListener(
+ const uno::Reference<container::XContainerListener>& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellFieldsObj::removeContainerListener(
+ const uno::Reference<container::XContainerListener>& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+// XRefreshable
+void SAL_CALL ScCellFieldsObj::refresh( )
+{
+ std::unique_lock g(aMutex);
+ if (maRefreshListeners.getLength(g))
+ {
+ // Call all listeners.
+ lang::EventObject aEvent;
+ aEvent.Source.set(uno::Reference< util::XRefreshable >(this));
+ maRefreshListeners.notifyEach( g, &util::XRefreshListener::refreshed, aEvent );
+ }
+}
+
+void SAL_CALL ScCellFieldsObj::addRefreshListener( const uno::Reference< util::XRefreshListener >& xListener )
+{
+ if (xListener.is())
+ {
+ std::unique_lock g(aMutex);
+ maRefreshListeners.addInterface(g, xListener);
+ }
+}
+
+void SAL_CALL ScCellFieldsObj::removeRefreshListener( const uno::Reference<util::XRefreshListener >& xListener )
+{
+ if (xListener.is())
+ {
+ std::unique_lock g(aMutex);
+ maRefreshListeners.removeInterface(g, xListener);
+ }
+}
+
+ScHeaderFieldsObj::ScHeaderFieldsObj(ScHeaderFooterTextData& rData) :
+ mrData(rData)
+{
+ mpEditSource.reset( new ScHeaderFooterEditSource(rData) );
+}
+
+ScHeaderFieldsObj::~ScHeaderFieldsObj()
+{
+ mpEditSource.reset();
+
+ // increment refcount to prevent double call of dtor
+ osl_atomic_increment( &m_refCount );
+
+ std::unique_lock g(aMutex);
+ if (maRefreshListeners.getLength(g))
+ {
+ lang::EventObject aEvent;
+ aEvent.Source = getXWeak();
+ maRefreshListeners.disposeAndClear(g, aEvent);
+ }
+}
+
+// XIndexAccess (via XTextFields)
+
+uno::Reference<text::XTextField> ScHeaderFieldsObj::GetObjectByIndex_Impl(sal_Int32 Index) const
+{
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ SvxFieldData* pData = aTempEngine.FindByIndex(static_cast<sal_uInt16>(Index));
+ if (!pData)
+ return nullptr;
+
+ // Get the parent text range instance.
+ uno::Reference<text::XTextRange> xTextRange;
+ uno::Reference<sheet::XHeaderFooterContent> xContentObj = mrData.GetContentObj();
+ if (!xContentObj.is())
+ throw uno::RuntimeException("");
+
+ rtl::Reference<ScHeaderFooterContentObj> pContentObj = ScHeaderFooterContentObj::getImplementation(xContentObj);
+ uno::Reference<text::XText> xText;
+
+ switch ( mrData.GetPart() )
+ {
+ case ScHeaderFooterPart::LEFT:
+ xText = pContentObj->getLeftText();
+ break;
+ case ScHeaderFooterPart::CENTER:
+ xText = pContentObj->getCenterText();
+ break;
+ case ScHeaderFooterPart::RIGHT:
+ xText = pContentObj->getRightText();
+ break;
+ }
+
+ xTextRange = xText;
+
+ sal_Int32 nPar = aTempEngine.GetFieldPar();
+ sal_Int32 nPos = aTempEngine.GetFieldPos();
+ ESelection aSelection( nPar, nPos, nPar, nPos+1 ); // Field size is 1 character
+
+ sal_Int32 eRealType = pData->GetClassId();
+ uno::Reference<text::XTextField> xRet(
+ new ScEditFieldObj(xTextRange, std::make_unique<ScHeaderFooterEditSource>(mrData), eRealType, aSelection));
+ return xRet;
+}
+
+sal_Int32 SAL_CALL ScHeaderFieldsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ return aTempEngine.CountFields();
+}
+
+uno::Any SAL_CALL ScHeaderFieldsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<text::XTextField> xField(GetObjectByIndex_Impl(nIndex));
+ if (!xField.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xField);
+}
+
+uno::Type SAL_CALL ScHeaderFieldsObj::getElementType()
+{
+ return cppu::UnoType<text::XTextField>::get();
+}
+
+sal_Bool SAL_CALL ScHeaderFieldsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Reference<container::XEnumeration> SAL_CALL ScHeaderFieldsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.text.TextFieldEnumeration");
+}
+
+void SAL_CALL ScHeaderFieldsObj::addContainerListener(
+ const uno::Reference<container::XContainerListener>& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScHeaderFieldsObj::removeContainerListener(
+ const uno::Reference<container::XContainerListener>& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+// XRefreshable
+void SAL_CALL ScHeaderFieldsObj::refresh( )
+{
+ std::unique_lock g(aMutex);
+ if (maRefreshListeners.getLength(g))
+ {
+ // Call all listeners.
+ lang::EventObject aEvent;
+ aEvent.Source.set(uno::Reference< util::XRefreshable >(this));
+ maRefreshListeners.notifyEach( g, &util::XRefreshListener::refreshed, aEvent);
+ }
+}
+
+void SAL_CALL ScHeaderFieldsObj::addRefreshListener( const uno::Reference< util::XRefreshListener >& xListener )
+{
+ if (xListener.is())
+ {
+ std::unique_lock g(aMutex);
+ maRefreshListeners.addInterface(g, xListener);
+ }
+}
+
+void SAL_CALL ScHeaderFieldsObj::removeRefreshListener( const uno::Reference<util::XRefreshListener >& xListener )
+{
+ if (xListener.is())
+ {
+ std::unique_lock g(aMutex);
+ maRefreshListeners.removeInterface(g, xListener);
+ }
+}
+
+SvxFieldData& ScEditFieldObj::getData()
+{
+ if (!mpData)
+ {
+ switch (meType)
+ {
+ case text::textfield::Type::DATE:
+ mpData.reset(new SvxDateField);
+ break;
+ case text::textfield::Type::EXTENDED_FILE:
+ mpData.reset(
+ new SvxExtFileField(OUString(), SvxFileType::Var, SvxFileFormat::NameAndExt));
+ break;
+ case text::textfield::Type::PAGE:
+ mpData.reset(new SvxPageField);
+ break;
+ case text::textfield::Type::PAGES:
+ mpData.reset(new SvxPagesField);
+ break;
+ case text::textfield::Type::TABLE:
+ mpData.reset(new SvxTableField);
+ break;
+ case text::textfield::Type::TIME:
+ mpData.reset(new SvxTimeField);
+ break;
+ case text::textfield::Type::EXTENDED_TIME:
+ {
+ if (mbIsDate)
+ mpData.reset(new SvxDateField);
+ else
+ mpData.reset(new SvxExtTimeField);
+ }
+ break;
+ case text::textfield::Type::DOCINFO_TITLE:
+ mpData.reset(new SvxFileField);
+ break;
+ case text::textfield::Type::URL:
+ mpData.reset(
+ new SvxURLField(OUString(), OUString(), SvxURLFormat::AppDefault));
+ break;
+ default:
+ mpData.reset(new SvxFieldData);
+ }
+ }
+ return *mpData;
+}
+
+void ScEditFieldObj::setPropertyValueURL(const OUString& rName, const css::uno::Any& rVal)
+{
+ OUString aStrVal;
+ if (mpEditSource)
+ {
+ // Edit engine instance already exists for this field item. Use it.
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ // don't care about the type (only URLs can be found in the cells)
+ SvxFieldData* pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::UNSPECIFIED);
+ OSL_ENSURE(pField,"setPropertyValue: Field not found");
+ if (!pField)
+ return;
+
+ if (pField->GetClassId() != text::textfield::Type::URL)
+ // Make sure this is indeed a URL field.
+ return;
+
+ SvxURLField* pURL = static_cast<SvxURLField*>(pField);
+
+ if (rName == SC_UNONAME_URL)
+ {
+ if (rVal >>= aStrVal)
+ pURL->SetURL(aStrVal);
+ }
+ else if (rName == SC_UNONAME_REPR)
+ {
+ if (rVal >>= aStrVal)
+ pURL->SetRepresentation(aStrVal);
+ }
+ else if (rName == SC_UNONAME_TARGET)
+ {
+ if (rVal >>= aStrVal)
+ pURL->SetTargetFrame(aStrVal);
+ }
+ else
+ throw beans::UnknownPropertyException(rName);
+
+ pEditEngine->QuickInsertField( SvxFieldItem(*pField, EE_FEATURE_FIELD), aSelection );
+ mpEditSource->UpdateData();
+ return;
+ }
+
+ // Edit engine instance not yet present. Store the item data for later use.
+ SvxURLField& rData = static_cast<SvxURLField&>(getData());
+ if (rName == SC_UNONAME_URL)
+ {
+ if (rVal >>= aStrVal)
+ rData.SetURL(aStrVal);
+ }
+ else if (rName == SC_UNONAME_REPR)
+ {
+ if (rVal >>= aStrVal)
+ rData.SetRepresentation(aStrVal);
+ }
+ else if (rName == SC_UNONAME_TARGET)
+ {
+ if (rVal >>= aStrVal)
+ rData.SetTargetFrame(aStrVal);
+ }
+ else
+ throw beans::UnknownPropertyException(rName);
+}
+
+uno::Any ScEditFieldObj::getPropertyValueURL(const OUString& rName)
+{
+ uno::Any aRet;
+
+ // anchor type is always "as character", text wrap always "none"
+
+ if (mpEditSource)
+ {
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ // don't care about the type (only URLs can be found in the cells)
+ const SvxFieldData* pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::UNSPECIFIED);
+ OSL_ENSURE(pField,"getPropertyValue: Field not found");
+ if (!pField)
+ throw uno::RuntimeException();
+
+ if (pField->GetClassId() != text::textfield::Type::URL)
+ throw uno::RuntimeException();
+
+ const SvxURLField* pURL = static_cast<const SvxURLField*>(pField);
+
+ if (rName == SC_UNONAME_URL)
+ aRet <<= pURL->GetURL();
+ else if (rName == SC_UNONAME_REPR)
+ aRet <<= pURL->GetRepresentation();
+ else if (rName == SC_UNONAME_TARGET)
+ aRet <<= pURL->GetTargetFrame();
+ else
+ throw beans::UnknownPropertyException(rName);
+ }
+ else // not inserted yet
+ {
+ const SvxURLField& rURL = static_cast<const SvxURLField&>(getData());
+
+ if (rName == SC_UNONAME_URL)
+ aRet <<= rURL.GetURL();
+ else if (rName == SC_UNONAME_REPR)
+ aRet <<= rURL.GetRepresentation();
+ else if (rName == SC_UNONAME_TARGET)
+ aRet <<= rURL.GetTargetFrame();
+ else
+ throw beans::UnknownPropertyException(rName);
+ }
+ return aRet;
+}
+
+void ScEditFieldObj::setPropertyValueFile(const OUString& rName, const uno::Any& rVal)
+{
+ if (rName != SC_UNONAME_FILEFORM)
+ throw beans::UnknownPropertyException(rName);
+
+ sal_Int16 nIntVal = 0;
+ if (!(rVal >>= nIntVal))
+ return;
+
+ SvxFileFormat eFormat = lcl_UnoToSvxFileFormat(nIntVal);
+ if (mpEditSource)
+ {
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ SvxFieldData* pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::EXTENDED_FILE);
+ OSL_ENSURE(pField, "setPropertyValueFile: Field not found");
+ if (pField)
+ {
+ SvxExtFileField* pExtFile = static_cast<SvxExtFileField*>(pField); // local to the ScUnoEditEngine
+ pExtFile->SetFormat(eFormat);
+ pEditEngine->QuickInsertField(SvxFieldItem(*pField, EE_FEATURE_FIELD), aSelection);
+ mpEditSource->UpdateData();
+ }
+ }
+ else
+ {
+ SvxExtFileField& rExtFile = static_cast<SvxExtFileField&>(getData());
+ rExtFile.SetFormat(eFormat);
+ }
+
+}
+
+uno::Any ScEditFieldObj::getPropertyValueFile(const OUString& rName)
+{
+ uno::Any aRet;
+ if (rName != SC_UNONAME_FILEFORM)
+ throw beans::UnknownPropertyException(rName);
+
+ SvxFileFormat eFormat = SvxFileFormat::NameAndExt;
+ const SvxFieldData* pField = nullptr;
+ if (mpEditSource)
+ {
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::EXTENDED_FILE);
+ }
+ else
+ pField = &getData();
+
+ OSL_ENSURE(pField, "setPropertyValueFile: Field not found");
+ if (!pField)
+ throw uno::RuntimeException();
+
+ const SvxExtFileField* pExtFile = static_cast<const SvxExtFileField*>(pField);
+ eFormat = pExtFile->GetFormat();
+ sal_Int16 nIntVal = lcl_SvxToUnoFileFormat(eFormat);
+ aRet <<= nIntVal;
+
+ return aRet;
+}
+
+void ScEditFieldObj::setPropertyValueDateTime(const OUString& rName, const uno::Any& rVal)
+{
+ if (mpEditSource)
+ {
+ // Field already inserted.
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ SvxFieldData* pField = aTempEngine.FindByPos(aSelection.nStartPara, aSelection.nStartPos, meType);
+ if (!pField)
+ return;
+
+ switch (meType)
+ {
+ case text::textfield::Type::DATE:
+ {
+ SvxDateField* p = static_cast<SvxDateField*>(pField);
+ if (rName == SC_UNONAME_ISDATE)
+ {
+ // Do nothing for now.
+ }
+ else if (rName == SC_UNONAME_ISFIXED)
+ {
+ SvxDateType eType = rVal.get<bool>() ? SvxDateType::Fix : SvxDateType::Var;
+ p->SetType(eType);
+ }
+ else if (rName == SC_UNONAME_DATETIME)
+ {
+ maDateTime = rVal.get<util::DateTime>();
+ Date aDate(maDateTime.Day, maDateTime.Month, maDateTime.Year);
+ p->SetFixDate(aDate);
+ }
+ else if (rName == SC_UNONAME_NUMFMT)
+ {
+ mnNumFormat = rVal.get<sal_Int32>();
+ p->SetFormat(static_cast<SvxDateFormat>(mnNumFormat));
+ }
+ else
+ throw beans::UnknownPropertyException(rName);
+ }
+ break;
+ case text::textfield::Type::TIME:
+ {
+ // SvxTimeField doesn't have any attributes.
+ if (rName != SC_UNONAME_ISDATE && rName != SC_UNONAME_ISFIXED &&
+ rName != SC_UNONAME_DATETIME && rName != SC_UNONAME_NUMFMT)
+ throw beans::UnknownPropertyException(rName);
+ }
+ break;
+ case text::textfield::Type::EXTENDED_TIME:
+ {
+ SvxExtTimeField* p = static_cast<SvxExtTimeField*>(pField);
+ if (rName == SC_UNONAME_ISDATE)
+ {
+ // Do nothing for now.
+ }
+ else if (rName == SC_UNONAME_ISFIXED)
+ {
+ SvxTimeType eType = rVal.get<bool>() ? SvxTimeType::Fix : SvxTimeType::Var;
+ p->SetType(eType);
+ }
+ else if (rName == SC_UNONAME_DATETIME)
+ {
+ maDateTime = rVal.get<util::DateTime>();
+ tools::Time aTime(maDateTime);
+ p->SetFixTime(aTime);
+ }
+ else if (rName == SC_UNONAME_NUMFMT)
+ {
+ mnNumFormat = rVal.get<sal_Int32>();
+ p->SetFormat(static_cast<SvxTimeFormat>(mnNumFormat));
+ }
+ else
+ throw beans::UnknownPropertyException(rName);
+ }
+ break;
+ default:
+ throw beans::UnknownPropertyException(rName);
+ }
+ }
+ else
+ {
+ if (rName == SC_UNONAME_ISDATE)
+ mbIsDate = rVal.get<bool>();
+ else if (rName == SC_UNONAME_ISFIXED)
+ mbIsFixed = rVal.get<bool>();
+ else if (rName == SC_UNONAME_DATETIME)
+ maDateTime = rVal.get<util::DateTime>();
+ else if (rName == SC_UNONAME_NUMFMT)
+ mnNumFormat = rVal.get<sal_Int32>();
+ else
+ throw beans::UnknownPropertyException(rName);
+ }
+}
+
+uno::Any ScEditFieldObj::getPropertyValueDateTime(const OUString& rName)
+{
+ if (mpEditSource)
+ {
+ // Field already inserted.
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ SvxFieldData* pField = aTempEngine.FindByPos(aSelection.nStartPara, aSelection.nStartPos, meType);
+ if (!pField)
+ throw uno::RuntimeException();
+
+ switch (meType)
+ {
+ case text::textfield::Type::DATE:
+ {
+ SvxDateField* p = static_cast<SvxDateField*>(pField);
+ if (rName == SC_UNONAME_ISDATE)
+ return uno::Any(true);
+
+ if (rName == SC_UNONAME_ISFIXED)
+ return uno::Any(p->GetType() == SvxDateType::Fix);
+
+ if (rName == SC_UNONAME_DATETIME)
+ {
+ Date aD(p->GetFixDate());
+ maDateTime.Year = aD.GetYear();
+ maDateTime.Month = aD.GetMonth();
+ maDateTime.Day = aD.GetDay();
+ maDateTime.Hours = 0;
+ maDateTime.Minutes = 0;
+ maDateTime.Seconds = 0;
+ maDateTime.NanoSeconds = 0;
+ return uno::Any(maDateTime);
+ }
+
+ if (rName == SC_UNONAME_NUMFMT)
+ return uno::Any(static_cast<sal_Int32>(p->GetFormat()));
+ }
+ break;
+ case text::textfield::Type::TIME:
+ {
+ // SvxTimeField doesn't have any attributes.
+ if (rName == SC_UNONAME_ISDATE)
+ return uno::Any(false);
+
+ if (rName == SC_UNONAME_ISFIXED)
+ return uno::Any(false);
+
+ if (rName == SC_UNONAME_DATETIME)
+ // This is the best we can do.
+ return uno::Any(maDateTime);
+
+ if (rName == SC_UNONAME_NUMFMT)
+ // Same as above.
+ return uno::Any(sal_Int32(0));
+ }
+ break;
+ case text::textfield::Type::EXTENDED_TIME:
+ {
+ SvxExtTimeField* p = static_cast<SvxExtTimeField*>(pField);
+ if (rName == SC_UNONAME_ISDATE)
+ return uno::Any(false);
+
+ if (rName == SC_UNONAME_ISFIXED)
+ return uno::Any(p->GetType() == SvxTimeType::Fix);
+
+ if (rName == SC_UNONAME_DATETIME)
+ {
+ tools::Time aT(p->GetFixTime());
+ maDateTime.Year = 0;
+ maDateTime.Month = 0;
+ maDateTime.Day = 0;
+ maDateTime.Hours = aT.GetHour();
+ maDateTime.Minutes = aT.GetMin();
+ maDateTime.Seconds = aT.GetSec();
+ maDateTime.NanoSeconds = aT.GetNanoSec();
+ return uno::Any(maDateTime);
+ }
+
+ if (rName == SC_UNONAME_NUMFMT)
+ return uno::Any(static_cast<sal_Int32>(p->GetFormat()));
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ else
+ {
+ if (rName == SC_UNONAME_ISDATE)
+ return uno::Any(mbIsDate);
+
+ if (rName == SC_UNONAME_ISFIXED)
+ return uno::Any(mbIsFixed);
+
+ if (rName == SC_UNONAME_DATETIME)
+ return uno::Any(maDateTime);
+
+ if (rName == SC_UNONAME_NUMFMT)
+ return uno::Any(mnNumFormat);
+ }
+
+ throw beans::UnknownPropertyException(rName);
+}
+
+void ScEditFieldObj::setPropertyValueSheet(const OUString& rName, const uno::Any& rVal)
+{
+ if (mpEditSource)
+ {
+ // Edit engine instance already exists for this field item. Use it.
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ // don't care about the type (only URLs can be found in the cells)
+ SvxFieldData* pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::UNSPECIFIED);
+ OSL_ENSURE(pField,"setPropertyValue: Field not found");
+ if (!pField)
+ return;
+
+ if (pField->GetClassId() != text::textfield::Type::TABLE)
+ // Make sure this is indeed a URL field.
+ return;
+
+ SvxTableField* p = static_cast<SvxTableField*>(pField);
+
+ if (rName != SC_UNONAME_TABLEPOS)
+ throw beans::UnknownPropertyException(rName);
+
+ sal_Int32 nTab = rVal.get<sal_Int32>();
+ p->SetTab(nTab);
+
+
+ pEditEngine->QuickInsertField(SvxFieldItem(*pField, EE_FEATURE_FIELD), aSelection);
+ mpEditSource->UpdateData();
+ return;
+ }
+
+ // Edit engine instance not yet present. Store the item data for later use.
+ SvxTableField& r = static_cast<SvxTableField&>(getData());
+ if (rName != SC_UNONAME_TABLEPOS)
+ throw beans::UnknownPropertyException(rName);
+
+ sal_Int32 nTab = rVal.get<sal_Int32>();
+ r.SetTab(nTab);
+}
+
+ScEditFieldObj::ScEditFieldObj(
+ uno::Reference<text::XTextRange> xContent,
+ std::unique_ptr<ScEditSource> pEditSrc, sal_Int32 eType, const ESelection& rSel) :
+ pPropSet(nullptr),
+ mpEditSource(std::move(pEditSrc)),
+ aSelection(rSel),
+ meType(eType), mpContent(std::move(xContent)), mnNumFormat(0), mbIsDate(false), mbIsFixed(false)
+{
+ switch (meType)
+ {
+ case text::textfield::Type::DOCINFO_TITLE:
+ pPropSet = getEmptyPropertySet();
+ break;
+ case text::textfield::Type::EXTENDED_FILE:
+ pPropSet = lcl_GetFileFieldPropertySet();
+ break;
+ case text::textfield::Type::URL:
+ pPropSet = lcl_GetURLPropertySet();
+ break;
+ case text::textfield::Type::DATE:
+ case text::textfield::Type::TIME:
+ case text::textfield::Type::EXTENDED_TIME:
+ pPropSet = getDateTimePropertySet();
+ break;
+ default:
+ pPropSet = lcl_GetHeaderFieldPropertySet();
+ }
+
+ if (meType == text::textfield::Type::DATE)
+ mbIsDate = true;
+}
+
+void ScEditFieldObj::InitDoc(
+ const uno::Reference<text::XTextRange>& rContent, std::unique_ptr<ScEditSource> pEditSrc, const ESelection& rSel)
+{
+ if (!mpEditSource)
+ {
+ mpContent = rContent;
+ mpData.reset();
+
+ aSelection = rSel;
+ mpEditSource = std::move( pEditSrc );
+ }
+}
+
+ScEditFieldObj::~ScEditFieldObj()
+{
+}
+
+SvxFieldItem ScEditFieldObj::CreateFieldItem()
+{
+ OSL_ENSURE( !mpEditSource, "CreateFieldItem with inserted field" );
+ return SvxFieldItem(getData(), EE_FEATURE_FIELD);
+}
+
+void ScEditFieldObj::DeleteField()
+{
+ if (mpEditSource)
+ {
+ SvxTextForwarder* pForwarder = mpEditSource->GetTextForwarder();
+ pForwarder->QuickInsertText( OUString(), aSelection );
+ mpEditSource->UpdateData();
+
+ aSelection.nEndPara = aSelection.nStartPara;
+ aSelection.nEndPos = aSelection.nStartPos;
+
+ //! Broadcast in order to adjust selection in other objects
+ //! (also for other actions)
+ }
+}
+
+bool ScEditFieldObj::IsInserted() const
+{
+ return mpEditSource != nullptr;
+}
+
+// XTextField
+
+OUString SAL_CALL ScEditFieldObj::getPresentation( sal_Bool bShowCommand )
+{
+ SolarMutexGuard aGuard;
+
+ if (!mpEditSource)
+ return OUString();
+
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ // don't care about the type (only URLs can be found in the cells)
+ const SvxFieldData* pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::UNSPECIFIED);
+ OSL_ENSURE(pField,"getPresentation: Field not found");
+ if (!pField)
+ return OUString();
+
+ switch (meType)
+ {
+ case text::textfield::Type::URL:
+ {
+ if (pField->GetClassId() != text::textfield::Type::URL)
+ // Not a URL field, but URL is expected.
+ throw uno::RuntimeException();
+
+ const SvxURLField* pURL = static_cast<const SvxURLField*>(pField);
+ return bShowCommand ? pURL->GetURL() : pURL->GetRepresentation();
+ }
+ break;
+ default:
+ ;
+ }
+ return OUString();
+}
+
+// XTextContent
+
+void SAL_CALL ScEditFieldObj::attach( const uno::Reference<text::XTextRange>& xTextRange )
+{
+ SolarMutexGuard aGuard;
+ if (xTextRange.is())
+ {
+ uno::Reference<text::XText> xText(xTextRange->getText());
+ if (xText.is())
+ {
+ xText->insertTextContent( xTextRange, this, true );
+ }
+ }
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScEditFieldObj::getAnchor()
+{
+ SolarMutexGuard aGuard;
+ return mpContent;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScEditFieldObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<beans::XPropertySetInfo> aRef = pPropSet->getPropertySetInfo();
+ return aRef;
+}
+
+void SAL_CALL ScEditFieldObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ if (aPropertyName == SC_UNONAME_ANCHOR)
+ {
+ aValue >>= mpContent;
+ return;
+ }
+
+ switch (meType)
+ {
+ case text::textfield::Type::URL:
+ setPropertyValueURL(aPropertyName, aValue);
+ break;
+ case text::textfield::Type::EXTENDED_FILE:
+ setPropertyValueFile(aPropertyName, aValue);
+ break;
+ case text::textfield::Type::DATE:
+ case text::textfield::Type::TIME:
+ case text::textfield::Type::EXTENDED_TIME:
+ setPropertyValueDateTime(aPropertyName, aValue);
+ break;
+ case text::textfield::Type::TABLE:
+ setPropertyValueSheet(aPropertyName, aValue);
+ break;
+ case text::textfield::Type::DOCINFO_TITLE:
+ default:
+ throw beans::UnknownPropertyException(OUString::number(meType));
+ }
+}
+
+uno::Any SAL_CALL ScEditFieldObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ if (aPropertyName == SC_UNONAME_TEXTFIELD_TYPE)
+ return uno::Any(meType);
+
+ if (aPropertyName == SC_UNONAME_ANCHOR)
+ return uno::Any(mpContent);
+
+ if (aPropertyName == SC_UNONAME_ANCTYPE)
+ {
+ uno::Any aRet;
+ aRet <<= text::TextContentAnchorType_AS_CHARACTER;
+ return aRet;
+ }
+ if (aPropertyName == SC_UNONAME_ANCTYPES)
+ {
+ uno::Any aRet;
+ uno::Sequence<text::TextContentAnchorType> aSeq { text::TextContentAnchorType_AS_CHARACTER };
+ aRet <<= aSeq;
+ return aRet;
+ }
+ if (aPropertyName == SC_UNONAME_TEXTWRAP)
+ {
+ uno::Any aRet;
+ aRet <<= text::WrapTextMode_NONE;
+ return aRet;
+ }
+
+ switch (meType)
+ {
+ case text::textfield::Type::URL:
+ return getPropertyValueURL(aPropertyName);
+ case text::textfield::Type::EXTENDED_FILE:
+ return getPropertyValueFile(aPropertyName);
+ case text::textfield::Type::DATE:
+ case text::textfield::Type::TIME:
+ case text::textfield::Type::EXTENDED_TIME:
+ return getPropertyValueDateTime(aPropertyName);
+ case text::textfield::Type::DOCINFO_TITLE:
+ default:
+ throw beans::UnknownPropertyException(OUString::number(meType));
+ }
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScEditFieldObj )
+
+// XServiceInfo
+
+OUString SAL_CALL ScEditFieldObj::getImplementationName()
+{
+ return "ScEditFieldObj";
+}
+
+sal_Bool SAL_CALL ScEditFieldObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScEditFieldObj::getSupportedServiceNames()
+{
+ return {"com.sun.star.text.TextField",
+ "com.sun.star.text.TextContent"};
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScEditFieldObj::getTypes()
+{
+ return comphelper::concatSequences(
+ ScEditFieldObj_Base::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<text::XTextField>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get()
+ } );
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScEditFieldObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/filtuno.cxx b/sc/source/ui/unoobj/filtuno.cxx
new file mode 100644
index 0000000000..fa520e23ae
--- /dev/null
+++ b/sc/source/ui/unoobj/filtuno.cxx
@@ -0,0 +1,371 @@
+/* -*- 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 <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <tools/urlobj.hxx>
+#include <vcl/svapp.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <connectivity/dbtools.hxx>
+#include <osl/diagnose.h>
+
+#include <filtuno.hxx>
+#include <miscuno.hxx>
+#include <scdll.hxx>
+#include <imoptdlg.hxx>
+#include <asciiopt.hxx>
+#include <docsh.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <scabstdlg.hxx>
+#include <i18nlangtag/lang.h>
+
+#include <optutil.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace connectivity::dbase;
+
+constexpr OUString SCFILTEROPTIONSOBJ_SERVICE = u"com.sun.star.ui.dialogs.FilterOptionsDialog"_ustr;
+constexpr OUStringLiteral SCFILTEROPTIONSOBJ_IMPLNAME = u"com.sun.star.comp.Calc.FilterOptionsDialog";
+
+SC_SIMPLE_SERVICE_INFO( ScFilterOptionsObj, SCFILTEROPTIONSOBJ_IMPLNAME, SCFILTEROPTIONSOBJ_SERVICE )
+
+constexpr OUStringLiteral SC_UNONAME_FILENAME = u"URL";
+constexpr OUStringLiteral SC_UNONAME_FILTERNAME = u"FilterName";
+constexpr OUString SC_UNONAME_FILTEROPTIONS = u"FilterOptions"_ustr;
+constexpr OUStringLiteral SC_UNONAME_INPUTSTREAM = u"InputStream";
+
+constexpr OUString DBF_CHAR_SET = u"CharSet"_ustr;
+constexpr OUString DBF_SEP_PATH_IMPORT = u"Office.Calc/Dialogs/DBFImport"_ustr;
+constexpr OUString DBF_SEP_PATH_EXPORT = u"Office.Calc/Dialogs/DBFExport"_ustr;
+
+namespace
+{
+
+ enum class charsetSource
+ {
+ charset_from_file,
+ charset_from_user_setting,
+ charset_default
+ };
+
+ charsetSource load_CharSet(rtl_TextEncoding &nCharSet, bool bExport, SvStream* dbf_Stream)
+ {
+ if (dbf_Stream && dbfReadCharset(nCharSet, dbf_Stream))
+ {
+ return charsetSource::charset_from_file;
+ }
+
+ Sequence<Any> aValues;
+ const Any *pProperties;
+ Sequence<OUString> aNames { DBF_CHAR_SET };
+ ScLinkConfigItem aItem( bExport ? DBF_SEP_PATH_EXPORT : DBF_SEP_PATH_IMPORT );
+
+ aValues = aItem.GetProperties( aNames );
+ pProperties = aValues.getConstArray();
+
+ if( pProperties[0].hasValue() )
+ {
+ sal_Int32 nChar = 0;
+ pProperties[0] >>= nChar;
+ if( nChar >= 0)
+ {
+ nCharSet = static_cast<rtl_TextEncoding>(nChar);
+ return charsetSource::charset_from_user_setting;
+ }
+ }
+
+ // Default choice
+ nCharSet = RTL_TEXTENCODING_IBM_850;
+ return charsetSource::charset_default;
+ }
+
+ void save_CharSet( rtl_TextEncoding nCharSet, bool bExport )
+ {
+ Sequence<Any> aValues;
+ Any *pProperties;
+ Sequence<OUString> aNames { DBF_CHAR_SET };
+ ScLinkConfigItem aItem( bExport ? DBF_SEP_PATH_EXPORT : DBF_SEP_PATH_IMPORT );
+
+ aValues = aItem.GetProperties( aNames );
+ pProperties = aValues.getArray();
+ pProperties[0] <<= static_cast<sal_Int32>(nCharSet);
+
+ aItem.PutProperties(aNames, aValues);
+ }
+}
+
+ScFilterOptionsObj::ScFilterOptionsObj() :
+ bExport( false )
+{
+}
+
+ScFilterOptionsObj::~ScFilterOptionsObj()
+{
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_FilterOptionsDialog_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScFilterOptionsObj);
+}
+
+// XPropertyAccess
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScFilterOptionsObj::getPropertyValues()
+{
+ return comphelper::InitPropertySequence({
+ { SC_UNONAME_FILTEROPTIONS, Any(aFilterOptions) }
+ });
+}
+
+void SAL_CALL ScFilterOptionsObj::setPropertyValues( const uno::Sequence<beans::PropertyValue>& aProps )
+{
+ for (const beans::PropertyValue& rProp : aProps)
+ {
+ OUString aPropName(rProp.Name);
+
+ if ( aPropName == SC_UNONAME_FILENAME )
+ rProp.Value >>= aFileName;
+ else if ( aPropName == SC_UNONAME_FILTERNAME )
+ rProp.Value >>= aFilterName;
+ else if ( aPropName == SC_UNONAME_FILTEROPTIONS )
+ rProp.Value >>= aFilterOptions;
+ else if ( aPropName == SC_UNONAME_INPUTSTREAM )
+ rProp.Value >>= xInputStream;
+ }
+}
+
+// XExecutableDialog
+
+void SAL_CALL ScFilterOptionsObj::setTitle( const OUString& /* aTitle */ )
+{
+ // not used
+}
+
+sal_Int16 SAL_CALL ScFilterOptionsObj::execute()
+{
+ sal_Int16 nRet = ui::dialogs::ExecutableDialogResults::CANCEL;
+
+ OUString aFilterString( aFilterName );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ if ( !bExport && aFilterString == ScDocShell::GetAsciiFilterName() )
+ {
+ // ascii import is special...
+
+ INetURLObject aURL( aFileName );
+ // tdf#132421 - don't URL encode filename for the import ASCII dialog title
+ OUString aPrivDatName(aURL.GetLastName(INetURLObject::DecodeMechanism::Unambiguous));
+ std::unique_ptr<SvStream> pInStream;
+ if ( xInputStream.is() )
+ pInStream = utl::UcbStreamHelper::CreateStream( xInputStream );
+
+ ScopedVclPtr<AbstractScImportAsciiDlg> pDlg(pFact->CreateScImportAsciiDlg(Application::GetFrameWeld(xDialogParent), aPrivDatName,
+ pInStream.get(), SC_IMPORTFILE));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ ScAsciiOptions aOptions;
+ pDlg->GetOptions( aOptions );
+ pDlg->SaveParameters();
+ aFilterOptions = aOptions.WriteToString();
+ nRet = ui::dialogs::ExecutableDialogResults::OK;
+ }
+ }
+ else if ( aFilterString == ScDocShell::GetWebQueryFilterName() || aFilterString == ScDocShell::GetHtmlFilterName() )
+ {
+ if (bExport)
+ nRet = ui::dialogs::ExecutableDialogResults::OK; // export HTML without dialog
+ else
+ {
+ // HTML import.
+ ScopedVclPtr<AbstractScTextImportOptionsDlg> pDlg(
+ pFact->CreateScTextImportOptionsDlg(Application::GetFrameWeld(xDialogParent)));
+
+ if (pDlg->Execute() == RET_OK)
+ {
+ LanguageType eLang = pDlg->GetLanguageType();
+ OUStringBuffer aBuf;
+
+ aBuf.append(static_cast<sal_Int32>(static_cast<sal_uInt16>(eLang)));
+ aBuf.append(' ');
+ aBuf.append(pDlg->IsDateConversionSet() ? u'1' : u'0');
+ aBuf.append(' ');
+ aBuf.append(pDlg->IsScientificConversionSet() ? u'1' : u'0');
+ aFilterOptions = aBuf.makeStringAndClear();
+ nRet = ui::dialogs::ExecutableDialogResults::OK;
+ }
+ }
+ }
+ else
+ {
+ bool bDBEnc = false;
+ bool bAscii = false;
+ bool skipDialog = false;
+
+ sal_Unicode const cStrDel = '"';
+ sal_Unicode cAsciiDel = ';';
+ rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
+
+ OUString aTitle;
+ bool bIncludeBOM = false;
+
+ if ( aFilterString == ScDocShell::GetAsciiFilterName() )
+ {
+ // ascii export (import is handled above)
+
+ INetURLObject aURL( aFileName );
+ OUString aExt(aURL.getExtension());
+ if (aExt.equalsIgnoreAsciiCase("CSV"))
+ cAsciiDel = ',';
+ else
+ cAsciiDel = '\t';
+
+ aTitle = ScResId( STR_EXPORT_ASCII );
+ bAscii = true;
+
+ ScAsciiOptions aOptions;
+ aOptions.ReadFromString(aFilterOptions);
+ bIncludeBOM = aOptions.GetIncludeBOM();
+ }
+ else if ( aFilterString == ScDocShell::GetLotusFilterName() )
+ {
+ // lotus is only imported
+ OSL_ENSURE( !bExport, "Filter Options for Lotus Export is not implemented" );
+
+ aTitle = ScResId( STR_IMPORT_LOTUS );
+ eEncoding = RTL_TEXTENCODING_IBM_437;
+ }
+ else if ( aFilterString == ScDocShell::GetDBaseFilterName() )
+ {
+ if ( bExport )
+ {
+ // dBase export
+ aTitle = ScResId( STR_EXPORT_DBF );
+ }
+ else
+ {
+ // dBase import
+ aTitle = ScResId( STR_IMPORT_DBF );
+ }
+
+ std::unique_ptr<SvStream> pInStream;
+ if ( xInputStream.is() )
+ pInStream = utl::UcbStreamHelper::CreateStream( xInputStream );
+ switch(load_CharSet( eEncoding, bExport, pInStream.get()))
+ {
+ case charsetSource::charset_from_file:
+ skipDialog = true;
+ break;
+ case charsetSource::charset_from_user_setting:
+ case charsetSource::charset_default:
+ break;
+ }
+ bDBEnc = true;
+ // pInStream goes out of scope, the stream is automatically closed
+ }
+ else if ( aFilterString == ScDocShell::GetDifFilterName() )
+ {
+ if ( bExport )
+ {
+ // DIF export
+ aTitle = ScResId( STR_EXPORT_DIF );
+ }
+ else
+ {
+ // DIF import
+ aTitle = ScResId( STR_IMPORT_DIF );
+ }
+ // common for DIF import/export
+ eEncoding = RTL_TEXTENCODING_MS_1252;
+ }
+
+ ScImportOptions aOptions( cAsciiDel, cStrDel, eEncoding);
+ aOptions.bIncludeBOM = bIncludeBOM;
+ if(skipDialog)
+ {
+ // TODO: check we are not missing some of the stuff that ScImportOptionsDlg::GetImportOptions
+ // (file sc/source/ui/dbgui/scuiimoptdlg.cxx) does
+ // that is, if the dialog sets options that are not selected by the user (!)
+ // then we are missing them here.
+ // Then we may need to rip them out of the dialog.
+ // Or we actually change the dialog to not display if skipDialog==true
+ // in that case, add an argument skipDialog to CreateScImportOptionsDlg
+ nRet = ui::dialogs::ExecutableDialogResults::OK;
+ }
+ else
+ {
+ ScopedVclPtr<AbstractScImportOptionsDlg> pDlg(pFact->CreateScImportOptionsDlg(Application::GetFrameWeld(xDialogParent),
+ bAscii, &aOptions, &aTitle,
+ bDBEnc, !bExport));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ pDlg->SaveImportOptions();
+ pDlg->GetImportOptions( aOptions );
+ save_CharSet( aOptions.eCharSet, bExport );
+ nRet = ui::dialogs::ExecutableDialogResults::OK;
+ }
+ }
+ if (nRet == ui::dialogs::ExecutableDialogResults::OK)
+ {
+ if ( bAscii )
+ aFilterOptions = aOptions.BuildString();
+ else
+ aFilterOptions = aOptions.aStrFont;
+ }
+ }
+
+ xInputStream.clear(); // don't hold the stream longer than necessary
+
+ return nRet;
+}
+
+// XImporter
+
+void SAL_CALL ScFilterOptionsObj::setTargetDocument( const uno::Reference<lang::XComponent>& /* xDoc */ )
+{
+ bExport = false;
+}
+
+// XExporter
+
+void SAL_CALL ScFilterOptionsObj::setSourceDocument( const uno::Reference<lang::XComponent>& /* xDoc */ )
+{
+ bExport = true;
+}
+
+// XInitialization
+
+void SAL_CALL ScFilterOptionsObj::initialize(const uno::Sequence<uno::Any>& rArguments)
+{
+ ::comphelper::NamedValueCollection aProperties(rArguments);
+ if (aProperties.has("ParentWindow"))
+ aProperties.get("ParentWindow") >>= xDialogParent;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/fmtuno.cxx b/sc/source/ui/unoobj/fmtuno.cxx
new file mode 100644
index 0000000000..1b91855917
--- /dev/null
+++ b/sc/source/ui/unoobj/fmtuno.cxx
@@ -0,0 +1,913 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <svl/style.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/sheet/ConditionOperator2.hpp>
+#include <com/sun/star/sheet/ValidationAlertStyle.hpp>
+#include <com/sun/star/sheet/ValidationType.hpp>
+#include <com/sun/star/sheet/TableValidationVisibility.hpp>
+
+#include <fmtuno.hxx>
+#include <miscuno.hxx>
+#include <validat.hxx>
+#include <document.hxx>
+#include <unonames.hxx>
+#include <tokenarray.hxx>
+#include <tokenuno.hxx>
+#include <stylehelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::formula;
+
+// map only for PropertySetInfo
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetValidatePropertyMap()
+{
+ static const SfxItemPropertyMapEntry aValidatePropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ERRALSTY, 0, cppu::UnoType<sheet::ValidationAlertStyle>::get(), 0, 0},
+ { SC_UNONAME_ERRMESS, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_ERRTITLE, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_IGNOREBL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_INPMESS, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_INPTITLE, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_SHOWERR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_SHOWINP, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_SHOWLIST, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_TYPE, 0, cppu::UnoType<sheet::ValidationType>::get(), 0, 0},
+ };
+ return aValidatePropertyMap_Impl;
+}
+
+SC_SIMPLE_SERVICE_INFO( ScTableConditionalEntry, "ScTableConditionalEntry", "com.sun.star.sheet.TableConditionalEntry" )
+SC_SIMPLE_SERVICE_INFO( ScTableConditionalFormat, "ScTableConditionalFormat", "com.sun.star.sheet.TableConditionalFormat" )
+SC_SIMPLE_SERVICE_INFO( ScTableValidationObj, "ScTableValidationObj", "com.sun.star.sheet.TableValidation" )
+
+static sal_Int32 lcl_ConditionModeToOperatorNew( ScConditionMode eMode )
+{
+ sal_Int32 eOper = sheet::ConditionOperator2::NONE;
+ switch (eMode)
+ {
+ case ScConditionMode::Equal: eOper = sheet::ConditionOperator2::EQUAL; break;
+ case ScConditionMode::Less: eOper = sheet::ConditionOperator2::LESS; break;
+ case ScConditionMode::Greater: eOper = sheet::ConditionOperator2::GREATER; break;
+ case ScConditionMode::EqLess: eOper = sheet::ConditionOperator2::LESS_EQUAL; break;
+ case ScConditionMode::EqGreater: eOper = sheet::ConditionOperator2::GREATER_EQUAL; break;
+ case ScConditionMode::NotEqual: eOper = sheet::ConditionOperator2::NOT_EQUAL; break;
+ case ScConditionMode::Between: eOper = sheet::ConditionOperator2::BETWEEN; break;
+ case ScConditionMode::NotBetween: eOper = sheet::ConditionOperator2::NOT_BETWEEN; break;
+ case ScConditionMode::Direct: eOper = sheet::ConditionOperator2::FORMULA; break;
+ case ScConditionMode::Duplicate: eOper = sheet::ConditionOperator2::DUPLICATE; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return eOper;
+}
+
+static sheet::ConditionOperator lcl_ConditionModeToOperator( ScConditionMode eMode )
+{
+ sheet::ConditionOperator eOper = sheet::ConditionOperator_NONE;
+ switch (eMode)
+ {
+ case ScConditionMode::Equal: eOper = sheet::ConditionOperator_EQUAL; break;
+ case ScConditionMode::Less: eOper = sheet::ConditionOperator_LESS; break;
+ case ScConditionMode::Greater: eOper = sheet::ConditionOperator_GREATER; break;
+ case ScConditionMode::EqLess: eOper = sheet::ConditionOperator_LESS_EQUAL; break;
+ case ScConditionMode::EqGreater: eOper = sheet::ConditionOperator_GREATER_EQUAL; break;
+ case ScConditionMode::NotEqual: eOper = sheet::ConditionOperator_NOT_EQUAL; break;
+ case ScConditionMode::Between: eOper = sheet::ConditionOperator_BETWEEN; break;
+ case ScConditionMode::NotBetween: eOper = sheet::ConditionOperator_NOT_BETWEEN; break;
+ case ScConditionMode::Direct: eOper = sheet::ConditionOperator_FORMULA; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return eOper;
+}
+
+static ScConditionMode lcl_ConditionOperatorToMode( sheet::ConditionOperator eOper )
+{
+ ScConditionMode eMode = ScConditionMode::NONE;
+ switch (eOper)
+ {
+ case sheet::ConditionOperator_EQUAL: eMode = ScConditionMode::Equal; break;
+ case sheet::ConditionOperator_LESS: eMode = ScConditionMode::Less; break;
+ case sheet::ConditionOperator_GREATER: eMode = ScConditionMode::Greater; break;
+ case sheet::ConditionOperator_LESS_EQUAL: eMode = ScConditionMode::EqLess; break;
+ case sheet::ConditionOperator_GREATER_EQUAL: eMode = ScConditionMode::EqGreater; break;
+ case sheet::ConditionOperator_NOT_EQUAL: eMode = ScConditionMode::NotEqual; break;
+ case sheet::ConditionOperator_BETWEEN: eMode = ScConditionMode::Between; break;
+ case sheet::ConditionOperator_NOT_BETWEEN: eMode = ScConditionMode::NotBetween; break;
+ case sheet::ConditionOperator_FORMULA: eMode = ScConditionMode::Direct; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return eMode;
+}
+
+ScCondFormatEntryItem::ScCondFormatEntryItem() :
+ meGrammar1( FormulaGrammar::GRAM_UNSPECIFIED ),
+ meGrammar2( FormulaGrammar::GRAM_UNSPECIFIED ),
+ meMode( ScConditionMode::NONE )
+{
+}
+
+ScTableConditionalFormat::ScTableConditionalFormat(
+ const ScDocument* pDoc, sal_uLong nKey, SCTAB nTab, FormulaGrammar::Grammar eGrammar)
+{
+ // read the entry from the document...
+
+ if ( !(pDoc && nKey) )
+ return;
+
+ ScConditionalFormatList* pList = pDoc->GetCondFormList(nTab);
+ if (!pList)
+ return;
+
+ const ScConditionalFormat* pFormat = pList->GetFormat( nKey );
+ if (!pFormat)
+ return;
+
+ // During save to XML.
+ if (pDoc->IsInExternalReferenceMarking())
+ pFormat->MarkUsedExternalReferences();
+
+ size_t nEntryCount = pFormat->size();
+ for (size_t i=0; i<nEntryCount; i++)
+ {
+ ScCondFormatEntryItem aItem;
+ const ScFormatEntry* pFrmtEntry = pFormat->GetEntry(i);
+ if(pFrmtEntry->GetType() != ScFormatEntry::Type::Condition &&
+ pFrmtEntry->GetType() != ScFormatEntry::Type::ExtCondition)
+ continue;
+
+ const ScCondFormatEntry* pFormatEntry = static_cast<const ScCondFormatEntry*>(pFrmtEntry);
+ aItem.meMode = pFormatEntry->GetOperation();
+ aItem.maPos = pFormatEntry->GetValidSrcPos();
+ aItem.maExpr1 = pFormatEntry->GetExpression(aItem.maPos, 0, 0, eGrammar);
+ aItem.maExpr2 = pFormatEntry->GetExpression(aItem.maPos, 1, 0, eGrammar);
+ aItem.meGrammar1 = aItem.meGrammar2 = eGrammar;
+ aItem.maStyle = pFormatEntry->GetStyle();
+
+ AddEntry_Impl(aItem);
+ }
+}
+
+namespace {
+
+FormulaGrammar::Grammar lclResolveGrammar( FormulaGrammar::Grammar eExtGrammar, FormulaGrammar::Grammar eIntGrammar )
+{
+ if( eExtGrammar != FormulaGrammar::GRAM_UNSPECIFIED )
+ return eExtGrammar;
+ OSL_ENSURE( eIntGrammar != FormulaGrammar::GRAM_UNSPECIFIED, "lclResolveGrammar - unspecified grammar, using GRAM_API" );
+ return (eIntGrammar == FormulaGrammar::GRAM_UNSPECIFIED) ? FormulaGrammar::GRAM_API : eIntGrammar;
+}
+
+} // namespace
+
+void ScTableConditionalFormat::FillFormat( ScConditionalFormat& rFormat,
+ ScDocument& rDoc, FormulaGrammar::Grammar eGrammar) const
+{
+ // ScConditionalFormat = Core-Struktur, has to be empty
+
+ OSL_ENSURE( rFormat.IsEmpty(), "FillFormat: format not empty" );
+
+ for (const auto & i : maEntries)
+ {
+ ScCondFormatEntryItem aData;
+ i->GetData(aData);
+
+ FormulaGrammar::Grammar eGrammar1 = lclResolveGrammar( eGrammar, aData.meGrammar1 );
+ FormulaGrammar::Grammar eGrammar2 = lclResolveGrammar( eGrammar, aData.meGrammar2 );
+
+ ScCondFormatEntry* pCoreEntry = new ScCondFormatEntry( aData.meMode, aData.maExpr1, aData.maExpr2,
+ rDoc, aData.maPos, aData.maStyle, aData.maExprNmsp1, aData.maExprNmsp2, eGrammar1, eGrammar2 );
+
+ if ( !aData.maPosStr.isEmpty() )
+ pCoreEntry->SetSrcString( aData.maPosStr );
+
+ if ( aData.maTokens1.hasElements() )
+ {
+ ScTokenArray aTokenArray(rDoc);
+ if ( ScTokenConversion::ConvertToTokenArray(rDoc, aTokenArray, aData.maTokens1) )
+ pCoreEntry->SetFormula1(aTokenArray);
+ }
+
+ if ( aData.maTokens2.hasElements() )
+ {
+ ScTokenArray aTokenArray(rDoc);
+ if ( ScTokenConversion::ConvertToTokenArray(rDoc, aTokenArray, aData.maTokens2) )
+ pCoreEntry->SetFormula2(aTokenArray);
+ }
+ rFormat.AddEntry( pCoreEntry );
+ }
+}
+
+ScTableConditionalFormat::~ScTableConditionalFormat()
+{
+}
+
+void ScTableConditionalFormat::AddEntry_Impl(const ScCondFormatEntryItem& aEntry)
+{
+ rtl::Reference<ScTableConditionalEntry> pNew = new ScTableConditionalEntry(aEntry);
+ maEntries.emplace_back(pNew);
+}
+
+// XSheetConditionalFormat
+
+ScTableConditionalEntry* ScTableConditionalFormat::GetObjectByIndex_Impl(sal_uInt16 nIndex) const
+{
+ return nIndex < maEntries.size() ? maEntries[nIndex].get() : nullptr;
+}
+
+void SAL_CALL ScTableConditionalFormat::addNew(
+ const uno::Sequence<beans::PropertyValue >& aConditionalEntry )
+{
+ SolarMutexGuard aGuard;
+ ScCondFormatEntryItem aEntry;
+ aEntry.meMode = ScConditionMode::NONE;
+
+ for (const beans::PropertyValue& rProp : aConditionalEntry)
+ {
+ if ( rProp.Name == SC_UNONAME_OPERATOR )
+ {
+ sal_Int32 eOper = ScUnoHelpFunctions::GetEnumFromAny( rProp.Value );
+ aEntry.meMode = ScConditionEntry::GetModeFromApi( static_cast<sheet::ConditionOperator>(eOper) );
+ }
+ else if ( rProp.Name == SC_UNONAME_FORMULA1 )
+ {
+ OUString aStrVal;
+ uno::Sequence<sheet::FormulaToken> aTokens;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maExpr1 = aStrVal;
+ else if ( rProp.Value >>= aTokens )
+ {
+ aEntry.maExpr1.clear();
+ aEntry.maTokens1 = aTokens;
+ }
+ }
+ else if ( rProp.Name == SC_UNONAME_FORMULA2 )
+ {
+ OUString aStrVal;
+ uno::Sequence<sheet::FormulaToken> aTokens;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maExpr2 = aStrVal;
+ else if ( rProp.Value >>= aTokens )
+ {
+ aEntry.maExpr2.clear();
+ aEntry.maTokens2 = aTokens;
+ }
+ }
+ else if ( rProp.Name == SC_UNONAME_SOURCEPOS )
+ {
+ table::CellAddress aAddress;
+ if ( rProp.Value >>= aAddress )
+ aEntry.maPos = ScAddress( static_cast<SCCOL>(aAddress.Column), static_cast<SCROW>(aAddress.Row), aAddress.Sheet );
+ }
+ else if ( rProp.Name == SC_UNONAME_SOURCESTR )
+ {
+ OUString aStrVal;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maPosStr = aStrVal;
+ }
+ else if ( rProp.Name == SC_UNONAME_STYLENAME )
+ {
+ OUString aStrVal;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maStyle = ScStyleNameConversion::ProgrammaticToDisplayName(
+ aStrVal, SfxStyleFamily::Para );
+ }
+ else if ( rProp.Name == SC_UNONAME_FORMULANMSP1 )
+ {
+ OUString aStrVal;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maExprNmsp1 = aStrVal;
+ }
+ else if ( rProp.Name == SC_UNONAME_FORMULANMSP2 )
+ {
+ OUString aStrVal;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maExprNmsp2 = aStrVal;
+ }
+ else if ( rProp.Name == SC_UNONAME_GRAMMAR1 )
+ {
+ sal_Int32 nVal = 0;
+ if ( rProp.Value >>= nVal )
+ aEntry.meGrammar1 = static_cast< FormulaGrammar::Grammar >( nVal );
+ }
+ else if ( rProp.Name == SC_UNONAME_GRAMMAR2 )
+ {
+ sal_Int32 nVal = 0;
+ if ( rProp.Value >>= nVal )
+ aEntry.meGrammar2 = static_cast< FormulaGrammar::Grammar >( nVal );
+ }
+ else
+ {
+ OSL_FAIL("wrong property");
+ //! Exception...
+ }
+ }
+
+ AddEntry_Impl(aEntry);
+}
+
+void SAL_CALL ScTableConditionalFormat::removeByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+
+ if (nIndex >= 0 && o3tl::make_unsigned(nIndex) < maEntries.size())
+ {
+ maEntries.erase(maEntries.begin()+nIndex);
+ }
+}
+
+void SAL_CALL ScTableConditionalFormat::clear()
+{
+ SolarMutexGuard aGuard;
+ maEntries.clear();
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScTableConditionalFormat::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.TableConditionalEntryEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScTableConditionalFormat::getCount()
+{
+ SolarMutexGuard aGuard;
+ return maEntries.size();
+}
+
+uno::Any SAL_CALL ScTableConditionalFormat::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XSheetConditionalEntry> xEntry(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if (!xEntry.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xEntry);
+}
+
+uno::Type SAL_CALL ScTableConditionalFormat::getElementType()
+{
+ return cppu::UnoType<sheet::XSheetConditionalEntry>::get();
+}
+
+sal_Bool SAL_CALL ScTableConditionalFormat::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// conditional format entries have no real names
+// -> generate name from index
+
+static OUString lcl_GetEntryNameFromIndex( sal_Int32 nIndex )
+{
+ OUString aRet = "Entry" + OUString::number( nIndex );
+ return aRet;
+}
+
+uno::Any SAL_CALL ScTableConditionalFormat::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<sheet::XSheetConditionalEntry> xEntry;
+ tools::Long nCount = maEntries.size();
+ for (tools::Long i=0; i<nCount; i++)
+ if ( aName == lcl_GetEntryNameFromIndex(i) )
+ {
+ xEntry.set(GetObjectByIndex_Impl(static_cast<sal_uInt16>(i)));
+ break;
+ }
+
+ if (!xEntry.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xEntry);
+}
+
+uno::Sequence<OUString> SAL_CALL ScTableConditionalFormat::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ tools::Long nCount = maEntries.size();
+ uno::Sequence<OUString> aNames(nCount);
+ OUString* pArray = aNames.getArray();
+ for (tools::Long i=0; i<nCount; i++)
+ pArray[i] = lcl_GetEntryNameFromIndex(i);
+
+ return aNames;
+}
+
+sal_Bool SAL_CALL ScTableConditionalFormat::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ tools::Long nCount = maEntries.size();
+ for (tools::Long i=0; i<nCount; i++)
+ if ( aName == lcl_GetEntryNameFromIndex(i) )
+ return true;
+
+ return false;
+}
+
+ScTableConditionalEntry::ScTableConditionalEntry(ScCondFormatEntryItem aItem) :
+ aData(std::move( aItem ))
+{
+ // #i113668# only store the settings, keep no reference to parent object
+}
+
+ScTableConditionalEntry::~ScTableConditionalEntry()
+{
+}
+
+void ScTableConditionalEntry::GetData(ScCondFormatEntryItem& rData) const
+{
+ rData = aData;
+}
+
+// XSheetCondition
+
+sheet::ConditionOperator SAL_CALL ScTableConditionalEntry::getOperator()
+{
+ SolarMutexGuard aGuard;
+ return lcl_ConditionModeToOperator( aData.meMode );
+}
+
+void SAL_CALL ScTableConditionalEntry::setOperator( sheet::ConditionOperator nOperator )
+{
+ SolarMutexGuard aGuard;
+ aData.meMode = lcl_ConditionOperatorToMode( nOperator );
+}
+
+sal_Int32 SAL_CALL ScTableConditionalEntry::getConditionOperator()
+{
+ SolarMutexGuard aGuard;
+ return lcl_ConditionModeToOperatorNew( aData.meMode );
+}
+
+void SAL_CALL ScTableConditionalEntry::setConditionOperator( sal_Int32 nOperator )
+{
+ SolarMutexGuard aGuard;
+ aData.meMode = ScConditionEntry::GetModeFromApi( static_cast<sheet::ConditionOperator>(nOperator) );
+}
+
+OUString SAL_CALL ScTableConditionalEntry::getFormula1()
+{
+ SolarMutexGuard aGuard;
+ return aData.maExpr1;
+}
+
+void SAL_CALL ScTableConditionalEntry::setFormula1( const OUString& aFormula1 )
+{
+ SolarMutexGuard aGuard;
+ aData.maExpr1 = aFormula1;
+}
+
+OUString SAL_CALL ScTableConditionalEntry::getFormula2()
+{
+ SolarMutexGuard aGuard;
+ return aData.maExpr2;
+}
+
+void SAL_CALL ScTableConditionalEntry::setFormula2( const OUString& aFormula2 )
+{
+ SolarMutexGuard aGuard;
+ aData.maExpr2 = aFormula2;
+}
+
+table::CellAddress SAL_CALL ScTableConditionalEntry::getSourcePosition()
+{
+ SolarMutexGuard aGuard;
+ table::CellAddress aRet;
+ aRet.Column = aData.maPos.Col();
+ aRet.Row = aData.maPos.Row();
+ aRet.Sheet = aData.maPos.Tab();
+ return aRet;
+}
+
+void SAL_CALL ScTableConditionalEntry::setSourcePosition( const table::CellAddress& aSourcePosition )
+{
+ SolarMutexGuard aGuard;
+ aData.maPos.Set( static_cast<SCCOL>(aSourcePosition.Column), static_cast<SCROW>(aSourcePosition.Row), aSourcePosition.Sheet );
+}
+
+// XSheetConditionalEntry
+
+OUString SAL_CALL ScTableConditionalEntry::getStyleName()
+{
+ SolarMutexGuard aGuard;
+ return ScStyleNameConversion::DisplayToProgrammaticName( aData.maStyle, SfxStyleFamily::Para );
+}
+
+void SAL_CALL ScTableConditionalEntry::setStyleName( const OUString& aStyleName )
+{
+ SolarMutexGuard aGuard;
+ aData.maStyle = ScStyleNameConversion::ProgrammaticToDisplayName( aStyleName, SfxStyleFamily::Para );
+}
+
+ScTableValidationObj::ScTableValidationObj(const ScDocument& rDoc, sal_uInt32 nKey,
+ const formula::FormulaGrammar::Grammar eGrammar) :
+ aPropSet( lcl_GetValidatePropertyMap() )
+{
+ // read the entry from the document...
+
+ bool bFound = false;
+ if (nKey)
+ {
+ const ScValidationData* pData = rDoc.GetValidationEntry( nKey );
+ if (pData)
+ {
+ nMode = pData->GetOperation();
+ aSrcPos = pData->GetValidSrcPos(); // valid pos for expressions
+ aExpr1 = pData->GetExpression( aSrcPos, 0, 0, eGrammar );
+ aExpr2 = pData->GetExpression( aSrcPos, 1, 0, eGrammar );
+ meGrammar1 = meGrammar2 = eGrammar;
+ nValMode = sal::static_int_cast<sal_uInt16>( pData->GetDataMode() );
+ bIgnoreBlank = pData->IsIgnoreBlank();
+ nShowList = pData->GetListType();
+ bShowInput = pData->GetInput( aInputTitle, aInputMessage );
+ ScValidErrorStyle eStyle;
+ bShowError = pData->GetErrMsg( aErrorTitle, aErrorMessage, eStyle );
+ nErrorStyle = sal::static_int_cast<sal_uInt16>( eStyle );
+
+ // During save to XML, sheet::ValidationType_ANY formulas are not
+ // saved, even if in the list, see
+ // ScMyValidationsContainer::GetCondition(), so shall not mark
+ // anything in use.
+ if (nValMode != SC_VALID_ANY && rDoc.IsInExternalReferenceMarking())
+ pData->MarkUsedExternalReferences();
+
+ bFound = true;
+ }
+ }
+ if (!bFound)
+ ClearData_Impl(); // Defaults
+}
+
+ScValidationData* ScTableValidationObj::CreateValidationData( ScDocument& rDoc,
+ formula::FormulaGrammar::Grammar eGrammar ) const
+{
+ // ScValidationData = Core-Struktur
+
+ FormulaGrammar::Grammar eGrammar1 = lclResolveGrammar( eGrammar, meGrammar1 );
+ FormulaGrammar::Grammar eGrammar2 = lclResolveGrammar( eGrammar, meGrammar2 );
+
+ ScValidationData* pRet = new ScValidationData( static_cast<ScValidationMode>(nValMode),
+ nMode,
+ aExpr1, aExpr2, rDoc, aSrcPos,
+ maExprNmsp1, maExprNmsp2,
+ eGrammar1, eGrammar2 );
+ pRet->SetIgnoreBlank(bIgnoreBlank);
+ pRet->SetListType(nShowList);
+
+ if ( aTokens1.hasElements() )
+ {
+ ScTokenArray aTokenArray(rDoc);
+ if ( ScTokenConversion::ConvertToTokenArray(rDoc, aTokenArray, aTokens1) )
+ pRet->SetFormula1(aTokenArray);
+ }
+
+ if ( aTokens2.hasElements() )
+ {
+ ScTokenArray aTokenArray(rDoc);
+ if ( ScTokenConversion::ConvertToTokenArray(rDoc, aTokenArray, aTokens2) )
+ pRet->SetFormula2(aTokenArray);
+ }
+
+ // set strings for error / input even if disabled (and disable afterwards)
+ pRet->SetInput( aInputTitle, aInputMessage );
+ if (!bShowInput)
+ pRet->ResetInput();
+ pRet->SetError( aErrorTitle, aErrorMessage, static_cast<ScValidErrorStyle>(nErrorStyle) );
+ if (!bShowError)
+ pRet->ResetError();
+
+ if ( !aPosString.isEmpty() )
+ pRet->SetSrcString( aPosString );
+
+ return pRet;
+}
+
+void ScTableValidationObj::ClearData_Impl()
+{
+ nMode = ScConditionMode::NONE;
+ nValMode = SC_VALID_ANY;
+ bIgnoreBlank = true;
+ nShowList = sheet::TableValidationVisibility::UNSORTED;
+ bShowInput = false;
+ bShowError = false;
+ nErrorStyle = SC_VALERR_STOP;
+ aSrcPos.Set(0,0,0);
+ aExpr1.clear();
+ aExpr2.clear();
+ maExprNmsp1.clear();
+ maExprNmsp2.clear();
+ meGrammar1 = meGrammar2 = FormulaGrammar::GRAM_UNSPECIFIED; // will be overridden when needed
+ aInputTitle.clear();
+ aInputMessage.clear();
+ aErrorTitle.clear();
+ aErrorMessage.clear();
+}
+
+ScTableValidationObj::~ScTableValidationObj()
+{
+}
+
+// XSheetCondition
+
+sheet::ConditionOperator SAL_CALL ScTableValidationObj::getOperator()
+{
+ SolarMutexGuard aGuard;
+ return lcl_ConditionModeToOperator( nMode );
+}
+
+void SAL_CALL ScTableValidationObj::setOperator( sheet::ConditionOperator nOperator )
+{
+ SolarMutexGuard aGuard;
+ nMode = lcl_ConditionOperatorToMode( nOperator );
+}
+
+sal_Int32 SAL_CALL ScTableValidationObj::getConditionOperator()
+{
+ SolarMutexGuard aGuard;
+ return lcl_ConditionModeToOperatorNew( nMode );
+}
+
+void SAL_CALL ScTableValidationObj::setConditionOperator( sal_Int32 nOperator )
+{
+ SolarMutexGuard aGuard;
+ nMode = ScConditionEntry::GetModeFromApi( static_cast<css::sheet::ConditionOperator>(nOperator) );
+}
+
+OUString SAL_CALL ScTableValidationObj::getFormula1()
+{
+ SolarMutexGuard aGuard;
+ return aExpr1;
+}
+
+void SAL_CALL ScTableValidationObj::setFormula1( const OUString& aFormula1 )
+{
+ SolarMutexGuard aGuard;
+ aExpr1 = aFormula1;
+}
+
+OUString SAL_CALL ScTableValidationObj::getFormula2()
+{
+ SolarMutexGuard aGuard;
+ return aExpr2;
+}
+
+void SAL_CALL ScTableValidationObj::setFormula2( const OUString& aFormula2 )
+{
+ SolarMutexGuard aGuard;
+ aExpr2 = aFormula2;
+}
+
+table::CellAddress SAL_CALL ScTableValidationObj::getSourcePosition()
+{
+ SolarMutexGuard aGuard;
+ table::CellAddress aRet;
+ aRet.Column = aSrcPos.Col();
+ aRet.Row = aSrcPos.Row();
+ aRet.Sheet = aSrcPos.Tab();
+ return aRet;
+}
+
+void SAL_CALL ScTableValidationObj::setSourcePosition( const table::CellAddress& aSourcePosition )
+{
+ SolarMutexGuard aGuard;
+ aSrcPos.Set( static_cast<SCCOL>(aSourcePosition.Column), static_cast<SCROW>(aSourcePosition.Row), aSourcePosition.Sheet );
+}
+
+uno::Sequence<sheet::FormulaToken> SAL_CALL ScTableValidationObj::getTokens( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ if (nIndex >= 2 || nIndex < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ return nIndex == 0 ? aTokens1 : aTokens2;
+}
+
+void SAL_CALL ScTableValidationObj::setTokens( sal_Int32 nIndex, const uno::Sequence<sheet::FormulaToken>& aTokens )
+{
+ SolarMutexGuard aGuard;
+ if (nIndex >= 2 || nIndex < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ if (nIndex == 0)
+ {
+ aTokens1 = aTokens;
+ aExpr1.clear();
+ }
+ else if (nIndex == 1)
+ {
+ aTokens2 = aTokens;
+ aExpr2.clear();
+ }
+}
+
+sal_Int32 SAL_CALL ScTableValidationObj::getCount()
+{
+ return 2;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableValidationObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScTableValidationObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == SC_UNONAME_SHOWINP ) bShowInput = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if ( aPropertyName == SC_UNONAME_SHOWERR ) bShowError = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if ( aPropertyName == SC_UNONAME_IGNOREBL ) bIgnoreBlank = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if ( aPropertyName == SC_UNONAME_SHOWLIST ) aValue >>= nShowList;
+ else if ( aPropertyName == SC_UNONAME_INPTITLE )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aInputTitle = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_INPMESS )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aInputMessage = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_ERRTITLE )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aErrorTitle = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_ERRMESS )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aErrorMessage = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_TYPE )
+ {
+ sheet::ValidationType eType = static_cast<sheet::ValidationType>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
+ switch (eType)
+ {
+ case sheet::ValidationType_ANY: nValMode = SC_VALID_ANY; break;
+ case sheet::ValidationType_WHOLE: nValMode = SC_VALID_WHOLE; break;
+ case sheet::ValidationType_DECIMAL: nValMode = SC_VALID_DECIMAL; break;
+ case sheet::ValidationType_DATE: nValMode = SC_VALID_DATE; break;
+ case sheet::ValidationType_TIME: nValMode = SC_VALID_TIME; break;
+ case sheet::ValidationType_TEXT_LEN: nValMode = SC_VALID_TEXTLEN; break;
+ case sheet::ValidationType_LIST: nValMode = SC_VALID_LIST; break;
+ case sheet::ValidationType_CUSTOM: nValMode = SC_VALID_CUSTOM; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_ERRALSTY )
+ {
+ sheet::ValidationAlertStyle eStyle = static_cast<sheet::ValidationAlertStyle>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
+ switch (eStyle)
+ {
+ case sheet::ValidationAlertStyle_STOP: nErrorStyle = SC_VALERR_STOP; break;
+ case sheet::ValidationAlertStyle_WARNING: nErrorStyle = SC_VALERR_WARNING; break;
+ case sheet::ValidationAlertStyle_INFO: nErrorStyle = SC_VALERR_INFO; break;
+ case sheet::ValidationAlertStyle_MACRO: nErrorStyle = SC_VALERR_MACRO; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_SOURCESTR )
+ {
+ // internal - only for XML filter, not in PropertySetInfo, only set
+
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aPosString = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_FORMULANMSP1 )
+ {
+ // internal - only for XML filter, not in PropertySetInfo, only set
+
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ maExprNmsp1 = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_FORMULANMSP2 )
+ {
+ // internal - only for XML filter, not in PropertySetInfo, only set
+
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ maExprNmsp2 = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_GRAMMAR1 )
+ {
+ // internal - only for XML filter, not in PropertySetInfo, only set
+
+ sal_Int32 nVal = 0;
+ if ( aValue >>= nVal )
+ meGrammar1 = static_cast< FormulaGrammar::Grammar >(nVal);
+ }
+ else if ( aPropertyName == SC_UNONAME_GRAMMAR2 )
+ {
+ // internal - only for XML filter, not in PropertySetInfo, only set
+
+ sal_Int32 nVal = 0;
+ if ( aValue >>= nVal )
+ meGrammar2 = static_cast< FormulaGrammar::Grammar >(nVal);
+ }
+}
+
+uno::Any SAL_CALL ScTableValidationObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if ( aPropertyName == SC_UNONAME_SHOWINP ) aRet <<= bShowInput;
+ else if ( aPropertyName == SC_UNONAME_SHOWERR ) aRet <<= bShowError;
+ else if ( aPropertyName == SC_UNONAME_IGNOREBL ) aRet <<= bIgnoreBlank;
+ else if ( aPropertyName == SC_UNONAME_SHOWLIST ) aRet <<= nShowList;
+ else if ( aPropertyName == SC_UNONAME_INPTITLE ) aRet <<= aInputTitle;
+ else if ( aPropertyName == SC_UNONAME_INPMESS ) aRet <<= aInputMessage;
+ else if ( aPropertyName == SC_UNONAME_ERRTITLE ) aRet <<= aErrorTitle;
+ else if ( aPropertyName == SC_UNONAME_ERRMESS ) aRet <<= aErrorMessage;
+ else if ( aPropertyName == SC_UNONAME_TYPE )
+ {
+ sheet::ValidationType eType = sheet::ValidationType_ANY;
+ switch (nValMode)
+ {
+ case SC_VALID_ANY: eType = sheet::ValidationType_ANY; break;
+ case SC_VALID_WHOLE: eType = sheet::ValidationType_WHOLE; break;
+ case SC_VALID_DECIMAL: eType = sheet::ValidationType_DECIMAL; break;
+ case SC_VALID_DATE: eType = sheet::ValidationType_DATE; break;
+ case SC_VALID_TIME: eType = sheet::ValidationType_TIME; break;
+ case SC_VALID_TEXTLEN: eType = sheet::ValidationType_TEXT_LEN; break;
+ case SC_VALID_LIST: eType = sheet::ValidationType_LIST; break;
+ case SC_VALID_CUSTOM: eType = sheet::ValidationType_CUSTOM; break;
+ }
+ aRet <<= eType;
+ }
+ else if ( aPropertyName == SC_UNONAME_ERRALSTY )
+ {
+ sheet::ValidationAlertStyle eStyle = sheet::ValidationAlertStyle_STOP;
+ switch (nErrorStyle)
+ {
+ case SC_VALERR_STOP: eStyle = sheet::ValidationAlertStyle_STOP; break;
+ case SC_VALERR_WARNING: eStyle = sheet::ValidationAlertStyle_WARNING; break;
+ case SC_VALERR_INFO: eStyle = sheet::ValidationAlertStyle_INFO; break;
+ case SC_VALERR_MACRO: eStyle = sheet::ValidationAlertStyle_MACRO; break;
+ }
+ aRet <<= eStyle;
+ }
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScTableValidationObj )
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/forbiuno.cxx b/sc/source/ui/unoobj/forbiuno.cxx
new file mode 100644
index 0000000000..0928170c55
--- /dev/null
+++ b/sc/source/ui/unoobj/forbiuno.cxx
@@ -0,0 +1,81 @@
+/* -*- 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 <editeng/forbiddencharacterstable.hxx>
+#include <comphelper/processfactory.hxx>
+#include <vcl/svapp.hxx>
+
+#include <forbiuno.hxx>
+#include <docsh.hxx>
+
+using namespace ::com::sun::star;
+
+static std::shared_ptr<SvxForbiddenCharactersTable> lcl_GetForbidden( ScDocShell* pDocSh )
+{
+ std::shared_ptr<SvxForbiddenCharactersTable> xRet;
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ xRet = rDoc.GetForbiddenCharacters();
+ if (!xRet)
+ {
+ // create an empty SvxForbiddenCharactersTable for SvxUnoForbiddenCharsTable,
+ // so changes can be stored.
+ xRet = SvxForbiddenCharactersTable::makeForbiddenCharactersTable(comphelper::getProcessComponentContext());
+ rDoc.SetForbiddenCharacters( xRet );
+ }
+ }
+ return xRet;
+}
+
+ScForbiddenCharsObj::ScForbiddenCharsObj( ScDocShell* pDocSh ) :
+ SvxUnoForbiddenCharsTable( lcl_GetForbidden( pDocSh ) ),
+ pDocShell( pDocSh )
+{
+ if (pDocShell)
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScForbiddenCharsObj::~ScForbiddenCharsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScForbiddenCharsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // document gone
+ }
+}
+
+void ScForbiddenCharsObj::onChange()
+{
+ if (pDocShell)
+ {
+ pDocShell->GetDocument().SetForbiddenCharacters( mxForbiddenChars );
+ pDocShell->PostPaintGridAll();
+ pDocShell->SetDocumentModified();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/funcuno.cxx b/sc/source/ui/unoobj/funcuno.cxx
new file mode 100644
index 0000000000..6f5226452b
--- /dev/null
+++ b/sc/source/ui/unoobj/funcuno.cxx
@@ -0,0 +1,653 @@
+/* -*- 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 <cppuhelper/supportsservice.hxx>
+#include <sfx2/app.hxx>
+#include <svl/itemprop.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+
+#include <funcuno.hxx>
+#include <miscuno.hxx>
+#include <cellsuno.hxx>
+#include <scdll.hxx>
+#include <document.hxx>
+#include <compiler.hxx>
+#include <formula/errorcodes.hxx>
+#include <callform.hxx>
+#include <addincol.hxx>
+#include <rangeseq.hxx>
+#include <formulacell.hxx>
+#include <docoptio.hxx>
+#include <optuno.hxx>
+#include <markdata.hxx>
+#include <patattr.hxx>
+#include <docpool.hxx>
+#include <attrib.hxx>
+#include <clipparam.hxx>
+#include <stringutil.hxx>
+#include <tokenarray.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+
+// registered as implementation for service FunctionAccess,
+// also supports service SpreadsheetDocumentSettings (to set null date etc.)
+
+constexpr OUString SCFUNCTIONACCESS_SERVICE = u"com.sun.star.sheet.FunctionAccess"_ustr;
+constexpr OUString SCDOCSETTINGS_SERVICE = u"com.sun.star.sheet.SpreadsheetDocumentSettings"_ustr;
+
+// helper to use cached document if not in use, temporary document otherwise
+
+namespace {
+
+class ScTempDocSource
+{
+private:
+ ScTempDocCache& rCache;
+ ScDocumentUniquePtr pTempDoc;
+
+ static ScDocument* CreateDocument(); // create and initialize doc
+
+public:
+ explicit ScTempDocSource( ScTempDocCache& rDocCache );
+ ~ScTempDocSource() COVERITY_NOEXCEPT_FALSE;
+
+ ScDocument* GetDocument();
+};
+
+}
+
+ScDocument* ScTempDocSource::CreateDocument()
+{
+ ScDocument* pDoc = new ScDocument( SCDOCMODE_FUNCTIONACCESS );
+ pDoc->MakeTable( 0 );
+ return pDoc;
+}
+
+ScTempDocSource::ScTempDocSource( ScTempDocCache& rDocCache ) :
+ rCache( rDocCache )
+{
+ if ( rCache.IsInUse() )
+ pTempDoc.reset(CreateDocument());
+ else
+ {
+ rCache.SetInUse( true );
+ if ( !rCache.GetDocument() )
+ rCache.SetDocument( CreateDocument() );
+ }
+}
+
+ScTempDocSource::~ScTempDocSource() COVERITY_NOEXCEPT_FALSE
+{
+ if ( !pTempDoc )
+ rCache.SetInUse( false );
+}
+
+ScDocument* ScTempDocSource::GetDocument()
+{
+ if ( pTempDoc )
+ return pTempDoc.get();
+ else
+ return rCache.GetDocument();
+}
+
+ScTempDocCache::ScTempDocCache()
+ : bInUse(false)
+{
+}
+
+void ScTempDocCache::SetDocument( ScDocument* pNew )
+{
+ OSL_ENSURE(!xDoc, "ScTempDocCache::SetDocument: already set");
+ xDoc.reset(pNew);
+}
+
+void ScTempDocCache::Clear()
+{
+ OSL_ENSURE( !bInUse, "ScTempDocCache::Clear: bInUse" );
+ xDoc.reset();
+}
+
+// copy results from one document into another
+//! merge this with ScAreaLink::Refresh
+//! copy directly without a clipboard document?
+
+static bool lcl_CopyData( ScDocument* pSrcDoc, const ScRange& rSrcRange,
+ ScDocument* pDestDoc, const ScAddress& rDestPos )
+{
+ SCTAB nSrcTab = rSrcRange.aStart.Tab();
+ SCTAB nDestTab = rDestPos.Tab();
+
+ ScRange aNewRange( rDestPos, ScAddress(
+ rSrcRange.aEnd.Col() - rSrcRange.aStart.Col() + rDestPos.Col(),
+ rSrcRange.aEnd.Row() - rSrcRange.aStart.Row() + rDestPos.Row(),
+ nDestTab ) );
+
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+ ScMarkData aSourceMark(pSrcDoc->GetSheetLimits());
+ aSourceMark.SelectOneTable( nSrcTab ); // for CopyToClip
+ aSourceMark.SetMarkArea( rSrcRange );
+ ScClipParam aClipParam(rSrcRange, false);
+ pSrcDoc->CopyToClip(aClipParam, pClipDoc.get(), &aSourceMark, false, false);
+
+ if ( pClipDoc->HasAttrib( 0,0,nSrcTab, pClipDoc->MaxCol(), pClipDoc->MaxRow(),nSrcTab,
+ HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
+ {
+ ScPatternAttr aPattern( pSrcDoc->GetPool() );
+ aPattern.GetItemSet().Put( ScMergeAttr() ); // Defaults
+ aPattern.GetItemSet().Put( ScMergeFlagAttr() );
+ pClipDoc->ApplyPatternAreaTab( 0,0, pClipDoc->MaxCol(), pClipDoc->MaxRow(), nSrcTab, aPattern );
+ }
+
+ ScMarkData aDestMark(pDestDoc->GetSheetLimits());
+ aDestMark.SelectOneTable( nDestTab );
+ aDestMark.SetMarkArea( aNewRange );
+ pDestDoc->CopyFromClip( aNewRange, aDestMark, InsertDeleteFlags::ALL & ~InsertDeleteFlags::FORMULA, nullptr, pClipDoc.get(), false );
+
+ return true;
+}
+
+ScFunctionAccess::ScFunctionAccess() :
+ aPropertyMap( ScDocOptionsHelper::GetPropertyMap() ),
+ mbArray( true ), // default according to behaviour of older Office versions
+ mbValid( true )
+{
+ StartListening( *SfxGetpApp() ); // for SfxHintId::Deinitializing
+}
+
+ScFunctionAccess::~ScFunctionAccess()
+{
+ pOptions.reset();
+ {
+ // SfxBroadcaster::RemoveListener checks DBG_TESTSOLARMUTEX():
+ SolarMutexGuard g;
+ EndListeningAll();
+ }
+}
+
+void ScFunctionAccess::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Deinitializing )
+ {
+ // document must not be used anymore
+ aDocCache.Clear();
+ mbValid = false;
+ }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ScFunctionAccess_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScFunctionAccess);
+}
+
+// XServiceInfo
+OUString SAL_CALL ScFunctionAccess::getImplementationName()
+{
+ return "stardiv.StarCalc.ScFunctionAccess";
+}
+
+sal_Bool SAL_CALL ScFunctionAccess::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScFunctionAccess::getSupportedServiceNames()
+{
+ return {SCFUNCTIONACCESS_SERVICE, SCDOCSETTINGS_SERVICE};
+}
+
+// XPropertySet (document settings)
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFunctionAccess::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropertyMap ));
+ return aRef;
+}
+
+void SAL_CALL ScFunctionAccess::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == "IsArrayFunction" )
+ {
+ if( !(aValue >>= mbArray) )
+ throw lang::IllegalArgumentException();
+ }
+ else
+ {
+ if ( !pOptions )
+ pOptions.reset( new ScDocOptions() );
+
+ // options aren't initialized from configuration - always get the same default behaviour
+
+ bool bDone = ScDocOptionsHelper::setPropertyValue( *pOptions, aPropertyMap, aPropertyName, aValue );
+ if (!bDone)
+ throw beans::UnknownPropertyException(aPropertyName);
+ }
+}
+
+uno::Any SAL_CALL ScFunctionAccess::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == "IsArrayFunction" )
+ return uno::Any( mbArray );
+
+ if ( !pOptions )
+ pOptions.reset( new ScDocOptions() );
+
+ // options aren't initialized from configuration - always get the same default behaviour
+
+ return ScDocOptionsHelper::getPropertyValue( *pOptions, aPropertyMap, aPropertyName );
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFunctionAccess )
+
+// XFunctionAccess
+
+static bool lcl_AddFunctionToken( ScTokenArray& rArray, const OUString& rName,const ScCompiler& rCompiler )
+{
+ // function names are always case-insensitive
+ OUString aUpper = ScGlobal::getCharClass().uppercase(rName);
+
+ // same options as in ScCompiler::IsOpCode:
+ // 1. built-in function name
+
+ OpCode eOp = rCompiler.GetEnglishOpCode( aUpper );
+ if ( eOp != ocNone )
+ {
+ rArray.AddOpCode( eOp );
+ return true;
+ }
+
+ // 2. old add in functions
+
+ if (ScGlobal::GetLegacyFuncCollection()->findByName(aUpper))
+ {
+ rArray.AddExternal(aUpper.getStr());
+ return true;
+ }
+
+ // 3. new (uno) add in functions
+
+ OUString aIntName =
+ ScGlobal::GetAddInCollection()->FindFunction(aUpper, false);
+ if (!aIntName.isEmpty())
+ {
+ rArray.AddExternal(aIntName.getStr()); // international name
+ return true;
+ }
+
+ return false; // no valid function name
+}
+
+static void lcl_AddRef( ScTokenArray& rArray, sal_Int32 nStartRow, sal_Int32 nColCount, sal_Int32 nRowCount )
+{
+ ScComplexRefData aRef;
+ aRef.InitRange(ScRange(0,nStartRow,0,nColCount-1,nStartRow+nRowCount-1,0));
+ rArray.AddDoubleReference(aRef);
+}
+
+namespace {
+
+class SimpleVisitor
+{
+protected:
+ bool mbArgError;
+ ScDocument* mpDoc;
+public:
+ explicit SimpleVisitor( ScDocument* pDoc ) : mbArgError( false ), mpDoc( pDoc ) {}
+ // could possibly just get away with JUST the following overload
+ // 1) virtual void visitElem( long& nCol, long& nRow, const double& elem )
+ // 2) virtual void visitElem( long& nCol, long& nRow, const OUString& elem )
+ // 3) virtual void visitElem( long& nCol, long& nRow, const uno::Any& elem )
+ // the other types methods are here just to reflect the orig code and for
+ // completeness.
+
+ void visitElem( sal_Int32 nCol, sal_Int32 nRow, sal_Int16 elem )
+ {
+ mpDoc->SetValue( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), 0, elem );
+ }
+ void visitElem( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 elem )
+ {
+ mpDoc->SetValue( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), 0, elem );
+ }
+ void visitElem( sal_Int32 nCol, sal_Int32 nRow, const double& elem )
+ {
+ mpDoc->SetValue( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), 0, elem );
+ }
+ void visitElem( sal_Int32 nCol, sal_Int32 nRow, const OUString& elem )
+ {
+ if (!elem.isEmpty())
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ mpDoc->SetString(ScAddress(nCol,nRow,0), elem, &aParam);
+ }
+ }
+ void visitElem( sal_Int32 nCol, sal_Int32 nRow, const uno::Any& rElement )
+ {
+ uno::TypeClass eElemClass = rElement.getValueTypeClass();
+ if ( eElemClass == uno::TypeClass_VOID )
+ {
+ // leave empty
+ }
+ else if ( eElemClass == uno::TypeClass_BYTE ||
+ eElemClass == uno::TypeClass_SHORT ||
+ eElemClass == uno::TypeClass_UNSIGNED_SHORT ||
+ eElemClass == uno::TypeClass_LONG ||
+ eElemClass == uno::TypeClass_UNSIGNED_LONG ||
+ eElemClass == uno::TypeClass_FLOAT ||
+ eElemClass == uno::TypeClass_DOUBLE )
+ {
+ // accept integer types because Basic passes a floating point
+ // variable as byte, short or long if it's an integer number.
+ double fVal(0.0);
+ rElement >>= fVal;
+ visitElem( nCol, nRow, fVal );
+ }
+ else if ( eElemClass == uno::TypeClass_STRING )
+ {
+ OUString aUStr;
+ rElement >>= aUStr;
+ visitElem( nCol, nRow, aUStr );
+ }
+ else
+ mbArgError = true;
+ }
+ bool hasArgError() const { return mbArgError; }
+};
+
+template< class seq >
+class SequencesContainer
+{
+ uno::Sequence< uno::Sequence< seq > > maSeq;
+
+ sal_Int32& mrDocRow;
+ bool mbOverflow;
+ bool mbArgError;
+ ScDocument* mpDoc;
+ ScTokenArray& mrTokenArr;
+
+public:
+ SequencesContainer( const uno::Any& rArg, ScTokenArray& rTokenArr, sal_Int32& rDocRow, ScDocument* pDoc ) :
+ mrDocRow( rDocRow ), mbOverflow(false), mbArgError(false), mpDoc( pDoc ), mrTokenArr( rTokenArr )
+ {
+ rArg >>= maSeq;
+ }
+
+ void process()
+ {
+ SimpleVisitor aVisitor(mpDoc);
+ sal_Int32 nStartRow = mrDocRow;
+ sal_Int32 nRowCount = maSeq.getLength();
+ sal_Int32 nMaxColCount = 0;
+ for ( const uno::Sequence< seq >& rRow : std::as_const(maSeq) )
+ {
+ sal_Int32 nColCount = rRow.getLength();
+ if ( nColCount > nMaxColCount )
+ nMaxColCount = nColCount;
+ for (sal_Int32 nCol=0; nCol<nColCount; nCol++)
+ if ( nCol <= mpDoc->MaxCol() && mrDocRow <= mpDoc->MaxRow() )
+ aVisitor.visitElem( nCol, mrDocRow, rRow[ nCol ] );
+ else
+ mbOverflow=true;
+ mrDocRow++;
+ }
+ mbArgError = aVisitor.hasArgError();
+ if (!mbOverflow)
+ {
+ if (nRowCount && nMaxColCount)
+ lcl_AddRef( mrTokenArr, nStartRow, nMaxColCount, nRowCount );
+ else if (nRowCount == 1 && !nMaxColCount)
+ // Empty Sequence<Sequence<Any>> is omitted argument.
+ mrTokenArr.AddOpCode( ocMissing);
+ }
+ }
+ bool getOverflow() const { return mbOverflow; }
+ bool getArgError() const { return mbArgError; }
+};
+
+template <class T>
+class ArrayOfArrayProc
+{
+public:
+static void processSequences( ScDocument* pDoc, const uno::Any& rArg, ScTokenArray& rTokenArr,
+ sal_Int32& rDocRow, bool& rArgErr, bool& rOverflow )
+{
+ SequencesContainer< T > aContainer( rArg, rTokenArr, rDocRow, pDoc );
+ aContainer.process();
+ rArgErr = aContainer.getArgError();
+ rOverflow = aContainer.getOverflow();
+}
+};
+
+}
+
+uno::Any SAL_CALL ScFunctionAccess::callFunction( const OUString& aName,
+ const uno::Sequence<uno::Any>& aArguments )
+{
+ SolarMutexGuard aGuard;
+
+ if (!mbValid)
+ throw uno::RuntimeException();
+
+ // use cached document if not in use, temporary document otherwise
+ // (deleted in ScTempDocSource dtor)
+ ScTempDocSource aSource( aDocCache );
+ ScDocument* pDoc = aSource.GetDocument();
+ const static SCTAB nTempSheet = 1;
+ // Create an extra tab to contain the Function Cell
+ // this will allow full rows to be used.
+ if ( !pDoc->HasTable( nTempSheet ) )
+ pDoc->MakeTable( nTempSheet );
+
+ /// TODO: check
+ ScAddress aAdr;
+ ScCompiler aCompiler(*pDoc, aAdr, pDoc->GetGrammar());
+
+ // find function
+
+ ScTokenArray aTokenArr(*pDoc);
+ if ( !lcl_AddFunctionToken( aTokenArr, aName,aCompiler ) )
+ {
+ // function not found
+ throw container::NoSuchElementException();
+ }
+
+ // set options (null date, etc.)
+
+ if ( pOptions )
+ pDoc->SetDocOptions( *pOptions );
+
+ // add arguments to token array
+
+ bool bArgErr = false;
+ bool bOverflow = false;
+ sal_Int32 nDocRow = 0;
+ tools::Long nArgCount = aArguments.getLength();
+ const uno::Any* pArgArr = aArguments.getConstArray();
+
+ svl::SharedStringPool& rSPool = pDoc->GetSharedStringPool();
+ aTokenArr.AddOpCode(ocOpen);
+ for (tools::Long nPos=0; nPos<nArgCount; nPos++)
+ {
+ if ( nPos > 0 )
+ aTokenArr.AddOpCode(ocSep);
+
+ const uno::Any& rArg = pArgArr[nPos];
+
+ uno::TypeClass eClass = rArg.getValueTypeClass();
+ const uno::Type& aType = rArg.getValueType();
+ if ( eClass == uno::TypeClass_BYTE ||
+ eClass == uno::TypeClass_BOOLEAN ||
+ eClass == uno::TypeClass_SHORT ||
+ eClass == uno::TypeClass_UNSIGNED_SHORT ||
+ eClass == uno::TypeClass_LONG ||
+ eClass == uno::TypeClass_UNSIGNED_LONG ||
+ eClass == uno::TypeClass_FLOAT ||
+ eClass == uno::TypeClass_DOUBLE )
+ {
+ // accept integer types because Basic passes a floating point
+ // variable as byte, short or long if it's an integer number.
+ double fVal = 0;
+ rArg >>= fVal;
+ aTokenArr.AddDouble( fVal );
+ }
+ else if ( eClass == uno::TypeClass_STRING )
+ {
+ OUString aUStr;
+ rArg >>= aUStr;
+ aTokenArr.AddString(rSPool.intern(aUStr));
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int16> >>::get() ) )
+ {
+ ArrayOfArrayProc<sal_Int16>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int32> >>::get() ) )
+ {
+ ArrayOfArrayProc<sal_Int32>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<double> >>::get() ) )
+ {
+ ArrayOfArrayProc<double>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<OUString> >>::get() ) )
+ {
+ ArrayOfArrayProc<OUString>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<uno::Any> >>::get() ) )
+ {
+ ArrayOfArrayProc<uno::Any>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( cppu::UnoType<table::XCellRange>::get()) )
+ {
+ // currently, only our own cell ranges are supported
+
+ uno::Reference<table::XCellRange> xRange(rArg, uno::UNO_QUERY);
+ ScCellRangesBase* pImpl = dynamic_cast<ScCellRangesBase*>( xRange.get() );
+ if ( pImpl )
+ {
+ ScDocument* pSrcDoc = pImpl->GetDocument();
+ const ScRangeList& rRanges = pImpl->GetRangeList();
+ if ( pSrcDoc && rRanges.size() == 1 )
+ {
+ ScRange const & rSrcRange = rRanges[ 0 ];
+
+ sal_Int32 nStartRow = nDocRow;
+ sal_Int32 nColCount = rSrcRange.aEnd.Col() - rSrcRange.aStart.Col() + 1;
+ sal_Int32 nRowCount = rSrcRange.aEnd.Row() - rSrcRange.aStart.Row() + 1;
+
+ if ( nStartRow + nRowCount > pDoc->GetSheetLimits().GetMaxRowCount() )
+ bOverflow = true;
+ else
+ {
+ // copy data
+ if ( !lcl_CopyData( pSrcDoc, rSrcRange, pDoc, ScAddress( 0, static_cast<SCROW>(nDocRow), 0 ) ) )
+ bOverflow = true;
+ }
+
+ nDocRow += nRowCount;
+ if ( !bOverflow )
+ lcl_AddRef( aTokenArr, nStartRow, nColCount, nRowCount );
+ }
+ else
+ bArgErr = true;
+ }
+ else
+ bArgErr = true;
+ }
+ else
+ bArgErr = true; // invalid type
+ }
+ aTokenArr.AddOpCode(ocClose);
+ aTokenArr.AddOpCode(ocStop);
+
+ // execute formula
+
+ uno::Any aRet;
+ if ( !bArgErr && !bOverflow && nDocRow <= pDoc->GetSheetLimits().GetMaxRowCount() )
+ {
+ ScAddress aFormulaPos( 0, 0, nTempSheet );
+ // GRAM_API doesn't really matter for the token array but fits with
+ // other API compatibility grammars.
+ ScFormulaCell* pFormula = new ScFormulaCell(
+ *pDoc, aFormulaPos, aTokenArr, formula::FormulaGrammar::GRAM_API,
+ mbArray ? ScMatrixMode::Formula : ScMatrixMode::NONE );
+ pFormula = pDoc->SetFormulaCell(aFormulaPos, pFormula);
+ if (mbArray && pFormula)
+ pFormula->SetMatColsRows(1,1); // the cell dimensions (only one cell)
+
+ // call GetMatrix before GetErrCode because GetMatrix always recalculates
+ // if there is no matrix result
+
+ const ScMatrix* pMat = (mbArray && pFormula) ? pFormula->GetMatrix() : nullptr;
+ FormulaError nErrCode = pFormula ? pFormula->GetErrCode() : FormulaError::IllegalArgument;
+ if ( nErrCode == FormulaError::NONE )
+ {
+ if ( pMat )
+ {
+ // array result
+ ScRangeToSequence::FillMixedArray( aRet, pMat );
+ }
+ else if ( pFormula->IsValue() )
+ {
+ // numeric value
+ aRet <<= pFormula->GetValue();
+ }
+ else
+ {
+ // string result
+ OUString aStrVal = pFormula->GetString().getString();
+ aRet <<= aStrVal;
+ }
+ }
+ else if ( nErrCode == FormulaError::NotAvailable )
+ {
+ // #N/A: leave result empty, no exception
+ }
+ else
+ {
+ // any other error: IllegalArgumentException
+ bArgErr = true;
+ }
+
+ pDoc->DeleteAreaTab( 0, 0, pDoc->MaxCol(), pDoc->MaxRow(), 0, InsertDeleteFlags::ALL );
+ pDoc->DeleteAreaTab( 0, 0, 0, 0, nTempSheet, InsertDeleteFlags::ALL );
+ }
+
+ if (bOverflow)
+ throw uno::RuntimeException();
+
+ if (bArgErr)
+ throw lang::IllegalArgumentException();
+
+ return aRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/linkuno.cxx b/sc/source/ui/unoobj/linkuno.cxx
new file mode 100644
index 0000000000..b8c6a9c7e3
--- /dev/null
+++ b/sc/source/ui/unoobj/linkuno.cxx
@@ -0,0 +1,1688 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/sequence.hxx>
+#include <formula/token.hxx>
+#include <svl/hint.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <svl/sharedstringpool.hxx>
+
+#include <linkuno.hxx>
+#include <miscuno.hxx>
+#include <convuno.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <tablink.hxx>
+#include <arealink.hxx>
+#include <hints.hxx>
+#include <unonames.hxx>
+#include <rangeseq.hxx>
+#include <scmatrix.hxx>
+#include <documentlinkmgr.hxx>
+
+#include <string_view>
+#include <vector>
+
+using namespace com::sun::star;
+using namespace formula;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::lang::IllegalArgumentException;
+using ::com::sun::star::uno::RuntimeException;
+using ::std::vector;
+
+// used for sheet- and area link:
+static std::span<const SfxItemPropertyMapEntry> lcl_GetSheetLinkMap()
+{
+ static const SfxItemPropertyMapEntry aSheetLinkMap_Impl[] =
+ {
+ { SC_UNONAME_FILTER, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_FILTOPT, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_LINKURL, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_REFDELAY, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_REFPERIOD, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ };
+ return aSheetLinkMap_Impl;
+}
+
+SC_SIMPLE_SERVICE_INFO( ScAreaLinkObj, "ScAreaLinkObj", "com.sun.star.sheet.CellAreaLink" )
+SC_SIMPLE_SERVICE_INFO( ScAreaLinksObj, "ScAreaLinksObj", "com.sun.star.sheet.CellAreaLinks" )
+SC_SIMPLE_SERVICE_INFO( ScDDELinkObj, "ScDDELinkObj", "com.sun.star.sheet.DDELink" )
+SC_SIMPLE_SERVICE_INFO( ScDDELinksObj, "ScDDELinksObj", "com.sun.star.sheet.DDELinks" )
+SC_SIMPLE_SERVICE_INFO( ScSheetLinkObj, "ScSheetLinkObj", "com.sun.star.sheet.SheetLink" )
+SC_SIMPLE_SERVICE_INFO( ScSheetLinksObj, "ScSheetLinksObj", "com.sun.star.sheet.SheetLinks" )
+
+ScSheetLinkObj::ScSheetLinkObj(ScDocShell* pDocSh, OUString aName) :
+ aPropSet( lcl_GetSheetLinkMap() ),
+ pDocShell( pDocSh ),
+ aFileName(std::move( aName ))
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScSheetLinkObj::~ScSheetLinkObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScSheetLinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! notify if links in document are changed
+ // UpdateRef is not needed here
+
+ if ( auto pRefreshHint = dynamic_cast<const ScLinkRefreshedHint*>(&rHint) )
+ {
+ if ( pRefreshHint->GetLinkType() == ScLinkRefType::SHEET && pRefreshHint->GetUrl() == aFileName )
+ Refreshed_Impl();
+ }
+ else
+ {
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // pointer is invalid
+ }
+}
+
+ScTableLink* ScSheetLinkObj::GetLink_Impl() const
+{
+ if (pDocShell)
+ {
+ sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
+ size_t nCount = pLinkManager->GetLinks().size();
+ for (size_t i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
+ if (auto pTabLink = dynamic_cast<ScTableLink*>( pBase))
+ {
+ if ( pTabLink->GetFileName() == aFileName )
+ return pTabLink;
+ }
+ }
+ }
+ return nullptr; // not found
+}
+
+// XNamed
+
+OUString SAL_CALL ScSheetLinkObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return getFileName(); // Name is the same as filename (URL)
+}
+
+void SAL_CALL ScSheetLinkObj::setName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ setFileName(aName); // Name is the same as filename (URL)
+}
+
+// XRefreshable
+
+void SAL_CALL ScSheetLinkObj::refresh()
+{
+ SolarMutexGuard aGuard;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ pLink->Refresh( pLink->GetFileName(), pLink->GetFilterName(), nullptr, pLink->GetRefreshDelaySeconds() );
+}
+
+void SAL_CALL ScSheetLinkObj::addRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRefreshListeners.push_back( xListener );
+
+ // hold one additional ref to keep this object alive as long as there are listeners
+ if ( aRefreshListeners.size() == 1 )
+ acquire();
+}
+
+void SAL_CALL ScSheetLinkObj::removeRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ size_t nCount = aRefreshListeners.size();
+ for ( size_t n=nCount; n--; )
+ {
+ uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n];
+ if ( rObj == xListener )
+ {
+ aRefreshListeners.erase( aRefreshListeners.begin() + n );
+ if ( aRefreshListeners.empty() )
+ release(); // release ref for listeners
+ break;
+ }
+ }
+}
+
+void ScSheetLinkObj::Refreshed_Impl()
+{
+ lang::EventObject aEvent;
+ aEvent.Source.set(getXWeak());
+ for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners)
+ xRefreshListener->refreshed( aEvent );
+}
+
+void ScSheetLinkObj::ModifyRefreshDelay_Impl( sal_Int32 nRefresh )
+{
+ ScTableLink* pLink = GetLink_Impl();
+ if( pLink )
+ pLink->SetRefreshDelay( static_cast<sal_uLong>(nRefresh) );
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSheetLinkObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScSheetLinkObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ OUString aValStr;
+ if ( aPropertyName == SC_UNONAME_LINKURL )
+ {
+ if ( aValue >>= aValStr )
+ setFileName( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_FILTER )
+ {
+ if ( aValue >>= aValStr )
+ setFilter( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_FILTOPT )
+ {
+ if ( aValue >>= aValStr )
+ setFilterOptions( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_REFPERIOD )
+ {
+ sal_Int32 nRefresh = 0;
+ if ( aValue >>= nRefresh )
+ setRefreshDelay( nRefresh );
+ }
+ else if ( aPropertyName == SC_UNONAME_REFDELAY )
+ {
+ sal_Int32 nRefresh = 0;
+ if ( aValue >>= nRefresh )
+ setRefreshDelay( nRefresh );
+ }
+}
+
+uno::Any SAL_CALL ScSheetLinkObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ if ( aPropertyName == SC_UNONAME_LINKURL )
+ aRet <<= getFileName();
+ else if ( aPropertyName == SC_UNONAME_FILTER )
+ aRet <<= getFilter();
+ else if ( aPropertyName == SC_UNONAME_FILTOPT )
+ aRet <<= getFilterOptions();
+ else if ( aPropertyName == SC_UNONAME_REFPERIOD )
+ aRet <<= getRefreshDelay();
+ else if ( aPropertyName == SC_UNONAME_REFDELAY )
+ aRet <<= getRefreshDelay();
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSheetLinkObj )
+
+// internal:
+
+OUString ScSheetLinkObj::getFileName() const
+{
+ SolarMutexGuard aGuard;
+ return aFileName;
+}
+
+void ScSheetLinkObj::setFileName(const OUString& rNewName)
+{
+ SolarMutexGuard aGuard;
+ ScTableLink* pLink = GetLink_Impl();
+ if (!pLink)
+ return;
+
+ // pLink->Refresh with a new file name confuses sfx2::LinkManager
+ // therefore we transplant the sheets manually and create new links with UpdateLinks
+
+ OUString aNewStr(ScGlobal::GetAbsDocName( rNewName, pDocShell ));
+
+ // first transplant the sheets
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ if ( rDoc.IsLinked(nTab) && rDoc.GetLinkDoc(nTab) == aFileName ) // old file
+ rDoc.SetLink( nTab, rDoc.GetLinkMode(nTab), aNewStr,
+ rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab),
+ rDoc.GetLinkTab(nTab),
+ rDoc.GetLinkRefreshDelay(nTab) ); // only change the file
+
+ // update links
+ //! Undo !!!
+
+ pDocShell->UpdateLinks(); // remove old links, possibly set up new ones
+
+ // copy data
+
+ aFileName = aNewStr;
+ pLink = GetLink_Impl(); // new link with new name
+ if (pLink)
+ pLink->Update(); // incl. paint & undo for data
+}
+
+OUString ScSheetLinkObj::getFilter() const
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ aRet = pLink->GetFilterName();
+ return aRet;
+}
+
+void ScSheetLinkObj::setFilter(const OUString& rFilter)
+{
+ SolarMutexGuard aGuard;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ {
+ pLink->Refresh( aFileName, rFilter, nullptr, pLink->GetRefreshDelaySeconds() );
+ }
+}
+
+OUString ScSheetLinkObj::getFilterOptions() const
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ aRet = pLink->GetOptions();
+ return aRet;
+}
+
+void ScSheetLinkObj::setFilterOptions(const OUString& FilterOptions)
+{
+ SolarMutexGuard aGuard;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ {
+ OUString aOptStr(FilterOptions);
+ pLink->Refresh( aFileName, pLink->GetFilterName(), &aOptStr, pLink->GetRefreshDelaySeconds() );
+ }
+}
+
+sal_Int32 ScSheetLinkObj::getRefreshDelay() const
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nRet = 0;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ nRet = pLink->GetRefreshDelaySeconds();
+ return nRet;
+}
+
+void ScSheetLinkObj::setRefreshDelay(sal_Int32 nRefreshDelay)
+{
+ SolarMutexGuard aGuard;
+ ModifyRefreshDelay_Impl( nRefreshDelay );
+}
+
+ScSheetLinksObj::ScSheetLinksObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScSheetLinksObj::~ScSheetLinksObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScSheetLinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // we don't care about update of references here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XSheetLinks
+
+rtl::Reference<ScSheetLinkObj> ScSheetLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
+{
+ if (!pDocShell)
+ return nullptr;
+
+ typedef std::unordered_set<OUString> StrSetType;
+ StrSetType aNames;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ sal_Int32 nCount = 0;
+ for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
+ {
+ if (!rDoc.IsLinked(nTab))
+ continue;
+
+ OUString aLinkDoc = rDoc.GetLinkDoc(nTab);
+ if (aNames.insert(aLinkDoc).second)
+ {
+ // unique document name.
+ if (nCount == nIndex)
+ return new ScSheetLinkObj( pDocShell, aLinkDoc );
+ ++nCount;
+ }
+ }
+
+ return nullptr; // no document or index too large
+}
+
+rtl::Reference<ScSheetLinkObj> ScSheetLinksObj::GetObjectByName_Impl(const OUString& aName)
+{
+ // Name is the same as file name
+
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ if (rDoc.IsLinked(nTab))
+ {
+ //! case-insensitive ???
+ OUString aLinkDoc = rDoc.GetLinkDoc( nTab );
+ if ( aLinkDoc == aName )
+ return new ScSheetLinkObj( pDocShell, aName );
+ }
+ }
+
+ return nullptr;
+}
+
+// XEnumerationAccess
+uno::Reference<container::XEnumeration> SAL_CALL ScSheetLinksObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.SheetLinksEnumeration");
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL ScSheetLinksObj::getCount()
+{
+ typedef std::unordered_set<OUString> StrSetType;
+
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ return 0;
+
+ sal_Int32 nCount = 0;
+
+ StrSetType aNames;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
+ {
+ if (!rDoc.IsLinked(nTab))
+ continue;
+
+ OUString aLinkDoc = rDoc.GetLinkDoc(nTab);
+ if (aNames.insert(aLinkDoc).second)
+ ++nCount;
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL ScSheetLinksObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<beans::XPropertySet> xLink(GetObjectByIndex_Impl(nIndex));
+ if (!xLink.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xLink);
+}
+
+uno::Type SAL_CALL ScSheetLinksObj::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL ScSheetLinksObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Any SAL_CALL ScSheetLinksObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<beans::XPropertySet> xLink(GetObjectByName_Impl(aName));
+ if (!xLink.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xLink);
+}
+
+sal_Bool SAL_CALL ScSheetLinksObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ // Name is the same as file name
+
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ if (rDoc.IsLinked(nTab))
+ {
+ //! case-insensitive ???
+ OUString aLinkDoc(rDoc.GetLinkDoc( nTab ));
+ if ( aLinkDoc == aName )
+ return true;
+ }
+ }
+ return false;
+}
+
+uno::Sequence<OUString> SAL_CALL ScSheetLinksObj::getElementNames()
+{
+ typedef std::unordered_set<OUString> StrSetType;
+
+ SolarMutexGuard aGuard;
+ // Name is the same as file name
+
+ if (!pDocShell)
+ return uno::Sequence<OUString>();
+
+ StrSetType aNames;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+
+ sal_Int32 nLinkCount = getCount();
+ uno::Sequence<OUString> aSeq(nLinkCount);
+ OUString* pAry = aSeq.getArray();
+ size_t nPos = 0;
+ for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
+ {
+ if (!rDoc.IsLinked(nTab))
+ continue;
+
+ OUString aLinkDoc = rDoc.GetLinkDoc(nTab);
+ if (aNames.insert(aLinkDoc).second)
+ pAry[nPos++] = aLinkDoc;
+ }
+ OSL_ENSURE( nPos==static_cast<size_t>(nLinkCount), "verzaehlt" );
+ return aSeq;
+}
+
+static ScAreaLink* lcl_GetAreaLink( ScDocShell* pDocShell, size_t nPos )
+{
+ if (pDocShell)
+ {
+ sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
+ size_t nTotalCount = pLinkManager->GetLinks().size();
+ size_t nAreaCount = 0;
+ for (size_t i=0; i<nTotalCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
+ if (auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase))
+ {
+ if ( nAreaCount == nPos )
+ return pAreaLink;
+ ++nAreaCount;
+ }
+ }
+ }
+ return nullptr; // not found
+}
+
+ScAreaLinkObj::ScAreaLinkObj(ScDocShell* pDocSh, size_t nP) :
+ aPropSet( lcl_GetSheetLinkMap() ),
+ pDocShell( pDocSh ),
+ nPos( nP )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScAreaLinkObj::~ScAreaLinkObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScAreaLinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! notify if links in document are changed
+ // UpdateRef is not needed here
+
+ if ( auto pRefreshedHint = dynamic_cast<const ScLinkRefreshedHint*>(&rHint) )
+ {
+ if ( pRefreshedHint->GetLinkType() == ScLinkRefType::AREA )
+ {
+ // get this link to compare dest position
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if ( pLink && pLink->GetDestArea().aStart == pRefreshedHint->GetDestPos() )
+ Refreshed_Impl();
+ }
+ }
+ else
+ {
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // pointer is invalid
+ }
+}
+
+// XFileLink
+
+void ScAreaLinkObj::Modify_Impl( const OUString* pNewFile, const OUString* pNewFilter,
+ const OUString* pNewOptions, const OUString* pNewSource,
+ const table::CellRangeAddress* pNewDest )
+{
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (!pLink)
+ return;
+
+ OUString aFile (pLink->GetFile());
+ OUString aFilter (pLink->GetFilter());
+ OUString aOptions (pLink->GetOptions());
+ OUString aSource (pLink->GetSource());
+ ScRange aDest (pLink->GetDestArea());
+ sal_Int32 nRefreshDelaySeconds = pLink->GetRefreshDelaySeconds();
+
+ //! Undo delete
+ //! Undo merge
+
+ sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
+ pLinkManager->Remove( pLink );
+ pLink = nullptr; // deleted along with remove
+
+ bool bFitBlock = true; // move, if the size changes with update
+ if (pNewFile)
+ {
+ aFile = ScGlobal::GetAbsDocName( *pNewFile, pDocShell ); //! in InsertAreaLink?
+ }
+ if (pNewFilter)
+ aFilter = *pNewFilter;
+ if (pNewOptions)
+ aOptions = *pNewOptions;
+ if (pNewSource)
+ aSource = *pNewSource;
+ if (pNewDest)
+ {
+ ScUnoConversion::FillScRange( aDest, *pNewDest );
+ bFitBlock = false; // new range was specified -> do not move the content
+ }
+ pDocShell->GetDocFunc().InsertAreaLink( aFile, aFilter, aOptions, aSource,
+ aDest, nRefreshDelaySeconds, bFitBlock, true );
+}
+
+void ScAreaLinkObj::ModifyRefreshDelay_Impl( sal_Int32 nRefreshDelaySeconds )
+{
+ ScAreaLink* pLink = lcl_GetAreaLink( pDocShell, nPos );
+ if( pLink )
+ pLink->SetRefreshDelay( nRefreshDelaySeconds );
+}
+
+// XRefreshable
+
+void SAL_CALL ScAreaLinkObj::refresh()
+{
+ SolarMutexGuard aGuard;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ pLink->Refresh( pLink->GetFile(), pLink->GetFilter(), pLink->GetSource(), pLink->GetRefreshDelaySeconds() );
+}
+
+void SAL_CALL ScAreaLinkObj::addRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRefreshListeners.push_back( xListener );
+
+ // hold one additional ref to keep this object alive as long as there are listeners
+ if ( aRefreshListeners.size() == 1 )
+ acquire();
+}
+
+void SAL_CALL ScAreaLinkObj::removeRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ size_t nCount = aRefreshListeners.size();
+ for ( size_t n=nCount; n--; )
+ {
+ uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n];
+ if ( rObj == xListener )
+ {
+ aRefreshListeners.erase( aRefreshListeners.begin() + n );
+ if ( aRefreshListeners.empty() )
+ release(); // release ref for listeners
+ break;
+ }
+
+ if(n == 0)
+ break;
+ }
+}
+
+void ScAreaLinkObj::Refreshed_Impl()
+{
+ lang::EventObject aEvent;
+ aEvent.Source.set(getXWeak());
+ for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners)
+ xRefreshListener->refreshed( aEvent );
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAreaLinkObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScAreaLinkObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ OUString aValStr;
+ if ( aPropertyName == SC_UNONAME_LINKURL )
+ {
+ if ( aValue >>= aValStr )
+ setFileName( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_FILTER )
+ {
+ if ( aValue >>= aValStr )
+ setFilter( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_FILTOPT )
+ {
+ if ( aValue >>= aValStr )
+ setFilterOptions( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_REFPERIOD )
+ {
+ sal_Int32 nRefresh = 0;
+ if ( aValue >>= nRefresh )
+ setRefreshDelay( nRefresh );
+ }
+ else if ( aPropertyName == SC_UNONAME_REFDELAY )
+ {
+ sal_Int32 nRefresh = 0;
+ if ( aValue >>= nRefresh )
+ setRefreshDelay( nRefresh );
+ }
+}
+
+uno::Any SAL_CALL ScAreaLinkObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ if ( aPropertyName == SC_UNONAME_LINKURL )
+ aRet <<= getFileName();
+ else if ( aPropertyName == SC_UNONAME_FILTER )
+ aRet <<= getFilter();
+ else if ( aPropertyName == SC_UNONAME_FILTOPT )
+ aRet <<= getFilterOptions();
+ else if ( aPropertyName == SC_UNONAME_REFPERIOD )
+ aRet <<= getRefreshDelay();
+ else if ( aPropertyName == SC_UNONAME_REFDELAY )
+ aRet <<= getRefreshDelay();
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAreaLinkObj )
+
+// internal:
+
+OUString ScAreaLinkObj::getFileName() const
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ aRet = pLink->GetFile();
+ return aRet;
+}
+
+void ScAreaLinkObj::setFileName(const OUString& rNewName)
+{
+ SolarMutexGuard aGuard;
+ Modify_Impl( &rNewName, nullptr, nullptr, nullptr, nullptr );
+}
+
+OUString ScAreaLinkObj::getFilter() const
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ aRet = pLink->GetFilter();
+ return aRet;
+}
+
+void ScAreaLinkObj::setFilter(const OUString& Filter)
+{
+ SolarMutexGuard aGuard;
+ Modify_Impl( nullptr, &Filter, nullptr, nullptr, nullptr );
+}
+
+OUString ScAreaLinkObj::getFilterOptions() const
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ aRet = pLink->GetOptions();
+ return aRet;
+}
+
+void ScAreaLinkObj::setFilterOptions(const OUString& FilterOptions)
+{
+ SolarMutexGuard aGuard;
+ Modify_Impl( nullptr, nullptr, &FilterOptions, nullptr, nullptr );
+}
+
+sal_Int32 ScAreaLinkObj::getRefreshDelay() const
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nRet = 0;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ nRet = pLink->GetRefreshDelaySeconds();
+ return nRet;
+}
+
+void ScAreaLinkObj::setRefreshDelay(sal_Int32 nRefreshDelay)
+{
+ SolarMutexGuard aGuard;
+ ModifyRefreshDelay_Impl( nRefreshDelay );
+}
+
+// XAreaLink
+
+OUString SAL_CALL ScAreaLinkObj::getSourceArea()
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ aRet = pLink->GetSource();
+ return aRet;
+}
+
+void SAL_CALL ScAreaLinkObj::setSourceArea( const OUString& aSourceArea )
+{
+ SolarMutexGuard aGuard;
+ Modify_Impl( nullptr, nullptr, nullptr, &aSourceArea, nullptr );
+}
+
+table::CellRangeAddress SAL_CALL ScAreaLinkObj::getDestArea()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ ScUnoConversion::FillApiRange( aRet, pLink->GetDestArea() );
+ return aRet;
+}
+
+void SAL_CALL ScAreaLinkObj::setDestArea( const table::CellRangeAddress& aDestArea )
+{
+ SolarMutexGuard aGuard;
+ Modify_Impl( nullptr, nullptr, nullptr, nullptr, &aDestArea );
+}
+
+ScAreaLinksObj::ScAreaLinksObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScAreaLinksObj::~ScAreaLinksObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScAreaLinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // we don't care about update of references here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XAreaLinks
+
+rtl::Reference<ScAreaLinkObj> ScAreaLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
+{
+ if ( pDocShell && nIndex >= 0 && nIndex < getCount() )
+ return new ScAreaLinkObj( pDocShell, static_cast<size_t>(nIndex) );
+
+ return nullptr; // not found
+}
+
+void SAL_CALL ScAreaLinksObj::insertAtPosition( const table::CellAddress& aDestPos,
+ const OUString& aFileName,
+ const OUString& aSourceArea,
+ const OUString& aFilter,
+ const OUString& aFilterOptions )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ OUString aFileStr (aFileName);
+ ScAddress aDestAddr( static_cast<SCCOL>(aDestPos.Column), static_cast<SCROW>(aDestPos.Row), aDestPos.Sheet );
+
+ aFileStr = ScGlobal::GetAbsDocName( aFileStr, pDocShell ); //! in InsertAreaLink ???
+ pDocShell->GetDocFunc().InsertAreaLink( aFileStr, aFilter, aFilterOptions,
+ aSourceArea, ScRange(aDestAddr),
+ /*nRefreshDelaySeconds*/0, false, true ); // don't move contents
+ }
+}
+
+void SAL_CALL ScAreaLinksObj::removeByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, static_cast<size_t>(nIndex));
+ if (pLink)
+ {
+ //! SetAddUndo or what
+
+ sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
+ pLinkManager->Remove( pLink );
+ }
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScAreaLinksObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.CellAreaLinksEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScAreaLinksObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nAreaCount = 0;
+ if (pDocShell)
+ {
+ sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
+ size_t nTotalCount = pLinkManager->GetLinks().size();
+ for (size_t i=0; i<nTotalCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
+ if (dynamic_cast<const ScAreaLink*>( pBase) != nullptr)
+ ++nAreaCount;
+ }
+ }
+ return nAreaCount;
+}
+
+uno::Any SAL_CALL ScAreaLinksObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XAreaLink> xLink(GetObjectByIndex_Impl(nIndex));
+ if (!xLink.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xLink);
+
+}
+
+uno::Type SAL_CALL ScAreaLinksObj::getElementType()
+{
+ return cppu::UnoType<sheet::XAreaLink>::get();
+}
+
+sal_Bool SAL_CALL ScAreaLinksObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+ScDDELinkObj::ScDDELinkObj(ScDocShell* pDocSh, OUString aA,
+ OUString aT, OUString aI) :
+ pDocShell( pDocSh ),
+ aAppl(std::move( aA )),
+ aTopic(std::move( aT )),
+ aItem(std::move( aI ))
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDDELinkObj::~ScDDELinkObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDDELinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! notify if links in document are changed
+ // UpdateRef is not needed here
+
+ if ( auto pRefreshedHint = dynamic_cast<const ScLinkRefreshedHint*>(&rHint) )
+ {
+ if ( pRefreshedHint->GetLinkType() == ScLinkRefType::DDE &&
+ pRefreshedHint->GetDdeAppl() == aAppl &&
+ pRefreshedHint->GetDdeTopic() == aTopic &&
+ pRefreshedHint->GetDdeItem() == aItem ) //! mode is ignored
+ Refreshed_Impl();
+ }
+ else
+ {
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // pointer is invalid
+ }
+}
+
+// XNamed
+
+static OUString lcl_BuildDDEName( std::u16string_view rAppl, std::u16string_view rTopic, std::u16string_view rItem )
+{
+ // Appl|Topic!Item (like Excel)
+ OUString aRet = OUString::Concat(rAppl) + "|" + rTopic + "!" + rItem;
+ return aRet;
+}
+
+OUString SAL_CALL ScDDELinkObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return lcl_BuildDDEName( aAppl, aTopic, aItem );
+}
+
+void SAL_CALL ScDDELinkObj::setName( const OUString& /* aName */ )
+{
+ // name can't be changed (formulas wouldn't find the link)
+ throw uno::RuntimeException();
+}
+
+// XDDELink
+
+OUString SAL_CALL ScDDELinkObj::getApplication()
+{
+ //! Test if the link is still in the document?
+
+ return aAppl;
+}
+
+OUString SAL_CALL ScDDELinkObj::getTopic()
+{
+ //! Test if the link is still in the document?
+
+ return aTopic;
+}
+
+OUString SAL_CALL ScDDELinkObj::getItem()
+{
+ //! Test if the link is still in the document?
+
+ return aItem;
+}
+
+// XRefreshable
+
+void SAL_CALL ScDDELinkObj::refresh()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ sc::DocumentLinkManager& rMgr = pDocShell->GetDocument().GetDocLinkManager();
+ rMgr.updateDdeLink(aAppl, aTopic, aItem);
+ }
+}
+
+void SAL_CALL ScDDELinkObj::addRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRefreshListeners.push_back( xListener );
+
+ // hold one additional ref to keep this object alive as long as there are listeners
+ if ( aRefreshListeners.size() == 1 )
+ acquire();
+}
+
+void SAL_CALL ScDDELinkObj::removeRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ size_t nCount = aRefreshListeners.size();
+ for ( size_t n=nCount; n--; )
+ {
+ uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n];
+ if ( rObj == xListener )
+ {
+ aRefreshListeners.erase( aRefreshListeners.begin() + n );
+ if ( aRefreshListeners.empty() )
+ release(); // release ref for listeners
+ break;
+ }
+ }
+}
+
+// XDDELinkResults
+
+uno::Sequence< uno::Sequence< uno::Any > > ScDDELinkObj::getResults( )
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence< uno::Sequence< uno::Any > > aReturn;
+ bool bSuccess = false;
+
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ size_t nPos = 0;
+ if ( rDoc.FindDdeLink( aAppl, aTopic, aItem, SC_DDE_IGNOREMODE, nPos ) )
+ {
+ const ScMatrix* pMatrix = rDoc.GetDdeLinkResultMatrix( nPos );
+ if ( pMatrix )
+ {
+ uno::Any aAny;
+ if ( ScRangeToSequence::FillMixedArray( aAny, pMatrix, true ) )
+ {
+ aAny >>= aReturn;
+ }
+ }
+ bSuccess = true;
+ }
+ }
+
+ if ( !bSuccess )
+ {
+ throw uno::RuntimeException(
+ "ScDDELinkObj::getResults: failed to get results!" );
+ }
+
+ return aReturn;
+}
+
+void ScDDELinkObj::setResults( const uno::Sequence< uno::Sequence< uno::Any > >& aResults )
+{
+ SolarMutexGuard aGuard;
+ bool bSuccess = false;
+
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ size_t nPos = 0;
+ if ( rDoc.FindDdeLink( aAppl, aTopic, aItem, SC_DDE_IGNOREMODE, nPos ) )
+ {
+ ScMatrixRef xMatrix = ScSequenceToMatrix::CreateMixedMatrix( Any(aResults) );
+ bSuccess = rDoc.SetDdeLinkResultMatrix( nPos, xMatrix );
+ }
+ }
+
+ if ( !bSuccess )
+ {
+ throw uno::RuntimeException(
+ "ScDDELinkObj::setResults: failed to set results!" );
+ }
+}
+
+void ScDDELinkObj::Refreshed_Impl()
+{
+ lang::EventObject aEvent;
+ aEvent.Source.set(getXWeak());
+ for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners)
+ xRefreshListener->refreshed( aEvent );
+}
+
+ScDDELinksObj::ScDDELinksObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDDELinksObj::~ScDDELinksObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDDELinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // we don't care about update of references here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XDDELinks
+
+rtl::Reference<ScDDELinkObj> ScDDELinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
+{
+ if (pDocShell)
+ {
+ OUString aAppl, aTopic, aItem;
+ if ( pDocShell->GetDocument().GetDdeLinkData( static_cast<size_t>(nIndex), aAppl, aTopic, aItem ) )
+ return new ScDDELinkObj( pDocShell, aAppl, aTopic, aItem );
+ }
+ return nullptr;
+}
+
+rtl::Reference<ScDDELinkObj> ScDDELinksObj::GetObjectByName_Impl(std::u16string_view aName)
+{
+ if (pDocShell)
+ {
+ OUString aAppl, aTopic, aItem;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ size_t nCount = rDoc.GetDocLinkManager().getDdeLinkCount();
+ for (size_t i=0; i<nCount; i++)
+ {
+ rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem );
+ if ( lcl_BuildDDEName(aAppl, aTopic, aItem) == aName )
+ return new ScDDELinkObj( pDocShell, aAppl, aTopic, aItem );
+ }
+ }
+ return nullptr;
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScDDELinksObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.DDELinksEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDDELinksObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nAreaCount = 0;
+ if (pDocShell)
+ nAreaCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount();
+ return nAreaCount;
+}
+
+uno::Any SAL_CALL ScDDELinksObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XDDELink> xLink(GetObjectByIndex_Impl(nIndex));
+ if (!xLink.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xLink);
+}
+
+uno::Type SAL_CALL ScDDELinksObj::getElementType()
+{
+ return cppu::UnoType<sheet::XDDELink>::get();
+}
+
+sal_Bool SAL_CALL ScDDELinksObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Any SAL_CALL ScDDELinksObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XDDELink> xLink(GetObjectByName_Impl(aName));
+ if (!xLink.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xLink);
+}
+
+uno::Sequence<OUString> SAL_CALL ScDDELinksObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ OUString aAppl, aTopic, aItem;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ size_t nCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount();
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+
+ for (size_t i=0; i<nCount; i++)
+ {
+ rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem );
+ pAry[i] = lcl_BuildDDEName(aAppl, aTopic, aItem);
+ }
+ return aSeq;
+ }
+ return uno::Sequence<OUString>();
+}
+
+sal_Bool SAL_CALL ScDDELinksObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ OUString aAppl, aTopic, aItem;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ size_t nCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount();
+ for (size_t i=0; i<nCount; i++)
+ {
+ rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem );
+ if ( lcl_BuildDDEName(aAppl, aTopic, aItem) == aName )
+ return true;
+ }
+ }
+ return false;
+}
+
+// XDDELinks
+
+uno::Reference< sheet::XDDELink > ScDDELinksObj::addDDELink(
+ const OUString& aApplication, const OUString& aTopic,
+ const OUString& aItem, css::sheet::DDELinkMode nMode )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< sheet::XDDELink > xLink;
+
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_uInt8 nMod = SC_DDE_DEFAULT;
+ switch ( nMode )
+ {
+ case sheet::DDELinkMode_DEFAULT:
+ {
+ nMod = SC_DDE_DEFAULT;
+ }
+ break;
+ case sheet::DDELinkMode_ENGLISH:
+ {
+ nMod = SC_DDE_ENGLISH;
+ }
+ break;
+ case sheet::DDELinkMode_TEXT:
+ {
+ nMod = SC_DDE_TEXT;
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+
+ if ( rDoc.CreateDdeLink( aApplication, aTopic, aItem, nMod, ScMatrixRef() ) )
+ {
+ const OUString aName( lcl_BuildDDEName( aApplication, aTopic, aItem ) );
+ xLink.set( GetObjectByName_Impl( aName ) );
+ }
+ }
+
+ if ( !xLink.is() )
+ {
+ throw uno::RuntimeException(
+ "ScDDELinksObj::addDDELink: cannot add DDE link!" );
+ }
+
+ return xLink;
+}
+
+ScExternalSheetCacheObj::ScExternalSheetCacheObj(ScDocShell* pDocShell, ScExternalRefCache::TableTypeRef pTable, size_t nIndex) :
+ mpDocShell(pDocShell),
+ mpTable(std::move(pTable)),
+ mnIndex(nIndex)
+{
+}
+
+ScExternalSheetCacheObj::~ScExternalSheetCacheObj()
+{
+}
+
+void SAL_CALL ScExternalSheetCacheObj::setCellValue(sal_Int32 nCol, sal_Int32 nRow, const Any& rValue)
+{
+ SolarMutexGuard aGuard;
+ if (nRow < 0 || nCol < 0)
+ throw IllegalArgumentException();
+
+ ScExternalRefCache::TokenRef pToken;
+ double fVal = 0.0;
+ OUString aVal;
+ if (rValue >>= fVal)
+ pToken.reset(new FormulaDoubleToken(fVal));
+ else if (rValue >>= aVal)
+ {
+ svl::SharedStringPool& rPool = mpDocShell->GetDocument().GetSharedStringPool();
+ svl::SharedString aSS = rPool.intern(aVal);
+ pToken.reset(new FormulaStringToken(std::move(aSS)));
+ }
+ else
+ // unidentified value type.
+ return;
+
+ mpTable->setCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), pToken);
+}
+
+Any SAL_CALL ScExternalSheetCacheObj::getCellValue(sal_Int32 nCol, sal_Int32 nRow)
+{
+ SolarMutexGuard aGuard;
+ if (nRow < 0 || nCol < 0)
+ throw IllegalArgumentException();
+
+ FormulaToken* pToken = mpTable->getCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow)).get();
+ if (!pToken)
+ throw IllegalArgumentException();
+
+ Any aValue;
+ switch (pToken->GetType())
+ {
+ case svDouble:
+ {
+ double fVal = pToken->GetDouble();
+ aValue <<= fVal;
+ }
+ break;
+ case svString:
+ {
+ OUString aVal = pToken->GetString().getString();
+ aValue <<= aVal;
+ }
+ break;
+ default:
+ throw IllegalArgumentException();
+ }
+ return aValue;
+}
+
+Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllRows()
+{
+ SolarMutexGuard aGuard;
+ vector<SCROW> aRows;
+ mpTable->getAllRows(aRows);
+ size_t nSize = aRows.size();
+ Sequence<sal_Int32> aRowsSeq(nSize);
+ auto aRowsSeqRange = asNonConstRange(aRowsSeq);
+ for (size_t i = 0; i < nSize; ++i)
+ aRowsSeqRange[i] = aRows[i];
+
+ return aRowsSeq;
+}
+
+Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllColumns(sal_Int32 nRow)
+{
+ SolarMutexGuard aGuard;
+ if (nRow < 0)
+ throw IllegalArgumentException();
+
+ vector<SCCOL> aCols;
+ mpTable->getAllCols(static_cast<SCROW>(nRow), aCols);
+ size_t nSize = aCols.size();
+ Sequence<sal_Int32> aColsSeq(nSize);
+ auto aColsSeqRange = asNonConstRange(aColsSeq);
+ for (size_t i = 0; i < nSize; ++i)
+ aColsSeqRange[i] = aCols[i];
+
+ return aColsSeq;
+}
+
+sal_Int32 SAL_CALL ScExternalSheetCacheObj::getTokenIndex()
+{
+ return static_cast< sal_Int32 >( mnIndex );
+}
+
+ScExternalDocLinkObj::ScExternalDocLinkObj(ScDocShell* pDocShell, ScExternalRefManager* pRefMgr, sal_uInt16 nFileId) :
+ mpDocShell(pDocShell), mpRefMgr(pRefMgr), mnFileId(nFileId)
+{
+}
+
+ScExternalDocLinkObj::~ScExternalDocLinkObj()
+{
+}
+
+uno::Reference< sheet::XExternalSheetCache > SAL_CALL ScExternalDocLinkObj::addSheetCache(
+ const OUString& aSheetName, sal_Bool bDynamicCache )
+{
+ SolarMutexGuard aGuard;
+ size_t nIndex = 0;
+ ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aSheetName, true, &nIndex);
+ if (!bDynamicCache)
+ // Set the whole table cached to prevent access to the source document.
+ pTable->setWholeTableCached();
+
+ uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(mpDocShell, pTable, nIndex));
+ return aSheetCache;
+}
+
+Any SAL_CALL ScExternalDocLinkObj::getByName(const OUString &aName)
+{
+ SolarMutexGuard aGuard;
+ size_t nIndex = 0;
+ ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aName, false, &nIndex);
+ if (!pTable)
+ throw container::NoSuchElementException();
+
+ uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(mpDocShell, pTable, nIndex));
+
+ return Any(aSheetCache);
+}
+
+Sequence< OUString > SAL_CALL ScExternalDocLinkObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ vector<OUString> aTabNames;
+ mpRefMgr->getAllCachedTableNames(mnFileId, aTabNames);
+
+ // #i116940# be consistent with getByName: include only table names which have a cache already
+ vector<OUString> aValidNames;
+ std::copy_if(aTabNames.begin(), aTabNames.end(), std::back_inserter(aValidNames),
+ [&](const OUString& rTabName) { return mpRefMgr->getCacheTable(mnFileId, rTabName, false); });
+
+ Sequence<OUString> aSeq(comphelper::containerToSequence(aValidNames));
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScExternalDocLinkObj::hasByName(const OUString &aName)
+{
+ SolarMutexGuard aGuard;
+
+ // #i116940# be consistent with getByName: allow only table names which have a cache already
+ ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aName, false);
+ return bool(pTable);
+}
+
+sal_Int32 SAL_CALL ScExternalDocLinkObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ // #i116940# be consistent with getByName: count only table names which have a cache already
+ return getElementNames().getLength();
+}
+
+Any SAL_CALL ScExternalDocLinkObj::getByIndex(sal_Int32 nApiIndex)
+{
+ SolarMutexGuard aGuard;
+
+ // #i116940# Can't use nApiIndex as index for the ref manager, because the API counts only
+ // the entries which have a cache already. Quick solution: Use getElementNames.
+ Sequence< OUString > aNames( getElementNames() );
+ if (nApiIndex < 0 || nApiIndex >= aNames.getLength())
+ throw lang::IndexOutOfBoundsException();
+
+ size_t nIndex = 0;
+ ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aNames[nApiIndex], false, &nIndex);
+ if (!pTable)
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(mpDocShell, pTable, nIndex));
+
+ return Any(aSheetCache);
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL ScExternalDocLinkObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XEnumeration > aRef(
+ new ScIndexEnumeration(this, "com.sun.star.sheet.ExternalDocLink"));
+ return aRef;
+}
+
+uno::Type SAL_CALL ScExternalDocLinkObj::getElementType()
+{
+ return cppu::UnoType<sheet::XExternalDocLink>::get();
+}
+
+sal_Bool SAL_CALL ScExternalDocLinkObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+
+ // #i116940# be consistent with getByName: count only table names which have a cache already
+ return getElementNames().hasElements();
+}
+
+sal_Int32 SAL_CALL ScExternalDocLinkObj::getTokenIndex()
+{
+ return static_cast<sal_Int32>(mnFileId);
+}
+
+ScExternalDocLinksObj::ScExternalDocLinksObj(ScDocShell* pDocShell) :
+ mpDocShell(pDocShell),
+ mpRefMgr(pDocShell->GetDocument().GetExternalRefManager())
+{
+}
+
+ScExternalDocLinksObj::~ScExternalDocLinksObj()
+{
+}
+
+uno::Reference< sheet::XExternalDocLink > SAL_CALL ScExternalDocLinksObj::addDocLink(
+ const OUString& aDocName )
+{
+ SolarMutexGuard aGuard;
+ OUString aDocUrl( ScGlobal::GetAbsDocName( aDocName, mpDocShell));
+ sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aDocUrl);
+ uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId));
+ return aDocLink;
+}
+
+Any SAL_CALL ScExternalDocLinksObj::getByName(const OUString &aName)
+{
+ SolarMutexGuard aGuard;
+ OUString aDocUrl( ScGlobal::GetAbsDocName( aName, mpDocShell));
+ if (!mpRefMgr->hasExternalFile(aDocUrl))
+ throw container::NoSuchElementException();
+
+ sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aDocUrl);
+ uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId));
+
+ return Any(aDocLink);
+}
+
+Sequence< OUString > SAL_CALL ScExternalDocLinksObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 n = mpRefMgr->getExternalFileCount();
+ Sequence<OUString> aSeq(n);
+ auto aSeqRange = asNonConstRange(aSeq);
+ for (sal_uInt16 i = 0; i < n; ++i)
+ {
+ const OUString* pName = mpRefMgr->getExternalFileName(i);
+ aSeqRange[i] = pName ? *pName : OUString();
+ }
+
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScExternalDocLinksObj::hasByName(const OUString &aName)
+{
+ SolarMutexGuard aGuard;
+ return mpRefMgr->hasExternalFile(aName);
+}
+
+sal_Int32 SAL_CALL ScExternalDocLinksObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return mpRefMgr->getExternalFileCount();
+}
+
+Any SAL_CALL ScExternalDocLinksObj::getByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ if (nIndex > ::std::numeric_limits<sal_uInt16>::max() || nIndex < ::std::numeric_limits<sal_uInt16>::min())
+ throw lang::IndexOutOfBoundsException();
+
+ sal_uInt16 nFileId = static_cast<sal_uInt16>(nIndex);
+
+ if (!mpRefMgr->hasExternalFile(nFileId))
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId));
+ return Any(aDocLink);
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL ScExternalDocLinksObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XEnumeration > aRef(
+ new ScIndexEnumeration(this, "com.sun.star.sheet.ExternalDocLinks"));
+ return aRef;
+}
+
+uno::Type SAL_CALL ScExternalDocLinksObj::getElementType()
+{
+ return cppu::UnoType<sheet::XExternalDocLinks>::get();
+}
+
+sal_Bool SAL_CALL ScExternalDocLinksObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return mpRefMgr->getExternalFileCount() > 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/listenercalls.cxx b/sc/source/ui/unoobj/listenercalls.cxx
new file mode 100644
index 0000000000..7ff7c7df09
--- /dev/null
+++ b/sc/source/ui/unoobj/listenercalls.cxx
@@ -0,0 +1,69 @@
+/* -*- 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 <com/sun/star/util/XModifyListener.hpp>
+#include <osl/diagnose.h>
+
+#include <listenercalls.hxx>
+
+using namespace com::sun::star;
+
+ScUnoListenerCalls::ScUnoListenerCalls() {}
+
+ScUnoListenerCalls::~ScUnoListenerCalls()
+{
+ OSL_ENSURE(aEntries.empty(), "unhandled listener calls remaining");
+}
+
+void ScUnoListenerCalls::Add(const uno::Reference<util::XModifyListener>& rListener,
+ const lang::EventObject& rEvent)
+{
+ if (rListener.is())
+ aEntries.emplace_back(rListener, rEvent);
+}
+
+void ScUnoListenerCalls::ExecuteAndClear()
+{
+ // Execute all stored calls and remove them from the list.
+ // During each modified() call, Add may be called again.
+ // These new calls are executed here, too.
+
+ std::list<ScUnoListenerEntry>::iterator aItr(aEntries.begin());
+ while (aItr != aEntries.end())
+ {
+ ScUnoListenerEntry aEntry = *aItr;
+ try
+ {
+ aEntry.xListener->modified(aEntry.aEvent);
+ }
+ catch (const uno::RuntimeException&)
+ {
+ // the listener is an external object and may throw a RuntimeException
+ // for reasons we don't know
+ }
+
+ // New calls that are added during the modified() call are appended to the end
+ // of aEntries, so the loop will catch them, too (as long as erase happens
+ // after modified).
+
+ aItr = aEntries.erase(aItr);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/miscuno.cxx b/sc/source/ui/unoobj/miscuno.cxx
new file mode 100644
index 0000000000..5c875bc0b7
--- /dev/null
+++ b/sc/source/ui/unoobj/miscuno.cxx
@@ -0,0 +1,285 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/any.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+
+#include <miscuno.hxx>
+
+using namespace com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Any;
+
+SC_SIMPLE_SERVICE_INFO( ScNameToIndexAccess, "ScNameToIndexAccess", "stardiv.unknown" )
+
+bool ScUnoHelpFunctions::GetBoolProperty( const uno::Reference<beans::XPropertySet>& xProp,
+ const OUString& rName, bool bDefault )
+{
+ bool bRet = bDefault;
+ if ( xProp.is() )
+ {
+ try
+ {
+ xProp->getPropertyValue( rName ) >>= bRet;
+ }
+ catch(uno::Exception&)
+ {
+ // keep default
+ }
+ }
+ return bRet;
+}
+
+sal_Int16 ScUnoHelpFunctions::GetShortProperty( const css::uno::Reference< css::beans::XPropertySet>& xProp,
+ const OUString& rName, sal_Int16 nDefault )
+{
+ sal_Int16 nRet = nDefault;
+ if ( xProp.is() )
+ {
+ try
+ {
+ xProp->getPropertyValue( rName ) >>= nRet;
+ }
+ catch(uno::Exception&)
+ {
+ // keep default
+ }
+ }
+ return nRet;
+}
+
+sal_Int32 ScUnoHelpFunctions::GetLongProperty( const uno::Reference<beans::XPropertySet>& xProp,
+ const OUString& rName )
+{
+ sal_Int32 nRet = 0;
+ if ( xProp.is() )
+ {
+ try
+ {
+ //! type conversion???
+ xProp->getPropertyValue( rName ) >>= nRet;
+ }
+ catch(uno::Exception&)
+ {
+ // keep default
+ }
+ }
+ return nRet;
+}
+
+sal_Int32 ScUnoHelpFunctions::GetEnumPropertyImpl( const uno::Reference<beans::XPropertySet>& xProp,
+ const OUString& rName, sal_Int32 nDefault )
+{
+ sal_Int32 nRet = nDefault;
+ if ( xProp.is() )
+ {
+ try
+ {
+ uno::Any aAny(xProp->getPropertyValue( rName ));
+
+ if ( aAny.getValueTypeClass() == uno::TypeClass_ENUM )
+ {
+ //! get enum value from any???
+ nRet = *static_cast<sal_Int32 const *>(aAny.getValue());
+ }
+ else
+ {
+ //! type conversion???
+ aAny >>= nRet;
+ }
+ }
+ catch(uno::Exception&)
+ {
+ // keep default
+ }
+ }
+ return nRet;
+}
+
+OUString ScUnoHelpFunctions::GetStringProperty(
+ const Reference<beans::XPropertySet>& xProp, const OUString& rName, const OUString& rDefault )
+{
+ OUString aRet = rDefault;
+ if (!xProp.is())
+ return aRet;
+
+ try
+ {
+ Any any = xProp->getPropertyValue(rName);
+ any >>= aRet;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ return aRet;
+}
+
+bool ScUnoHelpFunctions::GetBoolFromAny( const uno::Any& aAny )
+{
+ auto b = o3tl::tryAccess<bool>(aAny);
+ return b.has_value() && *b;
+}
+
+sal_Int16 ScUnoHelpFunctions::GetInt16FromAny( const uno::Any& aAny )
+{
+ sal_Int16 nRet = 0;
+ if ( aAny >>= nRet )
+ return nRet;
+ return 0;
+}
+
+sal_Int32 ScUnoHelpFunctions::GetInt32FromAny( const uno::Any& aAny )
+{
+ sal_Int32 nRet = 0;
+ if ( aAny >>= nRet )
+ return nRet;
+ return 0;
+}
+
+sal_Int32 ScUnoHelpFunctions::GetEnumFromAny( const uno::Any& aAny )
+{
+ sal_Int32 nRet = 0;
+ if ( aAny.getValueTypeClass() == uno::TypeClass_ENUM )
+ nRet = *static_cast<sal_Int32 const *>(aAny.getValue());
+ else
+ aAny >>= nRet;
+ return nRet;
+}
+
+void ScUnoHelpFunctions::SetOptionalPropertyValue(
+ const Reference<beans::XPropertySet>& rPropSet, const char* pPropName, const Any& rVal )
+{
+ SetOptionalPropertyValue(rPropSet, OUString::createFromAscii(pPropName), rVal);
+}
+
+void ScUnoHelpFunctions::SetOptionalPropertyValue(
+ const Reference<beans::XPropertySet>& rPropSet, const OUString& sPropName, const Any& rVal )
+{
+ try
+ {
+ rPropSet->setPropertyValue(sPropName, rVal);
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ // ignored - not supported.
+ }
+}
+
+ScIndexEnumeration::ScIndexEnumeration(uno::Reference<container::XIndexAccess> xInd,
+ OUString aServiceName) :
+ xIndex(std::move( xInd )),
+ sServiceName(std::move(aServiceName)),
+ nPos( 0 )
+{
+}
+
+ScIndexEnumeration::~ScIndexEnumeration()
+{
+}
+
+// XEnumeration
+
+sal_Bool SAL_CALL ScIndexEnumeration::hasMoreElements()
+{
+ SolarMutexGuard aGuard;
+ return ( nPos < xIndex->getCount() );
+}
+
+uno::Any SAL_CALL ScIndexEnumeration::nextElement()
+{
+ SolarMutexGuard aGuard;
+ uno::Any aReturn;
+ try
+ {
+ aReturn = xIndex->getByIndex(nPos++);
+ }
+ catch (lang::IndexOutOfBoundsException&)
+ {
+ throw container::NoSuchElementException();
+ }
+ return aReturn;
+}
+
+OUString SAL_CALL ScIndexEnumeration::getImplementationName()
+{
+ return "ScIndexEnumeration";
+}
+
+sal_Bool SAL_CALL ScIndexEnumeration::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString >
+ SAL_CALL ScIndexEnumeration::getSupportedServiceNames()
+{
+ return { sServiceName };
+}
+
+ScNameToIndexAccess::ScNameToIndexAccess( css::uno::Reference<
+ css::container::XNameAccess> xNameObj ) :
+ xNameAccess(std::move( xNameObj ))
+{
+ //! test for XIndexAccess interface at rNameObj, use that instead!
+
+ if ( xNameAccess.is() )
+ aNames = xNameAccess->getElementNames();
+}
+
+ScNameToIndexAccess::~ScNameToIndexAccess()
+{
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScNameToIndexAccess::getCount( )
+{
+ return aNames.getLength();
+}
+
+css::uno::Any SAL_CALL ScNameToIndexAccess::getByIndex( sal_Int32 nIndex )
+{
+ if ( xNameAccess.is() && nIndex >= 0 && nIndex < aNames.getLength() )
+ return xNameAccess->getByName( aNames.getConstArray()[nIndex] );
+
+ throw lang::IndexOutOfBoundsException();
+}
+
+// XElementAccess
+
+css::uno::Type SAL_CALL ScNameToIndexAccess::getElementType( )
+{
+ if ( xNameAccess.is() )
+ return xNameAccess->getElementType();
+ else
+ return uno::Type();
+}
+
+sal_Bool SAL_CALL ScNameToIndexAccess::hasElements( )
+{
+ return getCount() > 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/nameuno.cxx b/sc/source/ui/unoobj/nameuno.cxx
new file mode 100644
index 0000000000..6a43a4c05f
--- /dev/null
+++ b/sc/source/ui/unoobj/nameuno.cxx
@@ -0,0 +1,1147 @@
+/* -*- 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 <o3tl/safeint.hxx>
+#include <svl/hint.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/sheet/NamedRangeFlag.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <unotools/charclass.hxx>
+
+#include <nameuno.hxx>
+#include <miscuno.hxx>
+#include <cellsuno.hxx>
+#include <convuno.hxx>
+#include <targuno.hxx>
+#include <tokenuno.hxx>
+#include <tokenarray.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <rangenam.hxx>
+#include <unonames.hxx>
+
+#include <scui_def.hxx>
+
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Any;
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetNamedRangeMap()
+{
+ static const SfxItemPropertyMapEntry aNamedRangeMap_Impl[] =
+ {
+ { SC_UNO_LINKDISPBIT, 0, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_LINKDISPNAME, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TOKENINDEX, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ISSHAREDFMLA, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ };
+ return aNamedRangeMap_Impl;
+}
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetNamedRangesMap()
+{
+ static const SfxItemPropertyMapEntry aNamedRangesMap_Impl[] =
+ {
+ { SC_UNO_MODIFY_BROADCAST, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ };
+ return aNamedRangesMap_Impl;
+}
+
+constexpr OUString SCNAMEDRANGEOBJ_SERVICE = u"com.sun.star.sheet.NamedRange"_ustr;
+
+SC_SIMPLE_SERVICE_INFO( ScLabelRangeObj, "ScLabelRangeObj", "com.sun.star.sheet.LabelRange" )
+SC_SIMPLE_SERVICE_INFO( ScLabelRangesObj, "ScLabelRangesObj", "com.sun.star.sheet.LabelRanges" )
+SC_SIMPLE_SERVICE_INFO( ScNamedRangesObj, "ScNamedRangesObj", "com.sun.star.sheet.NamedRanges" )
+
+// Database named ranges are not considered by getCount, hasByName, removeByName and getElementNames
+// Note that hidden named ranges are considered by these methods
+static bool lcl_UserVisibleName(const ScRangeData& rData)
+{
+ //! as method to ScRangeData
+ return !rData.HasType(ScRangeData::Type::Database);
+}
+
+ScNamedRangeObj::ScNamedRangeObj( rtl::Reference< ScNamedRangesObj > xParent, ScDocShell* pDocSh, OUString aNm, Reference<container::XNamed> const & xSheet):
+ mxParent(std::move(xParent)),
+ pDocShell( pDocSh ),
+ aName(std::move( aNm )),
+ mxSheet( xSheet )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScNamedRangeObj::~ScNamedRangeObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScNamedRangeObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update is of no interest
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // became invalid
+}
+
+// Helper functions
+
+ScRangeData* ScNamedRangeObj::GetRangeData_Impl()
+{
+ ScRangeData* pRet = nullptr;
+ if (pDocShell)
+ {
+ ScRangeName* pNames;
+ SCTAB nTab = GetTab_Impl();
+ if (nTab >= 0)
+ pNames = pDocShell->GetDocument().GetRangeName(nTab);
+ else
+ pNames = pDocShell->GetDocument().GetRangeName();
+ if (pNames)
+ {
+ pRet = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
+ if (pRet)
+ pRet->ValidateTabRefs(); // adjust relative tab refs to valid tables
+ }
+ }
+ return pRet;
+}
+
+SCTAB ScNamedRangeObj::GetTab_Impl()
+{
+ if (mxSheet.is())
+ {
+ if (!pDocShell)
+ return -2;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab;
+ OUString sName = mxSheet->getName();
+ bool bFound = rDoc.GetTable(sName, nTab);
+ assert(bFound); (void)bFound; // fouled up?
+ return nTab;
+ }
+ else
+ return -1;//global range name
+}
+
+// sheet::XNamedRange
+
+void ScNamedRangeObj::Modify_Impl( const OUString* pNewName, const ScTokenArray* pNewTokens, const OUString* pNewContent,
+ const ScAddress* pNewPos, const ScRangeData::Type* pNewType,
+ const formula::FormulaGrammar::Grammar eGrammar )
+{
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangeName* pNames;
+ SCTAB nTab = GetTab_Impl();
+ if (nTab >= 0)
+ pNames = rDoc.GetRangeName(nTab);
+ else
+ pNames = rDoc.GetRangeName();
+ if (!pNames)
+ return;
+
+ const ScRangeData* pOld = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
+ if (!pOld)
+ return;
+
+ std::unique_ptr<ScRangeName> pNewRanges(new ScRangeName(*pNames));
+
+ OUString aInsName = pOld->GetName();
+ if (pNewName)
+ aInsName = *pNewName;
+
+ // Content string based => no problems with changed positions and such.
+ OUString aContent = pOld->GetSymbol(eGrammar);
+ if (pNewContent)
+ aContent = *pNewContent;
+
+ ScAddress aPos = pOld->GetPos();
+ if (pNewPos)
+ aPos = *pNewPos;
+
+ ScRangeData::Type nType = pOld->GetType();
+ if (pNewType)
+ nType = *pNewType;
+
+ ScRangeData* pNew = nullptr;
+ if (pNewTokens)
+ pNew = new ScRangeData( rDoc, aInsName, *pNewTokens, aPos, nType );
+ else
+ pNew = new ScRangeData( rDoc, aInsName, aContent, aPos, nType, eGrammar );
+
+ pNew->SetIndex( pOld->GetIndex() );
+
+ pNewRanges->erase(*pOld);
+ if (pNewRanges->insert(pNew))
+ {
+ pDocShell->GetDocFunc().SetNewRangeNames(std::move(pNewRanges), mxParent->IsModifyAndBroadcast(), nTab);
+
+ aName = aInsName; //! broadcast?
+ }
+ else
+ {
+ pNew = nullptr; //! uno::Exception/Error or something
+ }
+}
+
+OUString SAL_CALL ScNamedRangeObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return aName;
+}
+
+void SAL_CALL ScNamedRangeObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ //! adapt formulas ?????
+
+ OUString aNewStr(aNewName);
+ // GRAM_API for API compatibility.
+ Modify_Impl( &aNewStr, nullptr, nullptr, nullptr, nullptr,formula::FormulaGrammar::GRAM_API );
+
+ if ( aName != aNewStr ) // some error occurred...
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+OUString SAL_CALL ScNamedRangeObj::getContent()
+{
+ SolarMutexGuard aGuard;
+ OUString aContent;
+ ScRangeData* pData = GetRangeData_Impl();
+ if (pData)
+ // GRAM_API for API compatibility.
+ aContent = pData->GetSymbol(formula::FormulaGrammar::GRAM_API);
+ return aContent;
+}
+
+void SAL_CALL ScNamedRangeObj::setContent( const OUString& aContent )
+{
+ SolarMutexGuard aGuard;
+ OUString aContStr(aContent);
+ // GRAM_API for API compatibility.
+ Modify_Impl( nullptr, nullptr, &aContStr, nullptr, nullptr,formula::FormulaGrammar::GRAM_API );
+}
+
+table::CellAddress SAL_CALL ScNamedRangeObj::getReferencePosition()
+{
+ SolarMutexGuard aGuard;
+ ScAddress aPos;
+ ScRangeData* pData = GetRangeData_Impl();
+ if (pData)
+ aPos = pData->GetPos();
+ table::CellAddress aAddress;
+ aAddress.Column = aPos.Col();
+ aAddress.Row = aPos.Row();
+ aAddress.Sheet = aPos.Tab();
+ if (pDocShell)
+ {
+ SCTAB nDocTabs = pDocShell->GetDocument().GetTableCount();
+ if ( aAddress.Sheet >= nDocTabs && nDocTabs > 0 )
+ {
+ // Even after ValidateTabRefs, the position can be invalid if
+ // the content points to preceding tables. The resulting string
+ // is invalid in any case, so the position is just shifted.
+ aAddress.Sheet = nDocTabs - 1;
+ }
+ }
+ return aAddress;
+}
+
+void SAL_CALL ScNamedRangeObj::setReferencePosition( const table::CellAddress& aReferencePosition )
+{
+ SolarMutexGuard aGuard;
+ ScAddress aPos( static_cast<SCCOL>(aReferencePosition.Column), static_cast<SCROW>(aReferencePosition.Row), aReferencePosition.Sheet );
+ // GRAM_API for API compatibility.
+ Modify_Impl( nullptr, nullptr, nullptr, &aPos, nullptr,formula::FormulaGrammar::GRAM_API );
+}
+
+sal_Int32 SAL_CALL ScNamedRangeObj::getType()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nType=0;
+ ScRangeData* pData = GetRangeData_Impl();
+ if (pData)
+ {
+ // do not return internal ScRangeData::Type flags
+ if ( pData->HasType(ScRangeData::Type::Criteria) ) nType |= sheet::NamedRangeFlag::FILTER_CRITERIA;
+ if ( pData->HasType(ScRangeData::Type::PrintArea) ) nType |= sheet::NamedRangeFlag::PRINT_AREA;
+ if ( pData->HasType(ScRangeData::Type::ColHeader) ) nType |= sheet::NamedRangeFlag::COLUMN_HEADER;
+ if ( pData->HasType(ScRangeData::Type::RowHeader) ) nType |= sheet::NamedRangeFlag::ROW_HEADER;
+ if ( pData->HasType(ScRangeData::Type::Hidden) ) nType |= sheet::NamedRangeFlag::HIDDEN;
+ }
+ return nType;
+}
+
+void SAL_CALL ScNamedRangeObj::setType( sal_Int32 nUnoType )
+{
+ SolarMutexGuard aGuard;
+ ScRangeData::Type nNewType = ScRangeData::Type::Name;
+ if ( nUnoType & sheet::NamedRangeFlag::FILTER_CRITERIA ) nNewType |= ScRangeData::Type::Criteria;
+ if ( nUnoType & sheet::NamedRangeFlag::PRINT_AREA ) nNewType |= ScRangeData::Type::PrintArea;
+ if ( nUnoType & sheet::NamedRangeFlag::COLUMN_HEADER ) nNewType |= ScRangeData::Type::ColHeader;
+ if ( nUnoType & sheet::NamedRangeFlag::ROW_HEADER ) nNewType |= ScRangeData::Type::RowHeader;
+ if ( nUnoType & sheet::NamedRangeFlag::HIDDEN ) nNewType |= ScRangeData::Type::Hidden;
+
+ // GRAM_API for API compatibility.
+ Modify_Impl( nullptr, nullptr, nullptr, nullptr, &nNewType,formula::FormulaGrammar::GRAM_API );
+}
+
+// XFormulaTokens
+
+uno::Sequence<sheet::FormulaToken> SAL_CALL ScNamedRangeObj::getTokens()
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence<sheet::FormulaToken> aSequence;
+ ScRangeData* pData = GetRangeData_Impl();
+ if (pData && pDocShell)
+ {
+ ScTokenArray* pTokenArray = pData->GetCode();
+ if ( pTokenArray )
+ ScTokenConversion::ConvertToTokenSequence( pDocShell->GetDocument(), aSequence, *pTokenArray );
+ }
+ return aSequence;
+}
+
+void SAL_CALL ScNamedRangeObj::setTokens( const uno::Sequence<sheet::FormulaToken>& rTokens )
+{
+ SolarMutexGuard aGuard;
+ if( pDocShell )
+ {
+ ScTokenArray aTokenArray(pDocShell->GetDocument());
+ (void)ScTokenConversion::ConvertToTokenArray( pDocShell->GetDocument(), aTokenArray, rTokens );
+ // GRAM_API for API compatibility.
+ Modify_Impl( nullptr, &aTokenArray, nullptr, nullptr, nullptr, formula::FormulaGrammar::GRAM_API );
+ }
+}
+
+// XCellRangeSource
+
+uno::Reference<table::XCellRange> SAL_CALL ScNamedRangeObj::getReferredCells()
+{
+ SolarMutexGuard aGuard;
+ ScRange aRange;
+ ScRangeData* pData = GetRangeData_Impl();
+ if ( pData && pData->IsValidReference( aRange ) )
+ {
+ //! static function to create ScCellObj/ScCellRangeObj at ScCellRangeObj ???
+
+ if ( aRange.aStart == aRange.aEnd )
+ return new ScCellObj( pDocShell, aRange.aStart );
+ else
+ return new ScCellRangeObj( pDocShell, aRange );
+ }
+ return nullptr;
+}
+
+// beans::XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScNamedRangeObj::getPropertySetInfo()
+{
+ static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetNamedRangeMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScNamedRangeObj::setPropertyValue(
+ const OUString& rPropertyName, const uno::Any& /*aValue*/ )
+{
+ if ( rPropertyName == SC_UNONAME_ISSHAREDFMLA )
+ {
+ // Ignore this.
+ }
+}
+
+uno::Any SAL_CALL ScNamedRangeObj::getPropertyValue( const OUString& rPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ if ( rPropertyName == SC_UNO_LINKDISPBIT )
+ {
+ // no target bitmaps for individual entries (would be all equal)
+ // ScLinkTargetTypeObj::SetLinkTargetBitmap( aRet, SC_LINKTARGETTYPE_RANGENAME );
+ }
+ else if ( rPropertyName == SC_UNO_LINKDISPNAME )
+ aRet <<= aName;
+ else if ( rPropertyName == SC_UNONAME_TOKENINDEX )
+ {
+ // get index for use in formula tokens (read-only)
+ ScRangeData* pData = GetRangeData_Impl();
+ if (pData)
+ aRet <<= static_cast<sal_Int32>(pData->GetIndex());
+ }
+ else if ( rPropertyName == SC_UNONAME_ISSHAREDFMLA )
+ {
+ if (GetRangeData_Impl())
+ aRet <<= false;
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScNamedRangeObj )
+
+// lang::XServiceInfo
+
+OUString SAL_CALL ScNamedRangeObj::getImplementationName()
+{
+ return "ScNamedRangeObj";
+}
+
+sal_Bool SAL_CALL ScNamedRangeObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScNamedRangeObj::getSupportedServiceNames()
+{
+ return {SCNAMEDRANGEOBJ_SERVICE, SCLINKTARGET_SERVICE};
+}
+
+ScNamedRangesObj::ScNamedRangesObj(ScDocShell* pDocSh) :
+ mbModifyAndBroadcast(true),
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScNamedRangesObj::~ScNamedRangesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScNamedRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update is of no interest
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// sheet::XNamedRanges
+
+void SAL_CALL ScNamedRangesObj::addNewByName( const OUString& aName,
+ const OUString& aContent, const table::CellAddress& aPosition,
+ sal_Int32 nUnoType )
+{
+ SolarMutexGuard aGuard;
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), aPosition.Sheet );
+
+ ScRangeData::Type nNewType = ScRangeData::Type::Name;
+ if ( nUnoType & sheet::NamedRangeFlag::FILTER_CRITERIA ) nNewType |= ScRangeData::Type::Criteria;
+ if ( nUnoType & sheet::NamedRangeFlag::PRINT_AREA ) nNewType |= ScRangeData::Type::PrintArea;
+ if ( nUnoType & sheet::NamedRangeFlag::COLUMN_HEADER ) nNewType |= ScRangeData::Type::ColHeader;
+ if ( nUnoType & sheet::NamedRangeFlag::ROW_HEADER ) nNewType |= ScRangeData::Type::RowHeader;
+ if ( nUnoType & sheet::NamedRangeFlag::HIDDEN ) nNewType |= ScRangeData::Type::Hidden;
+
+ bool bDone = false;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ // tdf#119457 - check for a valid range name and cell reference
+ switch (ScRangeData::IsNameValid(aName, rDoc))
+ {
+ case ScRangeData::IsNameValidType::NAME_INVALID_CELL_REF:
+ throw uno::RuntimeException(
+ "Invalid name. Reference to a cell, or a range of cells not allowed",
+ getXWeak());
+ break;
+ case ScRangeData::IsNameValidType::NAME_INVALID_BAD_STRING:
+ throw uno::RuntimeException(
+ "Invalid name. Start with a letter, use only letters, numbers and underscore",
+ getXWeak());
+ break;
+ case ScRangeData::IsNameValidType::NAME_VALID:
+ if (ScRangeName* pNames = GetRangeName_Impl();
+ pNames
+ && !pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName)))
+ {
+ std::unique_ptr<ScRangeName> pNewRanges(new ScRangeName( *pNames ));
+ // GRAM_API for API compatibility.
+ ScRangeData* pNew = new ScRangeData( rDoc, aName, aContent,
+ aPos, nNewType,formula::FormulaGrammar::GRAM_API );
+ if ( pNewRanges->insert(pNew) )
+ {
+ pDocShell->GetDocFunc().SetNewRangeNames(std::move(pNewRanges), mbModifyAndBroadcast, GetTab_Impl());
+ bDone = true;
+ }
+ else
+ {
+ pNew = nullptr;
+ }
+ }
+ }
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScNamedRangesObj::addNewFromTitles( const table::CellRangeAddress& aSource,
+ sheet::Border aBorder )
+{
+ SolarMutexGuard aGuard;
+ //! this cannot be an enum, because multiple bits can be set !!!
+
+ bool bTop = ( aBorder == sheet::Border_TOP );
+ bool bLeft = ( aBorder == sheet::Border_LEFT );
+ bool bBottom = ( aBorder == sheet::Border_BOTTOM );
+ bool bRight = ( aBorder == sheet::Border_RIGHT );
+
+ ScRange aRange;
+ ScUnoConversion::FillScRange( aRange, aSource );
+
+ CreateNameFlags nFlags = CreateNameFlags::NONE;
+ if (bTop) nFlags |= CreateNameFlags::Top;
+ if (bLeft) nFlags |= CreateNameFlags::Left;
+ if (bBottom) nFlags |= CreateNameFlags::Bottom;
+ if (bRight) nFlags |= CreateNameFlags::Right;
+
+ if (nFlags != CreateNameFlags::NONE)
+ pDocShell->GetDocFunc().CreateNames( aRange, nFlags, true, GetTab_Impl() );
+}
+
+void SAL_CALL ScNamedRangesObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ ScRangeName* pNames = GetRangeName_Impl();
+ if (pNames)
+ {
+ const ScRangeData* pData = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
+ if (pData && lcl_UserVisibleName(*pData))
+ {
+ std::unique_ptr<ScRangeName> pNewRanges(new ScRangeName(*pNames));
+ pNewRanges->erase(*pData);
+ pDocShell->GetDocFunc().SetNewRangeNames( std::move(pNewRanges), mbModifyAndBroadcast, GetTab_Impl());
+ bDone = true;
+ }
+ }
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScNamedRangesObj::outputList( const table::CellAddress& aOutputPosition )
+{
+ SolarMutexGuard aGuard;
+ ScAddress aPos( static_cast<SCCOL>(aOutputPosition.Column), static_cast<SCROW>(aOutputPosition.Row), aOutputPosition.Sheet );
+ if (pDocShell)
+ pDocShell->GetDocFunc().InsertNameList( aPos, true );
+}
+
+// container::XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScNamedRangesObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.NamedRangesEnumeration");
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScNamedRangesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ tools::Long nRet = 0;
+ if (pDocShell)
+ {
+ ScRangeName* pNames = GetRangeName_Impl();
+ if (pNames)
+ {
+ for (const auto& rName : *pNames)
+ if (lcl_UserVisibleName(*rName.second))
+ ++nRet;
+ }
+ }
+ return nRet;
+}
+
+uno::Any SAL_CALL ScNamedRangesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< sheet::XNamedRange > xRange(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if ( !xRange.is() )
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRange);
+}
+
+uno::Type SAL_CALL ScNamedRangesObj::getElementType()
+{
+ return cppu::UnoType<sheet::XNamedRange>::get(); // must be suitable for getByIndex
+}
+
+sal_Bool SAL_CALL ScNamedRangesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+Reference<beans::XPropertySetInfo> SAL_CALL ScNamedRangesObj::getPropertySetInfo()
+{
+ static Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo(lcl_GetNamedRangesMap()));
+ return aRef;
+}
+
+void SAL_CALL ScNamedRangesObj::setPropertyValue(
+ const OUString& rPropertyName, const uno::Any& aValue )
+{
+ if ( rPropertyName == SC_UNO_MODIFY_BROADCAST )
+ {
+ aValue >>= mbModifyAndBroadcast;
+ }
+}
+
+Any SAL_CALL ScNamedRangesObj::getPropertyValue( const OUString& rPropertyName )
+{
+ Any aRet;
+ if ( rPropertyName == SC_UNO_MODIFY_BROADCAST )
+ {
+ aRet <<= mbModifyAndBroadcast;
+ }
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScNamedRangesObj )
+
+uno::Any SAL_CALL ScNamedRangesObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< sheet::XNamedRange > xRange(GetObjectByName_Impl(aName));
+ if ( !xRange.is() )
+ throw container::NoSuchElementException();
+
+ return uno::Any(xRange);
+}
+
+uno::Sequence<OUString> SAL_CALL ScNamedRangesObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScRangeName* pNames = GetRangeName_Impl();
+ if (pNames)
+ {
+ tools::Long nVisCount = getCount(); // names with lcl_UserVisibleName
+ uno::Sequence<OUString> aSeq(nVisCount);
+ OUString* pAry = aSeq.getArray();
+ sal_uInt16 nVisPos = 0;
+ for (const auto& rName : *pNames)
+ {
+ if (lcl_UserVisibleName(*rName.second))
+ pAry[nVisPos++] = rName.second->GetName();
+ }
+ return aSeq;
+ }
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScNamedRangesObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScRangeName* pNames = GetRangeName_Impl();
+ if (pNames)
+ {
+ const ScRangeData* pData = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
+ if (pData && lcl_UserVisibleName(*pData))
+ return true;
+ }
+ }
+ return false;
+}
+
+/** called from the XActionLockable interface methods on initial locking */
+void ScNamedRangesObj::lock()
+{
+ pDocShell->GetDocument().PreprocessRangeNameUpdate();
+}
+
+/** called from the XActionLockable interface methods on final unlock */
+void ScNamedRangesObj::unlock()
+{
+ pDocShell->GetDocument().CompileHybridFormula();
+}
+
+// document::XActionLockable
+
+sal_Bool ScNamedRangesObj::isActionLocked()
+{
+ SolarMutexGuard aGuard;
+ return pDocShell->GetDocument().GetNamedRangesLockCount() != 0;
+}
+
+void ScNamedRangesObj::addActionLock()
+{
+ SolarMutexGuard aGuard;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
+ ++nLockCount;
+ if ( nLockCount == 1 )
+ {
+ lock();
+ }
+ rDoc.SetNamedRangesLockCount( nLockCount );
+}
+
+void ScNamedRangesObj::removeActionLock()
+{
+ SolarMutexGuard aGuard;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
+ if ( nLockCount > 0 )
+ {
+ --nLockCount;
+ if ( nLockCount == 0 )
+ {
+ unlock();
+ }
+ rDoc.SetNamedRangesLockCount( nLockCount );
+ }
+}
+
+void ScNamedRangesObj::setActionLocks( sal_Int16 nLock )
+{
+ SolarMutexGuard aGuard;
+ if ( nLock < 0 )
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
+ if ( nLock == 0 && nLockCount > 0 )
+ {
+ unlock();
+ }
+ if ( nLock > 0 && nLockCount == 0 )
+ {
+ lock();
+ }
+ rDoc.SetNamedRangesLockCount( nLock );
+}
+
+sal_Int16 ScNamedRangesObj::resetActionLocks()
+{
+ SolarMutexGuard aGuard;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
+ if ( nLockCount > 0 )
+ {
+ unlock();
+ }
+ rDoc.SetNamedRangesLockCount( 0 );
+ return nLockCount;
+}
+
+ScGlobalNamedRangesObj::ScGlobalNamedRangesObj(ScDocShell* pDocSh)
+ : ScNamedRangesObj(pDocSh)
+{
+
+}
+
+ScGlobalNamedRangesObj::~ScGlobalNamedRangesObj()
+{
+
+}
+
+rtl::Reference<ScNamedRangeObj> ScGlobalNamedRangesObj::GetObjectByIndex_Impl(sal_uInt16 nIndex)
+{
+ if (!pDocShell)
+ return nullptr;
+
+ ScRangeName* pNames = pDocShell->GetDocument().GetRangeName();
+ if (!pNames)
+ return nullptr;
+
+ sal_uInt16 nPos = 0;
+ for (const auto& rName : *pNames)
+ {
+ if (lcl_UserVisibleName(*rName.second))
+ {
+ if (nPos == nIndex)
+ return new ScNamedRangeObj(this, pDocShell, rName.second->GetName());
+ }
+ ++nPos;
+ }
+ return nullptr;
+}
+
+rtl::Reference<ScNamedRangeObj> ScGlobalNamedRangesObj::GetObjectByName_Impl(const OUString& aName)
+{
+ if ( pDocShell && hasByName(aName) )
+ return new ScNamedRangeObj(this, pDocShell, aName);
+ return nullptr;
+}
+
+ScRangeName* ScGlobalNamedRangesObj::GetRangeName_Impl()
+{
+ return pDocShell->GetDocument().GetRangeName();
+}
+
+SCTAB ScGlobalNamedRangesObj::GetTab_Impl()
+{
+ return -1;
+}
+
+ScLocalNamedRangesObj::ScLocalNamedRangesObj( ScDocShell* pDocSh, uno::Reference<container::XNamed> xSheet )
+ : ScNamedRangesObj(pDocSh),
+ mxSheet(std::move(xSheet))
+{
+
+}
+
+ScLocalNamedRangesObj::~ScLocalNamedRangesObj()
+{
+
+}
+
+rtl::Reference<ScNamedRangeObj> ScLocalNamedRangesObj::GetObjectByName_Impl(const OUString& aName)
+{
+ if ( pDocShell && hasByName( aName ) )
+ return new ScNamedRangeObj( this, pDocShell, aName, mxSheet);
+ return nullptr;
+
+}
+
+rtl::Reference<ScNamedRangeObj> ScLocalNamedRangesObj::GetObjectByIndex_Impl( sal_uInt16 nIndex )
+{
+ if (!pDocShell)
+ return nullptr;
+
+ OUString aName = mxSheet->getName();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab;
+ if (!rDoc.GetTable(aName, nTab))
+ return nullptr;
+
+ ScRangeName* pNames = rDoc.GetRangeName( nTab );
+ if (!pNames)
+ return nullptr;
+
+ sal_uInt16 nPos = 0;
+ for (const auto& rName : *pNames)
+ {
+ if (lcl_UserVisibleName(*rName.second))
+ {
+ if (nPos == nIndex)
+ return new ScNamedRangeObj(this, pDocShell, rName.second->GetName(), mxSheet);
+ }
+ ++nPos;
+ }
+ return nullptr;
+}
+
+ScRangeName* ScLocalNamedRangesObj::GetRangeName_Impl()
+{
+ SCTAB nTab = GetTab_Impl();
+ return pDocShell->GetDocument().GetRangeName( nTab );
+}
+
+SCTAB ScLocalNamedRangesObj::GetTab_Impl()
+{
+ SCTAB nTab;
+ (void)pDocShell->GetDocument().GetTable(mxSheet->getName(), nTab);
+ return nTab;
+}
+
+ScLabelRangeObj::ScLabelRangeObj(ScDocShell* pDocSh, bool bCol, const ScRange& rR) :
+ pDocShell( pDocSh ),
+ bColumn( bCol ),
+ aRange( rR )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScLabelRangeObj::~ScLabelRangeObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScLabelRangeObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! Ref-Update !!!
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // became invalid
+}
+
+// Helper functions
+
+ScRangePair* ScLabelRangeObj::GetData_Impl()
+{
+ ScRangePair* pRet = nullptr;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+ if (pList)
+ pRet = pList->Find( aRange );
+ }
+ return pRet;
+}
+
+void ScLabelRangeObj::Modify_Impl( const ScRange* pLabel, const ScRange* pData )
+{
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pOldList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+ if (!pOldList)
+ return;
+
+ ScRangePairListRef xNewList(pOldList->Clone());
+ ScRangePair* pEntry = xNewList->Find( aRange );
+ if (!pEntry)
+ return;
+
+ if ( pLabel )
+ pEntry->GetRange(0) = *pLabel;
+ if ( pData )
+ pEntry->GetRange(1) = *pData;
+
+ xNewList->Join( *pEntry, true );
+
+ if (bColumn)
+ rDoc.GetColNameRangesRef() = xNewList;
+ else
+ rDoc.GetRowNameRangesRef() = xNewList;
+
+ rDoc.CompileColRowNameFormula();
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid );
+ pDocShell->SetDocumentModified();
+
+ //! Undo ?!?! (here and from dialog)
+
+ if ( pLabel )
+ aRange = *pLabel; // adapt object to find range again
+}
+
+// sheet::XLabelRange
+
+table::CellRangeAddress SAL_CALL ScLabelRangeObj::getLabelArea()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScRangePair* pData = GetData_Impl();
+ if (pData)
+ ScUnoConversion::FillApiRange( aRet, pData->GetRange(0) );
+ return aRet;
+}
+
+void SAL_CALL ScLabelRangeObj::setLabelArea( const table::CellRangeAddress& aLabelArea )
+{
+ SolarMutexGuard aGuard;
+ ScRange aLabelRange;
+ ScUnoConversion::FillScRange( aLabelRange, aLabelArea );
+ Modify_Impl( &aLabelRange, nullptr );
+}
+
+table::CellRangeAddress SAL_CALL ScLabelRangeObj::getDataArea()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScRangePair* pData = GetData_Impl();
+ if (pData)
+ ScUnoConversion::FillApiRange( aRet, pData->GetRange(1) );
+ return aRet;
+}
+
+void SAL_CALL ScLabelRangeObj::setDataArea( const table::CellRangeAddress& aDataArea )
+{
+ SolarMutexGuard aGuard;
+ ScRange aDataRange;
+ ScUnoConversion::FillScRange( aDataRange, aDataArea );
+ Modify_Impl( nullptr, &aDataRange );
+}
+
+ScLabelRangesObj::ScLabelRangesObj(ScDocShell* pDocSh, bool bCol) :
+ pDocShell( pDocSh ),
+ bColumn( bCol )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScLabelRangesObj::~ScLabelRangesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScLabelRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update is of no interest
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// sheet::XLabelRanges
+
+rtl::Reference<ScLabelRangeObj> ScLabelRangesObj::GetObjectByIndex_Impl(size_t nIndex)
+{
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+ if ( pList && nIndex < pList->size() )
+ {
+ ScRangePair & rData = (*pList)[nIndex];
+ return new ScLabelRangeObj( pDocShell, bColumn, rData.GetRange(0) );
+ }
+ }
+ return nullptr;
+}
+
+void SAL_CALL ScLabelRangesObj::addNew( const table::CellRangeAddress& aLabelArea,
+ const table::CellRangeAddress& aDataArea )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pOldList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+ if (!pOldList)
+ return;
+
+ ScRangePairListRef xNewList(pOldList->Clone());
+
+ ScRange aLabelRange;
+ ScRange aDataRange;
+ ScUnoConversion::FillScRange( aLabelRange, aLabelArea );
+ ScUnoConversion::FillScRange( aDataRange, aDataArea );
+ xNewList->Join( ScRangePair( aLabelRange, aDataRange ) );
+
+ if (bColumn)
+ rDoc.GetColNameRangesRef() = xNewList;
+ else
+ rDoc.GetRowNameRangesRef() = xNewList;
+
+ rDoc.CompileColRowNameFormula();
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid );
+ pDocShell->SetDocumentModified();
+
+ //! Undo ?!?! (here and from dialog)
+}
+
+void SAL_CALL ScLabelRangesObj::removeByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pOldList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+
+ if ( pOldList && nIndex >= 0 && o3tl::make_unsigned(nIndex) < pOldList->size() )
+ {
+ ScRangePairListRef xNewList(pOldList->Clone());
+
+ xNewList->Remove( nIndex );
+
+ if (bColumn)
+ rDoc.GetColNameRangesRef() = xNewList;
+ else
+ rDoc.GetRowNameRangesRef() = xNewList;
+
+ rDoc.CompileColRowNameFormula();
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid );
+ pDocShell->SetDocumentModified();
+ bDone = true;
+
+ //! Undo ?!?! (here and from dialog)
+ }
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// container::XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScLabelRangesObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.LabelRangesEnumeration");
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScLabelRangesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+ if (pList)
+ return pList->size();
+ }
+ return 0;
+}
+
+uno::Any SAL_CALL ScLabelRangesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< sheet::XLabelRange > xRange(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if ( !xRange.is() )
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRange);
+}
+
+uno::Type SAL_CALL ScLabelRangesObj::getElementType()
+{
+ return cppu::UnoType<sheet::XLabelRange>::get(); // must be suitable for getByIndex
+}
+
+sal_Bool SAL_CALL ScLabelRangesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/notesuno.cxx b/sc/source/ui/unoobj/notesuno.cxx
new file mode 100644
index 0000000000..4e99431dd4
--- /dev/null
+++ b/sc/source/ui/unoobj/notesuno.cxx
@@ -0,0 +1,231 @@
+/* -*- 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 <notesuno.hxx>
+
+#include <vcl/svapp.hxx>
+#include <svl/hint.hxx>
+#include <editeng/unoipset.hxx>
+#include <editeng/unotext.hxx>
+#include <editeng/unoprnms.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdocapt.hxx>
+
+#include <postit.hxx>
+#include <cellsuno.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <editsrc.hxx>
+#include <miscuno.hxx>
+
+using namespace com::sun::star;
+
+static const SvxItemPropertySet* lcl_GetAnnotationPropertySet()
+{
+ static const SfxItemPropertyMapEntry aAnnotationPropertyMap_Impl[] =
+ {
+ SVX_UNOEDIT_CHAR_PROPERTIES,
+ SVX_UNOEDIT_FONT_PROPERTIES,
+ SVX_UNOEDIT_PARA_PROPERTIES,
+ SVX_UNOEDIT_NUMBERING_PROPERTY, // for completeness of service ParagraphProperties
+ };
+ static SvxItemPropertySet aAnnotationPropertySet_Impl( aAnnotationPropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ return &aAnnotationPropertySet_Impl;
+}
+
+SC_SIMPLE_SERVICE_INFO( ScAnnotationObj, "ScAnnotationObj", "com.sun.star.sheet.CellAnnotation" )
+//SC_SIMPLE_SERVICE_INFO( ScAnnotationShapeObj, "ScAnnotationShapeObj", "com.sun.star.sheet.CellAnnotationShape" )
+
+ScAnnotationObj::ScAnnotationObj(ScDocShell* pDocSh, const ScAddress& rPos) :
+ pDocShell( pDocSh ),
+ aCellPos( rPos )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ // pUnoText is allocated on demand (GetUnoText)
+ // can't be aggregated because getString/setString is handled here
+}
+
+ScAnnotationObj::~ScAnnotationObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScAnnotationObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XChild
+
+uno::Reference<uno::XInterface> SAL_CALL ScAnnotationObj::getParent()
+{
+ SolarMutexGuard aGuard;
+
+ // parent of note is the related cell
+ //! find and reset existing object ???
+
+ if (pDocShell)
+ return cppu::getXWeak(new ScCellObj( pDocShell, aCellPos ));
+
+ return nullptr;
+}
+
+void SAL_CALL ScAnnotationObj::setParent( const uno::Reference<uno::XInterface>& /* Parent */ )
+{
+ // ain't there
+ //! exception or what ??!
+}
+
+// XSimpleText
+
+uno::Reference<text::XTextCursor> SAL_CALL ScAnnotationObj::createTextCursor()
+{
+ SolarMutexGuard aGuard;
+ // notes does not need special treatment
+ return GetUnoText().createTextCursor();
+}
+
+uno::Reference<text::XTextCursor> SAL_CALL ScAnnotationObj::createTextCursorByRange(
+ const uno::Reference<text::XTextRange>& aTextPosition )
+{
+ SolarMutexGuard aGuard;
+ // notes does not need special treatment
+ return GetUnoText().createTextCursorByRange(aTextPosition);
+}
+
+OUString SAL_CALL ScAnnotationObj::getString()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getString();
+}
+
+void SAL_CALL ScAnnotationObj::setString( const OUString& aText )
+{
+ SolarMutexGuard aGuard;
+ GetUnoText().setString(aText);
+}
+
+void SAL_CALL ScAnnotationObj::insertString( const uno::Reference<text::XTextRange>& xRange,
+ const OUString& aString, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ GetUnoText().insertString( xRange, aString, bAbsorb );
+}
+
+void SAL_CALL ScAnnotationObj::insertControlCharacter( const uno::Reference<text::XTextRange>& xRange,
+ sal_Int16 nControlCharacter, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ GetUnoText().insertControlCharacter( xRange, nControlCharacter, bAbsorb );
+}
+
+uno::Reference<text::XText> SAL_CALL ScAnnotationObj::getText()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getText();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScAnnotationObj::getStart()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getStart();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScAnnotationObj::getEnd()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getEnd();
+}
+
+// XSheetAnnotation
+
+table::CellAddress SAL_CALL ScAnnotationObj::getPosition()
+{
+ SolarMutexGuard aGuard;
+ table::CellAddress aAdr;
+ aAdr.Sheet = aCellPos.Tab();
+ aAdr.Column = aCellPos.Col();
+ aAdr.Row = aCellPos.Row();
+ return aAdr;
+}
+
+OUString SAL_CALL ScAnnotationObj::getAuthor()
+{
+ SolarMutexGuard aGuard;
+ const ScPostIt* pNote = ImplGetNote();
+ return pNote ? pNote->GetAuthor() : OUString();
+}
+
+OUString SAL_CALL ScAnnotationObj::getDate()
+{
+ SolarMutexGuard aGuard;
+ const ScPostIt* pNote = ImplGetNote();
+ return pNote ? pNote->GetDate() : OUString();
+}
+
+sal_Bool SAL_CALL ScAnnotationObj::getIsVisible()
+{
+ SolarMutexGuard aGuard;
+ const ScPostIt* pNote = ImplGetNote();
+ return pNote && pNote->IsCaptionShown();
+}
+
+void SAL_CALL ScAnnotationObj::setIsVisible( sal_Bool bIsVisible )
+{
+ SolarMutexGuard aGuard;
+ // show/hide note with undo action
+ if( pDocShell )
+ pDocShell->GetDocFunc().ShowNote( aCellPos, bIsVisible );
+}
+
+// XSheetAnnotationShapeSupplier
+uno::Reference < drawing::XShape > SAL_CALL ScAnnotationObj::getAnnotationShape()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference < drawing::XShape > xShape;
+ if( const ScPostIt* pNote = ImplGetNote() )
+ if( SdrObject* pCaption = pNote->GetOrCreateCaption( aCellPos ) )
+ xShape.set( pCaption->getUnoShape(), uno::UNO_QUERY );
+ return xShape;
+}
+
+SvxUnoText& ScAnnotationObj::GetUnoText()
+{
+ if (!pUnoText.is())
+ {
+ ScAnnotationEditSource aEditSource( pDocShell, aCellPos );
+ pUnoText = new SvxUnoText( &aEditSource, lcl_GetAnnotationPropertySet(),
+ uno::Reference<text::XText>() );
+ }
+ return *pUnoText;
+}
+
+const ScPostIt* ScAnnotationObj::ImplGetNote() const
+{
+ return pDocShell ? pDocShell->GetDocument().GetNote(aCellPos) : nullptr;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/optuno.cxx b/sc/source/ui/unoobj/optuno.cxx
new file mode 100644
index 0000000000..09e17add09
--- /dev/null
+++ b/sc/source/ui/unoobj/optuno.cxx
@@ -0,0 +1,221 @@
+/* -*- 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 <svl/itemprop.hxx>
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/util/Date.hpp>
+
+#include <optuno.hxx>
+#include <miscuno.hxx>
+#include <unonames.hxx>
+#include <docoptio.hxx>
+
+using namespace com::sun::star;
+
+std::span<const SfxItemPropertyMapEntry> ScDocOptionsHelper::GetPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aMap[] =
+ {
+ { SC_UNO_CALCASSHOWN, PROP_UNO_CALCASSHOWN , cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_DEFTABSTOP, PROP_UNO_DEFTABSTOP , cppu::UnoType<sal_Int16>::get(), 0, 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_NULLDATE, PROP_UNO_NULLDATE , cppu::UnoType<util::Date>::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},
+ };
+ return aMap;
+}
+
+bool ScDocOptionsHelper::setPropertyValue( ScDocOptions& rOptions,
+ const SfxItemPropertyMap& rPropMap,
+ std::u16string_view aPropertyName, const uno::Any& aValue )
+{
+ //! use map (with new identifiers)
+
+ const SfxItemPropertyMapEntry* pEntry = rPropMap.getByName(aPropertyName );
+ if( !pEntry || !pEntry->nWID )
+ return false;
+ switch( pEntry->nWID )
+ {
+ case PROP_UNO_CALCASSHOWN :
+ rOptions.SetCalcAsShown( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_DEFTABSTOP :
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ rOptions.SetTabDistance( nIntVal );
+ }
+ break;
+ case PROP_UNO_IGNORECASE :
+ rOptions.SetIgnoreCase( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_ITERENABLED:
+ rOptions.SetIter( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_ITERCOUNT :
+ {
+ sal_Int32 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ rOptions.SetIterCount( static_cast<sal_uInt16>(nIntVal) );
+ }
+ break;
+ case PROP_UNO_ITEREPSILON :
+ {
+ double fDoubleVal = 0;
+ if ( aValue >>= fDoubleVal )
+ rOptions.SetIterEps( fDoubleVal );
+ }
+ break;
+ case PROP_UNO_LOOKUPLABELS :
+ rOptions.SetLookUpColRowNames( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_MATCHWHOLE :
+ rOptions.SetMatchWholeCell( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_NULLDATE:
+ {
+ util::Date aDate;
+ if ( aValue >>= aDate )
+ rOptions.SetDate( aDate.Day, aDate.Month, aDate.Year );
+ }
+ break;
+ case PROP_UNO_SPELLONLINE:
+ rOptions.SetAutoSpell( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_STANDARDDEC:
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ rOptions.SetStdPrecision( nIntVal );
+ }
+ break;
+ case PROP_UNO_REGEXENABLED:
+ rOptions.SetFormulaRegexEnabled( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_WILDCARDSENABLED:
+ rOptions.SetFormulaWildcardsEnabled( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ default:;
+ }
+ return true;
+}
+
+uno::Any ScDocOptionsHelper::getPropertyValue(
+ const ScDocOptions& rOptions,
+ const SfxItemPropertyMap& rPropMap,
+ std::u16string_view aPropertyName )
+{
+ uno::Any aRet;
+ const SfxItemPropertyMapEntry* pEntry = rPropMap.getByName( aPropertyName );
+ if( !pEntry || !pEntry->nWID )
+ return aRet;
+ switch( pEntry->nWID )
+ {
+ case PROP_UNO_CALCASSHOWN :
+ aRet <<= rOptions.IsCalcAsShown();
+ break;
+ case PROP_UNO_DEFTABSTOP :
+ aRet <<= static_cast<sal_Int16>( rOptions.GetTabDistance() );
+ break;
+ case PROP_UNO_IGNORECASE :
+ aRet <<= rOptions.IsIgnoreCase();
+ break;
+ case PROP_UNO_ITERENABLED:
+ aRet <<= rOptions.IsIter();
+ break;
+ case PROP_UNO_ITERCOUNT:
+ aRet <<= static_cast<sal_Int32>( rOptions.GetIterCount() );
+ break;
+ case PROP_UNO_ITEREPSILON:
+ aRet <<= rOptions.GetIterEps();
+ break;
+ case PROP_UNO_LOOKUPLABELS:
+ aRet <<= rOptions.IsLookUpColRowNames();
+ break;
+ case PROP_UNO_MATCHWHOLE:
+ aRet <<= rOptions.IsMatchWholeCell();
+ break;
+ case PROP_UNO_NULLDATE:
+ {
+ sal_uInt16 nD, nM;
+ sal_Int16 nY;
+ rOptions.GetDate( nD, nM, nY );
+ util::Date aDate( nD, nM, nY );
+ aRet <<= aDate;
+ }
+ break;
+ case PROP_UNO_SPELLONLINE:
+ aRet <<= rOptions.IsAutoSpell();
+ break;
+ case PROP_UNO_STANDARDDEC :
+ aRet <<= static_cast<sal_Int16>( rOptions.GetStdPrecision() );
+ break;
+ case PROP_UNO_REGEXENABLED:
+ aRet <<= rOptions.IsFormulaRegexEnabled();
+ break;
+ case PROP_UNO_WILDCARDSENABLED:
+ aRet <<= rOptions.IsFormulaWildcardsEnabled();
+ break;
+ default:;
+ }
+ return aRet;
+}
+
+ScDocOptionsObj::ScDocOptionsObj( const ScDocOptions& rOpt ) :
+ ScModelObj( nullptr ),
+ aOptions( rOpt )
+{
+}
+
+ScDocOptionsObj::~ScDocOptionsObj()
+{
+}
+
+void SAL_CALL ScDocOptionsObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ bool bDone = ScDocOptionsHelper::setPropertyValue( aOptions, GetPropertySet().getPropertyMap(), aPropertyName, aValue );
+
+ if (!bDone)
+ ScModelObj::setPropertyValue( aPropertyName, aValue );
+}
+
+uno::Any SAL_CALL ScDocOptionsObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aRet(ScDocOptionsHelper::getPropertyValue( aOptions, GetPropertySet().getPropertyMap(), aPropertyName ));
+ if ( !aRet.hasValue() )
+ aRet = ScModelObj::getPropertyValue( aPropertyName );
+
+ return aRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/pageuno.cxx b/sc/source/ui/unoobj/pageuno.cxx
new file mode 100644
index 0000000000..3ca903e63e
--- /dev/null
+++ b/sc/source/ui/unoobj/pageuno.cxx
@@ -0,0 +1,60 @@
+/* -*- 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 <cppuhelper/supportsservice.hxx>
+#include <rtl/ustring.hxx>
+#include <pageuno.hxx>
+#include <shapeuno.hxx>
+
+using namespace ::com::sun::star;
+
+ScPageObj::ScPageObj( SdrPage* pPage ) :
+ SvxDrawPage( pPage )
+{
+}
+
+ScPageObj::~ScPageObj() noexcept
+{
+}
+
+uno::Reference<drawing::XShape > ScPageObj::CreateShape( SdrObject *pObj ) const
+{
+ uno::Reference<drawing::XShape> xShape(SvxDrawPage::CreateShape( pObj ));
+
+ new ScShapeObj( xShape ); // aggregates object and modifies xShape
+
+ return xShape;
+}
+
+OUString SAL_CALL ScPageObj::getImplementationName()
+{
+ return "ScPageObj";
+}
+
+sal_Bool SAL_CALL ScPageObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScPageObj::getSupportedServiceNames()
+{
+ return { "com.sun.star.sheet.SpreadsheetDrawPage" };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/scdetect.cxx b/sc/source/ui/unoobj/scdetect.cxx
new file mode 100644
index 0000000000..e5fc5848e1
--- /dev/null
+++ b/sc/source/ui/unoobj/scdetect.cxx
@@ -0,0 +1,353 @@
+/* -*- 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 "scdetect.hxx"
+
+#include <sal/macros.h>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <unotools/mediadescriptor.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/fcontnr.hxx>
+
+using namespace ::com::sun::star;
+using utl::MediaDescriptor;
+
+namespace {
+
+// table with search pattern
+// meaning of the sequences
+// 0x00??: the exact byte 0x?? must be at that place
+// 0x0100: read over a byte (don't care)
+// 0x02nn: a byte of 0xnn variations follows
+// 0x8000: recognition finished
+
+#define M_DC 0x0100
+#define M_ALT(CNT) (0x0200+(CNT))
+#define M_END 0x8000
+
+const sal_uInt16 pLotus[] = // Lotus 1/1A/2
+ { 0x0000, 0x0000, 0x0002, 0x0000,
+ M_ALT(2), 0x0004, 0x0006,
+ 0x0004, M_END };
+
+const sal_uInt16 pLotusNew[] = // Lotus >= 9.7
+ { 0x0000, 0x0000, M_DC, 0x0000, // Rec# + Len (0x1a)
+ M_ALT(3), 0x0003, 0x0004, 0x0005, // File Revision Code 97->ME
+ 0x0010, 0x0004, 0x0000, 0x0000,
+ M_END };
+
+const sal_uInt16 pLotus2[] = // Lotus >3
+ { 0x0000, 0x0000, 0x001A, 0x0000, // Rec# + Len (26)
+ M_ALT(2), 0x0000, 0x0002, // File Revision Code
+ 0x0010,
+ 0x0004, 0x0000, // File Revision Subcode
+ M_END };
+
+const sal_uInt16 pQPro[] =
+ { 0x0000, 0x0000, 0x0002, 0x0000,
+ M_ALT(4), 0x0001, 0x0002, // WB1, WB2
+ 0x0006, 0x0007, // QPro 6/7 (?)
+ 0x0010,
+ M_END };
+
+const sal_uInt16 pDIF1[] = // DIF with CR-LF
+ {
+ 'T', 'A', 'B', 'L', 'E',
+ M_DC, M_DC,
+ '0', ',', '1',
+ M_DC, M_DC,
+ '\"',
+ M_END };
+
+const sal_uInt16 pDIF2[] = // DIF with CR or LF
+ {
+ 'T', 'A', 'B', 'L', 'E',
+ M_DC,
+ '0', ',', '1',
+ M_DC,
+ '\"',
+ M_END };
+
+const sal_uInt16 pSylk[] = // Sylk
+ {
+ 'I', 'D', ';',
+ M_ALT(3), 'P', 'N', 'E', // 'P' plus undocumented Excel extensions 'N' and 'E'
+ M_END };
+
+bool detectThisFormat(SvStream& rStr, const sal_uInt16* pSearch)
+{
+ sal_uInt8 nByte;
+ rStr.Seek( 0 ); // in the beginning everything was bad...
+ rStr.ReadUChar( nByte );
+ bool bSync = true;
+ while( !rStr.eof() && bSync )
+ {
+ sal_uInt16 nMuster = *pSearch;
+
+ if( nMuster < 0x0100 )
+ { // compare bytes
+ if( static_cast<sal_uInt8>(nMuster) != nByte )
+ bSync = false;
+ }
+ else if( nMuster & M_DC )
+ { // don't care
+ }
+ else if( nMuster & M_ALT(0) )
+ { // alternative Bytes
+ sal_uInt8 nCntAlt = static_cast<sal_uInt8>(nMuster);
+ bSync = false; // first unsynchron
+ while( nCntAlt > 0 )
+ {
+ pSearch++;
+ if( static_cast<sal_uInt8>(*pSearch) == nByte )
+ bSync = true; // only now synchronization
+ nCntAlt--;
+ }
+ }
+ else if( nMuster & M_END )
+ { // Format detected
+ return true;
+ }
+
+ pSearch++;
+ rStr.ReadUChar( nByte );
+ }
+
+ return false;
+}
+
+}
+
+ScFilterDetect::ScFilterDetect()
+{
+}
+
+ScFilterDetect::~ScFilterDetect()
+{
+}
+
+#if 0
+// This method is no longer used, but I do want to keep this for now to see
+// if we could transfer this check to the now centralized ascii detection
+// code in the filter module.
+static sal_Bool lcl_MayBeAscii( SvStream& rStream )
+{
+ // ASCII/CSV is considered possible if there are no null bytes, or a Byte
+ // Order Mark is present, or if, for Unicode UCS2/UTF-16, all null bytes
+ // are on either even or uneven byte positions.
+
+ rStream.Seek(STREAM_SEEK_TO_BEGIN);
+
+ const size_t nBufSize = 2048;
+ sal_uInt16 aBuffer[ nBufSize ];
+ sal_uInt8* pByte = reinterpret_cast<sal_uInt8*>(aBuffer);
+ sal_uLong nBytesRead = rStream.Read( pByte, nBufSize*2);
+
+ if ( nBytesRead >= 2 && (aBuffer[0] == 0xfffe || aBuffer[0] == 0xfeff) )
+ {
+ // Unicode BOM file may contain null bytes.
+ return sal_True;
+ }
+
+ const sal_uInt16* p = aBuffer;
+ sal_uInt16 nMask = 0xffff;
+ nBytesRead /= 2;
+ while( nBytesRead-- && nMask )
+ {
+ sal_uInt16 nVal = *p++ & nMask;
+ if (!(nVal & 0x00ff))
+ nMask &= 0xff00;
+ if (!(nVal & 0xff00))
+ nMask &= 0x00ff;
+ }
+
+ return nMask != 0;
+}
+#endif
+
+static bool lcl_MayBeDBase( SvStream& rStream )
+{
+ // Look for dbf marker, see connectivity/source/inc/dbase/DTable.hxx
+ // DBFType for values.
+ const sal_uInt8 nValidMarks[] = {
+ 0x03, 0x04, 0x05, 0x30, 0x31, 0x43, 0xB3, 0x83, 0x8b, 0x8e, 0xf5 };
+ sal_uInt8 nMark;
+ rStream.Seek(STREAM_SEEK_TO_BEGIN);
+ rStream.ReadUChar( nMark );
+ bool bValidMark = false;
+ for (size_t i=0; i < SAL_N_ELEMENTS(nValidMarks) && !bValidMark; ++i)
+ {
+ if (nValidMarks[i] == nMark)
+ bValidMark = true;
+ }
+ if ( !bValidMark )
+ return false;
+
+ const size_t nHeaderBlockSize = 32;
+ // Empty dbf is >= 32*2+1 bytes in size.
+ const size_t nEmptyDbf = nHeaderBlockSize * 2 + 1;
+
+ sal_uInt64 nSize = rStream.TellEnd();
+ if ( nSize < nEmptyDbf )
+ return false;
+
+ // count of records at 4
+ rStream.Seek(4);
+ sal_uInt32 nRecords(0);
+ rStream.ReadUInt32(nRecords);
+
+ // length of header starts at 8
+ rStream.Seek(8);
+ sal_uInt16 nHeaderLen;
+ rStream.ReadUInt16( nHeaderLen );
+
+ // size of record at 10
+ sal_uInt16 nRecordSize(0);
+ rStream.ReadUInt16(nRecordSize);
+
+ if ( nHeaderLen < nEmptyDbf || nSize < nHeaderLen )
+ return false;
+
+ // see DTable.cxx ODbaseTable::readHeader()
+ if (0 == nRecordSize)
+ return false;
+
+ // see DTable.cxx ODbaseTable::construct() line 546
+ if (0 == nRecords)
+ {
+ nRecords = (nSize - nHeaderLen) / nRecordSize;
+ }
+
+ // tdf#84834 sanity check of size
+ // tdf#106423: a dbf file can have 0 record, so no need to check nRecords
+ if (nSize < nHeaderLen + nRecords * sal_uInt64(nRecordSize))
+ return false;
+
+ // Last byte of header must be 0x0d, this is how it's specified.
+ // #i9581#,#i26407# but some applications don't follow the specification
+ // and pad the header with one byte 0x00 to reach an
+ // even boundary. Some (#i88577# ) even pad more or pad using a 0x1a ^Z
+ // control character (#i8857#). This results in:
+ // Last byte of header must be 0x0d on 32 bytes boundary.
+ sal_uInt16 nBlocks = (nHeaderLen - 1) / nHeaderBlockSize;
+ sal_uInt8 nEndFlag = 0;
+ while ( nBlocks > 1 && nEndFlag != 0x0d ) {
+ rStream.Seek( nBlocks-- * nHeaderBlockSize );
+ rStream.ReadUChar( nEndFlag );
+ }
+
+ return ( 0x0d == nEndFlag );
+}
+
+OUString SAL_CALL ScFilterDetect::detect( uno::Sequence<beans::PropertyValue>& lDescriptor )
+{
+ MediaDescriptor aMediaDesc( lDescriptor );
+ OUString aTypeName = aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_TYPENAME, OUString() );
+ uno::Reference< io::XInputStream > xStream ( aMediaDesc[MediaDescriptor::PROP_INPUTSTREAM], uno::UNO_QUERY );
+ if ( !xStream.is() )
+ return OUString();
+
+ SfxMedium aMedium;
+ aMedium.UseInteractionHandler( false );
+ aMedium.setStreamToLoadFrom( xStream, true );
+
+ SvStream* pStream = aMedium.GetInStream();
+ if ( !pStream || pStream->GetError() )
+ // No stream, no detection.
+ return OUString();
+
+ const char* pSearchFilterName = nullptr;
+ if (aTypeName == "calc_Lotus")
+ {
+ if (!detectThisFormat(*pStream, pLotus) && !detectThisFormat(*pStream, pLotusNew) && !detectThisFormat(*pStream, pLotus2))
+ return OUString();
+
+ pSearchFilterName = "Lotus";
+ }
+ else if (aTypeName == "calc_QPro")
+ {
+ if (!detectThisFormat(*pStream, pQPro))
+ return OUString();
+
+ pSearchFilterName = "Quattro Pro 6.0";
+ }
+ else if (aTypeName == "calc_SYLK")
+ {
+ if (!detectThisFormat(*pStream, pSylk))
+ return OUString();
+
+ pSearchFilterName = "SYLK";
+ }
+ else if (aTypeName == "calc_DIF")
+ {
+ if (!detectThisFormat(*pStream, pDIF1) && !detectThisFormat(*pStream, pDIF2))
+ return OUString();
+
+ pSearchFilterName = "DIF";
+ }
+ else if (aTypeName == "calc_dBase")
+ {
+ if (!lcl_MayBeDBase(*pStream))
+ return OUString();
+
+ pSearchFilterName = "dBase";
+ }
+ else
+ return OUString();
+
+ SfxFilterMatcher aMatcher("scalc");
+ std::shared_ptr<const SfxFilter> pFilter = aMatcher.GetFilter4FilterName(OUString::createFromAscii(pSearchFilterName));
+
+ if (!pFilter)
+ return OUString();
+
+ aMediaDesc[MediaDescriptor::PROP_FILTERNAME] <<= pFilter->GetName();
+ aMediaDesc >> lDescriptor;
+ return aTypeName;
+}
+
+OUString SAL_CALL ScFilterDetect::getImplementationName()
+{
+ return "com.sun.star.comp.calc.FormatDetector";
+}
+
+sal_Bool ScFilterDetect::supportsService( const OUString& sServiceName )
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+css::uno::Sequence<OUString> ScFilterDetect::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ExtendedTypeDetection" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_calc_FormatDetector_get_implementation(css::uno::XComponentContext* /*context*/,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ScFilterDetect);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/scdetect.hxx b/sc/source/ui/unoobj/scdetect.hxx
new file mode 100644
index 0000000000..697bd8d58e
--- /dev/null
+++ b/sc/source/ui/unoobj/scdetect.hxx
@@ -0,0 +1,49 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/document/XExtendedFilterDetection.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <rtl/ustring.hxx>
+
+namespace com::sun::star {
+ namespace beans { struct PropertyValue; }
+}
+
+class ScFilterDetect : public ::cppu::WeakImplHelper< css::document::XExtendedFilterDetection, css::lang::XServiceInfo >
+{
+public:
+ explicit ScFilterDetect();
+ virtual ~ScFilterDetect() override;
+
+ /* XServiceInfo */
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& sServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XExtendedFilterDetect
+
+ virtual OUString SAL_CALL detect( css::uno::Sequence<css::beans::PropertyValue>& lDescriptor ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/servuno.cxx b/sc/source/ui/unoobj/servuno.cxx
new file mode 100644
index 0000000000..4326817027
--- /dev/null
+++ b/sc/source/ui/unoobj/servuno.cxx
@@ -0,0 +1,625 @@
+/* -*- 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 <memory>
+#include <config_features.h>
+
+#include <sal/macros.h>
+#include <svtools/unoimap.hxx>
+#include <svx/unofill.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/text/textfield/Type.hpp>
+
+#include <editsrc.hxx>
+#include <servuno.hxx>
+#include <unonames.hxx>
+#include <appluno.hxx>
+#include <cellsuno.hxx>
+#include <fielduno.hxx>
+#include <styleuno.hxx>
+#include <afmtuno.hxx>
+#include <defltuno.hxx>
+#include <drdefuno.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <confuno.hxx>
+#include <shapeuno.hxx>
+#include "cellvaluebinding.hxx"
+#include "celllistsource.hxx"
+#include <addruno.hxx>
+#include <chart2uno.hxx>
+#include <tokenuno.hxx>
+#include <PivotTableDataProvider.hxx>
+
+// Support creation of GraphicStorageHandler and EmbeddedObjectResolver
+#include <svx/xmleohlp.hxx>
+#include <svx/xmlgrhlp.hxx>
+#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
+#include <com/sun/star/document/XCodeNameQuery.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <svx/unomod.hxx>
+#include <vbahelper/vbaaccesshelper.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <basic/basmgr.hxx>
+#include <sfx2/app.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/script/vba/XVBACompatibility.hpp>
+
+using namespace ::com::sun::star;
+
+#if HAVE_FEATURE_SCRIPTING
+
+static bool isInVBAMode( ScDocShell& rDocSh )
+{
+ uno::Reference<script::XLibraryContainer> xLibContainer = rDocSh.GetBasicContainer();
+ uno::Reference<script::vba::XVBACompatibility> xVBACompat( xLibContainer, uno::UNO_QUERY );
+ if ( xVBACompat.is() )
+ return xVBACompat->getVBACompatibilityMode();
+ return false;
+}
+
+#endif
+
+namespace {
+
+#if HAVE_FEATURE_SCRIPTING
+class ScVbaObjectForCodeNameProvider : public ::cppu::WeakImplHelper< container::XNameAccess >
+{
+ uno::Any maWorkbook;
+ uno::Any maCachedObject;
+ ScDocShell* mpDocShell;
+public:
+ explicit ScVbaObjectForCodeNameProvider( ScDocShell* pDocShell ) : mpDocShell( pDocShell )
+ {
+ uno::Sequence< uno::Any > aArgs{
+ // access the application object ( parent for workbook )
+ uno::Any(ooo::vba::createVBAUnoAPIServiceWithArgs( mpDocShell, "ooo.vba.Application", {} )),
+ uno::Any(uno::Reference(static_cast<css::sheet::XSpreadsheetDocument*>(mpDocShell->GetModel())))
+ };
+ maWorkbook <<= ooo::vba::createVBAUnoAPIServiceWithArgs( mpDocShell, "ooo.vba.excel.Workbook", aArgs );
+ }
+
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
+ {
+ SolarMutexGuard aGuard;
+ maCachedObject = uno::Any(); // clear cached object
+
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ // aName is generated from the stream name which can be different ( case-wise )
+ // from the code name
+ if( aName.equalsIgnoreAsciiCase( rDoc.GetCodeName() ) )
+ maCachedObject = maWorkbook;
+ else
+ {
+ OUString sCodeName;
+ SCTAB nCount = rDoc.GetTableCount();
+ for( SCTAB i = 0; i < nCount; i++ )
+ {
+ rDoc.GetCodeName( i, sCodeName );
+ // aName is generated from the stream name which can be different ( case-wise )
+ // from the code name
+ if( sCodeName.equalsIgnoreAsciiCase( aName ) )
+ {
+ OUString sSheetName;
+ if( rDoc.GetName( i, sSheetName ) )
+ {
+ rtl::Reference< ScModelObj > xSpreadDoc( mpDocShell->GetModel() );
+ uno::Reference<sheet::XSpreadsheets > xSheets( xSpreadDoc->getSheets(), uno::UNO_SET_THROW );
+ uno::Reference< container::XIndexAccess > xIndexAccess( xSheets, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheet > xSheet( xIndexAccess->getByIndex( i ), uno::UNO_QUERY_THROW );
+ uno::Sequence< uno::Any > aArgs{ maWorkbook, uno::Any(uno::Reference< frame::XModel >(xSpreadDoc)), uno::Any(sSheetName) };
+ // use the convenience function
+ maCachedObject <<= ooo::vba::createVBAUnoAPIServiceWithArgs( mpDocShell, "ooo.vba.excel.Worksheet", aArgs );
+ break;
+ }
+ }
+ }
+ }
+ return maCachedObject.hasValue();
+
+ }
+ css::uno::Any SAL_CALL getByName( const OUString& aName ) override
+ {
+ SolarMutexGuard aGuard;
+ if ( !hasByName( aName ) )
+ throw css::container::NoSuchElementException();
+ return maCachedObject;
+ }
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override
+ {
+ SolarMutexGuard aGuard;
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ SCTAB nCount = rDoc.GetTableCount();
+ uno::Sequence< OUString > aNames( nCount + 1 );
+ auto pNames = aNames.getArray();
+ SCTAB index = 0;
+ OUString sCodeName;
+ for( ; index < nCount; ++index )
+ {
+ rDoc.GetCodeName( index, sCodeName );
+ pNames[ index ] = sCodeName;
+ }
+ pNames[ index ] = rDoc.GetCodeName();
+ return aNames;
+ }
+ // XElemenAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override { return uno::Type(); }
+ virtual sal_Bool SAL_CALL hasElements( ) override { return true; }
+
+};
+
+class ScVbaCodeNameProvider : public ::cppu::WeakImplHelper< document::XCodeNameQuery >
+{
+ ScDocShell& mrDocShell;
+public:
+ explicit ScVbaCodeNameProvider( ScDocShell& rDocShell ) : mrDocShell(rDocShell) {}
+ // XCodeNameQuery
+ OUString SAL_CALL getCodeNameForObject( const uno::Reference< uno::XInterface >& xIf ) override
+ {
+ SolarMutexGuard aGuard;
+ OUString sCodeName;
+
+ // need to find the page ( and index ) for this control
+ uno::Reference< container::XIndexAccess > xIndex( mrDocShell.GetModel()->getDrawPages(), uno::UNO_QUERY_THROW );
+ sal_Int32 nLen = xIndex->getCount();
+ bool bMatched = false;
+ for ( sal_Int32 index = 0; index < nLen; ++index )
+ {
+ try
+ {
+ uno::Reference< form::XFormsSupplier > xFormSupplier( xIndex->getByIndex( index ), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xFormIndex( xFormSupplier->getForms(), uno::UNO_QUERY_THROW );
+ // get the www-standard container
+ uno::Reference< container::XIndexAccess > xFormControls( xFormIndex->getByIndex(0), uno::UNO_QUERY_THROW );
+ sal_Int32 nCntrls = xFormControls->getCount();
+ for( sal_Int32 cIndex = 0; cIndex < nCntrls; ++cIndex )
+ {
+ uno::Reference< uno::XInterface > xControl( xFormControls->getByIndex( cIndex ), uno::UNO_QUERY_THROW );
+ bMatched = ( xControl == xIf );
+ if ( bMatched )
+ {
+ OUString sName;
+ mrDocShell.GetDocument().GetCodeName( static_cast<SCTAB>( index ), sName );
+ sCodeName = sName;
+ }
+ }
+ }
+ catch( uno::Exception& ) {}
+ if ( bMatched )
+ break;
+ }
+ // Probably should throw here ( if !bMatched )
+ return sCodeName;
+ }
+
+ OUString SAL_CALL getCodeNameForContainer( const uno::Reference<uno::XInterface>& xContainer ) override
+ {
+ SolarMutexGuard aGuard;
+ uno::Reference<container::XIndexAccess> xIndex(mrDocShell.GetModel()->getDrawPages(), uno::UNO_QUERY_THROW);
+
+ for (sal_Int32 i = 0, n = xIndex->getCount(); i < n; ++i)
+ {
+ try
+ {
+ uno::Reference<form::XFormsSupplier> xFormSupplier(xIndex->getByIndex(i), uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xFormIndex(xFormSupplier->getForms(), uno::UNO_QUERY_THROW);
+ // get the www-standard container
+ uno::Reference<container::XIndexAccess> xFormControls(xFormIndex->getByIndex(0), uno::UNO_QUERY_THROW);
+ if (xFormControls == xContainer)
+ {
+ OUString aName;
+ if (mrDocShell.GetDocument().GetCodeName(static_cast<SCTAB>(i), aName))
+ return aName;
+ }
+ }
+ catch( uno::Exception& ) {}
+ }
+ return OUString();
+ }
+};
+
+#endif
+
+using Type = ScServiceProvider::Type;
+
+struct ProvNamesId_Type
+{
+ OUString pName;
+ ScServiceProvider::Type nType;
+};
+
+const ProvNamesId_Type aProvNamesId[] =
+{
+ { "com.sun.star.sheet.Spreadsheet", Type::SHEET },
+ { "com.sun.star.text.TextField.URL", Type::URLFIELD },
+ { "com.sun.star.text.TextField.PageNumber", Type::PAGEFIELD },
+ { "com.sun.star.text.TextField.PageCount", Type::PAGESFIELD },
+ { "com.sun.star.text.TextField.Date", Type::DATEFIELD },
+ { "com.sun.star.text.TextField.Time", Type::TIMEFIELD },
+ { "com.sun.star.text.TextField.DateTime", Type::EXT_TIMEFIELD },
+ { "com.sun.star.text.TextField.DocInfo.Title", Type::TITLEFIELD },
+ { "com.sun.star.text.TextField.FileName", Type::FILEFIELD },
+ { "com.sun.star.text.TextField.SheetName", Type::SHEETFIELD },
+ { "com.sun.star.style.CellStyle", Type::CELLSTYLE },
+ { "com.sun.star.style.PageStyle", Type::PAGESTYLE },
+ { "com.sun.star.style.GraphicStyle", Type::GRAPHICSTYLE },
+ { "com.sun.star.sheet.TableAutoFormat", Type::AUTOFORMAT },
+ { "com.sun.star.sheet.TableAutoFormats", Type::AUTOFORMATS },
+ { "com.sun.star.sheet.SheetCellRanges", Type::CELLRANGES },
+ { "com.sun.star.sheet.FunctionDescriptions", Type::FUNCTIONDESCRIPTIONS },
+ { "com.sun.star.sheet.GlobalSheetSettings", Type::GLOBALSHEETSETTINGS },
+ { "com.sun.star.sheet.RecentFunctions", Type::RECENTFUNCTIONS },
+ { "com.sun.star.drawing.GradientTable", Type::GRADTAB },
+ { "com.sun.star.drawing.HatchTable", Type::HATCHTAB },
+ { "com.sun.star.drawing.BitmapTable", Type::BITMAPTAB },
+ { "com.sun.star.drawing.TransparencyGradientTable", Type::TRGRADTAB },
+ { "com.sun.star.drawing.MarkerTable", Type::MARKERTAB },
+ { "com.sun.star.drawing.DashTable", Type::DASHTAB },
+ { "com.sun.star.text.NumberingRules", Type::NUMRULES },
+ { "com.sun.star.sheet.Defaults", Type::DOCDEFLTS },
+ { "com.sun.star.drawing.Defaults", Type::DRAWDEFLTS },
+ { "com.sun.star.comp.SpreadsheetSettings", Type::DOCSPRSETT },
+ { "com.sun.star.document.Settings", Type::DOCCONF },
+ { "com.sun.star.image.ImageMapRectangleObject", Type::IMAP_RECT },
+ { "com.sun.star.image.ImageMapCircleObject", Type::IMAP_CIRC },
+ { "com.sun.star.image.ImageMapPolygonObject", Type::IMAP_POLY },
+
+ // Support creation of GraphicStorageHandler and EmbeddedObjectResolver
+ { "com.sun.star.document.ExportGraphicStorageHandler", Type::EXPORT_GRAPHIC_STORAGE_HANDLER },
+ { "com.sun.star.document.ImportGraphicStorageHandler", Type::IMPORT_GRAPHIC_STORAGE_HANDLER },
+ { "com.sun.star.document.ExportEmbeddedObjectResolver", Type::EXPORT_EOR },
+ { "com.sun.star.document.ImportEmbeddedObjectResolver", Type::IMPORT_EOR },
+
+ { SC_SERVICENAME_VALBIND, Type::VALBIND },
+ { SC_SERVICENAME_LISTCELLBIND, Type::LISTCELLBIND },
+ { SC_SERVICENAME_LISTSOURCE, Type::LISTSOURCE },
+ { SC_SERVICENAME_CELLADDRESS, Type::CELLADDRESS },
+ { SC_SERVICENAME_RANGEADDRESS, Type::RANGEADDRESS },
+
+ { "com.sun.star.sheet.DocumentSettings",Type::SHEETDOCSET },
+
+ { SC_SERVICENAME_CHDATAPROV, Type::CHDATAPROV },
+ { SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER, Type::CHART_PIVOTTABLE_DATAPROVIDER },
+ { SC_SERVICENAME_FORMULAPARS, Type::FORMULAPARS },
+ { SC_SERVICENAME_OPCODEMAPPER, Type::OPCODEMAPPER },
+ { "ooo.vba.VBAObjectModuleObjectProvider", Type::VBAOBJECTPROVIDER },
+ { "ooo.vba.VBACodeNameProvider", Type::VBACODENAMEPROVIDER },
+ { "ooo.vba.VBAGlobals", Type::VBAGLOBALS },
+
+ // case-correct versions of the service names (#i102468#)
+ { "com.sun.star.text.textfield.URL", Type::URLFIELD },
+ { "com.sun.star.text.textfield.PageNumber", Type::PAGEFIELD },
+ { "com.sun.star.text.textfield.PageCount", Type::PAGESFIELD },
+ { "com.sun.star.text.textfield.Date", Type::DATEFIELD },
+ { "com.sun.star.text.textfield.Time", Type::TIMEFIELD },
+ { "com.sun.star.text.textfield.DateTime", Type::EXT_TIMEFIELD },
+ { "com.sun.star.text.textfield.docinfo.Title", Type::TITLEFIELD },
+ { "com.sun.star.text.textfield.FileName", Type::FILEFIELD },
+ { "com.sun.star.text.textfield.SheetName", Type::SHEETFIELD },
+ { "ooo.vba.VBAGlobals", Type::VBAGLOBALS },
+};
+
+// old service names that were in 567 still work in createInstance,
+// in case some macro is still using them
+const ProvNamesId_Type aOldNames[] =
+{
+ { "stardiv.one.text.TextField.URL", Type::URLFIELD },
+ { "stardiv.one.text.TextField.PageNumber", Type::PAGEFIELD },
+ { "stardiv.one.text.TextField.PageCount", Type::PAGESFIELD },
+ { "stardiv.one.text.TextField.Date", Type::DATEFIELD },
+ { "stardiv.one.text.TextField.Time", Type::TIMEFIELD },
+ { "stardiv.one.text.TextField.DocumentTitle", Type::TITLEFIELD },
+ { "stardiv.one.text.TextField.FileName", Type::FILEFIELD },
+ { "stardiv.one.text.TextField.SheetName", Type::SHEETFIELD },
+ { "stardiv.one.style.CellStyle", Type::CELLSTYLE },
+ { "stardiv.one.style.PageStyle", Type::PAGESTYLE },
+};
+
+sal_Int32 getFieldType(ScServiceProvider::Type nOldType)
+{
+ switch (nOldType)
+ {
+ case Type::URLFIELD:
+ return text::textfield::Type::URL;
+ case Type::PAGEFIELD:
+ return text::textfield::Type::PAGE;
+ case Type::PAGESFIELD:
+ return text::textfield::Type::PAGES;
+ case Type::DATEFIELD:
+ return text::textfield::Type::DATE;
+ case Type::TIMEFIELD:
+ return text::textfield::Type::TIME;
+ case Type::EXT_TIMEFIELD:
+ return text::textfield::Type::EXTENDED_TIME;
+ case Type::TITLEFIELD:
+ return text::textfield::Type::DOCINFO_TITLE;
+ case Type::FILEFIELD:
+ return text::textfield::Type::EXTENDED_FILE;
+ case Type::SHEETFIELD:
+ return text::textfield::Type::TABLE;
+ default:
+ ;
+ }
+
+ return text::textfield::Type::URL; // default to URL for no reason whatsoever.
+}
+
+} // namespace
+
+
+ScServiceProvider::Type ScServiceProvider::GetProviderType(std::u16string_view rServiceName)
+{
+ if (!rServiceName.empty())
+ {
+ for (const ProvNamesId_Type & i : aProvNamesId)
+ {
+ if (rServiceName == i.pName)
+ {
+ return i.nType;
+ }
+ }
+
+ for (const ProvNamesId_Type & rOldName : aOldNames)
+ {
+ if (rServiceName == rOldName.pName)
+ {
+ OSL_FAIL("old service name used");
+ return rOldName.nType;
+ }
+ }
+ }
+ return Type::INVALID;
+}
+
+uno::Reference<uno::XInterface> ScServiceProvider::MakeInstance(
+ Type nType, ScDocShell* pDocShell )
+{
+ uno::Reference<uno::XInterface> xRet;
+
+ switch (nType)
+ {
+ case Type::SHEET:
+ // not inserted yet - DocShell=Null
+ xRet.set(static_cast<sheet::XSpreadsheet*>(new ScTableSheetObj(nullptr,0)));
+ break;
+ case Type::URLFIELD:
+ case Type::PAGEFIELD:
+ case Type::PAGESFIELD:
+ case Type::DATEFIELD:
+ case Type::TIMEFIELD:
+ case Type::EXT_TIMEFIELD:
+ case Type::TITLEFIELD:
+ case Type::FILEFIELD:
+ case Type::SHEETFIELD:
+ {
+ uno::Reference<text::XTextRange> xNullContent;
+ xRet.set(static_cast<text::XTextField*>(
+ new ScEditFieldObj(xNullContent, nullptr, getFieldType(nType), ESelection())));
+ } break;
+ case Type::CELLSTYLE:
+ xRet.set(static_cast<style::XStyle*>(new ScStyleObj( nullptr, SfxStyleFamily::Para, OUString() )));
+ break;
+ case Type::PAGESTYLE:
+ xRet.set(static_cast<style::XStyle*>(new ScStyleObj( nullptr, SfxStyleFamily::Page, OUString() )));
+ break;
+ case Type::GRAPHICSTYLE:
+ if (pDocShell)
+ {
+ pDocShell->MakeDrawLayer();
+ xRet.set(static_cast<style::XStyle*>(new ScStyleObj( nullptr, SfxStyleFamily::Frame, OUString() )));
+ }
+ break;
+ case Type::AUTOFORMAT:
+ xRet.set(static_cast<container::XIndexAccess*>(new ScAutoFormatObj( SC_AFMTOBJ_INVALID )));
+ break;
+ case Type::AUTOFORMATS:
+ xRet.set(static_cast<container::XIndexAccess*>(new ScAutoFormatsObj()));
+ break;
+ case Type::CELLRANGES:
+ // isn't inserted, rather filled
+ // -> DocShell must be set, but empty ranges
+ if (pDocShell)
+ xRet.set(static_cast<sheet::XSheetCellRanges*>(new ScCellRangesObj( pDocShell, ScRangeList() )));
+ break;
+ case Type::FUNCTIONDESCRIPTIONS:
+ xRet.set(static_cast<sheet::XFunctionDescriptions*>(new ScFunctionListObj()));
+ break;
+ case Type::GLOBALSHEETSETTINGS:
+ xRet.set(static_cast<sheet::XGlobalSheetSettings*>(new ScSpreadsheetSettings()));
+ break;
+ case Type::RECENTFUNCTIONS:
+ xRet.set(static_cast<sheet::XRecentFunctions*>(new ScRecentFunctionsObj()));
+ break;
+ case Type::DOCDEFLTS:
+ if (pDocShell)
+ xRet.set(static_cast<beans::XPropertySet*>(new ScDocDefaultsObj( pDocShell )));
+ break;
+ case Type::DRAWDEFLTS:
+ if (pDocShell)
+ xRet.set(static_cast<beans::XPropertySet*>(new ScDrawDefaultsObj( pDocShell )));
+ break;
+
+ // Drawing layer tables are not in SvxUnoDrawMSFactory,
+ // because SvxUnoDrawMSFactory doesn't have a SdrModel pointer.
+ // Drawing layer is always allocated if not there (MakeDrawLayer).
+
+ case Type::GRADTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoGradientTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::HATCHTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoHatchTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::BITMAPTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoBitmapTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::TRGRADTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoTransGradientTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::MARKERTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoMarkerTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::DASHTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoDashTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::NUMRULES:
+ if (pDocShell)
+ xRet.set(SvxCreateNumRule( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::DOCSPRSETT:
+ case Type::SHEETDOCSET:
+ case Type::DOCCONF:
+ if (pDocShell)
+ xRet.set(static_cast<beans::XPropertySet*>(new ScDocumentConfiguration(pDocShell)));
+ break;
+ case Type::IMAP_RECT:
+ xRet.set(SvUnoImageMapRectangleObject_createInstance( ScShapeObj::GetSupportedMacroItems() ));
+ break;
+ case Type::IMAP_CIRC:
+ xRet.set(SvUnoImageMapCircleObject_createInstance( ScShapeObj::GetSupportedMacroItems() ));
+ break;
+ case Type::IMAP_POLY:
+ xRet.set(SvUnoImageMapPolygonObject_createInstance( ScShapeObj::GetSupportedMacroItems() ));
+ break;
+
+ // Support creation of GraphicStorageHandler and EmbeddedObjectResolver
+ case Type::EXPORT_GRAPHIC_STORAGE_HANDLER:
+ xRet.set(getXWeak(new SvXMLGraphicHelper( SvXMLGraphicHelperMode::Write )));
+ break;
+ case Type::IMPORT_GRAPHIC_STORAGE_HANDLER:
+ xRet.set(getXWeak(new SvXMLGraphicHelper( SvXMLGraphicHelperMode::Read )));
+ break;
+ case Type::EXPORT_EOR:
+ if (pDocShell)
+ xRet.set(getXWeak(new SvXMLEmbeddedObjectHelper( *pDocShell, SvXMLEmbeddedObjectHelperMode::Write )));
+ break;
+ case Type::IMPORT_EOR:
+ if (pDocShell)
+ xRet.set(getXWeak(new SvXMLEmbeddedObjectHelper( *pDocShell, SvXMLEmbeddedObjectHelperMode::Read )));
+ break;
+ case Type::VALBIND:
+ case Type::LISTCELLBIND:
+ if (pDocShell)
+ {
+ bool bListPos = ( nType == Type::LISTCELLBIND );
+ uno::Reference<sheet::XSpreadsheetDocument> xDoc( pDocShell->GetBaseModel(), uno::UNO_QUERY );
+ xRet.set(*new calc::OCellValueBinding( xDoc, bListPos ));
+ }
+ break;
+ case Type::LISTSOURCE:
+ if (pDocShell)
+ {
+ uno::Reference<sheet::XSpreadsheetDocument> xDoc( pDocShell->GetBaseModel(), uno::UNO_QUERY );
+ xRet.set(*new calc::OCellListSource( xDoc ));
+ }
+ break;
+ case Type::CELLADDRESS:
+ case Type::RANGEADDRESS:
+ if (pDocShell)
+ {
+ bool bIsRange = ( nType == Type::RANGEADDRESS );
+ xRet.set(*new ScAddressConversionObj( pDocShell, bIsRange ));
+ }
+ break;
+ case Type::CHDATAPROV:
+ if (pDocShell)
+ xRet = *new ScChart2DataProvider( &pDocShell->GetDocument() );
+ break;
+ case Type::CHART_PIVOTTABLE_DATAPROVIDER:
+ if (pDocShell)
+ xRet = *new sc::PivotTableDataProvider(pDocShell->GetDocument());
+ break;
+ case Type::FORMULAPARS:
+ if (pDocShell)
+ xRet.set(static_cast<sheet::XFormulaParser*>(new ScFormulaParserObj( pDocShell )));
+ break;
+ case Type::OPCODEMAPPER:
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScAddress aAddress;
+ ScCompiler* pComp = new ScCompiler(rDoc, aAddress, rDoc.GetGrammar());
+ xRet.set(static_cast<sheet::XFormulaOpCodeMapper*>(new ScFormulaOpCodeMapperObj(::std::unique_ptr<formula::FormulaCompiler> (pComp))));
+ break;
+ }
+ break;
+#if HAVE_FEATURE_SCRIPTING
+ case Type::VBAOBJECTPROVIDER:
+ if (pDocShell && pDocShell->GetDocument().IsInVBAMode())
+ {
+ xRet.set(static_cast<container::XNameAccess*>(new ScVbaObjectForCodeNameProvider( pDocShell )));
+ }
+ break;
+ case Type::VBACODENAMEPROVIDER:
+ if ( pDocShell && isInVBAMode( *pDocShell ) )
+ {
+ xRet.set(static_cast<document::XCodeNameQuery*>(new ScVbaCodeNameProvider(*pDocShell)));
+ }
+ break;
+ case Type::VBAGLOBALS:
+ if (pDocShell)
+ {
+ uno::Any aGlobs;
+ if ( !pDocShell->GetBasicManager()->GetGlobalUNOConstant( "VBAGlobals", aGlobs ) )
+ {
+ uno::Sequence< uno::Any > aArgs{ uno::Any(uno::Reference(static_cast<css::sheet::XSpreadsheetDocument*>(pDocShell->GetModel()))) };
+ xRet = ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( "ooo.vba.excel.Globals", aArgs );
+ pDocShell->GetBasicManager()->SetGlobalUNOConstant( "VBAGlobals", uno::Any( xRet ) );
+ BasicManager* pAppMgr = SfxApplication::GetBasicManager();
+ if ( pAppMgr )
+ pAppMgr->SetGlobalUNOConstant( "ThisExcelDoc", aArgs[ 0 ] );
+
+ // create the VBA document event processor
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents(
+ ::ooo::vba::createVBAUnoAPIServiceWithArgs( pDocShell, "com.sun.star.script.vba.VBASpreadsheetEventProcessor", aArgs ), uno::UNO_QUERY );
+ pDocShell->GetDocument().SetVbaEventProcessor( xVbaEvents );
+ }
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return xRet;
+}
+
+uno::Sequence<OUString> ScServiceProvider::GetAllServiceNames()
+{
+ const sal_uInt16 nEntries = SAL_N_ELEMENTS(aProvNamesId);
+ uno::Sequence<OUString> aRet(nEntries);
+ OUString* pArray = aRet.getArray();
+ for (sal_uInt16 i = 0; i < nEntries; i++)
+ {
+ pArray[i] = aProvNamesId[i].pName;
+ }
+ return aRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/shapeuno.cxx b/sc/source/ui/unoobj/shapeuno.cxx
new file mode 100644
index 0000000000..5d1ecadb08
--- /dev/null
+++ b/sc/source/ui/unoobj/shapeuno.cxx
@@ -0,0 +1,1469 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+#include <svtools/unoevent.hxx>
+#include <svtools/unoimap.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/event.hxx>
+#include <editeng/unofield.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+
+#include <shapeuno.hxx>
+#include <cellsuno.hxx>
+#include <textuno.hxx>
+#include <fielduno.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <userdat.hxx>
+#include <unonames.hxx>
+#include <styleuno.hxx>
+
+using namespace ::com::sun::star;
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetShapeMap()
+{
+ static const SfxItemPropertyMapEntry aShapeMap_Impl[] =
+ {
+ { SC_UNONAME_ANCHOR, 0, cppu::UnoType<uno::XInterface>::get(), 0, 0 },
+ { SC_UNONAME_RESIZE_WITH_CELL, 0, cppu::UnoType<sal_Bool>::get(), 0, 0 },
+ { SC_UNONAME_HORIPOS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_IMAGEMAP, 0, cppu::UnoType<container::XIndexContainer>::get(), 0, 0 },
+ { SC_UNONAME_VERTPOS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_MOVEPROTECT, 0, cppu::UnoType<sal_Bool>::get(), 0, 0 },
+ { SC_UNONAME_HYPERLINK, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_URL, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_STYLE, 0, cppu::UnoType<style::XStyle>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
+ };
+ return aShapeMap_Impl;
+}
+
+const SvEventDescription* ScShapeObj::GetSupportedMacroItems()
+{
+ static const SvEventDescription aMacroDescriptionsImpl[] =
+ {
+ { SvMacroItemId::NONE, nullptr }
+ };
+ return aMacroDescriptionsImpl;
+}
+ScMacroInfo* ScShapeObj_getShapeHyperMacroInfo( const ScShapeObj* pShape, bool bCreate = false )
+{
+ if( pShape )
+ if( SdrObject* pObj = pShape->GetSdrObject() )
+ return ScDrawLayer::GetMacroInfo( pObj, bCreate );
+ return nullptr;
+}
+
+ScShapeObj::ScShapeObj( uno::Reference<drawing::XShape>& xShape ) :
+ pShapePropertySet(nullptr),
+ pShapePropertyState(nullptr),
+ bIsTextShape(false),
+ bIsNoteCaption(false)
+{
+ osl_atomic_increment( &m_refCount );
+
+ {
+ mxShapeAgg.set( xShape, uno::UNO_QUERY );
+ // extra block to force deletion of the temporary before setDelegator
+ }
+
+ if (mxShapeAgg.is())
+ {
+ xShape = nullptr; // during setDelegator, mxShapeAgg must be the only ref
+
+ mxShapeAgg->setDelegator( getXWeak() );
+
+ xShape.set(uno::Reference<drawing::XShape>( mxShapeAgg, uno::UNO_QUERY ));
+
+ bIsTextShape = ( comphelper::getFromUnoTunnel<SvxUnoTextBase>( mxShapeAgg ) != nullptr );
+ }
+
+ {
+ SdrObject* pObj = GetSdrObject();
+ if ( pObj )
+ {
+ bIsNoteCaption = ScDrawLayer::IsNoteCaption( pObj );
+ }
+ }
+
+ osl_atomic_decrement( &m_refCount );
+}
+
+ScShapeObj::~ScShapeObj()
+{
+// if (mxShapeAgg.is())
+// mxShapeAgg->setDelegator(uno::Reference<uno::XInterface>());
+}
+
+// XInterface
+
+uno::Any SAL_CALL ScShapeObj::queryInterface( const uno::Type& rType )
+{
+ uno::Any aRet = ScShapeObj_Base::queryInterface( rType );
+
+ if ( !aRet.hasValue() && bIsTextShape )
+ aRet = ScShapeObj_TextBase::queryInterface( rType );
+
+ if ( !aRet.hasValue() && bIsNoteCaption )
+ aRet = ScShapeObj_ChildBase::queryInterface( rType );
+
+ if ( !aRet.hasValue() && mxShapeAgg.is() )
+ aRet = mxShapeAgg->queryAggregation( rType );
+
+ return aRet;
+}
+
+void SAL_CALL ScShapeObj::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL ScShapeObj::release() noexcept
+{
+ OWeakObject::release();
+}
+
+void ScShapeObj::GetShapePropertySet()
+{
+ // #i61908# Store the result of queryAggregation in a member.
+ // The reference in mxShapeAgg is kept for this object's lifetime, so the pointer is always valid.
+
+ if (!pShapePropertySet)
+ {
+ uno::Reference<beans::XPropertySet> xProp;
+ if ( mxShapeAgg.is() )
+ mxShapeAgg->queryAggregation( cppu::UnoType<beans::XPropertySet>::get()) >>= xProp;
+ pShapePropertySet = xProp.get();
+ }
+}
+
+void ScShapeObj::GetShapePropertyState()
+{
+ // #i61908# Store the result of queryAggregation in a member.
+ // The reference in mxShapeAgg is kept for this object's lifetime, so the pointer is always valid.
+
+ if (!pShapePropertyState)
+ {
+ uno::Reference<beans::XPropertyState> xState;
+ if ( mxShapeAgg.is() )
+ mxShapeAgg->queryAggregation( cppu::UnoType<beans::XPropertyState>::get()) >>= xState;
+ pShapePropertyState = xState.get();
+ }
+}
+
+static uno::Reference<lang::XComponent> lcl_GetComponent( const uno::Reference<uno::XAggregation>& xAgg )
+{
+ uno::Reference<lang::XComponent> xRet;
+ if ( xAgg.is() )
+ xAgg->queryAggregation( cppu::UnoType<lang::XComponent>::get()) >>= xRet;
+ return xRet;
+}
+
+static uno::Reference<text::XText> lcl_GetText( const uno::Reference<uno::XAggregation>& xAgg )
+{
+ uno::Reference<text::XText> xRet;
+ if ( xAgg.is() )
+ xAgg->queryAggregation( cppu::UnoType<text::XText>::get()) >>= xRet;
+ return xRet;
+}
+
+static uno::Reference<text::XSimpleText> lcl_GetSimpleText( const uno::Reference<uno::XAggregation>& xAgg )
+{
+ uno::Reference<text::XSimpleText> xRet;
+ if ( xAgg.is() )
+ xAgg->queryAggregation( cppu::UnoType<text::XSimpleText>::get()) >>= xRet;
+ return xRet;
+}
+
+static uno::Reference<text::XTextRange> lcl_GetTextRange( const uno::Reference<uno::XAggregation>& xAgg )
+{
+ uno::Reference<text::XTextRange> xRet;
+ if ( xAgg.is() )
+ xAgg->queryAggregation( cppu::UnoType<text::XTextRange>::get()) >>= xRet;
+ return xRet;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScShapeObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+
+ // #i61527# cache property set info for this object
+ if ( !mxPropSetInfo.is() )
+ {
+ // mix own and aggregated properties:
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ {
+ uno::Reference<beans::XPropertySetInfo> xAggInfo(pShapePropertySet->getPropertySetInfo());
+ const uno::Sequence<beans::Property> aPropSeq(xAggInfo->getProperties());
+ mxPropSetInfo.set(new SfxExtItemPropertySetInfo( lcl_GetShapeMap(), aPropSeq ));
+ }
+ }
+ return mxPropSetInfo;
+}
+
+static bool lcl_GetPageNum( const SdrPage* pPage, SdrModel& rModel, SCTAB& rNum )
+{
+ sal_uInt16 nCount = rModel.GetPageCount();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if ( rModel.GetPage(i) == pPage )
+ {
+ rNum = static_cast<SCTAB>(i);
+ return true;
+ }
+
+ return false;
+}
+
+static bool lcl_GetCaptionPoint( const uno::Reference< drawing::XShape >& xShape, awt::Point& rCaptionPoint )
+{
+ bool bReturn = false;
+ OUString sType(xShape->getShapeType());
+ bool bCaptionShape( sType == "com.sun.star.drawing.CaptionShape" );
+ if (bCaptionShape)
+ {
+ uno::Reference < beans::XPropertySet > xShapeProp (xShape, uno::UNO_QUERY);
+ if (xShapeProp.is())
+ {
+ xShapeProp->getPropertyValue("CaptionPoint") >>= rCaptionPoint;
+ bReturn = true;
+ }
+ }
+ return bReturn;
+}
+
+static ScRange lcl_GetAnchorCell( const uno::Reference< drawing::XShape >& xShape, const ScDocument* pDoc, SCTAB nTab,
+ awt::Point& rUnoPoint, awt::Size& rUnoSize, awt::Point& rCaptionPoint )
+{
+ ScRange aReturn;
+ rUnoPoint = xShape->getPosition();
+ bool bCaptionShape(lcl_GetCaptionPoint(xShape, rCaptionPoint));
+ if (pDoc->IsNegativePage(nTab))
+ {
+ rUnoSize = xShape->getSize();
+ rUnoPoint.X += rUnoSize.Width; // the right top point is base
+ if (bCaptionShape)
+ {
+ if (rCaptionPoint.X > 0 && rCaptionPoint.X > rUnoSize.Width)
+ rUnoPoint.X += rCaptionPoint.X - rUnoSize.Width;
+ if (rCaptionPoint.Y < 0)
+ rUnoPoint.Y += rCaptionPoint.Y;
+ }
+ aReturn = pDoc->GetRange( nTab, tools::Rectangle( VCLPoint(rUnoPoint), VCLPoint(rUnoPoint) ));
+ }
+ else
+ {
+ if (bCaptionShape)
+ {
+ if (rCaptionPoint.X < 0)
+ rUnoPoint.X += rCaptionPoint.X;
+ if (rCaptionPoint.Y < 0)
+ rUnoPoint.Y += rCaptionPoint.Y;
+ }
+ aReturn = pDoc->GetRange( nTab, tools::Rectangle( VCLPoint(rUnoPoint), VCLPoint(rUnoPoint) ));
+ }
+
+ return aReturn;
+}
+
+static awt::Point lcl_GetRelativePos( const uno::Reference< drawing::XShape >& xShape, const ScDocument* pDoc, SCTAB nTab, ScRange& rRange,
+ awt::Size& rUnoSize, awt::Point& rCaptionPoint)
+{
+ awt::Point aUnoPoint;
+ rRange = lcl_GetAnchorCell(xShape, pDoc, nTab, aUnoPoint, rUnoSize, rCaptionPoint);
+ tools::Rectangle aRect(pDoc->GetMMRect( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aStart.Tab() ));
+ Point aPoint = pDoc->IsNegativePage(nTab) ? aRect.TopRight() : aRect.TopLeft();
+ aUnoPoint.X -= aPoint.X();
+ aUnoPoint.Y -= aPoint.Y();
+ return aUnoPoint;
+}
+
+void SAL_CALL ScShapeObj::setPropertyValue(const OUString& aPropertyName, const uno::Any& aValue)
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == SC_UNONAME_ANCHOR )
+ {
+ uno::Reference<sheet::XCellRangeAddressable> xRangeAdd(aValue, uno::UNO_QUERY);
+ if (!xRangeAdd.is())
+ throw lang::IllegalArgumentException("only XCell or XSpreadsheet objects allowed", getXWeak(), 0);
+
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ ScDocument* pDoc(rModel.GetDocument());
+
+ if ( pDoc )
+ {
+ if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ table::CellRangeAddress aAddress = xRangeAdd->getRangeAddress();
+ if (nTab == aAddress.Sheet)
+ {
+ tools::Rectangle aRect(pDoc->GetMMRect( static_cast<SCCOL>(aAddress.StartColumn), static_cast<SCROW>(aAddress.StartRow),
+ static_cast<SCCOL>(aAddress.EndColumn), static_cast<SCROW>(aAddress.EndRow), aAddress.Sheet ));
+ awt::Point aRelPoint;
+ uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
+ if (xShape.is())
+ {
+ Point aPoint;
+ Point aEndPoint;
+ if (pDoc->IsNegativePage(nTab))
+ {
+ aPoint = aRect.TopRight();
+ aEndPoint = aRect.BottomLeft();
+ }
+ else
+ {
+ aPoint = aRect.TopLeft();
+ aEndPoint = aRect.BottomRight();
+ }
+ awt::Size aUnoSize;
+ awt::Point aCaptionPoint;
+ ScRange aRange;
+ aRelPoint = lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint );
+ awt::Point aUnoPoint(aRelPoint);
+
+ aUnoPoint.X += aPoint.X();
+ aUnoPoint.Y += aPoint.Y();
+
+ if ( aUnoPoint.Y > aEndPoint.Y() )
+ aUnoPoint.Y = aEndPoint.Y() - 2;
+ if (pDoc->IsNegativePage(nTab))
+ {
+ if ( aUnoPoint.X < aEndPoint.X() )
+ aUnoPoint.X = aEndPoint.X() + 2;
+ aUnoPoint.X -= aUnoSize.Width;
+ // remove difference to caption point
+ if (aCaptionPoint.X > 0 && aCaptionPoint.X > aUnoSize.Width)
+ aUnoPoint.X -= aCaptionPoint.X - aUnoSize.Width;
+ }
+ else
+ {
+ if ( aUnoPoint.X > aEndPoint.X() )
+ aUnoPoint.X = aEndPoint.X() - 2;
+ if (aCaptionPoint.X < 0)
+ aUnoPoint.X -= aCaptionPoint.X;
+ }
+ if (aCaptionPoint.Y < 0)
+ aUnoPoint.Y -= aCaptionPoint.Y;
+
+ xShape->setPosition(aUnoPoint);
+ pDocSh->SetModified();
+ }
+
+ if (aAddress.StartRow != aAddress.EndRow) //should be a Spreadsheet
+ {
+ OSL_ENSURE(aAddress.StartRow == 0 && aAddress.EndRow == pDoc->MaxRow() &&
+ aAddress.StartColumn == 0 && aAddress.EndColumn == pDoc->MaxCol(), "here should be a XSpreadsheet");
+ ScDrawLayer::SetPageAnchored(*pObj);
+ }
+ else
+ {
+ OSL_ENSURE(aAddress.StartRow == aAddress.EndRow &&
+ aAddress.StartColumn == aAddress.EndColumn, "here should be a XCell");
+ ScDrawObjData aAnchor;
+ aAnchor.maStart = ScAddress(aAddress.StartColumn, aAddress.StartRow, aAddress.Sheet);
+ aAnchor.maStartOffset = Point(aRelPoint.X, aRelPoint.Y);
+ ScDrawObjData* pDrawObjData = ScDrawLayer::GetObjData(pObj);
+ if (pDrawObjData)
+ aAnchor.mbResizeWithCell = pDrawObjData->mbResizeWithCell;
+ //Uno sets the Anchor in terms of the unrotated shape, not much we can do
+ //about that since uno also displays the shape geometry in terms of the unrotated
+ //shape. #TODO think about changing the anchoring behaviour here too
+ //Currently we've only got a start anchor, not an end-anchor, so generate that now
+ ScDrawLayer::UpdateCellAnchorFromPositionEnd(*pObj, aAnchor, *pDoc, aAddress.Sheet);
+ ScDrawLayer::SetCellAnchored(*pObj, aAnchor);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+ else if ( aPropertyName == SC_UNONAME_RESIZE_WITH_CELL )
+ {
+ SdrObject* pObj = GetSdrObject();
+ if (!pObj)
+ return;
+ ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObj);
+
+ // Nothing to do if anchored to page
+ if (aAnchorType == SCA_PAGE)
+ return;
+
+ ScDrawObjData* pDrawObjData = ScDrawLayer::GetObjData(pObj);
+ if (!pDrawObjData)
+ return;
+
+ aValue >>= pDrawObjData->mbResizeWithCell;
+ ScDrawLayer::SetCellAnchored(*pObj, *pDrawObjData);
+ }
+ else if ( aPropertyName == SC_UNONAME_IMAGEMAP )
+ {
+ SdrObject* pObj = GetSdrObject();
+ if ( pObj )
+ {
+ ImageMap aImageMap;
+ uno::Reference< uno::XInterface > xImageMapInt(aValue, uno::UNO_QUERY);
+
+ if( !xImageMapInt.is() || !SvUnoImageMap_fillImageMap( xImageMapInt, aImageMap ) )
+ throw lang::IllegalArgumentException();
+
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo(pObj);
+ if( pIMapInfo )
+ {
+ // replace existing image map
+ pIMapInfo->SetImageMap( aImageMap );
+ }
+ else
+ {
+ // insert new user data with image map
+ pObj->AppendUserData(std::unique_ptr<SdrObjUserData>(new SvxIMapInfo(aImageMap) ));
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_HORIPOS )
+ {
+ sal_Int32 nPos = 0;
+ if (aValue >>= nPos)
+ {
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ ScDocument* pDoc = rModel.GetDocument();
+ if ( pDoc )
+ {
+ if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
+ {
+ uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
+ if (xShape.is())
+ {
+ if (ScDrawLayer::GetAnchorType(*pObj) == SCA_PAGE)
+ {
+ awt::Point aPoint(xShape->getPosition());
+ awt::Size aSize(xShape->getSize());
+ awt::Point aCaptionPoint;
+ if (pDoc->IsNegativePage(nTab))
+ {
+ nPos *= -1;
+ nPos -= aSize.Width;
+ }
+ if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
+ {
+ if (pDoc->IsNegativePage(nTab))
+ {
+ if (aCaptionPoint.X > 0 && aCaptionPoint.X > aSize.Width)
+ nPos -= aCaptionPoint.X - aSize.Width;
+ }
+ else
+ {
+ if (aCaptionPoint.X < 0)
+ nPos -= aCaptionPoint.X;
+ }
+ }
+ aPoint.X = nPos;
+ xShape->setPosition(aPoint);
+ pDocSh->SetModified();
+ }
+ else if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL
+ || ScDrawLayer::GetAnchorType(*pObj)
+ == SCA_CELL_RESIZE)
+ {
+ awt::Size aUnoSize;
+ awt::Point aCaptionPoint;
+ ScRange aRange;
+ awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
+ tools::Rectangle aRect(pDoc->GetMMRect( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab() ));
+ if (pDoc->IsNegativePage(nTab))
+ {
+ aUnoPoint.X = -nPos;
+ Point aPoint(aRect.TopRight());
+ Point aEndPoint(aRect.BottomLeft());
+ aUnoPoint.X += aPoint.X();
+ if (aUnoPoint.X < aEndPoint.X())
+ aUnoPoint.X = aEndPoint.X() + 2;
+ aUnoPoint.X -= aUnoSize.Width;
+ if (aCaptionPoint.X > 0 && aCaptionPoint.X > aUnoSize.Width)
+ aUnoPoint.X -= aCaptionPoint.X - aUnoSize.Width;
+ }
+ else
+ {
+ aUnoPoint.X = nPos;
+ Point aPoint(aRect.TopLeft());
+ Point aEndPoint(aRect.BottomRight());
+ aUnoPoint.X += aPoint.X();
+ if (aUnoPoint.X > aEndPoint.X())
+ aUnoPoint.X = aEndPoint.X() - 2;
+ if (aCaptionPoint.X < 0)
+ aUnoPoint.X -= aCaptionPoint.X;
+ }
+ aUnoPoint.Y = xShape->getPosition().Y;
+ xShape->setPosition(aUnoPoint);
+ pDocSh->SetModified();
+ }
+ else
+ {
+ OSL_FAIL("unknown anchor type");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_VERTPOS )
+ {
+ sal_Int32 nPos = 0;
+ if (aValue >>= nPos)
+ {
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ ScDocument* pDoc = rModel.GetDocument();
+ if ( pDoc )
+ {
+ if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
+ {
+ uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
+ if (xShape.is())
+ {
+ if (ScDrawLayer::GetAnchorType(*pObj) == SCA_PAGE)
+ {
+ awt::Point aPoint = xShape->getPosition();
+ awt::Point aCaptionPoint;
+ if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
+ {
+ if (aCaptionPoint.Y < 0)
+ nPos -= aCaptionPoint.Y;
+ }
+ aPoint.Y = nPos;
+ xShape->setPosition(aPoint);
+ pDocSh->SetModified();
+ }
+ else if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL
+ || ScDrawLayer::GetAnchorType(*pObj)
+ == SCA_CELL_RESIZE)
+ {
+ awt::Size aUnoSize;
+ awt::Point aCaptionPoint;
+ ScRange aRange;
+ awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
+ tools::Rectangle aRect(pDoc->GetMMRect( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab() ));
+ Point aPoint(aRect.TopRight());
+ Point aEndPoint(aRect.BottomLeft());
+ aUnoPoint.Y = nPos;
+ aUnoPoint.Y += aPoint.Y();
+ if (aUnoPoint.Y > aEndPoint.Y())
+ aUnoPoint.Y = aEndPoint.Y() - 2;
+ if (aCaptionPoint.Y < 0)
+ aUnoPoint.Y -= aCaptionPoint.Y;
+ aUnoPoint.X = xShape->getPosition().X;
+ xShape->setPosition(aUnoPoint);
+ pDocSh->SetModified();
+ }
+ else
+ {
+ OSL_FAIL("unknown anchor type");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_HYPERLINK ||
+ aPropertyName == SC_UNONAME_URL )
+ {
+ OUString sHyperlink;
+ SdrObject* pObj = GetSdrObject();
+ if (pObj && (aValue >>= sHyperlink))
+ pObj->setHyperlink(sHyperlink);
+ }
+ else if ( aPropertyName == SC_UNONAME_MOVEPROTECT )
+ {
+ if( SdrObject* pObj = GetSdrObject() )
+ {
+ bool aProt = false;
+ if( aValue >>= aProt )
+ pObj->SetMoveProtect( aProt );
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_STYLE )
+ {
+ if (SdrObject* pObj = GetSdrObject())
+ {
+ uno::Reference<style::XStyle> xStyle(aValue, uno::UNO_QUERY);
+ auto pStyleSheetObj = dynamic_cast<ScStyleObj*>(xStyle.get());
+ if (!pStyleSheetObj)
+ throw lang::IllegalArgumentException();
+
+ auto pStyleSheet = pStyleSheetObj->GetStyle_Impl();
+ auto pOldStyleSheet = pObj->GetStyleSheet();
+
+ if (pStyleSheet != pOldStyleSheet)
+ pObj->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), false);
+ }
+ }
+ else
+ {
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ pShapePropertySet->setPropertyValue( aPropertyName, aValue );
+ }
+}
+
+uno::Any SAL_CALL ScShapeObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aAny;
+ if ( aPropertyName == SC_UNONAME_ANCHOR )
+ {
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ ScDocument* pDoc = rModel.GetDocument();
+ if ( pDoc )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
+ {
+ uno::Reference< uno::XInterface > xAnchor;
+ if (ScDrawObjData *pAnchor = ScDrawLayer::GetObjDataTab(pObj, nTab))
+ xAnchor.set(cppu::getXWeak(new ScCellObj( pDocSh, pAnchor->maStart)));
+ else
+ xAnchor.set(cppu::getXWeak(new ScTableSheetObj( pDocSh, nTab )));
+ aAny <<= xAnchor;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_RESIZE_WITH_CELL)
+ {
+ bool bIsResizeWithCell = false;
+ SdrObject* pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScAnchorType anchorType = ScDrawLayer::GetAnchorType(*pObj);
+ bIsResizeWithCell = (anchorType == SCA_CELL_RESIZE);
+ }
+ aAny <<= bIsResizeWithCell;
+ }
+ else if ( aPropertyName == SC_UNONAME_IMAGEMAP )
+ {
+ uno::Reference< uno::XInterface > xImageMap;
+ SdrObject* pObj = GetSdrObject();
+ if ( pObj )
+ {
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo(GetSdrObject());
+ if( pIMapInfo )
+ {
+ const ImageMap& rIMap = pIMapInfo->GetImageMap();
+ xImageMap.set(SvUnoImageMap_createInstance( rIMap, GetSupportedMacroItems() ));
+ }
+ else
+ xImageMap = SvUnoImageMap_createInstance();
+ }
+ aAny <<= uno::Reference< container::XIndexContainer >::query( xImageMap );
+ }
+ else if ( aPropertyName == SC_UNONAME_HORIPOS )
+ {
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ ScDocument* pDoc = rModel.GetDocument();
+ if ( pDoc )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
+ if (xShape.is())
+ {
+ if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL
+ || ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL_RESIZE)
+ {
+ awt::Size aUnoSize;
+ awt::Point aCaptionPoint;
+ ScRange aRange;
+ awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
+ if (pDoc->IsNegativePage(nTab))
+ aUnoPoint.X *= -1;
+ aAny <<= aUnoPoint.X;
+ }
+ else
+ {
+ awt::Point aCaptionPoint;
+ awt::Point aUnoPoint(xShape->getPosition());
+ awt::Size aUnoSize(xShape->getSize());
+ if (pDoc->IsNegativePage(nTab))
+ {
+ aUnoPoint.X *= -1;
+ aUnoPoint.X -= aUnoSize.Width;
+ }
+ if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
+ {
+ if (pDoc->IsNegativePage(nTab))
+ {
+ if (aCaptionPoint.X > 0 && aCaptionPoint.X > aUnoSize.Width)
+ aUnoPoint.X -= aCaptionPoint.X - aUnoSize.Width;
+ }
+ else
+ {
+ if (aCaptionPoint.X < 0)
+ aUnoPoint.X += aCaptionPoint.X;
+ }
+ }
+ aAny <<= aUnoPoint.X;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_VERTPOS )
+ {
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ ScDocument* pDoc = rModel.GetDocument();
+ if ( pDoc )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
+ if (xShape.is())
+ {
+ if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL
+ || ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL_RESIZE)
+ {
+ awt::Size aUnoSize;
+ awt::Point aCaptionPoint;
+ ScRange aRange;
+ awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
+
+ aAny <<= aUnoPoint.Y;
+ }
+ else
+ {
+ awt::Point aUnoPoint(xShape->getPosition());
+ awt::Point aCaptionPoint;
+ if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
+ {
+ if (aCaptionPoint.Y < 0)
+ aUnoPoint.Y += aCaptionPoint.Y;
+ }
+ aAny <<= aUnoPoint.Y;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_HYPERLINK ||
+ aPropertyName == SC_UNONAME_URL )
+ {
+ OUString sHlink;
+ if (SdrObject* pObj = GetSdrObject())
+ sHlink = pObj->getHyperlink();
+ aAny <<= sHlink;
+ }
+ else if ( aPropertyName == SC_UNONAME_MOVEPROTECT )
+ {
+ bool aProt = false;
+ if ( SdrObject* pObj = GetSdrObject() )
+ aProt = pObj->IsMoveProtect();
+ aAny <<= aProt;
+ }
+ else if ( aPropertyName == SC_UNONAME_STYLE )
+ {
+ if (SdrObject* pObj = GetSdrObject())
+ {
+ if (auto pStyleSheet = pObj->GetStyleSheet())
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ ScDocument* pDoc = rModel.GetDocument();
+ aAny <<= uno::Reference<style::XStyle>(new ScStyleObj(
+ pDoc ? pDoc->GetDocumentShell() : nullptr,
+ SfxStyleFamily::Frame, pStyleSheet->GetName()));
+ }
+ }
+ }
+ else
+ {
+ if(!pShapePropertySet) //performance consideration
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ aAny = pShapePropertySet->getPropertyValue( aPropertyName );
+ }
+
+ return aAny;
+}
+
+void SAL_CALL ScShapeObj::addPropertyChangeListener( const OUString& aPropertyName,
+ const uno::Reference<beans::XPropertyChangeListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ pShapePropertySet->addPropertyChangeListener( aPropertyName, aListener );
+}
+
+void SAL_CALL ScShapeObj::removePropertyChangeListener( const OUString& aPropertyName,
+ const uno::Reference<beans::XPropertyChangeListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ pShapePropertySet->removePropertyChangeListener( aPropertyName, aListener );
+}
+
+void SAL_CALL ScShapeObj::addVetoableChangeListener( const OUString& aPropertyName,
+ const uno::Reference<beans::XVetoableChangeListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ pShapePropertySet->addVetoableChangeListener( aPropertyName, aListener );
+}
+
+void SAL_CALL ScShapeObj::removeVetoableChangeListener( const OUString& aPropertyName,
+ const uno::Reference<beans::XVetoableChangeListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ pShapePropertySet->removeVetoableChangeListener( aPropertyName, aListener );
+}
+
+// XPropertyState
+
+beans::PropertyState SAL_CALL ScShapeObj::getPropertyState( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ beans::PropertyState eRet = beans::PropertyState_DIRECT_VALUE;
+ if ( aPropertyName == SC_UNONAME_IMAGEMAP )
+ {
+ // ImageMap is always "direct"
+ }
+ else if ( aPropertyName == SC_UNONAME_ANCHOR )
+ {
+ // Anchor is always "direct"
+ }
+ else if ( aPropertyName == SC_UNONAME_HORIPOS )
+ {
+ // HoriPos is always "direct"
+ }
+ else if ( aPropertyName == SC_UNONAME_VERTPOS )
+ {
+ // VertPos is always "direct"
+ }
+ else
+ {
+ GetShapePropertyState();
+ if (pShapePropertyState)
+ eRet = pShapePropertyState->getPropertyState( aPropertyName );
+ }
+
+ return eRet;
+}
+
+uno::Sequence<beans::PropertyState> SAL_CALL ScShapeObj::getPropertyStates(
+ const uno::Sequence<OUString>& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+
+ // simple loop to get own and aggregated states
+
+ uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength());
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.getArray(),
+ [this](const OUString& rName) -> beans::PropertyState { return getPropertyState(rName); });
+ return aRet;
+}
+
+void SAL_CALL ScShapeObj::setPropertyToDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == SC_UNONAME_IMAGEMAP )
+ {
+ SdrObject* pObj = GetSdrObject();
+ if ( pObj )
+ {
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo(pObj);
+ if( pIMapInfo )
+ {
+ ImageMap aEmpty;
+ pIMapInfo->SetImageMap( aEmpty ); // replace with empty image map
+ }
+ else
+ {
+ // nothing to do (no need to insert user data for an empty map)
+ }
+ }
+ }
+ else
+ {
+ GetShapePropertyState();
+ if (pShapePropertyState)
+ pShapePropertyState->setPropertyToDefault( aPropertyName );
+ }
+}
+
+uno::Any SAL_CALL ScShapeObj::getPropertyDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aAny;
+ if ( aPropertyName == SC_UNONAME_IMAGEMAP )
+ {
+ // default: empty ImageMap
+ uno::Reference< uno::XInterface > xImageMap(SvUnoImageMap_createInstance());
+ aAny <<= uno::Reference< container::XIndexContainer >::query( xImageMap );
+ }
+ else
+ {
+ GetShapePropertyState();
+ if (pShapePropertyState)
+ aAny = pShapePropertyState->getPropertyDefault( aPropertyName );
+ }
+
+ return aAny;
+}
+
+// XTextContent
+
+void SAL_CALL ScShapeObj::attach( const uno::Reference<text::XTextRange>& /* xTextRange */ )
+{
+ throw lang::IllegalArgumentException(); // anchor cannot be changed
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getAnchor()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextRange> xRet;
+
+ SdrObject* pObj = GetSdrObject();
+ if( pObj )
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+ ScDocument* pDoc = rModel.GetDocument();
+
+ if ( pPage && pDoc )
+ {
+ if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ Point aPos(pObj->GetCurrentBoundRect().TopLeft());
+ ScRange aRange(pDoc->GetRange( nTab, tools::Rectangle( aPos, aPos ) ));
+
+ // anchor is always the cell
+
+ xRet.set(new ScCellObj( pDocSh, aRange.aStart ));
+ }
+ }
+ }
+ }
+
+ return xRet;
+}
+
+// XComponent
+
+void SAL_CALL ScShapeObj::dispose()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<lang::XComponent> xAggComp(lcl_GetComponent(mxShapeAgg));
+ if ( xAggComp.is() )
+ xAggComp->dispose();
+}
+
+void SAL_CALL ScShapeObj::addEventListener(
+ const uno::Reference<lang::XEventListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<lang::XComponent> xAggComp(lcl_GetComponent(mxShapeAgg));
+ if ( xAggComp.is() )
+ xAggComp->addEventListener(xListener);
+}
+
+void SAL_CALL ScShapeObj::removeEventListener(
+ const uno::Reference<lang::XEventListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<lang::XComponent> xAggComp(lcl_GetComponent(mxShapeAgg));
+ if ( xAggComp.is() )
+ xAggComp->removeEventListener(xListener);
+}
+
+// XText
+// (special handling for ScCellFieldObj)
+
+static void lcl_CopyOneProperty( beans::XPropertySet& rDest, beans::XPropertySet& rSource, const OUString& aNameStr )
+{
+ try
+ {
+ rDest.setPropertyValue( aNameStr, rSource.getPropertyValue( aNameStr ) );
+ }
+ catch (uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "Exception in text field");
+ }
+}
+
+void SAL_CALL ScShapeObj::insertTextContent( const uno::Reference<text::XTextRange>& xRange,
+ const uno::Reference<text::XTextContent>& xContent,
+ sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextContent> xEffContent;
+
+ ScEditFieldObj* pCellField = dynamic_cast<ScEditFieldObj*>( xContent.get() );
+ if ( pCellField )
+ {
+ // createInstance("TextField.URL") from the document creates a ScCellFieldObj.
+ // To insert it into drawing text, a SvxUnoTextField is needed instead.
+ // The ScCellFieldObj object is left in non-inserted state.
+
+ rtl::Reference<SvxUnoTextField> pDrawField = new SvxUnoTextField( text::textfield::Type::URL );
+ xEffContent.set(pDrawField);
+ lcl_CopyOneProperty( *pDrawField, *pCellField, SC_UNONAME_URL );
+ lcl_CopyOneProperty( *pDrawField, *pCellField, SC_UNONAME_REPR );
+ lcl_CopyOneProperty( *pDrawField, *pCellField, SC_UNONAME_TARGET );
+ }
+ else
+ xEffContent.set(xContent);
+
+ uno::Reference<text::XText> xAggText(lcl_GetText(mxShapeAgg));
+ if ( xAggText.is() )
+ xAggText->insertTextContent( xRange, xEffContent, bAbsorb );
+}
+
+void SAL_CALL ScShapeObj::removeTextContent( const uno::Reference<text::XTextContent>& xContent )
+{
+ SolarMutexGuard aGuard;
+
+ // ScCellFieldObj can't be used here.
+
+ uno::Reference<text::XText> xAggText(lcl_GetText(mxShapeAgg));
+ if ( xAggText.is() )
+ xAggText->removeTextContent( xContent );
+}
+
+// XSimpleText (parent of XText)
+// Use own SvxUnoTextCursor subclass - everything is just passed to aggregated object
+
+uno::Reference<text::XTextCursor> SAL_CALL ScShapeObj::createTextCursor()
+{
+ SolarMutexGuard aGuard;
+
+ if ( mxShapeAgg.is() )
+ {
+ // ScDrawTextCursor must be used to ensure the ScShapeObj is returned by getText
+
+ SvxUnoTextBase* pText = comphelper::getFromUnoTunnel<SvxUnoTextBase>( mxShapeAgg );
+ if (pText)
+ return new ScDrawTextCursor( this, *pText );
+ }
+
+ return uno::Reference<text::XTextCursor>();
+}
+
+uno::Reference<text::XTextCursor> SAL_CALL ScShapeObj::createTextCursorByRange(
+ const uno::Reference<text::XTextRange>& aTextPosition )
+{
+ SolarMutexGuard aGuard;
+
+ if ( mxShapeAgg.is() && aTextPosition.is() )
+ {
+ // ScDrawTextCursor must be used to ensure the ScShapeObj is returned by getText
+
+ SvxUnoTextBase* pText = comphelper::getFromUnoTunnel<SvxUnoTextBase>( mxShapeAgg );
+ SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( aTextPosition );
+ if ( pText && pRange )
+ {
+ rtl::Reference<SvxUnoTextCursor> pCursor = new ScDrawTextCursor( this, *pText );
+ pCursor->SetSelection( pRange->GetSelection() );
+ return pCursor;
+ }
+ }
+
+ return uno::Reference<text::XTextCursor>();
+}
+
+void SAL_CALL ScShapeObj::insertString( const uno::Reference<text::XTextRange>& xRange,
+ const OUString& aString, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XSimpleText> xAggSimpleText(lcl_GetSimpleText(mxShapeAgg));
+ if ( !xAggSimpleText.is() )
+ throw uno::RuntimeException();
+
+ xAggSimpleText->insertString( xRange, aString, bAbsorb );
+}
+
+void SAL_CALL ScShapeObj::insertControlCharacter( const uno::Reference<text::XTextRange>& xRange,
+ sal_Int16 nControlCharacter, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XSimpleText> xAggSimpleText(lcl_GetSimpleText(mxShapeAgg));
+ if ( !xAggSimpleText.is() )
+ throw uno::RuntimeException();
+
+ xAggSimpleText->insertControlCharacter( xRange, nControlCharacter, bAbsorb );
+}
+
+// XTextRange
+// (parent of XSimpleText)
+
+uno::Reference<text::XText> SAL_CALL ScShapeObj::getText()
+{
+ return this;
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getStart()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
+ if ( !xAggTextRange.is() )
+ throw uno::RuntimeException();
+
+ return xAggTextRange->getStart();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getEnd()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
+ if ( !xAggTextRange.is() )
+ throw uno::RuntimeException();
+
+ return xAggTextRange->getEnd();
+}
+
+OUString SAL_CALL ScShapeObj::getString()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
+ if ( !xAggTextRange.is() )
+ throw uno::RuntimeException();
+
+ return xAggTextRange->getString();
+}
+
+void SAL_CALL ScShapeObj::setString( const OUString& aText )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
+ if ( !xAggTextRange.is() )
+ throw uno::RuntimeException();
+
+ xAggTextRange->setString( aText );
+}
+
+// XChild
+
+uno::Reference< uno::XInterface > SAL_CALL ScShapeObj::getParent()
+{
+ SolarMutexGuard aGuard;
+
+ // receive cell position from caption object (parent of a note caption is the note cell)
+ SdrObject* pObj = GetSdrObject();
+ if( pObj )
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+ ScDocument* pDoc = rModel.GetDocument();
+
+ if ( pPage && pDoc )
+ {
+ if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ const ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( pObj, nTab );
+ if( pCaptData )
+ return cppu::getXWeak( new ScCellObj( pDocSh, pCaptData->maStart ) );
+ }
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+void SAL_CALL ScShapeObj::setParent( const uno::Reference< uno::XInterface >& )
+{
+ throw lang::NoSupportException();
+}
+
+// XTypeProvider
+
+uno::Sequence<uno::Type> SAL_CALL ScShapeObj::getTypes()
+{
+ uno::Sequence< uno::Type > aBaseTypes( ScShapeObj_Base::getTypes() );
+
+ uno::Sequence< uno::Type > aTextTypes;
+ if ( bIsTextShape )
+ aTextTypes = ScShapeObj_TextBase::getTypes();
+
+ uno::Reference<lang::XTypeProvider> xBaseProvider;
+ if ( mxShapeAgg.is() )
+ mxShapeAgg->queryAggregation( cppu::UnoType<lang::XTypeProvider>::get()) >>= xBaseProvider;
+ OSL_ENSURE( xBaseProvider.is(), "ScShapeObj: No XTypeProvider from aggregated shape!" );
+
+ uno::Sequence< uno::Type > aAggTypes;
+ if( xBaseProvider.is() )
+ aAggTypes = xBaseProvider->getTypes();
+
+ return ::comphelper::concatSequences( aBaseTypes, aTextTypes, aAggTypes );
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScShapeObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+SdrObject* ScShapeObj::GetSdrObject() const noexcept
+{
+ if(mxShapeAgg.is())
+ return SdrObject::getSdrObjectFromXShape( mxShapeAgg );
+ return nullptr;
+}
+
+constexpr OUString SC_EVENTACC_ONCLICK = u"OnClick"_ustr;
+constexpr OUString SC_EVENTACC_SCRIPT = u"Script"_ustr;
+constexpr OUString SC_EVENTACC_EVENTTYPE = u"EventType"_ustr;
+
+class ShapeUnoEventAccessImpl : public ::cppu::WeakImplHelper< container::XNameReplace >
+{
+private:
+ ScShapeObj* mpShape;
+
+ ScMacroInfo* getInfo( bool bCreate )
+ {
+ return ScShapeObj_getShapeHyperMacroInfo( mpShape, bCreate );
+ }
+
+public:
+ explicit ShapeUnoEventAccessImpl( ScShapeObj* pShape ): mpShape( pShape )
+ {
+ }
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override
+ {
+ if ( !hasByName( aName ) )
+ throw container::NoSuchElementException();
+ uno::Sequence< beans::PropertyValue > aProperties;
+ aElement >>= aProperties;
+ bool isEventType = false;
+ for( const beans::PropertyValue& rProperty : std::as_const(aProperties) )
+ {
+ if ( rProperty.Name == SC_EVENTACC_EVENTTYPE )
+ {
+ isEventType = true;
+ continue;
+ }
+ if ( isEventType && (rProperty.Name == SC_EVENTACC_SCRIPT) )
+ {
+ OUString sValue;
+ if ( rProperty.Value >>= sValue )
+ {
+ ScMacroInfo* pInfo = getInfo( true );
+ OSL_ENSURE( pInfo, "shape macro info could not be created!" );
+ if ( !pInfo )
+ break;
+ pInfo->SetMacro( sValue );
+ }
+ }
+ }
+ }
+
+ // XNameAccess
+ virtual uno::Any SAL_CALL getByName( const OUString& aName ) override
+ {
+ uno::Sequence< beans::PropertyValue > aProperties;
+ ScMacroInfo* pInfo = getInfo(false);
+
+ if ( aName != SC_EVENTACC_ONCLICK )
+ {
+ throw container::NoSuchElementException();
+ }
+
+ if ( pInfo && !pInfo->GetMacro().isEmpty() )
+ {
+ aProperties = { comphelper::makePropertyValue(SC_EVENTACC_EVENTTYPE,
+ SC_EVENTACC_SCRIPT),
+ comphelper::makePropertyValue(SC_EVENTACC_SCRIPT, pInfo->GetMacro()) };
+ }
+
+ return uno::Any( aProperties );
+ }
+
+ virtual uno::Sequence< OUString > SAL_CALL getElementNames() override
+ {
+ uno::Sequence<OUString> aSeq { SC_EVENTACC_ONCLICK };
+ return aSeq;
+ }
+
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
+ {
+ return aName == SC_EVENTACC_ONCLICK;
+ }
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override
+ {
+ return cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get();
+ }
+
+ virtual sal_Bool SAL_CALL hasElements() override
+ {
+ // elements are always present (but contained property sequences may be empty)
+ return true;
+ }
+};
+
+::uno::Reference< container::XNameReplace > SAL_CALL
+ScShapeObj::getEvents( )
+{
+ return new ShapeUnoEventAccessImpl( this );
+}
+
+OUString SAL_CALL ScShapeObj::getImplementationName( )
+{
+ return "com.sun.star.comp.sc.ScShapeObj";
+}
+
+sal_Bool SAL_CALL ScShapeObj::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL ScShapeObj::getSupportedServiceNames( )
+{
+ uno::Reference<lang::XServiceInfo> xSI;
+ if ( mxShapeAgg.is() )
+ mxShapeAgg->queryAggregation( cppu::UnoType<lang::XServiceInfo>::get() ) >>= xSI;
+
+ uno::Sequence< OUString > aSupported;
+ if ( xSI.is() )
+ aSupported = xSI->getSupportedServiceNames();
+
+ aSupported.realloc( aSupported.getLength() + 1 );
+ aSupported.getArray()[ aSupported.getLength() - 1 ] = "com.sun.star.sheet.Shape";
+
+ if( bIsNoteCaption )
+ {
+ aSupported.realloc( aSupported.getLength() + 1 );
+ aSupported.getArray()[ aSupported.getLength() - 1 ] = "com.sun.star.sheet.CellAnnotationShape";
+ }
+
+ return aSupported;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/srchuno.cxx b/sc/source/ui/unoobj/srchuno.cxx
new file mode 100644
index 0000000000..a5b59a330c
--- /dev/null
+++ b/sc/source/ui/unoobj/srchuno.cxx
@@ -0,0 +1,195 @@
+/* -*- 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 <scitems.hxx>
+#include <svl/srchitem.hxx>
+#include <vcl/svapp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <srchuno.hxx>
+#include <miscuno.hxx>
+#include <unonames.hxx>
+
+using namespace com::sun::star;
+
+//! SearchWords searches in whole cells - rename it ???
+
+// SfxItemPropertyMapEntry only for GetPropertySetInfo
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetSearchPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aSearchPropertyMap_Impl[] =
+ {
+ { SC_UNO_SRCHBACK, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHBYROW, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHCASE, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHREGEXP, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHWILDCARD, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHSIM, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHSIMADD, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SRCHSIMEX, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SRCHSIMREL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHSIMREM, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SRCHSTYLES, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHTYPE, 0, cppu::UnoType<sal_Int16>::get(), 0, 0}, // enum TableSearch is gone
+ { SC_UNO_SRCHWORDS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHWCESCCHAR, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ };
+ return aSearchPropertyMap_Impl;
+}
+
+constexpr OUString SCSEARCHDESCRIPTOR_SERVICE = u"com.sun.star.util.SearchDescriptor"_ustr;
+constexpr OUString SCREPLACEDESCRIPTOR_SERVICE = u"com.sun.star.util.ReplaceDescriptor"_ustr;
+
+ScCellSearchObj::ScCellSearchObj() :
+ aPropSet(lcl_GetSearchPropertyMap()),
+ pSearchItem( new SvxSearchItem( SCITEM_SEARCHDATA ) )
+{
+ // Defaults:
+ pSearchItem->SetWordOnly(false);
+ pSearchItem->SetExact(false);
+ pSearchItem->SetMatchFullHalfWidthForms(false);
+ pSearchItem->SetUseAsianOptions(false); // or all asian bits would have to be handled
+ pSearchItem->SetBackward(false);
+ pSearchItem->SetSelection(false);
+ pSearchItem->SetRegExp(false);
+ pSearchItem->SetWildcard(false);
+ pSearchItem->SetPattern(false);
+ pSearchItem->SetLevenshtein(false);
+ pSearchItem->SetLEVRelaxed(false);
+ pSearchItem->SetLEVOther(2);
+ pSearchItem->SetLEVShorter(2);
+ pSearchItem->SetLEVLonger(2);
+ // Calc-Flags
+ pSearchItem->SetRowDirection(false);
+ pSearchItem->SetCellType(SvxSearchCellType::FORMULA);
+
+ // Selection-Flag will be set when this is called
+}
+
+ScCellSearchObj::~ScCellSearchObj()
+{
+}
+
+// XSearchDescriptor
+
+OUString SAL_CALL ScCellSearchObj::getSearchString()
+{
+ SolarMutexGuard aGuard;
+ return pSearchItem->GetSearchString();
+}
+
+void SAL_CALL ScCellSearchObj::setSearchString( const OUString& aString )
+{
+ SolarMutexGuard aGuard;
+ pSearchItem->SetSearchString( aString );
+}
+
+// XReplaceDescriptor
+
+OUString SAL_CALL ScCellSearchObj::getReplaceString()
+{
+ SolarMutexGuard aGuard;
+ return pSearchItem->GetReplaceString();
+}
+
+void SAL_CALL ScCellSearchObj::setReplaceString( const OUString& aReplaceString )
+{
+ SolarMutexGuard aGuard;
+ pSearchItem->SetReplaceString( aReplaceString );
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCellSearchObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScCellSearchObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if (aPropertyName == SC_UNO_SRCHBACK) pSearchItem->SetBackward( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHBYROW) pSearchItem->SetRowDirection( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHCASE) pSearchItem->SetExact( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHREGEXP) pSearchItem->SetRegExp( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHWILDCARD) pSearchItem->SetWildcard( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSIM) pSearchItem->SetLevenshtein( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSIMREL) pSearchItem->SetLEVRelaxed( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSTYLES) pSearchItem->SetPattern( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHWORDS) pSearchItem->SetWordOnly( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSIMADD) pSearchItem->SetLEVLonger( ScUnoHelpFunctions::GetInt16FromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSIMEX) pSearchItem->SetLEVOther( ScUnoHelpFunctions::GetInt16FromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSIMREM) pSearchItem->SetLEVShorter( ScUnoHelpFunctions::GetInt16FromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHTYPE) pSearchItem->SetCellType( static_cast<SvxSearchCellType>(ScUnoHelpFunctions::GetInt16FromAny( aValue )) );
+ else if (aPropertyName == SC_UNO_SRCHFILTERED) pSearchItem->SetSearchFiltered( ScUnoHelpFunctions::GetBoolFromAny(aValue) );
+ else if (aPropertyName == SC_UNO_SRCHFORMATTED) pSearchItem->SetSearchFormatted( ScUnoHelpFunctions::GetBoolFromAny(aValue) );
+ else if (aPropertyName == SC_UNO_SRCHWCESCCHAR) pSearchItem->SetWildcardEscapeCharacter( ScUnoHelpFunctions::GetInt32FromAny(aValue) );
+}
+
+uno::Any SAL_CALL ScCellSearchObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if (aPropertyName == SC_UNO_SRCHBACK) aRet <<= pSearchItem->GetBackward();
+ else if (aPropertyName == SC_UNO_SRCHBYROW) aRet <<= pSearchItem->GetRowDirection();
+ else if (aPropertyName == SC_UNO_SRCHCASE) aRet <<= pSearchItem->GetExact();
+ else if (aPropertyName == SC_UNO_SRCHREGEXP) aRet <<= pSearchItem->GetRegExp();
+ else if (aPropertyName == SC_UNO_SRCHWILDCARD) aRet <<= pSearchItem->GetWildcard();
+ else if (aPropertyName == SC_UNO_SRCHSIM) aRet <<= pSearchItem->IsLevenshtein();
+ else if (aPropertyName == SC_UNO_SRCHSIMREL) aRet <<= pSearchItem->IsLEVRelaxed();
+ else if (aPropertyName == SC_UNO_SRCHSTYLES) aRet <<= pSearchItem->GetPattern();
+ else if (aPropertyName == SC_UNO_SRCHWORDS) aRet <<= pSearchItem->GetWordOnly();
+ else if (aPropertyName == SC_UNO_SRCHSIMADD) aRet <<= static_cast<sal_Int16>(pSearchItem->GetLEVLonger());
+ else if (aPropertyName == SC_UNO_SRCHSIMEX) aRet <<= static_cast<sal_Int16>(pSearchItem->GetLEVOther());
+ else if (aPropertyName == SC_UNO_SRCHSIMREM) aRet <<= static_cast<sal_Int16>(pSearchItem->GetLEVShorter());
+ else if (aPropertyName == SC_UNO_SRCHTYPE) aRet <<= static_cast<sal_Int16>(pSearchItem->GetCellType());
+ else if (aPropertyName == SC_UNO_SRCHFILTERED) aRet <<= pSearchItem->IsSearchFiltered();
+ else if (aPropertyName == SC_UNO_SRCHFORMATTED) aRet <<= pSearchItem->IsSearchFormatted();
+ else if (aPropertyName == SC_UNO_SRCHWCESCCHAR) aRet <<= pSearchItem->GetWildcardEscapeCharacter();
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScCellSearchObj )
+
+// XServiceInfo
+
+OUString SAL_CALL ScCellSearchObj::getImplementationName()
+{
+ return "ScCellSearchObj";
+}
+
+sal_Bool SAL_CALL ScCellSearchObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellSearchObj::getSupportedServiceNames()
+{
+ return {SCSEARCHDESCRIPTOR_SERVICE, SCREPLACEDESCRIPTOR_SERVICE};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/styleuno.cxx b/sc/source/ui/unoobj/styleuno.cxx
new file mode 100644
index 0000000000..8dd6fc58f8
--- /dev/null
+++ b/sc/source/ui/unoobj/styleuno.cxx
@@ -0,0 +1,2069 @@
+/* -*- 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 <scitems.hxx>
+#include <editeng/memberids.h>
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/numitem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/pbinitem.hxx>
+#include <svx/unomid.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/unoshprp.hxx>
+#include <svx/xflbstit.hxx>
+#include <svx/xflbmtit.hxx>
+#include <editeng/unonrule.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <utility>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <svl/numformat.hxx>
+#include <svl/intitem.hxx>
+#include <svl/zformat.hxx>
+#include <tools/fract.hxx>
+#include <tools/UnitConversion.hxx>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/drawing/BitmapMode.hpp>
+#include <com/sun/star/table/BorderLine.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/table/TableBorder2.hpp>
+#include <com/sun/star/table/ShadowFormat.hpp>
+#include <com/sun/star/table/CellHoriJustify.hpp>
+#include <com/sun/star/table/CellOrientation.hpp>
+#include <com/sun/star/style/PageStyleLayout.hpp>
+#include <com/sun/star/style/GraphicLocation.hpp>
+#include <com/sun/star/sheet/XHeaderFooterContent.hpp>
+#include <com/sun/star/util/CellProtection.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <CommonProperties.hxx>
+#include <styleuno.hxx>
+#include <docsh.hxx>
+#include <attrib.hxx>
+#include <stlpool.hxx>
+#include <docpool.hxx>
+#include <miscuno.hxx>
+#include <tablink.hxx>
+#include <unonames.hxx>
+#include <unowids.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <cellsuno.hxx>
+#include <stylehelper.hxx>
+
+using namespace ::com::sun::star;
+
+static const SfxItemPropertySet* lcl_GetGraphicStyleSet()
+{
+ static const SfxItemPropertyMapEntry aGraphicStyleMap_Impl[] =
+ {
+ SVX_UNOEDIT_NUMBERING_PROPERTY,
+ SHADOW_PROPERTIES
+ LINE_PROPERTIES
+ LINE_PROPERTIES_START_END
+ FILL_PROPERTIES
+ EDGERADIUS_PROPERTIES
+ TEXT_PROPERTIES_DEFAULTS
+ CONNECTOR_PROPERTIES
+ SPECIAL_DIMENSIONING_PROPERTIES_DEFAULTS
+ {SC_UNONAME_HIDDEN, ATTR_HIDDEN, cppu::UnoType<sal_Bool>::get(), 0, 0 },
+ {SC_UNONAME_DISPNAME, SC_WID_UNO_DISPNAME, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ };
+ static SfxItemPropertySet aGraphicStyleSet_Impl( aGraphicStyleMap_Impl );
+ return &aGraphicStyleSet_Impl;
+}
+
+static const SfxItemPropertySet* lcl_GetCellStyleSet()
+{
+ static const SfxItemPropertyMapEntry aCellStyleMap_Impl[] =
+ {
+ {SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ CELL_BORDER_PROPERTIES
+ CELL_BACKGROUND_COLOR_PROPERTIES
+ {SC_UNONAME_CELLPRO, ATTR_PROTECTION, ::cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ CHAR_COLOR_PROPERTIES
+ {SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ {SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ {SC_UNONAME_CFONT, ATTR_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ {SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ {SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ {SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ {SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ {SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ {SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ {SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ {SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ {SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ {SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ {SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ {SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ {SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ {SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ {SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ {SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, ::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ {SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ {SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ {SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, ::cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ {SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,::cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ {SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,::cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ {SC_UNONAME_COVER, ATTR_FONT_OVERLINE, ::cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ {SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ {SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ {SC_UNONAME_CPOST, ATTR_FONT_POSTURE, ::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ {SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ {SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ {SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ {SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ {SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,::cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ {SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ {SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ {SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, ::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ {SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ {SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ {SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ {SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ {SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ {SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ {SC_UNONAME_DISPNAME, SC_WID_UNO_DISPNAME,::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ {SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, ::cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ {SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ {SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+// {SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ {SC_UNONAME_CELLORI, ATTR_STACKED, ::cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ {SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ {SC_UNONAME_PBMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ {SC_UNONAME_PINDENT, ATTR_INDENT, ::cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ {SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ {SC_UNONAME_PLMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ {SC_UNONAME_PRMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ {SC_UNONAME_PTMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ {SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNONAME_SHADOW, ATTR_SHADOW, ::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ {SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, ::cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ {SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD2, ::cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ {SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ {SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {SC_UNONAME_HIDDEN, ATTR_HIDDEN, cppu::UnoType<sal_Bool>::get(), 0, 0 },
+ {SC_UNONAME_HYPERLINK, ATTR_HYPERLINK, cppu::UnoType<OUString>::get(), 0, 0 },
+ };
+ static SfxItemPropertySet aCellStyleSet_Impl( aCellStyleMap_Impl );
+ return &aCellStyleSet_Impl;
+}
+
+// map with all site attributes including header and footer attributes
+
+static const SfxItemPropertySet * lcl_GetPageStyleSet()
+{
+ static const SfxItemPropertyMapEntry aPageStyleMap_Impl[] =
+ {
+ {SC_UNO_PAGE_BACKCOLOR, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {SC_UNO_PAGE_GRAPHICFILT, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_FILTER },
+ {SC_UNO_PAGE_GRAPHICLOC, ATTR_BACKGROUND, ::cppu::UnoType<style::GraphicLocation>::get(), 0, MID_GRAPHIC_POSITION },
+ {SC_UNO_PAGE_GRAPHICURL, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_URL },
+ {SC_UNO_PAGE_GRAPHIC, ATTR_BACKGROUND, ::cppu::UnoType<graphic::XGraphic>::get(), 0, MID_GRAPHIC },
+ {SC_UNO_PAGE_BACKTRANS, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ {OLD_UNO_PAGE_BACKCOLOR, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {SC_UNO_PAGE_BORDERDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BORDER_DISTANCE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_BOTTBORDER, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_BOTTBRDDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_BOTTMARGIN, ATTR_ULSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_LO_MARGIN | CONVERT_TWIPS },
+ {SC_UNO_PAGE_CENTERHOR, ATTR_PAGE_HORCENTER,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_CENTERVER, ATTR_PAGE_VERCENTER,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNONAME_DISPNAME, SC_WID_UNO_DISPNAME,::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ {SC_UNO_PAGE_FIRSTPAGE, ATTR_PAGE_FIRSTPAGENO,::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {SC_UNO_PAGE_FIRSTFTRSHARED, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FIRSTHDRSHARED, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FIRSTFTRCONT, ATTR_PAGE_FOOTERFIRST,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+ {SC_UNO_PAGE_FIRSTHDRCONT, ATTR_PAGE_HEADERFIRST,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+
+ {SC_UNO_PAGE_FTRBACKCOL, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRGRFFILT, SC_WID_UNO_FOOTERSET,::cppu::UnoType<OUString>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRGRFLOC, SC_WID_UNO_FOOTERSET,::cppu::UnoType<style::GraphicLocation>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRGRFURL, SC_WID_UNO_FOOTERSET,::cppu::UnoType<OUString>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRGRF, SC_WID_UNO_FOOTERSET,::cppu::UnoType<graphic::XGraphic>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRBACKTRAN, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {OLD_UNO_PAGE_FTRBACKCOL, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRBODYDIST, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRBRDDIST, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRBOTTBOR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRBOTTBDIS, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {OLD_UNO_PAGE_FTRDYNAMIC, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRHEIGHT, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRDYNAMIC, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRON, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRSHARED, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRLEFTBOR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRLEFTBDIS, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRLEFTMAR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {OLD_UNO_PAGE_FTRON, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRRIGHTBOR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRRIGHTBDIS,SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRRIGHTMAR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRSHADOW, SC_WID_UNO_FOOTERSET,::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 },
+ {OLD_UNO_PAGE_FTRSHARED, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRTOPBOR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRTOPBDIS, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+
+ {SC_UNO_PAGE_HDRBACKCOL, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRGRFFILT, SC_WID_UNO_HEADERSET,::cppu::UnoType<OUString>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRGRFLOC, SC_WID_UNO_HEADERSET,::cppu::UnoType<style::GraphicLocation>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRGRFURL, SC_WID_UNO_HEADERSET,::cppu::UnoType<OUString>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRGRF, SC_WID_UNO_HEADERSET,::cppu::UnoType<graphic::XGraphic>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRBACKTRAN, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {OLD_UNO_PAGE_HDRBACKCOL, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRBODYDIST, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRBRDDIST, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRBOTTBOR, SC_WID_UNO_HEADERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRBOTTBDIS, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {OLD_UNO_PAGE_HDRDYNAMIC, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRHEIGHT, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRDYNAMIC, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRON, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRSHARED, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRLEFTBOR, SC_WID_UNO_HEADERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRLEFTBDIS, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRLEFTMAR, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {OLD_UNO_PAGE_HDRON, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRRIGHTBOR, SC_WID_UNO_HEADERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRRIGHTBDIS,SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRRIGHTMAR, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRSHADOW, SC_WID_UNO_HEADERSET,::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 },
+ {OLD_UNO_PAGE_HDRSHARED, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRTOPBOR, SC_WID_UNO_HEADERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRTOPBDIS, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+
+ {SC_UNO_PAGE_HEIGHT, ATTR_PAGE_SIZE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_SIZE_HEIGHT | CONVERT_TWIPS },
+ {OLD_UNO_PAGE_BACKTRANS, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ {SC_UNO_PAGE_LANDSCAPE, ATTR_PAGE, cppu::UnoType<bool>::get(), 0, MID_PAGE_ORIENTATION },
+ {SC_UNO_PAGE_LEFTBORDER, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_LEFTBRDDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_LEFTMARGIN, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_L_MARGIN | CONVERT_TWIPS },
+ {SC_UNO_PAGE_LEFTFTRCONT, ATTR_PAGE_FOOTERLEFT,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+ {SC_UNO_PAGE_LEFTHDRCONT, ATTR_PAGE_HEADERLEFT,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+ {SC_UNO_PAGE_NUMBERTYPE, ATTR_PAGE, ::cppu::UnoType<sal_Int16>::get(), 0, MID_PAGE_NUMTYPE },
+ {SC_UNO_PAGE_SCALEVAL, ATTR_PAGE_SCALE, ::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {SC_UNO_PAGE_SYTLELAYOUT, ATTR_PAGE, ::cppu::UnoType<style::PageStyleLayout>::get(), 0, MID_PAGE_LAYOUT },
+ {SC_UNO_PAGE_PRINTANNOT, ATTR_PAGE_NOTES, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_PRINTCHARTS, ATTR_PAGE_CHARTS, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_PRINTDOWN, ATTR_PAGE_TOPDOWN, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_PRINTDRAW, ATTR_PAGE_DRAWINGS, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_PRINTFORMUL, ATTR_PAGE_FORMULAS, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_PRINTGRID, ATTR_PAGE_GRID, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_PRINTHEADER, ATTR_PAGE_HEADERS, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_PRINTOBJS, ATTR_PAGE_OBJECTS, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_PRINTZERO, ATTR_PAGE_NULLVALS, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_PAPERTRAY, ATTR_PAGE_PAPERBIN, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ {SC_UNO_PAGE_RIGHTBORDER, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_RIGHTBRDDIST,ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_RIGHTMARGIN, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_R_MARGIN | CONVERT_TWIPS },
+ {SC_UNO_PAGE_RIGHTFTRCON, ATTR_PAGE_FOOTERRIGHT,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+ {SC_UNO_PAGE_RIGHTHDRCON, ATTR_PAGE_HEADERRIGHT,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+ {SC_UNO_PAGE_SCALETOPAG, ATTR_PAGE_SCALETOPAGES,::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {SC_UNO_PAGE_SCALETOX, ATTR_PAGE_SCALETO, ::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {SC_UNO_PAGE_SCALETOY, ATTR_PAGE_SCALETO, ::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {SC_UNO_PAGE_SHADOWFORM, ATTR_SHADOW, ::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ {SC_UNO_PAGE_SIZE, ATTR_PAGE_SIZE, ::cppu::UnoType<awt::Size>::get(), 0, MID_SIZE_SIZE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_TOPBORDER, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_TOPBRDDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_TOPMARGIN, ATTR_ULSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_UP_MARGIN | CONVERT_TWIPS },
+ {OLD_UNO_PAGE_FTRBACKTRAN,SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {OLD_UNO_PAGE_HDRBACKTRAN,SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ {SC_UNO_PAGE_WIDTH, ATTR_PAGE_SIZE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_SIZE_WIDTH | CONVERT_TWIPS },
+ {SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {SC_UNONAME_HIDDEN, ATTR_HIDDEN, cppu::UnoType<sal_Bool>::get(), 0, 0 },
+ };
+ static SfxItemPropertySet aPageStyleSet_Impl( aPageStyleMap_Impl );
+ return &aPageStyleSet_Impl;
+}
+
+// map with content of the Header-Item-Sets
+
+static const SfxItemPropertyMap* lcl_GetHeaderStyleMap()
+{
+ static const SfxItemPropertyMapEntry aHeaderStyleMap_Impl[] =
+ {
+ {SC_UNO_PAGE_HDRBACKCOL, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {SC_UNO_PAGE_HDRGRFFILT, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_FILTER },
+ {SC_UNO_PAGE_HDRGRFLOC, ATTR_BACKGROUND, ::cppu::UnoType<style::GraphicLocation>::get(), 0, MID_GRAPHIC_POSITION },
+ {SC_UNO_PAGE_HDRGRFURL, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_URL },
+ {SC_UNO_PAGE_HDRGRF, ATTR_BACKGROUND, ::cppu::UnoType<graphic::XGraphic>::get(), 0, MID_GRAPHIC },
+ {SC_UNO_PAGE_HDRBACKTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ {OLD_UNO_PAGE_HDRBACKCOL, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {SC_UNO_PAGE_HDRBODYDIST, ATTR_ULSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_LO_MARGIN | CONVERT_TWIPS },
+ {SC_UNO_PAGE_HDRBRDDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BORDER_DISTANCE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_HDRBOTTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_HDRBOTTBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE | CONVERT_TWIPS },
+ {OLD_UNO_PAGE_HDRDYNAMIC, ATTR_PAGE_DYNAMIC, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRHEIGHT, ATTR_PAGE_SIZE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_SIZE_HEIGHT | CONVERT_TWIPS },
+ {SC_UNO_PAGE_HDRDYNAMIC, ATTR_PAGE_DYNAMIC, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRON, ATTR_PAGE_ON, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRSHARED, ATTR_PAGE_SHARED, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FIRSTHDRSHARED, ATTR_PAGE_SHARED_FIRST, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRLEFTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_HDRLEFTBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_HDRLEFTMAR, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_L_MARGIN | CONVERT_TWIPS },
+ {OLD_UNO_PAGE_HDRON, ATTR_PAGE_ON, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRRIGHTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_HDRRIGHTBDIS,ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_HDRRIGHTMAR, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_R_MARGIN | CONVERT_TWIPS },
+ {SC_UNO_PAGE_HDRSHADOW, ATTR_SHADOW, ::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ {OLD_UNO_PAGE_HDRSHARED, ATTR_PAGE_SHARED, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_HDRTOPBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_HDRTOPBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE | CONVERT_TWIPS },
+ {OLD_UNO_PAGE_HDRBACKTRAN,ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ };
+ static SfxItemPropertyMap aHeaderStyleMap( aHeaderStyleMap_Impl );
+ return &aHeaderStyleMap;
+}
+
+// map with content of the Footer-Item-Sets
+
+static const SfxItemPropertyMap* lcl_GetFooterStyleMap()
+{
+ static const SfxItemPropertyMapEntry aFooterStyleMap_Impl[] =
+ {
+ {SC_UNO_PAGE_FTRBACKCOL, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {SC_UNO_PAGE_FTRGRFFILT, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_FILTER },
+ {SC_UNO_PAGE_FTRGRFLOC, ATTR_BACKGROUND, ::cppu::UnoType<style::GraphicLocation>::get(), 0, MID_GRAPHIC_POSITION },
+ {SC_UNO_PAGE_FTRGRFURL, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_URL },
+ {SC_UNO_PAGE_FTRGRF, ATTR_BACKGROUND, ::cppu::UnoType<graphic::XGraphic>::get(), 0, MID_GRAPHIC },
+ {SC_UNO_PAGE_FTRBACKTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ {OLD_UNO_PAGE_FTRBACKCOL, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {SC_UNO_PAGE_FTRBODYDIST, ATTR_ULSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_UP_MARGIN | CONVERT_TWIPS },
+ {SC_UNO_PAGE_FTRBRDDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BORDER_DISTANCE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_FTRBOTTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_FTRBOTTBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE | CONVERT_TWIPS },
+ {OLD_UNO_PAGE_FTRDYNAMIC, ATTR_PAGE_DYNAMIC, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRHEIGHT, ATTR_PAGE_SIZE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_SIZE_HEIGHT | CONVERT_TWIPS },
+ {SC_UNO_PAGE_FTRDYNAMIC, ATTR_PAGE_DYNAMIC, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRON, ATTR_PAGE_ON, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRSHARED, ATTR_PAGE_SHARED, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FIRSTFTRSHARED, ATTR_PAGE_SHARED_FIRST, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRLEFTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_FTRLEFTBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_FTRLEFTMAR, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_L_MARGIN | CONVERT_TWIPS },
+ {OLD_UNO_PAGE_FTRON, ATTR_PAGE_ON, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRRIGHTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_FTRRIGHTBDIS,ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {SC_UNO_PAGE_FTRRIGHTMAR, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_R_MARGIN | CONVERT_TWIPS },
+ {SC_UNO_PAGE_FTRSHADOW, ATTR_SHADOW, ::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ {OLD_UNO_PAGE_FTRSHARED, ATTR_PAGE_SHARED, cppu::UnoType<bool>::get(), 0, 0 },
+ {SC_UNO_PAGE_FTRTOPBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ {SC_UNO_PAGE_FTRTOPBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE | CONVERT_TWIPS },
+ {OLD_UNO_PAGE_FTRBACKTRAN,ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ };
+ static SfxItemPropertyMap aFooterStyleMap( aFooterStyleMap_Impl );
+ return &aFooterStyleMap;
+}
+
+// access index on the style types: 0 = Cell, 1 = Page, 2 = Drawing
+
+#define SC_STYLE_FAMILY_COUNT 3
+
+constexpr OUString SC_FAMILYNAME_CELL = u"CellStyles"_ustr;
+constexpr OUString SC_FAMILYNAME_PAGE = u"PageStyles"_ustr;
+constexpr OUString SC_FAMILYNAME_GRAPHIC = u"GraphicStyles"_ustr;
+
+const SfxStyleFamily aStyleFamilyTypes[SC_STYLE_FAMILY_COUNT] = { SfxStyleFamily::Para, SfxStyleFamily::Page, SfxStyleFamily::Frame };
+
+constexpr OUString SCSTYLE_SERVICE = u"com.sun.star.style.Style"_ustr;
+constexpr OUString SCCELLSTYLE_SERVICE = u"com.sun.star.style.CellStyle"_ustr;
+constexpr OUString SCPAGESTYLE_SERVICE = u"com.sun.star.style.PageStyle"_ustr;
+constexpr OUString SCGRAPHICSTYLE_SERVICE = u"com.sun.star.style.GraphicStyle"_ustr;
+
+SC_SIMPLE_SERVICE_INFO( ScStyleFamiliesObj, "ScStyleFamiliesObj", "com.sun.star.style.StyleFamilies" )
+SC_SIMPLE_SERVICE_INFO( ScStyleFamilyObj, "ScStyleFamilyObj", "com.sun.star.style.StyleFamily" )
+
+constexpr OUString SC_PAPERBIN_DEFAULTNAME = u"[From printer settings]"_ustr;
+
+static bool lcl_AnyTabProtected( const ScDocument& rDoc )
+{
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB i=0; i<nTabCount; i++)
+ if (rDoc.IsTabProtected(i))
+ return true;
+ return false;
+}
+
+ScStyleFamiliesObj::ScStyleFamiliesObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScStyleFamiliesObj::~ScStyleFamiliesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScStyleFamiliesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XStyleFamilies
+
+rtl::Reference<ScStyleFamilyObj> ScStyleFamiliesObj::GetObjectByType_Impl(SfxStyleFamily nType) const
+{
+ if ( pDocShell )
+ {
+ if ( nType == SfxStyleFamily::Para )
+ return new ScStyleFamilyObj( pDocShell, SfxStyleFamily::Para );
+ else if ( nType == SfxStyleFamily::Page )
+ return new ScStyleFamilyObj( pDocShell, SfxStyleFamily::Page );
+ else if ( nType == SfxStyleFamily::Frame )
+ return new ScStyleFamilyObj( pDocShell, SfxStyleFamily::Frame );
+ }
+ OSL_FAIL("getStyleFamilyByType: no DocShell or wrong SfxStyleFamily");
+ return nullptr;
+}
+
+rtl::Reference<ScStyleFamilyObj> ScStyleFamiliesObj::GetObjectByIndex_Impl(sal_uInt32 nIndex) const
+{
+ if ( nIndex < SC_STYLE_FAMILY_COUNT )
+ return GetObjectByType_Impl(aStyleFamilyTypes[nIndex]);
+
+ return nullptr; // invalid index
+}
+
+rtl::Reference<ScStyleFamilyObj> ScStyleFamiliesObj::GetObjectByName_Impl(std::u16string_view aName) const
+{
+ if ( pDocShell )
+ {
+ if ( aName == SC_FAMILYNAME_CELL )
+ return new ScStyleFamilyObj( pDocShell, SfxStyleFamily::Para );
+ else if ( aName == SC_FAMILYNAME_PAGE )
+ return new ScStyleFamilyObj( pDocShell, SfxStyleFamily::Page );
+ else if ( aName == SC_FAMILYNAME_GRAPHIC )
+ return new ScStyleFamilyObj( pDocShell, SfxStyleFamily::Frame );
+ }
+ // no assertion - called directly from getByName
+ return nullptr;
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScStyleFamiliesObj::getCount()
+{
+ return SC_STYLE_FAMILY_COUNT;
+}
+
+uno::Any SAL_CALL ScStyleFamiliesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XNameContainer > xFamily(GetObjectByIndex_Impl(nIndex));
+ if (!xFamily.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xFamily);
+}
+
+uno::Type SAL_CALL ScStyleFamiliesObj::getElementType()
+{
+ return cppu::UnoType<container::XNameContainer>::get(); // has to fit to getByIndex
+}
+
+sal_Bool SAL_CALL ScStyleFamiliesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// container::XNameAccess
+
+uno::Any SAL_CALL ScStyleFamiliesObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XNameContainer > xFamily(GetObjectByName_Impl(aName));
+ if (!xFamily.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xFamily);
+}
+
+uno::Sequence<OUString> SAL_CALL ScStyleFamiliesObj::getElementNames()
+{
+ return {SC_FAMILYNAME_CELL, SC_FAMILYNAME_PAGE, SC_FAMILYNAME_GRAPHIC};
+}
+
+sal_Bool SAL_CALL ScStyleFamiliesObj::hasByName( const OUString& aName )
+{
+ return aName == SC_FAMILYNAME_CELL || aName == SC_FAMILYNAME_PAGE || aName == SC_FAMILYNAME_GRAPHIC;
+}
+
+// style::XStyleLoader
+
+void SAL_CALL ScStyleFamiliesObj::loadStylesFromURL( const OUString& aURL,
+ const uno::Sequence<beans::PropertyValue>& aOptions )
+{
+ //! use aOptions (like Writer)
+ //! set flag to disable filter option dialogs when importing
+
+ OUString aFilter; // empty - detect
+ OUString aFiltOpt;
+ uno::Reference<io::XInputStream> xInputStream;
+ if (aURL == "private:stream")
+ {
+ for (const auto& rProp : aOptions)
+ {
+ if (rProp.Name == "InputStream")
+ {
+ rProp.Value >>= xInputStream;
+ if (!xInputStream.is())
+ {
+ throw lang::IllegalArgumentException(
+ "Parameter 'InputStream' could not be converted "
+ "to type 'com::sun::star::io::XInputStream'",
+ nullptr, 0);
+ }
+ break;
+ }
+ }
+ }
+
+ ScDocumentLoader aLoader( aURL, aFilter, aFiltOpt, 0, nullptr, xInputStream );
+
+ ScDocShell* pSource = aLoader.GetDocShell();
+
+ loadStylesFromDocShell(pSource, aOptions);
+}
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScStyleFamiliesObj::getStyleLoaderOptions()
+{
+ // return defaults for options (?)
+ return comphelper::InitPropertySequence({
+ { SC_UNONAME_OVERWSTL, uno::Any(true) },
+ { SC_UNONAME_LOADCELL, uno::Any(true) },
+ { SC_UNONAME_LOADPAGE, uno::Any(true) }
+ });
+}
+
+// style::XStyleLoader2
+
+void SAL_CALL ScStyleFamiliesObj::loadStylesFromDocument( const uno::Reference < lang::XComponent > & aSourceComponent,
+ const uno::Sequence<beans::PropertyValue>& aOptions )
+{
+ // Source document docShell
+ if ( !aSourceComponent.is() )
+ throw uno::RuntimeException();
+
+ ScDocShell* pDocShellSrc = dynamic_cast<ScDocShell*> (SfxObjectShell::GetShellFromComponent(aSourceComponent));
+
+ loadStylesFromDocShell(pDocShellSrc, aOptions);
+}
+
+// private
+
+void ScStyleFamiliesObj::loadStylesFromDocShell( ScDocShell* pSource,
+ const uno::Sequence<beans::PropertyValue>& aOptions )
+{
+
+ if ( !(pSource && pDocShell) )
+ return;
+
+ // collect options
+
+ bool bLoadReplace = true; // defaults
+ bool bLoadCellStyles = true;
+ bool bLoadPageStyles = true;
+
+ for (const beans::PropertyValue& rProp : aOptions)
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == SC_UNONAME_OVERWSTL)
+ bLoadReplace = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_LOADCELL)
+ bLoadCellStyles = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_LOADPAGE)
+ bLoadPageStyles = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ }
+
+ pDocShell->LoadStylesArgs( *pSource, bLoadReplace, bLoadCellStyles, bLoadPageStyles );
+ pDocShell->SetDocumentModified(); // paint is inside LoadStyles
+}
+
+ScStyleFamilyObj::ScStyleFamilyObj(ScDocShell* pDocSh, SfxStyleFamily eFam) :
+ pDocShell( pDocSh ),
+ eFamily( eFam )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScStyleFamilyObj::~ScStyleFamilyObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScStyleFamilyObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // has become invalid
+ }
+}
+
+// XStyleFamily
+
+rtl::Reference<ScStyleObj> ScStyleFamilyObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
+{
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+
+ SfxStyleSheetIterator aIter( pStylePool, eFamily );
+ if ( nIndex < aIter.Count() )
+ {
+ SfxStyleSheetBase* pStyle = aIter[nIndex];
+ if ( pStyle )
+ {
+ return new ScStyleObj( pDocShell, eFamily, pStyle->GetName() );
+ }
+ }
+ }
+ return nullptr;
+}
+
+rtl::Reference<ScStyleObj> ScStyleFamilyObj::GetObjectByName_Impl(const OUString& aName)
+{
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ if ( pStylePool->Find( aName, eFamily ) )
+ return new ScStyleObj( pDocShell, eFamily, aName );
+ }
+ return nullptr;
+}
+
+void SAL_CALL ScStyleFamilyObj::insertByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ // reflection does not need to be uno::XInterface, can be any interface...
+ uno::Reference< uno::XInterface > xInterface(aElement, uno::UNO_QUERY);
+ if ( xInterface.is() )
+ {
+ ScStyleObj* pStyleObj = dynamic_cast<ScStyleObj*>( xInterface.get() );
+ if ( pStyleObj && pStyleObj->GetFamily() == eFamily &&
+ !pStyleObj->IsInserted() ) // not yet inserted?
+ {
+ OUString aNameStr(ScStyleNameConversion::ProgrammaticToDisplayName( aName, eFamily ));
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+
+ //! DocFunc function ???
+ //! Undo ?????????????
+
+ if ( pStylePool->Find( aNameStr, eFamily ) ) // not available yet
+ throw container::ElementExistException();
+
+ (void)pStylePool->Make( aNameStr, eFamily, SfxStyleSearchBits::UserDefined );
+
+ if ( eFamily == SfxStyleFamily::Para && !rDoc.IsImportingXML() )
+ rDoc.GetPool()->CellStyleCreated( aNameStr, rDoc );
+
+ pStyleObj->InitDoc( pDocShell, aNameStr ); // object can be used
+
+ if (!rDoc.IsImportingXML())
+ pDocShell->SetDocumentModified(); // new style not used yet
+ bDone = true;
+
+ }
+ }
+
+ if (!bDone)
+ {
+ // other errors are handled above
+ throw lang::IllegalArgumentException();
+ }
+}
+
+void SAL_CALL ScStyleFamilyObj::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ //! combine?
+ removeByName( aName );
+ insertByName( aName, aElement );
+}
+
+void SAL_CALL ScStyleFamilyObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bFound = false;
+ if ( pDocShell )
+ {
+ OUString aString(ScStyleNameConversion::ProgrammaticToDisplayName( aName, eFamily ));
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+
+ //! DocFunc function??
+ //! Undo ?????????????
+
+ SfxStyleSheetBase* pStyle = pStylePool->Find( aString, eFamily );
+ if (pStyle)
+ {
+ bFound = true;
+ if ( eFamily == SfxStyleFamily::Para )
+ {
+ // like ScViewFunc::RemoveStyleSheetInUse
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Point aLogic = pVDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
+ double nPPTX = aLogic.X() / 1000.0;
+ double nPPTY = aLogic.Y() / 1000.0;
+ Fraction aZoom(1,1);
+ rDoc.StyleSheetChanged( pStyle, false, pVDev, nPPTX, nPPTY, aZoom, aZoom );
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+ pDocShell->SetDocumentModified();
+
+ pStylePool->Remove( pStyle );
+
+ //! InvalidateAttribs(); // Bindings-Invalidate
+ }
+ else if ( eFamily == SfxStyleFamily::Page )
+ {
+ if ( rDoc.RemovePageStyleInUse( aString ) )
+ pDocShell->PageStyleModified( ScResId(STR_STYLENAME_STANDARD), true );
+
+ pStylePool->Remove( pStyle );
+
+ SfxBindings* pBindings = pDocShell->GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_STYLE_FAMILY4 );
+ pDocShell->SetDocumentModified();
+ }
+ else
+ {
+ pStylePool->Remove( pStyle );
+
+ SfxBindings* pBindings = pDocShell->GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_STYLE_FAMILY3 );
+ pDocShell->SetDocumentModified();
+ }
+ }
+ }
+
+ if (!bFound)
+ throw container::NoSuchElementException();
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScStyleFamilyObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+
+ SfxStyleSheetIterator aIter( pStylePool, eFamily );
+ return aIter.Count();
+ }
+ return 0;
+}
+
+uno::Any SAL_CALL ScStyleFamilyObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< style::XStyle > xObj(GetObjectByIndex_Impl(nIndex));
+ if (!xObj.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xObj);
+}
+
+uno::Type SAL_CALL ScStyleFamilyObj::getElementType()
+{
+ return cppu::UnoType<style::XStyle>::get(); // has to fit to getByIndex
+}
+
+sal_Bool SAL_CALL ScStyleFamilyObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// container::XNameAccess
+
+uno::Any SAL_CALL ScStyleFamilyObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< style::XStyle > xObj(
+ GetObjectByName_Impl( ScStyleNameConversion::ProgrammaticToDisplayName( aName, eFamily ) ));
+ if (!xObj.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xObj);
+}
+
+uno::Sequence<OUString> SAL_CALL ScStyleFamilyObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+
+ SfxStyleSheetIterator aIter( pStylePool, eFamily );
+ sal_uInt16 nCount = aIter.Count();
+
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ SfxStyleSheetBase* pStyle = aIter.First();
+ sal_uInt16 nPos = 0;
+ while (pStyle)
+ {
+ OSL_ENSURE( nPos < nCount, "Count is wrong" );
+ if (nPos < nCount)
+ pAry[nPos++] = ScStyleNameConversion::DisplayToProgrammaticName(
+ pStyle->GetName(), eFamily );
+ pStyle = aIter.Next();
+ }
+ return aSeq;
+ }
+ return uno::Sequence<OUString>();
+}
+
+sal_Bool SAL_CALL ScStyleFamilyObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ OUString aString(ScStyleNameConversion::ProgrammaticToDisplayName( aName, eFamily ));
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ if ( pStylePool->Find( aString, eFamily ) )
+ return true;
+ }
+ return false;
+}
+
+// XPropertySet
+
+uno::Reference< beans::XPropertySetInfo > SAL_CALL ScStyleFamilyObj::getPropertySetInfo( )
+{
+ OSL_FAIL( "###unexpected!" );
+ return uno::Reference< beans::XPropertySetInfo >();
+}
+
+void SAL_CALL ScStyleFamilyObj::setPropertyValue( const OUString&, const uno::Any& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+uno::Any SAL_CALL ScStyleFamilyObj::getPropertyValue( const OUString& sPropertyName )
+{
+ uno::Any aRet;
+
+ if ( sPropertyName != "DisplayName" )
+ {
+ throw beans::UnknownPropertyException( "unknown property: " + sPropertyName, getXWeak() );
+ }
+
+ SolarMutexGuard aGuard;
+ TranslateId pResId;
+ switch ( eFamily )
+ {
+ case SfxStyleFamily::Para:
+ pResId = STR_STYLE_FAMILY_CELL; break;
+ case SfxStyleFamily::Page:
+ pResId = STR_STYLE_FAMILY_PAGE; break;
+ case SfxStyleFamily::Frame:
+ pResId = STR_STYLE_FAMILY_GRAPHICS; break;
+ default:
+ OSL_FAIL( "ScStyleFamilyObj::getPropertyValue(): invalid family" );
+ }
+ if (pResId)
+ {
+ OUString sDisplayName(ScResId(pResId));
+ aRet <<= sDisplayName;
+ }
+
+ return aRet;
+}
+
+void SAL_CALL ScStyleFamilyObj::addPropertyChangeListener( const OUString&, const uno::Reference< beans::XPropertyChangeListener >& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+void SAL_CALL ScStyleFamilyObj::removePropertyChangeListener( const OUString&, const uno::Reference< beans::XPropertyChangeListener >& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+void SAL_CALL ScStyleFamilyObj::addVetoableChangeListener( const OUString&, const uno::Reference< beans::XVetoableChangeListener >& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+void SAL_CALL ScStyleFamilyObj::removeVetoableChangeListener( const OUString&, const uno::Reference< beans::XVetoableChangeListener >& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+// default ctor is needed for reflection
+
+ScStyleObj::ScStyleObj(ScDocShell* pDocSh, SfxStyleFamily eFam, OUString aName)
+ : pDocShell(pDocSh)
+ , eFamily(eFam)
+ , aStyleName(std::move(aName))
+ , pStyle_cached(nullptr)
+{
+ if (eFam == SfxStyleFamily::Para)
+ pPropSet = lcl_GetCellStyleSet();
+ else if (eFam == SfxStyleFamily::Page)
+ pPropSet = lcl_GetPageStyleSet();
+ else
+ pPropSet = lcl_GetGraphicStyleSet();
+
+ // if create by ServiceProvider then pDocShell is NULL
+
+ if (pDocShell)
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+void ScStyleObj::InitDoc( ScDocShell* pNewDocSh, const OUString& rNewName )
+{
+ if ( pNewDocSh && !pDocShell )
+ {
+ aStyleName = rNewName;
+ pDocShell = pNewDocSh;
+ pDocShell->GetDocument().AddUnoObject(*this);
+ }
+}
+
+ScStyleObj::~ScStyleObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScStyleObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // has become invalid
+ }
+}
+
+SfxStyleSheetBase* ScStyleObj::GetStyle_Impl( bool bUseCachedValue )
+{
+ if ( bUseCachedValue )
+ return pStyle_cached;
+
+ pStyle_cached = nullptr;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ pStyle_cached = pStylePool->Find( aStyleName, eFamily );
+ }
+ return pStyle_cached;
+}
+
+// style::XStyle
+
+sal_Bool SAL_CALL ScStyleObj::isUserDefined()
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (pStyle)
+ return pStyle->IsUserDefined();
+ return false;
+}
+
+sal_Bool SAL_CALL ScStyleObj::isInUse()
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (pStyle)
+ return pStyle->IsUsed();
+ return false;
+}
+
+OUString SAL_CALL ScStyleObj::getParentStyle()
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (pStyle)
+ return ScStyleNameConversion::DisplayToProgrammaticName( pStyle->GetParent(), eFamily );
+ return OUString();
+}
+
+void SAL_CALL ScStyleObj::setParentStyle( const OUString& rParentStyle )
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (!pStyle)
+ return;
+
+ // cell styles cannot be modified if any sheet is protected
+ if ( eFamily == SfxStyleFamily::Para && lcl_AnyTabProtected( pDocShell->GetDocument() ) )
+ return; //! exception?
+
+ //! DocFunc function??
+ //! Undo ?????????????
+
+ OUString aString(ScStyleNameConversion::ProgrammaticToDisplayName( rParentStyle, eFamily ));
+ bool bOk = pStyle->SetParent( aString );
+ if (!bOk)
+ return;
+
+ // as by setPropertyValue
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( eFamily == SfxStyleFamily::Para )
+ {
+ // update line height
+
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Point aLogic = pVDev->LogicToPixel( Point(1000,1000), MapMode(MapUnit::MapTwip));
+ double nPPTX = aLogic.X() / 1000.0;
+ double nPPTY = aLogic.Y() / 1000.0;
+ Fraction aZoom(1,1);
+ rDoc.StyleSheetChanged( pStyle, false, pVDev, nPPTX, nPPTY, aZoom, aZoom );
+
+ if (!rDoc.IsImportingXML())
+ {
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+ pDocShell->SetDocumentModified();
+ }
+ }
+ else if ( eFamily == SfxStyleFamily::Page )
+ {
+ //! ModifyStyleSheet on document (save old values)
+
+ pDocShell->PageStyleModified( aStyleName, true );
+ }
+ else
+ static_cast<SfxStyleSheet*>(GetStyle_Impl())->Broadcast(SfxHint(SfxHintId::DataChanged));
+}
+
+// container::XNamed
+
+OUString SAL_CALL ScStyleObj::getName()
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (pStyle)
+ return ScStyleNameConversion::DisplayToProgrammaticName( pStyle->GetName(), eFamily );
+ return OUString();
+}
+
+void SAL_CALL ScStyleObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (!pStyle)
+ return;
+
+ // cell styles cannot be renamed if any sheet is protected
+ if ( eFamily == SfxStyleFamily::Para && lcl_AnyTabProtected( pDocShell->GetDocument() ) )
+ return; //! exception?
+
+ //! DocFunc function??
+ //! Undo ?????????????
+
+ bool bOk = pStyle->SetName( aNewName );
+ if (!bOk)
+ return;
+
+ aStyleName = aNewName; //! notify other objects for this style?
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( eFamily == SfxStyleFamily::Para && !rDoc.IsImportingXML() )
+ rDoc.GetPool()->CellStyleCreated( aNewName, rDoc );
+
+ // cell styles = 2, drawing styles = 3, page styles = 4
+ sal_uInt16 nId = eFamily == SfxStyleFamily::Para ? SID_STYLE_FAMILY2 :
+ (eFamily == SfxStyleFamily::Page ? SID_STYLE_FAMILY4 : SID_STYLE_FAMILY3);
+ SfxBindings* pBindings = pDocShell->GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( nId );
+ pBindings->Invalidate( SID_STYLE_APPLY );
+ }
+}
+
+uno::Reference<container::XIndexReplace> ScStyleObj::CreateEmptyNumberingRules()
+{
+ SvxNumRule aRule( SvxNumRuleFlags::NONE, 0, true ); // nothing supported
+ return SvxCreateNumRule( aRule );
+}
+
+// beans::XPropertyState
+
+const SfxItemSet* ScStyleObj::GetStyleItemSet_Impl( std::u16string_view rPropName,
+ const SfxItemPropertyMapEntry*& rpResultEntry )
+{
+ SfxStyleSheetBase* pStyle = GetStyle_Impl( true );
+ if ( pStyle )
+ {
+ const SfxItemPropertyMapEntry* pEntry = nullptr;
+ if ( eFamily == SfxStyleFamily::Page )
+ {
+ pEntry = lcl_GetHeaderStyleMap()->getByName( rPropName );
+ if ( pEntry ) // only item-WIDs in header/footer map
+ {
+ rpResultEntry = pEntry;
+ return &pStyle->GetItemSet().Get(ATTR_PAGE_HEADERSET).GetItemSet();
+ }
+ pEntry = lcl_GetFooterStyleMap()->getByName( rPropName );
+ if ( pEntry ) // only item-WIDs in header/footer map
+ {
+ rpResultEntry = pEntry;
+ return &pStyle->GetItemSet().Get(ATTR_PAGE_FOOTERSET).GetItemSet();
+ }
+ }
+ pEntry = pPropSet->getPropertyMap().getByName( rPropName );
+ if ( pEntry )
+ {
+ rpResultEntry = pEntry;
+ return &pStyle->GetItemSet();
+ }
+ }
+
+ rpResultEntry = nullptr;
+ return nullptr;
+}
+
+beans::PropertyState ScStyleObj::getPropertyState_Impl( std::u16string_view aPropertyName )
+{
+ beans::PropertyState eRet = beans::PropertyState_DIRECT_VALUE;
+
+ const SfxItemPropertyMapEntry* pResultEntry = nullptr;
+ const SfxItemSet* pItemSet = GetStyleItemSet_Impl( aPropertyName, pResultEntry );
+
+ if ( pItemSet && pResultEntry )
+ {
+ sal_uInt16 nWhich = pResultEntry->nWID;
+ if ( nWhich == SC_WID_UNO_TBLBORD || nWhich == SC_WID_UNO_TBLBORD2 )
+ {
+ nWhich = ATTR_BORDER;
+ }
+ if ( nWhich == OWN_ATTR_FILLBMP_MODE )
+ {
+ if ( pItemSet->GetItemState( XATTR_FILLBMP_STRETCH, false ) == SfxItemState::SET ||
+ pItemSet->GetItemState( XATTR_FILLBMP_TILE, false ) == SfxItemState::SET )
+ {
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ }
+ else
+ {
+ eRet = beans::PropertyState_AMBIGUOUS_VALUE;
+ }
+ }
+ else if ( nWhich == SDRATTR_TEXTDIRECTION )
+ {
+ eRet = beans::PropertyState_DEFAULT_VALUE;
+ }
+ else if ( IsScItemWid( nWhich ) || eFamily == SfxStyleFamily::Frame )
+ {
+ SfxItemState eState = pItemSet->GetItemState( nWhich, false );
+
+// // if no rotate value is set, look at orientation
+// //! also for a fixed value of 0 (in case orientation is ambiguous)?
+// if ( nWhich == ATTR_ROTATE_VALUE && eState == SfxItemState::DEFAULT )
+// eState = pItemSet->GetItemState( ATTR_ORIENTATION, sal_False );
+
+ if ( eState == SfxItemState::SET )
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ else if ( eState == SfxItemState::DEFAULT )
+ eRet = beans::PropertyState_DEFAULT_VALUE;
+ else
+ {
+ assert(eFamily == SfxStyleFamily::Frame);
+ eRet = beans::PropertyState_AMBIGUOUS_VALUE;
+ }
+ }
+ }
+ return eRet;
+}
+
+beans::PropertyState SAL_CALL ScStyleObj::getPropertyState( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ return getPropertyState_Impl( aPropertyName );
+}
+
+uno::Sequence<beans::PropertyState> SAL_CALL ScStyleObj::getPropertyStates( const uno::Sequence<OUString>& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ uno::Sequence<beans::PropertyState> aRet( aPropertyNames.getLength() );
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.getArray(),
+ [this](const OUString& rName) -> beans::PropertyState { return getPropertyState_Impl(rName); });
+ return aRet;
+}
+
+void SAL_CALL ScStyleObj::setPropertyToDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ const SfxItemPropertyMapEntry* pEntry = pPropSet->getPropertyMap().getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ setPropertyValue_Impl( aPropertyName, pEntry, nullptr );
+}
+
+uno::Any ScStyleObj::getPropertyDefault_Impl( std::u16string_view aPropertyName )
+{
+ uno::Any aAny;
+
+ const SfxItemPropertyMapEntry* pResultEntry = nullptr;
+ const SfxItemSet* pStyleSet = GetStyleItemSet_Impl( aPropertyName, pResultEntry );
+
+ if ( pStyleSet && pResultEntry )
+ {
+ sal_uInt16 nWhich = pResultEntry->nWID;
+
+ if ( IsScItemWid( nWhich ) )
+ {
+ // Default is default from ItemPool, not from Standard-Style,
+ // so it is the same as in setPropertyToDefault
+ SfxItemSet aEmptySet( *pStyleSet->GetPool(), pStyleSet->GetRanges() );
+ // default items with wrong Slot-ID are not functional in SfxItemPropertySet3
+ //! change Slot-IDs...
+ if ( aEmptySet.GetPool()->GetSlotId(nWhich) == nWhich &&
+ aEmptySet.GetItemState(nWhich, false) == SfxItemState::DEFAULT )
+ {
+ aEmptySet.Put( aEmptySet.Get( nWhich ) );
+ }
+ const SfxItemSet* pItemSet = &aEmptySet;
+
+ switch ( nWhich ) // special item handling
+ {
+ case ATTR_VALUE_FORMAT:
+ // default has no language set
+ aAny <<= sal_Int32( static_cast<const SfxUInt32Item&>(pItemSet->Get(nWhich)).GetValue() );
+ break;
+ case ATTR_INDENT:
+ aAny <<= sal_Int16( convertTwipToMm100(static_cast<const ScIndentItem&>(
+ pItemSet->Get(nWhich)).GetValue()) );
+ break;
+ case ATTR_PAGE_SCALE:
+ case ATTR_PAGE_SCALETOPAGES:
+ case ATTR_PAGE_FIRSTPAGENO:
+ aAny <<= sal_Int16( static_cast<const SfxUInt16Item&>(pItemSet->Get(nWhich)).GetValue() );
+ break;
+ case ATTR_PAGE_CHARTS:
+ case ATTR_PAGE_OBJECTS:
+ case ATTR_PAGE_DRAWINGS:
+ //! define sal_Bool-MID for ScViewObjectModeItem?
+ aAny <<= static_cast<const ScViewObjectModeItem&>(pItemSet->Get(nWhich)).GetValue() == VOBJ_MODE_SHOW;
+ break;
+ case ATTR_PAGE_SCALETO:
+ {
+ const ScPageScaleToItem aItem(static_cast<const ScPageScaleToItem&>(pItemSet->Get(nWhich)));
+ if ( aPropertyName == SC_UNO_PAGE_SCALETOX )
+ aAny <<= static_cast<sal_Int16>(aItem.GetWidth());
+ else
+ aAny <<= static_cast<sal_Int16>(aItem.GetHeight());
+ }
+ break;
+ default:
+ pPropSet->getPropertyValue( *pResultEntry, *pItemSet, aAny );
+ }
+ }
+ else if ( IsScUnoWid( nWhich ) )
+ {
+ SfxItemSet aEmptySet( *pStyleSet->GetPool(), pStyleSet->GetRanges() );
+ const SfxItemSet* pItemSet = &aEmptySet;
+ switch ( nWhich )
+ {
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ {
+ const SfxPoolItem& rItem = pItemSet->Get(ATTR_BORDER);
+ SvxBoxItem aOuter(static_cast<const SvxBoxItem&>(rItem));
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ if (nWhich == SC_WID_UNO_TBLBORD2)
+ ScHelperFunctions::AssignTableBorder2ToAny(aAny, aOuter, aInner, true);
+ else
+ ScHelperFunctions::AssignTableBorderToAny(aAny, aOuter, aInner, true);
+ }
+ break;
+ }
+ }
+ else if ( nWhich == SDRATTR_TEXTDIRECTION )
+ {
+ aAny <<= false;
+ }
+ else if ( nWhich == OWN_ATTR_FILLBMP_MODE )
+ {
+ aAny <<= css::drawing::BitmapMode_REPEAT;
+ }
+ else if ( nWhich != OWN_ATTR_TEXTCOLUMNS )
+ {
+ SfxItemSet aItemSet(*pStyleSet->GetPool(), pStyleSet->GetRanges());
+ aAny = SvxItemPropertySet_getPropertyValue(pResultEntry, aItemSet);
+ }
+ }
+ return aAny;
+}
+
+uno::Any SAL_CALL ScStyleObj::getPropertyDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ return getPropertyDefault_Impl( aPropertyName );
+}
+
+uno::Sequence<uno::Any> SAL_CALL ScStyleObj::getPropertyDefaults( const uno::Sequence<OUString>& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ uno::Sequence<uno::Any> aSequence( aPropertyNames.getLength() );
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aSequence.getArray(),
+ [this](const OUString& rName) -> uno::Any { return getPropertyDefault_Impl(rName); });
+ return aSequence;
+}
+
+// XMultiPropertySet
+
+void SAL_CALL ScStyleObj::setPropertyValues( const uno::Sequence< OUString >& aPropertyNames,
+ const uno::Sequence< uno::Any >& aValues )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ if ( aValues.getLength() != aPropertyNames.getLength() )
+ throw lang::IllegalArgumentException();
+
+ const OUString* pNames = aPropertyNames.getConstArray();
+ const uno::Any* pValues = aValues.getConstArray();
+ const SfxItemPropertyMap& rPropertyMap = pPropSet->getPropertyMap();
+ for ( sal_Int32 i = 0; i < aPropertyNames.getLength(); i++ )
+ {
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( pNames[i] );
+ setPropertyValue_Impl( pNames[i], pEntry, &pValues[i] );
+ }
+}
+
+uno::Sequence<uno::Any> SAL_CALL ScStyleObj::getPropertyValues( const uno::Sequence< OUString >& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ uno::Sequence<uno::Any> aSequence( aPropertyNames.getLength() );
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aSequence.getArray(),
+ [this](const OUString& rName) -> uno::Any { return getPropertyValue_Impl(rName); });
+ return aSequence;
+}
+
+void SAL_CALL ScStyleObj::addPropertiesChangeListener( const uno::Sequence<OUString>& /* aPropertyNames */,
+ const uno::Reference<beans::XPropertiesChangeListener>& /* xListener */ )
+{
+ // no bound properties
+}
+
+void SAL_CALL ScStyleObj::removePropertiesChangeListener(
+ const uno::Reference<beans::XPropertiesChangeListener>& /* xListener */ )
+{
+ // no bound properties
+}
+
+void SAL_CALL ScStyleObj::firePropertiesChangeEvent( const uno::Sequence<OUString>& /* aPropertyNames */,
+ const uno::Reference<beans::XPropertiesChangeListener>& /* xListener */ )
+{
+ // no bound properties
+}
+
+// XMultiPropertyStates
+// getPropertyStates already defined for XPropertyState
+
+void SAL_CALL ScStyleObj::setAllPropertiesToDefault()
+{
+ SolarMutexGuard aGuard;
+
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if ( !pStyle )
+ return;
+
+ // cell styles cannot be modified if any sheet is protected
+ if ( eFamily == SfxStyleFamily::Para && lcl_AnyTabProtected( pDocShell->GetDocument() ) )
+ throw uno::RuntimeException();
+
+ SfxItemSet& rSet = pStyle->GetItemSet();
+ rSet.ClearItem(); // set all items to default
+
+ //! merge with SetOneProperty
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( eFamily == SfxStyleFamily::Para )
+ {
+ // row heights
+
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Point aLogic = pVDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
+ double nPPTX = aLogic.X() / 1000.0;
+ double nPPTY = aLogic.Y() / 1000.0;
+ Fraction aZoom(1,1);
+ rDoc.StyleSheetChanged( pStyle, false, pVDev, nPPTX, nPPTY, aZoom, aZoom );
+
+ if (!rDoc.IsImportingXML())
+ {
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+ pDocShell->SetDocumentModified();
+ }
+ }
+ else if ( eFamily == SfxStyleFamily::Page )
+ {
+ // #i22448# apply the default BoxInfoItem for page styles again
+ // (same content as in ScStyleSheet::GetItemSet, to control the dialog)
+ SvxBoxInfoItem aBoxInfoItem( ATTR_BORDER_INNER );
+ aBoxInfoItem.SetTable( false );
+ aBoxInfoItem.SetDist( true );
+ aBoxInfoItem.SetValid( SvxBoxInfoItemValidFlags::DISTANCE );
+ rSet.Put( aBoxInfoItem );
+
+ pDocShell->PageStyleModified( aStyleName, true );
+ }
+ else
+ static_cast<SfxStyleSheet*>(GetStyle_Impl())->Broadcast(SfxHint(SfxHintId::DataChanged));
+}
+
+void SAL_CALL ScStyleObj::setPropertiesToDefault( const uno::Sequence<OUString>& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ const SfxItemPropertyMap& rPropertyMap = pPropSet->getPropertyMap();
+ for ( const OUString& rName : aPropertyNames )
+ {
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( rName );
+ setPropertyValue_Impl( rName, pEntry, nullptr );
+ }
+}
+
+// beans::XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScStyleObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ return pPropSet->getPropertySetInfo();
+}
+
+void SAL_CALL ScStyleObj::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ const SfxItemPropertyMapEntry* pEntry = pPropSet->getPropertyMap().getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ setPropertyValue_Impl( aPropertyName, pEntry, &aValue );
+}
+
+void ScStyleObj::setPropertyValue_Impl( std::u16string_view rPropertyName, const SfxItemPropertyMapEntry* pEntry, const uno::Any* pValue )
+{
+ SfxStyleSheetBase* pStyle = GetStyle_Impl( true );
+ if ( !(pStyle && pEntry) )
+ return;
+
+ // cell styles cannot be modified if any sheet is protected
+ if ( eFamily == SfxStyleFamily::Para && lcl_AnyTabProtected( pDocShell->GetDocument() ) )
+ throw uno::RuntimeException();
+
+ SfxItemSet& rSet = pStyle->GetItemSet(); // change directly in active Style
+ bool bDone = false;
+ if ( eFamily == SfxStyleFamily::Page )
+ {
+ if(pEntry->nWID == SC_WID_UNO_HEADERSET)
+ {
+ const SfxItemPropertyMapEntry* pHeaderEntry = lcl_GetHeaderStyleMap()->getByName( rPropertyName );
+ if ( pHeaderEntry ) // only item-WIDs in header/footer map
+ {
+ SvxSetItem aNewHeader( rSet.Get(ATTR_PAGE_HEADERSET) );
+ if (pValue)
+ pPropSet->setPropertyValue( *pHeaderEntry, *pValue, aNewHeader.GetItemSet() );
+ else
+ aNewHeader.GetItemSet().ClearItem( pHeaderEntry->nWID );
+ rSet.Put( aNewHeader );
+ bDone = true;
+ }
+ }
+ else if(pEntry->nWID == SC_WID_UNO_FOOTERSET)
+ {
+ const SfxItemPropertyMapEntry* pFooterEntry = lcl_GetFooterStyleMap()->getByName( rPropertyName );
+ if ( pFooterEntry ) // only item-WIDs in header/footer map
+ {
+ SvxSetItem aNewFooter( rSet.Get(ATTR_PAGE_FOOTERSET) );
+ if (pValue)
+ pPropSet->setPropertyValue( *pFooterEntry, *pValue, aNewFooter.GetItemSet() );
+ else
+ aNewFooter.GetItemSet().ClearItem( pFooterEntry->nWID );
+ rSet.Put( aNewFooter );
+ bDone = true;
+ }
+ }
+ }
+ if (!bDone)
+ {
+ if (IsScItemWid(pEntry->nWID))
+ {
+ if (pValue)
+ {
+ switch (pEntry->nWID) // special item handling
+ {
+ case ATTR_VALUE_FORMAT:
+ {
+ // language for number formats
+ SvNumberFormatter* pFormatter
+ = pDocShell->GetDocument().GetFormatTable();
+ sal_uInt32 nOldFormat = rSet.Get(ATTR_VALUE_FORMAT).GetValue();
+ LanguageType eOldLang
+ = rSet.Get(ATTR_LANGUAGE_FORMAT).GetLanguage();
+ pFormatter->GetFormatForLanguageIfBuiltIn(nOldFormat, eOldLang);
+
+ sal_uInt32 nNewFormat = 0;
+ *pValue >>= nNewFormat;
+ rSet.Put(SfxUInt32Item(ATTR_VALUE_FORMAT, nNewFormat));
+
+ const SvNumberformat* pNewEntry = pFormatter->GetEntry(nNewFormat);
+ LanguageType eNewLang
+ = pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
+ if (eNewLang != eOldLang && eNewLang != LANGUAGE_DONTKNOW)
+ rSet.Put(SvxLanguageItem(eNewLang, ATTR_LANGUAGE_FORMAT));
+
+ //! keep default state of number format if only language changed?
+ }
+ break;
+ case ATTR_INDENT:
+ {
+ sal_Int16 nVal = 0;
+ *pValue >>= nVal;
+ rSet.Put(ScIndentItem(o3tl::toTwips(nVal, o3tl::Length::mm100)));
+ }
+ break;
+ case ATTR_ROTATE_VALUE:
+ {
+ sal_Int32 nRotVal = 0;
+ if (*pValue >>= nRotVal)
+ {
+ // stored value is always between 0 and 360 deg.
+ nRotVal %= 36000;
+ if (nRotVal < 0)
+ nRotVal += 36000;
+ rSet.Put(ScRotateValueItem(Degree100(nRotVal)));
+ }
+ }
+ break;
+ case ATTR_STACKED:
+ {
+ table::CellOrientation eOrient;
+ if (*pValue >>= eOrient)
+ {
+ switch (eOrient)
+ {
+ case table::CellOrientation_STANDARD:
+ rSet.Put(ScVerticalStackCell(false));
+ break;
+ case table::CellOrientation_TOPBOTTOM:
+ rSet.Put(ScVerticalStackCell(false));
+ rSet.Put(ScRotateValueItem(27000_deg100));
+ break;
+ case table::CellOrientation_BOTTOMTOP:
+ rSet.Put(ScVerticalStackCell(false));
+ rSet.Put(ScRotateValueItem(9000_deg100));
+ break;
+ case table::CellOrientation_STACKED:
+ rSet.Put(ScVerticalStackCell(true));
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ break;
+ case ATTR_PAGE_SCALE:
+ case ATTR_PAGE_SCALETOPAGES:
+ {
+ rSet.ClearItem(ATTR_PAGE_SCALETOPAGES);
+ rSet.ClearItem(ATTR_PAGE_SCALE);
+ rSet.ClearItem(ATTR_PAGE_SCALETO);
+ sal_Int16 nVal = 0;
+ *pValue >>= nVal;
+ rSet.Put(SfxUInt16Item(pEntry->nWID, nVal));
+ }
+ break;
+ case ATTR_PAGE_FIRSTPAGENO:
+ {
+ sal_Int16 nVal = 0;
+ *pValue >>= nVal;
+ rSet.Put(SfxUInt16Item(ATTR_PAGE_FIRSTPAGENO, nVal));
+ }
+ break;
+ case ATTR_PAGE_CHARTS:
+ case ATTR_PAGE_OBJECTS:
+ case ATTR_PAGE_DRAWINGS:
+ {
+ bool bBool = false;
+ *pValue >>= bBool;
+ //! need to define sal_Bool-MID for ScViewObjectModeItem?
+ rSet.Put(ScViewObjectModeItem(
+ pEntry->nWID, bBool ? VOBJ_MODE_SHOW : VOBJ_MODE_HIDE));
+ }
+ break;
+ case ATTR_PAGE_PAPERBIN:
+ {
+ sal_uInt8 nTray = PAPERBIN_PRINTER_SETTINGS;
+ bool bFound = false;
+
+ OUString aName;
+ if (*pValue >>= aName)
+ {
+ if (aName == SC_PAPERBIN_DEFAULTNAME)
+ bFound = true;
+ else
+ {
+ Printer* pPrinter = pDocShell->GetPrinter();
+ if (pPrinter)
+ {
+ const sal_uInt16 nCount = pPrinter->GetPaperBinCount();
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ if (aName == pPrinter->GetPaperBinName(i))
+ {
+ nTray = static_cast<sal_uInt8>(i);
+ bFound = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!bFound)
+ throw lang::IllegalArgumentException();
+
+ rSet.Put(SvxPaperBinItem(ATTR_PAGE_PAPERBIN, nTray));
+
+ }
+ break;
+ case ATTR_PAGE_SCALETO:
+ {
+ sal_Int16 nPages = 0;
+ if (*pValue >>= nPages)
+ {
+ ScPageScaleToItem aItem = rSet.Get(ATTR_PAGE_SCALETO);
+ if (rPropertyName == SC_UNO_PAGE_SCALETOX)
+ aItem.SetWidth(static_cast<sal_uInt16>(nPages));
+ else
+ aItem.SetHeight(static_cast<sal_uInt16>(nPages));
+ rSet.Put(aItem);
+ rSet.ClearItem(ATTR_PAGE_SCALETOPAGES);
+ rSet.ClearItem(ATTR_PAGE_SCALE);
+ }
+ }
+ break;
+ case ATTR_HIDDEN:
+ {
+ bool bHidden = false;
+ if (*pValue >>= bHidden)
+ pStyle->SetHidden(bHidden);
+ }
+ break;
+ default:
+ // default items with wrong Slot-ID are not working in SfxItemPropertySet3
+ //! change Slot-IDs...
+ if (rSet.GetPool()->GetSlotId(pEntry->nWID) == pEntry->nWID
+ && rSet.GetItemState(pEntry->nWID, false) == SfxItemState::DEFAULT)
+ {
+ rSet.Put(rSet.Get(pEntry->nWID));
+ }
+ pPropSet->setPropertyValue(*pEntry, *pValue, rSet);
+ }
+ }
+ else
+ {
+ rSet.ClearItem(pEntry->nWID);
+ // language for number formats
+ if (pEntry->nWID == ATTR_VALUE_FORMAT)
+ rSet.ClearItem(ATTR_LANGUAGE_FORMAT);
+
+ //! for ATTR_ROTATE_VALUE, also reset ATTR_ORIENTATION?
+ }
+ }
+ else if (IsScUnoWid(pEntry->nWID))
+ {
+ switch (pEntry->nWID)
+ {
+ case SC_WID_UNO_TBLBORD:
+ {
+ if (pValue)
+ {
+ table::TableBorder aBorder;
+ if (*pValue >>= aBorder)
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems(aOuter, aInner, aBorder);
+ rSet.Put(aOuter);
+ }
+ }
+ else
+ {
+ rSet.ClearItem(ATTR_BORDER);
+ }
+ }
+ break;
+ case SC_WID_UNO_TBLBORD2:
+ {
+ if (pValue)
+ {
+ table::TableBorder2 aBorder2;
+ if (*pValue >>= aBorder2)
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems(aOuter, aInner, aBorder2);
+ rSet.Put(aOuter);
+ }
+ }
+ else
+ {
+ rSet.ClearItem(ATTR_BORDER);
+ }
+ }
+ break;
+ }
+ }
+ else if (pEntry->nWID == OWN_ATTR_FILLBMP_MODE)
+ {
+ css::drawing::BitmapMode eMode;
+ if (!pValue)
+ {
+ rSet.ClearItem(XATTR_FILLBMP_STRETCH);
+ rSet.ClearItem(XATTR_FILLBMP_TILE);
+ }
+ else if (*pValue >>= eMode)
+ {
+ rSet.Put(XFillBmpStretchItem(eMode == css::drawing::BitmapMode_STRETCH));
+ rSet.Put(XFillBmpTileItem(eMode == css::drawing::BitmapMode_REPEAT));
+ }
+ }
+ else if(pEntry->nMemberId == MID_NAME &&
+ (pEntry->nWID == XATTR_FILLBITMAP || pEntry->nWID == XATTR_FILLGRADIENT ||
+ pEntry->nWID == XATTR_FILLHATCH || pEntry->nWID == XATTR_FILLFLOATTRANSPARENCE ||
+ pEntry->nWID == XATTR_LINESTART || pEntry->nWID == XATTR_LINEEND || pEntry->nWID == XATTR_LINEDASH))
+ {
+ OUString aTempName;
+ if (*pValue >>= aTempName)
+ SvxShape::SetFillAttribute(pEntry->nWID, aTempName, rSet);
+ }
+ else if(pEntry->nWID == SDRATTR_TEXTDIRECTION)
+ {
+ return; // not yet implemented for styles
+ }
+ else if(!SvxUnoTextRangeBase::SetPropertyValueHelper(pEntry, *pValue, rSet))
+ {
+ SvxItemPropertySet_setPropertyValue(pEntry, *pValue, rSet);
+ }
+ }
+
+ //! DocFunc-??
+ //! Undo ??
+
+ if ( eFamily == SfxStyleFamily::Para )
+ {
+ // If we are loading, we can delay line height calculation, because we are going to re-calc all of those
+ // after load.
+ if (pDocShell && !pDocShell->IsLoading())
+ {
+ // update line height
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Point aLogic = pVDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
+ double nPPTX = aLogic.X() / 1000.0;
+ double nPPTY = aLogic.Y() / 1000.0;
+ Fraction aZoom(1,1);
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.StyleSheetChanged( pStyle, false, pVDev, nPPTX, nPPTY, aZoom, aZoom );
+
+ if (!rDoc.IsImportingXML())
+ {
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+ pDocShell->SetDocumentModified();
+ }
+ }
+ }
+ else if ( eFamily == SfxStyleFamily::Page )
+ {
+ //! ModifyStyleSheet on document (save old values)
+
+ pDocShell->PageStyleModified( aStyleName, true );
+ }
+ else
+ static_cast<SfxStyleSheet*>(GetStyle_Impl())->Broadcast(SfxHint(SfxHintId::DataChanged));
+}
+
+uno::Any ScStyleObj::getPropertyValue_Impl( std::u16string_view aPropertyName )
+{
+ uno::Any aAny;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl( true );
+
+ if ( aPropertyName == SC_UNONAME_DISPNAME ) // read-only
+ {
+ // core always has the display name
+ if ( pStyle )
+ aAny <<= pStyle->GetName();
+ }
+ else
+ {
+ const SfxItemPropertyMapEntry* pResultEntry = nullptr;
+ const SfxItemSet* pItemSet = GetStyleItemSet_Impl( aPropertyName, pResultEntry );
+
+ if ( pItemSet && pResultEntry )
+ {
+ sal_uInt16 nWhich = pResultEntry->nWID;
+
+ if ( IsScItemWid( nWhich ) )
+ {
+ switch ( nWhich ) // for special item handling
+ {
+ case ATTR_VALUE_FORMAT:
+ if ( pDocShell )
+ {
+ sal_uInt32 nOldFormat =
+ pItemSet->Get( ATTR_VALUE_FORMAT ).GetValue();
+ LanguageType eOldLang =
+ pItemSet->Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
+ nOldFormat = pDocShell->GetDocument().GetFormatTable()->
+ GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
+ aAny <<= nOldFormat;
+ }
+ break;
+ case ATTR_INDENT:
+ aAny <<= sal_Int16( convertTwipToMm100(static_cast<const ScIndentItem&>(
+ pItemSet->Get(nWhich)).GetValue()) );
+ break;
+ case ATTR_STACKED:
+ {
+ Degree100 nRot = pItemSet->Get(ATTR_ROTATE_VALUE).GetValue();
+ bool bStacked = static_cast<const ScVerticalStackCell&>(pItemSet->Get(nWhich)).GetValue();
+ SvxOrientationItem( nRot, bStacked, TypedWhichId<SvxOrientationItem>(0) ).QueryValue( aAny );
+ }
+ break;
+ case ATTR_PAGE_SCALE:
+ case ATTR_PAGE_SCALETOPAGES:
+ case ATTR_PAGE_FIRSTPAGENO:
+ aAny <<= sal_Int16( static_cast<const SfxUInt16Item&>(pItemSet->Get(nWhich)).GetValue() );
+ break;
+ case ATTR_PAGE_CHARTS:
+ case ATTR_PAGE_OBJECTS:
+ case ATTR_PAGE_DRAWINGS:
+ //! define sal_Bool-MID for ScViewObjectModeItem?
+ aAny <<= static_cast<const ScViewObjectModeItem&>(pItemSet->Get(nWhich)).GetValue() == VOBJ_MODE_SHOW;
+ break;
+ case ATTR_PAGE_PAPERBIN:
+ {
+ // property PrinterPaperTray is the name of the tray
+
+ sal_uInt8 nValue = static_cast<const SvxPaperBinItem&>(pItemSet->Get(nWhich)).GetValue();
+ OUString aName;
+ if ( nValue == PAPERBIN_PRINTER_SETTINGS )
+ aName = SC_PAPERBIN_DEFAULTNAME;
+ else
+ {
+ Printer* pPrinter = pDocShell->GetPrinter();
+ if (pPrinter)
+ aName = pPrinter->GetPaperBinName( nValue );
+ }
+ aAny <<= aName;
+ }
+ break;
+ case ATTR_PAGE_SCALETO:
+ {
+ const ScPageScaleToItem& aItem(pItemSet->Get(ATTR_PAGE_SCALETO));
+ if ( aPropertyName == SC_UNO_PAGE_SCALETOX )
+ aAny <<= static_cast<sal_Int16>(aItem.GetWidth());
+ else
+ aAny <<= static_cast<sal_Int16>(aItem.GetHeight());
+ }
+ break;
+ case ATTR_HIDDEN:
+ {
+ bool bHidden = pStyle && pStyle->IsHidden();
+ aAny <<= bHidden;
+ }
+ break;
+ default:
+ // Default-Items with wrong Slot-ID don't work in SfxItemPropertySet3
+ //! change Slot-IDs...
+ if ( pItemSet->GetPool()->GetSlotId(nWhich) == nWhich &&
+ pItemSet->GetItemState(nWhich, false) == SfxItemState::DEFAULT )
+ {
+ SfxItemSet aNoEmptySet( *pItemSet );
+ aNoEmptySet.Put( aNoEmptySet.Get( nWhich ) );
+ pPropSet->getPropertyValue( *pResultEntry, aNoEmptySet, aAny );
+ }
+ else
+ pPropSet->getPropertyValue( *pResultEntry, *pItemSet, aAny );
+ }
+ }
+ else if ( IsScUnoWid( nWhich ) )
+ {
+ switch ( nWhich )
+ {
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ {
+ const SfxPoolItem& rItem = pItemSet->Get(ATTR_BORDER);
+ SvxBoxItem aOuter(static_cast<const SvxBoxItem&>(rItem));
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ if (nWhich == SC_WID_UNO_TBLBORD2)
+ ScHelperFunctions::AssignTableBorder2ToAny(aAny, aOuter, aInner,
+ true);
+ else
+ ScHelperFunctions::AssignTableBorderToAny(aAny, aOuter, aInner,
+ true);
+ }
+ break;
+ }
+ }
+ else if ( nWhich == SDRATTR_TEXTDIRECTION )
+ {
+ aAny <<= false;
+ }
+ else if ( nWhich == OWN_ATTR_FILLBMP_MODE )
+ {
+ const XFillBmpStretchItem* pStretchItem = pItemSet->GetItem<XFillBmpStretchItem>(XATTR_FILLBMP_STRETCH);
+ const XFillBmpTileItem* pTileItem = pItemSet->GetItem<XFillBmpTileItem>(XATTR_FILLBMP_TILE);
+
+ if ( pStretchItem && pTileItem )
+ {
+ if ( pTileItem->GetValue() )
+ aAny <<= css::drawing::BitmapMode_REPEAT;
+ else if ( pStretchItem->GetValue() )
+ aAny <<= css::drawing::BitmapMode_STRETCH;
+ else
+ aAny <<= css::drawing::BitmapMode_NO_REPEAT;
+ }
+ }
+ else if ( nWhich != OWN_ATTR_TEXTCOLUMNS )
+ {
+ if (!SvxUnoTextRangeBase::GetPropertyValueHelper(*pItemSet, pResultEntry, aAny))
+ aAny = SvxItemPropertySet_getPropertyValue(pResultEntry, *pItemSet);
+
+ // since the sfx uint16 item now exports a sal_Int32, we may have to fix this here
+ if (pResultEntry->aType == ::cppu::UnoType<sal_Int16>::get() &&
+ aAny.getValueType() == ::cppu::UnoType<sal_Int32>::get())
+ {
+ aAny <<= static_cast<sal_Int16>(aAny.get<sal_Int32>());
+ }
+ }
+ }
+ }
+
+ return aAny;
+}
+
+uno::Any SAL_CALL ScStyleObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ return getPropertyValue_Impl( aPropertyName );
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScStyleObj )
+
+// lang::XServiceInfo
+
+OUString SAL_CALL ScStyleObj::getImplementationName()
+{
+ return "ScStyleObj";
+}
+
+sal_Bool SAL_CALL ScStyleObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScStyleObj::getSupportedServiceNames()
+{
+ if (eFamily == SfxStyleFamily::Page)
+ return {SCSTYLE_SERVICE, SCPAGESTYLE_SERVICE};
+
+ if (eFamily == SfxStyleFamily::Frame)
+ return {SCSTYLE_SERVICE, SCGRAPHICSTYLE_SERVICE};
+
+ return {SCSTYLE_SERVICE, SCCELLSTYLE_SERVICE};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/targuno.cxx b/sc/source/ui/unoobj/targuno.cxx
new file mode 100644
index 0000000000..635c918f36
--- /dev/null
+++ b/sc/source/ui/unoobj/targuno.cxx
@@ -0,0 +1,293 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <svl/itemprop.hxx>
+#include <svl/hint.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include <targuno.hxx>
+#include <miscuno.hxx>
+#include <docuno.hxx>
+#include <datauno.hxx>
+#include <nameuno.hxx>
+#include <docsh.hxx>
+#include <content.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <unonames.hxx>
+
+using namespace ::com::sun::star;
+
+const TranslateId aTypeResIds[SC_LINKTARGETTYPE_COUNT] =
+{
+ SCSTR_CONTENT_TABLE, // SC_LINKTARGETTYPE_SHEET
+ SCSTR_CONTENT_RANGENAME, // SC_LINKTARGETTYPE_RANGENAME
+ SCSTR_CONTENT_DBAREA // SC_LINKTARGETTYPE_DBAREA
+};
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetLinkTargetMap()
+{
+ static const SfxItemPropertyMapEntry aLinkTargetMap_Impl[] =
+ {
+ { SC_UNO_LINKDISPBIT, 0, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_LINKDISPNAME, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ };
+ return aLinkTargetMap_Impl;
+}
+
+// service for ScLinkTargetTypeObj is not defined
+// must not support document::LinkTarget because the target type cannot be used as a target
+
+SC_SIMPLE_SERVICE_INFO( ScLinkTargetTypesObj, "ScLinkTargetTypesObj", "com.sun.star.document.LinkTargets" )
+SC_SIMPLE_SERVICE_INFO( ScLinkTargetTypeObj, "ScLinkTargetTypeObj", "com.sun.star.document.LinkTargetSupplier" )
+SC_SIMPLE_SERVICE_INFO( ScLinkTargetsObj, "ScLinkTargetsObj", "com.sun.star.document.LinkTargets" )
+
+ScLinkTargetTypesObj::ScLinkTargetTypesObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ for (sal_uInt16 i=0; i<SC_LINKTARGETTYPE_COUNT; i++)
+ aNames[i] = ScResId(aTypeResIds[i]);
+}
+
+ScLinkTargetTypesObj::~ScLinkTargetTypesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScLinkTargetTypesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // document gone
+}
+
+// container::XNameAccess
+
+uno::Any SAL_CALL ScLinkTargetTypesObj::getByName(const OUString& aName)
+{
+ if (pDocShell)
+ {
+ for (sal_uInt16 i=0; i<SC_LINKTARGETTYPE_COUNT; i++)
+ if ( aNames[i] == aName )
+ return uno::Any(uno::Reference< beans::XPropertySet >(new ScLinkTargetTypeObj( pDocShell, i )));
+ }
+
+ throw container::NoSuchElementException();
+}
+
+uno::Sequence<OUString> SAL_CALL ScLinkTargetTypesObj::getElementNames()
+{
+ uno::Sequence<OUString> aRet(SC_LINKTARGETTYPE_COUNT);
+ OUString* pArray = aRet.getArray();
+ for (sal_uInt16 i=0; i<SC_LINKTARGETTYPE_COUNT; i++)
+ pArray[i] = aNames[i];
+ return aRet;
+}
+
+sal_Bool SAL_CALL ScLinkTargetTypesObj::hasByName(const OUString& aName)
+{
+ for (const auto & i : aNames)
+ if ( i == aName )
+ return true;
+ return false;
+}
+
+// container::XElementAccess
+
+uno::Type SAL_CALL ScLinkTargetTypesObj::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL ScLinkTargetTypesObj::hasElements()
+{
+ return true;
+}
+
+ScLinkTargetTypeObj::ScLinkTargetTypeObj(ScDocShell* pDocSh, sal_uInt16 nT) :
+ pDocShell( pDocSh ),
+ nType( nT )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+ aName = ScResId(aTypeResIds[nType]); //! on demand?
+}
+
+ScLinkTargetTypeObj::~ScLinkTargetTypeObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScLinkTargetTypeObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // document gone
+}
+
+// document::XLinkTargetSupplier
+
+uno::Reference< container::XNameAccess > SAL_CALL ScLinkTargetTypeObj::getLinks()
+{
+ uno::Reference< container::XNameAccess > xCollection;
+
+ if ( pDocShell )
+ {
+ switch ( nType )
+ {
+ case SC_LINKTARGETTYPE_SHEET:
+ xCollection.set(new ScTableSheetsObj(pDocShell));
+ break;
+ case SC_LINKTARGETTYPE_RANGENAME:
+ xCollection.set(new ScGlobalNamedRangesObj(pDocShell));
+ break;
+ case SC_LINKTARGETTYPE_DBAREA:
+ xCollection.set(new ScDatabaseRangesObj(pDocShell));
+ break;
+ default:
+ OSL_FAIL("invalid type");
+ }
+ }
+
+ // wrap collection in ScLinkTargetsObj because service document::LinkTargets requires
+ // beans::XPropertySet as ElementType in container::XNameAccess.
+ if ( xCollection.is() )
+ return new ScLinkTargetsObj( xCollection );
+ return nullptr;
+}
+
+// beans::XPropertySet
+
+uno::Reference< beans::XPropertySetInfo > SAL_CALL ScLinkTargetTypeObj::getPropertySetInfo()
+{
+ static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetLinkTargetMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScLinkTargetTypeObj::setPropertyValue(const OUString& /* aPropertyName */,
+ const uno::Any& /* aValue */)
+{
+ // everything is read-only
+ //! exception?
+}
+
+constexpr OUString aContentBmps[]=
+{
+ RID_BMP_CONTENT_TABLE,
+ RID_BMP_CONTENT_RANGENAME,
+ RID_BMP_CONTENT_DBAREA,
+ RID_BMP_CONTENT_GRAPHIC,
+ RID_BMP_CONTENT_OLEOBJECT,
+ RID_BMP_CONTENT_NOTE,
+ RID_BMP_CONTENT_AREALINK,
+ RID_BMP_CONTENT_DRAWING
+};
+
+void ScLinkTargetTypeObj::SetLinkTargetBitmap( uno::Any& rRet, sal_uInt16 nType )
+{
+ ScContentId nImgId = ScContentId::ROOT;
+ switch ( nType )
+ {
+ case SC_LINKTARGETTYPE_SHEET:
+ nImgId = ScContentId::TABLE;
+ break;
+ case SC_LINKTARGETTYPE_RANGENAME:
+ nImgId = ScContentId::RANGENAME;
+ break;
+ case SC_LINKTARGETTYPE_DBAREA:
+ nImgId = ScContentId::DBAREA;
+ break;
+ }
+ if (nImgId != ScContentId::ROOT)
+ {
+ BitmapEx aBitmapEx { aContentBmps[static_cast<int>(nImgId) -1 ] };
+ rRet <<= VCLUnoHelper::CreateBitmap(aBitmapEx);
+ }
+}
+
+uno::Any SAL_CALL ScLinkTargetTypeObj::getPropertyValue(const OUString& PropertyName)
+{
+ uno::Any aRet;
+ if ( PropertyName == SC_UNO_LINKDISPBIT )
+ SetLinkTargetBitmap( aRet, nType );
+ else if ( PropertyName == SC_UNO_LINKDISPNAME )
+ aRet <<= aName;
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScLinkTargetTypeObj )
+
+ScLinkTargetsObj::ScLinkTargetsObj( uno::Reference< container::XNameAccess > xColl ) :
+ xCollection(std::move( xColl ))
+{
+ OSL_ENSURE( xCollection.is(), "ScLinkTargetsObj: NULL" );
+}
+
+ScLinkTargetsObj::~ScLinkTargetsObj()
+{
+}
+
+// container::XNameAccess
+
+uno::Any SAL_CALL ScLinkTargetsObj::getByName(const OUString& aName)
+{
+ uno::Reference<beans::XPropertySet> xProp(xCollection->getByName(aName), uno::UNO_QUERY);
+ if (xProp.is())
+ return uno::Any(xProp);
+
+ throw container::NoSuchElementException();
+}
+
+uno::Sequence<OUString> SAL_CALL ScLinkTargetsObj::getElementNames()
+{
+ return xCollection->getElementNames();
+}
+
+sal_Bool SAL_CALL ScLinkTargetsObj::hasByName(const OUString& aName)
+{
+ return xCollection->hasByName(aName);
+}
+
+// container::XElementAccess
+
+uno::Type SAL_CALL ScLinkTargetsObj::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL ScLinkTargetsObj::hasElements()
+{
+ return xCollection->hasElements();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/textuno.cxx b/sc/source/ui/unoobj/textuno.cxx
new file mode 100644
index 0000000000..6102cdb9fa
--- /dev/null
+++ b/sc/source/ui/unoobj/textuno.cxx
@@ -0,0 +1,869 @@
+/* -*- 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 <memory>
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdobj.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/unoprnms.hxx>
+#include <editeng/unofored.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+
+#include <editeng/unoipset.hxx>
+#include <textuno.hxx>
+#include <fielduno.hxx>
+#include <editsrc.hxx>
+#include <docsh.hxx>
+#include <editutil.hxx>
+#include <miscuno.hxx>
+#include <cellsuno.hxx>
+#include <cellvalue.hxx>
+#include <cellform.hxx>
+#include <patattr.hxx>
+#include <docfunc.hxx>
+#include <scmod.hxx>
+
+using namespace com::sun::star;
+
+static const SvxItemPropertySet * lcl_GetHdFtPropertySet()
+{
+ static const SvxItemPropertySet aHdFtPropertySet_Impl = [] {
+ static SfxItemPropertyMapEntry aHdFtPropertyMap_Impl[] =
+ {
+ SVX_UNOEDIT_CHAR_PROPERTIES,
+ SVX_UNOEDIT_FONT_PROPERTIES,
+ SVX_UNOEDIT_PARA_PROPERTIES,
+ SVX_UNOEDIT_NUMBERING_PROPERTY, // for completeness of service ParagraphProperties
+ };
+
+ // modify PropertyMap to include CONVERT_TWIPS flag for font height
+ // (headers/footers are in twips)
+
+ for (auto & rEntry : aHdFtPropertyMap_Impl)
+ {
+ if ( ( rEntry.nWID == EE_CHAR_FONTHEIGHT ||
+ rEntry.nWID == EE_CHAR_FONTHEIGHT_CJK ||
+ rEntry.nWID == EE_CHAR_FONTHEIGHT_CTL ) &&
+ rEntry.nMemberId == MID_FONTHEIGHT )
+ {
+ rEntry.nMemberId |= CONVERT_TWIPS;
+ }
+ }
+
+ return SvxItemPropertySet(aHdFtPropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool());
+ }();
+ return &aHdFtPropertySet_Impl;
+}
+
+SC_SIMPLE_SERVICE_INFO( ScHeaderFooterContentObj, "ScHeaderFooterContentObj", "com.sun.star.sheet.HeaderFooterContent" )
+SC_SIMPLE_SERVICE_INFO( ScHeaderFooterTextObj, "ScHeaderFooterTextObj", "stardiv.one.Text.Text" )
+
+ScHeaderFooterContentObj::ScHeaderFooterContentObj()
+{
+}
+
+ScHeaderFooterContentObj::~ScHeaderFooterContentObj() {}
+
+const EditTextObject* ScHeaderFooterContentObj::GetLeftEditObject() const
+{
+ return mxLeftText->GetTextObject();
+}
+
+const EditTextObject* ScHeaderFooterContentObj::GetCenterEditObject() const
+{
+ return mxCenterText->GetTextObject();
+}
+
+const EditTextObject* ScHeaderFooterContentObj::GetRightEditObject() const
+{
+ return mxRightText->GetTextObject();
+}
+
+// XHeaderFooterContent
+
+uno::Reference<text::XText> SAL_CALL ScHeaderFooterContentObj::getLeftText()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<text::XText> xInt(*mxLeftText, uno::UNO_QUERY);
+ return xInt;
+}
+
+uno::Reference<text::XText> SAL_CALL ScHeaderFooterContentObj::getCenterText()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<text::XText> xInt(*mxCenterText, uno::UNO_QUERY);
+ return xInt;
+}
+
+uno::Reference<text::XText> SAL_CALL ScHeaderFooterContentObj::getRightText()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<text::XText> xInt(*mxRightText, uno::UNO_QUERY);
+ return xInt;
+}
+
+rtl::Reference<ScHeaderFooterContentObj> ScHeaderFooterContentObj::getImplementation(
+ const uno::Reference<sheet::XHeaderFooterContent>& rObj)
+{
+ return dynamic_cast<ScHeaderFooterContentObj*>(rObj.get());
+}
+
+void ScHeaderFooterContentObj::Init( const EditTextObject* pLeft,
+ const EditTextObject* pCenter,
+ const EditTextObject* pRight )
+{
+ uno::Reference<css::sheet::XHeaderFooterContent> xThis(this);
+ mxLeftText = rtl::Reference<ScHeaderFooterTextObj>(new ScHeaderFooterTextObj(xThis, ScHeaderFooterPart::LEFT, pLeft));
+ mxCenterText = rtl::Reference<ScHeaderFooterTextObj>(new ScHeaderFooterTextObj(xThis, ScHeaderFooterPart::CENTER, pCenter));
+ mxRightText = rtl::Reference<ScHeaderFooterTextObj>(new ScHeaderFooterTextObj(xThis, ScHeaderFooterPart::RIGHT, pRight));
+}
+
+ScHeaderFooterTextData::ScHeaderFooterTextData(
+ uno::WeakReference<sheet::XHeaderFooterContent> xContent, ScHeaderFooterPart nP, const EditTextObject* pTextObj) :
+ mpTextObj(pTextObj ? pTextObj->Clone() : nullptr),
+ xContentObj(std::move( xContent )),
+ nPart( nP ),
+ bDataValid(false)
+{
+}
+
+ScHeaderFooterTextData::~ScHeaderFooterTextData()
+{
+ SolarMutexGuard aGuard; // needed for EditEngine dtor
+
+ pForwarder.reset();
+ pEditEngine.reset();
+}
+
+SvxTextForwarder* ScHeaderFooterTextData::GetTextForwarder()
+{
+ if (!pEditEngine)
+ {
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->FreezeIdRanges();
+ std::unique_ptr<ScHeaderEditEngine> pHdrEngine(new ScHeaderEditEngine( pEnginePool.get() ));
+
+ pHdrEngine->EnableUndo( false );
+ pHdrEngine->SetRefMapMode(MapMode(MapUnit::MapTwip));
+
+ // default font must be set, independently of document
+ // -> use global pool from module
+
+ SfxItemSet aDefaults( pHdrEngine->GetEmptyItemSet() );
+ const ScPatternAttr& rPattern = SC_MOD()->GetPool().GetDefaultItem(ATTR_PATTERN);
+ rPattern.FillEditItemSet( &aDefaults );
+ // FillEditItemSet adjusts font height to 1/100th mm,
+ // but for header/footer twips is needed, as in the PatternAttr:
+ aDefaults.Put( rPattern.GetItem(ATTR_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT) );
+ aDefaults.Put( rPattern.GetItem(ATTR_CJK_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CJK) ) ;
+ aDefaults.Put( rPattern.GetItem(ATTR_CTL_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CTL) );
+ pHdrEngine->SetDefaults( aDefaults );
+
+ ScHeaderFieldData aData;
+ ScHeaderFooterTextObj::FillDummyFieldData( aData );
+ pHdrEngine->SetData( aData );
+
+ pEditEngine = std::move(pHdrEngine);
+ pForwarder.reset( new SvxEditEngineForwarder(*pEditEngine) );
+ }
+
+ if (bDataValid)
+ return pForwarder.get();
+
+ if (mpTextObj)
+ pEditEngine->SetTextCurrentDefaults(*mpTextObj);
+
+ bDataValid = true;
+ return pForwarder.get();
+}
+
+void ScHeaderFooterTextData::UpdateData()
+{
+ if (pEditEngine)
+ {
+ mpTextObj = pEditEngine->CreateTextObject();
+ }
+}
+
+void ScHeaderFooterTextData::UpdateData(EditEngine& rEditEngine)
+{
+ mpTextObj = rEditEngine.CreateTextObject();
+ bDataValid = false;
+}
+
+ScHeaderFooterTextObj::ScHeaderFooterTextObj(
+ const uno::WeakReference<sheet::XHeaderFooterContent>& xContent, ScHeaderFooterPart nP, const EditTextObject* pTextObj) :
+ aTextData(xContent, nP, pTextObj)
+{
+ // ScHeaderFooterTextData acquires rContent
+ // pUnoText is created on demand (getString/setString work without it)
+}
+
+void ScHeaderFooterTextObj::CreateUnoText_Impl()
+{
+ if (!mxUnoText.is())
+ {
+ // can't be aggregated because getString/setString is handled here
+ ScHeaderFooterEditSource aEditSrc(aTextData);
+ mxUnoText.set(new SvxUnoText(&aEditSrc, lcl_GetHdFtPropertySet(), uno::Reference<text::XText>()));
+ }
+}
+
+ScHeaderFooterTextObj::~ScHeaderFooterTextObj() {}
+
+const EditTextObject* ScHeaderFooterTextObj::GetTextObject() const
+{
+ return aTextData.GetTextObject();
+}
+
+const SvxUnoText& ScHeaderFooterTextObj::GetUnoText()
+{
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return *mxUnoText;
+}
+
+// XText
+
+uno::Reference<text::XTextCursor> SAL_CALL ScHeaderFooterTextObj::createTextCursor()
+{
+ SolarMutexGuard aGuard;
+ return new ScHeaderFooterTextCursor( this );
+}
+
+uno::Reference<text::XTextCursor> SAL_CALL ScHeaderFooterTextObj::createTextCursorByRange(
+ const uno::Reference<text::XTextRange>& aTextPosition )
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->createTextCursorByRange(aTextPosition);
+ //! like ScCellObj::createTextCursorByRange, if SvxUnoTextRange_getReflection available
+}
+
+void ScHeaderFooterTextObj::FillDummyFieldData( ScHeaderFieldData& rData )
+{
+ OUString aDummy("???");
+ rData.aTitle = aDummy;
+ rData.aLongDocName = aDummy;
+ rData.aShortDocName = aDummy;
+ rData.aTabName = aDummy;
+ rData.nPageNo = 1;
+ rData.nTotalPages = 99;
+}
+
+OUString SAL_CALL ScHeaderFooterTextObj::getString()
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ const EditTextObject* pData;
+
+ uno::Reference<css::sheet::XHeaderFooterContent> xContentObj = aTextData.GetContentObj();
+ if (!xContentObj.is())
+ throw css::uno::RuntimeException(
+ "ScHeaderFooterTextObj::getString: no ContentObj");
+
+ rtl::Reference<ScHeaderFooterContentObj> pObj = ScHeaderFooterContentObj::getImplementation(xContentObj);
+
+ switch ( aTextData.GetPart() )
+ {
+ case ScHeaderFooterPart::LEFT:
+ pData = pObj->GetLeftEditObject();
+ break;
+ case ScHeaderFooterPart::CENTER:
+ pData = pObj->GetCenterEditObject();
+ break;
+ case ScHeaderFooterPart::RIGHT:
+ pData = pObj->GetRightEditObject();
+ break;
+ default:
+ SAL_WARN("sc.ui","unexpected enum value of ScHeaderFooterPart");
+ pData = nullptr;
+ }
+
+ if (pData)
+ {
+ // for pure text, no font info is needed in pool defaults
+ ScHeaderEditEngine aEditEngine( EditEngine::CreatePool().get() );
+
+ ScHeaderFieldData aData;
+ FillDummyFieldData( aData );
+ aEditEngine.SetData( aData );
+
+ aEditEngine.SetTextCurrentDefaults(*pData);
+ aRet = ScEditUtil::GetSpaceDelimitedString( aEditEngine );
+ }
+ return aRet;
+}
+
+void SAL_CALL ScHeaderFooterTextObj::setString( const OUString& aText )
+{
+ SolarMutexGuard aGuard;
+
+ // for pure text, no font info is needed in pool defaults
+ ScHeaderEditEngine aEditEngine(EditEngine::CreatePool().get());
+ aEditEngine.SetTextCurrentDefaults( aText );
+ aTextData.UpdateData(aEditEngine);
+}
+
+void SAL_CALL ScHeaderFooterTextObj::insertString( const uno::Reference<text::XTextRange>& xRange,
+ const OUString& aString, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ mxUnoText->insertString( xRange, aString, bAbsorb );
+}
+
+void SAL_CALL ScHeaderFooterTextObj::insertControlCharacter(
+ const uno::Reference<text::XTextRange>& xRange,
+ sal_Int16 nControlCharacter, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ mxUnoText->insertControlCharacter( xRange, nControlCharacter, bAbsorb );
+}
+
+void SAL_CALL ScHeaderFooterTextObj::insertTextContent(
+ const uno::Reference<text::XTextRange >& xRange,
+ const uno::Reference<text::XTextContent >& xContent,
+ sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ if ( xContent.is() && xRange.is() )
+ {
+ ScEditFieldObj* pHeaderField = dynamic_cast<ScEditFieldObj*>( xContent.get() );
+
+ SvxUnoTextRangeBase* pTextRange =
+ comphelper::getFromUnoTunnel<ScHeaderFooterTextCursor>( xRange );
+
+ if ( pHeaderField && !pHeaderField->IsInserted() && pTextRange )
+ {
+ SvxEditSource* pEditSource = pTextRange->GetEditSource();
+ ESelection aSelection(pTextRange->GetSelection());
+
+ if (!bAbsorb)
+ {
+ // don't replace -> append at end
+ aSelection.Adjust();
+ aSelection.nStartPara = aSelection.nEndPara;
+ aSelection.nStartPos = aSelection.nEndPos;
+ }
+
+ SvxFieldItem aItem(pHeaderField->CreateFieldItem());
+
+ SvxTextForwarder* pForwarder = pEditSource->GetTextForwarder();
+ pForwarder->QuickInsertField( aItem, aSelection );
+ pEditSource->UpdateData();
+
+ // new selection: a digit
+ aSelection.Adjust();
+ aSelection.nEndPara = aSelection.nStartPara;
+ aSelection.nEndPos = aSelection.nStartPos + 1;
+
+ uno::Reference<text::XTextRange> xTextRange;
+ switch ( aTextData.GetPart() )
+ {
+ case ScHeaderFooterPart::LEFT:
+ xTextRange = aTextData.GetContentObj()->getLeftText();
+ break;
+ case ScHeaderFooterPart::CENTER:
+ xTextRange = aTextData.GetContentObj()->getCenterText();
+ break;
+ case ScHeaderFooterPart::RIGHT:
+ xTextRange = aTextData.GetContentObj()->getRightText();
+ break;
+ }
+
+ pHeaderField->InitDoc(xTextRange, std::make_unique<ScHeaderFooterEditSource>(aTextData), aSelection);
+
+ // for bAbsorb=FALSE, the new selection must be behind the inserted content
+ // (the xml filter relies on this)
+ if (!bAbsorb)
+ aSelection.nStartPos = aSelection.nEndPos;
+
+ pTextRange->SetSelection( aSelection );
+
+ return;
+ }
+ }
+
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ mxUnoText->insertTextContent( xRange, xContent, bAbsorb );
+}
+
+void SAL_CALL ScHeaderFooterTextObj::removeTextContent(
+ const uno::Reference<text::XTextContent>& xContent )
+{
+ SolarMutexGuard aGuard;
+ if ( xContent.is() )
+ {
+ ScEditFieldObj* pHeaderField = dynamic_cast<ScEditFieldObj*>(xContent.get());
+ if ( pHeaderField && pHeaderField->IsInserted() )
+ {
+ //! check if the field is in this cell
+ pHeaderField->DeleteField();
+ return;
+ }
+ }
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ mxUnoText->removeTextContent( xContent );
+}
+
+uno::Reference<text::XText> SAL_CALL ScHeaderFooterTextObj::getText()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->getText();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScHeaderFooterTextObj::getStart()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->getStart();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScHeaderFooterTextObj::getEnd()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->getEnd();
+}
+
+// XTextFieldsSupplier
+
+uno::Reference<container::XEnumerationAccess> SAL_CALL ScHeaderFooterTextObj::getTextFields()
+{
+ SolarMutexGuard aGuard;
+ // all fields
+ return new ScHeaderFieldsObj(aTextData);
+}
+
+uno::Reference<container::XNameAccess> SAL_CALL ScHeaderFooterTextObj::getTextFieldMasters()
+{
+ // this does not exists in Calc (?)
+ return nullptr;
+}
+
+// XTextRangeMover
+
+void SAL_CALL ScHeaderFooterTextObj::moveTextRange(
+ const uno::Reference<text::XTextRange>& xRange,
+ sal_Int16 nParagraphs )
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ mxUnoText->moveTextRange( xRange, nParagraphs );
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScHeaderFooterTextObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->createEnumeration();
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScHeaderFooterTextObj::getElementType()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->getElementType();
+}
+
+sal_Bool SAL_CALL ScHeaderFooterTextObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->hasElements();
+}
+
+ScCellTextCursor::ScCellTextCursor(ScCellObj& rText) :
+ SvxUnoTextCursor( rText.GetUnoText() ),
+ mxTextObj( &rText )
+{
+}
+
+ScCellTextCursor::~ScCellTextCursor() noexcept
+{
+}
+
+// SvxUnoTextCursor methods reimplemented here to return the right objects:
+
+uno::Reference<text::XText> SAL_CALL ScCellTextCursor::getText()
+{
+ return mxTextObj;
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScCellTextCursor::getStart()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScCellTextCursor> pNew = new ScCellTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nEndPara = aNewSel.nStartPara;
+ aNewSel.nEndPos = aNewSel.nStartPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScCellTextCursor::getEnd()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScCellTextCursor> pNew = new ScCellTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nStartPara = aNewSel.nEndPara;
+ aNewSel.nStartPos = aNewSel.nEndPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION2_IMPL(ScCellTextCursor, SvxUnoTextCursor);
+
+ScHeaderFooterTextCursor::ScHeaderFooterTextCursor(rtl::Reference<ScHeaderFooterTextObj> const & rText) :
+ SvxUnoTextCursor( rText->GetUnoText() ),
+ rTextObj( rText )
+{}
+
+ScHeaderFooterTextCursor::~ScHeaderFooterTextCursor() noexcept {};
+
+// SvxUnoTextCursor methods reimplemented here to return the right objects:
+
+uno::Reference<text::XText> SAL_CALL ScHeaderFooterTextCursor::getText()
+{
+ SolarMutexGuard aGuard;
+ return rTextObj;
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScHeaderFooterTextCursor::getStart()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScHeaderFooterTextCursor> pNew = new ScHeaderFooterTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nEndPara = aNewSel.nStartPara;
+ aNewSel.nEndPos = aNewSel.nStartPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScHeaderFooterTextCursor::getEnd()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScHeaderFooterTextCursor> pNew = new ScHeaderFooterTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nStartPara = aNewSel.nEndPara;
+ aNewSel.nStartPos = aNewSel.nEndPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION2_IMPL(ScHeaderFooterTextCursor, SvxUnoTextCursor);
+
+ScDrawTextCursor::ScDrawTextCursor( uno::Reference<text::XText> xParent,
+ const SvxUnoTextBase& rText ) :
+ SvxUnoTextCursor( rText ),
+ xParentText(std::move( xParent ))
+
+{
+}
+
+ScDrawTextCursor::~ScDrawTextCursor() noexcept
+{
+}
+
+// SvxUnoTextCursor methods reimplemented here to return the right objects:
+
+uno::Reference<text::XText> SAL_CALL ScDrawTextCursor::getText()
+{
+ SolarMutexGuard aGuard;
+ return xParentText;
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScDrawTextCursor::getStart()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScDrawTextCursor> pNew = new ScDrawTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nEndPara = aNewSel.nStartPara;
+ aNewSel.nEndPos = aNewSel.nStartPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScDrawTextCursor::getEnd()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScDrawTextCursor> pNew = new ScDrawTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nStartPara = aNewSel.nEndPara;
+ aNewSel.nStartPos = aNewSel.nEndPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION2_IMPL(ScDrawTextCursor, SvxUnoTextCursor);
+
+ScSimpleEditSourceHelper::ScSimpleEditSourceHelper()
+{
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->SetDefaultMetric( MapUnit::Map100thMM );
+ pEnginePool->FreezeIdRanges();
+
+ pEditEngine.reset( new ScFieldEditEngine(nullptr, pEnginePool.get(), nullptr, true) ); // TRUE: become owner of pool
+ pForwarder.reset( new SvxEditEngineForwarder( *pEditEngine ) );
+ pOriginalSource.reset( new ScSimpleEditSource( pForwarder.get() ) );
+}
+
+ScSimpleEditSourceHelper::~ScSimpleEditSourceHelper()
+{
+ SolarMutexGuard aGuard; // needed for EditEngine dtor
+
+ pOriginalSource.reset();
+ pForwarder.reset();
+ pEditEngine.reset();
+}
+
+ScEditEngineTextObj::ScEditEngineTextObj() :
+ SvxUnoText( GetOriginalSource(), ScCellObj::GetEditPropertySet(), uno::Reference<text::XText>() )
+{
+}
+
+ScEditEngineTextObj::~ScEditEngineTextObj() noexcept
+{
+}
+
+void ScEditEngineTextObj::SetText( const EditTextObject& rTextObject )
+{
+ GetEditEngine()->SetTextCurrentDefaults( rTextObject );
+
+ ESelection aSel;
+ ::GetSelection( aSel, GetEditSource()->GetTextForwarder() );
+ SetSelection( aSel );
+}
+
+std::unique_ptr<EditTextObject> ScEditEngineTextObj::CreateTextObject()
+{
+ return GetEditEngine()->CreateTextObject();
+}
+
+ScCellTextData::ScCellTextData(ScDocShell* pDocSh, const ScAddress& rP) :
+ pDocShell( pDocSh ),
+ aCellPos( rP ),
+ bDataValid( false ),
+ bInUpdate( false ),
+ bDirty( false ),
+ bDoUpdate( true )
+{
+ if (pDocShell)
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScCellTextData::~ScCellTextData()
+{
+ SolarMutexGuard aGuard; // needed for EditEngine dtor
+
+ if (pDocShell)
+ {
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+ pDocShell->GetDocument().DisposeFieldEditEngine(pEditEngine);
+ }
+ else
+ pEditEngine.reset();
+
+ pForwarder.reset();
+
+ pOriginalSource.reset();
+}
+
+ScCellEditSource* ScCellTextData::GetOriginalSource()
+{
+ if (!pOriginalSource)
+ pOriginalSource.reset( new ScCellEditSource(pDocShell, aCellPos) );
+ return pOriginalSource.get();
+}
+
+SvxTextForwarder* ScCellTextData::GetTextForwarder()
+{
+ if (!pEditEngine)
+ {
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pEditEngine = rDoc.CreateFieldEditEngine();
+ }
+ else
+ {
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->FreezeIdRanges();
+ pEditEngine.reset( new ScFieldEditEngine(nullptr, pEnginePool.get(), nullptr, true) );
+ }
+ // currently, GetPortions doesn't work if UpdateMode is sal_False,
+ // this will be fixed (in EditEngine) by src600
+// pEditEngine->SetUpdateMode( sal_False );
+ pEditEngine->EnableUndo( false );
+ if (pDocShell)
+ pEditEngine->SetRefDevice(pDocShell->GetRefDevice());
+ else
+ pEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
+ pForwarder.reset( new SvxEditEngineForwarder(*pEditEngine) );
+ }
+
+ if (bDataValid)
+ return pForwarder.get();
+
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SfxItemSet aDefaults( pEditEngine->GetEmptyItemSet() );
+ if( const ScPatternAttr* pPattern =
+ rDoc.GetPattern( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab() ) )
+ {
+ pPattern->FillEditItemSet( &aDefaults );
+ pPattern->FillEditParaItems( &aDefaults ); // including alignment etc. (for reading)
+ }
+
+ ScRefCellValue aCell(rDoc, aCellPos);
+ if (aCell.getType() == CELLTYPE_EDIT)
+ {
+ const EditTextObject* pObj = aCell.getEditText();
+ pEditEngine->SetTextNewDefaults(*pObj, aDefaults);
+ }
+ else
+ {
+ sal_uInt32 nFormat = rDoc.GetNumberFormat(aCellPos);
+ OUString aText = ScCellFormat::GetInputString(aCell, nFormat, *rDoc.GetFormatTable(), rDoc);
+ if (!aText.isEmpty())
+ pEditEngine->SetTextNewDefaults(aText, aDefaults);
+ else
+ pEditEngine->SetDefaults(aDefaults);
+ }
+ }
+
+ bDataValid = true;
+ return pForwarder.get();
+}
+
+void ScCellTextData::UpdateData()
+{
+ if ( bDoUpdate )
+ {
+ OSL_ENSURE(pEditEngine != nullptr, "no EditEngine for UpdateData()");
+ if ( pDocShell && pEditEngine )
+ {
+ // during the own UpdateData call, bDataValid must not be reset,
+ // or things like attributes after the text would be lost
+ // (are not stored in the cell)
+ bInUpdate = true; // prevents bDataValid from being reset
+ pDocShell->GetDocFunc().PutData(aCellPos, *pEditEngine, true); // always as text
+
+ bInUpdate = false;
+ bDirty = false;
+ }
+ }
+ else
+ bDirty = true;
+}
+
+void ScCellTextData::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // invalid now
+
+ pForwarder.reset();
+ pEditEngine.reset(); // EditEngine uses document's pool
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ if (!bInUpdate) // not for own UpdateData calls
+ bDataValid = false; // text has to be read from the cell again
+ }
+}
+
+ScCellTextObj::ScCellTextObj(ScDocShell* pDocSh, const ScAddress& rP) :
+ ScCellTextData( pDocSh, rP ),
+ SvxUnoText( GetOriginalSource(), ScCellObj::GetEditPropertySet(), uno::Reference<text::XText>() )
+{
+}
+
+ScCellTextObj::~ScCellTextObj() COVERITY_NOEXCEPT_FALSE
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/tokenuno.cxx b/sc/source/ui/unoobj/tokenuno.cxx
new file mode 100644
index 0000000000..90b0a87e30
--- /dev/null
+++ b/sc/source/ui/unoobj/tokenuno.cxx
@@ -0,0 +1,520 @@
+/* -*- 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 <memory>
+#include <tokenuno.hxx>
+
+#include <sal/macros.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/sheet/ComplexReference.hpp>
+#include <com/sun/star/sheet/ExternalReference.hpp>
+#include <com/sun/star/sheet/ReferenceFlags.hpp>
+#include <com/sun/star/sheet/AddressConvention.hpp>
+#include <com/sun/star/sheet/NameToken.hpp>
+#include <com/sun/star/table/CellAddress.hpp>
+
+#include <svl/itemprop.hxx>
+#include <vcl/svapp.hxx>
+#include <comphelper/string.hxx>
+
+#include <miscuno.hxx>
+#include <convuno.hxx>
+#include <unonames.hxx>
+#include <compiler.hxx>
+#include <tokenarray.hxx>
+#include <docsh.hxx>
+#include <rangeseq.hxx>
+#include <externalrefmgr.hxx>
+
+using namespace ::formula;
+using namespace ::com::sun::star;
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetFormulaParserMap()
+{
+ static const SfxItemPropertyMapEntry aFormulaParserMap_Impl[] =
+ {
+ { SC_UNO_COMPILEFAP, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_COMPILEENGLISH, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_IGNORELEADING, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_FORMULACONVENTION, 0, cppu::UnoType<decltype(sheet::AddressConvention::UNSPECIFIED)>::get(), 0, 0 },
+ { SC_UNO_OPCODEMAP, 0, cppu::UnoType<uno::Sequence< sheet::FormulaOpCodeMapEntry >>::get(), 0, 0 },
+ };
+ return aFormulaParserMap_Impl;
+}
+
+const formula::FormulaGrammar::AddressConvention aConvMap[] = {
+ formula::FormulaGrammar::CONV_OOO, // <- AddressConvention::OOO
+ formula::FormulaGrammar::CONV_XL_A1, // <- AddressConvention::XL_A1
+ formula::FormulaGrammar::CONV_XL_R1C1, // <- AddressConvention::XL_R1C1
+ formula::FormulaGrammar::CONV_XL_OOX, // <- AddressConvention::XL_OOX
+ formula::FormulaGrammar::CONV_LOTUS_A1 // <- AddressConvention::LOTUS_A1
+};
+// sal_Int16 because of comparison of integer expressions below.
+constexpr sal_Int16 nConvMapCount = SAL_N_ELEMENTS(aConvMap);
+
+
+SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS )
+
+ScFormulaParserObj::ScFormulaParserObj(ScDocShell* pDocSh) :
+ mpDocShell( pDocSh ),
+ mnConv( sheet::AddressConvention::UNSPECIFIED ),
+ mbEnglish( false ),
+ mbIgnoreSpaces( true ),
+ mbCompileFAP( false ),
+ mbRefConventionChartOOXML( false )
+{
+ mpDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScFormulaParserObj::~ScFormulaParserObj()
+{
+ SolarMutexGuard g;
+
+ if (mpDocShell)
+ mpDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScFormulaParserObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ mpDocShell = nullptr;
+}
+
+// XFormulaParser
+
+void ScFormulaParserObj::SetCompilerFlags( ScCompiler& rCompiler ) const
+{
+ formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_UNSPECIFIED;
+ if (mnConv >= 0 && mnConv < nConvMapCount)
+ eConv = aConvMap[mnConv];
+
+ // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We
+ // don't need to initialize things twice.
+ if (mxOpCodeMap)
+ rCompiler.SetFormulaLanguage( mxOpCodeMap );
+ else
+ {
+ const sal_Int32 nFormulaLanguage = (eConv == formula::FormulaGrammar::CONV_XL_OOX ?
+ sheet::FormulaLanguage::OOXML :
+ (mbEnglish ? sheet::FormulaLanguage::ENGLISH : sheet::FormulaLanguage::NATIVE));
+ ScCompiler::OpCodeMapPtr xMap = rCompiler.GetOpCodeMap( nFormulaLanguage);
+ rCompiler.SetFormulaLanguage( xMap);
+ }
+
+ rCompiler.SetRefConvention( eConv );
+ rCompiler.EnableJumpCommandReorder(!mbCompileFAP);
+ rCompiler.EnableStopOnError(!mbCompileFAP);
+
+ rCompiler.SetExternalLinks(maExternalLinks);
+ rCompiler.SetRefConventionChartOOXML(mbRefConventionChartOOXML);
+}
+
+uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula(
+ const OUString& aFormula, const table::CellAddress& rReferencePos )
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence<sheet::FormulaToken> aRet;
+
+ if (mpDocShell)
+ {
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ ScExternalRefManager::ApiGuard aExtRefGuard(rDoc);
+
+ ScAddress aRefPos( ScAddress::UNINITIALIZED );
+ ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
+ ScCompiler aCompiler( rDoc, aRefPos, rDoc.GetGrammar());
+ SetCompilerFlags( aCompiler );
+
+ std::unique_ptr<ScTokenArray> pCode = aCompiler.CompileString( aFormula );
+ ScTokenConversion::ConvertToTokenSequence( rDoc, aRet, *pCode );
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScFormulaParserObj::printFormula(
+ const uno::Sequence<sheet::FormulaToken>& aTokens, const table::CellAddress& rReferencePos )
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+
+ if (mpDocShell)
+ {
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ ScTokenArray aCode(rDoc);
+ (void)ScTokenConversion::ConvertToTokenArray( rDoc, aCode, aTokens );
+ ScAddress aRefPos( ScAddress::UNINITIALIZED );
+ ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
+ ScCompiler aCompiler(rDoc, aRefPos, aCode, rDoc.GetGrammar());
+ SetCompilerFlags( aCompiler );
+
+ OUStringBuffer aBuffer;
+ aCompiler.CreateStringFromTokenArray( aBuffer );
+ aRet = aBuffer.makeStringAndClear();
+ }
+
+ return aRet;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFormulaParserObj::getPropertySetInfo()
+{
+ static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScFormulaParserObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ if ( aPropertyName == SC_UNO_COMPILEFAP )
+ {
+ aValue >>= mbCompileFAP;
+ }
+ else if ( aPropertyName == SC_UNO_COMPILEENGLISH )
+ {
+ bool bOldEnglish = mbEnglish;
+ if (!(aValue >>= mbEnglish))
+ throw lang::IllegalArgumentException();
+
+ // Need to recreate the symbol map to change English property
+ // because the map is const. So for performance reasons set
+ // CompileEnglish _before_ OpCodeMap!
+ if (mxOpCodeMap && mbEnglish != bOldEnglish)
+ {
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ ScCompiler aCompiler( rDoc, ScAddress(), rDoc.GetGrammar());
+ mxOpCodeMap = formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping, mbEnglish);
+ }
+
+ }
+ else if ( aPropertyName == SC_UNO_FORMULACONVENTION )
+ {
+ aValue >>= mnConv;
+
+ bool bOldEnglish = mbEnglish;
+ if (mnConv >= 0 && mnConv < nConvMapCount
+ && aConvMap[mnConv] == formula::FormulaGrammar::CONV_XL_OOX)
+ mbEnglish = true;
+
+ // Same as for SC_UNO_COMPILEENGLISH, though an OpCodeMap should not
+ // had been set for CONV_XL_OOX.
+ if (mxOpCodeMap && mbEnglish != bOldEnglish)
+ {
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ ScCompiler aCompiler( rDoc, ScAddress(), rDoc.GetGrammar());
+ mxOpCodeMap = formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping, mbEnglish);
+ }
+ }
+ else if ( aPropertyName == SC_UNO_IGNORELEADING )
+ {
+ aValue >>= mbIgnoreSpaces;
+ }
+ else if ( aPropertyName == SC_UNO_OPCODEMAP )
+ {
+ if (!(aValue >>= maOpCodeMapping))
+ throw lang::IllegalArgumentException();
+
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ ScCompiler aCompiler(rDoc, ScAddress(), rDoc.GetGrammar());
+ mxOpCodeMap = formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping, mbEnglish);
+
+ }
+ else if ( aPropertyName == SC_UNO_EXTERNALLINKS )
+ {
+ if (!(aValue >>= maExternalLinks))
+ throw lang::IllegalArgumentException();
+ }
+ else if ( aPropertyName == SC_UNO_REF_CONV_CHARTOOXML )
+ {
+ if (!(aValue >>= mbRefConventionChartOOXML))
+ throw lang::IllegalArgumentException();
+ }
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+}
+
+uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ if ( aPropertyName == SC_UNO_COMPILEFAP )
+ {
+ aRet <<= mbCompileFAP;
+ }
+ else if ( aPropertyName == SC_UNO_COMPILEENGLISH )
+ {
+ aRet <<= mbEnglish;
+ }
+ else if ( aPropertyName == SC_UNO_FORMULACONVENTION )
+ {
+ aRet <<= mnConv;
+ }
+ else if ( aPropertyName == SC_UNO_IGNORELEADING )
+ {
+ aRet <<= mbIgnoreSpaces;
+ }
+ else if ( aPropertyName == SC_UNO_OPCODEMAP )
+ {
+ aRet <<= maOpCodeMapping;
+ }
+ else if ( aPropertyName == SC_UNO_EXTERNALLINKS )
+ {
+ aRet <<= maExternalLinks;
+ }
+ else if ( aPropertyName == SC_UNO_REF_CONV_CHARTOOXML )
+ {
+ aRet <<= mbRefConventionChartOOXML;
+ }
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj )
+
+static void lcl_ExternalRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
+{
+ rAPI.Column = 0;
+ rAPI.Row = 0;
+ rAPI.Sheet = 0;
+ rAPI.RelativeColumn = 0;
+ rAPI.RelativeRow = 0;
+ rAPI.RelativeSheet = 0;
+
+ sal_Int32 nFlags = 0;
+ if ( rRef.IsColRel() )
+ {
+ nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
+ rAPI.RelativeColumn = rRef.Col();
+ }
+ else
+ rAPI.Column = rRef.Col();
+
+ if ( rRef.IsRowRel() )
+ {
+ nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
+ rAPI.RelativeRow = rRef.Row();
+ }
+ else
+ rAPI.Row = rRef.Row();
+
+ if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
+ if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
+ if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
+ if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
+ rAPI.Flags = nFlags;
+}
+
+static void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
+{
+ sal_Int32 nFlags = 0;
+ if ( rRef.IsColRel() )
+ {
+ nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
+ rAPI.RelativeColumn = rRef.Col();
+ rAPI.Column = 0;
+ }
+ else
+ {
+ rAPI.RelativeColumn = 0;
+ rAPI.Column = rRef.Col();
+ }
+
+ if ( rRef.IsRowRel() )
+ {
+ nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
+ rAPI.RelativeRow = rRef.Row();
+ rAPI.Row = 0;
+ }
+ else
+ {
+ rAPI.RelativeRow = 0;
+ rAPI.Row = rRef.Row();
+ }
+
+ if ( rRef.IsTabRel() )
+ {
+ nFlags |= sheet::ReferenceFlags::SHEET_RELATIVE;
+ rAPI.RelativeSheet = rRef.Tab();
+ rAPI.Sheet = 0;
+ }
+ else
+ {
+ rAPI.RelativeSheet = 0;
+ rAPI.Sheet = rRef.Tab();
+ }
+
+ if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
+ if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
+ if ( rRef.IsTabDeleted() ) nFlags |= sheet::ReferenceFlags::SHEET_DELETED;
+ if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
+ if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
+ rAPI.Flags = nFlags;
+}
+
+bool ScTokenConversion::ConvertToTokenArray( ScDocument& rDoc,
+ ScTokenArray& rTokenArray, const uno::Sequence<sheet::FormulaToken>& rSequence )
+{
+ return !rTokenArray.Fill(rSequence, rDoc.GetSharedStringPool(), rDoc.GetExternalRefManager());
+}
+
+void ScTokenConversion::ConvertToTokenSequence( const ScDocument& rDoc,
+ uno::Sequence<sheet::FormulaToken>& rSequence, const ScTokenArray& rTokenArray )
+{
+ sal_Int32 nLen = static_cast<sal_Int32>(rTokenArray.GetLen());
+ formula::FormulaToken** pTokens = rTokenArray.GetArray();
+ if ( pTokens )
+ {
+ rSequence.realloc(nLen);
+ auto pSequence = rSequence.getArray();
+ for (sal_Int32 nPos=0; nPos<nLen; nPos++)
+ {
+ const formula::FormulaToken& rToken = *pTokens[nPos];
+ sheet::FormulaToken& rAPI = pSequence[nPos];
+
+ OpCode eOpCode = rToken.GetOpCode();
+ // eOpCode may be changed in the following switch/case
+ switch ( rToken.GetType() )
+ {
+ case svByte:
+ // Only the count of spaces is stored as "long". Parameter count is ignored.
+ if ( eOpCode == ocSpaces )
+ rAPI.Data <<= static_cast<sal_Int32>(rToken.GetByte());
+ else if (eOpCode == ocWhitespace)
+ {
+ // Convention is one character repeated.
+ if (rToken.GetByte() == 1)
+ rAPI.Data <<= OUString( rToken.GetChar());
+ else
+ {
+ OUStringBuffer aBuf( rToken.GetByte());
+ comphelper::string::padToLength( aBuf, rToken.GetByte(), rToken.GetChar());
+ rAPI.Data <<= aBuf.makeStringAndClear();
+ }
+ }
+ else
+ rAPI.Data.clear(); // no data
+ break;
+ case formula::svDouble:
+ rAPI.Data <<= rToken.GetDouble();
+ break;
+ case formula::svString:
+ rAPI.Data <<= rToken.GetString().getString();
+ break;
+ case svExternal:
+ // Function name is stored as string.
+ // Byte (parameter count) is ignored.
+ rAPI.Data <<= rToken.GetExternal();
+ break;
+ case svSingleRef:
+ {
+ sheet::SingleReference aSingleRef;
+ lcl_SingleRefToApi( aSingleRef, *rToken.GetSingleRef() );
+ rAPI.Data <<= aSingleRef;
+ }
+ break;
+ case formula::svDoubleRef:
+ {
+ sheet::ComplexReference aCompRef;
+ lcl_SingleRefToApi( aCompRef.Reference1, *rToken.GetSingleRef() );
+ lcl_SingleRefToApi( aCompRef.Reference2, *rToken.GetSingleRef2() );
+ rAPI.Data <<= aCompRef;
+ }
+ break;
+ case svIndex:
+ {
+ sheet::NameToken aNameToken;
+ aNameToken.Index = static_cast<sal_Int32>( rToken.GetIndex() );
+ aNameToken.Sheet = rToken.GetSheet();
+ rAPI.Data <<= aNameToken;
+ }
+ break;
+ case svMatrix:
+ if (!ScRangeToSequence::FillMixedArray( rAPI.Data, rToken.GetMatrix(), true))
+ rAPI.Data.clear();
+ break;
+ case svExternalSingleRef:
+ {
+ sheet::SingleReference aSingleRef;
+ lcl_ExternalRefToApi( aSingleRef, *rToken.GetSingleRef() );
+ size_t nCacheId;
+ rDoc.GetExternalRefManager()->getCacheTable(
+ rToken.GetIndex(), rToken.GetString().getString(), false, &nCacheId);
+ aSingleRef.Sheet = static_cast< sal_Int32 >( nCacheId );
+ sheet::ExternalReference aExtRef;
+ aExtRef.Index = rToken.GetIndex();
+ aExtRef.Reference <<= aSingleRef;
+ rAPI.Data <<= aExtRef;
+ eOpCode = ocPush;
+ }
+ break;
+ case svExternalDoubleRef:
+ {
+ sheet::ComplexReference aComplRef;
+ lcl_ExternalRefToApi( aComplRef.Reference1, *rToken.GetSingleRef() );
+ lcl_ExternalRefToApi( aComplRef.Reference2, *rToken.GetSingleRef2() );
+ size_t nCacheId;
+ rDoc.GetExternalRefManager()->getCacheTable(
+ rToken.GetIndex(), rToken.GetString().getString(), false, &nCacheId);
+ aComplRef.Reference1.Sheet = static_cast< sal_Int32 >( nCacheId );
+ // NOTE: This assumes that cached sheets are in consecutive order!
+ aComplRef.Reference2.Sheet =
+ aComplRef.Reference1.Sheet +
+ (rToken.GetSingleRef2()->Tab() - rToken.GetSingleRef()->Tab());
+ sheet::ExternalReference aExtRef;
+ aExtRef.Index = rToken.GetIndex();
+ aExtRef.Reference <<= aComplRef;
+ rAPI.Data <<= aExtRef;
+ eOpCode = ocPush;
+ }
+ break;
+ case svExternalName:
+ {
+ sheet::ExternalReference aExtRef;
+ aExtRef.Index = rToken.GetIndex();
+ aExtRef.Reference <<= rToken.GetString().getString();
+ rAPI.Data <<= aExtRef;
+ eOpCode = ocPush;
+ }
+ break;
+ default:
+ SAL_WARN("sc", "ScTokenConversion::ConvertToTokenSequence: unhandled token type " << StackVarEnumToString(rToken.GetType()));
+ [[fallthrough]];
+ case svJump: // occurs with ocIf, ocChoose
+ case svError: // seems to be fairly common, and probably not exceptional and not worth a warning?
+ case svMissing: // occurs with ocMissing
+ case svSep: // occurs with ocSep, ocOpen, ocClose, ocArray*
+ rAPI.Data.clear(); // no data
+ }
+ rAPI.OpCode = static_cast<sal_Int32>(eOpCode); //! assuming equal values for the moment
+ }
+ }
+ else
+ rSequence.realloc(0);
+}
+
+ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::unique_ptr<formula::FormulaCompiler> && _pCompiler)
+: formula::FormulaOpCodeMapperObj(std::move(_pCompiler))
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/unodoc.cxx b/sc/source/ui/unoobj/unodoc.cxx
new file mode 100644
index 0000000000..bed297df7c
--- /dev/null
+++ b/sc/source/ui/unoobj/unodoc.cxx
@@ -0,0 +1,45 @@
+/* -*- 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 <sfx2/sfxmodelfactory.hxx>
+
+#include <scdll.hxx>
+#include <vcl/svapp.hxx>
+
+#include <docsh.hxx>
+
+using namespace ::com::sun::star;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_SpreadsheetDocument_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const& args)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ css::uno::Reference<css::uno::XInterface> xInterface = sfx2::createSfxModelInstance(args,
+ [](SfxModelFlags _nCreationFlags)
+ {
+ SfxObjectShell* pShell = new ScDocShell( _nCreationFlags );
+ return uno::Reference< uno::XInterface >( pShell->GetModel() );
+ });
+ xInterface->acquire();
+ return xInterface.get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/unoreflist.cxx b/sc/source/ui/unoobj/unoreflist.cxx
new file mode 100644
index 0000000000..fff4d0fd9d
--- /dev/null
+++ b/sc/source/ui/unoobj/unoreflist.cxx
@@ -0,0 +1,55 @@
+/* -*- 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 <unoreflist.hxx>
+#include <document.hxx>
+#include <utility>
+
+ScUnoRefList::ScUnoRefList()
+{
+}
+
+ScUnoRefList::~ScUnoRefList()
+{
+}
+
+void ScUnoRefList::Add( sal_Int64 nId, const ScRangeList& rOldRanges )
+{
+ aEntries.emplace_back( nId, rOldRanges );
+}
+
+void ScUnoRefList::Undo( ScDocument* pDoc )
+{
+ for (const auto & entry: aEntries)
+ {
+ ScUnoRefUndoHint aHint(entry);
+ pDoc->BroadcastUno( aHint );
+ }
+}
+
+ScUnoRefUndoHint::ScUnoRefUndoHint( ScUnoRefEntry aRefEntry ) :
+ aEntry(std::move( aRefEntry ))
+{
+}
+
+ScUnoRefUndoHint::~ScUnoRefUndoHint()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/viewuno.cxx b/sc/source/ui/unoobj/viewuno.cxx
new file mode 100644
index 0000000000..2d066bcfc2
--- /dev/null
+++ b/sc/source/ui/unoobj/viewuno.cxx
@@ -0,0 +1,2220 @@
+/* -*- 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 <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/drawing/ShapeCollection.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
+#include <com/sun/star/util/VetoException.hpp>
+#include <com/sun/star/view/DocumentZoomType.hpp>
+
+#include <editeng/outliner.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/fmshell.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <comphelper/profilezone.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <vcl/svapp.hxx>
+
+#include <drawsh.hxx>
+#include <drtxtob.hxx>
+#include <transobj.hxx>
+#include <editsh.hxx>
+#include <viewuno.hxx>
+#include <cellsuno.hxx>
+#include <miscuno.hxx>
+#include <tabvwsh.hxx>
+#include <prevwsh.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <attrib.hxx>
+#include <drawview.hxx>
+#include <fupoor.hxx>
+#include <sc.hrc>
+#include <unonames.hxx>
+#include <scmod.hxx>
+#include <appoptio.hxx>
+#include <gridwin.hxx>
+#include <sheetevents.hxx>
+#include <markdata.hxx>
+#include <scextopt.hxx>
+#include <preview.hxx>
+#include <inputhdl.hxx>
+#include <inputwin.hxx>
+#include <svx/sdrhittesthelper.hxx>
+#include <formatsh.hxx>
+#include <sfx2/app.hxx>
+#include <scitems.hxx>
+
+using namespace com::sun::star;
+
+//! Clipping Marks
+
+// no Which-ID here, Map only for PropertySetInfo
+
+static std::span<const SfxItemPropertyMapEntry> lcl_GetViewOptPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aViewOptPropertyMap_Impl[] =
+ {
+ { OLD_UNO_COLROWHDR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_GRIDCOLOR, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_COLROWHDR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_HORSCROLL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHEETTABS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_VERTSCROLL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_HIDESPELL, 0, cppu::UnoType<bool>::get(), 0, 0}, /* deprecated #i91949 */
+ { OLD_UNO_HORSCROLL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_OUTLSYMB, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_VALUEHIGH, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { OLD_UNO_OUTLSYMB, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { OLD_UNO_SHEETTABS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWANCHOR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWCHARTS, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SHOWDRAW, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SHOWFORM, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWGRID, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWHELP, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWNOTES, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWFORMULASMARKS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWOBJ, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SHOWPAGEBR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWZERO, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { OLD_UNO_VALUEHIGH, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { OLD_UNO_VERTSCROLL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_VISAREA, 0, cppu::UnoType<awt::Rectangle>::get(), 0, 0},
+ { SC_UNO_ZOOMTYPE, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_ZOOMVALUE, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_VISAREASCREEN,0, cppu::UnoType<awt::Rectangle>::get(), 0, 0},
+ { SC_UNO_FORMULABARHEIGHT,0,cppu::UnoType<sal_Int16>::get(), 0, 0},
+ };
+ return aViewOptPropertyMap_Impl;
+}
+
+constexpr OUString SCTABVIEWOBJ_SERVICE = u"com.sun.star.sheet.SpreadsheetView"_ustr;
+constexpr OUString SCVIEWSETTINGS_SERVICE = u"com.sun.star.sheet.SpreadsheetViewSettings"_ustr;
+
+SC_SIMPLE_SERVICE_INFO( ScViewPaneBase, "ScViewPaneObj", "com.sun.star.sheet.SpreadsheetViewPane" )
+
+ScViewPaneBase::ScViewPaneBase(ScTabViewShell* pViewSh, sal_uInt16 nP) :
+ pViewShell( pViewSh ),
+ nPane( nP )
+{
+ if (pViewShell)
+ StartListening(*pViewShell);
+}
+
+ScViewPaneBase::~ScViewPaneBase()
+{
+ SolarMutexGuard g;
+
+ if (pViewShell)
+ EndListening(*pViewShell);
+}
+
+void ScViewPaneBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pViewShell = nullptr;
+}
+
+uno::Any SAL_CALL ScViewPaneBase::queryInterface( const uno::Type& rType )
+{
+ uno::Any aReturn = ::cppu::queryInterface(rType,
+ static_cast<sheet::XViewPane*>(this),
+ static_cast<sheet::XCellRangeReferrer*>(this),
+ static_cast<view::XFormLayerAccess*>(this),
+ static_cast<view::XControlAccess*>(this),
+ static_cast<lang::XServiceInfo*>(this),
+ static_cast<lang::XTypeProvider*>(this));
+ if ( aReturn.hasValue() )
+ return aReturn;
+
+ return uno::Any(); // OWeakObject is in derived objects
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScViewPaneBase::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes
+ {
+ cppu::UnoType<sheet::XViewPane>::get(),
+ cppu::UnoType<sheet::XCellRangeReferrer>::get(),
+ cppu::UnoType<view::XFormLayerAccess>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ };
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScViewPaneBase::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XViewPane
+
+sal_Int32 SAL_CALL ScViewPaneBase::getFirstVisibleColumn()
+{
+ SolarMutexGuard aGuard;
+ if (pViewShell)
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScHSplitPos eWhichH = WhichH( eWhich );
+
+ return rViewData.GetPosX( eWhichH );
+ }
+ OSL_FAIL("no View ?!?"); //! Exception?
+ return 0;
+}
+
+void SAL_CALL ScViewPaneBase::setFirstVisibleColumn(sal_Int32 nFirstVisibleColumn)
+{
+ SolarMutexGuard aGuard;
+ if (pViewShell)
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScHSplitPos eWhichH = WhichH( eWhich );
+
+ tools::Long nDeltaX = static_cast<tools::Long>(nFirstVisibleColumn) - rViewData.GetPosX( eWhichH );
+ pViewShell->ScrollX( nDeltaX, eWhichH );
+ }
+}
+
+sal_Int32 SAL_CALL ScViewPaneBase::getFirstVisibleRow()
+{
+ SolarMutexGuard aGuard;
+ if (pViewShell)
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScVSplitPos eWhichV = WhichV( eWhich );
+
+ return rViewData.GetPosY( eWhichV );
+ }
+ OSL_FAIL("no View ?!?"); //! Exception?
+ return 0;
+}
+
+void SAL_CALL ScViewPaneBase::setFirstVisibleRow( sal_Int32 nFirstVisibleRow )
+{
+ SolarMutexGuard aGuard;
+ if (pViewShell)
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScVSplitPos eWhichV = WhichV( eWhich );
+
+ tools::Long nDeltaY = static_cast<tools::Long>(nFirstVisibleRow) - rViewData.GetPosY( eWhichV );
+ pViewShell->ScrollY( nDeltaY, eWhichV );
+ }
+}
+
+table::CellRangeAddress SAL_CALL ScViewPaneBase::getVisibleRange()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aAdr;
+ if (pViewShell)
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScHSplitPos eWhichH = WhichH( eWhich );
+ ScVSplitPos eWhichV = WhichV( eWhich );
+
+ // VisibleCellsX returns only completely visible cells
+ // VisibleRange in Excel also partially visible ones
+ //! do the same ???
+
+ SCCOL nVisX = rViewData.VisibleCellsX( eWhichH );
+ SCROW nVisY = rViewData.VisibleCellsY( eWhichV );
+ if (!nVisX) nVisX = 1; // there has to be something in the range
+ if (!nVisY) nVisY = 1;
+ aAdr.Sheet = rViewData.GetTabNo();
+ aAdr.StartColumn = rViewData.GetPosX( eWhichH );
+ aAdr.StartRow = rViewData.GetPosY( eWhichV );
+ aAdr.EndColumn = aAdr.StartColumn + nVisX - 1;
+ aAdr.EndRow = aAdr.StartRow + nVisY - 1;
+ }
+ return aAdr;
+}
+
+// XCellRangeSource
+
+uno::Reference<table::XCellRange> SAL_CALL ScViewPaneBase::getReferredCells()
+{
+ SolarMutexGuard aGuard;
+ if (pViewShell)
+ {
+ ScDocShell* pDocSh = pViewShell->GetViewData().GetDocShell();
+
+ table::CellRangeAddress aAdr(getVisibleRange()); //! helper function with ScRange?
+ ScRange aRange( static_cast<SCCOL>(aAdr.StartColumn), static_cast<SCROW>(aAdr.StartRow), aAdr.Sheet,
+ static_cast<SCCOL>(aAdr.EndColumn), static_cast<SCROW>(aAdr.EndRow), aAdr.Sheet );
+ if ( aRange.aStart == aRange.aEnd )
+ return new ScCellObj( pDocSh, aRange.aStart );
+ else
+ return new ScCellRangeObj( pDocSh, aRange );
+ }
+
+ return nullptr;
+}
+
+namespace
+{
+ bool lcl_prepareFormShellCall( ScTabViewShell* _pViewShell, sal_uInt16 _nPane, FmFormShell*& _rpFormShell, vcl::Window*& _rpWindow, SdrView*& _rpSdrView )
+ {
+ if ( !_pViewShell )
+ return false;
+
+ ScViewData& rViewData = _pViewShell->GetViewData();
+ ScSplitPos eWhich = ( _nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(_nPane);
+ _rpWindow = _pViewShell->GetWindowByPos( eWhich );
+ _rpSdrView = _pViewShell->GetScDrawView();
+ _rpFormShell = _pViewShell->GetFormShell();
+ return ( _rpFormShell != nullptr ) && ( _rpSdrView != nullptr )&& ( _rpWindow != nullptr );
+ }
+}
+
+// XFormLayerAccess
+uno::Reference< form::runtime::XFormController > SAL_CALL ScViewPaneBase::getFormController( const uno::Reference< form::XForm >& Form )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference< form::runtime::XFormController > xController;
+
+ vcl::Window* pWindow( nullptr );
+ SdrView* pSdrView( nullptr );
+ FmFormShell* pFormShell( nullptr );
+ if ( lcl_prepareFormShellCall( pViewShell, nPane, pFormShell, pWindow, pSdrView ) )
+ xController = FmFormShell::GetFormController( Form, *pSdrView, *pWindow->GetOutDev() );
+
+ return xController;
+}
+
+sal_Bool SAL_CALL ScViewPaneBase::isFormDesignMode( )
+{
+ SolarMutexGuard aGuard;
+
+ bool bIsFormDesignMode( true );
+
+ FmFormShell* pFormShell( pViewShell ? pViewShell->GetFormShell() : nullptr );
+ if ( pFormShell )
+ bIsFormDesignMode = pFormShell->IsDesignMode();
+
+ return bIsFormDesignMode;
+}
+
+void SAL_CALL ScViewPaneBase::setFormDesignMode( sal_Bool DesignMode )
+{
+ SolarMutexGuard aGuard;
+
+ vcl::Window* pWindow( nullptr );
+ SdrView* pSdrView( nullptr );
+ FmFormShell* pFormShell( nullptr );
+ if ( lcl_prepareFormShellCall( pViewShell, nPane, pFormShell, pWindow, pSdrView ) )
+ pFormShell->SetDesignMode( DesignMode );
+}
+
+// XControlAccess
+
+uno::Reference<awt::XControl> SAL_CALL ScViewPaneBase::getControl(
+ const uno::Reference<awt::XControlModel>& xModel )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<awt::XControl> xRet;
+
+ vcl::Window* pWindow( nullptr );
+ SdrView* pSdrView( nullptr );
+ FmFormShell* pFormShell( nullptr );
+ if ( lcl_prepareFormShellCall( pViewShell, nPane, pFormShell, pWindow, pSdrView ) )
+ pFormShell->GetFormControl( xModel, *pSdrView, *pWindow->GetOutDev(), xRet );
+
+ if ( !xRet.is() )
+ throw container::NoSuchElementException(); // no control found
+
+ return xRet;
+}
+
+awt::Rectangle ScViewPaneBase::GetVisArea() const
+{
+ awt::Rectangle aVisArea;
+ if (pViewShell)
+ {
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ pViewShell->GetViewData().GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScGridWindow* pWindow = static_cast<ScGridWindow*>(pViewShell->GetWindowByPos(eWhich));
+ ScDocument& rDoc = pViewShell->GetViewData().GetDocument();
+ if (pWindow)
+ {
+ ScHSplitPos eWhichH = ((eWhich == SC_SPLIT_TOPLEFT) || (eWhich == SC_SPLIT_BOTTOMLEFT)) ?
+ SC_SPLIT_LEFT : SC_SPLIT_RIGHT;
+ ScVSplitPos eWhichV = ((eWhich == SC_SPLIT_TOPLEFT) || (eWhich == SC_SPLIT_TOPRIGHT)) ?
+ SC_SPLIT_TOP : SC_SPLIT_BOTTOM;
+ ScAddress aCell(pViewShell->GetViewData().GetPosX(eWhichH),
+ pViewShell->GetViewData().GetPosY(eWhichV),
+ pViewShell->GetViewData().GetTabNo());
+ tools::Rectangle aCellRect( rDoc.GetMMRect( aCell.Col(), aCell.Row(), aCell.Col(), aCell.Row(), aCell.Tab() ) );
+ Size aVisSize( pWindow->PixelToLogic( pWindow->GetSizePixel(), pWindow->GetDrawMapMode( true ) ) );
+ Point aVisPos( aCellRect.TopLeft() );
+ if ( rDoc.IsLayoutRTL( aCell.Tab() ) )
+ {
+ aVisPos = aCellRect.TopRight();
+ aVisPos.AdjustX( -(aVisSize.Width()) );
+ }
+ tools::Rectangle aVisRect( aVisPos, aVisSize );
+ aVisArea = AWTRectangle(aVisRect);
+ }
+ }
+ return aVisArea;
+}
+
+ScViewPaneObj::ScViewPaneObj(ScTabViewShell* pViewSh, sal_uInt16 nP) :
+ ScViewPaneBase( pViewSh, nP )
+{
+}
+
+ScViewPaneObj::~ScViewPaneObj()
+{
+}
+
+uno::Any SAL_CALL ScViewPaneObj::queryInterface( const uno::Type& rType )
+{
+ // ScViewPaneBase has everything except OWeakObject
+
+ uno::Any aRet(ScViewPaneBase::queryInterface( rType ));
+ if (!aRet.hasValue())
+ aRet = OWeakObject::queryInterface( rType );
+ return aRet;
+}
+
+void SAL_CALL ScViewPaneObj::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL ScViewPaneObj::release() noexcept
+{
+ OWeakObject::release();
+}
+
+// We need default ctor for SMART_REFLECTION_IMPLEMENTATION
+
+ScTabViewObj::ScTabViewObj( ScTabViewShell* pViewSh ) :
+ ScViewPaneBase( pViewSh, SC_VIEWPANE_ACTIVE ),
+ SfxBaseController( pViewSh ),
+ aPropSet( lcl_GetViewOptPropertyMap() ),
+ aMouseClickHandlers( 0 ),
+ aActivationListeners( 0 ),
+ nPreviousTab( 0 ),
+ bDrawSelModeSet(false),
+ bFilteredRangeSelection(false),
+ mbLeftMousePressed(false)
+{
+ if (pViewSh)
+ nPreviousTab = pViewSh->GetViewData().GetTabNo();
+}
+
+ScTabViewObj::~ScTabViewObj()
+{
+ //! Listening or something along that line
+ if (!aMouseClickHandlers.empty())
+ {
+ acquire();
+ EndMouseListening();
+ }
+ if (!aActivationListeners.empty())
+ {
+ acquire();
+ EndActivationListening();
+ }
+}
+
+uno::Any SAL_CALL ScTabViewObj::queryInterface( const uno::Type& rType )
+{
+ uno::Any aReturn = ::cppu::queryInterface(rType,
+ static_cast<sheet::XSpreadsheetView*>(this),
+ static_cast<sheet::XEnhancedMouseClickBroadcaster*>(this),
+ static_cast<sheet::XActivationBroadcaster*>(this),
+ static_cast<container::XEnumerationAccess*>(this),
+ static_cast<container::XIndexAccess*>(this),
+ static_cast<container::XElementAccess*>(static_cast<container::XIndexAccess*>(this)),
+ static_cast<view::XSelectionSupplier*>(this),
+ static_cast<beans::XPropertySet*>(this),
+ static_cast<sheet::XViewSplitable*>(this),
+ static_cast<sheet::XViewFreezable*>(this),
+ static_cast<sheet::XRangeSelection*>(this),
+ static_cast<sheet::XSelectedSheetsSupplier*>(this),
+ static_cast<datatransfer::XTransferableSupplier*>(this));
+ if ( aReturn.hasValue() )
+ return aReturn;
+
+ uno::Any aRet(ScViewPaneBase::queryInterface( rType ));
+ if (!aRet.hasValue())
+ aRet = SfxBaseController::queryInterface( rType );
+ return aRet;
+}
+
+void SAL_CALL ScTabViewObj::acquire() noexcept
+{
+ SfxBaseController::acquire();
+}
+
+void SAL_CALL ScTabViewObj::release() noexcept
+{
+ SfxBaseController::release();
+}
+
+static void lcl_CallActivate( ScDocShell* pDocSh, SCTAB nTab, ScSheetEventId nEvent )
+{
+ ScDocument& rDoc = pDocSh->GetDocument();
+ // when deleting a sheet, nPreviousTab can be invalid
+ // (could be handled with reference updates)
+ if (!rDoc.HasTable(nTab))
+ return;
+
+ const ScSheetEvents* pEvents = rDoc.GetSheetEvents(nTab);
+ if (pEvents)
+ {
+ const OUString* pScript = pEvents->GetScript(nEvent);
+ if (pScript)
+ {
+ uno::Any aRet;
+ uno::Sequence<uno::Any> aParams;
+ uno::Sequence<sal_Int16> aOutArgsIndex;
+ uno::Sequence<uno::Any> aOutArgs;
+ /*ErrCode eRet =*/ pDocSh->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
+ }
+ }
+
+ // execute VBA event handlers
+ try
+ {
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( rDoc.GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ // the parameter is the clicked object, as in the mousePressed call above
+ uno::Sequence< uno::Any > aArgs{ uno::Any(nTab) };
+ xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+void ScTabViewObj::SheetChanged( bool bSameTabButMoved )
+{
+ if ( !GetViewShell() )
+ return;
+
+ ScViewData& rViewData = GetViewShell()->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ if (!aActivationListeners.empty())
+ {
+ sheet::ActivationEvent aEvent;
+ uno::Reference< sheet::XSpreadsheetView > xView(this);
+ aEvent.Source.set(xView, uno::UNO_QUERY);
+ aEvent.ActiveSheet = new ScTableSheetObj(pDocSh, rViewData.GetTabNo());
+ // Listener's handler may remove it from the listeners list
+ for (size_t i = aActivationListeners.size(); i > 0; --i)
+ {
+ try
+ {
+ aActivationListeners[i - 1]->activeSpreadsheetChanged( aEvent );
+ }
+ catch( uno::Exception& )
+ {
+ aActivationListeners.erase(aActivationListeners.begin() + (i - 1));
+ }
+ }
+ }
+
+ /* Handle sheet events, but do not trigger event handlers, if the old
+ active sheet gets re-activated after inserting/deleting/moving a sheet. */
+ SCTAB nNewTab = rViewData.GetTabNo();
+ if ( !bSameTabButMoved && (nNewTab != nPreviousTab) )
+ {
+ lcl_CallActivate( pDocSh, nPreviousTab, ScSheetEventId::UNFOCUS );
+ lcl_CallActivate( pDocSh, nNewTab, ScSheetEventId::FOCUS );
+ }
+ nPreviousTab = nNewTab;
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScTabViewObj::getTypes()
+{
+ return comphelper::concatSequences(
+ ScViewPaneBase::getTypes(),
+ SfxBaseController::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XSpreadsheetView>::get(),
+ cppu::UnoType<container::XEnumerationAccess>::get(),
+ cppu::UnoType<container::XIndexAccess>::get(),
+ cppu::UnoType<view::XSelectionSupplier>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<sheet::XViewSplitable>::get(),
+ cppu::UnoType<sheet::XViewFreezable>::get(),
+ cppu::UnoType<sheet::XRangeSelection>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get(),
+ cppu::UnoType<sheet::XEnhancedMouseClickBroadcaster>::get(),
+ cppu::UnoType<sheet::XActivationBroadcaster>::get(),
+ cppu::UnoType<datatransfer::XTransferableSupplier>::get()
+ } );
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScTabViewObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XDocumentView
+
+static bool lcl_TabInRanges( SCTAB nTab, const ScRangeList& rRanges )
+{
+ for (size_t i = 0, nCount = rRanges.size(); i < nCount; ++i)
+ {
+ const ScRange & rRange = rRanges[ i ];
+ if ( nTab >= rRange.aStart.Tab() && nTab <= rRange.aEnd.Tab() )
+ return true;
+ }
+ return false;
+}
+
+static void lcl_ShowObject( ScTabViewShell& rViewSh, const ScDrawView& rDrawView, const SdrObject* pSelObj )
+{
+ bool bFound = false;
+ SCTAB nObjectTab = 0;
+
+ SdrModel& rModel = rDrawView.GetModel();
+ sal_uInt16 nPageCount = rModel.GetPageCount();
+ for (sal_uInt16 i=0; i<nPageCount && !bFound; i++)
+ {
+ SdrPage* pPage = rModel.GetPage(i);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bFound)
+ {
+ if ( pObject == pSelObj )
+ {
+ bFound = true;
+ nObjectTab = static_cast<SCTAB>(i);
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+
+ if (bFound)
+ {
+ rViewSh.SetTabNo( nObjectTab );
+ rViewSh.ScrollToObject( pSelObj );
+ }
+}
+
+sal_Bool SAL_CALL ScTabViewObj::select( const uno::Any& aSelection )
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+
+ if ( !pViewSh )
+ return false;
+
+ //! Type of aSelection can be some specific interface instead of XInterface
+
+ bool bRet = false;
+ uno::Reference<uno::XInterface> xInterface(aSelection, uno::UNO_QUERY);
+ if ( !xInterface.is() ) //clear all selections
+ {
+ ScDrawView* pDrawView = pViewSh->GetScDrawView();
+ if (pDrawView)
+ {
+ pDrawView->ScEndTextEdit();
+ pDrawView->UnmarkAll();
+ }
+ else //#102232#; if there is no DrawView remove range selection
+ pViewSh->Unmark();
+ bRet = true;
+ }
+
+ if (bDrawSelModeSet) // remove DrawSelMode if set by API; if necessary it will be set again later
+ {
+ pViewSh->SetDrawSelMode(false);
+ pViewSh->UpdateLayerLocks();
+ bDrawSelModeSet = false;
+ }
+
+ if (bRet)
+ return bRet;
+
+ ScCellRangesBase* pRangesImp = dynamic_cast<ScCellRangesBase*>( xInterface.get() );
+ uno::Reference<drawing::XShapes> xShapeColl( xInterface, uno::UNO_QUERY );
+ uno::Reference<drawing::XShape> xShapeSel( xInterface, uno::UNO_QUERY );
+ SvxShape* pShapeImp = comphelper::getFromUnoTunnel<SvxShape>( xShapeSel );
+
+ if (pRangesImp) // Cell ranges
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetDocShell() == pRangesImp->GetDocShell() )
+ {
+ // perhaps remove drawing selection first
+ // (MarkListHasChanged removes sheet selection)
+
+ ScDrawView* pDrawView = pViewSh->GetScDrawView();
+ if (pDrawView)
+ {
+ pDrawView->ScEndTextEdit();
+ pDrawView->UnmarkAll();
+ }
+ FuPoor* pFunc = pViewSh->GetDrawFuncPtr();
+ if ( pFunc && pFunc->GetSlotID() != SID_OBJECT_SELECT )
+ {
+ // execute the slot of drawing function again -> switch off
+ SfxDispatcher* pDisp = pViewSh->GetDispatcher();
+ if (pDisp)
+ pDisp->Execute( pFunc->GetSlotID(), SfxCallMode::SYNCHRON );
+ }
+ pViewSh->SetDrawShell(false);
+ pViewSh->SetDrawSelMode(false); // after Dispatcher-Execute
+
+ // select ranges
+
+ const ScRangeList& rRanges = pRangesImp->GetRangeList();
+ size_t nRangeCount = rRanges.size();
+ // for empty range list, remove selection (cursor remains where it was)
+ if ( nRangeCount == 0 )
+ pViewSh->Unmark();
+ else if ( nRangeCount == 1 )
+ pViewSh->MarkRange( rRanges[ 0 ] );
+ else
+ {
+ // multiselection
+
+ const ScRange & rFirst = rRanges[ 0 ];
+ if ( !lcl_TabInRanges( rViewData.GetTabNo(), rRanges ) )
+ pViewSh->SetTabNo( rFirst.aStart.Tab() );
+ pViewSh->DoneBlockMode();
+ pViewSh->InitOwnBlockMode( rFirst ); /* TODO: or even the overall range? */
+ rViewData.GetMarkData().MarkFromRangeList( rRanges, true );
+ pViewSh->MarkDataChanged();
+ rViewData.GetDocShell()->PostPaintGridAll(); // Marks (old&new)
+ pViewSh->AlignToCursor( rFirst.aStart.Col(), rFirst.aStart.Row(),
+ SC_FOLLOW_JUMP );
+ pViewSh->SetCursor( rFirst.aStart.Col(), rFirst.aStart.Row() );
+
+ //! method of the view to select RangeList
+ }
+ bRet = true;
+ }
+ }
+ else if ( pShapeImp || xShapeColl.is() ) // Drawing-Layer
+ {
+ ScDrawView* pDrawView = pViewSh->GetScDrawView();
+ if (pDrawView)
+ {
+ pDrawView->ScEndTextEdit();
+ pDrawView->UnmarkAll();
+
+ if (pShapeImp) // single shape
+ {
+ SdrObject *pObj = pShapeImp->GetSdrObject();
+ if (pObj)
+ {
+ lcl_ShowObject( *pViewSh, *pDrawView, pObj );
+ SdrPageView* pPV = pDrawView->GetSdrPageView();
+ if ( pPV && pObj->getSdrPageFromSdrObject() == pPV->GetPage() )
+ {
+ pDrawView->MarkObj( pObj, pPV );
+ bRet = true;
+ }
+ }
+ }
+ else // Shape-Collection (xShapeColl is not 0)
+ {
+ // We'll switch to the sheet where the first object is
+ // and select all objects on that sheet
+ //!?throw exception when objects are on different sheets?
+
+ tools::Long nCount = xShapeColl->getCount();
+ if (nCount)
+ {
+ SdrPageView* pPV = nullptr;
+ bool bAllMarked(true);
+ for ( tools::Long i = 0; i < nCount; i++ )
+ {
+ uno::Reference<drawing::XShape> xShapeInt(xShapeColl->getByIndex(i), uno::UNO_QUERY);
+ if (xShapeInt.is())
+ {
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape( xShapeInt );
+ if (pObj)
+ {
+ if (!bDrawSelModeSet && (pObj->GetLayer() == SC_LAYER_BACK))
+ {
+ pViewSh->SetDrawSelMode(true);
+ pViewSh->UpdateLayerLocks();
+ bDrawSelModeSet = true;
+ }
+ if (!pPV) // first object
+ {
+ lcl_ShowObject( *pViewSh, *pDrawView, pObj );
+ pPV = pDrawView->GetSdrPageView();
+ }
+ if ( pPV && pObj->getSdrPageFromSdrObject() == pPV->GetPage() )
+ {
+ if (pDrawView->IsObjMarkable( pObj, pPV ))
+ pDrawView->MarkObj( pObj, pPV );
+ else
+ bAllMarked = false;
+ }
+ }
+ }
+ }
+ if (bAllMarked)
+ bRet = true;
+ }
+ else
+ bRet = true; // empty XShapes (all shapes are deselected)
+ }
+
+ if (bRet)
+ pViewSh->SetDrawShell(true);
+ }
+ }
+
+ if (!bRet)
+ throw lang::IllegalArgumentException();
+
+ return bRet;
+}
+
+uno::Reference<drawing::XShapes> ScTabViewShell::getSelectedXShapes()
+{
+ uno::Reference<drawing::XShapes> xShapes;
+ SdrView* pSdrView = GetScDrawView();
+ if (pSdrView)
+ {
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+ if (nMarkCount)
+ {
+ // generate ShapeCollection (like in SdXImpressView::getSelection in Draw)
+ // XInterfaceRef will be returned and it has to be UsrObject-XInterface
+ xShapes = drawing::ShapeCollection::create(comphelper::getProcessComponentContext());
+
+ for (size_t i = 0; i < nMarkCount; ++i)
+ {
+ SdrObject* pDrawObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if (pDrawObj)
+ {
+ uno::Reference<drawing::XShape> xShape( pDrawObj->getUnoShape(), uno::UNO_QUERY );
+ if (xShape.is())
+ xShapes->add(xShape);
+ }
+ }
+ }
+ }
+ return xShapes;
+}
+
+uno::Any SAL_CALL ScTabViewObj::getSelection()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ rtl::Reference<ScCellRangesBase> pObj;
+ if (pViewSh)
+ {
+ // is something selected in drawing layer?
+ uno::Reference<uno::XInterface> xRet(pViewSh->getSelectedXShapes());
+ if (xRet.is())
+ return uno::Any(xRet);
+
+ // otherwise sheet (cell) selection
+
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+
+ const ScMarkData& rMark = rViewData.GetMarkData();
+ SCTAB nTabs = rMark.GetSelectCount();
+
+ ScRange aRange;
+ ScMarkType eMarkType = rViewData.GetSimpleArea(aRange);
+ if ( nTabs == 1 && (eMarkType == SC_MARK_SIMPLE) )
+ {
+ // tdf#154803 - check if range is entirely merged
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const ScMergeAttr* pMergeAttr = rDoc.GetAttr(aRange.aStart, ATTR_MERGE);
+ SCCOL nColSpan = 1;
+ SCROW nRowSpan = 1;
+ if (pMergeAttr && pMergeAttr->IsMerged())
+ {
+ nColSpan = pMergeAttr->GetColMerge();
+ nRowSpan = pMergeAttr->GetRowMerge();
+ }
+ // tdf#147122 - return cell object when a simple selection is entirely merged
+ if (aRange.aStart == aRange.aEnd
+ || (aRange.aEnd.Col() - aRange.aStart.Col() == nColSpan - 1
+ && aRange.aEnd.Row() - aRange.aStart.Row() == nRowSpan - 1))
+ pObj = new ScCellObj( pDocSh, aRange.aStart );
+ else
+ pObj = new ScCellRangeObj( pDocSh, aRange );
+ }
+ else if ( nTabs == 1 && (eMarkType == SC_MARK_SIMPLE_FILTERED) )
+ {
+ ScMarkData aFilteredMark( rMark );
+ ScViewUtil::UnmarkFiltered( aFilteredMark, pDocSh->GetDocument());
+ ScRangeList aRangeList;
+ aFilteredMark.FillRangeListWithMarks( &aRangeList, false);
+ // Theoretically a selection may start and end on a filtered row.
+ switch ( aRangeList.size() )
+ {
+ case 0:
+ // No unfiltered row, we have to return some object, so
+ // here is one with no ranges.
+ pObj = new ScCellRangesObj( pDocSh, aRangeList );
+ break;
+ case 1:
+ {
+ const ScRange& rRange = aRangeList[ 0 ];
+ if (rRange.aStart == rRange.aEnd)
+ pObj = new ScCellObj( pDocSh, rRange.aStart );
+ else
+ pObj = new ScCellRangeObj( pDocSh, rRange );
+ }
+ break;
+ default:
+ pObj = new ScCellRangesObj( pDocSh, aRangeList );
+ }
+ }
+ else // multiselection
+ {
+ ScRangeListRef xRanges;
+ rViewData.GetMultiArea( xRanges );
+
+ // if there are more sheets, copy ranges
+ //! should this happen in ScMarkData::FillRangeListWithMarks already?
+ if ( nTabs > 1 )
+ rMark.ExtendRangeListTables( xRanges.get() );
+
+ pObj = new ScCellRangesObj( pDocSh, *xRanges );
+ }
+
+ if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ // remember if the selection was from the cursor position without anything selected
+ // (used when rendering the selection)
+
+ pObj->SetCursorOnly( true );
+ }
+ }
+
+ return uno::Any(uno::Reference(cppu::getXWeak(pObj.get())));
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScTabViewObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.SpreadsheetViewPanesEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScTabViewObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ sal_uInt16 nPanes = 0;
+ if (pViewSh)
+ {
+ nPanes = 1;
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ nPanes *= 2;
+ if ( rViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ nPanes *= 2;
+ }
+ return nPanes;
+}
+
+uno::Any SAL_CALL ScTabViewObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XViewPane> xPane(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if (!xPane.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xPane);
+}
+
+uno::Type SAL_CALL ScTabViewObj::getElementType()
+{
+ return cppu::UnoType<sheet::XViewPane>::get();
+}
+
+sal_Bool SAL_CALL ScTabViewObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XSpreadsheetView
+
+rtl::Reference<ScViewPaneObj> ScTabViewObj::GetObjectByIndex_Impl(sal_uInt16 nIndex) const
+{
+ static const ScSplitPos ePosHV[4] =
+ { SC_SPLIT_TOPLEFT, SC_SPLIT_BOTTOMLEFT, SC_SPLIT_TOPRIGHT, SC_SPLIT_BOTTOMRIGHT };
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScSplitPos eWhich = SC_SPLIT_BOTTOMLEFT; // default position
+ bool bError = false;
+ ScViewData& rViewData = pViewSh->GetViewData();
+ bool bHor = ( rViewData.GetHSplitMode() != SC_SPLIT_NONE );
+ bool bVer = ( rViewData.GetVSplitMode() != SC_SPLIT_NONE );
+ if ( bHor && bVer )
+ {
+ // bottom left, bottom right, top left, top right - like in Excel
+ if ( nIndex < 4 )
+ eWhich = ePosHV[nIndex];
+ else
+ bError = true;
+ }
+ else if ( bHor )
+ {
+ if ( nIndex > 1 )
+ bError = true;
+ else if ( nIndex == 1 )
+ eWhich = SC_SPLIT_BOTTOMRIGHT;
+ // otherwise SC_SPLIT_BOTTOMLEFT
+ }
+ else if ( bVer )
+ {
+ if ( nIndex > 1 )
+ bError = true;
+ else if ( nIndex == 0 )
+ eWhich = SC_SPLIT_TOPLEFT;
+ // otherwise SC_SPLIT_BOTTOMLEFT
+ }
+ else if ( nIndex > 0 )
+ bError = true; // not split: only 0 is valid
+
+ if (!bError)
+ return new ScViewPaneObj( pViewSh, sal::static_int_cast<sal_uInt16>(eWhich) );
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSpreadsheet> SAL_CALL ScTabViewObj::getActiveSheet()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ SCTAB nTab = rViewData.GetTabNo();
+ return new ScTableSheetObj( rViewData.GetDocShell(), nTab );
+ }
+ return nullptr;
+}
+
+// support expand (but not replace) the active sheet
+void SAL_CALL ScTabViewObj::setActiveSheet( const uno::Reference<sheet::XSpreadsheet>& xActiveSheet )
+{
+ SolarMutexGuard aGuard;
+ comphelper::ProfileZone aZone("setActiveSheet");
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if ( !(pViewSh && xActiveSheet.is()) )
+ return;
+
+ // XSpreadsheet and ScCellRangesBase -> has to be the same sheet
+
+ ScCellRangesBase* pRangesImp = dynamic_cast<ScCellRangesBase*>( xActiveSheet.get() );
+ if ( pRangesImp && pViewSh->GetViewData().GetDocShell() == pRangesImp->GetDocShell() )
+ {
+ const ScRangeList& rRanges = pRangesImp->GetRangeList();
+ if ( rRanges.size() == 1 )
+ {
+ SCTAB nNewTab = rRanges[ 0 ].aStart.Tab();
+ if ( pViewSh->GetViewData().GetDocument().HasTable(nNewTab) )
+ pViewSh->SetTabNo( nNewTab );
+ }
+ }
+}
+
+uno::Reference< uno::XInterface > ScTabViewObj::GetClickedObject(const Point& rPoint) const
+{
+ uno::Reference< uno::XInterface > xTarget;
+ if (GetViewShell())
+ {
+ SCCOL nX;
+ SCROW nY;
+ ScViewData& rData = GetViewShell()->GetViewData();
+ ScSplitPos eSplitMode = rData.GetActivePart();
+ SCTAB nTab(rData.GetTabNo());
+ rData.GetPosFromPixel( rPoint.X(), rPoint.Y(), eSplitMode, nX, nY);
+
+ ScAddress aCellPos (nX, nY, nTab);
+ rtl::Reference<ScCellObj> pCellObj = new ScCellObj(rData.GetDocShell(), aCellPos);
+
+ xTarget.set(uno::Reference<table::XCell>(pCellObj), uno::UNO_QUERY);
+
+ ScDocument& rDoc = rData.GetDocument();
+ if (ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer())
+ {
+ SdrPage* pDrawPage = nullptr;
+ if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab))
+ pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+
+ SdrView* pDrawView = GetViewShell()->GetScDrawView();
+
+ if (pDrawPage && pDrawView && pDrawView->GetSdrPageView())
+ {
+ vcl::Window* pActiveWin = rData.GetActiveWin();
+ Point aPos = pActiveWin->PixelToLogic(rPoint);
+
+ double fHitLog = pActiveWin->PixelToLogic(Size(pDrawView->GetHitTolerancePixel(),0)).Width();
+
+ for (const rtl::Reference<SdrObject>& pObj : *pDrawPage)
+ {
+ if (SdrObjectPrimitiveHit(*pObj, aPos, {fHitLog, fHitLog}, *pDrawView->GetSdrPageView(), nullptr, false))
+ {
+ xTarget.set(pObj->getUnoShape(), uno::UNO_QUERY);
+ break;
+ }
+ }
+ }
+ }
+ }
+ return xTarget;
+}
+
+bool ScTabViewObj::IsMouseListening() const
+{
+ if ( !aMouseClickHandlers.empty() )
+ return true;
+
+ // also include sheet events, because MousePressed must be called for them
+ ScViewData& rViewData = GetViewShell()->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ return
+ rDoc.HasSheetEventScript( nTab, ScSheetEventId::RIGHTCLICK, true ) ||
+ rDoc.HasSheetEventScript( nTab, ScSheetEventId::DOUBLECLICK, true ) ||
+ rDoc.HasSheetEventScript( nTab, ScSheetEventId::SELECT, true );
+
+}
+
+bool ScTabViewObj::MousePressed( const awt::MouseEvent& e )
+{
+ bool bReturn(false);
+ if ( e.Buttons == css::awt::MouseButton::LEFT )
+ mbLeftMousePressed = true;
+
+ uno::Reference< uno::XInterface > xTarget = GetClickedObject(Point(e.X, e.Y));
+ if (!aMouseClickHandlers.empty() && xTarget.is())
+ {
+ awt::EnhancedMouseEvent aMouseEvent;
+
+ aMouseEvent.Buttons = e.Buttons;
+ aMouseEvent.X = e.X;
+ aMouseEvent.Y = e.Y;
+ aMouseEvent.ClickCount = e.ClickCount;
+ aMouseEvent.PopupTrigger = e.PopupTrigger;
+ aMouseEvent.Target = xTarget;
+ aMouseEvent.Modifiers = e.Modifiers;
+
+ // Listener's handler may remove it from the listeners list
+ for (size_t i = aMouseClickHandlers.size(); i > 0; --i)
+ {
+ try
+ {
+ if (!aMouseClickHandlers[i - 1]->mousePressed(aMouseEvent))
+ bReturn = true;
+ }
+ catch ( uno::Exception& )
+ {
+ aMouseClickHandlers.erase(aMouseClickHandlers.begin() + (i - 1));
+ }
+ }
+ }
+
+ // handle sheet events
+ bool bDoubleClick = ( e.Buttons == awt::MouseButton::LEFT && e.ClickCount == 2 );
+ bool bRightClick = ( e.Buttons == awt::MouseButton::RIGHT && e.ClickCount == 1 );
+ if ( ( bDoubleClick || bRightClick ) && !bReturn && xTarget.is())
+ {
+ ScSheetEventId nEvent = bDoubleClick ? ScSheetEventId::DOUBLECLICK : ScSheetEventId::RIGHTCLICK;
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ const ScSheetEvents* pEvents = rDoc.GetSheetEvents(nTab);
+ if (pEvents)
+ {
+ const OUString* pScript = pEvents->GetScript(nEvent);
+ if (pScript)
+ {
+ // the macro parameter is the clicked object, as in the mousePressed call above
+ uno::Sequence<uno::Any> aParams{ uno::Any(xTarget) };
+
+ uno::Any aRet;
+ uno::Sequence<sal_Int16> aOutArgsIndex;
+ uno::Sequence<uno::Any> aOutArgs;
+
+ /*ErrCode eRet =*/ pDocSh->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
+
+ // look for a boolean return value of true
+ bool bRetValue = false;
+ if ((aRet >>= bRetValue) && bRetValue)
+ bReturn = true;
+ }
+ }
+
+ // execute VBA event handler
+ if (!bReturn && xTarget.is()) try
+ {
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( rDoc.GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ // the parameter is the clicked object, as in the mousePressed call above
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xTarget) };
+ xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs );
+ }
+ catch( util::VetoException& )
+ {
+ bReturn = true;
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+
+ return bReturn;
+}
+
+bool ScTabViewObj::MouseReleased( const awt::MouseEvent& e )
+{
+ if ( e.Buttons == css::awt::MouseButton::LEFT )
+ {
+ try
+ {
+ ScTabViewShell* pViewSh = GetViewShell();
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( rDoc.GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ uno::Sequence< uno::Any > aArgs{ getSelection() };
+ xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( ScSheetEventId::SELECT ), aArgs );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ mbLeftMousePressed = false;
+ }
+
+ bool bReturn(false);
+
+ if (!aMouseClickHandlers.empty())
+ {
+ uno::Reference< uno::XInterface > xTarget = GetClickedObject(Point(e.X, e.Y));
+
+ if (xTarget.is())
+ {
+ awt::EnhancedMouseEvent aMouseEvent;
+
+ aMouseEvent.Buttons = e.Buttons;
+ aMouseEvent.X = e.X;
+ aMouseEvent.Y = e.Y;
+ aMouseEvent.ClickCount = e.ClickCount;
+ aMouseEvent.PopupTrigger = e.PopupTrigger;
+ aMouseEvent.Target = xTarget;
+ aMouseEvent.Modifiers = e.Modifiers;
+
+ // Listener's handler may remove it from the listeners list
+ for (size_t i = aMouseClickHandlers.size(); i > 0; --i)
+ {
+ try
+ {
+ if (!aMouseClickHandlers[i - 1]->mouseReleased( aMouseEvent ))
+ bReturn = true;
+ }
+ catch ( uno::Exception& )
+ {
+ aMouseClickHandlers.erase(aMouseClickHandlers.begin() + (i - 1));
+ }
+ }
+ }
+ }
+ return bReturn;
+}
+
+// XEnhancedMouseClickBroadcaster
+
+void ScTabViewObj::EndMouseListening()
+{
+ lang::EventObject aEvent;
+ aEvent.Source = getXWeak();
+ for (const auto& rListener : aMouseClickHandlers)
+ {
+ try
+ {
+ rListener->disposing(aEvent);
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ aMouseClickHandlers.clear();
+}
+
+void ScTabViewObj::EndActivationListening()
+{
+ lang::EventObject aEvent;
+ aEvent.Source = getXWeak();
+ for (const auto& rListener : aActivationListeners)
+ {
+ try
+ {
+ rListener->disposing(aEvent);
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ aActivationListeners.clear();
+}
+
+void SAL_CALL ScTabViewObj::addEnhancedMouseClickHandler( const uno::Reference< awt::XEnhancedMouseClickHandler >& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ if (aListener.is())
+ {
+ aMouseClickHandlers.push_back( aListener );
+ }
+}
+
+void SAL_CALL ScTabViewObj::removeEnhancedMouseClickHandler( const uno::Reference< awt::XEnhancedMouseClickHandler >& aListener )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = aMouseClickHandlers.size();
+ std::erase(aMouseClickHandlers, aListener);
+ if (aMouseClickHandlers.empty() && (nCount > 0)) // only if last listener removed
+ EndMouseListening();
+}
+
+// XActivationBroadcaster
+
+void SAL_CALL ScTabViewObj::addActivationEventListener( const uno::Reference< sheet::XActivationEventListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ if (aListener.is())
+ {
+ aActivationListeners.push_back( aListener );
+ }
+}
+
+void SAL_CALL ScTabViewObj::removeActivationEventListener( const uno::Reference< sheet::XActivationEventListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = aActivationListeners.size();
+ std::erase(aActivationListeners, aListener);
+ if (aActivationListeners.empty() && (nCount > 0)) // only if last listener removed
+ EndActivationListening();
+}
+
+sal_Int16 ScTabViewObj::GetZoom() const
+{
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ const Fraction& rZoomY = pViewSh->GetViewData().GetZoomY(); // Y will be shown
+ return static_cast<sal_Int16>(tools::Long( rZoomY * 100 ));
+ }
+ return 0;
+}
+
+void ScTabViewObj::SetZoom(sal_Int16 nZoom)
+{
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ if ( nZoom != GetZoom() && nZoom != 0 )
+ {
+ if (!pViewSh->GetViewData().IsPagebreakMode())
+ {
+ ScModule* pScMod = SC_MOD();
+ ScAppOptions aNewOpt(pScMod->GetAppOptions());
+ aNewOpt.SetZoom( nZoom );
+ aNewOpt.SetZoomType( pViewSh->GetViewData().GetView()->GetZoomType() );
+ pScMod->SetAppOptions( aNewOpt );
+ }
+ }
+ Fraction aFract( nZoom, 100 );
+ pViewSh->SetZoom( aFract, aFract, true );
+ pViewSh->PaintGrid();
+ pViewSh->PaintTop();
+ pViewSh->PaintLeft();
+ pViewSh->GetViewFrame().GetBindings().Invalidate( SID_ATTR_ZOOM );
+ pViewSh->GetViewFrame().GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
+ pViewSh->GetViewFrame().GetBindings().Invalidate(SID_ZOOM_IN);
+ pViewSh->GetViewFrame().GetBindings().Invalidate(SID_ZOOM_OUT);
+}
+
+sal_Int16 ScTabViewObj::GetZoomType() const
+{
+ sal_Int16 aZoomType = view::DocumentZoomType::OPTIMAL;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ SvxZoomType eZoomType = pViewSh->GetViewData().GetView()->GetZoomType();
+ switch (eZoomType)
+ {
+ case SvxZoomType::PERCENT:
+ aZoomType = view::DocumentZoomType::BY_VALUE;
+ break;
+ case SvxZoomType::OPTIMAL:
+ aZoomType = view::DocumentZoomType::OPTIMAL;
+ break;
+ case SvxZoomType::WHOLEPAGE:
+ aZoomType = view::DocumentZoomType::ENTIRE_PAGE;
+ break;
+ case SvxZoomType::PAGEWIDTH:
+ aZoomType = view::DocumentZoomType::PAGE_WIDTH;
+ break;
+ case SvxZoomType::PAGEWIDTH_NOBORDER:
+ aZoomType = view::DocumentZoomType::PAGE_WIDTH_EXACT;
+ break;
+ }
+ }
+ return aZoomType;
+}
+
+void ScTabViewObj::SetZoomType(sal_Int16 aZoomType)
+{
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ ScDBFunc* pView = pViewSh->GetViewData().GetView();
+ if (!pView)
+ return;
+
+ SvxZoomType eZoomType;
+ switch (aZoomType)
+ {
+ case view::DocumentZoomType::BY_VALUE:
+ eZoomType = SvxZoomType::PERCENT;
+ break;
+ case view::DocumentZoomType::OPTIMAL:
+ eZoomType = SvxZoomType::OPTIMAL;
+ break;
+ case view::DocumentZoomType::ENTIRE_PAGE:
+ eZoomType = SvxZoomType::WHOLEPAGE;
+ break;
+ case view::DocumentZoomType::PAGE_WIDTH:
+ eZoomType = SvxZoomType::PAGEWIDTH;
+ break;
+ case view::DocumentZoomType::PAGE_WIDTH_EXACT:
+ eZoomType = SvxZoomType::PAGEWIDTH_NOBORDER;
+ break;
+ default:
+ eZoomType = SvxZoomType::OPTIMAL;
+ }
+ sal_Int16 nZoom(GetZoom());
+ sal_Int16 nOldZoom(nZoom);
+ if ( eZoomType == SvxZoomType::PERCENT )
+ {
+ if ( nZoom < MINZOOM ) nZoom = MINZOOM;
+ if ( nZoom > MAXZOOM ) nZoom = MAXZOOM;
+ }
+ else
+ nZoom = pView->CalcZoom( eZoomType, nOldZoom );
+
+ switch ( eZoomType )
+ {
+ case SvxZoomType::WHOLEPAGE:
+ case SvxZoomType::PAGEWIDTH:
+ pView->SetZoomType( eZoomType, true );
+ break;
+
+ default:
+ pView->SetZoomType( SvxZoomType::PERCENT, true );
+ }
+ SetZoom( nZoom );
+}
+
+sal_Bool SAL_CALL ScTabViewObj::getIsWindowSplit()
+{
+ SolarMutexGuard aGuard;
+ // what menu slot SID_WINDOW_SPLIT does
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ return ( rViewData.GetHSplitMode() == SC_SPLIT_NORMAL ||
+ rViewData.GetVSplitMode() == SC_SPLIT_NORMAL );
+ }
+
+ return false;
+}
+
+sal_Bool SAL_CALL ScTabViewObj::hasFrozenPanes()
+{
+ SolarMutexGuard aGuard;
+ // what menu slot SID_WINDOW_FIX does
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ return ( rViewData.GetHSplitMode() == SC_SPLIT_FIX ||
+ rViewData.GetVSplitMode() == SC_SPLIT_FIX );
+ }
+
+ return false;
+}
+
+sal_Int32 SAL_CALL ScTabViewObj::getSplitHorizontal()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ return rViewData.GetHSplitPos();
+ }
+ return 0;
+}
+
+sal_Int32 SAL_CALL ScTabViewObj::getSplitVertical()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ return rViewData.GetVSplitPos();
+ }
+ return 0;
+}
+
+sal_Int32 SAL_CALL ScTabViewObj::getSplitColumn()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ {
+ tools::Long nSplit = rViewData.GetHSplitPos();
+
+ ScSplitPos ePos = SC_SPLIT_BOTTOMLEFT;
+ if ( rViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ ePos = SC_SPLIT_TOPLEFT;
+
+ SCCOL nCol;
+ SCROW nRow;
+ rViewData.GetPosFromPixel( nSplit, 0, ePos, nCol, nRow, false );
+ if ( nCol > 0 )
+ return nCol;
+ }
+ }
+ return 0;
+}
+
+sal_Int32 SAL_CALL ScTabViewObj::getSplitRow()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ {
+ tools::Long nSplit = rViewData.GetVSplitPos();
+
+ // split vertically
+ SCCOL nCol;
+ SCROW nRow;
+ rViewData.GetPosFromPixel( 0, nSplit, SC_SPLIT_TOPLEFT, nCol, nRow, false );
+ if ( nRow > 0 )
+ return nRow;
+ }
+ }
+ return 0;
+}
+
+void SAL_CALL ScTabViewObj::splitAtPosition( sal_Int32 nPixelX, sal_Int32 nPixelY )
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ pViewSh->SplitAtPixel( Point( nPixelX, nPixelY ) );
+ pViewSh->FreezeSplitters( false );
+ pViewSh->InvalidateSplit();
+ }
+}
+
+void SAL_CALL ScTabViewObj::freezeAtPosition( sal_Int32 nColumns, sal_Int32 nRows )
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ // first, remove them all -> no stress with scrolling in the meantime
+
+ pViewSh->RemoveSplit();
+
+ Point aWinStart;
+ vcl::Window* pWin = pViewSh->GetWindowByPos( SC_SPLIT_BOTTOMLEFT );
+ if (pWin)
+ aWinStart = pWin->GetPosPixel();
+
+ ScViewData& rViewData = pViewSh->GetViewData();
+ Point aSplit(rViewData.GetScrPos( static_cast<SCCOL>(nColumns), static_cast<SCROW>(nRows), SC_SPLIT_BOTTOMLEFT, true ));
+ aSplit += aWinStart;
+
+ pViewSh->SplitAtPixel( aSplit );
+ pViewSh->FreezeSplitters( true );
+ pViewSh->InvalidateSplit();
+}
+
+void SAL_CALL ScTabViewObj::addSelectionChangeListener(
+ const uno::Reference<view::XSelectionChangeListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+ aSelectionChgListeners.push_back( xListener );
+}
+
+void SAL_CALL ScTabViewObj::removeSelectionChangeListener(
+ const uno::Reference< view::XSelectionChangeListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ auto it = std::find(aSelectionChgListeners.begin(), aSelectionChgListeners.end(), xListener); //! why the hassle with queryInterface?
+ if (it != aSelectionChgListeners.end())
+ aSelectionChgListeners.erase(it);
+}
+
+void ScTabViewObj::SelectionChanged()
+{
+ // Selection changed so end any style preview
+ // Note: executing this slot through the dispatcher
+ // will cause the style dialog to be raised so we go
+ // direct here
+ ScFormatShell aShell( GetViewShell()->GetViewData() );
+ SfxAllItemSet reqList( SfxGetpApp()->GetPool() );
+ SfxRequest aReq( SID_STYLE_END_PREVIEW, SfxCallMode::SLOT, reqList );
+ aShell.ExecuteStyle( aReq );
+ lang::EventObject aEvent;
+ aEvent.Source.set(getXWeak());
+ for (const auto& rListener : aSelectionChgListeners)
+ rListener->selectionChanged( aEvent );
+
+ // handle sheet events
+ ScTabViewShell* pViewSh = GetViewShell();
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ const ScSheetEvents* pEvents = rDoc.GetSheetEvents(nTab);
+ if (pEvents)
+ {
+ const OUString* pScript = pEvents->GetScript(ScSheetEventId::SELECT);
+ if (pScript)
+ {
+ // the macro parameter is the selection as returned by getSelection
+ uno::Sequence<uno::Any> aParams{ getSelection() };
+ uno::Any aRet;
+ uno::Sequence<sal_Int16> aOutArgsIndex;
+ uno::Sequence<uno::Any> aOutArgs;
+ /*ErrCode eRet =*/ pDocSh->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
+ }
+ }
+
+ SfxApplication::Get()->Broadcast( SfxHint( SfxHintId::ScSelectionChanged ) );
+
+ if ( mbLeftMousePressed ) // selection still in progress
+ return;
+
+ try
+ {
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( rDoc.GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ uno::Sequence< uno::Any > aArgs{ getSelection() };
+ xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( ScSheetEventId::SELECT ), aArgs );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+// XPropertySet (view options)
+//! provide those also in application?
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTabViewObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScTabViewObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == SC_UNO_FILTERED_RANGE_SELECTION )
+ {
+ bFilteredRangeSelection = ScUnoHelpFunctions::GetBoolFromAny(aValue);
+ return;
+ }
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ ScViewData& rViewData = pViewSh->GetViewData();
+ const ScViewOptions& rOldOpt = pViewSh->GetViewData().GetOptions();
+ ScViewOptions aNewOpt(rOldOpt);
+
+ if ( aPropertyName == SC_UNO_COLROWHDR || aPropertyName == OLD_UNO_COLROWHDR )
+ aNewOpt.SetOption( VOPT_HEADER, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_HORSCROLL || aPropertyName == OLD_UNO_HORSCROLL )
+ aNewOpt.SetOption( VOPT_HSCROLL, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_OUTLSYMB || aPropertyName == OLD_UNO_OUTLSYMB )
+ aNewOpt.SetOption( VOPT_OUTLINER, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHEETTABS || aPropertyName == OLD_UNO_SHEETTABS )
+ aNewOpt.SetOption( VOPT_TABCONTROLS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWANCHOR )
+ aNewOpt.SetOption( VOPT_ANCHOR, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWFORM )
+ aNewOpt.SetOption( VOPT_FORMULAS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWGRID )
+ aNewOpt.SetOption( VOPT_GRID, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWHELP )
+ aNewOpt.SetOption( VOPT_HELPLINES, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWNOTES )
+ aNewOpt.SetOption( VOPT_NOTES, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWFORMULASMARKS )
+ aNewOpt.SetOption( VOPT_FORMULAS_MARKS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWPAGEBR )
+ aNewOpt.SetOption( VOPT_PAGEBREAKS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWZERO )
+ aNewOpt.SetOption( VOPT_NULLVALS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_VALUEHIGH || aPropertyName == OLD_UNO_VALUEHIGH )
+ aNewOpt.SetOption( VOPT_SYNTAX, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_VERTSCROLL || aPropertyName == OLD_UNO_VERTSCROLL )
+ aNewOpt.SetOption( VOPT_VSCROLL, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWOBJ )
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ {
+ //#i80528# adapt to new range eventually
+ if(sal_Int16(VOBJ_MODE_HIDE) < nIntVal) nIntVal = sal_Int16(VOBJ_MODE_SHOW);
+
+ aNewOpt.SetObjMode( VOBJ_TYPE_OLE, static_cast<ScVObjMode>(nIntVal));
+ }
+ }
+ else if ( aPropertyName == SC_UNO_SHOWCHARTS )
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ {
+ //#i80528# adapt to new range eventually
+ if(sal_Int16(VOBJ_MODE_HIDE) < nIntVal) nIntVal = sal_Int16(VOBJ_MODE_SHOW);
+
+ aNewOpt.SetObjMode( VOBJ_TYPE_CHART, static_cast<ScVObjMode>(nIntVal));
+ }
+ }
+ else if ( aPropertyName == SC_UNO_SHOWDRAW )
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ {
+ //#i80528# adapt to new range eventually
+ if(sal_Int16(VOBJ_MODE_HIDE) < nIntVal) nIntVal = sal_Int16(VOBJ_MODE_SHOW);
+
+ aNewOpt.SetObjMode( VOBJ_TYPE_DRAW, static_cast<ScVObjMode>(nIntVal));
+ }
+ }
+ else if ( aPropertyName == SC_UNO_GRIDCOLOR )
+ {
+ Color nIntVal;
+ if ( aValue >>= nIntVal )
+ aNewOpt.SetGridColor( nIntVal, OUString() );
+ }
+ else if ( aPropertyName == SC_UNO_ZOOMTYPE )
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ SetZoomType(nIntVal);
+ }
+ else if ( aPropertyName == SC_UNO_ZOOMVALUE )
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ SetZoom(nIntVal);
+ }
+ else if ( aPropertyName == SC_UNO_FORMULABARHEIGHT )
+ {
+ sal_Int16 nIntVal = ScUnoHelpFunctions::GetInt16FromAny(aValue);
+ if (nIntVal > 0)
+ {
+ rViewData.SetFormulaBarLines(nIntVal);
+ // Notify formula bar about changed lines
+ ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
+ if (pInputHdl)
+ {
+ ScInputWindow* pInputWin = pInputHdl->GetInputWindow();
+ if (pInputWin)
+ pInputWin->NumLinesChanged();
+ }
+ }
+ }
+
+ // Options are set on the view and document (for new views),
+ // so that they remain during saving.
+ //! In the app (module) we need an extra options to tune that
+ //! (for new documents)
+
+ if ( aNewOpt == rOldOpt )
+ return;
+
+ rViewData.SetOptions( aNewOpt );
+ rViewData.GetDocument().SetViewOptions( aNewOpt );
+ rViewData.GetDocShell()->SetDocumentModified(); //! really?
+
+ pViewSh->UpdateFixPos();
+ pViewSh->PaintGrid();
+ pViewSh->PaintTop();
+ pViewSh->PaintLeft();
+ pViewSh->PaintExtras();
+ pViewSh->InvalidateBorder();
+
+ SfxBindings& rBindings = pViewSh->GetViewFrame().GetBindings();
+ rBindings.Invalidate( FID_TOGGLEHEADERS ); // -> check in menu
+ rBindings.Invalidate( FID_TOGGLESYNTAX );
+}
+
+uno::Any SAL_CALL ScTabViewObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if ( aPropertyName == SC_UNO_FILTERED_RANGE_SELECTION )
+ {
+ aRet <<= bFilteredRangeSelection;
+ return aRet;
+ }
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ const ScViewOptions& rOpt = rViewData.GetOptions();
+
+ if ( aPropertyName == SC_UNO_COLROWHDR || aPropertyName == OLD_UNO_COLROWHDR )
+ aRet <<= rOpt.GetOption( VOPT_HEADER );
+ else if ( aPropertyName == SC_UNO_HORSCROLL || aPropertyName == OLD_UNO_HORSCROLL )
+ aRet <<= rOpt.GetOption( VOPT_HSCROLL );
+ else if ( aPropertyName == SC_UNO_OUTLSYMB || aPropertyName == OLD_UNO_OUTLSYMB )
+ aRet <<= rOpt.GetOption( VOPT_OUTLINER );
+ else if ( aPropertyName == SC_UNO_SHEETTABS || aPropertyName == OLD_UNO_SHEETTABS )
+ aRet <<= rOpt.GetOption( VOPT_TABCONTROLS );
+ else if ( aPropertyName == SC_UNO_SHOWANCHOR ) aRet <<= rOpt.GetOption( VOPT_ANCHOR );
+ else if ( aPropertyName == SC_UNO_SHOWFORM ) aRet <<= rOpt.GetOption( VOPT_FORMULAS );
+ else if ( aPropertyName == SC_UNO_SHOWGRID ) aRet <<= rOpt.GetOption( VOPT_GRID );
+ else if ( aPropertyName == SC_UNO_SHOWHELP ) aRet <<= rOpt.GetOption( VOPT_HELPLINES );
+ else if ( aPropertyName == SC_UNO_SHOWNOTES ) aRet <<= rOpt.GetOption( VOPT_NOTES );
+ else if ( aPropertyName == SC_UNO_SHOWFORMULASMARKS ) aRet <<= rOpt.GetOption( VOPT_FORMULAS_MARKS );
+ else if ( aPropertyName == SC_UNO_SHOWPAGEBR ) aRet <<= rOpt.GetOption( VOPT_PAGEBREAKS );
+ else if ( aPropertyName == SC_UNO_SHOWZERO ) aRet <<= rOpt.GetOption( VOPT_NULLVALS );
+ else if ( aPropertyName == SC_UNO_VALUEHIGH || aPropertyName == OLD_UNO_VALUEHIGH )
+ aRet <<= rOpt.GetOption( VOPT_SYNTAX );
+ else if ( aPropertyName == SC_UNO_VERTSCROLL || aPropertyName == OLD_UNO_VERTSCROLL )
+ aRet <<= rOpt.GetOption( VOPT_VSCROLL );
+ else if ( aPropertyName == SC_UNO_SHOWOBJ ) aRet <<= static_cast<sal_Int16>( rOpt.GetObjMode( VOBJ_TYPE_OLE ) );
+ else if ( aPropertyName == SC_UNO_SHOWCHARTS ) aRet <<= static_cast<sal_Int16>( rOpt.GetObjMode( VOBJ_TYPE_CHART ) );
+ else if ( aPropertyName == SC_UNO_SHOWDRAW ) aRet <<= static_cast<sal_Int16>( rOpt.GetObjMode( VOBJ_TYPE_DRAW ) );
+ else if ( aPropertyName == SC_UNO_GRIDCOLOR ) aRet <<= rOpt.GetGridColor();
+ else if ( aPropertyName == SC_UNO_VISAREA ) aRet <<= GetVisArea();
+ else if ( aPropertyName == SC_UNO_ZOOMTYPE ) aRet <<= GetZoomType();
+ else if ( aPropertyName == SC_UNO_ZOOMVALUE ) aRet <<= GetZoom();
+ else if ( aPropertyName == SC_UNO_FORMULABARHEIGHT ) aRet <<= rViewData.GetFormulaBarLines();
+ else if ( aPropertyName == SC_UNO_VISAREASCREEN )
+ {
+ vcl::Window* pActiveWin = rViewData.GetActiveWin();
+ if ( pActiveWin )
+ {
+ AbsoluteScreenPixelRectangle aRect = pActiveWin->GetWindowExtentsAbsolute();
+ aRet <<= AWTRectangle( aRect );
+ }
+ }
+ }
+
+ return aRet;
+}
+
+void SAL_CALL ScTabViewObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ aPropertyChgListeners.push_back( xListener );
+}
+
+void SAL_CALL ScTabViewObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ auto it = std::find(aPropertyChgListeners.begin(), aPropertyChgListeners.end(), xListener); //! Why the nonsense with queryInterface?
+ if (it != aPropertyChgListeners.end())
+ aPropertyChgListeners.erase(it);
+}
+
+void SAL_CALL ScTabViewObj::addVetoableChangeListener( const OUString& /* PropertyName */,
+ const uno::Reference<beans::XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+void SAL_CALL ScTabViewObj::removeVetoableChangeListener( const OUString& /* PropertyName */,
+ const uno::Reference<beans::XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+void ScTabViewObj::VisAreaChanged()
+{
+ beans::PropertyChangeEvent aEvent;
+ aEvent.Source.set(getXWeak());
+ for (const auto& rListener : aPropertyChgListeners)
+ rListener->propertyChange( aEvent );
+}
+
+// XRangeSelection
+
+void SAL_CALL ScTabViewObj::startRangeSelection(
+ const uno::Sequence<beans::PropertyValue>& aArguments )
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ OUString aInitVal, aTitle;
+ bool bCloseOnButtonUp = false;
+ bool bSingleCell = false;
+ bool bMultiSelection = false;
+
+ OUString aStrVal;
+ for (const beans::PropertyValue& rProp : aArguments)
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == SC_UNONAME_CLOSEONUP )
+ bCloseOnButtonUp = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_TITLE )
+ {
+ if ( rProp.Value >>= aStrVal )
+ aTitle = aStrVal;
+ }
+ else if (aPropName == SC_UNONAME_INITVAL )
+ {
+ if ( rProp.Value >>= aStrVal )
+ aInitVal = aStrVal;
+ }
+ else if (aPropName == SC_UNONAME_SINGLECELL )
+ bSingleCell = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_MULTISEL )
+ bMultiSelection = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ }
+
+ pViewSh->StartSimpleRefDialog( aTitle, aInitVal, bCloseOnButtonUp, bSingleCell, bMultiSelection );
+}
+
+void SAL_CALL ScTabViewObj::abortRangeSelection()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ pViewSh->StopSimpleRefDialog();
+}
+
+void SAL_CALL ScTabViewObj::addRangeSelectionListener(
+ const uno::Reference<sheet::XRangeSelectionListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRangeSelListeners.push_back( xListener );
+}
+
+void SAL_CALL ScTabViewObj::removeRangeSelectionListener(
+ const uno::Reference<sheet::XRangeSelectionListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+ auto it = std::find(aRangeSelListeners.begin(), aRangeSelListeners.end(), xListener);
+ if (it != aRangeSelListeners.end())
+ aRangeSelListeners.erase(it);
+}
+
+void SAL_CALL ScTabViewObj::addRangeSelectionChangeListener(
+ const uno::Reference<sheet::XRangeSelectionChangeListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRangeChgListeners.push_back( xListener );
+}
+
+void SAL_CALL ScTabViewObj::removeRangeSelectionChangeListener(
+ const uno::Reference<sheet::XRangeSelectionChangeListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+ auto it = std::find(aRangeChgListeners.begin(), aRangeChgListeners.end(), xListener);
+ if (it != aRangeChgListeners.end())
+ aRangeChgListeners.erase(it);
+}
+
+void ScTabViewObj::RangeSelDone( const OUString& rText )
+{
+ sheet::RangeSelectionEvent aEvent;
+ aEvent.Source.set(getXWeak());
+ aEvent.RangeDescriptor = rText;
+
+ // copy on the stack because listener could remove itself
+ auto const listeners(aRangeSelListeners);
+
+ for (const auto& rListener : listeners)
+ rListener->done( aEvent );
+}
+
+void ScTabViewObj::RangeSelAborted( const OUString& rText )
+{
+ sheet::RangeSelectionEvent aEvent;
+ aEvent.Source.set(getXWeak());
+ aEvent.RangeDescriptor = rText;
+
+ // copy on the stack because listener could remove itself
+ auto const listeners(aRangeSelListeners);
+
+ for (const auto& rListener : listeners)
+ rListener->aborted( aEvent );
+}
+
+void ScTabViewObj::RangeSelChanged( const OUString& rText )
+{
+ sheet::RangeSelectionEvent aEvent;
+ aEvent.Source.set(getXWeak());
+ aEvent.RangeDescriptor = rText;
+
+ // copy on the stack because listener could remove itself
+ auto const listener(aRangeChgListeners);
+
+ for (const auto& rListener : listener)
+ rListener->descriptorChanged( aEvent );
+}
+
+// XServiceInfo
+OUString SAL_CALL ScTabViewObj::getImplementationName()
+{
+ return "ScTabViewObj";
+}
+
+sal_Bool SAL_CALL ScTabViewObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScTabViewObj::getSupportedServiceNames()
+{
+ return {SCTABVIEWOBJ_SERVICE, SCVIEWSETTINGS_SERVICE};
+}
+
+// XUnoTunnel
+
+css::uno::Reference< css::datatransfer::XTransferable > SAL_CALL ScTabViewObj::getTransferable()
+{
+ SolarMutexGuard aGuard;
+ ScEditShell* pShell = dynamic_cast<ScEditShell*>( GetViewShell()->GetViewFrame().GetDispatcher()->GetShell(0) );
+ if (pShell)
+ return pShell->GetEditView()->GetTransferable();
+
+ ScDrawTextObjectBar* pTextShell = dynamic_cast<ScDrawTextObjectBar*>( GetViewShell()->GetViewFrame().GetDispatcher()->GetShell(0) );
+ if (pTextShell)
+ {
+ ScViewData& rViewData = GetViewShell()->GetViewData();
+ ScDrawView* pView = rViewData.GetScDrawView();
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+ if (pOutView)
+ return pOutView->GetEditView().GetTransferable();
+ }
+
+ ScDrawShell* pDrawShell = dynamic_cast<ScDrawShell*>( GetViewShell()->GetViewFrame().GetDispatcher()->GetShell(0) );
+ if (pDrawShell)
+ return pDrawShell->GetDrawView()->CopyToTransferable();
+
+ return GetViewShell()->CopyToTransferable();
+}
+
+void SAL_CALL ScTabViewObj::insertTransferable( const css::uno::Reference< css::datatransfer::XTransferable >& xTrans )
+{
+ SolarMutexGuard aGuard;
+ ScEditShell* pShell = dynamic_cast<ScEditShell*>( GetViewShell()->GetViewFrame().GetDispatcher()->GetShell(0) );
+ if (pShell)
+ pShell->GetEditView()->InsertText( xTrans, OUString(), false );
+ else
+ {
+ ScDrawTextObjectBar* pTextShell = dynamic_cast<ScDrawTextObjectBar*>( GetViewShell()->GetViewFrame().GetDispatcher()->GetShell(0) );
+ if (pTextShell)
+ {
+ ScViewData& rViewData = GetViewShell()->GetViewData();
+ ScDrawView* pView = rViewData.GetScDrawView();
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+ if ( pOutView )
+ {
+ pOutView->GetEditView().InsertText( xTrans, OUString(), false );
+ return;
+ }
+ }
+
+ GetViewShell()->PasteFromTransferable( xTrans );
+ }
+}
+
+namespace {
+
+uno::Sequence<sal_Int32> toSequence(const ScMarkData::MarkedTabsType& rSelected)
+{
+ uno::Sequence<sal_Int32> aRet(rSelected.size());
+ auto aRetRange = asNonConstRange(aRet);
+ size_t i = 0;
+ for (const auto& rTab : rSelected)
+ {
+ aRetRange[i] = static_cast<sal_Int32>(rTab);
+ ++i;
+ }
+
+ return aRet;
+}
+
+}
+
+uno::Sequence<sal_Int32> ScTabViewObj::getSelectedSheets()
+{
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return uno::Sequence<sal_Int32>();
+
+ ScViewData& rViewData = pViewSh->GetViewData();
+
+ // #i95280# when printing from the shell, the view is never activated,
+ // so Excel view settings must also be evaluated here.
+ ScExtDocOptions* pExtOpt = rViewData.GetDocument().GetExtDocOptions();
+ if (pExtOpt && pExtOpt->IsChanged())
+ {
+ pViewSh->GetViewData().ReadExtOptions(*pExtOpt); // Excel view settings
+ pViewSh->SetTabNo(pViewSh->GetViewData().GetTabNo(), true);
+ pExtOpt->SetChanged(false);
+ }
+
+ return toSequence(rViewData.GetMarkData().GetSelectedTabs());
+}
+
+ScPreviewObj::ScPreviewObj(ScPreviewShell* pViewSh) :
+ SfxBaseController(pViewSh),
+ mpViewShell(pViewSh)
+{
+ if (mpViewShell)
+ StartListening(*mpViewShell);
+}
+
+ScPreviewObj::~ScPreviewObj()
+{
+ if (mpViewShell)
+ EndListening(*mpViewShell);
+}
+
+uno::Any ScPreviewObj::queryInterface(const uno::Type& rType)
+{
+ uno::Any aReturn = ::cppu::queryInterface(rType,
+ static_cast<sheet::XSelectedSheetsSupplier*>(this));
+ if ( aReturn.hasValue() )
+ return aReturn;
+ return SfxBaseController::queryInterface(rType);
+}
+
+void ScPreviewObj::acquire() noexcept
+{
+ SfxBaseController::acquire();
+}
+
+void ScPreviewObj::release() noexcept
+{
+ SfxBaseController::release();
+}
+
+void ScPreviewObj::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ mpViewShell = nullptr;
+}
+
+uno::Sequence<sal_Int32> ScPreviewObj::getSelectedSheets()
+{
+ ScPreview* p = mpViewShell ? mpViewShell->GetPreview() : nullptr;
+ if (!p)
+ return uno::Sequence<sal_Int32>();
+
+ return toSequence(p->GetSelectedTabs());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/warnpassword.cxx b/sc/source/ui/unoobj/warnpassword.cxx
new file mode 100644
index 0000000000..b8ccbffa2e
--- /dev/null
+++ b/sc/source/ui/unoobj/warnpassword.cxx
@@ -0,0 +1,62 @@
+/* -*- 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 <warnpassword.hxx>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <sfx2/docfile.hxx>
+#include <ucbhelper/simpleinteractionrequest.hxx>
+#include <com/sun/star/task/InteractionClassification.hpp>
+#include <com/sun/star/ucb/InteractiveAppException.hpp>
+#include <svx/svxerr.hxx>
+#include <rtl/ref.hxx>
+
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::XInterface;
+using ::com::sun::star::task::InteractionClassification_QUERY;
+using ::com::sun::star::task::XInteractionHandler;
+using ::com::sun::star::ucb::InteractiveAppException;
+
+bool ScWarnPassword::WarningOnPassword( SfxMedium& rMedium )
+{
+ bool bReturn = true;
+ Reference< XInteractionHandler > xHandler( rMedium.GetInteractionHandler());
+ if( xHandler.is() )
+ {
+ Any aException( InteractiveAppException("",
+ Reference <XInterface> (),
+ InteractionClassification_QUERY,
+ sal_uInt32(ERRCODE_SVX_EXPORT_FILTER_CRYPT)));
+
+ rtl::Reference< ucbhelper::SimpleInteractionRequest > xRequest
+ = new ucbhelper::SimpleInteractionRequest(
+ aException,
+ ContinuationFlags::Approve | ContinuationFlags::Disapprove );
+
+ xHandler->handle( xRequest );
+
+ const ContinuationFlags nResp = xRequest->getResponse();
+
+ if ( nResp == ContinuationFlags::Disapprove )
+ bReturn = false;
+ }
+ return bReturn;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */