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