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 String
&, 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 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
);
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
)
156 bVisible
= bSynchron
= bUseCache
= sal_True
;
157 bWasLastEditOK
= sal_False
;
158 aLinkName
= rLinkName
;
159 pImplData
= new ImplBaseLinkData
;
160 nObjType
= nObjectType
;
164 DBG_ASSERT( pObj
, "Where is my left-most object" );
168 if( OBJECT_DDE_EXTERN
== nObjType
)
170 sal_uInt16 nItemStt
= 0;
171 DdeTopic
* pTopic
= FindTopic( aLinkName
, &nItemStt
);
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
);
185 else if( pObj
->Connect( this ) )
189 //--------------------------------------------------------------------------
191 SvBaseLink::~SvBaseLink()
197 case OBJECT_DDE_EXTERN
:
198 if( !pImplData
->DDEType
.pItem
->IsInDTOR() )
199 delete pImplData
->DDEType
.pItem
;
207 IMPL_LINK( SvBaseLink
, EndEditHdl
, String
*, _pNewName
)
211 sNewName
= *_pNewName
;
212 if ( !ExecuteEdit( sNewName
) )
214 bWasLastEditOK
= ( sNewName
.Len() > 0 );
215 if ( pImpl
->m_aEndEditLink
.IsSet() )
216 pImpl
->m_aEndEditLink
.Call( this );
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
)
237 //--------------------------------------------------------------------------
239 void SvBaseLink::SetObj( SvLinkSource
* pObj
)
241 DBG_ASSERT( (nObjType
& OBJECT_CLIENT_SO
&&
242 pImplData
->ClientType
.bIntrnlLnk
) ||
243 nObjType
== OBJECT_CLIENT_GRF
,
248 //--------------------------------------------------------------------------
250 void SvBaseLink::SetLinkSourceName( const String
& rLnkNm
)
252 if( aLinkName
== rLnkNm
)
255 AddNextRef(); // should be superfluous
256 // remove old connection
263 ReleaseRef(); // should be superfluous
266 //--------------------------------------------------------------------------
268 String
SvBaseLink::GetLinkSourceName() const
273 //--------------------------------------------------------------------------
275 void SvBaseLink::SetUpdateMode( sal_uInt16 nMode
)
277 if( ( OBJECT_CLIENT_SO
& nObjType
) &&
278 pImplData
->ClientType
.nUpdateMode
!= nMode
)
283 pImplData
->ClientType
.nUpdateMode
= nMode
;
290 void SvBaseLink::clearStreamToLoadFrom()
292 m_xInputStreamToLoadFrom
.clear();
295 xObj
->clearStreamToLoadFrom();
299 sal_Bool
SvBaseLink::Update()
301 if( OBJECT_CLIENT_SO
& nObjType
)
310 xObj
->setStreamToLoadFrom(m_xInputStreamToLoadFrom
,m_bIsReadOnly
);
311 String
sMimeType( SotExchange::GetFormatMimeType(
312 pImplData
->ClientType
.nCntntType
));
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 );
327 // should be asynschron?
328 if( xObj
->IsPending() )
331 // we do not need the object anymore
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
)
355 DBG_ASSERT( !xObj
.Is(), "object already exist" );
357 if( OBJECT_CLIENT_DDE
== nObjType
)
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!
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 ) ) )
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
;
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()
421 xObj
->RemoveAllDataAdvise( this );
422 xObj
->RemoveConnectAdvise( this );
427 SvBaseLink::UpdateResult
SvBaseLink::DataChanged( const String
&, const ::com::sun::star::uno::Any
& )
431 case OBJECT_DDE_EXTERN
:
432 if( pImplData
->DDEType
.pItem
)
433 pImplData
->DDEType
.pItem
->Notify();
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() );
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 );
457 ref
->Edit( pParent
, this, aLink
);
464 xObj
->Edit( pParent
, this, aLink
);
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
);
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
);
507 ErrorBox( pImpl
->m_pParentWin
, WB_OK
, sError
).Execute();
510 else if( !pImpl
->m_bIsConnect
)
512 pImpl
->m_bIsConnect
= false;
516 void SvBaseLink::Closed()
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
);
540 DdeData
* ImplDdeItem::Get( sal_uIntPtr nFormat
)
542 if( pLink
->GetObj() )
544 // is it still valid?
545 if( bIsValidData
&& nFormat
== aData
.GetFormat() )
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
;
562 bIsValidData
= sal_False
;
567 sal_Bool
ImplDdeItem::Put( const DdeData
* )
569 OSL_FAIL( "ImplDdeItem::Put not implemented" );
574 void ImplDdeItem::AdviseLoop( sal_Bool bOpen
)
576 // Connection is closed, so also unsubscribe link
577 if( pLink
->GetObj() )
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
);
590 // So that no-one gets the idea to delete the pointer
591 // when Disconnecting!
592 SvBaseLinkRef
aRef( pLink
);
599 static DdeTopic
* FindTopic( const String
& rLinkName
, sal_uInt16
* pItemStt
)
601 if( 0 == rLinkName
.Len() )
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
) );
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
)
629 // then we try once to create it
630 if( i
|| !pService
->MakeTopic( sTopic
) )
631 break; // did not work, exiting
641 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */