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 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 112 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 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 131 SvDDEObject::SvDDEObject() 132 : pConnection( 0 ), pLink( 0 ), pRequest( 0 ), pGetData( 0 ), nError( 0 ) 133 { 134 SetUpdateTimeout( 100 ); 135 bWaitForData = sal_False; 136 } 137 138 SvDDEObject::~SvDDEObject() 139 { 140 delete pLink; 141 delete pRequest; 142 delete pConnection; 143 } 144 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 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 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 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 318 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 332 sal_Bool SvDDEObject::IsDataComplete() const 333 { 334 return bWaitForData; 335 } 336 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 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