tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / unoobj / docuno.cxx
blob19ef534be1e6c1285b65f5eb6802dfef46b7bc90
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_feature_opencl.h>
22 #include <scitems.hxx>
24 #include <comphelper/dispatchcommand.hxx>
25 #include <comphelper/propertysequence.hxx>
26 #include <comphelper/propertyvalue.hxx>
27 #include <comphelper/sequence.hxx>
28 #include <editeng/brushitem.hxx>
29 #include <editeng/editview.hxx>
30 #include <editeng/memberids.h>
31 #include <editeng/outliner.hxx>
32 #include <editeng/lrspitem.hxx>
33 #include <editeng/ulspitem.hxx>
34 #include <editeng/sizeitem.hxx>
35 #include <o3tl/any.hxx>
36 #include <o3tl/safeint.hxx>
37 #include <svx/fmview.hxx>
38 #include <svx/svditer.hxx>
39 #include <svx/svdpage.hxx>
40 #include <svx/svxids.hrc>
42 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
43 #include <officecfg/Office/Common.hxx>
44 #include <officecfg/Office/Calc.hxx>
45 #include <svl/numuno.hxx>
46 #include <svl/hint.hxx>
47 #include <unotools/moduleoptions.hxx>
48 #include <sfx2/bindings.hxx>
49 #include <sfx2/dispatch.hxx>
50 #include <sfx2/viewfrm.hxx>
51 #include <svx/unopage.hxx>
52 #include <vcl/pdfextoutdevdata.hxx>
53 #include <vcl/print.hxx>
54 #include <vcl/svapp.hxx>
55 #include <tools/json_writer.hxx>
56 #include <tools/multisel.hxx>
57 #include <tools/UnitConversion.hxx>
58 #include <toolkit/awt/vclxdevice.hxx>
60 #include <float.h>
62 #include <com/sun/star/beans/PropertyAttribute.hpp>
63 #include <com/sun/star/util/Date.hpp>
64 #include <com/sun/star/util/XTheme.hpp>
65 #include <com/sun/star/sheet/XNamedRanges.hpp>
66 #include <com/sun/star/sheet/XLabelRanges.hpp>
67 #include <com/sun/star/sheet/XSelectedSheetsSupplier.hpp>
68 #include <com/sun/star/sheet/XUnnamedDatabaseRanges.hpp>
69 #include <com/sun/star/i18n/XForbiddenCharacters.hpp>
70 #include <com/sun/star/script/XLibraryContainer.hpp>
71 #include <com/sun/star/lang/XInitialization.hpp>
72 #include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
73 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
74 #include <com/sun/star/script/XInvocation.hpp>
75 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
76 #include <com/sun/star/beans/XFastPropertySet.hpp>
77 #include <comphelper/indexedpropertyvalues.hxx>
78 #include <comphelper/lok.hxx>
79 #include <comphelper/processfactory.hxx>
80 #include <comphelper/profilezone.hxx>
81 #include <comphelper/servicehelper.hxx>
82 #include <comphelper/string.hxx>
83 #include <cppuhelper/queryinterface.hxx>
84 #include <cppuhelper/supportsservice.hxx>
85 #if HAVE_FEATURE_OPENCL
86 #include <opencl/platforminfo.hxx>
87 #endif
88 #include <sfx2/lokhelper.hxx>
89 #include <sfx2/lokcomponenthelpers.hxx>
90 #include <sfx2/LokControlHandler.hxx>
91 #include <docmodel/uno/UnoTheme.hxx>
92 #include <docmodel/theme/Theme.hxx>
94 #include <cellsuno.hxx>
95 #include <columnspanset.hxx>
96 #include <convuno.hxx>
97 #include <datauno.hxx>
98 #include <docfunc.hxx>
99 #include <docoptio.hxx>
100 #include <docsh.hxx>
101 #include <docuno.hxx>
102 #include <drwlayer.hxx>
103 #include <forbiuno.hxx>
104 #include <formulagroup.hxx>
105 #include <gridwin.hxx>
106 #include <hints.hxx>
107 #include <inputhdl.hxx>
108 #include <inputopt.hxx>
109 #include <interpre.hxx>
110 #include <linkuno.hxx>
111 #include <markdata.hxx>
112 #include <miscuno.hxx>
113 #include <nameuno.hxx>
114 #include <notesuno.hxx>
115 #include <optuno.hxx>
116 #include <pfuncache.hxx>
117 #include <postit.hxx>
118 #include <printfun.hxx>
119 #include <rangeutl.hxx>
120 #include <scmod.hxx>
121 #include <scresid.hxx>
122 #include <servuno.hxx>
123 #include <shapeuno.hxx>
124 #include <sheetevents.hxx>
125 #include <styleuno.hxx>
126 #include <tabvwsh.hxx>
127 #include <targuno.hxx>
128 #include <unonames.hxx>
129 #include <ViewSettingsSequenceDefines.hxx>
130 #include <editsh.hxx>
131 #include <drawsh.hxx>
132 #include <drtxtob.hxx>
133 #include <transobj.hxx>
134 #include <chgtrack.hxx>
135 #include <table.hxx>
136 #include <appoptio.hxx>
137 #include <formulaopt.hxx>
138 #include <output.hxx>
139 #include <stlpool.hxx>
141 #include <strings.hrc>
143 using namespace com::sun::star;
145 // #i111553# provides the name of the VBA constant for this document type (e.g. 'ThisExcelDoc' for Calc)
146 constexpr OUString SC_UNO_VBAGLOBNAME = u"VBAGlobalConstantName"_ustr;
148 // no Which-ID here, map only for PropertySetInfo
150 //! rename this, those are no longer only options
151 static std::span<const SfxItemPropertyMapEntry> lcl_GetDocOptPropertyMap()
153 static const SfxItemPropertyMapEntry aDocOptPropertyMap_Impl[] =
155 { SC_UNO_APPLYFMDES, 0, cppu::UnoType<bool>::get(), 0, 0},
156 { SC_UNO_AREALINKS, 0, cppu::UnoType<sheet::XAreaLinks>::get(), 0, 0},
157 { SC_UNO_AUTOCONTFOC, 0, cppu::UnoType<bool>::get(), 0, 0},
158 { SC_UNO_BASICLIBRARIES, 0, cppu::UnoType<script::XLibraryContainer>::get(), beans::PropertyAttribute::READONLY, 0},
159 { SC_UNO_DIALOGLIBRARIES, 0, cppu::UnoType<script::XLibraryContainer>::get(), beans::PropertyAttribute::READONLY, 0},
160 { SC_UNO_VBAGLOBNAME, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0},
161 { SC_UNO_CALCASSHOWN, PROP_UNO_CALCASSHOWN, cppu::UnoType<bool>::get(), 0, 0},
162 { SC_UNONAME_CLOCAL, 0, cppu::UnoType<lang::Locale>::get(), 0, 0},
163 { SC_UNO_CJK_CLOCAL, 0, cppu::UnoType<lang::Locale>::get(), 0, 0},
164 { SC_UNO_CTL_CLOCAL, 0, cppu::UnoType<lang::Locale>::get(), 0, 0},
165 { SC_UNO_COLLABELRNG, 0, cppu::UnoType<sheet::XLabelRanges>::get(), 0, 0},
166 { SC_UNO_DDELINKS, 0, cppu::UnoType<container::XNameAccess>::get(), 0, 0},
167 { SC_UNO_DEFTABSTOP, PROP_UNO_DEFTABSTOP, cppu::UnoType<sal_Int16>::get(), 0, 0},
168 { SC_UNO_EXTERNALDOCLINKS, 0, cppu::UnoType<sheet::XExternalDocLinks>::get(), 0, 0},
169 { SC_UNO_FORBIDDEN, 0, cppu::UnoType<i18n::XForbiddenCharacters>::get(), beans::PropertyAttribute::READONLY, 0},
170 { SC_UNO_HASDRAWPAGES, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
171 { SC_UNO_IGNORECASE, PROP_UNO_IGNORECASE, cppu::UnoType<bool>::get(), 0, 0},
172 { SC_UNO_ITERENABLED, PROP_UNO_ITERENABLED, cppu::UnoType<bool>::get(), 0, 0},
173 { SC_UNO_ITERCOUNT, PROP_UNO_ITERCOUNT, cppu::UnoType<sal_Int32>::get(), 0, 0},
174 { SC_UNO_ITEREPSILON, PROP_UNO_ITEREPSILON, cppu::UnoType<double>::get(), 0, 0},
175 { SC_UNO_LOOKUPLABELS, PROP_UNO_LOOKUPLABELS, cppu::UnoType<bool>::get(), 0, 0},
176 { SC_UNO_MATCHWHOLE, PROP_UNO_MATCHWHOLE, cppu::UnoType<bool>::get(), 0, 0},
177 { SC_UNO_NAMEDRANGES, 0, cppu::UnoType<sheet::XNamedRanges>::get(), 0, 0},
178 { SC_UNO_THEME, 0, cppu::UnoType<util::XTheme>::get(), 0, 0},
179 { SC_UNO_DATABASERNG, 0, cppu::UnoType<sheet::XDatabaseRanges>::get(), 0, 0},
180 { SC_UNO_NULLDATE, PROP_UNO_NULLDATE, cppu::UnoType<util::Date>::get(), 0, 0},
181 { SC_UNO_ROWLABELRNG, 0, cppu::UnoType<sheet::XLabelRanges>::get(), 0, 0},
182 { SC_UNO_SHEETLINKS, 0, cppu::UnoType<container::XNameAccess>::get(), 0, 0},
183 { SC_UNO_SPELLONLINE, 0, cppu::UnoType<bool>::get(), 0, 0},
184 { SC_UNO_STANDARDDEC, PROP_UNO_STANDARDDEC, cppu::UnoType<sal_Int16>::get(), 0, 0},
185 { SC_UNO_REGEXENABLED, PROP_UNO_REGEXENABLED, cppu::UnoType<bool>::get(), 0, 0},
186 { SC_UNO_WILDCARDSENABLED, PROP_UNO_WILDCARDSENABLED, cppu::UnoType<bool>::get(), 0, 0},
187 { SC_UNO_RUNTIMEUID, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0},
188 { SC_UNO_HASVALIDSIGNATURES, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
189 { SC_UNO_ALLOWLINKUPDATE, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
190 { SC_UNO_ISLOADED, 0, cppu::UnoType<bool>::get(), 0, 0},
191 { SC_UNO_ISUNDOENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
192 { SC_UNO_RECORDCHANGES, 0, cppu::UnoType<bool>::get(), 0, 0},
193 { SC_UNO_ISRECORDCHANGESPROTECTED,0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
194 { SC_UNO_ISADJUSTHEIGHTENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
195 { SC_UNO_ISEXECUTELINKENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
196 { SC_UNO_ISCHANGEREADONLYENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
197 { SC_UNO_REFERENCEDEVICE, 0, cppu::UnoType<awt::XDevice>::get(), beans::PropertyAttribute::READONLY, 0},
198 {u"BuildId"_ustr, 0, ::cppu::UnoType<OUString>::get(), 0, 0},
199 { SC_UNO_CODENAME, 0, cppu::UnoType<OUString>::get(), 0, 0},
200 { SC_UNO_INTEROPGRABBAG, 0, cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get(), 0, 0},
202 return aDocOptPropertyMap_Impl;
205 //! StandardDecimals as property and from NumberFormatter ????????
207 static std::span<const SfxItemPropertyMapEntry> lcl_GetColumnsPropertyMap()
209 static const SfxItemPropertyMapEntry aColumnsPropertyMap_Impl[] =
211 { SC_UNONAME_MANPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
212 { SC_UNONAME_NEWPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
213 { SC_UNONAME_CELLVIS, 0, cppu::UnoType<bool>::get(), 0, 0 },
214 { SC_UNONAME_OWIDTH, 0, cppu::UnoType<bool>::get(), 0, 0 },
215 { SC_UNONAME_CELLWID, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
217 return aColumnsPropertyMap_Impl;
220 static std::span<const SfxItemPropertyMapEntry> lcl_GetRowsPropertyMap()
222 static const SfxItemPropertyMapEntry aRowsPropertyMap_Impl[] =
224 { SC_UNONAME_CELLHGT, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
225 { SC_UNONAME_CELLFILT, 0, cppu::UnoType<bool>::get(), 0, 0 },
226 { SC_UNONAME_OHEIGHT, 0, cppu::UnoType<bool>::get(), 0, 0 },
227 { SC_UNONAME_MANPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
228 { SC_UNONAME_NEWPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
229 { SC_UNONAME_CELLVIS, 0, cppu::UnoType<bool>::get(), 0, 0 },
230 { SC_UNONAME_CELLBACK, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
231 { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
232 // not sorted, not used with SfxItemPropertyMapEntry::GetByName
234 return aRowsPropertyMap_Impl;
237 constexpr OUString SCMODELOBJ_SERVICE = u"com.sun.star.sheet.SpreadsheetDocument"_ustr;
238 constexpr OUString SCDOCSETTINGS_SERVICE = u"com.sun.star.sheet.SpreadsheetDocumentSettings"_ustr;
239 constexpr OUString SCDOC_SERVICE = u"com.sun.star.document.OfficeDocument"_ustr;
241 SC_SIMPLE_SERVICE_INFO( ScAnnotationsObj, u"ScAnnotationsObj"_ustr, u"com.sun.star.sheet.CellAnnotations"_ustr )
242 SC_SIMPLE_SERVICE_INFO( ScDrawPagesObj, u"ScDrawPagesObj"_ustr, u"com.sun.star.drawing.DrawPages"_ustr )
243 SC_SIMPLE_SERVICE_INFO( ScScenariosObj, u"ScScenariosObj"_ustr, u"com.sun.star.sheet.Scenarios"_ustr )
244 SC_SIMPLE_SERVICE_INFO( ScSpreadsheetSettingsObj, u"ScSpreadsheetSettingsObj"_ustr, u"com.sun.star.sheet.SpreadsheetDocumentSettings"_ustr )
245 SC_SIMPLE_SERVICE_INFO( ScTableColumnsObj, u"ScTableColumnsObj"_ustr, u"com.sun.star.table.TableColumns"_ustr )
246 SC_SIMPLE_SERVICE_INFO( ScTableRowsObj, u"ScTableRowsObj"_ustr, u"com.sun.star.table.TableRows"_ustr )
247 SC_SIMPLE_SERVICE_INFO( ScTableSheetsObj, u"ScTableSheetsObj"_ustr, u"com.sun.star.sheet.Spreadsheets"_ustr )
249 class ScPrintUIOptions : public vcl::PrinterOptionsHelper
251 public:
252 ScPrintUIOptions();
253 void SetDefaults();
256 ScPrintUIOptions::ScPrintUIOptions()
258 const ScPrintOptions& rPrintOpt = ScModule::get()->GetPrintOptions();
259 sal_Int32 nContent = rPrintOpt.GetAllSheets() ? 0 : 1;
260 bool bSuppress = rPrintOpt.GetSkipEmpty();
262 sal_Int32 nNumProps= 10, nIdx = 0;
264 m_aUIProperties.resize(nNumProps);
266 // load the writer PrinterOptions into the custom tab
267 m_aUIProperties[nIdx].Name = "OptionsUIFile";
268 m_aUIProperties[nIdx++].Value <<= u"modules/scalc/ui/printeroptions.ui"_ustr;
270 // create Section for spreadsheet (results in an extra tab page in dialog)
271 SvtModuleOptions aOpt;
272 OUString aAppGroupname( ScResId( SCSTR_PRINTOPT_PRODNAME ) );
273 aAppGroupname = aAppGroupname.replaceFirst( "%s", aOpt.GetModuleName( SvtModuleOptions::EModule::CALC ) );
274 m_aUIProperties[nIdx++].Value = setGroupControlOpt(u"tabcontrol-page2"_ustr, aAppGroupname, OUString());
276 // show subgroup for pages
277 m_aUIProperties[nIdx++].Value = setSubgroupControlOpt(u"pages"_ustr, ScResId( SCSTR_PRINTOPT_PAGES ), OUString());
279 // create a bool option for empty pages
280 m_aUIProperties[nIdx++].Value = setBoolControlOpt(u"suppressemptypages"_ustr, ScResId( SCSTR_PRINTOPT_SUPPRESSEMPTY ),
281 u".HelpID:vcl:PrintDialog:IsSuppressEmptyPages:CheckBox"_ustr,
282 u"IsSuppressEmptyPages"_ustr,
283 bSuppress);
284 // show Subgroup for print content
285 vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt;
286 aPrintRangeOpt.maGroupHint = "PrintRange";
287 m_aUIProperties[nIdx++].Value = setSubgroupControlOpt(u"printrange"_ustr, ScResId( SCSTR_PRINTOPT_PAGES ),
288 OUString(),
289 aPrintRangeOpt);
291 // create a choice for the content to create
292 uno::Sequence< OUString > aChoices{
293 ScResId( SCSTR_PRINTOPT_ALLSHEETS ),
294 ScResId( SCSTR_PRINTOPT_SELECTEDSHEETS ),
295 ScResId( SCSTR_PRINTOPT_SELECTEDCELLS )};
296 uno::Sequence< OUString > aHelpIds{
297 u".HelpID:vcl:PrintDialog:PrintContent:ListBox"_ustr};
298 m_aUIProperties[nIdx++].Value = setChoiceListControlOpt( u"printextrabox"_ustr, OUString(),
299 aHelpIds, u"PrintContent"_ustr,
300 aChoices, nContent );
302 // show Subgroup for print range
303 aPrintRangeOpt.mbInternalOnly = true;
304 m_aUIProperties[nIdx++].Value = setSubgroupControlOpt(u"fromwhich"_ustr, ScResId( SCSTR_PRINTOPT_FROMWHICH ),
305 OUString(),
306 aPrintRangeOpt);
308 // create a choice for the range to print
309 OUString aPrintRangeName( u"PrintRange"_ustr );
310 aChoices = { ScResId( SCSTR_PRINTOPT_PRINTALLPAGES ), ScResId( SCSTR_PRINTOPT_PRINTPAGES ) };
311 aHelpIds = { u".HelpID:vcl:PrintDialog:PrintRange:RadioButton:0"_ustr,
312 u".HelpID:vcl:PrintDialog:PrintRange:RadioButton:1"_ustr };
313 uno::Sequence< OUString > aWidgetIds{ u"rbAllPages"_ustr, u"rbRangePages"_ustr };
314 m_aUIProperties[nIdx++].Value = setChoiceRadiosControlOpt(aWidgetIds, OUString(),
315 aHelpIds,
316 aPrintRangeName,
317 aChoices,
318 0 );
320 // create an Edit dependent on "Pages" selected
321 vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt( aPrintRangeName, 1, true );
322 m_aUIProperties[nIdx++].Value = setEditControlOpt(u"pagerange"_ustr, OUString(),
323 u".HelpID:vcl:PrintDialog:PageRange:Edit"_ustr,
324 u"PageRange"_ustr, OUString(), aPageRangeOpt);
326 vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintRangeName, 0, true);
327 m_aUIProperties[ nIdx++ ].Value = setChoiceListControlOpt(u"evenoddbox"_ustr,
328 OUString(),
329 uno::Sequence<OUString>(),
330 u"EvenOdd"_ustr,
331 uno::Sequence<OUString>(),
333 uno::Sequence< sal_Bool >(),
334 aEvenOddOpt);
336 assert(nIdx == nNumProps);
339 void ScPrintUIOptions::SetDefaults()
341 // re-initialize the default values from print options
343 const ScPrintOptions& rPrintOpt = ScModule::get()->GetPrintOptions();
344 sal_Int32 nContent = rPrintOpt.GetAllSheets() ? 0 : 1;
345 bool bSuppress = rPrintOpt.GetSkipEmpty();
347 for (beans::PropertyValue & rPropValue : m_aUIProperties)
349 uno::Sequence<beans::PropertyValue> aUIProp;
350 if ( rPropValue.Value >>= aUIProp )
352 for (auto& rProp : asNonConstRange(aUIProp))
354 OUString aName = rProp.Name;
355 if ( aName == "Property" )
357 beans::PropertyValue aPropertyValue;
358 if ( rProp.Value >>= aPropertyValue )
360 if ( aPropertyValue.Name == "PrintContent" )
362 aPropertyValue.Value <<= nContent;
363 rProp.Value <<= aPropertyValue;
365 else if ( aPropertyValue.Name == "IsSuppressEmptyPages" )
367 aPropertyValue.Value <<= bSuppress;
368 rProp.Value <<= aPropertyValue;
373 rPropValue.Value <<= aUIProp;
378 void ScModelObj::CreateAndSet(ScDocShell* pDocSh)
380 if (pDocSh)
381 pDocSh->SetBaseModel( new ScModelObj(pDocSh) );
384 SdrModel& ScModelObj::getSdrModelFromUnoModel() const
386 ScDocument& rDoc(pDocShell->GetDocument());
388 if(!rDoc.GetDrawLayer())
390 rDoc.InitDrawLayer();
393 return *rDoc.GetDrawLayer(); // TTTT should be reference
396 ScModelObj::ScModelObj( ScDocShell* pDocSh ) :
397 SfxBaseModel( pDocSh ),
398 aPropSet( lcl_GetDocOptPropertyMap() ),
399 pDocShell( pDocSh ),
400 maChangesListeners( m_aMutex )
402 // pDocShell may be NULL if this is the base of a ScDocOptionsObj
403 if ( pDocShell )
405 pDocShell->GetDocument().AddUnoObject(*this); // SfxModel is derived from SfxListener
409 ScModelObj::~ScModelObj()
411 SolarMutexGuard g;
413 if (pDocShell)
414 pDocShell->GetDocument().RemoveUnoObject(*this);
416 if (xNumberAgg.is())
417 xNumberAgg->setDelegator(uno::Reference<uno::XInterface>());
419 pPrintFuncCache.reset();
420 pPrinterOptions.reset();
423 uno::Reference< uno::XAggregation> const & ScModelObj::GetFormatter()
425 // pDocShell may be NULL if this is the base of a ScDocOptionsObj
426 if ( !xNumberAgg.is() && pDocShell )
428 // setDelegator changes RefCount, so we'd better hold the reference ourselves
429 // (directly in m_refCount, so we don't delete ourselves with release())
430 osl_atomic_increment( &m_refCount );
431 // we need a reference to SvNumberFormatsSupplierObj during queryInterface,
432 // otherwise it'll be deleted
433 uno::Reference<util::XNumberFormatsSupplier> xFormatter(
434 new SvNumberFormatsSupplierObj(pDocShell->GetDocument().GetThreadedContext().GetFormatTable() ));
436 xNumberAgg.set(uno::Reference<uno::XAggregation>( xFormatter, uno::UNO_QUERY ));
437 // extra block to force deletion of the temporary before setDelegator
440 // during setDelegator no additional reference should exist
441 xFormatter = nullptr;
443 if (xNumberAgg.is())
444 xNumberAgg->setDelegator( getXWeak() );
445 osl_atomic_decrement( &m_refCount );
446 } // if ( !xNumberAgg.is() )
447 return xNumberAgg;
450 ScDocument* ScModelObj::GetDocument() const
452 if (pDocShell)
453 return &pDocShell->GetDocument();
454 return nullptr;
457 SfxObjectShell* ScModelObj::GetEmbeddedObject() const
459 return pDocShell;
462 void ScModelObj::UpdateAllRowHeights()
464 if (pDocShell)
465 pDocShell->UpdateAllRowHeights();
468 void ScModelObj::BeforeXMLLoading()
470 if (pDocShell)
471 pDocShell->BeforeXMLLoading();
474 void ScModelObj::AfterXMLLoading()
476 if (pDocShell)
477 pDocShell->AfterXMLLoading(true);
480 ScSheetSaveData* ScModelObj::GetSheetSaveData()
482 if (pDocShell)
483 return pDocShell->GetSheetSaveData();
484 return nullptr;
487 ScFormatSaveData* ScModelObj::GetFormatSaveData()
489 if (pDocShell)
490 return pDocShell->GetFormatSaveData();
491 return nullptr;
494 void ScModelObj::RepaintRange( const ScRange& rRange )
496 if (pDocShell)
497 pDocShell->PostPaint( rRange, PaintPartFlags::Grid );
500 void ScModelObj::RepaintRange( const ScRangeList& rRange )
502 if (pDocShell)
503 pDocShell->PostPaint(rRange, PaintPartFlags::Grid, SC_PF_TESTMERGE);
506 static OString getTabViewRenderState(ScTabViewShell& rTabViewShell)
508 OStringBuffer aState;
509 const ScViewRenderingOptions& rViewRenderingOptions = rTabViewShell.GetViewRenderingData();
511 if (rTabViewShell.IsAutoSpell())
512 aState.append('S');
513 if (rViewRenderingOptions.GetDocColor() == svtools::ColorConfig::GetDefaultColor(svtools::DOCCOLOR, 1))
514 aState.append('D');
516 aState.append(';');
518 OString aThemeName = OUStringToOString(rViewRenderingOptions.GetColorSchemeName(), RTL_TEXTENCODING_UTF8);
519 aState.append(aThemeName);
521 return aState.makeStringAndClear();
524 static ScViewData* lcl_getViewMatchingDocZoomTab(const Fraction& rZoomX,
525 const Fraction& rZoomY,
526 const SCTAB nTab,
527 const ViewShellDocId& rDocId,
528 std::string_view rViewRenderState)
530 constexpr size_t nMaxIter = 5;
531 size_t nIter = 0;
532 for (SfxViewShell* pViewShell = SfxViewShell::GetFirst();
533 pViewShell && nIter < nMaxIter;
534 (pViewShell = SfxViewShell::GetNext(*pViewShell)), ++nIter)
536 if (pViewShell->GetDocId() != rDocId)
537 continue;
539 ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
540 if (!pTabViewShell)
541 continue;
543 ScViewData& rData = pTabViewShell->GetViewData();
544 if (rData.GetTabNo() == nTab && rData.GetZoomX() == rZoomX && rData.GetZoomY() == rZoomY &&
545 getTabViewRenderState(*pTabViewShell) == rViewRenderState)
547 return &rData;
551 return nullptr;
554 void ScModelObj::paintTile( VirtualDevice& rDevice,
555 int nOutputWidth, int nOutputHeight,
556 int nTilePosX, int nTilePosY,
557 tools::Long nTileWidth, tools::Long nTileHeight )
559 ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
561 // FIXME: Can this happen? What should we do?
562 if (!pViewShell)
563 return;
565 ScViewData* pActiveViewData = &pViewShell->GetViewData();
566 Fraction aFracX(o3tl::toTwips(nOutputWidth, o3tl::Length::px), nTileWidth);
567 Fraction aFracY(o3tl::toTwips(nOutputHeight, o3tl::Length::px), nTileHeight);
569 // Try to find a view that matches the tile-zoom requested by iterating over
570 // first few shells. This is to avoid switching of zooms in ScGridWindow::PaintTile
571 // and hence avoid grid-offset recomputation on all shapes which is not cheap.
572 ScViewData* pViewData = lcl_getViewMatchingDocZoomTab(aFracX, aFracY,
573 pActiveViewData->GetTabNo(), pViewShell->GetDocId(),
574 getTabViewRenderState(*pViewShell));
575 if (!pViewData)
576 pViewData = pActiveViewData;
578 ScGridWindow* pGridWindow = pViewData->GetActiveWin();
580 // update the size of the area we are painting
581 // FIXME we want to use only the minimal necessary size, like the
582 // following; but for the moment there is too many problems with that and
583 // interaction with editeng used for the cell editing
584 //Size aTileSize(nOutputWidth, nOutputHeight);
585 //if (pGridWindow->GetOutputSizePixel() != aTileSize)
586 // pGridWindow->SetOutputSizePixel(Size(nOutputWidth, nOutputHeight));
587 // so instead for now, set the viewport size to document size
589 // Fetch the document size and the tiled rendering area together,
590 // because the tiled rendering area is not cheap to compute, and we want
591 // to pass it down to ScGridWindow::PaintFile to avoid computing twice.
592 SCCOL nTiledRenderingAreaEndCol = 0;
593 SCROW nTiledRenderingAreaEndRow = 0;
594 Size aDocSize = getDocumentSize(nTiledRenderingAreaEndCol, nTiledRenderingAreaEndRow);
596 pGridWindow->SetOutputSizePixel(Size(aDocSize.Width() * pViewData->GetPPTX(), aDocSize.Height() * pViewData->GetPPTY()));
598 pGridWindow->PaintTile( rDevice, nOutputWidth, nOutputHeight,
599 nTilePosX, nTilePosY, nTileWidth, nTileHeight,
600 nTiledRenderingAreaEndCol, nTiledRenderingAreaEndRow );
602 // Draw Form controls
603 ScDrawLayer* pDrawLayer = pDocShell->GetDocument().GetDrawLayer();
604 SdrPage* pPage = pDrawLayer->GetPage(sal_uInt16(pViewData->GetTabNo()));
605 SdrView* pDrawView = pViewData->GetViewShell()->GetScDrawView();
606 tools::Rectangle aTileRect(Point(nTilePosX, nTilePosY), Size(nTileWidth, nTileHeight));
607 Size aOutputSize(nOutputWidth, nOutputHeight);
608 LokControlHandler::paintControlTile(pPage, pDrawView, *pGridWindow, rDevice, aOutputSize, aTileRect);
611 void ScModelObj::setPart( int nPart, bool /*bAllowChangeFocus*/ )
613 ScViewData* pViewData = ScDocShell::GetViewData();
614 if (!pViewData)
615 return;
617 ScTabView* pTabView = pViewData->GetView();
618 if (!pTabView)
619 return;
621 if (SdrView* pDrawView = pViewData->GetViewShell()->GetScDrawView())
622 pDrawView->SetNegativeX(comphelper::LibreOfficeKit::isActive() &&
623 pViewData->GetDocument().IsLayoutRTL(nPart));
625 pTabView->SelectTabPage(nPart + 1);
628 int ScModelObj::getParts()
630 ScDocument& rDoc = pDocShell->GetDocument();
631 return rDoc.GetTableCount();
634 int ScModelObj::getPart()
636 ScViewData* pViewData = ScDocShell::GetViewData();
637 return pViewData ? pViewData->GetViewShell()->getPart() : 0;
640 OUString ScModelObj::getPartInfo( int nPart )
642 ScViewData* pViewData = ScDocShell::GetViewData();
643 if (!pViewData)
644 return OUString();
646 const bool bIsVisible = pViewData->GetDocument().IsVisible(nPart);
647 const bool bIsProtected = pViewData->GetDocument().IsTabProtected(nPart);
648 //FIXME: Implement IsSelected().
649 const bool bIsSelected = false; //pViewData->GetDocument()->IsSelected(nPart);
650 const bool bIsRTLLayout = pViewData->GetDocument().IsLayoutRTL(nPart);
652 ::tools::JsonWriter jsonWriter;
653 jsonWriter.put("visible", static_cast<unsigned int>(bIsVisible));
654 jsonWriter.put("rtllayout", static_cast<unsigned int>(bIsRTLLayout));
655 jsonWriter.put("protected", static_cast<unsigned int>(bIsProtected));
656 jsonWriter.put("selected", static_cast<unsigned int>(bIsSelected));
658 OUString tabName;
659 pViewData->GetDocument().GetName(nPart, tabName);
660 jsonWriter.put("name", tabName);
662 sal_Int64 hashCode;
663 pViewData->GetDocument().GetHashCode(nPart, hashCode);
664 jsonWriter.put("hash", hashCode);
666 Size lastColRow = getDataArea(nPart);
667 jsonWriter.put("lastcolumn", lastColRow.getWidth());
668 jsonWriter.put("lastrow", lastColRow.getHeight());
670 return OStringToOUString(jsonWriter.finishAndGetAsOString(), RTL_TEXTENCODING_UTF8);
673 OUString ScModelObj::getPartName( int nPart )
675 ScViewData* pViewData = ScDocShell::GetViewData();
676 if (!pViewData)
677 return OUString();
679 OUString sTabName;
680 pViewData->GetDocument().GetName(nPart, sTabName);
681 return sTabName;
684 OUString ScModelObj::getPartHash( int nPart )
686 ScViewData* pViewData = ScDocShell::GetViewData();
687 if (!pViewData)
688 return OUString();
690 sal_Int64 nHashCode;
691 return (pViewData->GetDocument().GetHashCode(nPart, nHashCode) ? OUString::number(nHashCode) : OUString());
694 VclPtr<vcl::Window> ScModelObj::getDocWindow()
696 SolarMutexGuard aGuard;
698 ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
700 // FIXME: Can this happen? What should we do?
701 if (!pViewShell)
702 return VclPtr<vcl::Window>();
704 if (VclPtr<vcl::Window> pWindow = SfxLokHelper::getInPlaceDocWindow(pViewShell))
705 return pWindow;
707 return pViewShell->GetViewData().GetActiveWin();
710 Size ScModelObj::getDocumentSize()
712 SCCOL nTiledRenderingAreaEndCol = 0;
713 SCROW nTiledRenderingAreaEndRow = 0;
714 return getDocumentSize(nTiledRenderingAreaEndCol, nTiledRenderingAreaEndRow);
717 Size ScModelObj::getDocumentSize(SCCOL& rnTiledRenderingAreaEndCol, SCROW& rnTiledRenderingAreaEndRow)
719 Size aSize(10, 10); // minimum size
721 ScViewData* pViewData = ScDocShell::GetViewData();
722 if (!pViewData)
723 return aSize;
725 SCTAB nTab = pViewData->GetTabNo();
726 rnTiledRenderingAreaEndCol = 0;
727 rnTiledRenderingAreaEndRow = 0;
728 const ScDocument& rDoc = pDocShell->GetDocument();
730 rDoc.GetTiledRenderingArea(nTab, rnTiledRenderingAreaEndCol, rnTiledRenderingAreaEndRow);
732 const ScDocument* pThisDoc = &rDoc;
733 const double fPPTX = pViewData->GetPPTX();
734 const double fPPTY = pViewData->GetPPTY();
736 auto GetColWidthPx = [pThisDoc, fPPTX, nTab](SCCOL nCol) {
737 const sal_uInt16 nSize = pThisDoc->GetColWidth(nCol, nTab);
738 return ScViewData::ToPixel(nSize, fPPTX);
741 tools::Long nDocWidthPixel = pViewData->GetLOKWidthHelper().computePosition(rnTiledRenderingAreaEndCol, GetColWidthPx);
742 tools::Long nDocHeightPixel = pThisDoc->GetScaledRowHeight(0, rnTiledRenderingAreaEndRow, nTab, fPPTY);
744 if (nDocWidthPixel > 0 && nDocHeightPixel > 0)
746 // convert to twips
747 aSize.setWidth(nDocWidthPixel / fPPTX);
748 aSize.setHeight(nDocHeightPixel / fPPTY);
750 else
752 // convert to twips
753 aSize.setWidth(rDoc.GetColWidth(0, rnTiledRenderingAreaEndCol, nTab));
754 aSize.setHeight(rDoc.GetRowHeight(0, rnTiledRenderingAreaEndRow, nTab));
757 return aSize;
760 Size ScModelObj::getDataArea(long nPart)
762 Size aSize(1, 1);
764 ScViewData* pViewData = ScDocShell::GetViewData();
765 if (!pViewData || !pDocShell)
766 return aSize;
768 SCTAB nTab = nPart;
769 SCCOL nEndCol = 0;
770 SCROW nEndRow = 0;
771 ScDocument& rDoc = pDocShell->GetDocument();
773 ScTable* pTab = rDoc.FetchTable(nTab);
774 if (!pTab)
775 return aSize;
777 pTab->GetCellArea(nEndCol, nEndRow);
778 aSize = Size(nEndCol, nEndRow);
780 return aSize;
783 void ScModelObj::postKeyEvent(int nType, int nCharCode, int nKeyCode)
785 SolarMutexGuard aGuard;
786 SfxLokHelper::postKeyEventAsync(getDocWindow(), nType, nCharCode, nKeyCode);
789 void ScModelObj::postMouseEvent(int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
791 SolarMutexGuard aGuard;
793 ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
795 // FIXME: Can this happen? What should we do?
796 if (!pViewShell)
797 return;
799 ScViewData* pViewData = &pViewShell->GetViewData();
801 ScGridWindow* pGridWindow = pViewData->GetActiveWin();
803 if (!pGridWindow)
804 return;
806 SCTAB nTab = pViewData->GetTabNo();
807 const ScDocument& rDoc = pDocShell->GetDocument();
808 bool bDrawNegativeX = rDoc.IsNegativePage(nTab);
809 if (SfxLokHelper::testInPlaceComponentMouseEventHit(pViewShell, nType, nX, nY, nCount,
810 nButtons, nModifier, pViewData->GetPPTX(),
811 pViewData->GetPPTY(), bDrawNegativeX))
812 return;
814 Point aPointTwip(nX, nY);
816 // Check if a control is hit
817 Point aPointHMM = o3tl::convert(aPointTwip, o3tl::Length::twip, o3tl::Length::mm100);
818 Point aPointHMMDraw(bDrawNegativeX ? -aPointHMM.X() : aPointHMM.X(), aPointHMM.Y());
819 ScDrawLayer* pDrawLayer = pDocShell->GetDocument().GetDrawLayer();
820 SdrPage* pPage = pDrawLayer->GetPage(sal_uInt16(nTab));
821 SdrView* pDrawView = pViewData->GetViewShell()->GetScDrawView();
822 if (LokControlHandler::postMouseEvent(pPage, pDrawView, *pGridWindow, nType, aPointHMMDraw, nCount, nButtons, nModifier))
823 return;
825 if (!pGridWindow->HasChildPathFocus(true))
826 pGridWindow->GrabFocus();
828 // Calc operates in pixels...
829 const Point aPosition(nX * pViewData->GetPPTX() + pGridWindow->GetOutOffXPixel(),
830 nY * pViewData->GetPPTY() + pGridWindow->GetOutOffYPixel());
832 VclEventId aEvent = VclEventId::NONE;
833 MouseEvent aData(aPosition, nCount, MouseEventModifiers::SIMPLECLICK, nButtons, nModifier);
834 aData.setLogicPosition(aPointHMM);
835 switch (nType)
837 case LOK_MOUSEEVENT_MOUSEBUTTONDOWN:
838 aEvent = VclEventId::WindowMouseButtonDown;
839 break;
840 case LOK_MOUSEEVENT_MOUSEBUTTONUP:
841 aEvent = VclEventId::WindowMouseButtonUp;
842 break;
843 case LOK_MOUSEEVENT_MOUSEMOVE:
844 aEvent = VclEventId::WindowMouseMove;
845 break;
846 default:
847 break;
850 Application::LOKHandleMouseEvent(aEvent, pGridWindow, &aData);
853 void ScModelObj::setTextSelection(int nType, int nX, int nY)
855 SolarMutexGuard aGuard;
857 ScViewData* pViewData = ScDocShell::GetViewData();
858 if (!pViewData)
859 return;
861 ScTabViewShell* pViewShell = pViewData->GetViewShell();
863 LokChartHelper aChartHelper(pViewShell);
864 if (aChartHelper.setTextSelection(nType, nX, nY))
865 return;
867 ScInputHandler* pInputHandler = ScModule::get()->GetInputHdl(pViewShell);
868 ScDrawView* pDrawView = pViewData->GetScDrawView();
870 bool bHandled = false;
872 if (pInputHandler && pInputHandler->IsInputMode())
874 // forwarding to editeng - we are editing the cell content
875 EditView* pTableView = pInputHandler->GetTableView();
876 assert(pTableView);
878 Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
880 if (pTableView && pTableView->GetOutputArea().Contains(aPoint))
882 switch (nType)
884 case LOK_SETTEXTSELECTION_START:
885 pTableView->SetCursorLogicPosition(aPoint, /*bPoint=*/false, /*bClearMark=*/false);
886 break;
887 case LOK_SETTEXTSELECTION_END:
888 pTableView->SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/false);
889 break;
890 case LOK_SETTEXTSELECTION_RESET:
891 pTableView->SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/true);
892 break;
893 default:
894 assert(false);
895 break;
897 bHandled = true;
900 else if (pDrawView && pDrawView->IsTextEdit())
902 // forwarding to editeng - we are editing the text in shape
903 OutlinerView* pOutlinerView = pDrawView->GetTextEditOutlinerView();
904 EditView& rEditView = pOutlinerView->GetEditView();
906 Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
907 switch (nType)
909 case LOK_SETTEXTSELECTION_START:
910 rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/false, /*bClearMark=*/false);
911 break;
912 case LOK_SETTEXTSELECTION_END:
913 rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/false);
914 break;
915 case LOK_SETTEXTSELECTION_RESET:
916 rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/true);
917 break;
918 default:
919 assert(false);
920 break;
922 bHandled = true;
925 if (!bHandled)
927 // just update the cell selection
928 ScGridWindow* pGridWindow = pViewData->GetActiveWin();
929 if (!pGridWindow)
930 return;
932 // move the cell selection handles
933 pGridWindow->SetCellSelectionPixel(nType, nX * pViewData->GetPPTX(), nY * pViewData->GetPPTY());
937 uno::Reference<datatransfer::XTransferable> ScModelObj::getSelection()
939 SolarMutexGuard aGuard;
941 TransferableDataHelper aDataHelper;
942 uno::Reference<datatransfer::XTransferable> xTransferable;
944 if (ScViewData* pViewData = ScDocShell::GetViewData())
946 if ( ScEditShell * pShell = dynamic_cast<ScEditShell*>( pViewData->GetViewShell()->GetViewFrame().GetDispatcher()->GetShell(0) ) )
947 xTransferable = pShell->GetEditView()->GetTransferable();
948 else if ( nullptr != dynamic_cast<ScDrawTextObjectBar*>( pViewData->GetViewShell()->GetViewFrame().GetDispatcher()->GetShell(0) ))
950 ScDrawView* pView = pViewData->GetScDrawView();
951 OutlinerView* pOutView = pView->GetTextEditOutlinerView();
952 if (pOutView)
953 xTransferable = pOutView->GetEditView().GetTransferable();
955 else if ( ScDrawShell * pDrawShell = dynamic_cast<ScDrawShell*>( pViewData->GetViewShell()->GetViewFrame().GetDispatcher()->GetShell(0) ) )
956 xTransferable = pDrawShell->GetDrawView()->CopyToTransferable();
957 else
958 xTransferable = pViewData->GetViewShell()->CopyToTransferable();
961 if (!xTransferable.is())
962 xTransferable.set( aDataHelper.GetTransferable() );
964 return xTransferable;
967 void ScModelObj::setGraphicSelection(int nType, int nX, int nY)
969 SolarMutexGuard aGuard;
971 ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
973 // FIXME: Can this happen? What should we do?
974 if (!pViewShell)
975 return;
977 ScViewData* pViewData = &pViewShell->GetViewData();
979 ScGridWindow* pGridWindow = pViewData->GetActiveWin();
981 double fPPTX = pViewData->GetPPTX();
982 double fPPTY = pViewData->GetPPTY();
984 pViewShell = pViewData->GetViewShell();
985 LokChartHelper aChartHelper(pViewShell);
986 if (aChartHelper.setGraphicSelection(nType, nX, nY, fPPTX, fPPTY))
987 return;
989 int nPixelX = nX * fPPTX;
990 int nPixelY = nY * fPPTY;
992 switch (nType)
994 case LOK_SETGRAPHICSELECTION_START:
996 MouseEvent aClickEvent(Point(nPixelX, nPixelY), 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
997 pGridWindow->MouseButtonDown(aClickEvent);
998 MouseEvent aMoveEvent(Point(nPixelX, nPixelY), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
999 pGridWindow->MouseMove(aMoveEvent);
1001 break;
1002 case LOK_SETGRAPHICSELECTION_END:
1004 MouseEvent aMoveEvent(Point(nPixelX, nPixelY), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
1005 pGridWindow->MouseMove(aMoveEvent);
1006 MouseEvent aClickEvent(Point(nPixelX, nPixelY), 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1007 pGridWindow->MouseButtonUp(aClickEvent);
1009 break;
1010 default:
1011 assert(false);
1012 break;
1016 void ScModelObj::resetSelection()
1018 SolarMutexGuard aGuard;
1020 ScViewData* pViewData = ScDocShell::GetViewData();
1021 if (!pViewData)
1022 return;
1024 ScTabViewShell* pViewShell = pViewData->GetViewShell();
1026 // deselect the shapes & texts
1027 ScDrawView* pDrawView = pViewShell->GetScDrawView();
1028 if (pDrawView)
1030 pDrawView->ScEndTextEdit();
1031 pDrawView->UnmarkAll();
1033 else
1034 pViewShell->Unmark();
1036 // and hide the cell and text selection
1037 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, ""_ostr);
1038 SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", ""_ostr);
1041 void ScModelObj::setClipboard(const uno::Reference<datatransfer::clipboard::XClipboard>& xClipboard)
1043 SolarMutexGuard aGuard;
1045 ScViewData* pViewData = ScDocShell::GetViewData();
1046 if (!pViewData)
1047 return;
1049 pViewData->GetActiveWin()->SetClipboard(xClipboard);
1052 bool ScModelObj::isMimeTypeSupported()
1054 SolarMutexGuard aGuard;
1056 ScViewData* pViewData = ScDocShell::GetViewData();
1057 if (!pViewData)
1058 return false;
1061 TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromSystemClipboard(pViewData->GetActiveWin()));
1062 return EditEngine::HasValidData(aDataHelper.GetTransferable());
1065 static void lcl_sendLOKDocumentBackground(const ScViewData* pViewData)
1067 ScDocShell* pDocSh = pViewData->GetDocShell();
1068 ScDocument& rDoc = pDocSh->GetDocument();
1069 const SfxPoolItem& rItem(rDoc.getCellAttributeHelper().getDefaultCellAttribute().GetItem(ATTR_BACKGROUND));
1070 const SvxBrushItem& rBackground = static_cast<const SvxBrushItem&>(rItem);
1071 const Color& rColor = rBackground.GetColor();
1073 ScTabViewShell* pViewShell = pViewData->GetViewShell();
1074 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_DOCUMENT_BACKGROUND_COLOR, rColor.AsRGBHexString().toUtf8());
1077 void ScModelObj::setClientZoom(int nTilePixelWidth_, int nTilePixelHeight_, int nTileTwipWidth_, int nTileTwipHeight_)
1079 ScViewData* pViewData = ScDocShell::GetViewData();
1080 if (!pViewData)
1081 return;
1083 // Currently in LOK clients the doc background cannot be changed, so send this sparingly as possible but for every view.
1084 // FIXME: Find a better place to trigger this callback where it would be called just once per view creation.
1085 // Doing this in ScTabViewShell init code does not work because callbacks do not work at that point for the first view.
1086 lcl_sendLOKDocumentBackground(pViewData);
1088 const Fraction newZoomX(o3tl::toTwips(nTilePixelWidth_, o3tl::Length::px), nTileTwipWidth_);
1089 const Fraction newZoomY(o3tl::toTwips(nTilePixelHeight_, o3tl::Length::px), nTileTwipHeight_);
1091 double fDeltaPPTX = std::abs(ScGlobal::nScreenPPTX * static_cast<double>(newZoomX) - pViewData->GetPPTX());
1092 double fDeltaPPTY = std::abs(ScGlobal::nScreenPPTY * static_cast<double>(newZoomY) - pViewData->GetPPTY());
1093 constexpr double fEps = 1E-08;
1095 if (pViewData->GetZoomX() == newZoomX && pViewData->GetZoomY() == newZoomY && fDeltaPPTX < fEps && fDeltaPPTY < fEps)
1096 return;
1098 pViewData->SetZoom(newZoomX, newZoomY, true);
1099 if (ScTabViewShell* pViewShell = pViewData->GetViewShell())
1100 pViewShell->SyncGridWindowMapModeFromDrawMapMode();
1101 // sync zoom to Input Handler like ScTabViewShell::Activate does
1102 if (ScInputHandler* pHdl = ScModule::get()->GetInputHdl())
1103 pHdl->SetRefScale(pViewData->GetZoomX(), pViewData->GetZoomY());
1105 // refresh our view's take on other view's cursors & selections
1106 pViewData->GetActiveWin()->updateKitOtherCursors();
1107 pViewData->GetActiveWin()->updateOtherKitSelections();
1109 if (ScDrawView* pDrawView = pViewData->GetScDrawView())
1110 pDrawView->resetGridOffsetsForAllSdrPageViews();
1113 void ScModelObj::getRowColumnHeaders(const tools::Rectangle& rRectangle, tools::JsonWriter& rJsonWriter)
1115 ScViewData* pViewData = ScDocShell::GetViewData();
1116 if (!pViewData)
1117 return;
1119 ScTabView* pTabView = pViewData->GetView();
1120 if (!pTabView)
1121 return;
1123 pTabView->getRowColumnHeaders(rRectangle, rJsonWriter);
1126 OString ScModelObj::getSheetGeometryData(bool bColumns, bool bRows, bool bSizes, bool bHidden,
1127 bool bFiltered, bool bGroups)
1129 ScViewData* pViewData = ScDocShell::GetViewData();
1130 if (!pViewData)
1131 return ""_ostr;
1133 ScTabView* pTabView = pViewData->GetView();
1134 if (!pTabView)
1135 return ""_ostr;
1137 return pTabView->getSheetGeometryData(bColumns, bRows, bSizes, bHidden, bFiltered, bGroups);
1140 void ScModelObj::getCellCursor(tools::JsonWriter& rJsonWriter)
1142 SolarMutexGuard aGuard;
1144 ScViewData* pViewData = ScDocShell::GetViewData();
1145 if (!pViewData)
1146 return;
1148 ScGridWindow* pGridWindow = pViewData->GetActiveWin();
1149 if (!pGridWindow)
1150 return;
1152 rJsonWriter.put("commandName", ".uno:CellCursor");
1153 rJsonWriter.put("commandValues", pGridWindow->getCellCursor());
1156 PointerStyle ScModelObj::getPointer()
1158 SolarMutexGuard aGuard;
1160 ScViewData* pViewData = ScDocShell::GetViewData();
1161 if (!pViewData)
1162 return PointerStyle::Arrow;
1164 ScGridWindow* pGridWindow = pViewData->GetActiveWin();
1165 if (!pGridWindow)
1166 return PointerStyle::Arrow;
1168 return pGridWindow->GetPointer();
1171 void ScModelObj::getTrackedChanges(tools::JsonWriter& rJson)
1173 if (pDocShell)
1175 if (ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack())
1176 pChangeTrack->GetChangeTrackInfo(rJson);
1180 void ScModelObj::setClientVisibleArea(const tools::Rectangle& rRectangle)
1182 ScViewData* pViewData = ScDocShell::GetViewData();
1183 if (!pViewData)
1184 return;
1186 // set the PgUp/PgDown offset
1187 pViewData->ForcePageUpDownOffset(rRectangle.GetHeight());
1189 // Store the visible area so that we can use at places like shape insertion
1190 pViewData->setLOKVisibleArea(rRectangle);
1192 if (comphelper::LibreOfficeKit::isCompatFlagSet(
1193 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
1195 ScTabView* pTabView = pViewData->GetView();
1196 if (pTabView)
1197 pTabView->extendTiledAreaIfNeeded();
1201 void ScModelObj::setOutlineState(bool bColumn, int nLevel, int nIndex, bool bHidden)
1203 ScViewData* pViewData = ScDocShell::GetViewData();
1204 if (!pViewData)
1205 return;
1207 ScDBFunc* pFunc = pViewData->GetView();
1209 if (pFunc)
1210 pFunc->SetOutlineState(bColumn, nLevel, nIndex, bHidden);
1213 void ScModelObj::getPostIts(tools::JsonWriter& rJsonWriter)
1215 if (!pDocShell)
1216 return;
1218 ScDocument& rDoc = pDocShell->GetDocument();
1219 std::vector<sc::NoteEntry> aNotes;
1220 rDoc.GetAllNoteEntries(aNotes);
1222 auto commentsNode = rJsonWriter.startArray("comments");
1223 for (const sc::NoteEntry& aNote : aNotes)
1225 auto commentNode = rJsonWriter.startStruct();
1227 rJsonWriter.put("id", aNote.mpNote->GetId());
1228 rJsonWriter.put("tab", aNote.maPos.Tab());
1229 rJsonWriter.put("author", aNote.mpNote->GetAuthor());
1230 rJsonWriter.put("dateTime", aNote.mpNote->GetDate());
1231 rJsonWriter.put("text", aNote.mpNote->GetText());
1233 // Calculating the cell cursor position
1234 if (ScViewData* pViewData = ScDocShell::GetViewData())
1236 ScGridWindow* pGridWindow = pViewData->GetActiveWin();
1237 if (pGridWindow)
1239 rJsonWriter.put("cellRange", ScPostIt::NoteRangeToJsonString(rDoc, aNote.maPos));
1245 OString ScPostIt::NoteRangeToJsonString(const ScDocument& rDoc, const ScAddress& rPos)
1247 SCCOL nX(rPos.Col());
1248 SCROW nY(rPos.Row());
1249 OString aStartCellAddress(OString::number(nX) + " " + OString::number(nY));
1250 const ScPatternAttr* pMarkPattern = rDoc.GetPattern(nX, nY, rPos.Tab());
1251 const ScMergeAttr* pMergeItem = nullptr;
1252 if (pMarkPattern && pMarkPattern->GetItemSet().GetItemState(ATTR_MERGE, false, &pMergeItem) == SfxItemState::SET)
1254 SCCOL nCol = pMergeItem->GetColMerge();
1255 if (nCol > 1)
1256 nX += nCol - 1;
1257 SCROW nRow = pMergeItem->GetRowMerge();
1258 if (nRow > 1)
1259 nY += nRow - 1;
1261 OString aEndCellAddress(OString::number(nX) + " " + OString::number(nY));
1262 return aStartCellAddress + " " + aEndCellAddress;
1265 void ScModelObj::getPostItsPos(tools::JsonWriter& rJsonWriter)
1267 if (!pDocShell)
1268 return;
1270 ScDocument& rDoc = pDocShell->GetDocument();
1271 std::vector<sc::NoteEntry> aNotes;
1272 rDoc.GetAllNoteEntries(aNotes);
1274 auto commentsNode = rJsonWriter.startArray("commentsPos");
1275 for (const sc::NoteEntry& aNote : aNotes)
1277 auto commentNode = rJsonWriter.startStruct();
1279 rJsonWriter.put("id", aNote.mpNote->GetId());
1280 rJsonWriter.put("tab", aNote.maPos.Tab());
1282 // Calculating the cell cursor position
1283 if (ScViewData* pViewData = ScDocShell::GetViewData())
1285 ScGridWindow* pGridWindow = pViewData->GetActiveWin();
1286 if (pGridWindow)
1288 rJsonWriter.put("cellRange", ScPostIt::NoteRangeToJsonString(rDoc, aNote.maPos));
1294 void ScModelObj::completeFunction(const OUString& rFunctionName)
1296 if (ScInputHandler* pHdl = ScModule::get()->GetInputHdl())
1298 assert(!rFunctionName.isEmpty());
1299 pHdl->LOKPasteFunctionData(rFunctionName);
1303 OString ScModelObj::getViewRenderState(SfxViewShell* pViewShell)
1305 ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
1306 if (!pTabViewShell)
1308 ScViewData* pViewData = ScDocShell::GetViewData();
1309 pTabViewShell = pViewData ? pViewData->GetViewShell() : nullptr;
1312 if (pTabViewShell)
1313 return getTabViewRenderState(*pTabViewShell);
1315 return OString();
1318 void ScModelObj::initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments)
1320 SolarMutexGuard aGuard;
1322 ScModule* mod = ScModule::get();
1323 // enable word autocompletion
1324 ScAppOptions aAppOptions(mod->GetAppOptions());
1325 aAppOptions.SetAutoComplete(true);
1326 mod->SetAppOptions(aAppOptions);
1328 OUString sThemeName;
1329 OUString sBackgroundThemeName;
1331 for (const beans::PropertyValue& rValue : rArguments)
1333 if (rValue.Name == ".uno:SpellOnline" && rValue.Value.has<bool>())
1335 ScViewData* pViewData = ScDocShell::GetViewData();
1336 if (ScTabViewShell* pTabViewShell = pViewData ? pViewData->GetViewShell() : nullptr)
1337 pTabViewShell->EnableAutoSpell(rValue.Value.get<bool>());
1339 else if (rValue.Name == ".uno:ChangeTheme" && rValue.Value.has<OUString>())
1340 sThemeName = rValue.Value.get<OUString>();
1341 else if (rValue.Name == ".uno:InvertBackground" && rValue.Value.has<OUString>())
1342 sBackgroundThemeName = rValue.Value.get<OUString>();
1345 // show us the text exactly
1346 ScInputOptions aInputOptions(mod->GetInputOptions());
1347 aInputOptions.SetTextWysiwyg(true);
1348 aInputOptions.SetReplaceCellsWarn(false);
1349 mod->SetInputOptions(aInputOptions);
1350 if (pDocShell)
1351 pDocShell->CalcOutputFactor();
1353 // when the "This document may contain formatting or content that cannot
1354 // be saved..." dialog appears, it is auto-cancelled with tiled rendering,
1355 // causing 'Save' being disabled; so let's always save to the original
1356 // format
1357 auto xChanges = comphelper::ConfigurationChanges::create();
1358 officecfg::Office::Common::Save::Document::WarnAlienFormat::set(false, xChanges);
1359 xChanges->commit();
1361 // if we know what theme the user wants, then we can dispatch that now early
1362 if (!sThemeName.isEmpty())
1364 css::uno::Sequence<css::beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
1366 { "NewTheme", uno::Any(sThemeName) }
1367 }));
1368 comphelper::dispatchCommand(u".uno:ChangeTheme"_ustr, aPropertyValues);
1370 if (!sBackgroundThemeName.isEmpty())
1372 css::uno::Sequence<css::beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
1374 { "NewTheme", uno::Any(sBackgroundThemeName) }
1375 }));
1376 comphelper::dispatchCommand(".uno:InvertBackground", aPropertyValues);
1380 uno::Any SAL_CALL ScModelObj::queryInterface( const uno::Type& rType )
1382 uno::Any aReturn = ::cppu::queryInterface(rType,
1383 static_cast< sheet::XSpreadsheetDocument *>(this),
1384 static_cast< document::XActionLockable *>(this),
1385 static_cast< sheet::XCalculatable *>(this),
1386 static_cast< util::XProtectable *>(this),
1387 static_cast< drawing::XDrawPagesSupplier *>(this),
1388 static_cast< sheet::XGoalSeek *>(this),
1389 static_cast< sheet::XConsolidatable *>(this),
1390 static_cast< sheet::XDocumentAuditing *>(this),
1391 static_cast< style::XStyleFamiliesSupplier *>(this),
1392 static_cast< view::XRenderable *>(this),
1393 static_cast< document::XLinkTargetSupplier *>(this),
1394 static_cast< beans::XPropertySet *>(this),
1395 static_cast< lang::XMultiServiceFactory *>(this),
1396 static_cast< lang::XServiceInfo *>(this),
1397 static_cast< util::XChangesNotifier *>(this),
1398 static_cast< sheet::opencl::XOpenCLSelection *>(this),
1399 static_cast< chart2::XDataProviderAccess *>(this));
1400 if ( aReturn.hasValue() )
1401 return aReturn;
1403 uno::Any aRet(SfxBaseModel::queryInterface( rType ));
1404 if ( !aRet.hasValue()
1405 && rType != cppu::UnoType<css::document::XDocumentEventBroadcaster>::get()
1406 && rType != cppu::UnoType<css::frame::XController>::get()
1407 && rType != cppu::UnoType<css::frame::XFrame>::get()
1408 && rType != cppu::UnoType<css::script::XInvocation>::get()
1409 && rType != cppu::UnoType<css::beans::XFastPropertySet>::get()
1410 && rType != cppu::UnoType<css::awt::XWindow>::get())
1412 GetFormatter();
1413 if ( xNumberAgg.is() )
1414 aRet = xNumberAgg->queryAggregation( rType );
1417 return aRet;
1420 void SAL_CALL ScModelObj::acquire() noexcept
1422 SfxBaseModel::acquire();
1425 void SAL_CALL ScModelObj::release() noexcept
1427 SfxBaseModel::release();
1430 uno::Sequence<uno::Type> SAL_CALL ScModelObj::getTypes()
1432 static const uno::Sequence<uno::Type> aTypes = [&]()
1434 uno::Sequence<uno::Type> aAggTypes;
1435 if ( GetFormatter().is() )
1437 const uno::Type& rProvType = cppu::UnoType<lang::XTypeProvider>::get();
1438 uno::Any aNumProv(xNumberAgg->queryAggregation(rProvType));
1439 if(auto xNumProv
1440 = o3tl::tryAccess<uno::Reference<lang::XTypeProvider>>(aNumProv))
1442 aAggTypes = (*xNumProv)->getTypes();
1445 return comphelper::concatSequences(
1446 SfxBaseModel::getTypes(),
1447 aAggTypes,
1448 uno::Sequence<uno::Type>
1450 cppu::UnoType<sheet::XSpreadsheetDocument>::get(),
1451 cppu::UnoType<document::XActionLockable>::get(),
1452 cppu::UnoType<sheet::XCalculatable>::get(),
1453 cppu::UnoType<util::XProtectable>::get(),
1454 cppu::UnoType<drawing::XDrawPagesSupplier>::get(),
1455 cppu::UnoType<sheet::XGoalSeek>::get(),
1456 cppu::UnoType<sheet::XConsolidatable>::get(),
1457 cppu::UnoType<sheet::XDocumentAuditing>::get(),
1458 cppu::UnoType<style::XStyleFamiliesSupplier>::get(),
1459 cppu::UnoType<view::XRenderable>::get(),
1460 cppu::UnoType<document::XLinkTargetSupplier>::get(),
1461 cppu::UnoType<beans::XPropertySet>::get(),
1462 cppu::UnoType<lang::XMultiServiceFactory>::get(),
1463 cppu::UnoType<lang::XServiceInfo>::get(),
1464 cppu::UnoType<util::XChangesNotifier>::get(),
1465 cppu::UnoType<sheet::opencl::XOpenCLSelection>::get(),
1466 } );
1467 }();
1468 return aTypes;
1471 uno::Sequence<sal_Int8> SAL_CALL ScModelObj::getImplementationId()
1473 return css::uno::Sequence<sal_Int8>();
1476 void ScModelObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1478 // Not interested in reference update hints here
1480 const SfxHintId nId = rHint.GetId();
1481 if ( nId == SfxHintId::Dying )
1483 pDocShell = nullptr; // has become invalid
1484 if (xNumberAgg.is())
1486 SvNumberFormatsSupplierObj* pNumFmt =
1487 comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(
1488 uno::Reference<util::XNumberFormatsSupplier>(xNumberAgg, uno::UNO_QUERY) );
1489 if ( pNumFmt )
1490 pNumFmt->SetNumberFormatter( nullptr );
1493 pPrintFuncCache.reset(); // must be deleted because it has a pointer to the DocShell
1494 m_pPrintState.reset();
1496 else if ( nId == SfxHintId::DataChanged )
1498 // cached data for rendering become invalid when contents change
1499 // (if a broadcast is added to SetDrawModified, is has to be tested here, too)
1501 pPrintFuncCache.reset();
1502 m_pPrintState.reset();
1504 // handle "OnCalculate" sheet events (search also for VBA event handlers)
1505 if ( pDocShell )
1507 ScDocument& rDoc = pDocShell->GetDocument();
1508 if ( rDoc.GetVbaEventProcessor().is() )
1510 // If the VBA event processor is set, HasAnyCalcNotification is much faster than HasAnySheetEventScript
1511 if ( rDoc.HasAnyCalcNotification() && rDoc.HasAnySheetEventScript( ScSheetEventId::CALCULATE, true ) )
1512 HandleCalculateEvents();
1514 else
1516 if ( rDoc.HasAnySheetEventScript( ScSheetEventId::CALCULATE ) )
1517 HandleCalculateEvents();
1522 // always call parent - SfxBaseModel might need to handle the same hints again
1523 SfxBaseModel::Notify( rBC, rHint ); // SfxBaseModel is derived from SfxListener
1526 // XSpreadsheetDocument
1528 uno::Reference<sheet::XSpreadsheets> SAL_CALL ScModelObj::getSheets()
1530 SolarMutexGuard aGuard;
1531 if (pDocShell)
1532 return new ScTableSheetsObj(pDocShell);
1533 return nullptr;
1536 css::uno::Reference< ::css::chart2::data::XDataProvider > SAL_CALL ScModelObj::createDataProvider()
1538 if (pDocShell)
1540 return css::uno::Reference< ::css::chart2::data::XDataProvider > (
1541 ScServiceProvider::MakeInstance(ScServiceProvider::Type::CHDATAPROV, pDocShell), uno::UNO_QUERY);
1543 return nullptr;
1546 // XStyleFamiliesSupplier
1548 uno::Reference<container::XNameAccess> SAL_CALL ScModelObj::getStyleFamilies()
1550 SolarMutexGuard aGuard;
1551 if (pDocShell)
1552 return new ScStyleFamiliesObj(pDocShell);
1553 return nullptr;
1556 // XRenderable
1558 static OutputDevice* lcl_GetRenderDevice( const uno::Sequence<beans::PropertyValue>& rOptions )
1560 OutputDevice* pRet = nullptr;
1561 for (const beans::PropertyValue& rProp : rOptions)
1563 const OUString & rPropName = rProp.Name;
1565 if (rPropName == SC_UNONAME_RENDERDEV)
1567 uno::Reference<awt::XDevice> xRenderDevice(rProp.Value, uno::UNO_QUERY);
1568 if ( xRenderDevice.is() )
1570 VCLXDevice* pDevice = dynamic_cast<VCLXDevice*>( xRenderDevice.get() );
1571 if ( pDevice )
1573 pRet = pDevice->GetOutputDevice().get();
1574 pRet->SetDigitLanguage( ScModule::GetOptDigitLanguage() );
1579 return pRet;
1582 static bool lcl_ParseTarget( const OUString& rTarget, ScRange& rTargetRange, tools::Rectangle& rTargetRect,
1583 bool& rIsSheet, ScDocument& rDoc, SCTAB nSourceTab )
1585 // test in same order as in SID_CURRENTCELL execute
1587 ScAddress aAddress;
1588 SCTAB nNameTab;
1589 sal_Int32 nNumeric = 0;
1591 bool bRangeValid = false;
1592 bool bRectValid = false;
1594 if ( rTargetRange.Parse( rTarget, rDoc ) & ScRefFlags::VALID )
1596 bRangeValid = true; // range reference
1598 else if ( aAddress.Parse( rTarget, rDoc ) & ScRefFlags::VALID )
1600 rTargetRange = aAddress;
1601 bRangeValid = true; // cell reference
1603 else if ( ScRangeUtil::MakeRangeFromName( rTarget, rDoc, nSourceTab, rTargetRange ) ||
1604 ScRangeUtil::MakeRangeFromName( rTarget, rDoc, nSourceTab, rTargetRange, RUTL_DBASE ) )
1606 bRangeValid = true; // named range or database range
1608 else if ( comphelper::string::isdigitAsciiString(rTarget) &&
1609 ( nNumeric = rTarget.toInt32() ) > 0 && nNumeric <= rDoc.MaxRow()+1 )
1611 // row number is always mapped to cell A(row) on the same sheet
1612 rTargetRange = ScAddress( 0, static_cast<SCROW>(nNumeric-1), nSourceTab ); // target row number is 1-based
1613 bRangeValid = true; // row number
1615 else if ( rDoc.GetTable( rTarget, nNameTab ) )
1617 rTargetRange = ScAddress(0,0,nNameTab);
1618 bRangeValid = true; // sheet name
1619 rIsSheet = true; // needs special handling (first page of the sheet)
1621 else
1623 // look for named drawing object
1625 ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
1626 if ( pDrawLayer )
1628 SCTAB nTabCount = rDoc.GetTableCount();
1629 for (SCTAB i=0; i<nTabCount && !bRangeValid; i++)
1631 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(i));
1632 OSL_ENSURE(pPage,"Page ?");
1633 if (pPage)
1635 SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
1636 SdrObject* pObject = aIter.Next();
1637 while (pObject && !bRangeValid)
1639 if ( ScDrawLayer::GetVisibleName( pObject ) == rTarget )
1641 rTargetRect = pObject->GetLogicRect(); // 1/100th mm
1642 rTargetRange = rDoc.GetRange( i, rTargetRect ); // underlying cells
1643 bRangeValid = bRectValid = true; // rectangle is valid
1645 pObject = aIter.Next();
1651 if ( bRangeValid && !bRectValid )
1653 // get rectangle for cell range
1654 rTargetRect = rDoc.GetMMRect( rTargetRange.aStart.Col(), rTargetRange.aStart.Row(),
1655 rTargetRange.aEnd.Col(), rTargetRange.aEnd.Row(),
1656 rTargetRange.aStart.Tab() );
1659 return bRangeValid;
1662 static Printer* lcl_GetPrinter(const uno::Sequence<beans::PropertyValue>& rOptions)
1664 Printer* pPrinter = nullptr;
1665 OutputDevice* pDev = lcl_GetRenderDevice(rOptions);
1666 if (pDev && pDev->GetOutDevType() == OUTDEV_PRINTER)
1667 pPrinter = dynamic_cast<Printer*>(pDev);
1668 return pPrinter;
1671 static Size lcl_GetPrintPageSize(Size aSize)
1673 aSize.setWidth(o3tl::convert(aSize.Width(), o3tl::Length::mm100, o3tl::Length::twip));
1674 aSize.setHeight(o3tl::convert(aSize.Height(), o3tl::Length::mm100, o3tl::Length::twip));
1675 return aSize;
1678 bool ScModelObj::FillRenderMarkData( const uno::Any& aSelection,
1679 const uno::Sequence< beans::PropertyValue >& rOptions,
1680 ScMarkData& rMark,
1681 ScPrintSelectionStatus& rStatus, OUString& rPagesStr,
1682 bool& rbRenderToGraphic ) const
1684 OSL_ENSURE( !rMark.IsMarked() && !rMark.IsMultiMarked(), "FillRenderMarkData: MarkData must be empty" );
1685 OSL_ENSURE( pDocShell, "FillRenderMarkData: DocShell must be set" );
1687 bool bDone = false;
1689 uno::Reference<frame::XController> xView;
1691 // defaults when no options are passed: all sheets, include empty pages
1692 bool bSelectedSheetsOnly = false;
1693 bool bSuppressEmptyPages = true;
1695 bool bHasPrintContent = false;
1696 sal_Int32 nPrintContent = 0; // all sheets / selected sheets / selected cells
1697 sal_Int32 nPrintRange = 0; // all pages / pages
1698 sal_Int32 nEOContent = 0; // even pages / odd pages
1699 OUString aPageRange; // "pages" edit value
1701 for( const auto& rOption : rOptions )
1703 if ( rOption.Name == "IsOnlySelectedSheets" )
1705 rOption.Value >>= bSelectedSheetsOnly;
1707 else if ( rOption.Name == "IsSuppressEmptyPages" )
1709 rOption.Value >>= bSuppressEmptyPages;
1711 else if ( rOption.Name == "PageRange" )
1713 rOption.Value >>= aPageRange;
1715 else if ( rOption.Name == "PrintRange" )
1717 rOption.Value >>= nPrintRange;
1719 else if ( rOption.Name == "EvenOdd" )
1721 rOption.Value >>= nEOContent;
1723 else if ( rOption.Name == "PrintContent" )
1725 bHasPrintContent = true;
1726 rOption.Value >>= nPrintContent;
1728 else if ( rOption.Name == "View" )
1730 rOption.Value >>= xView;
1732 else if ( rOption.Name == "RenderToGraphic" )
1734 rOption.Value >>= rbRenderToGraphic;
1738 // "Print Content" selection wins over "Selected Sheets" option
1739 if ( bHasPrintContent )
1740 bSelectedSheetsOnly = ( nPrintContent != 0 );
1742 uno::Reference<uno::XInterface> xInterface(aSelection, uno::UNO_QUERY);
1743 if ( xInterface.is() )
1745 ScCellRangesBase* pSelObj = dynamic_cast<ScCellRangesBase*>( xInterface.get() );
1746 uno::Reference< drawing::XShapes > xShapes( xInterface, uno::UNO_QUERY );
1747 if ( pSelObj && pSelObj->GetDocShell() == pDocShell )
1749 bool bSheet = ( dynamic_cast<ScTableSheetObj*>( pSelObj ) != nullptr );
1750 bool bCursor = pSelObj->IsCursorOnly();
1751 const ScRangeList& rRanges = pSelObj->GetRangeList();
1753 rMark.MarkFromRangeList( rRanges, false );
1754 rMark.MarkToSimple();
1756 if ( rMark.IsMultiMarked() )
1758 // #i115266# copy behavior of old printing:
1759 // treat multiple selection like a single selection with the enclosing range
1760 const ScRange& aMultiMarkArea = rMark.GetMultiMarkArea();
1761 rMark.ResetMark();
1762 rMark.SetMarkArea( aMultiMarkArea );
1765 if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
1767 // a sheet object is treated like an empty selection: print the used area of the sheet
1769 if ( bCursor || bSheet ) // nothing selected -> use whole tables
1771 rMark.ResetMark(); // doesn't change table selection
1772 rStatus.SetMode( ScPrintSelectionMode::Cursor );
1774 else
1775 rStatus.SetMode( ScPrintSelectionMode::Range );
1777 rStatus.SetRanges( rRanges );
1778 bDone = true;
1780 // multi selection isn't supported
1782 else if( xShapes.is() )
1784 //print a selected ole object
1785 // multi selection isn't supported yet
1786 uno::Reference< drawing::XShape > xShape( xShapes->getByIndex(0), uno::UNO_QUERY );
1787 SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape );
1788 if( pSdrObj && pDocShell )
1790 ScDocument& rDoc = pDocShell->GetDocument();
1791 tools::Rectangle aObjRect = pSdrObj->GetCurrentBoundRect();
1792 SCTAB nCurrentTab = ScDocShell::GetCurTab();
1793 ScRange aRange = rDoc.GetRange( nCurrentTab, aObjRect );
1794 rMark.SetMarkArea( aRange );
1796 if( rMark.IsMarked() && !rMark.IsMultiMarked() )
1798 rStatus.SetMode( ScPrintSelectionMode::RangeExclusivelyOleAndDrawObjects );
1799 bDone = true;
1803 else if ( comphelper::getFromUnoTunnel<ScModelObj>( xInterface ) == this )
1805 // render the whole document
1806 // -> no selection, all sheets
1808 SCTAB nTabCount = pDocShell->GetDocument().GetTableCount();
1809 for (SCTAB nTab = 0; nTab < nTabCount; nTab++)
1810 rMark.SelectTable( nTab, true );
1811 rStatus.SetMode( ScPrintSelectionMode::Document );
1812 bDone = true;
1814 // other selection types aren't supported
1817 // restrict to selected sheets if a view is available
1818 uno::Reference<sheet::XSelectedSheetsSupplier> xSelectedSheets(xView, uno::UNO_QUERY);
1819 if (bSelectedSheetsOnly && pDocShell && xSelectedSheets.is())
1821 const uno::Sequence<sal_Int32> aSelected = xSelectedSheets->getSelectedSheets();
1822 ScMarkData::MarkedTabsType aSelectedTabs;
1823 SCTAB nMaxTab = pDocShell->GetDocument().GetTableCount() -1;
1824 for (const auto& rSelected : aSelected)
1826 SCTAB nSelected = static_cast<SCTAB>(rSelected);
1827 if (ValidTab(nSelected, nMaxTab))
1828 aSelectedTabs.insert(nSelected);
1830 rMark.SetSelectedTabs(aSelectedTabs);
1833 ScPrintOptions aNewOptions;
1834 aNewOptions.SetSkipEmpty( bSuppressEmptyPages );
1835 aNewOptions.SetAllSheets( !bSelectedSheetsOnly );
1836 rStatus.SetOptions( aNewOptions );
1838 // "PrintRange" enables (1) or disables (0) the "PageRange" edit
1839 if ( nPrintRange == 1 )
1840 rPagesStr = aPageRange;
1841 else
1842 rPagesStr.clear();
1844 return bDone;
1847 sal_Int32 SAL_CALL ScModelObj::getRendererCount(const uno::Any& aSelection,
1848 const uno::Sequence<beans::PropertyValue>& rOptions)
1850 SolarMutexGuard aGuard;
1851 if (!pDocShell)
1853 throw lang::DisposedException( OUString(),
1854 static_cast< sheet::XSpreadsheetDocument* >(this) );
1857 ScMarkData aMark(GetDocument()->GetSheetLimits());
1858 ScPrintSelectionStatus aStatus;
1859 OUString aPagesStr;
1860 bool bRenderToGraphic = false;
1861 if ( !FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr, bRenderToGraphic ) )
1862 return 0;
1864 Size aPrintPageSize;
1865 bool bPrintAreaReset = false;
1866 bool bPrintPageLandscape = false;
1867 bool bUsePrintDialogSetting = false;
1868 Printer* pPrinter = lcl_GetPrinter(rOptions);
1869 if (pPrinter)
1871 if (pPrinter->IsUsePrintDialogSetting())
1873 bUsePrintDialogSetting = true;
1874 bPrintPageLandscape = (pPrinter->GetOrientation() == Orientation::Landscape);
1875 aPrintPageSize = lcl_GetPrintPageSize(pPrinter->GetPrintPageSize());
1877 else // reset the print area created by the Print Dialog to the page style's print area.
1878 bPrintAreaReset = pPrinter->IsPrintAreaReset();
1881 // The same ScPrintFuncCache object in pPrintFuncCache is used as long as
1882 // the same selection is used (aStatus) and the document isn't changed
1883 // (pPrintFuncCache is cleared in Notify handler)
1885 if (!pPrintFuncCache || !pPrintFuncCache->IsSameSelection(aStatus) || bUsePrintDialogSetting
1886 || bPrintAreaReset)
1888 pPrintFuncCache.reset(new ScPrintFuncCache(pDocShell, aMark, std::move(aStatus), aPrintPageSize,
1889 bPrintPageLandscape, bUsePrintDialogSetting));
1891 sal_Int32 nPages = pPrintFuncCache->GetPageCount();
1893 m_pPrintState.reset();
1894 maValidPages.clear();
1896 sal_Int32 nContent = 0;
1897 sal_Int32 nEOContent = 0;
1898 bool bSinglePageSheets = false;
1899 for ( const auto& rValue : rOptions)
1901 if ( rValue.Name == "PrintRange" )
1903 rValue.Value >>= nContent;
1905 else if ( rValue.Name == "SinglePageSheets" )
1907 rValue.Value >>= bSinglePageSheets;
1909 else if ( rValue.Name == "EvenOdd" )
1911 rValue.Value >>= nEOContent;
1915 if (bSinglePageSheets)
1917 return pDocShell->GetDocument().GetTableCount();
1920 bool bIsPrintEvenPages = (nEOContent != 1 && nContent == 0) || nContent != 0;
1921 bool bIsPrintOddPages = (nEOContent != 2 && nContent == 0) || nContent != 0;
1923 for ( sal_Int32 nPage = 1; nPage <= nPages; nPage++ )
1925 if ( (bIsPrintEvenPages && IsOnEvenPage( nPage )) || (bIsPrintOddPages && !IsOnEvenPage( nPage )) )
1926 maValidPages.push_back( nPage );
1929 sal_Int32 nSelectCount = static_cast<sal_Int32>( maValidPages.size() );
1931 if ( nEOContent == 1 || nEOContent == 2 ) // even pages / odd pages
1932 return nSelectCount;
1934 if ( !aPagesStr.isEmpty() )
1936 StringRangeEnumerator aRangeEnum( aPagesStr, 0, nPages-1 );
1937 nSelectCount = aRangeEnum.size();
1939 return (nSelectCount > 0) ? nSelectCount : 1;
1942 static sal_Int32 lcl_GetRendererNum( sal_Int32 nSelRenderer, std::u16string_view rPagesStr, sal_Int32 nTotalPages )
1944 if ( rPagesStr.empty() )
1945 return nSelRenderer;
1947 StringRangeEnumerator aRangeEnum( rPagesStr, 0, nTotalPages-1 );
1948 StringRangeEnumerator::Iterator aIter = aRangeEnum.begin();
1949 StringRangeEnumerator::Iterator aEnd = aRangeEnum.end();
1950 for ( ; nSelRenderer > 0 && aIter != aEnd; --nSelRenderer )
1951 ++aIter;
1953 return *aIter; // returns -1 if reached the end
1956 static bool lcl_renderSelectionToGraphic( bool bRenderToGraphic, const ScPrintSelectionStatus& rStatus )
1958 return bRenderToGraphic && rStatus.GetMode() == ScPrintSelectionMode::Range;
1961 uno::Sequence<beans::PropertyValue> SAL_CALL ScModelObj::getRenderer( sal_Int32 nSelRenderer,
1962 const uno::Any& aSelection, const uno::Sequence<beans::PropertyValue>& rOptions )
1964 SolarMutexGuard aGuard;
1965 if (!pDocShell)
1967 throw lang::DisposedException( OUString(),
1968 static_cast< sheet::XSpreadsheetDocument* >(this) );
1971 ScMarkData aMark(pDocShell->GetDocument().GetSheetLimits());
1972 ScPrintSelectionStatus aStatus;
1973 OUString aPagesStr;
1974 // #i115266# if FillRenderMarkData fails, keep nTotalPages at 0, but still handle getRenderer(0) below
1975 tools::Long nTotalPages = 0;
1976 bool bRenderToGraphic = false;
1977 bool bSinglePageSheets = false;
1978 if ( FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr, bRenderToGraphic ) )
1980 if ( !pPrintFuncCache || !pPrintFuncCache->IsSameSelection( aStatus ) )
1982 pPrintFuncCache.reset(new ScPrintFuncCache( pDocShell, aMark, aStatus ));
1984 nTotalPages = pPrintFuncCache->GetPageCount();
1987 for ( const auto& rValue : rOptions)
1989 if ( rValue.Name == "SinglePageSheets" )
1991 rValue.Value >>= bSinglePageSheets;
1992 break;
1996 if (bSinglePageSheets)
1997 nTotalPages = pDocShell->GetDocument().GetTableCount();
1999 sal_Int32 nRenderer = lcl_GetRendererNum( nSelRenderer, aPagesStr, nTotalPages );
2001 if ( nRenderer < 0 )
2003 if ( nSelRenderer != 0 )
2004 throw lang::IllegalArgumentException();
2006 // getRenderer(0) is used to query the settings, so it must always return something
2008 awt::Size aPageSize;
2009 if (lcl_renderSelectionToGraphic( bRenderToGraphic, aStatus))
2011 assert( aMark.IsMarked());
2012 const ScRange& aRange = aMark.GetMarkArea();
2013 tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
2014 aRange.aStart.Col(), aRange.aStart.Row(),
2015 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
2016 aPageSize.Width = aMMRect.GetWidth();
2017 aPageSize.Height = aMMRect.GetHeight();
2019 else
2021 SCTAB const nCurTab = 0; //! use current sheet from view?
2022 ScPrintFunc aDefaultFunc( pDocShell, pDocShell->GetPrinter(), nCurTab );
2023 Size aTwips = aDefaultFunc.GetPageSize();
2024 aPageSize.Width = convertTwipToMm100(aTwips.Width());
2025 aPageSize.Height = convertTwipToMm100(aTwips.Height());
2028 uno::Sequence<beans::PropertyValue> aSequence( comphelper::InitPropertySequence({
2029 { SC_UNONAME_PAGESIZE, uno::Any(aPageSize) }
2030 }));
2032 if( ! pPrinterOptions )
2033 pPrinterOptions.reset(new ScPrintUIOptions);
2034 else
2035 pPrinterOptions->SetDefaults();
2036 pPrinterOptions->appendPrintUIOptions( aSequence );
2037 return aSequence;
2041 // printer is used as device (just for page layout), draw view is not needed
2043 SCTAB nTab;
2044 if (bSinglePageSheets)
2045 nTab = nSelRenderer;
2046 else if ( !maValidPages.empty() )
2047 nTab = pPrintFuncCache->GetTabForPage( maValidPages.at( nRenderer )-1 );
2048 else
2049 nTab = pPrintFuncCache->GetTabForPage( nRenderer );
2052 ScRange aRange;
2053 const ScRange* pSelRange = nullptr;
2054 if ( bSinglePageSheets )
2056 SCCOL nStartCol;
2057 SCROW nStartRow;
2058 const ScDocument* pDocument = &pDocShell->GetDocument();
2059 pDocument->GetDataStart( nTab, nStartCol, nStartRow );
2060 SCCOL nEndCol;
2061 SCROW nEndRow;
2062 pDocument->GetPrintArea( nTab, nEndCol, nEndRow );
2064 aRange.aStart = ScAddress(nStartCol, nStartRow, nTab);
2065 aRange.aEnd = ScAddress(nEndCol, nEndRow, nTab);
2067 table::CellRangeAddress aRangeAddress( nTab,
2068 aRange.aStart.Col(), aRange.aStart.Row(),
2069 aRange.aEnd.Col(), aRange.aEnd.Row() );
2070 tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
2071 aRange.aStart.Col(), aRange.aStart.Row(),
2072 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
2074 const awt::Size aPageSize(aMMRect.GetWidth(), aMMRect.GetHeight());
2075 const awt::Point aCalcPagePos(aMMRect.Left(), aMMRect.Top());
2077 uno::Sequence<beans::PropertyValue> aSequence
2079 comphelper::makePropertyValue(SC_UNONAME_PAGESIZE, aPageSize),
2080 // #i111158# all positions are relative to the whole page, including non-printable area
2081 comphelper::makePropertyValue(SC_UNONAME_INC_NP_AREA, true),
2082 comphelper::makePropertyValue(SC_UNONAME_SOURCERANGE, aRangeAddress),
2083 comphelper::makePropertyValue(SC_UNONAME_CALCPAGESIZE, aPageSize), // TODO aPageSize too ?
2084 comphelper::makePropertyValue(SC_UNONAME_CALCPAGEPOS, aCalcPagePos)
2087 if( ! pPrinterOptions )
2088 pPrinterOptions.reset(new ScPrintUIOptions);
2089 else
2090 pPrinterOptions->SetDefaults();
2091 pPrinterOptions->appendPrintUIOptions( aSequence );
2092 return aSequence;
2094 else if ( aMark.IsMarked() )
2096 aRange = aMark.GetMarkArea();
2097 pSelRange = &aRange;
2100 awt::Size aPageSize;
2101 bool bWasCellRange = false;
2102 ScRange aCellRange;
2103 if (lcl_renderSelectionToGraphic( bRenderToGraphic, aStatus))
2105 bWasCellRange = true;
2106 aCellRange = aRange;
2107 tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
2108 aRange.aStart.Col(), aRange.aStart.Row(),
2109 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
2110 aPageSize.Width = aMMRect.GetWidth();
2111 aPageSize.Height = aMMRect.GetHeight();
2113 else
2115 Size aPrintPageSize;
2116 bool bPrintPageLandscape = false;
2117 bool bUsePrintDialogSetting = false;
2118 Printer* pPrinter = lcl_GetPrinter(rOptions);
2119 if (pPrinter)
2121 if (pPrinter->IsUsePrintDialogSetting())
2123 bUsePrintDialogSetting = true;
2124 bPrintPageLandscape = (pPrinter->GetOrientation() == Orientation::Landscape);
2125 aPrintPageSize = lcl_GetPrintPageSize(pPrinter->GetPrintPageSize());
2129 std::unique_ptr<ScPrintFunc, o3tl::default_delete<ScPrintFunc>> pPrintFunc;
2130 if (m_pPrintState && m_pPrintState->nPrintTab == nTab)
2131 pPrintFunc.reset(new ScPrintFunc(pDocShell, pDocShell->GetPrinter(), *m_pPrintState,
2132 &aStatus.GetOptions(), aPrintPageSize,
2133 bPrintPageLandscape,
2134 bUsePrintDialogSetting));
2135 else
2136 pPrintFunc.reset(new ScPrintFunc(pDocShell, pDocShell->GetPrinter(), nTab,
2137 pPrintFuncCache->GetFirstAttr(nTab), nTotalPages,
2138 pSelRange, &aStatus.GetOptions(), nullptr,
2139 aPrintPageSize, bPrintPageLandscape,
2140 bUsePrintDialogSetting));
2141 pPrintFunc->SetRenderFlag( true );
2143 sal_Int32 nContent = 0;
2144 sal_Int32 nEOContent = 0;
2145 for ( const auto& rValue : rOptions)
2147 if ( rValue.Name == "PrintRange" )
2149 rValue.Value >>= nContent;
2151 else if ( rValue.Name == "EvenOdd" )
2153 rValue.Value >>= nEOContent;
2157 MultiSelection aPage;
2158 aPage.SetTotalRange( Range(0,RANGE_MAX) );
2160 bool bOddOrEven = (nContent == 0 && nEOContent == 1) || (nContent == 1 && nEOContent == 2); // even pages or odd pages
2161 // tdf#127682 when odd/even allow nRenderer of 0 even when maValidPages is empty
2162 // to allow PrinterController::abortJob to spool an empty page as part of
2163 // its abort procedure
2164 if (bOddOrEven && !maValidPages.empty())
2165 aPage.Select( maValidPages.at(nRenderer) );
2166 else
2167 aPage.Select( nRenderer+1 );
2169 tools::Long nDisplayStart = pPrintFuncCache->GetDisplayStart( nTab );
2170 tools::Long nTabStart = pPrintFuncCache->GetTabStart( nTab );
2172 (void)pPrintFunc->DoPrint( aPage, nTabStart, nDisplayStart, false, nullptr );
2174 bWasCellRange = pPrintFunc->GetLastSourceRange( aCellRange );
2175 Size aTwips = pPrintFunc->GetPageSize();
2177 if (!m_pPrintState || nRenderer == nTabStart)
2179 m_pPrintState.reset(new ScPrintState());
2180 pPrintFunc->GetPrintState(*m_pPrintState);
2183 aPageSize.Width = convertTwipToMm100(aTwips.Width());
2184 aPageSize.Height = convertTwipToMm100(aTwips.Height());
2187 tools::Long nPropCount = bWasCellRange ? 5 : 4;
2188 uno::Sequence<beans::PropertyValue> aSequence(nPropCount);
2189 beans::PropertyValue* pArray = aSequence.getArray();
2190 pArray[0].Name = SC_UNONAME_PAGESIZE;
2191 pArray[0].Value <<= aPageSize;
2192 // #i111158# all positions are relative to the whole page, including non-printable area
2193 pArray[1].Name = SC_UNONAME_INC_NP_AREA;
2194 pArray[1].Value <<= true;
2195 if ( bWasCellRange )
2197 table::CellRangeAddress aRangeAddress( nTab,
2198 aCellRange.aStart.Col(), aCellRange.aStart.Row(),
2199 aCellRange.aEnd.Col(), aCellRange.aEnd.Row() );
2200 tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
2201 aCellRange.aStart.Col(), aCellRange.aStart.Row(),
2202 aCellRange.aEnd.Col(), aCellRange.aEnd.Row(), aCellRange.aStart.Tab()));
2204 const awt::Size aCalcPageSize(aMMRect.GetWidth(), aMMRect.GetHeight());
2205 const awt::Point aCalcPagePos(aMMRect.Left(), aMMRect.Top());
2207 pArray[2].Name = SC_UNONAME_SOURCERANGE;
2208 pArray[2].Value <<= aRangeAddress;
2209 pArray[3].Name = SC_UNONAME_CALCPAGESIZE;
2210 pArray[3].Value <<= aCalcPageSize;
2211 pArray[4].Name = SC_UNONAME_CALCPAGEPOS;
2212 pArray[4].Value <<= aCalcPagePos;
2215 if( ! pPrinterOptions )
2216 pPrinterOptions.reset(new ScPrintUIOptions);
2217 else
2218 pPrinterOptions->SetDefaults();
2219 pPrinterOptions->appendPrintUIOptions( aSequence );
2220 return aSequence;
2223 static void lcl_PDFExportHelper(const OutputDevice* pDev, const OUString& rTabName, bool bIsFirstPage)
2225 vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData());
2226 if (pPDF)
2228 css::lang::Locale const docLocale(Application::GetSettings().GetLanguageTag().getLocale());
2229 pPDF->SetDocumentLocale(docLocale);
2231 // first page of a sheet: add outline item for the sheet name
2233 if (pPDF->GetIsExportBookmarks())
2235 // the sheet starts at the top of the page
2236 tools::Rectangle aArea(pDev->PixelToLogic(tools::Rectangle(0, 0, 0, 0)));
2237 sal_Int32 nDestID = pPDF->CreateDest(aArea);
2238 // top-level
2239 pPDF->CreateOutlineItem(-1/*nParent*/, rTabName, nDestID);
2241 // #i56629# add the named destination stuff
2242 if (pPDF->GetIsExportNamedDestinations())
2244 tools::Rectangle aArea(pDev->PixelToLogic(tools::Rectangle(0, 0, 0, 0)));
2245 //need the PDF page number here
2246 pPDF->CreateNamedDest(rTabName, aArea);
2249 if (pPDF->GetIsExportTaggedPDF())
2251 if (bIsFirstPage)
2252 pPDF->WrapBeginStructureElement(vcl::PDFWriter::Document, u"Workbook"_ustr);
2253 else
2254 { // if there is a new worksheet(not first), delete and add new ScPDFState
2255 assert(pPDF->GetScPDFState());
2256 delete pPDF->GetScPDFState();
2257 pPDF->SetScPDFState(nullptr);
2260 assert(pPDF->GetScPDFState() == nullptr);
2261 pPDF->SetScPDFState(new ScEnhancedPDFState());
2266 static void lcl_PDFExportBookmarkHelper(OutputDevice* pDev, ScDocument& rDoc,
2267 const std::unique_ptr<ScPrintFuncCache>& pPrintFuncCache,
2268 const ScMarkData& rMark, sal_Int32 nTab)
2270 // resolve the hyperlinks for PDF export
2272 vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData());
2273 if (!pPDF || pPDF->GetBookmarks().empty())
2274 return;
2276 // iterate over the hyperlinks that were output for this page
2278 std::vector<vcl::PDFExtOutDevBookmarkEntry>& rBookmarks = pPDF->GetBookmarks();
2279 for (const auto& rBookmark : rBookmarks)
2281 OUString aBookmark = rBookmark.aBookmark;
2282 if (aBookmark.toChar() == '#')
2284 // try to resolve internal link
2286 OUString aTarget(aBookmark.copy(1));
2288 ScRange aTargetRange;
2289 tools::Rectangle aTargetRect; // 1/100th mm
2290 bool bIsSheet = false;
2291 bool bValid = lcl_ParseTarget(aTarget, aTargetRange, aTargetRect, bIsSheet, rDoc, nTab);
2293 if (bValid)
2295 sal_Int32 nPage = -1;
2296 tools::Rectangle aArea;
2297 if (bIsSheet)
2299 // Get first page for sheet (if nothing from that sheet is printed,
2300 // this page can show a different sheet)
2301 nPage = pPrintFuncCache->GetTabStart(aTargetRange.aStart.Tab());
2302 aArea = pDev->PixelToLogic(tools::Rectangle(0, 0, 0, 0));
2304 else
2306 pPrintFuncCache->InitLocations(rMark, pDev); // does nothing if already initialized
2308 ScPrintPageLocation aLocation;
2309 if (pPrintFuncCache->FindLocation(aTargetRange.aStart, aLocation))
2311 nPage = aLocation.nPage;
2313 // get the rectangle of the page's cell range in 1/100th mm
2314 ScRange aLocRange = aLocation.aCellRange;
2315 tools::Rectangle aLocationMM = rDoc.GetMMRect(
2316 aLocRange.aStart.Col(), aLocRange.aStart.Row(), aLocRange.aEnd.Col(),
2317 aLocRange.aEnd.Row(), aLocRange.aStart.Tab());
2318 tools::Rectangle aLocationPixel = aLocation.aRectangle;
2320 // Scale and move the target rectangle from aLocationMM to aLocationPixel,
2321 // to get the target rectangle in pixels.
2322 assert(aLocationPixel.GetWidth() != 0 && aLocationPixel.GetHeight() != 0);
2324 Fraction aScaleX(aLocationPixel.GetWidth(), aLocationMM.GetWidth());
2325 Fraction aScaleY(aLocationPixel.GetHeight(), aLocationMM.GetHeight());
2327 tools::Long nX1
2328 = aLocationPixel.Left()
2329 + static_cast<tools::Long>(
2330 Fraction(aTargetRect.Left() - aLocationMM.Left(), 1) * aScaleX);
2331 tools::Long nX2
2332 = aLocationPixel.Left()
2333 + static_cast<tools::Long>(
2334 Fraction(aTargetRect.Right() - aLocationMM.Left(), 1) * aScaleX);
2335 tools::Long nY1
2336 = aLocationPixel.Top()
2337 + static_cast<tools::Long>(
2338 Fraction(aTargetRect.Top() - aLocationMM.Top(), 1) * aScaleY);
2339 tools::Long nY2
2340 = aLocationPixel.Top()
2341 + static_cast<tools::Long>(
2342 Fraction(aTargetRect.Bottom() - aLocationMM.Top(), 1) * aScaleY);
2344 if (nX1 > aLocationPixel.Right())
2345 nX1 = aLocationPixel.Right();
2346 if (nX2 > aLocationPixel.Right())
2347 nX2 = aLocationPixel.Right();
2348 if (nY1 > aLocationPixel.Bottom())
2349 nY1 = aLocationPixel.Bottom();
2350 if (nY2 > aLocationPixel.Bottom())
2351 nY2 = aLocationPixel.Bottom();
2353 // The link target area is interpreted using the device's MapMode at
2354 // the time of the CreateDest call, so PixelToLogic can be used here,
2355 // regardless of the MapMode that is actually selected.
2356 aArea = pDev->PixelToLogic(tools::Rectangle(nX1, nY1, nX2, nY2));
2360 if (nPage >= 0)
2361 pPDF->SetLinkDest(rBookmark.nLinkId, pPDF->CreateDest(aArea, nPage));
2364 else
2366 // external link, use as-is
2367 pPDF->SetLinkURL(rBookmark.nLinkId, aBookmark);
2370 rBookmarks.clear();
2373 static void lcl_SetMediaScreen(const uno::Reference<drawing::XShape>& xMediaShape,
2374 const OutputDevice* pDev, tools::Rectangle& aRect,
2375 sal_Int32 nPageNumb)
2377 OUString sMediaURL;
2378 uno::Reference<beans::XPropertySet> xPropSet(xMediaShape, uno::UNO_QUERY);
2379 xPropSet->getPropertyValue(u"MediaURL"_ustr) >>= sMediaURL;
2380 if (sMediaURL.isEmpty())
2381 return;
2382 vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData());
2383 if (!pPDF)
2384 return;
2386 OUString sTitle;
2387 xPropSet->getPropertyValue(u"Title"_ustr) >>= sTitle;
2388 OUString sDescription;
2389 xPropSet->getPropertyValue(u"Description"_ustr) >>= sDescription;
2390 OUString const altText(sTitle.isEmpty() ? sDescription
2391 : sDescription.isEmpty()
2392 ? sTitle
2393 : OUString::Concat(sTitle) + OUString::Concat("\n")
2394 + OUString::Concat(sDescription));
2396 OUString const mimeType(xPropSet->getPropertyValue(u"MediaMimeType"_ustr).get<OUString>());
2397 SdrObject* pSdrObj(SdrObject::getSdrObjectFromXShape(xMediaShape));
2398 sal_Int32 nScreenId = pPDF->CreateScreen(aRect, altText, mimeType, nPageNumb, pSdrObj);
2399 if (sMediaURL.startsWith("vnd.sun.star.Package:"))
2401 // Embedded media
2402 OUString aTempFileURL;
2403 xPropSet->getPropertyValue(u"PrivateTempFileURL"_ustr) >>= aTempFileURL;
2404 pPDF->SetScreenStream(nScreenId, aTempFileURL);
2406 else // Linked media
2407 pPDF->SetScreenURL(nScreenId, sMediaURL);
2410 static void lcl_PDFExportMediaShapeScreen(const OutputDevice* pDev, const std::unique_ptr<ScPrintState>& rState,
2411 ScDocument& rDoc, SCTAB nTab, tools::Long nStartPage,
2412 bool bSinglePageSheets)
2414 ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
2415 vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData());
2416 if (pPDF && pPDF->GetIsExportTaggedPDF() && pDrawLayer)
2419 if (!bSinglePageSheets)
2421 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
2422 OSL_ENSURE(pPage, "Page ?");
2423 if (pPage)
2425 ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
2426 SfxStyleSheetBase* pStyleSheet = pStylePool->Find(rDoc.GetPageStyle(nTab), SfxStyleFamily::Page);
2427 SfxItemSet* pItemSet = &pStyleSheet->GetItemSet();
2429 tools::Long nLeftMargin(pItemSet->Get(ATTR_LRSPACE).ResolveLeft({}));
2430 nLeftMargin = o3tl::convert(nLeftMargin, o3tl::Length::twip, o3tl::Length::mm100);
2432 tools::Long nTopMargin(pItemSet->Get(ATTR_ULSPACE).GetUpper());
2433 nTopMargin = o3tl::convert(nTopMargin, o3tl::Length::twip, o3tl::Length::mm100);
2435 tools::Long nHeader = 0;
2436 const SvxSetItem* pHeaderSetItem = &pItemSet->Get(ATTR_PAGE_HEADERSET);
2437 bool bHasHdr = pHeaderSetItem->GetItemSet().Get(ATTR_PAGE_ON).GetValue();
2438 if (bHasHdr)
2440 const SfxItemSet* pHeaderSet = &pHeaderSetItem->GetItemSet();
2441 tools::Long nHdrHeight = pHeaderSet->Get(ATTR_PAGE_SIZE).GetSize().Height();
2442 nHeader = o3tl::convert(nHdrHeight, o3tl::Length::twip, o3tl::Length::mm100);
2445 bool bTopDown = pItemSet->Get(ATTR_PAGE_TOPDOWN).GetValue();
2447 SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
2448 SdrObject* pObj = aIter.Next();
2449 while (pObj && pObj->IsVisible())
2451 uno::Reference<drawing::XShape> xShape(pObj->getUnoShape(), uno::UNO_QUERY);
2452 if (xShape->getShapeType() == "com.sun.star.drawing.MediaShape")
2454 SCCOL nX1, nX2;
2455 SCROW nY1, nY2;
2456 sal_Int32 nPageNumb = nStartPage;
2457 if (bTopDown) // top-bottom page order
2459 nX1 = 0;
2460 for (size_t i = 0; i < rState->m_aRanges.m_nPagesX; ++i)
2462 nX2 = (*rState->m_aRanges.m_xPageEndX)[i];
2463 for (size_t j = 0; j < rState->m_aRanges.m_nPagesY; ++j)
2465 auto& rPageRow = (*rState->m_aRanges.m_xPageRows)[j];
2466 nY1 = rPageRow.GetStartRow();
2467 nY2 = rPageRow.GetEndRow();
2469 tools::Rectangle aPageRect(rDoc.GetMMRect(nX1, nY1, nX2, nY2, nTab));
2470 tools::Rectangle aTmpRect(aPageRect.GetIntersection(pObj->GetCurrentBoundRect()));
2471 if (!aTmpRect.IsEmpty())
2473 tools::Long nPosX(aTmpRect.getX() - aPageRect.getX() + nLeftMargin);
2474 tools::Long nPosY(aTmpRect.getY() - aPageRect.getY() + nHeader + nTopMargin);
2475 tools::Rectangle aRect(Point(nPosX, nPosY), aTmpRect.GetSize());
2476 lcl_SetMediaScreen(xShape, pDev, aRect, nPageNumb);
2478 ++nPageNumb;
2480 nX1 = nX2 + 1;
2483 else // left to right page order
2485 for (size_t i = 0; i < rState->m_aRanges.m_nPagesY; ++i)
2487 auto& rPageRow = (*rState->m_aRanges.m_xPageRows)[i];
2488 nY1 = rPageRow.GetStartRow();
2489 nY2 = rPageRow.GetEndRow();
2490 nX1 = 0;
2491 for (size_t j = 0; j < rState->m_aRanges.m_nPagesX; ++j)
2493 nX2 = (*rState->m_aRanges.m_xPageEndX)[j];
2495 tools::Rectangle aPageRect(rDoc.GetMMRect(nX1, nY1, nX2, nY2, nTab));
2496 tools::Rectangle aTmpRect(aPageRect.GetIntersection(pObj->GetCurrentBoundRect()));
2497 if (!aTmpRect.IsEmpty())
2499 tools::Long nPosX(aTmpRect.getX() - aPageRect.getX() + nLeftMargin);
2500 tools::Long nPosY(aTmpRect.getY() - aPageRect.getY() + nHeader + nTopMargin);
2501 tools::Rectangle aRect(Point(nPosX, nPosY), aTmpRect.GetSize());
2502 lcl_SetMediaScreen(xShape, pDev, aRect, nPageNumb);
2504 ++nPageNumb;
2505 nX1 = nX2 + 1;
2510 pObj = aIter.Next();
2514 else // export whole sheet
2516 SCTAB nTabCount = rDoc.GetTableCount();
2517 for (SCTAB i = 0; i < nTabCount; ++i)
2519 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(i));
2520 OSL_ENSURE(pPage, "Page ?");
2521 if (pPage)
2523 SdrObjListIter aIter(pPage, SdrIterMode::DeepWithGroups);
2524 SdrObject* pObj = aIter.Next();
2525 while (pObj && pObj->IsVisible())
2527 uno::Reference<drawing::XShape> xShape(pObj->getUnoShape(), uno::UNO_QUERY);
2528 if (xShape->getShapeType() == "com.sun.star.drawing.MediaShape")
2530 tools::Rectangle aRect(pObj->GetCurrentBoundRect());
2531 lcl_SetMediaScreen(xShape, pDev, aRect, i);
2533 pObj = aIter.Next();
2541 void SAL_CALL ScModelObj::render( sal_Int32 nSelRenderer, const uno::Any& aSelection,
2542 const uno::Sequence<beans::PropertyValue>& rOptions )
2544 SolarMutexGuard aGuard;
2545 if (!pDocShell)
2547 throw lang::DisposedException( OUString(),
2548 static_cast< sheet::XSpreadsheetDocument* >(this) );
2551 ScMarkData aMark(pDocShell->GetDocument().GetSheetLimits());
2552 ScPrintSelectionStatus aStatus;
2553 OUString aPagesStr;
2554 bool bRenderToGraphic = false;
2555 bool bSinglePageSheets = false;
2556 bool bIsFirstPage = false;
2557 bool bIsLastPage = false;
2558 if ( !FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr, bRenderToGraphic ) )
2559 throw lang::IllegalArgumentException();
2561 if ( !pPrintFuncCache || !pPrintFuncCache->IsSameSelection( aStatus ) )
2563 pPrintFuncCache.reset(new ScPrintFuncCache( pDocShell, aMark, aStatus ));
2565 tools::Long nTotalPages = pPrintFuncCache->GetPageCount();
2567 for ( const auto& rValue : rOptions)
2569 if ( rValue.Name == "SinglePageSheets" )
2571 rValue.Value >>= bSinglePageSheets;
2573 else if (rValue.Name == "IsFirstPage")
2575 rValue.Value >>= bIsFirstPage;
2577 else if (rValue.Name == "IsLastPage")
2579 rValue.Value >>= bIsLastPage;
2583 if (bSinglePageSheets)
2584 nTotalPages = pDocShell->GetDocument().GetTableCount();
2586 // if no pages counted then user must be trying to print sheet/selection without any content (i.e empty)
2587 if (nTotalPages == 0)
2589 ScPrintOptions aNewOptions = aStatus.GetOptions();
2590 aNewOptions.SetSkipEmpty(false);
2591 aStatus.SetOptions(aNewOptions);
2593 pPrintFuncCache.reset(new ScPrintFuncCache( pDocShell, aMark, aStatus ));
2594 nTotalPages = pPrintFuncCache->GetPageCount();
2597 sal_Int32 nRenderer = lcl_GetRendererNum( nSelRenderer, aPagesStr, nTotalPages ); // 0, "", 0
2598 if ( nRenderer < 0 )
2599 throw lang::IllegalArgumentException();
2601 OutputDevice* pDev = lcl_GetRenderDevice( rOptions );
2602 if ( !pDev )
2603 throw lang::IllegalArgumentException();
2605 ScDocument& rDoc = pDocShell->GetDocument();
2607 SCTAB nTab;
2608 if (!maValidPages.empty())
2609 nTab = pPrintFuncCache->GetTabForPage(maValidPages.at(nRenderer) - 1);
2610 else
2611 nTab = pPrintFuncCache->GetTabForPage(nRenderer);
2613 tools::Long nTabStart = pPrintFuncCache->GetTabStart(nTab);
2615 if (nRenderer == nTabStart)
2616 lcl_PDFExportMediaShapeScreen(pDev, m_pPrintState, rDoc, nTab, nTabStart, bSinglePageSheets);
2618 ScRange aRange;
2619 const ScRange* pSelRange = nullptr;
2620 if ( bSinglePageSheets )
2622 awt::Size aPageSize;
2623 SCCOL nStartCol;
2624 SCROW nStartRow;
2625 rDoc.GetDataStart( nSelRenderer, nStartCol, nStartRow );
2626 SCCOL nEndCol;
2627 SCROW nEndRow;
2628 rDoc.GetPrintArea( nSelRenderer, nEndCol, nEndRow );
2630 aRange.aStart = ScAddress(nStartCol, nStartRow, nSelRenderer);
2631 aRange.aEnd = ScAddress(nEndCol, nEndRow, nSelRenderer);
2633 tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
2634 aRange.aStart.Col(), aRange.aStart.Row(),
2635 aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
2637 aPageSize.Width = aMMRect.GetWidth();
2638 aPageSize.Height = aMMRect.GetHeight();
2640 //Set visible tab
2641 SCTAB nVisTab = rDoc.GetVisibleTab();
2642 if (nVisTab != nSelRenderer)
2644 nVisTab = nSelRenderer;
2645 rDoc.SetVisibleTab(nVisTab);
2648 OUString aTabName;
2649 rDoc.GetName(nVisTab, aTabName);
2650 lcl_PDFExportHelper(pDev, aTabName, bIsFirstPage);
2652 pDocShell->DoDraw(pDev, Point(0,0), Size(aPageSize.Width, aPageSize.Height), JobSetup());
2654 vcl::PDFExtOutDevData* pPDFData = dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData());
2655 if (pPDFData && pPDFData->GetIsExportTaggedPDF() && bIsLastPage)
2657 pPDFData->EndStructureElement(); // Workbook
2658 assert(pPDFData->GetScPDFState());
2659 delete pPDFData->GetScPDFState();
2660 pPDFData->SetScPDFState(nullptr);
2663 lcl_PDFExportBookmarkHelper(pDev, rDoc, pPrintFuncCache, aMark, nVisTab);
2665 return;
2667 else if ( aMark.IsMarked() )
2669 aRange = aMark.GetMarkArea();
2670 pSelRange = &aRange;
2673 if (lcl_renderSelectionToGraphic( bRenderToGraphic, aStatus))
2675 // Similar to as in and when calling ScTransferObj::PaintToDev()
2677 tools::Rectangle aBound( Point(), pDev->GetOutputSize());
2679 ScViewData aViewData(rDoc);
2681 aViewData.SetTabNo( aRange.aStart.Tab() );
2682 aViewData.SetScreen( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() );
2684 const double nPrintFactor = 1.0; /* XXX: currently (2017-08-28) is not evaluated */
2685 // The bMetaFile argument maybe could be
2686 // pDev->GetConnectMetaFile() != nullptr
2687 // but for some yet unknown reason does not draw cell content if true.
2688 ScPrintFunc::DrawToDev( rDoc, pDev, nPrintFactor, aBound, &aViewData, false /*bMetaFile*/ );
2690 return;
2693 struct DrawViewKeeper
2695 std::unique_ptr<FmFormView> mpDrawView;
2696 DrawViewKeeper() {}
2697 ~DrawViewKeeper()
2699 if (mpDrawView)
2701 mpDrawView->HideSdrPage();
2702 mpDrawView.reset();
2705 } aDrawViewKeeper;
2707 ScDrawLayer* pModel = rDoc.GetDrawLayer();
2709 if( pModel )
2711 aDrawViewKeeper.mpDrawView.reset( new FmFormView(
2712 *pModel,
2713 pDev) );
2714 aDrawViewKeeper.mpDrawView->ShowSdrPage(aDrawViewKeeper.mpDrawView->GetModel().GetPage(nTab));
2715 aDrawViewKeeper.mpDrawView->SetPrintPreview();
2718 Size aPrintPageSize;
2719 bool bPrintPageLandscape = false;
2720 bool bUsePrintDialogSetting = false;
2721 Printer* pPrinter = lcl_GetPrinter(rOptions);
2722 if (pPrinter)
2724 if (pPrinter->IsUsePrintDialogSetting())
2726 bUsePrintDialogSetting = true;
2727 bPrintPageLandscape = (pPrinter->GetOrientation() == Orientation::Landscape);
2728 aPrintPageSize = lcl_GetPrintPageSize(pPrinter->GetPrintPageSize());
2732 // to increase performance, ScPrintState might be used here for subsequent
2733 // pages of the same sheet
2735 std::unique_ptr<ScPrintFunc, o3tl::default_delete<ScPrintFunc>> pPrintFunc;
2736 if (m_pPrintState && m_pPrintState->nPrintTab == nTab
2737 && ! pSelRange) // tdf#120161 use selection to set required printed area
2738 pPrintFunc.reset(new ScPrintFunc(pDev, pDocShell, *m_pPrintState, &aStatus.GetOptions(),
2739 aPrintPageSize, bPrintPageLandscape,
2740 bUsePrintDialogSetting));
2741 else
2742 pPrintFunc.reset(new ScPrintFunc(pDev, pDocShell, nTab, pPrintFuncCache->GetFirstAttr(nTab), nTotalPages, pSelRange, &aStatus.GetOptions()));
2744 pPrintFunc->SetDrawView( aDrawViewKeeper.mpDrawView.get() );
2745 pPrintFunc->SetRenderFlag( true );
2746 if( aStatus.GetMode() == ScPrintSelectionMode::RangeExclusivelyOleAndDrawObjects )
2747 pPrintFunc->SetExclusivelyDrawOleAndDrawObjects();
2749 sal_Int32 nContent = 0;
2750 sal_Int32 nEOContent = 0;
2751 for ( const auto& rValue : rOptions)
2753 if ( rValue.Name == "PrintRange" )
2755 rValue.Value >>= nContent;
2757 else if ( rValue.Name == "EvenOdd" )
2759 rValue.Value >>= nEOContent;
2763 MultiSelection aPage;
2764 aPage.SetTotalRange( Range(0,RANGE_MAX) );
2766 bool bOddOrEven = (nContent == 0 && nEOContent == 1) || (nContent == 0 && nEOContent == 2); // even pages or odd pages
2767 // tdf#127682 when odd/even allow nRenderer of 0 even when maValidPages is empty
2768 // to allow PrinterController::abortJob to spool an empty page as part of
2769 // its abort procedure
2770 if (bOddOrEven && !maValidPages.empty())
2771 aPage.Select( maValidPages.at( nRenderer ) );
2772 else
2773 aPage.Select( nRenderer+1 );
2775 tools::Long nDisplayStart = pPrintFuncCache->GetDisplayStart( nTab );
2777 if ( nRenderer == nTabStart || bIsFirstPage )
2779 OUString aTabName;
2780 rDoc.GetName(nTab, aTabName);
2781 lcl_PDFExportHelper(pDev, aTabName, bIsFirstPage);
2784 (void)pPrintFunc->DoPrint( aPage, nTabStart, nDisplayStart, true, nullptr );
2786 vcl::PDFExtOutDevData* pPDFData = dynamic_cast<vcl::PDFExtOutDevData*>(pDev->GetExtOutDevData());
2787 if (pPDFData && pPDFData->GetIsExportTaggedPDF() && bIsLastPage)
2789 pPDFData->EndStructureElement(); // Workbook
2790 assert(pPDFData->GetScPDFState());
2791 delete pPDFData->GetScPDFState();
2792 pPDFData->SetScPDFState(nullptr);
2795 if (!m_pPrintState)
2797 m_pPrintState.reset(new ScPrintState());
2798 pPrintFunc->GetPrintState(*m_pPrintState);
2801 lcl_PDFExportBookmarkHelper(pDev, rDoc, pPrintFuncCache, aMark, nTab);
2804 // XLinkTargetSupplier
2806 uno::Reference<container::XNameAccess> SAL_CALL ScModelObj::getLinks()
2808 SolarMutexGuard aGuard;
2809 if (pDocShell)
2810 return new ScLinkTargetTypesObj(pDocShell);
2811 return nullptr;
2814 // XActionLockable
2816 sal_Bool SAL_CALL ScModelObj::isActionLocked()
2818 SolarMutexGuard aGuard;
2819 bool bLocked = false;
2820 if (pDocShell)
2821 bLocked = ( pDocShell->GetLockCount() != 0 );
2822 return bLocked;
2825 void SAL_CALL ScModelObj::addActionLock()
2827 SolarMutexGuard aGuard;
2828 if (pDocShell)
2829 pDocShell->LockDocument();
2832 void SAL_CALL ScModelObj::removeActionLock()
2834 SolarMutexGuard aGuard;
2835 if (pDocShell)
2836 pDocShell->UnlockDocument();
2839 void SAL_CALL ScModelObj::setActionLocks( sal_Int16 nLock )
2841 SolarMutexGuard aGuard;
2842 if (pDocShell)
2843 pDocShell->SetLockCount(nLock);
2846 sal_Int16 SAL_CALL ScModelObj::resetActionLocks()
2848 SolarMutexGuard aGuard;
2849 sal_uInt16 nRet = 0;
2850 if (pDocShell)
2852 nRet = pDocShell->GetLockCount();
2853 pDocShell->SetLockCount(0);
2855 return nRet;
2858 void SAL_CALL ScModelObj::lockControllers()
2860 SolarMutexGuard aGuard;
2861 SfxBaseModel::lockControllers();
2862 if (pDocShell)
2863 pDocShell->LockPaint();
2866 void SAL_CALL ScModelObj::unlockControllers()
2868 SolarMutexGuard aGuard;
2869 if (hasControllersLocked())
2871 SfxBaseModel::unlockControllers();
2872 if (pDocShell)
2873 pDocShell->UnlockPaint();
2877 // XCalculate
2879 void SAL_CALL ScModelObj::calculate()
2881 SolarMutexGuard aGuard;
2882 if (pDocShell)
2884 comphelper::ProfileZone aZone("calculate");
2885 pDocShell->DoRecalc(true);
2887 else
2889 OSL_FAIL("no DocShell"); //! throw exception?
2893 void SAL_CALL ScModelObj::calculateAll()
2895 SolarMutexGuard aGuard;
2896 if (pDocShell)
2898 comphelper::ProfileZone aZone("calculateAll");
2899 pDocShell->DoHardRecalc();
2901 else
2903 OSL_FAIL("no DocShell"); //! throw exception?
2907 sal_Bool SAL_CALL ScModelObj::isAutomaticCalculationEnabled()
2909 SolarMutexGuard aGuard;
2910 if (pDocShell)
2911 return pDocShell->GetDocument().GetAutoCalc();
2913 OSL_FAIL("no DocShell"); //! throw exception?
2914 return false;
2917 void SAL_CALL ScModelObj::enableAutomaticCalculation( sal_Bool bEnabledIn )
2919 bool bEnabled(bEnabledIn);
2920 SolarMutexGuard aGuard;
2921 if (pDocShell)
2923 ScDocument& rDoc = pDocShell->GetDocument();
2924 if ( rDoc.GetAutoCalc() != bEnabled )
2926 rDoc.SetAutoCalc( bEnabled );
2927 pDocShell->SetDocumentModified();
2930 else
2932 OSL_FAIL("no DocShell"); //! throw exception?
2936 // XProtectable
2938 void SAL_CALL ScModelObj::protect( const OUString& aPassword )
2940 SolarMutexGuard aGuard;
2941 // #i108245# if already protected, don't change anything
2942 if ( pDocShell && !pDocShell->GetDocument().IsDocProtected() )
2944 pDocShell->GetDocFunc().Protect( TABLEID_DOC, aPassword );
2948 void SAL_CALL ScModelObj::unprotect( const OUString& aPassword )
2950 SolarMutexGuard aGuard;
2951 if (pDocShell)
2953 bool bDone = pDocShell->GetDocFunc().Unprotect( TABLEID_DOC, aPassword, true );
2954 if (!bDone)
2955 throw lang::IllegalArgumentException();
2959 sal_Bool SAL_CALL ScModelObj::isProtected()
2961 SolarMutexGuard aGuard;
2962 if (pDocShell)
2963 return pDocShell->GetDocument().IsDocProtected();
2965 OSL_FAIL("no DocShell"); //! throw exception?
2966 return false;
2969 // XDrawPagesSupplier
2971 uno::Reference<drawing::XDrawPages> SAL_CALL ScModelObj::getDrawPages()
2973 SolarMutexGuard aGuard;
2974 if (pDocShell)
2975 return new ScDrawPagesObj(pDocShell);
2977 OSL_FAIL("no DocShell"); //! throw exception?
2978 return nullptr;
2981 // XGoalSeek
2983 sheet::GoalResult SAL_CALL ScModelObj::seekGoal(
2984 const table::CellAddress& aFormulaPosition,
2985 const table::CellAddress& aVariablePosition,
2986 const OUString& aGoalValue )
2988 SolarMutexGuard aGuard;
2989 sheet::GoalResult aResult;
2990 aResult.Divergence = DBL_MAX; // not found
2991 if (pDocShell)
2993 weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
2994 ScDocument& rDoc = pDocShell->GetDocument();
2995 double fValue = 0.0;
2996 bool bFound = rDoc.Solver(
2997 static_cast<SCCOL>(aFormulaPosition.Column), static_cast<SCROW>(aFormulaPosition.Row), aFormulaPosition.Sheet,
2998 static_cast<SCCOL>(aVariablePosition.Column), static_cast<SCROW>(aVariablePosition.Row), aVariablePosition.Sheet,
2999 aGoalValue, fValue );
3000 aResult.Result = fValue;
3001 if (bFound)
3002 aResult.Divergence = 0.0; //! this is a lie
3004 return aResult;
3007 // XConsolidatable
3009 uno::Reference<sheet::XConsolidationDescriptor> SAL_CALL ScModelObj::createConsolidationDescriptor(
3010 sal_Bool bEmpty )
3012 SolarMutexGuard aGuard;
3013 rtl::Reference<ScConsolidationDescriptor> pNew = new ScConsolidationDescriptor;
3014 if ( pDocShell && !bEmpty )
3016 ScDocument& rDoc = pDocShell->GetDocument();
3017 const ScConsolidateParam* pParam = rDoc.GetConsolidateDlgData();
3018 if (pParam)
3019 pNew->SetParam( *pParam );
3021 return pNew;
3024 void SAL_CALL ScModelObj::consolidate(
3025 const uno::Reference<sheet::XConsolidationDescriptor>& xDescriptor )
3027 SolarMutexGuard aGuard;
3028 // in theory, this could also be a different object, so use only
3029 // public XConsolidationDescriptor interface to copy the data into
3030 // ScConsolidationDescriptor object
3031 //! but if this already is ScConsolidationDescriptor, do it directly via getImplementation?
3033 rtl::Reference< ScConsolidationDescriptor > xImpl(new ScConsolidationDescriptor);
3034 xImpl->setFunction( xDescriptor->getFunction() );
3035 xImpl->setSources( xDescriptor->getSources() );
3036 xImpl->setStartOutputPosition( xDescriptor->getStartOutputPosition() );
3037 xImpl->setUseColumnHeaders( xDescriptor->getUseColumnHeaders() );
3038 xImpl->setUseRowHeaders( xDescriptor->getUseRowHeaders() );
3039 xImpl->setInsertLinks( xDescriptor->getInsertLinks() );
3041 if (pDocShell)
3043 const ScConsolidateParam& rParam = xImpl->GetParam();
3044 pDocShell->DoConsolidate( rParam );
3045 pDocShell->GetDocument().SetConsolidateDlgData( std::unique_ptr<ScConsolidateParam>(new ScConsolidateParam(rParam)) );
3049 // XDocumentAuditing
3051 void SAL_CALL ScModelObj::refreshArrows()
3053 SolarMutexGuard aGuard;
3054 if (pDocShell)
3055 pDocShell->GetDocFunc().DetectiveRefresh();
3058 // XViewDataSupplier
3059 uno::Reference< container::XIndexAccess > SAL_CALL ScModelObj::getViewData( )
3061 uno::Reference < container::XIndexAccess > xRet( SfxBaseModel::getViewData() );
3063 if( !xRet.is() )
3065 SolarMutexGuard aGuard;
3066 if (pDocShell && pDocShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED)
3068 rtl::Reference< comphelper::IndexedPropertyValuesContainer > xCont = new comphelper::IndexedPropertyValuesContainer();
3069 xRet = xCont;
3071 OUString sName;
3072 pDocShell->GetDocument().GetName( pDocShell->GetDocument().GetVisibleTab(), sName );
3073 SCCOL nPosLeft = pDocShell->GetDocument().GetPosLeft();
3074 SCROW nPosTop = pDocShell->GetDocument().GetPosTop();
3075 uno::Sequence< beans::PropertyValue > aSeq{
3076 comphelper::makePropertyValue(SC_ACTIVETABLE, sName),
3077 comphelper::makePropertyValue(SC_POSITIONLEFT, nPosLeft),
3078 comphelper::makePropertyValue(SC_POSITIONTOP, nPosTop)
3080 xCont->insertByIndex( 0, uno::Any( aSeq ) );
3084 return xRet;
3087 // XPropertySet (Doc-Options)
3088 //! provide them also to the application?
3090 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScModelObj::getPropertySetInfo()
3092 SolarMutexGuard aGuard;
3093 static uno::Reference<beans::XPropertySetInfo> aRef(
3094 new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
3095 return aRef;
3098 void SAL_CALL ScModelObj::setPropertyValue(
3099 const OUString& aPropertyName, const uno::Any& aValue )
3101 SolarMutexGuard aGuard;
3103 if (!pDocShell)
3104 return;
3106 ScDocument& rDoc = pDocShell->GetDocument();
3107 const ScDocOptions& rOldOpt = rDoc.GetDocOptions();
3108 ScDocOptions aNewOpt = rOldOpt;
3109 // Don't recalculate while loading XML, when the formula text is stored
3110 // Recalculation after loading is handled separately.
3111 bool bHardRecalc = !rDoc.IsImportingXML();
3113 bool bOpt = ScDocOptionsHelper::setPropertyValue( aNewOpt, aPropSet.getPropertyMap(), aPropertyName, aValue );
3114 if (bOpt)
3116 // done...
3117 if ( aPropertyName == SC_UNO_IGNORECASE ||
3118 aPropertyName == SC_UNONAME_REGEXP ||
3119 aPropertyName == SC_UNONAME_WILDCARDS ||
3120 aPropertyName == SC_UNO_LOOKUPLABELS )
3121 bHardRecalc = false;
3123 else if (aPropertyName == SC_UNO_SPELLONLINE)
3125 if (ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false))
3126 pViewShell->EnableAutoSpell(ScUnoHelpFunctions::GetBoolFromAny(aValue));
3128 else if ( aPropertyName == SC_UNONAME_CLOCAL )
3130 lang::Locale aLocale;
3131 if ( aValue >>= aLocale )
3133 LanguageType eLatin, eCjk, eCtl;
3134 rDoc.GetLanguage( eLatin, eCjk, eCtl );
3135 eLatin = ScUnoConversion::GetLanguage(aLocale);
3136 rDoc.SetLanguage( eLatin, eCjk, eCtl );
3139 else if ( aPropertyName == SC_UNO_CODENAME )
3141 OUString sCodeName;
3142 if ( aValue >>= sCodeName )
3143 rDoc.SetCodeName( sCodeName );
3145 else if ( aPropertyName == SC_UNO_CJK_CLOCAL )
3147 lang::Locale aLocale;
3148 if ( aValue >>= aLocale )
3150 LanguageType eLatin, eCjk, eCtl;
3151 rDoc.GetLanguage( eLatin, eCjk, eCtl );
3152 eCjk = ScUnoConversion::GetLanguage(aLocale);
3153 rDoc.SetLanguage( eLatin, eCjk, eCtl );
3156 else if ( aPropertyName == SC_UNO_CTL_CLOCAL )
3158 lang::Locale aLocale;
3159 if ( aValue >>= aLocale )
3161 LanguageType eLatin, eCjk, eCtl;
3162 rDoc.GetLanguage( eLatin, eCjk, eCtl );
3163 eCtl = ScUnoConversion::GetLanguage(aLocale);
3164 rDoc.SetLanguage( eLatin, eCjk, eCtl );
3167 else if ( aPropertyName == SC_UNO_APPLYFMDES )
3169 // model is created if not there
3170 ScDrawLayer* pModel = pDocShell->MakeDrawLayer();
3171 pModel->SetOpenInDesignMode( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
3173 SfxBindings* pBindings = pDocShell->GetViewBindings();
3174 if (pBindings)
3175 pBindings->Invalidate( SID_FM_OPEN_READONLY );
3177 else if ( aPropertyName == SC_UNO_AUTOCONTFOC )
3179 // model is created if not there
3180 ScDrawLayer* pModel = pDocShell->MakeDrawLayer();
3181 pModel->SetAutoControlFocus( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
3183 SfxBindings* pBindings = pDocShell->GetViewBindings();
3184 if (pBindings)
3185 pBindings->Invalidate( SID_FM_AUTOCONTROLFOCUS );
3187 else if ( aPropertyName == SC_UNO_ISLOADED )
3189 pDocShell->SetEmpty( !ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
3191 else if ( aPropertyName == SC_UNO_ISUNDOENABLED )
3193 bool bUndoEnabled = ScUnoHelpFunctions::GetBoolFromAny( aValue );
3194 rDoc.EnableUndo( bUndoEnabled );
3195 pDocShell->GetUndoManager()->SetMaxUndoActionCount(
3196 bUndoEnabled
3197 ? officecfg::Office::Common::Undo::Steps::get() : 0);
3199 else if ( aPropertyName == SC_UNO_RECORDCHANGES )
3201 bool bRecordChangesEnabled = ScUnoHelpFunctions::GetBoolFromAny( aValue );
3203 bool bChangeAllowed = true;
3204 if (!bRecordChangesEnabled)
3205 bChangeAllowed = !pDocShell->HasChangeRecordProtection();
3207 if (bChangeAllowed)
3208 pDocShell->SetChangeRecording(bRecordChangesEnabled);
3210 else if ( aPropertyName == SC_UNO_ISADJUSTHEIGHTENABLED )
3212 if( ScUnoHelpFunctions::GetBoolFromAny( aValue ) )
3213 rDoc.UnlockAdjustHeight();
3214 else
3215 rDoc.LockAdjustHeight();
3217 else if ( aPropertyName == SC_UNO_ISEXECUTELINKENABLED )
3219 rDoc.EnableExecuteLink( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
3221 else if ( aPropertyName == SC_UNO_ISCHANGEREADONLYENABLED )
3223 rDoc.EnableChangeReadOnly( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
3225 else if ( aPropertyName == "BuildId" )
3227 aValue >>= maBuildId;
3229 else if ( aPropertyName == "SavedObject" ) // set from chart after saving
3231 OUString aObjName;
3232 aValue >>= aObjName;
3233 if ( !aObjName.isEmpty() )
3234 rDoc.RestoreChartListener( aObjName );
3236 else if ( aPropertyName == SC_UNO_INTEROPGRABBAG )
3238 setGrabBagItem(aValue);
3240 else if (aPropertyName == SC_UNO_THEME)
3242 SdrModel& rSdrModel = getSdrModelFromUnoModel();
3243 uno::Reference<util::XTheme> xTheme;
3244 if (aValue >>= xTheme)
3246 auto& rUnoTheme = dynamic_cast<UnoTheme&>(*xTheme);
3247 rSdrModel.setTheme(rUnoTheme.getTheme());
3251 if ( aNewOpt != rOldOpt )
3253 rDoc.SetDocOptions( aNewOpt );
3254 //! Recalc only for options that need it?
3255 if ( bHardRecalc )
3256 pDocShell->DoHardRecalc();
3257 pDocShell->SetDocumentModified();
3261 uno::Any SAL_CALL ScModelObj::getPropertyValue( const OUString& aPropertyName )
3263 SolarMutexGuard aGuard;
3264 uno::Any aRet;
3266 if (pDocShell)
3268 ScDocument& rDoc = pDocShell->GetDocument();
3269 const ScDocOptions& rOpt = rDoc.GetDocOptions();
3270 aRet = ScDocOptionsHelper::getPropertyValue( rOpt, aPropSet.getPropertyMap(), aPropertyName );
3271 if ( aRet.hasValue() )
3273 // done...
3275 else if (aPropertyName == SC_UNO_SPELLONLINE)
3277 if (ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false))
3278 aRet <<= pViewShell->IsAutoSpell();
3280 else if ( aPropertyName == SC_UNONAME_CLOCAL )
3282 LanguageType eLatin, eCjk, eCtl;
3283 rDoc.GetLanguage( eLatin, eCjk, eCtl );
3285 lang::Locale aLocale;
3286 ScUnoConversion::FillLocale( aLocale, eLatin );
3287 aRet <<= aLocale;
3289 else if ( aPropertyName == SC_UNO_CODENAME )
3291 aRet <<= rDoc.GetCodeName();
3294 else if ( aPropertyName == SC_UNO_CJK_CLOCAL )
3296 LanguageType eLatin, eCjk, eCtl;
3297 rDoc.GetLanguage( eLatin, eCjk, eCtl );
3299 lang::Locale aLocale;
3300 ScUnoConversion::FillLocale( aLocale, eCjk );
3301 aRet <<= aLocale;
3303 else if ( aPropertyName == SC_UNO_CTL_CLOCAL )
3305 LanguageType eLatin, eCjk, eCtl;
3306 rDoc.GetLanguage( eLatin, eCjk, eCtl );
3308 lang::Locale aLocale;
3309 ScUnoConversion::FillLocale( aLocale, eCtl );
3310 aRet <<= aLocale;
3312 else if ( aPropertyName == SC_UNO_NAMEDRANGES )
3314 aRet <<= uno::Reference<sheet::XNamedRanges>(new ScGlobalNamedRangesObj( pDocShell ));
3316 else if ( aPropertyName == SC_UNO_DATABASERNG )
3318 aRet <<= uno::Reference<sheet::XDatabaseRanges>(new ScDatabaseRangesObj( pDocShell ));
3320 else if ( aPropertyName == SC_UNO_UNNAMEDDBRNG )
3322 aRet <<= uno::Reference<sheet::XUnnamedDatabaseRanges>(new ScUnnamedDatabaseRangesObj(pDocShell));
3324 else if ( aPropertyName == SC_UNO_COLLABELRNG )
3326 aRet <<= uno::Reference<sheet::XLabelRanges>(new ScLabelRangesObj( pDocShell, true ));
3328 else if ( aPropertyName == SC_UNO_ROWLABELRNG )
3330 aRet <<= uno::Reference<sheet::XLabelRanges>(new ScLabelRangesObj( pDocShell, false ));
3332 else if ( aPropertyName == SC_UNO_AREALINKS )
3334 aRet <<= uno::Reference<sheet::XAreaLinks>(new ScAreaLinksObj( pDocShell ));
3336 else if ( aPropertyName == SC_UNO_DDELINKS )
3338 aRet <<= uno::Reference<container::XNameAccess>(new ScDDELinksObj( pDocShell ));
3340 else if ( aPropertyName == SC_UNO_EXTERNALDOCLINKS )
3342 aRet <<= uno::Reference<sheet::XExternalDocLinks>(new ScExternalDocLinksObj(pDocShell));
3344 else if ( aPropertyName == SC_UNO_SHEETLINKS )
3346 aRet <<= uno::Reference<container::XNameAccess>(new ScSheetLinksObj( pDocShell ));
3348 else if ( aPropertyName == SC_UNO_APPLYFMDES )
3350 // default for no model is TRUE
3351 ScDrawLayer* pModel = rDoc.GetDrawLayer();
3352 bool bOpenInDesign = pModel == nullptr || pModel->GetOpenInDesignMode();
3353 aRet <<= bOpenInDesign;
3355 else if ( aPropertyName == SC_UNO_AUTOCONTFOC )
3357 // default for no model is FALSE
3358 ScDrawLayer* pModel = rDoc.GetDrawLayer();
3359 bool bAutoControlFocus = pModel && pModel->GetAutoControlFocus();
3360 aRet <<= bAutoControlFocus;
3362 else if ( aPropertyName == SC_UNO_FORBIDDEN )
3364 aRet <<= uno::Reference<i18n::XForbiddenCharacters>(new ScForbiddenCharsObj( pDocShell ));
3366 else if ( aPropertyName == SC_UNO_HASDRAWPAGES )
3368 aRet <<= (pDocShell->GetDocument().GetDrawLayer() != nullptr);
3370 else if ( aPropertyName == SC_UNO_BASICLIBRARIES )
3372 aRet <<= pDocShell->GetBasicContainer();
3374 else if ( aPropertyName == SC_UNO_DIALOGLIBRARIES )
3376 aRet <<= pDocShell->GetDialogContainer();
3378 else if ( aPropertyName == SC_UNO_VBAGLOBNAME )
3380 /* #i111553# This property provides the name of the constant that
3381 will be used to store this model in the global Basic manager.
3382 That constant will be equivalent to 'ThisComponent' but for
3383 each application, so e.g. a 'ThisExcelDoc' and a 'ThisWordDoc'
3384 constant can co-exist, as required by VBA. */
3385 aRet <<= u"ThisExcelDoc"_ustr;
3387 else if ( aPropertyName == SC_UNO_RUNTIMEUID )
3389 aRet <<= getRuntimeUID();
3391 else if ( aPropertyName == SC_UNO_HASVALIDSIGNATURES )
3393 aRet <<= hasValidSignatures();
3395 else if ( aPropertyName == SC_UNO_ALLOWLINKUPDATE)
3397 comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = pDocShell->getEmbeddedObjectContainer();
3398 aRet <<= rEmbeddedObjectContainer.getUserAllowsLinkUpdate();
3400 else if ( aPropertyName == SC_UNO_ISLOADED )
3402 aRet <<= !pDocShell->IsEmpty();
3404 else if ( aPropertyName == SC_UNO_ISUNDOENABLED )
3406 aRet <<= rDoc.IsUndoEnabled();
3408 else if ( aPropertyName == SC_UNO_RECORDCHANGES )
3410 aRet <<= pDocShell->IsChangeRecording();
3412 else if ( aPropertyName == SC_UNO_ISRECORDCHANGESPROTECTED )
3414 aRet <<= pDocShell->HasChangeRecordProtection();
3416 else if ( aPropertyName == SC_UNO_ISADJUSTHEIGHTENABLED )
3418 aRet <<= !( rDoc.IsAdjustHeightLocked() );
3420 else if ( aPropertyName == SC_UNO_ISEXECUTELINKENABLED )
3422 aRet <<= rDoc.IsExecuteLinkEnabled();
3424 else if ( aPropertyName == SC_UNO_ISCHANGEREADONLYENABLED )
3426 aRet <<= rDoc.IsChangeReadOnlyEnabled();
3428 else if ( aPropertyName == SC_UNO_REFERENCEDEVICE )
3430 rtl::Reference<VCLXDevice> pXDev = new VCLXDevice();
3431 pXDev->SetOutputDevice( rDoc.GetRefDevice() );
3432 aRet <<= uno::Reference< awt::XDevice >( pXDev );
3434 else if ( aPropertyName == "BuildId" )
3436 aRet <<= maBuildId;
3438 else if ( aPropertyName == "InternalDocument" )
3440 aRet <<= (pDocShell->GetCreateMode() == SfxObjectCreateMode::INTERNAL);
3442 else if ( aPropertyName == SC_UNO_INTEROPGRABBAG )
3444 getGrabBagItem(aRet);
3446 else if (aPropertyName == SC_UNO_THEME)
3448 SdrModel& rSdrModel = getSdrModelFromUnoModel();
3449 css::uno::Reference<css::util::XTheme> xTheme;
3450 auto pTheme = rSdrModel.getTheme();
3451 if (pTheme)
3452 xTheme = model::theme::createXTheme(pTheme);
3453 aRet <<= xTheme;
3457 return aRet;
3460 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScModelObj )
3462 // XMultiServiceFactory
3464 css::uno::Reference<css::uno::XInterface> ScModelObj::create(
3465 OUString const & aServiceSpecifier,
3466 css::uno::Sequence<css::uno::Any> const * arguments)
3468 using ServiceType = ScServiceProvider::Type;
3470 uno::Reference<uno::XInterface> xRet;
3471 ServiceType nType = ScServiceProvider::GetProviderType(aServiceSpecifier);
3472 if ( nType != ServiceType::INVALID )
3474 // drawing layer tables must be kept as long as the model is alive
3475 // return stored instance if already set
3476 switch ( nType )
3478 case ServiceType::GRADTAB: xRet.set(xDrawGradTab); break;
3479 case ServiceType::HATCHTAB: xRet.set(xDrawHatchTab); break;
3480 case ServiceType::BITMAPTAB: xRet.set(xDrawBitmapTab); break;
3481 case ServiceType::TRGRADTAB: xRet.set(xDrawTrGradTab); break;
3482 case ServiceType::MARKERTAB: xRet.set(xDrawMarkerTab); break;
3483 case ServiceType::DASHTAB: xRet.set(xDrawDashTab); break;
3484 case ServiceType::CHDATAPROV: xRet.set(xChartDataProv); break;
3485 case ServiceType::VBAOBJECTPROVIDER: xRet.set(xObjProvider); break;
3486 default: break;
3489 // #i64497# If a chart is in a temporary document during clipboard paste,
3490 // there should be no data provider, so that own data is used
3491 bool bCreate =
3492 ( nType != ServiceType::CHDATAPROV ||
3493 ( pDocShell->GetCreateMode() != SfxObjectCreateMode::INTERNAL ));
3494 // this should never happen, i.e. the temporary document should never be
3495 // loaded, because this unlinks the data
3496 assert(bCreate);
3498 if ( !xRet.is() && bCreate )
3500 xRet.set(ScServiceProvider::MakeInstance( nType, pDocShell ));
3502 // store created instance
3503 switch ( nType )
3505 case ServiceType::GRADTAB: xDrawGradTab.set(xRet); break;
3506 case ServiceType::HATCHTAB: xDrawHatchTab.set(xRet); break;
3507 case ServiceType::BITMAPTAB: xDrawBitmapTab.set(xRet); break;
3508 case ServiceType::TRGRADTAB: xDrawTrGradTab.set(xRet); break;
3509 case ServiceType::MARKERTAB: xDrawMarkerTab.set(xRet); break;
3510 case ServiceType::DASHTAB: xDrawDashTab.set(xRet); break;
3511 case ServiceType::CHDATAPROV: xChartDataProv.set(xRet); break;
3512 case ServiceType::VBAOBJECTPROVIDER: xObjProvider.set(xRet); break;
3513 default: break;
3517 else
3519 // we offload everything we don't know to SvxFmMSFactory,
3520 // it'll throw exception if this isn't okay ...
3524 xRet = arguments == nullptr
3525 ? SvxFmMSFactory::createInstance(aServiceSpecifier)
3526 : SvxFmMSFactory::createInstanceWithArguments(
3527 aServiceSpecifier, *arguments);
3528 // extra block to force deletion of the temporary before ScShapeObj ctor (setDelegator)
3530 catch ( lang::ServiceNotRegisteredException & )
3534 // if the drawing factory created a shape, a ScShapeObj has to be used
3535 // to support own properties like ImageMap:
3537 uno::Reference<drawing::XShape> xShape( xRet, uno::UNO_QUERY );
3538 if ( xShape.is() )
3540 xRet.clear(); // for aggregation, xShape must be the object's only ref
3541 new ScShapeObj( xShape ); // aggregates object and modifies xShape
3542 xRet.set(xShape);
3545 return xRet;
3548 uno::Reference<uno::XInterface> SAL_CALL ScModelObj::createInstance(
3549 const OUString& aServiceSpecifier )
3551 SolarMutexGuard aGuard;
3552 return create(aServiceSpecifier, nullptr);
3555 uno::Reference<uno::XInterface> SAL_CALL ScModelObj::createInstanceWithArguments(
3556 const OUString& ServiceSpecifier,
3557 const uno::Sequence<uno::Any>& aArgs )
3559 //! distinguish between own services and those of drawing layer?
3561 SolarMutexGuard aGuard;
3562 uno::Reference<uno::XInterface> xInt(create(ServiceSpecifier, &aArgs));
3564 if ( aArgs.hasElements() )
3566 // used only for cell value binding so far - it can be initialized after creating
3568 uno::Reference<lang::XInitialization> xInit( xInt, uno::UNO_QUERY );
3569 if ( xInit.is() )
3570 xInit->initialize( aArgs );
3573 return xInt;
3576 uno::Sequence<OUString> SAL_CALL ScModelObj::getAvailableServiceNames()
3578 SolarMutexGuard aGuard;
3580 return comphelper::concatSequences( ScServiceProvider::GetAllServiceNames(),
3581 SvxFmMSFactory::getAvailableServiceNames() );
3584 // XServiceInfo
3585 OUString SAL_CALL ScModelObj::getImplementationName()
3587 return u"ScModelObj"_ustr;
3588 /* // Matching the .component information:
3589 return OUString( "com.sun.star.comp.Calc.SpreadsheetDocument" );
3593 sal_Bool SAL_CALL ScModelObj::supportsService( const OUString& rServiceName )
3595 return cppu::supportsService(this, rServiceName);
3598 uno::Sequence<OUString> SAL_CALL ScModelObj::getSupportedServiceNames()
3600 return {SCMODELOBJ_SERVICE, SCDOCSETTINGS_SERVICE, SCDOC_SERVICE};
3603 // XUnoTunnel
3605 sal_Int64 SAL_CALL ScModelObj::getSomething(
3606 const uno::Sequence<sal_Int8 >& rId )
3608 if ( comphelper::isUnoTunnelId<ScModelObj>(rId) )
3610 return comphelper::getSomething_cast(this);
3613 if ( comphelper::isUnoTunnelId<SfxObjectShell>(rId) )
3615 return comphelper::getSomething_cast(pDocShell);
3618 // aggregated number formats supplier has XUnoTunnel, too
3619 // interface from aggregated object must be obtained via queryAggregation
3621 sal_Int64 nRet = SfxBaseModel::getSomething( rId );
3622 if ( nRet )
3623 return nRet;
3625 if ( GetFormatter().is() )
3627 const uno::Type& rTunnelType = cppu::UnoType<lang::XUnoTunnel>::get();
3628 uno::Any aNumTunnel(xNumberAgg->queryAggregation(rTunnelType));
3629 if(auto xTunnelAgg = o3tl::tryAccess<uno::Reference<lang::XUnoTunnel>>(
3630 aNumTunnel))
3632 return (*xTunnelAgg)->getSomething( rId );
3636 return 0;
3639 const uno::Sequence<sal_Int8>& ScModelObj::getUnoTunnelId()
3641 static const comphelper::UnoIdInit theScModelObjUnoTunnelId;
3642 return theScModelObjUnoTunnelId.getSeq();
3645 // XChangesNotifier
3647 void ScModelObj::addChangesListener( const uno::Reference< util::XChangesListener >& aListener )
3649 SolarMutexGuard aGuard;
3650 maChangesListeners.addInterface( aListener );
3653 void ScModelObj::removeChangesListener( const uno::Reference< util::XChangesListener >& aListener )
3655 SolarMutexGuard aGuard;
3656 maChangesListeners.removeInterface( aListener );
3659 bool ScModelObj::HasChangesListeners() const
3661 if ( maChangesListeners.getLength() > 0 )
3662 return true;
3664 // "change" event set in any sheet?
3665 return pDocShell && pDocShell->GetDocument().HasAnySheetEventScript(ScSheetEventId::CHANGE);
3668 namespace
3671 void lcl_dataAreaInvalidation(ScModelObj* pModel,
3672 const ScRangeList& rRanges,
3673 bool bInvalidateDataArea, bool bExtendDataArea)
3675 size_t nRangeCount = rRanges.size();
3677 for ( size_t nIndex = 0; nIndex < nRangeCount; ++nIndex )
3679 ScRange const & rRange = rRanges[ nIndex ];
3680 ScAddress const & rEnd = rRange.aEnd;
3681 SCTAB nTab = rEnd.Tab();
3683 bool bAreaExtended = false;
3685 if (bExtendDataArea)
3687 const Size aCurrentDataArea = pModel->getDataArea( nTab );
3689 SCCOL nLastCol = aCurrentDataArea.Width();
3690 SCROW nLastRow = aCurrentDataArea.Height();
3692 bAreaExtended = rEnd.Col() > nLastCol || rEnd.Row() > nLastRow;
3695 bool bInvalidate = bAreaExtended || bInvalidateDataArea;
3696 if ( bInvalidate )
3698 if ( comphelper::LibreOfficeKit::isActive() )
3699 SfxLokHelper::notifyPartSizeChangedAllViews( pModel, nTab );
3706 void ScModelObj::NotifyChanges( const OUString& rOperation, const ScRangeList& rRanges,
3707 const uno::Sequence< beans::PropertyValue >& rProperties )
3709 OUString aOperation = rOperation;
3710 bool bIsDataAreaInvalidateType = aOperation == "data-area-invalidate";
3711 bool bIsDataAreaExtendType = aOperation == "data-area-extend";
3713 bool bInvalidateDataArea = bIsDataAreaInvalidateType
3714 || HelperNotifyChanges::isDataAreaInvalidateType(aOperation);
3715 bool bExtendDataArea = bIsDataAreaExtendType || aOperation == "cell-change";
3717 if ( pDocShell )
3719 lcl_dataAreaInvalidation(this, rRanges, bInvalidateDataArea, bExtendDataArea);
3721 // check if we were called only to update data area
3722 if (bIsDataAreaInvalidateType || bIsDataAreaExtendType)
3723 return;
3725 // backward-compatibility Operation conversion
3726 // FIXME: make sure it can be passed
3727 if (rOperation == "delete-content" || rOperation == "undo"
3728 || rOperation == "redo" || rOperation == "paste")
3729 aOperation = "cell-change";
3732 if ( pDocShell && HasChangesListeners() )
3734 util::ChangesEvent aEvent;
3735 aEvent.Source.set(getXWeak());
3736 aEvent.Base <<= aEvent.Source;
3738 size_t nRangeCount = rRanges.size();
3739 aEvent.Changes.realloc( static_cast< sal_Int32 >( nRangeCount ) );
3740 auto pChanges = aEvent.Changes.getArray();
3741 for ( size_t nIndex = 0; nIndex < nRangeCount; ++nIndex )
3743 uno::Reference< table::XCellRange > xRangeObj;
3745 ScRange const & rRange = rRanges[ nIndex ];
3746 if ( rRange.aStart == rRange.aEnd )
3748 xRangeObj.set( new ScCellObj( pDocShell, rRange.aStart ) );
3750 else
3752 xRangeObj.set( new ScCellRangeObj( pDocShell, rRange ) );
3755 util::ElementChange& rChange = pChanges[ static_cast< sal_Int32 >( nIndex ) ];
3756 rChange.Accessor <<= aOperation;
3757 rChange.Element <<= rProperties;
3758 rChange.ReplacedElement <<= xRangeObj;
3761 ::comphelper::OInterfaceIteratorHelper3 aIter( maChangesListeners );
3762 while ( aIter.hasMoreElements() )
3766 aIter.next()->changesOccurred( aEvent );
3768 catch( uno::Exception& )
3774 // handle sheet events
3775 //! separate method with ScMarkData? Then change HasChangesListeners back.
3776 if ( !(aOperation == "cell-change" && pDocShell) )
3777 return;
3779 ScMarkData aMarkData(pDocShell->GetDocument().GetSheetLimits());
3780 aMarkData.MarkFromRangeList( rRanges, false );
3781 ScDocument& rDoc = pDocShell->GetDocument();
3782 SCTAB nTabCount = rDoc.GetTableCount();
3783 for (const SCTAB& nTab : aMarkData)
3785 if (nTab >= nTabCount)
3786 break;
3787 const ScSheetEvents* pEvents = rDoc.GetSheetEvents(nTab);
3788 if (pEvents)
3790 const OUString* pScript = pEvents->GetScript(ScSheetEventId::CHANGE);
3791 if (pScript)
3793 ScRangeList aTabRanges; // collect ranges on this sheet
3794 size_t nRangeCount = rRanges.size();
3795 for ( size_t nIndex = 0; nIndex < nRangeCount; ++nIndex )
3797 ScRange const & rRange = rRanges[ nIndex ];
3798 if ( rRange.aStart.Tab() == nTab )
3799 aTabRanges.push_back( rRange );
3801 size_t nTabRangeCount = aTabRanges.size();
3802 if ( nTabRangeCount > 0 )
3804 uno::Reference<uno::XInterface> xTarget;
3805 if ( nTabRangeCount == 1 )
3807 ScRange const & rRange = aTabRanges[ 0 ];
3808 if ( rRange.aStart == rRange.aEnd )
3809 xTarget.set( cppu::getXWeak( new ScCellObj( pDocShell, rRange.aStart ) ) );
3810 else
3811 xTarget.set( cppu::getXWeak( new ScCellRangeObj( pDocShell, rRange ) ) );
3813 else
3814 xTarget.set( cppu::getXWeak( new ScCellRangesObj( pDocShell, aTabRanges ) ) );
3816 uno::Sequence<uno::Any> aParams{ uno::Any(xTarget) };
3818 uno::Any aRet;
3819 uno::Sequence<sal_Int16> aOutArgsIndex;
3820 uno::Sequence<uno::Any> aOutArgs;
3822 /*ErrCode eRet =*/ pDocShell->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
3829 void ScModelObj::HandleCalculateEvents()
3831 if (!pDocShell)
3832 return;
3834 ScDocument& rDoc = pDocShell->GetDocument();
3835 // don't call events before the document is visible
3836 // (might also set a flag on SfxEventHintId::LoadFinished and only disable while loading)
3837 if ( rDoc.IsDocVisible() )
3839 SCTAB nTabCount = rDoc.GetTableCount();
3840 for (SCTAB nTab = 0; nTab < nTabCount; nTab++)
3842 if (rDoc.HasCalcNotification(nTab))
3844 if (const ScSheetEvents* pEvents = rDoc.GetSheetEvents( nTab ))
3846 if (const OUString* pScript = pEvents->GetScript(ScSheetEventId::CALCULATE))
3848 uno::Any aRet;
3849 uno::Sequence<uno::Any> aParams;
3850 uno::Sequence<sal_Int16> aOutArgsIndex;
3851 uno::Sequence<uno::Any> aOutArgs;
3852 pDocShell->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
3858 uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( rDoc.GetVbaEventProcessor(), uno::UNO_SET_THROW );
3859 uno::Sequence< uno::Any > aArgs{ uno::Any(nTab) };
3860 xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( ScSheetEventId::CALCULATE ), aArgs );
3862 catch( uno::Exception& )
3868 rDoc.ResetCalcNotifications();
3871 // XOpenCLSelection
3873 sal_Bool ScModelObj::isOpenCLEnabled()
3875 return ScCalcConfig::isOpenCLEnabled();
3878 void ScModelObj::enableOpenCL(sal_Bool bEnable)
3880 if (ScCalcConfig::isOpenCLEnabled() == static_cast<bool>(bEnable))
3881 return;
3882 if (ScCalcConfig::getForceCalculationType() != ForceCalculationNone)
3883 return;
3885 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
3886 officecfg::Office::Common::Misc::UseOpenCL::set(bEnable, batch);
3887 batch->commit();
3889 ScCalcConfig aConfig = ScInterpreter::GetGlobalConfig();
3890 if (bEnable)
3891 aConfig.setOpenCLConfigToDefault();
3892 ScInterpreter::SetGlobalConfig(aConfig);
3894 #if HAVE_FEATURE_OPENCL
3895 sc::FormulaGroupInterpreter::switchOpenCLDevice(u"", true);
3896 #endif
3898 ScDocument* pDoc = GetDocument();
3899 pDoc->CheckVectorizationState();
3903 void ScModelObj::enableAutomaticDeviceSelection(sal_Bool bForce)
3905 ScCalcConfig aConfig = ScInterpreter::GetGlobalConfig();
3906 aConfig.mbOpenCLAutoSelect = true;
3907 ScInterpreter::SetGlobalConfig(aConfig);
3908 ScModule* mod = ScModule::get();
3909 ScFormulaOptions aOptions = mod->GetFormulaOptions();
3910 aOptions.SetCalcConfig(aConfig);
3911 mod->SetFormulaOptions(aOptions);
3912 #if !HAVE_FEATURE_OPENCL
3913 (void) bForce;
3914 #else
3915 sc::FormulaGroupInterpreter::switchOpenCLDevice(u"", true, bForce);
3916 #endif
3919 void ScModelObj::disableAutomaticDeviceSelection()
3921 ScCalcConfig aConfig = ScInterpreter::GetGlobalConfig();
3922 aConfig.mbOpenCLAutoSelect = false;
3923 ScInterpreter::SetGlobalConfig(aConfig);
3924 ScModule* mod = ScModule::get();
3925 ScFormulaOptions aOptions = mod->GetFormulaOptions();
3926 aOptions.SetCalcConfig(aConfig);
3927 mod->SetFormulaOptions(aOptions);
3930 void ScModelObj::selectOpenCLDevice( sal_Int32 nPlatform, sal_Int32 nDevice )
3932 if(nPlatform < 0 || nDevice < 0)
3933 throw uno::RuntimeException();
3935 #if !HAVE_FEATURE_OPENCL
3936 throw uno::RuntimeException();
3937 #else
3938 std::vector<OpenCLPlatformInfo> aPlatformInfo;
3939 sc::FormulaGroupInterpreter::fillOpenCLInfo(aPlatformInfo);
3940 if(o3tl::make_unsigned(nPlatform) >= aPlatformInfo.size())
3941 throw uno::RuntimeException();
3943 if(o3tl::make_unsigned(nDevice) >= aPlatformInfo[nPlatform].maDevices.size())
3944 throw uno::RuntimeException();
3946 OUString aDeviceString = aPlatformInfo[nPlatform].maVendor + " " + aPlatformInfo[nPlatform].maDevices[nDevice].maName;
3947 sc::FormulaGroupInterpreter::switchOpenCLDevice(aDeviceString, false);
3948 #endif
3951 sal_Int32 ScModelObj::getPlatformID()
3953 #if !HAVE_FEATURE_OPENCL
3954 return -1;
3955 #else
3956 sal_Int32 nPlatformId;
3957 sal_Int32 nDeviceId;
3958 sc::FormulaGroupInterpreter::getOpenCLDeviceInfo(nDeviceId, nPlatformId);
3959 return nPlatformId;
3960 #endif
3963 sal_Int32 ScModelObj::getDeviceID()
3965 #if !HAVE_FEATURE_OPENCL
3966 return -1;
3967 #else
3968 sal_Int32 nPlatformId;
3969 sal_Int32 nDeviceId;
3970 sc::FormulaGroupInterpreter::getOpenCLDeviceInfo(nDeviceId, nPlatformId);
3971 return nDeviceId;
3972 #endif
3975 uno::Sequence< sheet::opencl::OpenCLPlatform > ScModelObj::getOpenCLPlatforms()
3977 #if !HAVE_FEATURE_OPENCL
3978 return uno::Sequence<sheet::opencl::OpenCLPlatform>();
3979 #else
3980 std::vector<OpenCLPlatformInfo> aPlatformInfo;
3981 sc::FormulaGroupInterpreter::fillOpenCLInfo(aPlatformInfo);
3983 uno::Sequence<sheet::opencl::OpenCLPlatform> aRet(aPlatformInfo.size());
3984 auto aRetRange = asNonConstRange(aRet);
3985 for(size_t i = 0; i < aPlatformInfo.size(); ++i)
3987 aRetRange[i].Name = aPlatformInfo[i].maName;
3988 aRetRange[i].Vendor = aPlatformInfo[i].maVendor;
3990 aRetRange[i].Devices.realloc(aPlatformInfo[i].maDevices.size());
3991 auto pDevices = aRetRange[i].Devices.getArray();
3992 for(size_t j = 0; j < aPlatformInfo[i].maDevices.size(); ++j)
3994 const OpenCLDeviceInfo& rDevice = aPlatformInfo[i].maDevices[j];
3995 pDevices[j].Name = rDevice.maName;
3996 pDevices[j].Vendor = rDevice.maVendor;
3997 pDevices[j].Driver = rDevice.maDriver;
4001 return aRet;
4002 #endif
4005 namespace {
4007 /// @throws css::uno::RuntimeException
4008 void setOpcodeSubsetTest(bool bFlag)
4010 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
4011 officecfg::Office::Calc::Formula::Calculation::OpenCLSubsetOnly::set(bFlag, batch);
4012 batch->commit();
4017 void ScModelObj::enableOpcodeSubsetTest()
4019 setOpcodeSubsetTest(true);
4022 void ScModelObj::disableOpcodeSubsetTest()
4024 setOpcodeSubsetTest(false);
4027 sal_Bool ScModelObj::isOpcodeSubsetTested()
4029 return officecfg::Office::Calc::Formula::Calculation::OpenCLSubsetOnly::get();
4032 void ScModelObj::setFormulaCellNumberLimit( sal_Int32 number )
4034 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
4035 officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::set(number, batch);
4036 batch->commit();
4039 sal_Int32 ScModelObj::getFormulaCellNumberLimit()
4041 return officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::get();
4044 ScDrawPagesObj::ScDrawPagesObj(ScDocShell* pDocSh) :
4045 pDocShell( pDocSh )
4047 pDocShell->GetDocument().AddUnoObject(*this);
4050 ScDrawPagesObj::~ScDrawPagesObj()
4052 SolarMutexGuard g;
4054 if (pDocShell)
4055 pDocShell->GetDocument().RemoveUnoObject(*this);
4058 void ScDrawPagesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
4060 // we don't care about update of references here
4062 if ( rHint.GetId() == SfxHintId::Dying )
4064 pDocShell = nullptr; // became invalid
4068 uno::Reference<drawing::XDrawPage> ScDrawPagesObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
4070 if (pDocShell)
4072 ScDrawLayer* pDrawLayer = pDocShell->MakeDrawLayer();
4073 OSL_ENSURE(pDrawLayer,"Cannot create Draw-Layer");
4074 if ( pDrawLayer && nIndex >= 0 && nIndex < pDocShell->GetDocument().GetTableCount() )
4076 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nIndex));
4077 OSL_ENSURE(pPage,"Draw-Page not found");
4078 if (pPage)
4080 return uno::Reference<drawing::XDrawPage> (pPage->getUnoPage(), uno::UNO_QUERY);
4084 return nullptr;
4087 // XDrawPages
4089 uno::Reference<drawing::XDrawPage> SAL_CALL ScDrawPagesObj::insertNewByIndex( sal_Int32 nPos )
4091 SolarMutexGuard aGuard;
4092 uno::Reference<drawing::XDrawPage> xRet;
4093 if (pDocShell)
4095 OUString aNewName;
4096 pDocShell->GetDocument().CreateValidTabName(aNewName);
4097 if ( pDocShell->GetDocFunc().InsertTable( static_cast<SCTAB>(nPos),
4098 aNewName, true, true ) )
4099 xRet.set(GetObjectByIndex_Impl( nPos ));
4101 return xRet;
4104 void SAL_CALL ScDrawPagesObj::remove( const uno::Reference<drawing::XDrawPage>& xPage )
4106 SolarMutexGuard aGuard;
4107 SvxDrawPage* pImp = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
4108 if ( pDocShell && pImp )
4110 SdrPage* pPage = pImp->GetSdrPage();
4111 if (pPage)
4113 SCTAB nPageNum = static_cast<SCTAB>(pPage->GetPageNum());
4114 pDocShell->GetDocFunc().DeleteTable( nPageNum, true );
4119 // XIndexAccess
4121 sal_Int32 SAL_CALL ScDrawPagesObj::getCount()
4123 SolarMutexGuard aGuard;
4124 if (pDocShell)
4125 return pDocShell->GetDocument().GetTableCount();
4126 return 0;
4129 uno::Any SAL_CALL ScDrawPagesObj::getByIndex( sal_Int32 nIndex )
4131 SolarMutexGuard aGuard;
4132 uno::Reference<drawing::XDrawPage> xPage(GetObjectByIndex_Impl(nIndex));
4133 if (!xPage.is())
4134 throw lang::IndexOutOfBoundsException();
4136 return uno::Any(xPage);
4139 uno::Type SAL_CALL ScDrawPagesObj::getElementType()
4141 return cppu::UnoType<drawing::XDrawPage>::get();
4144 sal_Bool SAL_CALL ScDrawPagesObj::hasElements()
4146 SolarMutexGuard aGuard;
4147 return ( getCount() != 0 );
4150 ScTableSheetsObj::ScTableSheetsObj(ScDocShell* pDocSh) :
4151 pDocShell( pDocSh )
4153 pDocShell->GetDocument().AddUnoObject(*this);
4156 ScTableSheetsObj::~ScTableSheetsObj()
4158 SolarMutexGuard g;
4160 if (pDocShell)
4161 pDocShell->GetDocument().RemoveUnoObject(*this);
4164 void ScTableSheetsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
4166 // we don't care about update of references here
4168 if ( rHint.GetId() == SfxHintId::Dying )
4170 pDocShell = nullptr; // became invalid
4174 // XSpreadsheets
4176 rtl::Reference<ScTableSheetObj> ScTableSheetsObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
4178 if ( pDocShell && nIndex >= 0 && nIndex < pDocShell->GetDocument().GetTableCount() )
4179 return new ScTableSheetObj( pDocShell, static_cast<SCTAB>(nIndex) );
4181 return nullptr;
4184 rtl::Reference<ScTableSheetObj> ScTableSheetsObj::GetObjectByName_Impl(const OUString& aName) const
4186 if (pDocShell)
4188 SCTAB nIndex;
4189 if ( pDocShell->GetDocument().GetTable( aName, nIndex ) )
4190 return new ScTableSheetObj( pDocShell, nIndex );
4192 return nullptr;
4195 void SAL_CALL ScTableSheetsObj::insertNewByName( const OUString& aName, sal_Int16 nPosition )
4197 SolarMutexGuard aGuard;
4198 bool bDone = false;
4199 if (pDocShell)
4201 bDone = pDocShell->GetDocFunc().InsertTable( nPosition, aName, true, true );
4203 if (!bDone)
4204 throw uno::RuntimeException(u"ScTableSheetsObj::insertNewByName(): Illegal object name or bad index. Duplicate name?"_ustr); // no other exceptions specified
4207 void SAL_CALL ScTableSheetsObj::moveByName( const OUString& aName, sal_Int16 nDestination )
4209 SolarMutexGuard aGuard;
4210 bool bDone = false;
4211 if (pDocShell)
4213 SCTAB nSource;
4214 if ( pDocShell->GetDocument().GetTable( aName, nSource ) )
4215 bDone = pDocShell->MoveTable( nSource, nDestination, false, true );
4217 if (!bDone)
4218 throw uno::RuntimeException(); // no other exceptions specified
4221 void SAL_CALL ScTableSheetsObj::copyByName( const OUString& aName,
4222 const OUString& aCopy, sal_Int16 nDestination )
4224 SolarMutexGuard aGuard;
4225 bool bDone = false;
4226 if (pDocShell)
4228 SCTAB nSource;
4229 if ( pDocShell->GetDocument().GetTable( aName, nSource ) )
4231 bDone = pDocShell->MoveTable( nSource, nDestination, true, true );
4232 if (bDone)
4234 // #i92477# any index past the last sheet means "append" in MoveTable
4235 SCTAB nResultTab = static_cast<SCTAB>(nDestination);
4236 SCTAB nTabCount = pDocShell->GetDocument().GetTableCount(); // count after copying
4237 if (nResultTab >= nTabCount)
4238 nResultTab = nTabCount - 1;
4240 bDone = pDocShell->GetDocFunc().RenameTable( nResultTab, aCopy,
4241 true, true );
4245 if (!bDone)
4246 throw uno::RuntimeException(u"ScTableSheetsObj::copyByName(): Illegal object name or bad index. Duplicate name?"_ustr); // no other exceptions specified
4249 void SAL_CALL ScTableSheetsObj::insertByName( const OUString& aName, const uno::Any& aElement )
4251 SolarMutexGuard aGuard;
4252 bool bDone = false;
4253 bool bIllArg = false;
4255 //! Type of aElement can be some specific interface instead of XInterface
4257 if ( pDocShell )
4259 uno::Reference<uno::XInterface> xInterface(aElement, uno::UNO_QUERY);
4260 if ( xInterface.is() )
4262 ScTableSheetObj* pSheetObj = dynamic_cast<ScTableSheetObj*>( xInterface.get() );
4263 if ( pSheetObj && !pSheetObj->GetDocShell() ) // not inserted yet?
4265 ScDocument& rDoc = pDocShell->GetDocument();
4266 SCTAB nDummy;
4267 if ( rDoc.GetTable( aName, nDummy ) )
4269 // name already exists
4270 throw container::ElementExistException();
4272 SCTAB nPosition = rDoc.GetTableCount();
4273 bDone = pDocShell->GetDocFunc().InsertTable( nPosition, aName,
4274 true, true );
4275 if (bDone)
4276 pSheetObj->InitInsertSheet( pDocShell, nPosition );
4277 // set document and new range in the object
4279 else
4280 bIllArg = true;
4282 else
4283 bIllArg = true;
4286 if (!bDone)
4288 if (bIllArg)
4289 throw lang::IllegalArgumentException();
4290 else
4291 throw uno::RuntimeException(); // ElementExistException is handled above
4295 void SAL_CALL ScTableSheetsObj::replaceByName( const OUString& aName, const uno::Any& aElement )
4297 SolarMutexGuard aGuard;
4298 bool bDone = false;
4299 bool bIllArg = false;
4301 //! Type of aElement can be some specific interface instead of XInterface
4303 if ( pDocShell )
4305 uno::Reference<uno::XInterface> xInterface(aElement, uno::UNO_QUERY);
4306 if ( xInterface.is() )
4308 ScTableSheetObj* pSheetObj = dynamic_cast<ScTableSheetObj*>( xInterface.get() );
4309 if ( pSheetObj && !pSheetObj->GetDocShell() ) // not inserted yet?
4311 SCTAB nPosition;
4312 if ( !pDocShell->GetDocument().GetTable( aName, nPosition ) )
4314 // not found
4315 throw container::NoSuchElementException();
4318 if ( pDocShell->GetDocFunc().DeleteTable( nPosition, true ) )
4320 // InsertTable can't really go wrong now
4321 bDone = pDocShell->GetDocFunc().InsertTable( nPosition, aName, true, true );
4322 if (bDone)
4323 pSheetObj->InitInsertSheet( pDocShell, nPosition );
4327 else
4328 bIllArg = true;
4330 else
4331 bIllArg = true;
4334 if (!bDone)
4336 if (bIllArg)
4337 throw lang::IllegalArgumentException();
4338 else
4339 throw uno::RuntimeException(); // NoSuchElementException is handled above
4343 void SAL_CALL ScTableSheetsObj::removeByName( const OUString& aName )
4345 SolarMutexGuard aGuard;
4346 bool bDone = false;
4347 if (pDocShell)
4349 SCTAB nIndex;
4350 if ( !pDocShell->GetDocument().GetTable( aName, nIndex ) )
4351 throw container::NoSuchElementException(); // not found
4352 bDone = pDocShell->GetDocFunc().DeleteTable( nIndex, true );
4355 if (!bDone)
4356 throw uno::RuntimeException(); // NoSuchElementException is handled above
4359 sal_Int32 ScTableSheetsObj::importSheet(
4360 const uno::Reference < sheet::XSpreadsheetDocument > & xDocSrc,
4361 const OUString& srcName, const sal_Int32 nDestPosition )
4363 //pDocShell is the destination
4364 ScDocument& rDocDest = pDocShell->GetDocument();
4366 // Source document docShell
4367 if ( !xDocSrc.is() )
4368 throw uno::RuntimeException();
4369 ScModelObj* pObj = comphelper::getFromUnoTunnel<ScModelObj>(xDocSrc);
4370 ScDocShell* pDocShellSrc = static_cast<ScDocShell*>(pObj->GetEmbeddedObject());
4372 // SourceSheet Position and does srcName exists ?
4373 SCTAB nIndexSrc;
4374 if ( !pDocShellSrc->GetDocument().GetTable( srcName, nIndexSrc ) )
4375 throw lang::IllegalArgumentException();
4377 // Check the validity of destination index.
4378 SCTAB nCount = rDocDest.GetTableCount();
4379 SCTAB nIndexDest = static_cast<SCTAB>(nDestPosition);
4380 if (nIndexDest > nCount || nIndexDest < 0)
4381 throw lang::IndexOutOfBoundsException();
4383 // Transfer Tab
4384 pDocShell->TransferTab(
4385 *pDocShellSrc, nIndexSrc, nIndexDest, true/*bInsertNew*/, true/*bNotifyAndPaint*/ );
4387 return nIndexDest;
4390 // XCellRangesAccess
4392 uno::Reference< table::XCell > SAL_CALL ScTableSheetsObj::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow, sal_Int32 nSheet )
4394 SolarMutexGuard aGuard;
4395 rtl::Reference<ScTableSheetObj> xSheet = GetObjectByIndex_Impl(static_cast<sal_uInt16>(nSheet));
4396 if (! xSheet.is())
4397 throw lang::IndexOutOfBoundsException();
4399 return xSheet->getCellByPosition(nColumn, nRow);
4402 uno::Reference< table::XCellRange > SAL_CALL ScTableSheetsObj::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom, sal_Int32 nSheet )
4404 SolarMutexGuard aGuard;
4405 rtl::Reference<ScTableSheetObj> xSheet = GetObjectByIndex_Impl(static_cast<sal_uInt16>(nSheet));
4406 if (! xSheet.is())
4407 throw lang::IndexOutOfBoundsException();
4409 return xSheet->getCellRangeByPosition(nLeft, nTop, nRight, nBottom);
4412 uno::Sequence < uno::Reference< table::XCellRange > > SAL_CALL ScTableSheetsObj::getCellRangesByName( const OUString& aRange )
4414 SolarMutexGuard aGuard;
4415 uno::Sequence < uno::Reference < table::XCellRange > > xRet;
4417 ScRangeList aRangeList;
4418 ScDocument& rDoc = pDocShell->GetDocument();
4419 if (!ScRangeStringConverter::GetRangeListFromString( aRangeList, aRange, rDoc, ::formula::FormulaGrammar::CONV_OOO, ';' ))
4420 throw lang::IllegalArgumentException();
4422 size_t nCount = aRangeList.size();
4423 if (!nCount)
4424 throw lang::IllegalArgumentException();
4426 xRet.realloc(nCount);
4427 auto pRet = xRet.getArray();
4428 for( size_t nIndex = 0; nIndex < nCount; nIndex++ )
4430 const ScRange & rRange = aRangeList[ nIndex ];
4431 pRet[nIndex] = new ScCellRangeObj(pDocShell, rRange);
4434 return xRet;
4437 // XEnumerationAccess
4439 uno::Reference<container::XEnumeration> SAL_CALL ScTableSheetsObj::createEnumeration()
4441 SolarMutexGuard aGuard;
4442 return new ScIndexEnumeration(this, u"com.sun.star.sheet.SpreadsheetsEnumeration"_ustr);
4445 // XIndexAccess
4447 sal_Int32 SAL_CALL ScTableSheetsObj::getCount()
4449 SolarMutexGuard aGuard;
4450 if (pDocShell)
4451 return pDocShell->GetDocument().GetTableCount();
4452 return 0;
4455 uno::Any SAL_CALL ScTableSheetsObj::getByIndex( sal_Int32 nIndex )
4457 SolarMutexGuard aGuard;
4458 uno::Reference<sheet::XSpreadsheet> xSheet(GetObjectByIndex_Impl(nIndex));
4459 if (!xSheet.is())
4460 throw lang::IndexOutOfBoundsException();
4462 return uno::Any(xSheet);
4464 // return uno::Any();
4467 uno::Type SAL_CALL ScTableSheetsObj::getElementType()
4469 return cppu::UnoType<sheet::XSpreadsheet>::get();
4472 sal_Bool SAL_CALL ScTableSheetsObj::hasElements()
4474 SolarMutexGuard aGuard;
4475 return ( getCount() != 0 );
4478 // XNameAccess
4480 uno::Any SAL_CALL ScTableSheetsObj::getByName( const OUString& aName )
4482 SolarMutexGuard aGuard;
4483 uno::Reference<sheet::XSpreadsheet> xSheet(GetObjectByName_Impl(aName));
4484 if (!xSheet.is())
4485 throw container::NoSuchElementException();
4487 return uno::Any(xSheet);
4490 uno::Sequence<OUString> SAL_CALL ScTableSheetsObj::getElementNames()
4492 SolarMutexGuard aGuard;
4493 if (pDocShell)
4495 ScDocument& rDoc = pDocShell->GetDocument();
4496 SCTAB nCount = rDoc.GetTableCount();
4497 OUString aName;
4498 uno::Sequence<OUString> aSeq(nCount);
4499 OUString* pAry = aSeq.getArray();
4500 for (SCTAB i=0; i<nCount; i++)
4502 rDoc.GetName( i, aName );
4503 pAry[i] = aName;
4505 return aSeq;
4507 return uno::Sequence<OUString>();
4510 sal_Bool SAL_CALL ScTableSheetsObj::hasByName( const OUString& aName )
4512 SolarMutexGuard aGuard;
4513 if (pDocShell)
4515 SCTAB nIndex;
4516 if ( pDocShell->GetDocument().GetTable( aName, nIndex ) )
4517 return true;
4519 return false;
4522 ScTableColumnsObj::ScTableColumnsObj(ScDocShell* pDocSh, SCTAB nT, SCCOL nSC, SCCOL nEC) :
4523 pDocShell( pDocSh ),
4524 nTab ( nT ),
4525 nStartCol( nSC ),
4526 nEndCol ( nEC )
4528 pDocShell->GetDocument().AddUnoObject(*this);
4531 ScTableColumnsObj::~ScTableColumnsObj()
4533 SolarMutexGuard g;
4535 if (pDocShell)
4536 pDocShell->GetDocument().RemoveUnoObject(*this);
4539 void ScTableColumnsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
4541 if ( rHint.GetId() == SfxHintId::ScUpdateRef )
4543 //! update of references for sheet and its start/end
4545 else if ( rHint.GetId() == SfxHintId::Dying )
4547 pDocShell = nullptr; // became invalid
4551 // XTableColumns
4553 rtl::Reference<ScTableColumnObj> ScTableColumnsObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
4555 SCCOL nCol = static_cast<SCCOL>(nIndex) + nStartCol;
4556 if ( pDocShell && nCol <= nEndCol )
4557 return new ScTableColumnObj( pDocShell, nCol, nTab );
4559 return nullptr; // wrong index
4562 rtl::Reference<ScTableColumnObj> ScTableColumnsObj::GetObjectByName_Impl(std::u16string_view aName) const
4564 SCCOL nCol = 0;
4565 if (pDocShell && ::AlphaToCol(pDocShell->GetDocument(), nCol, aName))
4566 if (nCol >= nStartCol && nCol <= nEndCol)
4567 return new ScTableColumnObj( pDocShell, nCol, nTab );
4569 return nullptr;
4572 void SAL_CALL ScTableColumnsObj::insertByIndex( sal_Int32 nPosition, sal_Int32 nCount )
4574 SolarMutexGuard aGuard;
4575 bool bDone = false;
4576 if ( pDocShell )
4578 const ScDocument& rDoc = pDocShell->GetDocument();
4579 if ( nCount > 0 && nPosition >= 0 && nStartCol+nPosition <= nEndCol &&
4580 nStartCol+nPosition+nCount-1 <= rDoc.MaxCol() )
4582 ScRange aRange( static_cast<SCCOL>(nStartCol+nPosition), 0, nTab,
4583 static_cast<SCCOL>(nStartCol+nPosition+nCount-1), rDoc.MaxRow(), nTab );
4584 bDone = pDocShell->GetDocFunc().InsertCells( aRange, nullptr, INS_INSCOLS_BEFORE, true, true );
4587 if (!bDone)
4588 throw uno::RuntimeException(); // no other exceptions specified
4591 void SAL_CALL ScTableColumnsObj::removeByIndex( sal_Int32 nIndex, sal_Int32 nCount )
4593 SolarMutexGuard aGuard;
4594 bool bDone = false;
4595 // the range to be deleted has to lie within the object
4596 if ( pDocShell )
4598 const ScDocument& rDoc = pDocShell->GetDocument();
4599 if ( nCount > 0 && nIndex >= 0 && nStartCol+nIndex+nCount-1 <= nEndCol )
4601 ScRange aRange( static_cast<SCCOL>(nStartCol+nIndex), 0, nTab,
4602 static_cast<SCCOL>(nStartCol+nIndex+nCount-1), rDoc.MaxRow(), nTab );
4603 bDone = pDocShell->GetDocFunc().DeleteCells( aRange, nullptr, DelCellCmd::Cols, true );
4606 if (!bDone)
4607 throw uno::RuntimeException(); // no other exceptions specified
4610 // XEnumerationAccess
4612 uno::Reference<container::XEnumeration> SAL_CALL ScTableColumnsObj::createEnumeration()
4614 SolarMutexGuard aGuard;
4615 return new ScIndexEnumeration(this, u"com.sun.star.table.TableColumnsEnumeration"_ustr);
4618 // XIndexAccess
4620 sal_Int32 SAL_CALL ScTableColumnsObj::getCount()
4622 SolarMutexGuard aGuard;
4623 return nEndCol - nStartCol + 1;
4626 uno::Any SAL_CALL ScTableColumnsObj::getByIndex( sal_Int32 nIndex )
4628 SolarMutexGuard aGuard;
4629 uno::Reference<table::XCellRange> xColumn(GetObjectByIndex_Impl(nIndex));
4630 if (!xColumn.is())
4631 throw lang::IndexOutOfBoundsException();
4633 return uno::Any(xColumn);
4637 uno::Type SAL_CALL ScTableColumnsObj::getElementType()
4639 return cppu::UnoType<table::XCellRange>::get();
4642 sal_Bool SAL_CALL ScTableColumnsObj::hasElements()
4644 SolarMutexGuard aGuard;
4645 return ( getCount() != 0 );
4648 uno::Any SAL_CALL ScTableColumnsObj::getByName( const OUString& aName )
4650 SolarMutexGuard aGuard;
4651 uno::Reference<table::XCellRange> xColumn(GetObjectByName_Impl(aName));
4652 if (!xColumn.is())
4653 throw container::NoSuchElementException();
4655 return uno::Any(xColumn);
4658 uno::Sequence<OUString> SAL_CALL ScTableColumnsObj::getElementNames()
4660 SolarMutexGuard aGuard;
4661 SCCOL nCount = nEndCol - nStartCol + 1;
4662 uno::Sequence<OUString> aSeq(nCount);
4663 OUString* pAry = aSeq.getArray();
4664 for (SCCOL i=0; i<nCount; i++)
4665 pAry[i] = ::ScColToAlpha( nStartCol + i );
4667 return aSeq;
4670 sal_Bool SAL_CALL ScTableColumnsObj::hasByName( const OUString& aName )
4672 SolarMutexGuard aGuard;
4673 SCCOL nCol = 0;
4674 if (pDocShell && ::AlphaToCol(pDocShell->GetDocument(), nCol, aName))
4675 if (nCol >= nStartCol && nCol <= nEndCol)
4676 return true;
4678 return false; // not found
4681 // XPropertySet
4683 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableColumnsObj::getPropertySetInfo()
4685 static uno::Reference<beans::XPropertySetInfo> aRef(
4686 new SfxItemPropertySetInfo( lcl_GetColumnsPropertyMap() ));
4687 return aRef;
4690 void SAL_CALL ScTableColumnsObj::setPropertyValue(
4691 const OUString& aPropertyName, const uno::Any& aValue )
4693 SolarMutexGuard aGuard;
4694 if (!pDocShell)
4695 throw uno::RuntimeException();
4697 std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(nStartCol,nEndCol));
4698 ScDocFunc& rFunc = pDocShell->GetDocFunc();
4700 if ( aPropertyName == SC_UNONAME_CELLWID )
4702 sal_Int32 nNewWidth = 0;
4703 if ( aValue >>= nNewWidth )
4704 rFunc.SetWidthOrHeight(
4705 true, aColArr, nTab, SC_SIZE_ORIGINAL, o3tl::toTwips(nNewWidth, o3tl::Length::mm100), true, true);
4707 else if ( aPropertyName == SC_UNONAME_CELLVIS )
4709 bool bVis = ScUnoHelpFunctions::GetBoolFromAny( aValue );
4710 ScSizeMode eMode = bVis ? SC_SIZE_SHOW : SC_SIZE_DIRECT;
4711 rFunc.SetWidthOrHeight(true, aColArr, nTab, eMode, 0, true, true);
4712 // SC_SIZE_DIRECT with size 0: hide
4714 else if ( aPropertyName == SC_UNONAME_OWIDTH )
4716 bool bOpt = ScUnoHelpFunctions::GetBoolFromAny( aValue );
4717 if (bOpt)
4718 rFunc.SetWidthOrHeight(
4719 true, aColArr, nTab, SC_SIZE_OPTIMAL, STD_EXTRA_WIDTH, true, true);
4720 // sal_False for columns currently has no effect
4722 else if ( aPropertyName == SC_UNONAME_NEWPAGE || aPropertyName == SC_UNONAME_MANPAGE )
4724 //! single function to set/remove all breaks?
4725 bool bSet = ScUnoHelpFunctions::GetBoolFromAny( aValue );
4726 for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
4727 if (bSet)
4728 rFunc.InsertPageBreak( true, ScAddress(nCol,0,nTab), true, true );
4729 else
4730 rFunc.RemovePageBreak( true, ScAddress(nCol,0,nTab), true, true );
4734 uno::Any SAL_CALL ScTableColumnsObj::getPropertyValue( const OUString& aPropertyName )
4736 SolarMutexGuard aGuard;
4737 if (!pDocShell)
4738 throw uno::RuntimeException();
4740 ScDocument& rDoc = pDocShell->GetDocument();
4741 uno::Any aAny;
4743 //! loop over all columns for current state?
4745 if ( aPropertyName == SC_UNONAME_CELLWID )
4747 // for hidden column, return original height
4748 sal_uInt16 nWidth = rDoc.GetOriginalWidth( nStartCol, nTab );
4749 aAny <<= static_cast<sal_Int32>(convertTwipToMm100(nWidth));
4751 else if ( aPropertyName == SC_UNONAME_CELLVIS )
4753 bool bVis = !rDoc.ColHidden(nStartCol, nTab);
4754 aAny <<= bVis;
4756 else if ( aPropertyName == SC_UNONAME_OWIDTH )
4758 bool bOpt = !(rDoc.GetColFlags( nStartCol, nTab ) & CRFlags::ManualSize);
4759 aAny <<= bOpt;
4761 else if ( aPropertyName == SC_UNONAME_NEWPAGE )
4763 ScBreakType nBreak = rDoc.HasColBreak(nStartCol, nTab);
4764 aAny <<= (nBreak != ScBreakType::NONE);
4766 else if ( aPropertyName == SC_UNONAME_MANPAGE )
4768 ScBreakType nBreak = rDoc.HasColBreak(nStartCol, nTab);
4769 aAny <<= bool(nBreak & ScBreakType::Manual);
4772 return aAny;
4775 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScTableColumnsObj )
4777 ScTableRowsObj::ScTableRowsObj(ScDocShell* pDocSh, SCTAB nT, SCROW nSR, SCROW nER) :
4778 pDocShell( pDocSh ),
4779 nTab ( nT ),
4780 nStartRow( nSR ),
4781 nEndRow ( nER )
4783 pDocShell->GetDocument().AddUnoObject(*this);
4786 ScTableRowsObj::~ScTableRowsObj()
4788 SolarMutexGuard g;
4790 if (pDocShell)
4791 pDocShell->GetDocument().RemoveUnoObject(*this);
4794 void ScTableRowsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
4796 if ( rHint.GetId() == SfxHintId::ScUpdateRef )
4798 //! update of references for sheet and its start/end
4800 else if ( rHint.GetId() == SfxHintId::Dying )
4802 pDocShell = nullptr; // became invalid
4806 // XTableRows
4808 rtl::Reference<ScTableRowObj> ScTableRowsObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
4810 SCROW nRow = static_cast<SCROW>(nIndex) + nStartRow;
4811 if ( pDocShell && nRow <= nEndRow )
4812 return new ScTableRowObj( pDocShell, nRow, nTab );
4814 return nullptr; // wrong index
4817 void SAL_CALL ScTableRowsObj::insertByIndex( sal_Int32 nPosition, sal_Int32 nCount )
4819 SolarMutexGuard aGuard;
4820 bool bDone = false;
4821 if ( pDocShell )
4823 const ScDocument& rDoc = pDocShell->GetDocument();
4824 if ( nCount > 0 && nPosition >= 0 && nStartRow+nPosition <= nEndRow &&
4825 nStartRow+nPosition+nCount-1 <= rDoc.MaxRow() )
4827 ScRange aRange( 0, static_cast<SCROW>(nStartRow+nPosition), nTab,
4828 rDoc.MaxCol(), static_cast<SCROW>(nStartRow+nPosition+nCount-1), nTab );
4829 bDone = pDocShell->GetDocFunc().InsertCells( aRange, nullptr, INS_INSROWS_BEFORE, true, true );
4832 if (!bDone)
4833 throw uno::RuntimeException(); // no other exceptions specified
4836 void SAL_CALL ScTableRowsObj::removeByIndex( sal_Int32 nIndex, sal_Int32 nCount )
4838 SolarMutexGuard aGuard;
4839 bool bDone = false;
4840 // the range to be deleted has to lie within the object
4841 if ( pDocShell && nCount > 0 && nIndex >= 0 && nStartRow+nIndex+nCount-1 <= nEndRow )
4843 const ScDocument& rDoc = pDocShell->GetDocument();
4844 ScRange aRange( 0, static_cast<SCROW>(nStartRow+nIndex), nTab,
4845 rDoc.MaxCol(), static_cast<SCROW>(nStartRow+nIndex+nCount-1), nTab );
4846 bDone = pDocShell->GetDocFunc().DeleteCells( aRange, nullptr, DelCellCmd::Rows, true );
4848 if (!bDone)
4849 throw uno::RuntimeException(); // no other exceptions specified
4852 // XEnumerationAccess
4854 uno::Reference<container::XEnumeration> SAL_CALL ScTableRowsObj::createEnumeration()
4856 SolarMutexGuard aGuard;
4857 return new ScIndexEnumeration(this, u"com.sun.star.table.TableRowsEnumeration"_ustr);
4860 // XIndexAccess
4862 sal_Int32 SAL_CALL ScTableRowsObj::getCount()
4864 SolarMutexGuard aGuard;
4865 return nEndRow - nStartRow + 1;
4868 uno::Any SAL_CALL ScTableRowsObj::getByIndex( sal_Int32 nIndex )
4870 SolarMutexGuard aGuard;
4871 uno::Reference<table::XCellRange> xRow(GetObjectByIndex_Impl(nIndex));
4872 if (!xRow.is())
4873 throw lang::IndexOutOfBoundsException();
4875 return uno::Any(xRow);
4878 uno::Type SAL_CALL ScTableRowsObj::getElementType()
4880 return cppu::UnoType<table::XCellRange>::get();
4883 sal_Bool SAL_CALL ScTableRowsObj::hasElements()
4885 SolarMutexGuard aGuard;
4886 return ( getCount() != 0 );
4889 // XPropertySet
4891 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableRowsObj::getPropertySetInfo()
4893 static uno::Reference<beans::XPropertySetInfo> aRef(
4894 new SfxItemPropertySetInfo( lcl_GetRowsPropertyMap() ));
4895 return aRef;
4898 void SAL_CALL ScTableRowsObj::setPropertyValue(
4899 const OUString& aPropertyName, const uno::Any& aValue )
4901 SolarMutexGuard aGuard;
4902 if (!pDocShell)
4903 throw uno::RuntimeException();
4905 ScDocFunc& rFunc = pDocShell->GetDocFunc();
4906 ScDocument& rDoc = pDocShell->GetDocument();
4907 std::vector<sc::ColRowSpan> aRowArr(1, sc::ColRowSpan(nStartRow,nEndRow));
4909 if ( aPropertyName == SC_UNONAME_OHEIGHT )
4911 sal_Int32 nNewHeight = 0;
4912 if ( rDoc.IsImportingXML() && ( aValue >>= nNewHeight ) )
4914 // used to set the stored row height for rows with optimal height when loading.
4916 // TODO: It's probably cleaner to use a different property name
4917 // for this.
4918 rDoc.SetRowHeightOnly( nStartRow, nEndRow, nTab, o3tl::toTwips(nNewHeight, o3tl::Length::mm100) );
4920 else
4922 bool bOpt = ScUnoHelpFunctions::GetBoolFromAny( aValue );
4923 if (bOpt)
4924 rFunc.SetWidthOrHeight(false, aRowArr, nTab, SC_SIZE_OPTIMAL, 0, true, true);
4925 else
4927 //! manually set old heights again?
4931 else if ( aPropertyName == SC_UNONAME_CELLHGT )
4933 sal_Int32 nNewHeight = 0;
4934 if ( aValue >>= nNewHeight )
4936 if (rDoc.IsImportingXML())
4938 // TODO: This is a band-aid fix. Eventually we need to
4939 // re-work ods' style import to get it to set styles to
4940 // ScDocument directly.
4941 rDoc.SetRowHeightOnly( nStartRow, nEndRow, nTab, o3tl::toTwips(nNewHeight, o3tl::Length::mm100) );
4942 rDoc.SetManualHeight( nStartRow, nEndRow, nTab, true );
4944 else
4945 rFunc.SetWidthOrHeight(
4946 false, aRowArr, nTab, SC_SIZE_ORIGINAL, o3tl::toTwips(nNewHeight, o3tl::Length::mm100), true, true);
4949 else if ( aPropertyName == SC_UNONAME_CELLVIS )
4951 bool bVis = ScUnoHelpFunctions::GetBoolFromAny( aValue );
4952 ScSizeMode eMode = bVis ? SC_SIZE_SHOW : SC_SIZE_DIRECT;
4953 rFunc.SetWidthOrHeight(false, aRowArr, nTab, eMode, 0, true, true);
4954 // SC_SIZE_DIRECT with size 0: hide
4956 else if ( aPropertyName == SC_UNONAME_VISFLAG )
4958 // #i116460# Shortcut to only set the flag, without drawing layer update etc.
4959 // Should only be used from import filters.
4960 rDoc.SetRowHidden(nStartRow, nEndRow, nTab, !ScUnoHelpFunctions::GetBoolFromAny( aValue ));
4962 else if ( aPropertyName == SC_UNONAME_CELLFILT )
4964 //! undo etc.
4965 if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
4966 rDoc.SetRowFiltered(nStartRow, nEndRow, nTab, true);
4967 else
4968 rDoc.SetRowFiltered(nStartRow, nEndRow, nTab, false);
4970 else if ( aPropertyName == SC_UNONAME_NEWPAGE || aPropertyName == SC_UNONAME_MANPAGE )
4972 //! single function to set/remove all breaks?
4973 bool bSet = ScUnoHelpFunctions::GetBoolFromAny( aValue );
4974 for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
4975 if (bSet)
4976 rFunc.InsertPageBreak( false, ScAddress(0,nRow,nTab), true, true );
4977 else
4978 rFunc.RemovePageBreak( false, ScAddress(0,nRow,nTab), true, true );
4980 else if ( aPropertyName == SC_UNONAME_CELLBACK || aPropertyName == SC_UNONAME_CELLTRAN )
4982 // #i57867# Background color is specified for row styles in the file format,
4983 // so it has to be supported along with the row properties (import only).
4985 // Use ScCellRangeObj to set the property for all cells in the rows
4986 // (this means, the "row attribute" must be set before individual cell attributes).
4988 ScRange aRange( 0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab );
4989 uno::Reference<beans::XPropertySet> xRangeObj = new ScCellRangeObj( pDocShell, aRange );
4990 xRangeObj->setPropertyValue( aPropertyName, aValue );
4994 uno::Any SAL_CALL ScTableRowsObj::getPropertyValue( const OUString& aPropertyName )
4996 SolarMutexGuard aGuard;
4997 if (!pDocShell)
4998 throw uno::RuntimeException();
5000 ScDocument& rDoc = pDocShell->GetDocument();
5001 uno::Any aAny;
5003 //! loop over all rows for current state?
5005 if ( aPropertyName == SC_UNONAME_CELLHGT )
5007 // for hidden row, return original height
5008 sal_uInt16 nHeight = rDoc.GetOriginalHeight( nStartRow, nTab );
5009 aAny <<= static_cast<sal_Int32>(convertTwipToMm100(nHeight));
5011 else if ( aPropertyName == SC_UNONAME_CELLVIS )
5013 SCROW nLastRow;
5014 bool bVis = !rDoc.RowHidden(nStartRow, nTab, nullptr, &nLastRow);
5015 aAny <<= bVis;
5017 else if ( aPropertyName == SC_UNONAME_CELLFILT )
5019 bool bVis = rDoc.RowFiltered(nStartRow, nTab);
5020 aAny <<= bVis;
5022 else if ( aPropertyName == SC_UNONAME_OHEIGHT )
5024 bool bOpt = !(rDoc.GetRowFlags( nStartRow, nTab ) & CRFlags::ManualSize);
5025 aAny <<= bOpt;
5027 else if ( aPropertyName == SC_UNONAME_NEWPAGE )
5029 ScBreakType nBreak = rDoc.HasRowBreak(nStartRow, nTab);
5030 aAny <<= (nBreak != ScBreakType::NONE);
5032 else if ( aPropertyName == SC_UNONAME_MANPAGE )
5034 ScBreakType nBreak = rDoc.HasRowBreak(nStartRow, nTab);
5035 aAny <<= bool(nBreak & ScBreakType::Manual);
5037 else if ( aPropertyName == SC_UNONAME_CELLBACK || aPropertyName == SC_UNONAME_CELLTRAN )
5039 // Use ScCellRangeObj to get the property from the cell range
5040 // (for completeness only, this is not used by the XML filter).
5042 ScRange aRange( 0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab );
5043 uno::Reference<beans::XPropertySet> xRangeObj = new ScCellRangeObj( pDocShell, aRange );
5044 aAny = xRangeObj->getPropertyValue( aPropertyName );
5047 return aAny;
5050 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScTableRowsObj )
5052 ScSpreadsheetSettingsObj::~ScSpreadsheetSettingsObj()
5056 // XPropertySet
5058 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSpreadsheetSettingsObj::getPropertySetInfo()
5060 return nullptr;
5063 void SAL_CALL ScSpreadsheetSettingsObj::setPropertyValue(
5064 const OUString& /* aPropertyName */, const uno::Any& /* aValue */ )
5068 uno::Any SAL_CALL ScSpreadsheetSettingsObj::getPropertyValue( const OUString& /* aPropertyName */ )
5070 return uno::Any();
5073 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSpreadsheetSettingsObj )
5075 ScAnnotationsObj::ScAnnotationsObj(ScDocShell* pDocSh, SCTAB nT) :
5076 pDocShell( pDocSh ),
5077 nTab( nT )
5079 pDocShell->GetDocument().AddUnoObject(*this);
5082 ScAnnotationsObj::~ScAnnotationsObj()
5084 SolarMutexGuard g;
5086 if (pDocShell)
5087 pDocShell->GetDocument().RemoveUnoObject(*this);
5090 void ScAnnotationsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
5092 //! adjust nTab when updating references!!!
5094 if ( rHint.GetId() == SfxHintId::Dying )
5096 pDocShell = nullptr; // became invalid
5100 bool ScAnnotationsObj::GetAddressByIndex_Impl( sal_Int32 nIndex, ScAddress& rPos ) const
5102 if (!pDocShell)
5103 return false;
5105 ScDocument& rDoc = pDocShell->GetDocument();
5106 rPos = rDoc.GetNotePosition(nIndex, nTab);
5107 return rPos.IsValid();
5110 rtl::Reference<ScAnnotationObj> ScAnnotationsObj::GetObjectByIndex_Impl( sal_Int32 nIndex ) const
5112 if (pDocShell)
5114 ScAddress aPos;
5115 if ( GetAddressByIndex_Impl( nIndex, aPos ) )
5116 return new ScAnnotationObj( pDocShell, aPos );
5118 return nullptr;
5121 // XSheetAnnotations
5123 void SAL_CALL ScAnnotationsObj::insertNew(
5124 const table::CellAddress& aPosition, const OUString& rText )
5126 SolarMutexGuard aGuard;
5127 if (pDocShell)
5129 OSL_ENSURE( aPosition.Sheet == nTab, "addAnnotation with a wrong Sheet" );
5130 ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
5131 pDocShell->GetDocFunc().ReplaceNote( aPos, rText, nullptr, nullptr, true );
5135 void SAL_CALL ScAnnotationsObj::removeByIndex( sal_Int32 nIndex )
5137 SolarMutexGuard aGuard;
5138 if (pDocShell)
5140 ScAddress aPos;
5141 if ( GetAddressByIndex_Impl( nIndex, aPos ) )
5143 ScMarkData aMarkData(pDocShell->GetDocument().GetSheetLimits());
5144 aMarkData.SelectTable( aPos.Tab(), true );
5145 aMarkData.SetMultiMarkArea( ScRange(aPos) );
5147 pDocShell->GetDocFunc().DeleteContents( aMarkData, InsertDeleteFlags::NOTE, true, true );
5152 // XEnumerationAccess
5154 uno::Reference<container::XEnumeration> SAL_CALL ScAnnotationsObj::createEnumeration()
5156 //! iterate directly (more efficiently)?
5158 SolarMutexGuard aGuard;
5159 return new ScIndexEnumeration(this, u"com.sun.star.sheet.CellAnnotationsEnumeration"_ustr);
5162 // XIndexAccess
5164 sal_Int32 SAL_CALL ScAnnotationsObj::getCount()
5166 SolarMutexGuard aGuard;
5167 sal_Int32 nCount = 0;
5168 if (pDocShell)
5170 const ScDocument& rDoc = pDocShell->GetDocument();
5171 for (SCCOL nCol : rDoc.GetAllocatedColumnsRange(nTab, 0, rDoc.MaxCol()))
5172 nCount += rDoc.GetNoteCount(nTab, nCol);
5174 return nCount;
5177 uno::Any SAL_CALL ScAnnotationsObj::getByIndex( sal_Int32 nIndex )
5179 SolarMutexGuard aGuard;
5180 uno::Reference<sheet::XSheetAnnotation> xAnnotation(GetObjectByIndex_Impl(nIndex));
5181 if (!xAnnotation.is())
5182 throw lang::IndexOutOfBoundsException();
5184 return uno::Any(xAnnotation);
5187 uno::Type SAL_CALL ScAnnotationsObj::getElementType()
5189 return cppu::UnoType<sheet::XSheetAnnotation>::get();
5192 sal_Bool SAL_CALL ScAnnotationsObj::hasElements()
5194 SolarMutexGuard aGuard;
5195 return ( getCount() != 0 );
5198 ScScenariosObj::ScScenariosObj(ScDocShell* pDocSh, SCTAB nT) :
5199 pDocShell( pDocSh ),
5200 nTab ( nT )
5202 pDocShell->GetDocument().AddUnoObject(*this);
5205 ScScenariosObj::~ScScenariosObj()
5207 SolarMutexGuard g;
5209 if (pDocShell)
5210 pDocShell->GetDocument().RemoveUnoObject(*this);
5213 void ScScenariosObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
5215 if ( rHint.GetId() == SfxHintId::ScUpdateRef )
5217 //! update of references for sheet and its start/end
5219 else if ( rHint.GetId() == SfxHintId::Dying )
5221 pDocShell = nullptr; // became invalid
5225 // XScenarios
5227 bool ScScenariosObj::GetScenarioIndex_Impl( std::u16string_view rName, SCTAB& rIndex )
5229 //! Case-insensitive ????
5231 if ( pDocShell )
5233 OUString aTabName;
5234 ScDocument& rDoc = pDocShell->GetDocument();
5235 SCTAB nCount = static_cast<SCTAB>(getCount());
5236 for (SCTAB i=0; i<nCount; i++)
5237 if (rDoc.GetName( nTab+i+1, aTabName ))
5238 if (aTabName == rName)
5240 rIndex = i;
5241 return true;
5245 return false;
5248 rtl::Reference<ScTableSheetObj> ScScenariosObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
5250 sal_uInt16 nCount = static_cast<sal_uInt16>(getCount());
5251 if ( pDocShell && nIndex >= 0 && nIndex < nCount )
5252 return new ScTableSheetObj( pDocShell, nTab+static_cast<SCTAB>(nIndex)+1 );
5254 return nullptr; // no document or wrong index
5257 rtl::Reference<ScTableSheetObj> ScScenariosObj::GetObjectByName_Impl(std::u16string_view aName)
5259 SCTAB nIndex;
5260 if ( pDocShell && GetScenarioIndex_Impl( aName, nIndex ) )
5261 return new ScTableSheetObj( pDocShell, nTab+nIndex+1 );
5263 return nullptr; // not found
5266 void SAL_CALL ScScenariosObj::addNewByName( const OUString& aName,
5267 const uno::Sequence<table::CellRangeAddress>& aRanges,
5268 const OUString& aComment )
5270 SolarMutexGuard aGuard;
5271 if ( !pDocShell )
5272 return;
5274 ScMarkData aMarkData(pDocShell->GetDocument().GetSheetLimits());
5275 aMarkData.SelectTable( nTab, true );
5277 for (const table::CellRangeAddress& rRange : aRanges)
5279 OSL_ENSURE( rRange.Sheet == nTab, "addScenario with a wrong Tab" );
5280 ScRange aRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), nTab,
5281 static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), nTab );
5283 aMarkData.SetMultiMarkArea( aRange );
5286 ScScenarioFlags const nFlags = ScScenarioFlags::ShowFrame | ScScenarioFlags::PrintFrame
5287 | ScScenarioFlags::TwoWay | ScScenarioFlags::Protected;
5289 pDocShell->MakeScenario( nTab, aName, aComment, COL_LIGHTGRAY, nFlags, aMarkData );
5292 void SAL_CALL ScScenariosObj::removeByName( const OUString& aName )
5294 SolarMutexGuard aGuard;
5295 SCTAB nIndex;
5296 if ( pDocShell && GetScenarioIndex_Impl( aName, nIndex ) )
5297 pDocShell->GetDocFunc().DeleteTable( nTab+nIndex+1, true );
5300 // XEnumerationAccess
5302 uno::Reference<container::XEnumeration> SAL_CALL ScScenariosObj::createEnumeration()
5304 SolarMutexGuard aGuard;
5305 return new ScIndexEnumeration(this, u"com.sun.star.sheet.ScenariosEnumeration"_ustr);
5308 // XIndexAccess
5310 sal_Int32 SAL_CALL ScScenariosObj::getCount()
5312 SolarMutexGuard aGuard;
5313 SCTAB nCount = 0;
5314 if ( pDocShell )
5316 ScDocument& rDoc = pDocShell->GetDocument();
5317 if (!rDoc.IsScenario(nTab))
5319 SCTAB nTabCount = rDoc.GetTableCount();
5320 SCTAB nNext = nTab + 1;
5321 while (nNext < nTabCount && rDoc.IsScenario(nNext))
5323 ++nCount;
5324 ++nNext;
5328 return nCount;
5331 uno::Any SAL_CALL ScScenariosObj::getByIndex( sal_Int32 nIndex )
5333 SolarMutexGuard aGuard;
5334 uno::Reference<sheet::XScenario> xScen(GetObjectByIndex_Impl(nIndex));
5335 if (!xScen.is())
5336 throw lang::IndexOutOfBoundsException();
5338 return uno::Any(xScen);
5341 uno::Type SAL_CALL ScScenariosObj::getElementType()
5343 return cppu::UnoType<sheet::XScenario>::get();
5346 sal_Bool SAL_CALL ScScenariosObj::hasElements()
5348 SolarMutexGuard aGuard;
5349 return ( getCount() != 0 );
5352 uno::Any SAL_CALL ScScenariosObj::getByName( const OUString& aName )
5354 SolarMutexGuard aGuard;
5355 uno::Reference<sheet::XScenario> xScen(GetObjectByName_Impl(aName));
5356 if (!xScen.is())
5357 throw container::NoSuchElementException();
5359 return uno::Any(xScen);
5362 uno::Sequence<OUString> SAL_CALL ScScenariosObj::getElementNames()
5364 SolarMutexGuard aGuard;
5365 SCTAB nCount = static_cast<SCTAB>(getCount());
5366 uno::Sequence<OUString> aSeq(nCount);
5368 if ( pDocShell ) // otherwise Count = 0
5370 OUString aTabName;
5371 ScDocument& rDoc = pDocShell->GetDocument();
5372 OUString* pAry = aSeq.getArray();
5373 for (SCTAB i=0; i<nCount; i++)
5374 if (rDoc.GetName( nTab+i+1, aTabName ))
5375 pAry[i] = aTabName;
5378 return aSeq;
5381 sal_Bool SAL_CALL ScScenariosObj::hasByName( const OUString& aName )
5383 SolarMutexGuard aGuard;
5384 SCTAB nIndex;
5385 return GetScenarioIndex_Impl( aName, nIndex );
5388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */