Branch libreoffice-5-0-4
[LibreOffice.git] / sfx2 / source / appl / lnkbase2.cxx
blobac35800f3d99dccdfe5b0fbe4ec3f78c59c43429
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sfx2/lnkbase.hxx>
22 #include <sot/exchange.hxx>
23 #include <com/sun/star/uno/Any.hxx>
24 #include <com/sun/star/uno/Sequence.hxx>
25 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
26 #include <vcl/layout.hxx>
27 #include <sfx2/linkmgr.hxx>
28 #include <vcl/svapp.hxx>
29 #include "app.hrc"
30 #include <sfx2/sfxresid.hxx>
31 #include <sfx2/filedlghelper.hxx>
32 #include <tools/debug.hxx>
33 #include <svl/svdde.hxx>
35 using namespace ::com::sun::star;
36 using namespace ::com::sun::star::uno;
38 namespace sfx2
41 TYPEINIT0( SvBaseLink )
43 class ImplDdeItem;
45 struct BaseLink_Impl
47 Link<> m_aEndEditLink;
48 LinkManager* m_pLinkMgr;
49 VclPtr<vcl::Window> m_pParentWin;
50 FileDialogHelper* m_pFileDlg;
51 bool m_bIsConnect;
53 BaseLink_Impl() :
54 m_pLinkMgr( NULL )
55 , m_pParentWin( NULL )
56 , m_pFileDlg( NULL )
57 , m_bIsConnect( false )
60 ~BaseLink_Impl()
61 { delete m_pFileDlg; }
64 // only for internal management
65 struct ImplBaseLinkData
67 struct tClientType
69 // applies for all links
70 SotClipboardFormatId nCntntType; // Update Format
71 // Not Ole-Links
72 bool bIntrnlLnk; // It is an internal link
73 SfxLinkUpdateMode nUpdateMode; // UpdateMode
76 struct tDDEType
78 ImplDdeItem* pItem;
81 union {
82 tClientType ClientType;
83 tDDEType DDEType;
85 ImplBaseLinkData()
87 ClientType.nCntntType = SotClipboardFormatId::NONE;
88 ClientType.bIntrnlLnk = false;
89 ClientType.nUpdateMode = SfxLinkUpdateMode::NONE;
90 DDEType.pItem = NULL;
95 class ImplDdeItem : public DdeGetPutItem
97 SvBaseLink* pLink;
98 DdeData aData;
99 Sequence< sal_Int8 > aSeq; // Datacontainer for DdeData !!!
100 bool bIsValidData : 1;
101 bool bIsInDTOR : 1;
102 public:
103 #if defined WNT
104 ImplDdeItem( SvBaseLink& rLink, const OUString& rStr )
105 : DdeGetPutItem( rStr ), pLink( &rLink ), bIsValidData( false ),
106 bIsInDTOR( false )
108 #endif
109 virtual ~ImplDdeItem();
111 virtual DdeData* Get( SotClipboardFormatId ) SAL_OVERRIDE;
112 virtual bool Put( const DdeData* ) SAL_OVERRIDE;
113 virtual void AdviseLoop( bool ) SAL_OVERRIDE;
115 void Notify()
117 bIsValidData = false;
118 DdeGetPutItem::NotifyClient();
121 bool IsInDTOR() const { return bIsInDTOR; }
126 SvBaseLink::SvBaseLink()
127 : m_bIsReadOnly(false)
129 pImpl = new BaseLink_Impl();
130 nObjType = OBJECT_CLIENT_SO;
131 pImplData = new ImplBaseLinkData;
132 bVisible = bSynchron = bUseCache = true;
133 bWasLastEditOK = false;
138 SvBaseLink::SvBaseLink( SfxLinkUpdateMode nUpdateMode, SotClipboardFormatId nContentType )
139 : m_bIsReadOnly(false)
141 pImpl = new BaseLink_Impl();
142 nObjType = OBJECT_CLIENT_SO;
143 pImplData = new ImplBaseLinkData;
144 bVisible = bSynchron = bUseCache = true;
145 bWasLastEditOK = false;
147 // It is going to be a Ole-Link,
148 pImplData->ClientType.nUpdateMode = nUpdateMode;
149 pImplData->ClientType.nCntntType = nContentType;
150 pImplData->ClientType.bIntrnlLnk = false;
153 #if defined WNT
155 static DdeTopic* FindTopic( const OUString & rLinkName, sal_uInt16* pItemStt )
157 if( rLinkName.isEmpty() )
158 return 0;
160 OUString sNm( rLinkName );
161 sal_Int32 nTokenPos = 0;
162 OUString sService( sNm.getToken( 0, cTokenSeparator, nTokenPos ) );
164 DdeServices& rSvc = DdeService::GetServices();
165 for (DdeServices::iterator aI = rSvc.begin(); aI != rSvc.end(); ++aI)
167 DdeService* pService = *aI;
168 if( pService->GetName() == sService )
170 // then we search for the Topic
171 OUString sTopic( sNm.getToken( 0, cTokenSeparator, nTokenPos ) );
172 if( pItemStt )
173 *pItemStt = nTokenPos;
175 std::vector<DdeTopic*>& rTopics = pService->GetTopics();
177 for( int i = 0; i < 2; ++i )
179 for( std::vector<DdeTopic*>::iterator iterTopic = rTopics.begin();
180 iterTopic != rTopics.end(); ++iterTopic )
181 if( (*iterTopic)->GetName() == sTopic )
182 return *iterTopic;
184 // Topic not found?
185 // then we try once to create it
186 if( i || !pService->MakeTopic( sTopic ) )
187 break; // did not work, exiting
189 break;
192 return 0;
195 SvBaseLink::SvBaseLink( const OUString& rLinkName, sal_uInt16 nObjectType, SvLinkSource* pObj )
196 : pImpl(0)
197 , m_bIsReadOnly(false)
199 bVisible = bSynchron = bUseCache = true;
200 bWasLastEditOK = false;
201 aLinkName = rLinkName;
202 pImplData = new ImplBaseLinkData;
203 nObjType = nObjectType;
205 if( !pObj )
207 DBG_ASSERT( pObj, "Where is my left-most object" );
208 return;
211 if( OBJECT_DDE_EXTERN == nObjType )
213 sal_uInt16 nItemStt = 0;
214 DdeTopic* pTopic = FindTopic( aLinkName, &nItemStt );
215 if( pTopic )
217 // then we have it all together
218 // MM_TODO how do I get the name
219 OUString aStr = aLinkName; // xLinkName->GetDisplayName();
220 aStr = aStr.copy( nItemStt );
221 pImplData->DDEType.pItem = new ImplDdeItem( *this, aStr );
222 pTopic->InsertItem( pImplData->DDEType.pItem );
224 // store the Advice
225 xObj = pObj;
228 else if( pObj->Connect( this ) )
229 xObj = pObj;
232 #endif
234 SvBaseLink::~SvBaseLink()
236 Disconnect();
238 switch( nObjType )
240 case OBJECT_DDE_EXTERN:
241 if( !pImplData->DDEType.pItem->IsInDTOR() )
242 delete pImplData->DDEType.pItem;
243 break;
246 delete pImplData;
247 delete pImpl;
250 IMPL_LINK( SvBaseLink, EndEditHdl, OUString*, _pNewName )
252 OUString sNewName;
253 if ( _pNewName )
254 sNewName = *_pNewName;
255 if ( !ExecuteEdit( sNewName ) )
256 sNewName.clear();
257 bWasLastEditOK = !sNewName.isEmpty();
258 if ( pImpl->m_aEndEditLink.IsSet() )
259 pImpl->m_aEndEditLink.Call( this );
260 return 0;
265 void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP )
267 DBG_ASSERT( nObjType != OBJECT_CLIENT_DDE, "type already set" );
268 DBG_ASSERT( !xObj.Is(), "object exist" );
270 nObjType = nObjTypeP;
275 void SvBaseLink::SetName( const OUString & rNm )
277 aLinkName = rNm;
282 void SvBaseLink::SetObj( SvLinkSource * pObj )
284 DBG_ASSERT( (nObjType & OBJECT_CLIENT_SO &&
285 pImplData->ClientType.bIntrnlLnk) ||
286 nObjType == OBJECT_CLIENT_GRF,
287 "no intern link" );
288 xObj = pObj;
293 void SvBaseLink::SetLinkSourceName( const OUString & rLnkNm )
295 if( aLinkName == rLnkNm )
296 return;
298 AddNextRef(); // should be superfluous
299 // remove old connection
300 Disconnect();
302 aLinkName = rLnkNm;
304 // New Connection
305 _GetRealObject();
306 ReleaseRef(); // should be superfluous
314 void SvBaseLink::SetUpdateMode( SfxLinkUpdateMode nMode )
316 if( ( OBJECT_CLIENT_SO & nObjType ) &&
317 pImplData->ClientType.nUpdateMode != nMode )
319 AddNextRef();
320 Disconnect();
322 pImplData->ClientType.nUpdateMode = nMode;
323 _GetRealObject();
324 ReleaseRef();
328 // #i88291#
329 void SvBaseLink::clearStreamToLoadFrom()
331 m_xInputStreamToLoadFrom.clear();
332 if( xObj.Is() )
334 xObj->clearStreamToLoadFrom();
338 bool SvBaseLink::Update()
340 if( OBJECT_CLIENT_SO & nObjType )
342 AddNextRef();
343 Disconnect();
345 _GetRealObject();
346 ReleaseRef();
347 if( xObj.Is() )
349 xObj->setStreamToLoadFrom(m_xInputStreamToLoadFrom,m_bIsReadOnly);
350 OUString sMimeType( SotExchange::GetFormatMimeType(
351 pImplData->ClientType.nCntntType ));
352 Any aData;
354 if( xObj->GetData( aData, sMimeType ) )
356 UpdateResult eRes = DataChanged(sMimeType, aData);
357 bool bSuccess = eRes == SUCCESS;
358 //for manual Updates there is no need to hold the ServerObject
359 if( OBJECT_CLIENT_DDE == nObjType &&
360 SfxLinkUpdateMode::ONCALL == GetUpdateMode() && xObj.Is() )
361 xObj->RemoveAllDataAdvise( this );
362 return bSuccess;
364 if( xObj.Is() )
366 // should be asynschron?
367 if( xObj->IsPending() )
368 return true;
370 // we do not need the object anymore
371 AddNextRef();
372 Disconnect();
373 ReleaseRef();
377 return false;
381 SfxLinkUpdateMode SvBaseLink::GetUpdateMode() const
383 return ( OBJECT_CLIENT_SO & nObjType )
384 ? pImplData->ClientType.nUpdateMode
385 : SfxLinkUpdateMode::ONCALL;
389 void SvBaseLink::_GetRealObject( bool bConnect)
391 if( !pImpl->m_pLinkMgr )
392 return;
394 DBG_ASSERT( !xObj.Is(), "object already exist" );
396 if( OBJECT_CLIENT_DDE == nObjType )
398 OUString sServer;
399 if( sfx2::LinkManager::GetDisplayNames( this, &sServer ) &&
400 sServer == Application::GetAppName() ) // internal Link !!!
402 // so that the Internal link can be created!
403 nObjType = OBJECT_INTERN;
404 xObj = sfx2::LinkManager::CreateObj( this );
406 pImplData->ClientType.bIntrnlLnk = true;
407 nObjType = OBJECT_CLIENT_DDE; // so we know what it once was!
409 else
411 pImplData->ClientType.bIntrnlLnk = false;
412 xObj = sfx2::LinkManager::CreateObj( this );
415 else if( (OBJECT_CLIENT_SO & nObjType) )
416 xObj = sfx2::LinkManager::CreateObj( this );
418 if( bConnect && ( !xObj.Is() || !xObj->Connect( this ) ) )
419 Disconnect();
422 SotClipboardFormatId SvBaseLink::GetContentType() const
424 if( OBJECT_CLIENT_SO & nObjType )
425 return pImplData->ClientType.nCntntType;
427 return SotClipboardFormatId::NONE; // all Formats ?
431 bool SvBaseLink::SetContentType( SotClipboardFormatId nType )
433 if( OBJECT_CLIENT_SO & nObjType )
435 pImplData->ClientType.nCntntType = nType;
436 return true;
438 return false;
441 LinkManager* SvBaseLink::GetLinkManager()
443 return pImpl->m_pLinkMgr;
446 const LinkManager* SvBaseLink::GetLinkManager() const
448 return pImpl->m_pLinkMgr;
451 void SvBaseLink::SetLinkManager( LinkManager* _pMgr )
453 pImpl->m_pLinkMgr = _pMgr;
456 void SvBaseLink::Disconnect()
458 if( xObj.Is() )
460 xObj->RemoveAllDataAdvise( this );
461 xObj->RemoveConnectAdvise( this );
462 xObj.Clear();
466 SvBaseLink::UpdateResult SvBaseLink::DataChanged( const OUString &, const ::com::sun::star::uno::Any & )
468 switch( nObjType )
470 case OBJECT_DDE_EXTERN:
471 if( pImplData->DDEType.pItem )
472 pImplData->DDEType.pItem->Notify();
473 break;
475 return SUCCESS;
478 void SvBaseLink::Edit( vcl::Window* pParent, const Link<>& rEndEditHdl )
480 pImpl->m_pParentWin = pParent;
481 pImpl->m_aEndEditLink = rEndEditHdl;
482 pImpl->m_bIsConnect = xObj.Is();
483 if( !pImpl->m_bIsConnect )
484 _GetRealObject( xObj.Is() );
486 bool bAsync = false;
487 Link<> aLink = LINK( this, SvBaseLink, EndEditHdl );
489 if( OBJECT_CLIENT_SO & nObjType && pImplData->ClientType.bIntrnlLnk )
491 if( pImpl->m_pLinkMgr )
493 SvLinkSourceRef ref = sfx2::LinkManager::CreateObj( this );
494 if( ref.Is() )
496 ref->Edit( pParent, this, aLink );
497 bAsync = true;
501 else
503 xObj->Edit( pParent, this, aLink );
504 bAsync = true;
507 if ( !bAsync )
509 ExecuteEdit( OUString() );
510 bWasLastEditOK = false;
511 if ( pImpl->m_aEndEditLink.IsSet() )
512 pImpl->m_aEndEditLink.Call( this );
516 bool SvBaseLink::ExecuteEdit( const OUString& _rNewName )
518 if( !_rNewName.isEmpty() )
520 SetLinkSourceName( _rNewName );
521 if( !Update() )
523 OUString sApp, sTopic, sItem, sError;
524 sfx2::LinkManager::GetDisplayNames( this, &sApp, &sTopic, &sItem );
525 if( nObjType == OBJECT_CLIENT_DDE )
527 sError = SFX2_RESSTR(STR_DDE_ERROR);
529 sal_Int32 nFndPos = sError.indexOf( '%' );
530 if( -1 != nFndPos )
532 sError = sError.replaceAt( nFndPos, 1, sApp );
533 nFndPos = nFndPos + sApp.getLength();
535 if( -1 != ( nFndPos = sError.indexOf( '%', nFndPos )))
537 sError = sError.replaceAt( nFndPos, 1, sTopic );
538 nFndPos = nFndPos + sTopic.getLength();
540 if( -1 != ( nFndPos = sError.indexOf( '%', nFndPos )))
541 sError = sError.replaceAt( nFndPos, 1, sItem );
545 else
546 return false;
548 ScopedVclPtrInstance<MessageDialog>::Create(pImpl->m_pParentWin, sError)->Execute();
551 else if( !pImpl->m_bIsConnect )
552 Disconnect();
553 pImpl->m_bIsConnect = false;
554 return true;
557 void SvBaseLink::Closed()
559 if( xObj.Is() )
560 xObj->RemoveAllDataAdvise( this );
563 FileDialogHelper & SvBaseLink::GetInsertFileDialog(const OUString& rFactory) const
565 if ( pImpl->m_pFileDlg )
566 delete pImpl->m_pFileDlg;
567 pImpl->m_pFileDlg = new FileDialogHelper(
568 ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
569 SFXWB_INSERT, rFactory);
570 return *pImpl->m_pFileDlg;
573 ImplDdeItem::~ImplDdeItem()
575 bIsInDTOR = true;
576 // So that no-one gets the idea to delete the pointer when Disconnecting!
577 SvBaseLinkRef aRef( pLink );
578 aRef->Disconnect();
581 DdeData* ImplDdeItem::Get( SotClipboardFormatId nFormat )
583 if( pLink->GetObj() )
585 // is it still valid?
586 if( bIsValidData && nFormat == aData.GetFormat() )
587 return &aData;
589 Any aValue;
590 OUString sMimeType( SotExchange::GetFormatMimeType( nFormat ));
591 if( pLink->GetObj()->GetData( aValue, sMimeType ) )
593 if( aValue >>= aSeq )
595 aData = DdeData( aSeq.getConstArray(), aSeq.getLength(), nFormat );
597 bIsValidData = true;
598 return &aData;
602 aSeq.realloc( 0 );
603 bIsValidData = false;
604 return 0;
608 bool ImplDdeItem::Put( const DdeData* )
610 OSL_FAIL( "ImplDdeItem::Put not implemented" );
611 return false;
615 void ImplDdeItem::AdviseLoop( bool bOpen )
617 // Connection is closed, so also unsubscribe link
618 if( pLink->GetObj() )
620 if( bOpen )
622 // A connection is re-established
623 if( OBJECT_DDE_EXTERN == pLink->GetObjType() )
625 pLink->GetObj()->AddDataAdvise( pLink, OUString("text/plain;charset=utf-16"), ADVISEMODE_NODATA );
626 pLink->GetObj()->AddConnectAdvise( pLink );
629 else
631 // So that no-one gets the idea to delete the pointer
632 // when Disconnecting!
633 SvBaseLinkRef aRef( pLink );
634 aRef->Disconnect();
641 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */