xref: /trunk/main/sc/source/ui/unoobj/linkuno.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 #include <svl/smplhint.hxx>
34 #include <sfx2/linkmgr.hxx>
35 
36 #include "linkuno.hxx"
37 #include "miscuno.hxx"
38 #include "convuno.hxx"
39 #include "docsh.hxx"
40 #include "docfunc.hxx"
41 #include "collect.hxx"
42 #include "tablink.hxx"
43 #include "arealink.hxx"
44 #include "unoguard.hxx"
45 #include "hints.hxx"
46 #include "unonames.hxx"
47 #include "rangeseq.hxx"
48 #include "token.hxx"
49 
50 #include <vector>
51 #include <climits>
52 
53 using namespace com::sun::star;
54 using namespace formula;
55 using ::com::sun::star::uno::Any;
56 using ::com::sun::star::uno::Reference;
57 using ::com::sun::star::uno::Sequence;
58 using ::com::sun::star::uno::UNO_QUERY;
59 using ::com::sun::star::uno::UNO_QUERY_THROW;
60 using ::com::sun::star::lang::IllegalArgumentException;
61 using ::com::sun::star::uno::RuntimeException;
62 using ::rtl::OUString;
63 using ::std::vector;
64 
65 //------------------------------------------------------------------------
66 
67 //  fuer Sheet- und Area-Links benutzt:
68 const SfxItemPropertyMapEntry* lcl_GetSheetLinkMap()
69 {
70     static SfxItemPropertyMapEntry aSheetLinkMap_Impl[] =
71     {
72         {MAP_CHAR_LEN(SC_UNONAME_FILTER),   0,  &getCppuType((rtl::OUString*)0),    0, 0 },
73         {MAP_CHAR_LEN(SC_UNONAME_FILTOPT),  0,  &getCppuType((rtl::OUString*)0),    0, 0 },
74         {MAP_CHAR_LEN(SC_UNONAME_LINKURL),  0,  &getCppuType((rtl::OUString*)0),    0, 0 },
75         {MAP_CHAR_LEN(SC_UNONAME_REFDELAY), 0,  &getCppuType((sal_Int32*)0),        0, 0 },
76         {MAP_CHAR_LEN(SC_UNONAME_REFPERIOD),    0,  &getCppuType((sal_Int32*)0),        0, 0 },
77         {0,0,0,0,0,0}
78     };
79     return aSheetLinkMap_Impl;
80 }
81 
82 //------------------------------------------------------------------------
83 
84 SV_IMPL_PTRARR( XRefreshListenerArr_Impl, XRefreshListenerPtr );
85 
86 SC_SIMPLE_SERVICE_INFO( ScAreaLinkObj, "ScAreaLinkObj", "com.sun.star.sheet.CellAreaLink" )
87 SC_SIMPLE_SERVICE_INFO( ScAreaLinksObj, "ScAreaLinksObj", "com.sun.star.sheet.CellAreaLinks" )
88 SC_SIMPLE_SERVICE_INFO( ScDDELinkObj, "ScDDELinkObj", "com.sun.star.sheet.DDELink" )
89 SC_SIMPLE_SERVICE_INFO( ScDDELinksObj, "ScDDELinksObj", "com.sun.star.sheet.DDELinks" )
90 SC_SIMPLE_SERVICE_INFO( ScSheetLinkObj, "ScSheetLinkObj", "com.sun.star.sheet.SheetLink" )
91 SC_SIMPLE_SERVICE_INFO( ScSheetLinksObj, "ScSheetLinksObj", "com.sun.star.sheet.SheetLinks" )
92 
93 //------------------------------------------------------------------------
94 
95 ScSheetLinkObj::ScSheetLinkObj(ScDocShell* pDocSh, const String& rName) :
96     aPropSet( lcl_GetSheetLinkMap() ),
97     pDocShell( pDocSh ),
98     aFileName( rName )
99 {
100     pDocShell->GetDocument()->AddUnoObject(*this);
101 }
102 
103 ScSheetLinkObj::~ScSheetLinkObj()
104 {
105     if (pDocShell)
106         pDocShell->GetDocument()->RemoveUnoObject(*this);
107 }
108 
109 void ScSheetLinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
110 {
111     //! notify if links in document are changed
112     //  UpdateRef is not needed here
113 
114     if ( rHint.ISA( SfxSimpleHint ) )
115     {
116         if ( ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
117             pDocShell = NULL;       // pointer is invalid
118     }
119     else if ( rHint.ISA( ScLinkRefreshedHint ) )
120     {
121         const ScLinkRefreshedHint& rLH = (const ScLinkRefreshedHint&) rHint;
122         if ( rLH.GetLinkType() == SC_LINKREFTYPE_SHEET && rLH.GetUrl() == aFileName )
123             Refreshed_Impl();
124     }
125 }
126 
127 ScTableLink* ScSheetLinkObj::GetLink_Impl() const
128 {
129     if (pDocShell)
130     {
131         sfx2::LinkManager* pLinkManager = pDocShell->GetDocument()->GetLinkManager();
132         sal_uInt16 nCount = pLinkManager->GetLinks().Count();
133         for (sal_uInt16 i=0; i<nCount; i++)
134         {
135             ::sfx2::SvBaseLink* pBase = *pLinkManager->GetLinks()[i];
136             if (pBase->ISA(ScTableLink))
137             {
138                 ScTableLink* pTabLink = (ScTableLink*)pBase;
139                 if ( pTabLink->GetFileName() == aFileName )
140                     return pTabLink;
141             }
142         }
143     }
144     return NULL;    // nicht gefunden
145 }
146 
147 // XNamed
148 
149 rtl::OUString SAL_CALL ScSheetLinkObj::getName() throw(uno::RuntimeException)
150 {
151     ScUnoGuard aGuard;
152     return getFileName();   // Name ist der Dateiname (URL)
153 }
154 
155 void SAL_CALL ScSheetLinkObj::setName( const rtl::OUString& aName ) throw(uno::RuntimeException)
156 {
157     ScUnoGuard aGuard;
158     setFileName(aName);     // Name ist der Dateiname (URL)
159 }
160 
161 // XRefreshable
162 
163 void SAL_CALL ScSheetLinkObj::refresh() throw(uno::RuntimeException)
164 {
165     ScUnoGuard aGuard;
166     ScTableLink* pLink = GetLink_Impl();
167     if (pLink)
168         pLink->Refresh( pLink->GetFileName(), pLink->GetFilterName(), NULL, pLink->GetRefreshDelay() );
169 }
170 
171 void SAL_CALL ScSheetLinkObj::addRefreshListener(
172                                 const uno::Reference<util::XRefreshListener >& xListener )
173                                                 throw(uno::RuntimeException)
174 {
175     ScUnoGuard aGuard;
176     uno::Reference<util::XRefreshListener>* pObj =
177             new uno::Reference<util::XRefreshListener>( xListener );
178     aRefreshListeners.Insert( pObj, aRefreshListeners.Count() );
179 
180     //  hold one additional ref to keep this object alive as long as there are listeners
181     if ( aRefreshListeners.Count() == 1 )
182         acquire();
183 }
184 
185 void SAL_CALL ScSheetLinkObj::removeRefreshListener(
186                                 const uno::Reference<util::XRefreshListener >& xListener )
187                                                 throw(uno::RuntimeException)
188 {
189     ScUnoGuard aGuard;
190     sal_uInt16 nCount = aRefreshListeners.Count();
191     for ( sal_uInt16 n=nCount; n--; )
192     {
193         uno::Reference<util::XRefreshListener>* pObj = aRefreshListeners[n];
194         if ( *pObj == xListener )
195         {
196             aRefreshListeners.DeleteAndDestroy( n );
197             if ( aRefreshListeners.Count() == 0 )
198                 release();                          // release ref for listeners
199             break;
200         }
201     }
202 }
203 
204 void ScSheetLinkObj::Refreshed_Impl()
205 {
206     lang::EventObject aEvent;
207     aEvent.Source.set((cppu::OWeakObject*)this);
208     for ( sal_uInt16 n=0; n<aRefreshListeners.Count(); n++ )
209         (*aRefreshListeners[n])->refreshed( aEvent );
210 }
211 
212 void ScSheetLinkObj::ModifyRefreshDelay_Impl( sal_Int32 nRefresh )
213 {
214     ScTableLink* pLink = GetLink_Impl();
215     if( pLink )
216         pLink->SetRefreshDelay( (sal_uLong) nRefresh );
217 }
218 
219 // XPropertySet
220 
221 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSheetLinkObj::getPropertySetInfo()
222                                                         throw(uno::RuntimeException)
223 {
224     ScUnoGuard aGuard;
225     static uno::Reference<beans::XPropertySetInfo> aRef(
226         new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
227     return aRef;
228 }
229 
230 void SAL_CALL ScSheetLinkObj::setPropertyValue(
231                         const rtl::OUString& aPropertyName, const uno::Any& aValue )
232                 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
233                         lang::IllegalArgumentException, lang::WrappedTargetException,
234                         uno::RuntimeException)
235 {
236     ScUnoGuard aGuard;
237     String aNameString(aPropertyName);
238     rtl::OUString aValStr;
239     if ( aNameString.EqualsAscii( SC_UNONAME_LINKURL ) )
240     {
241         if ( aValue >>= aValStr )
242             setFileName( aValStr );
243     }
244     else if ( aNameString.EqualsAscii( SC_UNONAME_FILTER ) )
245     {
246         if ( aValue >>= aValStr )
247             setFilter( aValStr );
248     }
249     else if ( aNameString.EqualsAscii( SC_UNONAME_FILTOPT ) )
250     {
251         if ( aValue >>= aValStr )
252             setFilterOptions( aValStr );
253     }
254     else if ( aNameString.EqualsAscii( SC_UNONAME_REFPERIOD ) )
255     {
256         sal_Int32 nRefresh = 0;
257         if ( aValue >>= nRefresh )
258             setRefreshDelay( nRefresh );
259     }
260     else if ( aNameString.EqualsAscii( SC_UNONAME_REFDELAY ) )
261     {
262         sal_Int32 nRefresh = 0;
263         if ( aValue >>= nRefresh )
264             setRefreshDelay( nRefresh );
265     }
266 }
267 
268 uno::Any SAL_CALL ScSheetLinkObj::getPropertyValue( const rtl::OUString& aPropertyName )
269                 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
270                         uno::RuntimeException)
271 {
272     ScUnoGuard aGuard;
273     String aNameString(aPropertyName);
274     uno::Any aRet;
275     if ( aNameString.EqualsAscii( SC_UNONAME_LINKURL ) )
276         aRet <<= getFileName();
277     else if ( aNameString.EqualsAscii( SC_UNONAME_FILTER ) )
278         aRet <<= getFilter();
279     else if ( aNameString.EqualsAscii( SC_UNONAME_FILTOPT ) )
280         aRet <<= getFilterOptions();
281     else if ( aNameString.EqualsAscii( SC_UNONAME_REFPERIOD ) )
282         aRet <<= getRefreshDelay();
283     else if ( aNameString.EqualsAscii( SC_UNONAME_REFDELAY ) )
284         aRet <<= getRefreshDelay();
285     return aRet;
286 }
287 
288 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSheetLinkObj )
289 
290 // internal:
291 
292 rtl::OUString ScSheetLinkObj::getFileName(void) const
293 {
294     ScUnoGuard aGuard;
295     return aFileName;
296 }
297 
298 void ScSheetLinkObj::setFileName(const rtl::OUString& rNewName)
299 {
300     ScUnoGuard aGuard;
301     ScTableLink* pLink = GetLink_Impl();
302     if (pLink)
303     {
304         //  pLink->Refresh mit neuem Dateinamen bringt sfx2::LinkManager durcheinander
305         //  darum per Hand die Tabellen umsetzen und Link per UpdateLinks neu erzeugen
306 
307         String aNewStr(ScGlobal::GetAbsDocName( String(rNewName), pDocShell ));
308 
309         //  zuerst Tabellen umsetzen
310 
311         ScDocument* pDoc = pDocShell->GetDocument();
312         SCTAB nTabCount = pDoc->GetTableCount();
313         for (SCTAB nTab=0; nTab<nTabCount; nTab++)
314             if ( pDoc->IsLinked(nTab) && pDoc->GetLinkDoc(nTab) == aFileName )  // alte Datei
315                 pDoc->SetLink( nTab, pDoc->GetLinkMode(nTab), aNewStr,
316                                 pDoc->GetLinkFlt(nTab), pDoc->GetLinkOpt(nTab),
317                                 pDoc->GetLinkTab(nTab),
318                                 pDoc->GetLinkRefreshDelay(nTab) );  // nur Datei aendern
319 
320         //  Links updaten
321         //! Undo !!!
322 
323         pLink = NULL;               // wird bei UpdateLinks ungueltig
324         pDocShell->UpdateLinks();   // alter Link raus, evtl. neuen Link anlegen
325 
326         //  Daten kopieren
327 
328         aFileName = aNewStr;
329         pLink = GetLink_Impl();     // neuer Link mit neuem Namen
330         if (pLink)
331             pLink->Update();        // inkl. Paint & Undo fuer Daten
332     }
333 }
334 
335 rtl::OUString ScSheetLinkObj::getFilter(void) const
336 {
337     ScUnoGuard aGuard;
338     rtl::OUString aRet;
339     ScTableLink* pLink = GetLink_Impl();
340     if (pLink)
341         aRet = pLink->GetFilterName();
342     return aRet;
343 }
344 
345 void ScSheetLinkObj::setFilter(const rtl::OUString& Filter)
346 {
347     ScUnoGuard aGuard;
348     ScTableLink* pLink = GetLink_Impl();
349     if (pLink)
350     {
351         String aFilterStr(Filter);
352         pLink->Refresh( aFileName, aFilterStr, NULL, pLink->GetRefreshDelay() );
353     }
354 }
355 
356 rtl::OUString ScSheetLinkObj::getFilterOptions(void) const
357 {
358     ScUnoGuard aGuard;
359     rtl::OUString aRet;
360     ScTableLink* pLink = GetLink_Impl();
361     if (pLink)
362         aRet = pLink->GetOptions();
363     return aRet;
364 }
365 
366 void ScSheetLinkObj::setFilterOptions(const rtl::OUString& FilterOptions)
367 {
368     ScUnoGuard aGuard;
369     ScTableLink* pLink = GetLink_Impl();
370     if (pLink)
371     {
372         String aOptStr(FilterOptions);
373         pLink->Refresh( aFileName, pLink->GetFilterName(), &aOptStr, pLink->GetRefreshDelay() );
374     }
375 }
376 
377 sal_Int32 ScSheetLinkObj::getRefreshDelay(void) const
378 {
379     ScUnoGuard aGuard;
380     sal_Int32 nRet = 0;
381     ScTableLink* pLink = GetLink_Impl();
382     if (pLink)
383         nRet = (sal_Int32) pLink->GetRefreshDelay();
384     return nRet;
385 }
386 
387 void ScSheetLinkObj::setRefreshDelay(sal_Int32 nRefreshDelay)
388 {
389     ScUnoGuard aGuard;
390     ModifyRefreshDelay_Impl( nRefreshDelay );
391 }
392 
393 //------------------------------------------------------------------------
394 
395 ScSheetLinksObj::ScSheetLinksObj(ScDocShell* pDocSh) :
396     pDocShell( pDocSh )
397 {
398     pDocShell->GetDocument()->AddUnoObject(*this);
399 }
400 
401 ScSheetLinksObj::~ScSheetLinksObj()
402 {
403     if (pDocShell)
404         pDocShell->GetDocument()->RemoveUnoObject(*this);
405 }
406 
407 void ScSheetLinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
408 {
409     //  Referenz-Update interessiert hier nicht
410 
411     if ( rHint.ISA( SfxSimpleHint ) &&
412             ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
413     {
414         pDocShell = NULL;       // ungueltig geworden
415     }
416 }
417 
418 // XSheetLinks
419 
420 ScSheetLinkObj* ScSheetLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
421 {
422     if (pDocShell)
423     {
424         sal_Int32 nCount = 0;
425         ScStrCollection aNames; // um doppelte wegzulassen
426         ScDocument* pDoc = pDocShell->GetDocument();
427         SCTAB nTabCount = pDoc->GetTableCount();
428         for (SCTAB nTab=0; nTab<nTabCount; nTab++)
429             if (pDoc->IsLinked(nTab))
430             {
431                 String aLinkDoc = pDoc->GetLinkDoc( nTab );
432                 StrData* pData = new StrData(aLinkDoc);
433                 if (aNames.Insert(pData))
434                 {
435                     if ( nCount == nIndex )
436                         return new ScSheetLinkObj( pDocShell, aLinkDoc );
437                     ++nCount;
438                 }
439                 else
440                     delete pData;
441             }
442     }
443     return NULL;    // kein Dokument oder Index zu gross
444 }
445 
446 ScSheetLinkObj* ScSheetLinksObj::GetObjectByName_Impl(const rtl::OUString& aName)
447 {
448     //  Name ist der Dateiname
449 
450     if (pDocShell)
451     {
452         String aNameStr(aName);
453 
454         ScDocument* pDoc = pDocShell->GetDocument();
455         SCTAB nTabCount = pDoc->GetTableCount();
456         for (SCTAB nTab=0; nTab<nTabCount; nTab++)
457             if (pDoc->IsLinked(nTab))
458             {
459                 //! case-insensitiv ???
460                 String aLinkDoc = pDoc->GetLinkDoc( nTab );
461                 if ( aLinkDoc == aNameStr )
462                     return new ScSheetLinkObj( pDocShell, aNameStr );
463             }
464     }
465 
466     return NULL;
467 }
468 
469 // XEnumerationAccess
470 
471 uno::Reference<container::XEnumeration> SAL_CALL ScSheetLinksObj::createEnumeration()
472                                                     throw(uno::RuntimeException)
473 {
474     ScUnoGuard aGuard;
475     return new ScIndexEnumeration(this, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sheet.SheetLinksEnumeration")));
476 }
477 
478 // XIndexAccess
479 
480 sal_Int32 SAL_CALL ScSheetLinksObj::getCount() throw(uno::RuntimeException)
481 {
482     ScUnoGuard aGuard;
483     sal_Int32 nCount = 0;
484     if (pDocShell)
485     {
486         ScStrCollection aNames; // um doppelte wegzulassen
487         ScDocument* pDoc = pDocShell->GetDocument();
488         SCTAB nTabCount = pDoc->GetTableCount();
489         for (SCTAB nTab=0; nTab<nTabCount; nTab++)
490             if (pDoc->IsLinked(nTab))
491             {
492                 String aLinkDoc(pDoc->GetLinkDoc( nTab ));
493                 StrData* pData = new StrData(aLinkDoc);
494                 if (aNames.Insert(pData))
495                     ++nCount;
496                 else
497                     delete pData;
498             }
499     }
500     return nCount;
501 }
502 
503 uno::Any SAL_CALL ScSheetLinksObj::getByIndex( sal_Int32 nIndex )
504                             throw(lang::IndexOutOfBoundsException,
505                                     lang::WrappedTargetException, uno::RuntimeException)
506 {
507     ScUnoGuard aGuard;
508     uno::Reference<beans::XPropertySet> xLink(GetObjectByIndex_Impl(nIndex));
509     if (xLink.is())
510         return uno::makeAny(xLink);
511     else
512         throw lang::IndexOutOfBoundsException();
513 //    return uno::Any();
514 }
515 
516 uno::Type SAL_CALL ScSheetLinksObj::getElementType() throw(uno::RuntimeException)
517 {
518     ScUnoGuard aGuard;
519     return getCppuType((uno::Reference<beans::XPropertySet>*)0);
520 }
521 
522 sal_Bool SAL_CALL ScSheetLinksObj::hasElements() throw(uno::RuntimeException)
523 {
524     ScUnoGuard aGuard;
525     return ( getCount() != 0 );
526 }
527 
528 uno::Any SAL_CALL ScSheetLinksObj::getByName( const rtl::OUString& aName )
529             throw(container::NoSuchElementException,
530                     lang::WrappedTargetException, uno::RuntimeException)
531 {
532     ScUnoGuard aGuard;
533     uno::Reference<beans::XPropertySet> xLink(GetObjectByName_Impl(aName));
534     if (xLink.is())
535         return uno::makeAny(xLink);
536     else
537         throw container::NoSuchElementException();
538 //    return uno::Any();
539 }
540 
541 sal_Bool SAL_CALL ScSheetLinksObj::hasByName( const rtl::OUString& aName )
542                                         throw(uno::RuntimeException)
543 {
544     ScUnoGuard aGuard;
545     //  Name ist der Dateiname
546 
547     if (pDocShell)
548     {
549         String aNameStr(aName);
550 
551         ScDocument* pDoc = pDocShell->GetDocument();
552         SCTAB nTabCount = pDoc->GetTableCount();
553         for (SCTAB nTab=0; nTab<nTabCount; nTab++)
554             if (pDoc->IsLinked(nTab))
555             {
556                 //! case-insensitiv ???
557                 String aLinkDoc(pDoc->GetLinkDoc( nTab ));
558                 if ( aLinkDoc == aNameStr )
559                     return sal_True;
560             }
561     }
562     return sal_False;
563 }
564 
565 uno::Sequence<rtl::OUString> SAL_CALL ScSheetLinksObj::getElementNames() throw(uno::RuntimeException)
566 {
567     ScUnoGuard aGuard;
568     //  Name ist der Dateiname
569 
570     if (pDocShell)
571     {
572         ScStrCollection aNames; // um doppelte wegzulassen
573         ScDocument* pDoc = pDocShell->GetDocument();
574         SCTAB nTabCount = pDoc->GetTableCount();
575         String aName;
576 
577         sal_Int32 nLinkCount = getCount();
578         uno::Sequence<rtl::OUString> aSeq(nLinkCount);
579         rtl::OUString* pAry = aSeq.getArray();
580         sal_uInt16 nPos = 0;
581         for (SCTAB nTab=0; nTab<nTabCount; nTab++)
582         {
583             if (pDoc->IsLinked(nTab))
584             {
585                 String aLinkDoc(pDoc->GetLinkDoc( nTab ));
586                 StrData* pData = new StrData(aLinkDoc);
587                 if (aNames.Insert(pData))
588                     pAry[nPos++] = aLinkDoc;
589                 else
590                     delete pData;
591             }
592         }
593         DBG_ASSERT( nPos==nLinkCount, "verzaehlt" );
594         return aSeq;
595     }
596     return uno::Sequence<rtl::OUString>();
597 }
598 
599 //------------------------------------------------------------------------
600 
601 ScAreaLink* lcl_GetAreaLink( ScDocShell* pDocShell, sal_uInt16 nPos )
602 {
603     if (pDocShell)
604     {
605         sfx2::LinkManager* pLinkManager = pDocShell->GetDocument()->GetLinkManager();
606         sal_uInt16 nTotalCount = pLinkManager->GetLinks().Count();
607         sal_uInt16 nAreaCount = 0;
608         for (sal_uInt16 i=0; i<nTotalCount; i++)
609         {
610             ::sfx2::SvBaseLink* pBase = *pLinkManager->GetLinks()[i];
611             if (pBase->ISA(ScAreaLink))
612             {
613                 if ( nAreaCount == nPos )
614                     return (ScAreaLink*)pBase;
615                 ++nAreaCount;
616             }
617         }
618     }
619     return NULL;    // nicht gefunden
620 }
621 
622 ScAreaLinkObj::ScAreaLinkObj(ScDocShell* pDocSh, sal_uInt16 nP) :
623     aPropSet( lcl_GetSheetLinkMap() ),
624     pDocShell( pDocSh ),
625     nPos( nP )
626 {
627     pDocShell->GetDocument()->AddUnoObject(*this);
628 }
629 
630 ScAreaLinkObj::~ScAreaLinkObj()
631 {
632     if (pDocShell)
633         pDocShell->GetDocument()->RemoveUnoObject(*this);
634 }
635 
636 void ScAreaLinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
637 {
638     //! notify if links in document are changed
639     //  UpdateRef is not needed here
640 
641     if ( rHint.ISA( SfxSimpleHint ) )
642     {
643         if ( ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
644             pDocShell = NULL;       // pointer is invalid
645     }
646     else if ( rHint.ISA( ScLinkRefreshedHint ) )
647     {
648         const ScLinkRefreshedHint& rLH = (const ScLinkRefreshedHint&) rHint;
649         if ( rLH.GetLinkType() == SC_LINKREFTYPE_AREA )
650         {
651             //  get this link to compare dest position
652             ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
653             if ( pLink && pLink->GetDestArea().aStart == rLH.GetDestPos() )
654                 Refreshed_Impl();
655         }
656     }
657 }
658 
659 // XFileLink
660 
661 void ScAreaLinkObj::Modify_Impl( const rtl::OUString* pNewFile, const rtl::OUString* pNewFilter,
662                                  const rtl::OUString* pNewOptions, const rtl::OUString* pNewSource,
663                                  const table::CellRangeAddress* pNewDest )
664 {
665     ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
666     if (pLink)
667     {
668         String aFile    (pLink->GetFile());
669         String aFilter  (pLink->GetFilter());
670         String aOptions (pLink->GetOptions());
671         String aSource  (pLink->GetSource());
672         ScRange aDest   (pLink->GetDestArea());
673         sal_uLong nRefresh  = pLink->GetRefreshDelay();
674 
675         //! Undo fuer Loeschen
676         //! Undo zusammenfassen
677 
678         sfx2::LinkManager* pLinkManager = pDocShell->GetDocument()->GetLinkManager();
679         pLinkManager->Remove( pLink );
680         pLink = NULL;   // bei Remove geloescht
681 
682         sal_Bool bFitBlock = sal_True;          // verschieben, wenn durch Update Groesse geaendert
683         if (pNewFile)
684         {
685             aFile = String( *pNewFile );
686             aFile = ScGlobal::GetAbsDocName( aFile, pDocShell );    //! in InsertAreaLink?
687         }
688         if (pNewFilter)
689             aFilter = String( *pNewFilter );
690         if (pNewOptions)
691             aOptions = String( *pNewOptions );
692         if (pNewSource)
693             aSource = String( *pNewSource );
694         if (pNewDest)
695         {
696             ScUnoConversion::FillScRange( aDest, *pNewDest );
697             bFitBlock = sal_False;  // neuer Bereich angegeben -> keine Inhalte verschieben
698         }
699 
700         ScDocFunc aFunc(*pDocShell);
701         aFunc.InsertAreaLink( aFile, aFilter, aOptions, aSource, aDest, nRefresh, bFitBlock, sal_True );
702     }
703 }
704 
705 void ScAreaLinkObj::ModifyRefreshDelay_Impl( sal_Int32 nRefresh )
706 {
707     ScAreaLink* pLink = lcl_GetAreaLink( pDocShell, nPos );
708     if( pLink )
709         pLink->SetRefreshDelay( (sal_uLong) nRefresh );
710 }
711 
712 // XRefreshable
713 
714 void SAL_CALL ScAreaLinkObj::refresh() throw(uno::RuntimeException)
715 {
716     ScUnoGuard aGuard;
717     ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
718     if (pLink)
719         pLink->Refresh( pLink->GetFile(), pLink->GetFilter(), pLink->GetSource(), pLink->GetRefreshDelay() );
720 }
721 
722 void SAL_CALL ScAreaLinkObj::addRefreshListener(
723                                 const uno::Reference<util::XRefreshListener >& xListener )
724                                                 throw(uno::RuntimeException)
725 {
726     ScUnoGuard aGuard;
727     uno::Reference<util::XRefreshListener>* pObj =
728             new uno::Reference<util::XRefreshListener>( xListener );
729     aRefreshListeners.Insert( pObj, aRefreshListeners.Count() );
730 
731     //  hold one additional ref to keep this object alive as long as there are listeners
732     if ( aRefreshListeners.Count() == 1 )
733         acquire();
734 }
735 
736 void SAL_CALL ScAreaLinkObj::removeRefreshListener(
737                                 const uno::Reference<util::XRefreshListener >& xListener )
738                                                 throw(uno::RuntimeException)
739 {
740     ScUnoGuard aGuard;
741     sal_uInt16 nCount = aRefreshListeners.Count();
742     for ( sal_uInt16 n=nCount; n--; )
743     {
744         uno::Reference<util::XRefreshListener>* pObj = aRefreshListeners[n];
745         if ( *pObj == xListener )
746         {
747             aRefreshListeners.DeleteAndDestroy( n );
748             if ( aRefreshListeners.Count() == 0 )
749                 release();                          // release ref for listeners
750             break;
751         }
752     }
753 }
754 
755 void ScAreaLinkObj::Refreshed_Impl()
756 {
757     lang::EventObject aEvent;
758     aEvent.Source.set((cppu::OWeakObject*)this);
759     for ( sal_uInt16 n=0; n<aRefreshListeners.Count(); n++ )
760         (*aRefreshListeners[n])->refreshed( aEvent );
761 }
762 
763 // XPropertySet
764 
765 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAreaLinkObj::getPropertySetInfo()
766                                                         throw(uno::RuntimeException)
767 {
768     ScUnoGuard aGuard;
769     static uno::Reference<beans::XPropertySetInfo> aRef(
770         new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
771     return aRef;
772 }
773 
774 void SAL_CALL ScAreaLinkObj::setPropertyValue(
775                         const rtl::OUString& aPropertyName, const uno::Any& aValue )
776                 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
777                         lang::IllegalArgumentException, lang::WrappedTargetException,
778                         uno::RuntimeException)
779 {
780     ScUnoGuard aGuard;
781     String aNameString(aPropertyName);
782     rtl::OUString aValStr;
783     if ( aNameString.EqualsAscii( SC_UNONAME_LINKURL ) )
784     {
785         if ( aValue >>= aValStr )
786             setFileName( aValStr );
787     }
788     else if ( aNameString.EqualsAscii( SC_UNONAME_FILTER ) )
789     {
790         if ( aValue >>= aValStr )
791             setFilter( aValStr );
792     }
793     else if ( aNameString.EqualsAscii( SC_UNONAME_FILTOPT ) )
794     {
795         if ( aValue >>= aValStr )
796             setFilterOptions( aValStr );
797     }
798     else if ( aNameString.EqualsAscii( SC_UNONAME_REFPERIOD ) )
799     {
800         sal_Int32 nRefresh = 0;
801         if ( aValue >>= nRefresh )
802             setRefreshDelay( nRefresh );
803     }
804     else if ( aNameString.EqualsAscii( SC_UNONAME_REFDELAY ) )
805     {
806         sal_Int32 nRefresh = 0;
807         if ( aValue >>= nRefresh )
808             setRefreshDelay( nRefresh );
809     }
810 }
811 
812 uno::Any SAL_CALL ScAreaLinkObj::getPropertyValue( const rtl::OUString& aPropertyName )
813                 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
814                         uno::RuntimeException)
815 {
816     ScUnoGuard aGuard;
817     String aNameString(aPropertyName);
818     uno::Any aRet;
819     if ( aNameString.EqualsAscii( SC_UNONAME_LINKURL ) )
820         aRet <<= getFileName();
821     else if ( aNameString.EqualsAscii( SC_UNONAME_FILTER ) )
822         aRet <<= getFilter();
823     else if ( aNameString.EqualsAscii( SC_UNONAME_FILTOPT ) )
824         aRet <<= getFilterOptions();
825     else if ( aNameString.EqualsAscii( SC_UNONAME_REFPERIOD ) )
826         aRet <<= getRefreshDelay();
827     else if ( aNameString.EqualsAscii( SC_UNONAME_REFDELAY ) )
828         aRet <<= getRefreshDelay();
829     return aRet;
830 }
831 
832 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAreaLinkObj )
833 
834 //  internal:
835 
836 rtl::OUString ScAreaLinkObj::getFileName(void) const
837 {
838     ScUnoGuard aGuard;
839     rtl::OUString aRet;
840     ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
841     if (pLink)
842         aRet = pLink->GetFile();
843     return aRet;
844 }
845 
846 void ScAreaLinkObj::setFileName(const rtl::OUString& rNewName)
847 {
848     ScUnoGuard aGuard;
849     Modify_Impl( &rNewName, NULL, NULL, NULL, NULL );
850 }
851 
852 rtl::OUString ScAreaLinkObj::getFilter(void) const
853 {
854     ScUnoGuard aGuard;
855     rtl::OUString aRet;
856     ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
857     if (pLink)
858         aRet = pLink->GetFilter();
859     return aRet;
860 }
861 
862 void ScAreaLinkObj::setFilter(const rtl::OUString& Filter)
863 {
864     ScUnoGuard aGuard;
865     Modify_Impl( NULL, &Filter, NULL, NULL, NULL );
866 }
867 
868 rtl::OUString ScAreaLinkObj::getFilterOptions(void) const
869 {
870     ScUnoGuard aGuard;
871     rtl::OUString aRet;
872     ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
873     if (pLink)
874         aRet = pLink->GetOptions();
875     return aRet;
876 }
877 
878 void ScAreaLinkObj::setFilterOptions(const rtl::OUString& FilterOptions)
879 {
880     ScUnoGuard aGuard;
881     Modify_Impl( NULL, NULL, &FilterOptions, NULL, NULL );
882 }
883 
884 sal_Int32 ScAreaLinkObj::getRefreshDelay(void) const
885 {
886     ScUnoGuard aGuard;
887     sal_Int32 nRet = 0;
888     ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
889     if (pLink)
890         nRet = (sal_Int32) pLink->GetRefreshDelay();
891     return nRet;
892 }
893 
894 void ScAreaLinkObj::setRefreshDelay(sal_Int32 nRefreshDelay)
895 {
896     ScUnoGuard aGuard;
897     ModifyRefreshDelay_Impl( nRefreshDelay );
898 }
899 
900 // XAreaLink
901 
902 rtl::OUString SAL_CALL ScAreaLinkObj::getSourceArea() throw(uno::RuntimeException)
903 {
904     ScUnoGuard aGuard;
905     rtl::OUString aRet;
906     ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
907     if (pLink)
908         aRet = pLink->GetSource();
909     return aRet;
910 }
911 
912 void SAL_CALL ScAreaLinkObj::setSourceArea( const rtl::OUString& aSourceArea )
913                                             throw(uno::RuntimeException)
914 {
915     ScUnoGuard aGuard;
916     Modify_Impl( NULL, NULL, NULL, &aSourceArea, NULL );
917 }
918 
919 table::CellRangeAddress SAL_CALL ScAreaLinkObj::getDestArea() throw(uno::RuntimeException)
920 {
921     ScUnoGuard aGuard;
922     table::CellRangeAddress aRet;
923     ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
924     if (pLink)
925         ScUnoConversion::FillApiRange( aRet, pLink->GetDestArea() );
926     return aRet;
927 }
928 
929 void SAL_CALL ScAreaLinkObj::setDestArea( const table::CellRangeAddress& aDestArea )
930                                             throw(uno::RuntimeException)
931 {
932     ScUnoGuard aGuard;
933     Modify_Impl( NULL, NULL, NULL, NULL, &aDestArea );
934 }
935 
936 //------------------------------------------------------------------------
937 
938 ScAreaLinksObj::ScAreaLinksObj(ScDocShell* pDocSh) :
939     pDocShell( pDocSh )
940 {
941     pDocShell->GetDocument()->AddUnoObject(*this);
942 }
943 
944 ScAreaLinksObj::~ScAreaLinksObj()
945 {
946     if (pDocShell)
947         pDocShell->GetDocument()->RemoveUnoObject(*this);
948 }
949 
950 void ScAreaLinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
951 {
952     //  Referenz-Update interessiert hier nicht
953 
954     if ( rHint.ISA( SfxSimpleHint ) &&
955             ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
956     {
957         pDocShell = NULL;       // ungueltig geworden
958     }
959 }
960 
961 // XAreaLinks
962 
963 ScAreaLinkObj* ScAreaLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
964 {
965     if ( pDocShell && nIndex >= 0 && nIndex < getCount() )
966         return new ScAreaLinkObj( pDocShell, (sal_uInt16)nIndex );
967 
968     return NULL;    // nicht gefunden
969 }
970 
971 void SAL_CALL ScAreaLinksObj::insertAtPosition( const table::CellAddress& aDestPos,
972                                                 const rtl::OUString& aFileName,
973                                                 const rtl::OUString& aSourceArea,
974                                                 const rtl::OUString& aFilter,
975                                                 const rtl::OUString& aFilterOptions )
976                                             throw(uno::RuntimeException)
977 {
978     ScUnoGuard aGuard;
979     if (pDocShell)
980     {
981         String aFileStr   (aFileName);
982         String aFilterStr (aFilter);
983         String aOptionStr (aFilterOptions);
984         String aSourceStr (aSourceArea);
985         ScAddress aDestAddr( (SCCOL)aDestPos.Column, (SCROW)aDestPos.Row, aDestPos.Sheet );
986 
987         aFileStr = ScGlobal::GetAbsDocName( aFileStr, pDocShell );  //! in InsertAreaLink ???
988 
989         ScDocFunc aFunc(*pDocShell);
990         aFunc.InsertAreaLink( aFileStr, aFilterStr, aOptionStr,
991                                 aSourceStr, ScRange(aDestAddr),
992                                 0, sal_False, sal_True );                   // keine Inhalte verschieben
993     }
994 }
995 
996 void SAL_CALL ScAreaLinksObj::removeByIndex( sal_Int32 nIndex ) throw(uno::RuntimeException)
997 {
998     ScUnoGuard aGuard;
999     ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, (sal_uInt16)nIndex);
1000     if (pLink)
1001     {
1002         //! SetAddUndo oder so
1003 
1004         sfx2::LinkManager* pLinkManager = pDocShell->GetDocument()->GetLinkManager();
1005         pLinkManager->Remove( pLink );
1006     }
1007 }
1008 
1009 // XEnumerationAccess
1010 
1011 uno::Reference<container::XEnumeration> SAL_CALL ScAreaLinksObj::createEnumeration()
1012                                                     throw(uno::RuntimeException)
1013 {
1014     ScUnoGuard aGuard;
1015     return new ScIndexEnumeration(this, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sheet.CellAreaLinksEnumeration")));
1016 }
1017 
1018 // XIndexAccess
1019 
1020 sal_Int32 SAL_CALL ScAreaLinksObj::getCount() throw(uno::RuntimeException)
1021 {
1022     ScUnoGuard aGuard;
1023     sal_Int32 nAreaCount = 0;
1024     if (pDocShell)
1025     {
1026         sfx2::LinkManager* pLinkManager = pDocShell->GetDocument()->GetLinkManager();
1027         sal_uInt16 nTotalCount = pLinkManager->GetLinks().Count();
1028         for (sal_uInt16 i=0; i<nTotalCount; i++)
1029         {
1030             ::sfx2::SvBaseLink* pBase = *pLinkManager->GetLinks()[i];
1031             if (pBase->ISA(ScAreaLink))
1032                 ++nAreaCount;
1033         }
1034     }
1035     return nAreaCount;
1036 }
1037 
1038 uno::Any SAL_CALL ScAreaLinksObj::getByIndex( sal_Int32 nIndex )
1039                             throw(lang::IndexOutOfBoundsException,
1040                                     lang::WrappedTargetException, uno::RuntimeException)
1041 {
1042     ScUnoGuard aGuard;
1043     uno::Reference<sheet::XAreaLink> xLink(GetObjectByIndex_Impl(nIndex));
1044     if (xLink.is())
1045         return uno::makeAny(xLink);
1046     else
1047         throw lang::IndexOutOfBoundsException();
1048 //    return uno::Any();
1049 }
1050 
1051 uno::Type SAL_CALL ScAreaLinksObj::getElementType() throw(uno::RuntimeException)
1052 {
1053     ScUnoGuard aGuard;
1054     return getCppuType((uno::Reference<sheet::XAreaLink>*)0);
1055 }
1056 
1057 sal_Bool SAL_CALL ScAreaLinksObj::hasElements() throw(uno::RuntimeException)
1058 {
1059     ScUnoGuard aGuard;
1060     return ( getCount() != 0 );
1061 }
1062 
1063 //------------------------------------------------------------------------
1064 
1065 ScDDELinkObj::ScDDELinkObj(ScDocShell* pDocSh, const String& rA,
1066                             const String& rT, const String& rI) :
1067     pDocShell( pDocSh ),
1068     aAppl( rA ),
1069     aTopic( rT ),
1070     aItem( rI )
1071 {
1072     pDocShell->GetDocument()->AddUnoObject(*this);
1073 }
1074 
1075 ScDDELinkObj::~ScDDELinkObj()
1076 {
1077     if (pDocShell)
1078         pDocShell->GetDocument()->RemoveUnoObject(*this);
1079 }
1080 
1081 void ScDDELinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
1082 {
1083     //! notify if links in document are changed
1084     //  UpdateRef is not needed here
1085 
1086     if ( rHint.ISA( SfxSimpleHint ) )
1087     {
1088         if ( ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
1089             pDocShell = NULL;       // pointer is invalid
1090     }
1091     else if ( rHint.ISA( ScLinkRefreshedHint ) )
1092     {
1093         const ScLinkRefreshedHint& rLH = (const ScLinkRefreshedHint&) rHint;
1094         if ( rLH.GetLinkType() == SC_LINKREFTYPE_DDE &&
1095              rLH.GetDdeAppl()  == aAppl &&
1096              rLH.GetDdeTopic() == aTopic &&
1097              rLH.GetDdeItem()  == aItem )       //! mode is ignored
1098             Refreshed_Impl();
1099     }
1100 }
1101 
1102 // XNamed
1103 
1104 String lcl_BuildDDEName( const String& rAppl, const String& rTopic, const String& rItem )
1105 {
1106     //  Appl|Topic!Item (wie Excel)
1107     String aRet = rAppl;
1108     aRet += '|';
1109     aRet += rTopic;
1110     aRet += '!';
1111     aRet += rItem;
1112     return aRet;
1113 }
1114 
1115 rtl::OUString SAL_CALL ScDDELinkObj::getName() throw(uno::RuntimeException)
1116 {
1117     ScUnoGuard aGuard;
1118     return lcl_BuildDDEName( aAppl, aTopic, aItem );
1119 }
1120 
1121 void SAL_CALL ScDDELinkObj::setName( const rtl::OUString& /* aName */ ) throw(uno::RuntimeException)
1122 {
1123     //  name can't be changed (formulas wouldn't find the link)
1124     throw uno::RuntimeException();
1125 }
1126 
1127 // XDDELink
1128 
1129 rtl::OUString SAL_CALL ScDDELinkObj::getApplication() throw(uno::RuntimeException)
1130 {
1131     ScUnoGuard aGuard;
1132     //! Test, ob Link noch im Dokument enthalten?
1133 
1134     return aAppl;
1135 }
1136 
1137 rtl::OUString SAL_CALL ScDDELinkObj::getTopic() throw(uno::RuntimeException)
1138 {
1139     ScUnoGuard aGuard;
1140     //! Test, ob Link noch im Dokument enthalten?
1141 
1142     return aTopic;
1143 }
1144 
1145 rtl::OUString SAL_CALL ScDDELinkObj::getItem() throw(uno::RuntimeException)
1146 {
1147     ScUnoGuard aGuard;
1148     //! Test, ob Link noch im Dokument enthalten?
1149 
1150     return aItem;
1151 }
1152 
1153 // XRefreshable
1154 
1155 void SAL_CALL ScDDELinkObj::refresh() throw(uno::RuntimeException)
1156 {
1157     ScUnoGuard aGuard;
1158     if (pDocShell)
1159     {
1160         ScDocument* pDoc = pDocShell->GetDocument();
1161         (void)pDoc->UpdateDdeLink( aAppl, aTopic, aItem );
1162         //! Fehler abfragen
1163     }
1164 }
1165 
1166 void SAL_CALL ScDDELinkObj::addRefreshListener(
1167                                 const uno::Reference<util::XRefreshListener >& xListener )
1168                                                 throw(uno::RuntimeException)
1169 {
1170     ScUnoGuard aGuard;
1171     uno::Reference<util::XRefreshListener>* pObj =
1172             new uno::Reference<util::XRefreshListener>( xListener );
1173     aRefreshListeners.Insert( pObj, aRefreshListeners.Count() );
1174 
1175     //  hold one additional ref to keep this object alive as long as there are listeners
1176     if ( aRefreshListeners.Count() == 1 )
1177         acquire();
1178 }
1179 
1180 void SAL_CALL ScDDELinkObj::removeRefreshListener(
1181                                 const uno::Reference<util::XRefreshListener >& xListener )
1182                                                 throw(uno::RuntimeException)
1183 {
1184     ScUnoGuard aGuard;
1185     sal_uInt16 nCount = aRefreshListeners.Count();
1186     for ( sal_uInt16 n=nCount; n--; )
1187     {
1188         uno::Reference<util::XRefreshListener>* pObj = aRefreshListeners[n];
1189         if ( *pObj == xListener )
1190         {
1191             aRefreshListeners.DeleteAndDestroy( n );
1192             if ( aRefreshListeners.Count() == 0 )
1193                 release();                          // release ref for listeners
1194             break;
1195         }
1196     }
1197 }
1198 
1199 // XDDELinkResults
1200 
1201 uno::Sequence< uno::Sequence< uno::Any > > ScDDELinkObj::getResults(  )
1202     throw (uno::RuntimeException)
1203 {
1204     ScUnoGuard aGuard;
1205     uno::Sequence< uno::Sequence< uno::Any > > aReturn;
1206     bool bSuccess = false;
1207 
1208     if ( pDocShell )
1209     {
1210         ScDocument* pDoc = pDocShell->GetDocument();
1211         if ( pDoc )
1212         {
1213             sal_uInt16 nPos = 0;
1214             if ( pDoc->FindDdeLink( aAppl, aTopic, aItem, SC_DDE_IGNOREMODE, nPos ) )
1215             {
1216                 const ScMatrix* pMatrix = pDoc->GetDdeLinkResultMatrix( nPos );
1217                 if ( pMatrix )
1218                 {
1219                     uno::Any aAny;
1220                     if ( ScRangeToSequence::FillMixedArray( aAny, pMatrix, true ) )
1221                     {
1222                         aAny >>= aReturn;
1223                     }
1224                 }
1225                 bSuccess = true;
1226             }
1227         }
1228     }
1229 
1230     if ( !bSuccess )
1231     {
1232         throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
1233             "ScDDELinkObj::getResults: failed to get results!" ) ),
1234             uno::Reference< uno::XInterface >() );
1235     }
1236 
1237     return aReturn;
1238 }
1239 
1240 void ScDDELinkObj::setResults( const uno::Sequence< uno::Sequence< uno::Any > >& aResults )
1241     throw (uno::RuntimeException)
1242 {
1243     ScUnoGuard aGuard;
1244     bool bSuccess = false;
1245 
1246     if ( pDocShell )
1247     {
1248         ScDocument* pDoc = pDocShell->GetDocument();
1249         if ( pDoc )
1250         {
1251             sal_uInt16 nPos = 0;
1252             if ( pDoc->FindDdeLink( aAppl, aTopic, aItem, SC_DDE_IGNOREMODE, nPos ) )
1253             {
1254                 uno::Any aAny;
1255                 aAny <<= aResults;
1256                 ScMatrixRef xMatrix = ScSequenceToMatrix::CreateMixedMatrix( aAny );
1257                 bSuccess = pDoc->SetDdeLinkResultMatrix( nPos, xMatrix );
1258             }
1259         }
1260     }
1261 
1262     if ( !bSuccess )
1263     {
1264         throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
1265             "ScDDELinkObj::setResults: failed to set results!" ) ),
1266             uno::Reference< uno::XInterface >() );
1267     }
1268 }
1269 
1270 void ScDDELinkObj::Refreshed_Impl()
1271 {
1272     lang::EventObject aEvent;
1273     aEvent.Source.set((cppu::OWeakObject*)this);
1274     for ( sal_uInt16 n=0; n<aRefreshListeners.Count(); n++ )
1275         (*aRefreshListeners[n])->refreshed( aEvent );
1276 }
1277 
1278 //------------------------------------------------------------------------
1279 
1280 ScDDELinksObj::ScDDELinksObj(ScDocShell* pDocSh) :
1281     pDocShell( pDocSh )
1282 {
1283     pDocShell->GetDocument()->AddUnoObject(*this);
1284 }
1285 
1286 ScDDELinksObj::~ScDDELinksObj()
1287 {
1288     if (pDocShell)
1289         pDocShell->GetDocument()->RemoveUnoObject(*this);
1290 }
1291 
1292 void ScDDELinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
1293 {
1294     //  Referenz-Update interessiert hier nicht
1295 
1296     if ( rHint.ISA( SfxSimpleHint ) &&
1297             ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
1298     {
1299         pDocShell = NULL;       // ungueltig geworden
1300     }
1301 }
1302 
1303 // XDDELinks
1304 
1305 ScDDELinkObj* ScDDELinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
1306 {
1307     if (pDocShell)
1308     {
1309         String aAppl, aTopic, aItem;
1310         if ( nIndex <= USHRT_MAX &&
1311                 pDocShell->GetDocument()->GetDdeLinkData( (sal_uInt16)nIndex, aAppl, aTopic, aItem ) )
1312             return new ScDDELinkObj( pDocShell, aAppl, aTopic, aItem );
1313     }
1314     return NULL;
1315 }
1316 
1317 ScDDELinkObj* ScDDELinksObj::GetObjectByName_Impl(const rtl::OUString& aName)
1318 {
1319     if (pDocShell)
1320     {
1321         String aNamStr(aName);
1322         String aAppl, aTopic, aItem;
1323 
1324         ScDocument* pDoc = pDocShell->GetDocument();
1325         sal_uInt16 nCount = pDoc->GetDdeLinkCount();
1326         for (sal_uInt16 i=0; i<nCount; i++)
1327         {
1328             pDoc->GetDdeLinkData( i, aAppl, aTopic, aItem );
1329             if ( lcl_BuildDDEName(aAppl, aTopic, aItem) == aNamStr )
1330                 return new ScDDELinkObj( pDocShell, aAppl, aTopic, aItem );
1331         }
1332     }
1333     return NULL;
1334 }
1335 
1336 // XEnumerationAccess
1337 
1338 uno::Reference<container::XEnumeration> SAL_CALL ScDDELinksObj::createEnumeration()
1339                                                     throw(uno::RuntimeException)
1340 {
1341     ScUnoGuard aGuard;
1342     return new ScIndexEnumeration(this, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sheet.DDELinksEnumeration")));
1343 }
1344 
1345 // XIndexAccess
1346 
1347 sal_Int32 SAL_CALL ScDDELinksObj::getCount() throw(uno::RuntimeException)
1348 {
1349     ScUnoGuard aGuard;
1350     sal_Int32 nAreaCount = 0;
1351     if (pDocShell)
1352         nAreaCount = pDocShell->GetDocument()->GetDdeLinkCount();
1353     return nAreaCount;
1354 }
1355 
1356 uno::Any SAL_CALL ScDDELinksObj::getByIndex( sal_Int32 nIndex )
1357                             throw(lang::IndexOutOfBoundsException,
1358                                     lang::WrappedTargetException, uno::RuntimeException)
1359 {
1360     ScUnoGuard aGuard;
1361     uno::Reference<sheet::XDDELink> xLink(GetObjectByIndex_Impl(nIndex));
1362     if (xLink.is())
1363         return uno::makeAny(xLink);
1364     else
1365         throw lang::IndexOutOfBoundsException();
1366 //    return uno::Any();
1367 }
1368 
1369 uno::Type SAL_CALL ScDDELinksObj::getElementType() throw(uno::RuntimeException)
1370 {
1371     ScUnoGuard aGuard;
1372     return getCppuType((uno::Reference<sheet::XDDELink>*)0);
1373 }
1374 
1375 sal_Bool SAL_CALL ScDDELinksObj::hasElements() throw(uno::RuntimeException)
1376 {
1377     ScUnoGuard aGuard;
1378     return ( getCount() != 0 );
1379 }
1380 
1381 uno::Any SAL_CALL ScDDELinksObj::getByName( const rtl::OUString& aName )
1382             throw(container::NoSuchElementException,
1383                     lang::WrappedTargetException, uno::RuntimeException)
1384 {
1385     ScUnoGuard aGuard;
1386     uno::Reference<sheet::XDDELink> xLink(GetObjectByName_Impl(aName));
1387     if (xLink.is())
1388         return uno::makeAny(xLink);
1389     else
1390         throw container::NoSuchElementException();
1391 //    return uno::Any();
1392 }
1393 
1394 uno::Sequence<rtl::OUString> SAL_CALL ScDDELinksObj::getElementNames() throw(uno::RuntimeException)
1395 {
1396     ScUnoGuard aGuard;
1397     if (pDocShell)
1398     {
1399         String aAppl, aTopic, aItem;
1400 
1401         ScDocument* pDoc = pDocShell->GetDocument();
1402         sal_uInt16 nCount = pDoc->GetDdeLinkCount();
1403         uno::Sequence<rtl::OUString> aSeq(nCount);
1404         rtl::OUString* pAry = aSeq.getArray();
1405 
1406         for (sal_uInt16 i=0; i<nCount; i++)
1407         {
1408             pDoc->GetDdeLinkData( i, aAppl, aTopic, aItem );
1409             pAry[i] = lcl_BuildDDEName(aAppl, aTopic, aItem);
1410         }
1411         return aSeq;
1412     }
1413     return uno::Sequence<rtl::OUString>();
1414 }
1415 
1416 sal_Bool SAL_CALL ScDDELinksObj::hasByName( const rtl::OUString& aName )
1417                                         throw(uno::RuntimeException)
1418 {
1419     ScUnoGuard aGuard;
1420     if (pDocShell)
1421     {
1422         String aNamStr(aName);
1423         String aAppl, aTopic, aItem;
1424 
1425         ScDocument* pDoc = pDocShell->GetDocument();
1426         sal_uInt16 nCount = pDoc->GetDdeLinkCount();
1427         for (sal_uInt16 i=0; i<nCount; i++)
1428         {
1429             pDoc->GetDdeLinkData( i, aAppl, aTopic, aItem );
1430             if ( lcl_BuildDDEName(aAppl, aTopic, aItem) == aNamStr )
1431                 return sal_True;
1432         }
1433     }
1434     return sal_False;
1435 }
1436 
1437 // XDDELinks
1438 
1439 uno::Reference< sheet::XDDELink > ScDDELinksObj::addDDELink(
1440     const ::rtl::OUString& aApplication, const ::rtl::OUString& aTopic,
1441     const ::rtl::OUString& aItem, ::com::sun::star::sheet::DDELinkMode nMode )
1442     throw (uno::RuntimeException)
1443 {
1444     ScUnoGuard aGuard;
1445     uno::Reference< sheet::XDDELink > xLink;
1446 
1447     if ( pDocShell )
1448     {
1449         ScDocument* pDoc = pDocShell->GetDocument();
1450         if ( pDoc )
1451         {
1452             sal_uInt8 nMod = SC_DDE_DEFAULT;
1453             switch ( nMode )
1454             {
1455                 case sheet::DDELinkMode_DEFAULT:
1456                     {
1457                         nMod = SC_DDE_DEFAULT;
1458                     }
1459                     break;
1460                 case sheet::DDELinkMode_ENGLISH:
1461                     {
1462                         nMod = SC_DDE_ENGLISH;
1463                     }
1464                     break;
1465                 case sheet::DDELinkMode_TEXT:
1466                     {
1467                         nMod = SC_DDE_TEXT;
1468                     }
1469                     break;
1470                 default:
1471                     {
1472                     }
1473                     break;
1474             }
1475 
1476             if ( pDoc->CreateDdeLink( aApplication, aTopic, aItem, nMod ) )
1477             {
1478                 const ::rtl::OUString aName( lcl_BuildDDEName( aApplication, aTopic, aItem ) );
1479                 xLink.set( GetObjectByName_Impl( aName ) );
1480             }
1481         }
1482     }
1483 
1484     if ( !xLink.is() )
1485     {
1486         throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
1487             "ScDDELinksObj::addDDELink: cannot add DDE link!" ) ),
1488             uno::Reference< uno::XInterface >() );
1489     }
1490 
1491     return xLink;
1492 }
1493 
1494 // ============================================================================
1495 
1496 ScExternalSheetCacheObj::ScExternalSheetCacheObj(ScExternalRefCache::TableTypeRef pTable, size_t nIndex) :
1497     mpTable(pTable),
1498     mnIndex(nIndex)
1499 {
1500 }
1501 
1502 ScExternalSheetCacheObj::~ScExternalSheetCacheObj()
1503 {
1504 }
1505 
1506 void SAL_CALL ScExternalSheetCacheObj::setCellValue(sal_Int32 nCol, sal_Int32 nRow, const Any& rValue)
1507     throw (IllegalArgumentException, RuntimeException)
1508 {
1509     ScUnoGuard aGuard;
1510     if (nRow < 0 || nCol < 0)
1511         throw IllegalArgumentException();
1512 
1513     ScExternalRefCache::TokenRef pToken;
1514     double fVal = 0.0;
1515     OUString aVal;
1516     if (rValue >>= fVal)
1517         pToken.reset(new FormulaDoubleToken(fVal));
1518     else if (rValue >>= aVal)
1519         pToken.reset(new FormulaStringToken(aVal));
1520     else
1521         // unidentified value type.
1522         return;
1523 
1524     mpTable->setCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), pToken);
1525 }
1526 
1527 Any SAL_CALL ScExternalSheetCacheObj::getCellValue(sal_Int32 nCol, sal_Int32 nRow)
1528     throw (IllegalArgumentException, RuntimeException)
1529 {
1530     ScUnoGuard aGuard;
1531     if (nRow < 0 || nCol < 0)
1532         throw IllegalArgumentException();
1533 
1534     FormulaToken* pToken = mpTable->getCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow)).get();
1535     if (!pToken)
1536         throw IllegalArgumentException();
1537 
1538     Any aValue;
1539     switch (pToken->GetType())
1540     {
1541         case svDouble:
1542         {
1543             double fVal = pToken->GetDouble();
1544             aValue <<= fVal;
1545         }
1546         break;
1547         case svString:
1548         {
1549             OUString aVal = pToken->GetString();
1550             aValue <<= aVal;
1551         }
1552         break;
1553         default:
1554             throw IllegalArgumentException();
1555     }
1556     return aValue;
1557 }
1558 
1559 Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllRows()
1560     throw (RuntimeException)
1561 {
1562     ScUnoGuard aGuard;
1563     vector<SCROW> aRows;
1564     mpTable->getAllRows(aRows);
1565     size_t nSize = aRows.size();
1566     Sequence<sal_Int32> aRowsSeq(nSize);
1567     for (size_t i = 0; i < nSize; ++i)
1568         aRowsSeq[i] = aRows[i];
1569 
1570     return aRowsSeq;
1571 }
1572 
1573 Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllColumns(sal_Int32 nRow)
1574     throw (IllegalArgumentException, RuntimeException)
1575 {
1576     ScUnoGuard aGuard;
1577     if (nRow < 0)
1578         throw IllegalArgumentException();
1579 
1580     vector<SCCOL> aCols;
1581     mpTable->getAllCols(static_cast<SCROW>(nRow), aCols);
1582     size_t nSize = aCols.size();
1583     Sequence<sal_Int32> aColsSeq(nSize);
1584     for (size_t i = 0; i < nSize; ++i)
1585         aColsSeq[i] = aCols[i];
1586 
1587     return aColsSeq;
1588 }
1589 
1590 sal_Int32 SAL_CALL ScExternalSheetCacheObj::getTokenIndex()
1591         throw (RuntimeException)
1592 {
1593     return static_cast< sal_Int32 >( mnIndex );
1594 }
1595 
1596 // ============================================================================
1597 
1598 ScExternalDocLinkObj::ScExternalDocLinkObj(ScExternalRefManager* pRefMgr, sal_uInt16 nFileId) :
1599     mpRefMgr(pRefMgr), mnFileId(nFileId)
1600 {
1601 }
1602 
1603 ScExternalDocLinkObj::~ScExternalDocLinkObj()
1604 {
1605 }
1606 
1607 Reference< sheet::XExternalSheetCache > SAL_CALL ScExternalDocLinkObj::addSheetCache(
1608     const OUString& aSheetName, sal_Bool bDynamicCache )
1609         throw (RuntimeException)
1610 {
1611     ScUnoGuard aGuard;
1612     size_t nIndex = 0;
1613     ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aSheetName, true, &nIndex);
1614     if (!bDynamicCache)
1615         // Set the whole table cached to prevent access to the source document.
1616         pTable->setWholeTableCached();
1617 
1618     Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(pTable, nIndex));
1619     return aSheetCache;
1620 }
1621 
1622 Any SAL_CALL ScExternalDocLinkObj::getByName(const::rtl::OUString &aName)
1623         throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException)
1624 {
1625     ScUnoGuard aGuard;
1626     size_t nIndex = 0;
1627     ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aName, false, &nIndex);
1628     if (!pTable)
1629         throw container::NoSuchElementException();
1630 
1631     Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(pTable, nIndex));
1632 
1633     Any aAny;
1634     aAny <<= aSheetCache;
1635     return aAny;
1636 }
1637 
1638 Sequence< OUString > SAL_CALL ScExternalDocLinkObj::getElementNames()
1639         throw (RuntimeException)
1640 {
1641     ScUnoGuard aGuard;
1642     vector<String> aTabNames;
1643     mpRefMgr->getAllCachedTableNames(mnFileId, aTabNames);
1644 
1645     // #i116940# be consistent with getByName: include only table names which have a cache already
1646     vector<String> aValidNames;
1647     for (vector<String>::const_iterator aIter = aTabNames.begin(); aIter != aTabNames.end(); ++aIter)
1648         if (mpRefMgr->getCacheTable(mnFileId, *aIter, false))
1649             aValidNames.push_back(*aIter);
1650 
1651     size_t n = aValidNames.size();
1652     Sequence<OUString> aSeq(n);
1653     for (size_t i = 0; i < n; ++i)
1654         aSeq[i] = aValidNames[i];
1655     return aSeq;
1656 }
1657 
1658 sal_Bool SAL_CALL ScExternalDocLinkObj::hasByName(const OUString &aName)
1659         throw (RuntimeException)
1660 {
1661     ScUnoGuard aGuard;
1662 
1663     // #i116940# be consistent with getByName: allow only table names which have a cache already
1664     ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aName, false);
1665     return (pTable.get() != NULL);
1666 }
1667 
1668 sal_Int32 SAL_CALL ScExternalDocLinkObj::getCount()
1669         throw (RuntimeException)
1670 {
1671     ScUnoGuard aGuard;
1672 
1673     // #i116940# be consistent with getByName: count only table names which have a cache already
1674     return getElementNames().getLength();
1675 }
1676 
1677 Any SAL_CALL ScExternalDocLinkObj::getByIndex(sal_Int32 nApiIndex)
1678         throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, RuntimeException)
1679 {
1680     ScUnoGuard aGuard;
1681 
1682     // #i116940# Can't use nApiIndex as index for the ref manager, because the API counts only
1683     // the entries which have a cache already. Quick solution: Use getElementNames.
1684 
1685     Sequence< OUString > aNames( getElementNames() );
1686     if (nApiIndex < 0 || nApiIndex >= aNames.getLength())
1687         throw lang::IndexOutOfBoundsException();
1688 
1689     size_t nIndex = 0;
1690     ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aNames[nApiIndex], false, &nIndex);
1691     if (!pTable)
1692         throw lang::IndexOutOfBoundsException();
1693 
1694     Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(pTable, nIndex));
1695 
1696     Any aAny;
1697     aAny <<= aSheetCache;
1698     return aAny;
1699 }
1700 
1701 Reference< container::XEnumeration > SAL_CALL ScExternalDocLinkObj::createEnumeration()
1702         throw (RuntimeException)
1703 {
1704     ScUnoGuard aGuard;
1705     Reference< container::XEnumeration > aRef(
1706         new ScIndexEnumeration(this, OUString::createFromAscii(
1707             "com.sun.star.sheet.ExternalDocLink")));
1708     return aRef;
1709 }
1710 
1711 uno::Type SAL_CALL ScExternalDocLinkObj::getElementType()
1712         throw (RuntimeException)
1713 {
1714     ScUnoGuard aGuard;
1715     return getCppuType(static_cast<Reference<sheet::XExternalDocLink>*>(0));
1716 }
1717 
1718 sal_Bool SAL_CALL ScExternalDocLinkObj::hasElements()
1719         throw (RuntimeException)
1720 {
1721     ScUnoGuard aGuard;
1722 
1723     // #i116940# be consistent with getByName: count only table names which have a cache already
1724     return ( getElementNames().getLength() > 0 );
1725 }
1726 
1727 sal_Int32 SAL_CALL ScExternalDocLinkObj::getTokenIndex()
1728         throw (RuntimeException)
1729 {
1730     return static_cast<sal_Int32>(mnFileId);
1731 }
1732 
1733 // ============================================================================
1734 
1735 ScExternalDocLinksObj::ScExternalDocLinksObj(ScDocShell* pDocShell) :
1736     mpDocShell(pDocShell),
1737     mpRefMgr(pDocShell->GetDocument()->GetExternalRefManager())
1738 {
1739 }
1740 
1741 ScExternalDocLinksObj::~ScExternalDocLinksObj()
1742 {
1743 }
1744 
1745 Reference< sheet::XExternalDocLink > SAL_CALL ScExternalDocLinksObj::addDocLink(
1746     const OUString& aDocName )
1747         throw (RuntimeException)
1748 {
1749     ScUnoGuard aGuard;
1750     sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aDocName);
1751     Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpRefMgr, nFileId));
1752     return aDocLink;
1753 }
1754 
1755 Any SAL_CALL ScExternalDocLinksObj::getByName(const::rtl::OUString &aName)
1756         throw (container::NoSuchElementException, lang::WrappedTargetException, RuntimeException)
1757 {
1758     ScUnoGuard aGuard;
1759     if (!mpRefMgr->hasExternalFile(aName))
1760         throw container::NoSuchElementException();
1761 
1762     sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aName);
1763     Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpRefMgr, nFileId));
1764 
1765     Any aAny;
1766     aAny <<= aDocLink;
1767     return aAny;
1768 }
1769 
1770 Sequence< OUString > SAL_CALL ScExternalDocLinksObj::getElementNames()
1771         throw (RuntimeException)
1772 {
1773     ScUnoGuard aGuard;
1774     sal_uInt16 n = mpRefMgr->getExternalFileCount();
1775     Sequence<OUString> aSeq(n);
1776     for (sal_uInt16 i = 0; i < n; ++i)
1777     {
1778         const String* pName = mpRefMgr->getExternalFileName(i);
1779         aSeq[i] = pName ? *pName : EMPTY_STRING;
1780     }
1781 
1782     return aSeq;
1783 }
1784 
1785 sal_Bool SAL_CALL ScExternalDocLinksObj::hasByName(const OUString &aName)
1786         throw (RuntimeException)
1787 {
1788     ScUnoGuard aGuard;
1789     return mpRefMgr->hasExternalFile(aName);
1790 }
1791 
1792 sal_Int32 SAL_CALL ScExternalDocLinksObj::getCount()
1793         throw (RuntimeException)
1794 {
1795     ScUnoGuard aGuard;
1796     return mpRefMgr->getExternalFileCount();
1797 }
1798 
1799 Any SAL_CALL ScExternalDocLinksObj::getByIndex(sal_Int32 nIndex)
1800         throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, RuntimeException)
1801 {
1802     ScUnoGuard aGuard;
1803     if (nIndex > ::std::numeric_limits<sal_uInt16>::max() || nIndex < ::std::numeric_limits<sal_uInt16>::min())
1804         throw lang::IndexOutOfBoundsException();
1805 
1806     sal_uInt16 nFileId = static_cast<sal_uInt16>(nIndex);
1807 
1808     if (!mpRefMgr->hasExternalFile(nFileId))
1809         throw lang::IndexOutOfBoundsException();
1810 
1811     Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpRefMgr, nFileId));
1812     Any aAny;
1813     aAny <<= aDocLink;
1814     return aAny;
1815 }
1816 
1817 Reference< container::XEnumeration > SAL_CALL ScExternalDocLinksObj::createEnumeration()
1818         throw (RuntimeException)
1819 {
1820     ScUnoGuard aGuard;
1821     Reference< container::XEnumeration > aRef(
1822         new ScIndexEnumeration(this, OUString::createFromAscii(
1823             "com.sun.star.sheet.ExternalDocLinks")));
1824     return aRef;
1825 }
1826 
1827 uno::Type SAL_CALL ScExternalDocLinksObj::getElementType()
1828         throw (RuntimeException)
1829 {
1830     ScUnoGuard aGuard;
1831     return getCppuType(static_cast<Reference<sheet::XExternalDocLinks>*>(0));
1832 }
1833 
1834 sal_Bool SAL_CALL ScExternalDocLinksObj::hasElements()
1835         throw (RuntimeException)
1836 {
1837     ScUnoGuard aGuard;
1838     return mpRefMgr->getExternalFileCount() > 0;
1839 }
1840 
1841