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 32 #include <sfx2/lnkbase.hxx> 33 #include <sot/exchange.hxx> 34 #include <com/sun/star/uno/Any.hxx> 35 #include <com/sun/star/uno/Sequence.hxx> 36 #include <vcl/msgbox.hxx> 37 #include <sfx2/linkmgr.hxx> 38 #include <vcl/svapp.hxx> 39 #include "app.hrc" 40 #include "sfx2/sfxresid.hxx" 41 #include <sfx2/filedlghelper.hxx> 42 #include <tools/debug.hxx> 43 #include <svl/svdde.hxx> 44 45 using namespace ::com::sun::star::uno; 46 47 namespace sfx2 48 { 49 50 TYPEINIT0( SvBaseLink ) 51 52 static DdeTopic* FindTopic( const String &, sal_uInt16* = 0 ); 53 54 class ImplDdeItem; 55 56 struct BaseLink_Impl 57 { 58 Link m_aEndEditLink; 59 LinkManager* m_pLinkMgr; 60 Window* m_pParentWin; 61 FileDialogHelper* m_pFileDlg; 62 bool m_bIsConnect; 63 64 BaseLink_Impl() : 65 m_pLinkMgr( NULL ) 66 , m_pParentWin( NULL ) 67 , m_pFileDlg( NULL ) 68 , m_bIsConnect( false ) 69 {} 70 71 ~BaseLink_Impl() 72 { delete m_pFileDlg; } 73 }; 74 75 // nur fuer die interne Verwaltung 76 struct ImplBaseLinkData 77 { 78 struct tClientType 79 { 80 // gilt fuer alle Links 81 sal_uIntPtr nCntntType; // Update Format 82 // nicht Ole-Links 83 sal_Bool bIntrnlLnk; // ist es ein interner Link 84 sal_uInt16 nUpdateMode;// UpdateMode 85 }; 86 87 struct tDDEType 88 { 89 ImplDdeItem* pItem; 90 }; 91 92 union { 93 tClientType ClientType; 94 tDDEType DDEType; 95 }; 96 ImplBaseLinkData() 97 { 98 ClientType.nCntntType = 0; 99 ClientType.bIntrnlLnk = sal_False; 100 ClientType.nUpdateMode = 0; 101 DDEType.pItem = NULL; 102 } 103 }; 104 105 106 class ImplDdeItem : public DdeGetPutItem 107 { 108 SvBaseLink* pLink; 109 DdeData aData; 110 Sequence< sal_Int8 > aSeq; // Datacontainer for DdeData !!! 111 sal_Bool bIsValidData : 1; 112 sal_Bool bIsInDTOR : 1; 113 public: 114 ImplDdeItem( SvBaseLink& rLink, const String& rStr ) 115 : DdeGetPutItem( rStr ), pLink( &rLink ), bIsValidData( sal_False ), 116 bIsInDTOR( sal_False ) 117 {} 118 virtual ~ImplDdeItem(); 119 120 virtual DdeData* Get( sal_uIntPtr ); 121 virtual sal_Bool Put( const DdeData* ); 122 virtual void AdviseLoop( sal_Bool ); 123 124 void Notify() 125 { 126 bIsValidData = sal_False; 127 DdeGetPutItem::NotifyClient(); 128 } 129 130 sal_Bool IsInDTOR() const { return bIsInDTOR; } 131 }; 132 133 134 /************************************************************************ 135 |* SvBaseLink::SvBaseLink() 136 |* 137 |* Beschreibung 138 *************************************************************************/ 139 140 SvBaseLink::SvBaseLink() 141 { 142 pImpl = new BaseLink_Impl(); 143 nObjType = OBJECT_CLIENT_SO; 144 pImplData = new ImplBaseLinkData; 145 bVisible = bSynchron = bUseCache = sal_True; 146 bWasLastEditOK = sal_False; 147 } 148 149 /************************************************************************ 150 |* SvBaseLink::SvBaseLink() 151 |* 152 |* Beschreibung 153 *************************************************************************/ 154 155 SvBaseLink::SvBaseLink( sal_uInt16 nUpdateMode, sal_uIntPtr nContentType ) 156 { 157 pImpl = new BaseLink_Impl(); 158 nObjType = OBJECT_CLIENT_SO; 159 pImplData = new ImplBaseLinkData; 160 bVisible = bSynchron = bUseCache = sal_True; 161 bWasLastEditOK = sal_False; 162 163 // falls es ein Ole-Link wird, 164 pImplData->ClientType.nUpdateMode = nUpdateMode; 165 pImplData->ClientType.nCntntType = nContentType; 166 pImplData->ClientType.bIntrnlLnk = sal_False; 167 } 168 169 /************************************************************************ 170 |* SvBaseLink::SvBaseLink() 171 |* 172 |* Beschreibung 173 *************************************************************************/ 174 175 SvBaseLink::SvBaseLink( const String& rLinkName, sal_uInt16 nObjectType, SvLinkSource* pObj ) 176 { 177 bVisible = bSynchron = bUseCache = sal_True; 178 bWasLastEditOK = sal_False; 179 aLinkName = rLinkName; 180 pImplData = new ImplBaseLinkData; 181 nObjType = nObjectType; 182 183 if( !pObj ) 184 { 185 DBG_ASSERT( pObj, "Wo ist mein zu linkendes Object" ); 186 return; 187 } 188 189 if( OBJECT_DDE_EXTERN == nObjType ) 190 { 191 sal_uInt16 nItemStt = 0; 192 DdeTopic* pTopic = FindTopic( aLinkName, &nItemStt ); 193 if( pTopic ) 194 { 195 // dann haben wir alles zusammen 196 // MM hat gefummelt ??? 197 // MM_TODO wie kriege ich den Namen 198 String aStr = aLinkName; // xLinkName->GetDisplayName(); 199 aStr = aStr.Copy( nItemStt ); 200 pImplData->DDEType.pItem = new ImplDdeItem( *this, aStr ); 201 pTopic->InsertItem( pImplData->DDEType.pItem ); 202 203 // dann koennen wir uns auch das Advise merken 204 xObj = pObj; 205 } 206 } 207 else if( pObj->Connect( this ) ) 208 xObj = pObj; 209 } 210 211 /************************************************************************ 212 |* SvBaseLink::~SvBaseLink() 213 |* 214 |* Beschreibung 215 *************************************************************************/ 216 217 SvBaseLink::~SvBaseLink() 218 { 219 Disconnect(); 220 221 switch( nObjType ) 222 { 223 case OBJECT_DDE_EXTERN: 224 if( !pImplData->DDEType.pItem->IsInDTOR() ) 225 delete pImplData->DDEType.pItem; 226 break; 227 } 228 229 delete pImplData; 230 } 231 232 IMPL_LINK( SvBaseLink, EndEditHdl, String*, _pNewName ) 233 { 234 String sNewName; 235 if ( _pNewName ) 236 sNewName = *_pNewName; 237 if ( !ExecuteEdit( sNewName ) ) 238 sNewName.Erase(); 239 bWasLastEditOK = ( sNewName.Len() > 0 ); 240 if ( pImpl->m_aEndEditLink.IsSet() ) 241 pImpl->m_aEndEditLink.Call( this ); 242 return 0; 243 } 244 245 /************************************************************************ 246 |* SvBaseLink::SetObjType() 247 |* 248 |* Beschreibung 249 *************************************************************************/ 250 251 void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP ) 252 { 253 DBG_ASSERT( nObjType != OBJECT_CLIENT_DDE, "type already set" ); 254 DBG_ASSERT( !xObj.Is(), "object exist" ); 255 256 nObjType = nObjTypeP; 257 } 258 259 /************************************************************************ 260 |* SvBaseLink::SetName() 261 |* 262 |* Beschreibung 263 *************************************************************************/ 264 265 void SvBaseLink::SetName( const String & rNm ) 266 { 267 aLinkName = rNm; 268 } 269 270 /************************************************************************ 271 |* SvBaseLink::GetName() 272 |* 273 |* Beschreibung 274 *************************************************************************/ 275 276 String SvBaseLink::GetName() const 277 { 278 return aLinkName; 279 } 280 281 /************************************************************************ 282 |* SvBaseLink::SetObj() 283 |* 284 |* Beschreibung 285 *************************************************************************/ 286 287 void SvBaseLink::SetObj( SvLinkSource * pObj ) 288 { 289 DBG_ASSERT( (nObjType & OBJECT_CLIENT_SO && 290 pImplData->ClientType.bIntrnlLnk) || 291 nObjType == OBJECT_CLIENT_GRF, 292 "no intern link" ); 293 xObj = pObj; 294 } 295 296 /************************************************************************ 297 |* SvBaseLink::SetLinkSourceName() 298 |* 299 |* Beschreibung 300 *************************************************************************/ 301 302 void SvBaseLink::SetLinkSourceName( const String & rLnkNm ) 303 { 304 if( aLinkName == rLnkNm ) 305 return; 306 307 AddNextRef(); // sollte ueberfluessig sein 308 // Alte Verbindung weg 309 Disconnect(); 310 311 aLinkName = rLnkNm; 312 313 // Neu verbinden 314 _GetRealObject(); 315 ReleaseRef(); // sollte ueberfluessig sein 316 } 317 318 /************************************************************************ 319 |* SvBaseLink::GetLinkSourceName() 320 |* 321 |* Beschreibung 322 *************************************************************************/ 323 324 String SvBaseLink::GetLinkSourceName() const 325 { 326 return aLinkName; 327 } 328 329 330 /************************************************************************ 331 |* SvBaseLink::SetUpdateMode() 332 |* 333 |* Beschreibung 334 *************************************************************************/ 335 336 void SvBaseLink::SetUpdateMode( sal_uInt16 nMode ) 337 { 338 if( ( OBJECT_CLIENT_SO & nObjType ) && 339 pImplData->ClientType.nUpdateMode != nMode ) 340 { 341 AddNextRef(); 342 Disconnect(); 343 344 pImplData->ClientType.nUpdateMode = nMode; 345 _GetRealObject(); 346 ReleaseRef(); 347 } 348 } 349 350 // --> OD 2008-06-19 #i88291# 351 void SvBaseLink::clearStreamToLoadFrom() 352 { 353 m_xInputStreamToLoadFrom.clear(); 354 if( xObj.Is() ) 355 { 356 xObj->clearStreamToLoadFrom(); 357 } 358 } 359 // <-- 360 361 sal_Bool SvBaseLink::Update() 362 { 363 if( OBJECT_CLIENT_SO & nObjType ) 364 { 365 AddNextRef(); 366 Disconnect(); 367 368 _GetRealObject(); 369 ReleaseRef(); 370 if( xObj.Is() ) 371 { 372 xObj->setStreamToLoadFrom(m_xInputStreamToLoadFrom,m_bIsReadOnly); 373 // m_xInputStreamToLoadFrom = 0; 374 String sMimeType( SotExchange::GetFormatMimeType( 375 pImplData->ClientType.nCntntType )); 376 Any aData; 377 378 if( xObj->GetData( aData, sMimeType ) ) 379 { 380 DataChanged( sMimeType, aData ); 381 //JP 13.07.00: Bug 76817 - for manual Updates there is no 382 // need to hold the ServerObject 383 if( OBJECT_CLIENT_DDE == nObjType && 384 LINKUPDATE_ONCALL == GetUpdateMode() && xObj.Is() ) 385 xObj->RemoveAllDataAdvise( this ); 386 return sal_True; 387 } 388 if( xObj.Is() ) 389 { 390 // sollten wir asynschron sein? 391 if( xObj->IsPending() ) 392 return sal_True; 393 394 // dann brauchen wir das Object auch nicht mehr 395 AddNextRef(); 396 Disconnect(); 397 ReleaseRef(); 398 } 399 } 400 } 401 return sal_False; 402 } 403 404 405 sal_uInt16 SvBaseLink::GetUpdateMode() const 406 { 407 return ( OBJECT_CLIENT_SO & nObjType ) 408 ? pImplData->ClientType.nUpdateMode 409 : sal::static_int_cast< sal_uInt16 >( LINKUPDATE_ONCALL ); 410 } 411 412 413 void SvBaseLink::_GetRealObject( sal_Bool bConnect) 414 { 415 if( !pImpl->m_pLinkMgr ) 416 return; 417 418 DBG_ASSERT( !xObj.Is(), "object already exist" ); 419 420 if( OBJECT_CLIENT_DDE == nObjType ) 421 { 422 String sServer; 423 if( pImpl->m_pLinkMgr->GetDisplayNames( this, &sServer ) && 424 sServer == GetpApp()->GetAppName() ) // interner Link !!! 425 { 426 // damit der Internal - Link erzeugt werden kann !!! 427 nObjType = OBJECT_INTERN; 428 xObj = pImpl->m_pLinkMgr->CreateObj( this ); 429 430 pImplData->ClientType.bIntrnlLnk = sal_True; 431 nObjType = OBJECT_CLIENT_DDE; // damit wir wissen was es mal war !! 432 } 433 else 434 { 435 pImplData->ClientType.bIntrnlLnk = sal_False; 436 xObj = pImpl->m_pLinkMgr->CreateObj( this ); 437 } 438 } 439 else if( (OBJECT_CLIENT_SO & nObjType) ) 440 xObj = pImpl->m_pLinkMgr->CreateObj( this ); 441 442 if( bConnect && ( !xObj.Is() || !xObj->Connect( this ) ) ) 443 Disconnect(); 444 } 445 446 sal_uIntPtr SvBaseLink::GetContentType() const 447 { 448 if( OBJECT_CLIENT_SO & nObjType ) 449 return pImplData->ClientType.nCntntType; 450 451 return 0; // alle Formate ? 452 } 453 454 455 sal_Bool SvBaseLink::SetContentType( sal_uIntPtr nType ) 456 { 457 if( OBJECT_CLIENT_SO & nObjType ) 458 { 459 pImplData->ClientType.nCntntType = nType; 460 return sal_True; 461 } 462 return sal_False; 463 } 464 465 LinkManager* SvBaseLink::GetLinkManager() 466 { 467 return pImpl->m_pLinkMgr; 468 } 469 470 const LinkManager* SvBaseLink::GetLinkManager() const 471 { 472 return pImpl->m_pLinkMgr; 473 } 474 475 void SvBaseLink::SetLinkManager( LinkManager* _pMgr ) 476 { 477 pImpl->m_pLinkMgr = _pMgr; 478 } 479 480 void SvBaseLink::Disconnect() 481 { 482 if( xObj.Is() ) 483 { 484 xObj->RemoveAllDataAdvise( this ); 485 xObj->RemoveConnectAdvise( this ); 486 xObj.Clear(); 487 } 488 } 489 490 void SvBaseLink::DataChanged( const String &, const ::com::sun::star::uno::Any & ) 491 { 492 switch( nObjType ) 493 { 494 case OBJECT_DDE_EXTERN: 495 if( pImplData->DDEType.pItem ) 496 pImplData->DDEType.pItem->Notify(); 497 break; 498 } 499 } 500 501 void SvBaseLink::Edit( Window* pParent, const Link& rEndEditHdl ) 502 { 503 pImpl->m_pParentWin = pParent; 504 pImpl->m_aEndEditLink = rEndEditHdl; 505 pImpl->m_bIsConnect = ( xObj.Is() != sal_False ); 506 if( !pImpl->m_bIsConnect ) 507 _GetRealObject( xObj.Is() ); 508 509 bool bAsync = false; 510 Link aLink = LINK( this, SvBaseLink, EndEditHdl ); 511 512 if( OBJECT_CLIENT_SO & nObjType && pImplData->ClientType.bIntrnlLnk ) 513 { 514 if( pImpl->m_pLinkMgr ) 515 { 516 SvLinkSourceRef ref = pImpl->m_pLinkMgr->CreateObj( this ); 517 if( ref.Is() ) 518 { 519 ref->Edit( pParent, this, aLink ); 520 bAsync = true; 521 } 522 } 523 } 524 else 525 { 526 xObj->Edit( pParent, this, aLink ); 527 bAsync = true; 528 } 529 530 if ( !bAsync ) 531 { 532 ExecuteEdit( String() ); 533 bWasLastEditOK = sal_False; 534 if ( pImpl->m_aEndEditLink.IsSet() ) 535 pImpl->m_aEndEditLink.Call( this ); 536 } 537 } 538 539 bool SvBaseLink::ExecuteEdit( const String& _rNewName ) 540 { 541 if( _rNewName.Len() != 0 ) 542 { 543 SetLinkSourceName( _rNewName ); 544 if( !Update() ) 545 { 546 String sApp, sTopic, sItem, sError; 547 pImpl->m_pLinkMgr->GetDisplayNames( this, &sApp, &sTopic, &sItem ); 548 if( nObjType == OBJECT_CLIENT_DDE ) 549 { 550 sError = SfxResId( STR_DDE_ERROR ); 551 552 sal_uInt16 nFndPos = sError.Search( '%' ); 553 if( STRING_NOTFOUND != nFndPos ) 554 { 555 sError.Erase( nFndPos, 1 ).Insert( sApp, nFndPos ); 556 nFndPos = nFndPos + sApp.Len(); 557 } 558 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos ))) 559 { 560 sError.Erase( nFndPos, 1 ).Insert( sTopic, nFndPos ); 561 nFndPos = nFndPos + sTopic.Len(); 562 } 563 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos ))) 564 sError.Erase( nFndPos, 1 ).Insert( sItem, nFndPos ); 565 } 566 else 567 return false; 568 569 ErrorBox( pImpl->m_pParentWin, WB_OK, sError ).Execute(); 570 } 571 } 572 else if( !pImpl->m_bIsConnect ) 573 Disconnect(); 574 pImpl->m_bIsConnect = false; 575 return true; 576 } 577 578 void SvBaseLink::Closed() 579 { 580 if( xObj.Is() ) 581 // beim Advise Abmelden 582 xObj->RemoveAllDataAdvise( this ); 583 } 584 585 FileDialogHelper* SvBaseLink::GetFileDialog( sal_uInt32 nFlags, const String& rFactory ) const 586 { 587 if ( pImpl->m_pFileDlg ) 588 delete pImpl->m_pFileDlg; 589 pImpl->m_pFileDlg = new FileDialogHelper( nFlags, rFactory ); 590 return pImpl->m_pFileDlg; 591 } 592 593 ImplDdeItem::~ImplDdeItem() 594 { 595 bIsInDTOR = sal_True; 596 // damit im Disconnect nicht jemand auf die Idee kommt, den Pointer zu 597 // loeschen!! 598 SvBaseLinkRef aRef( pLink ); 599 aRef->Disconnect(); 600 } 601 602 DdeData* ImplDdeItem::Get( sal_uIntPtr nFormat ) 603 { 604 if( pLink->GetObj() ) 605 { 606 // ist das noch gueltig? 607 if( bIsValidData && nFormat == aData.GetFormat() ) 608 return &aData; 609 610 Any aValue; 611 String sMimeType( SotExchange::GetFormatMimeType( nFormat )); 612 if( pLink->GetObj()->GetData( aValue, sMimeType ) ) 613 { 614 if( aValue >>= aSeq ) 615 { 616 aData = DdeData( (const char *)aSeq.getConstArray(), aSeq.getLength(), nFormat ); 617 618 bIsValidData = sal_True; 619 return &aData; 620 } 621 } 622 } 623 aSeq.realloc( 0 ); 624 bIsValidData = sal_False; 625 return 0; 626 } 627 628 629 sal_Bool ImplDdeItem::Put( const DdeData* ) 630 { 631 DBG_ERROR( "ImplDdeItem::Put not implemented" ); 632 return sal_False; 633 } 634 635 636 void ImplDdeItem::AdviseLoop( sal_Bool bOpen ) 637 { 638 // Verbindung wird geschlossen, also Link abmelden 639 if( pLink->GetObj() ) 640 { 641 if( bOpen ) 642 { 643 // es wird wieder eine Verbindung hergestellt 644 if( OBJECT_DDE_EXTERN == pLink->GetObjType() ) 645 { 646 pLink->GetObj()->AddDataAdvise( pLink, String::CreateFromAscii( "text/plain;charset=utf-16" ), ADVISEMODE_NODATA ); 647 pLink->GetObj()->AddConnectAdvise( pLink ); 648 } 649 } 650 else 651 { 652 // damit im Disconnect nicht jemand auf die Idee kommt, 653 // den Pointer zu loeschen!! 654 SvBaseLinkRef aRef( pLink ); 655 aRef->Disconnect(); 656 } 657 } 658 } 659 660 661 static DdeTopic* FindTopic( const String & rLinkName, sal_uInt16* pItemStt ) 662 { 663 if( 0 == rLinkName.Len() ) 664 return 0; 665 666 String sNm( rLinkName ); 667 sal_uInt16 nTokenPos = 0; 668 String sService( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) ); 669 670 DdeServices& rSvc = DdeService::GetServices(); 671 for( DdeService* pService = rSvc.First(); pService; 672 pService = rSvc.Next() ) 673 if( pService->GetName() == sService ) 674 { 675 // dann suchen wir uns das Topic 676 String sTopic( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) ); 677 if( pItemStt ) 678 *pItemStt = nTokenPos; 679 680 DdeTopics& rTopics = pService->GetTopics(); 681 682 for( int i = 0; i < 2; ++i ) 683 { 684 for( DdeTopic* pTopic = rTopics.First(); pTopic; 685 pTopic = rTopics.Next() ) 686 if( pTopic->GetName() == sTopic ) 687 return pTopic; 688 689 // Topic nicht gefunden ? 690 // dann versuchen wir ihn mal anzulegen 691 if( i || !pService->MakeTopic( sTopic ) ) 692 break; // hat nicht geklappt, also raus 693 } 694 break; 695 } 696 return 0; 697 } 698 699 } 700