1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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
;
41 TYPEINIT0( SvBaseLink
)
43 static DdeTopic
* FindTopic( const OUString
&, sal_uInt16
* = 0 );
50 LinkManager
* m_pLinkMgr
;
52 FileDialogHelper
* m_pFileDlg
;
57 , m_pParentWin( NULL
)
59 , m_bIsConnect( false )
63 { delete m_pFileDlg
; }
66 // only for internal management
67 struct ImplBaseLinkData
71 // applies for all links
72 sal_uIntPtr nCntntType
; // Update Format
74 sal_Bool bIntrnlLnk
; // It is an internal link
75 sal_uInt16 nUpdateMode
; // UpdateMode
84 tClientType ClientType
;
89 ClientType
.nCntntType
= 0;
90 ClientType
.bIntrnlLnk
= sal_False
;
91 ClientType
.nUpdateMode
= 0;
97 class ImplDdeItem
: public DdeGetPutItem
101 Sequence
< sal_Int8
> aSeq
; // Datacontainer for DdeData !!!
102 sal_Bool bIsValidData
: 1;
103 sal_Bool bIsInDTOR
: 1;
105 ImplDdeItem( SvBaseLink
& rLink
, const OUString
& rStr
)
106 : DdeGetPutItem( rStr
), pLink( &rLink
), bIsValidData( sal_False
),
107 bIsInDTOR( sal_False
)
109 virtual ~ImplDdeItem();
111 virtual DdeData
* Get( sal_uIntPtr
);
112 virtual bool Put( const DdeData
* );
113 virtual void AdviseLoop( bool );
117 bIsValidData
= sal_False
;
118 DdeGetPutItem::NotifyClient();
121 sal_Bool
IsInDTOR() const { return bIsInDTOR
; }
124 //--------------------------------------------------------------------------
126 SvBaseLink::SvBaseLink()
127 : m_bIsReadOnly(false)
129 pImpl
= new BaseLink_Impl();
130 nObjType
= OBJECT_CLIENT_SO
;
131 pImplData
= new ImplBaseLinkData
;
132 bVisible
= bSynchron
= bUseCache
= sal_True
;
133 bWasLastEditOK
= sal_False
;
136 //--------------------------------------------------------------------------
138 SvBaseLink::SvBaseLink( sal_uInt16 nUpdateMode
, sal_uIntPtr nContentType
)
139 : m_bIsReadOnly(false)
141 pImpl
= new BaseLink_Impl();
142 nObjType
= OBJECT_CLIENT_SO
;
143 pImplData
= new ImplBaseLinkData
;
144 bVisible
= bSynchron
= bUseCache
= sal_True
;
145 bWasLastEditOK
= sal_False
;
147 // It it going to be a Ole-Link,
148 pImplData
->ClientType
.nUpdateMode
= nUpdateMode
;
149 pImplData
->ClientType
.nCntntType
= nContentType
;
150 pImplData
->ClientType
.bIntrnlLnk
= sal_False
;
153 //--------------------------------------------------------------------------
155 SvBaseLink::SvBaseLink( const OUString
& rLinkName
, sal_uInt16 nObjectType
, SvLinkSource
* pObj
)
157 , m_bIsReadOnly(false)
159 bVisible
= bSynchron
= bUseCache
= sal_True
;
160 bWasLastEditOK
= sal_False
;
161 aLinkName
= rLinkName
;
162 pImplData
= new ImplBaseLinkData
;
163 nObjType
= nObjectType
;
167 DBG_ASSERT( pObj
, "Where is my left-most object" );
171 if( OBJECT_DDE_EXTERN
== nObjType
)
173 sal_uInt16 nItemStt
= 0;
174 DdeTopic
* pTopic
= FindTopic( aLinkName
, &nItemStt
);
177 // then we have it all together
178 // MM_TODO how do I get the name
179 OUString aStr
= aLinkName
; // xLinkName->GetDisplayName();
180 aStr
= aStr
.copy( nItemStt
);
181 pImplData
->DDEType
.pItem
= new ImplDdeItem( *this, aStr
);
182 pTopic
->InsertItem( pImplData
->DDEType
.pItem
);
188 else if( pObj
->Connect( this ) )
192 //--------------------------------------------------------------------------
194 SvBaseLink::~SvBaseLink()
200 case OBJECT_DDE_EXTERN
:
201 if( !pImplData
->DDEType
.pItem
->IsInDTOR() )
202 delete pImplData
->DDEType
.pItem
;
210 IMPL_LINK( SvBaseLink
, EndEditHdl
, OUString
*, _pNewName
)
214 sNewName
= *_pNewName
;
215 if ( !ExecuteEdit( sNewName
) )
217 bWasLastEditOK
= !sNewName
.isEmpty();
218 if ( pImpl
->m_aEndEditLink
.IsSet() )
219 pImpl
->m_aEndEditLink
.Call( this );
223 //--------------------------------------------------------------------------
225 void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP
)
227 DBG_ASSERT( nObjType
!= OBJECT_CLIENT_DDE
, "type already set" );
228 DBG_ASSERT( !xObj
.Is(), "object exist" );
230 nObjType
= nObjTypeP
;
233 //--------------------------------------------------------------------------
235 void SvBaseLink::SetName( const OUString
& rNm
)
240 //--------------------------------------------------------------------------
242 void SvBaseLink::SetObj( SvLinkSource
* pObj
)
244 DBG_ASSERT( (nObjType
& OBJECT_CLIENT_SO
&&
245 pImplData
->ClientType
.bIntrnlLnk
) ||
246 nObjType
== OBJECT_CLIENT_GRF
,
251 //--------------------------------------------------------------------------
253 void SvBaseLink::SetLinkSourceName( const OUString
& rLnkNm
)
255 if( aLinkName
== rLnkNm
)
258 AddNextRef(); // should be superfluous
259 // remove old connection
266 ReleaseRef(); // should be superfluous
269 //--------------------------------------------------------------------------
271 OUString
SvBaseLink::GetLinkSourceName() const
276 //--------------------------------------------------------------------------
278 void SvBaseLink::SetUpdateMode( sal_uInt16 nMode
)
280 if( ( OBJECT_CLIENT_SO
& nObjType
) &&
281 pImplData
->ClientType
.nUpdateMode
!= nMode
)
286 pImplData
->ClientType
.nUpdateMode
= nMode
;
293 void SvBaseLink::clearStreamToLoadFrom()
295 m_xInputStreamToLoadFrom
.clear();
298 xObj
->clearStreamToLoadFrom();
302 sal_Bool
SvBaseLink::Update()
304 if( OBJECT_CLIENT_SO
& nObjType
)
313 xObj
->setStreamToLoadFrom(m_xInputStreamToLoadFrom
,m_bIsReadOnly
);
314 OUString
sMimeType( SotExchange::GetFormatMimeType(
315 pImplData
->ClientType
.nCntntType
));
318 if( xObj
->GetData( aData
, sMimeType
) )
320 UpdateResult eRes
= DataChanged(sMimeType
, aData
);
321 bool bSuccess
= eRes
== SUCCESS
;
322 //for manual Updates there is no need to hold the ServerObject
323 if( OBJECT_CLIENT_DDE
== nObjType
&&
324 LINKUPDATE_ONCALL
== GetUpdateMode() && xObj
.Is() )
325 xObj
->RemoveAllDataAdvise( this );
330 // should be asynschron?
331 if( xObj
->IsPending() )
334 // we do not need the object anymore
345 sal_uInt16
SvBaseLink::GetUpdateMode() const
347 return ( OBJECT_CLIENT_SO
& nObjType
)
348 ? pImplData
->ClientType
.nUpdateMode
349 : sal::static_int_cast
< sal_uInt16
>( LINKUPDATE_ONCALL
);
353 void SvBaseLink::_GetRealObject( sal_Bool bConnect
)
355 if( !pImpl
->m_pLinkMgr
)
358 DBG_ASSERT( !xObj
.Is(), "object already exist" );
360 if( OBJECT_CLIENT_DDE
== nObjType
)
363 if( pImpl
->m_pLinkMgr
->GetDisplayNames( this, &sServer
) &&
364 sServer
== GetpApp()->GetAppName() ) // internal Link !!!
366 // so that the Internal link can be created!
367 nObjType
= OBJECT_INTERN
;
368 xObj
= pImpl
->m_pLinkMgr
->CreateObj( this );
370 pImplData
->ClientType
.bIntrnlLnk
= sal_True
;
371 nObjType
= OBJECT_CLIENT_DDE
; // so we know what it once was!
375 pImplData
->ClientType
.bIntrnlLnk
= sal_False
;
376 xObj
= pImpl
->m_pLinkMgr
->CreateObj( this );
379 else if( (OBJECT_CLIENT_SO
& nObjType
) )
380 xObj
= pImpl
->m_pLinkMgr
->CreateObj( this );
382 if( bConnect
&& ( !xObj
.Is() || !xObj
->Connect( this ) ) )
386 sal_uIntPtr
SvBaseLink::GetContentType() const
388 if( OBJECT_CLIENT_SO
& nObjType
)
389 return pImplData
->ClientType
.nCntntType
;
391 return 0; // all Formats ?
395 sal_Bool
SvBaseLink::SetContentType( sal_uIntPtr nType
)
397 if( OBJECT_CLIENT_SO
& nObjType
)
399 pImplData
->ClientType
.nCntntType
= nType
;
405 LinkManager
* SvBaseLink::GetLinkManager()
407 return pImpl
->m_pLinkMgr
;
410 const LinkManager
* SvBaseLink::GetLinkManager() const
412 return pImpl
->m_pLinkMgr
;
415 void SvBaseLink::SetLinkManager( LinkManager
* _pMgr
)
417 pImpl
->m_pLinkMgr
= _pMgr
;
420 void SvBaseLink::Disconnect()
424 xObj
->RemoveAllDataAdvise( this );
425 xObj
->RemoveConnectAdvise( this );
430 SvBaseLink::UpdateResult
SvBaseLink::DataChanged( const OUString
&, const ::com::sun::star::uno::Any
& )
434 case OBJECT_DDE_EXTERN
:
435 if( pImplData
->DDEType
.pItem
)
436 pImplData
->DDEType
.pItem
->Notify();
442 void SvBaseLink::Edit( Window
* pParent
, const Link
& rEndEditHdl
)
444 pImpl
->m_pParentWin
= pParent
;
445 pImpl
->m_aEndEditLink
= rEndEditHdl
;
446 pImpl
->m_bIsConnect
= ( xObj
.Is() != sal_False
);
447 if( !pImpl
->m_bIsConnect
)
448 _GetRealObject( xObj
.Is() );
451 Link aLink
= LINK( this, SvBaseLink
, EndEditHdl
);
453 if( OBJECT_CLIENT_SO
& nObjType
&& pImplData
->ClientType
.bIntrnlLnk
)
455 if( pImpl
->m_pLinkMgr
)
457 SvLinkSourceRef ref
= pImpl
->m_pLinkMgr
->CreateObj( this );
460 ref
->Edit( pParent
, this, aLink
);
467 xObj
->Edit( pParent
, this, aLink
);
473 ExecuteEdit( OUString() );
474 bWasLastEditOK
= sal_False
;
475 if ( pImpl
->m_aEndEditLink
.IsSet() )
476 pImpl
->m_aEndEditLink
.Call( this );
480 bool SvBaseLink::ExecuteEdit( const OUString
& _rNewName
)
482 if( !_rNewName
.isEmpty() )
484 SetLinkSourceName( _rNewName
);
487 OUString sApp
, sTopic
, sItem
, sError
;
488 pImpl
->m_pLinkMgr
->GetDisplayNames( this, &sApp
, &sTopic
, &sItem
);
489 if( nObjType
== OBJECT_CLIENT_DDE
)
491 sError
= SFX2_RESSTR(STR_DDE_ERROR
);
493 sal_Int32 nFndPos
= sError
.indexOf( '%' );
496 sError
= sError
.replaceAt( nFndPos
, 1, sApp
);
497 nFndPos
= nFndPos
+ sApp
.getLength();
499 if( -1 != ( nFndPos
= sError
.indexOf( '%', nFndPos
)))
501 sError
= sError
.replaceAt( nFndPos
, 1, sTopic
);
502 nFndPos
= nFndPos
+ sTopic
.getLength();
504 if( -1 != ( nFndPos
= sError
.indexOf( '%', nFndPos
)))
505 sError
= sError
.replaceAt( nFndPos
, 1, sItem
);
512 ErrorBox( pImpl
->m_pParentWin
, WB_OK
, sError
).Execute();
515 else if( !pImpl
->m_bIsConnect
)
517 pImpl
->m_bIsConnect
= false;
521 void SvBaseLink::Closed()
524 xObj
->RemoveAllDataAdvise( this );
527 FileDialogHelper
& SvBaseLink::GetInsertFileDialog(const OUString
& rFactory
) const
529 if ( pImpl
->m_pFileDlg
)
530 delete pImpl
->m_pFileDlg
;
531 pImpl
->m_pFileDlg
= new FileDialogHelper(
532 ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE
,
533 SFXWB_INSERT
, rFactory
);
534 return *pImpl
->m_pFileDlg
;
537 ImplDdeItem::~ImplDdeItem()
539 bIsInDTOR
= sal_True
;
540 // So that no-one gets the idea to delete the pointer when Disconnecting!
541 SvBaseLinkRef
aRef( pLink
);
545 DdeData
* ImplDdeItem::Get( sal_uIntPtr nFormat
)
547 if( pLink
->GetObj() )
549 // is it still valid?
550 if( bIsValidData
&& nFormat
== aData
.GetFormat() )
554 OUString
sMimeType( SotExchange::GetFormatMimeType( nFormat
));
555 if( pLink
->GetObj()->GetData( aValue
, sMimeType
) )
557 if( aValue
>>= aSeq
)
559 aData
= DdeData( (const char *)aSeq
.getConstArray(), aSeq
.getLength(), nFormat
);
561 bIsValidData
= sal_True
;
567 bIsValidData
= sal_False
;
572 bool ImplDdeItem::Put( const DdeData
* )
574 OSL_FAIL( "ImplDdeItem::Put not implemented" );
579 void ImplDdeItem::AdviseLoop( bool bOpen
)
581 // Connection is closed, so also unsubscribe link
582 if( pLink
->GetObj() )
586 // A connection is re-established
587 if( OBJECT_DDE_EXTERN
== pLink
->GetObjType() )
589 pLink
->GetObj()->AddDataAdvise( pLink
, OUString("text/plain;charset=utf-16"), ADVISEMODE_NODATA
);
590 pLink
->GetObj()->AddConnectAdvise( pLink
);
595 // So that no-one gets the idea to delete the pointer
596 // when Disconnecting!
597 SvBaseLinkRef
aRef( pLink
);
604 static DdeTopic
* FindTopic( const OUString
& rLinkName
, sal_uInt16
* pItemStt
)
606 if( rLinkName
.isEmpty() )
609 OUString
sNm( rLinkName
);
610 sal_Int32 nTokenPos
= 0;
611 OUString
sService( sNm
.getToken( 0, cTokenSeparator
, nTokenPos
) );
613 DdeServices
& rSvc
= DdeService::GetServices();
614 for (DdeServices::iterator aI
= rSvc
.begin(); aI
!= rSvc
.end(); ++aI
)
616 DdeService
* pService
= *aI
;
617 if( pService
->GetName() == sService
)
619 // then we search for the Topic
620 OUString
sTopic( sNm
.getToken( 0, cTokenSeparator
, nTokenPos
) );
622 *pItemStt
= nTokenPos
;
624 std::vector
<DdeTopic
*>& rTopics
= pService
->GetTopics();
626 for( int i
= 0; i
< 2; ++i
)
628 for( std::vector
<DdeTopic
*>::iterator iterTopic
= rTopics
.begin();
629 iterTopic
!= rTopics
.end(); ++iterTopic
)
630 if( (*iterTopic
)->GetName() == sTopic
)
634 // then we try once to create it
635 if( i
|| !pService
->MakeTopic( sTopic
) )
636 break; // did not work, exiting
646 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */