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