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
