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