/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sfx2.hxx" #include #include #include #include #include #include #include #include "app.hrc" #include "sfx2/sfxresid.hxx" #include #include #include using namespace ::com::sun::star::uno; namespace sfx2 { TYPEINIT0( SvBaseLink ) static DdeTopic* FindTopic( const String &, sal_uInt16* = 0 ); class ImplDdeItem; struct BaseLink_Impl { Link m_aEndEditLink; LinkManager* m_pLinkMgr; Window* m_pParentWin; FileDialogHelper* m_pFileDlg; bool m_bIsConnect; BaseLink_Impl() : m_pLinkMgr( NULL ) , m_pParentWin( NULL ) , m_pFileDlg( NULL ) , m_bIsConnect( false ) {} ~BaseLink_Impl() { delete m_pFileDlg; } }; // nur fuer die interne Verwaltung struct ImplBaseLinkData { struct tClientType { // gilt fuer alle Links sal_uIntPtr nCntntType; // Update Format // nicht Ole-Links sal_Bool bIntrnlLnk; // ist es ein interner Link sal_uInt16 nUpdateMode;// UpdateMode }; struct tDDEType { ImplDdeItem* pItem; }; union { tClientType ClientType; tDDEType DDEType; }; ImplBaseLinkData() { ClientType.nCntntType = 0; ClientType.bIntrnlLnk = sal_False; ClientType.nUpdateMode = 0; DDEType.pItem = NULL; } }; class ImplDdeItem : public DdeGetPutItem { SvBaseLink* pLink; DdeData aData; Sequence< sal_Int8 > aSeq; // Datacontainer for DdeData !!! sal_Bool bIsValidData : 1; sal_Bool bIsInDTOR : 1; public: ImplDdeItem( SvBaseLink& rLink, const String& rStr ) : DdeGetPutItem( rStr ), pLink( &rLink ), bIsValidData( sal_False ), bIsInDTOR( sal_False ) {} virtual ~ImplDdeItem(); virtual DdeData* Get( sal_uIntPtr ); virtual sal_Bool Put( const DdeData* ); virtual void AdviseLoop( sal_Bool ); void Notify() { bIsValidData = sal_False; DdeGetPutItem::NotifyClient(); } sal_Bool IsInDTOR() const { return bIsInDTOR; } }; /************************************************************************ |* SvBaseLink::SvBaseLink() |* |* Beschreibung *************************************************************************/ SvBaseLink::SvBaseLink() : SvRefBase(), xObj(), aLinkName(), pImpl(new BaseLink_Impl()), nObjType(OBJECT_CLIENT_SO), bVisible(sal_True), bSynchron(sal_True), bUseCache(sal_True), bWasLastEditOK(sal_False), pImplData(new ImplBaseLinkData), m_bIsReadOnly(false), m_xInputStreamToLoadFrom() { } /************************************************************************ |* SvBaseLink::SvBaseLink() |* |* Beschreibung *************************************************************************/ SvBaseLink::SvBaseLink( sal_uInt16 nUpdateMode, sal_uIntPtr nContentType ) : SvRefBase(), xObj(), aLinkName(), pImpl(new BaseLink_Impl()), nObjType(OBJECT_CLIENT_SO), bVisible(sal_True), bSynchron(sal_True), bUseCache(sal_True), bWasLastEditOK(sal_False), pImplData(new ImplBaseLinkData), m_bIsReadOnly(false), m_xInputStreamToLoadFrom() { // falls es ein Ole-Link wird, pImplData->ClientType.nUpdateMode = nUpdateMode; pImplData->ClientType.nCntntType = nContentType; pImplData->ClientType.bIntrnlLnk = sal_False; } /************************************************************************ |* SvBaseLink::SvBaseLink() |* |* Beschreibung *************************************************************************/ SvBaseLink::SvBaseLink( const String& rLinkName, sal_uInt16 nObjectType, SvLinkSource* pObj ) : SvRefBase(), xObj(), aLinkName(rLinkName), pImpl(0), nObjType(nObjectType), bVisible(sal_True), bSynchron(sal_True), bUseCache(sal_True), bWasLastEditOK(sal_False), pImplData(new ImplBaseLinkData), m_bIsReadOnly(false), m_xInputStreamToLoadFrom() { if( !pObj ) { DBG_ASSERT( pObj, "Wo ist mein zu linkendes Object" ); return; } if( OBJECT_DDE_EXTERN == nObjType ) { sal_uInt16 nItemStt = 0; DdeTopic* pTopic = FindTopic( aLinkName, &nItemStt ); if( pTopic ) { // dann haben wir alles zusammen // MM hat gefummelt ??? // MM_TODO wie kriege ich den Namen String aStr = aLinkName; // xLinkName->GetDisplayName(); aStr = aStr.Copy( nItemStt ); pImplData->DDEType.pItem = new ImplDdeItem( *this, aStr ); pTopic->InsertItem( pImplData->DDEType.pItem ); // dann koennen wir uns auch das Advise merken xObj = pObj; } } else if( pObj->Connect( this ) ) xObj = pObj; } /************************************************************************ |* SvBaseLink::~SvBaseLink() |* |* Beschreibung *************************************************************************/ SvBaseLink::~SvBaseLink() { Disconnect(); switch( nObjType ) { case OBJECT_DDE_EXTERN: if( !pImplData->DDEType.pItem->IsInDTOR() ) delete pImplData->DDEType.pItem; break; } delete pImplData; if(pImpl) { delete pImpl; } } IMPL_LINK( SvBaseLink, EndEditHdl, String*, _pNewName ) { if(pImpl) { String sNewName; if ( _pNewName ) sNewName = *_pNewName; if ( !ExecuteEdit( sNewName ) ) sNewName.Erase(); bWasLastEditOK = ( sNewName.Len() > 0 ); if ( pImpl->m_aEndEditLink.IsSet() ) pImpl->m_aEndEditLink.Call( this ); } else { OSL_ENSURE(false, "No pImpl (!)"); } return 0; } /************************************************************************ |* SvBaseLink::SetObjType() |* |* Beschreibung *************************************************************************/ void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP ) { DBG_ASSERT( nObjType != OBJECT_CLIENT_DDE, "type already set" ); DBG_ASSERT( !xObj.Is(), "object exist" ); nObjType = nObjTypeP; } /************************************************************************ |* SvBaseLink::SetName() |* |* Beschreibung *************************************************************************/ void SvBaseLink::SetName( const String & rNm ) { aLinkName = rNm; } /************************************************************************ |* SvBaseLink::GetName() |* |* Beschreibung *************************************************************************/ String SvBaseLink::GetName() const { return aLinkName; } /************************************************************************ |* SvBaseLink::SetObj() |* |* Beschreibung *************************************************************************/ void SvBaseLink::SetObj( SvLinkSource * pObj ) { DBG_ASSERT( (nObjType & OBJECT_CLIENT_SO && pImplData->ClientType.bIntrnlLnk) || nObjType == OBJECT_CLIENT_GRF, "no intern link" ); xObj = pObj; } /************************************************************************ |* SvBaseLink::SetLinkSourceName() |* |* Beschreibung *************************************************************************/ void SvBaseLink::SetLinkSourceName( const String & rLnkNm ) { if( aLinkName == rLnkNm ) return; AddNextRef(); // sollte ueberfluessig sein // Alte Verbindung weg Disconnect(); aLinkName = rLnkNm; // Neu verbinden _GetRealObject(); ReleaseRef(); // sollte ueberfluessig sein } /************************************************************************ |* SvBaseLink::GetLinkSourceName() |* |* Beschreibung *************************************************************************/ String SvBaseLink::GetLinkSourceName() const { return aLinkName; } /************************************************************************ |* SvBaseLink::SetUpdateMode() |* |* Beschreibung *************************************************************************/ void SvBaseLink::SetUpdateMode( sal_uInt16 nMode ) { if( ( OBJECT_CLIENT_SO & nObjType ) && pImplData->ClientType.nUpdateMode != nMode ) { AddNextRef(); Disconnect(); pImplData->ClientType.nUpdateMode = nMode; _GetRealObject(); ReleaseRef(); } } // --> OD 2008-06-19 #i88291# void SvBaseLink::clearStreamToLoadFrom() { m_xInputStreamToLoadFrom.clear(); if( xObj.Is() ) { xObj->clearStreamToLoadFrom(); } } // <-- sal_Bool SvBaseLink::Update() { if( OBJECT_CLIENT_SO & nObjType ) { AddNextRef(); Disconnect(); _GetRealObject(); ReleaseRef(); if( xObj.Is() ) { xObj->setStreamToLoadFrom(m_xInputStreamToLoadFrom,m_bIsReadOnly); // m_xInputStreamToLoadFrom = 0; String sMimeType( SotExchange::GetFormatMimeType( pImplData->ClientType.nCntntType )); Any aData; if( xObj->GetData( aData, sMimeType ) ) { DataChanged( sMimeType, aData ); //JP 13.07.00: Bug 76817 - for manual Updates there is no // need to hold the ServerObject if( OBJECT_CLIENT_DDE == nObjType && LINKUPDATE_ONCALL == GetUpdateMode() && xObj.Is() ) xObj->RemoveAllDataAdvise( this ); return sal_True; } if( xObj.Is() ) { // sollten wir asynschron sein? if( xObj->IsPending() ) return sal_True; // dann brauchen wir das Object auch nicht mehr AddNextRef(); Disconnect(); ReleaseRef(); } } } return sal_False; } sal_uInt16 SvBaseLink::GetUpdateMode() const { return ( OBJECT_CLIENT_SO & nObjType ) ? pImplData->ClientType.nUpdateMode : sal::static_int_cast< sal_uInt16 >( LINKUPDATE_ONCALL ); } void SvBaseLink::_GetRealObject( sal_Bool bConnect) { if(pImpl) { if( !pImpl->m_pLinkMgr ) return; DBG_ASSERT( !xObj.Is(), "object already exist" ); if( OBJECT_CLIENT_DDE == nObjType ) { String sServer; if( pImpl->m_pLinkMgr->GetDisplayNames( this, &sServer ) && sServer == GetpApp()->GetAppName() ) // interner Link !!! { // damit der Internal - Link erzeugt werden kann !!! nObjType = OBJECT_INTERN; xObj = pImpl->m_pLinkMgr->CreateObj( this ); pImplData->ClientType.bIntrnlLnk = sal_True; nObjType = OBJECT_CLIENT_DDE; // damit wir wissen was es mal war !! } else { pImplData->ClientType.bIntrnlLnk = sal_False; xObj = pImpl->m_pLinkMgr->CreateObj( this ); } } else if( OBJECT_CLIENT_SO & nObjType ) xObj = pImpl->m_pLinkMgr->CreateObj( this ); if( bConnect && ( !xObj.Is() || !xObj->Connect( this ) ) ) Disconnect(); } else { OSL_ENSURE(false, "No pImpl (!)"); } } sal_uIntPtr SvBaseLink::GetContentType() const { if( OBJECT_CLIENT_SO & nObjType ) return pImplData->ClientType.nCntntType; return 0; // alle Formate ? } sal_Bool SvBaseLink::SetContentType( sal_uIntPtr nType ) { if( OBJECT_CLIENT_SO & nObjType ) { pImplData->ClientType.nCntntType = nType; return sal_True; } return sal_False; } LinkManager* SvBaseLink::GetLinkManager() { if(pImpl) { return pImpl->m_pLinkMgr; } return 0; } const LinkManager* SvBaseLink::GetLinkManager() const { if(pImpl) { return pImpl->m_pLinkMgr; } return 0; } void SvBaseLink::SetLinkManager( LinkManager* _pMgr ) { if(pImpl) { pImpl->m_pLinkMgr = _pMgr; } else { OSL_ENSURE(false, "No pImpl (!)"); } } void SvBaseLink::Disconnect() { if( xObj.Is() ) { xObj->RemoveAllDataAdvise( this ); xObj->RemoveConnectAdvise( this ); xObj.Clear(); } } void SvBaseLink::DataChanged( const String &, const ::com::sun::star::uno::Any & ) { switch( nObjType ) { case OBJECT_DDE_EXTERN: if( pImplData->DDEType.pItem ) pImplData->DDEType.pItem->Notify(); break; } } void SvBaseLink::Edit( Window* pParent, const Link& rEndEditHdl ) { if(pImpl) { pImpl->m_pParentWin = pParent; pImpl->m_aEndEditLink = rEndEditHdl; pImpl->m_bIsConnect = ( xObj.Is() != sal_False ); if( !pImpl->m_bIsConnect ) _GetRealObject( xObj.Is() ); bool bAsync = false; Link aLink = LINK( this, SvBaseLink, EndEditHdl ); if( OBJECT_CLIENT_SO & nObjType && pImplData->ClientType.bIntrnlLnk ) { if( pImpl->m_pLinkMgr ) { SvLinkSourceRef ref = pImpl->m_pLinkMgr->CreateObj( this ); if( ref.Is() ) { ref->Edit( pParent, this, aLink ); bAsync = true; } } } else { xObj->Edit( pParent, this, aLink ); bAsync = true; } if ( !bAsync ) { ExecuteEdit( String() ); bWasLastEditOK = sal_False; if ( pImpl->m_aEndEditLink.IsSet() ) pImpl->m_aEndEditLink.Call( this ); } } else { OSL_ENSURE(false, "No pImpl (!)"); } } bool SvBaseLink::ExecuteEdit( const String& _rNewName ) { if(pImpl) { if( _rNewName.Len() != 0 ) { SetLinkSourceName( _rNewName ); if( !Update() ) { String sApp, sTopic, sItem, sError; pImpl->m_pLinkMgr->GetDisplayNames( this, &sApp, &sTopic, &sItem ); if( nObjType == OBJECT_CLIENT_DDE ) { sError = SfxResId( STR_DDE_ERROR ); sal_uInt16 nFndPos = sError.Search( '%' ); if( STRING_NOTFOUND != nFndPos ) { sError.Erase( nFndPos, 1 ).Insert( sApp, nFndPos ); nFndPos = nFndPos + sApp.Len(); } if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos ))) { sError.Erase( nFndPos, 1 ).Insert( sTopic, nFndPos ); nFndPos = nFndPos + sTopic.Len(); } if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos ))) sError.Erase( nFndPos, 1 ).Insert( sItem, nFndPos ); } else return false; ErrorBox( pImpl->m_pParentWin, WB_OK, sError ).Execute(); } } else if( !pImpl->m_bIsConnect ) Disconnect(); pImpl->m_bIsConnect = false; return true; } else { OSL_ENSURE(false, "No pImpl (!)"); return false; } } void SvBaseLink::Closed() { if( xObj.Is() ) // beim Advise Abmelden xObj->RemoveAllDataAdvise( this ); } FileDialogHelper* SvBaseLink::GetFileDialog( sal_uInt32 nFlags, const String& rFactory ) const { if(pImpl) { if ( pImpl->m_pFileDlg ) delete pImpl->m_pFileDlg; pImpl->m_pFileDlg = new FileDialogHelper( nFlags, rFactory ); return pImpl->m_pFileDlg; } else { OSL_ENSURE(false, "No pImpl (!)"); return 0; } } ImplDdeItem::~ImplDdeItem() { bIsInDTOR = sal_True; // damit im Disconnect nicht jemand auf die Idee kommt, den Pointer zu // loeschen!! SvBaseLinkRef aRef( pLink ); aRef->Disconnect(); } DdeData* ImplDdeItem::Get( sal_uIntPtr nFormat ) { if( pLink->GetObj() ) { // ist das noch gueltig? if( bIsValidData && nFormat == aData.GetFormat() ) return &aData; Any aValue; String sMimeType( SotExchange::GetFormatMimeType( nFormat )); if( pLink->GetObj()->GetData( aValue, sMimeType ) ) { if( aValue >>= aSeq ) { aData = DdeData( (const char *)aSeq.getConstArray(), aSeq.getLength(), nFormat ); bIsValidData = sal_True; return &aData; } } } aSeq.realloc( 0 ); bIsValidData = sal_False; return 0; } sal_Bool ImplDdeItem::Put( const DdeData* ) { DBG_ERROR( "ImplDdeItem::Put not implemented" ); return sal_False; } void ImplDdeItem::AdviseLoop( sal_Bool bOpen ) { // Verbindung wird geschlossen, also Link abmelden if( pLink->GetObj() ) { if( bOpen ) { // es wird wieder eine Verbindung hergestellt if( OBJECT_DDE_EXTERN == pLink->GetObjType() ) { pLink->GetObj()->AddDataAdvise( pLink, String::CreateFromAscii( "text/plain;charset=utf-16" ), ADVISEMODE_NODATA ); pLink->GetObj()->AddConnectAdvise( pLink ); } } else { // damit im Disconnect nicht jemand auf die Idee kommt, // den Pointer zu loeschen!! SvBaseLinkRef aRef( pLink ); aRef->Disconnect(); } } } static DdeTopic* FindTopic( const String & rLinkName, sal_uInt16* pItemStt ) { if( 0 == rLinkName.Len() ) return 0; String sNm( rLinkName ); sal_uInt16 nTokenPos = 0; String sService( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) ); DdeServices& rSvc = DdeService::GetServices(); for( DdeService* pService = rSvc.First(); pService; pService = rSvc.Next() ) if( pService->GetName() == sService ) { // dann suchen wir uns das Topic String sTopic( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) ); if( pItemStt ) *pItemStt = nTokenPos; DdeTopics& rTopics = pService->GetTopics(); for( int i = 0; i < 2; ++i ) { for( DdeTopic* pTopic = rTopics.First(); pTopic; pTopic = rTopics.Next() ) if( pTopic->GetName() == sTopic ) return pTopic; // Topic nicht gefunden ? // dann versuchen wir ihn mal anzulegen if( i || !pService->MakeTopic( sTopic ) ) break; // hat nicht geklappt, also raus } break; } return 0; } }