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