Update ooo320-m1
[ooovba.git] / sc / source / core / data / documen8.cxx
blob32868f2f2a5363e557780ad4784166ed3373506e
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: documen8.cxx,v $
10 * $Revision: 1.52.32.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
35 #define _ZFORLIST_DECLARE_TABLE
36 #include "scitems.hxx"
37 #include <svx/eeitem.hxx>
39 #include <tools/string.hxx>
40 #include <svx/editobj.hxx>
41 #include <svx/editstat.hxx>
42 #include <svx/frmdiritem.hxx>
43 #include <svx/langitem.hxx>
44 #include <svx/linkmgr.hxx>
45 #include <svx/scripttypeitem.hxx>
46 #include <svx/unolingu.hxx>
47 #include <sfx2/bindings.hxx>
48 #include <sfx2/objsh.hxx>
49 #include <sfx2/printer.hxx>
50 #include <sfx2/viewfrm.hxx>
51 #include <sfx2/viewsh.hxx>
52 #include <svtools/flagitem.hxx>
53 #include <svtools/intitem.hxx>
54 #define _SVSTDARR_USHORTS
55 #include <svtools/svstdarr.hxx>
56 #include <svtools/zforlist.hxx>
57 #include <svtools/zformat.hxx>
58 #include <svtools/misccfg.hxx>
59 #include <sfx2/app.hxx>
60 #include <unotools/transliterationwrapper.hxx>
61 #include <svtools/securityoptions.hxx>
63 #include <vcl/virdev.hxx>
64 #include <vcl/msgbox.hxx>
66 #include "inputopt.hxx"
67 #include "global.hxx"
68 #include "table.hxx"
69 #include "column.hxx"
70 #include "cell.hxx"
71 #include "poolhelp.hxx"
72 #include "docpool.hxx"
73 #include "stlpool.hxx"
74 #include "stlsheet.hxx"
75 #include "docoptio.hxx"
76 #include "viewopti.hxx"
77 #include "scextopt.hxx"
78 #include "rechead.hxx"
79 #include "ddelink.hxx"
80 #include "scmatrix.hxx"
81 #include "arealink.hxx"
82 #include "dociter.hxx"
83 #include "patattr.hxx"
84 #include "hints.hxx"
85 #include "editutil.hxx"
86 #include "progress.hxx"
87 #include "document.hxx"
88 #include "chartlis.hxx"
89 #include "chartlock.hxx"
90 #include "refupdat.hxx"
91 #include "validat.hxx" // fuer HasMacroCalls
92 #include "markdata.hxx"
93 #include "scmod.hxx"
94 #include "printopt.hxx"
95 #include "externalrefmgr.hxx"
96 #include "globstr.hrc"
97 #include "sc.hrc"
98 #include "charthelper.hxx"
99 #include "dpobject.hxx"
100 #include "macromgr.hxx"
102 #define GET_SCALEVALUE(set,id) ((const SfxUInt16Item&)(set.Get( id ))).GetValue()
104 // states for online spelling in the visible range (0 is set initially)
105 #define VSPL_START 0
106 #define VSPL_DONE 1
109 // STATIC DATA -----------------------------------------------------------
111 //------------------------------------------------------------------------
113 void ScDocument::ImplCreateOptions()
115 pDocOptions = new ScDocOptions();
116 pViewOptions = new ScViewOptions();
119 //------------------------------------------------------------------------
121 void ScDocument::ImplDeleteOptions()
123 delete pDocOptions;
124 delete pViewOptions;
125 delete pExtDocOptions;
128 //------------------------------------------------------------------------
130 SfxPrinter* ScDocument::GetPrinter(BOOL bCreateIfNotExist)
132 if ( !pPrinter && bCreateIfNotExist )
134 SfxItemSet* pSet =
135 new SfxItemSet( *xPoolHelper->GetDocPool(),
136 SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN,
137 SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC,
138 SID_PRINT_SELECTEDSHEET, SID_PRINT_SELECTEDSHEET,
139 SID_SCPRINTOPTIONS, SID_SCPRINTOPTIONS,
140 NULL );
142 SfxMiscCfg* pOffCfg = SFX_APP()->GetMiscConfig();
143 if ( pOffCfg )
145 USHORT nFlags = 0;
146 if ( pOffCfg->IsPaperOrientationWarning() )
147 nFlags |= SFX_PRINTER_CHG_ORIENTATION;
148 if ( pOffCfg->IsPaperSizeWarning() )
149 nFlags |= SFX_PRINTER_CHG_SIZE;
150 pSet->Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, nFlags ) );
151 pSet->Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, pOffCfg->IsNotFoundWarning() ) );
154 pPrinter = new SfxPrinter( pSet );
155 pPrinter->SetMapMode( MAP_100TH_MM );
156 UpdateDrawPrinter();
157 pPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
160 return pPrinter;
163 //------------------------------------------------------------------------
165 void ScDocument::SetPrinter( SfxPrinter* pNewPrinter )
167 if ( pNewPrinter == pPrinter )
169 // #i6706# SetPrinter is called with the same printer again if
170 // the JobSetup has changed. In that case just call UpdateDrawPrinter
171 // (SetRefDevice for drawing layer) because of changed text sizes.
172 UpdateDrawPrinter();
174 else
176 SfxPrinter* pOld = pPrinter;
177 pPrinter = pNewPrinter;
178 UpdateDrawPrinter();
179 pPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
180 delete pOld;
182 InvalidateTextWidth(NULL, NULL, FALSE); // in both cases
185 //------------------------------------------------------------------------
187 void ScDocument::SetPrintOptions()
189 if ( !pPrinter ) GetPrinter(); // setzt pPrinter
190 DBG_ASSERT( pPrinter, "Error in printer creation :-/" );
192 if ( pPrinter )
194 SfxMiscCfg* pOffCfg = SFX_APP()->GetMiscConfig();
195 if ( pOffCfg )
197 SfxItemSet aOptSet( pPrinter->GetOptions() );
199 USHORT nFlags = 0;
200 if ( pOffCfg->IsPaperOrientationWarning() )
201 nFlags |= SFX_PRINTER_CHG_ORIENTATION;
202 if ( pOffCfg->IsPaperSizeWarning() )
203 nFlags |= SFX_PRINTER_CHG_SIZE;
204 aOptSet.Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, nFlags ) );
205 aOptSet.Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, pOffCfg->IsNotFoundWarning() ) );
207 pPrinter->SetOptions( aOptSet );
212 //------------------------------------------------------------------------
214 VirtualDevice* ScDocument::GetVirtualDevice_100th_mm()
216 if (!pVirtualDevice_100th_mm)
218 // pVirtualDevice_100th_mm = new VirtualDevice;
219 // pVirtualDevice_100th_mm->SetMapMode( MAP_100TH_MM );
221 pVirtualDevice_100th_mm = new VirtualDevice( 1 );
222 pVirtualDevice_100th_mm->SetReferenceDevice(VirtualDevice::REFDEV_MODE_MSO1);
223 MapMode aMapMode( pVirtualDevice_100th_mm->GetMapMode() );
224 aMapMode.SetMapUnit( MAP_100TH_MM );
225 pVirtualDevice_100th_mm->SetMapMode( aMapMode );
227 return pVirtualDevice_100th_mm;
230 OutputDevice* ScDocument::GetRefDevice()
232 // Create printer like ref device, see Writer...
233 OutputDevice* pRefDevice = NULL;
234 if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
235 pRefDevice = GetPrinter();
236 else
237 pRefDevice = GetVirtualDevice_100th_mm();
238 return pRefDevice;
241 //------------------------------------------------------------------------
243 void ScDocument::ModifyStyleSheet( SfxStyleSheetBase& rStyleSheet,
244 const SfxItemSet& rChanges )
246 SfxItemSet& rSet = rStyleSheet.GetItemSet();
248 switch ( rStyleSheet.GetFamily() )
250 case SFX_STYLE_FAMILY_PAGE:
252 const USHORT nOldScale = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALE);
253 const USHORT nOldScaleToPages = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALETOPAGES);
254 rSet.Put( rChanges );
255 const USHORT nNewScale = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALE);
256 const USHORT nNewScaleToPages = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALETOPAGES);
258 if ( (nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages) )
259 InvalidateTextWidth( rStyleSheet.GetName() );
261 if( SvtLanguageOptions().IsCTLFontEnabled() )
263 const SfxPoolItem *pItem = NULL;
264 if( rChanges.GetItemState(ATTR_WRITINGDIR, TRUE, &pItem ) == SFX_ITEM_SET )
265 ScChartHelper::DoUpdateAllCharts( this );
268 break;
270 case SFX_STYLE_FAMILY_PARA:
272 BOOL bNumFormatChanged;
273 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
274 rSet, rChanges ) )
275 InvalidateTextWidth( NULL, NULL, bNumFormatChanged );
277 for (SCTAB nTab=0; nTab<=MAXTAB; ++nTab)
278 if (pTab[nTab] && pTab[nTab]->IsStreamValid())
279 pTab[nTab]->SetStreamValid( FALSE );
281 ULONG nOldFormat =
282 ((const SfxUInt32Item*)&rSet.Get(
283 ATTR_VALUE_FORMAT ))->GetValue();
284 ULONG nNewFormat =
285 ((const SfxUInt32Item*)&rChanges.Get(
286 ATTR_VALUE_FORMAT ))->GetValue();
287 LanguageType eNewLang, eOldLang;
288 eNewLang = eOldLang = LANGUAGE_DONTKNOW;
289 if ( nNewFormat != nOldFormat )
291 SvNumberFormatter* pFormatter = GetFormatTable();
292 eOldLang = pFormatter->GetEntry( nOldFormat )->GetLanguage();
293 eNewLang = pFormatter->GetEntry( nNewFormat )->GetLanguage();
296 // Bedeutung der Items in rChanges:
297 // Item gesetzt - Aenderung uebernehmen
298 // Dontcare - Default setzen
299 // Default - keine Aenderung
300 // ("keine Aenderung" geht nicht mit PutExtended, darum Schleife)
301 for (USHORT nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; nWhich++)
303 const SfxPoolItem* pItem;
304 SfxItemState eState = rChanges.GetItemState( nWhich, FALSE, &pItem );
305 if ( eState == SFX_ITEM_SET )
306 rSet.Put( *pItem );
307 else if ( eState == SFX_ITEM_DONTCARE )
308 rSet.ClearItem( nWhich );
309 // bei Default nichts
312 if ( eNewLang != eOldLang )
313 rSet.Put(
314 SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
316 break;
317 default:
319 // added to avoid warnings
324 //------------------------------------------------------------------------
326 void ScDocument::CopyStdStylesFrom( ScDocument* pSrcDoc )
328 // #b5017505# number format exchange list has to be handled here, too
329 NumFmtMergeHandler aNumFmtMergeHdl(this, pSrcDoc);
330 xPoolHelper->GetStylePool()->CopyStdStylesFrom( pSrcDoc->xPoolHelper->GetStylePool() );
333 //------------------------------------------------------------------------
335 void ScDocument::InvalidateTextWidth( const String& rStyleName )
337 const SCTAB nCount = GetTableCount();
338 for ( SCTAB i=0; i<nCount && pTab[i]; i++ )
339 if ( pTab[i]->GetPageStyle() == rStyleName )
340 InvalidateTextWidth( i );
343 //------------------------------------------------------------------------
345 void ScDocument::InvalidateTextWidth( SCTAB nTab )
347 ScAddress aAdrFrom( 0, 0, nTab );
348 ScAddress aAdrTo ( MAXCOL, MAXROW, nTab );
349 InvalidateTextWidth( &aAdrFrom, &aAdrTo, FALSE );
352 //------------------------------------------------------------------------
354 BOOL ScDocument::IsPageStyleInUse( const String& rStrPageStyle, SCTAB* pInTab )
356 BOOL bInUse = FALSE;
357 const SCTAB nCount = GetTableCount();
358 SCTAB i;
360 for ( i = 0; !bInUse && i < nCount && pTab[i]; i++ )
361 bInUse = ( pTab[i]->GetPageStyle() == rStrPageStyle );
363 if ( pInTab )
364 *pInTab = i-1;
366 return bInUse;
369 //------------------------------------------------------------------------
371 BOOL ScDocument::RemovePageStyleInUse( const String& rStyle )
373 BOOL bWasInUse = FALSE;
374 const SCTAB nCount = GetTableCount();
376 for ( SCTAB i=0; i<nCount && pTab[i]; i++ )
377 if ( pTab[i]->GetPageStyle() == rStyle )
379 bWasInUse = TRUE;
380 pTab[i]->SetPageStyle( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) );
383 return bWasInUse;
386 BOOL ScDocument::RenamePageStyleInUse( const String& rOld, const String& rNew )
388 BOOL bWasInUse = FALSE;
389 const SCTAB nCount = GetTableCount();
391 for ( SCTAB i=0; i<nCount && pTab[i]; i++ )
392 if ( pTab[i]->GetPageStyle() == rOld )
394 bWasInUse = TRUE;
395 pTab[i]->SetPageStyle( rNew );
398 return bWasInUse;
401 //------------------------------------------------------------------------
403 BYTE ScDocument::GetEditTextDirection(SCTAB nTab) const
405 EEHorizontalTextDirection eRet = EE_HTEXTDIR_DEFAULT;
407 String aStyleName = GetPageStyle( nTab );
408 SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aStyleName, SFX_STYLE_FAMILY_PAGE );
409 if ( pStyle )
411 SfxItemSet& rStyleSet = pStyle->GetItemSet();
412 SvxFrameDirection eDirection = (SvxFrameDirection)
413 ((const SvxFrameDirectionItem&)rStyleSet.Get( ATTR_WRITINGDIR )).GetValue();
415 if ( eDirection == FRMDIR_HORI_LEFT_TOP )
416 eRet = EE_HTEXTDIR_L2R;
417 else if ( eDirection == FRMDIR_HORI_RIGHT_TOP )
418 eRet = EE_HTEXTDIR_R2L;
419 // else (invalid for EditEngine): keep "default"
422 return sal::static_int_cast<BYTE>(eRet);
425 ScMacroManager* ScDocument::GetMacroManager()
427 if (!mpMacroMgr.get())
428 mpMacroMgr.reset(new ScMacroManager(this));
429 return mpMacroMgr.get();
432 //------------------------------------------------------------------------
434 void ScDocument::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
435 BOOL bNumFormatChanged )
437 BOOL bBroadcast = (bNumFormatChanged && GetDocOptions().IsCalcAsShown() && !IsImportingXML() && !IsClipboard());
438 if ( pAdrFrom && !pAdrTo )
440 const SCTAB nTab = pAdrFrom->Tab();
442 if ( pTab[nTab] )
443 pTab[nTab]->InvalidateTextWidth( pAdrFrom, NULL, bNumFormatChanged, bBroadcast );
445 else
447 const SCTAB nTabStart = pAdrFrom ? pAdrFrom->Tab() : 0;
448 const SCTAB nTabEnd = pAdrTo ? pAdrTo->Tab() : MAXTAB;
450 for ( SCTAB nTab=nTabStart; nTab<=nTabEnd; nTab++ )
451 if ( pTab[nTab] )
452 pTab[nTab]->InvalidateTextWidth( pAdrFrom, pAdrTo, bNumFormatChanged, bBroadcast );
456 //------------------------------------------------------------------------
458 #define CALCMAX 1000 // Berechnungen
459 #define ABORT_EVENTS (INPUT_ANY & ~INPUT_TIMER & ~INPUT_OTHER)
461 BOOL ScDocument::IdleCalcTextWidth() // TRUE = demnaechst wieder versuchen
463 // #i75610# if a printer hasn't been set or created yet, don't create one for this
464 if ( bIdleDisabled || IsInLinkUpdate() || GetPrinter(FALSE) == NULL )
465 return FALSE;
466 bIdleDisabled = TRUE;
468 // ULONG nMs = 0;
469 // USHORT nIter = 0;
471 const ULONG nStart = Time::GetSystemTicks();
472 double nPPTX = 0.0;
473 double nPPTY = 0.0;
474 OutputDevice* pDev = NULL;
475 MapMode aOldMap;
476 ScStyleSheet* pStyle = NULL;
477 ScColumnIterator* pColIter = NULL;
478 ScTable* pTable = NULL;
479 ScColumn* pColumn = NULL;
480 ScBaseCell* pCell = NULL;
481 SCTAB nTab = aCurTextWidthCalcPos.Tab();
482 SCROW nRow = aCurTextWidthCalcPos.Row();
483 SCsCOL nCol = aCurTextWidthCalcPos.Col();
484 USHORT nRestart = 0;
485 USHORT nZoom = 0;
486 BOOL bNeedMore= FALSE;
488 if ( !ValidRow(nRow) )
489 nRow = 0, nCol--;
490 if ( nCol < 0 )
491 nCol = MAXCOL, nTab++;
492 if ( !ValidTab(nTab) || !pTab[nTab] )
493 nTab = 0;
495 // DBG_ERROR( String("Start = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) );
497 // SearchMask/Family muss gemerkt werden,
498 // damit z.B. der Organizer nicht durcheinanderkommt, wenn zwischendurch eine
499 // Query-Box aufgemacht wird !!!
501 ScStyleSheetPool* pStylePool = xPoolHelper->GetStylePool();
502 USHORT nOldMask = pStylePool->GetSearchMask();
503 SfxStyleFamily eOldFam = pStylePool->GetSearchFamily();
505 pTable = pTab[nTab];
506 pStylePool->SetSearchMask( SFX_STYLE_FAMILY_PAGE, SFXSTYLEBIT_ALL );
507 pStyle = (ScStyleSheet*)pStylePool->Find( pTable->aPageStyle,
508 SFX_STYLE_FAMILY_PAGE );
510 DBG_ASSERT( pStyle, "Missing StyleSheet :-/" );
512 BOOL bProgress = FALSE;
513 if ( pStyle && 0 == GET_SCALEVALUE(pStyle->GetItemSet(),ATTR_PAGE_SCALETOPAGES) )
515 USHORT nCount = 0;
517 nZoom = GET_SCALEVALUE(pStyle->GetItemSet(),ATTR_PAGE_SCALE);
518 Fraction aZoomFract( nZoom, 100 );
519 pColumn = &pTable->aCol[nCol];
520 pColIter = new ScColumnIterator( pColumn, nRow, MAXROW );
522 while ( (nZoom > 0) && (nCount < CALCMAX) && (nRestart < 2) )
524 if ( pColIter->Next( nRow, pCell ) )
526 if ( TEXTWIDTH_DIRTY == pCell->GetTextWidth() )
528 if ( !pDev )
530 pDev = GetPrinter();
531 aOldMap = pDev->GetMapMode();
532 pDev->SetMapMode( MAP_PIXEL ); // wichtig fuer GetNeededSize
534 Point aPix1000 = pDev->LogicToPixel( Point(1000,1000), MAP_TWIP );
535 nPPTX = aPix1000.X() / 1000.0;
536 nPPTY = aPix1000.Y() / 1000.0;
538 if ( !bProgress && pCell->GetCellType() == CELLTYPE_FORMULA
539 && ((ScFormulaCell*)pCell)->GetDirty() )
541 ScProgress::CreateInterpretProgress( this, FALSE );
542 bProgress = TRUE;
545 // DBG_ERROR( String("t,c,r = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) );
546 // DBG_ERROR( String("nOldWidth = ") + String(pCell->GetTextWidth()) );
548 USHORT nNewWidth = (USHORT)GetNeededSize( nCol, nRow, nTab,
549 pDev, nPPTX, nPPTY,
550 aZoomFract,aZoomFract, TRUE,
551 TRUE ); // bTotalSize
553 // DBG_ERROR( String("nNewWidth = ") + String(nNewWidth) );
555 pCell->SetTextWidth( nNewWidth );
557 bNeedMore = TRUE;
560 else
562 BOOL bNewTab = FALSE;
564 nRow = 0;
565 nCol--;
567 if ( nCol < 0 )
569 nCol = MAXCOL;
570 nTab++;
571 bNewTab = TRUE;
574 if ( !ValidTab(nTab) || !pTab[nTab] )
576 nTab = 0;
577 nRestart++;
578 bNewTab = TRUE;
581 if ( nRestart < 2 )
583 if ( bNewTab )
585 pTable = pTab[nTab];
586 pStyle = (ScStyleSheet*)pStylePool->Find( pTable->aPageStyle,
587 SFX_STYLE_FAMILY_PAGE );
589 if ( pStyle )
591 SfxItemSet& rSet = pStyle->GetItemSet();
592 if ( GET_SCALEVALUE( rSet, ATTR_PAGE_SCALETOPAGES ) == 0 )
593 nZoom = GET_SCALEVALUE(rSet, ATTR_PAGE_SCALE );
594 else
595 nZoom = 0;
597 else
599 DBG_ERROR( "Missing StyleSheet :-/" );
603 if ( nZoom > 0 )
605 delete pColIter;
607 pColumn = &pTable->aCol[nCol];
608 pColIter = new ScColumnIterator( pColumn, nRow, MAXROW );
610 else
611 nTab++; // Tabelle nicht mit absolutem Zoom -> naechste
615 // nIter = nCount;
617 nCount++;
619 // Idle Berechnung abbrechen, wenn Berechnungen laenger als
620 // 50ms dauern, oder nach 32 Berechnungen mal nachschauen, ob
621 // bestimmte Events anstehen, die Beachtung wuenschen:
623 // nMs = SysTicksToMs( GetSysTicks() - nStart );
625 if ( ( 50L < Time::GetSystemTicks() - nStart )
626 || ( !(nCount&31) && Application::AnyInput( ABORT_EVENTS ) ) )
627 nCount = CALCMAX;
630 else
631 nTab++; // Tabelle nicht mit absolutem Zoom -> naechste
633 if ( bProgress )
634 ScProgress::DeleteInterpretProgress();
636 delete pColIter;
638 // DBG_ERROR( String(nCount) + String(" End = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) );
640 if (pDev)
641 pDev->SetMapMode(aOldMap);
643 aCurTextWidthCalcPos.SetTab( nTab );
644 aCurTextWidthCalcPos.SetRow( nRow );
645 aCurTextWidthCalcPos.SetCol( (SCCOL)nCol );
647 // DBG_ERROR( String(nMs) + String(" ms (") + String(nIter) + String(')') );
649 pStylePool->SetSearchMask( eOldFam, nOldMask );
650 bIdleDisabled = FALSE;
652 return bNeedMore;
655 //------------------------------------------------------------------------
657 class ScSpellStatus
659 public:
660 BOOL bModified;
662 ScSpellStatus() : bModified(FALSE) {};
664 DECL_LINK (EventHdl, EditStatus*);
667 IMPL_LINK( ScSpellStatus, EventHdl, EditStatus *, pStatus )
669 ULONG nStatus = pStatus->GetStatusWord();
670 if ( nStatus & EE_STAT_WRONGWORDCHANGED )
671 bModified = TRUE;
673 return 0;
676 // SPELL_MAXCELLS muss mindestens 256 sein, solange am Iterator keine
677 // Start-Spalte gesetzt werden kann
679 //! SPELL_MAXTEST fuer Timer und Idle unterschiedlich ???
681 // SPELL_MAXTEST now divided between visible and rest of document
683 #define SPELL_MAXTEST_VIS 1
684 #define SPELL_MAXTEST_ALL 3
685 #define SPELL_MAXCELLS 256
687 BOOL ScDocument::OnlineSpellInRange( const ScRange& rSpellRange, ScAddress& rSpellPos,
688 USHORT nMaxTest )
690 ScEditEngineDefaulter* pEngine = NULL; //! am Dokument speichern
691 SfxItemSet* pDefaults = NULL;
692 ScSpellStatus aStatus;
694 USHORT nCellCount = 0; // Zellen insgesamt
695 USHORT nTestCount = 0; // Aufrufe Spelling
696 BOOL bChanged = FALSE; // Aenderungen?
698 SCCOL nCol = rSpellRange.aStart.Col(); // iterator always starts on the left edge
699 SCROW nRow = rSpellPos.Row();
700 SCTAB nTab = rSpellPos.Tab();
701 if ( !pTab[nTab] ) // sheet deleted?
703 nTab = rSpellRange.aStart.Tab();
704 nRow = rSpellRange.aStart.Row();
705 if ( !pTab[nTab] )
707 // may happen for visible range
708 return FALSE;
711 ScHorizontalCellIterator aIter( this, nTab,
712 rSpellRange.aStart.Col(), nRow,
713 rSpellRange.aEnd.Col(), rSpellRange.aEnd.Row() );
714 ScBaseCell* pCell = aIter.GetNext( nCol, nRow );
715 // skip everything left of rSpellPos:
716 while ( pCell && nRow == rSpellPos.Row() && nCol < rSpellPos.Col() )
717 pCell = aIter.GetNext( nCol, nRow );
719 for (; pCell; pCell = aIter.GetNext(nCol, nRow))
721 if (pDPCollection && pDPCollection->HasDPTable(nCol, nRow, nTab))
722 // Don't spell check within datapilot table.
723 continue;
725 CellType eType = pCell->GetCellType();
726 if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
728 if (!pEngine)
730 // #71154# ScTabEditEngine is needed
731 // because MapMode must be set for some old documents
732 pEngine = new ScTabEditEngine( this );
733 pEngine->SetControlWord( pEngine->GetControlWord() |
734 ( EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS ) );
735 pEngine->SetStatusEventHdl( LINK( &aStatus, ScSpellStatus, EventHdl ) );
736 // Delimiters hier wie in inputhdl.cxx !!!
737 pEngine->SetWordDelimiters(
738 ScEditUtil::ModifyDelimiters( pEngine->GetWordDelimiters() ) );
739 pDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() );
741 com::sun::star::uno::Reference<com::sun::star::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
743 pEngine->SetSpeller( xXSpellChecker1 );
746 const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
747 pPattern->FillEditItemSet( pDefaults );
748 pEngine->SetDefaults( pDefaults, FALSE ); //! noetig ?
750 USHORT nCellLang = ((const SvxLanguageItem&)
751 pPattern->GetItem(ATTR_FONT_LANGUAGE)).GetValue();
752 if ( nCellLang == LANGUAGE_SYSTEM )
753 nCellLang = Application::GetSettings().GetLanguage(); // never use SYSTEM for spelling
754 pEngine->SetDefaultLanguage( nCellLang );
756 if ( eType == CELLTYPE_STRING )
758 String aText;
759 ((ScStringCell*)pCell)->GetString(aText);
760 pEngine->SetText( aText );
762 else
763 pEngine->SetText( *((ScEditCell*)pCell)->GetData() );
765 aStatus.bModified = FALSE;
766 pEngine->CompleteOnlineSpelling();
767 if ( aStatus.bModified ) // Fehler dazu oder weggekommen?
769 BOOL bNeedEdit = TRUE; // Test auf einfachen Text
770 if ( !pEngine->HasOnlineSpellErrors() )
772 ScEditAttrTester aTester( pEngine );
773 bNeedEdit = aTester.NeedsObject();
776 if ( bNeedEdit )
778 EditTextObject* pNewData = pEngine->CreateTextObject();
779 if ( eType == CELLTYPE_EDIT )
780 ((ScEditCell*)pCell)->SetData( pNewData,
781 pEngine->GetEditTextObjectPool() );
782 else
783 PutCell( nCol, nRow, nTab, new ScEditCell( pNewData,
784 this, pEngine->GetEditTextObjectPool() ) );
785 delete pNewData;
787 else // einfacher String
788 PutCell( nCol, nRow, nTab, new ScStringCell( pEngine->GetText() ) );
790 // Paint
791 if (pShell)
793 // #47751# Seitenvorschau ist davon nicht betroffen
794 // (sollte jedenfalls nicht)
795 ScPaintHint aHint( ScRange( nCol, nRow, nTab ), PAINT_GRID );
796 aHint.SetPrintFlag( FALSE );
797 pShell->Broadcast( aHint );
800 bChanged = TRUE;
803 if ( ++nTestCount >= nMaxTest ) // checked enough text?
804 break;
807 if ( ++nCellCount >= SPELL_MAXCELLS ) // seen enough cells?
808 break;
811 if ( pCell )
813 ++nCol; // continue after last cell
814 if ( nCol > rSpellRange.aEnd.Col() )
816 nCol = rSpellRange.aStart.Col();
817 ++nRow;
818 if ( nRow > rSpellRange.aEnd.Row() )
819 pCell = NULL;
823 if (!pCell) // end of range reached -> next sheet
825 ++nTab;
826 if ( nTab > rSpellRange.aEnd.Tab() || !pTab[nTab] )
827 nTab = rSpellRange.aStart.Tab();
828 nCol = rSpellRange.aStart.Col();
829 nRow = rSpellRange.aStart.Row();
831 nVisSpellState = VSPL_DONE; //! only if this is for the visible range
833 rSpellPos.Set( nCol, nRow, nTab );
835 delete pDefaults;
836 delete pEngine; // bevor aStatus out of scope geht
838 return bChanged;
842 BOOL ScDocument::ContinueOnlineSpelling()
844 if ( bIdleDisabled || !pDocOptions->IsAutoSpell() || (pShell && pShell->IsReadOnly()) )
845 return FALSE;
847 // #i48433# set bInsertingFromOtherDoc flag so there are no broadcasts when PutCell is called
848 // (same behavior as in RemoveAutoSpellObj: just transfer the broadcaster)
849 BOOL bOldInserting = IsInsertingFromOtherDoc();
850 SetInsertingFromOtherDoc( TRUE );
852 //! use one EditEngine for both calls
854 // #41504# first check visible range
855 BOOL bResult = OnlineSpellInRange( aVisSpellRange, aVisSpellPos, SPELL_MAXTEST_VIS );
857 // during first pass through visible range, always continue
858 if ( nVisSpellState == VSPL_START )
859 bResult = TRUE;
861 if (bResult)
863 // if errors found, continue there
864 OnlineSpellInRange( aVisSpellRange, aVisSpellPos, SPELL_MAXTEST_ALL );
866 else
868 // if nothing found there, continue with rest of document
869 ScRange aTotalRange( 0,0,0, MAXCOL,MAXROW,MAXTAB );
870 bResult = OnlineSpellInRange( aTotalRange, aOnlineSpellPos, SPELL_MAXTEST_ALL );
873 SetInsertingFromOtherDoc( bOldInserting );
875 return bResult;
879 void ScDocument::SetOnlineSpellPos( const ScAddress& rPos )
881 aOnlineSpellPos = rPos;
883 // skip visible area for aOnlineSpellPos
884 if ( aVisSpellRange.In( aOnlineSpellPos ) )
885 aOnlineSpellPos = aVisSpellRange.aEnd;
888 BOOL ScDocument::SetVisibleSpellRange( const ScRange& rNewRange )
890 BOOL bChange = ( aVisSpellRange != rNewRange );
891 if (bChange)
893 // continue spelling through visible range when scrolling down
894 BOOL bContDown = ( nVisSpellState == VSPL_START && rNewRange.In( aVisSpellPos ) &&
895 rNewRange.aStart.Row() > aVisSpellRange.aStart.Row() &&
896 rNewRange.aStart.Col() == aVisSpellRange.aStart.Col() &&
897 rNewRange.aEnd.Col() == aVisSpellRange.aEnd.Col() );
899 aVisSpellRange = rNewRange;
901 if ( !bContDown )
903 aVisSpellPos = aVisSpellRange.aStart;
904 nVisSpellState = VSPL_START;
907 // skip visible area for aOnlineSpellPos
908 if ( aVisSpellRange.In( aOnlineSpellPos ) )
909 aOnlineSpellPos = aVisSpellRange.aEnd;
911 return bChange;
914 void ScDocument::RemoveAutoSpellObj()
916 // alle Spelling-Informationen entfernen
918 for (SCTAB nTab=0; nTab<=MAXTAB && pTab[nTab]; nTab++)
919 pTab[nTab]->RemoveAutoSpellObj();
922 //------------------------------------------------------------------------
924 BOOL ScDocument::IdleCheckLinks() // TRUE = demnaechst wieder versuchen
926 BOOL bAnyLeft = FALSE;
928 if (GetLinkManager())
930 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
931 USHORT nCount = rLinks.Count();
932 for (USHORT i=0; i<nCount; i++)
934 ::sfx2::SvBaseLink* pBase = *rLinks[i];
935 if (pBase->ISA(ScDdeLink))
937 ScDdeLink* pDdeLink = (ScDdeLink*)pBase;
938 if (pDdeLink->NeedsUpdate())
940 pDdeLink->TryUpdate();
941 if (pDdeLink->NeedsUpdate()) // war nix?
942 bAnyLeft = TRUE;
948 return bAnyLeft;
951 void ScDocument::SaveDdeLinks(SvStream& rStream) const
953 // bei 4.0-Export alle mit Modus != DEFAULT weglassen
954 BOOL bExport40 = ( rStream.GetVersion() <= SOFFICE_FILEFORMAT_40 );
956 const ::sfx2::SvBaseLinks& rLinks = GetLinkManager()->GetLinks();
957 USHORT nCount = rLinks.Count();
959 // erstmal zaehlen...
961 USHORT nDdeCount = 0;
962 USHORT i;
963 for (i=0; i<nCount; i++)
965 ::sfx2::SvBaseLink* pBase = *rLinks[i];
966 if (pBase->ISA(ScDdeLink))
967 if ( !bExport40 || ((ScDdeLink*)pBase)->GetMode() == SC_DDE_DEFAULT )
968 ++nDdeCount;
971 // Header
973 ScMultipleWriteHeader aHdr( rStream );
974 rStream << nDdeCount;
976 // Links speichern
978 for (i=0; i<nCount; i++)
980 ::sfx2::SvBaseLink* pBase = *rLinks[i];
981 if (pBase->ISA(ScDdeLink))
983 ScDdeLink* pLink = (ScDdeLink*)pBase;
984 if ( !bExport40 || pLink->GetMode() == SC_DDE_DEFAULT )
985 pLink->Store( rStream, aHdr );
990 void ScDocument::LoadDdeLinks(SvStream& rStream)
992 ScMultipleReadHeader aHdr( rStream );
994 GetLinkManager();
995 USHORT nCount;
996 rStream >> nCount;
997 for (USHORT i=0; i<nCount; i++)
999 ScDdeLink* pLink = new ScDdeLink( this, rStream, aHdr );
1000 pLinkManager->InsertDDELink( pLink,
1001 pLink->GetAppl(), pLink->GetTopic(), pLink->GetItem() );
1005 BOOL ScDocument::HasDdeLinks() const
1007 if (GetLinkManager()) // Clipboard z.B. hat keinen LinkManager
1009 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1010 USHORT nCount = rLinks.Count();
1011 for (USHORT i=0; i<nCount; i++)
1012 if ((*rLinks[i])->ISA(ScDdeLink))
1013 return TRUE;
1016 return FALSE;
1019 void ScDocument::SetInLinkUpdate(BOOL bSet)
1021 // called from TableLink and AreaLink
1023 DBG_ASSERT( bInLinkUpdate != bSet, "SetInLinkUpdate twice" );
1024 bInLinkUpdate = bSet;
1027 BOOL ScDocument::IsInLinkUpdate() const
1029 return bInLinkUpdate || IsInDdeLinkUpdate();
1032 void ScDocument::UpdateExternalRefLinks()
1034 if (!GetLinkManager())
1035 return;
1037 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1038 USHORT nCount = rLinks.Count();
1040 bool bAny = false;
1041 for (USHORT i = 0; i < nCount; ++i)
1043 ::sfx2::SvBaseLink* pBase = *rLinks[i];
1044 ScExternalRefLink* pRefLink = dynamic_cast<ScExternalRefLink*>(pBase);
1045 if (pRefLink)
1047 pRefLink->Update();
1048 bAny = true;
1051 if (bAny)
1053 TrackFormulas();
1054 pShell->Broadcast( SfxSimpleHint(FID_DATACHANGED) );
1055 ResetChanged( ScRange(0, 0, 0, MAXCOL, MAXROW, MAXTAB) );
1057 // #i101960# set document modified, as in TrackTimeHdl for DDE links
1058 if (!pShell->IsModified())
1060 pShell->SetModified( TRUE );
1061 SfxBindings* pBindings = GetViewBindings();
1062 if (pBindings)
1064 pBindings->Invalidate( SID_SAVEDOC );
1065 pBindings->Invalidate( SID_DOC_MODIFIED );
1071 void ScDocument::UpdateDdeLinks()
1073 if (GetLinkManager())
1075 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1076 USHORT nCount = rLinks.Count();
1077 USHORT i;
1079 // #49226# falls das Updaten laenger dauert, erstmal alle Werte
1080 // zuruecksetzen, damit nichts altes (falsches) stehen bleibt
1081 BOOL bAny = FALSE;
1082 for (i=0; i<nCount; i++)
1084 ::sfx2::SvBaseLink* pBase = *rLinks[i];
1085 if (pBase->ISA(ScDdeLink))
1087 ((ScDdeLink*)pBase)->ResetValue();
1088 bAny = TRUE;
1091 if (bAny)
1093 // Formeln berechnen und painten wie im TrackTimeHdl
1094 TrackFormulas();
1095 pShell->Broadcast( SfxSimpleHint( FID_DATACHANGED ) );
1096 ResetChanged( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB) );
1098 // wenn FID_DATACHANGED irgendwann mal asynchron werden sollte
1099 // (z.B. mit Invalidate am Window), muss hier ein Update erzwungen werden.
1102 // nun wirklich updaten...
1103 for (i=0; i<nCount; i++)
1105 ::sfx2::SvBaseLink* pBase = *rLinks[i];
1106 if (pBase->ISA(ScDdeLink))
1107 ((ScDdeLink*)pBase)->TryUpdate(); // bei DDE-Links TryUpdate statt Update
1112 BOOL ScDocument::UpdateDdeLink( const String& rAppl, const String& rTopic, const String& rItem )
1114 // fuer refresh() per StarOne Api
1115 // ResetValue() fuer einzelnen Link nicht noetig
1116 //! wenn's mal alles asynchron wird, aber auch hier
1118 BOOL bFound = FALSE;
1119 if (GetLinkManager())
1121 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1122 USHORT nCount = rLinks.Count();
1123 for (USHORT i=0; i<nCount; i++)
1125 ::sfx2::SvBaseLink* pBase = *rLinks[i];
1126 if (pBase->ISA(ScDdeLink))
1128 ScDdeLink* pDdeLink = (ScDdeLink*)pBase;
1129 if ( pDdeLink->GetAppl() == rAppl &&
1130 pDdeLink->GetTopic() == rTopic &&
1131 pDdeLink->GetItem() == rItem )
1133 pDdeLink->TryUpdate();
1134 bFound = TRUE; // koennen theoretisch mehrere sein (Mode), darum weitersuchen
1139 return bFound;
1142 void ScDocument::DisconnectDdeLinks()
1144 if (GetLinkManager())
1146 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1147 USHORT nCount = rLinks.Count();
1148 for (USHORT i=0; i<nCount; i++)
1150 ::sfx2::SvBaseLink* pBase = *rLinks[i];
1151 if (pBase->ISA(ScDdeLink))
1152 pBase->Disconnect(); // bleibt im LinkManager eingetragen
1157 void ScDocument::CopyDdeLinks( ScDocument* pDestDoc ) const
1159 if (bIsClip) // aus Stream erzeugen
1161 if (pClipData)
1163 pClipData->Seek(0);
1164 pDestDoc->LoadDdeLinks(*pClipData);
1167 else if (GetLinkManager()) // Links direkt kopieren
1169 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1170 USHORT nCount = rLinks.Count();
1171 for (USHORT i=0; i<nCount; i++)
1173 ::sfx2::SvBaseLink* pBase = *rLinks[i];
1174 if (pBase->ISA(ScDdeLink))
1176 ScDdeLink* pNew = new ScDdeLink( pDestDoc, *(ScDdeLink*)pBase );
1178 pDestDoc->pLinkManager->InsertDDELink( pNew,
1179 pNew->GetAppl(), pNew->GetTopic(), pNew->GetItem() );
1185 USHORT ScDocument::GetDdeLinkCount() const
1187 USHORT nDdeCount = 0;
1188 if (GetLinkManager())
1190 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1191 USHORT nCount = rLinks.Count();
1192 for (USHORT i=0; i<nCount; i++)
1193 if ((*rLinks[i])->ISA(ScDdeLink))
1194 ++nDdeCount;
1196 return nDdeCount;
1199 // ----------------------------------------------------------------------------
1201 namespace {
1203 /** Tries to find the specified DDE link.
1204 @param pnDdePos (out-param) if not 0, the index of the DDE link is returned here
1205 (does not include other links from link manager).
1206 @return The DDE link, if it exists, otherwise 0. */
1207 ScDdeLink* lclGetDdeLink(
1208 const SvxLinkManager* pLinkManager,
1209 const String& rAppl, const String& rTopic, const String& rItem, BYTE nMode,
1210 USHORT* pnDdePos = NULL )
1212 if( pLinkManager )
1214 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1215 USHORT nCount = rLinks.Count();
1216 if( pnDdePos ) *pnDdePos = 0;
1217 for( USHORT nIndex = 0; nIndex < nCount; ++nIndex )
1219 ::sfx2::SvBaseLink* pLink = *rLinks[ nIndex ];
1220 if( ScDdeLink* pDdeLink = PTR_CAST( ScDdeLink, pLink ) )
1222 if( (pDdeLink->GetAppl() == rAppl) &&
1223 (pDdeLink->GetTopic() == rTopic) &&
1224 (pDdeLink->GetItem() == rItem) &&
1225 ((nMode == SC_DDE_IGNOREMODE) || (nMode == pDdeLink->GetMode())) )
1226 return pDdeLink;
1227 if( pnDdePos ) ++*pnDdePos;
1231 return NULL;
1234 /** Returns a pointer to the specified DDE link.
1235 @param nDdePos Index of the DDE link (does not include other links from link manager).
1236 @return The DDE link, if it exists, otherwise 0. */
1237 ScDdeLink* lclGetDdeLink( const SvxLinkManager* pLinkManager, USHORT nDdePos )
1239 if( pLinkManager )
1241 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1242 USHORT nCount = rLinks.Count();
1243 USHORT nDdeIndex = 0; // counts only the DDE links
1244 for( USHORT nIndex = 0; nIndex < nCount; ++nIndex )
1246 ::sfx2::SvBaseLink* pLink = *rLinks[ nIndex ];
1247 if( ScDdeLink* pDdeLink = PTR_CAST( ScDdeLink, pLink ) )
1249 if( nDdeIndex == nDdePos )
1250 return pDdeLink;
1251 ++nDdeIndex;
1255 return NULL;
1258 } // namespace
1260 // ----------------------------------------------------------------------------
1262 bool ScDocument::FindDdeLink( const String& rAppl, const String& rTopic, const String& rItem, BYTE nMode, USHORT& rnDdePos )
1264 return lclGetDdeLink( GetLinkManager(), rAppl, rTopic, rItem, nMode, &rnDdePos ) != NULL;
1267 bool ScDocument::GetDdeLinkData( USHORT nDdePos, String& rAppl, String& rTopic, String& rItem ) const
1269 if( const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) )
1271 rAppl = pDdeLink->GetAppl();
1272 rTopic = pDdeLink->GetTopic();
1273 rItem = pDdeLink->GetItem();
1274 return true;
1276 return false;
1279 bool ScDocument::GetDdeLinkMode( USHORT nDdePos, BYTE& rnMode ) const
1281 if( const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) )
1283 rnMode = pDdeLink->GetMode();
1284 return true;
1286 return false;
1289 const ScMatrix* ScDocument::GetDdeLinkResultMatrix( USHORT nDdePos ) const
1291 const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos );
1292 return pDdeLink ? pDdeLink->GetResult() : NULL;
1295 bool ScDocument::CreateDdeLink( const String& rAppl, const String& rTopic, const String& rItem, BYTE nMode, ScMatrix* pResults )
1297 /* Create a DDE link without updating it (i.e. for Excel import), to prevent
1298 unwanted connections. First try to find existing link. Set result array
1299 on existing and new links. */
1300 //! store DDE links additionally at document (for efficiency)?
1301 DBG_ASSERT( nMode != SC_DDE_IGNOREMODE, "ScDocument::CreateDdeLink - SC_DDE_IGNOREMODE not allowed here" );
1302 if( GetLinkManager() && (nMode != SC_DDE_IGNOREMODE) )
1304 ScDdeLink* pDdeLink = lclGetDdeLink( pLinkManager, rAppl, rTopic, rItem, nMode );
1305 if( !pDdeLink )
1307 // create a new DDE link, but without TryUpdate
1308 pDdeLink = new ScDdeLink( this, rAppl, rTopic, rItem, nMode );
1309 pLinkManager->InsertDDELink( pDdeLink, rAppl, rTopic, rItem );
1312 // insert link results
1313 if( pResults )
1314 pDdeLink->SetResult( pResults );
1316 return true;
1318 return false;
1321 bool ScDocument::SetDdeLinkResultMatrix( USHORT nDdePos, ScMatrix* pResults )
1323 if( ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) )
1325 pDdeLink->SetResult( pResults );
1326 return true;
1328 return false;
1331 //------------------------------------------------------------------------
1333 BOOL ScDocument::HasAreaLinks() const
1335 if (GetLinkManager()) // Clipboard z.B. hat keinen LinkManager
1337 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1338 USHORT nCount = rLinks.Count();
1339 for (USHORT i=0; i<nCount; i++)
1340 if ((*rLinks[i])->ISA(ScAreaLink))
1341 return TRUE;
1344 return FALSE;
1347 void ScDocument::UpdateAreaLinks()
1349 if (GetLinkManager())
1351 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1352 USHORT nCount = rLinks.Count();
1353 for (USHORT i=0; i<nCount; i++)
1355 ::sfx2::SvBaseLink* pBase = *rLinks[i];
1356 if (pBase->ISA(ScAreaLink))
1357 pBase->Update();
1362 void ScDocument::DeleteAreaLinksOnTab( SCTAB nTab )
1364 if (GetLinkManager())
1366 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1367 USHORT nPos = 0;
1368 while ( nPos < rLinks.Count() )
1370 const ::sfx2::SvBaseLink* pBase = *rLinks[nPos];
1371 if ( pBase->ISA(ScAreaLink) &&
1372 static_cast<const ScAreaLink*>(pBase)->GetDestArea().aStart.Tab() == nTab )
1373 pLinkManager->Remove( nPos );
1374 else
1375 ++nPos;
1380 void ScDocument::UpdateRefAreaLinks( UpdateRefMode eUpdateRefMode,
1381 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
1383 if (GetLinkManager())
1385 bool bAnyUpdate = false;
1387 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
1388 USHORT nCount = rLinks.Count();
1389 for (USHORT i=0; i<nCount; i++)
1391 ::sfx2::SvBaseLink* pBase = *rLinks[i];
1392 if (pBase->ISA(ScAreaLink))
1394 ScAreaLink* pLink = (ScAreaLink*) pBase;
1395 ScRange aOutRange = pLink->GetDestArea();
1397 SCCOL nCol1 = aOutRange.aStart.Col();
1398 SCROW nRow1 = aOutRange.aStart.Row();
1399 SCTAB nTab1 = aOutRange.aStart.Tab();
1400 SCCOL nCol2 = aOutRange.aEnd.Col();
1401 SCROW nRow2 = aOutRange.aEnd.Row();
1402 SCTAB nTab2 = aOutRange.aEnd.Tab();
1404 ScRefUpdateRes eRes =
1405 ScRefUpdate::Update( this, eUpdateRefMode,
1406 rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
1407 rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
1408 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
1409 if ( eRes != UR_NOTHING )
1411 pLink->SetDestArea( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) );
1412 bAnyUpdate = true;
1417 if ( bAnyUpdate )
1419 // #i52120# Look for duplicates (after updating all positions).
1420 // If several links start at the same cell, the one with the lower index is removed
1421 // (file format specifies only one link definition for a cell).
1423 USHORT nFirstIndex = 0;
1424 while ( nFirstIndex < nCount )
1426 bool bFound = false;
1427 ::sfx2::SvBaseLink* pFirst = *rLinks[nFirstIndex];
1428 if ( pFirst->ISA(ScAreaLink) )
1430 ScAddress aFirstPos = static_cast<ScAreaLink*>(pFirst)->GetDestArea().aStart;
1431 for ( USHORT nSecondIndex = nFirstIndex + 1; nSecondIndex < nCount && !bFound; ++nSecondIndex )
1433 ::sfx2::SvBaseLink* pSecond = *rLinks[nSecondIndex];
1434 if ( pSecond->ISA(ScAreaLink) &&
1435 static_cast<ScAreaLink*>(pSecond)->GetDestArea().aStart == aFirstPos )
1437 // remove the first link, exit the inner loop, don't increment nFirstIndex
1438 pLinkManager->Remove( pFirst );
1439 nCount = rLinks.Count();
1440 bFound = true;
1444 if (!bFound)
1445 ++nFirstIndex;
1451 //------------------------------------------------------------------------
1453 // TimerDelays etc.
1454 void ScDocument::KeyInput( const KeyEvent& )
1456 if ( pChartListenerCollection->GetCount() )
1457 pChartListenerCollection->StartTimer();
1458 if( apTemporaryChartLock.get() )
1459 apTemporaryChartLock->StartOrContinueLocking();
1462 // ----------------------------------------------------------------------------
1464 BOOL ScDocument::CheckMacroWarn()
1466 // The check for macro configuration, macro warning and disabling is now handled
1467 // in SfxObjectShell::AdjustMacroMode, called by SfxObjectShell::CallBasic.
1469 return TRUE;
1472 //------------------------------------------------------------------------
1474 SfxBindings* ScDocument::GetViewBindings()
1476 // used to invalidate slots after changes to this document
1478 if ( !pShell )
1479 return NULL; // no ObjShell -> no view
1481 // first check current view
1482 SfxViewFrame* pViewFrame = SfxViewFrame::Current();
1483 if ( pViewFrame && pViewFrame->GetObjectShell() != pShell ) // wrong document?
1484 pViewFrame = NULL;
1486 // otherwise use first view for this doc
1487 if ( !pViewFrame )
1488 pViewFrame = SfxViewFrame::GetFirst( pShell );
1490 if (pViewFrame)
1491 return &pViewFrame->GetBindings();
1492 else
1493 return NULL;
1496 //------------------------------------------------------------------------
1498 void lcl_TransliterateEditEngine( ScEditEngineDefaulter& rEngine,
1499 utl::TransliterationWrapper& rTranslitarationWrapper,
1500 BOOL bConsiderLanguage, ScDocument* pDoc )
1502 //! should use TransliterateText method of EditEngine instead, when available!
1504 sal_uInt16 nLanguage = LANGUAGE_SYSTEM;
1506 USHORT nParCount = rEngine.GetParagraphCount();
1507 for (USHORT nPar=0; nPar<nParCount; nPar++)
1509 SvUShorts aPortions;
1510 rEngine.GetPortions( (USHORT)nPar, aPortions );
1512 for ( USHORT nPos = aPortions.Count(); nPos; )
1514 --nPos;
1515 USHORT nEnd = aPortions.GetObject( nPos );
1516 USHORT nStart = nPos ? aPortions.GetObject( nPos - 1 ) : 0;
1518 ESelection aSel( nPar, nStart, nPar, nEnd );
1519 String aOldStr = rEngine.GetText( aSel );
1520 SfxItemSet aAttr = rEngine.GetAttribs( aSel );
1522 if ( aAttr.GetItemState( EE_FEATURE_FIELD ) != SFX_ITEM_ON ) // fields are not touched
1524 if ( bConsiderLanguage )
1526 BYTE nScript = pDoc->GetStringScriptType( aOldStr );
1527 USHORT nWhich = ( nScript == SCRIPTTYPE_ASIAN ) ? EE_CHAR_LANGUAGE_CJK :
1528 ( ( nScript == SCRIPTTYPE_COMPLEX ) ? EE_CHAR_LANGUAGE_CTL :
1529 EE_CHAR_LANGUAGE );
1530 nLanguage = ((const SvxLanguageItem&)aAttr.Get(nWhich)).GetValue();
1533 com::sun::star::uno::Sequence<sal_Int32> aOffsets;
1534 String aNewStr = rTranslitarationWrapper.transliterate( aOldStr, nLanguage, 0, aOldStr.Len(), &aOffsets );
1536 if ( aNewStr != aOldStr )
1538 // replace string, keep attributes
1540 rEngine.QuickInsertText( aNewStr, aSel );
1541 aSel.nEndPos = aSel.nStartPos + aNewStr.Len();
1542 rEngine.QuickSetAttribs( aAttr, aSel );
1549 void ScDocument::TransliterateText( const ScMarkData& rMultiMark, sal_Int32 nType )
1551 DBG_ASSERT( rMultiMark.IsMultiMarked(), "TransliterateText: no selection" );
1553 utl::TransliterationWrapper aTranslitarationWrapper( xServiceManager, nType );
1554 BOOL bConsiderLanguage = aTranslitarationWrapper.needLanguageForTheMode();
1555 sal_uInt16 nLanguage = LANGUAGE_SYSTEM;
1557 ScEditEngineDefaulter* pEngine = NULL; // not using pEditEngine member because of defaults
1559 SCTAB nCount = GetTableCount();
1560 for (SCTAB nTab = 0; nTab < nCount; nTab++)
1561 if ( pTab[nTab] && rMultiMark.GetTableSelect(nTab) )
1563 SCCOL nCol = 0;
1564 SCROW nRow = 0;
1566 BOOL bFound = rMultiMark.IsCellMarked( nCol, nRow );
1567 if (!bFound)
1568 bFound = GetNextMarkedCell( nCol, nRow, nTab, rMultiMark );
1570 while (bFound)
1572 const ScBaseCell* pCell = GetCell( ScAddress( nCol, nRow, nTab ) );
1573 CellType eType = pCell ? pCell->GetCellType() : CELLTYPE_NONE;
1575 if ( eType == CELLTYPE_STRING )
1577 String aOldStr;
1578 ((const ScStringCell*)pCell)->GetString(aOldStr);
1579 xub_StrLen nOldLen = aOldStr.Len();
1581 if ( bConsiderLanguage )
1583 BYTE nScript = GetStringScriptType( aOldStr ); //! cell script type?
1584 USHORT 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();
1590 com::sun::star::uno::Sequence<sal_Int32> aOffsets;
1591 String aNewStr = aTranslitarationWrapper.transliterate( aOldStr, nLanguage, 0, nOldLen, &aOffsets );
1593 if ( aNewStr != aOldStr )
1594 PutCell( nCol, nRow, nTab, new ScStringCell( aNewStr ) );
1596 else if ( eType == CELLTYPE_EDIT )
1598 if (!pEngine)
1599 pEngine = new ScFieldEditEngine( GetEnginePool(), GetEditPool() );
1601 // defaults from cell attributes must be set so right language is used
1602 const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
1603 SfxItemSet* pDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() );
1604 pPattern->FillEditItemSet( pDefaults );
1605 pEngine->SetDefaults( pDefaults, TRUE );
1607 const EditTextObject* pData = ((const ScEditCell*)pCell)->GetData();
1608 pEngine->SetText( *pData );
1610 pEngine->ClearModifyFlag();
1612 lcl_TransliterateEditEngine( *pEngine, aTranslitarationWrapper, bConsiderLanguage, this );
1614 if ( pEngine->IsModified() )
1616 ScEditAttrTester aTester( pEngine );
1617 if ( aTester.NeedsObject() )
1619 // remove defaults (paragraph attributes) before creating text object
1620 SfxItemSet* pEmpty = new SfxItemSet( pEngine->GetEmptyItemSet() );
1621 pEngine->SetDefaults( pEmpty, TRUE );
1623 EditTextObject* pNewData = pEngine->CreateTextObject();
1624 PutCell( nCol, nRow, nTab,
1625 new ScEditCell( pNewData, this, pEngine->GetEditTextObjectPool() ) );
1626 delete pNewData;
1628 else
1630 String aNewStr = pEngine->GetText();
1631 PutCell( nCol, nRow, nTab, new ScStringCell( aNewStr ) );
1636 bFound = GetNextMarkedCell( nCol, nRow, nTab, rMultiMark );
1640 delete pEngine;