xref: /AOO41X/main/sfx2/source/appl/linkmgr2.cxx (revision 7ae7f31ca19699670dca92065bf642f9fc090ed6)
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 <com/sun/star/lang/XMultiServiceFactory.hpp>
28 #include <com/sun/star/util/XURLTransformer.hpp>
29 
30 #include <sfx2/objsh.hxx>
31 #include <svl/urihelper.hxx>
32 #include <sot/formats.hxx>
33 #include <tools/urlobj.hxx>
34 #include <sot/exchange.hxx>
35 #include <tools/debug.hxx>
36 #include <vcl/msgbox.hxx>
37 #include <sfx2/lnkbase.hxx>
38 #include <sfx2/app.hxx>
39 #include <vcl/graph.hxx>
40 #include <svl/stritem.hxx>
41 #include <svl/eitem.hxx>
42 #include <svl/intitem.hxx>
43 #include <unotools/localfilehelper.hxx>
44 #include <comphelper/processfactory.hxx>
45 #include <i18npool/mslangid.hxx>
46 #include <sfx2/request.hxx>
47 #include <vcl/dibtools.hxx>
48 
49 #include "fileobj.hxx"
50 #include "impldde.hxx"
51 #include "app.hrc"
52 #include "sfx2/sfxresid.hxx"
53 
54 #define _SVSTDARR_STRINGSDTOR
55 #include <svl/svstdarr.hxx>
56 
57 namespace sfx2
58 {
59 
60 class SvxInternalLink : public sfx2::SvLinkSource
61 {
62 public:
63 	SvxInternalLink() {}
64 
65     virtual sal_Bool Connect( sfx2::SvBaseLink* );
66 };
67 
68 
69 SV_IMPL_PTRARR( SvBaseLinks, SvBaseLinkRefPtr )
70 
71 LinkManager::LinkManager(SfxObjectShell* p)
72 	: pPersist(p),
73 	mAutoAskUpdateAllLinks(sal_False),
74 	mUpdateAsked(sal_False)
75 {
76 }
77 
78 LinkManager::~LinkManager()
79 {
80 	SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData();
81 	for( sal_uInt16 n = aLinkTbl.Count(); n; --n, ++ppRef )
82 	{
83 		if( (*ppRef)->Is() )
84 		{
85 			(*(*ppRef))->Disconnect();
86             (*(*ppRef))->SetLinkManager( NULL );
87 		}
88 		delete *ppRef;
89 	}
90 }
91 
92 
93 /************************************************************************
94 |*    LinkManager::Remove()
95 |*
96 |*    Beschreibung
97 *************************************************************************/
98 
99 void LinkManager::Remove( SvBaseLink *pLink )
100 {
101 	// keine Links doppelt einfuegen
102 	int bFound = sal_False;
103 	SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData();
104 	for( sal_uInt16 n = aLinkTbl.Count(); n; --n, ++ppRef )
105 	{
106 		if( pLink == *(*ppRef) )
107 		{
108 			(*(*ppRef))->Disconnect();
109             (*(*ppRef))->SetLinkManager( NULL );
110 			(*(*ppRef)).Clear();
111 			bFound = sal_True;
112 		}
113 
114 		// falls noch leere rum stehen sollten, weg damit
115 		if( !(*ppRef)->Is() )
116 		{
117 			delete *ppRef;
118 			aLinkTbl.Remove( aLinkTbl.Count() - n, 1 );
119 			if( bFound )
120 				return ;
121 			--ppRef;
122 		}
123 	}
124 }
125 
126 
127 void LinkManager::Remove( sal_uInt16 nPos, sal_uInt16 nCnt )
128 {
129 	if( nCnt && nPos < aLinkTbl.Count() )
130 	{
131 		if( nPos + nCnt > aLinkTbl.Count() )
132 			nCnt = aLinkTbl.Count() - nPos;
133 
134 		SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData() + nPos;
135 		for( sal_uInt16 n = nCnt; n; --n, ++ppRef )
136 		{
137 			if( (*ppRef)->Is() )
138 			{
139 				(*(*ppRef))->Disconnect();
140                 (*(*ppRef))->SetLinkManager( NULL );
141 			}
142 			delete *ppRef;
143 		}
144 		aLinkTbl.Remove( nPos, nCnt );
145 	}
146 }
147 
148 
149 sal_Bool LinkManager::Insert( SvBaseLink* pLink )
150 {
151 	// keine Links doppelt einfuegen
152 	for( sal_uInt16 n = 0; n < aLinkTbl.Count(); ++n )
153 	{
154 		SvBaseLinkRef* pTmp = aLinkTbl[ n ];
155 		if( !pTmp->Is() )
156 			aLinkTbl.DeleteAndDestroy( n-- );
157 
158 		if( pLink == *pTmp )
159 			return sal_False;
160 	}
161 
162 	SvBaseLinkRef* pTmp = new SvBaseLinkRef( pLink );
163     pLink->SetLinkManager( this );
164 	aLinkTbl.Insert( pTmp, aLinkTbl.Count() );
165 	if (mAutoAskUpdateAllLinks)
166 	{
167 		Window *parent = NULL;
168 		SfxObjectShell* persist = GetPersist();
169 		if (persist != NULL)
170 			parent = GetPersist()->GetDialogParent();
171 
172 		SetUserAllowsLinkUpdate(pLink, GetUserAllowsLinkUpdate(parent));
173 	}
174 
175 	return sal_True;
176 }
177 
178 
179 sal_Bool LinkManager::InsertLink( SvBaseLink * pLink,
180 								sal_uInt16 nObjType,
181 								sal_uInt16 nUpdateMode,
182 								const String* pName )
183 {
184 	// unbedingt zuerst
185 	pLink->SetObjType( nObjType );
186 	if( pName )
187 		pLink->SetName( *pName );
188 	pLink->SetUpdateMode( nUpdateMode );
189 	return Insert( pLink );
190 }
191 
192 
193 sal_Bool LinkManager::InsertDDELink( SvBaseLink * pLink,
194 									const String& rServer,
195 									const String& rTopic,
196 									const String& rItem )
197 {
198 	if( !( OBJECT_CLIENT_SO & pLink->GetObjType() ) )
199 		return sal_False;
200 
201 	String sCmd;
202 	::sfx2::MakeLnkName( sCmd, &rServer, rTopic, rItem );
203 
204 	pLink->SetObjType( OBJECT_CLIENT_DDE );
205 	pLink->SetName( sCmd );
206 	return Insert( pLink );
207 }
208 
209 
210 sal_Bool LinkManager::InsertDDELink( SvBaseLink * pLink )
211 {
212 	DBG_ASSERT( OBJECT_CLIENT_SO & pLink->GetObjType(), "no OBJECT_CLIENT_SO" );
213 	if( !( OBJECT_CLIENT_SO & pLink->GetObjType() ) )
214 		return sal_False;
215 
216 	if( pLink->GetObjType() == OBJECT_CLIENT_SO )
217 		pLink->SetObjType( OBJECT_CLIENT_DDE );
218 
219 	return Insert( pLink );
220 }
221 
222 
223 // erfrage die Strings fuer den Dialog
224 sal_Bool LinkManager::GetDisplayNames( const SvBaseLink * pLink,
225 										String* pType,
226 										String* pFile,
227 										String* pLinkStr,
228 										String* pFilter ) const
229 {
230 	sal_Bool bRet = sal_False;
231 	const String sLNm( pLink->GetLinkSourceName() );
232 	if( sLNm.Len() )
233 	{
234 		switch( pLink->GetObjType() )
235 		{
236 		    case OBJECT_CLIENT_FILE:
237 		    case OBJECT_CLIENT_GRF:
238 		    case OBJECT_CLIENT_OLE:
239 			    {
240 				    sal_uInt16 nPos = 0;
241 				    String sFile( sLNm.GetToken( 0, ::sfx2::cTokenSeperator, nPos ) );
242 				    String sRange( sLNm.GetToken( 0, ::sfx2::cTokenSeperator, nPos ) );
243 
244 				    if( pFile )
245 					    *pFile = sFile;
246 				    if( pLinkStr )
247 					    *pLinkStr = sRange;
248 				    if( pFilter )
249 					    *pFilter = sLNm.Copy( nPos );
250 
251 				    if( pType )
252 				    {
253 					    sal_uInt16 nObjType = pLink->GetObjType();
254 					    *pType = String( SfxResId(
255 								    ( OBJECT_CLIENT_FILE == nObjType || OBJECT_CLIENT_OLE == nObjType )
256 										    ? RID_SVXSTR_FILELINK
257 										    : RID_SVXSTR_GRAFIKLINK ));
258 				    }
259 				    bRet = sal_True;
260 			    }
261 			    break;
262 		    case OBJECT_CLIENT_DDE:
263 	            {
264 		            sal_uInt16 nTmp = 0;
265 		            String sCmd( sLNm );
266 		            String sServer( sCmd.GetToken( 0, cTokenSeperator, nTmp ) );
267 		            String sTopic( sCmd.GetToken( 0, cTokenSeperator, nTmp ) );
268 
269 		            if( pType )
270 			            *pType = sServer;
271 		            if( pFile )
272 			            *pFile = sTopic;
273 		            if( pLinkStr )
274 			            *pLinkStr = sCmd.Copy( nTmp );
275 		            bRet = sal_True;
276 		        }
277 		        break;
278 	        default:
279 	            break;
280 	    }
281 	}
282 
283 	return bRet;
284 }
285 
286 void LinkManager::SetAutoAskUpdateAllLinks()
287 {
288 	mAutoAskUpdateAllLinks = sal_True;
289     mUpdateAsked = sal_False;
290 }
291 
292 void LinkManager::SetNeverAskUpdateAllLinks()
293 {
294     mAutoAskUpdateAllLinks = sal_False;
295     mAllowUpdate = sal_True;
296     mUpdateAsked = sal_True;
297 }
298 
299 sal_Bool LinkManager::GetUserAllowsLinkUpdate(Window *pParentWin)
300 {
301 	if (!mUpdateAsked)
302 	{
303 		if (QueryBox(pParentWin, WB_YES_NO | WB_DEF_NO, SfxResId(STR_QUERY_UPDATE_LINKS)).Execute() == RET_YES)
304 			mAllowUpdate = sal_True;
305 		else
306 			mAllowUpdate = sal_False;
307 		mUpdateAsked = sal_True;
308 	}
309 	return mAllowUpdate;
310 }
311 
312 void LinkManager::SetUserAllowsLinkUpdate(SvBaseLink *pLink, sal_Bool allows)
313 {
314 	SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
315 
316 	if (pShell)
317 	{
318 		comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = pShell->getEmbeddedObjectContainer();
319 		rEmbeddedObjectContainer.setUserAllowsLinkUpdate(allows);
320 	}
321 }
322 
323 
324 void LinkManager::UpdateAllLinks(
325     sal_Bool bAskUpdate,
326     sal_Bool /*bCallErrHdl*/,
327     sal_Bool bUpdateGrfLinks,
328     Window* pParentWin )
329 {
330 	SvStringsDtor aApps, aTopics, aItems;
331 	String sApp, sTopic, sItem;
332 
333 	// erstmal eine Kopie vom Array machen, damit sich updatende Links in
334 	// Links in ... nicht dazwischen funken!!
335 	SvPtrarr aTmpArr( 255, 50 );
336 	sal_uInt16 n;
337 	for( n = 0; n < aLinkTbl.Count(); ++n )
338 	{
339 		SvBaseLink* pLink = *aLinkTbl[ n ];
340 		if( !pLink )
341 		{
342 			Remove( n-- );
343 			continue;
344 		}
345 		aTmpArr.Insert( pLink, aTmpArr.Count() );
346 	}
347 
348 	for( n = 0; n < aTmpArr.Count(); ++n )
349 	{
350 		SvBaseLink* pLink = (SvBaseLink*)aTmpArr[ n ];
351 
352 		// suche erstmal im Array nach dem Eintrag
353 		sal_uInt16 nFndPos = USHRT_MAX;
354 		for( sal_uInt16 i = 0; i < aLinkTbl.Count(); ++i )
355 			if( pLink == *aLinkTbl[ i ] )
356 			{
357 				nFndPos = i;
358 				break;
359 			}
360 
361 		if( USHRT_MAX == nFndPos )
362 			continue;					// war noch nicht vorhanden!
363 
364 		// do not update graphic links yet
365 		if( !pLink->IsVisible() ||
366 			( !bUpdateGrfLinks && OBJECT_CLIENT_GRF == pLink->GetObjType() ))
367 			continue;
368 
369 		sal_Bool allows = sal_True;
370 
371 		if (bAskUpdate)
372 		{
373 			allows = GetUserAllowsLinkUpdate(pParentWin);
374 		}
375 
376 		SetUserAllowsLinkUpdate(pLink, allows);
377 	    bAskUpdate = sal_False;		// one time is OK
378 
379 		if (allows)
380 			pLink->Update();
381 
382 	}
383 }
384 
385 /************************************************************************
386 |*    SvBaseLink::CreateObject()
387 |*
388 |*    Beschreibung
389 *************************************************************************/
390 
391 SvLinkSourceRef LinkManager::CreateObj( SvBaseLink * pLink )
392 {
393 	switch( pLink->GetObjType() )
394 	{
395 	    case OBJECT_CLIENT_FILE:
396 	    case OBJECT_CLIENT_GRF:
397 	    case OBJECT_CLIENT_OLE:
398 		    return new SvFileObject;
399 	    case OBJECT_INTERN:
400 		    return new SvxInternalLink;
401         case OBJECT_CLIENT_DDE:
402 		    return new SvDDEObject;
403 	    default:
404         	return SvLinkSourceRef();
405    	}
406 }
407 
408 sal_Bool LinkManager::InsertServer( SvLinkSource* pObj )
409 {
410 	// keine doppelt einfuegen
411 	if( !pObj || USHRT_MAX != aServerTbl.GetPos( pObj ) )
412 		return sal_False;
413 
414 	aServerTbl.Insert( pObj, aServerTbl.Count() );
415 	return sal_True;
416 }
417 
418 
419 void LinkManager::RemoveServer( SvLinkSource* pObj )
420 {
421 	sal_uInt16 nPos = aServerTbl.GetPos( pObj );
422 	if( USHRT_MAX != nPos )
423 		aServerTbl.Remove( nPos, 1 );
424 }
425 
426 
427 void MakeLnkName( String& rName, const String* pType, const String& rFile,
428 					const String& rLink, const String* pFilter )
429 {
430 	if( pType )
431 		(rName = *pType).EraseLeadingChars().EraseTrailingChars() += cTokenSeperator;
432 	else if( rName.Len() )
433 		rName.Erase();
434 
435 	((rName += rFile).EraseLeadingChars().EraseTrailingChars() +=
436 		cTokenSeperator ).EraseLeadingChars().EraseTrailingChars() += rLink;
437 	if( pFilter )
438 		((rName += cTokenSeperator ) += *pFilter).EraseLeadingChars().EraseTrailingChars();
439 }
440 
441 sal_Bool LinkManager::InsertFileLink( sfx2::SvBaseLink& rLink,
442 									sal_uInt16 nFileType,
443 									const String& rFileNm,
444 									const String* pFilterNm,
445 									const String* pRange )
446 {
447 	if( !( OBJECT_CLIENT_SO & rLink.GetObjType() ))
448 		return sal_False;
449 
450 	String sCmd( rFileNm );
451 	sCmd += ::sfx2::cTokenSeperator;
452 	if( pRange )
453 		sCmd += *pRange;
454 	if( pFilterNm )
455 		( sCmd += ::sfx2::cTokenSeperator ) += *pFilterNm;
456 
457 	return InsertLink( &rLink, nFileType, sfx2::LINKUPDATE_ONCALL, &sCmd );
458 }
459 
460 sal_Bool LinkManager::InsertFileLink( sfx2::SvBaseLink& rLink )
461 {
462 	if( OBJECT_CLIENT_FILE == ( OBJECT_CLIENT_FILE & rLink.GetObjType() ))
463 		return InsertLink( &rLink, rLink.GetObjType(), sfx2::LINKUPDATE_ONCALL );
464 	return sal_False;
465 }
466 
467 // eine Uebertragung wird abgebrochen, also alle DownloadMedien canceln
468 // (ist zur Zeit nur fuer die FileLinks interressant!)
469 void LinkManager::CancelTransfers()
470 {
471 	SvFileObject* pFileObj;
472 	sfx2::SvBaseLink* pLnk;
473 
474 	const sfx2::SvBaseLinks& rLnks = GetLinks();
475 	for( sal_uInt16 n = rLnks.Count(); n; )
476 		if( 0 != ( pLnk = &(*rLnks[ --n ])) &&
477 			OBJECT_CLIENT_FILE == (OBJECT_CLIENT_FILE & pLnk->GetObjType()) &&
478 			0 != ( pFileObj = (SvFileObject*)pLnk->GetObj() ) )
479 //			0 != ( pFileObj = (SvFileObject*)SvFileObject::ClassFactory()->
480 //									CastAndAddRef( pLnk->GetObj() )) )
481 			pFileObj->CancelTransfers();
482 }
483 
484 	// um Status Informationen aus dem FileObject an den BaseLink zu
485 	// senden, gibt es eine eigene ClipBoardId. Das SvData-Object hat
486 	// dann die entsprechenden Informationen als String.
487 	// Wird zur Zeit fuer FileObject in Verbindung mit JavaScript benoetigt
488 	// - das braucht Informationen ueber Load/Abort/Error
489 sal_uIntPtr LinkManager::RegisterStatusInfoId()
490 {
491 	static sal_uIntPtr nFormat = 0;
492 
493 	if( !nFormat )
494 	{
495 // wie sieht die neue Schnittstelle aus?
496 //		nFormat = Exchange::RegisterFormatName( "StatusInfo vom SvxInternalLink" );
497 		nFormat = SotExchange::RegisterFormatName(
498 					String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM(
499 								"StatusInfo vom SvxInternalLink" )));
500 	}
501 	return nFormat;
502 }
503 
504 // ----------------------------------------------------------------------
505 
506 sal_Bool LinkManager::GetGraphicFromAny( const String& rMimeType,
507 								const ::com::sun::star::uno::Any & rValue,
508 								Graphic& rGrf )
509 {
510 	sal_Bool bRet = sal_False;
511 	::com::sun::star::uno::Sequence< sal_Int8 > aSeq;
512 	if( rValue.hasValue() && ( rValue >>= aSeq ) )
513 	{
514 		SvMemoryStream aMemStm( (void*)aSeq.getConstArray(), aSeq.getLength(),
515 								STREAM_READ );
516 		aMemStm.Seek( 0 );
517 
518 		switch( SotExchange::GetFormatIdFromMimeType( rMimeType ) )
519 		{
520 		case SOT_FORMATSTR_ID_SVXB:
521 			{
522 				aMemStm >> rGrf;
523 				bRet = sal_True;
524 			}
525 			break;
526 		case FORMAT_GDIMETAFILE:
527 			{
528 				GDIMetaFile aMtf;
529 				aMtf.Read( aMemStm );
530 				rGrf = aMtf;
531 				bRet = sal_True;
532 			}
533 			break;
534 		case FORMAT_BITMAP:
535 			{
536 				Bitmap aBmp;
537                 ReadDIB(aBmp, aMemStm, true);
538 				rGrf = aBmp;
539 				bRet = sal_True;
540 			}
541 			break;
542 		}
543 	}
544 	return bRet;
545 }
546 
547 sal_Bool LinkManager::urlIsSafe( const ::rtl::OUString &url )
548 {
549 	if ( url.getLength() == 0 ) {
550 		return sal_False;
551 	}
552 	if ( !xURLTransformer.is() ) {
553 		const com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > xContext ( ::comphelper::getProcessComponentContext() );
554 		com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiComponentFactory > xFactory ( xContext->getServiceManager(), ::com::sun::star::uno::UNO_QUERY );
555 		if ( !xFactory.is() ) {
556 			return sal_False;
557 		}
558 		xURLTransformer.set( xFactory->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.util.URLTransformer" ), xContext), com::sun::star::uno::UNO_QUERY );
559 		if ( !xURLTransformer.is() ) {
560 			return sal_False;
561 		}
562 	}
563 	com::sun::star::util::URL aURL;
564 	aURL.Complete = url;
565 	sal_Bool b = xURLTransformer->parseSmart( aURL, ::rtl::OUString() );
566 	if ( !b ) {
567 		return sal_False;
568 	}
569 	return urlIsSafe( aURL );
570 }
571 
572 sal_Bool LinkManager::urlIsSafe( const ::com::sun::star::util::URL &url )
573 {
574 	sal_Bool result = ( url.Path.getLength() == 0 ) &&
575 		( url.Server.getLength() == 0);
576 	return result;
577 }
578 
579 
580 sal_Bool LinkManager::urlIsVendor( const ::rtl::OUString &url )
581 {
582 	if ( url.matchIgnoreAsciiCaseAsciiL( "vnd.sun.star.", 13, 0 ) ) {
583 		return url.matchIgnoreAsciiCaseAsciiL ( "expand", 6, 13 ) ||
584 			url.matchIgnoreAsciiCaseAsciiL ( "script", 6, 13 ) ||
585 			url.matchIgnoreAsciiCaseAsciiL ( "tdoc", 4, 13 ) ||
586 			url.matchIgnoreAsciiCaseAsciiL ( "uno", 3, 13 );
587 	}
588 	return sal_False;
589 }
590 
591 
592 // ----------------------------------------------------------------------
593 String lcl_DDE_RelToAbs( const String& rTopic, const String& rBaseURL )
594 {
595 	String sRet;
596 	INetURLObject aURL( rTopic );
597 	if( INET_PROT_NOT_VALID == aURL.GetProtocol() )
598         utl::LocalFileHelper::ConvertSystemPathToURL( rTopic, rBaseURL, sRet );
599 	if( !sRet.Len() )
600         sRet = URIHelper::SmartRel2Abs( INetURLObject(rBaseURL), rTopic, URIHelper::GetMaybeFileHdl(), true );
601 	return sRet;
602 }
603 
604 sal_Bool SvxInternalLink::Connect( sfx2::SvBaseLink* pLink )
605 {
606 	SfxObjectShell* pFndShell = 0;
607 	sal_uInt16 nUpdateMode = com::sun::star::document::UpdateDocMode::NO_UPDATE;
608 	String sTopic, sItem, sReferer;
609 	if( pLink->GetLinkManager() &&
610 		pLink->GetLinkManager()->GetDisplayNames( pLink, 0, &sTopic, &sItem )
611 		&& sTopic.Len() )
612 	{
613 		// erstmal nur ueber die DocumentShells laufen und die mit dem
614 		// Namen heraussuchen:
615 
616 	    com::sun::star::lang::Locale aLocale;
617 	    MsLangId::convertLanguageToLocale( LANGUAGE_SYSTEM, aLocale );
618 		CharClass aCC( aLocale );
619 
620         String sNm( sTopic ), sTmp;
621 		aCC.toLower( sNm );
622 
623 		TypeId aType( TYPE(SfxObjectShell) );
624 
625 		sal_Bool bFirst = sal_True;
626         SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
627         if( pShell && pShell->GetMedium() )
628 		{
629             sReferer = pShell->GetMedium()->GetBaseURL();
630 			SFX_ITEMSET_ARG( pShell->GetMedium()->GetItemSet(), pItem, SfxUInt16Item, SID_UPDATEDOCMODE, sal_False );
631 			if ( pItem )
632 				nUpdateMode = pItem->GetValue();
633 		}
634 
635         String sNmURL( lcl_DDE_RelToAbs( sTopic, sReferer ) );
636 		aCC.toLower( sNmURL );
637 
638 		if ( !pShell )
639 		{
640 			bFirst = sal_False;
641             pShell = SfxObjectShell::GetFirst( &aType, sal_False );
642 		}
643 
644 		while( pShell )
645 		{
646 			if( !sTmp.Len() )
647 			{
648 				sTmp = pShell->GetTitle( SFX_TITLE_FULLNAME );
649                 sTmp = lcl_DDE_RelToAbs(sTmp, sReferer );
650 			}
651 
652 
653 			aCC.toLower( sTmp );
654 			if( sTmp == sNmURL )		// die wollen wir haben
655 			{
656 				pFndShell = pShell;
657 				break;
658 			}
659 
660 			if( bFirst )
661 			{
662 				bFirst = sal_False;
663                 pShell = SfxObjectShell::GetFirst( &aType, sal_False );
664 			}
665 			else
666                 pShell = SfxObjectShell::GetNext( *pShell, &aType, sal_False );
667 
668 			sTmp.Erase();
669 		}
670 	}
671 
672 	// empty topics are not allowed - which document is it
673 	if( !sTopic.Len() )
674 		return sal_False;
675 
676 	if( !pFndShell )
677 	{
678 		// dann versuche die Datei zu laden:
679 		INetURLObject aURL( sTopic );
680 		INetProtocol eOld = aURL.GetProtocol();
681         aURL.SetURL( sTopic = lcl_DDE_RelToAbs( sTopic, sReferer ) );
682 		if( INET_PROT_NOT_VALID != eOld ||
683 			INET_PROT_HTTP != aURL.GetProtocol() )
684 		{
685 			SfxStringItem aName( SID_FILE_NAME, sTopic );
686             SfxBoolItem aMinimized(SID_MINIMIZED, sal_True);
687             SfxBoolItem aHidden(SID_HIDDEN, sal_True);
688             SfxStringItem aTarget( SID_TARGETNAME, String::CreateFromAscii("_blank") );
689 			SfxStringItem aReferer( SID_REFERER, sReferer );
690 			SfxUInt16Item aUpdate( SID_UPDATEDOCMODE, nUpdateMode );
691             SfxBoolItem aReadOnly(SID_DOC_READONLY, sal_True);
692 
693             // #i14200# (DDE-link crashes wordprocessor)
694             SfxAllItemSet aArgs( SFX_APP()->GetPool() );
695             aArgs.Put(aReferer);
696             aArgs.Put(aTarget);
697             aArgs.Put(aHidden);
698             aArgs.Put(aMinimized);
699             aArgs.Put(aName);
700 			aArgs.Put(aUpdate);
701 			aArgs.Put(aReadOnly);
702             pFndShell = SfxObjectShell::CreateAndLoadObject( aArgs );
703 		}
704 	}
705 
706 	sal_Bool bRet = sal_False;
707 	if( pFndShell )
708 	{
709 		sfx2::SvLinkSource* pNewSrc = pFndShell->DdeCreateLinkSource( sItem );
710 		if( pNewSrc )
711 		{
712 			bRet = sal_True;
713 
714 			::com::sun::star::datatransfer::DataFlavor aFl;
715 			SotExchange::GetFormatDataFlavor( pLink->GetContentType(), aFl );
716 
717 			pLink->SetObj( pNewSrc );
718 			pNewSrc->AddDataAdvise( pLink, aFl.MimeType,
719 								sfx2::LINKUPDATE_ONCALL == pLink->GetUpdateMode()
720 									? ADVISEMODE_ONLYONCE
721 									: 0 );
722 		}
723 	}
724 	return bRet;
725 }
726 
727 
728 }
729 
730 
731 
732