1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <sfx2/lnkbase.hxx>
31 #include <sot/exchange.hxx>
32 #include <com/sun/star/uno/Any.hxx>
33 #include <com/sun/star/uno/Sequence.hxx>
34 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
35 #include <vcl/msgbox.hxx>
36 #include <sfx2/linkmgr.hxx>
37 #include <vcl/svapp.hxx>
39 #include "sfx2/sfxresid.hxx"
40 #include <sfx2/filedlghelper.hxx>
41 #include <tools/debug.hxx>
42 #include <svl/svdde.hxx>
44 using namespace ::com::sun::star
;
45 using namespace ::com::sun::star::uno
;
50 TYPEINIT0( SvBaseLink
)
52 static DdeTopic
* FindTopic( const String
&, sal_uInt16
* = 0 );
59 LinkManager
* m_pLinkMgr
;
61 FileDialogHelper
* m_pFileDlg
;
66 , m_pParentWin( NULL
)
68 , m_bIsConnect( false )
72 { delete m_pFileDlg
; }
75 // only for internal management
76 struct ImplBaseLinkData
80 // applies for all links
81 sal_uIntPtr nCntntType
; // Update Format
83 sal_Bool bIntrnlLnk
; // It is an internal link
84 sal_uInt16 nUpdateMode
; // UpdateMode
93 tClientType ClientType
;
98 ClientType
.nCntntType
= 0;
99 ClientType
.bIntrnlLnk
= sal_False
;
100 ClientType
.nUpdateMode
= 0;
101 DDEType
.pItem
= NULL
;
106 class ImplDdeItem
: public DdeGetPutItem
110 Sequence
< sal_Int8
> aSeq
; // Datacontainer for DdeData !!!
111 sal_Bool bIsValidData
: 1;
112 sal_Bool bIsInDTOR
: 1;
114 ImplDdeItem( SvBaseLink
& rLink
, const String
& rStr
)
115 : DdeGetPutItem( rStr
), pLink( &rLink
), bIsValidData( sal_False
),
116 bIsInDTOR( sal_False
)
118 virtual ~ImplDdeItem();
120 virtual DdeData
* Get( sal_uIntPtr
);
121 virtual sal_Bool
Put( const DdeData
* );
122 virtual void AdviseLoop( sal_Bool
);
126 bIsValidData
= sal_False
;
127 DdeGetPutItem::NotifyClient();
130 sal_Bool
IsInDTOR() const { return bIsInDTOR
; }
133 //--------------------------------------------------------------------------
135 SvBaseLink::SvBaseLink()
137 pImpl
= new BaseLink_Impl();
138 nObjType
= OBJECT_CLIENT_SO
;
139 pImplData
= new ImplBaseLinkData
;
140 bVisible
= bSynchron
= bUseCache
= sal_True
;
141 bWasLastEditOK
= sal_False
;
144 //--------------------------------------------------------------------------
146 SvBaseLink::SvBaseLink( sal_uInt16 nUpdateMode
, sal_uIntPtr nContentType
)
148 pImpl
= new BaseLink_Impl();
149 nObjType
= OBJECT_CLIENT_SO
;
150 pImplData
= new ImplBaseLinkData
;
151 bVisible
= bSynchron
= bUseCache
= sal_True
;
152 bWasLastEditOK
= sal_False
;
154 // It it going to be a Ole-Link,
155 pImplData
->ClientType
.nUpdateMode
= nUpdateMode
;
156 pImplData
->ClientType
.nCntntType
= nContentType
;
157 pImplData
->ClientType
.bIntrnlLnk
= sal_False
;
160 //--------------------------------------------------------------------------
162 SvBaseLink::SvBaseLink( const String
& rLinkName
, sal_uInt16 nObjectType
, SvLinkSource
* pObj
)
165 bVisible
= bSynchron
= bUseCache
= sal_True
;
166 bWasLastEditOK
= sal_False
;
167 aLinkName
= rLinkName
;
168 pImplData
= new ImplBaseLinkData
;
169 nObjType
= nObjectType
;
173 DBG_ASSERT( pObj
, "Where is my left-most object" );
177 if( OBJECT_DDE_EXTERN
== nObjType
)
179 sal_uInt16 nItemStt
= 0;
180 DdeTopic
* pTopic
= FindTopic( aLinkName
, &nItemStt
);
183 // then we have it all together
184 // MM_TODO how do I get the name
185 String aStr
= aLinkName
; // xLinkName->GetDisplayName();
186 aStr
= aStr
.Copy( nItemStt
);
187 pImplData
->DDEType
.pItem
= new ImplDdeItem( *this, aStr
);
188 pTopic
->InsertItem( pImplData
->DDEType
.pItem
);
194 else if( pObj
->Connect( this ) )
198 //--------------------------------------------------------------------------
200 SvBaseLink::~SvBaseLink()
206 case OBJECT_DDE_EXTERN
:
207 if( !pImplData
->DDEType
.pItem
->IsInDTOR() )
208 delete pImplData
->DDEType
.pItem
;
216 IMPL_LINK( SvBaseLink
, EndEditHdl
, String
*, _pNewName
)
220 sNewName
= *_pNewName
;
221 if ( !ExecuteEdit( sNewName
) )
223 bWasLastEditOK
= ( sNewName
.Len() > 0 );
224 if ( pImpl
->m_aEndEditLink
.IsSet() )
225 pImpl
->m_aEndEditLink
.Call( this );
229 //--------------------------------------------------------------------------
231 void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP
)
233 DBG_ASSERT( nObjType
!= OBJECT_CLIENT_DDE
, "type already set" );
234 DBG_ASSERT( !xObj
.Is(), "object exist" );
236 nObjType
= nObjTypeP
;
239 //--------------------------------------------------------------------------
241 void SvBaseLink::SetName( const String
& rNm
)
246 //--------------------------------------------------------------------------
248 void SvBaseLink::SetObj( SvLinkSource
* pObj
)
250 DBG_ASSERT( (nObjType
& OBJECT_CLIENT_SO
&&
251 pImplData
->ClientType
.bIntrnlLnk
) ||
252 nObjType
== OBJECT_CLIENT_GRF
,
257 //--------------------------------------------------------------------------
259 void SvBaseLink::SetLinkSourceName( const String
& rLnkNm
)
261 if( aLinkName
== rLnkNm
)
264 AddNextRef(); // should be superfluous
265 // remove old connection
272 ReleaseRef(); // should be superfluous
275 //--------------------------------------------------------------------------
277 String
SvBaseLink::GetLinkSourceName() const
282 //--------------------------------------------------------------------------
284 void SvBaseLink::SetUpdateMode( sal_uInt16 nMode
)
286 if( ( OBJECT_CLIENT_SO
& nObjType
) &&
287 pImplData
->ClientType
.nUpdateMode
!= nMode
)
292 pImplData
->ClientType
.nUpdateMode
= nMode
;
299 void SvBaseLink::clearStreamToLoadFrom()
301 m_xInputStreamToLoadFrom
.clear();
304 xObj
->clearStreamToLoadFrom();
308 sal_Bool
SvBaseLink::Update()
310 if( OBJECT_CLIENT_SO
& nObjType
)
319 xObj
->setStreamToLoadFrom(m_xInputStreamToLoadFrom
,m_bIsReadOnly
);
320 String
sMimeType( SotExchange::GetFormatMimeType(
321 pImplData
->ClientType
.nCntntType
));
324 if( xObj
->GetData( aData
, sMimeType
) )
326 UpdateResult eRes
= DataChanged(sMimeType
, aData
);
327 bool bSuccess
= eRes
== SUCCESS
;
328 //for manual Updates there is no need to hold the ServerObject
329 if( OBJECT_CLIENT_DDE
== nObjType
&&
330 LINKUPDATE_ONCALL
== GetUpdateMode() && xObj
.Is() )
331 xObj
->RemoveAllDataAdvise( this );
336 // should be asynschron?
337 if( xObj
->IsPending() )
340 // we do not need the object anymore
351 sal_uInt16
SvBaseLink::GetUpdateMode() const
353 return ( OBJECT_CLIENT_SO
& nObjType
)
354 ? pImplData
->ClientType
.nUpdateMode
355 : sal::static_int_cast
< sal_uInt16
>( LINKUPDATE_ONCALL
);
359 void SvBaseLink::_GetRealObject( sal_Bool bConnect
)
361 if( !pImpl
->m_pLinkMgr
)
364 DBG_ASSERT( !xObj
.Is(), "object already exist" );
366 if( OBJECT_CLIENT_DDE
== nObjType
)
369 if( pImpl
->m_pLinkMgr
->GetDisplayNames( this, &sServer
) &&
370 sServer
== GetpApp()->GetAppName() ) // internal Link !!!
372 // so that the Internal link can be created!
373 nObjType
= OBJECT_INTERN
;
374 xObj
= pImpl
->m_pLinkMgr
->CreateObj( this );
376 pImplData
->ClientType
.bIntrnlLnk
= sal_True
;
377 nObjType
= OBJECT_CLIENT_DDE
; // so we know what it once was!
381 pImplData
->ClientType
.bIntrnlLnk
= sal_False
;
382 xObj
= pImpl
->m_pLinkMgr
->CreateObj( this );
385 else if( (OBJECT_CLIENT_SO
& nObjType
) )
386 xObj
= pImpl
->m_pLinkMgr
->CreateObj( this );
388 if( bConnect
&& ( !xObj
.Is() || !xObj
->Connect( this ) ) )
392 sal_uIntPtr
SvBaseLink::GetContentType() const
394 if( OBJECT_CLIENT_SO
& nObjType
)
395 return pImplData
->ClientType
.nCntntType
;
397 return 0; // all Formats ?
401 sal_Bool
SvBaseLink::SetContentType( sal_uIntPtr nType
)
403 if( OBJECT_CLIENT_SO
& nObjType
)
405 pImplData
->ClientType
.nCntntType
= nType
;
411 LinkManager
* SvBaseLink::GetLinkManager()
413 return pImpl
->m_pLinkMgr
;
416 const LinkManager
* SvBaseLink::GetLinkManager() const
418 return pImpl
->m_pLinkMgr
;
421 void SvBaseLink::SetLinkManager( LinkManager
* _pMgr
)
423 pImpl
->m_pLinkMgr
= _pMgr
;
426 void SvBaseLink::Disconnect()
430 xObj
->RemoveAllDataAdvise( this );
431 xObj
->RemoveConnectAdvise( this );
436 SvBaseLink::UpdateResult
SvBaseLink::DataChanged( const String
&, const ::com::sun::star::uno::Any
& )
440 case OBJECT_DDE_EXTERN
:
441 if( pImplData
->DDEType
.pItem
)
442 pImplData
->DDEType
.pItem
->Notify();
448 void SvBaseLink::Edit( Window
* pParent
, const Link
& rEndEditHdl
)
450 pImpl
->m_pParentWin
= pParent
;
451 pImpl
->m_aEndEditLink
= rEndEditHdl
;
452 pImpl
->m_bIsConnect
= ( xObj
.Is() != sal_False
);
453 if( !pImpl
->m_bIsConnect
)
454 _GetRealObject( xObj
.Is() );
457 Link aLink
= LINK( this, SvBaseLink
, EndEditHdl
);
459 if( OBJECT_CLIENT_SO
& nObjType
&& pImplData
->ClientType
.bIntrnlLnk
)
461 if( pImpl
->m_pLinkMgr
)
463 SvLinkSourceRef ref
= pImpl
->m_pLinkMgr
->CreateObj( this );
466 ref
->Edit( pParent
, this, aLink
);
473 xObj
->Edit( pParent
, this, aLink
);
479 ExecuteEdit( String() );
480 bWasLastEditOK
= sal_False
;
481 if ( pImpl
->m_aEndEditLink
.IsSet() )
482 pImpl
->m_aEndEditLink
.Call( this );
486 bool SvBaseLink::ExecuteEdit( const String
& _rNewName
)
488 if( _rNewName
.Len() != 0 )
490 SetLinkSourceName( _rNewName
);
493 String sApp
, sTopic
, sItem
, sError
;
494 pImpl
->m_pLinkMgr
->GetDisplayNames( this, &sApp
, &sTopic
, &sItem
);
495 if( nObjType
== OBJECT_CLIENT_DDE
)
497 sError
= SFX2_RESSTR(STR_DDE_ERROR
);
499 sal_uInt16 nFndPos
= sError
.Search( '%' );
500 if( STRING_NOTFOUND
!= nFndPos
)
502 sError
.Erase( nFndPos
, 1 ).Insert( sApp
, nFndPos
);
503 nFndPos
= nFndPos
+ sApp
.Len();
505 if( STRING_NOTFOUND
!= ( nFndPos
= sError
.Search( '%', nFndPos
)))
507 sError
.Erase( nFndPos
, 1 ).Insert( sTopic
, nFndPos
);
508 nFndPos
= nFndPos
+ sTopic
.Len();
510 if( STRING_NOTFOUND
!= ( nFndPos
= sError
.Search( '%', nFndPos
)))
511 sError
.Erase( nFndPos
, 1 ).Insert( sItem
, nFndPos
);
516 ErrorBox( pImpl
->m_pParentWin
, WB_OK
, sError
).Execute();
519 else if( !pImpl
->m_bIsConnect
)
521 pImpl
->m_bIsConnect
= false;
525 void SvBaseLink::Closed()
528 xObj
->RemoveAllDataAdvise( this );
531 FileDialogHelper
& SvBaseLink::GetInsertFileDialog(const String
& rFactory
) const
533 if ( pImpl
->m_pFileDlg
)
534 delete pImpl
->m_pFileDlg
;
535 pImpl
->m_pFileDlg
= new FileDialogHelper(
536 ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE
,
537 SFXWB_INSERT
, rFactory
);
538 return *pImpl
->m_pFileDlg
;
541 ImplDdeItem::~ImplDdeItem()
543 bIsInDTOR
= sal_True
;
544 // So that no-one gets the idea to delete the pointer when Disconnecting!
545 SvBaseLinkRef
aRef( pLink
);
549 DdeData
* ImplDdeItem::Get( sal_uIntPtr nFormat
)
551 if( pLink
->GetObj() )
553 // is it still valid?
554 if( bIsValidData
&& nFormat
== aData
.GetFormat() )
558 String
sMimeType( SotExchange::GetFormatMimeType( nFormat
));
559 if( pLink
->GetObj()->GetData( aValue
, sMimeType
) )
561 if( aValue
>>= aSeq
)
563 aData
= DdeData( (const char *)aSeq
.getConstArray(), aSeq
.getLength(), nFormat
);
565 bIsValidData
= sal_True
;
571 bIsValidData
= sal_False
;
576 sal_Bool
ImplDdeItem::Put( const DdeData
* )
578 OSL_FAIL( "ImplDdeItem::Put not implemented" );
583 void ImplDdeItem::AdviseLoop( sal_Bool bOpen
)
585 // Connection is closed, so also unsubscribe link
586 if( pLink
->GetObj() )
590 // A connection is re-established
591 if( OBJECT_DDE_EXTERN
== pLink
->GetObjType() )
593 pLink
->GetObj()->AddDataAdvise( pLink
, String::CreateFromAscii( "text/plain;charset=utf-16" ), ADVISEMODE_NODATA
);
594 pLink
->GetObj()->AddConnectAdvise( pLink
);
599 // So that no-one gets the idea to delete the pointer
600 // when Disconnecting!
601 SvBaseLinkRef
aRef( pLink
);
608 static DdeTopic
* FindTopic( const String
& rLinkName
, sal_uInt16
* pItemStt
)
610 if( 0 == rLinkName
.Len() )
613 String
sNm( rLinkName
);
614 sal_uInt16 nTokenPos
= 0;
615 String
sService( sNm
.GetToken( 0, cTokenSeperator
, nTokenPos
) );
617 DdeServices
& rSvc
= DdeService::GetServices();
618 for( DdeService
* pService
= rSvc
.First(); pService
;
619 pService
= rSvc
.Next() )
620 if( pService
->GetName() == sService
)
622 // then we search for the Topic
623 String
sTopic( sNm
.GetToken( 0, cTokenSeperator
, nTokenPos
) );
625 *pItemStt
= nTokenPos
;
627 std::vector
<DdeTopic
*>& rTopics
= pService
->GetTopics();
629 for( int i
= 0; i
< 2; ++i
)
631 for( std::vector
<DdeTopic
*>::iterator iterTopic
= rTopics
.begin();
632 iterTopic
!= rTopics
.end(); ++iterTopic
)
633 if( (*iterTopic
)->GetName() == sTopic
)
637 // then we try once to create it
638 if( i
|| !pService
->MakeTopic( sTopic
) )
639 break; // did not work, exiting
648 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */