merge the formfield patch from ooo-build
[ooovba.git] / sfx2 / source / appl / lnkbase2.cxx
blob41a139d19bede269b1bf5e7970fd7f61bcbdb469
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: lnkbase2.cxx,v $
10 * $Revision: 1.14 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sfx2.hxx"
35 #include <sfx2/lnkbase.hxx>
36 #include <sot/exchange.hxx>
37 #include <com/sun/star/uno/Any.hxx>
38 #include <com/sun/star/uno/Sequence.hxx>
39 #include <vcl/msgbox.hxx>
41 #include <sfx2/linkmgr.hxx>
42 //#include "svuidlg.hrc"
43 //#include "iface.hxx"
44 #include <vcl/svapp.hxx>
45 //#include <soerr.hxx>
47 #include "app.hrc"
48 #include "sfxresid.hxx"
49 #include <sfx2/filedlghelper.hxx>
51 #include <tools/debug.hxx>
53 #include <svtools/svdde.hxx>
55 using namespace ::com::sun::star::uno;
57 namespace sfx2
60 TYPEINIT0( SvBaseLink )
62 static DdeTopic* FindTopic( const String &, USHORT* = 0 );
64 class ImplDdeItem;
66 struct BaseLink_Impl
68 Link m_aEndEditLink;
69 SvLinkManager* m_pLinkMgr;
70 Window* m_pParentWin;
71 FileDialogHelper* m_pFileDlg;
72 bool m_bIsConnect;
74 BaseLink_Impl() :
75 m_pLinkMgr( NULL )
76 , m_pParentWin( NULL )
77 , m_pFileDlg( NULL )
78 , m_bIsConnect( false )
81 ~BaseLink_Impl()
82 { delete m_pFileDlg; }
85 // nur fuer die interne Verwaltung
86 struct ImplBaseLinkData
88 struct tClientType
90 // gilt fuer alle Links
91 ULONG nCntntType; // Update Format
92 // nicht Ole-Links
93 BOOL bIntrnlLnk; // ist es ein interner Link
94 USHORT nUpdateMode;// UpdateMode
97 struct tDDEType
99 ImplDdeItem* pItem;
102 union {
103 tClientType ClientType;
104 tDDEType DDEType;
106 ImplBaseLinkData()
108 ClientType.nCntntType = 0;
109 ClientType.bIntrnlLnk = FALSE;
110 ClientType.nUpdateMode = 0;
111 DDEType.pItem = NULL;
116 class ImplDdeItem : public DdeGetPutItem
118 SvBaseLink* pLink;
119 DdeData aData;
120 Sequence< sal_Int8 > aSeq; // Datacontainer for DdeData !!!
121 BOOL bIsValidData : 1;
122 BOOL bIsInDTOR : 1;
123 public:
124 ImplDdeItem( SvBaseLink& rLink, const String& rStr )
125 : DdeGetPutItem( rStr ), pLink( &rLink ), bIsValidData( FALSE ),
126 bIsInDTOR( FALSE )
128 virtual ~ImplDdeItem();
130 virtual DdeData* Get( ULONG );
131 virtual BOOL Put( const DdeData* );
132 virtual void AdviseLoop( BOOL );
134 void Notify()
136 bIsValidData = FALSE;
137 DdeGetPutItem::NotifyClient();
140 BOOL IsInDTOR() const { return bIsInDTOR; }
144 /************************************************************************
145 |* SvBaseLink::SvBaseLink()
147 |* Beschreibung
148 *************************************************************************/
150 SvBaseLink::SvBaseLink()
152 pImpl = new BaseLink_Impl();
153 nObjType = OBJECT_CLIENT_SO;
154 pImplData = new ImplBaseLinkData;
155 bVisible = bSynchron = bUseCache = TRUE;
156 bWasLastEditOK = FALSE;
159 /************************************************************************
160 |* SvBaseLink::SvBaseLink()
162 |* Beschreibung
163 *************************************************************************/
165 SvBaseLink::SvBaseLink( USHORT nUpdateMode, ULONG nContentType )
167 pImpl = new BaseLink_Impl();
168 nObjType = OBJECT_CLIENT_SO;
169 pImplData = new ImplBaseLinkData;
170 bVisible = bSynchron = bUseCache = TRUE;
171 bWasLastEditOK = FALSE;
173 // falls es ein Ole-Link wird,
174 pImplData->ClientType.nUpdateMode = nUpdateMode;
175 pImplData->ClientType.nCntntType = nContentType;
176 pImplData->ClientType.bIntrnlLnk = FALSE;
179 /************************************************************************
180 |* SvBaseLink::SvBaseLink()
182 |* Beschreibung
183 *************************************************************************/
185 SvBaseLink::SvBaseLink( const String& rLinkName, USHORT nObjectType, SvLinkSource* pObj )
187 bVisible = bSynchron = bUseCache = TRUE;
188 bWasLastEditOK = FALSE;
189 aLinkName = rLinkName;
190 pImplData = new ImplBaseLinkData;
191 nObjType = nObjectType;
193 if( !pObj )
195 DBG_ASSERT( pObj, "Wo ist mein zu linkendes Object" );
196 return;
199 if( OBJECT_DDE_EXTERN == nObjType )
201 USHORT nItemStt = 0;
202 DdeTopic* pTopic = FindTopic( aLinkName, &nItemStt );
203 if( pTopic )
205 // dann haben wir alles zusammen
206 // MM hat gefummelt ???
207 // MM_TODO wie kriege ich den Namen
208 String aStr = aLinkName; // xLinkName->GetDisplayName();
209 aStr = aStr.Copy( nItemStt );
210 pImplData->DDEType.pItem = new ImplDdeItem( *this, aStr );
211 pTopic->InsertItem( pImplData->DDEType.pItem );
213 // dann koennen wir uns auch das Advise merken
214 xObj = pObj;
217 else if( pObj->Connect( this ) )
218 xObj = pObj;
221 /************************************************************************
222 |* SvBaseLink::~SvBaseLink()
224 |* Beschreibung
225 *************************************************************************/
227 SvBaseLink::~SvBaseLink()
229 Disconnect();
231 switch( nObjType )
233 case OBJECT_DDE_EXTERN:
234 if( !pImplData->DDEType.pItem->IsInDTOR() )
235 delete pImplData->DDEType.pItem;
236 break;
239 delete pImplData;
242 IMPL_LINK( SvBaseLink, EndEditHdl, String*, _pNewName )
244 String sNewName;
245 if ( _pNewName )
246 sNewName = *_pNewName;
247 if ( !ExecuteEdit( sNewName ) )
248 sNewName.Erase();
249 bWasLastEditOK = ( sNewName.Len() > 0 );
250 if ( pImpl->m_aEndEditLink.IsSet() )
251 pImpl->m_aEndEditLink.Call( this );
252 return 0;
255 /************************************************************************
256 |* SvBaseLink::SetObjType()
258 |* Beschreibung
259 *************************************************************************/
261 void SvBaseLink::SetObjType( USHORT nObjTypeP )
263 DBG_ASSERT( nObjType != OBJECT_CLIENT_DDE, "type already set" );
264 DBG_ASSERT( !xObj.Is(), "object exist" );
266 nObjType = nObjTypeP;
269 /************************************************************************
270 |* SvBaseLink::SetName()
272 |* Beschreibung
273 *************************************************************************/
275 void SvBaseLink::SetName( const String & rNm )
277 aLinkName = rNm;
280 /************************************************************************
281 |* SvBaseLink::GetName()
283 |* Beschreibung
284 *************************************************************************/
286 String SvBaseLink::GetName() const
288 return aLinkName;
291 /************************************************************************
292 |* SvBaseLink::SetObj()
294 |* Beschreibung
295 *************************************************************************/
297 void SvBaseLink::SetObj( SvLinkSource * pObj )
299 DBG_ASSERT( (nObjType & OBJECT_CLIENT_SO &&
300 pImplData->ClientType.bIntrnlLnk) ||
301 nObjType == OBJECT_CLIENT_GRF,
302 "no intern link" );
303 xObj = pObj;
306 /************************************************************************
307 |* SvBaseLink::SetLinkSourceName()
309 |* Beschreibung
310 *************************************************************************/
312 void SvBaseLink::SetLinkSourceName( const String & rLnkNm )
314 if( aLinkName == rLnkNm )
315 return;
317 AddNextRef(); // sollte ueberfluessig sein
318 // Alte Verbindung weg
319 Disconnect();
321 aLinkName = rLnkNm;
323 // Neu verbinden
324 _GetRealObject();
325 ReleaseRef(); // sollte ueberfluessig sein
328 /************************************************************************
329 |* SvBaseLink::GetLinkSourceName()
331 |* Beschreibung
332 *************************************************************************/
334 String SvBaseLink::GetLinkSourceName() const
336 return aLinkName;
340 /************************************************************************
341 |* SvBaseLink::SetUpdateMode()
343 |* Beschreibung
344 *************************************************************************/
346 void SvBaseLink::SetUpdateMode( USHORT nMode )
348 if( ( OBJECT_CLIENT_SO & nObjType ) &&
349 pImplData->ClientType.nUpdateMode != nMode )
351 AddNextRef();
352 Disconnect();
354 pImplData->ClientType.nUpdateMode = nMode;
355 _GetRealObject();
356 ReleaseRef();
360 // --> OD 2008-06-19 #i88291#
361 void SvBaseLink::clearStreamToLoadFrom()
363 m_xInputStreamToLoadFrom.clear();
364 if( xObj.Is() )
366 xObj->clearStreamToLoadFrom();
369 // <--
371 BOOL SvBaseLink::Update()
373 if( OBJECT_CLIENT_SO & nObjType )
375 AddNextRef();
376 Disconnect();
378 _GetRealObject();
379 ReleaseRef();
380 if( xObj.Is() )
382 xObj->setStreamToLoadFrom(m_xInputStreamToLoadFrom,m_bIsReadOnly);
383 // m_xInputStreamToLoadFrom = 0;
384 String sMimeType( SotExchange::GetFormatMimeType(
385 pImplData->ClientType.nCntntType ));
386 Any aData;
388 if( xObj->GetData( aData, sMimeType ) )
390 DataChanged( sMimeType, aData );
391 //JP 13.07.00: Bug 76817 - for manual Updates there is no
392 // need to hold the ServerObject
393 if( OBJECT_CLIENT_DDE == nObjType &&
394 LINKUPDATE_ONCALL == GetUpdateMode() && xObj.Is() )
395 xObj->RemoveAllDataAdvise( this );
396 return TRUE;
398 if( xObj.Is() )
400 // sollten wir asynschron sein?
401 if( xObj->IsPending() )
402 return TRUE;
404 // dann brauchen wir das Object auch nicht mehr
405 AddNextRef();
406 Disconnect();
407 ReleaseRef();
411 return FALSE;
415 USHORT SvBaseLink::GetUpdateMode() const
417 return ( OBJECT_CLIENT_SO & nObjType )
418 ? pImplData->ClientType.nUpdateMode
419 : sal::static_int_cast< USHORT >( LINKUPDATE_ONCALL );
423 void SvBaseLink::_GetRealObject( BOOL bConnect)
425 if( !pImpl->m_pLinkMgr )
426 return;
428 DBG_ASSERT( !xObj.Is(), "object already exist" );
430 if( OBJECT_CLIENT_DDE == nObjType )
432 String sServer;
433 if( pImpl->m_pLinkMgr->GetDisplayNames( this, &sServer ) &&
434 sServer == GetpApp()->GetAppName() ) // interner Link !!!
436 // damit der Internal - Link erzeugt werden kann !!!
437 nObjType = OBJECT_INTERN;
438 xObj = pImpl->m_pLinkMgr->CreateObj( this );
440 pImplData->ClientType.bIntrnlLnk = TRUE;
441 nObjType = OBJECT_CLIENT_DDE; // damit wir wissen was es mal war !!
443 else
445 pImplData->ClientType.bIntrnlLnk = FALSE;
446 xObj = pImpl->m_pLinkMgr->CreateObj( this );
449 else if( (OBJECT_CLIENT_SO & nObjType) )
450 xObj = pImpl->m_pLinkMgr->CreateObj( this );
452 if( bConnect && ( !xObj.Is() || !xObj->Connect( this ) ) )
453 Disconnect();
456 ULONG SvBaseLink::GetContentType() const
458 if( OBJECT_CLIENT_SO & nObjType )
459 return pImplData->ClientType.nCntntType;
461 return 0; // alle Formate ?
465 BOOL SvBaseLink::SetContentType( ULONG nType )
467 if( OBJECT_CLIENT_SO & nObjType )
469 pImplData->ClientType.nCntntType = nType;
470 return TRUE;
472 return FALSE;
475 SvLinkManager* SvBaseLink::GetLinkManager()
477 return pImpl->m_pLinkMgr;
480 const SvLinkManager* SvBaseLink::GetLinkManager() const
482 return pImpl->m_pLinkMgr;
485 void SvBaseLink::SetLinkManager( SvLinkManager* _pMgr )
487 pImpl->m_pLinkMgr = _pMgr;
490 void SvBaseLink::Disconnect()
492 if( xObj.Is() )
494 xObj->RemoveAllDataAdvise( this );
495 xObj->RemoveConnectAdvise( this );
496 xObj.Clear();
500 void SvBaseLink::DataChanged( const String &, const ::com::sun::star::uno::Any & )
502 switch( nObjType )
504 case OBJECT_DDE_EXTERN:
505 if( pImplData->DDEType.pItem )
506 pImplData->DDEType.pItem->Notify();
507 break;
511 void SvBaseLink::Edit( Window* pParent, const Link& rEndEditHdl )
513 pImpl->m_pParentWin = pParent;
514 pImpl->m_aEndEditLink = rEndEditHdl;
515 pImpl->m_bIsConnect = ( xObj.Is() != sal_False );
516 if( !pImpl->m_bIsConnect )
517 _GetRealObject( xObj.Is() );
519 bool bAsync = false;
520 Link aLink = LINK( this, SvBaseLink, EndEditHdl );
522 if( OBJECT_CLIENT_SO & nObjType && pImplData->ClientType.bIntrnlLnk )
524 if( pImpl->m_pLinkMgr )
526 SvLinkSourceRef ref = pImpl->m_pLinkMgr->CreateObj( this );
527 if( ref.Is() )
529 ref->Edit( pParent, this, aLink );
530 bAsync = true;
534 else
536 xObj->Edit( pParent, this, aLink );
537 bAsync = true;
540 if ( !bAsync )
542 ExecuteEdit( String() );
543 bWasLastEditOK = FALSE;
544 if ( pImpl->m_aEndEditLink.IsSet() )
545 pImpl->m_aEndEditLink.Call( this );
549 bool SvBaseLink::ExecuteEdit( const String& _rNewName )
551 if( _rNewName.Len() != 0 )
553 SetLinkSourceName( _rNewName );
554 if( !Update() )
556 String sApp, sTopic, sItem, sError;
557 pImpl->m_pLinkMgr->GetDisplayNames( this, &sApp, &sTopic, &sItem );
558 if( nObjType == OBJECT_CLIENT_DDE )
560 sError = SfxResId( STR_DDE_ERROR );
562 USHORT nFndPos = sError.Search( '%' );
563 if( STRING_NOTFOUND != nFndPos )
565 sError.Erase( nFndPos, 1 ).Insert( sApp, nFndPos );
566 nFndPos = nFndPos + sApp.Len();
568 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos )))
570 sError.Erase( nFndPos, 1 ).Insert( sTopic, nFndPos );
571 nFndPos = nFndPos + sTopic.Len();
573 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos )))
574 sError.Erase( nFndPos, 1 ).Insert( sItem, nFndPos );
576 else
577 return false;
579 ErrorBox( pImpl->m_pParentWin, WB_OK, sError ).Execute();
582 else if( !pImpl->m_bIsConnect )
583 Disconnect();
584 pImpl->m_bIsConnect = false;
585 return true;
588 void SvBaseLink::Closed()
590 if( xObj.Is() )
591 // beim Advise Abmelden
592 xObj->RemoveAllDataAdvise( this );
595 FileDialogHelper* SvBaseLink::GetFileDialog( sal_uInt32 nFlags, const String& rFactory ) const
597 if ( pImpl->m_pFileDlg )
598 delete pImpl->m_pFileDlg;
599 pImpl->m_pFileDlg = new FileDialogHelper( nFlags, rFactory );
600 return pImpl->m_pFileDlg;
603 ImplDdeItem::~ImplDdeItem()
605 bIsInDTOR = TRUE;
606 // damit im Disconnect nicht jemand auf die Idee kommt, den Pointer zu
607 // loeschen!!
608 SvBaseLinkRef aRef( pLink );
609 aRef->Disconnect();
612 DdeData* ImplDdeItem::Get( ULONG nFormat )
614 if( pLink->GetObj() )
616 // ist das noch gueltig?
617 if( bIsValidData && nFormat == aData.GetFormat() )
618 return &aData;
620 Any aValue;
621 String sMimeType( SotExchange::GetFormatMimeType( nFormat ));
622 if( pLink->GetObj()->GetData( aValue, sMimeType ) )
624 if( aValue >>= aSeq )
626 aData = DdeData( (const char *)aSeq.getConstArray(), aSeq.getLength(), nFormat );
628 bIsValidData = TRUE;
629 return &aData;
633 aSeq.realloc( 0 );
634 bIsValidData = FALSE;
635 return 0;
639 BOOL ImplDdeItem::Put( const DdeData* )
641 DBG_ERROR( "ImplDdeItem::Put not implemented" );
642 return FALSE;
646 void ImplDdeItem::AdviseLoop( BOOL bOpen )
648 // Verbindung wird geschlossen, also Link abmelden
649 if( pLink->GetObj() )
651 if( bOpen )
653 // es wird wieder eine Verbindung hergestellt
654 if( OBJECT_DDE_EXTERN == pLink->GetObjType() )
656 pLink->GetObj()->AddDataAdvise( pLink, String::CreateFromAscii( "text/plain;charset=utf-16" ), ADVISEMODE_NODATA );
657 pLink->GetObj()->AddConnectAdvise( pLink );
660 else
662 // damit im Disconnect nicht jemand auf die Idee kommt,
663 // den Pointer zu loeschen!!
664 SvBaseLinkRef aRef( pLink );
665 aRef->Disconnect();
671 static DdeTopic* FindTopic( const String & rLinkName, USHORT* pItemStt )
673 if( 0 == rLinkName.Len() )
674 return 0;
676 String sNm( rLinkName );
677 USHORT nTokenPos = 0;
678 String sService( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) );
680 DdeServices& rSvc = DdeService::GetServices();
681 for( DdeService* pService = rSvc.First(); pService;
682 pService = rSvc.Next() )
683 if( pService->GetName() == sService )
685 // dann suchen wir uns das Topic
686 String sTopic( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) );
687 if( pItemStt )
688 *pItemStt = nTokenPos;
690 DdeTopics& rTopics = pService->GetTopics();
692 for( int i = 0; i < 2; ++i )
694 for( DdeTopic* pTopic = rTopics.First(); pTopic;
695 pTopic = rTopics.Next() )
696 if( pTopic->GetName() == sTopic )
697 return pTopic;
699 // Topic nicht gefunden ?
700 // dann versuchen wir ihn mal anzulegen
701 if( i || !pService->MakeTopic( sTopic ) )
702 break; // hat nicht geklappt, also raus
704 break;
706 return 0;