xref: /aoo41x/main/sfx2/source/appl/impldde.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 #if defined(WNT)
32 #include <tools/svwin.h>
33 #endif
34 
35 #include "impldde.hxx"
36 
37 #include <vcl/svapp.hxx>
38 #include <vcl/fixed.hxx>
39 #include <vcl/edit.hxx>
40 #include <vcl/button.hxx>
41 #include <vcl/msgbox.hxx>
42 #include <sot/exchange.hxx>
43 #include <rtl/ustring.hxx>
44 
45 #include "dde.hrc"
46 #include <sfx2/lnkbase.hxx>
47 #include <sfx2/linkmgr.hxx>
48 #include "sfx2/sfxresid.hxx"
49 
50 #include <com/sun/star/uno/Any.hxx>
51 #include <com/sun/star/uno/Sequence.hxx>
52 
53 #include <svl/svdde.hxx>
54 #include <sot/formats.hxx>
55 
56 #define DDELINK_COLD		0
57 #define DDELINK_HOT 		1
58 
59 #define DDELINK_ERROR_APP	1
60 #define DDELINK_ERROR_DATA	2
61 #define DDELINK_ERROR_LINK	3
62 
63 using namespace ::com::sun::star::uno;
64 
65 namespace sfx2
66 {
67 
68 class SvDDELinkEditDialog : public ModalDialog
69 {
70     FixedText aFtDdeApp;
71     Edit aEdDdeApp;
72     FixedText aFtDdeTopic;
73     Edit aEdDdeTopic;
74     FixedText aFtDdeItem;
75     Edit aEdDdeItem;
76     FixedLine aGroupDdeChg;
77     OKButton aOKButton1;
78     CancelButton aCancelButton1;
79 
80     DECL_STATIC_LINK( SvDDELinkEditDialog, EditHdl_Impl, Edit* );
81 public:
82 	SvDDELinkEditDialog( Window* pParent, SvBaseLink* );
83 	String GetCmd() const;
84 };
85 
86 SvDDELinkEditDialog::SvDDELinkEditDialog( Window* pParent, SvBaseLink* pLink )
87     : ModalDialog( pParent, SfxResId( MD_DDE_LINKEDIT ) ),
88     aFtDdeApp( this, SfxResId( FT_DDE_APP ) ),
89     aEdDdeApp( this, SfxResId( ED_DDE_APP ) ),
90     aFtDdeTopic( this, SfxResId( FT_DDE_TOPIC ) ),
91     aEdDdeTopic( this, SfxResId( ED_DDE_TOPIC ) ),
92     aFtDdeItem( this, SfxResId( FT_DDE_ITEM ) ),
93     aEdDdeItem( this, SfxResId( ED_DDE_ITEM ) ),
94     aGroupDdeChg( this, SfxResId( GROUP_DDE_CHG ) ),
95     aOKButton1( this, SfxResId( 1 ) ),
96     aCancelButton1( this, SfxResId( 1 ) )
97 {
98     FreeResource();
99 
100 	String sServer, sTopic, sItem;
101 	pLink->GetLinkManager()->GetDisplayNames( pLink, &sServer, &sTopic, &sItem );
102 
103 	aEdDdeApp.SetText( sServer );
104 	aEdDdeTopic.SetText( sTopic );
105 	aEdDdeItem.SetText( sItem );
106 
107 	aEdDdeApp.SetModifyHdl( STATIC_LINK( this, SvDDELinkEditDialog, EditHdl_Impl));
108 	aEdDdeTopic.SetModifyHdl( STATIC_LINK( this, SvDDELinkEditDialog, EditHdl_Impl));
109 	aEdDdeItem.SetModifyHdl( STATIC_LINK( this, SvDDELinkEditDialog, EditHdl_Impl));
110 
111 	aOKButton1.Enable( sServer.Len() && sTopic.Len() && sItem.Len() );
112 }
113 
114 String SvDDELinkEditDialog::GetCmd() const
115 {
116 	String sCmd( aEdDdeApp.GetText() ), sRet;
117     ::sfx2::MakeLnkName( sRet, &sCmd, aEdDdeTopic.GetText(), aEdDdeItem.GetText() );
118 	return sRet;
119 }
120 
121 IMPL_STATIC_LINK( SvDDELinkEditDialog, EditHdl_Impl, Edit *, pEdit )
122 {
123     (void)pEdit; // unused variable
124     pThis->aOKButton1.Enable( pThis->aEdDdeApp.GetText().Len() &&
125 							  pThis->aEdDdeTopic.GetText().Len() &&
126 							  pThis->aEdDdeItem.GetText().Len() );
127 	return 0;
128 }
129 
130 /*  */
131 
132 
133 SvDDEObject::SvDDEObject()
134 	: pConnection( 0 ), pLink( 0 ), pRequest( 0 ), pGetData( 0 ), nError( 0 )
135 {
136 	SetUpdateTimeout( 100 );
137 	bWaitForData = sal_False;
138 }
139 
140 SvDDEObject::~SvDDEObject()
141 {
142 	delete pLink;
143 	delete pRequest;
144 	delete pConnection;
145 }
146 
147 sal_Bool SvDDEObject::GetData( ::com::sun::star::uno::Any & rData /*out param*/,
148 							const String & rMimeType,
149 							sal_Bool bSynchron )
150 {
151 	if( !pConnection )
152 		return sal_False;
153 
154 	if( pConnection->GetError() )		// dann versuchen wir es nochmal
155 	{
156 		String sServer( pConnection->GetServiceName() );
157 		String sTopic( pConnection->GetTopicName() );
158 
159 		delete pConnection;
160 		pConnection = new DdeConnection( sServer, sTopic );
161 		if( pConnection->GetError() )
162 			nError = DDELINK_ERROR_APP;
163 	}
164 
165 	if( bWaitForData )		// wir sind rekursiv drin, wieder raus
166 		return sal_False;
167 
168 	// Verriegeln gegen Reentrance
169 	bWaitForData = sal_True;
170 
171 	// falls gedruckt werden soll, warten wir bis die Daten vorhanden sind
172 	if( bSynchron )
173 	{
174 		DdeRequest aReq( *pConnection, sItem, 5000 );
175 		aReq.SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) );
176 		aReq.SetFormat( SotExchange::GetFormatIdFromMimeType( rMimeType ));
177 
178 		pGetData = &rData;
179 
180 		do {
181 			aReq.Execute();
182 		} while( aReq.GetError() && ImplHasOtherFormat( aReq ) );
183 
184 		if( pConnection->GetError() )
185 			nError = DDELINK_ERROR_DATA;
186 
187 		bWaitForData = sal_False;
188 	}
189 	else
190 	{
191 		// ansonsten wird es asynchron ausgefuehrt
192 //		if( !pLink || !pLink->IsBusy() )
193 		{
194 			if( pRequest )
195 				delete pRequest;
196 
197 			pRequest = new DdeRequest( *pConnection, sItem );
198 			pRequest->SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) );
199 			pRequest->SetDoneHdl( LINK( this, SvDDEObject, ImplDoneDDEData ) );
200 			pRequest->SetFormat( SotExchange::GetFormatIdFromMimeType(
201 									rMimeType ) );
202 			pRequest->Execute();
203 		}
204 
205 		::rtl::OUString aEmptyStr;
206 		rData <<= aEmptyStr;
207 	}
208 	return 0 == pConnection->GetError();
209 }
210 
211 
212 sal_Bool SvDDEObject::Connect( SvBaseLink * pSvLink )
213 {
214 #if defined(WNT)
215 	static sal_Bool bInWinExec = sal_False;
216 #endif
217 	sal_uInt16 nLinkType = pSvLink->GetUpdateMode();
218 	if( pConnection )		// Verbindung steht ja schon
219 	{
220 		// tja, dann nur noch als Abhaengig eintragen
221 		AddDataAdvise( pSvLink,
222 				SotExchange::GetFormatMimeType( pSvLink->GetContentType()),
223 				LINKUPDATE_ONCALL == nLinkType
224 						? ADVISEMODE_ONLYONCE
225 						: 0 );
226 		AddConnectAdvise( pSvLink );
227 
228 		return sal_True;
229 	}
230 
231 	if( !pSvLink->GetLinkManager() )
232 		return sal_False;
233 
234 	String sServer, sTopic;
235 	pSvLink->GetLinkManager()->GetDisplayNames( pSvLink, &sServer, &sTopic, &sItem );
236 
237 	if( !sServer.Len() || !sTopic.Len() || !sItem.Len() )
238 		return sal_False;
239 
240 	pConnection = new DdeConnection( sServer, sTopic );
241 	if( pConnection->GetError() )
242 	{
243 		// kann man denn das System-Topic ansprechen ?
244 		// dann ist der Server oben, kennt nur nicht das Topic!
245 		if( sTopic.EqualsIgnoreCaseAscii( "SYSTEM" ) )
246 		{
247 			sal_Bool bSysTopic;
248 			{
249 				DdeConnection aTmp( sServer, String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "SYSTEM" ) ) );
250 				bSysTopic = !aTmp.GetError();
251 			}
252 
253 			if( bSysTopic )
254 			{
255 				nError = DDELINK_ERROR_DATA;
256 				return sal_False;
257 			}
258 			// ansonsten unter Win/WinNT die Applikation direkt starten
259 		}
260 
261 #if defined(WNT)
262 
263 		// Server nicht da, starten und nochmal versuchen
264 		if( !bInWinExec )
265 		{
266 			ByteString aCmdLine( sServer, RTL_TEXTENCODING_ASCII_US );
267 			aCmdLine.Append( ".exe " );
268 			aCmdLine.Append( ByteString( sTopic, RTL_TEXTENCODING_ASCII_US ) );
269 
270 			if( WinExec( aCmdLine.GetBuffer(), SW_SHOWMINIMIZED ) < 32 )
271 				nError = DDELINK_ERROR_APP;
272 			else
273 			{
274 				sal_uInt16 i;
275 				for( i=0; i<5; i++ )
276 				{
277 					bInWinExec = sal_True;
278 					Application::Reschedule();
279 					bInWinExec = sal_False;
280 
281 					delete pConnection;
282 					pConnection = new DdeConnection( sServer, sTopic );
283 					if( !pConnection->GetError() )
284 						break;
285 				}
286 
287 				if( i == 5 )
288 				{
289 					nError = DDELINK_ERROR_APP;
290 				}
291 			}
292 		}
293 		else
294 #endif	// WNT
295 		{
296 			nError = DDELINK_ERROR_APP;
297 		}
298 	}
299 
300 	if( LINKUPDATE_ALWAYS == nLinkType && !pLink && !pConnection->GetError() )
301 	{
302 		// Hot Link einrichten, Daten kommen irgendwann spaeter
303 		pLink = new DdeHotLink( *pConnection, sItem );
304 		pLink->SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) );
305 		pLink->SetDoneHdl( LINK( this, SvDDEObject, ImplDoneDDEData ) );
306 		pLink->SetFormat( pSvLink->GetContentType() );
307 		pLink->Execute();
308 	}
309 
310 	if( pConnection->GetError() )
311 		return sal_False;
312 
313 	AddDataAdvise( pSvLink,
314 				SotExchange::GetFormatMimeType( pSvLink->GetContentType()),
315 				LINKUPDATE_ONCALL == nLinkType
316 						? ADVISEMODE_ONLYONCE
317 						: 0 );
318 	AddConnectAdvise( pSvLink );
319 	SetUpdateTimeout( 0 );
320 	return sal_True;
321 }
322 
323 void SvDDEObject::Edit( Window* pParent, sfx2::SvBaseLink* pBaseLink, const Link& rEndEditHdl )
324 {
325     SvDDELinkEditDialog aDlg( pParent, pBaseLink );
326     if ( RET_OK == aDlg.Execute() && rEndEditHdl.IsSet() )
327     {
328         String sCommand = aDlg.GetCmd();
329         rEndEditHdl.Call( &sCommand );
330     }
331 }
332 
333 sal_Bool SvDDEObject::ImplHasOtherFormat( DdeTransaction& rReq )
334 {
335 	sal_uInt16 nFmt = 0;
336 	switch( rReq.GetFormat() )
337 	{
338 	case FORMAT_RTF:
339 		nFmt = FORMAT_STRING;
340 		break;
341 
342 	case SOT_FORMATSTR_ID_HTML_SIMPLE:
343 	case SOT_FORMATSTR_ID_HTML:
344 		nFmt = FORMAT_RTF;
345 		break;
346 
347 	case FORMAT_GDIMETAFILE:
348 		nFmt = FORMAT_BITMAP;
349 		break;
350 
351 	case SOT_FORMATSTR_ID_SVXB:
352 		nFmt = FORMAT_GDIMETAFILE;
353 		break;
354 
355 	// sonst noch irgendwas ??
356 	}
357 	if( nFmt )
358 		rReq.SetFormat( nFmt );		// damit nochmal versuchen
359 	return 0 != nFmt;
360 }
361 
362 sal_Bool SvDDEObject::IsPending() const
363 /*	[Beschreibung]
364 
365 	Die Methode stellt fest, ob aus einem DDE-Object die Daten gelesen
366 	werden kann.
367 	Zurueckgegeben wird:
368 		ERRCODE_NONE 			wenn sie komplett gelesen wurde
369 		ERRCODE_SO_PENDING		wenn sie noch nicht komplett gelesen wurde
370 		ERRCODE_SO_FALSE		sonst
371 */
372 {
373 	return bWaitForData;
374 }
375 
376 sal_Bool SvDDEObject::IsDataComplete() const
377 {
378 	return bWaitForData;
379 }
380 
381 IMPL_LINK( SvDDEObject, ImplGetDDEData, DdeData*, pData )
382 {
383 	sal_uIntPtr nFmt = pData->GetFormat();
384 	switch( nFmt )
385 	{
386 	case FORMAT_GDIMETAFILE:
387 		break;
388 
389 	case FORMAT_BITMAP:
390 		break;
391 
392 	default:
393 		{
394 			const sal_Char* p = (sal_Char*)( pData->operator const void*() );
395 			long nLen = FORMAT_STRING == nFmt ? (p ? strlen( p ) : 0) : (long)*pData;
396 
397 			Sequence< sal_Int8 > aSeq( (const sal_Int8*)p, nLen );
398 			if( pGetData )
399 			{
400 				*pGetData <<= aSeq; 	// Daten kopieren
401 				pGetData = 0;			// und den Pointer bei mir zuruecksetzen
402 			}
403 			else
404 			{
405 				Any aVal;
406 				aVal <<= aSeq;
407 				DataChanged( SotExchange::GetFormatMimeType(
408 												pData->GetFormat() ), aVal );
409 				bWaitForData = sal_False;
410 			}
411 		}
412 	}
413 
414 	return 0;
415 }
416 
417 IMPL_LINK( SvDDEObject, ImplDoneDDEData, void*, pData )
418 {
419 	sal_Bool bValid = (sal_Bool)(sal_uIntPtr)pData;
420 	if( !bValid && ( pRequest || pLink ))
421 	{
422 		DdeTransaction* pReq = 0;
423 		if( !pLink || ( pLink && pLink->IsBusy() ))
424 			pReq = pRequest;		// dann kann nur der fertig sein
425 		else if( pRequest && pRequest->IsBusy() )
426 			pReq = pLink;			// dann kann nur der fertig sein
427 
428 		if( pReq )
429 		{
430 			if( ImplHasOtherFormat( *pReq ) )
431 			{
432 				pReq->Execute();
433 			}
434 			else if( pReq == pRequest )
435 			{
436 				// das wars dann
437 				bWaitForData = sal_False;
438 			}
439 		}
440 	}
441 	else
442 		// das warten ist beendet
443 		bWaitForData = sal_False;
444 
445 	return 0;
446 }
447 
448 }
449