| /************************************************************** |
| * |
| * 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/linkmgr.hxx> |
| #include <com/sun/star/document/UpdateDocMode.hpp> |
| #include <sfx2/objsh.hxx> |
| #include <svl/urihelper.hxx> |
| #include <sot/formats.hxx> |
| #include <tools/urlobj.hxx> |
| #include <sot/exchange.hxx> |
| #include <tools/debug.hxx> |
| #include <vcl/msgbox.hxx> |
| #include <sfx2/lnkbase.hxx> |
| #include <sfx2/app.hxx> |
| #include <vcl/graph.hxx> |
| #include <svl/stritem.hxx> |
| #include <svl/eitem.hxx> |
| #include <svl/intitem.hxx> |
| #include <unotools/localfilehelper.hxx> |
| #include <i18npool/mslangid.hxx> |
| #include <sfx2/request.hxx> |
| #include <vcl/dibtools.hxx> |
| |
| #include "fileobj.hxx" |
| #include "impldde.hxx" |
| #include "app.hrc" |
| #include "sfx2/sfxresid.hxx" |
| |
| #define _SVSTDARR_STRINGSDTOR |
| #include <svl/svstdarr.hxx> |
| |
| namespace sfx2 |
| { |
| |
| class SvxInternalLink : public sfx2::SvLinkSource |
| { |
| public: |
| SvxInternalLink() {} |
| |
| virtual sal_Bool Connect( sfx2::SvBaseLink* ); |
| }; |
| |
| |
| SV_IMPL_PTRARR( SvBaseLinks, SvBaseLinkRefPtr ) |
| |
| LinkManager::LinkManager(SfxObjectShell* p) |
| : pPersist( p ) |
| { |
| } |
| |
| |
| LinkManager::~LinkManager() |
| { |
| SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData(); |
| for( sal_uInt16 n = aLinkTbl.Count(); n; --n, ++ppRef ) |
| { |
| if( (*ppRef)->Is() ) |
| { |
| (*(*ppRef))->Disconnect(); |
| (*(*ppRef))->SetLinkManager( NULL ); |
| } |
| delete *ppRef; |
| } |
| } |
| |
| |
| /************************************************************************ |
| |* LinkManager::Remove() |
| |* |
| |* Beschreibung |
| *************************************************************************/ |
| |
| void LinkManager::Remove( SvBaseLink *pLink ) |
| { |
| // keine Links doppelt einfuegen |
| int bFound = sal_False; |
| SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData(); |
| for( sal_uInt16 n = aLinkTbl.Count(); n; --n, ++ppRef ) |
| { |
| if( pLink == *(*ppRef) ) |
| { |
| (*(*ppRef))->Disconnect(); |
| (*(*ppRef))->SetLinkManager( NULL ); |
| (*(*ppRef)).Clear(); |
| bFound = sal_True; |
| } |
| |
| // falls noch leere rum stehen sollten, weg damit |
| if( !(*ppRef)->Is() ) |
| { |
| delete *ppRef; |
| aLinkTbl.Remove( aLinkTbl.Count() - n, 1 ); |
| if( bFound ) |
| return ; |
| --ppRef; |
| } |
| } |
| } |
| |
| |
| void LinkManager::Remove( sal_uInt16 nPos, sal_uInt16 nCnt ) |
| { |
| if( nCnt && nPos < aLinkTbl.Count() ) |
| { |
| if( nPos + nCnt > aLinkTbl.Count() ) |
| nCnt = aLinkTbl.Count() - nPos; |
| |
| SvBaseLinkRef** ppRef = (SvBaseLinkRef**)aLinkTbl.GetData() + nPos; |
| for( sal_uInt16 n = nCnt; n; --n, ++ppRef ) |
| { |
| if( (*ppRef)->Is() ) |
| { |
| (*(*ppRef))->Disconnect(); |
| (*(*ppRef))->SetLinkManager( NULL ); |
| } |
| delete *ppRef; |
| } |
| aLinkTbl.Remove( nPos, nCnt ); |
| } |
| } |
| |
| |
| sal_Bool LinkManager::Insert( SvBaseLink* pLink ) |
| { |
| // keine Links doppelt einfuegen |
| for( sal_uInt16 n = 0; n < aLinkTbl.Count(); ++n ) |
| { |
| SvBaseLinkRef* pTmp = aLinkTbl[ n ]; |
| if( !pTmp->Is() ) |
| aLinkTbl.DeleteAndDestroy( n-- ); |
| |
| if( pLink == *pTmp ) |
| return sal_False; |
| } |
| |
| SvBaseLinkRef* pTmp = new SvBaseLinkRef( pLink ); |
| pLink->SetLinkManager( this ); |
| aLinkTbl.Insert( pTmp, aLinkTbl.Count() ); |
| return sal_True; |
| } |
| |
| |
| sal_Bool LinkManager::InsertLink( SvBaseLink * pLink, |
| sal_uInt16 nObjType, |
| sal_uInt16 nUpdateMode, |
| const String* pName ) |
| { |
| // unbedingt zuerst |
| pLink->SetObjType( nObjType ); |
| if( pName ) |
| pLink->SetName( *pName ); |
| pLink->SetUpdateMode( nUpdateMode ); |
| return Insert( pLink ); |
| } |
| |
| |
| sal_Bool LinkManager::InsertDDELink( SvBaseLink * pLink, |
| const String& rServer, |
| const String& rTopic, |
| const String& rItem ) |
| { |
| if( !( OBJECT_CLIENT_SO & pLink->GetObjType() ) ) |
| return sal_False; |
| |
| String sCmd; |
| ::sfx2::MakeLnkName( sCmd, &rServer, rTopic, rItem ); |
| |
| pLink->SetObjType( OBJECT_CLIENT_DDE ); |
| pLink->SetName( sCmd ); |
| return Insert( pLink ); |
| } |
| |
| |
| sal_Bool LinkManager::InsertDDELink( SvBaseLink * pLink ) |
| { |
| DBG_ASSERT( OBJECT_CLIENT_SO & pLink->GetObjType(), "no OBJECT_CLIENT_SO" ); |
| if( !( OBJECT_CLIENT_SO & pLink->GetObjType() ) ) |
| return sal_False; |
| |
| if( pLink->GetObjType() == OBJECT_CLIENT_SO ) |
| pLink->SetObjType( OBJECT_CLIENT_DDE ); |
| |
| return Insert( pLink ); |
| } |
| |
| |
| // erfrage die Strings fuer den Dialog |
| sal_Bool LinkManager::GetDisplayNames( const SvBaseLink * pLink, |
| String* pType, |
| String* pFile, |
| String* pLinkStr, |
| String* pFilter ) const |
| { |
| sal_Bool bRet = sal_False; |
| const String sLNm( pLink->GetLinkSourceName() ); |
| if( sLNm.Len() ) |
| { |
| switch( pLink->GetObjType() ) |
| { |
| case OBJECT_CLIENT_FILE: |
| case OBJECT_CLIENT_GRF: |
| case OBJECT_CLIENT_OLE: |
| { |
| sal_uInt16 nPos = 0; |
| String sFile( sLNm.GetToken( 0, ::sfx2::cTokenSeperator, nPos ) ); |
| String sRange( sLNm.GetToken( 0, ::sfx2::cTokenSeperator, nPos ) ); |
| |
| if( pFile ) |
| *pFile = sFile; |
| if( pLinkStr ) |
| *pLinkStr = sRange; |
| if( pFilter ) |
| *pFilter = sLNm.Copy( nPos ); |
| |
| if( pType ) |
| { |
| sal_uInt16 nObjType = pLink->GetObjType(); |
| *pType = String( SfxResId( |
| ( OBJECT_CLIENT_FILE == nObjType || OBJECT_CLIENT_OLE == nObjType ) |
| ? RID_SVXSTR_FILELINK |
| : RID_SVXSTR_GRAFIKLINK )); |
| } |
| bRet = sal_True; |
| } |
| break; |
| case OBJECT_CLIENT_DDE: |
| { |
| sal_uInt16 nTmp = 0; |
| String sCmd( sLNm ); |
| String sServer( sCmd.GetToken( 0, cTokenSeperator, nTmp ) ); |
| String sTopic( sCmd.GetToken( 0, cTokenSeperator, nTmp ) ); |
| |
| if( pType ) |
| *pType = sServer; |
| if( pFile ) |
| *pFile = sTopic; |
| if( pLinkStr ) |
| *pLinkStr = sCmd.Copy( nTmp ); |
| bRet = sal_True; |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| |
| return bRet; |
| } |
| |
| |
| void LinkManager::UpdateAllLinks( |
| sal_Bool bAskUpdate, |
| sal_Bool /*bCallErrHdl*/, |
| sal_Bool bUpdateGrfLinks, |
| Window* pParentWin ) |
| { |
| SvStringsDtor aApps, aTopics, aItems; |
| String sApp, sTopic, sItem; |
| |
| // erstmal eine Kopie vom Array machen, damit sich updatende Links in |
| // Links in ... nicht dazwischen funken!! |
| SvPtrarr aTmpArr( 255, 50 ); |
| sal_uInt16 n; |
| for( n = 0; n < aLinkTbl.Count(); ++n ) |
| { |
| SvBaseLink* pLink = *aLinkTbl[ n ]; |
| if( !pLink ) |
| { |
| Remove( n-- ); |
| continue; |
| } |
| aTmpArr.Insert( pLink, aTmpArr.Count() ); |
| } |
| |
| for( n = 0; n < aTmpArr.Count(); ++n ) |
| { |
| SvBaseLink* pLink = (SvBaseLink*)aTmpArr[ n ]; |
| |
| // suche erstmal im Array nach dem Eintrag |
| sal_uInt16 nFndPos = USHRT_MAX; |
| for( sal_uInt16 i = 0; i < aLinkTbl.Count(); ++i ) |
| if( pLink == *aLinkTbl[ i ] ) |
| { |
| nFndPos = i; |
| break; |
| } |
| |
| if( USHRT_MAX == nFndPos ) |
| continue; // war noch nicht vorhanden! |
| |
| // Graphic-Links noch nicht updaten |
| if( !pLink->IsVisible() || |
| ( !bUpdateGrfLinks && OBJECT_CLIENT_GRF == pLink->GetObjType() )) |
| continue; |
| |
| if( bAskUpdate ) |
| { |
| int nRet = QueryBox( pParentWin, WB_YES_NO | WB_DEF_YES, SfxResId( STR_QUERY_UPDATE_LINKS ) ).Execute(); |
| if( RET_YES != nRet ) |
| { |
| SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist(); |
| |
| if(pShell) |
| { |
| comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = pShell->getEmbeddedObjectContainer(); |
| rEmbeddedObjectContainer.setUserAllowsLinkUpdate(false); |
| } |
| |
| return ; // es soll nichts geupdatet werden |
| } |
| bAskUpdate = sal_False; // einmal reicht |
| } |
| |
| pLink->Update(); |
| } |
| } |
| |
| /************************************************************************ |
| |* SvBaseLink::CreateObject() |
| |* |
| |* Beschreibung |
| *************************************************************************/ |
| |
| SvLinkSourceRef LinkManager::CreateObj( SvBaseLink * pLink ) |
| { |
| switch( pLink->GetObjType() ) |
| { |
| case OBJECT_CLIENT_FILE: |
| case OBJECT_CLIENT_GRF: |
| case OBJECT_CLIENT_OLE: |
| return new SvFileObject; |
| case OBJECT_INTERN: |
| return new SvxInternalLink; |
| case OBJECT_CLIENT_DDE: |
| return new SvDDEObject; |
| default: |
| return SvLinkSourceRef(); |
| } |
| } |
| |
| sal_Bool LinkManager::InsertServer( SvLinkSource* pObj ) |
| { |
| // keine doppelt einfuegen |
| if( !pObj || USHRT_MAX != aServerTbl.GetPos( pObj ) ) |
| return sal_False; |
| |
| aServerTbl.Insert( pObj, aServerTbl.Count() ); |
| return sal_True; |
| } |
| |
| |
| void LinkManager::RemoveServer( SvLinkSource* pObj ) |
| { |
| sal_uInt16 nPos = aServerTbl.GetPos( pObj ); |
| if( USHRT_MAX != nPos ) |
| aServerTbl.Remove( nPos, 1 ); |
| } |
| |
| |
| void MakeLnkName( String& rName, const String* pType, const String& rFile, |
| const String& rLink, const String* pFilter ) |
| { |
| if( pType ) |
| (rName = *pType).EraseLeadingChars().EraseTrailingChars() += cTokenSeperator; |
| else if( rName.Len() ) |
| rName.Erase(); |
| |
| ((rName += rFile).EraseLeadingChars().EraseTrailingChars() += |
| cTokenSeperator ).EraseLeadingChars().EraseTrailingChars() += rLink; |
| if( pFilter ) |
| ((rName += cTokenSeperator ) += *pFilter).EraseLeadingChars().EraseTrailingChars(); |
| } |
| |
| sal_Bool LinkManager::InsertFileLink( sfx2::SvBaseLink& rLink, |
| sal_uInt16 nFileType, |
| const String& rFileNm, |
| const String* pFilterNm, |
| const String* pRange ) |
| { |
| if( !( OBJECT_CLIENT_SO & rLink.GetObjType() )) |
| return sal_False; |
| |
| String sCmd( rFileNm ); |
| sCmd += ::sfx2::cTokenSeperator; |
| if( pRange ) |
| sCmd += *pRange; |
| if( pFilterNm ) |
| ( sCmd += ::sfx2::cTokenSeperator ) += *pFilterNm; |
| |
| return InsertLink( &rLink, nFileType, sfx2::LINKUPDATE_ONCALL, &sCmd ); |
| } |
| |
| sal_Bool LinkManager::InsertFileLink( sfx2::SvBaseLink& rLink ) |
| { |
| if( OBJECT_CLIENT_FILE == ( OBJECT_CLIENT_FILE & rLink.GetObjType() )) |
| return InsertLink( &rLink, rLink.GetObjType(), sfx2::LINKUPDATE_ONCALL ); |
| return sal_False; |
| } |
| |
| // eine Uebertragung wird abgebrochen, also alle DownloadMedien canceln |
| // (ist zur Zeit nur fuer die FileLinks interressant!) |
| void LinkManager::CancelTransfers() |
| { |
| SvFileObject* pFileObj; |
| sfx2::SvBaseLink* pLnk; |
| |
| const sfx2::SvBaseLinks& rLnks = GetLinks(); |
| for( sal_uInt16 n = rLnks.Count(); n; ) |
| if( 0 != ( pLnk = &(*rLnks[ --n ])) && |
| OBJECT_CLIENT_FILE == (OBJECT_CLIENT_FILE & pLnk->GetObjType()) && |
| 0 != ( pFileObj = (SvFileObject*)pLnk->GetObj() ) ) |
| // 0 != ( pFileObj = (SvFileObject*)SvFileObject::ClassFactory()-> |
| // CastAndAddRef( pLnk->GetObj() )) ) |
| pFileObj->CancelTransfers(); |
| } |
| |
| // um Status Informationen aus dem FileObject an den BaseLink zu |
| // senden, gibt es eine eigene ClipBoardId. Das SvData-Object hat |
| // dann die entsprechenden Informationen als String. |
| // Wird zur Zeit fuer FileObject in Verbindung mit JavaScript benoetigt |
| // - das braucht Informationen ueber Load/Abort/Error |
| sal_uIntPtr LinkManager::RegisterStatusInfoId() |
| { |
| static sal_uIntPtr nFormat = 0; |
| |
| if( !nFormat ) |
| { |
| // wie sieht die neue Schnittstelle aus? |
| // nFormat = Exchange::RegisterFormatName( "StatusInfo vom SvxInternalLink" ); |
| nFormat = SotExchange::RegisterFormatName( |
| String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( |
| "StatusInfo vom SvxInternalLink" ))); |
| } |
| return nFormat; |
| } |
| |
| // ---------------------------------------------------------------------- |
| |
| sal_Bool LinkManager::GetGraphicFromAny( const String& rMimeType, |
| const ::com::sun::star::uno::Any & rValue, |
| Graphic& rGrf ) |
| { |
| sal_Bool bRet = sal_False; |
| ::com::sun::star::uno::Sequence< sal_Int8 > aSeq; |
| if( rValue.hasValue() && ( rValue >>= aSeq ) ) |
| { |
| SvMemoryStream aMemStm( (void*)aSeq.getConstArray(), aSeq.getLength(), |
| STREAM_READ ); |
| aMemStm.Seek( 0 ); |
| |
| switch( SotExchange::GetFormatIdFromMimeType( rMimeType ) ) |
| { |
| case SOT_FORMATSTR_ID_SVXB: |
| { |
| aMemStm >> rGrf; |
| bRet = sal_True; |
| } |
| break; |
| case FORMAT_GDIMETAFILE: |
| { |
| GDIMetaFile aMtf; |
| aMtf.Read( aMemStm ); |
| rGrf = aMtf; |
| bRet = sal_True; |
| } |
| break; |
| case FORMAT_BITMAP: |
| { |
| Bitmap aBmp; |
| ReadDIB(aBmp, aMemStm, true); |
| rGrf = aBmp; |
| bRet = sal_True; |
| } |
| break; |
| } |
| } |
| return bRet; |
| } |
| |
| |
| // ---------------------------------------------------------------------- |
| String lcl_DDE_RelToAbs( const String& rTopic, const String& rBaseURL ) |
| { |
| String sRet; |
| INetURLObject aURL( rTopic ); |
| if( INET_PROT_NOT_VALID == aURL.GetProtocol() ) |
| utl::LocalFileHelper::ConvertSystemPathToURL( rTopic, rBaseURL, sRet ); |
| if( !sRet.Len() ) |
| sRet = URIHelper::SmartRel2Abs( INetURLObject(rBaseURL), rTopic, URIHelper::GetMaybeFileHdl(), true ); |
| return sRet; |
| } |
| |
| sal_Bool SvxInternalLink::Connect( sfx2::SvBaseLink* pLink ) |
| { |
| SfxObjectShell* pFndShell = 0; |
| sal_uInt16 nUpdateMode = com::sun::star::document::UpdateDocMode::NO_UPDATE; |
| String sTopic, sItem, sReferer; |
| if( pLink->GetLinkManager() && |
| pLink->GetLinkManager()->GetDisplayNames( pLink, 0, &sTopic, &sItem ) |
| && sTopic.Len() ) |
| { |
| // erstmal nur ueber die DocumentShells laufen und die mit dem |
| // Namen heraussuchen: |
| |
| com::sun::star::lang::Locale aLocale; |
| MsLangId::convertLanguageToLocale( LANGUAGE_SYSTEM, aLocale ); |
| CharClass aCC( aLocale ); |
| |
| String sNm( sTopic ), sTmp; |
| aCC.toLower( sNm ); |
| |
| TypeId aType( TYPE(SfxObjectShell) ); |
| |
| sal_Bool bFirst = sal_True; |
| SfxObjectShell* pShell = pLink->GetLinkManager()->GetPersist(); |
| if( pShell && pShell->GetMedium() ) |
| { |
| sReferer = pShell->GetMedium()->GetBaseURL(); |
| SFX_ITEMSET_ARG( pShell->GetMedium()->GetItemSet(), pItem, SfxUInt16Item, SID_UPDATEDOCMODE, sal_False ); |
| if ( pItem ) |
| nUpdateMode = pItem->GetValue(); |
| } |
| |
| String sNmURL( lcl_DDE_RelToAbs( sTopic, sReferer ) ); |
| aCC.toLower( sNmURL ); |
| |
| if ( !pShell ) |
| { |
| bFirst = sal_False; |
| pShell = SfxObjectShell::GetFirst( &aType, sal_False ); |
| } |
| |
| while( pShell ) |
| { |
| if( !sTmp.Len() ) |
| { |
| sTmp = pShell->GetTitle( SFX_TITLE_FULLNAME ); |
| sTmp = lcl_DDE_RelToAbs(sTmp, sReferer ); |
| } |
| |
| |
| aCC.toLower( sTmp ); |
| if( sTmp == sNmURL ) // die wollen wir haben |
| { |
| pFndShell = pShell; |
| break; |
| } |
| |
| if( bFirst ) |
| { |
| bFirst = sal_False; |
| pShell = SfxObjectShell::GetFirst( &aType, sal_False ); |
| } |
| else |
| pShell = SfxObjectShell::GetNext( *pShell, &aType, sal_False ); |
| |
| sTmp.Erase(); |
| } |
| } |
| |
| // empty topics are not allowed - which document is it |
| if( !sTopic.Len() ) |
| return sal_False; |
| |
| if( !pFndShell ) |
| { |
| // dann versuche die Datei zu laden: |
| INetURLObject aURL( sTopic ); |
| INetProtocol eOld = aURL.GetProtocol(); |
| aURL.SetURL( sTopic = lcl_DDE_RelToAbs( sTopic, sReferer ) ); |
| if( INET_PROT_NOT_VALID != eOld || |
| INET_PROT_HTTP != aURL.GetProtocol() ) |
| { |
| SfxStringItem aName( SID_FILE_NAME, sTopic ); |
| SfxBoolItem aMinimized(SID_MINIMIZED, sal_True); |
| SfxBoolItem aHidden(SID_HIDDEN, sal_True); |
| SfxStringItem aTarget( SID_TARGETNAME, String::CreateFromAscii("_blank") ); |
| SfxStringItem aReferer( SID_REFERER, sReferer ); |
| SfxUInt16Item aUpdate( SID_UPDATEDOCMODE, nUpdateMode ); |
| SfxBoolItem aReadOnly(SID_DOC_READONLY, sal_True); |
| |
| // #i14200# (DDE-link crashes wordprocessor) |
| SfxAllItemSet aArgs( SFX_APP()->GetPool() ); |
| aArgs.Put(aReferer); |
| aArgs.Put(aTarget); |
| aArgs.Put(aHidden); |
| aArgs.Put(aMinimized); |
| aArgs.Put(aName); |
| aArgs.Put(aUpdate); |
| aArgs.Put(aReadOnly); |
| pFndShell = SfxObjectShell::CreateAndLoadObject( aArgs ); |
| } |
| } |
| |
| sal_Bool bRet = sal_False; |
| if( pFndShell ) |
| { |
| sfx2::SvLinkSource* pNewSrc = pFndShell->DdeCreateLinkSource( sItem ); |
| if( pNewSrc ) |
| { |
| bRet = sal_True; |
| |
| ::com::sun::star::datatransfer::DataFlavor aFl; |
| SotExchange::GetFormatDataFlavor( pLink->GetContentType(), aFl ); |
| |
| pLink->SetObj( pNewSrc ); |
| pNewSrc->AddDataAdvise( pLink, aFl.MimeType, |
| sfx2::LINKUPDATE_ONCALL == pLink->GetUpdateMode() |
| ? ADVISEMODE_ONLYONCE |
| : 0 ); |
| } |
| } |
| return bRet; |
| } |
| |
| |
| } |
| |
| |
| |