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