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