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