| /************************************************************** |
| * |
| * 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 <sfx2/lnkbase.hxx> |
| #include <sot/exchange.hxx> |
| #include <com/sun/star/uno/Any.hxx> |
| #include <com/sun/star/uno/Sequence.hxx> |
| #include <vcl/msgbox.hxx> |
| #include <sfx2/linkmgr.hxx> |
| #include <vcl/svapp.hxx> |
| #include "app.hrc" |
| #include "sfx2/sfxresid.hxx" |
| #include <sfx2/filedlghelper.hxx> |
| #include <tools/debug.hxx> |
| #include <svl/svdde.hxx> |
| |
| 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; |
| } |
| |
| } |