1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sc.hxx" 30 31 32 #define _ZFORLIST_DECLARE_TABLE 33 #include "scitems.hxx" 34 #include <editeng/eeitem.hxx> 35 36 #include <tools/string.hxx> 37 #include <editeng/editobj.hxx> 38 #include <editeng/editstat.hxx> 39 #include <editeng/frmdiritem.hxx> 40 #include <editeng/langitem.hxx> 41 #include <sfx2/linkmgr.hxx> 42 #include <editeng/scripttypeitem.hxx> 43 #include <editeng/unolingu.hxx> 44 #include <sfx2/bindings.hxx> 45 #include <sfx2/objsh.hxx> 46 #include <sfx2/printer.hxx> 47 #include <sfx2/viewfrm.hxx> 48 #include <sfx2/viewsh.hxx> 49 #include <svl/flagitem.hxx> 50 #include <svl/intitem.hxx> 51 #define _SVSTDARR_USHORTS 52 #include <svl/svstdarr.hxx> 53 #include <svl/zforlist.hxx> 54 #include <svl/zformat.hxx> 55 #include <unotools/misccfg.hxx> 56 #include <sfx2/app.hxx> 57 #include <unotools/transliterationwrapper.hxx> 58 #include <unotools/securityoptions.hxx> 59 60 #include <vcl/virdev.hxx> 61 #include <vcl/msgbox.hxx> 62 63 #include <com/sun/star/i18n/TransliterationModulesExtra.hpp> 64 65 #include "inputopt.hxx" 66 #include "global.hxx" 67 #include "table.hxx" 68 #include "column.hxx" 69 #include "cell.hxx" 70 #include "poolhelp.hxx" 71 #include "docpool.hxx" 72 #include "stlpool.hxx" 73 #include "stlsheet.hxx" 74 #include "docoptio.hxx" 75 #include "viewopti.hxx" 76 #include "scextopt.hxx" 77 #include "rechead.hxx" 78 #include "ddelink.hxx" 79 #include "scmatrix.hxx" 80 #include "arealink.hxx" 81 #include "dociter.hxx" 82 #include "patattr.hxx" 83 #include "hints.hxx" 84 #include "editutil.hxx" 85 #include "progress.hxx" 86 #include "document.hxx" 87 #include "chartlis.hxx" 88 #include "chartlock.hxx" 89 #include "refupdat.hxx" 90 #include "validat.hxx" // fuer HasMacroCalls 91 #include "markdata.hxx" 92 #include "scmod.hxx" 93 #include "printopt.hxx" 94 #include "externalrefmgr.hxx" 95 #include "globstr.hrc" 96 #include "sc.hrc" 97 #include "charthelper.hxx" 98 #include "dpobject.hxx" 99 #include "docuno.hxx" 100 101 #define GET_SCALEVALUE(set,id) ((const SfxUInt16Item&)(set.Get( id ))).GetValue() 102 103 // states for online spelling in the visible range (0 is set initially) 104 #define VSPL_START 0 105 #define VSPL_DONE 1 106 107 108 // STATIC DATA ----------------------------------------------------------- 109 110 //------------------------------------------------------------------------ 111 112 void ScDocument::ImplCreateOptions() 113 { 114 pDocOptions = new ScDocOptions(); 115 pViewOptions = new ScViewOptions(); 116 } 117 118 //------------------------------------------------------------------------ 119 120 void ScDocument::ImplDeleteOptions() 121 { 122 delete pDocOptions; 123 delete pViewOptions; 124 delete pExtDocOptions; 125 } 126 127 //------------------------------------------------------------------------ 128 129 SfxPrinter* ScDocument::GetPrinter(sal_Bool bCreateIfNotExist) 130 { 131 if ( !pPrinter && bCreateIfNotExist ) 132 { 133 SfxItemSet* pSet = 134 new SfxItemSet( *xPoolHelper->GetDocPool(), 135 SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN, 136 SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC, 137 SID_PRINT_SELECTEDSHEET, SID_PRINT_SELECTEDSHEET, 138 SID_SCPRINTOPTIONS, SID_SCPRINTOPTIONS, 139 NULL ); 140 141 ::utl::MiscCfg aMisc; 142 sal_uInt16 nFlags = 0; 143 if ( aMisc.IsPaperOrientationWarning() ) 144 nFlags |= SFX_PRINTER_CHG_ORIENTATION; 145 if ( aMisc.IsPaperSizeWarning() ) 146 nFlags |= SFX_PRINTER_CHG_SIZE; 147 pSet->Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, nFlags ) ); 148 pSet->Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, aMisc.IsNotFoundWarning() ) ); 149 150 pPrinter = new SfxPrinter( pSet ); 151 pPrinter->SetMapMode( MAP_100TH_MM ); 152 UpdateDrawPrinter(); 153 pPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() ); 154 } 155 156 return pPrinter; 157 } 158 159 //------------------------------------------------------------------------ 160 161 void ScDocument::SetPrinter( SfxPrinter* pNewPrinter ) 162 { 163 if ( pNewPrinter == pPrinter ) 164 { 165 // #i6706# SetPrinter is called with the same printer again if 166 // the JobSetup has changed. In that case just call UpdateDrawPrinter 167 // (SetRefDevice for drawing layer) because of changed text sizes. 168 UpdateDrawPrinter(); 169 } 170 else 171 { 172 SfxPrinter* pOld = pPrinter; 173 pPrinter = pNewPrinter; 174 UpdateDrawPrinter(); 175 pPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() ); 176 delete pOld; 177 } 178 InvalidateTextWidth(NULL, NULL, sal_False); // in both cases 179 } 180 181 //------------------------------------------------------------------------ 182 183 void ScDocument::SetPrintOptions() 184 { 185 if ( !pPrinter ) GetPrinter(); // setzt pPrinter 186 DBG_ASSERT( pPrinter, "Error in printer creation :-/" ); 187 188 if ( pPrinter ) 189 { 190 ::utl::MiscCfg aMisc; 191 SfxItemSet aOptSet( pPrinter->GetOptions() ); 192 193 sal_uInt16 nFlags = 0; 194 if ( aMisc.IsPaperOrientationWarning() ) 195 nFlags |= SFX_PRINTER_CHG_ORIENTATION; 196 if ( aMisc.IsPaperSizeWarning() ) 197 nFlags |= SFX_PRINTER_CHG_SIZE; 198 aOptSet.Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, nFlags ) ); 199 aOptSet.Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, aMisc.IsNotFoundWarning() ) ); 200 201 pPrinter->SetOptions( aOptSet ); 202 } 203 } 204 205 //------------------------------------------------------------------------ 206 207 VirtualDevice* ScDocument::GetVirtualDevice_100th_mm() 208 { 209 if (!pVirtualDevice_100th_mm) 210 { 211 // pVirtualDevice_100th_mm = new VirtualDevice; 212 // pVirtualDevice_100th_mm->SetMapMode( MAP_100TH_MM ); 213 214 pVirtualDevice_100th_mm = new VirtualDevice( 1 ); 215 pVirtualDevice_100th_mm->SetReferenceDevice(VirtualDevice::REFDEV_MODE_MSO1); 216 MapMode aMapMode( pVirtualDevice_100th_mm->GetMapMode() ); 217 aMapMode.SetMapUnit( MAP_100TH_MM ); 218 pVirtualDevice_100th_mm->SetMapMode( aMapMode ); 219 } 220 return pVirtualDevice_100th_mm; 221 } 222 223 OutputDevice* ScDocument::GetRefDevice() 224 { 225 // Create printer like ref device, see Writer... 226 OutputDevice* pRefDevice = NULL; 227 if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() ) 228 pRefDevice = GetPrinter(); 229 else 230 pRefDevice = GetVirtualDevice_100th_mm(); 231 return pRefDevice; 232 } 233 234 //------------------------------------------------------------------------ 235 236 void ScDocument::ModifyStyleSheet( SfxStyleSheetBase& rStyleSheet, 237 const SfxItemSet& rChanges ) 238 { 239 SfxItemSet& rSet = rStyleSheet.GetItemSet(); 240 241 switch ( rStyleSheet.GetFamily() ) 242 { 243 case SFX_STYLE_FAMILY_PAGE: 244 { 245 const sal_uInt16 nOldScale = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALE); 246 const sal_uInt16 nOldScaleToPages = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALETOPAGES); 247 rSet.Put( rChanges ); 248 const sal_uInt16 nNewScale = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALE); 249 const sal_uInt16 nNewScaleToPages = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALETOPAGES); 250 251 if ( (nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages) ) 252 InvalidateTextWidth( rStyleSheet.GetName() ); 253 254 if( SvtLanguageOptions().IsCTLFontEnabled() ) 255 { 256 const SfxPoolItem *pItem = NULL; 257 if( rChanges.GetItemState(ATTR_WRITINGDIR, sal_True, &pItem ) == SFX_ITEM_SET ) 258 ScChartHelper::DoUpdateAllCharts( this ); 259 } 260 } 261 break; 262 263 case SFX_STYLE_FAMILY_PARA: 264 { 265 sal_Bool bNumFormatChanged; 266 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, 267 rSet, rChanges ) ) 268 InvalidateTextWidth( NULL, NULL, bNumFormatChanged ); 269 270 for (SCTAB nTab=0; nTab<=MAXTAB; ++nTab) 271 if (pTab[nTab] && pTab[nTab]->IsStreamValid()) 272 pTab[nTab]->SetStreamValid( sal_False ); 273 274 sal_uLong nOldFormat = 275 ((const SfxUInt32Item*)&rSet.Get( 276 ATTR_VALUE_FORMAT ))->GetValue(); 277 sal_uLong nNewFormat = 278 ((const SfxUInt32Item*)&rChanges.Get( 279 ATTR_VALUE_FORMAT ))->GetValue(); 280 LanguageType eNewLang, eOldLang; 281 eNewLang = eOldLang = LANGUAGE_DONTKNOW; 282 if ( nNewFormat != nOldFormat ) 283 { 284 SvNumberFormatter* pFormatter = GetFormatTable(); 285 eOldLang = pFormatter->GetEntry( nOldFormat )->GetLanguage(); 286 eNewLang = pFormatter->GetEntry( nNewFormat )->GetLanguage(); 287 } 288 289 // Bedeutung der Items in rChanges: 290 // Item gesetzt - Aenderung uebernehmen 291 // Dontcare - Default setzen 292 // Default - keine Aenderung 293 // ("keine Aenderung" geht nicht mit PutExtended, darum Schleife) 294 for (sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; nWhich++) 295 { 296 const SfxPoolItem* pItem; 297 SfxItemState eState = rChanges.GetItemState( nWhich, sal_False, &pItem ); 298 if ( eState == SFX_ITEM_SET ) 299 rSet.Put( *pItem ); 300 else if ( eState == SFX_ITEM_DONTCARE ) 301 rSet.ClearItem( nWhich ); 302 // bei Default nichts 303 } 304 305 if ( eNewLang != eOldLang ) 306 rSet.Put( 307 SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) ); 308 } 309 break; 310 default: 311 { 312 // added to avoid warnings 313 } 314 } 315 } 316 317 //------------------------------------------------------------------------ 318 319 void ScDocument::CopyStdStylesFrom( ScDocument* pSrcDoc ) 320 { 321 // #b5017505# number format exchange list has to be handled here, too 322 NumFmtMergeHandler aNumFmtMergeHdl(this, pSrcDoc); 323 xPoolHelper->GetStylePool()->CopyStdStylesFrom( pSrcDoc->xPoolHelper->GetStylePool() ); 324 } 325 326 //------------------------------------------------------------------------ 327 328 void ScDocument::InvalidateTextWidth( const String& rStyleName ) 329 { 330 const SCTAB nCount = GetTableCount(); 331 for ( SCTAB i=0; i<nCount && pTab[i]; i++ ) 332 if ( pTab[i]->GetPageStyle() == rStyleName ) 333 InvalidateTextWidth( i ); 334 } 335 336 //------------------------------------------------------------------------ 337 338 void ScDocument::InvalidateTextWidth( SCTAB nTab ) 339 { 340 ScAddress aAdrFrom( 0, 0, nTab ); 341 ScAddress aAdrTo ( MAXCOL, MAXROW, nTab ); 342 InvalidateTextWidth( &aAdrFrom, &aAdrTo, sal_False ); 343 } 344 345 //------------------------------------------------------------------------ 346 347 sal_Bool ScDocument::IsPageStyleInUse( const String& rStrPageStyle, SCTAB* pInTab ) 348 { 349 sal_Bool bInUse = sal_False; 350 const SCTAB nCount = GetTableCount(); 351 SCTAB i; 352 353 for ( i = 0; !bInUse && i < nCount && pTab[i]; i++ ) 354 bInUse = ( pTab[i]->GetPageStyle() == rStrPageStyle ); 355 356 if ( pInTab ) 357 *pInTab = i-1; 358 359 return bInUse; 360 } 361 362 //------------------------------------------------------------------------ 363 364 sal_Bool ScDocument::RemovePageStyleInUse( const String& rStyle ) 365 { 366 sal_Bool bWasInUse = sal_False; 367 const SCTAB nCount = GetTableCount(); 368 369 for ( SCTAB i=0; i<nCount && pTab[i]; i++ ) 370 if ( pTab[i]->GetPageStyle() == rStyle ) 371 { 372 bWasInUse = sal_True; 373 pTab[i]->SetPageStyle( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) ); 374 } 375 376 return bWasInUse; 377 } 378 379 sal_Bool ScDocument::RenamePageStyleInUse( const String& rOld, const String& rNew ) 380 { 381 sal_Bool bWasInUse = sal_False; 382 const SCTAB nCount = GetTableCount(); 383 384 for ( SCTAB i=0; i<nCount && pTab[i]; i++ ) 385 if ( pTab[i]->GetPageStyle() == rOld ) 386 { 387 bWasInUse = sal_True; 388 pTab[i]->SetPageStyle( rNew ); 389 } 390 391 return bWasInUse; 392 } 393 394 //------------------------------------------------------------------------ 395 396 sal_uInt8 ScDocument::GetEditTextDirection(SCTAB nTab) const 397 { 398 EEHorizontalTextDirection eRet = EE_HTEXTDIR_DEFAULT; 399 400 String aStyleName = GetPageStyle( nTab ); 401 SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aStyleName, SFX_STYLE_FAMILY_PAGE ); 402 if ( pStyle ) 403 { 404 SfxItemSet& rStyleSet = pStyle->GetItemSet(); 405 SvxFrameDirection eDirection = (SvxFrameDirection) 406 ((const SvxFrameDirectionItem&)rStyleSet.Get( ATTR_WRITINGDIR )).GetValue(); 407 408 if ( eDirection == FRMDIR_HORI_LEFT_TOP ) 409 eRet = EE_HTEXTDIR_L2R; 410 else if ( eDirection == FRMDIR_HORI_RIGHT_TOP ) 411 eRet = EE_HTEXTDIR_R2L; 412 // else (invalid for EditEngine): keep "default" 413 } 414 415 return sal::static_int_cast<sal_uInt8>(eRet); 416 } 417 418 //------------------------------------------------------------------------ 419 420 void ScDocument::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo, 421 sal_Bool bNumFormatChanged ) 422 { 423 sal_Bool bBroadcast = (bNumFormatChanged && GetDocOptions().IsCalcAsShown() && !IsImportingXML() && !IsClipboard()); 424 if ( pAdrFrom && !pAdrTo ) 425 { 426 const SCTAB nTab = pAdrFrom->Tab(); 427 428 if ( pTab[nTab] ) 429 pTab[nTab]->InvalidateTextWidth( pAdrFrom, NULL, bNumFormatChanged, bBroadcast ); 430 } 431 else 432 { 433 const SCTAB nTabStart = pAdrFrom ? pAdrFrom->Tab() : 0; 434 const SCTAB nTabEnd = pAdrTo ? pAdrTo->Tab() : MAXTAB; 435 436 for ( SCTAB nTab=nTabStart; nTab<=nTabEnd; nTab++ ) 437 if ( pTab[nTab] ) 438 pTab[nTab]->InvalidateTextWidth( pAdrFrom, pAdrTo, bNumFormatChanged, bBroadcast ); 439 } 440 } 441 442 //------------------------------------------------------------------------ 443 444 #define CALCMAX 1000 // Berechnungen 445 #define ABORT_EVENTS (INPUT_ANY & ~INPUT_TIMER & ~INPUT_OTHER) 446 447 sal_Bool ScDocument::IdleCalcTextWidth() // sal_True = demnaechst wieder versuchen 448 { 449 // #i75610# if a printer hasn't been set or created yet, don't create one for this 450 if ( bIdleDisabled || IsInLinkUpdate() || GetPrinter(sal_False) == NULL ) 451 return sal_False; 452 bIdleDisabled = sal_True; 453 454 // sal_uLong nMs = 0; 455 // sal_uInt16 nIter = 0; 456 457 const sal_uLong nStart = Time::GetSystemTicks(); 458 double nPPTX = 0.0; 459 double nPPTY = 0.0; 460 OutputDevice* pDev = NULL; 461 MapMode aOldMap; 462 ScStyleSheet* pStyle = NULL; 463 ScColumnIterator* pColIter = NULL; 464 ScTable* pTable = NULL; 465 ScColumn* pColumn = NULL; 466 ScBaseCell* pCell = NULL; 467 SCTAB nTab = aCurTextWidthCalcPos.Tab(); 468 SCROW nRow = aCurTextWidthCalcPos.Row(); 469 SCsCOL nCol = aCurTextWidthCalcPos.Col(); 470 sal_uInt16 nRestart = 0; 471 sal_uInt16 nZoom = 0; 472 sal_Bool bNeedMore= sal_False; 473 474 if ( !ValidRow(nRow) ) 475 nRow = 0, nCol--; 476 if ( nCol < 0 ) 477 nCol = MAXCOL, nTab++; 478 if ( !ValidTab(nTab) || !pTab[nTab] ) 479 nTab = 0; 480 481 // DBG_ERROR( String("Start = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) ); 482 483 // SearchMask/Family muss gemerkt werden, 484 // damit z.B. der Organizer nicht durcheinanderkommt, wenn zwischendurch eine 485 // Query-Box aufgemacht wird !!! 486 487 ScStyleSheetPool* pStylePool = xPoolHelper->GetStylePool(); 488 sal_uInt16 nOldMask = pStylePool->GetSearchMask(); 489 SfxStyleFamily eOldFam = pStylePool->GetSearchFamily(); 490 491 pTable = pTab[nTab]; 492 pStylePool->SetSearchMask( SFX_STYLE_FAMILY_PAGE, SFXSTYLEBIT_ALL ); 493 pStyle = (ScStyleSheet*)pStylePool->Find( pTable->aPageStyle, 494 SFX_STYLE_FAMILY_PAGE ); 495 496 DBG_ASSERT( pStyle, "Missing StyleSheet :-/" ); 497 498 sal_Bool bProgress = sal_False; 499 if ( pStyle && 0 == GET_SCALEVALUE(pStyle->GetItemSet(),ATTR_PAGE_SCALETOPAGES) ) 500 { 501 sal_uInt16 nCount = 0; 502 503 nZoom = GET_SCALEVALUE(pStyle->GetItemSet(),ATTR_PAGE_SCALE); 504 Fraction aZoomFract( nZoom, 100 ); 505 pColumn = &pTable->aCol[nCol]; 506 pColIter = new ScColumnIterator( pColumn, nRow, MAXROW ); 507 508 while ( (nZoom > 0) && (nCount < CALCMAX) && (nRestart < 2) ) 509 { 510 if ( pColIter->Next( nRow, pCell ) ) 511 { 512 if ( TEXTWIDTH_DIRTY == pCell->GetTextWidth() ) 513 { 514 if ( !pDev ) 515 { 516 pDev = GetPrinter(); 517 aOldMap = pDev->GetMapMode(); 518 pDev->SetMapMode( MAP_PIXEL ); // wichtig fuer GetNeededSize 519 520 Point aPix1000 = pDev->LogicToPixel( Point(1000,1000), MAP_TWIP ); 521 nPPTX = aPix1000.X() / 1000.0; 522 nPPTY = aPix1000.Y() / 1000.0; 523 } 524 if ( !bProgress && pCell->GetCellType() == CELLTYPE_FORMULA 525 && ((ScFormulaCell*)pCell)->GetDirty() ) 526 { 527 ScProgress::CreateInterpretProgress( this, sal_False ); 528 bProgress = sal_True; 529 } 530 531 // DBG_ERROR( String("t,c,r = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) ); 532 // DBG_ERROR( String("nOldWidth = ") + String(pCell->GetTextWidth()) ); 533 534 sal_uInt16 nNewWidth = (sal_uInt16)GetNeededSize( nCol, nRow, nTab, 535 pDev, nPPTX, nPPTY, 536 aZoomFract,aZoomFract, sal_True, 537 sal_True ); // bTotalSize 538 539 // DBG_ERROR( String("nNewWidth = ") + String(nNewWidth) ); 540 541 pCell->SetTextWidth( nNewWidth ); 542 543 bNeedMore = sal_True; 544 } 545 } 546 else 547 { 548 sal_Bool bNewTab = sal_False; 549 550 nRow = 0; 551 nCol--; 552 553 if ( nCol < 0 ) 554 { 555 nCol = MAXCOL; 556 nTab++; 557 bNewTab = sal_True; 558 } 559 560 if ( !ValidTab(nTab) || !pTab[nTab] ) 561 { 562 nTab = 0; 563 nRestart++; 564 bNewTab = sal_True; 565 } 566 567 if ( nRestart < 2 ) 568 { 569 if ( bNewTab ) 570 { 571 pTable = pTab[nTab]; 572 pStyle = (ScStyleSheet*)pStylePool->Find( pTable->aPageStyle, 573 SFX_STYLE_FAMILY_PAGE ); 574 575 if ( pStyle ) 576 { 577 SfxItemSet& rSet = pStyle->GetItemSet(); 578 if ( GET_SCALEVALUE( rSet, ATTR_PAGE_SCALETOPAGES ) == 0 ) 579 nZoom = GET_SCALEVALUE(rSet, ATTR_PAGE_SCALE ); 580 else 581 nZoom = 0; 582 } 583 else 584 { 585 DBG_ERROR( "Missing StyleSheet :-/" ); 586 } 587 } 588 589 if ( nZoom > 0 ) 590 { 591 delete pColIter; 592 593 pColumn = &pTable->aCol[nCol]; 594 pColIter = new ScColumnIterator( pColumn, nRow, MAXROW ); 595 } 596 else 597 nTab++; // Tabelle nicht mit absolutem Zoom -> naechste 598 } 599 } 600 601 // nIter = nCount; 602 603 nCount++; 604 605 // Idle Berechnung abbrechen, wenn Berechnungen laenger als 606 // 50ms dauern, oder nach 32 Berechnungen mal nachschauen, ob 607 // bestimmte Events anstehen, die Beachtung wuenschen: 608 609 // nMs = SysTicksToMs( GetSysTicks() - nStart ); 610 611 if ( ( 50L < Time::GetSystemTicks() - nStart ) 612 || ( !(nCount&31) && Application::AnyInput( ABORT_EVENTS ) ) ) 613 nCount = CALCMAX; 614 } 615 } 616 else 617 nTab++; // Tabelle nicht mit absolutem Zoom -> naechste 618 619 if ( bProgress ) 620 ScProgress::DeleteInterpretProgress(); 621 622 delete pColIter; 623 624 // DBG_ERROR( String(nCount) + String(" End = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) ); 625 626 if (pDev) 627 pDev->SetMapMode(aOldMap); 628 629 aCurTextWidthCalcPos.SetTab( nTab ); 630 aCurTextWidthCalcPos.SetRow( nRow ); 631 aCurTextWidthCalcPos.SetCol( (SCCOL)nCol ); 632 633 // DBG_ERROR( String(nMs) + String(" ms (") + String(nIter) + String(')') ); 634 635 pStylePool->SetSearchMask( eOldFam, nOldMask ); 636 bIdleDisabled = sal_False; 637 638 return bNeedMore; 639 } 640 641 //------------------------------------------------------------------------ 642 643 class ScSpellStatus 644 { 645 public: 646 sal_Bool bModified; 647 648 ScSpellStatus() : bModified(sal_False) {}; 649 650 DECL_LINK (EventHdl, EditStatus*); 651 }; 652 653 IMPL_LINK( ScSpellStatus, EventHdl, EditStatus *, pStatus ) 654 { 655 sal_uLong nStatus = pStatus->GetStatusWord(); 656 if ( nStatus & EE_STAT_WRONGWORDCHANGED ) 657 bModified = sal_True; 658 659 return 0; 660 } 661 662 // SPELL_MAXCELLS muss mindestens 256 sein, solange am Iterator keine 663 // Start-Spalte gesetzt werden kann 664 665 //! SPELL_MAXTEST fuer Timer und Idle unterschiedlich ??? 666 667 // SPELL_MAXTEST now divided between visible and rest of document 668 669 #define SPELL_MAXTEST_VIS 1 670 #define SPELL_MAXTEST_ALL 3 671 #define SPELL_MAXCELLS 256 672 673 sal_Bool ScDocument::OnlineSpellInRange( const ScRange& rSpellRange, ScAddress& rSpellPos, 674 sal_uInt16 nMaxTest ) 675 { 676 ScEditEngineDefaulter* pEngine = NULL; //! am Dokument speichern 677 SfxItemSet* pDefaults = NULL; 678 ScSpellStatus aStatus; 679 680 sal_uInt16 nCellCount = 0; // Zellen insgesamt 681 sal_uInt16 nTestCount = 0; // Aufrufe Spelling 682 sal_Bool bChanged = sal_False; // Aenderungen? 683 684 SCCOL nCol = rSpellRange.aStart.Col(); // iterator always starts on the left edge 685 SCROW nRow = rSpellPos.Row(); 686 SCTAB nTab = rSpellPos.Tab(); 687 if ( !pTab[nTab] ) // sheet deleted? 688 { 689 nTab = rSpellRange.aStart.Tab(); 690 nRow = rSpellRange.aStart.Row(); 691 if ( !pTab[nTab] ) 692 { 693 // may happen for visible range 694 return sal_False; 695 } 696 } 697 ScHorizontalCellIterator aIter( this, nTab, 698 rSpellRange.aStart.Col(), nRow, 699 rSpellRange.aEnd.Col(), rSpellRange.aEnd.Row() ); 700 ScBaseCell* pCell = aIter.GetNext( nCol, nRow ); 701 // skip everything left of rSpellPos: 702 while ( pCell && nRow == rSpellPos.Row() && nCol < rSpellPos.Col() ) 703 pCell = aIter.GetNext( nCol, nRow ); 704 705 for (; pCell; pCell = aIter.GetNext(nCol, nRow)) 706 { 707 if (pDPCollection && pDPCollection->HasDPTable(nCol, nRow, nTab)) 708 // Don't spell check within datapilot table. 709 continue; 710 711 CellType eType = pCell->GetCellType(); 712 if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT ) 713 { 714 if (!pEngine) 715 { 716 // #71154# ScTabEditEngine is needed 717 // because MapMode must be set for some old documents 718 pEngine = new ScTabEditEngine( this ); 719 pEngine->SetControlWord( pEngine->GetControlWord() | 720 ( EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS ) ); 721 pEngine->SetStatusEventHdl( LINK( &aStatus, ScSpellStatus, EventHdl ) ); 722 // Delimiters hier wie in inputhdl.cxx !!! 723 pEngine->SetWordDelimiters( 724 ScEditUtil::ModifyDelimiters( pEngine->GetWordDelimiters() ) ); 725 pDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() ); 726 727 com::sun::star::uno::Reference<com::sun::star::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() ); 728 729 pEngine->SetSpeller( xXSpellChecker1 ); 730 } 731 732 const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab ); 733 pPattern->FillEditItemSet( pDefaults ); 734 pEngine->SetDefaults( pDefaults, sal_False ); //! noetig ? 735 736 sal_uInt16 nCellLang = ((const SvxLanguageItem&) 737 pPattern->GetItem(ATTR_FONT_LANGUAGE)).GetValue(); 738 if ( nCellLang == LANGUAGE_SYSTEM ) 739 nCellLang = Application::GetSettings().GetLanguage(); // never use SYSTEM for spelling 740 pEngine->SetDefaultLanguage( nCellLang ); 741 742 if ( eType == CELLTYPE_STRING ) 743 { 744 String aText; 745 ((ScStringCell*)pCell)->GetString(aText); 746 pEngine->SetText( aText ); 747 } 748 else 749 pEngine->SetText( *((ScEditCell*)pCell)->GetData() ); 750 751 aStatus.bModified = sal_False; 752 pEngine->CompleteOnlineSpelling(); 753 if ( aStatus.bModified ) // Fehler dazu oder weggekommen? 754 { 755 sal_Bool bNeedEdit = sal_True; // Test auf einfachen Text 756 if ( !pEngine->HasOnlineSpellErrors() ) 757 { 758 ScEditAttrTester aTester( pEngine ); 759 bNeedEdit = aTester.NeedsObject(); 760 } 761 762 if ( bNeedEdit ) 763 { 764 EditTextObject* pNewData = pEngine->CreateTextObject(); 765 if ( eType == CELLTYPE_EDIT ) 766 ((ScEditCell*)pCell)->SetData( pNewData, 767 pEngine->GetEditTextObjectPool() ); 768 else 769 PutCell( nCol, nRow, nTab, new ScEditCell( pNewData, 770 this, pEngine->GetEditTextObjectPool() ) ); 771 delete pNewData; 772 } 773 else // einfacher String 774 PutCell( nCol, nRow, nTab, new ScStringCell( pEngine->GetText() ) ); 775 776 // Paint 777 if (pShell) 778 { 779 // #47751# Seitenvorschau ist davon nicht betroffen 780 // (sollte jedenfalls nicht) 781 ScPaintHint aHint( ScRange( nCol, nRow, nTab ), PAINT_GRID ); 782 aHint.SetPrintFlag( sal_False ); 783 pShell->Broadcast( aHint ); 784 } 785 786 bChanged = sal_True; 787 } 788 789 if ( ++nTestCount >= nMaxTest ) // checked enough text? 790 break; 791 } 792 793 if ( ++nCellCount >= SPELL_MAXCELLS ) // seen enough cells? 794 break; 795 } 796 797 if ( pCell ) 798 { 799 ++nCol; // continue after last cell 800 if ( nCol > rSpellRange.aEnd.Col() ) 801 { 802 nCol = rSpellRange.aStart.Col(); 803 ++nRow; 804 if ( nRow > rSpellRange.aEnd.Row() ) 805 pCell = NULL; 806 } 807 } 808 809 if (!pCell) // end of range reached -> next sheet 810 { 811 ++nTab; 812 if ( nTab > rSpellRange.aEnd.Tab() || !pTab[nTab] ) 813 nTab = rSpellRange.aStart.Tab(); 814 nCol = rSpellRange.aStart.Col(); 815 nRow = rSpellRange.aStart.Row(); 816 817 nVisSpellState = VSPL_DONE; //! only if this is for the visible range 818 } 819 rSpellPos.Set( nCol, nRow, nTab ); 820 821 delete pDefaults; 822 delete pEngine; // bevor aStatus out of scope geht 823 824 return bChanged; 825 } 826 827 828 sal_Bool ScDocument::ContinueOnlineSpelling() 829 { 830 if ( bIdleDisabled || !pDocOptions->IsAutoSpell() || (pShell && pShell->IsReadOnly()) ) 831 return sal_False; 832 833 // #i48433# set bInsertingFromOtherDoc flag so there are no broadcasts when PutCell is called 834 // (same behavior as in RemoveAutoSpellObj: just transfer the broadcaster) 835 sal_Bool bOldInserting = IsInsertingFromOtherDoc(); 836 SetInsertingFromOtherDoc( sal_True ); 837 838 //! use one EditEngine for both calls 839 840 // #41504# first check visible range 841 sal_Bool bResult = OnlineSpellInRange( aVisSpellRange, aVisSpellPos, SPELL_MAXTEST_VIS ); 842 843 // during first pass through visible range, always continue 844 if ( nVisSpellState == VSPL_START ) 845 bResult = sal_True; 846 847 if (bResult) 848 { 849 // if errors found, continue there 850 OnlineSpellInRange( aVisSpellRange, aVisSpellPos, SPELL_MAXTEST_ALL ); 851 } 852 else 853 { 854 // if nothing found there, continue with rest of document 855 ScRange aTotalRange( 0,0,0, MAXCOL,MAXROW,MAXTAB ); 856 bResult = OnlineSpellInRange( aTotalRange, aOnlineSpellPos, SPELL_MAXTEST_ALL ); 857 } 858 859 SetInsertingFromOtherDoc( bOldInserting ); 860 861 return bResult; 862 } 863 864 865 void ScDocument::SetOnlineSpellPos( const ScAddress& rPos ) 866 { 867 aOnlineSpellPos = rPos; 868 869 // skip visible area for aOnlineSpellPos 870 if ( aVisSpellRange.In( aOnlineSpellPos ) ) 871 aOnlineSpellPos = aVisSpellRange.aEnd; 872 } 873 874 sal_Bool ScDocument::SetVisibleSpellRange( const ScRange& rNewRange ) 875 { 876 sal_Bool bChange = ( aVisSpellRange != rNewRange ); 877 if (bChange) 878 { 879 // continue spelling through visible range when scrolling down 880 sal_Bool bContDown = ( nVisSpellState == VSPL_START && rNewRange.In( aVisSpellPos ) && 881 rNewRange.aStart.Row() > aVisSpellRange.aStart.Row() && 882 rNewRange.aStart.Col() == aVisSpellRange.aStart.Col() && 883 rNewRange.aEnd.Col() == aVisSpellRange.aEnd.Col() ); 884 885 aVisSpellRange = rNewRange; 886 887 if ( !bContDown ) 888 { 889 aVisSpellPos = aVisSpellRange.aStart; 890 nVisSpellState = VSPL_START; 891 } 892 893 // skip visible area for aOnlineSpellPos 894 if ( aVisSpellRange.In( aOnlineSpellPos ) ) 895 aOnlineSpellPos = aVisSpellRange.aEnd; 896 } 897 return bChange; 898 } 899 900 void ScDocument::RemoveAutoSpellObj() 901 { 902 // alle Spelling-Informationen entfernen 903 904 for (SCTAB nTab=0; nTab<=MAXTAB && pTab[nTab]; nTab++) 905 pTab[nTab]->RemoveAutoSpellObj(); 906 } 907 908 void ScDocument::RepaintRange( const ScRange& rRange ) 909 { 910 if ( bIsVisible && pShell ) 911 { 912 ScModelObj* pModel = ScModelObj::getImplementation( pShell->GetModel() ); 913 if ( pModel ) 914 pModel->RepaintRange( rRange ); // locked repaints are checked there 915 } 916 } 917 918 //------------------------------------------------------------------------ 919 920 sal_Bool ScDocument::IdleCheckLinks() // sal_True = demnaechst wieder versuchen 921 { 922 sal_Bool bAnyLeft = sal_False; 923 924 if (GetLinkManager()) 925 { 926 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 927 sal_uInt16 nCount = rLinks.Count(); 928 for (sal_uInt16 i=0; i<nCount; i++) 929 { 930 ::sfx2::SvBaseLink* pBase = *rLinks[i]; 931 if (pBase->ISA(ScDdeLink)) 932 { 933 ScDdeLink* pDdeLink = (ScDdeLink*)pBase; 934 if (pDdeLink->NeedsUpdate()) 935 { 936 pDdeLink->TryUpdate(); 937 if (pDdeLink->NeedsUpdate()) // war nix? 938 bAnyLeft = sal_True; 939 } 940 } 941 } 942 } 943 944 return bAnyLeft; 945 } 946 947 void ScDocument::SaveDdeLinks(SvStream& rStream) const 948 { 949 // bei 4.0-Export alle mit Modus != DEFAULT weglassen 950 sal_Bool bExport40 = ( rStream.GetVersion() <= SOFFICE_FILEFORMAT_40 ); 951 952 const ::sfx2::SvBaseLinks& rLinks = GetLinkManager()->GetLinks(); 953 sal_uInt16 nCount = rLinks.Count(); 954 955 // erstmal zaehlen... 956 957 sal_uInt16 nDdeCount = 0; 958 sal_uInt16 i; 959 for (i=0; i<nCount; i++) 960 { 961 ::sfx2::SvBaseLink* pBase = *rLinks[i]; 962 if (pBase->ISA(ScDdeLink)) 963 if ( !bExport40 || ((ScDdeLink*)pBase)->GetMode() == SC_DDE_DEFAULT ) 964 ++nDdeCount; 965 } 966 967 // Header 968 969 ScMultipleWriteHeader aHdr( rStream ); 970 rStream << nDdeCount; 971 972 // Links speichern 973 974 for (i=0; i<nCount; i++) 975 { 976 ::sfx2::SvBaseLink* pBase = *rLinks[i]; 977 if (pBase->ISA(ScDdeLink)) 978 { 979 ScDdeLink* pLink = (ScDdeLink*)pBase; 980 if ( !bExport40 || pLink->GetMode() == SC_DDE_DEFAULT ) 981 pLink->Store( rStream, aHdr ); 982 } 983 } 984 } 985 986 void ScDocument::LoadDdeLinks(SvStream& rStream) 987 { 988 ScMultipleReadHeader aHdr( rStream ); 989 990 GetLinkManager(); 991 sal_uInt16 nCount; 992 rStream >> nCount; 993 for (sal_uInt16 i=0; i<nCount; i++) 994 { 995 ScDdeLink* pLink = new ScDdeLink( this, rStream, aHdr ); 996 pLinkManager->InsertDDELink( pLink, 997 pLink->GetAppl(), pLink->GetTopic(), pLink->GetItem() ); 998 } 999 } 1000 1001 sal_Bool ScDocument::HasDdeLinks() const 1002 { 1003 if (GetLinkManager()) // Clipboard z.B. hat keinen LinkManager 1004 { 1005 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1006 sal_uInt16 nCount = rLinks.Count(); 1007 for (sal_uInt16 i=0; i<nCount; i++) 1008 if ((*rLinks[i])->ISA(ScDdeLink)) 1009 return sal_True; 1010 } 1011 1012 return sal_False; 1013 } 1014 1015 void ScDocument::SetInLinkUpdate(sal_Bool bSet) 1016 { 1017 // called from TableLink and AreaLink 1018 1019 DBG_ASSERT( bInLinkUpdate != bSet, "SetInLinkUpdate twice" ); 1020 bInLinkUpdate = bSet; 1021 } 1022 1023 sal_Bool ScDocument::IsInLinkUpdate() const 1024 { 1025 return bInLinkUpdate || IsInDdeLinkUpdate(); 1026 } 1027 1028 void ScDocument::UpdateExternalRefLinks() 1029 { 1030 if (!GetLinkManager()) 1031 return; 1032 1033 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1034 sal_uInt16 nCount = rLinks.Count(); 1035 1036 bool bAny = false; 1037 for (sal_uInt16 i = 0; i < nCount; ++i) 1038 { 1039 ::sfx2::SvBaseLink* pBase = *rLinks[i]; 1040 ScExternalRefLink* pRefLink = dynamic_cast<ScExternalRefLink*>(pBase); 1041 if (pRefLink) 1042 { 1043 pRefLink->Update(); 1044 bAny = true; 1045 } 1046 } 1047 if (bAny) 1048 { 1049 TrackFormulas(); 1050 pShell->Broadcast( SfxSimpleHint(FID_DATACHANGED) ); 1051 ResetChanged( ScRange(0, 0, 0, MAXCOL, MAXROW, MAXTAB) ); 1052 1053 // #i101960# set document modified, as in TrackTimeHdl for DDE links 1054 if (!pShell->IsModified()) 1055 { 1056 pShell->SetModified( sal_True ); 1057 SfxBindings* pBindings = GetViewBindings(); 1058 if (pBindings) 1059 { 1060 pBindings->Invalidate( SID_SAVEDOC ); 1061 pBindings->Invalidate( SID_DOC_MODIFIED ); 1062 } 1063 } 1064 } 1065 } 1066 1067 void ScDocument::UpdateDdeLinks() 1068 { 1069 if (GetLinkManager()) 1070 { 1071 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1072 sal_uInt16 nCount = rLinks.Count(); 1073 sal_uInt16 i; 1074 1075 // #49226# falls das Updaten laenger dauert, erstmal alle Werte 1076 // zuruecksetzen, damit nichts altes (falsches) stehen bleibt 1077 sal_Bool bAny = sal_False; 1078 for (i=0; i<nCount; i++) 1079 { 1080 ::sfx2::SvBaseLink* pBase = *rLinks[i]; 1081 if (pBase->ISA(ScDdeLink)) 1082 { 1083 ((ScDdeLink*)pBase)->ResetValue(); 1084 bAny = sal_True; 1085 } 1086 } 1087 if (bAny) 1088 { 1089 // Formeln berechnen und painten wie im TrackTimeHdl 1090 TrackFormulas(); 1091 pShell->Broadcast( SfxSimpleHint( FID_DATACHANGED ) ); 1092 ResetChanged( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB) ); 1093 1094 // wenn FID_DATACHANGED irgendwann mal asynchron werden sollte 1095 // (z.B. mit Invalidate am Window), muss hier ein Update erzwungen werden. 1096 } 1097 1098 // nun wirklich updaten... 1099 for (i=0; i<nCount; i++) 1100 { 1101 ::sfx2::SvBaseLink* pBase = *rLinks[i]; 1102 if (pBase->ISA(ScDdeLink)) 1103 ((ScDdeLink*)pBase)->TryUpdate(); // bei DDE-Links TryUpdate statt Update 1104 } 1105 } 1106 } 1107 1108 sal_Bool ScDocument::UpdateDdeLink( const String& rAppl, const String& rTopic, const String& rItem ) 1109 { 1110 // fuer refresh() per StarOne Api 1111 // ResetValue() fuer einzelnen Link nicht noetig 1112 //! wenn's mal alles asynchron wird, aber auch hier 1113 1114 sal_Bool bFound = sal_False; 1115 if (GetLinkManager()) 1116 { 1117 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1118 sal_uInt16 nCount = rLinks.Count(); 1119 for (sal_uInt16 i=0; i<nCount; i++) 1120 { 1121 ::sfx2::SvBaseLink* pBase = *rLinks[i]; 1122 if (pBase->ISA(ScDdeLink)) 1123 { 1124 ScDdeLink* pDdeLink = (ScDdeLink*)pBase; 1125 if ( pDdeLink->GetAppl() == rAppl && 1126 pDdeLink->GetTopic() == rTopic && 1127 pDdeLink->GetItem() == rItem ) 1128 { 1129 pDdeLink->TryUpdate(); 1130 bFound = sal_True; // koennen theoretisch mehrere sein (Mode), darum weitersuchen 1131 } 1132 } 1133 } 1134 } 1135 return bFound; 1136 } 1137 1138 void ScDocument::DisconnectDdeLinks() 1139 { 1140 if (GetLinkManager()) 1141 { 1142 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1143 sal_uInt16 nCount = rLinks.Count(); 1144 for (sal_uInt16 i=0; i<nCount; i++) 1145 { 1146 ::sfx2::SvBaseLink* pBase = *rLinks[i]; 1147 if (pBase->ISA(ScDdeLink)) 1148 pBase->Disconnect(); // bleibt im LinkManager eingetragen 1149 } 1150 } 1151 } 1152 1153 void ScDocument::CopyDdeLinks( ScDocument* pDestDoc ) const 1154 { 1155 if (bIsClip) // aus Stream erzeugen 1156 { 1157 if (pClipData) 1158 { 1159 pClipData->Seek(0); 1160 pDestDoc->LoadDdeLinks(*pClipData); 1161 } 1162 } 1163 else if (GetLinkManager()) // Links direkt kopieren 1164 { 1165 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1166 sal_uInt16 nCount = rLinks.Count(); 1167 for (sal_uInt16 i=0; i<nCount; i++) 1168 { 1169 ::sfx2::SvBaseLink* pBase = *rLinks[i]; 1170 if (pBase->ISA(ScDdeLink)) 1171 { 1172 ScDdeLink* pNew = new ScDdeLink( pDestDoc, *(ScDdeLink*)pBase ); 1173 1174 pDestDoc->pLinkManager->InsertDDELink( pNew, 1175 pNew->GetAppl(), pNew->GetTopic(), pNew->GetItem() ); 1176 } 1177 } 1178 } 1179 } 1180 1181 sal_uInt16 ScDocument::GetDdeLinkCount() const 1182 { 1183 sal_uInt16 nDdeCount = 0; 1184 if (GetLinkManager()) 1185 { 1186 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1187 sal_uInt16 nCount = rLinks.Count(); 1188 for (sal_uInt16 i=0; i<nCount; i++) 1189 if ((*rLinks[i])->ISA(ScDdeLink)) 1190 ++nDdeCount; 1191 } 1192 return nDdeCount; 1193 } 1194 1195 // ---------------------------------------------------------------------------- 1196 1197 namespace { 1198 1199 /** Tries to find the specified DDE link. 1200 @param pnDdePos (out-param) if not 0, the index of the DDE link is returned here 1201 (does not include other links from link manager). 1202 @return The DDE link, if it exists, otherwise 0. */ 1203 ScDdeLink* lclGetDdeLink( 1204 const sfx2::LinkManager* pLinkManager, 1205 const String& rAppl, const String& rTopic, const String& rItem, sal_uInt8 nMode, 1206 sal_uInt16* pnDdePos = NULL ) 1207 { 1208 if( pLinkManager ) 1209 { 1210 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1211 sal_uInt16 nCount = rLinks.Count(); 1212 if( pnDdePos ) *pnDdePos = 0; 1213 for( sal_uInt16 nIndex = 0; nIndex < nCount; ++nIndex ) 1214 { 1215 ::sfx2::SvBaseLink* pLink = *rLinks[ nIndex ]; 1216 if( ScDdeLink* pDdeLink = PTR_CAST( ScDdeLink, pLink ) ) 1217 { 1218 if( (pDdeLink->GetAppl() == rAppl) && 1219 (pDdeLink->GetTopic() == rTopic) && 1220 (pDdeLink->GetItem() == rItem) && 1221 ((nMode == SC_DDE_IGNOREMODE) || (nMode == pDdeLink->GetMode())) ) 1222 return pDdeLink; 1223 if( pnDdePos ) ++*pnDdePos; 1224 } 1225 } 1226 } 1227 return NULL; 1228 } 1229 1230 /** Returns a pointer to the specified DDE link. 1231 @param nDdePos Index of the DDE link (does not include other links from link manager). 1232 @return The DDE link, if it exists, otherwise 0. */ 1233 ScDdeLink* lclGetDdeLink( const sfx2::LinkManager* pLinkManager, sal_uInt16 nDdePos ) 1234 { 1235 if( pLinkManager ) 1236 { 1237 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1238 sal_uInt16 nCount = rLinks.Count(); 1239 sal_uInt16 nDdeIndex = 0; // counts only the DDE links 1240 for( sal_uInt16 nIndex = 0; nIndex < nCount; ++nIndex ) 1241 { 1242 ::sfx2::SvBaseLink* pLink = *rLinks[ nIndex ]; 1243 if( ScDdeLink* pDdeLink = PTR_CAST( ScDdeLink, pLink ) ) 1244 { 1245 if( nDdeIndex == nDdePos ) 1246 return pDdeLink; 1247 ++nDdeIndex; 1248 } 1249 } 1250 } 1251 return NULL; 1252 } 1253 1254 } // namespace 1255 1256 // ---------------------------------------------------------------------------- 1257 1258 bool ScDocument::FindDdeLink( const String& rAppl, const String& rTopic, const String& rItem, sal_uInt8 nMode, sal_uInt16& rnDdePos ) 1259 { 1260 return lclGetDdeLink( GetLinkManager(), rAppl, rTopic, rItem, nMode, &rnDdePos ) != NULL; 1261 } 1262 1263 bool ScDocument::GetDdeLinkData( sal_uInt16 nDdePos, String& rAppl, String& rTopic, String& rItem ) const 1264 { 1265 if( const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) ) 1266 { 1267 rAppl = pDdeLink->GetAppl(); 1268 rTopic = pDdeLink->GetTopic(); 1269 rItem = pDdeLink->GetItem(); 1270 return true; 1271 } 1272 return false; 1273 } 1274 1275 bool ScDocument::GetDdeLinkMode( sal_uInt16 nDdePos, sal_uInt8& rnMode ) const 1276 { 1277 if( const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) ) 1278 { 1279 rnMode = pDdeLink->GetMode(); 1280 return true; 1281 } 1282 return false; 1283 } 1284 1285 const ScMatrix* ScDocument::GetDdeLinkResultMatrix( sal_uInt16 nDdePos ) const 1286 { 1287 const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ); 1288 return pDdeLink ? pDdeLink->GetResult() : NULL; 1289 } 1290 1291 bool ScDocument::CreateDdeLink( const String& rAppl, const String& rTopic, const String& rItem, sal_uInt8 nMode, ScMatrix* pResults ) 1292 { 1293 /* Create a DDE link without updating it (i.e. for Excel import), to prevent 1294 unwanted connections. First try to find existing link. Set result array 1295 on existing and new links. */ 1296 //! store DDE links additionally at document (for efficiency)? 1297 DBG_ASSERT( nMode != SC_DDE_IGNOREMODE, "ScDocument::CreateDdeLink - SC_DDE_IGNOREMODE not allowed here" ); 1298 if( GetLinkManager() && (nMode != SC_DDE_IGNOREMODE) ) 1299 { 1300 ScDdeLink* pDdeLink = lclGetDdeLink( pLinkManager, rAppl, rTopic, rItem, nMode ); 1301 if( !pDdeLink ) 1302 { 1303 // create a new DDE link, but without TryUpdate 1304 pDdeLink = new ScDdeLink( this, rAppl, rTopic, rItem, nMode ); 1305 pLinkManager->InsertDDELink( pDdeLink, rAppl, rTopic, rItem ); 1306 } 1307 1308 // insert link results 1309 if( pResults ) 1310 pDdeLink->SetResult( pResults ); 1311 1312 return true; 1313 } 1314 return false; 1315 } 1316 1317 bool ScDocument::SetDdeLinkResultMatrix( sal_uInt16 nDdePos, ScMatrix* pResults ) 1318 { 1319 if( ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) ) 1320 { 1321 pDdeLink->SetResult( pResults ); 1322 return true; 1323 } 1324 return false; 1325 } 1326 1327 //------------------------------------------------------------------------ 1328 1329 sal_Bool ScDocument::HasAreaLinks() const 1330 { 1331 if (GetLinkManager()) // Clipboard z.B. hat keinen LinkManager 1332 { 1333 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1334 sal_uInt16 nCount = rLinks.Count(); 1335 for (sal_uInt16 i=0; i<nCount; i++) 1336 if ((*rLinks[i])->ISA(ScAreaLink)) 1337 return sal_True; 1338 } 1339 1340 return sal_False; 1341 } 1342 1343 void ScDocument::UpdateAreaLinks() 1344 { 1345 if (GetLinkManager()) 1346 { 1347 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1348 sal_uInt16 nCount = rLinks.Count(); 1349 for (sal_uInt16 i=0; i<nCount; i++) 1350 { 1351 ::sfx2::SvBaseLink* pBase = *rLinks[i]; 1352 if (pBase->ISA(ScAreaLink)) 1353 pBase->Update(); 1354 } 1355 } 1356 } 1357 1358 void ScDocument::DeleteAreaLinksOnTab( SCTAB nTab ) 1359 { 1360 if (GetLinkManager()) 1361 { 1362 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1363 sal_uInt16 nPos = 0; 1364 while ( nPos < rLinks.Count() ) 1365 { 1366 const ::sfx2::SvBaseLink* pBase = *rLinks[nPos]; 1367 if ( pBase->ISA(ScAreaLink) && 1368 static_cast<const ScAreaLink*>(pBase)->GetDestArea().aStart.Tab() == nTab ) 1369 pLinkManager->Remove( nPos ); 1370 else 1371 ++nPos; 1372 } 1373 } 1374 } 1375 1376 void ScDocument::UpdateRefAreaLinks( UpdateRefMode eUpdateRefMode, 1377 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) 1378 { 1379 if (GetLinkManager()) 1380 { 1381 bool bAnyUpdate = false; 1382 1383 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); 1384 sal_uInt16 nCount = rLinks.Count(); 1385 for (sal_uInt16 i=0; i<nCount; i++) 1386 { 1387 ::sfx2::SvBaseLink* pBase = *rLinks[i]; 1388 if (pBase->ISA(ScAreaLink)) 1389 { 1390 ScAreaLink* pLink = (ScAreaLink*) pBase; 1391 ScRange aOutRange = pLink->GetDestArea(); 1392 1393 SCCOL nCol1 = aOutRange.aStart.Col(); 1394 SCROW nRow1 = aOutRange.aStart.Row(); 1395 SCTAB nTab1 = aOutRange.aStart.Tab(); 1396 SCCOL nCol2 = aOutRange.aEnd.Col(); 1397 SCROW nRow2 = aOutRange.aEnd.Row(); 1398 SCTAB nTab2 = aOutRange.aEnd.Tab(); 1399 1400 ScRefUpdateRes eRes = 1401 ScRefUpdate::Update( this, eUpdateRefMode, 1402 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(), 1403 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz, 1404 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); 1405 if ( eRes != UR_NOTHING ) 1406 { 1407 pLink->SetDestArea( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) ); 1408 bAnyUpdate = true; 1409 } 1410 } 1411 } 1412 1413 if ( bAnyUpdate ) 1414 { 1415 // #i52120# Look for duplicates (after updating all positions). 1416 // If several links start at the same cell, the one with the lower index is removed 1417 // (file format specifies only one link definition for a cell). 1418 1419 sal_uInt16 nFirstIndex = 0; 1420 while ( nFirstIndex < nCount ) 1421 { 1422 bool bFound = false; 1423 ::sfx2::SvBaseLink* pFirst = *rLinks[nFirstIndex]; 1424 if ( pFirst->ISA(ScAreaLink) ) 1425 { 1426 ScAddress aFirstPos = static_cast<ScAreaLink*>(pFirst)->GetDestArea().aStart; 1427 for ( sal_uInt16 nSecondIndex = nFirstIndex + 1; nSecondIndex < nCount && !bFound; ++nSecondIndex ) 1428 { 1429 ::sfx2::SvBaseLink* pSecond = *rLinks[nSecondIndex]; 1430 if ( pSecond->ISA(ScAreaLink) && 1431 static_cast<ScAreaLink*>(pSecond)->GetDestArea().aStart == aFirstPos ) 1432 { 1433 // remove the first link, exit the inner loop, don't increment nFirstIndex 1434 pLinkManager->Remove( pFirst ); 1435 nCount = rLinks.Count(); 1436 bFound = true; 1437 } 1438 } 1439 } 1440 if (!bFound) 1441 ++nFirstIndex; 1442 } 1443 } 1444 } 1445 } 1446 1447 //------------------------------------------------------------------------ 1448 1449 // TimerDelays etc. 1450 void ScDocument::KeyInput( const KeyEvent& ) 1451 { 1452 if ( pChartListenerCollection->GetCount() ) 1453 pChartListenerCollection->StartTimer(); 1454 if( apTemporaryChartLock.get() ) 1455 apTemporaryChartLock->StartOrContinueLocking(); 1456 } 1457 1458 // ---------------------------------------------------------------------------- 1459 1460 sal_Bool ScDocument::CheckMacroWarn() 1461 { 1462 // The check for macro configuration, macro warning and disabling is now handled 1463 // in SfxObjectShell::AdjustMacroMode, called by SfxObjectShell::CallBasic. 1464 1465 return sal_True; 1466 } 1467 1468 //------------------------------------------------------------------------ 1469 1470 SfxBindings* ScDocument::GetViewBindings() 1471 { 1472 // used to invalidate slots after changes to this document 1473 1474 if ( !pShell ) 1475 return NULL; // no ObjShell -> no view 1476 1477 // first check current view 1478 SfxViewFrame* pViewFrame = SfxViewFrame::Current(); 1479 if ( pViewFrame && pViewFrame->GetObjectShell() != pShell ) // wrong document? 1480 pViewFrame = NULL; 1481 1482 // otherwise use first view for this doc 1483 if ( !pViewFrame ) 1484 pViewFrame = SfxViewFrame::GetFirst( pShell ); 1485 1486 if (pViewFrame) 1487 return &pViewFrame->GetBindings(); 1488 else 1489 return NULL; 1490 } 1491 1492 //------------------------------------------------------------------------ 1493 1494 void ScDocument::TransliterateText( const ScMarkData& rMultiMark, sal_Int32 nType ) 1495 { 1496 DBG_ASSERT( rMultiMark.IsMultiMarked(), "TransliterateText: no selection" ); 1497 1498 utl::TransliterationWrapper aTranslitarationWrapper( xServiceManager, nType ); 1499 sal_Bool bConsiderLanguage = aTranslitarationWrapper.needLanguageForTheMode(); 1500 sal_uInt16 nLanguage = LANGUAGE_SYSTEM; 1501 1502 ScEditEngineDefaulter* pEngine = NULL; // not using pEditEngine member because of defaults 1503 1504 SCTAB nCount = GetTableCount(); 1505 for (SCTAB nTab = 0; nTab < nCount; nTab++) 1506 if ( pTab[nTab] && rMultiMark.GetTableSelect(nTab) ) 1507 { 1508 SCCOL nCol = 0; 1509 SCROW nRow = 0; 1510 1511 sal_Bool bFound = rMultiMark.IsCellMarked( nCol, nRow ); 1512 if (!bFound) 1513 bFound = GetNextMarkedCell( nCol, nRow, nTab, rMultiMark ); 1514 1515 while (bFound) 1516 { 1517 const ScBaseCell* pCell = GetCell( ScAddress( nCol, nRow, nTab ) ); 1518 CellType eType = pCell ? pCell->GetCellType() : CELLTYPE_NONE; 1519 1520 // #i115128# TITLE_CASE/SENTENCE_CASE need the extra handling in EditEngine (loop over words/sentences). 1521 // Still use TransliterationWrapper directly for text cells with other transliteration types, 1522 // for performance reasons. 1523 1524 if ( eType == CELLTYPE_EDIT || 1525 ( eType == CELLTYPE_STRING && ( nType == com::sun::star::i18n::TransliterationModulesExtra::SENTENCE_CASE || 1526 nType == com::sun::star::i18n::TransliterationModulesExtra::TITLE_CASE ) ) ) 1527 { 1528 if (!pEngine) 1529 pEngine = new ScFieldEditEngine( GetEnginePool(), GetEditPool() ); 1530 1531 // defaults from cell attributes must be set so right language is used 1532 const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab ); 1533 SfxItemSet* pDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() ); 1534 pPattern->FillEditItemSet( pDefaults ); 1535 pEngine->SetDefaults( pDefaults, sal_True ); 1536 1537 if ( eType == CELLTYPE_STRING ) 1538 pEngine->SetText( static_cast<const ScStringCell*>(pCell)->GetString() ); 1539 else 1540 { 1541 const EditTextObject* pData = static_cast<const ScEditCell*>(pCell)->GetData(); 1542 pEngine->SetText( *pData ); 1543 } 1544 pEngine->ClearModifyFlag(); 1545 1546 sal_uInt16 nLastPar = pEngine->GetParagraphCount(); 1547 if (nLastPar) 1548 --nLastPar; 1549 xub_StrLen nTxtLen = pEngine->GetTextLen(nLastPar); 1550 ESelection aSelAll( 0, 0, nLastPar, nTxtLen ); 1551 1552 pEngine->TransliterateText( aSelAll, nType ); 1553 1554 if ( pEngine->IsModified() ) 1555 { 1556 ScEditAttrTester aTester( pEngine ); 1557 if ( aTester.NeedsObject() ) 1558 { 1559 // remove defaults (paragraph attributes) before creating text object 1560 SfxItemSet* pEmpty = new SfxItemSet( pEngine->GetEmptyItemSet() ); 1561 pEngine->SetDefaults( pEmpty, sal_True ); 1562 1563 EditTextObject* pNewData = pEngine->CreateTextObject(); 1564 PutCell( nCol, nRow, nTab, 1565 new ScEditCell( pNewData, this, pEngine->GetEditTextObjectPool() ) ); 1566 delete pNewData; 1567 } 1568 else 1569 { 1570 String aNewStr = pEngine->GetText(); 1571 PutCell( nCol, nRow, nTab, new ScStringCell( aNewStr ) ); 1572 } 1573 } 1574 } 1575 else if ( eType == CELLTYPE_STRING ) 1576 { 1577 String aOldStr; 1578 ((const ScStringCell*)pCell)->GetString(aOldStr); 1579 xub_StrLen nOldLen = aOldStr.Len(); 1580 1581 if ( bConsiderLanguage ) 1582 { 1583 sal_uInt8 nScript = GetStringScriptType( aOldStr ); //! cell script type? 1584 sal_uInt16 nWhich = ( nScript == SCRIPTTYPE_ASIAN ) ? ATTR_CJK_FONT_LANGUAGE : 1585 ( ( nScript == SCRIPTTYPE_COMPLEX ) ? ATTR_CTL_FONT_LANGUAGE : 1586 ATTR_FONT_LANGUAGE ); 1587 nLanguage = ((const SvxLanguageItem*)GetAttr( nCol, nRow, nTab, nWhich ))->GetValue(); 1588 } 1589 1590 com::sun::star::uno::Sequence<sal_Int32> aOffsets; 1591 String aNewStr = aTranslitarationWrapper.transliterate( aOldStr, nLanguage, 0, nOldLen, &aOffsets ); 1592 1593 if ( aNewStr != aOldStr ) 1594 PutCell( nCol, nRow, nTab, new ScStringCell( aNewStr ) ); 1595 } 1596 1597 bFound = GetNextMarkedCell( nCol, nRow, nTab, rMultiMark ); 1598 } 1599 } 1600 1601 delete pEngine; 1602 } 1603 1604