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 <comphelper/processfactory.hxx> 22 #include <editeng/eeitem.hxx> 23 24 #include <svx/algitem.hxx> 25 #include <svtools/colorcfg.hxx> 26 #include <editeng/editview.hxx> 27 #include <editeng/editstat.hxx> 28 #include <editeng/escapementitem.hxx> 29 #include <editeng/flditem.hxx> 30 #include <editeng/numitem.hxx> 31 #include <editeng/justifyitem.hxx> 32 #include <editeng/editobj.hxx> 33 #include <vcl/svapp.hxx> 34 #include <vcl/outdev.hxx> 35 #include <svl/inethist.hxx> 36 #include <unotools/syslocale.hxx> 37 #include <sfx2/objsh.hxx> 38 #include <osl/diagnose.h> 39 40 #include <com/sun/star/text/textfield/Type.hpp> 41 #include <com/sun/star/document/XDocumentProperties.hpp> 42 43 #include <editutil.hxx> 44 #include <global.hxx> 45 #include <attrib.hxx> 46 #include <document.hxx> 47 #include <docpool.hxx> 48 #include <patattr.hxx> 49 #include <scmod.hxx> 50 #include <inputopt.hxx> 51 #include <compiler.hxx> 52 53 using namespace com::sun::star; 54 55 // delimiters additionally to EditEngine default: 56 57 ScEditUtil::ScEditUtil( ScDocument* pDocument, SCCOL nX, SCROW nY, SCTAB nZ, 58 const Point& rScrPosPixel, 59 OutputDevice* pDevice, double nScaleX, double nScaleY, 60 const Fraction& rX, const Fraction& rY ) : 61 pDoc(pDocument),nCol(nX),nRow(nY),nTab(nZ), 62 aScrPos(rScrPosPixel),pDev(pDevice), 63 nPPTX(nScaleX),nPPTY(nScaleY),aZoomX(rX),aZoomY(rY) {} 64 65 OUString ScEditUtil::ModifyDelimiters( const OUString& rOld ) 66 { 67 // underscore is used in function argument names 68 OUString aRet = rOld.replaceAll("_", "") + 69 "=()+-*/^&<>" + 70 ScCompiler::GetNativeSymbol(ocSep); // argument separator is localized. 71 return aRet; 72 } 73 74 static OUString lcl_GetDelimitedString( const EditEngine& rEngine, const sal_Char c ) 75 { 76 sal_Int32 nParCount = rEngine.GetParagraphCount(); 77 OUStringBuffer aRet( nParCount * 80 ); 78 for (sal_Int32 nPar=0; nPar<nParCount; nPar++) 79 { 80 if (nPar > 0) 81 aRet.append(c); 82 aRet.append( rEngine.GetText( nPar )); 83 } 84 return aRet.makeStringAndClear(); 85 } 86 87 static OUString lcl_GetDelimitedString( const EditTextObject& rEdit, const sal_Char c ) 88 { 89 sal_Int32 nParCount = rEdit.GetParagraphCount(); 90 OUStringBuffer aRet( nParCount * 80 ); 91 for (sal_Int32 nPar=0; nPar<nParCount; nPar++) 92 { 93 if (nPar > 0) 94 aRet.append(c); 95 aRet.append( rEdit.GetText( nPar )); 96 } 97 return aRet.makeStringAndClear(); 98 } 99 100 OUString ScEditUtil::GetSpaceDelimitedString( const EditEngine& rEngine ) 101 { 102 return lcl_GetDelimitedString(rEngine, ' '); 103 } 104 OUString ScEditUtil::GetMultilineString( const EditEngine& rEngine ) 105 { 106 return lcl_GetDelimitedString(rEngine, '\n'); 107 } 108 109 OUString ScEditUtil::GetMultilineString( const EditTextObject& rEdit ) 110 { 111 return lcl_GetDelimitedString(rEdit, '\n'); 112 } 113 114 OUString ScEditUtil::GetString( const EditTextObject& rEditText, const ScDocument* pDoc ) 115 { 116 if( !rEditText.HasField()) 117 return GetMultilineString( rEditText ); 118 119 static osl::Mutex aMutex; 120 osl::MutexGuard aGuard( aMutex); 121 // ScFieldEditEngine is needed to resolve field contents. 122 if (pDoc) 123 { 124 /* TODO: make ScDocument::GetEditEngine() const? Most likely it's only 125 * not const because of the pointer assignment, make that mutable, and 126 * then remove the ugly const_cast here. */ 127 EditEngine& rEE = const_cast<ScDocument*>(pDoc)->GetEditEngine(); 128 rEE.SetText( rEditText); 129 return GetMultilineString( rEE); 130 } 131 else 132 { 133 EditEngine& rEE = ScGlobal::GetStaticFieldEditEngine(); 134 rEE.SetText( rEditText); 135 return GetMultilineString( rEE); 136 } 137 } 138 139 std::unique_ptr<EditTextObject> ScEditUtil::CreateURLObjectFromURL( ScDocument& rDoc, const OUString& rURL, const OUString& rText ) 140 { 141 SvxURLField aUrlField( rURL, rText, SvxURLFormat::AppDefault); 142 EditEngine& rEE = rDoc.GetEditEngine(); 143 rEE.SetText( EMPTY_OUSTRING ); 144 rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), 145 ESelection( EE_PARA_MAX_COUNT, EE_TEXTPOS_MAX_COUNT ) ); 146 147 return rEE.CreateTextObject(); 148 } 149 150 void ScEditUtil::RemoveCharAttribs( EditTextObject& rEditText, const ScPatternAttr& rAttr ) 151 { 152 static const struct { 153 sal_uInt16 nAttrType; 154 sal_uInt16 nCharType; 155 } AttrTypeMap[] = { 156 { ATTR_FONT, EE_CHAR_FONTINFO }, 157 { ATTR_FONT_HEIGHT, EE_CHAR_FONTHEIGHT }, 158 { ATTR_FONT_WEIGHT, EE_CHAR_WEIGHT }, 159 { ATTR_FONT_COLOR, EE_CHAR_COLOR } 160 }; 161 162 const SfxItemSet& rSet = rAttr.GetItemSet(); 163 const SfxPoolItem* pItem; 164 for (size_t i = 0; i < SAL_N_ELEMENTS(AttrTypeMap); ++i) 165 { 166 if ( rSet.GetItemState(AttrTypeMap[i].nAttrType, false, &pItem) == SfxItemState::SET ) 167 rEditText.RemoveCharAttribs(AttrTypeMap[i].nCharType); 168 } 169 } 170 171 std::unique_ptr<EditTextObject> ScEditUtil::Clone( const EditTextObject& rObj, ScDocument& rDestDoc ) 172 { 173 std::unique_ptr<EditTextObject> pNew; 174 175 EditEngine& rEngine = rDestDoc.GetEditEngine(); 176 if (rObj.HasOnlineSpellErrors()) 177 { 178 EEControlBits nControl = rEngine.GetControlWord(); 179 const EEControlBits nSpellControl = EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS; 180 bool bNewControl = ( (nControl & nSpellControl) != nSpellControl ); 181 if (bNewControl) 182 rEngine.SetControlWord(nControl | nSpellControl); 183 rEngine.SetText(rObj); 184 pNew = rEngine.CreateTextObject(); 185 if (bNewControl) 186 rEngine.SetControlWord(nControl); 187 } 188 else 189 { 190 rEngine.SetText(rObj); 191 pNew = rEngine.CreateTextObject(); 192 } 193 194 return pNew; 195 } 196 197 OUString ScEditUtil::GetCellFieldValue( 198 const SvxFieldData& rFieldData, const ScDocument* pDoc, boost::optional<Color>* ppTextColor ) 199 { 200 OUString aRet; 201 switch (rFieldData.GetClassId()) 202 { 203 case text::textfield::Type::URL: 204 { 205 const SvxURLField& rField = static_cast<const SvxURLField&>(rFieldData); 206 const OUString& aURL = rField.GetURL(); 207 208 switch (rField.GetFormat()) 209 { 210 case SvxURLFormat::AppDefault: //TODO: configurable with App??? 211 case SvxURLFormat::Repr: 212 aRet = rField.GetRepresentation(); 213 break; 214 case SvxURLFormat::Url: 215 aRet = aURL; 216 break; 217 default: 218 ; 219 } 220 221 svtools::ColorConfigEntry eEntry = 222 INetURLHistory::GetOrCreate()->QueryUrl(aURL) ? svtools::LINKSVISITED : svtools::LINKS; 223 224 if (ppTextColor) 225 *ppTextColor = SC_MOD()->GetColorConfig().GetColorValue(eEntry).nColor; 226 } 227 break; 228 case text::textfield::Type::EXTENDED_TIME: 229 { 230 const SvxExtTimeField& rField = static_cast<const SvxExtTimeField&>(rFieldData); 231 if (pDoc) 232 aRet = rField.GetFormatted(*pDoc->GetFormatTable(), ScGlobal::eLnge); 233 else 234 { 235 /* TODO: quite expensive, we could have a global formatter? */ 236 SvNumberFormatter aFormatter( comphelper::getProcessComponentContext(), ScGlobal::eLnge ); 237 aRet = rField.GetFormatted(aFormatter, ScGlobal::eLnge); 238 } 239 } 240 break; 241 case text::textfield::Type::DATE: 242 { 243 Date aDate(Date::SYSTEM); 244 aRet = ScGlobal::pLocaleData->getDate(aDate); 245 } 246 break; 247 case text::textfield::Type::DOCINFO_TITLE: 248 { 249 if (pDoc) 250 { 251 SfxObjectShell* pDocShell = pDoc->GetDocumentShell(); 252 if (pDocShell) 253 { 254 aRet = pDocShell->getDocProperties()->getTitle(); 255 if (aRet.isEmpty()) 256 aRet = pDocShell->GetTitle(); 257 } 258 } 259 if (aRet.isEmpty()) 260 aRet = "?"; 261 } 262 break; 263 case text::textfield::Type::TABLE: 264 { 265 const SvxTableField& rField = static_cast<const SvxTableField&>(rFieldData); 266 SCTAB nTab = rField.GetTab(); 267 OUString aName; 268 if (pDoc && pDoc->GetName(nTab, aName)) 269 aRet = aName; 270 else 271 aRet = "?"; 272 } 273 break; 274 default: 275 aRet = "?"; 276 } 277 278 if (aRet.isEmpty()) // empty is yuck 279 aRet = " "; // space is default of EditEngine 280 281 return aRet; 282 } 283 284 tools::Rectangle ScEditUtil::GetEditArea( const ScPatternAttr* pPattern, bool bForceToTop ) 285 { 286 // bForceToTop = always align to top, for editing 287 // (sal_False for querying URLs etc.) 288 289 if (!pPattern) 290 pPattern = pDoc->GetPattern( nCol, nRow, nTab ); 291 292 Point aStartPos = aScrPos; 293 294 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); 295 long nLayoutSign = bLayoutRTL ? -1 : 1; 296 297 const ScMergeAttr* pMerge = &pPattern->GetItem(ATTR_MERGE); 298 long nCellX = static_cast<long>( pDoc->GetColWidth(nCol,nTab) * nPPTX ); 299 if ( pMerge->GetColMerge() > 1 ) 300 { 301 SCCOL nCountX = pMerge->GetColMerge(); 302 for (SCCOL i=1; i<nCountX; i++) 303 nCellX += static_cast<long>( pDoc->GetColWidth(nCol+i,nTab) * nPPTX ); 304 } 305 long nCellY = static_cast<long>( pDoc->GetRowHeight(nRow,nTab) * nPPTY ); 306 if ( pMerge->GetRowMerge() > 1 ) 307 { 308 SCROW nCountY = pMerge->GetRowMerge(); 309 nCellY += static_cast<long>(pDoc->GetScaledRowHeight( nRow+1, nRow+nCountY-1, nTab, nPPTY)); 310 } 311 312 const SvxMarginItem* pMargin = &pPattern->GetItem(ATTR_MARGIN); 313 sal_uInt16 nIndent = 0; 314 if ( pPattern->GetItem(ATTR_HOR_JUSTIFY).GetValue() == 315 SvxCellHorJustify::Left ) 316 nIndent = pPattern->GetItem(ATTR_INDENT).GetValue(); 317 long nPixDifX = static_cast<long>( ( pMargin->GetLeftMargin() + nIndent ) * nPPTX ); 318 aStartPos.AdjustX(nPixDifX * nLayoutSign ); 319 nCellX -= nPixDifX + static_cast<long>( pMargin->GetRightMargin() * nPPTX ); // due to line feed, etc. 320 321 // align vertical position to the one in the table 322 323 long nPixDifY; 324 long nTopMargin = static_cast<long>( pMargin->GetTopMargin() * nPPTY ); 325 SvxCellVerJustify eJust = pPattern->GetItem(ATTR_VER_JUSTIFY).GetValue(); 326 327 // asian vertical is always edited top-aligned 328 bool bAsianVertical = pPattern->GetItem( ATTR_STACKED ).GetValue() && 329 pPattern->GetItem( ATTR_VERTICAL_ASIAN ).GetValue(); 330 331 if ( eJust == SvxCellVerJustify::Top || 332 ( bForceToTop && ( SC_MOD()->GetInputOptions().GetTextWysiwyg() || bAsianVertical ) ) ) 333 nPixDifY = nTopMargin; 334 else 335 { 336 MapMode aMode = pDev->GetMapMode(); 337 pDev->SetMapMode(MapMode(MapUnit::MapPixel)); 338 339 long nTextHeight = pDoc->GetNeededSize( nCol, nRow, nTab, 340 pDev, nPPTX, nPPTY, aZoomX, aZoomY, false ); 341 if (!nTextHeight) 342 { // empty cell 343 vcl::Font aFont; 344 // font color doesn't matter here 345 pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aZoomY ); 346 pDev->SetFont(aFont); 347 nTextHeight = pDev->GetTextHeight() + nTopMargin + 348 static_cast<long>( pMargin->GetBottomMargin() * nPPTY ); 349 } 350 351 pDev->SetMapMode(aMode); 352 353 if ( nTextHeight > nCellY + nTopMargin || bForceToTop ) 354 nPixDifY = 0; // too large -> begin at the top 355 else 356 { 357 if ( eJust == SvxCellVerJustify::Center ) 358 nPixDifY = nTopMargin + ( nCellY - nTextHeight ) / 2; 359 else 360 nPixDifY = nCellY - nTextHeight + nTopMargin; // JUSTIFY_BOTTOM 361 } 362 } 363 364 aStartPos.AdjustY(nPixDifY ); 365 nCellY -= nPixDifY; 366 367 if ( bLayoutRTL ) 368 aStartPos.AdjustX( -(nCellX - 2) ); // excluding grid on both sides 369 370 // -1 -> don't overwrite grid 371 return tools::Rectangle( aStartPos, Size(nCellX-1,nCellY-1) ); 372 } 373 374 ScEditAttrTester::ScEditAttrTester( ScEditEngineDefaulter* pEng ) : 375 pEngine( pEng ), 376 bNeedsObject( false ), 377 bNeedsCellAttr( false ) 378 { 379 if ( pEngine->GetParagraphCount() > 1 ) 380 { 381 bNeedsObject = true; //TODO: find cell attributes ? 382 } 383 else 384 { 385 const SfxPoolItem* pItem = nullptr; 386 pEditAttrs.reset( new SfxItemSet( pEngine->GetAttribs( 387 ESelection(0,0,0,pEngine->GetTextLen(0)), EditEngineAttribs::OnlyHard ) ) ); 388 const SfxItemSet& rEditDefaults = pEngine->GetDefaults(); 389 390 for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bNeedsObject; nId++) 391 { 392 SfxItemState eState = pEditAttrs->GetItemState( nId, false, &pItem ); 393 if (eState == SfxItemState::DONTCARE) 394 bNeedsObject = true; 395 else if (eState == SfxItemState::SET) 396 { 397 if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING || 398 nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS ) 399 { 400 // Escapement and kerning are kept in EditEngine because there are no 401 // corresponding cell format items. User defined attributes are kept in 402 // EditEngine because "user attributes applied to all the text" is different 403 // from "user attributes applied to the cell". 404 405 if ( *pItem != rEditDefaults.Get(nId) ) 406 bNeedsObject = true; 407 } 408 else 409 if (!bNeedsCellAttr) 410 if ( *pItem != rEditDefaults.Get(nId) ) 411 bNeedsCellAttr = true; 412 // rEditDefaults contains the defaults from the cell format 413 } 414 } 415 416 // contains field commands? 417 418 SfxItemState eFieldState = pEditAttrs->GetItemState( EE_FEATURE_FIELD, false ); 419 if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET ) 420 bNeedsObject = true; 421 422 // not converted characters? 423 424 SfxItemState eConvState = pEditAttrs->GetItemState( EE_FEATURE_NOTCONV, false ); 425 if ( eConvState == SfxItemState::DONTCARE || eConvState == SfxItemState::SET ) 426 bNeedsObject = true; 427 } 428 } 429 430 ScEditAttrTester::~ScEditAttrTester() 431 { 432 } 433 434 ScEnginePoolHelper::ScEnginePoolHelper( SfxItemPool* pEnginePoolP, 435 bool bDeleteEnginePoolP ) 436 : 437 pEnginePool( pEnginePoolP ), 438 pDefaults( nullptr ), 439 bDeleteEnginePool( bDeleteEnginePoolP ), 440 bDeleteDefaults( false ) 441 { 442 } 443 444 ScEnginePoolHelper::ScEnginePoolHelper( const ScEnginePoolHelper& rOrg ) 445 : 446 pEnginePool( rOrg.bDeleteEnginePool ? rOrg.pEnginePool->Clone() : rOrg.pEnginePool ), 447 pDefaults( nullptr ), 448 bDeleteEnginePool( rOrg.bDeleteEnginePool ), 449 bDeleteDefaults( false ) 450 { 451 } 452 453 ScEnginePoolHelper::~ScEnginePoolHelper() 454 { 455 if ( bDeleteDefaults ) 456 delete pDefaults; 457 if ( bDeleteEnginePool ) 458 SfxItemPool::Free(pEnginePool); 459 } 460 461 ScEditEngineDefaulter::ScEditEngineDefaulter( SfxItemPool* pEnginePoolP, 462 bool bDeleteEnginePoolP ) 463 : 464 ScEnginePoolHelper( pEnginePoolP, bDeleteEnginePoolP ), 465 EditEngine( pEnginePoolP ) 466 { 467 // All EditEngines use ScGlobal::GetEditDefaultLanguage as DefaultLanguage. 468 // DefaultLanguage for InputHandler's EditEngine is updated later. 469 470 SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() ); 471 } 472 473 ScEditEngineDefaulter::ScEditEngineDefaulter( const ScEditEngineDefaulter& rOrg ) 474 : 475 ScEnginePoolHelper( rOrg ), 476 EditEngine( pEnginePool ) 477 { 478 SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() ); 479 } 480 481 ScEditEngineDefaulter::~ScEditEngineDefaulter() 482 { 483 } 484 485 void ScEditEngineDefaulter::SetDefaults( const SfxItemSet& rSet, bool bRememberCopy ) 486 { 487 if ( bRememberCopy ) 488 { 489 if ( bDeleteDefaults ) 490 delete pDefaults; 491 pDefaults = new SfxItemSet( rSet ); 492 bDeleteDefaults = true; 493 } 494 const SfxItemSet& rNewSet = bRememberCopy ? *pDefaults : rSet; 495 bool bUndo = IsUndoEnabled(); 496 EnableUndo( false ); 497 bool bUpdateMode = GetUpdateMode(); 498 if ( bUpdateMode ) 499 SetUpdateMode( false ); 500 sal_Int32 nPara = GetParagraphCount(); 501 for ( sal_Int32 j=0; j<nPara; j++ ) 502 { 503 SetParaAttribs( j, rNewSet ); 504 } 505 if ( bUpdateMode ) 506 SetUpdateMode( true ); 507 if ( bUndo ) 508 EnableUndo( true ); 509 } 510 511 void ScEditEngineDefaulter::SetDefaults( SfxItemSet* pSet ) 512 { 513 if ( bDeleteDefaults ) 514 delete pDefaults; 515 pDefaults = pSet; 516 bDeleteDefaults = true; 517 if ( pDefaults ) 518 SetDefaults( *pDefaults, false ); 519 } 520 521 void ScEditEngineDefaulter::SetDefaultItem( const SfxPoolItem& rItem ) 522 { 523 if ( !pDefaults ) 524 { 525 pDefaults = new SfxItemSet( GetEmptyItemSet() ); 526 bDeleteDefaults = true; 527 } 528 pDefaults->Put( rItem ); 529 SetDefaults( *pDefaults, false ); 530 } 531 532 const SfxItemSet& ScEditEngineDefaulter::GetDefaults() 533 { 534 if ( !pDefaults ) 535 { 536 pDefaults = new SfxItemSet( GetEmptyItemSet() ); 537 bDeleteDefaults = true; 538 } 539 return *pDefaults; 540 } 541 542 void ScEditEngineDefaulter::SetText( const EditTextObject& rTextObject ) 543 { 544 bool bUpdateMode = GetUpdateMode(); 545 if ( bUpdateMode ) 546 SetUpdateMode( false ); 547 EditEngine::SetText( rTextObject ); 548 if ( pDefaults ) 549 SetDefaults( *pDefaults, false ); 550 if ( bUpdateMode ) 551 SetUpdateMode( true ); 552 } 553 554 void ScEditEngineDefaulter::SetTextNewDefaults( const EditTextObject& rTextObject, 555 const SfxItemSet& rSet, bool bRememberCopy ) 556 { 557 bool bUpdateMode = GetUpdateMode(); 558 if ( bUpdateMode ) 559 SetUpdateMode( false ); 560 EditEngine::SetText( rTextObject ); 561 SetDefaults( rSet, bRememberCopy ); 562 if ( bUpdateMode ) 563 SetUpdateMode( true ); 564 } 565 566 void ScEditEngineDefaulter::SetTextNewDefaults( const EditTextObject& rTextObject, 567 SfxItemSet* pSet ) 568 { 569 bool bUpdateMode = GetUpdateMode(); 570 if ( bUpdateMode ) 571 SetUpdateMode( false ); 572 EditEngine::SetText( rTextObject ); 573 SetDefaults( pSet ); 574 if ( bUpdateMode ) 575 SetUpdateMode( true ); 576 } 577 578 void ScEditEngineDefaulter::SetText( const OUString& rText ) 579 { 580 bool bUpdateMode = GetUpdateMode(); 581 if ( bUpdateMode ) 582 SetUpdateMode( false ); 583 EditEngine::SetText( rText ); 584 if ( pDefaults ) 585 SetDefaults( *pDefaults, false ); 586 if ( bUpdateMode ) 587 SetUpdateMode( true ); 588 } 589 590 void ScEditEngineDefaulter::SetTextNewDefaults( const OUString& rText, 591 const SfxItemSet& rSet ) 592 { 593 bool bUpdateMode = GetUpdateMode(); 594 if ( bUpdateMode ) 595 SetUpdateMode( false ); 596 EditEngine::SetText( rText ); 597 SetDefaults( rSet ); 598 if ( bUpdateMode ) 599 SetUpdateMode( true ); 600 } 601 602 void ScEditEngineDefaulter::SetTextNewDefaults( const OUString& rText, 603 SfxItemSet* pSet ) 604 { 605 bool bUpdateMode = GetUpdateMode(); 606 if ( bUpdateMode ) 607 SetUpdateMode( false ); 608 EditEngine::SetText( rText ); 609 SetDefaults( pSet ); 610 if ( bUpdateMode ) 611 SetUpdateMode( true ); 612 } 613 614 void ScEditEngineDefaulter::RepeatDefaults() 615 { 616 if ( pDefaults ) 617 { 618 sal_Int32 nPara = GetParagraphCount(); 619 for ( sal_Int32 j=0; j<nPara; j++ ) 620 SetParaAttribs( j, *pDefaults ); 621 } 622 } 623 624 void ScEditEngineDefaulter::RemoveParaAttribs() 625 { 626 std::unique_ptr<SfxItemSet> pCharItems; 627 bool bUpdateMode = GetUpdateMode(); 628 if ( bUpdateMode ) 629 SetUpdateMode( false ); 630 sal_Int32 nParCount = GetParagraphCount(); 631 for (sal_Int32 nPar=0; nPar<nParCount; nPar++) 632 { 633 const SfxItemSet& rParaAttribs = GetParaAttribs( nPar ); 634 sal_uInt16 nWhich; 635 for (nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich ++) 636 { 637 const SfxPoolItem* pParaItem; 638 if ( rParaAttribs.GetItemState( nWhich, false, &pParaItem ) == SfxItemState::SET ) 639 { 640 // if defaults are set, use only items that are different from default 641 if ( !pDefaults || *pParaItem != pDefaults->Get(nWhich) ) 642 { 643 if (!pCharItems) 644 pCharItems.reset(new SfxItemSet( GetEmptyItemSet() )); 645 pCharItems->Put( *pParaItem ); 646 } 647 } 648 } 649 650 if ( pCharItems ) 651 { 652 std::vector<sal_Int32> aPortions; 653 GetPortions( nPar, aPortions ); 654 655 // loop through the portions of the paragraph, and set only those items 656 // that are not overridden by existing character attributes 657 658 sal_Int32 nStart = 0; 659 for ( const sal_Int32 nEnd : aPortions ) 660 { 661 ESelection aSel( nPar, nStart, nPar, nEnd ); 662 SfxItemSet aOldCharAttrs = GetAttribs( aSel ); 663 SfxItemSet aNewCharAttrs = *pCharItems; 664 for (nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich ++) 665 { 666 // Clear those items that are different from existing character attributes. 667 // Where no character attributes are set, GetAttribs returns the paragraph attributes. 668 const SfxPoolItem* pItem; 669 if ( aNewCharAttrs.GetItemState( nWhich, false, &pItem ) == SfxItemState::SET && 670 *pItem != aOldCharAttrs.Get(nWhich) ) 671 { 672 aNewCharAttrs.ClearItem(nWhich); 673 } 674 } 675 if ( aNewCharAttrs.Count() ) 676 QuickSetAttribs( aNewCharAttrs, aSel ); 677 678 nStart = nEnd; 679 } 680 681 pCharItems.reset(); 682 } 683 684 if ( rParaAttribs.Count() ) 685 { 686 // clear all paragraph attributes (including defaults), 687 // so they are not contained in resulting EditTextObjects 688 689 SetParaAttribs( nPar, SfxItemSet( *rParaAttribs.GetPool(), rParaAttribs.GetRanges() ) ); 690 } 691 } 692 if ( bUpdateMode ) 693 SetUpdateMode( true ); 694 } 695 696 ScTabEditEngine::ScTabEditEngine( ScDocument* pDoc ) 697 : ScFieldEditEngine( pDoc, pDoc->GetEnginePool() ) 698 { 699 SetEditTextObjectPool( pDoc->GetEditPool() ); 700 Init(pDoc->GetPool()->GetDefaultItem(ATTR_PATTERN)); 701 } 702 703 ScTabEditEngine::ScTabEditEngine( const ScPatternAttr& rPattern, 704 SfxItemPool* pEngineItemPool, ScDocument* pDoc, SfxItemPool* pTextObjectPool ) 705 : ScFieldEditEngine( pDoc, pEngineItemPool, pTextObjectPool ) 706 { 707 if ( pTextObjectPool ) 708 SetEditTextObjectPool( pTextObjectPool ); 709 Init( rPattern ); 710 } 711 712 void ScTabEditEngine::Init( const ScPatternAttr& rPattern ) 713 { 714 SetRefMapMode(MapMode(MapUnit::Map100thMM)); 715 SfxItemSet* pEditDefaults = new SfxItemSet( GetEmptyItemSet() ); 716 rPattern.FillEditItemSet( pEditDefaults ); 717 SetDefaults( pEditDefaults ); 718 // we have no StyleSheets for text 719 SetControlWord( GetControlWord() & ~EEControlBits::RTFSTYLESHEETS ); 720 } 721 722 // field commands for header and footer 723 724 // numbers from \sw\source\core\doc\numbers.cxx 725 726 static OUString lcl_GetCharStr( sal_Int32 nNo ) 727 { 728 OSL_ENSURE( nNo, "0 is an invalid number !!" ); 729 OUString aStr; 730 731 const sal_Int32 coDiff = 'Z' - 'A' +1; 732 sal_Int32 nCalc; 733 734 do { 735 nCalc = nNo % coDiff; 736 if( !nCalc ) 737 nCalc = coDiff; 738 aStr = OUStringLiteral1( 'a' - 1 + nCalc ) + aStr; 739 nNo = sal::static_int_cast<sal_Int32>( nNo - nCalc ); 740 if( nNo ) 741 nNo /= coDiff; 742 } while( nNo ); 743 return aStr; 744 } 745 746 static OUString lcl_GetNumStr(sal_Int32 nNo, SvxNumType eType) 747 { 748 OUString aTmpStr('0'); 749 if( nNo ) 750 { 751 switch( eType ) 752 { 753 case css::style::NumberingType::CHARS_UPPER_LETTER: 754 case css::style::NumberingType::CHARS_LOWER_LETTER: 755 aTmpStr = lcl_GetCharStr( nNo ); 756 break; 757 758 case css::style::NumberingType::ROMAN_UPPER: 759 case css::style::NumberingType::ROMAN_LOWER: 760 if( nNo < 4000 ) 761 aTmpStr = SvxNumberFormat::CreateRomanString( nNo, ( eType == css::style::NumberingType::ROMAN_UPPER ) ); 762 else 763 aTmpStr.clear(); 764 break; 765 766 case css::style::NumberingType::NUMBER_NONE: 767 aTmpStr.clear(); 768 break; 769 770 // CHAR_SPECIAL: 771 // ???? 772 773 // case ARABIC: is default now 774 default: 775 aTmpStr = OUString::number(nNo); 776 break; 777 } 778 779 if( css::style::NumberingType::CHARS_UPPER_LETTER == eType ) 780 aTmpStr = aTmpStr.toAsciiUpperCase(); 781 } 782 return aTmpStr; 783 } 784 785 ScHeaderFieldData::ScHeaderFieldData() 786 : aDateTime ( DateTime::EMPTY ) 787 { 788 nPageNo = nTotalPages = 0; 789 eNumType = SVX_NUM_ARABIC; 790 } 791 792 ScHeaderEditEngine::ScHeaderEditEngine( SfxItemPool* pEnginePoolP ) 793 : ScEditEngineDefaulter( pEnginePoolP,true/*bDeleteEnginePoolP*/ ) 794 { 795 } 796 797 OUString ScHeaderEditEngine::CalcFieldValue( const SvxFieldItem& rField, 798 sal_Int32 /* nPara */, sal_Int32 /* nPos */, 799 boost::optional<Color>& /* rTxtColor */, boost::optional<Color>& /* rFldColor */ ) 800 { 801 const SvxFieldData* pFieldData = rField.GetField(); 802 if (!pFieldData) 803 return OUString("?"); 804 805 OUString aRet; 806 sal_Int32 nClsId = pFieldData->GetClassId(); 807 switch (nClsId) 808 { 809 case text::textfield::Type::PAGE: 810 aRet = lcl_GetNumStr( aData.nPageNo,aData.eNumType ); 811 break; 812 case text::textfield::Type::PAGES: 813 aRet = lcl_GetNumStr( aData.nTotalPages,aData.eNumType ); 814 break; 815 case text::textfield::Type::EXTENDED_TIME: 816 case text::textfield::Type::TIME: 817 // For now, time field in the header / footer is always dynamic. 818 aRet = ScGlobal::pLocaleData->getTime(aData.aDateTime); 819 break; 820 case text::textfield::Type::DOCINFO_TITLE: 821 aRet = aData.aTitle; 822 break; 823 case text::textfield::Type::EXTENDED_FILE: 824 { 825 switch (static_cast<const SvxExtFileField*>(pFieldData)->GetFormat()) 826 { 827 case SvxFileFormat::PathFull : 828 aRet = aData.aLongDocName; 829 break; 830 default: 831 aRet = aData.aShortDocName; 832 } 833 } 834 break; 835 case text::textfield::Type::TABLE: 836 aRet = aData.aTabName; 837 break; 838 case text::textfield::Type::DATE: 839 aRet = ScGlobal::pLocaleData->getDate(aData.aDateTime); 840 break; 841 default: 842 aRet = "?"; 843 } 844 845 return aRet; 846 } 847 848 // field data 849 850 ScFieldEditEngine::ScFieldEditEngine( 851 ScDocument* pDoc, SfxItemPool* pEnginePoolP, 852 SfxItemPool* pTextObjectPool, bool bDeleteEnginePoolP) : 853 ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP ), 854 mpDoc(pDoc), bExecuteURL(true) 855 { 856 if ( pTextObjectPool ) 857 SetEditTextObjectPool( pTextObjectPool ); 858 SetControlWord( EEControlBits(GetControlWord() | EEControlBits::MARKFIELDS) & ~EEControlBits::RTFSTYLESHEETS ); 859 } 860 861 OUString ScFieldEditEngine::CalcFieldValue( const SvxFieldItem& rField, 862 sal_Int32 /* nPara */, sal_Int32 /* nPos */, 863 boost::optional<Color>& rTxtColor, boost::optional<Color>& /* rFldColor */ ) 864 { 865 const SvxFieldData* pFieldData = rField.GetField(); 866 867 if (!pFieldData) 868 return OUString(" "); 869 870 return ScEditUtil::GetCellFieldValue(*pFieldData, mpDoc, &rTxtColor); 871 } 872 873 void ScFieldEditEngine::FieldClicked( const SvxFieldItem& rField, sal_Int32, sal_Int32 ) 874 { 875 if (!bExecuteURL) 876 return; 877 if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(rField.GetField())) 878 { 879 ScGlobal::OpenURL(pURLField->GetURL(), pURLField->GetTargetFrame()); 880 } 881 } 882 883 ScNoteEditEngine::ScNoteEditEngine( SfxItemPool* pEnginePoolP, 884 SfxItemPool* pTextObjectPool ) : 885 ScEditEngineDefaulter( pEnginePoolP, false/*bDeleteEnginePoolP*/ ) 886 { 887 if ( pTextObjectPool ) 888 SetEditTextObjectPool( pTextObjectPool ); 889 SetControlWord( EEControlBits(GetControlWord() | EEControlBits::MARKFIELDS) & ~EEControlBits::RTFSTYLESHEETS ); 890 } 891 892 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 893
