xref: /trunk/main/sc/source/core/data/documen8.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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