/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sfx2.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #ifndef GCC #endif #include #include "appdata.hxx" #include #include #include #include #include "sfxtypes.hxx" #include #include "helper.hxx" #include //======================================================================== String SfxDdeServiceName_Impl( const String& sIn ) { ByteString sTemp( sIn, RTL_TEXTENCODING_UTF8 ); ByteString sReturn; for ( sal_uInt16 n = sTemp.Len(); n; --n ) if ( sTemp.Copy( n-1, 1 ).IsAlphaNumericAscii() ) sReturn += sTemp.GetChar(n-1); return String( sReturn, RTL_TEXTENCODING_UTF8 ); } class ImplDdeService : public DdeService { public: ImplDdeService( const String& rNm ) : DdeService( rNm ) {} virtual sal_Bool MakeTopic( const String& ); virtual String Topics(); // virtual String Formats(); // virtual String SysItems(); // virtual String Status(); virtual sal_Bool SysTopicExecute( const String* pStr ); }; class SfxDdeTriggerTopic_Impl : public DdeTopic { public: SfxDdeTriggerTopic_Impl() : DdeTopic( DEFINE_CONST_UNICODE("TRIGGER") ) {} virtual sal_Bool Execute( const String* ); }; class SfxDdeDocTopic_Impl : public DdeTopic { public: SfxObjectShell* pSh; DdeData aData; ::com::sun::star::uno::Sequence< sal_Int8 > aSeq; SfxDdeDocTopic_Impl( SfxObjectShell* pShell ) : DdeTopic( pShell->GetTitle(SFX_TITLE_FULLNAME) ), pSh( pShell ) {} virtual DdeData* Get( sal_uIntPtr ); virtual sal_Bool Put( const DdeData* ); virtual sal_Bool Execute( const String* ); virtual sal_Bool StartAdviseLoop(); virtual sal_Bool MakeItem( const String& rItem ); // wird benoetigt? // virtual void Connect( long n ); // virtual void Disconnect( long n ); // virtual void StopAdviseLoop(); }; SV_DECL_PTRARR( SfxDdeDocTopics_Impl, SfxDdeDocTopic_Impl *, 4, 4 ) SV_IMPL_PTRARR( SfxDdeDocTopics_Impl, SfxDdeDocTopic_Impl *) //======================================================================== sal_Bool SfxAppEvent_Impl( ApplicationEvent &rAppEvent, const String &rCmd, const String &rEvent ) /* [Beschreibung] Pr"uft, ob 'rCmd' das Event 'rEvent' ist (ohne '(') und baut aus diesem dann ein zusammen, das per ausgef"uhrt werden kann. Ist 'rCmd' das angegegeben Event 'rEvent', dann wird TRUE zur"uckgegeben, sonst FALSE. [Beispiel] rCmd = "Open(\"d:\doc\doc.sdw\")" rEvent = "Open" */ { String aEvent( rEvent ); aEvent += '('; if ( rCmd.CompareIgnoreCaseToAscii( aEvent, aEvent.Len() ) == COMPARE_EQUAL ) { String aData( rCmd ); aData.Erase( 0, aEvent.Len() ); if ( aData.Len() > 2 ) { // in das ApplicationEvent-Format wandeln aData.Erase( aData.Len()-1, 1 ); for ( sal_uInt16 n = 0; n < aData.Len(); ++n ) { if ( aData.GetChar(n) == 0x0022 ) // " = 22h for ( ; aData.GetChar(++n) != 0x0022 ; ) /* empty loop */ ; else if ( aData.GetChar(n) == 0x0020 ) // SPACE = 20h aData.SetChar(n, '\n'); } aData.EraseAllChars( 0x0022 ); ApplicationAddress aAddr; rAppEvent = ApplicationEvent( String(), aAddr, ByteString( rEvent, RTL_TEXTENCODING_UTF8), aData ); return sal_True; } } return sal_False; } //------------------------------------------------------------------------- long SfxApplication::DdeExecute ( const String& rCmd // in unserer BASIC-Syntax formuliert ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seine SfxApplication-Subklasse gerichtete DDE-Kommandos zu empfangen. Die Basisimplementierung versteht die API-Funktionalit"at der betreffenden SfxApplication-Subklasse in BASIC-Syntax. R"uckgabewerte k"onnen dabei leider nicht "ubertragen werden. */ { // Print oder Open-Event? ApplicationEvent aAppEvent; if ( SfxAppEvent_Impl( aAppEvent, rCmd, DEFINE_CONST_UNICODE("Print") ) || SfxAppEvent_Impl( aAppEvent, rCmd, DEFINE_CONST_UNICODE("Open") ) ) GetpApp()->AppEvent( aAppEvent ); else { // alle anderen per BASIC StarBASIC* pBasic = GetBasic(); ENSURE_OR_RETURN( pBasic, "where's my basic?", 0 ); SbxVariable* pRet = pBasic->Execute( rCmd ); if( !pRet ) { SbxBase::ResetError(); return 0; } } return 1; } //-------------------------------------------------------------------- long SfxApplication::DdeGetData ( const String&, // das anzusprechende Item const String&, // in: Format ::com::sun::star::uno::Any& // out: angeforderte Daten ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seine SfxApplication-Subklasse gerichtete DDE-Daten-Anforderungen zu empfangen. Die Basisimplementierung liefert keine Daten und gibt 0 zur"uck. */ { return 0; } //-------------------------------------------------------------------- long SfxApplication::DdeSetData ( const String&, // das anzusprechende Item const String&, // in: Format const ::com::sun::star::uno::Any& // out: angeforderte Daten ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seine SfxApplication-Subklasse gerichtete DDE-Daten zu empfangen. Die Basisimplementierung nimmt keine Daten entgegen und liefert 0 zur"uck. */ { return 0; } //-------------------------------------------------------------------- ::sfx2::SvLinkSource* SfxApplication::DdeCreateLinkSource ( const String& // das zu erzeugende Item ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seiner SfxApplication-Subklasse einen DDE-Hotlink einzurichten Die Basisimplementierung erzeugt keinen und liefert 0 zur"uck. */ { return 0; } //======================================================================== long SfxObjectShell::DdeExecute ( const String& rCmd // in unserer BASIC-Syntax formuliert ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seine SfxObjectShell-Subklasse gerichtete DDE-Kommandos zu empfangen. Die Basisimplementierung f"uhrt nichts aus und liefert 0 zur"uck. */ { StarBASIC* pBasic = GetBasic(); DBG_ASSERT( pBasic, "Wo ist mein Basic???" ) ; SbxVariable* pRet = pBasic->Execute( rCmd ); if( !pRet ) { SbxBase::ResetError(); return 0; } return 1; } //-------------------------------------------------------------------- long SfxObjectShell::DdeGetData ( const String&, // das anzusprechende Item const String&, // in: Format ::com::sun::star::uno::Any& // out: angeforderte Daten ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seine SfxObjectShell-Subklasse gerichtete DDE-Daten-Anforderungen zu empfangen. Die Basisimplementierung liefert keine Daten und gibt 0 zur"uck. */ { return 0; } //-------------------------------------------------------------------- long SfxObjectShell::DdeSetData ( const String&, // das anzusprechende Item const String&, // in: Format const ::com::sun::star::uno::Any& // out: angeforderte Daten ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seine SfxObjectShell-Subklasse gerichtete DDE-Daten zu empfangen. Die Basisimplementierung nimmt keine Daten entgegen und liefert 0 zur"uck. */ { return 0; } //-------------------------------------------------------------------- ::sfx2::SvLinkSource* SfxObjectShell::DdeCreateLinkSource ( const String& // das zu erzeugende Item ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seiner SfxObjectShell-Subklasse einen DDE-Hotlink einzurichten Die Basisimplementierung erzeugt keinen und liefert 0 zur"uck. */ { return 0; } //======================================================================== long SfxViewFrame::DdeExecute ( const String& rCmd // in unserer BASIC-Syntax formuliert ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seine SfxViewFrame-Subklasse gerichtete DDE-Kommandos zu empfangen. Die Basisimplementierung versteht die API-Funktionalit"at des betreffenden SfxViewFrame, der darin dargestellten SfxViewShell und der betreffenden SfxObjectShell-Subklasse in BASIC-Syntax. R"uckgabewerte k"onnen dabei leider nicht "ubertragen werden. */ { if ( GetObjectShell() ) return GetObjectShell()->DdeExecute( rCmd ); return 0; } //-------------------------------------------------------------------- long SfxViewFrame::DdeGetData ( const String&, // das anzusprechende Item const String&, // in: Format ::com::sun::star::uno::Any& // out: angeforderte Daten ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seine SfxViewFrame-Subklasse gerichtete DDE-Daten-Anforderungen zu empfangen. Die Basisimplementierung liefert keine Daten und gibt 0 zur"uck. */ { return 0; } //-------------------------------------------------------------------- long SfxViewFrame::DdeSetData ( const String& , // das anzusprechende Item const String& , // in: Format const ::com::sun::star::uno::Any& // out: angeforderte Daten ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seine SfxViewFrame-Subklasse gerichtete DDE-Daten zu empfangen. Die Basisimplementierung nimmt keine Daten entgegen und liefert 0 zur"uck. */ { return 0; } //-------------------------------------------------------------------- ::sfx2::SvLinkSource* SfxViewFrame::DdeCreateLinkSource ( const String& // das zu erzeugende Item ) /* [Beschreibung] Diese Methode kann vom Applikationsentwickler "uberladen werden, um an seiner SfxViewFrame-Subklasse einen DDE-Hotlink einzurichten Die Basisimplementierung erzeugt keinen und liefert 0 zur"uck. */ { return 0; } //======================================================================== sal_Bool SfxApplication::InitializeDde() { DBG_ASSERT( !pAppData_Impl->pDdeService, "Dde kann nicht mehrfach initialisiert werden" ); pAppData_Impl->pDdeService = new ImplDdeService( Application::GetAppName() ); int nError = pAppData_Impl->pDdeService->GetError(); if( !nError ) { pAppData_Impl->pDocTopics = new SfxDdeDocTopics_Impl; // wir wollen auf jedenfall RTF unterstuetzen! pAppData_Impl->pDdeService->AddFormat( FORMAT_RTF ); // Config-Pfad als Topic wegen Mehrfachstart INetURLObject aOfficeLockFile( SvtPathOptions().GetUserConfigPath() ); aOfficeLockFile.insertName( DEFINE_CONST_UNICODE( "soffice.lck" ) ); String aService( SfxDdeServiceName_Impl( aOfficeLockFile.GetMainURL(INetURLObject::DECODE_TO_IURI) ) ); aService.ToUpperAscii(); pAppData_Impl->pDdeService2 = new ImplDdeService( aService ); pAppData_Impl->pTriggerTopic = new SfxDdeTriggerTopic_Impl; pAppData_Impl->pDdeService2->AddTopic( *pAppData_Impl->pTriggerTopic ); } return !nError; } void SfxAppData_Impl::DeInitDDE() { DELETEZ( pTriggerTopic ); DELETEZ( pDdeService2 ); DELETEZ( pDocTopics ); DELETEZ( pDdeService ); } //-------------------------------------------------------------------- void SfxApplication::AddDdeTopic( SfxObjectShell* pSh ) { DBG_ASSERT( pAppData_Impl->pDocTopics, "es gibt gar keinen Dde-Service" ); //OV: Im Serverbetrieb ist DDE abgeklemmt! if( !pAppData_Impl->pDocTopics ) return; // doppeltes Eintragen verhindern String sShellNm; sal_Bool bFnd = sal_False; for( sal_uInt16 n = pAppData_Impl->pDocTopics->Count(); n; ) if( (*pAppData_Impl->pDocTopics)[ --n ]->pSh == pSh ) { // JP 18.03.96 - Bug 26470 // falls das Document unbenannt wurde, ist trotzdem ein // neues Topics anzulegen! if( !bFnd ) { bFnd = sal_True; (sShellNm = pSh->GetTitle(SFX_TITLE_FULLNAME)).ToLowerAscii(); } String sNm( (*pAppData_Impl->pDocTopics)[ n ]->GetName() ); if( sShellNm == sNm.ToLowerAscii() ) return ; } const SfxDdeDocTopic_Impl* pTopic = new SfxDdeDocTopic_Impl( pSh ); pAppData_Impl->pDocTopics->Insert( pTopic, pAppData_Impl->pDocTopics->Count() ); pAppData_Impl->pDdeService->AddTopic( *pTopic ); } void SfxApplication::RemoveDdeTopic( SfxObjectShell* pSh ) { DBG_ASSERT( pAppData_Impl->pDocTopics, "es gibt gar keinen Dde-Service" ); //OV: Im Serverbetrieb ist DDE abgeklemmt! if( !pAppData_Impl->pDocTopics ) return; SfxDdeDocTopic_Impl* pTopic; for( sal_uInt16 n = pAppData_Impl->pDocTopics->Count(); n; ) if( ( pTopic = (*pAppData_Impl->pDocTopics)[ --n ])->pSh == pSh ) { pAppData_Impl->pDdeService->RemoveTopic( *pTopic ); pAppData_Impl->pDocTopics->DeleteAndDestroy( n ); } } const DdeService* SfxApplication::GetDdeService() const { return pAppData_Impl->pDdeService; } DdeService* SfxApplication::GetDdeService() { return pAppData_Impl->pDdeService; } //-------------------------------------------------------------------- sal_Bool ImplDdeService::MakeTopic( const String& rNm ) { // Workaround gegen Event nach unserem Main() unter OS/2 // passierte wenn man beim Beenden aus dem OffMgr die App neu startet if ( !Application::IsInExecute() ) return sal_False; // das Topic rNm wird gesucht, haben wir es ? // erstmal nur ueber die ObjectShells laufen und die mit dem // Namen heraussuchen: sal_Bool bRet = sal_False; String sNm( rNm ); sNm.ToLowerAscii(); TypeId aType( TYPE(SfxObjectShell) ); SfxObjectShell* pShell = SfxObjectShell::GetFirst( &aType ); while( pShell ) { String sTmp( pShell->GetTitle(SFX_TITLE_FULLNAME) ); sTmp.ToLowerAscii(); if( sTmp == sNm ) // die wollen wir haben { SFX_APP()->AddDdeTopic( pShell ); bRet = sal_True; break; } pShell = SfxObjectShell::GetNext( *pShell, &aType ); } if( !bRet ) { INetURLObject aWorkPath( SvtPathOptions().GetWorkPath() ); INetURLObject aFile; if ( aWorkPath.GetNewAbsURL( rNm, &aFile ) && SfxContentHelper::IsDocument( aFile.GetMainURL( INetURLObject::NO_DECODE ) ) ) { // File vorhanden // dann versuche die Datei zu laden: SfxStringItem aName( SID_FILE_NAME, aFile.GetMainURL( INetURLObject::NO_DECODE ) ); SfxBoolItem aNewView(SID_OPEN_NEW_VIEW, sal_True); SfxBoolItem aSilent(SID_SILENT, sal_True); SfxDispatcher* pDispatcher = SFX_APP()->GetDispatcher_Impl(); const SfxPoolItem* pRet = pDispatcher->Execute( SID_OPENDOC, SFX_CALLMODE_SYNCHRON, &aName, &aNewView, &aSilent, 0L ); if( pRet && pRet->ISA( SfxViewFrameItem ) && ((SfxViewFrameItem*)pRet)->GetFrame() && 0 != ( pShell = ((SfxViewFrameItem*)pRet) ->GetFrame()->GetObjectShell() ) ) { SFX_APP()->AddDdeTopic( pShell ); bRet = sal_True; } } } return bRet; } String ImplDdeService::Topics() { String sRet; if( GetSysTopic() ) sRet += GetSysTopic()->GetName(); TypeId aType( TYPE(SfxObjectShell) ); SfxObjectShell* pShell = SfxObjectShell::GetFirst( &aType ); while( pShell ) { if( SfxViewFrame::GetFirst( pShell ) ) { if( sRet.Len() ) sRet += '\t'; sRet += pShell->GetTitle(SFX_TITLE_FULLNAME); } pShell = SfxObjectShell::GetNext( *pShell, &aType ); } if( sRet.Len() ) sRet += DEFINE_CONST_UNICODE("\r\n"); return sRet; } sal_Bool ImplDdeService::SysTopicExecute( const String* pStr ) { return (sal_Bool)SFX_APP()->DdeExecute( *pStr ); } //-------------------------------------------------------------------- sal_Bool SfxDdeTriggerTopic_Impl::Execute( const String* ) { return sal_True; } //-------------------------------------------------------------------- DdeData* SfxDdeDocTopic_Impl::Get( sal_uIntPtr nFormat ) { String sMimeType( SotExchange::GetFormatMimeType( nFormat )); ::com::sun::star::uno::Any aValue; long nRet = pSh->DdeGetData( GetCurItem(), sMimeType, aValue ); if( nRet && aValue.hasValue() && ( aValue >>= aSeq ) ) { aData = DdeData( aSeq.getConstArray(), aSeq.getLength(), nFormat ); return &aData; } aSeq.realloc( 0 ); return 0; } sal_Bool SfxDdeDocTopic_Impl::Put( const DdeData* pData ) { aSeq = ::com::sun::star::uno::Sequence< sal_Int8 >( (sal_Int8*)(const void*)*pData, (long)*pData ); sal_Bool bRet; if( aSeq.getLength() ) { ::com::sun::star::uno::Any aValue; aValue <<= aSeq; String sMimeType( SotExchange::GetFormatMimeType( pData->GetFormat() )); bRet = 0 != pSh->DdeSetData( GetCurItem(), sMimeType, aValue ); } else bRet = sal_False; return bRet; } sal_Bool SfxDdeDocTopic_Impl::Execute( const String* pStr ) { long nRet = pStr ? pSh->DdeExecute( *pStr ) : 0; return 0 != nRet; } sal_Bool SfxDdeDocTopic_Impl::MakeItem( const String& rItem ) { AddItem( DdeItem( rItem ) ); return sal_True; } sal_Bool SfxDdeDocTopic_Impl::StartAdviseLoop() { sal_Bool bRet = sal_False; ::sfx2::SvLinkSource* pNewObj = pSh->DdeCreateLinkSource( GetCurItem() ); if( pNewObj ) { // dann richten wir auch einen entsprechenden SvBaseLink ein String sNm, sTmp( Application::GetAppName() ); ::sfx2::MakeLnkName( sNm, &sTmp, pSh->GetTitle(SFX_TITLE_FULLNAME), GetCurItem() ); new ::sfx2::SvBaseLink( sNm, OBJECT_DDE_EXTERN, pNewObj ); bRet = sal_True; } return bRet; }