xref: /trunk/main/sfx2/source/appl/linkmgr2.cxx (revision 137931e43899a1545869cb6af6ea936d8cee4956)
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 <svtools/linkpolicy.hxx>
45 #include <comphelper/processfactory.hxx>
46 #include <i18npool/mslangid.hxx>
47 #include <sfx2/request.hxx>
48 #include <vcl/dibtools.hxx>
49 
50 #include "fileobj.hxx"
51 #include "impldde.hxx"
52 #include "app.hrc"
53 #include "sfx2/sfxresid.hxx"
54 
55 #define _SVSTDARR_STRINGSDTOR
56 #include <svl/svstdarr.hxx>
57 
58 namespace sfx2
59 {
60 
61 class SvxInternalLink : public sfx2::SvLinkSource
62 {
63 public:
SvxInternalLink()64     SvxInternalLink() {}
65 
66     virtual sal_Bool Connect( sfx2::SvBaseLink* );
67 };
68 
69 
SV_IMPL_PTRARR(SvBaseLinks,SvBaseLinkRefPtr)70 SV_IMPL_PTRARR( SvBaseLinks, SvBaseLinkRefPtr )
71 
72 LinkManager::LinkManager(SfxObjectShell* p)
73     : pPersist(p),
74     mAutoAskUpdateAllLinks(sal_False),
75     mUpdateAsked(sal_False)
76 {
77 }
78 
~LinkManager()79 LinkManager::~LinkManager()
80 {
81     SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData();
82     for( sal_uInt16 n = aLinkTbl.Count(); n; --n, ++ppRef )
83     {
84         if( (*ppRef)->Is() )
85         {
86             (*(*ppRef))->Disconnect();
87             (*(*ppRef))->SetLinkManager( NULL );
88         }
89         delete *ppRef;
90     }
91 }
92 
93 
94 /************************************************************************
95 |*    LinkManager::Remove()
96 |*
97 |*    Description
98 *************************************************************************/
99 
Remove(SvBaseLink * pLink)100 void LinkManager::Remove( SvBaseLink *pLink )
101 {
102     // do not insert links double
103     int bFound = sal_False;
104     SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData();
105     for( sal_uInt16 n = aLinkTbl.Count(); n; --n, ++ppRef )
106     {
107         if( pLink == *(*ppRef) )
108         {
109             (*(*ppRef))->Disconnect();
110             (*(*ppRef))->SetLinkManager( NULL );
111             (*(*ppRef)).Clear();
112             bFound = sal_True;
113         }
114 
115         // if there are still some empty ones, get rid of them
116         if( !(*ppRef)->Is() )
117         {
118             delete *ppRef;
119             aLinkTbl.Remove( aLinkTbl.Count() - n, 1 );
120             if( bFound )
121                 return ;
122             --ppRef;
123         }
124     }
125 }
126 
127 
Remove(sal_uInt16 nPos,sal_uInt16 nCnt)128 void LinkManager::Remove( sal_uInt16 nPos, sal_uInt16 nCnt )
129 {
130     if( nCnt && nPos < aLinkTbl.Count() )
131     {
132         if( nPos + nCnt > aLinkTbl.Count() )
133             nCnt = aLinkTbl.Count() - nPos;
134 
135         SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData() + nPos;
136         for( sal_uInt16 n = nCnt; n; --n, ++ppRef )
137         {
138             if( (*ppRef)->Is() )
139             {
140                 (*(*ppRef))->Disconnect();
141                 (*(*ppRef))->SetLinkManager( NULL );
142             }
143             delete *ppRef;
144         }
145         aLinkTbl.Remove( nPos, nCnt );
146     }
147 }
148 
149 
Insert(SvBaseLink * pLink)150 sal_Bool LinkManager::Insert( SvBaseLink* pLink )
151 {
152 
153     // do not insert links double
154     for( sal_uInt16 n = 0; n < aLinkTbl.Count(); ++n )
155     {
156         SvBaseLinkRef* pTmp = aLinkTbl[ n ];
157         if( !pTmp->Is() )
158             aLinkTbl.DeleteAndDestroy( n-- );
159 
160         if( pLink == *pTmp )
161             return sal_False;
162     }
163 
164     SvBaseLinkRef* pTmp = new SvBaseLinkRef( pLink );
165     pLink->SetLinkManager( this );
166     aLinkTbl.Insert( pTmp, aLinkTbl.Count() );
167     if (mAutoAskUpdateAllLinks)
168     {
169         Window *parent = NULL;
170         SfxObjectShell* persist = GetPersist();
171         if (persist != NULL)
172             parent = GetPersist()->GetDialogParent();
173 
174         SetUserAllowsLinkUpdate(pLink, GetUserAllowsLinkUpdate(parent));
175     }
176 
177     return sal_True;
178 }
179 
180 
InsertLink(SvBaseLink * pLink,sal_uInt16 nObjType,sal_uInt16 nUpdateMode,const String * pName)181 sal_Bool LinkManager::InsertLink( SvBaseLink * pLink,
182                                 sal_uInt16 nObjType,
183                                 sal_uInt16 nUpdateMode,
184                                 const String* pName )
185 {
186     // in any case: do this first
187     pLink->SetObjType( nObjType );
188     if( pName )
189         pLink->SetName( *pName );
190     pLink->SetUpdateMode( nUpdateMode );
191     return Insert( pLink );
192 }
193 
194 
InsertDDELink(SvBaseLink * pLink,const String & rServer,const String & rTopic,const String & rItem)195 sal_Bool LinkManager::InsertDDELink( SvBaseLink * pLink,
196                                     const String& rServer,
197                                     const String& rTopic,
198                                     const String& rItem )
199 {
200     if( !( OBJECT_CLIENT_SO & pLink->GetObjType() ) )
201         return sal_False;
202 
203     String sCmd;
204     ::sfx2::MakeLnkName( sCmd, &rServer, rTopic, rItem );
205 
206     pLink->SetObjType( OBJECT_CLIENT_DDE );
207     pLink->SetName( sCmd );
208     return Insert( pLink );
209 }
210 
211 
InsertDDELink(SvBaseLink * pLink)212 sal_Bool LinkManager::InsertDDELink( SvBaseLink * pLink )
213 {
214     DBG_ASSERT( OBJECT_CLIENT_SO & pLink->GetObjType(), "no OBJECT_CLIENT_SO" );
215     if( !( OBJECT_CLIENT_SO & pLink->GetObjType() ) )
216         return sal_False;
217 
218     if( pLink->GetObjType() == OBJECT_CLIENT_SO )
219         pLink->SetObjType( OBJECT_CLIENT_DDE );
220 
221     return Insert( pLink );
222 }
223 
224 
225 // ask for the strings to be used in the dialog
GetDisplayNames(const SvBaseLink * pLink,String * pType,String * pFile,String * pLinkStr,String * pFilter) const226 sal_Bool LinkManager::GetDisplayNames( const SvBaseLink * pLink,
227                                         String* pType,
228                                         String* pFile,
229                                         String* pLinkStr,
230                                         String* pFilter ) const
231 {
232     sal_Bool bRet = sal_False;
233     const String sLNm( pLink->GetLinkSourceName() );
234     if( sLNm.Len() )
235     {
236         switch( pLink->GetObjType() )
237         {
238             case OBJECT_CLIENT_FILE:
239             case OBJECT_CLIENT_GRF:
240             case OBJECT_CLIENT_OLE:
241                 {
242                     sal_uInt16 nPos = 0;
243                     String sFile( sLNm.GetToken( 0, ::sfx2::cTokenSeperator, nPos ) );
244                     String sRange( sLNm.GetToken( 0, ::sfx2::cTokenSeperator, nPos ) );
245 
246                     if( pFile )
247                         *pFile = sFile;
248                     if( pLinkStr )
249                         *pLinkStr = sRange;
250                     if( pFilter )
251                         *pFilter = sLNm.Copy( nPos );
252 
253                     if( pType )
254                     {
255                         sal_uInt16 nObjType = pLink->GetObjType();
256                         *pType = String( SfxResId(
257                                     ( OBJECT_CLIENT_FILE == nObjType || OBJECT_CLIENT_OLE == nObjType )
258                                             ? RID_SVXSTR_FILELINK
259                                             : RID_SVXSTR_GRAFIKLINK ));
260                     }
261                     bRet = sal_True;
262                 }
263                 break;
264             case OBJECT_CLIENT_DDE:
265                 {
266                     sal_uInt16 nTmp = 0;
267                     String sCmd( sLNm );
268                     String sServer( sCmd.GetToken( 0, cTokenSeperator, nTmp ) );
269                     String sTopic( sCmd.GetToken( 0, cTokenSeperator, nTmp ) );
270 
271                     if( pType )
272                         *pType = sServer;
273                     if( pFile )
274                         *pFile = sTopic;
275                     if( pLinkStr )
276                         *pLinkStr = sCmd.Copy( nTmp );
277                     bRet = sal_True;
278                 }
279                 break;
280             default:
281                 break;
282         }
283     }
284 
285     return bRet;
286 }
287 
SetAutoAskUpdateAllLinks()288 void LinkManager::SetAutoAskUpdateAllLinks()
289 {
290     mAutoAskUpdateAllLinks = sal_True;
291     mUpdateAsked = sal_False;
292 }
293 
SetNeverAskUpdateAllLinks()294 void LinkManager::SetNeverAskUpdateAllLinks()
295 {
296     mAutoAskUpdateAllLinks = sal_False;
297     mAllowUpdate = sal_True;
298     mUpdateAsked = sal_True;
299 }
300 
GetUserAllowsLinkUpdate(Window * pParentWin)301 sal_Bool LinkManager::GetUserAllowsLinkUpdate(Window *pParentWin)
302 {
303     if (!mUpdateAsked)
304     {
305         if (QueryBox(pParentWin, WB_YES_NO | WB_DEF_NO, SfxResId(STR_QUERY_UPDATE_LINKS)).Execute() == RET_YES)
306             mAllowUpdate = sal_True;
307         else
308             mAllowUpdate = sal_False;
309         mUpdateAsked = sal_True;
310     }
311     return mAllowUpdate;
312 }
313 
SetUserAllowsLinkUpdate(SvBaseLink * pLink,sal_Bool allows)314 void LinkManager::SetUserAllowsLinkUpdate(SvBaseLink *pLink, sal_Bool allows)
315 {
316     SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
317 
318     if (pShell)
319     {
320         comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = pShell->getEmbeddedObjectContainer();
321         rEmbeddedObjectContainer.setUserAllowsLinkUpdate(allows);
322     }
323 }
324 
325 
UpdateAllLinks(sal_Bool bAskUpdate,sal_Bool,sal_Bool bUpdateGrfLinks,Window * pParentWin)326 void LinkManager::UpdateAllLinks(
327     sal_Bool bAskUpdate,
328     sal_Bool /*bCallErrHdl*/,
329     sal_Bool bUpdateGrfLinks,
330     Window* pParentWin )
331 {
332     SvStringsDtor aApps, aTopics, aItems;
333     String sApp, sTopic, sItem;
334 
335     // first create a copy of the array, so that updated links to not interfere with ... in between!!
336     SvPtrarr aTmpArr( 255, 50 );
337     sal_uInt16 n;
338     for( n = 0; n < aLinkTbl.Count(); ++n )
339     {
340         SvBaseLink* pLink = *aLinkTbl[ n ];
341         if( !pLink )
342         {
343             Remove( n-- );
344             continue;
345         }
346         aTmpArr.Insert( pLink, aTmpArr.Count() );
347     }
348 
349     for( n = 0; n < aTmpArr.Count(); ++n )
350     {
351         SvBaseLink* pLink = (SvBaseLink*)aTmpArr[ n ];
352 
353         // first search the entry in the array
354         sal_uInt16 nFndPos = USHRT_MAX;
355         for( sal_uInt16 i = 0; i < aLinkTbl.Count(); ++i )
356             if( pLink == *aLinkTbl[ i ] )
357             {
358                 nFndPos = i;
359                 break;
360             }
361 
362         if( USHRT_MAX == nFndPos )
363             continue;                   // was not already existing!
364 
365         // do not update graphic links yet
366         if( !pLink->IsVisible() ||
367             ( !bUpdateGrfLinks && OBJECT_CLIENT_GRF == pLink->GetObjType() ))
368             continue;
369 
370         sal_Bool allows = sal_True;
371 
372         if (bAskUpdate)
373         {
374             allows = GetUserAllowsLinkUpdate(pParentWin);
375         }
376 
377         SetUserAllowsLinkUpdate(pLink, allows);
378         bAskUpdate = sal_False;     // one time is OK
379 
380         if (allows)
381             pLink->Update();
382     }
383 }
384 
385 /************************************************************************
386 |*    SvBaseLink::CreateObject()
387 |*
388 |*    Description
389 *************************************************************************/
390 
CreateObj(SvBaseLink * pLink)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 
InsertServer(SvLinkSource * pObj)408 sal_Bool LinkManager::InsertServer( SvLinkSource* pObj )
409 {
410     // do not insert double
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 
RemoveServer(SvLinkSource * pObj)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 
MakeLnkName(String & rName,const String * pType,const String & rFile,const String & rLink,const String * pFilter)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 
InsertFileLink(sfx2::SvBaseLink & rLink,sal_uInt16 nFileType,const String & rFileNm,const String * pFilterNm,const String * pRange)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 
InsertFileLink(sfx2::SvBaseLink & rLink)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 // a transfer will be discontinued, therefore cancel all DownloadMedia
468 // (at the moment only interesting for the FileLinks!)
CancelTransfers()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     // to send status information from the FileObject to the BaseLink, there is an own ClipboardId.
485     // The SvData object has then the respective information as string.
486     // Currently this will be used for FileObject in connection with JavaScript
487     // - that needs information about Load/Abort/Error
RegisterStatusInfoId()488 sal_uIntPtr LinkManager::RegisterStatusInfoId()
489 {
490     static sal_uIntPtr nFormat = 0;
491 
492     if( !nFormat )
493     {
494 // how does the new interface look like?
495 //      nFormat = Exchange::RegisterFormatName( "StatusInfo vom SvxInternalLink" );
496         nFormat = SotExchange::RegisterFormatName(
497                     String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM(
498                                 "StatusInfo vom SvxInternalLink" )));
499     }
500     return nFormat;
501 }
502 
503 // ----------------------------------------------------------------------
504 
GetGraphicFromAny(const String & rMimeType,const::com::sun::star::uno::Any & rValue,Graphic & rGrf)505 sal_Bool LinkManager::GetGraphicFromAny( const String& rMimeType,
506                                 const ::com::sun::star::uno::Any & rValue,
507                                 Graphic& rGrf )
508 {
509     sal_Bool bRet = sal_False;
510     ::com::sun::star::uno::Sequence< sal_Int8 > aSeq;
511     if( rValue.hasValue() && ( rValue >>= aSeq ) )
512     {
513         SvMemoryStream aMemStm( (void*)aSeq.getConstArray(), aSeq.getLength(),
514                                 STREAM_READ );
515         aMemStm.Seek( 0 );
516 
517         switch( SotExchange::GetFormatIdFromMimeType( rMimeType ) )
518         {
519         case SOT_FORMATSTR_ID_SVXB:
520             {
521                 aMemStm >> rGrf;
522                 bRet = sal_True;
523             }
524             break;
525         case FORMAT_GDIMETAFILE:
526             {
527                 GDIMetaFile aMtf;
528                 aMtf.Read( aMemStm );
529                 rGrf = aMtf;
530                 bRet = sal_True;
531             }
532             break;
533         case FORMAT_BITMAP:
534             {
535                 Bitmap aBmp;
536                 ReadDIB(aBmp, aMemStm, true);
537                 rGrf = aBmp;
538                 bRet = sal_True;
539             }
540             break;
541         }
542     }
543     return bRet;
544 }
545 
urlIsSafe(const::rtl::OUString & url)546 sal_Bool LinkManager::urlIsSafe( const ::rtl::OUString &url )
547 {
548     if ( url.getLength() == 0 ) {
549         return sal_False;
550     }
551     if ( !xURLTransformer.is() ) {
552         const com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > xContext ( ::comphelper::getProcessComponentContext() );
553         com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiComponentFactory > xFactory ( xContext->getServiceManager(), ::com::sun::star::uno::UNO_QUERY );
554         if ( !xFactory.is() ) {
555             return sal_False;
556         }
557         xURLTransformer.set( xFactory->createInstanceWithContext( rtl::OUString::createFromAscii( "com.sun.star.util.URLTransformer" ), xContext), com::sun::star::uno::UNO_QUERY );
558         if ( !xURLTransformer.is() ) {
559             return sal_False;
560         }
561     }
562     com::sun::star::util::URL aURL;
563     aURL.Complete = url;
564     sal_Bool b = xURLTransformer->parseSmart( aURL, ::rtl::OUString() );
565     if ( !b ) {
566         return sal_False;
567     }
568     return urlIsSafe( aURL );
569 }
570 
urlIsSafe(const::com::sun::star::util::URL & url)571 sal_Bool LinkManager::urlIsSafe( const ::com::sun::star::util::URL &url )
572 {
573     sal_Bool result = ( url.Path.getLength() == 0 ) &&
574         ( url.Server.getLength() == 0);
575     return result;
576 }
577 
578 
urlIsVendor(const::rtl::OUString & url)579 sal_Bool LinkManager::urlIsVendor( const ::rtl::OUString &url )
580 {
581     // One definition of this scheme set, shared with the modules below sfx2
582     // that also have to apply it (see svtools/linkpolicy.hxx).
583     return ::svt::linkpolicy::isVendorUrl( url ) ? sal_True : sal_False;
584 }
585 
586 
587 // ----------------------------------------------------------------------
lcl_DDE_RelToAbs(const String & rTopic,const String & rBaseURL)588 String lcl_DDE_RelToAbs( const String& rTopic, const String& rBaseURL )
589 {
590     String sRet;
591     INetURLObject aURL( rTopic );
592     if( INET_PROT_NOT_VALID == aURL.GetProtocol() )
593         utl::LocalFileHelper::ConvertSystemPathToURL( rTopic, rBaseURL, sRet );
594     if( !sRet.Len() )
595         sRet = URIHelper::SmartRel2Abs( INetURLObject(rBaseURL), rTopic, URIHelper::GetMaybeFileHdl(), true );
596     return sRet;
597 }
598 
Connect(sfx2::SvBaseLink * pLink)599 sal_Bool SvxInternalLink::Connect( sfx2::SvBaseLink* pLink )
600 {
601     SfxObjectShell* pFndShell = 0;
602     sal_uInt16 nUpdateMode = com::sun::star::document::UpdateDocMode::NO_UPDATE;
603     String sTopic, sItem, sReferer;
604     if( pLink->GetLinkManager() &&
605         pLink->GetLinkManager()->GetDisplayNames( pLink, 0, &sTopic, &sItem )
606         && sTopic.Len() )
607     {
608         // for the moment run through the DocumentShells and search for the ones with names:
609 
610         com::sun::star::lang::Locale aLocale;
611         MsLangId::convertLanguageToLocale( LANGUAGE_SYSTEM, aLocale );
612         CharClass aCC( aLocale );
613 
614         String sNm( sTopic ), sTmp;
615         aCC.toLower( sNm );
616 
617         TypeId aType( TYPE(SfxObjectShell) );
618 
619         sal_Bool bFirst = sal_True;
620         SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist();
621         if( pShell && pShell->GetMedium() )
622         {
623             sReferer = pShell->GetMedium()->GetBaseURL();
624             SFX_ITEMSET_ARG( pShell->GetMedium()->GetItemSet(), pItem, SfxUInt16Item, SID_UPDATEDOCMODE, sal_False );
625             if ( pItem )
626                 nUpdateMode = pItem->GetValue();
627         }
628 
629         String sNmURL( lcl_DDE_RelToAbs( sTopic, sReferer ) );
630         aCC.toLower( sNmURL );
631 
632         if ( !pShell )
633         {
634             bFirst = sal_False;
635             pShell = SfxObjectShell::GetFirst( &aType, sal_False );
636         }
637 
638         while( pShell )
639         {
640             if( !sTmp.Len() )
641             {
642                 sTmp = pShell->GetTitle( SFX_TITLE_FULLNAME );
643                 sTmp = lcl_DDE_RelToAbs(sTmp, sReferer );
644             }
645 
646 
647             aCC.toLower( sTmp );
648             if( sTmp == sNmURL )        // these we want to have
649             {
650                 pFndShell = pShell;
651                 break;
652             }
653 
654             if( bFirst )
655             {
656                 bFirst = sal_False;
657                 pShell = SfxObjectShell::GetFirst( &aType, sal_False );
658             }
659             else
660                 pShell = SfxObjectShell::GetNext( *pShell, &aType, sal_False );
661 
662             sTmp.Erase();
663         }
664     }
665 
666     // empty topics are not allowed - which document is it
667     if( !sTopic.Len() )
668         return sal_False;
669 
670     if( !pFndShell )
671     {
672         // try to load the file:
673         INetURLObject aURL( sTopic );
674         INetProtocol eOld = aURL.GetProtocol();
675         aURL.SetURL( sTopic = lcl_DDE_RelToAbs( sTopic, sReferer ) );
676         if( INET_PROT_NOT_VALID != eOld ||
677             INET_PROT_HTTP != aURL.GetProtocol() )
678         {
679             SfxStringItem aName( SID_FILE_NAME, sTopic );
680             SfxBoolItem aMinimized(SID_MINIMIZED, sal_True);
681             SfxBoolItem aHidden(SID_HIDDEN, sal_True);
682             SfxStringItem aTarget( SID_TARGETNAME, String::CreateFromAscii("_blank") );
683             SfxStringItem aReferer( SID_REFERER, sReferer );
684             SfxUInt16Item aUpdate( SID_UPDATEDOCMODE, nUpdateMode );
685             SfxBoolItem aReadOnly(SID_DOC_READONLY, sal_True);
686 
687             // #i14200# (DDE-link crashes wordprocessor)
688             SfxAllItemSet aArgs( SFX_APP()->GetPool() );
689             aArgs.Put(aReferer);
690             aArgs.Put(aTarget);
691             aArgs.Put(aHidden);
692             aArgs.Put(aMinimized);
693             aArgs.Put(aName);
694             aArgs.Put(aUpdate);
695             aArgs.Put(aReadOnly);
696             pFndShell = SfxObjectShell::CreateAndLoadObject( aArgs );
697         }
698     }
699 
700     sal_Bool bRet = sal_False;
701     if( pFndShell )
702     {
703         sfx2::SvLinkSource* pNewSrc = pFndShell->DdeCreateLinkSource( sItem );
704         if( pNewSrc )
705         {
706             bRet = sal_True;
707 
708             ::com::sun::star::datatransfer::DataFlavor aFl;
709             SotExchange::GetFormatDataFlavor( pLink->GetContentType(), aFl );
710 
711             pLink->SetObj( pNewSrc );
712             pNewSrc->AddDataAdvise( pLink, aFl.MimeType,
713                                 sfx2::LINKUPDATE_ONCALL == pLink->GetUpdateMode()
714                                     ? ADVISEMODE_ONLYONCE
715                                     : 0 );
716         }
717     }
718     return bRet;
719 }
720 
721 
722 }
723