bump product version to 4.1.6.2
[LibreOffice.git] / sfx2 / source / appl / lnkbase2.cxx
blob7fd8c789418dea6b3cfa9121323475c1559d02ca
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sfx2/lnkbase.hxx>
22 #include <sot/exchange.hxx>
23 #include <com/sun/star/uno/Any.hxx>
24 #include <com/sun/star/uno/Sequence.hxx>
25 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
26 #include <vcl/msgbox.hxx>
27 #include <sfx2/linkmgr.hxx>
28 #include <vcl/svapp.hxx>
29 #include "app.hrc"
30 #include "sfx2/sfxresid.hxx"
31 #include <sfx2/filedlghelper.hxx>
32 #include <tools/debug.hxx>
33 #include <svl/svdde.hxx>
35 using namespace ::com::sun::star;
36 using namespace ::com::sun::star::uno;
38 namespace sfx2
41 TYPEINIT0( SvBaseLink )
43 static DdeTopic* FindTopic( const String &, sal_uInt16* = 0 );
45 class ImplDdeItem;
47 struct BaseLink_Impl
49 Link m_aEndEditLink;
50 LinkManager* m_pLinkMgr;
51 Window* m_pParentWin;
52 FileDialogHelper* m_pFileDlg;
53 bool m_bIsConnect;
55 BaseLink_Impl() :
56 m_pLinkMgr( NULL )
57 , m_pParentWin( NULL )
58 , m_pFileDlg( NULL )
59 , m_bIsConnect( false )
62 ~BaseLink_Impl()
63 { delete m_pFileDlg; }
66 // only for internal management
67 struct ImplBaseLinkData
69 struct tClientType
71 // applies for all links
72 sal_uIntPtr nCntntType; // Update Format
73 // Not Ole-Links
74 sal_Bool bIntrnlLnk; // It is an internal link
75 sal_uInt16 nUpdateMode; // UpdateMode
78 struct tDDEType
80 ImplDdeItem* pItem;
83 union {
84 tClientType ClientType;
85 tDDEType DDEType;
87 ImplBaseLinkData()
89 ClientType.nCntntType = 0;
90 ClientType.bIntrnlLnk = sal_False;
91 ClientType.nUpdateMode = 0;
92 DDEType.pItem = NULL;
97 class ImplDdeItem : public DdeGetPutItem
99 SvBaseLink* pLink;
100 DdeData aData;
101 Sequence< sal_Int8 > aSeq; // Datacontainer for DdeData !!!
102 sal_Bool bIsValidData : 1;
103 sal_Bool bIsInDTOR : 1;
104 public:
105 ImplDdeItem( SvBaseLink& rLink, const String& rStr )
106 : DdeGetPutItem( rStr ), pLink( &rLink ), bIsValidData( sal_False ),
107 bIsInDTOR( sal_False )
109 virtual ~ImplDdeItem();
111 virtual DdeData* Get( sal_uIntPtr );
112 virtual sal_Bool Put( const DdeData* );
113 virtual void AdviseLoop( sal_Bool );
115 void Notify()
117 bIsValidData = sal_False;
118 DdeGetPutItem::NotifyClient();
121 sal_Bool IsInDTOR() const { return bIsInDTOR; }
124 //--------------------------------------------------------------------------
126 SvBaseLink::SvBaseLink()
128 pImpl = new BaseLink_Impl();
129 nObjType = OBJECT_CLIENT_SO;
130 pImplData = new ImplBaseLinkData;
131 bVisible = bSynchron = bUseCache = sal_True;
132 bWasLastEditOK = sal_False;
135 //--------------------------------------------------------------------------
137 SvBaseLink::SvBaseLink( sal_uInt16 nUpdateMode, sal_uIntPtr nContentType )
139 pImpl = new BaseLink_Impl();
140 nObjType = OBJECT_CLIENT_SO;
141 pImplData = new ImplBaseLinkData;
142 bVisible = bSynchron = bUseCache = sal_True;
143 bWasLastEditOK = sal_False;
145 // It it going to be a Ole-Link,
146 pImplData->ClientType.nUpdateMode = nUpdateMode;
147 pImplData->ClientType.nCntntType = nContentType;
148 pImplData->ClientType.bIntrnlLnk = sal_False;
151 //--------------------------------------------------------------------------
153 SvBaseLink::SvBaseLink( const String& rLinkName, sal_uInt16 nObjectType, SvLinkSource* pObj )
154 : pImpl(0)
156 bVisible = bSynchron = bUseCache = sal_True;
157 bWasLastEditOK = sal_False;
158 aLinkName = rLinkName;
159 pImplData = new ImplBaseLinkData;
160 nObjType = nObjectType;
162 if( !pObj )
164 DBG_ASSERT( pObj, "Where is my left-most object" );
165 return;
168 if( OBJECT_DDE_EXTERN == nObjType )
170 sal_uInt16 nItemStt = 0;
171 DdeTopic* pTopic = FindTopic( aLinkName, &nItemStt );
172 if( pTopic )
174 // then we have it all together
175 // MM_TODO how do I get the name
176 String aStr = aLinkName; // xLinkName->GetDisplayName();
177 aStr = aStr.Copy( nItemStt );
178 pImplData->DDEType.pItem = new ImplDdeItem( *this, aStr );
179 pTopic->InsertItem( pImplData->DDEType.pItem );
181 // store the Advice
182 xObj = pObj;
185 else if( pObj->Connect( this ) )
186 xObj = pObj;
189 //--------------------------------------------------------------------------
191 SvBaseLink::~SvBaseLink()
193 Disconnect();
195 switch( nObjType )
197 case OBJECT_DDE_EXTERN:
198 if( !pImplData->DDEType.pItem->IsInDTOR() )
199 delete pImplData->DDEType.pItem;
200 break;
203 delete pImplData;
204 delete pImpl;
207 IMPL_LINK( SvBaseLink, EndEditHdl, String*, _pNewName )
209 String sNewName;
210 if ( _pNewName )
211 sNewName = *_pNewName;
212 if ( !ExecuteEdit( sNewName ) )
213 sNewName.Erase();
214 bWasLastEditOK = ( sNewName.Len() > 0 );
215 if ( pImpl->m_aEndEditLink.IsSet() )
216 pImpl->m_aEndEditLink.Call( this );
217 return 0;
220 //--------------------------------------------------------------------------
222 void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP )
224 DBG_ASSERT( nObjType != OBJECT_CLIENT_DDE, "type already set" );
225 DBG_ASSERT( !xObj.Is(), "object exist" );
227 nObjType = nObjTypeP;
230 //--------------------------------------------------------------------------
232 void SvBaseLink::SetName( const String & rNm )
234 aLinkName = rNm;
237 //--------------------------------------------------------------------------
239 void SvBaseLink::SetObj( SvLinkSource * pObj )
241 DBG_ASSERT( (nObjType & OBJECT_CLIENT_SO &&
242 pImplData->ClientType.bIntrnlLnk) ||
243 nObjType == OBJECT_CLIENT_GRF,
244 "no intern link" );
245 xObj = pObj;
248 //--------------------------------------------------------------------------
250 void SvBaseLink::SetLinkSourceName( const String & rLnkNm )
252 if( aLinkName == rLnkNm )
253 return;
255 AddNextRef(); // should be superfluous
256 // remove old connection
257 Disconnect();
259 aLinkName = rLnkNm;
261 // New Connection
262 _GetRealObject();
263 ReleaseRef(); // should be superfluous
266 //--------------------------------------------------------------------------
268 String SvBaseLink::GetLinkSourceName() const
270 return aLinkName;
273 //--------------------------------------------------------------------------
275 void SvBaseLink::SetUpdateMode( sal_uInt16 nMode )
277 if( ( OBJECT_CLIENT_SO & nObjType ) &&
278 pImplData->ClientType.nUpdateMode != nMode )
280 AddNextRef();
281 Disconnect();
283 pImplData->ClientType.nUpdateMode = nMode;
284 _GetRealObject();
285 ReleaseRef();
289 // #i88291#
290 void SvBaseLink::clearStreamToLoadFrom()
292 m_xInputStreamToLoadFrom.clear();
293 if( xObj.Is() )
295 xObj->clearStreamToLoadFrom();
299 sal_Bool SvBaseLink::Update()
301 if( OBJECT_CLIENT_SO & nObjType )
303 AddNextRef();
304 Disconnect();
306 _GetRealObject();
307 ReleaseRef();
308 if( xObj.Is() )
310 xObj->setStreamToLoadFrom(m_xInputStreamToLoadFrom,m_bIsReadOnly);
311 String sMimeType( SotExchange::GetFormatMimeType(
312 pImplData->ClientType.nCntntType ));
313 Any aData;
315 if( xObj->GetData( aData, sMimeType ) )
317 UpdateResult eRes = DataChanged(sMimeType, aData);
318 bool bSuccess = eRes == SUCCESS;
319 //for manual Updates there is no need to hold the ServerObject
320 if( OBJECT_CLIENT_DDE == nObjType &&
321 LINKUPDATE_ONCALL == GetUpdateMode() && xObj.Is() )
322 xObj->RemoveAllDataAdvise( this );
323 return bSuccess;
325 if( xObj.Is() )
327 // should be asynschron?
328 if( xObj->IsPending() )
329 return sal_True;
331 // we do not need the object anymore
332 AddNextRef();
333 Disconnect();
334 ReleaseRef();
338 return sal_False;
342 sal_uInt16 SvBaseLink::GetUpdateMode() const
344 return ( OBJECT_CLIENT_SO & nObjType )
345 ? pImplData->ClientType.nUpdateMode
346 : sal::static_int_cast< sal_uInt16 >( LINKUPDATE_ONCALL );
350 void SvBaseLink::_GetRealObject( sal_Bool bConnect)
352 if( !pImpl->m_pLinkMgr )
353 return;
355 DBG_ASSERT( !xObj.Is(), "object already exist" );
357 if( OBJECT_CLIENT_DDE == nObjType )
359 OUString sServer;
360 if( pImpl->m_pLinkMgr->GetDisplayNames( this, &sServer ) &&
361 sServer == OUString(GetpApp()->GetAppName()) ) // internal Link !!!
363 // so that the Internal link can be created!
364 nObjType = OBJECT_INTERN;
365 xObj = pImpl->m_pLinkMgr->CreateObj( this );
367 pImplData->ClientType.bIntrnlLnk = sal_True;
368 nObjType = OBJECT_CLIENT_DDE; // so we know what it once was!
370 else
372 pImplData->ClientType.bIntrnlLnk = sal_False;
373 xObj = pImpl->m_pLinkMgr->CreateObj( this );
376 else if( (OBJECT_CLIENT_SO & nObjType) )
377 xObj = pImpl->m_pLinkMgr->CreateObj( this );
379 if( bConnect && ( !xObj.Is() || !xObj->Connect( this ) ) )
380 Disconnect();
383 sal_uIntPtr SvBaseLink::GetContentType() const
385 if( OBJECT_CLIENT_SO & nObjType )
386 return pImplData->ClientType.nCntntType;
388 return 0; // all Formats ?
392 sal_Bool SvBaseLink::SetContentType( sal_uIntPtr nType )
394 if( OBJECT_CLIENT_SO & nObjType )
396 pImplData->ClientType.nCntntType = nType;
397 return sal_True;
399 return sal_False;
402 LinkManager* SvBaseLink::GetLinkManager()
404 return pImpl->m_pLinkMgr;
407 const LinkManager* SvBaseLink::GetLinkManager() const
409 return pImpl->m_pLinkMgr;
412 void SvBaseLink::SetLinkManager( LinkManager* _pMgr )
414 pImpl->m_pLinkMgr = _pMgr;
417 void SvBaseLink::Disconnect()
419 if( xObj.Is() )
421 xObj->RemoveAllDataAdvise( this );
422 xObj->RemoveConnectAdvise( this );
423 xObj.Clear();
427 SvBaseLink::UpdateResult SvBaseLink::DataChanged( const String &, const ::com::sun::star::uno::Any & )
429 switch( nObjType )
431 case OBJECT_DDE_EXTERN:
432 if( pImplData->DDEType.pItem )
433 pImplData->DDEType.pItem->Notify();
434 break;
436 return SUCCESS;
439 void SvBaseLink::Edit( Window* pParent, const Link& rEndEditHdl )
441 pImpl->m_pParentWin = pParent;
442 pImpl->m_aEndEditLink = rEndEditHdl;
443 pImpl->m_bIsConnect = ( xObj.Is() != sal_False );
444 if( !pImpl->m_bIsConnect )
445 _GetRealObject( xObj.Is() );
447 bool bAsync = false;
448 Link aLink = LINK( this, SvBaseLink, EndEditHdl );
450 if( OBJECT_CLIENT_SO & nObjType && pImplData->ClientType.bIntrnlLnk )
452 if( pImpl->m_pLinkMgr )
454 SvLinkSourceRef ref = pImpl->m_pLinkMgr->CreateObj( this );
455 if( ref.Is() )
457 ref->Edit( pParent, this, aLink );
458 bAsync = true;
462 else
464 xObj->Edit( pParent, this, aLink );
465 bAsync = true;
468 if ( !bAsync )
470 ExecuteEdit( String() );
471 bWasLastEditOK = sal_False;
472 if ( pImpl->m_aEndEditLink.IsSet() )
473 pImpl->m_aEndEditLink.Call( this );
477 bool SvBaseLink::ExecuteEdit( const String& _rNewName )
479 if( _rNewName.Len() != 0 )
481 SetLinkSourceName( _rNewName );
482 if( !Update() )
484 String sApp, sTopic, sItem, sError;
485 pImpl->m_pLinkMgr->GetDisplayNames( this, &sApp, &sTopic, &sItem );
486 if( nObjType == OBJECT_CLIENT_DDE )
488 sError = SFX2_RESSTR(STR_DDE_ERROR);
490 sal_uInt16 nFndPos = sError.Search( '%' );
491 if( STRING_NOTFOUND != nFndPos )
493 sError.Erase( nFndPos, 1 ).Insert( sApp, nFndPos );
494 nFndPos = nFndPos + sApp.Len();
496 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos )))
498 sError.Erase( nFndPos, 1 ).Insert( sTopic, nFndPos );
499 nFndPos = nFndPos + sTopic.Len();
501 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos )))
502 sError.Erase( nFndPos, 1 ).Insert( sItem, nFndPos );
504 else
505 return false;
507 ErrorBox( pImpl->m_pParentWin, WB_OK, sError ).Execute();
510 else if( !pImpl->m_bIsConnect )
511 Disconnect();
512 pImpl->m_bIsConnect = false;
513 return true;
516 void SvBaseLink::Closed()
518 if( xObj.Is() )
519 xObj->RemoveAllDataAdvise( this );
522 FileDialogHelper & SvBaseLink::GetInsertFileDialog(const String& rFactory) const
524 if ( pImpl->m_pFileDlg )
525 delete pImpl->m_pFileDlg;
526 pImpl->m_pFileDlg = new FileDialogHelper(
527 ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
528 SFXWB_INSERT, rFactory);
529 return *pImpl->m_pFileDlg;
532 ImplDdeItem::~ImplDdeItem()
534 bIsInDTOR = sal_True;
535 // So that no-one gets the idea to delete the pointer when Disconnecting!
536 SvBaseLinkRef aRef( pLink );
537 aRef->Disconnect();
540 DdeData* ImplDdeItem::Get( sal_uIntPtr nFormat )
542 if( pLink->GetObj() )
544 // is it still valid?
545 if( bIsValidData && nFormat == aData.GetFormat() )
546 return &aData;
548 Any aValue;
549 String sMimeType( SotExchange::GetFormatMimeType( nFormat ));
550 if( pLink->GetObj()->GetData( aValue, sMimeType ) )
552 if( aValue >>= aSeq )
554 aData = DdeData( (const char *)aSeq.getConstArray(), aSeq.getLength(), nFormat );
556 bIsValidData = sal_True;
557 return &aData;
561 aSeq.realloc( 0 );
562 bIsValidData = sal_False;
563 return 0;
567 sal_Bool ImplDdeItem::Put( const DdeData* )
569 OSL_FAIL( "ImplDdeItem::Put not implemented" );
570 return sal_False;
574 void ImplDdeItem::AdviseLoop( sal_Bool bOpen )
576 // Connection is closed, so also unsubscribe link
577 if( pLink->GetObj() )
579 if( bOpen )
581 // A connection is re-established
582 if( OBJECT_DDE_EXTERN == pLink->GetObjType() )
584 pLink->GetObj()->AddDataAdvise( pLink, OUString("text/plain;charset=utf-16"), ADVISEMODE_NODATA );
585 pLink->GetObj()->AddConnectAdvise( pLink );
588 else
590 // So that no-one gets the idea to delete the pointer
591 // when Disconnecting!
592 SvBaseLinkRef aRef( pLink );
593 aRef->Disconnect();
599 static DdeTopic* FindTopic( const String & rLinkName, sal_uInt16* pItemStt )
601 if( 0 == rLinkName.Len() )
602 return 0;
604 String sNm( rLinkName );
605 sal_Int32 nTokenPos = 0;
606 OUString sService( sNm.GetToken( 0, cTokenSeparator, nTokenPos ) );
608 DdeServices& rSvc = DdeService::GetServices();
609 for (DdeServices::iterator aI = rSvc.begin(); aI != rSvc.end(); ++aI)
611 DdeService* pService = *aI;
612 if( pService->GetName() == sService )
614 // then we search for the Topic
615 OUString sTopic( sNm.GetToken( 0, cTokenSeparator, nTokenPos ) );
616 if( pItemStt )
617 *pItemStt = nTokenPos;
619 std::vector<DdeTopic*>& rTopics = pService->GetTopics();
621 for( int i = 0; i < 2; ++i )
623 for( std::vector<DdeTopic*>::iterator iterTopic = rTopics.begin();
624 iterTopic != rTopics.end(); ++iterTopic )
625 if( (*iterTopic)->GetName() == sTopic )
626 return *iterTopic;
628 // Topic not found?
629 // then we try once to create it
630 if( i || !pService->MakeTopic( sTopic ) )
631 break; // did not work, exiting
633 break;
636 return 0;
641 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */