xref: /aoo42x/main/sfx2/source/appl/linkmgr2.cxx (revision 789caf29)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_sfx2.hxx"
24 
25 #include <sfx2/linkmgr.hxx>
26 #include <com/sun/star/document/UpdateDocMode.hpp>
27 #include <sfx2/objsh.hxx>
28 #include <svl/urihelper.hxx>
29 #include <sot/formats.hxx>
30 #include <tools/urlobj.hxx>
31 #include <sot/exchange.hxx>
32 #include <tools/debug.hxx>
33 #include <vcl/msgbox.hxx>
34 #include <sfx2/lnkbase.hxx>
35 #include <sfx2/app.hxx>
36 #include <vcl/graph.hxx>
37 #include <svl/stritem.hxx>
38 #include <svl/eitem.hxx>
39 #include <svl/intitem.hxx>
40 #include <unotools/localfilehelper.hxx>
41 #include <i18npool/mslangid.hxx>
42 #include <sfx2/request.hxx>
43 #include <vcl/dibtools.hxx>
44 
45 #include "fileobj.hxx"
46 #include "impldde.hxx"
47 #include "app.hrc"
48 #include "sfx2/sfxresid.hxx"
49 
50 #define _SVSTDARR_STRINGSDTOR
51 #include <svl/svstdarr.hxx>
52 
53 namespace sfx2
54 {
55 
56 class SvxInternalLink : public sfx2::SvLinkSource
57 {
58 public:
59 	SvxInternalLink() {}
60 
61     virtual sal_Bool Connect( sfx2::SvBaseLink* );
62 };
63 
64 
65 SV_IMPL_PTRARR( SvBaseLinks, SvBaseLinkRefPtr )
66 
67 LinkManager::LinkManager(SfxObjectShell* p)
68 	: pPersist(p),
69 	mUpdateAsked(sal_False),
70 	mAutoAskUpdateAllLinks(sal_False)
71 {
72 }
73 
74 LinkManager::~LinkManager()
75 {
76 	SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData();
77 	for( sal_uInt16 n = aLinkTbl.Count(); n; --n, ++ppRef )
78 	{
79 		if( (*ppRef)->Is() )
80 		{
81 			(*(*ppRef))->Disconnect();
82             (*(*ppRef))->SetLinkManager( NULL );
83 		}
84 		delete *ppRef;
85 	}
86 }
87 
88 
89 /************************************************************************
90 |*    LinkManager::Remove()
91 |*
92 |*    Description
93 *************************************************************************/
94 
95 void LinkManager::Remove( SvBaseLink *pLink )
96 {
97 	// do not insert links double
98 	int bFound = sal_False;
99 	SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData();
100 	for( sal_uInt16 n = aLinkTbl.Count(); n; --n, ++ppRef )
101 	{
102 		if( pLink == *(*ppRef) )
103 		{
104 			(*(*ppRef))->Disconnect();
105             (*(*ppRef))->SetLinkManager( NULL );
106 			(*(*ppRef)).Clear();
107 			bFound = sal_True;
108 		}
109 
110 		// if there are still some empty ones, get rid of them
111 		if( !(*ppRef)->Is() )
112 		{
113 			delete *ppRef;
114 			aLinkTbl.Remove( aLinkTbl.Count() - n, 1 );
115 			if( bFound )
116 				return ;
117 			--ppRef;
118 		}
119 	}
120 }
121 
122 
123 void LinkManager::Remove( sal_uInt16 nPos, sal_uInt16 nCnt )
124 {
125 	if( nCnt && nPos < aLinkTbl.Count() )
126 	{
127 		if( nPos + nCnt > aLinkTbl.Count() )
128 			nCnt = aLinkTbl.Count() - nPos;
129 
130 		SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData() + nPos;
131 		for( sal_uInt16 n = nCnt; n; --n, ++ppRef )
132 		{
133 			if( (*ppRef)->Is() )
134 			{
135 				(*(*ppRef))->Disconnect();
136                 (*(*ppRef))->SetLinkManager( NULL );
137 			}
138 			delete *ppRef;
139 		}
140 		aLinkTbl.Remove( nPos, nCnt );
141 	}
142 }
143 
144 
145 sal_Bool LinkManager::Insert( SvBaseLink* pLink )
146 {
147 
148 	// do not insert links double
149 	for( sal_uInt16 n = 0; n < aLinkTbl.Count(); ++n )
150 	{
151 		SvBaseLinkRef* pTmp = aLinkTbl[ n ];
152 		if( !pTmp->Is() )
153 			aLinkTbl.DeleteAndDestroy( n-- );
154 
155 		if( pLink == *pTmp )
156 			return sal_False;
157 	}
158 
159 	SvBaseLinkRef* pTmp = new SvBaseLinkRef( pLink );
160     pLink->SetLinkManager( this );
161 	aLinkTbl.Insert( pTmp, aLinkTbl.Count() );
162 	if (mAutoAskUpdateAllLinks)
163 	{
164 		Window *parent = NULL;
165 		SfxObjectShell* persist = GetPersist();
166 		if (persist != NULL)
167 			parent = GetPersist()->GetDialogParent();
168 
169 		SetUserAllowsLinkUpdate(pLink, GetUserAllowsLinkUpdate(parent));
170 	}
171 
172 	return sal_True;
173 }
174 
175 
176 sal_Bool LinkManager::InsertLink( SvBaseLink * pLink,
177 								sal_uInt16 nObjType,
178 								sal_uInt16 nUpdateMode,
179 								const String* pName )
180 {
181 	// in any case: do this first
182 	pLink->SetObjType( nObjType );
183 	if( pName )
184 		pLink->SetName( *pName );
185 	pLink->SetUpdateMode( nUpdateMode );
186 	return Insert( pLink );
187 }
188 
189 
190 sal_Bool LinkManager::InsertDDELink( SvBaseLink * pLink,
191 									const String& rServer,
192 									const String& rTopic,
193 									const String& rItem )
194 {
195 	if( !( OBJECT_CLIENT_SO & pLink->GetObjType() ) )
196 		return sal_False;
197 
198 	String sCmd;
199 	::sfx2::MakeLnkName( sCmd, &rServer, rTopic, rItem );
200 
201 	pLink->SetObjType( OBJECT_CLIENT_DDE );
202 	pLink->SetName( sCmd );
203 	return Insert( pLink );
204 }
205 
206 
207 sal_Bool LinkManager::InsertDDELink( SvBaseLink * pLink )
208 {
209 	DBG_ASSERT( OBJECT_CLIENT_SO & pLink->GetObjType(), "no OBJECT_CLIENT_SO" );
210 	if( !( OBJECT_CLIENT_SO & pLink->GetObjType() ) )
211 		return sal_False;
212 
213 	if( pLink->GetObjType() == OBJECT_CLIENT_SO )
214 		pLink->SetObjType( OBJECT_CLIENT_DDE );
215 
216 	return Insert( pLink );
217 }
218 
219 
220 // ask for the strings to be used in the dialog
221 sal_Bool LinkManager::GetDisplayNames( const SvBaseLink * pLink,
222 										String* pType,
223 										String* pFile,
224 										String* pLinkStr,
225 										String* pFilter ) const
226 {
227 	sal_Bool bRet = sal_False;
228 	const String sLNm( pLink->GetLinkSourceName() );
229 	if( sLNm.Len() )
230 	{
231 		switch( pLink->GetObjType() )
232 		{
233 		    case OBJECT_CLIENT_FILE:
234 		    case OBJECT_CLIENT_GRF:
235 		    case OBJECT_CLIENT_OLE:
236 			    {
237 				    sal_uInt16 nPos = 0;
238 				    String sFile( sLNm.GetToken( 0, ::sfx2::cTokenSeperator, nPos ) );
239 				    String sRange( sLNm.GetToken( 0, ::sfx2::cTokenSeperator, nPos ) );
240 
241 				    if( pFile )
242 					    *pFile = sFile;
243 				    if( pLinkStr )
244 					    *pLinkStr = sRange;
245 				    if( pFilter )
246 					    *pFilter = sLNm.Copy( nPos );
247 
248 				    if( pType )
249 				    {
250 					    sal_uInt16 nObjType = pLink->GetObjType();
251 					    *pType = String( SfxResId(
252 								    ( OBJECT_CLIENT_FILE == nObjType || OBJECT_CLIENT_OLE == nObjType )
253 										    ? RID_SVXSTR_FILELINK
254 										    : RID_SVXSTR_GRAFIKLINK ));
255 				    }
256 				    bRet = sal_True;
257 			    }
258 			    break;
259 		    case OBJECT_CLIENT_DDE:
260 	            {
261 		            sal_uInt16 nTmp = 0;
262 		            String sCmd( sLNm );
263 		            String sServer( sCmd.GetToken( 0, cTokenSeperator, nTmp ) );
264 		            String sTopic( sCmd.GetToken( 0, cTokenSeperator, nTmp ) );
265 
266 		            if( pType )
267 			            *pType = sServer;
268 		            if( pFile )
269 			            *pFile = sTopic;
270 		            if( pLinkStr )
271 			            *pLinkStr = sCmd.Copy( nTmp );
272 		            bRet = sal_True;
273 		        }
274 		        break;
275 	        default:
276 	            break;
277 	    }
278 	}
279 
280 	return bRet;
281 }
282 
283 void LinkManager::SetAutoAskUpdateAllLinks()
284 {
285 	mAutoAskUpdateAllLinks = sal_True;
286 }
287 
288 sal_Bool LinkManager::GetUserAllowsLinkUpdate(Window *pParentWin)
289 {
290 	if (!mUpdateAsked)
291 	{
292 		if (QueryBox(pParentWin, WB_YES_NO | WB_DEF_NO, SfxResId(STR_QUERY_UPDATE_LINKS)).Execute() == RET_YES)
293 			mAllowUpdate = sal_True;
294 		else
295 			mAllowUpdate = sal_False;
296 		mUpdateAsked = sal_True;
297 	}
298 	return mAllowUpdate;
299 }
300 
301 void LinkManager::SetUserAllowsLinkUpdate(SvBaseLink *pLink, sal_Bool allows)
302 {
303 	SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
304 
305 	if (pShell)
306 	{
307 		comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = pShell->getEmbeddedObjectContainer();
308 		rEmbeddedObjectContainer.setUserAllowsLinkUpdate(allows);
309 	}
310 }
311 
312 
313 void LinkManager::UpdateAllLinks(
314     sal_Bool bAskUpdate,
315     sal_Bool /*bCallErrHdl*/,
316     sal_Bool bUpdateGrfLinks,
317     Window* pParentWin )
318 {
319 	SvStringsDtor aApps, aTopics, aItems;
320 	String sApp, sTopic, sItem;
321 
322 	// first create a copy of the array, so that updated links to not interfere with ... in between!!
323 	SvPtrarr aTmpArr( 255, 50 );
324 	sal_uInt16 n;
325 	for( n = 0; n < aLinkTbl.Count(); ++n )
326 	{
327 		SvBaseLink* pLink = *aLinkTbl[ n ];
328 		if( !pLink )
329 		{
330 			Remove( n-- );
331 			continue;
332 		}
333 		aTmpArr.Insert( pLink, aTmpArr.Count() );
334 	}
335 
336 	for( n = 0; n < aTmpArr.Count(); ++n )
337 	{
338 		SvBaseLink* pLink = (SvBaseLink*)aTmpArr[ n ];
339 
340 		// first search the entry in the array
341 		sal_uInt16 nFndPos = USHRT_MAX;
342 		for( sal_uInt16 i = 0; i < aLinkTbl.Count(); ++i )
343 			if( pLink == *aLinkTbl[ i ] )
344 			{
345 				nFndPos = i;
346 				break;
347 			}
348 
349 		if( USHRT_MAX == nFndPos )
350 			continue;					// was not already existing!
351 
352 		// do not update graphic links yet
353 		if( !pLink->IsVisible() ||
354 			( !bUpdateGrfLinks && OBJECT_CLIENT_GRF == pLink->GetObjType() ))
355 			continue;
356 
357 		sal_Bool allows = sal_True;
358 
359 		if (bAskUpdate)
360 		{
361 			allows = GetUserAllowsLinkUpdate(pParentWin);
362 		}
363 
364 		SetUserAllowsLinkUpdate(pLink, allows);
365 	    bAskUpdate = sal_False;		// one time is OK
366 
367 		if (allows)
368 			pLink->Update();
369 	}
370 }
371 
372 /************************************************************************
373 |*    SvBaseLink::CreateObject()
374 |*
375 |*    Description
376 *************************************************************************/
377 
378 SvLinkSourceRef LinkManager::CreateObj( SvBaseLink * pLink )
379 {
380 	switch( pLink->GetObjType() )
381 	{
382 	    case OBJECT_CLIENT_FILE:
383 	    case OBJECT_CLIENT_GRF:
384 	    case OBJECT_CLIENT_OLE:
385 		    return new SvFileObject;
386 	    case OBJECT_INTERN:
387 		    return new SvxInternalLink;
388         case OBJECT_CLIENT_DDE:
389 		    return new SvDDEObject;
390 	    default:
391         	return SvLinkSourceRef();
392    	}
393 }
394 
395 sal_Bool LinkManager::InsertServer( SvLinkSource* pObj )
396 {
397 	// do not insert double
398 	if( !pObj || USHRT_MAX != aServerTbl.GetPos( pObj ) )
399 		return sal_False;
400 
401 	aServerTbl.Insert( pObj, aServerTbl.Count() );
402 	return sal_True;
403 }
404 
405 
406 void LinkManager::RemoveServer( SvLinkSource* pObj )
407 {
408 	sal_uInt16 nPos = aServerTbl.GetPos( pObj );
409 	if( USHRT_MAX != nPos )
410 		aServerTbl.Remove( nPos, 1 );
411 }
412 
413 
414 void MakeLnkName( String& rName, const String* pType, const String& rFile,
415 					const String& rLink, const String* pFilter )
416 {
417 	if( pType )
418 		(rName = *pType).EraseLeadingChars().EraseTrailingChars() += cTokenSeperator;
419 	else if( rName.Len() )
420 		rName.Erase();
421 
422 	((rName += rFile).EraseLeadingChars().EraseTrailingChars() +=
423 		cTokenSeperator ).EraseLeadingChars().EraseTrailingChars() += rLink;
424 	if( pFilter )
425 		((rName += cTokenSeperator ) += *pFilter).EraseLeadingChars().EraseTrailingChars();
426 }
427 
428 sal_Bool LinkManager::InsertFileLink( sfx2::SvBaseLink& rLink,
429 									sal_uInt16 nFileType,
430 									const String& rFileNm,
431 									const String* pFilterNm,
432 									const String* pRange )
433 {
434 	if( !( OBJECT_CLIENT_SO & rLink.GetObjType() ))
435 		return sal_False;
436 
437 	String sCmd( rFileNm );
438 	sCmd += ::sfx2::cTokenSeperator;
439 	if( pRange )
440 		sCmd += *pRange;
441 	if( pFilterNm )
442 		( sCmd += ::sfx2::cTokenSeperator ) += *pFilterNm;
443 
444 	return InsertLink( &rLink, nFileType, sfx2::LINKUPDATE_ONCALL, &sCmd );
445 }
446 
447 sal_Bool LinkManager::InsertFileLink( sfx2::SvBaseLink& rLink )
448 {
449 	if( OBJECT_CLIENT_FILE == ( OBJECT_CLIENT_FILE & rLink.GetObjType() ))
450 		return InsertLink( &rLink, rLink.GetObjType(), sfx2::LINKUPDATE_ONCALL );
451 	return sal_False;
452 }
453 
454 // a transfer will be discontinued, therefore cancel all DownloadMedia
455 // (at the moment only interesting for the FileLinks!)
456 void LinkManager::CancelTransfers()
457 {
458 	SvFileObject* pFileObj;
459 	sfx2::SvBaseLink* pLnk;
460 
461 	const sfx2::SvBaseLinks& rLnks = GetLinks();
462 	for( sal_uInt16 n = rLnks.Count(); n; )
463 		if( 0 != ( pLnk = &(*rLnks[ --n ])) &&
464 			OBJECT_CLIENT_FILE == (OBJECT_CLIENT_FILE & pLnk->GetObjType()) &&
465 			0 != ( pFileObj = (SvFileObject*)pLnk->GetObj() ) )
466 //			0 != ( pFileObj = (SvFileObject*)SvFileObject::ClassFactory()->
467 //									CastAndAddRef( pLnk->GetObj() )) )
468 			pFileObj->CancelTransfers();
469 }
470 
471 	// to send status information from the FileObject to the BaseLink, there is an own ClipboardId.
472 	// The SvData object has then the respective information as string.
473 	// Currently this will be used for FileObject in connection with JavaScript
474 	// - that needs information about Load/Abort/Error
475 sal_uIntPtr LinkManager::RegisterStatusInfoId()
476 {
477 	static sal_uIntPtr nFormat = 0;
478 
479 	if( !nFormat )
480 	{
481 // how does the new interface look like?
482 //		nFormat = Exchange::RegisterFormatName( "StatusInfo vom SvxInternalLink" );
483 		nFormat = SotExchange::RegisterFormatName(
484 					String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM(
485 								"StatusInfo vom SvxInternalLink" )));
486 	}
487 	return nFormat;
488 }
489 
490 // ----------------------------------------------------------------------
491 
492 sal_Bool LinkManager::GetGraphicFromAny( const String& rMimeType,
493 								const ::com::sun::star::uno::Any & rValue,
494 								Graphic& rGrf )
495 {
496 	sal_Bool bRet = sal_False;
497 	::com::sun::star::uno::Sequence< sal_Int8 > aSeq;
498 	if( rValue.hasValue() && ( rValue >>= aSeq ) )
499 	{
500 		SvMemoryStream aMemStm( (void*)aSeq.getConstArray(), aSeq.getLength(),
501 								STREAM_READ );
502 		aMemStm.Seek( 0 );
503 
504 		switch( SotExchange::GetFormatIdFromMimeType( rMimeType ) )
505 		{
506 		case SOT_FORMATSTR_ID_SVXB:
507 			{
508 				aMemStm >> rGrf;
509 				bRet = sal_True;
510 			}
511 			break;
512 		case FORMAT_GDIMETAFILE:
513 			{
514 				GDIMetaFile aMtf;
515 				aMtf.Read( aMemStm );
516 				rGrf = aMtf;
517 				bRet = sal_True;
518 			}
519 			break;
520 		case FORMAT_BITMAP:
521 			{
522 				Bitmap aBmp;
523                 ReadDIB(aBmp, aMemStm, true);
524 				rGrf = aBmp;
525 				bRet = sal_True;
526 			}
527 			break;
528 		}
529 	}
530 	return bRet;
531 }
532 
533 
534 // ----------------------------------------------------------------------
535 String lcl_DDE_RelToAbs( const String& rTopic, const String& rBaseURL )
536 {
537 	String sRet;
538 	INetURLObject aURL( rTopic );
539 	if( INET_PROT_NOT_VALID == aURL.GetProtocol() )
540         utl::LocalFileHelper::ConvertSystemPathToURL( rTopic, rBaseURL, sRet );
541 	if( !sRet.Len() )
542         sRet = URIHelper::SmartRel2Abs( INetURLObject(rBaseURL), rTopic, URIHelper::GetMaybeFileHdl(), true );
543 	return sRet;
544 }
545 
546 sal_Bool SvxInternalLink::Connect( sfx2::SvBaseLink* pLink )
547 {
548 	SfxObjectShell* pFndShell = 0;
549 	sal_uInt16 nUpdateMode = com::sun::star::document::UpdateDocMode::NO_UPDATE;
550 	String sTopic, sItem, sReferer;
551 	if( pLink->GetLinkManager() &&
552 		pLink->GetLinkManager()->GetDisplayNames( pLink, 0, &sTopic, &sItem )
553 		&& sTopic.Len() )
554 	{
555 		// for the moment run through the DocumentShells and search for the ones with names:
556 
557 	    com::sun::star::lang::Locale aLocale;
558 	    MsLangId::convertLanguageToLocale( LANGUAGE_SYSTEM, aLocale );
559 		CharClass aCC( aLocale );
560 
561         String sNm( sTopic ), sTmp;
562 		aCC.toLower( sNm );
563 
564 		TypeId aType( TYPE(SfxObjectShell) );
565 
566 		sal_Bool bFirst = sal_True;
567         SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
568         if( pShell && pShell->GetMedium() )
569 		{
570             sReferer = pShell->GetMedium()->GetBaseURL();
571 			SFX_ITEMSET_ARG( pShell->GetMedium()->GetItemSet(), pItem, SfxUInt16Item, SID_UPDATEDOCMODE, sal_False );
572 			if ( pItem )
573 				nUpdateMode = pItem->GetValue();
574 		}
575 
576         String sNmURL( lcl_DDE_RelToAbs( sTopic, sReferer ) );
577 		aCC.toLower( sNmURL );
578 
579 		if ( !pShell )
580 		{
581 			bFirst = sal_False;
582             pShell = SfxObjectShell::GetFirst( &aType, sal_False );
583 		}
584 
585 		while( pShell )
586 		{
587 			if( !sTmp.Len() )
588 			{
589 				sTmp = pShell->GetTitle( SFX_TITLE_FULLNAME );
590                 sTmp = lcl_DDE_RelToAbs(sTmp, sReferer );
591 			}
592 
593 
594 			aCC.toLower( sTmp );
595 			if( sTmp == sNmURL )		// these we want to have
596 			{
597 				pFndShell = pShell;
598 				break;
599 			}
600 
601 			if( bFirst )
602 			{
603 				bFirst = sal_False;
604                 pShell = SfxObjectShell::GetFirst( &aType, sal_False );
605 			}
606 			else
607                 pShell = SfxObjectShell::GetNext( *pShell, &aType, sal_False );
608 
609 			sTmp.Erase();
610 		}
611 	}
612 
613 	// empty topics are not allowed - which document is it
614 	if( !sTopic.Len() )
615 		return sal_False;
616 
617 	if( !pFndShell )
618 	{
619 		// try to load the file:
620 		INetURLObject aURL( sTopic );
621 		INetProtocol eOld = aURL.GetProtocol();
622         aURL.SetURL( sTopic = lcl_DDE_RelToAbs( sTopic, sReferer ) );
623 		if( INET_PROT_NOT_VALID != eOld ||
624 			INET_PROT_HTTP != aURL.GetProtocol() )
625 		{
626 			SfxStringItem aName( SID_FILE_NAME, sTopic );
627             SfxBoolItem aMinimized(SID_MINIMIZED, sal_True);
628             SfxBoolItem aHidden(SID_HIDDEN, sal_True);
629             SfxStringItem aTarget( SID_TARGETNAME, String::CreateFromAscii("_blank") );
630 			SfxStringItem aReferer( SID_REFERER, sReferer );
631 			SfxUInt16Item aUpdate( SID_UPDATEDOCMODE, nUpdateMode );
632             SfxBoolItem aReadOnly(SID_DOC_READONLY, sal_True);
633 
634             // #i14200# (DDE-link crashes wordprocessor)
635             SfxAllItemSet aArgs( SFX_APP()->GetPool() );
636             aArgs.Put(aReferer);
637             aArgs.Put(aTarget);
638             aArgs.Put(aHidden);
639             aArgs.Put(aMinimized);
640             aArgs.Put(aName);
641 			aArgs.Put(aUpdate);
642 			aArgs.Put(aReadOnly);
643             pFndShell = SfxObjectShell::CreateAndLoadObject( aArgs );
644 		}
645 	}
646 
647 	sal_Bool bRet = sal_False;
648 	if( pFndShell )
649 	{
650 		sfx2::SvLinkSource* pNewSrc = pFndShell->DdeCreateLinkSource( sItem );
651 		if( pNewSrc )
652 		{
653 			bRet = sal_True;
654 
655 			::com::sun::star::datatransfer::DataFlavor aFl;
656 			SotExchange::GetFormatDataFlavor( pLink->GetContentType(), aFl );
657 
658 			pLink->SetObj( pNewSrc );
659 			pNewSrc->AddDataAdvise( pLink, aFl.MimeType,
660 								sfx2::LINKUPDATE_ONCALL == pLink->GetUpdateMode()
661 									? ADVISEMODE_ONLYONCE
662 									: 0 );
663 		}
664 	}
665 	return bRet;
666 }
667 
668 
669 }
670 
671