xref: /AOO41X/main/sfx2/source/appl/impldde.cxx (revision d2c21ab4b7297aad887a80d59201103226c50555)
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