bump product version to 4.2.0.1
[LibreOffice.git] / sfx2 / source / appl / lnkbase2.cxx
blob3163debb7dff4ff559d2efdfc798ed71e2122b0e
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/msgbox.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 static DdeTopic* FindTopic( const OUString &, sal_uInt16* = 0 );
45 class ImplDdeItem;
47 struct BaseLink_Impl
49 Link m_aEndEditLink;
50 LinkManager* m_pLinkMgr;
51 Window* m_pParentWin;
52 FileDialogHelper* m_pFileDlg;
53 bool m_bIsConnect;
55 BaseLink_Impl() :
56 m_pLinkMgr( NULL )
57 , m_pParentWin( NULL )
58 , m_pFileDlg( NULL )
59 , m_bIsConnect( false )
62 ~BaseLink_Impl()
63 { delete m_pFileDlg; }
66 // only for internal management
67 struct ImplBaseLinkData
69 struct tClientType
71 // applies for all links
72 sal_uIntPtr nCntntType; // Update Format
73 // Not Ole-Links
74 sal_Bool bIntrnlLnk; // It is an internal link
75 sal_uInt16 nUpdateMode; // UpdateMode
78 struct tDDEType
80 ImplDdeItem* pItem;
83 union {
84 tClientType ClientType;
85 tDDEType DDEType;
87 ImplBaseLinkData()
89 ClientType.nCntntType = 0;
90 ClientType.bIntrnlLnk = sal_False;
91 ClientType.nUpdateMode = 0;
92 DDEType.pItem = NULL;
97 class ImplDdeItem : public DdeGetPutItem
99 SvBaseLink* pLink;
100 DdeData aData;
101 Sequence< sal_Int8 > aSeq; // Datacontainer for DdeData !!!
102 sal_Bool bIsValidData : 1;
103 sal_Bool bIsInDTOR : 1;
104 public:
105 ImplDdeItem( SvBaseLink& rLink, const OUString& rStr )
106 : DdeGetPutItem( rStr ), pLink( &rLink ), bIsValidData( sal_False ),
107 bIsInDTOR( sal_False )
109 virtual ~ImplDdeItem();
111 virtual DdeData* Get( sal_uIntPtr );
112 virtual bool Put( const DdeData* );
113 virtual void AdviseLoop( bool );
115 void Notify()
117 bIsValidData = sal_False;
118 DdeGetPutItem::NotifyClient();
121 sal_Bool IsInDTOR() const { return bIsInDTOR; }
124 //--------------------------------------------------------------------------
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 = sal_True;
133 bWasLastEditOK = sal_False;
136 //--------------------------------------------------------------------------
138 SvBaseLink::SvBaseLink( sal_uInt16 nUpdateMode, sal_uIntPtr nContentType )
139 : m_bIsReadOnly(false)
141 pImpl = new BaseLink_Impl();
142 nObjType = OBJECT_CLIENT_SO;
143 pImplData = new ImplBaseLinkData;
144 bVisible = bSynchron = bUseCache = sal_True;
145 bWasLastEditOK = sal_False;
147 // It it going to be a Ole-Link,
148 pImplData->ClientType.nUpdateMode = nUpdateMode;
149 pImplData->ClientType.nCntntType = nContentType;
150 pImplData->ClientType.bIntrnlLnk = sal_False;
153 //--------------------------------------------------------------------------
155 SvBaseLink::SvBaseLink( const OUString& rLinkName, sal_uInt16 nObjectType, SvLinkSource* pObj )
156 : pImpl(0)
157 , m_bIsReadOnly(false)
159 bVisible = bSynchron = bUseCache = sal_True;
160 bWasLastEditOK = sal_False;
161 aLinkName = rLinkName;
162 pImplData = new ImplBaseLinkData;
163 nObjType = nObjectType;
165 if( !pObj )
167 DBG_ASSERT( pObj, "Where is my left-most object" );
168 return;
171 if( OBJECT_DDE_EXTERN == nObjType )
173 sal_uInt16 nItemStt = 0;
174 DdeTopic* pTopic = FindTopic( aLinkName, &nItemStt );
175 if( pTopic )
177 // then we have it all together
178 // MM_TODO how do I get the name
179 OUString aStr = aLinkName; // xLinkName->GetDisplayName();
180 aStr = aStr.copy( nItemStt );
181 pImplData->DDEType.pItem = new ImplDdeItem( *this, aStr );
182 pTopic->InsertItem( pImplData->DDEType.pItem );
184 // store the Advice
185 xObj = pObj;
188 else if( pObj->Connect( this ) )
189 xObj = pObj;
192 //--------------------------------------------------------------------------
194 SvBaseLink::~SvBaseLink()
196 Disconnect();
198 switch( nObjType )
200 case OBJECT_DDE_EXTERN:
201 if( !pImplData->DDEType.pItem->IsInDTOR() )
202 delete pImplData->DDEType.pItem;
203 break;
206 delete pImplData;
207 delete pImpl;
210 IMPL_LINK( SvBaseLink, EndEditHdl, OUString*, _pNewName )
212 OUString sNewName;
213 if ( _pNewName )
214 sNewName = *_pNewName;
215 if ( !ExecuteEdit( sNewName ) )
216 sNewName = "";
217 bWasLastEditOK = !sNewName.isEmpty();
218 if ( pImpl->m_aEndEditLink.IsSet() )
219 pImpl->m_aEndEditLink.Call( this );
220 return 0;
223 //--------------------------------------------------------------------------
225 void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP )
227 DBG_ASSERT( nObjType != OBJECT_CLIENT_DDE, "type already set" );
228 DBG_ASSERT( !xObj.Is(), "object exist" );
230 nObjType = nObjTypeP;
233 //--------------------------------------------------------------------------
235 void SvBaseLink::SetName( const OUString & rNm )
237 aLinkName = rNm;
240 //--------------------------------------------------------------------------
242 void SvBaseLink::SetObj( SvLinkSource * pObj )
244 DBG_ASSERT( (nObjType & OBJECT_CLIENT_SO &&
245 pImplData->ClientType.bIntrnlLnk) ||
246 nObjType == OBJECT_CLIENT_GRF,
247 "no intern link" );
248 xObj = pObj;
251 //--------------------------------------------------------------------------
253 void SvBaseLink::SetLinkSourceName( const OUString & rLnkNm )
255 if( aLinkName == rLnkNm )
256 return;
258 AddNextRef(); // should be superfluous
259 // remove old connection
260 Disconnect();
262 aLinkName = rLnkNm;
264 // New Connection
265 _GetRealObject();
266 ReleaseRef(); // should be superfluous
269 //--------------------------------------------------------------------------
271 OUString SvBaseLink::GetLinkSourceName() const
273 return aLinkName;
276 //--------------------------------------------------------------------------
278 void SvBaseLink::SetUpdateMode( sal_uInt16 nMode )
280 if( ( OBJECT_CLIENT_SO & nObjType ) &&
281 pImplData->ClientType.nUpdateMode != nMode )
283 AddNextRef();
284 Disconnect();
286 pImplData->ClientType.nUpdateMode = nMode;
287 _GetRealObject();
288 ReleaseRef();
292 // #i88291#
293 void SvBaseLink::clearStreamToLoadFrom()
295 m_xInputStreamToLoadFrom.clear();
296 if( xObj.Is() )
298 xObj->clearStreamToLoadFrom();
302 sal_Bool SvBaseLink::Update()
304 if( OBJECT_CLIENT_SO & nObjType )
306 AddNextRef();
307 Disconnect();
309 _GetRealObject();
310 ReleaseRef();
311 if( xObj.Is() )
313 xObj->setStreamToLoadFrom(m_xInputStreamToLoadFrom,m_bIsReadOnly);
314 OUString sMimeType( SotExchange::GetFormatMimeType(
315 pImplData->ClientType.nCntntType ));
316 Any aData;
318 if( xObj->GetData( aData, sMimeType ) )
320 UpdateResult eRes = DataChanged(sMimeType, aData);
321 bool bSuccess = eRes == SUCCESS;
322 //for manual Updates there is no need to hold the ServerObject
323 if( OBJECT_CLIENT_DDE == nObjType &&
324 LINKUPDATE_ONCALL == GetUpdateMode() && xObj.Is() )
325 xObj->RemoveAllDataAdvise( this );
326 return bSuccess;
328 if( xObj.Is() )
330 // should be asynschron?
331 if( xObj->IsPending() )
332 return sal_True;
334 // we do not need the object anymore
335 AddNextRef();
336 Disconnect();
337 ReleaseRef();
341 return sal_False;
345 sal_uInt16 SvBaseLink::GetUpdateMode() const
347 return ( OBJECT_CLIENT_SO & nObjType )
348 ? pImplData->ClientType.nUpdateMode
349 : sal::static_int_cast< sal_uInt16 >( LINKUPDATE_ONCALL );
353 void SvBaseLink::_GetRealObject( sal_Bool bConnect)
355 if( !pImpl->m_pLinkMgr )
356 return;
358 DBG_ASSERT( !xObj.Is(), "object already exist" );
360 if( OBJECT_CLIENT_DDE == nObjType )
362 OUString sServer;
363 if( pImpl->m_pLinkMgr->GetDisplayNames( this, &sServer ) &&
364 sServer == GetpApp()->GetAppName() ) // internal Link !!!
366 // so that the Internal link can be created!
367 nObjType = OBJECT_INTERN;
368 xObj = pImpl->m_pLinkMgr->CreateObj( this );
370 pImplData->ClientType.bIntrnlLnk = sal_True;
371 nObjType = OBJECT_CLIENT_DDE; // so we know what it once was!
373 else
375 pImplData->ClientType.bIntrnlLnk = sal_False;
376 xObj = pImpl->m_pLinkMgr->CreateObj( this );
379 else if( (OBJECT_CLIENT_SO & nObjType) )
380 xObj = pImpl->m_pLinkMgr->CreateObj( this );
382 if( bConnect && ( !xObj.Is() || !xObj->Connect( this ) ) )
383 Disconnect();
386 sal_uIntPtr SvBaseLink::GetContentType() const
388 if( OBJECT_CLIENT_SO & nObjType )
389 return pImplData->ClientType.nCntntType;
391 return 0; // all Formats ?
395 sal_Bool SvBaseLink::SetContentType( sal_uIntPtr nType )
397 if( OBJECT_CLIENT_SO & nObjType )
399 pImplData->ClientType.nCntntType = nType;
400 return sal_True;
402 return sal_False;
405 LinkManager* SvBaseLink::GetLinkManager()
407 return pImpl->m_pLinkMgr;
410 const LinkManager* SvBaseLink::GetLinkManager() const
412 return pImpl->m_pLinkMgr;
415 void SvBaseLink::SetLinkManager( LinkManager* _pMgr )
417 pImpl->m_pLinkMgr = _pMgr;
420 void SvBaseLink::Disconnect()
422 if( xObj.Is() )
424 xObj->RemoveAllDataAdvise( this );
425 xObj->RemoveConnectAdvise( this );
426 xObj.Clear();
430 SvBaseLink::UpdateResult SvBaseLink::DataChanged( const OUString &, const ::com::sun::star::uno::Any & )
432 switch( nObjType )
434 case OBJECT_DDE_EXTERN:
435 if( pImplData->DDEType.pItem )
436 pImplData->DDEType.pItem->Notify();
437 break;
439 return SUCCESS;
442 void SvBaseLink::Edit( Window* pParent, const Link& rEndEditHdl )
444 pImpl->m_pParentWin = pParent;
445 pImpl->m_aEndEditLink = rEndEditHdl;
446 pImpl->m_bIsConnect = ( xObj.Is() != sal_False );
447 if( !pImpl->m_bIsConnect )
448 _GetRealObject( xObj.Is() );
450 bool bAsync = false;
451 Link aLink = LINK( this, SvBaseLink, EndEditHdl );
453 if( OBJECT_CLIENT_SO & nObjType && pImplData->ClientType.bIntrnlLnk )
455 if( pImpl->m_pLinkMgr )
457 SvLinkSourceRef ref = pImpl->m_pLinkMgr->CreateObj( this );
458 if( ref.Is() )
460 ref->Edit( pParent, this, aLink );
461 bAsync = true;
465 else
467 xObj->Edit( pParent, this, aLink );
468 bAsync = true;
471 if ( !bAsync )
473 ExecuteEdit( OUString() );
474 bWasLastEditOK = sal_False;
475 if ( pImpl->m_aEndEditLink.IsSet() )
476 pImpl->m_aEndEditLink.Call( this );
480 bool SvBaseLink::ExecuteEdit( const OUString& _rNewName )
482 if( !_rNewName.isEmpty() )
484 SetLinkSourceName( _rNewName );
485 if( !Update() )
487 OUString sApp, sTopic, sItem, sError;
488 pImpl->m_pLinkMgr->GetDisplayNames( this, &sApp, &sTopic, &sItem );
489 if( nObjType == OBJECT_CLIENT_DDE )
491 sError = SFX2_RESSTR(STR_DDE_ERROR);
493 sal_Int32 nFndPos = sError.indexOf( '%' );
494 if( -1 != nFndPos )
496 sError = sError.replaceAt( nFndPos, 1, sApp );
497 nFndPos = nFndPos + sApp.getLength();
499 if( -1 != ( nFndPos = sError.indexOf( '%', nFndPos )))
501 sError = sError.replaceAt( nFndPos, 1, sTopic );
502 nFndPos = nFndPos + sTopic.getLength();
504 if( -1 != ( nFndPos = sError.indexOf( '%', nFndPos )))
505 sError = sError.replaceAt( nFndPos, 1, sItem );
509 else
510 return false;
512 ErrorBox( pImpl->m_pParentWin, WB_OK, sError ).Execute();
515 else if( !pImpl->m_bIsConnect )
516 Disconnect();
517 pImpl->m_bIsConnect = false;
518 return true;
521 void SvBaseLink::Closed()
523 if( xObj.Is() )
524 xObj->RemoveAllDataAdvise( this );
527 FileDialogHelper & SvBaseLink::GetInsertFileDialog(const OUString& rFactory) const
529 if ( pImpl->m_pFileDlg )
530 delete pImpl->m_pFileDlg;
531 pImpl->m_pFileDlg = new FileDialogHelper(
532 ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
533 SFXWB_INSERT, rFactory);
534 return *pImpl->m_pFileDlg;
537 ImplDdeItem::~ImplDdeItem()
539 bIsInDTOR = sal_True;
540 // So that no-one gets the idea to delete the pointer when Disconnecting!
541 SvBaseLinkRef aRef( pLink );
542 aRef->Disconnect();
545 DdeData* ImplDdeItem::Get( sal_uIntPtr nFormat )
547 if( pLink->GetObj() )
549 // is it still valid?
550 if( bIsValidData && nFormat == aData.GetFormat() )
551 return &aData;
553 Any aValue;
554 OUString sMimeType( SotExchange::GetFormatMimeType( nFormat ));
555 if( pLink->GetObj()->GetData( aValue, sMimeType ) )
557 if( aValue >>= aSeq )
559 aData = DdeData( (const char *)aSeq.getConstArray(), aSeq.getLength(), nFormat );
561 bIsValidData = sal_True;
562 return &aData;
566 aSeq.realloc( 0 );
567 bIsValidData = sal_False;
568 return 0;
572 bool ImplDdeItem::Put( const DdeData* )
574 OSL_FAIL( "ImplDdeItem::Put not implemented" );
575 return false;
579 void ImplDdeItem::AdviseLoop( bool bOpen )
581 // Connection is closed, so also unsubscribe link
582 if( pLink->GetObj() )
584 if( bOpen )
586 // A connection is re-established
587 if( OBJECT_DDE_EXTERN == pLink->GetObjType() )
589 pLink->GetObj()->AddDataAdvise( pLink, OUString("text/plain;charset=utf-16"), ADVISEMODE_NODATA );
590 pLink->GetObj()->AddConnectAdvise( pLink );
593 else
595 // So that no-one gets the idea to delete the pointer
596 // when Disconnecting!
597 SvBaseLinkRef aRef( pLink );
598 aRef->Disconnect();
604 static DdeTopic* FindTopic( const OUString & rLinkName, sal_uInt16* pItemStt )
606 if( rLinkName.isEmpty() )
607 return 0;
609 OUString sNm( rLinkName );
610 sal_Int32 nTokenPos = 0;
611 OUString sService( sNm.getToken( 0, cTokenSeparator, nTokenPos ) );
613 DdeServices& rSvc = DdeService::GetServices();
614 for (DdeServices::iterator aI = rSvc.begin(); aI != rSvc.end(); ++aI)
616 DdeService* pService = *aI;
617 if( pService->GetName() == sService )
619 // then we search for the Topic
620 OUString sTopic( sNm.getToken( 0, cTokenSeparator, nTokenPos ) );
621 if( pItemStt )
622 *pItemStt = nTokenPos;
624 std::vector<DdeTopic*>& rTopics = pService->GetTopics();
626 for( int i = 0; i < 2; ++i )
628 for( std::vector<DdeTopic*>::iterator iterTopic = rTopics.begin();
629 iterTopic != rTopics.end(); ++iterTopic )
630 if( (*iterTopic)->GetName() == sTopic )
631 return *iterTopic;
633 // Topic not found?
634 // then we try once to create it
635 if( i || !pService->MakeTopic( sTopic ) )
636 break; // did not work, exiting
638 break;
641 return 0;
646 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */