xref: /aoo41x/main/sc/source/ui/unoobj/linkuno.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
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