Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / sfx2 / source / appl / appdde.cxx
blob98a7c5e8b3f0118fc20e22a3ed79f17a33abaefb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <vcl/wrkwin.hxx>
30 #include <svl/rectitem.hxx>
31 #include <svl/eitem.hxx>
32 #include <svl/intitem.hxx>
33 #include <basic/sbstar.hxx>
34 #include <svl/stritem.hxx>
35 #include <svl/svdde.hxx>
36 #include <sfx2/lnkbase.hxx>
37 #include <sfx2/linkmgr.hxx>
39 #include <tools/urlobj.hxx>
40 #include <tools/diagnose_ex.h>
41 #include <unotools/pathoptions.hxx>
43 #include <sfx2/app.hxx>
44 #include "appdata.hxx"
45 #include <sfx2/objsh.hxx>
46 #include <sfx2/viewfrm.hxx>
47 #include <sfx2/dispatch.hxx>
48 #include "sfxtypes.hxx"
49 #include <sfx2/sfxsids.hrc>
50 #include "helper.hxx"
51 #include <sfx2/docfile.hxx>
52 #include <comphelper/string.hxx>
53 #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
55 //========================================================================
57 String SfxDdeServiceName_Impl( const String& sIn )
59 String sReturn;
61 for ( sal_uInt16 n = sIn.Len(); n; --n )
63 sal_Unicode cChar = sIn.GetChar(n-1);
64 if (comphelper::string::isalnumAscii(cChar))
65 sReturn += cChar;
68 return sReturn;
71 #if defined( WNT )
72 class ImplDdeService : public DdeService
74 public:
75 ImplDdeService( const String& rNm )
76 : DdeService( rNm )
78 virtual sal_Bool MakeTopic( const String& );
80 virtual String Topics();
82 virtual sal_Bool SysTopicExecute( const String* pStr );
85 //--------------------------------------------------------------------
86 namespace
88 sal_Bool lcl_IsDocument( const String& rContent )
90 using namespace com::sun::star;
92 sal_Bool bRet = sal_False;
93 INetURLObject aObj( rContent );
94 DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" );
96 try
98 ::ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ucb::XCommandEnvironment > () );
99 bRet = aCnt.isDocument();
101 catch( const ucb::CommandAbortedException& )
103 DBG_WARNING( "CommandAbortedException" );
105 catch( const ucb::IllegalIdentifierException& )
107 DBG_WARNING( "IllegalIdentifierException" );
109 catch( const ucb::ContentCreationException& )
111 DBG_WARNING( "IllegalIdentifierException" );
113 catch( const uno::Exception& )
115 SAL_WARN( "sfx2.appl", "Any other exception" );
118 return bRet;
122 sal_Bool ImplDdeService::MakeTopic( const String& rNm )
124 // Workaround for Event after Main() under OS/2
125 // happens when exiting starts the App again
126 if ( !Application::IsInExecute() )
127 return sal_False;
129 // The Topic rNm is sought, do we have it?
130 // First only loop over the ObjectShells to find those
131 // with the specific name:
132 sal_Bool bRet = sal_False;
133 String sNm( rNm );
134 sNm.ToLowerAscii();
135 TypeId aType( TYPE(SfxObjectShell) );
136 SfxObjectShell* pShell = SfxObjectShell::GetFirst( &aType );
137 while( pShell )
139 String sTmp( pShell->GetTitle(SFX_TITLE_FULLNAME) );
140 sTmp.ToLowerAscii();
141 if( sTmp == sNm )
143 SFX_APP()->AddDdeTopic( pShell );
144 bRet = sal_True;
145 break;
147 pShell = SfxObjectShell::GetNext( *pShell, &aType );
150 if( !bRet )
152 INetURLObject aWorkPath( SvtPathOptions().GetWorkPath() );
153 INetURLObject aFile;
154 if ( aWorkPath.GetNewAbsURL( rNm, &aFile ) &&
155 lcl_IsDocument( aFile.GetMainURL( INetURLObject::NO_DECODE ) ) )
157 // File exists? then try to load it:
158 SfxStringItem aName( SID_FILE_NAME, aFile.GetMainURL( INetURLObject::NO_DECODE ) );
159 SfxBoolItem aNewView(SID_OPEN_NEW_VIEW, sal_True);
161 SfxBoolItem aSilent(SID_SILENT, sal_True);
162 SfxDispatcher* pDispatcher = SFX_APP()->GetDispatcher_Impl();
163 const SfxPoolItem* pRet = pDispatcher->Execute( SID_OPENDOC,
164 SFX_CALLMODE_SYNCHRON,
165 &aName, &aNewView,
166 &aSilent, 0L );
168 if( pRet && pRet->ISA( SfxViewFrameItem ) &&
169 ((SfxViewFrameItem*)pRet)->GetFrame() &&
170 0 != ( pShell = ((SfxViewFrameItem*)pRet)
171 ->GetFrame()->GetObjectShell() ) )
173 SFX_APP()->AddDdeTopic( pShell );
174 bRet = sal_True;
178 return bRet;
181 String ImplDdeService::Topics()
183 String sRet;
184 if( GetSysTopic() )
185 sRet += GetSysTopic()->GetName();
187 TypeId aType( TYPE(SfxObjectShell) );
188 SfxObjectShell* pShell = SfxObjectShell::GetFirst( &aType );
189 while( pShell )
191 if( SfxViewFrame::GetFirst( pShell ) )
193 if( sRet.Len() )
194 sRet += '\t';
195 sRet += pShell->GetTitle(SFX_TITLE_FULLNAME);
197 pShell = SfxObjectShell::GetNext( *pShell, &aType );
199 if( sRet.Len() )
200 sRet += DEFINE_CONST_UNICODE("\r\n");
201 return sRet;
204 sal_Bool ImplDdeService::SysTopicExecute( const String* pStr )
206 return (sal_Bool)SFX_APP()->DdeExecute( *pStr );
208 #endif
210 class SfxDdeTriggerTopic_Impl : public DdeTopic
212 public:
213 SfxDdeTriggerTopic_Impl()
214 : DdeTopic( DEFINE_CONST_UNICODE("TRIGGER") )
217 virtual sal_Bool Execute( const String* );
220 class SfxDdeDocTopic_Impl : public DdeTopic
222 public:
223 SfxObjectShell* pSh;
224 DdeData aData;
225 ::com::sun::star::uno::Sequence< sal_Int8 > aSeq;
227 SfxDdeDocTopic_Impl( SfxObjectShell* pShell )
228 : DdeTopic( pShell->GetTitle(SFX_TITLE_FULLNAME) ), pSh( pShell )
231 virtual DdeData* Get( sal_uIntPtr );
232 virtual sal_Bool Put( const DdeData* );
233 virtual sal_Bool Execute( const String* );
234 virtual sal_Bool StartAdviseLoop();
235 virtual sal_Bool MakeItem( const String& rItem );
239 SV_DECL_PTRARR( SfxDdeDocTopics_Impl, SfxDdeDocTopic_Impl *, 4 )
240 SV_IMPL_PTRARR( SfxDdeDocTopics_Impl, SfxDdeDocTopic_Impl *)
242 //========================================================================
244 sal_Bool SfxAppEvent_Impl( ApplicationEvent &rAppEvent,
245 const String &rCmd, const String &rEvent,
246 ApplicationEvent::Type eType )
248 /* [Description]
250 Checks if 'rCmd' of the event 'rEvent' is (without '(') and then assemble
251 this data into a <ApplicationEvent>, which can be excecuted through
252 <Application::AppEvent()>. If 'rCmd' is the given event 'rEvent', then
253 TRUE is returned, otherwise FALSE.
255 [Example]
257 rCmd = "Open(\"d:\doc\doc.sdw\")"
258 rEvent = "Open"
262 String aEvent( rEvent );
263 aEvent += '(';
264 if ( rCmd.CompareIgnoreCaseToAscii( aEvent, aEvent.Len() ) == COMPARE_EQUAL )
266 ::rtl::OUStringBuffer aData( rCmd );
267 aData.remove( 0, aEvent.Len() );
268 if ( aData.getLength() > 2 )
270 // Transform into the ApplicationEvent Format
271 aData.remove( aData.getLength() - 1, 1 );
272 for ( sal_Int32 n = 0; n < aData.getLength(); )
274 switch ( aData[n] )
276 case '"':
277 aData.remove( n, 1 );
278 while ( n < aData.getLength() && aData[n] != '"' )
279 ++n;
280 if ( n < aData.getLength() )
281 aData.remove( n, 1 );
282 break;
283 case ' ':
284 aData[n++] = '\n';
285 break;
286 default:
287 ++n;
288 break;
292 rAppEvent = ApplicationEvent(eType, aData.makeStringAndClear());
293 return sal_True;
297 return sal_False;
300 #if defined( WNT )
301 long SfxApplication::DdeExecute
303 const String& rCmd // Expressed in our BASIC-Syntax
306 /* Description]
308 This method can be overloaded by application developers, to receive
309 DDE-commands directed to thier SfxApplication subclass.
311 The base implementation understands the API functionality of the
312 relevant SfxApplication subclass in BASIC syntax. Return values can
313 not be transferred, unfortunately.
317 // Print or Open-Event?
318 ApplicationEvent aAppEvent;
319 if ( SfxAppEvent_Impl( aAppEvent, rCmd, DEFINE_CONST_UNICODE("Print"), ApplicationEvent::TYPE_PRINT ) ||
320 SfxAppEvent_Impl( aAppEvent, rCmd, DEFINE_CONST_UNICODE("Open"), ApplicationEvent::TYPE_OPEN ) )
321 GetpApp()->AppEvent( aAppEvent );
322 else
324 // all others are BASIC
325 StarBASIC* pBasic = GetBasic();
326 DBG_ASSERT( pBasic, "Where is the Basic???" );
327 SbxVariable* pRet = pBasic->Execute( rCmd );
328 if( !pRet )
330 SbxBase::ResetError();
331 return 0;
334 return 1;
336 #endif
338 long SfxObjectShell::DdeExecute
340 const String& rCmd // Expressed in our BASIC-Syntax
343 /* [Description]
345 This method can be overloaded by application developers, to receive
346 DDE-commands directed to the thier SfxApplication subclass.
348 The base implementation does nothing and returns 0.
352 #ifdef DISABLE_SCRIPTING
353 (void) rCmd;
354 #else
355 StarBASIC* pBasic = GetBasic();
356 DBG_ASSERT( pBasic, "Where is the Basic???" ) ;
357 SbxVariable* pRet = pBasic->Execute( rCmd );
358 if( !pRet )
360 SbxBase::ResetError();
361 return 0;
363 #endif
364 return 1;
367 //--------------------------------------------------------------------
369 long SfxObjectShell::DdeGetData
371 const String&, // the Item to be addressed
372 const String&, // in: Format
373 ::com::sun::star::uno::Any& // out: requested data
376 /* [Description]
378 This method can be overloaded by application developers, to receive
379 DDE-data-requests directed to thier SfxApplication subclass.
381 The base implementation provides no data and returns 0.
385 return 0;
388 //--------------------------------------------------------------------
390 long SfxObjectShell::DdeSetData
392 const String&, // the Item to be addressed
393 const String&, // in: Format
394 const ::com::sun::star::uno::Any& // out: requested data
397 /* [Description]
399 This method can be overloaded by application developers, to receive
400 DDE-data directed to thier SfxApplication subclass.
402 The base implementation is not receiving any data and returns 0.
406 return 0;
409 //--------------------------------------------------------------------
410 ::sfx2::SvLinkSource* SfxObjectShell::DdeCreateLinkSource
412 const String& // the Item to be addressed
415 /* [Description]
417 This method can be overloaded by application developers, to establish
418 a DDE-hotlink to thier SfxApplication subclass.
420 The base implementation is not generate a link and returns 0.
424 return 0;
427 void SfxObjectShell::ReconnectDdeLink(SfxObjectShell& /*rServer*/)
431 void SfxObjectShell::ReconnectDdeLinks(SfxObjectShell& rServer)
433 TypeId aType = TYPE(SfxObjectShell);
434 SfxObjectShell* p = GetFirst(&aType, false);
435 while (p)
437 if (&rServer != p)
438 p->ReconnectDdeLink(rServer);
440 p = GetNext(*p, &aType, false);
444 //========================================================================
446 long SfxViewFrame::DdeExecute
448 const String& rCmd // Expressed in our BASIC-Syntax
451 /* [Description]
453 This method can be overloaded by application developers, to receive
454 DDE-commands directed to the thier SfxApplication subclass.
456 The base implementation understands the API functionality of the
457 relevant SfxViewFrame, which is shown and the relevant SfxViewShell
458 and the relevant SfxApplication subclass in BASIC syntax. Return
459 values can not be transferred, unfortunately.
463 if ( GetObjectShell() )
464 return GetObjectShell()->DdeExecute( rCmd );
466 return 0;
469 //--------------------------------------------------------------------
471 long SfxViewFrame::DdeGetData
473 const String&, // the Item to be addressed
474 const String&, // in: Format
475 ::com::sun::star::uno::Any& // out: requested data
478 /* [Description]
480 This method can be overloaded by application developers, to receive
481 DDE-data-requests directed to thier SfxApplication subclass.
483 The base implementation provides no data and returns 0.
487 return 0;
490 //--------------------------------------------------------------------
492 long SfxViewFrame::DdeSetData
494 const String&, // the Item to be addressed
495 const String&, // in: Format
496 const ::com::sun::star::uno::Any& // out: requested data
499 /* [Description]
501 This method can be overloaded by application developers, to receive
502 DDE-data directed to thier SfxApplication subclass.
504 The base implementation is not receiving any data and returns 0.
508 return 0;
511 //--------------------------------------------------------------------
513 ::sfx2::SvLinkSource* SfxViewFrame::DdeCreateLinkSource
515 const String& // the Item to be addressed
518 /* [Description]
520 This method can be overloaded by application developers, to establish
521 a DDE-hotlink to thier SfxApplication subclass.
523 The base implementation is not generate a link and returns 0.
527 return 0;
530 //========================================================================
532 sal_Bool SfxApplication::InitializeDde()
534 int nError = 0;
535 #if defined( WNT )
536 DBG_ASSERT( !pAppData_Impl->pDdeService,
537 "Dde can not be initialized multiple times" );
539 pAppData_Impl->pDdeService = new ImplDdeService( Application::GetAppName() );
540 nError = pAppData_Impl->pDdeService->GetError();
541 if( !nError )
543 pAppData_Impl->pDocTopics = new SfxDdeDocTopics_Impl;
545 // we certainly want to support RTF!
546 pAppData_Impl->pDdeService->AddFormat( FORMAT_RTF );
548 // Config path as a topic becauseof multiple starts
549 INetURLObject aOfficeLockFile( SvtPathOptions().GetUserConfigPath() );
550 aOfficeLockFile.insertName( DEFINE_CONST_UNICODE( "soffice.lck" ) );
551 String aService( SfxDdeServiceName_Impl(
552 aOfficeLockFile.GetMainURL(INetURLObject::DECODE_TO_IURI) ) );
553 aService.ToUpperAscii();
554 pAppData_Impl->pDdeService2 = new ImplDdeService( aService );
555 pAppData_Impl->pTriggerTopic = new SfxDdeTriggerTopic_Impl;
556 pAppData_Impl->pDdeService2->AddTopic( *pAppData_Impl->pTriggerTopic );
558 #endif
559 return !nError;
562 void SfxAppData_Impl::DeInitDDE()
564 DELETEZ( pTriggerTopic );
565 DELETEZ( pDdeService2 );
566 DELETEZ( pDocTopics );
567 DELETEZ( pDdeService );
570 #if defined( WNT )
571 void SfxApplication::AddDdeTopic( SfxObjectShell* pSh )
573 DBG_ASSERT( pAppData_Impl->pDocTopics, "There is no Dde-Service" );
574 //OV: DDE is disconnected in server mode!
575 if( !pAppData_Impl->pDocTopics )
576 return;
578 // prevent double submit
579 String sShellNm;
580 sal_Bool bFnd = sal_False;
581 for( sal_uInt16 n = pAppData_Impl->pDocTopics->Count(); n; )
582 if( (*pAppData_Impl->pDocTopics)[ --n ]->pSh == pSh )
584 // If the document is untitled, is still a new Topic is created!
585 if( !bFnd )
587 bFnd = sal_True;
588 (sShellNm = pSh->GetTitle(SFX_TITLE_FULLNAME)).ToLowerAscii();
590 String sNm( (*pAppData_Impl->pDocTopics)[ n ]->GetName() );
591 if( sShellNm == sNm.ToLowerAscii() )
592 return ;
595 const SfxDdeDocTopic_Impl* pTopic = new SfxDdeDocTopic_Impl( pSh );
596 pAppData_Impl->pDocTopics->Insert( pTopic,
597 pAppData_Impl->pDocTopics->Count() );
598 pAppData_Impl->pDdeService->AddTopic( *pTopic );
600 #endif
602 void SfxApplication::RemoveDdeTopic( SfxObjectShell* pSh )
604 DBG_ASSERT( pAppData_Impl->pDocTopics, "There is no Dde-Service" );
605 //OV: DDE is disconnected in server mode!
606 if( !pAppData_Impl->pDocTopics )
607 return;
609 SfxDdeDocTopic_Impl* pTopic;
610 for( sal_uInt16 n = pAppData_Impl->pDocTopics->Count(); n; )
611 if( ( pTopic = (*pAppData_Impl->pDocTopics)[ --n ])->pSh == pSh )
613 pAppData_Impl->pDdeService->RemoveTopic( *pTopic );
614 pAppData_Impl->pDocTopics->DeleteAndDestroy( n );
618 const DdeService* SfxApplication::GetDdeService() const
620 return pAppData_Impl->pDdeService;
623 DdeService* SfxApplication::GetDdeService()
625 return pAppData_Impl->pDdeService;
628 //--------------------------------------------------------------------
630 sal_Bool SfxDdeTriggerTopic_Impl::Execute( const String* )
632 return sal_True;
635 //--------------------------------------------------------------------
636 DdeData* SfxDdeDocTopic_Impl::Get( sal_uIntPtr nFormat )
638 String sMimeType( SotExchange::GetFormatMimeType( nFormat ));
639 ::com::sun::star::uno::Any aValue;
640 long nRet = pSh->DdeGetData( GetCurItem(), sMimeType, aValue );
641 if( nRet && aValue.hasValue() && ( aValue >>= aSeq ) )
643 aData = DdeData( aSeq.getConstArray(), aSeq.getLength(), nFormat );
644 return &aData;
646 aSeq.realloc( 0 );
647 return 0;
650 sal_Bool SfxDdeDocTopic_Impl::Put( const DdeData* pData )
652 aSeq = ::com::sun::star::uno::Sequence< sal_Int8 >(
653 (sal_Int8*)(const void*)*pData, (long)*pData );
654 sal_Bool bRet;
655 if( aSeq.getLength() )
657 ::com::sun::star::uno::Any aValue;
658 aValue <<= aSeq;
659 String sMimeType( SotExchange::GetFormatMimeType( pData->GetFormat() ));
660 bRet = 0 != pSh->DdeSetData( GetCurItem(), sMimeType, aValue );
662 else
663 bRet = sal_False;
664 return bRet;
667 sal_Bool SfxDdeDocTopic_Impl::Execute( const String* pStr )
669 long nRet = pStr ? pSh->DdeExecute( *pStr ) : 0;
670 return 0 != nRet;
673 sal_Bool SfxDdeDocTopic_Impl::MakeItem( const String& rItem )
675 AddItem( DdeItem( rItem ) );
676 return sal_True;
679 sal_Bool SfxDdeDocTopic_Impl::StartAdviseLoop()
681 sal_Bool bRet = sal_False;
682 ::sfx2::SvLinkSource* pNewObj = pSh->DdeCreateLinkSource( GetCurItem() );
683 if( pNewObj )
685 // then we also establish a corresponding SvBaseLink
686 String sNm, sTmp( Application::GetAppName() );
687 ::sfx2::MakeLnkName( sNm, &sTmp, pSh->GetTitle(SFX_TITLE_FULLNAME), GetCurItem() );
688 new ::sfx2::SvBaseLink( sNm, OBJECT_DDE_EXTERN, pNewObj );
689 bRet = sal_True;
691 return bRet;
694 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */