xref: /trunk/main/sfx2/source/appl/lnkbase2.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sfx2.hxx"
30 
31 
32 #include <sfx2/lnkbase.hxx>
33 #include <sot/exchange.hxx>
34 #include <com/sun/star/uno/Any.hxx>
35 #include <com/sun/star/uno/Sequence.hxx>
36 #include <vcl/msgbox.hxx>
37 #include <sfx2/linkmgr.hxx>
38 #include <vcl/svapp.hxx>
39 #include "app.hrc"
40 #include "sfx2/sfxresid.hxx"
41 #include <sfx2/filedlghelper.hxx>
42 #include <tools/debug.hxx>
43 #include <svl/svdde.hxx>
44 
45 using namespace ::com::sun::star::uno;
46 
47 namespace sfx2
48 {
49 
50 TYPEINIT0( SvBaseLink )
51 
52 static DdeTopic* FindTopic( const String &, sal_uInt16* = 0 );
53 
54 class  ImplDdeItem;
55 
56 struct BaseLink_Impl
57 {
58     Link                m_aEndEditLink;
59     LinkManager*      m_pLinkMgr;
60     Window*             m_pParentWin;
61     FileDialogHelper*   m_pFileDlg;
62     bool                m_bIsConnect;
63 
64     BaseLink_Impl() :
65           m_pLinkMgr( NULL )
66         , m_pParentWin( NULL )
67         , m_pFileDlg( NULL )
68         , m_bIsConnect( false )
69         {}
70 
71     ~BaseLink_Impl()
72         { delete m_pFileDlg; }
73 };
74 
75 // nur fuer die interne Verwaltung
76 struct ImplBaseLinkData
77 {
78 	struct tClientType
79 	{
80 		// gilt fuer alle Links
81 		sal_uIntPtr				nCntntType; // Update Format
82 		// nicht Ole-Links
83 		sal_Bool 			bIntrnlLnk; // ist es ein interner Link
84 		sal_uInt16 			nUpdateMode;// UpdateMode
85 	};
86 
87 	struct tDDEType
88 	{
89 		ImplDdeItem* pItem;
90 	};
91 
92 	union {
93 		tClientType ClientType;
94 		tDDEType DDEType;
95 	};
96 	ImplBaseLinkData()
97 	{
98 		ClientType.nCntntType = 0;
99 		ClientType.bIntrnlLnk = sal_False;
100 		ClientType.nUpdateMode = 0;
101 		DDEType.pItem = NULL;
102 	}
103 };
104 
105 
106 class ImplDdeItem : public DdeGetPutItem
107 {
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 )
117 	{}
118 	virtual ~ImplDdeItem();
119 
120 	virtual DdeData* Get( sal_uIntPtr );
121 	virtual sal_Bool Put( const DdeData* );
122 	virtual void AdviseLoop( sal_Bool );
123 
124 	void Notify()
125 	{
126 		bIsValidData = sal_False;
127 		DdeGetPutItem::NotifyClient();
128 	}
129 
130 	sal_Bool IsInDTOR() const { return bIsInDTOR; }
131 };
132 
133 
134 /************************************************************************
135 |*	  SvBaseLink::SvBaseLink()
136 |*
137 |*	  Beschreibung
138 *************************************************************************/
139 
140 SvBaseLink::SvBaseLink()
141 {
142     pImpl = new BaseLink_Impl();
143 	nObjType = OBJECT_CLIENT_SO;
144 	pImplData = new ImplBaseLinkData;
145 	bVisible = bSynchron = bUseCache = sal_True;
146     bWasLastEditOK = sal_False;
147 }
148 
149 /************************************************************************
150 |*	  SvBaseLink::SvBaseLink()
151 |*
152 |*	  Beschreibung
153 *************************************************************************/
154 
155 SvBaseLink::SvBaseLink( sal_uInt16 nUpdateMode, sal_uIntPtr nContentType )
156 {
157     pImpl = new BaseLink_Impl();
158 	nObjType = OBJECT_CLIENT_SO;
159 	pImplData = new ImplBaseLinkData;
160 	bVisible = bSynchron = bUseCache = sal_True;
161     bWasLastEditOK = sal_False;
162 
163 	// falls es ein Ole-Link wird,
164 	pImplData->ClientType.nUpdateMode = nUpdateMode;
165 	pImplData->ClientType.nCntntType = nContentType;
166 	pImplData->ClientType.bIntrnlLnk = sal_False;
167 }
168 
169 /************************************************************************
170 |*	  SvBaseLink::SvBaseLink()
171 |*
172 |*	  Beschreibung
173 *************************************************************************/
174 
175 SvBaseLink::SvBaseLink( const String& rLinkName, sal_uInt16 nObjectType, SvLinkSource* pObj )
176 {
177 	bVisible = bSynchron = bUseCache = sal_True;
178     bWasLastEditOK = sal_False;
179 	aLinkName = rLinkName;
180 	pImplData = new ImplBaseLinkData;
181 	nObjType = nObjectType;
182 
183 	if( !pObj )
184 	{
185 		DBG_ASSERT( pObj, "Wo ist mein zu linkendes Object" );
186 		return;
187 	}
188 
189 	if( OBJECT_DDE_EXTERN == nObjType )
190 	{
191 		sal_uInt16 nItemStt = 0;
192 		DdeTopic* pTopic = FindTopic( aLinkName, &nItemStt );
193 		if( pTopic )
194 		{
195 			// dann haben wir alles zusammen
196 			// MM hat gefummelt ???
197 			// MM_TODO wie kriege ich den Namen
198 			String aStr = aLinkName; // xLinkName->GetDisplayName();
199 			aStr = aStr.Copy( nItemStt );
200 			pImplData->DDEType.pItem = new ImplDdeItem( *this, aStr );
201 			pTopic->InsertItem( pImplData->DDEType.pItem );
202 
203 			// dann koennen wir uns auch das Advise merken
204 			xObj = pObj;
205 		}
206 	}
207     else if( pObj->Connect( this ) )
208 		xObj = pObj;
209 }
210 
211 /************************************************************************
212 |*	  SvBaseLink::~SvBaseLink()
213 |*
214 |*	  Beschreibung
215 *************************************************************************/
216 
217 SvBaseLink::~SvBaseLink()
218 {
219 	Disconnect();
220 
221 	switch( nObjType )
222 	{
223 	case OBJECT_DDE_EXTERN:
224 		if( !pImplData->DDEType.pItem->IsInDTOR() )
225 			delete pImplData->DDEType.pItem;
226 		break;
227 	}
228 
229 	delete pImplData;
230 }
231 
232 IMPL_LINK( SvBaseLink, EndEditHdl, String*, _pNewName )
233 {
234     String sNewName;
235     if ( _pNewName )
236         sNewName = *_pNewName;
237     if ( !ExecuteEdit( sNewName ) )
238         sNewName.Erase();
239     bWasLastEditOK = ( sNewName.Len() > 0 );
240     if ( pImpl->m_aEndEditLink.IsSet() )
241         pImpl->m_aEndEditLink.Call( this );
242     return 0;
243 }
244 
245 /************************************************************************
246 |*	  SvBaseLink::SetObjType()
247 |*
248 |*	  Beschreibung
249 *************************************************************************/
250 
251 void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP )
252 {
253 	DBG_ASSERT( nObjType != OBJECT_CLIENT_DDE, "type already set" );
254 	DBG_ASSERT( !xObj.Is(), "object exist" );
255 
256 	nObjType = nObjTypeP;
257 }
258 
259 /************************************************************************
260 |*	  SvBaseLink::SetName()
261 |*
262 |*	  Beschreibung
263 *************************************************************************/
264 
265 void SvBaseLink::SetName( const String & rNm )
266 {
267 	aLinkName = rNm;
268 }
269 
270 /************************************************************************
271 |*	  SvBaseLink::GetName()
272 |*
273 |*	  Beschreibung
274 *************************************************************************/
275 
276 String SvBaseLink::GetName() const
277 {
278 	return aLinkName;
279 }
280 
281 /************************************************************************
282 |*	  SvBaseLink::SetObj()
283 |*
284 |*	  Beschreibung
285 *************************************************************************/
286 
287 void SvBaseLink::SetObj( SvLinkSource * pObj )
288 {
289 	DBG_ASSERT( (nObjType & OBJECT_CLIENT_SO &&
290 				pImplData->ClientType.bIntrnlLnk) ||
291 				nObjType == OBJECT_CLIENT_GRF,
292 				"no intern link" );
293 	xObj = pObj;
294 }
295 
296 /************************************************************************
297 |*	  SvBaseLink::SetLinkSourceName()
298 |*
299 |*	  Beschreibung
300 *************************************************************************/
301 
302 void SvBaseLink::SetLinkSourceName( const String & rLnkNm )
303 {
304 	if( aLinkName == rLnkNm )
305 		return;
306 
307 	AddNextRef(); // sollte ueberfluessig sein
308 	// Alte Verbindung weg
309 	Disconnect();
310 
311 	aLinkName = rLnkNm;
312 
313 	// Neu verbinden
314 	_GetRealObject();
315 	ReleaseRef(); // sollte ueberfluessig sein
316 }
317 
318 /************************************************************************
319 |*	  SvBaseLink::GetLinkSourceName()
320 |*
321 |*	  Beschreibung
322 *************************************************************************/
323 
324 String  SvBaseLink::GetLinkSourceName() const
325 {
326 	return aLinkName;
327 }
328 
329 
330 /************************************************************************
331 |*	  SvBaseLink::SetUpdateMode()
332 |*
333 |*	  Beschreibung
334 *************************************************************************/
335 
336 void SvBaseLink::SetUpdateMode( sal_uInt16 nMode )
337 {
338 	if( ( OBJECT_CLIENT_SO & nObjType ) &&
339 		pImplData->ClientType.nUpdateMode != nMode )
340 	{
341 		AddNextRef();
342 		Disconnect();
343 
344 		pImplData->ClientType.nUpdateMode = nMode;
345 		_GetRealObject();
346 		ReleaseRef();
347 	}
348 }
349 
350 // --> OD 2008-06-19 #i88291#
351 void SvBaseLink::clearStreamToLoadFrom()
352 {
353     m_xInputStreamToLoadFrom.clear();
354     if( xObj.Is() )
355     {
356         xObj->clearStreamToLoadFrom();
357     }
358 }
359 // <--
360 
361 sal_Bool SvBaseLink::Update()
362 {
363 	if( OBJECT_CLIENT_SO & nObjType )
364 	{
365 		AddNextRef();
366 		Disconnect();
367 
368 		_GetRealObject();
369 		ReleaseRef();
370 		if( xObj.Is() )
371 		{
372             xObj->setStreamToLoadFrom(m_xInputStreamToLoadFrom,m_bIsReadOnly);
373             // m_xInputStreamToLoadFrom = 0;
374 			String sMimeType( SotExchange::GetFormatMimeType(
375 							pImplData->ClientType.nCntntType ));
376 			Any aData;
377 
378 			if( xObj->GetData( aData, sMimeType ) )
379 			{
380 				DataChanged( sMimeType, aData );
381 				//JP 13.07.00: Bug 76817 - for manual Updates there is no
382 				//				need to hold the ServerObject
383 				if( OBJECT_CLIENT_DDE == nObjType &&
384 					LINKUPDATE_ONCALL == GetUpdateMode() && xObj.Is() )
385 					xObj->RemoveAllDataAdvise( this );
386 				return sal_True;
387 			}
388 			if( xObj.Is() )
389 			{
390 				// sollten wir asynschron sein?
391 				if( xObj->IsPending() )
392 					return sal_True;
393 
394 				// dann brauchen wir das Object auch nicht mehr
395 				AddNextRef();
396 				Disconnect();
397 				ReleaseRef();
398 			}
399 		}
400 	}
401 	return sal_False;
402 }
403 
404 
405 sal_uInt16 SvBaseLink::GetUpdateMode() const
406 {
407     return ( OBJECT_CLIENT_SO & nObjType )
408 			? pImplData->ClientType.nUpdateMode
409 			: sal::static_int_cast< sal_uInt16 >( LINKUPDATE_ONCALL );
410 }
411 
412 
413 void SvBaseLink::_GetRealObject( sal_Bool bConnect)
414 {
415     if( !pImpl->m_pLinkMgr )
416 		return;
417 
418 	DBG_ASSERT( !xObj.Is(), "object already exist" );
419 
420 	if( OBJECT_CLIENT_DDE == nObjType )
421 	{
422 		String sServer;
423         if( pImpl->m_pLinkMgr->GetDisplayNames( this, &sServer ) &&
424 			sServer == GetpApp()->GetAppName() )		// interner Link !!!
425 		{
426 			// damit der Internal - Link erzeugt werden kann !!!
427 			nObjType = OBJECT_INTERN;
428             xObj = pImpl->m_pLinkMgr->CreateObj( this );
429 
430 			pImplData->ClientType.bIntrnlLnk = sal_True;
431 			nObjType = OBJECT_CLIENT_DDE;		// damit wir wissen was es mal war !!
432 		}
433 		else
434 		{
435 			pImplData->ClientType.bIntrnlLnk = sal_False;
436             xObj = pImpl->m_pLinkMgr->CreateObj( this );
437 		}
438 	}
439 	else if( (OBJECT_CLIENT_SO & nObjType) )
440         xObj = pImpl->m_pLinkMgr->CreateObj( this );
441 
442     if( bConnect && ( !xObj.Is() || !xObj->Connect( this ) ) )
443 		Disconnect();
444 }
445 
446 sal_uIntPtr SvBaseLink::GetContentType() const
447 {
448 	if( OBJECT_CLIENT_SO & nObjType )
449 		return pImplData->ClientType.nCntntType;
450 
451 	return 0;		// alle Formate ?
452 }
453 
454 
455 sal_Bool SvBaseLink::SetContentType( sal_uIntPtr nType )
456 {
457 	if( OBJECT_CLIENT_SO & nObjType )
458 	{
459 		pImplData->ClientType.nCntntType = nType;
460 		return sal_True;
461 	}
462 	return sal_False;
463 }
464 
465 LinkManager* SvBaseLink::GetLinkManager()
466 {
467     return pImpl->m_pLinkMgr;
468 }
469 
470 const LinkManager* SvBaseLink::GetLinkManager() const
471 {
472     return pImpl->m_pLinkMgr;
473 }
474 
475 void SvBaseLink::SetLinkManager( LinkManager* _pMgr )
476 {
477     pImpl->m_pLinkMgr = _pMgr;
478 }
479 
480 void SvBaseLink::Disconnect()
481 {
482 	if( xObj.Is() )
483 	{
484 		xObj->RemoveAllDataAdvise( this );
485 		xObj->RemoveConnectAdvise( this );
486 		xObj.Clear();
487 	}
488 }
489 
490 void SvBaseLink::DataChanged( const String &, const ::com::sun::star::uno::Any & )
491 {
492 	switch( nObjType )
493 	{
494 	case OBJECT_DDE_EXTERN:
495 		if( pImplData->DDEType.pItem )
496 			pImplData->DDEType.pItem->Notify();
497 		break;
498 	}
499 }
500 
501 void SvBaseLink::Edit( Window* pParent, const Link& rEndEditHdl )
502 {
503     pImpl->m_pParentWin = pParent;
504     pImpl->m_aEndEditLink = rEndEditHdl;
505     pImpl->m_bIsConnect = ( xObj.Is() != sal_False );
506     if( !pImpl->m_bIsConnect )
507 		_GetRealObject( xObj.Is() );
508 
509     bool bAsync = false;
510     Link aLink = LINK( this, SvBaseLink, EndEditHdl );
511 
512     if( OBJECT_CLIENT_SO & nObjType && pImplData->ClientType.bIntrnlLnk )
513 	{
514         if( pImpl->m_pLinkMgr )
515 		{
516             SvLinkSourceRef ref = pImpl->m_pLinkMgr->CreateObj( this );
517 			if( ref.Is() )
518             {
519                 ref->Edit( pParent, this, aLink );
520                 bAsync = true;
521             }
522 		}
523 	}
524 	else
525     {
526         xObj->Edit( pParent, this, aLink );
527         bAsync = true;
528     }
529 
530     if ( !bAsync )
531     {
532         ExecuteEdit( String() );
533         bWasLastEditOK = sal_False;
534         if ( pImpl->m_aEndEditLink.IsSet() )
535             pImpl->m_aEndEditLink.Call( this );
536     }
537 }
538 
539 bool SvBaseLink::ExecuteEdit( const String& _rNewName )
540 {
541     if( _rNewName.Len() != 0 )
542     {
543         SetLinkSourceName( _rNewName );
544         if( !Update() )
545         {
546             String sApp, sTopic, sItem, sError;
547             pImpl->m_pLinkMgr->GetDisplayNames( this, &sApp, &sTopic, &sItem );
548             if( nObjType == OBJECT_CLIENT_DDE )
549             {
550                 sError = SfxResId( STR_DDE_ERROR );
551 
552                 sal_uInt16 nFndPos = sError.Search( '%' );
553                 if( STRING_NOTFOUND != nFndPos )
554                 {
555                     sError.Erase( nFndPos, 1 ).Insert( sApp, nFndPos );
556                     nFndPos = nFndPos + sApp.Len();
557                 }
558                 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos )))
559                 {
560                     sError.Erase( nFndPos, 1 ).Insert( sTopic, nFndPos );
561                     nFndPos = nFndPos + sTopic.Len();
562                 }
563                 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos )))
564                     sError.Erase( nFndPos, 1 ).Insert( sItem, nFndPos );
565             }
566             else
567                 return false;
568 
569             ErrorBox( pImpl->m_pParentWin, WB_OK, sError ).Execute();
570         }
571     }
572     else if( !pImpl->m_bIsConnect )
573         Disconnect();
574     pImpl->m_bIsConnect = false;
575     return true;
576 }
577 
578 void SvBaseLink::Closed()
579 {
580     if( xObj.Is() )
581         // beim Advise Abmelden
582         xObj->RemoveAllDataAdvise( this );
583 }
584 
585 FileDialogHelper* SvBaseLink::GetFileDialog( sal_uInt32 nFlags, const String& rFactory ) const
586 {
587     if ( pImpl->m_pFileDlg )
588         delete pImpl->m_pFileDlg;
589     pImpl->m_pFileDlg = new FileDialogHelper( nFlags, rFactory );
590     return pImpl->m_pFileDlg;
591 }
592 
593 ImplDdeItem::~ImplDdeItem()
594 {
595 	bIsInDTOR = sal_True;
596 	// damit im Disconnect nicht jemand auf die Idee kommt, den Pointer zu
597 	// loeschen!!
598 	SvBaseLinkRef aRef( pLink );
599 	aRef->Disconnect();
600 }
601 
602 DdeData* ImplDdeItem::Get( sal_uIntPtr nFormat )
603 {
604 	if( pLink->GetObj() )
605 	{
606 		// ist das noch gueltig?
607 		if( bIsValidData && nFormat == aData.GetFormat() )
608 			return &aData;
609 
610 		Any aValue;
611 		String sMimeType( SotExchange::GetFormatMimeType( nFormat ));
612 		if( pLink->GetObj()->GetData( aValue, sMimeType ) )
613 		{
614 			if( aValue >>= aSeq )
615 			{
616 				aData = DdeData( (const char *)aSeq.getConstArray(), aSeq.getLength(), nFormat );
617 
618 				bIsValidData = sal_True;
619 				return &aData;
620 			}
621 		}
622 	}
623 	aSeq.realloc( 0 );
624 	bIsValidData = sal_False;
625 	return 0;
626 }
627 
628 
629 sal_Bool ImplDdeItem::Put( const DdeData*  )
630 {
631 	DBG_ERROR( "ImplDdeItem::Put not implemented" );
632 	return sal_False;
633 }
634 
635 
636 void ImplDdeItem::AdviseLoop( sal_Bool bOpen )
637 {
638 	// Verbindung wird geschlossen, also Link abmelden
639 	if( pLink->GetObj() )
640 	{
641 		if( bOpen )
642 		{
643 			// es wird wieder eine Verbindung hergestellt
644 			if( OBJECT_DDE_EXTERN == pLink->GetObjType() )
645 			{
646 				pLink->GetObj()->AddDataAdvise( pLink, String::CreateFromAscii( "text/plain;charset=utf-16" ),	ADVISEMODE_NODATA );
647 				pLink->GetObj()->AddConnectAdvise( pLink );
648 			}
649 		}
650 		else
651 		{
652 			// damit im Disconnect nicht jemand auf die Idee kommt,
653 			// den Pointer zu loeschen!!
654 			SvBaseLinkRef aRef( pLink );
655 			aRef->Disconnect();
656 		}
657 	}
658 }
659 
660 
661 static DdeTopic* FindTopic( const String & rLinkName, sal_uInt16* pItemStt )
662 {
663 	if( 0 == rLinkName.Len() )
664 		return 0;
665 
666 	String sNm( rLinkName );
667 	sal_uInt16 nTokenPos = 0;
668 	String sService( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) );
669 
670 	DdeServices& rSvc = DdeService::GetServices();
671 	for( DdeService* pService = rSvc.First(); pService;
672 												pService = rSvc.Next() )
673 		if( pService->GetName() == sService )
674 		{
675 			// dann suchen wir uns das Topic
676 			String sTopic( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) );
677 			if( pItemStt )
678 				*pItemStt = nTokenPos;
679 
680 			DdeTopics& rTopics = pService->GetTopics();
681 
682 			for( int i = 0; i < 2; ++i )
683 			{
684 				for( DdeTopic* pTopic = rTopics.First(); pTopic;
685 												pTopic = rTopics.Next() )
686 					if( pTopic->GetName() == sTopic )
687 						return pTopic;
688 
689 				// Topic nicht gefunden ?
690 				// dann versuchen wir ihn mal anzulegen
691 				if( i || !pService->MakeTopic( sTopic ) )
692 					break;	// hat nicht geklappt, also raus
693 			}
694 			break;
695 		}
696 	return 0;
697 }
698 
699 }
700