xref: /core/sc/source/core/data/global.cxx (revision 1b7fc505)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <scitems.hxx>
21 #include <svx/algitem.hxx>
22 #include <editeng/brushitem.hxx>
23 #include <editeng/editobj.hxx>
24 #include <svl/srchitem.hxx>
25 #include <editeng/langitem.hxx>
26 #include <o3tl/unit_conversion.hxx>
27 #include <sfx2/docfile.hxx>
28 #include <sfx2/dispatch.hxx>
29 #include <sfx2/objsh.hxx>
30 #include <sfx2/sfxsids.hrc>
31 #include <sfx2/viewfrm.hxx>
32 #include <sfx2/viewsh.hxx>
33 #include <svl/intitem.hxx>
34 #include <svl/stritem.hxx>
35 #include <svl/zforlist.hxx>
36 #include <svl/zformat.hxx>
37 #include <vcl/keycodes.hxx>
38 #include <vcl/virdev.hxx>
39 #include <vcl/settings.hxx>
40 #include <vcl/svapp.hxx>
41 #include <unotools/charclass.hxx>
42 #include <unotools/securityoptions.hxx>
43 #include <osl/diagnose.h>
44 
45 #include <i18nlangtag/mslangid.hxx>
46 #include <comphelper/doublecheckedinit.hxx>
47 #include <comphelper/processfactory.hxx>
48 #include <comphelper/string.hxx>
49 #include <unotools/calendarwrapper.hxx>
50 #include <unotools/collatorwrapper.hxx>
51 #include <unotools/syslocale.hxx>
52 #include <unotools/transliterationwrapper.hxx>
53 
54 #include <comphelper/lok.hxx>
55 
56 #include <global.hxx>
57 #include <scresid.hxx>
58 #include <autoform.hxx>
59 #include <patattr.hxx>
60 #include <addincol.hxx>
61 #include <adiasync.hxx>
62 #include <userlist.hxx>
63 #include <interpre.hxx>
64 #include <unitconv.hxx>
65 #include <compiler.hxx>
66 #include <parclass.hxx>
67 #include <funcdesc.hxx>
68 #include <globstr.hrc>
69 #include <strings.hrc>
70 #include <scmod.hxx>
71 #include <editutil.hxx>
72 #include <docsh.hxx>
73 
74 tools::SvRef<ScDocShell>  ScGlobal::xDrawClipDocShellRef;
75 std::unique_ptr<SvxSearchItem> ScGlobal::xSearchItem;
76 std::unique_ptr<ScAutoFormat> ScGlobal::xAutoFormat;
77 std::atomic<LegacyFuncCollection*> ScGlobal::pLegacyFuncCollection(nullptr);
78 std::atomic<ScUnoAddInCollection*> ScGlobal::pAddInCollection(nullptr);
79 std::unique_ptr<ScUserList> ScGlobal::xUserList;
80 LanguageType    ScGlobal::eLnge = LANGUAGE_SYSTEM;
81 std::atomic<css::lang::Locale*> ScGlobal::pLocale(nullptr);
82 std::unique_ptr<SvtSysLocale>   ScGlobal::xSysLocale;
83 std::unique_ptr<CalendarWrapper> ScGlobal::xCalendar;
84 std::atomic<CollatorWrapper*> ScGlobal::pCollator(nullptr);
85 std::atomic<CollatorWrapper*> ScGlobal::pCaseCollator(nullptr);
86 std::atomic<::utl::TransliterationWrapper*> ScGlobal::pTransliteration(nullptr);
87 std::atomic<::utl::TransliterationWrapper*> ScGlobal::pCaseTransliteration(nullptr);
88 css::uno::Reference< css::i18n::XOrdinalSuffix> ScGlobal::xOrdinalSuffix;
89 const OUString  ScGlobal::aEmptyOUString;
90 OUString        ScGlobal::aStrClipDocName;
91 
92 std::unique_ptr<SvxBrushItem> ScGlobal::xEmptyBrushItem;
93 std::unique_ptr<SvxBrushItem> ScGlobal::xButtonBrushItem;
94 
95 std::unique_ptr<ScFunctionList> ScGlobal::xStarCalcFunctionList;
96 std::unique_ptr<ScFunctionMgr> ScGlobal::xStarCalcFunctionMgr;
97 
98 std::atomic<ScUnitConverter*> ScGlobal::pUnitConverter(nullptr);
99 std::unique_ptr<SvNumberFormatter> ScGlobal::xEnglishFormatter;
100 std::unique_ptr<ScFieldEditEngine> ScGlobal::xFieldEditEngine;
101 
102 double          ScGlobal::nScreenPPTX           = 96.0;
103 double          ScGlobal::nScreenPPTY           = 96.0;
104 
105 sal_uInt16          ScGlobal::nDefFontHeight        = 225;
106 sal_uInt16          ScGlobal::nStdRowHeight         = 256;
107 
108 tools::Long            ScGlobal::nLastRowHeightExtra   = 0;
109 tools::Long            ScGlobal::nLastColWidthExtra    = STD_EXTRA_WIDTH;
110 
111 SfxViewShell* pScActiveViewShell = nullptr; //FIXME: Make this a member
112 sal_uInt16 nScClickMouseModifier = 0;    //FIXME: This too
113 sal_uInt16 nScFillModeMouseModifier = 0; //FIXME: And this
114 
115 bool ScGlobal::bThreadedGroupCalcInProgress = false;
116 
117 // Static functions
118 
119 bool ScGlobal::HasAttrChanged( const SfxItemSet&  rNewAttrs,
120                                const SfxItemSet&  rOldAttrs,
121                                const sal_uInt16       nWhich )
122 {
123     bool                bInvalidate = false;
124     const SfxPoolItem*  pNewItem    = nullptr;
125     const SfxItemState  eNewState   = rNewAttrs.GetItemState( nWhich, true, &pNewItem );
126     const SfxPoolItem*  pOldItem    = nullptr;
127     const SfxItemState  eOldState   = rOldAttrs.GetItemState( nWhich, true, &pOldItem );
128 
129     if ( eNewState == eOldState )
130     {
131         // Both Items set
132         // PoolItems, meaning comparing pointers is valid
133         if ( SfxItemState::SET == eOldState )
134             bInvalidate = (pNewItem != pOldItem);
135     }
136     else
137     {
138         // Contains a Default Item
139         // PoolItems, meaning Item comparison necessary
140         if (!pOldItem)
141             pOldItem = &rOldAttrs.GetPool()->GetDefaultItem( nWhich );
142 
143         if (!pNewItem)
144             pNewItem = &rNewAttrs.GetPool()->GetDefaultItem( nWhich );
145 
146         bInvalidate = (*pNewItem != *pOldItem);
147     }
148 
149     return bInvalidate;
150 }
151 
152 sal_uInt32 ScGlobal::GetStandardFormat( SvNumberFormatter& rFormatter,
153         sal_uInt32 nFormat, SvNumFormatType nType )
154 {
155     const SvNumberformat* pFormat = rFormatter.GetEntry( nFormat );
156     if ( pFormat )
157         return rFormatter.GetStandardFormat( nFormat, nType, pFormat->GetLanguage() );
158     return rFormatter.GetStandardFormat( nType, eLnge );
159 }
160 
161 sal_uInt16 ScGlobal::GetStandardRowHeight()
162 {
163     return nStdRowHeight;
164 }
165 
166 SvNumberFormatter* ScGlobal::GetEnglishFormatter()
167 {
168     assert(!bThreadedGroupCalcInProgress);
169     if ( !xEnglishFormatter )
170     {
171         xEnglishFormatter.reset( new SvNumberFormatter(
172             ::comphelper::getProcessComponentContext(), LANGUAGE_ENGLISH_US ) );
173         xEnglishFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_INTL_FORMAT );
174     }
175     return xEnglishFormatter.get();
176 }
177 
178 bool ScGlobal::CheckWidthInvalidate( bool& bNumFormatChanged,
179                                      const SfxItemSet& rNewAttrs,
180                                      const SfxItemSet& rOldAttrs )
181 {
182     // Check whether attribute changes in rNewAttrs compared to rOldAttrs render
183     // the text width at a cell invalid
184     bNumFormatChanged =
185             HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_VALUE_FORMAT );
186     return ( bNumFormatChanged
187         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_LANGUAGE_FORMAT )
188         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT )
189         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CJK_FONT )
190         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CTL_FONT )
191         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_HEIGHT )
192         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CJK_FONT_HEIGHT )
193         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CTL_FONT_HEIGHT )
194         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_WEIGHT )
195         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CJK_FONT_WEIGHT )
196         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CTL_FONT_WEIGHT )
197         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_POSTURE )
198         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CJK_FONT_POSTURE )
199         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CTL_FONT_POSTURE )
200         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_UNDERLINE )
201         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_OVERLINE )
202         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_CROSSEDOUT )
203         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_CONTOUR )
204         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_SHADOWED )
205         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_STACKED )
206         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_ROTATE_VALUE )
207         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_ROTATE_MODE )
208         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_LINEBREAK )
209         || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_MARGIN )
210         );
211 }
212 
213 const SvxSearchItem& ScGlobal::GetSearchItem()
214 {
215     assert(!bThreadedGroupCalcInProgress);
216     if (!xSearchItem)
217     {
218         xSearchItem.reset(new SvxSearchItem( SID_SEARCH_ITEM ));
219         xSearchItem->SetAppFlag( SvxSearchApp::CALC );
220     }
221     return *xSearchItem;
222 }
223 
224 void ScGlobal::SetSearchItem( const SvxSearchItem& rNew )
225 {
226     assert(!bThreadedGroupCalcInProgress);
227     // FIXME: An assignment operator would be nice here
228     xSearchItem.reset(rNew.Clone());
229 
230     xSearchItem->SetWhich( SID_SEARCH_ITEM );
231     xSearchItem->SetAppFlag( SvxSearchApp::CALC );
232 }
233 
234 void ScGlobal::ClearAutoFormat()
235 {
236     assert(!bThreadedGroupCalcInProgress);
237     if (xAutoFormat)
238     {
239         //  When modified via StarOne then only the SaveLater flag is set and no saving is done.
240         //  If the flag is set then save now.
241         if (xAutoFormat->IsSaveLater())
242             xAutoFormat->Save();
243         xAutoFormat.reset();
244     }
245 }
246 
247 ScAutoFormat* ScGlobal::GetAutoFormat()
248 {
249     return xAutoFormat.get();
250 }
251 
252 ScAutoFormat* ScGlobal::GetOrCreateAutoFormat()
253 {
254     assert(!bThreadedGroupCalcInProgress);
255     if ( !xAutoFormat )
256     {
257         xAutoFormat.reset(new ScAutoFormat);
258         xAutoFormat->Load();
259     }
260 
261     return xAutoFormat.get();
262 }
263 
264 LegacyFuncCollection* ScGlobal::GetLegacyFuncCollection()
265 {
266     return comphelper::doubleCheckedInit( pLegacyFuncCollection, []() { return new LegacyFuncCollection(); });
267 }
268 
269 ScUnoAddInCollection* ScGlobal::GetAddInCollection()
270 {
271     return comphelper::doubleCheckedInit( pAddInCollection, []() { return new ScUnoAddInCollection(); });
272 }
273 
274 ScUserList* ScGlobal::GetUserList()
275 {
276     assert(!bThreadedGroupCalcInProgress);
277     // Hack: Load Cfg item at the App
278     global_InitAppOptions();
279 
280     if (!xUserList)
281         xUserList.reset(new ScUserList());
282     return xUserList.get();
283 }
284 
285 void ScGlobal::SetUserList( const ScUserList* pNewList )
286 {
287     assert(!bThreadedGroupCalcInProgress);
288     if ( pNewList )
289     {
290         if ( !xUserList )
291             xUserList.reset( new ScUserList( *pNewList ) );
292         else
293             *xUserList = *pNewList;
294     }
295     else
296     {
297         xUserList.reset();
298     }
299 }
300 
301 OUString ScGlobal::GetErrorString(FormulaError nErr)
302 {
303     const char* pErrNumber;
304     switch (nErr)
305     {
306         case FormulaError::NoRef:
307             pErrNumber = STR_NO_REF_TABLE;
308             break;
309         case FormulaError::NoAddin:
310             pErrNumber = STR_NO_ADDIN;
311             break;
312         case FormulaError::NoMacro:
313             pErrNumber = STR_NO_MACRO;
314             break;
315         case FormulaError::NotAvailable:
316             return ScCompiler::GetNativeSymbol(ocErrNA);
317         case FormulaError::NoName:
318             return ScCompiler::GetNativeSymbol(ocErrName);
319         case FormulaError::NoValue:
320             return ScCompiler::GetNativeSymbol(ocErrValue);
321         case FormulaError::NoCode:
322             return ScCompiler::GetNativeSymbol(ocErrNull);
323         case FormulaError::DivisionByZero:
324             return ScCompiler::GetNativeSymbol(ocErrDivZero);
325         case FormulaError::IllegalFPOperation:
326             return ScCompiler::GetNativeSymbol(ocErrNum);
327         default:
328             return ScResId(STR_ERROR_STR) + OUString::number( static_cast<int>(nErr) );
329     }
330     return ScResId(pErrNumber);
331 }
332 
333 OUString ScGlobal::GetLongErrorString(FormulaError nErr)
334 {
335     const char* pErrNumber;
336     switch (nErr)
337     {
338         case FormulaError::NONE:
339             return OUString();
340         case FormulaError::IllegalArgument:
341             pErrNumber = STR_LONG_ERR_ILL_ARG;
342         break;
343         case FormulaError::IllegalFPOperation:
344             pErrNumber = STR_LONG_ERR_ILL_FPO;
345         break;
346         case FormulaError::IllegalChar:
347             pErrNumber = STR_LONG_ERR_ILL_CHAR;
348         break;
349         case FormulaError::IllegalParameter:
350             pErrNumber = STR_LONG_ERR_ILL_PAR;
351         break;
352         case FormulaError::Pair:
353         case FormulaError::PairExpected:
354             pErrNumber = STR_LONG_ERR_PAIR;
355         break;
356         case FormulaError::OperatorExpected:
357             pErrNumber = STR_LONG_ERR_OP_EXP;
358         break;
359         case FormulaError::VariableExpected:
360         case FormulaError::ParameterExpected:
361             pErrNumber = STR_LONG_ERR_VAR_EXP;
362         break;
363         case FormulaError::CodeOverflow:
364             pErrNumber = STR_LONG_ERR_CODE_OVF;
365         break;
366         case FormulaError::StringOverflow:
367             pErrNumber = STR_LONG_ERR_STR_OVF;
368         break;
369         case FormulaError::StackOverflow:
370             pErrNumber = STR_LONG_ERR_STACK_OVF;
371         break;
372         case FormulaError::MatrixSize:
373             pErrNumber = STR_LONG_ERR_MATRIX_SIZE;
374         break;
375         case FormulaError::UnknownState:
376         case FormulaError::UnknownVariable:
377         case FormulaError::UnknownOpCode:
378         case FormulaError::UnknownStackVariable:
379         case FormulaError::UnknownToken:
380         case FormulaError::NoCode:
381             pErrNumber = STR_LONG_ERR_SYNTAX;
382         break;
383         case FormulaError::CircularReference:
384             pErrNumber = STR_LONG_ERR_CIRC_REF;
385         break;
386         case FormulaError::NoConvergence:
387             pErrNumber = STR_LONG_ERR_NO_CONV;
388         break;
389         case FormulaError::NoRef:
390             pErrNumber = STR_LONG_ERR_NO_REF;
391         break;
392         case FormulaError::NoName:
393             pErrNumber = STR_LONG_ERR_NO_NAME;
394         break;
395         case FormulaError::NoAddin:
396             pErrNumber = STR_LONG_ERR_NO_ADDIN;
397         break;
398         case FormulaError::NoMacro:
399             pErrNumber = STR_LONG_ERR_NO_MACRO;
400         break;
401         case FormulaError::DivisionByZero:
402             pErrNumber = STR_LONG_ERR_DIV_ZERO;
403         break;
404         case FormulaError::NestedArray:
405             pErrNumber = STR_ERR_LONG_NESTED_ARRAY;
406         break;
407         case FormulaError::BadArrayContent:
408             pErrNumber = STR_ERR_LONG_BAD_ARRAY_CONTENT;
409         break;
410         case FormulaError::LinkFormulaNeedingCheck:
411             pErrNumber = STR_ERR_LONG_LINK_FORMULA_NEEDING_CHECK;
412         break;
413         case FormulaError::NoValue:
414             pErrNumber = STR_LONG_ERR_NO_VALUE;
415         break;
416         case FormulaError::NotAvailable:
417             pErrNumber = STR_LONG_ERR_NV;
418         break;
419         default:
420             return ScResId(STR_ERROR_STR) + OUString::number( static_cast<int>(nErr) );
421     }
422     return ScResId(pErrNumber);
423 }
424 
425 SvxBrushItem* ScGlobal::GetButtonBrushItem()
426 {
427     assert(!bThreadedGroupCalcInProgress);
428     xButtonBrushItem->SetColor( Application::GetSettings().GetStyleSettings().GetFaceColor() );
429     return xButtonBrushItem.get();
430 }
431 
432 void ScGlobal::Init()
433 {
434     // The default language for number formats (ScGlobal::eLnge) must
435     // always be LANGUAGE_SYSTEM
436     // FIXME: So remove this variable?
437     eLnge = LANGUAGE_SYSTEM;
438 
439     xSysLocale = std::make_unique<SvtSysLocale>();
440 
441     xEmptyBrushItem = std::make_unique<SvxBrushItem>( COL_TRANSPARENT, ATTR_BACKGROUND );
442     xButtonBrushItem = std::make_unique<SvxBrushItem>( Color(), ATTR_BACKGROUND );
443 
444     InitPPT();
445     //ScCompiler::InitSymbolsNative();
446     // ScParameterClassification _after_ Compiler, needs function resources if
447     // arguments are to be merged in, which in turn need strings of function
448     // names from the compiler.
449     ScParameterClassification::Init();
450 
451     InitAddIns();
452 
453     aStrClipDocName = ScResId( SCSTR_NONAME ) + "1";
454 
455     //  ScDocumentPool::InitVersionMaps() has been called earlier already
456 }
457 
458 void ScGlobal::InitPPT()
459 {
460     OutputDevice* pDev = Application::GetDefaultDevice();
461 
462     if (comphelper::LibreOfficeKit::isActive())
463     {
464         // LOK: the below limited precision is not enough for RowColumnHeader.
465         nScreenPPTX = o3tl::convert<double>(pDev->GetDPIX(), o3tl::Length::twip, o3tl::Length::in);
466         nScreenPPTY = o3tl::convert<double>(pDev->GetDPIY(), o3tl::Length::twip, o3tl::Length::in);
467     }
468     else
469     {
470         // Avoid cumulative placement errors by intentionally limiting
471         // precision.
472         Point aPix1000 = pDev->LogicToPixel(Point(1000, 1000), MapMode(MapUnit::MapTwip));
473         nScreenPPTX = aPix1000.X() / 1000.0;
474         nScreenPPTY = aPix1000.Y() / 1000.0;
475     }
476 }
477 
478 const OUString& ScGlobal::GetClipDocName()
479 {
480     return aStrClipDocName;
481 }
482 
483 void ScGlobal::SetClipDocName( const OUString& rNew )
484 {
485     assert(!bThreadedGroupCalcInProgress);
486     aStrClipDocName = rNew;
487 }
488 
489 void ScGlobal::InitTextHeight(const SfxItemPool* pPool)
490 {
491     if (!pPool)
492     {
493         OSL_FAIL("ScGlobal::InitTextHeight: No Pool");
494         return;
495     }
496 
497     const ScPatternAttr& rPattern = pPool->GetDefaultItem(ATTR_PATTERN);
498 
499     OutputDevice* pDefaultDev = Application::GetDefaultDevice();
500     ScopedVclPtrInstance< VirtualDevice > pVirtWindow( *pDefaultDev );
501     pVirtWindow->SetMapMode(MapMode(MapUnit::MapPixel));
502     vcl::Font aDefFont;
503     rPattern.GetFont(aDefFont, SC_AUTOCOL_BLACK, pVirtWindow); // Font color doesn't matter here
504     pVirtWindow->SetFont(aDefFont);
505     sal_uInt16 nTest = static_cast<sal_uInt16>(
506         pVirtWindow->PixelToLogic(Size(0, pVirtWindow->GetTextHeight()), MapMode(MapUnit::MapTwip)).Height());
507 
508     if (nTest > nDefFontHeight)
509         nDefFontHeight = nTest;
510 
511     const SvxMarginItem& rMargin = rPattern.GetItem(ATTR_MARGIN);
512 
513     nTest = static_cast<sal_uInt16>(nDefFontHeight + rMargin.GetTopMargin()
514                                     + rMargin.GetBottomMargin() - STD_ROWHEIGHT_DIFF);
515 
516     if (nTest > nStdRowHeight)
517         nStdRowHeight = nTest;
518 }
519 
520 void ScGlobal::Clear()
521 {
522     // Destroy asyncs _before_ ExitExternalFunc!
523     theAddInAsyncTbl.clear();
524     ExitExternalFunc();
525     ClearAutoFormat();
526     xSearchItem.reset();
527     delete pLegacyFuncCollection.load(); pLegacyFuncCollection = nullptr;
528     delete pAddInCollection.load(); pAddInCollection = nullptr;
529     xUserList.reset();
530     xStarCalcFunctionList.reset(); // Destroy before ResMgr!
531     xStarCalcFunctionMgr.reset();
532     ScParameterClassification::Exit();
533     ScCompiler::DeInit();
534     ScInterpreter::GlobalExit(); // Delete static Stack
535 
536     xEmptyBrushItem.reset();
537     xButtonBrushItem.reset();
538     xEnglishFormatter.reset();
539     delete pCaseTransliteration.load(); pCaseTransliteration = nullptr;
540     delete pTransliteration.load(); pTransliteration = nullptr;
541     delete pCaseCollator.load(); pCaseCollator = nullptr;
542     delete pCollator.load(); pCollator = nullptr;
543     xCalendar.reset();
544     xSysLocale.reset();
545     delete pLocale.load(); pLocale = nullptr;
546 
547     delete pUnitConverter.load(); pUnitConverter = nullptr;
548     xFieldEditEngine.reset();
549 
550     xDrawClipDocShellRef.clear();
551 }
552 
553 rtl_TextEncoding ScGlobal::GetCharsetValue( const OUString& rCharSet )
554 {
555     // new TextEncoding values
556     if ( CharClass::isAsciiNumeric( rCharSet ) )
557     {
558         sal_Int32 nVal = rCharSet.toInt32();
559         if ( nVal == RTL_TEXTENCODING_DONTKNOW )
560             return osl_getThreadTextEncoding();
561         return static_cast<rtl_TextEncoding>(nVal);
562     }
563     // old CharSet values for compatibility
564     else if (rCharSet.equalsIgnoreAsciiCase("ANSI")     ) return RTL_TEXTENCODING_MS_1252;
565     else if (rCharSet.equalsIgnoreAsciiCase("MAC")      ) return RTL_TEXTENCODING_APPLE_ROMAN;
566     else if (rCharSet.equalsIgnoreAsciiCase("IBMPC")    ) return RTL_TEXTENCODING_IBM_850;
567     else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_437")) return RTL_TEXTENCODING_IBM_437;
568     else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_850")) return RTL_TEXTENCODING_IBM_850;
569     else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_860")) return RTL_TEXTENCODING_IBM_860;
570     else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_861")) return RTL_TEXTENCODING_IBM_861;
571     else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_863")) return RTL_TEXTENCODING_IBM_863;
572     else if (rCharSet.equalsIgnoreAsciiCase("IBMPC_865")) return RTL_TEXTENCODING_IBM_865;
573     // Some wrong "help" on the net mentions UTF8 and even unoconv uses it,
574     // which worked accidentally if the system encoding is UTF-8 anyway, so
575     // support it ;) but only when reading.
576     else if (rCharSet.equalsIgnoreAsciiCase("UTF8"))      return RTL_TEXTENCODING_UTF8;
577     else if (rCharSet.equalsIgnoreAsciiCase("UTF-8"))     return RTL_TEXTENCODING_UTF8;
578     else return osl_getThreadTextEncoding();
579 }
580 
581 OUString ScGlobal::GetCharsetString( rtl_TextEncoding eVal )
582 {
583     const char* pChar;
584     switch ( eVal )
585     {
586         // old CharSet strings for compatibility
587         case RTL_TEXTENCODING_MS_1252:      pChar = "ANSI";         break;
588         case RTL_TEXTENCODING_APPLE_ROMAN:  pChar = "MAC";          break;
589         // IBMPC == IBMPC_850
590         case RTL_TEXTENCODING_IBM_437:      pChar = "IBMPC_437";    break;
591         case RTL_TEXTENCODING_IBM_850:      pChar = "IBMPC_850";    break;
592         case RTL_TEXTENCODING_IBM_860:      pChar = "IBMPC_860";    break;
593         case RTL_TEXTENCODING_IBM_861:      pChar = "IBMPC_861";    break;
594         case RTL_TEXTENCODING_IBM_863:      pChar = "IBMPC_863";    break;
595         case RTL_TEXTENCODING_IBM_865:      pChar = "IBMPC_865";    break;
596         case RTL_TEXTENCODING_DONTKNOW:     pChar = "SYSTEM";       break;
597         // new string of TextEncoding value
598         default:
599             return OUString::number( eVal );
600     }
601     return OUString::createFromAscii(pChar);
602 }
603 
604 bool ScGlobal::HasStarCalcFunctionList()
605 {
606     return bool(xStarCalcFunctionList);
607 }
608 
609 ScFunctionList* ScGlobal::GetStarCalcFunctionList()
610 {
611     assert(!bThreadedGroupCalcInProgress);
612     if ( !xStarCalcFunctionList )
613         xStarCalcFunctionList.reset(new ScFunctionList);
614 
615     return xStarCalcFunctionList.get();
616 }
617 
618 ScFunctionMgr* ScGlobal::GetStarCalcFunctionMgr()
619 {
620     assert(!bThreadedGroupCalcInProgress);
621     if ( !xStarCalcFunctionMgr )
622         xStarCalcFunctionMgr.reset(new ScFunctionMgr);
623 
624     return xStarCalcFunctionMgr.get();
625 }
626 
627 void ScGlobal::ResetFunctionList()
628 {
629     // FunctionMgr has pointers into FunctionList, must also be updated
630     xStarCalcFunctionMgr.reset();
631     xStarCalcFunctionList.reset();
632 }
633 
634 ScUnitConverter* ScGlobal::GetUnitConverter()
635 {
636     return comphelper::doubleCheckedInit( pUnitConverter,
637         []() { return new ScUnitConverter; });
638 }
639 
640 const sal_Unicode* ScGlobal::UnicodeStrChr( const sal_Unicode* pStr,
641             sal_Unicode c )
642 {
643     if ( !pStr )
644         return nullptr;
645     while ( *pStr )
646     {
647         if ( *pStr == c )
648             return pStr;
649         pStr++;
650     }
651     return nullptr;
652 }
653 
654 OUString ScGlobal::addToken(const OUString& rTokenList, std::u16string_view rToken,
655     sal_Unicode cSep, sal_Int32 nSepCount, bool bForceSep)
656 {
657     OUStringBuffer aBuf(rTokenList);
658     if( bForceSep || (!rToken.empty() && !rTokenList.isEmpty()) )
659         comphelper::string::padToLength(aBuf, aBuf.getLength() + nSepCount, cSep);
660     aBuf.append(rToken);
661     return aBuf.makeStringAndClear();
662 }
663 
664 bool ScGlobal::IsQuoted( const OUString& rString, sal_Unicode cQuote )
665 {
666     return (rString.getLength() >= 2) && (rString[0] == cQuote) && (rString[ rString.getLength() - 1 ] == cQuote);
667 }
668 
669 void ScGlobal::AddQuotes( OUString& rString, sal_Unicode cQuote, bool bEscapeEmbedded )
670 {
671     if (bEscapeEmbedded)
672     {
673         sal_Unicode pQ[3];
674         pQ[0] = pQ[1] = cQuote;
675         pQ[2] = 0;
676         OUString aQuotes( pQ );
677         rString = rString.replaceAll( OUStringChar(cQuote), aQuotes);
678     }
679     rString = OUStringChar( cQuote ) + rString + OUStringChar( cQuote );
680 }
681 
682 void ScGlobal::EraseQuotes( OUString& rString, sal_Unicode cQuote, bool bUnescapeEmbedded )
683 {
684     if ( IsQuoted( rString, cQuote ) )
685     {
686         rString = rString.copy( 1, rString.getLength() - 2 );
687         if (bUnescapeEmbedded)
688         {
689             sal_Unicode pQ[3];
690             pQ[0] = pQ[1] = cQuote;
691             pQ[2] = 0;
692             OUString aQuotes( pQ );
693             rString = rString.replaceAll( aQuotes, OUStringChar(cQuote));
694         }
695     }
696 }
697 
698 sal_Int32 ScGlobal::FindUnquoted( const OUString& rString, sal_Unicode cChar, sal_Int32 nStart )
699 {
700     assert(nStart >= 0);
701     const sal_Unicode cQuote = '\'';
702     const sal_Unicode* const pStart = rString.getStr();
703     const sal_Unicode* const pStop = pStart + rString.getLength();
704     const sal_Unicode* p = pStart + nStart;
705     bool bQuoted = false;
706     while (p < pStop)
707     {
708         if (*p == cChar && !bQuoted)
709             return sal::static_int_cast< sal_Int32 >( p - pStart );
710         else if (*p == cQuote)
711         {
712             if (!bQuoted)
713                 bQuoted = true;
714             else if (p < pStop-1 && *(p+1) == cQuote)
715                 ++p;
716             else
717                 bQuoted = false;
718         }
719         ++p;
720     }
721     return -1;
722 }
723 
724 const sal_Unicode* ScGlobal::FindUnquoted( const sal_Unicode* pString, sal_Unicode cChar )
725 {
726     sal_Unicode cQuote = '\'';
727     const sal_Unicode* p = pString;
728     bool bQuoted = false;
729     while (*p)
730     {
731         if (*p == cChar && !bQuoted)
732             return p;
733         else if (*p == cQuote)
734         {
735             if (!bQuoted)
736                 bQuoted = true;
737             else if (*(p+1) == cQuote)
738                 ++p;
739             else
740                 bQuoted = false;
741         }
742         ++p;
743     }
744     return nullptr;
745 }
746 
747 bool ScGlobal::EETextObjEqual( const EditTextObject* pObj1,
748                                const EditTextObject* pObj2 )
749 {
750     if ( pObj1 == pObj2 ) // Both empty or the same object
751         return true;
752 
753     if ( pObj1 && pObj2 )
754         return pObj1->Equals( *pObj2);
755 
756     return false;
757 }
758 
759 void ScGlobal::OpenURL(const OUString& rURL, const OUString& rTarget, bool bIgnoreSettings)
760 {
761     // OpenURL is always called in the GridWindow by mouse clicks in some way or another.
762     // That's why pScActiveViewShell and nScClickMouseModifier are correct.
763 
764     // Fragments pointing into the current document should be always opened.
765     if (!bIgnoreSettings && !(ShouldOpenURL() || rURL.startsWith("#")))
766         return;
767 
768     SfxViewFrame* pViewFrm = SfxViewFrame::Current();
769     if (!pViewFrm)
770         return;
771 
772     OUString aUrlName( rURL );
773     SfxViewFrame* pFrame = nullptr;
774     const SfxObjectShell* pObjShell = nullptr;
775     OUString aReferName;
776     if ( pScActiveViewShell )
777     {
778         pFrame = pScActiveViewShell->GetViewFrame();
779         pObjShell = pFrame->GetObjectShell();
780         const SfxMedium* pMed = pObjShell->GetMedium();
781         if (pMed)
782             aReferName = pMed->GetName();
783     }
784 
785     // Don't fiddle with fragments pointing into current document.
786     // Also don't mess around with a vnd.sun.star.script or service or other
787     // internal "URI".
788     if (!aUrlName.startsWith("#")
789             && !aUrlName.startsWithIgnoreAsciiCase("vnd.sun.star.script:")
790             && !aUrlName.startsWithIgnoreAsciiCase("macro:")
791             && !aUrlName.startsWithIgnoreAsciiCase("slot:")
792             && !aUrlName.startsWithIgnoreAsciiCase("service:")
793             && !aUrlName.startsWithIgnoreAsciiCase(".uno:"))
794     {
795         // Any relative reference would fail with "not an absolute URL"
796         // error, try to construct an absolute URI with the path relative
797         // to the current document's path or work path, as usual for all
798         // external references.
799         // This then also, as ScGlobal::GetAbsDocName() uses
800         // INetURLObject::smartRel2Abs(), supports "\\" UNC path names as
801         // smb:// Samba shares and DOS path separators converted to proper
802         // file:// URI.
803         const OUString aNewUrlName( ScGlobal::GetAbsDocName( aUrlName, pObjShell));
804         if (!aNewUrlName.isEmpty())
805             aUrlName = aNewUrlName;
806     }
807 
808     SfxStringItem aUrl( SID_FILE_NAME, aUrlName );
809     SfxStringItem aTarget( SID_TARGETNAME, rTarget );
810     if ( nScClickMouseModifier & KEY_SHIFT )     // control-click -> into new window
811         aTarget.SetValue("_blank");
812 
813     SfxFrameItem aFrm( SID_DOCFRAME, pFrame );
814     SfxStringItem aReferer( SID_REFERER, aReferName );
815 
816     SfxBoolItem aNewView( SID_OPEN_NEW_VIEW, false );
817     SfxBoolItem aBrowsing( SID_BROWSE, true );
818 
819     // No SID_SILENT anymore
820     pViewFrm->GetDispatcher()->ExecuteList(SID_OPENDOC,
821             SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
822             { &aUrl, &aTarget, &aFrm, &aReferer, &aNewView, &aBrowsing });
823 }
824 
825 bool ScGlobal::ShouldOpenURL()
826 {
827     SvtSecurityOptions aSecOpt;
828     bool bCtrlClickHappened = (nScClickMouseModifier & KEY_MOD1);
829     bool bCtrlClickSecOption = aSecOpt.IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink );
830     if( bCtrlClickHappened && ! bCtrlClickSecOption )
831     {
832         // return since ctrl+click happened when the
833         // ctrl+click security option was disabled, link should not open
834         return false;
835     }
836     else if( ! bCtrlClickHappened && bCtrlClickSecOption )
837     {
838         // ctrl+click did not happen; only click happened maybe with some
839         // other key combo. and security option is set, so return
840         return false;
841     }
842     return true;
843 }
844 
845 bool ScGlobal::IsSystemRTL()
846 {
847     return MsLangId::isRightToLeft( Application::GetSettings().GetLanguageTag().getLanguageType() );
848 }
849 
850 SvtScriptType ScGlobal::GetDefaultScriptType()
851 {
852     // Used when text contains only WEAK characters.
853     // Script type of office language is used then (same as GetEditDefaultLanguage,
854     // to get consistent behavior of text in simple cells and EditEngine,
855     // also same as GetAppLanguage() in Writer)
856     return SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() );
857 }
858 
859 LanguageType ScGlobal::GetEditDefaultLanguage()
860 {
861     // Used for EditEngine::SetDefaultLanguage
862     return Application::GetSettings().GetLanguageTag().getLanguageType();
863 }
864 
865 sal_uInt16 ScGlobal::GetScriptedWhichID( SvtScriptType nScriptType, sal_uInt16 nWhich )
866 {
867     switch ( nScriptType )
868     {
869         case SvtScriptType::LATIN:
870         case SvtScriptType::ASIAN:
871         case SvtScriptType::COMPLEX:
872         break;      // take exact matches
873         default:    // prefer one, first COMPLEX, then ASIAN
874             if ( nScriptType & SvtScriptType::COMPLEX )
875                 nScriptType = SvtScriptType::COMPLEX;
876             else if ( nScriptType & SvtScriptType::ASIAN )
877                 nScriptType = SvtScriptType::ASIAN;
878     }
879     switch ( nScriptType )
880     {
881         case SvtScriptType::COMPLEX:
882         {
883             switch ( nWhich )
884             {
885                 case ATTR_FONT:
886                 case ATTR_CJK_FONT:
887                     nWhich = ATTR_CTL_FONT;
888                 break;
889                 case ATTR_FONT_HEIGHT:
890                 case ATTR_CJK_FONT_HEIGHT:
891                     nWhich = ATTR_CTL_FONT_HEIGHT;
892                 break;
893                 case ATTR_FONT_WEIGHT:
894                 case ATTR_CJK_FONT_WEIGHT:
895                     nWhich = ATTR_CTL_FONT_WEIGHT;
896                 break;
897                 case ATTR_FONT_POSTURE:
898                 case ATTR_CJK_FONT_POSTURE:
899                     nWhich = ATTR_CTL_FONT_POSTURE;
900                 break;
901             }
902         }
903         break;
904         case SvtScriptType::ASIAN:
905         {
906             switch ( nWhich )
907             {
908                 case ATTR_FONT:
909                 case ATTR_CTL_FONT:
910                     nWhich = ATTR_CJK_FONT;
911                 break;
912                 case ATTR_FONT_HEIGHT:
913                 case ATTR_CTL_FONT_HEIGHT:
914                     nWhich = ATTR_CJK_FONT_HEIGHT;
915                 break;
916                 case ATTR_FONT_WEIGHT:
917                 case ATTR_CTL_FONT_WEIGHT:
918                     nWhich = ATTR_CJK_FONT_WEIGHT;
919                 break;
920                 case ATTR_FONT_POSTURE:
921                 case ATTR_CTL_FONT_POSTURE:
922                     nWhich = ATTR_CJK_FONT_POSTURE;
923                 break;
924             }
925         }
926         break;
927         default:
928         {
929             switch ( nWhich )
930             {
931                 case ATTR_CTL_FONT:
932                 case ATTR_CJK_FONT:
933                     nWhich = ATTR_FONT;
934                 break;
935                 case ATTR_CTL_FONT_HEIGHT:
936                 case ATTR_CJK_FONT_HEIGHT:
937                     nWhich = ATTR_FONT_HEIGHT;
938                 break;
939                 case ATTR_CTL_FONT_WEIGHT:
940                 case ATTR_CJK_FONT_WEIGHT:
941                     nWhich = ATTR_FONT_WEIGHT;
942                 break;
943                 case ATTR_CTL_FONT_POSTURE:
944                 case ATTR_CJK_FONT_POSTURE:
945                     nWhich = ATTR_FONT_POSTURE;
946                 break;
947             }
948         }
949     }
950     return nWhich;
951 }
952 
953 void ScGlobal::AddLanguage( SfxItemSet& rSet, const SvNumberFormatter& rFormatter )
954 {
955     OSL_ENSURE( rSet.GetItemState( ATTR_LANGUAGE_FORMAT, false ) == SfxItemState::DEFAULT,
956         "ScGlobal::AddLanguage - language already added");
957 
958     const SfxPoolItem* pHardItem;
959     if ( rSet.GetItemState( ATTR_VALUE_FORMAT, false, &pHardItem ) != SfxItemState::SET )
960         return;
961 
962     const SvNumberformat* pHardFormat = rFormatter.GetEntry(
963         static_cast<const SfxUInt32Item*>(pHardItem)->GetValue() );
964 
965     sal_uInt32 nParentFmt = 0; // Pool default
966     const SfxItemSet* pParent = rSet.GetParent();
967     if ( pParent )
968         nParentFmt = pParent->Get( ATTR_VALUE_FORMAT ).GetValue();
969     const SvNumberformat* pParFormat = rFormatter.GetEntry( nParentFmt );
970 
971     if ( pHardFormat && pParFormat &&
972             (pHardFormat->GetLanguage() != pParFormat->GetLanguage()) )
973         rSet.Put( SvxLanguageItem( pHardFormat->GetLanguage(), ATTR_LANGUAGE_FORMAT ) );
974 }
975 
976 utl::TransliterationWrapper* ScGlobal::GetpTransliteration()
977 {
978     return comphelper::doubleCheckedInit( pTransliteration,
979         []()
980         {
981             const LanguageType eOfficeLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
982             ::utl::TransliterationWrapper* p = new ::utl::TransliterationWrapper(
983                 ::comphelper::getProcessComponentContext(), TransliterationFlags::IGNORE_CASE );
984             p->loadModuleIfNeeded( eOfficeLanguage );
985             return p;
986         });
987 }
988 ::utl::TransliterationWrapper* ScGlobal::GetCaseTransliteration()
989 {
990     return comphelper::doubleCheckedInit( pCaseTransliteration,
991         []()
992         {
993             const LanguageType eOfficeLanguage = Application::GetSettings().GetLanguageTag().getLanguageType();
994             ::utl::TransliterationWrapper* p = new ::utl::TransliterationWrapper(
995                 ::comphelper::getProcessComponentContext(), TransliterationFlags::NONE );
996             p->loadModuleIfNeeded( eOfficeLanguage );
997             return p;
998         });
999 }
1000 
1001 const LocaleDataWrapper* ScGlobal::getLocaleDataPtr()
1002 {
1003     OSL_ENSURE(
1004         xSysLocale,
1005         "ScGlobal::getLocaleDataPtr() called before ScGlobal::Init()");
1006 
1007     return &xSysLocale->GetLocaleData();
1008 }
1009 
1010 const CharClass* ScGlobal::getCharClassPtr()
1011 {
1012     OSL_ENSURE(
1013         xSysLocale,
1014         "ScGlobal::getCharClassPtr() called before ScGlobal::Init()");
1015 
1016     return xSysLocale->GetCharClassPtr();
1017 }
1018 
1019 CalendarWrapper*     ScGlobal::GetCalendar()
1020 {
1021     assert(!bThreadedGroupCalcInProgress);
1022     if ( !xCalendar )
1023     {
1024         xCalendar.reset( new CalendarWrapper( ::comphelper::getProcessComponentContext() ) );
1025         xCalendar->loadDefaultCalendar( *GetLocale() );
1026     }
1027     return xCalendar.get();
1028 }
1029 CollatorWrapper*        ScGlobal::GetCollator()
1030 {
1031     return comphelper::doubleCheckedInit( pCollator,
1032         []()
1033         {
1034             CollatorWrapper* p = new CollatorWrapper( ::comphelper::getProcessComponentContext() );
1035             p->loadDefaultCollator( *GetLocale(), SC_COLLATOR_IGNORES );
1036             return p;
1037         });
1038 }
1039 CollatorWrapper*        ScGlobal::GetCaseCollator()
1040 {
1041     return comphelper::doubleCheckedInit( pCaseCollator,
1042         []()
1043         {
1044             CollatorWrapper* p = new CollatorWrapper( ::comphelper::getProcessComponentContext() );
1045             p->loadDefaultCollator( *GetLocale(), 0 );
1046             return p;
1047         });
1048 }
1049 css::lang::Locale*     ScGlobal::GetLocale()
1050 {
1051     return comphelper::doubleCheckedInit( pLocale,
1052         []() { return new css::lang::Locale( Application::GetSettings().GetLanguageTag().getLocale()); });
1053 }
1054 
1055 ScFieldEditEngine& ScGlobal::GetStaticFieldEditEngine()
1056 {
1057     assert(!bThreadedGroupCalcInProgress);
1058     if (!xFieldEditEngine)
1059     {
1060         // Creating a ScFieldEditEngine with pDocument=NULL leads to document
1061         // specific fields not being resolvable! See
1062         // ScFieldEditEngine::CalcFieldValue(). pEnginePool=NULL lets
1063         // EditEngine internally create and delete a default pool.
1064         xFieldEditEngine.reset(new ScFieldEditEngine( nullptr, nullptr));
1065     }
1066     return *xFieldEditEngine;
1067 }
1068 
1069 OUString ScGlobal::ReplaceOrAppend( const OUString& rString,
1070         std::u16string_view rPlaceholder, const OUString& rReplacement )
1071 {
1072     if (rString.isEmpty())
1073         return rReplacement;
1074     sal_Int32 nFound = rString.indexOf( rPlaceholder);
1075     if (nFound < 0)
1076     {
1077         if (rString[rString.getLength()-1] == ' ')
1078             return rString + rReplacement;
1079         return rString + " " + rReplacement;
1080     }
1081     return rString.replaceFirst( rPlaceholder, rReplacement, &nFound);
1082 }
1083 
1084 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1085