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