Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / sfx2 / source / appl / lnkbase2.cxx
blob842a83ec0fa8828283a66e1c586f0bcad05ec3bc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <sfx2/lnkbase.hxx>
31 #include <sot/exchange.hxx>
32 #include <com/sun/star/uno/Any.hxx>
33 #include <com/sun/star/uno/Sequence.hxx>
34 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
35 #include <vcl/msgbox.hxx>
36 #include <sfx2/linkmgr.hxx>
37 #include <vcl/svapp.hxx>
38 #include "app.hrc"
39 #include "sfx2/sfxresid.hxx"
40 #include <sfx2/filedlghelper.hxx>
41 #include <tools/debug.hxx>
42 #include <svl/svdde.hxx>
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
47 namespace sfx2
50 TYPEINIT0( SvBaseLink )
52 static DdeTopic* FindTopic( const String &, sal_uInt16* = 0 );
54 class ImplDdeItem;
56 struct BaseLink_Impl
58 Link m_aEndEditLink;
59 LinkManager* m_pLinkMgr;
60 Window* m_pParentWin;
61 FileDialogHelper* m_pFileDlg;
62 bool m_bIsConnect;
64 BaseLink_Impl() :
65 m_pLinkMgr( NULL )
66 , m_pParentWin( NULL )
67 , m_pFileDlg( NULL )
68 , m_bIsConnect( false )
71 ~BaseLink_Impl()
72 { delete m_pFileDlg; }
75 // only for internal management
76 struct ImplBaseLinkData
78 struct tClientType
80 // applies for all links
81 sal_uIntPtr nCntntType; // Update Format
82 // Not Ole-Links
83 sal_Bool bIntrnlLnk; // It is an internal link
84 sal_uInt16 nUpdateMode; // UpdateMode
87 struct tDDEType
89 ImplDdeItem* pItem;
92 union {
93 tClientType ClientType;
94 tDDEType DDEType;
96 ImplBaseLinkData()
98 ClientType.nCntntType = 0;
99 ClientType.bIntrnlLnk = sal_False;
100 ClientType.nUpdateMode = 0;
101 DDEType.pItem = NULL;
106 class ImplDdeItem : public DdeGetPutItem
108 SvBaseLink* pLink;
109 DdeData aData;
110 Sequence< sal_Int8 > aSeq; // Datacontainer for DdeData !!!
111 sal_Bool bIsValidData : 1;
112 sal_Bool bIsInDTOR : 1;
113 public:
114 ImplDdeItem( SvBaseLink& rLink, const String& rStr )
115 : DdeGetPutItem( rStr ), pLink( &rLink ), bIsValidData( sal_False ),
116 bIsInDTOR( sal_False )
118 virtual ~ImplDdeItem();
120 virtual DdeData* Get( sal_uIntPtr );
121 virtual sal_Bool Put( const DdeData* );
122 virtual void AdviseLoop( sal_Bool );
124 void Notify()
126 bIsValidData = sal_False;
127 DdeGetPutItem::NotifyClient();
130 sal_Bool IsInDTOR() const { return bIsInDTOR; }
133 //--------------------------------------------------------------------------
135 SvBaseLink::SvBaseLink()
137 pImpl = new BaseLink_Impl();
138 nObjType = OBJECT_CLIENT_SO;
139 pImplData = new ImplBaseLinkData;
140 bVisible = bSynchron = bUseCache = sal_True;
141 bWasLastEditOK = sal_False;
144 //--------------------------------------------------------------------------
146 SvBaseLink::SvBaseLink( sal_uInt16 nUpdateMode, sal_uIntPtr nContentType )
148 pImpl = new BaseLink_Impl();
149 nObjType = OBJECT_CLIENT_SO;
150 pImplData = new ImplBaseLinkData;
151 bVisible = bSynchron = bUseCache = sal_True;
152 bWasLastEditOK = sal_False;
154 // It it going to be a Ole-Link,
155 pImplData->ClientType.nUpdateMode = nUpdateMode;
156 pImplData->ClientType.nCntntType = nContentType;
157 pImplData->ClientType.bIntrnlLnk = sal_False;
160 //--------------------------------------------------------------------------
162 SvBaseLink::SvBaseLink( const String& rLinkName, sal_uInt16 nObjectType, SvLinkSource* pObj )
163 : pImpl(0)
165 bVisible = bSynchron = bUseCache = sal_True;
166 bWasLastEditOK = sal_False;
167 aLinkName = rLinkName;
168 pImplData = new ImplBaseLinkData;
169 nObjType = nObjectType;
171 if( !pObj )
173 DBG_ASSERT( pObj, "Where is my left-most object" );
174 return;
177 if( OBJECT_DDE_EXTERN == nObjType )
179 sal_uInt16 nItemStt = 0;
180 DdeTopic* pTopic = FindTopic( aLinkName, &nItemStt );
181 if( pTopic )
183 // then we have it all together
184 // MM_TODO how do I get the name
185 String aStr = aLinkName; // xLinkName->GetDisplayName();
186 aStr = aStr.Copy( nItemStt );
187 pImplData->DDEType.pItem = new ImplDdeItem( *this, aStr );
188 pTopic->InsertItem( pImplData->DDEType.pItem );
190 // store the Advice
191 xObj = pObj;
194 else if( pObj->Connect( this ) )
195 xObj = pObj;
198 //--------------------------------------------------------------------------
200 SvBaseLink::~SvBaseLink()
202 Disconnect();
204 switch( nObjType )
206 case OBJECT_DDE_EXTERN:
207 if( !pImplData->DDEType.pItem->IsInDTOR() )
208 delete pImplData->DDEType.pItem;
209 break;
212 delete pImplData;
213 delete pImpl;
216 IMPL_LINK( SvBaseLink, EndEditHdl, String*, _pNewName )
218 String sNewName;
219 if ( _pNewName )
220 sNewName = *_pNewName;
221 if ( !ExecuteEdit( sNewName ) )
222 sNewName.Erase();
223 bWasLastEditOK = ( sNewName.Len() > 0 );
224 if ( pImpl->m_aEndEditLink.IsSet() )
225 pImpl->m_aEndEditLink.Call( this );
226 return 0;
229 //--------------------------------------------------------------------------
231 void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP )
233 DBG_ASSERT( nObjType != OBJECT_CLIENT_DDE, "type already set" );
234 DBG_ASSERT( !xObj.Is(), "object exist" );
236 nObjType = nObjTypeP;
239 //--------------------------------------------------------------------------
241 void SvBaseLink::SetName( const String & rNm )
243 aLinkName = rNm;
246 //--------------------------------------------------------------------------
248 void SvBaseLink::SetObj( SvLinkSource * pObj )
250 DBG_ASSERT( (nObjType & OBJECT_CLIENT_SO &&
251 pImplData->ClientType.bIntrnlLnk) ||
252 nObjType == OBJECT_CLIENT_GRF,
253 "no intern link" );
254 xObj = pObj;
257 //--------------------------------------------------------------------------
259 void SvBaseLink::SetLinkSourceName( const String & rLnkNm )
261 if( aLinkName == rLnkNm )
262 return;
264 AddNextRef(); // should be superfluous
265 // remove old connection
266 Disconnect();
268 aLinkName = rLnkNm;
270 // New Connection
271 _GetRealObject();
272 ReleaseRef(); // should be superfluous
275 //--------------------------------------------------------------------------
277 String SvBaseLink::GetLinkSourceName() const
279 return aLinkName;
282 //--------------------------------------------------------------------------
284 void SvBaseLink::SetUpdateMode( sal_uInt16 nMode )
286 if( ( OBJECT_CLIENT_SO & nObjType ) &&
287 pImplData->ClientType.nUpdateMode != nMode )
289 AddNextRef();
290 Disconnect();
292 pImplData->ClientType.nUpdateMode = nMode;
293 _GetRealObject();
294 ReleaseRef();
298 // #i88291#
299 void SvBaseLink::clearStreamToLoadFrom()
301 m_xInputStreamToLoadFrom.clear();
302 if( xObj.Is() )
304 xObj->clearStreamToLoadFrom();
308 sal_Bool SvBaseLink::Update()
310 if( OBJECT_CLIENT_SO & nObjType )
312 AddNextRef();
313 Disconnect();
315 _GetRealObject();
316 ReleaseRef();
317 if( xObj.Is() )
319 xObj->setStreamToLoadFrom(m_xInputStreamToLoadFrom,m_bIsReadOnly);
320 String sMimeType( SotExchange::GetFormatMimeType(
321 pImplData->ClientType.nCntntType ));
322 Any aData;
324 if( xObj->GetData( aData, sMimeType ) )
326 UpdateResult eRes = DataChanged(sMimeType, aData);
327 bool bSuccess = eRes == SUCCESS;
328 //for manual Updates there is no need to hold the ServerObject
329 if( OBJECT_CLIENT_DDE == nObjType &&
330 LINKUPDATE_ONCALL == GetUpdateMode() && xObj.Is() )
331 xObj->RemoveAllDataAdvise( this );
332 return bSuccess;
334 if( xObj.Is() )
336 // should be asynschron?
337 if( xObj->IsPending() )
338 return sal_True;
340 // we do not need the object anymore
341 AddNextRef();
342 Disconnect();
343 ReleaseRef();
347 return sal_False;
351 sal_uInt16 SvBaseLink::GetUpdateMode() const
353 return ( OBJECT_CLIENT_SO & nObjType )
354 ? pImplData->ClientType.nUpdateMode
355 : sal::static_int_cast< sal_uInt16 >( LINKUPDATE_ONCALL );
359 void SvBaseLink::_GetRealObject( sal_Bool bConnect)
361 if( !pImpl->m_pLinkMgr )
362 return;
364 DBG_ASSERT( !xObj.Is(), "object already exist" );
366 if( OBJECT_CLIENT_DDE == nObjType )
368 String sServer;
369 if( pImpl->m_pLinkMgr->GetDisplayNames( this, &sServer ) &&
370 sServer == GetpApp()->GetAppName() ) // internal Link !!!
372 // so that the Internal link can be created!
373 nObjType = OBJECT_INTERN;
374 xObj = pImpl->m_pLinkMgr->CreateObj( this );
376 pImplData->ClientType.bIntrnlLnk = sal_True;
377 nObjType = OBJECT_CLIENT_DDE; // so we know what it once was!
379 else
381 pImplData->ClientType.bIntrnlLnk = sal_False;
382 xObj = pImpl->m_pLinkMgr->CreateObj( this );
385 else if( (OBJECT_CLIENT_SO & nObjType) )
386 xObj = pImpl->m_pLinkMgr->CreateObj( this );
388 if( bConnect && ( !xObj.Is() || !xObj->Connect( this ) ) )
389 Disconnect();
392 sal_uIntPtr SvBaseLink::GetContentType() const
394 if( OBJECT_CLIENT_SO & nObjType )
395 return pImplData->ClientType.nCntntType;
397 return 0; // all Formats ?
401 sal_Bool SvBaseLink::SetContentType( sal_uIntPtr nType )
403 if( OBJECT_CLIENT_SO & nObjType )
405 pImplData->ClientType.nCntntType = nType;
406 return sal_True;
408 return sal_False;
411 LinkManager* SvBaseLink::GetLinkManager()
413 return pImpl->m_pLinkMgr;
416 const LinkManager* SvBaseLink::GetLinkManager() const
418 return pImpl->m_pLinkMgr;
421 void SvBaseLink::SetLinkManager( LinkManager* _pMgr )
423 pImpl->m_pLinkMgr = _pMgr;
426 void SvBaseLink::Disconnect()
428 if( xObj.Is() )
430 xObj->RemoveAllDataAdvise( this );
431 xObj->RemoveConnectAdvise( this );
432 xObj.Clear();
436 SvBaseLink::UpdateResult SvBaseLink::DataChanged( const String &, const ::com::sun::star::uno::Any & )
438 switch( nObjType )
440 case OBJECT_DDE_EXTERN:
441 if( pImplData->DDEType.pItem )
442 pImplData->DDEType.pItem->Notify();
443 break;
445 return SUCCESS;
448 void SvBaseLink::Edit( Window* pParent, const Link& rEndEditHdl )
450 pImpl->m_pParentWin = pParent;
451 pImpl->m_aEndEditLink = rEndEditHdl;
452 pImpl->m_bIsConnect = ( xObj.Is() != sal_False );
453 if( !pImpl->m_bIsConnect )
454 _GetRealObject( xObj.Is() );
456 bool bAsync = false;
457 Link aLink = LINK( this, SvBaseLink, EndEditHdl );
459 if( OBJECT_CLIENT_SO & nObjType && pImplData->ClientType.bIntrnlLnk )
461 if( pImpl->m_pLinkMgr )
463 SvLinkSourceRef ref = pImpl->m_pLinkMgr->CreateObj( this );
464 if( ref.Is() )
466 ref->Edit( pParent, this, aLink );
467 bAsync = true;
471 else
473 xObj->Edit( pParent, this, aLink );
474 bAsync = true;
477 if ( !bAsync )
479 ExecuteEdit( String() );
480 bWasLastEditOK = sal_False;
481 if ( pImpl->m_aEndEditLink.IsSet() )
482 pImpl->m_aEndEditLink.Call( this );
486 bool SvBaseLink::ExecuteEdit( const String& _rNewName )
488 if( _rNewName.Len() != 0 )
490 SetLinkSourceName( _rNewName );
491 if( !Update() )
493 String sApp, sTopic, sItem, sError;
494 pImpl->m_pLinkMgr->GetDisplayNames( this, &sApp, &sTopic, &sItem );
495 if( nObjType == OBJECT_CLIENT_DDE )
497 sError = SFX2_RESSTR(STR_DDE_ERROR);
499 sal_uInt16 nFndPos = sError.Search( '%' );
500 if( STRING_NOTFOUND != nFndPos )
502 sError.Erase( nFndPos, 1 ).Insert( sApp, nFndPos );
503 nFndPos = nFndPos + sApp.Len();
505 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos )))
507 sError.Erase( nFndPos, 1 ).Insert( sTopic, nFndPos );
508 nFndPos = nFndPos + sTopic.Len();
510 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos )))
511 sError.Erase( nFndPos, 1 ).Insert( sItem, nFndPos );
513 else
514 return false;
516 ErrorBox( pImpl->m_pParentWin, WB_OK, sError ).Execute();
519 else if( !pImpl->m_bIsConnect )
520 Disconnect();
521 pImpl->m_bIsConnect = false;
522 return true;
525 void SvBaseLink::Closed()
527 if( xObj.Is() )
528 xObj->RemoveAllDataAdvise( this );
531 FileDialogHelper & SvBaseLink::GetInsertFileDialog(const String& rFactory) const
533 if ( pImpl->m_pFileDlg )
534 delete pImpl->m_pFileDlg;
535 pImpl->m_pFileDlg = new FileDialogHelper(
536 ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
537 SFXWB_INSERT, rFactory);
538 return *pImpl->m_pFileDlg;
541 ImplDdeItem::~ImplDdeItem()
543 bIsInDTOR = sal_True;
544 // So that no-one gets the idea to delete the pointer when Disconnecting!
545 SvBaseLinkRef aRef( pLink );
546 aRef->Disconnect();
549 DdeData* ImplDdeItem::Get( sal_uIntPtr nFormat )
551 if( pLink->GetObj() )
553 // is it still valid?
554 if( bIsValidData && nFormat == aData.GetFormat() )
555 return &aData;
557 Any aValue;
558 String sMimeType( SotExchange::GetFormatMimeType( nFormat ));
559 if( pLink->GetObj()->GetData( aValue, sMimeType ) )
561 if( aValue >>= aSeq )
563 aData = DdeData( (const char *)aSeq.getConstArray(), aSeq.getLength(), nFormat );
565 bIsValidData = sal_True;
566 return &aData;
570 aSeq.realloc( 0 );
571 bIsValidData = sal_False;
572 return 0;
576 sal_Bool ImplDdeItem::Put( const DdeData* )
578 OSL_FAIL( "ImplDdeItem::Put not implemented" );
579 return sal_False;
583 void ImplDdeItem::AdviseLoop( sal_Bool bOpen )
585 // Connection is closed, so also unsubscribe link
586 if( pLink->GetObj() )
588 if( bOpen )
590 // A connection is re-established
591 if( OBJECT_DDE_EXTERN == pLink->GetObjType() )
593 pLink->GetObj()->AddDataAdvise( pLink, String::CreateFromAscii( "text/plain;charset=utf-16" ), ADVISEMODE_NODATA );
594 pLink->GetObj()->AddConnectAdvise( pLink );
597 else
599 // So that no-one gets the idea to delete the pointer
600 // when Disconnecting!
601 SvBaseLinkRef aRef( pLink );
602 aRef->Disconnect();
608 static DdeTopic* FindTopic( const String & rLinkName, sal_uInt16* pItemStt )
610 if( 0 == rLinkName.Len() )
611 return 0;
613 String sNm( rLinkName );
614 sal_uInt16 nTokenPos = 0;
615 String sService( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) );
617 DdeServices& rSvc = DdeService::GetServices();
618 for( DdeService* pService = rSvc.First(); pService;
619 pService = rSvc.Next() )
620 if( pService->GetName() == sService )
622 // then we search for the Topic
623 String sTopic( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) );
624 if( pItemStt )
625 *pItemStt = nTokenPos;
627 std::vector<DdeTopic*>& rTopics = pService->GetTopics();
629 for( int i = 0; i < 2; ++i )
631 for( std::vector<DdeTopic*>::iterator iterTopic = rTopics.begin();
632 iterTopic != rTopics.end(); ++iterTopic )
633 if( (*iterTopic)->GetName() == sTopic )
634 return *iterTopic;
636 // Topic not found?
637 // then we try once to create it
638 if( i || !pService->MakeTopic( sTopic ) )
639 break; // did not work, exiting
641 break;
643 return 0;
648 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */