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