1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sfx2.hxx" 30 31 #if defined(WNT) 32 #include <tools/svwin.h> 33 #endif 34 35 #include "impldde.hxx" 36 37 #include <vcl/svapp.hxx> 38 #include <vcl/fixed.hxx> 39 #include <vcl/edit.hxx> 40 #include <vcl/button.hxx> 41 #include <vcl/msgbox.hxx> 42 #include <sot/exchange.hxx> 43 #include <rtl/ustring.hxx> 44 45 #include "dde.hrc" 46 #include <sfx2/lnkbase.hxx> 47 #include <sfx2/linkmgr.hxx> 48 #include "sfx2/sfxresid.hxx" 49 50 #include <com/sun/star/uno/Any.hxx> 51 #include <com/sun/star/uno/Sequence.hxx> 52 53 #include <svl/svdde.hxx> 54 #include <sot/formats.hxx> 55 56 #define DDELINK_COLD 0 57 #define DDELINK_HOT 1 58 59 #define DDELINK_ERROR_APP 1 60 #define DDELINK_ERROR_DATA 2 61 #define DDELINK_ERROR_LINK 3 62 63 using namespace ::com::sun::star::uno; 64 65 namespace sfx2 66 { 67 68 class SvDDELinkEditDialog : public ModalDialog 69 { 70 FixedText aFtDdeApp; 71 Edit aEdDdeApp; 72 FixedText aFtDdeTopic; 73 Edit aEdDdeTopic; 74 FixedText aFtDdeItem; 75 Edit aEdDdeItem; 76 FixedLine aGroupDdeChg; 77 OKButton aOKButton1; 78 CancelButton aCancelButton1; 79 80 DECL_STATIC_LINK( SvDDELinkEditDialog, EditHdl_Impl, Edit* ); 81 public: 82 SvDDELinkEditDialog( Window* pParent, SvBaseLink* ); 83 String GetCmd() const; 84 }; 85 86 SvDDELinkEditDialog::SvDDELinkEditDialog( Window* pParent, SvBaseLink* pLink ) 87 : ModalDialog( pParent, SfxResId( MD_DDE_LINKEDIT ) ), 88 aFtDdeApp( this, SfxResId( FT_DDE_APP ) ), 89 aEdDdeApp( this, SfxResId( ED_DDE_APP ) ), 90 aFtDdeTopic( this, SfxResId( FT_DDE_TOPIC ) ), 91 aEdDdeTopic( this, SfxResId( ED_DDE_TOPIC ) ), 92 aFtDdeItem( this, SfxResId( FT_DDE_ITEM ) ), 93 aEdDdeItem( this, SfxResId( ED_DDE_ITEM ) ), 94 aGroupDdeChg( this, SfxResId( GROUP_DDE_CHG ) ), 95 aOKButton1( this, SfxResId( 1 ) ), 96 aCancelButton1( this, SfxResId( 1 ) ) 97 { 98 FreeResource(); 99 100 String sServer, sTopic, sItem; 101 pLink->GetLinkManager()->GetDisplayNames( pLink, &sServer, &sTopic, &sItem ); 102 103 aEdDdeApp.SetText( sServer ); 104 aEdDdeTopic.SetText( sTopic ); 105 aEdDdeItem.SetText( sItem ); 106 107 aEdDdeApp.SetModifyHdl( STATIC_LINK( this, SvDDELinkEditDialog, EditHdl_Impl)); 108 aEdDdeTopic.SetModifyHdl( STATIC_LINK( this, SvDDELinkEditDialog, EditHdl_Impl)); 109 aEdDdeItem.SetModifyHdl( STATIC_LINK( this, SvDDELinkEditDialog, EditHdl_Impl)); 110 111 aOKButton1.Enable( sServer.Len() && sTopic.Len() && sItem.Len() ); 112 } 113 114 String SvDDELinkEditDialog::GetCmd() const 115 { 116 String sCmd( aEdDdeApp.GetText() ), sRet; 117 ::sfx2::MakeLnkName( sRet, &sCmd, aEdDdeTopic.GetText(), aEdDdeItem.GetText() ); 118 return sRet; 119 } 120 121 IMPL_STATIC_LINK( SvDDELinkEditDialog, EditHdl_Impl, Edit *, pEdit ) 122 { 123 (void)pEdit; // unused variable 124 pThis->aOKButton1.Enable( pThis->aEdDdeApp.GetText().Len() && 125 pThis->aEdDdeTopic.GetText().Len() && 126 pThis->aEdDdeItem.GetText().Len() ); 127 return 0; 128 } 129 130 /* */ 131 132 133 SvDDEObject::SvDDEObject() 134 : pConnection( 0 ), pLink( 0 ), pRequest( 0 ), pGetData( 0 ), nError( 0 ) 135 { 136 SetUpdateTimeout( 100 ); 137 bWaitForData = sal_False; 138 } 139 140 SvDDEObject::~SvDDEObject() 141 { 142 delete pLink; 143 delete pRequest; 144 delete pConnection; 145 } 146 147 sal_Bool SvDDEObject::GetData( ::com::sun::star::uno::Any & rData /*out param*/, 148 const String & rMimeType, 149 sal_Bool bSynchron ) 150 { 151 if( !pConnection ) 152 return sal_False; 153 154 if( pConnection->GetError() ) // dann versuchen wir es nochmal 155 { 156 String sServer( pConnection->GetServiceName() ); 157 String sTopic( pConnection->GetTopicName() ); 158 159 delete pConnection; 160 pConnection = new DdeConnection( sServer, sTopic ); 161 if( pConnection->GetError() ) 162 nError = DDELINK_ERROR_APP; 163 } 164 165 if( bWaitForData ) // wir sind rekursiv drin, wieder raus 166 return sal_False; 167 168 // Verriegeln gegen Reentrance 169 bWaitForData = sal_True; 170 171 // falls gedruckt werden soll, warten wir bis die Daten vorhanden sind 172 if( bSynchron ) 173 { 174 DdeRequest aReq( *pConnection, sItem, 5000 ); 175 aReq.SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) ); 176 aReq.SetFormat( SotExchange::GetFormatIdFromMimeType( rMimeType )); 177 178 pGetData = &rData; 179 180 do { 181 aReq.Execute(); 182 } while( aReq.GetError() && ImplHasOtherFormat( aReq ) ); 183 184 if( pConnection->GetError() ) 185 nError = DDELINK_ERROR_DATA; 186 187 bWaitForData = sal_False; 188 } 189 else 190 { 191 // ansonsten wird es asynchron ausgefuehrt 192 // if( !pLink || !pLink->IsBusy() ) 193 { 194 if( pRequest ) 195 delete pRequest; 196 197 pRequest = new DdeRequest( *pConnection, sItem ); 198 pRequest->SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) ); 199 pRequest->SetDoneHdl( LINK( this, SvDDEObject, ImplDoneDDEData ) ); 200 pRequest->SetFormat( SotExchange::GetFormatIdFromMimeType( 201 rMimeType ) ); 202 pRequest->Execute(); 203 } 204 205 ::rtl::OUString aEmptyStr; 206 rData <<= aEmptyStr; 207 } 208 return 0 == pConnection->GetError(); 209 } 210 211 212 sal_Bool SvDDEObject::Connect( SvBaseLink * pSvLink ) 213 { 214 #if defined(WNT) 215 static sal_Bool bInWinExec = sal_False; 216 #endif 217 sal_uInt16 nLinkType = pSvLink->GetUpdateMode(); 218 if( pConnection ) // Verbindung steht ja schon 219 { 220 // tja, dann nur noch als Abhaengig eintragen 221 AddDataAdvise( pSvLink, 222 SotExchange::GetFormatMimeType( pSvLink->GetContentType()), 223 LINKUPDATE_ONCALL == nLinkType 224 ? ADVISEMODE_ONLYONCE 225 : 0 ); 226 AddConnectAdvise( pSvLink ); 227 228 return sal_True; 229 } 230 231 if( !pSvLink->GetLinkManager() ) 232 return sal_False; 233 234 String sServer, sTopic; 235 pSvLink->GetLinkManager()->GetDisplayNames( pSvLink, &sServer, &sTopic, &sItem ); 236 237 if( !sServer.Len() || !sTopic.Len() || !sItem.Len() ) 238 return sal_False; 239 240 pConnection = new DdeConnection( sServer, sTopic ); 241 if( pConnection->GetError() ) 242 { 243 // kann man denn das System-Topic ansprechen ? 244 // dann ist der Server oben, kennt nur nicht das Topic! 245 if( sTopic.EqualsIgnoreCaseAscii( "SYSTEM" ) ) 246 { 247 sal_Bool bSysTopic; 248 { 249 DdeConnection aTmp( sServer, String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "SYSTEM" ) ) ); 250 bSysTopic = !aTmp.GetError(); 251 } 252 253 if( bSysTopic ) 254 { 255 nError = DDELINK_ERROR_DATA; 256 return sal_False; 257 } 258 // ansonsten unter Win/WinNT die Applikation direkt starten 259 } 260 261 #if defined(WNT) 262 263 // Server nicht da, starten und nochmal versuchen 264 if( !bInWinExec ) 265 { 266 ByteString aCmdLine( sServer, RTL_TEXTENCODING_ASCII_US ); 267 aCmdLine.Append( ".exe " ); 268 aCmdLine.Append( ByteString( sTopic, RTL_TEXTENCODING_ASCII_US ) ); 269 270 if( WinExec( aCmdLine.GetBuffer(), SW_SHOWMINIMIZED ) < 32 ) 271 nError = DDELINK_ERROR_APP; 272 else 273 { 274 sal_uInt16 i; 275 for( i=0; i<5; i++ ) 276 { 277 bInWinExec = sal_True; 278 Application::Reschedule(); 279 bInWinExec = sal_False; 280 281 delete pConnection; 282 pConnection = new DdeConnection( sServer, sTopic ); 283 if( !pConnection->GetError() ) 284 break; 285 } 286 287 if( i == 5 ) 288 { 289 nError = DDELINK_ERROR_APP; 290 } 291 } 292 } 293 else 294 #endif // WNT 295 { 296 nError = DDELINK_ERROR_APP; 297 } 298 } 299 300 if( LINKUPDATE_ALWAYS == nLinkType && !pLink && !pConnection->GetError() ) 301 { 302 // Hot Link einrichten, Daten kommen irgendwann spaeter 303 pLink = new DdeHotLink( *pConnection, sItem ); 304 pLink->SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) ); 305 pLink->SetDoneHdl( LINK( this, SvDDEObject, ImplDoneDDEData ) ); 306 pLink->SetFormat( pSvLink->GetContentType() ); 307 pLink->Execute(); 308 } 309 310 if( pConnection->GetError() ) 311 return sal_False; 312 313 AddDataAdvise( pSvLink, 314 SotExchange::GetFormatMimeType( pSvLink->GetContentType()), 315 LINKUPDATE_ONCALL == nLinkType 316 ? ADVISEMODE_ONLYONCE 317 : 0 ); 318 AddConnectAdvise( pSvLink ); 319 SetUpdateTimeout( 0 ); 320 return sal_True; 321 } 322 323 void SvDDEObject::Edit( Window* pParent, sfx2::SvBaseLink* pBaseLink, const Link& rEndEditHdl ) 324 { 325 SvDDELinkEditDialog aDlg( pParent, pBaseLink ); 326 if ( RET_OK == aDlg.Execute() && rEndEditHdl.IsSet() ) 327 { 328 String sCommand = aDlg.GetCmd(); 329 rEndEditHdl.Call( &sCommand ); 330 } 331 } 332 333 sal_Bool SvDDEObject::ImplHasOtherFormat( DdeTransaction& rReq ) 334 { 335 sal_uInt16 nFmt = 0; 336 switch( rReq.GetFormat() ) 337 { 338 case FORMAT_RTF: 339 nFmt = FORMAT_STRING; 340 break; 341 342 case SOT_FORMATSTR_ID_HTML_SIMPLE: 343 case SOT_FORMATSTR_ID_HTML: 344 nFmt = FORMAT_RTF; 345 break; 346 347 case FORMAT_GDIMETAFILE: 348 nFmt = FORMAT_BITMAP; 349 break; 350 351 case SOT_FORMATSTR_ID_SVXB: 352 nFmt = FORMAT_GDIMETAFILE; 353 break; 354 355 // sonst noch irgendwas ?? 356 } 357 if( nFmt ) 358 rReq.SetFormat( nFmt ); // damit nochmal versuchen 359 return 0 != nFmt; 360 } 361 362 sal_Bool SvDDEObject::IsPending() const 363 /* [Beschreibung] 364 365 Die Methode stellt fest, ob aus einem DDE-Object die Daten gelesen 366 werden kann. 367 Zurueckgegeben wird: 368 ERRCODE_NONE wenn sie komplett gelesen wurde 369 ERRCODE_SO_PENDING wenn sie noch nicht komplett gelesen wurde 370 ERRCODE_SO_FALSE sonst 371 */ 372 { 373 return bWaitForData; 374 } 375 376 sal_Bool SvDDEObject::IsDataComplete() const 377 { 378 return bWaitForData; 379 } 380 381 IMPL_LINK( SvDDEObject, ImplGetDDEData, DdeData*, pData ) 382 { 383 sal_uIntPtr nFmt = pData->GetFormat(); 384 switch( nFmt ) 385 { 386 case FORMAT_GDIMETAFILE: 387 break; 388 389 case FORMAT_BITMAP: 390 break; 391 392 default: 393 { 394 const sal_Char* p = (sal_Char*)( pData->operator const void*() ); 395 long nLen = FORMAT_STRING == nFmt ? (p ? strlen( p ) : 0) : (long)*pData; 396 397 Sequence< sal_Int8 > aSeq( (const sal_Int8*)p, nLen ); 398 if( pGetData ) 399 { 400 *pGetData <<= aSeq; // Daten kopieren 401 pGetData = 0; // und den Pointer bei mir zuruecksetzen 402 } 403 else 404 { 405 Any aVal; 406 aVal <<= aSeq; 407 DataChanged( SotExchange::GetFormatMimeType( 408 pData->GetFormat() ), aVal ); 409 bWaitForData = sal_False; 410 } 411 } 412 } 413 414 return 0; 415 } 416 417 IMPL_LINK( SvDDEObject, ImplDoneDDEData, void*, pData ) 418 { 419 sal_Bool bValid = (sal_Bool)(sal_uIntPtr)pData; 420 if( !bValid && ( pRequest || pLink )) 421 { 422 DdeTransaction* pReq = 0; 423 if( !pLink || ( pLink && pLink->IsBusy() )) 424 pReq = pRequest; // dann kann nur der fertig sein 425 else if( pRequest && pRequest->IsBusy() ) 426 pReq = pLink; // dann kann nur der fertig sein 427 428 if( pReq ) 429 { 430 if( ImplHasOtherFormat( *pReq ) ) 431 { 432 pReq->Execute(); 433 } 434 else if( pReq == pRequest ) 435 { 436 // das wars dann 437 bWaitForData = sal_False; 438 } 439 } 440 } 441 else 442 // das warten ist beendet 443 bWaitForData = sal_False; 444 445 return 0; 446 } 447 448 } 449