From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- .../OfficeDev/DesktopEnvironment/Interceptor.java | 655 +++++++++++++++++++++ 1 file changed, 655 insertions(+) create mode 100644 odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Interceptor.java (limited to 'odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Interceptor.java') diff --git a/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Interceptor.java b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Interceptor.java new file mode 100644 index 000000000..380f8da3c --- /dev/null +++ b/odk/examples/DevelopersGuide/OfficeDev/DesktopEnvironment/Interceptor.java @@ -0,0 +1,655 @@ +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * + * The Contents of this file are made available subject to the terms of + * the BSD license. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +// Imports + +import java.util.ArrayList; + +import com.sun.star.frame.FrameActionEvent; +import com.sun.star.uno.UnoRuntime; + +// Implementation + +/* + * This class can be used to intercept dispatched URL's + * on any frame used in this demo application. + * It intercept all URL's which try to create a new empty frame. + * (e.g. "private:factory/swriter") + * Nobody can guarantee that this interception will be really used - + * because another interceptor (registered at a later time then this one!) + * will be called before this one. + * Implementation is executed inside a new thread to prevent application + * against possible deadlocks. This deadlocks can occur if + * synchronous/asynchronous ... normal ones and oneway calls are mixed. + * Notifications of listener will be oneway mostly - her reactions can + * be synchronous then. => deadlocks are possible + */ +public class Interceptor implements com.sun.star.frame.XFrameActionListener, + com.sun.star.frame.XDispatchProviderInterceptor, + com.sun.star.frame.XDispatch, + com.sun.star.frame.XInterceptorInfo, + IShutdownListener, + IOnewayLink +{ + + + /** + * const + * All these URL's are intercepted by this implementation. + */ + private static final String[] INTERCEPTED_URLS = { "private:factory/*" , + ".uno:SaveAs" , + "slot:5300" , + ".uno:Quit" }; + + + + /* + * @member m_xMaster use this interceptor if he doesn't handle queried dispatch request + * @member m_xSlave we can forward all unhandled requests to this slave interceptor + * @member m_xFrame intercepted frame + * @member m_bDead there exist more than one way to finish an object of this class - we must know it sometimes + */ + private com.sun.star.frame.XDispatchProvider m_xMaster ; + private com.sun.star.frame.XDispatchProvider m_xSlave ; + private com.sun.star.frame.XFrame m_xFrame ; + private boolean m_bIsActionListener ; + private boolean m_bIsRegistered ; + private boolean m_bDead ; + + + + /* + * ctor + * Initialize the new interceptor. Given frame reference can be used to + * register this interceptor on it automatically later. + * + * @seealso startListening() + * + * @param xFrame + * this interceptor will register himself at this frame to intercept dispatched URLs + */ + Interceptor(/*IN*/ com.sun.star.frame.XFrame xFrame) + { + m_xFrame = xFrame ; + m_xSlave = null ; + m_xMaster = null ; + m_bIsRegistered = false ; + m_bIsActionListener = false ; + m_bDead = false ; + } + + + + /* + * start working as frame action listener really. + * We will be frame action listener here. In case + * we get a frame action which indicates, that we should + * update our interception. Because such using of an interceptor + * isn't guaranteed - in case a newer one was registered... + */ + public void startListening() + { + com.sun.star.frame.XFrame xFrame = null; + synchronized(this) + { + if (m_bDead) + return; + if (m_xFrame==null) + return; + if (m_bIsActionListener) + return; + xFrame = m_xFrame; + } + m_xFrame.addFrameActionListener(this); + synchronized(this) + { + m_bIsActionListener=true; + } + } + + + + /* + * In case we got a oneway listener callback - we had to use the office + * asynchronous then. This method is the callback from the started thread + * (started inside the original oneway method). We found all parameters of + * the original request packed inside a vector. Here we unpack it and + * call the right internal helper method, which implements the right + * functionality. + * + * @seealso frameAction() + * @seealso dispatch() + * + * @param nRequest + * indicates, which was the original request (identifies the + * original called method) + * + * @param lParams + * the vector with all packed parameters of the original request + */ + public void execOneway(/*IN*/ int nRequest,/*IN*/ ArrayList lParams ) + { + synchronized(this) + { + if (m_bDead) + return; + } + + // was it frameAction()? + if (nRequest==OnewayExecutor.REQUEST_FRAMEACTION) + { + impl_frameAction((FrameActionEvent) lParams.get(0)); + } + else + // was it dispatch()? + if (nRequest==OnewayExecutor.REQUEST_DISPATCH) + { + com.sun.star.util.URL[] lOutURL = new com.sun.star.util.URL[1]; + com.sun.star.beans.PropertyValue[][] lOutProps = new com.sun.star.beans.PropertyValue[1][]; + + OnewayExecutor.decodeDispatch( + lParams , + lOutURL , + lOutProps ); + impl_dispatch(lOutURL[0],lOutProps[0]); + } + } + + + + /* + * callback for frame action events + * We use it to update our interception. Because if a new component was loaded into + * the frame or another interceptor was registered, we should refresh our connection + * to the frame. Otherwise we can't guarantee full functionality here. + * + * Note: Don't react synchronous in an asynchronous listener callback. So use a thread + * here to update anything. + * + * @seealso impl_frameAction() + * + * @param aEvent + * describes the action + */ + public /*ONEWAY*/ void frameAction(/*IN*/ com.sun.star.frame.FrameActionEvent aEvent) + { + synchronized(this) + { + if (m_bDead) + return; + } + + boolean bHandle = false; + switch(aEvent.Action.getValue()) + { + case com.sun.star.frame.FrameAction.COMPONENT_ATTACHED_value : bHandle=true; break; + case com.sun.star.frame.FrameAction.COMPONENT_DETACHING_value : bHandle=true; break; + case com.sun.star.frame.FrameAction.COMPONENT_REATTACHED_value : bHandle=true; break; + // Don't react for CONTEXT_CHANGED here. Ok it indicates, that may another interceptor + // was registered at the frame ... but if we register ourself there - we get a context + // changed too :-( Best way to produce a never ending recursion ... + // May be that somewhere find a safe mechanism to detect own produced frame action events + // and ignore it. + case com.sun.star.frame.FrameAction.CONTEXT_CHANGED_value : + System.out.println("Time to update interception ... but may it will start a recursion. So I let it :-("); + bHandle=false; + break; + } + + // ignore some events + if (! bHandle) + return; + + // pack the event and start thread - which call us back later + ArrayList lOutParams = new ArrayList(); + lOutParams.add(aEvent); + + OnewayExecutor aExecutor = new OnewayExecutor( this , + OnewayExecutor.REQUEST_FRAMEACTION , + lOutParams ); + aExecutor.start(); + } + + + + /* + * Indicates using of us as an interceptor. + * Now we have to react for the requests, we are registered. + * That means: load new empty documents - triggered by the new menu of the office. + * Because it's oneway - use thread for loading! + * + * @seealso impl_dispatch() + * + * @param aURL + * describes the document, which should be loaded + * + * @param lArguments + * optional parameters for loading + */ + public /*ONEWAY*/ void dispatch(/*IN*/ com.sun.star.util.URL aURL,/*IN*/ com.sun.star.beans.PropertyValue[] lArguments) + { + synchronized(this) + { + if (m_bDead) + return; + } + + com.sun.star.util.URL[] lInURL = new com.sun.star.util.URL[1]; + com.sun.star.beans.PropertyValue[][] lInArguments = new com.sun.star.beans.PropertyValue[1][]; + lInURL[0] = aURL ; + lInArguments[0] = lArguments; + + ArrayList lOutParams = OnewayExecutor.encodeDispatch( + lInURL , + lInArguments ); + OnewayExecutor aExecutor = new OnewayExecutor( this , + OnewayExecutor.REQUEST_DISPATCH , + lOutParams ); + aExecutor.start(); + } + + + + + /* + * Internal callback for frame action events, triggered by the used + * OnewayExecutor thread we started in frameAction(). + * We use it to update our interception on the internal saved frame. + * + * @param aEvent + * describes the action + */ + private void impl_frameAction(/*IN*/ com.sun.star.frame.FrameActionEvent aEvent) + { + synchronized(this) + { + if (m_bDead) + return; + } + + // deregistration will be done every time... + // But may it's not necessary to establish a new registration! + // Don't look for ignoring actions - it was done already inside original frameAction() call! + boolean bRegister = false; + + // analyze the event and decide which reaction is useful + switch(aEvent.Action.getValue()) + { + case com.sun.star.frame.FrameAction.COMPONENT_ATTACHED_value : bRegister = true ; break; + case com.sun.star.frame.FrameAction.COMPONENT_REATTACHED_value : bRegister = true ; break; + case com.sun.star.frame.FrameAction.COMPONENT_DETACHING_value : bRegister = false; break; + } + + com.sun.star.frame.XFrame xFrame = null ; + boolean bIsRegistered = false; + synchronized(this) + { + bIsRegistered = m_bIsRegistered; + m_bIsRegistered = false; + xFrame = m_xFrame; + } + + com.sun.star.frame.XDispatchProviderInterception xRegistration = UnoRuntime.queryInterface( + com.sun.star.frame.XDispatchProviderInterception.class, + xFrame); + + if(xRegistration==null) + return; + + if (bIsRegistered) + xRegistration.releaseDispatchProviderInterceptor(this); + + if (! bRegister) + return; + + xRegistration.registerDispatchProviderInterceptor(this); + synchronized(this) + { + m_bIsRegistered = true; + } + } + + + + /* + * Implementation of interface XDispatchProviderInterceptor + * These functions are used to build a list of interceptor objects + * connected in both ways. + * Searching for a right interceptor is made by forwarding any request + * from toppest master to lowest slave of this hierarchy. + * If an interceptor wish to handle the request he can break that + * and return himself as a dispatcher. + */ + public com.sun.star.frame.XDispatchProvider getSlaveDispatchProvider() + { + synchronized(this) + { + return m_xSlave; + } + } + + + + public void setSlaveDispatchProvider(com.sun.star.frame.XDispatchProvider xSlave) + { + synchronized(this) + { + m_xSlave = xSlave; + } + } + + + + public com.sun.star.frame.XDispatchProvider getMasterDispatchProvider() + { + synchronized(this) + { + return m_xMaster; + } + } + + + + public void setMasterDispatchProvider(com.sun.star.frame.XDispatchProvider xMaster) + { + synchronized(this) + { + m_xMaster = xMaster; + } + } + + + + /* + * Implementation of interface XDispatchProvider + * These functions are called from our master if he will not handle the outstanding request. + * Given parameter should be checked if they are right for us. If it's true, the returned + * dispatcher should be this implementation himself; otherwise call should be forwarded + * to the slave. + * + * @param aURL + * describes the request, which should be handled + * + * @param sTarget + * specifies the target frame for this request + * + * @param nSearchFlags + * optional search flags, if sTarget isn't a special one + * + * @return [XDispatch] + * a dispatch object, which can handle the given URL + * May be NULL! + */ + public com.sun.star.frame.XDispatch queryDispatch(/*IN*/ com.sun.star.util.URL aURL,/*IN*/ String sTarget,/*IN*/ int nSearchFlags) + { + synchronized(this) + { + if (m_bDead) + return null; + } + + // intercept loading empty documents into new created frames + if( + (sTarget.compareTo ("_blank" ) == 0 ) && + (aURL.Complete.startsWith("private:factory")) + ) + { + System.out.println("intercept private:factory"); + return this; + } + + // intercept opening the SaveAs dialog + if (aURL.Complete.startsWith(".uno:SaveAs")) + { + System.out.println("intercept SaveAs by returning null!"); + return null; + } + + // intercept "File->Exit" inside the menu + if ( + (aURL.Complete.startsWith("slot:5300")) || + (aURL.Complete.startsWith(".uno:Quit")) + ) + { + System.out.println("intercept File->Exit"); + return this; + } + + synchronized(this) + { + if (m_xSlave!=null) + return m_xSlave.queryDispatch(aURL, sTarget, nSearchFlags); + } + + return null; + } + + + + public com.sun.star.frame.XDispatch[] queryDispatches(/*IN*/ com.sun.star.frame.DispatchDescriptor[] lDescriptor) + { + synchronized(this) + { + if (m_bDead) + return null; + } + // Resolve any request separately by using own "dispatch()" method. + // Note: Don't pack return list if "null" objects occur! + int nCount = lDescriptor.length; + com.sun.star.frame.XDispatch[] lDispatcher = new com.sun.star.frame.XDispatch[nCount]; + for(int i=0; i