Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <sfx2/lnkbase.hxx>
22 : #include <sot/exchange.hxx>
23 : #include <com/sun/star/uno/Any.hxx>
24 : #include <com/sun/star/uno/Sequence.hxx>
25 : #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
26 : #include <vcl/layout.hxx>
27 : #include <sfx2/linkmgr.hxx>
28 : #include <vcl/svapp.hxx>
29 : #include "app.hrc"
30 : #include <sfx2/sfxresid.hxx>
31 : #include <sfx2/filedlghelper.hxx>
32 : #include <tools/debug.hxx>
33 : #include <svl/svdde.hxx>
34 :
35 : using namespace ::com::sun::star;
36 : using namespace ::com::sun::star::uno;
37 :
38 : namespace sfx2
39 : {
40 :
41 60 : TYPEINIT0( SvBaseLink )
42 :
43 : class ImplDdeItem;
44 :
45 : struct BaseLink_Impl
46 : {
47 : Link<> m_aEndEditLink;
48 : LinkManager* m_pLinkMgr;
49 : VclPtr<vcl::Window> m_pParentWin;
50 : FileDialogHelper* m_pFileDlg;
51 : bool m_bIsConnect;
52 :
53 64 : BaseLink_Impl() :
54 : m_pLinkMgr( NULL )
55 : , m_pParentWin( NULL )
56 : , m_pFileDlg( NULL )
57 64 : , m_bIsConnect( false )
58 64 : {}
59 :
60 62 : ~BaseLink_Impl()
61 62 : { delete m_pFileDlg; }
62 : };
63 :
64 : // only for internal management
65 : struct ImplBaseLinkData
66 : {
67 : struct tClientType
68 : {
69 : // applies for all links
70 : SotClipboardFormatId nCntntType; // Update Format
71 : // Not Ole-Links
72 : bool bIntrnlLnk; // It is an internal link
73 : SfxLinkUpdateMode nUpdateMode; // UpdateMode
74 : };
75 :
76 : struct tDDEType
77 : {
78 : ImplDdeItem* pItem;
79 : };
80 :
81 : union {
82 : tClientType ClientType;
83 : tDDEType DDEType;
84 : };
85 64 : ImplBaseLinkData()
86 : {
87 64 : ClientType.nCntntType = SotClipboardFormatId::NONE;
88 64 : ClientType.bIntrnlLnk = false;
89 64 : ClientType.nUpdateMode = SfxLinkUpdateMode::NONE;
90 64 : DDEType.pItem = NULL;
91 64 : }
92 : };
93 :
94 :
95 : class ImplDdeItem : public DdeGetPutItem
96 : {
97 : SvBaseLink* pLink;
98 : DdeData aData;
99 : Sequence< sal_Int8 > aSeq; // Datacontainer for DdeData !!!
100 : bool bIsValidData : 1;
101 : bool bIsInDTOR : 1;
102 : public:
103 : #if defined WNT
104 : ImplDdeItem( SvBaseLink& rLink, const OUString& rStr )
105 : : DdeGetPutItem( rStr ), pLink( &rLink ), bIsValidData( false ),
106 : bIsInDTOR( false )
107 : {}
108 : #endif
109 : virtual ~ImplDdeItem();
110 :
111 : virtual DdeData* Get( SotClipboardFormatId ) SAL_OVERRIDE;
112 : virtual bool Put( const DdeData* ) SAL_OVERRIDE;
113 : virtual void AdviseLoop( bool ) SAL_OVERRIDE;
114 :
115 0 : void Notify()
116 : {
117 0 : bIsValidData = false;
118 0 : DdeGetPutItem::NotifyClient();
119 0 : }
120 :
121 0 : bool IsInDTOR() const { return bIsInDTOR; }
122 : };
123 :
124 :
125 :
126 1 : SvBaseLink::SvBaseLink()
127 1 : : m_bIsReadOnly(false)
128 : {
129 1 : pImpl = new BaseLink_Impl();
130 1 : nObjType = OBJECT_CLIENT_SO;
131 1 : pImplData = new ImplBaseLinkData;
132 1 : bVisible = bSynchron = bUseCache = true;
133 1 : bWasLastEditOK = false;
134 1 : }
135 :
136 :
137 :
138 63 : SvBaseLink::SvBaseLink( SfxLinkUpdateMode nUpdateMode, SotClipboardFormatId nContentType )
139 63 : : m_bIsReadOnly(false)
140 : {
141 63 : pImpl = new BaseLink_Impl();
142 63 : nObjType = OBJECT_CLIENT_SO;
143 63 : pImplData = new ImplBaseLinkData;
144 63 : bVisible = bSynchron = bUseCache = true;
145 63 : bWasLastEditOK = false;
146 :
147 : // It is going to be a Ole-Link,
148 63 : pImplData->ClientType.nUpdateMode = nUpdateMode;
149 63 : pImplData->ClientType.nCntntType = nContentType;
150 63 : pImplData->ClientType.bIntrnlLnk = false;
151 63 : }
152 :
153 : #if defined WNT
154 :
155 : static DdeTopic* FindTopic( const OUString & rLinkName, sal_uInt16* pItemStt )
156 : {
157 : if( rLinkName.isEmpty() )
158 : return 0;
159 :
160 : OUString sNm( rLinkName );
161 : sal_Int32 nTokenPos = 0;
162 : OUString sService( sNm.getToken( 0, cTokenSeparator, nTokenPos ) );
163 :
164 : DdeServices& rSvc = DdeService::GetServices();
165 : for (DdeServices::iterator aI = rSvc.begin(); aI != rSvc.end(); ++aI)
166 : {
167 : DdeService* pService = *aI;
168 : if( pService->GetName() == sService )
169 : {
170 : // then we search for the Topic
171 : OUString sTopic( sNm.getToken( 0, cTokenSeparator, nTokenPos ) );
172 : if( pItemStt )
173 : *pItemStt = nTokenPos;
174 :
175 : std::vector<DdeTopic*>& rTopics = pService->GetTopics();
176 :
177 : for( int i = 0; i < 2; ++i )
178 : {
179 : for( std::vector<DdeTopic*>::iterator iterTopic = rTopics.begin();
180 : iterTopic != rTopics.end(); ++iterTopic )
181 : if( (*iterTopic)->GetName() == sTopic )
182 : return *iterTopic;
183 :
184 : // Topic not found?
185 : // then we try once to create it
186 : if( i || !pService->MakeTopic( sTopic ) )
187 : break; // did not work, exiting
188 : }
189 : break;
190 : }
191 : }
192 : return 0;
193 : }
194 :
195 : SvBaseLink::SvBaseLink( const OUString& rLinkName, sal_uInt16 nObjectType, SvLinkSource* pObj )
196 : : pImpl(0)
197 : , m_bIsReadOnly(false)
198 : {
199 : bVisible = bSynchron = bUseCache = true;
200 : bWasLastEditOK = false;
201 : aLinkName = rLinkName;
202 : pImplData = new ImplBaseLinkData;
203 : nObjType = nObjectType;
204 :
205 : if( !pObj )
206 : {
207 : DBG_ASSERT( pObj, "Where is my left-most object" );
208 : return;
209 : }
210 :
211 : if( OBJECT_DDE_EXTERN == nObjType )
212 : {
213 : sal_uInt16 nItemStt = 0;
214 : DdeTopic* pTopic = FindTopic( aLinkName, &nItemStt );
215 : if( pTopic )
216 : {
217 : // then we have it all together
218 : // MM_TODO how do I get the name
219 : OUString aStr = aLinkName; // xLinkName->GetDisplayName();
220 : aStr = aStr.copy( nItemStt );
221 : pImplData->DDEType.pItem = new ImplDdeItem( *this, aStr );
222 : pTopic->InsertItem( pImplData->DDEType.pItem );
223 :
224 : // store the Advice
225 : xObj = pObj;
226 : }
227 : }
228 : else if( pObj->Connect( this ) )
229 : xObj = pObj;
230 : }
231 :
232 : #endif
233 :
234 124 : SvBaseLink::~SvBaseLink()
235 : {
236 62 : Disconnect();
237 :
238 62 : switch( nObjType )
239 : {
240 : case OBJECT_DDE_EXTERN:
241 0 : if( !pImplData->DDEType.pItem->IsInDTOR() )
242 0 : delete pImplData->DDEType.pItem;
243 0 : break;
244 : }
245 :
246 62 : delete pImplData;
247 62 : delete pImpl;
248 62 : }
249 :
250 0 : IMPL_LINK( SvBaseLink, EndEditHdl, OUString*, _pNewName )
251 : {
252 0 : OUString sNewName;
253 0 : if ( _pNewName )
254 0 : sNewName = *_pNewName;
255 0 : if ( !ExecuteEdit( sNewName ) )
256 0 : sNewName.clear();
257 0 : bWasLastEditOK = !sNewName.isEmpty();
258 0 : if ( pImpl->m_aEndEditLink.IsSet() )
259 0 : pImpl->m_aEndEditLink.Call( this );
260 0 : return 0;
261 : }
262 :
263 :
264 :
265 65 : void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP )
266 : {
267 : DBG_ASSERT( nObjType != OBJECT_CLIENT_DDE, "type already set" );
268 : DBG_ASSERT( !xObj.Is(), "object exist" );
269 :
270 65 : nObjType = nObjTypeP;
271 65 : }
272 :
273 :
274 :
275 65 : void SvBaseLink::SetName( const OUString & rNm )
276 : {
277 65 : aLinkName = rNm;
278 65 : }
279 :
280 :
281 :
282 5 : void SvBaseLink::SetObj( SvLinkSource * pObj )
283 : {
284 : DBG_ASSERT( (nObjType & OBJECT_CLIENT_SO &&
285 : pImplData->ClientType.bIntrnlLnk) ||
286 : nObjType == OBJECT_CLIENT_GRF,
287 : "no intern link" );
288 5 : xObj = pObj;
289 5 : }
290 :
291 :
292 :
293 0 : void SvBaseLink::SetLinkSourceName( const OUString & rLnkNm )
294 : {
295 0 : if( aLinkName == rLnkNm )
296 0 : return;
297 :
298 0 : AddNextRef(); // should be superfluous
299 : // remove old connection
300 0 : Disconnect();
301 :
302 0 : aLinkName = rLnkNm;
303 :
304 : // New Connection
305 0 : _GetRealObject();
306 0 : ReleaseRef(); // should be superfluous
307 : }
308 :
309 :
310 :
311 :
312 :
313 :
314 66 : void SvBaseLink::SetUpdateMode( SfxLinkUpdateMode nMode )
315 : {
316 132 : if( ( OBJECT_CLIENT_SO & nObjType ) &&
317 66 : pImplData->ClientType.nUpdateMode != nMode )
318 : {
319 6 : AddNextRef();
320 6 : Disconnect();
321 :
322 6 : pImplData->ClientType.nUpdateMode = nMode;
323 6 : _GetRealObject();
324 6 : ReleaseRef();
325 : }
326 66 : }
327 :
328 : // #i88291#
329 0 : void SvBaseLink::clearStreamToLoadFrom()
330 : {
331 0 : m_xInputStreamToLoadFrom.clear();
332 0 : if( xObj.Is() )
333 : {
334 0 : xObj->clearStreamToLoadFrom();
335 : }
336 0 : }
337 :
338 38 : bool SvBaseLink::Update()
339 : {
340 38 : if( OBJECT_CLIENT_SO & nObjType )
341 : {
342 38 : AddNextRef();
343 38 : Disconnect();
344 :
345 38 : _GetRealObject();
346 38 : ReleaseRef();
347 38 : if( xObj.Is() )
348 : {
349 38 : xObj->setStreamToLoadFrom(m_xInputStreamToLoadFrom,m_bIsReadOnly);
350 : OUString sMimeType( SotExchange::GetFormatMimeType(
351 38 : pImplData->ClientType.nCntntType ));
352 38 : Any aData;
353 :
354 38 : if( xObj->GetData( aData, sMimeType ) )
355 : {
356 38 : UpdateResult eRes = DataChanged(sMimeType, aData);
357 38 : bool bSuccess = eRes == SUCCESS;
358 : //for manual Updates there is no need to hold the ServerObject
359 81 : if( OBJECT_CLIENT_DDE == nObjType &&
360 38 : SfxLinkUpdateMode::ONCALL == GetUpdateMode() && xObj.Is() )
361 0 : xObj->RemoveAllDataAdvise( this );
362 38 : return bSuccess;
363 : }
364 0 : if( xObj.Is() )
365 : {
366 : // should be asynschron?
367 0 : if( xObj->IsPending() )
368 0 : return true;
369 :
370 : // we do not need the object anymore
371 0 : AddNextRef();
372 0 : Disconnect();
373 0 : ReleaseRef();
374 0 : }
375 : }
376 : }
377 0 : return false;
378 : }
379 :
380 :
381 10 : SfxLinkUpdateMode SvBaseLink::GetUpdateMode() const
382 : {
383 10 : return ( OBJECT_CLIENT_SO & nObjType )
384 : ? pImplData->ClientType.nUpdateMode
385 10 : : SfxLinkUpdateMode::ONCALL;
386 : }
387 :
388 :
389 75 : void SvBaseLink::_GetRealObject( bool bConnect)
390 : {
391 75 : if( !pImpl->m_pLinkMgr )
392 81 : return;
393 :
394 : DBG_ASSERT( !xObj.Is(), "object already exist" );
395 :
396 69 : if( OBJECT_CLIENT_DDE == nObjType )
397 : {
398 5 : OUString sServer;
399 20 : if( sfx2::LinkManager::GetDisplayNames( this, &sServer ) &&
400 20 : sServer == Application::GetAppName() ) // internal Link !!!
401 : {
402 : // so that the Internal link can be created!
403 5 : nObjType = OBJECT_INTERN;
404 5 : xObj = sfx2::LinkManager::CreateObj( this );
405 :
406 5 : pImplData->ClientType.bIntrnlLnk = true;
407 5 : nObjType = OBJECT_CLIENT_DDE; // so we know what it once was!
408 : }
409 : else
410 : {
411 0 : pImplData->ClientType.bIntrnlLnk = false;
412 0 : xObj = sfx2::LinkManager::CreateObj( this );
413 5 : }
414 : }
415 64 : else if( (OBJECT_CLIENT_SO & nObjType) )
416 64 : xObj = sfx2::LinkManager::CreateObj( this );
417 :
418 69 : if( bConnect && ( !xObj.Is() || !xObj->Connect( this ) ) )
419 0 : Disconnect();
420 : }
421 :
422 102 : SotClipboardFormatId SvBaseLink::GetContentType() const
423 : {
424 102 : if( OBJECT_CLIENT_SO & nObjType )
425 102 : return pImplData->ClientType.nCntntType;
426 :
427 0 : return SotClipboardFormatId::NONE; // all Formats ?
428 : }
429 :
430 :
431 18 : bool SvBaseLink::SetContentType( SotClipboardFormatId nType )
432 : {
433 18 : if( OBJECT_CLIENT_SO & nObjType )
434 : {
435 18 : pImplData->ClientType.nCntntType = nType;
436 18 : return true;
437 : }
438 0 : return false;
439 : }
440 :
441 132 : LinkManager* SvBaseLink::GetLinkManager()
442 : {
443 132 : return pImpl->m_pLinkMgr;
444 : }
445 :
446 0 : const LinkManager* SvBaseLink::GetLinkManager() const
447 : {
448 0 : return pImpl->m_pLinkMgr;
449 : }
450 :
451 129 : void SvBaseLink::SetLinkManager( LinkManager* _pMgr )
452 : {
453 129 : pImpl->m_pLinkMgr = _pMgr;
454 129 : }
455 :
456 184 : void SvBaseLink::Disconnect()
457 : {
458 184 : if( xObj.Is() )
459 : {
460 68 : xObj->RemoveAllDataAdvise( this );
461 68 : xObj->RemoveConnectAdvise( this );
462 68 : xObj.Clear();
463 : }
464 184 : }
465 :
466 0 : SvBaseLink::UpdateResult SvBaseLink::DataChanged( const OUString &, const ::com::sun::star::uno::Any & )
467 : {
468 0 : switch( nObjType )
469 : {
470 : case OBJECT_DDE_EXTERN:
471 0 : if( pImplData->DDEType.pItem )
472 0 : pImplData->DDEType.pItem->Notify();
473 0 : break;
474 : }
475 0 : return SUCCESS;
476 : }
477 :
478 0 : void SvBaseLink::Edit( vcl::Window* pParent, const Link<>& rEndEditHdl )
479 : {
480 0 : pImpl->m_pParentWin = pParent;
481 0 : pImpl->m_aEndEditLink = rEndEditHdl;
482 0 : pImpl->m_bIsConnect = xObj.Is();
483 0 : if( !pImpl->m_bIsConnect )
484 0 : _GetRealObject( xObj.Is() );
485 :
486 0 : bool bAsync = false;
487 0 : Link<> aLink = LINK( this, SvBaseLink, EndEditHdl );
488 :
489 0 : if( OBJECT_CLIENT_SO & nObjType && pImplData->ClientType.bIntrnlLnk )
490 : {
491 0 : if( pImpl->m_pLinkMgr )
492 : {
493 0 : SvLinkSourceRef ref = sfx2::LinkManager::CreateObj( this );
494 0 : if( ref.Is() )
495 : {
496 0 : ref->Edit( pParent, this, aLink );
497 0 : bAsync = true;
498 0 : }
499 0 : }
500 : }
501 : else
502 : {
503 0 : xObj->Edit( pParent, this, aLink );
504 0 : bAsync = true;
505 : }
506 :
507 0 : if ( !bAsync )
508 : {
509 0 : ExecuteEdit( OUString() );
510 0 : bWasLastEditOK = false;
511 0 : if ( pImpl->m_aEndEditLink.IsSet() )
512 0 : pImpl->m_aEndEditLink.Call( this );
513 : }
514 0 : }
515 :
516 0 : bool SvBaseLink::ExecuteEdit( const OUString& _rNewName )
517 : {
518 0 : if( !_rNewName.isEmpty() )
519 : {
520 0 : SetLinkSourceName( _rNewName );
521 0 : if( !Update() )
522 : {
523 0 : OUString sApp, sTopic, sItem, sError;
524 0 : sfx2::LinkManager::GetDisplayNames( this, &sApp, &sTopic, &sItem );
525 0 : if( nObjType == OBJECT_CLIENT_DDE )
526 : {
527 0 : sError = SFX2_RESSTR(STR_DDE_ERROR);
528 :
529 0 : sal_Int32 nFndPos = sError.indexOf( '%' );
530 0 : if( -1 != nFndPos )
531 : {
532 0 : sError = sError.replaceAt( nFndPos, 1, sApp );
533 0 : nFndPos = nFndPos + sApp.getLength();
534 :
535 0 : if( -1 != ( nFndPos = sError.indexOf( '%', nFndPos )))
536 : {
537 0 : sError = sError.replaceAt( nFndPos, 1, sTopic );
538 0 : nFndPos = nFndPos + sTopic.getLength();
539 :
540 0 : if( -1 != ( nFndPos = sError.indexOf( '%', nFndPos )))
541 0 : sError = sError.replaceAt( nFndPos, 1, sItem );
542 : }
543 : }
544 : }
545 : else
546 0 : return false;
547 :
548 0 : ScopedVclPtrInstance<MessageDialog>::Create(pImpl->m_pParentWin, sError)->Execute();
549 : }
550 : }
551 0 : else if( !pImpl->m_bIsConnect )
552 0 : Disconnect();
553 0 : pImpl->m_bIsConnect = false;
554 0 : return true;
555 : }
556 :
557 0 : void SvBaseLink::Closed()
558 : {
559 0 : if( xObj.Is() )
560 0 : xObj->RemoveAllDataAdvise( this );
561 0 : }
562 :
563 0 : FileDialogHelper & SvBaseLink::GetInsertFileDialog(const OUString& rFactory) const
564 : {
565 0 : if ( pImpl->m_pFileDlg )
566 0 : delete pImpl->m_pFileDlg;
567 : pImpl->m_pFileDlg = new FileDialogHelper(
568 : ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
569 0 : SFXWB_INSERT, rFactory);
570 0 : return *pImpl->m_pFileDlg;
571 : }
572 :
573 0 : ImplDdeItem::~ImplDdeItem()
574 : {
575 0 : bIsInDTOR = true;
576 : // So that no-one gets the idea to delete the pointer when Disconnecting!
577 0 : SvBaseLinkRef aRef( pLink );
578 0 : aRef->Disconnect();
579 0 : }
580 :
581 0 : DdeData* ImplDdeItem::Get( SotClipboardFormatId nFormat )
582 : {
583 0 : if( pLink->GetObj() )
584 : {
585 : // is it still valid?
586 0 : if( bIsValidData && nFormat == aData.GetFormat() )
587 0 : return &aData;
588 :
589 0 : Any aValue;
590 0 : OUString sMimeType( SotExchange::GetFormatMimeType( nFormat ));
591 0 : if( pLink->GetObj()->GetData( aValue, sMimeType ) )
592 : {
593 0 : if( aValue >>= aSeq )
594 : {
595 0 : aData = DdeData( aSeq.getConstArray(), aSeq.getLength(), nFormat );
596 :
597 0 : bIsValidData = true;
598 0 : return &aData;
599 : }
600 0 : }
601 : }
602 0 : aSeq.realloc( 0 );
603 0 : bIsValidData = false;
604 0 : return 0;
605 : }
606 :
607 :
608 0 : bool ImplDdeItem::Put( const DdeData* )
609 : {
610 : OSL_FAIL( "ImplDdeItem::Put not implemented" );
611 0 : return false;
612 : }
613 :
614 :
615 0 : void ImplDdeItem::AdviseLoop( bool bOpen )
616 : {
617 : // Connection is closed, so also unsubscribe link
618 0 : if( pLink->GetObj() )
619 : {
620 0 : if( bOpen )
621 : {
622 : // A connection is re-established
623 0 : if( OBJECT_DDE_EXTERN == pLink->GetObjType() )
624 : {
625 0 : pLink->GetObj()->AddDataAdvise( pLink, OUString("text/plain;charset=utf-16"), ADVISEMODE_NODATA );
626 0 : pLink->GetObj()->AddConnectAdvise( pLink );
627 : }
628 : }
629 : else
630 : {
631 : // So that no-one gets the idea to delete the pointer
632 : // when Disconnecting!
633 0 : SvBaseLinkRef aRef( pLink );
634 0 : aRef->Disconnect();
635 : }
636 : }
637 0 : }
638 :
639 648 : }
640 :
641 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|