实现
协议处理器实现必须遵循服务定义 com.sun.star.frame.ProtocolHandler。至少必须支持 com.sun.star.frame.XDispatchProvider 接口。
XDispatchProvider
接口支持两个方法:
XDispatch queryDispatch( [in] ::com::sun::star::util::URL URL, [in] string TargetFrameName, [in] long SearchFlags ) sequence< XDispatch > queryDispatches( [in] sequence< DispatchDescriptor > Requests )
通过调用接口方法 com.sun.star.frame.XDispatchProvider:queryDispatch(),要求协议处理器同意执行给定的 URL。传入的 URL 应该进行解析和验证。如果 URL 有效,协议处理器可以处理它,则它应返回分发对象,以此表明它接受请求。
分发对象必须通过以下方法支持 com.sun.star.frame.XDispatch 接口
[oneway] void dispatch( [in] ::com::sun::star::util::URL URL, [in] sequence< ::com::sun::star::beans::PropertyValue > Arguments ) addStatusListener [oneway] void addStatusListener( [in] XStatusListener Control, [in] ::com::sun::star::util::URL URL ) removeStatusListener [oneway] void removeStatusListener( [in] XStatusListener Control, [in] ::com::sun::star::util::URL URL )
另外,分发对象还可以支持 com.sun.star.frame.XNotifyingDispatch 接口,该接口从 XDispatch
导出,并引入一个新方法 dispatchWithNotification()
。如果存在,应该首选使用此接口。
[oneway] void dispatchWithNotification( [in] com::sun::star::util::URL URL, [in] sequence<com::sun::star::beans::PropertyValue> Arguments, [in] com::sun::star::frame::XDispatchResultListener Listener);
基本的协议处理器可以自由实现 XDispatch,因此可以在 queryDispatch()
实现中返回其自身。但是建议返回专用的帮助程序分发对象,而不是协议处理器实例。这有助于降低状态更新的复杂性。通知单用分发对象的状态侦听器比通知多用分发对象的状态侦听器更容易,后者必须始终区分在 addStatusListener()
中给定的 URL。
要向 UI 提供命令的状态信息,需要在其注册期间立即回调 com.sun.star.frame.XStatusListener,例如:
public void addStatusListener(XStatusListener xControl, URL aURL) { FeatureStateEvent aState = new FeatureStateEvent(); aState.FeatureURL = aURL; aState.IsEnabled = true; aState.State = Boolean.TRUE; xControl.statusChanged(aState); m_lListenerContainer.add(xControl); } |
如果要使用与其一起工作的 com.sun.star.frame.Frame 环境进行初始化,协议处理器可以支持 void initialize( [in] sequence< any > aArguments )
协议处理器通常用于已知的 com.sun.star.frame.Frame.html" class="external text">com.sun.star.lang.XInitialization 接口。XInitialization 包含一个方法:
void initialize( [in] sequence< any > aArguments )
协议处理器通常用于已知的 com.sun.star.frame.Frame 上下文,因此如果存在 XInitialization
,分发框架总是通过 initialize()
将此框架上下文作为第一个参数传送。其 com.sun.star.frame.XFrame 接口提供了对控制器的访问,通过此控制器可以获取文档模型并顺利地开始处理文档。
以下插图显示了如何从 XFrame 接口获取控制器和文档模型。办公软件开发 - OpenOffice.org 应用环境 - 使用组件框架 将详细介绍框架(Frame)、控制器(Control)和模型(Model)的用法。
由于可以拒绝 queryDispatch()
调用,因此您可以使用占位符注册 URL 模式的协议处理器,并只接受所有可能的 URL 的子集。这样,处理器对象可以验证传入的 URL,如果无效则拒绝这些 URL。但是,此功能不能用于注册同一 URL 模式的不同协议处理器并由不同的处理器对象接受不同的子集,因为很难避免模糊性。
由于协议处理器是一个 UNO 组件,它必须包含 UNO 服务管理器所需的组件操作,这些操作是 Java 中的特定静态方法或 C++ 中的导出函数。它还必须实现用于启用与 UNO 和应用程序环境通信的核心接口。如果需要有关组件操作和核心接口的更多信息,请参阅 编写 UNO 组件 - 组件的体系结构 和 编写 UNO 组件 - 可实现的核心接口。
Java 协议处理器 - vnd.sun.star.framework.ExampleHandler
以下示例显示了 Java 中的一个简单的协议处理器实现。为简单起见,忽略了组件操作。
// imports #import com.sun.star.beans.*; #import com.sun.star.frame.*; #import com.sun.star.uno.*; #import com.sun.star.util.*; // definition public class ExampleHandler implements com.sun.star.frame.XDispatchProvider, com.sun.star.lang.XInitialization { // member /** points to the frame context in which this handler runs, is set in initialize()*/ private com.sun.star.frame.XFrame m_xContext; // Dispatch object as inner class class OwnDispatch implements com.sun.star.frame.XDispatch { /** the target frame, in which context this dispatch must work */ private com.sun.star.frame.XFrame m_xContext; /** describe the function of this dispatch. * Because a URL can contain e.g. optional arguments * this URL means the main part of such URL sets only. */ private com.sun.star.util.URL m_aMainURL; /** contains all interested status listener for this dispatch */ private java.lang.HashMap m_lListener; /** take over all neccessary parameters from outside. */ public OwnDispatch(com.sun.star.frame.XFrame xContext, com.sun.star.util.URL aMainURL) { m_xContext = xContext; m_aMainURL = aMainURL; } /** execute the functionality, which is described by this URL. * * @param aURL * this URL can describe the main function, we already know; * but it can specify a sub function too! But queryDispatch() * and dispatch() are used in a generic way ... * m_aMainURL and aURL will be the same. * * @param lArgs * optional arguments for this request */ public void dispatch(com.sun.star.util.URL aURL, com.sun.star.beans.PropertyValue lArgs) throws com.sun.star.uno.RuntimeException { // ... do function // ... inform listener if necessary } /** register a new listener and bind it toe given URL. * * Note: Because the listener does not know the current state * and may nobody change it next time, it is neccessary to inform it * immediately about this current state. So the listener is up to date. */ public void addStatusListener(com.sun.star.frame.XStatusListener xListener, com.sun.star.util.URL aURL) throws com.sun.star.uno.RuntimeException { // ... register listener for given URL // ... inform it immediatly about current state! xListener.statusChanged(...); } /** deregister a listener for this URL. */ public void removeStatusListener(com.sun.star.frame.XStatusListener xListener, com.sun.star.util.URLaURL) throws com.sun.star.uno.RuntimeException { // ... deregister listener for given URL } } /** set the target frame reference as context for all following dispatches. */ public void initialize(com.sun.star.uno.Any[] lContext) { m_xContext = (com.sun.star.frame.XFrame)com.sun.star.uno.AnyConverter.toObject(lContext[0]); } /** should return a valid dispatch object for the given URL. * * In case the URL is not valid an empty reference can be returned. * The parameter sTarget and nFlags can be ignored. The will be "_self" and 0 * everytime. */ public com.sun.star.frame.XDispatch queryDispatch(com.sun.star.util.URL aURL, java.lang.String sTarget, int nFlags ) throws com.sun.star.uno.RuntimeException { // check if given URL is valid for this protocol handler if (!aURL.Main.startsWith("myProtocol_1://") && !aURL.Main.startsWith("myProtocol_2://")) return null; // and return a specialized dispatch object // Of course "return this" would be possible too ... return (com.sun.star.frame.XDispatch)(new OwnDispatch(m_xContext, aURL)); } /** optimized API call for remote. * * It should be forwarded to queryDispatch() for every request item of the * given DispatchDescriptor list. * * But note: it is not allowed to pack the return list of dispatch objects. * Every request in source list must match to a reference (null or valid) in * the destination list! */ public com.sun.star.frame.XDispatch[] queryDispatches( com.sun.star.frame.DispatchDescriptor[] lRequests) throws com.sun.star.uno.RuntimeException { int c = lRequests.length; com.sun.star.frame.XDispatch[] lDispatches = new com.sun.star.frame.XDispatch[c]; for (int i=0; i<c; ++i) lDispatches[i] = queryDispatch(lRequests[i].FeatureURL, lRequests[i].FrameName, lRequests[i].SearchFlags); return lDispatches; } }
C++ Protocol Handler - org.openoffice.Office.addon.example
以下示例显示了 C++ 中的协议处理器。下面的 编写 UNO 组件 - 将组件集成到 OpenOffice.org - 插件的用户接口 将把此示例处理器集成到 OpenOffice.org 的图形用户界面。
以下代码显示了必须在 C++ 协议处理器示例中实现的 UNO 组件操作。三个 C 函数将重要信息返回到 UNO 环境:
-
component_getImplementationEnvironment()
通知共享库组件加载程序使用哪个编译程序建立库。 -
component_writeInfo()
由注册工具 regcomp 在注册过程中调用,或者在使用扩展管理器时间接调用。
-
component_getFactory()
提供用于请求的实现的单服务工厂。可以用此工厂只为一个服务规范创建任意数量的实例,因此它被称为单服务工厂,这与多服务工厂相反,后者可以为许多不同的服务规范创建实例。(单服务工厂与单一元素无关)。
#include <stdio.h> #ifndef _RTL_USTRING_HXX_ #include <rtl/ustring.hxx> #endif #ifndef _CPPUHELPER_QUERYINTERFACE_HXX_ #include <cppuhelper/queryinterface.hxx> // helper for queryInterface() impl #endif #ifndef _CPPUHELPER_FACTORY_HXX_ #include <cppuhelper/factory.hxx> // helper for component factory #endif // generated c++ interfaces #ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_ #include <com/sun/star/lang/XSingleServiceFactory.hpp> #endif #ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_ #include <com/sun/star/lang/XMultiServiceFactory.hpp> #endif #ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_ #include <com/sun/star/lang/XServiceInfo.hpp> #endif #ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HPP_ #include <com/sun/star/registry/XRegistryKey.hpp> #endif // include our specific addon header to get access to functions and definitions #include <addon.hxx> using namespace ::rtl; using namespace ::osl; using namespace ::cppu; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::lang; using namespace ::com::sun::star::registry; //################################################################################################## //#### EXPORTED #################################################################################### //################################################################################################## /** * Gives the environment this component belongs to. */ extern "C" void SAL_CALL component_getImplementationEnvironment(const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv) { *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; } /** * This function creates an implementation section in the registry and another subkey * * for each supported service. * @param pServiceManager the service manager * @param pRegistryKey the registry key */ extern "C" sal_Bool SAL_CALL component_writeInfo(void * pServiceManager, void * pRegistryKey) { sal_Bool result = sal_False; if (pRegistryKey) { try { Reference< XRegistryKey > xNewKey( reinterpret_cast< XRegistryKey * >( pRegistryKey )->createKey( OUString( RTL_CONSTASCII_USTRINGPARAM("/" IMPLEMENTATION_NAME "/UNO/SERVICES")) ) ); const Sequence< OUString > & rSNL = Addon_getSupportedServiceNames(); const OUString * pArray = rSNL.getConstArray(); for ( sal_Int32 nPos = rSNL.getLength(); nPos--; ) xNewKey->createKey( pArray[nPos] ); return sal_True; } catch (InvalidRegistryException &) { // we should not ignore exceptions } } return result; } /** * This function is called to get service factories for an implementation. * * @param pImplName name of implementation * @param pServiceManager a service manager, need for component creation * @param pRegistryKey the registry key for this component, need for persistent data * @return a component factory */ extern "C" void * SAL_CALL component_getFactory(const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey) { void * pRet = 0; if (rtl_str_compare( pImplName, IMPLEMENTATION_NAME ) == 0) { Reference< XSingleServiceFactory > xFactory(createSingleFactory( reinterpret_cast< XMultiServiceFactory * >(pServiceManager), OUString(RTL_CONSTASCII_USTRINGPARAM(IMPLEMENTATION_NAME)), Addon_createInstance, Addon_getSupportedServiceNames())); if (xFactory.is()) { xFactory->acquire(); pRet = xFactory.get(); } } return pRet; } //################################################################################################## //#### Helper functions for the implementation of UNO component interfaces ######################### //################################################################################################## ::rtl::OUString Addon_getImplementationName() throw (RuntimeException) { return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( IMPLEMENTATION_NAME ) ); } sal_Bool SAL_CALL Addon_supportsService( const ::rtl::OUString& ServiceName ) throw (RuntimeException) { return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( SERVICE_NAME ) ); } Sequence< ::rtl::OUString > SAL_CALL Addon_getSupportedServiceNames() throw (RuntimeException) { Sequence < ::rtl::OUString > aRet(1); ::rtl::OUString* pArray = aRet.getArray(); pArray[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( SERVICE_NAME ) ); return aRet; } Reference< XInterface > SAL_CALL Addon_createInstance( const Reference< XMultiServiceFactory > & rSMgr) throw( Exception ) { return (cppu::OWeakObject*) new Addon( rSMgr ); }
示例中的 C++ 协议处理器的实现名称为 org.openoffice.Office.addon.example
。它支持 URL 协议模式 org.openoffice.Office.addon.example: 并提供三个不同的 URL 命令:Function1
、Function2
和 Help
。
协议处理器可以实现 com.sun.star.frame.XDispatch 接口,因此在协议处理器中查询匹配给定 URL 的分发对象时,它可以返回对其自身的引用。
下面的 dispatch()
方法的实现显示了如何在协议处理器内部路由支持的命令。根据 URL 的路径部分,一个简单的消息框将显示已调用的函数。消息框使用 UNO 工具包实现,并将给定框架的容器窗口作为父窗口。
#ifndef _Addon_HXX #include <addon.hxx> #endif #ifndef _OSL_DIAGNOSE_H_ #include <osl/diagnose.h> #endif #ifndef _RTL_USTRING_HXX_ #include <rtl/ustring.hxx> #endif #ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_ #include <com/sun/star/lang/XMultiServiceFactory.hpp> #endif #ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_ #include <com/sun/star/beans/PropertyValue.hpp> #endif #ifndef _COM_SUN_STAR_FRAME_XFRAME_HPP_ #include <com/sun/star/frame/XFrame.hpp> #endif #ifndef _COM_SUN_STAR_FRAME_XCONTROLLER_HPP_ #include <com/sun/star/frame/XController.hpp> #endif #ifndef _COM_SUN_STAR_AWT_XTOOLKIT_HPP_ #include <com/sun/star/awt/XToolkit.hpp> #endif #ifndef _COM_SUN_STAR_AWT_XWINDOWPEER_HPP_ #include <com/sun/star/awt/XWindowPeer.hpp> #endif #ifndef _COM_SUN_STAR_AWT_WINDOWATTRIBUTE_HPP_ #include <com/sun/star/awt/WindowAttribute.hpp> #endif #ifndef _COM_SUN_STAR_AWT_XMESSAGEBOX_HPP_ #include <com/sun/star/awt/XMessageBox.hpp> #endif using rtl::OUString; using namespace com::sun::star::uno; using namespace com::sun::star::frame; using namespace com::sun::star::awt; using com::sun::star::lang::XMultiServiceFactory; using com::sun::star::beans::PropertyValue; using com::sun::star::util::URL; // This is the service name an Add-On has to implement #define SERVICE_NAME "com.sun.star.frame.ProtocolHandler" /** * Show a message box with the UNO based toolkit */ static void ShowMessageBox(const Reference< XToolkit >& rToolkit, const Reference< XFrame >& rFrame, const OUString& aTitle, const OUString& aMsgText) { if ( rFrame.is() && rToolkit.is() ) { // describe window properties. WindowDescriptor aDescriptor; aDescriptor.Type = WindowClass_MODALTOP ; aDescriptor.WindowServiceName = OUString( RTL_CONSTASCII_USTRINGPARAM( "infobox" )); aDescriptor.ParentIndex = -1 ; aDescriptor.Parent = Reference< XWindowPeer >( rFrame->getContainerWindow(), UNO_QUERY ) ; aDescriptor.Bounds = Rectangle(0,0,300,200) ; aDescriptor.WindowAttributes = WindowAttribute::BORDER | WindowAttribute::MOVEABLE | WindowAttribute::CLOSEABLE; Reference< XWindowPeer > xPeer = rToolkit->createWindow( aDescriptor ); if ( xPeer.is() ) { Reference< XMessageBox > xMsgBox( xPeer, UNO_QUERY ); if ( xMsgBox.is() ) { xMsgBox->setCaptionText( aTitle ); xMsgBox->setMessageText( aMsgText ); xMsgBox->execute(); } } } } //################################################################################################## //#### Implementation of the ProtocolHandler and Dispatch Interfaces ################### //################################################################################################## // XInitialization /** * Called by the Office framework. * We store the context information * given, like the frame we are bound to, into our members. */ void SAL_CALL Addon::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException) { Reference < XFrame > xFrame; if ( aArguments.getLength() ) { aArguments[0] >>= xFrame; mxFrame = xFrame; } // Create the toolkit to have access to it later mxToolkit = Reference< XToolkit >( mxMSF->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.Toolkit" ))), UNO_QUERY ); } // XDispatchProvider /** * Called by the Office framework. * We are ask to query the given URL and return a dispatch object if the URL * contains an Add-On command. */ Reference< XDispatch > SAL_CALL Addon::queryDispatch( const URL& aURL, const ::rtl::OUString& sTargetFrameName, sal_Int32 nSearchFlags ) throw( RuntimeException ) { Reference < XDispatch > xRet; if ( aURL.Protocol.compareToAscii("org.openoffice.Office.addon.example:") == 0 ) { if ( aURL.Path.compareToAscii( "Function1" ) == 0 ) xRet = this; else if ( aURL.Path.compareToAscii( "Function2" ) == 0 ) xRet = this; else if ( aURL.Path.compareToAscii( "Help" ) == 0 ) xRet = this; } return xRet; } /** * Called by the Office framework. * We are ask to query the given sequence of URLs and return dispatch objects if the URLs * contain Add-On commands. */ Sequence < Reference< XDispatch > > SAL_CALL Addon::queryDispatches( const Sequence < DispatchDescriptor >& seqDescripts ) throw( RuntimeException ) { sal_Int32 nCount = seqDescripts.getLength(); Sequence < Reference < XDispatch > > lDispatcher( nCount ); for( sal_Int32 i=0; i<nCount; ++i ) lDispatcher[i] = queryDispatch( seqDescripts[i].FeatureURL, seqDescripts[i].FrameName, seqDescripts[i].SearchFlags ); return lDispatcher; } // XDispatch /** * Called by the Office framework. * We are ask to execute the given Add-On command URL. */ void SAL_CALL Addon::dispatch( const URL& aURL, const Sequence < PropertyValue >& lArgs ) throw (RuntimeException) { if ( aURL.Protocol.compareToAscii("org.openoffice.Office.addon.example:") == 0 ) { if ( aURL.Path.compareToAscii( "Function1" ) == 0 ) { ShowMessageBox( mxToolkit, mxFrame, OUString( RTL_CONSTASCII_USTRINGPARAM( "SDK Add-On example" )), OUString( RTL_CONSTASCII_USTRINGPARAM( "Function 1 activated" )) ); } else if ( aURL.Path.compareToAscii( "Function2" ) == 0 ) { ShowMessageBox( mxToolkit, mxFrame, OUString( RTL_CONSTASCII_USTRINGPARAM( "SDK Add-On example" )), OUString( RTL_CONSTASCII_USTRINGPARAM( "Function 2 activated" )) ); } else if ( aURL.Path.compareToAscii( "Help" ) == 0 ) { // Show info box ShowMessageBox( mxToolkit, mxFrame, OUString( RTL_CONSTASCII_USTRINGPARAM( "About SDK Add-On example" )), OUString( RTL_CONSTASCII_USTRINGPARAM( "This is the SDK Add-On example"))); } } } /** * Called by the Office framework. * We are asked to store a status listener for the given URL. */ void SAL_CALL Addon::addStatusListener( const Reference< XStatusListener >& xControl, const URL& aURL ) throw (RuntimeException) { } /** * Called by the Office framework. * We are asked to remove a status listener for the given URL. */ void SAL_CALL Addon::removeStatusListener( const Reference< XStatusListener >& xControl, const URL& aURL ) throw (RuntimeException) { } //################################################################################################## //#### Implementation of the recommended/mandatory interfaces of a UNO component ################### //################################################################################################## // XServiceInfo ::rtl::OUString SAL_CALL Addon::getImplementationName( ) throw (RuntimeException) { return Addon_getImplementationName(); } sal_Bool SAL_CALL Addon::supportsService( const ::rtl::OUString& rServiceName ) throw (RuntimeException) { return Addon_supportsService( rServiceName ); } Sequence< ::rtl::OUString > SAL_CALL Addon::getSupportedServiceNames( ) throw (RuntimeException) { return Addon_getSupportedServiceNames(); }
Content on this page is licensed under the Public Documentation License (PDL). |