1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: lnkbase2.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sfx2.hxx"
35 #include <sfx2/lnkbase.hxx>
36 #include <sot/exchange.hxx>
37 #include <com/sun/star/uno/Any.hxx>
38 #include <com/sun/star/uno/Sequence.hxx>
39 #include <vcl/msgbox.hxx>
41 #include <sfx2/linkmgr.hxx>
42 //#include "svuidlg.hrc"
43 //#include "iface.hxx"
44 #include <vcl/svapp.hxx>
45 //#include <soerr.hxx>
48 #include "sfxresid.hxx"
49 #include <sfx2/filedlghelper.hxx>
51 #include <tools/debug.hxx>
53 #include <svtools/svdde.hxx>
55 using namespace ::com::sun::star::uno
;
60 TYPEINIT0( SvBaseLink
)
62 static DdeTopic
* FindTopic( const String
&, USHORT
* = 0 );
69 SvLinkManager
* m_pLinkMgr
;
71 FileDialogHelper
* m_pFileDlg
;
76 , m_pParentWin( NULL
)
78 , m_bIsConnect( false )
82 { delete m_pFileDlg
; }
85 // nur fuer die interne Verwaltung
86 struct ImplBaseLinkData
90 // gilt fuer alle Links
91 ULONG nCntntType
; // Update Format
93 BOOL bIntrnlLnk
; // ist es ein interner Link
94 USHORT nUpdateMode
;// UpdateMode
103 tClientType ClientType
;
108 ClientType
.nCntntType
= 0;
109 ClientType
.bIntrnlLnk
= FALSE
;
110 ClientType
.nUpdateMode
= 0;
111 DDEType
.pItem
= NULL
;
116 class ImplDdeItem
: public DdeGetPutItem
120 Sequence
< sal_Int8
> aSeq
; // Datacontainer for DdeData !!!
121 BOOL bIsValidData
: 1;
124 ImplDdeItem( SvBaseLink
& rLink
, const String
& rStr
)
125 : DdeGetPutItem( rStr
), pLink( &rLink
), bIsValidData( FALSE
),
128 virtual ~ImplDdeItem();
130 virtual DdeData
* Get( ULONG
);
131 virtual BOOL
Put( const DdeData
* );
132 virtual void AdviseLoop( BOOL
);
136 bIsValidData
= FALSE
;
137 DdeGetPutItem::NotifyClient();
140 BOOL
IsInDTOR() const { return bIsInDTOR
; }
144 /************************************************************************
145 |* SvBaseLink::SvBaseLink()
148 *************************************************************************/
150 SvBaseLink::SvBaseLink()
152 pImpl
= new BaseLink_Impl();
153 nObjType
= OBJECT_CLIENT_SO
;
154 pImplData
= new ImplBaseLinkData
;
155 bVisible
= bSynchron
= bUseCache
= TRUE
;
156 bWasLastEditOK
= FALSE
;
159 /************************************************************************
160 |* SvBaseLink::SvBaseLink()
163 *************************************************************************/
165 SvBaseLink::SvBaseLink( USHORT nUpdateMode
, ULONG nContentType
)
167 pImpl
= new BaseLink_Impl();
168 nObjType
= OBJECT_CLIENT_SO
;
169 pImplData
= new ImplBaseLinkData
;
170 bVisible
= bSynchron
= bUseCache
= TRUE
;
171 bWasLastEditOK
= FALSE
;
173 // falls es ein Ole-Link wird,
174 pImplData
->ClientType
.nUpdateMode
= nUpdateMode
;
175 pImplData
->ClientType
.nCntntType
= nContentType
;
176 pImplData
->ClientType
.bIntrnlLnk
= FALSE
;
179 /************************************************************************
180 |* SvBaseLink::SvBaseLink()
183 *************************************************************************/
185 SvBaseLink::SvBaseLink( const String
& rLinkName
, USHORT nObjectType
, SvLinkSource
* pObj
)
187 bVisible
= bSynchron
= bUseCache
= TRUE
;
188 bWasLastEditOK
= FALSE
;
189 aLinkName
= rLinkName
;
190 pImplData
= new ImplBaseLinkData
;
191 nObjType
= nObjectType
;
195 DBG_ASSERT( pObj
, "Wo ist mein zu linkendes Object" );
199 if( OBJECT_DDE_EXTERN
== nObjType
)
202 DdeTopic
* pTopic
= FindTopic( aLinkName
, &nItemStt
);
205 // dann haben wir alles zusammen
206 // MM hat gefummelt ???
207 // MM_TODO wie kriege ich den Namen
208 String aStr
= aLinkName
; // xLinkName->GetDisplayName();
209 aStr
= aStr
.Copy( nItemStt
);
210 pImplData
->DDEType
.pItem
= new ImplDdeItem( *this, aStr
);
211 pTopic
->InsertItem( pImplData
->DDEType
.pItem
);
213 // dann koennen wir uns auch das Advise merken
217 else if( pObj
->Connect( this ) )
221 /************************************************************************
222 |* SvBaseLink::~SvBaseLink()
225 *************************************************************************/
227 SvBaseLink::~SvBaseLink()
233 case OBJECT_DDE_EXTERN
:
234 if( !pImplData
->DDEType
.pItem
->IsInDTOR() )
235 delete pImplData
->DDEType
.pItem
;
242 IMPL_LINK( SvBaseLink
, EndEditHdl
, String
*, _pNewName
)
246 sNewName
= *_pNewName
;
247 if ( !ExecuteEdit( sNewName
) )
249 bWasLastEditOK
= ( sNewName
.Len() > 0 );
250 if ( pImpl
->m_aEndEditLink
.IsSet() )
251 pImpl
->m_aEndEditLink
.Call( this );
255 /************************************************************************
256 |* SvBaseLink::SetObjType()
259 *************************************************************************/
261 void SvBaseLink::SetObjType( USHORT nObjTypeP
)
263 DBG_ASSERT( nObjType
!= OBJECT_CLIENT_DDE
, "type already set" );
264 DBG_ASSERT( !xObj
.Is(), "object exist" );
266 nObjType
= nObjTypeP
;
269 /************************************************************************
270 |* SvBaseLink::SetName()
273 *************************************************************************/
275 void SvBaseLink::SetName( const String
& rNm
)
280 /************************************************************************
281 |* SvBaseLink::GetName()
284 *************************************************************************/
286 String
SvBaseLink::GetName() const
291 /************************************************************************
292 |* SvBaseLink::SetObj()
295 *************************************************************************/
297 void SvBaseLink::SetObj( SvLinkSource
* pObj
)
299 DBG_ASSERT( (nObjType
& OBJECT_CLIENT_SO
&&
300 pImplData
->ClientType
.bIntrnlLnk
) ||
301 nObjType
== OBJECT_CLIENT_GRF
,
306 /************************************************************************
307 |* SvBaseLink::SetLinkSourceName()
310 *************************************************************************/
312 void SvBaseLink::SetLinkSourceName( const String
& rLnkNm
)
314 if( aLinkName
== rLnkNm
)
317 AddNextRef(); // sollte ueberfluessig sein
318 // Alte Verbindung weg
325 ReleaseRef(); // sollte ueberfluessig sein
328 /************************************************************************
329 |* SvBaseLink::GetLinkSourceName()
332 *************************************************************************/
334 String
SvBaseLink::GetLinkSourceName() const
340 /************************************************************************
341 |* SvBaseLink::SetUpdateMode()
344 *************************************************************************/
346 void SvBaseLink::SetUpdateMode( USHORT nMode
)
348 if( ( OBJECT_CLIENT_SO
& nObjType
) &&
349 pImplData
->ClientType
.nUpdateMode
!= nMode
)
354 pImplData
->ClientType
.nUpdateMode
= nMode
;
360 // --> OD 2008-06-19 #i88291#
361 void SvBaseLink::clearStreamToLoadFrom()
363 m_xInputStreamToLoadFrom
.clear();
366 xObj
->clearStreamToLoadFrom();
371 BOOL
SvBaseLink::Update()
373 if( OBJECT_CLIENT_SO
& nObjType
)
382 xObj
->setStreamToLoadFrom(m_xInputStreamToLoadFrom
,m_bIsReadOnly
);
383 // m_xInputStreamToLoadFrom = 0;
384 String
sMimeType( SotExchange::GetFormatMimeType(
385 pImplData
->ClientType
.nCntntType
));
388 if( xObj
->GetData( aData
, sMimeType
) )
390 DataChanged( sMimeType
, aData
);
391 //JP 13.07.00: Bug 76817 - for manual Updates there is no
392 // need to hold the ServerObject
393 if( OBJECT_CLIENT_DDE
== nObjType
&&
394 LINKUPDATE_ONCALL
== GetUpdateMode() && xObj
.Is() )
395 xObj
->RemoveAllDataAdvise( this );
400 // sollten wir asynschron sein?
401 if( xObj
->IsPending() )
404 // dann brauchen wir das Object auch nicht mehr
415 USHORT
SvBaseLink::GetUpdateMode() const
417 return ( OBJECT_CLIENT_SO
& nObjType
)
418 ? pImplData
->ClientType
.nUpdateMode
419 : sal::static_int_cast
< USHORT
>( LINKUPDATE_ONCALL
);
423 void SvBaseLink::_GetRealObject( BOOL bConnect
)
425 if( !pImpl
->m_pLinkMgr
)
428 DBG_ASSERT( !xObj
.Is(), "object already exist" );
430 if( OBJECT_CLIENT_DDE
== nObjType
)
433 if( pImpl
->m_pLinkMgr
->GetDisplayNames( this, &sServer
) &&
434 sServer
== GetpApp()->GetAppName() ) // interner Link !!!
436 // damit der Internal - Link erzeugt werden kann !!!
437 nObjType
= OBJECT_INTERN
;
438 xObj
= pImpl
->m_pLinkMgr
->CreateObj( this );
440 pImplData
->ClientType
.bIntrnlLnk
= TRUE
;
441 nObjType
= OBJECT_CLIENT_DDE
; // damit wir wissen was es mal war !!
445 pImplData
->ClientType
.bIntrnlLnk
= FALSE
;
446 xObj
= pImpl
->m_pLinkMgr
->CreateObj( this );
449 else if( (OBJECT_CLIENT_SO
& nObjType
) )
450 xObj
= pImpl
->m_pLinkMgr
->CreateObj( this );
452 if( bConnect
&& ( !xObj
.Is() || !xObj
->Connect( this ) ) )
456 ULONG
SvBaseLink::GetContentType() const
458 if( OBJECT_CLIENT_SO
& nObjType
)
459 return pImplData
->ClientType
.nCntntType
;
461 return 0; // alle Formate ?
465 BOOL
SvBaseLink::SetContentType( ULONG nType
)
467 if( OBJECT_CLIENT_SO
& nObjType
)
469 pImplData
->ClientType
.nCntntType
= nType
;
475 SvLinkManager
* SvBaseLink::GetLinkManager()
477 return pImpl
->m_pLinkMgr
;
480 const SvLinkManager
* SvBaseLink::GetLinkManager() const
482 return pImpl
->m_pLinkMgr
;
485 void SvBaseLink::SetLinkManager( SvLinkManager
* _pMgr
)
487 pImpl
->m_pLinkMgr
= _pMgr
;
490 void SvBaseLink::Disconnect()
494 xObj
->RemoveAllDataAdvise( this );
495 xObj
->RemoveConnectAdvise( this );
500 void SvBaseLink::DataChanged( const String
&, const ::com::sun::star::uno::Any
& )
504 case OBJECT_DDE_EXTERN
:
505 if( pImplData
->DDEType
.pItem
)
506 pImplData
->DDEType
.pItem
->Notify();
511 void SvBaseLink::Edit( Window
* pParent
, const Link
& rEndEditHdl
)
513 pImpl
->m_pParentWin
= pParent
;
514 pImpl
->m_aEndEditLink
= rEndEditHdl
;
515 pImpl
->m_bIsConnect
= ( xObj
.Is() != sal_False
);
516 if( !pImpl
->m_bIsConnect
)
517 _GetRealObject( xObj
.Is() );
520 Link aLink
= LINK( this, SvBaseLink
, EndEditHdl
);
522 if( OBJECT_CLIENT_SO
& nObjType
&& pImplData
->ClientType
.bIntrnlLnk
)
524 if( pImpl
->m_pLinkMgr
)
526 SvLinkSourceRef ref
= pImpl
->m_pLinkMgr
->CreateObj( this );
529 ref
->Edit( pParent
, this, aLink
);
536 xObj
->Edit( pParent
, this, aLink
);
542 ExecuteEdit( String() );
543 bWasLastEditOK
= FALSE
;
544 if ( pImpl
->m_aEndEditLink
.IsSet() )
545 pImpl
->m_aEndEditLink
.Call( this );
549 bool SvBaseLink::ExecuteEdit( const String
& _rNewName
)
551 if( _rNewName
.Len() != 0 )
553 SetLinkSourceName( _rNewName
);
556 String sApp
, sTopic
, sItem
, sError
;
557 pImpl
->m_pLinkMgr
->GetDisplayNames( this, &sApp
, &sTopic
, &sItem
);
558 if( nObjType
== OBJECT_CLIENT_DDE
)
560 sError
= SfxResId( STR_DDE_ERROR
);
562 USHORT nFndPos
= sError
.Search( '%' );
563 if( STRING_NOTFOUND
!= nFndPos
)
565 sError
.Erase( nFndPos
, 1 ).Insert( sApp
, nFndPos
);
566 nFndPos
= nFndPos
+ sApp
.Len();
568 if( STRING_NOTFOUND
!= ( nFndPos
= sError
.Search( '%', nFndPos
)))
570 sError
.Erase( nFndPos
, 1 ).Insert( sTopic
, nFndPos
);
571 nFndPos
= nFndPos
+ sTopic
.Len();
573 if( STRING_NOTFOUND
!= ( nFndPos
= sError
.Search( '%', nFndPos
)))
574 sError
.Erase( nFndPos
, 1 ).Insert( sItem
, nFndPos
);
579 ErrorBox( pImpl
->m_pParentWin
, WB_OK
, sError
).Execute();
582 else if( !pImpl
->m_bIsConnect
)
584 pImpl
->m_bIsConnect
= false;
588 void SvBaseLink::Closed()
591 // beim Advise Abmelden
592 xObj
->RemoveAllDataAdvise( this );
595 FileDialogHelper
* SvBaseLink::GetFileDialog( sal_uInt32 nFlags
, const String
& rFactory
) const
597 if ( pImpl
->m_pFileDlg
)
598 delete pImpl
->m_pFileDlg
;
599 pImpl
->m_pFileDlg
= new FileDialogHelper( nFlags
, rFactory
);
600 return pImpl
->m_pFileDlg
;
603 ImplDdeItem::~ImplDdeItem()
606 // damit im Disconnect nicht jemand auf die Idee kommt, den Pointer zu
608 SvBaseLinkRef
aRef( pLink
);
612 DdeData
* ImplDdeItem::Get( ULONG nFormat
)
614 if( pLink
->GetObj() )
616 // ist das noch gueltig?
617 if( bIsValidData
&& nFormat
== aData
.GetFormat() )
621 String
sMimeType( SotExchange::GetFormatMimeType( nFormat
));
622 if( pLink
->GetObj()->GetData( aValue
, sMimeType
) )
624 if( aValue
>>= aSeq
)
626 aData
= DdeData( (const char *)aSeq
.getConstArray(), aSeq
.getLength(), nFormat
);
634 bIsValidData
= FALSE
;
639 BOOL
ImplDdeItem::Put( const DdeData
* )
641 DBG_ERROR( "ImplDdeItem::Put not implemented" );
646 void ImplDdeItem::AdviseLoop( BOOL bOpen
)
648 // Verbindung wird geschlossen, also Link abmelden
649 if( pLink
->GetObj() )
653 // es wird wieder eine Verbindung hergestellt
654 if( OBJECT_DDE_EXTERN
== pLink
->GetObjType() )
656 pLink
->GetObj()->AddDataAdvise( pLink
, String::CreateFromAscii( "text/plain;charset=utf-16" ), ADVISEMODE_NODATA
);
657 pLink
->GetObj()->AddConnectAdvise( pLink
);
662 // damit im Disconnect nicht jemand auf die Idee kommt,
663 // den Pointer zu loeschen!!
664 SvBaseLinkRef
aRef( pLink
);
671 static DdeTopic
* FindTopic( const String
& rLinkName
, USHORT
* pItemStt
)
673 if( 0 == rLinkName
.Len() )
676 String
sNm( rLinkName
);
677 USHORT nTokenPos
= 0;
678 String
sService( sNm
.GetToken( 0, cTokenSeperator
, nTokenPos
) );
680 DdeServices
& rSvc
= DdeService::GetServices();
681 for( DdeService
* pService
= rSvc
.First(); pService
;
682 pService
= rSvc
.Next() )
683 if( pService
->GetName() == sService
)
685 // dann suchen wir uns das Topic
686 String
sTopic( sNm
.GetToken( 0, cTokenSeperator
, nTokenPos
) );
688 *pItemStt
= nTokenPos
;
690 DdeTopics
& rTopics
= pService
->GetTopics();
692 for( int i
= 0; i
< 2; ++i
)
694 for( DdeTopic
* pTopic
= rTopics
.First(); pTopic
;
695 pTopic
= rTopics
.Next() )
696 if( pTopic
->GetName() == sTopic
)
699 // Topic nicht gefunden ?
700 // dann versuchen wir ihn mal anzulegen
701 if( i
|| !pService
->MakeTopic( sTopic
) )
702 break; // hat nicht geklappt, also raus