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/layout.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
)
47 Link
<> m_aEndEditLink
;
48 LinkManager
* m_pLinkMgr
;
49 VclPtr
<vcl::Window
> m_pParentWin
;
50 FileDialogHelper
* m_pFileDlg
;
55 , m_pParentWin( NULL
)
57 , m_bIsConnect( false )
61 { delete m_pFileDlg
; }
64 // only for internal management
65 struct ImplBaseLinkData
69 // applies for all links
70 SotClipboardFormatId nCntntType
; // Update Format
72 bool bIntrnlLnk
; // It is an internal link
73 SfxLinkUpdateMode nUpdateMode
; // UpdateMode
82 tClientType ClientType
;
87 ClientType
.nCntntType
= SotClipboardFormatId::NONE
;
88 ClientType
.bIntrnlLnk
= false;
89 ClientType
.nUpdateMode
= SfxLinkUpdateMode::NONE
;
95 class ImplDdeItem
: public DdeGetPutItem
99 Sequence
< sal_Int8
> aSeq
; // Datacontainer for DdeData !!!
100 bool bIsValidData
: 1;
104 ImplDdeItem( SvBaseLink
& rLink
, const OUString
& rStr
)
105 : DdeGetPutItem( rStr
), pLink( &rLink
), bIsValidData( false ),
109 virtual ~ImplDdeItem();
111 virtual DdeData
* Get( SotClipboardFormatId
) SAL_OVERRIDE
;
112 virtual bool Put( const DdeData
* ) SAL_OVERRIDE
;
113 virtual void AdviseLoop( bool ) SAL_OVERRIDE
;
117 bIsValidData
= false;
118 DdeGetPutItem::NotifyClient();
121 bool IsInDTOR() const { return bIsInDTOR
; }
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
= true;
133 bWasLastEditOK
= false;
138 SvBaseLink::SvBaseLink( SfxLinkUpdateMode nUpdateMode
, SotClipboardFormatId nContentType
)
139 : m_bIsReadOnly(false)
141 pImpl
= new BaseLink_Impl();
142 nObjType
= OBJECT_CLIENT_SO
;
143 pImplData
= new ImplBaseLinkData
;
144 bVisible
= bSynchron
= bUseCache
= true;
145 bWasLastEditOK
= false;
147 // It is going to be a Ole-Link,
148 pImplData
->ClientType
.nUpdateMode
= nUpdateMode
;
149 pImplData
->ClientType
.nCntntType
= nContentType
;
150 pImplData
->ClientType
.bIntrnlLnk
= false;
155 static DdeTopic
* FindTopic( const OUString
& rLinkName
, sal_uInt16
* pItemStt
)
157 if( rLinkName
.isEmpty() )
160 OUString
sNm( rLinkName
);
161 sal_Int32 nTokenPos
= 0;
162 OUString
sService( sNm
.getToken( 0, cTokenSeparator
, nTokenPos
) );
164 DdeServices
& rSvc
= DdeService::GetServices();
165 for (DdeServices::iterator aI
= rSvc
.begin(); aI
!= rSvc
.end(); ++aI
)
167 DdeService
* pService
= *aI
;
168 if( pService
->GetName() == sService
)
170 // then we search for the Topic
171 OUString
sTopic( sNm
.getToken( 0, cTokenSeparator
, nTokenPos
) );
173 *pItemStt
= nTokenPos
;
175 std::vector
<DdeTopic
*>& rTopics
= pService
->GetTopics();
177 for( int i
= 0; i
< 2; ++i
)
179 for( std::vector
<DdeTopic
*>::iterator iterTopic
= rTopics
.begin();
180 iterTopic
!= rTopics
.end(); ++iterTopic
)
181 if( (*iterTopic
)->GetName() == sTopic
)
185 // then we try once to create it
186 if( i
|| !pService
->MakeTopic( sTopic
) )
187 break; // did not work, exiting
195 SvBaseLink::SvBaseLink( const OUString
& rLinkName
, sal_uInt16 nObjectType
, SvLinkSource
* pObj
)
197 , m_bIsReadOnly(false)
199 bVisible
= bSynchron
= bUseCache
= true;
200 bWasLastEditOK
= false;
201 aLinkName
= rLinkName
;
202 pImplData
= new ImplBaseLinkData
;
203 nObjType
= nObjectType
;
207 DBG_ASSERT( pObj
, "Where is my left-most object" );
211 if( OBJECT_DDE_EXTERN
== nObjType
)
213 sal_uInt16 nItemStt
= 0;
214 DdeTopic
* pTopic
= FindTopic( aLinkName
, &nItemStt
);
217 // then we have it all together
218 // MM_TODO how do I get the name
219 OUString aStr
= aLinkName
; // xLinkName->GetDisplayName();
220 aStr
= aStr
.copy( nItemStt
);
221 pImplData
->DDEType
.pItem
= new ImplDdeItem( *this, aStr
);
222 pTopic
->InsertItem( pImplData
->DDEType
.pItem
);
228 else if( pObj
->Connect( this ) )
234 SvBaseLink::~SvBaseLink()
240 case OBJECT_DDE_EXTERN
:
241 if( !pImplData
->DDEType
.pItem
->IsInDTOR() )
242 delete pImplData
->DDEType
.pItem
;
250 IMPL_LINK( SvBaseLink
, EndEditHdl
, OUString
*, _pNewName
)
254 sNewName
= *_pNewName
;
255 if ( !ExecuteEdit( sNewName
) )
257 bWasLastEditOK
= !sNewName
.isEmpty();
258 if ( pImpl
->m_aEndEditLink
.IsSet() )
259 pImpl
->m_aEndEditLink
.Call( this );
265 void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP
)
267 DBG_ASSERT( nObjType
!= OBJECT_CLIENT_DDE
, "type already set" );
268 DBG_ASSERT( !xObj
.Is(), "object exist" );
270 nObjType
= nObjTypeP
;
275 void SvBaseLink::SetName( const OUString
& rNm
)
282 void SvBaseLink::SetObj( SvLinkSource
* pObj
)
284 DBG_ASSERT( (nObjType
& OBJECT_CLIENT_SO
&&
285 pImplData
->ClientType
.bIntrnlLnk
) ||
286 nObjType
== OBJECT_CLIENT_GRF
,
293 void SvBaseLink::SetLinkSourceName( const OUString
& rLnkNm
)
295 if( aLinkName
== rLnkNm
)
298 AddNextRef(); // should be superfluous
299 // remove old connection
306 ReleaseRef(); // should be superfluous
314 void SvBaseLink::SetUpdateMode( SfxLinkUpdateMode nMode
)
316 if( ( OBJECT_CLIENT_SO
& nObjType
) &&
317 pImplData
->ClientType
.nUpdateMode
!= nMode
)
322 pImplData
->ClientType
.nUpdateMode
= nMode
;
329 void SvBaseLink::clearStreamToLoadFrom()
331 m_xInputStreamToLoadFrom
.clear();
334 xObj
->clearStreamToLoadFrom();
338 bool SvBaseLink::Update()
340 if( OBJECT_CLIENT_SO
& nObjType
)
349 xObj
->setStreamToLoadFrom(m_xInputStreamToLoadFrom
,m_bIsReadOnly
);
350 OUString
sMimeType( SotExchange::GetFormatMimeType(
351 pImplData
->ClientType
.nCntntType
));
354 if( xObj
->GetData( aData
, sMimeType
) )
356 UpdateResult eRes
= DataChanged(sMimeType
, aData
);
357 bool bSuccess
= eRes
== SUCCESS
;
358 //for manual Updates there is no need to hold the ServerObject
359 if( OBJECT_CLIENT_DDE
== nObjType
&&
360 SfxLinkUpdateMode::ONCALL
== GetUpdateMode() && xObj
.Is() )
361 xObj
->RemoveAllDataAdvise( this );
366 // should be asynschron?
367 if( xObj
->IsPending() )
370 // we do not need the object anymore
381 SfxLinkUpdateMode
SvBaseLink::GetUpdateMode() const
383 return ( OBJECT_CLIENT_SO
& nObjType
)
384 ? pImplData
->ClientType
.nUpdateMode
385 : SfxLinkUpdateMode::ONCALL
;
389 void SvBaseLink::_GetRealObject( bool bConnect
)
391 if( !pImpl
->m_pLinkMgr
)
394 DBG_ASSERT( !xObj
.Is(), "object already exist" );
396 if( OBJECT_CLIENT_DDE
== nObjType
)
399 if( sfx2::LinkManager::GetDisplayNames( this, &sServer
) &&
400 sServer
== Application::GetAppName() ) // internal Link !!!
402 // so that the Internal link can be created!
403 nObjType
= OBJECT_INTERN
;
404 xObj
= sfx2::LinkManager::CreateObj( this );
406 pImplData
->ClientType
.bIntrnlLnk
= true;
407 nObjType
= OBJECT_CLIENT_DDE
; // so we know what it once was!
411 pImplData
->ClientType
.bIntrnlLnk
= false;
412 xObj
= sfx2::LinkManager::CreateObj( this );
415 else if( (OBJECT_CLIENT_SO
& nObjType
) )
416 xObj
= sfx2::LinkManager::CreateObj( this );
418 if( bConnect
&& ( !xObj
.Is() || !xObj
->Connect( this ) ) )
422 SotClipboardFormatId
SvBaseLink::GetContentType() const
424 if( OBJECT_CLIENT_SO
& nObjType
)
425 return pImplData
->ClientType
.nCntntType
;
427 return SotClipboardFormatId::NONE
; // all Formats ?
431 bool SvBaseLink::SetContentType( SotClipboardFormatId nType
)
433 if( OBJECT_CLIENT_SO
& nObjType
)
435 pImplData
->ClientType
.nCntntType
= nType
;
441 LinkManager
* SvBaseLink::GetLinkManager()
443 return pImpl
->m_pLinkMgr
;
446 const LinkManager
* SvBaseLink::GetLinkManager() const
448 return pImpl
->m_pLinkMgr
;
451 void SvBaseLink::SetLinkManager( LinkManager
* _pMgr
)
453 pImpl
->m_pLinkMgr
= _pMgr
;
456 void SvBaseLink::Disconnect()
460 xObj
->RemoveAllDataAdvise( this );
461 xObj
->RemoveConnectAdvise( this );
466 SvBaseLink::UpdateResult
SvBaseLink::DataChanged( const OUString
&, const ::com::sun::star::uno::Any
& )
470 case OBJECT_DDE_EXTERN
:
471 if( pImplData
->DDEType
.pItem
)
472 pImplData
->DDEType
.pItem
->Notify();
478 void SvBaseLink::Edit( vcl::Window
* pParent
, const Link
<>& rEndEditHdl
)
480 pImpl
->m_pParentWin
= pParent
;
481 pImpl
->m_aEndEditLink
= rEndEditHdl
;
482 pImpl
->m_bIsConnect
= xObj
.Is();
483 if( !pImpl
->m_bIsConnect
)
484 _GetRealObject( xObj
.Is() );
487 Link
<> aLink
= LINK( this, SvBaseLink
, EndEditHdl
);
489 if( OBJECT_CLIENT_SO
& nObjType
&& pImplData
->ClientType
.bIntrnlLnk
)
491 if( pImpl
->m_pLinkMgr
)
493 SvLinkSourceRef ref
= sfx2::LinkManager::CreateObj( this );
496 ref
->Edit( pParent
, this, aLink
);
503 xObj
->Edit( pParent
, this, aLink
);
509 ExecuteEdit( OUString() );
510 bWasLastEditOK
= false;
511 if ( pImpl
->m_aEndEditLink
.IsSet() )
512 pImpl
->m_aEndEditLink
.Call( this );
516 bool SvBaseLink::ExecuteEdit( const OUString
& _rNewName
)
518 if( !_rNewName
.isEmpty() )
520 SetLinkSourceName( _rNewName
);
523 OUString sApp
, sTopic
, sItem
, sError
;
524 sfx2::LinkManager::GetDisplayNames( this, &sApp
, &sTopic
, &sItem
);
525 if( nObjType
== OBJECT_CLIENT_DDE
)
527 sError
= SFX2_RESSTR(STR_DDE_ERROR
);
529 sal_Int32 nFndPos
= sError
.indexOf( '%' );
532 sError
= sError
.replaceAt( nFndPos
, 1, sApp
);
533 nFndPos
= nFndPos
+ sApp
.getLength();
535 if( -1 != ( nFndPos
= sError
.indexOf( '%', nFndPos
)))
537 sError
= sError
.replaceAt( nFndPos
, 1, sTopic
);
538 nFndPos
= nFndPos
+ sTopic
.getLength();
540 if( -1 != ( nFndPos
= sError
.indexOf( '%', nFndPos
)))
541 sError
= sError
.replaceAt( nFndPos
, 1, sItem
);
548 ScopedVclPtrInstance
<MessageDialog
>::Create(pImpl
->m_pParentWin
, sError
)->Execute();
551 else if( !pImpl
->m_bIsConnect
)
553 pImpl
->m_bIsConnect
= false;
557 void SvBaseLink::Closed()
560 xObj
->RemoveAllDataAdvise( this );
563 FileDialogHelper
& SvBaseLink::GetInsertFileDialog(const OUString
& rFactory
) const
565 if ( pImpl
->m_pFileDlg
)
566 delete pImpl
->m_pFileDlg
;
567 pImpl
->m_pFileDlg
= new FileDialogHelper(
568 ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE
,
569 SFXWB_INSERT
, rFactory
);
570 return *pImpl
->m_pFileDlg
;
573 ImplDdeItem::~ImplDdeItem()
576 // So that no-one gets the idea to delete the pointer when Disconnecting!
577 SvBaseLinkRef
aRef( pLink
);
581 DdeData
* ImplDdeItem::Get( SotClipboardFormatId nFormat
)
583 if( pLink
->GetObj() )
585 // is it still valid?
586 if( bIsValidData
&& nFormat
== aData
.GetFormat() )
590 OUString
sMimeType( SotExchange::GetFormatMimeType( nFormat
));
591 if( pLink
->GetObj()->GetData( aValue
, sMimeType
) )
593 if( aValue
>>= aSeq
)
595 aData
= DdeData( aSeq
.getConstArray(), aSeq
.getLength(), nFormat
);
603 bIsValidData
= false;
608 bool ImplDdeItem::Put( const DdeData
* )
610 OSL_FAIL( "ImplDdeItem::Put not implemented" );
615 void ImplDdeItem::AdviseLoop( bool bOpen
)
617 // Connection is closed, so also unsubscribe link
618 if( pLink
->GetObj() )
622 // A connection is re-established
623 if( OBJECT_DDE_EXTERN
== pLink
->GetObjType() )
625 pLink
->GetObj()->AddDataAdvise( pLink
, OUString("text/plain;charset=utf-16"), ADVISEMODE_NODATA
);
626 pLink
->GetObj()->AddConnectAdvise( pLink
);
631 // So that no-one gets the idea to delete the pointer
632 // when Disconnecting!
633 SvBaseLinkRef
aRef( pLink
);
641 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */