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