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>
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
)
61 for ( sal_uInt16 n
= sIn
.Len(); n
; --n
)
63 sal_Unicode cChar
= sIn
.GetChar(n
-1);
64 if (comphelper::string::isalnumAscii(cChar
))
72 class ImplDdeService
: public DdeService
75 ImplDdeService( const String
& rNm
)
78 virtual sal_Bool
MakeTopic( const String
& );
80 virtual String
Topics();
82 virtual sal_Bool
SysTopicExecute( const String
* pStr
);
85 //--------------------------------------------------------------------
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!" );
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" );
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() )
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
;
135 TypeId
aType( TYPE(SfxObjectShell
) );
136 SfxObjectShell
* pShell
= SfxObjectShell::GetFirst( &aType
);
139 String
sTmp( pShell
->GetTitle(SFX_TITLE_FULLNAME
) );
143 SFX_APP()->AddDdeTopic( pShell
);
147 pShell
= SfxObjectShell::GetNext( *pShell
, &aType
);
152 INetURLObject
aWorkPath( SvtPathOptions().GetWorkPath() );
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
,
168 if( pRet
&& pRet
->ISA( SfxViewFrameItem
) &&
169 ((SfxViewFrameItem
*)pRet
)->GetFrame() &&
170 0 != ( pShell
= ((SfxViewFrameItem
*)pRet
)
171 ->GetFrame()->GetObjectShell() ) )
173 SFX_APP()->AddDdeTopic( pShell
);
181 String
ImplDdeService::Topics()
185 sRet
+= GetSysTopic()->GetName();
187 TypeId
aType( TYPE(SfxObjectShell
) );
188 SfxObjectShell
* pShell
= SfxObjectShell::GetFirst( &aType
);
191 if( SfxViewFrame::GetFirst( pShell
) )
195 sRet
+= pShell
->GetTitle(SFX_TITLE_FULLNAME
);
197 pShell
= SfxObjectShell::GetNext( *pShell
, &aType
);
200 sRet
+= DEFINE_CONST_UNICODE("\r\n");
204 sal_Bool
ImplDdeService::SysTopicExecute( const String
* pStr
)
206 return (sal_Bool
)SFX_APP()->DdeExecute( *pStr
);
210 class SfxDdeTriggerTopic_Impl
: public DdeTopic
213 SfxDdeTriggerTopic_Impl()
214 : DdeTopic( DEFINE_CONST_UNICODE("TRIGGER") )
217 virtual sal_Bool
Execute( const String
* );
220 class SfxDdeDocTopic_Impl
: public DdeTopic
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
)
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.
257 rCmd = "Open(\"d:\doc\doc.sdw\")"
262 String
aEvent( rEvent
);
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(); )
277 aData
.remove( n
, 1 );
278 while ( n
< aData
.getLength() && aData
[n
] != '"' )
280 if ( n
< aData
.getLength() )
281 aData
.remove( n
, 1 );
292 rAppEvent
= ApplicationEvent(eType
, aData
.makeStringAndClear());
301 long SfxApplication::DdeExecute
303 const String
& rCmd
// Expressed in our BASIC-Syntax
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
);
324 // all others are BASIC
325 StarBASIC
* pBasic
= GetBasic();
326 DBG_ASSERT( pBasic
, "Where is the Basic???" );
327 SbxVariable
* pRet
= pBasic
->Execute( rCmd
);
330 SbxBase::ResetError();
338 long SfxObjectShell::DdeExecute
340 const String
& rCmd
// Expressed in our BASIC-Syntax
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
355 StarBASIC
* pBasic
= GetBasic();
356 DBG_ASSERT( pBasic
, "Where is the Basic???" ) ;
357 SbxVariable
* pRet
= pBasic
->Execute( rCmd
);
360 SbxBase::ResetError();
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
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.
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
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.
409 //--------------------------------------------------------------------
410 ::sfx2::SvLinkSource
* SfxObjectShell::DdeCreateLinkSource
412 const String
& // the Item to be addressed
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.
427 void SfxObjectShell::ReconnectDdeLink(SfxObjectShell
& /*rServer*/)
431 void SfxObjectShell::ReconnectDdeLinks(SfxObjectShell
& rServer
)
433 TypeId aType
= TYPE(SfxObjectShell
);
434 SfxObjectShell
* p
= GetFirst(&aType
, false);
438 p
->ReconnectDdeLink(rServer
);
440 p
= GetNext(*p
, &aType
, false);
444 //========================================================================
446 long SfxViewFrame::DdeExecute
448 const String
& rCmd
// Expressed in our BASIC-Syntax
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
);
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
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.
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
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.
511 //--------------------------------------------------------------------
513 ::sfx2::SvLinkSource
* SfxViewFrame::DdeCreateLinkSource
515 const String
& // the Item to be addressed
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.
530 //========================================================================
532 sal_Bool
SfxApplication::InitializeDde()
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();
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
);
562 void SfxAppData_Impl::DeInitDDE()
564 DELETEZ( pTriggerTopic
);
565 DELETEZ( pDdeService2
);
566 DELETEZ( pDocTopics
);
567 DELETEZ( pDdeService
);
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
)
578 // prevent double submit
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!
588 (sShellNm
= pSh
->GetTitle(SFX_TITLE_FULLNAME
)).ToLowerAscii();
590 String
sNm( (*pAppData_Impl
->pDocTopics
)[ n
]->GetName() );
591 if( sShellNm
== sNm
.ToLowerAscii() )
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
);
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
)
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
* )
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
);
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
);
655 if( aSeq
.getLength() )
657 ::com::sun::star::uno::Any aValue
;
659 String
sMimeType( SotExchange::GetFormatMimeType( pData
->GetFormat() ));
660 bRet
= 0 != pSh
->DdeSetData( GetCurItem(), sMimeType
, aValue
);
667 sal_Bool
SfxDdeDocTopic_Impl::Execute( const String
* pStr
)
669 long nRet
= pStr
? pSh
->DdeExecute( *pStr
) : 0;
673 sal_Bool
SfxDdeDocTopic_Impl::MakeItem( const String
& rItem
)
675 AddItem( DdeItem( rItem
) );
679 sal_Bool
SfxDdeDocTopic_Impl::StartAdviseLoop()
681 sal_Bool bRet
= sal_False
;
682 ::sfx2::SvLinkSource
* pNewObj
= pSh
->DdeCreateLinkSource( GetCurItem() );
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
);
694 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */