xref: /trunk/main/sfx2/source/appl/linkmgr2.cxx (revision ffd38472365e95f6a578737bc9a5eb0fac624a86)
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 |*    Description
97 *************************************************************************/
98 
99 void LinkManager::Remove( SvBaseLink *pLink )
100 {
101     // do not insert links double
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         // if there are still some empty ones, get rid of them
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 
152     // do not insert links double
153     for( sal_uInt16 n = 0; n < aLinkTbl.Count(); ++n )
154     {
155         SvBaseLinkRef* pTmp = aLinkTbl[ n ];
156         if( !pTmp->Is() )
157             aLinkTbl.DeleteAndDestroy( n-- );
158 
159         if( pLink == *pTmp )
160             return sal_False;
161     }
162 
163     SvBaseLinkRef* pTmp = new SvBaseLinkRef( pLink );
164     pLink->SetLinkManager( this );
165     aLinkTbl.Insert( pTmp, aLinkTbl.Count() );
166     if (mAutoAskUpdateAllLinks)
167     {
168         Window *parent = NULL;
169         SfxObjectShell* persist = GetPersist();
170         if (persist != NULL)
171             parent = GetPersist()->GetDialogParent();
172 
173         SetUserAllowsLinkUpdate(pLink, GetUserAllowsLinkUpdate(parent));
174     }
175 
176     return sal_True;
177 }
178 
179 
180 sal_Bool LinkManager::InsertLink( SvBaseLink * pLink,
181                                 sal_uInt16 nObjType,
182                                 sal_uInt16 nUpdateMode,
183                                 const String* pName )
184 {
185     // in any case: do this first
186     pLink->SetObjType( nObjType );
187     if( pName )
188         pLink->SetName( *pName );
189     pLink->SetUpdateMode( nUpdateMode );
190     return Insert( pLink );
191 }
192 
193 
194 sal_Bool LinkManager::InsertDDELink( SvBaseLink * pLink,
195                                     const String& rServer,
196                                     const String& rTopic,
197                                     const String& rItem )
198 {
199     if( !( OBJECT_CLIENT_SO & pLink->GetObjType() ) )
200         return sal_False;
201 
202     String sCmd;
203     ::sfx2::MakeLnkName( sCmd, &rServer, rTopic, rItem );
204 
205     pLink->SetObjType( OBJECT_CLIENT_DDE );
206     pLink->SetName( sCmd );
207     return Insert( pLink );
208 }
209 
210 
211 sal_Bool LinkManager::InsertDDELink( SvBaseLink * pLink )
212 {
213     DBG_ASSERT( OBJECT_CLIENT_SO & pLink->GetObjType(), "no OBJECT_CLIENT_SO" );
214     if( !( OBJECT_CLIENT_SO & pLink->GetObjType() ) )
215         return sal_False;
216 
217     if( pLink->GetObjType() == OBJECT_CLIENT_SO )
218         pLink->SetObjType( OBJECT_CLIENT_DDE );
219 
220     return Insert( pLink );
221 }
222 
223 
224 // ask for the strings to be used in the dialog
225 sal_Bool LinkManager::GetDisplayNames( const SvBaseLink * pLink,
226                                         String* pType,
227                                         String* pFile,
228                                         String* pLinkStr,
229                                         String* pFilter ) const
230 {
231     sal_Bool bRet = sal_False;
232     const String sLNm( pLink->GetLinkSourceName() );
233     if( sLNm.Len() )
234     {
235         switch( pLink->GetObjType() )
236         {
237             case OBJECT_CLIENT_FILE:
238             case OBJECT_CLIENT_GRF:
239             case OBJECT_CLIENT_OLE:
240                 {
241                     sal_uInt16 nPos = 0;
242                     String sFile( sLNm.GetToken( 0, ::sfx2::cTokenSeperator, nPos ) );
243                     String sRange( sLNm.GetToken( 0, ::sfx2::cTokenSeperator, nPos ) );
244 
245                     if( pFile )
246                         *pFile = sFile;
247                     if( pLinkStr )
248                         *pLinkStr = sRange;
249                     if( pFilter )
250                         *pFilter = sLNm.Copy( nPos );
251 
252                     if( pType )
253                     {
254                         sal_uInt16 nObjType = pLink->GetObjType();
255                         *pType = String( SfxResId(
256                                     ( OBJECT_CLIENT_FILE == nObjType || OBJECT_CLIENT_OLE == nObjType )
257                                             ? RID_SVXSTR_FILELINK
258                                             : RID_SVXSTR_GRAFIKLINK ));
259                     }
260                     bRet = sal_True;
261                 }
262                 break;
263             case OBJECT_CLIENT_DDE:
264                 {
265                     sal_uInt16 nTmp = 0;
266                     String sCmd( sLNm );
267                     String sServer( sCmd.GetToken( 0, cTokenSeperator, nTmp ) );
268                     String sTopic( sCmd.GetToken( 0, cTokenSeperator, nTmp ) );
269 
270                     if( pType )
271                         *pType = sServer;
272                     if( pFile )
273                         *pFile = sTopic;
274                     if( pLinkStr )
275                         *pLinkStr = sCmd.Copy( nTmp );
276                     bRet = sal_True;
277                 }
278                 break;
279             default:
280                 break;
281         }
282     }
283 
284     return bRet;
285 }
286 
287 void LinkManager::SetAutoAskUpdateAllLinks()
288 {
289     mAutoAskUpdateAllLinks = sal_True;
290     mUpdateAsked = sal_False;
291 }
292 
293 void LinkManager::SetNeverAskUpdateAllLinks()
294 {
295     mAutoAskUpdateAllLinks = sal_False;
296     mAllowUpdate = sal_True;
297     mUpdateAsked = sal_True;
298 }
299 
300 sal_Bool LinkManager::GetUserAllowsLinkUpdate(Window *pParentWin)
301 {
302     if (!mUpdateAsked)
303     {
304         if (QueryBox(pParentWin, WB_YES_NO | WB_DEF_NO, SfxResId(STR_QUERY_UPDATE_LINKS)).Execute() == RET_YES)
305             mAllowUpdate = sal_True;
306         else
307             mAllowUpdate = sal_False;
308         mUpdateAsked = sal_True;
309     }
310     return mAllowUpdate;
311 }
312 
313 void LinkManager::SetUserAllowsLinkUpdate(SvBaseLink *pLink, sal_Bool allows)
314 {
315     SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
316 
317     if (pShell)
318     {
319         comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = pShell->getEmbeddedObjectContainer();
320         rEmbeddedObjectContainer.setUserAllowsLinkUpdate(allows);
321     }
322 }
323 
324 
325 void LinkManager::UpdateAllLinks(
326     sal_Bool bAskUpdate,
327     sal_Bool /*bCallErrHdl*/,
328     sal_Bool bUpdateGrfLinks,
329     Window* pParentWin )
330 {
331     SvStringsDtor aApps, aTopics, aItems;
332     String sApp, sTopic, sItem;
333 
334     // first create a copy of the array, so that updated links to not interfere with ... in between!!
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         // first search the entry in the array
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;                   // was not already existing!
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 |*    SvBaseLink::CreateObject()
386 |*
387 |*    Description
388 *************************************************************************/
389 
390 SvLinkSourceRef LinkManager::CreateObj( SvBaseLink * pLink )
391 {
392     switch( pLink->GetObjType() )
393     {
394         case OBJECT_CLIENT_FILE:
395         case OBJECT_CLIENT_GRF:
396         case OBJECT_CLIENT_OLE:
397             return new SvFileObject;
398         case OBJECT_INTERN:
399             return new SvxInternalLink;
400         case OBJECT_CLIENT_DDE:
401             return new SvDDEObject;
402         default:
403             return SvLinkSourceRef();
404     }
405 }
406 
407 sal_Bool LinkManager::InsertServer( SvLinkSource* pObj )
408 {
409     // do not insert double
410     if( !pObj || USHRT_MAX != aServerTbl.GetPos( pObj ) )
411         return sal_False;
412 
413     aServerTbl.Insert( pObj, aServerTbl.Count() );
414     return sal_True;
415 }
416 
417 
418 void LinkManager::RemoveServer( SvLinkSource* pObj )
419 {
420     sal_uInt16 nPos = aServerTbl.GetPos( pObj );
421     if( USHRT_MAX != nPos )
422         aServerTbl.Remove( nPos, 1 );
423 }
424 
425 
426 void MakeLnkName( String& rName, const String* pType, const String& rFile,
427                     const String& rLink, const String* pFilter )
428 {
429     if( pType )
430         (rName = *pType).EraseLeadingChars().EraseTrailingChars() += cTokenSeperator;
431     else if( rName.Len() )
432         rName.Erase();
433 
434     ((rName += rFile).EraseLeadingChars().EraseTrailingChars() +=
435         cTokenSeperator ).EraseLeadingChars().EraseTrailingChars() += rLink;
436     if( pFilter )
437         ((rName += cTokenSeperator ) += *pFilter).EraseLeadingChars().EraseTrailingChars();
438 }
439 
440 sal_Bool LinkManager::InsertFileLink( sfx2::SvBaseLink& rLink,
441                                     sal_uInt16 nFileType,
442                                     const String& rFileNm,
443                                     const String* pFilterNm,
444                                     const String* pRange )
445 {
446     if( !( OBJECT_CLIENT_SO & rLink.GetObjType() ))
447         return sal_False;
448 
449     String sCmd( rFileNm );
450     sCmd += ::sfx2::cTokenSeperator;
451     if( pRange )
452         sCmd += *pRange;
453     if( pFilterNm )
454         ( sCmd += ::sfx2::cTokenSeperator ) += *pFilterNm;
455 
456     return InsertLink( &rLink, nFileType, sfx2::LINKUPDATE_ONCALL, &sCmd );
457 }
458 
459 sal_Bool LinkManager::InsertFileLink( sfx2::SvBaseLink& rLink )
460 {
461     if( OBJECT_CLIENT_FILE == ( OBJECT_CLIENT_FILE & rLink.GetObjType() ))
462         return InsertLink( &rLink, rLink.GetObjType(), sfx2::LINKUPDATE_ONCALL );
463     return sal_False;
464 }
465 
466 // a transfer will be discontinued, therefore cancel all DownloadMedia
467 // (at the moment only interesting for the FileLinks!)
468 void LinkManager::CancelTransfers()
469 {
470     SvFileObject* pFileObj;
471     sfx2::SvBaseLink* pLnk;
472 
473     const sfx2::SvBaseLinks& rLnks = GetLinks();
474     for( sal_uInt16 n = rLnks.Count(); n; )
475         if( 0 != ( pLnk = &(*rLnks[ --n ])) &&
476             OBJECT_CLIENT_FILE == (OBJECT_CLIENT_FILE & pLnk->GetObjType()) &&
477             0 != ( pFileObj = (SvFileObject*)pLnk->GetObj() ) )
478 //          0 != ( pFileObj = (SvFileObject*)SvFileObject::ClassFactory()->
479 //                                  CastAndAddRef( pLnk->GetObj() )) )
480             pFileObj->CancelTransfers();
481 }
482 
483     // to send status information from the FileObject to the BaseLink, there is an own ClipboardId.
484     // The SvData object has then the respective information as string.
485     // Currently this will be used for FileObject in connection with JavaScript
486     // - that needs information about Load/Abort/Error
487 sal_uIntPtr LinkManager::RegisterStatusInfoId()
488 {
489     static sal_uIntPtr nFormat = 0;
490 
491     if( !nFormat )
492     {
493 // how does the new interface look like?
494 //      nFormat = Exchange::RegisterFormatName( "StatusInfo vom SvxInternalLink" );
495         nFormat = SotExchange::RegisterFormatName(
496                     String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM(
497                                 "StatusInfo vom SvxInternalLink" )));
498     }
499     return nFormat;
500 }
501 
502 // ----------------------------------------------------------------------
503 
504 sal_Bool LinkManager::GetGraphicFromAny( const String& rMimeType,
505                                 const ::com::sun::star::uno::Any & rValue,
506                                 Graphic& rGrf )
507 {
508     sal_Bool bRet = sal_False;
509     ::com::sun::star::uno::Sequence< sal_Int8 > aSeq;
510     if( rValue.hasValue() && ( rValue >>= aSeq ) )
511     {
512         SvMemoryStream aMemStm( (void*)aSeq.getConstArray(), aSeq.getLength(),
513                                 STREAM_READ );
514         aMemStm.Seek( 0 );
515 
516         switch( SotExchange::GetFormatIdFromMimeType( rMimeType ) )
517         {
518         case SOT_FORMATSTR_ID_SVXB:
519             {
520                 aMemStm >> rGrf;
521                 bRet = sal_True;
522             }
523             break;
524         case FORMAT_GDIMETAFILE:
525             {
526                 GDIMetaFile aMtf;
527                 aMtf.Read( aMemStm );
528                 rGrf = aMtf;
529                 bRet = sal_True;
530             }
531             break;
532         case FORMAT_BITMAP:
533             {
534                 Bitmap aBmp;
535                 ReadDIB(aBmp, aMemStm, true);
536                 rGrf = aBmp;
537                 bRet = sal_True;
538             }
539             break;
540         }
541     }
542     return bRet;
543 }
544 
545 sal_Bool LinkManager::urlIsSafe( const ::rtl::OUString &url )
546 {
547     if ( url.getLength() == 0 ) {
548         return sal_False;
549     }
550     if ( !xURLTransformer.is() ) {
551         const com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > xContext ( ::comphelper::getProcessComponentContext() );
552         com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiComponentFactory > xFactory ( xContext->getServiceManager(), ::com::sun::star::uno::UNO_QUERY );
553         if ( !xFactory.is() ) {
554             return sal_False;
555         }
556         xURLTransformer.set( xFactory->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.util.URLTransformer" ), xContext), com::sun::star::uno::UNO_QUERY );
557         if ( !xURLTransformer.is() ) {
558             return sal_False;
559         }
560     }
561     com::sun::star::util::URL aURL;
562     aURL.Complete = url;
563     sal_Bool b = xURLTransformer->parseSmart( aURL, ::rtl::OUString() );
564     if ( !b ) {
565         return sal_False;
566     }
567     return urlIsSafe( aURL );
568 }
569 
570 sal_Bool LinkManager::urlIsSafe( const ::com::sun::star::util::URL &url )
571 {
572     sal_Bool result = ( url.Path.getLength() == 0 ) &&
573         ( url.Server.getLength() == 0);
574     return result;
575 }
576 
577 
578 sal_Bool LinkManager::urlIsVendor( const ::rtl::OUString &url )
579 {
580     if ( url.matchIgnoreAsciiCaseAsciiL( "vnd.sun.star.", 13, 0 ) ) {
581         return url.matchIgnoreAsciiCaseAsciiL ( "expand", 6, 13 ) ||
582             url.matchIgnoreAsciiCaseAsciiL ( "script", 6, 13 ) ||
583             url.matchIgnoreAsciiCaseAsciiL ( "tdoc", 4, 13 ) ||
584             url.matchIgnoreAsciiCaseAsciiL ( "uno", 3, 13 );
585     }
586     return sal_False;
587 }
588 
589 
590 // ----------------------------------------------------------------------
591 String lcl_DDE_RelToAbs( const String& rTopic, const String& rBaseURL )
592 {
593     String sRet;
594     INetURLObject aURL( rTopic );
595     if( INET_PROT_NOT_VALID == aURL.GetProtocol() )
596         utl::LocalFileHelper::ConvertSystemPathToURL( rTopic, rBaseURL, sRet );
597     if( !sRet.Len() )
598         sRet = URIHelper::SmartRel2Abs( INetURLObject(rBaseURL), rTopic, URIHelper::GetMaybeFileHdl(), true );
599     return sRet;
600 }
601 
602 sal_Bool SvxInternalLink::Connect( sfx2::SvBaseLink* pLink )
603 {
604     SfxObjectShell* pFndShell = 0;
605     sal_uInt16 nUpdateMode = com::sun::star::document::UpdateDocMode::NO_UPDATE;
606     String sTopic, sItem, sReferer;
607     if( pLink->GetLinkManager() &&
608         pLink->GetLinkManager()->GetDisplayNames( pLink, 0, &sTopic, &sItem )
609         && sTopic.Len() )
610     {
611         // for the moment run through the DocumentShells and search for the ones with names:
612 
613         com::sun::star::lang::Locale aLocale;
614         MsLangId::convertLanguageToLocale( LANGUAGE_SYSTEM, aLocale );
615         CharClass aCC( aLocale );
616 
617         String sNm( sTopic ), sTmp;
618         aCC.toLower( sNm );
619 
620         TypeId aType( TYPE(SfxObjectShell) );
621 
622         sal_Bool bFirst = sal_True;
623         SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
624         if( pShell && pShell->GetMedium() )
625         {
626             sReferer = pShell->GetMedium()->GetBaseURL();
627             SFX_ITEMSET_ARG( pShell->GetMedium()->GetItemSet(), pItem, SfxUInt16Item, SID_UPDATEDOCMODE, sal_False );
628             if ( pItem )
629                 nUpdateMode = pItem->GetValue();
630         }
631 
632         String sNmURL( lcl_DDE_RelToAbs( sTopic, sReferer ) );
633         aCC.toLower( sNmURL );
634 
635         if ( !pShell )
636         {
637             bFirst = sal_False;
638             pShell = SfxObjectShell::GetFirst( &aType, sal_False );
639         }
640 
641         while( pShell )
642         {
643             if( !sTmp.Len() )
644             {
645                 sTmp = pShell->GetTitle( SFX_TITLE_FULLNAME );
646                 sTmp = lcl_DDE_RelToAbs(sTmp, sReferer );
647             }
648 
649 
650             aCC.toLower( sTmp );
651             if( sTmp == sNmURL )        // these we want to have
652             {
653                 pFndShell = pShell;
654                 break;
655             }
656 
657             if( bFirst )
658             {
659                 bFirst = sal_False;
660                 pShell = SfxObjectShell::GetFirst( &aType, sal_False );
661             }
662             else
663                 pShell = SfxObjectShell::GetNext( *pShell, &aType, sal_False );
664 
665             sTmp.Erase();
666         }
667     }
668 
669     // empty topics are not allowed - which document is it
670     if( !sTopic.Len() )
671         return sal_False;
672 
673     if( !pFndShell )
674     {
675         // try to load the file:
676         INetURLObject aURL( sTopic );
677         INetProtocol eOld = aURL.GetProtocol();
678         aURL.SetURL( sTopic = lcl_DDE_RelToAbs( sTopic, sReferer ) );
679         if( INET_PROT_NOT_VALID != eOld ||
680             INET_PROT_HTTP != aURL.GetProtocol() )
681         {
682             SfxStringItem aName( SID_FILE_NAME, sTopic );
683             SfxBoolItem aMinimized(SID_MINIMIZED, sal_True);
684             SfxBoolItem aHidden(SID_HIDDEN, sal_True);
685             SfxStringItem aTarget( SID_TARGETNAME, String::CreateFromAscii("_blank") );
686             SfxStringItem aReferer( SID_REFERER, sReferer );
687             SfxUInt16Item aUpdate( SID_UPDATEDOCMODE, nUpdateMode );
688             SfxBoolItem aReadOnly(SID_DOC_READONLY, sal_True);
689 
690             // #i14200# (DDE-link crashes wordprocessor)
691             SfxAllItemSet aArgs( SFX_APP()->GetPool() );
692             aArgs.Put(aReferer);
693             aArgs.Put(aTarget);
694             aArgs.Put(aHidden);
695             aArgs.Put(aMinimized);
696             aArgs.Put(aName);
697             aArgs.Put(aUpdate);
698             aArgs.Put(aReadOnly);
699             pFndShell = SfxObjectShell::CreateAndLoadObject( aArgs );
700         }
701     }
702 
703     sal_Bool bRet = sal_False;
704     if( pFndShell )
705     {
706         sfx2::SvLinkSource* pNewSrc = pFndShell->DdeCreateLinkSource( sItem );
707         if( pNewSrc )
708         {
709             bRet = sal_True;
710 
711             ::com::sun::star::datatransfer::DataFlavor aFl;
712             SotExchange::GetFormatDataFlavor( pLink->GetContentType(), aFl );
713 
714             pLink->SetObj( pNewSrc );
715             pNewSrc->AddDataAdvise( pLink, aFl.MimeType,
716                                 sfx2::LINKUPDATE_ONCALL == pLink->GetUpdateMode()
717                                     ? ADVISEMODE_ONLYONCE
718                                     : 0 );
719         }
720     }
721     return bRet;
722 }
723 
724 
725 }
726