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