diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/IRSEInteractionProvider.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/IRSEInteractionProvider.java new file mode 100644 index 00000000000..0a491ede8b2 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/IRSEInteractionProvider.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Martin Oberhuber (Wind River) - [190231] initial API and implementation + * IBM Corporation - Javadoc for runInDefaultContext() method + *******************************************************************************/ +package org.eclipse.rse.core; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; + +/** + * Interaction Provider Interface. + * + * Classes implementing this interface provide a means for RSE to communicate + * with the outside world: via progress monitors, events and messages. A UI + * implementation of this interface would typically use UI components for user + * interaction; although this can be changed also intermittently. + * + * Non-UI headless applications may log messages rather than doing interactive + * messages, and may use different Threads for sending messages. + * + * @since org.eclipse.rse.core 3.0 + */ +public interface IRSEInteractionProvider { + + /** + * Return a default progress monitor for the context that's currently + * active. + * + * Usually, long-running operations should always be created from the client + * with a progress monitor that they can use. Historically, however, this + * has not always been done and is especially problematic in operations that + * are performed as the result of Callbacks. + * + * For such situations, this method returns a default progress monitor in a + * context that we guess. We try to use one default progress use one for all + * phases of a single operation, such as connecting and resolving. + * + * @return a default progress monitor + */ + public IProgressMonitor getDefaultProgressMonitor(); + + /** + *

+ * Runs the given IRSERunnableWithProgress in the default + * context available to this interaction provider, that provides a progress + * monitor. For example, if the default context is a + * ProgressMonitorDialog then the runnable is run using the + * dialog's progress monitor. This method is derived from + * IRunnableContext#run(). + *

+ *

+ * If fork is false, the current thread is + * used to run the runnable. Note that if fork is + * true, it is unspecified whether or not this method blocks + * until the runnable has been run. Implementers should document whether the + * runnable is run synchronously (blocking) or asynchronously + * (non-blocking), or if no assumption can be made about the blocking + * behaviour. + *

+ * + * @param fork true if the runnable should be run in a + * separate thread, and false to run in the same + * thread + * @param cancellable true to enable the cancellation, and + * false to make the operation uncancellable + * @param runnable the runnable to run + * + * @exception InvocationTargetException wraps any exception or error which + * occurs while running the runnable + * @exception InterruptedException propagated by the context if the runnable + * acknowledges cancellation by throwing this exception. This + * should not be thrown if cancellable is false. + */ + public void runInDefaultContext(boolean fork, boolean cancellable, IRSERunnableWithProgress runnable) throws InvocationTargetException, + InterruptedException; + + /** + * Asynchronously run the given runnable in a separate thread. + * + * UI implementations should have the runnable run in the dispatch thread, + * where it has access to UI components. This is used for notifications. + * Non-UI applications may choose any Thread they like, provided that two + * conditions are met: + *
    + *
  1. All Runnables are run on the same Thread. + *
  2. The ordering of Runnables remains intact. + *
+ * + * @param runnable the Runnable to run asynchronously + */ + public void asyncExec(Runnable runnable); + + /** + * Flush the Queue of Runnables enqueued with {@link #asyncExec(Runnable)}. + * + * This needs to be done when this interaction provider is to be replaced by + * a different one, in order to ensure that the ordering of all Runnables + * remains intact. + */ + public void flushRunnableQueue(); + + /** + * Show the given message or log it. + * + * In an interactive environment, this pops up a dialog asking the user to + * press an OK button. The method will not return before the OK button is + * pressed. + * + * @param msg the message to show + */ + public void showMessage(SystemMessage msg); +} diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/IRSERunnableWithProgress.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/IRSERunnableWithProgress.java new file mode 100644 index 00000000000..fed96814b8f --- /dev/null +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/IRSERunnableWithProgress.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2000, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Martin Oberhuber (Wind River) - [190231] Adapted from jface.operation.IRunnableWithProgress + *******************************************************************************/ +package org.eclipse.rse.core; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.runtime.IProgressMonitor; + +/** + * The IRSERunnableWithProgress interface should be implemented + * by any class whose instances are intended to be executed as a long-running + * operation. Long-running operations are typically presented at the UI via a + * modal dialog showing a progress indicator and a Cancel button. + * + * This interface is derived from + * org.eclipse.jface.operation.IRunnableWithProgress, but + * brought into no-UI space. The class must define a run method + * that takes a progress monitor. The run method is usually not + * invoked directly, but rather by passing the + * IRunnableWithProgress to the run method of an + * IRunnableContext, which provides the UI for the progress + * monitor and Cancel button. + * + * @see IRSEInteractionProvider + * @since org.eclipse.rse.core 3.0 + */ +public interface IRSERunnableWithProgress { + /** + * Runs this operation. Progress should be reported to the given progress + * monitor. This method is usually invoked by an + * IRunnableContext's run method, which + * supplies the progress monitor. A request to cancel the operation should + * be honored and acknowledged by throwing InterruptedException. + * + * @param monitor the progress monitor to use to display progress and + * receive requests for cancellation + * @exception InvocationTargetException if the run method must propagate a + * checked exception, it should wrap it inside an + * InvocationTargetException; runtime + * exceptions are automatically wrapped in an + * InvocationTargetException by the calling + * context + * @exception InterruptedException if the operation detects a request to + * cancel, using IProgressMonitor.isCanceled(), + * it should exit by throwing + * InterruptedException + * + * @see IRSEInteractionProvider + */ + public void run(IProgressMonitor monitor) throws InvocationTargetException, + InterruptedException; +} diff --git a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/RSECorePlugin.java b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/RSECorePlugin.java index decc88b6ead..1e8f73ea4c5 100644 --- a/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/RSECorePlugin.java +++ b/rse/plugins/org.eclipse.rse.core/src/org/eclipse/rse/core/RSECorePlugin.java @@ -22,6 +22,7 @@ * Martin Oberhuber (Wind River) - [215820] Move SystemRegistry implementation to Core * David Dykstal (IBM) - [197167] adding notification and waiting for RSE model * Martin Oberhuber (Wind River) - [cleanup] Add API "since" Javadoc tags + * Martin Oberhuber (Wind River) - [190231] Prepare API for UI/Non-UI Splitting ********************************************************************************/ package org.eclipse.rse.core; @@ -57,7 +58,7 @@ import org.osgi.framework.BundleContext; * RSECorePlugin provides the activation for the RSE core and acts as the * primary registry for logging, persistence, and the main RSE service * registries. - * + * * @noextend This class is not intended to be subclassed by clients. * @noinstantiate This class is not intended to be instantiated by clients. */ @@ -65,7 +66,7 @@ public class RSECorePlugin extends Plugin { /** * The plugin id for this plugin. Value "org.eclipse.rse.core". - * + * * @since org.eclipse.rse.core 3.0 */ public static final String PLUGIN_ID = "org.eclipse.rse.core"; //$NON-NLS-1$ @@ -85,7 +86,7 @@ public class RSECorePlugin extends Plugin { * {@link #isInitComplete(int)} which will return true if all phases of * initialization are complete. Clients must not assume any particular * ordering among phases based on the value. - * + * * @since org.eclipse.rse.core 3.0 */ public static final int INIT_ALL = 0; @@ -95,7 +96,7 @@ public class RSECorePlugin extends Plugin { * {@link #isInitComplete(int)} which will return true if the model phase of * the initialization is complete. Clients must not assume any particular * ordering among phases based on the value. - * + * * @since org.eclipse.rse.core 3.0 */ public static final int INIT_MODEL = 1; @@ -105,7 +106,7 @@ public class RSECorePlugin extends Plugin { * {@link #isInitComplete(int)} which will return true if the initializer * phase of the initialization is complete. Clients must not assume any * particular ordering among phases based on the value. - * + * * @since org.eclipse.rse.core 3.0 */ public static final int INIT_INITIALIZER = 2; @@ -115,6 +116,7 @@ public class RSECorePlugin extends Plugin { private ISystemRegistry _systemRegistry = null; private IRSEPersistenceManager _persistenceManager = null; private ISubSystemConfigurationProxy[] _subsystemConfigurations = null; + private IRSEInteractionProvider _interactionProvider = null; /** * Returns the singleton instance of RSECorePlugin. @@ -127,7 +129,7 @@ public class RSECorePlugin extends Plugin { /** * Waits until the RSE model has been fully restored from its persistent * form. Should be used before accessing pieces of the model. - * + * * @return an IStatus indicating how the initialization ended. * @throws InterruptedException if this wait was interrupted for some * reason. @@ -139,7 +141,7 @@ public class RSECorePlugin extends Plugin { /** * Waits until the RSE has completed a specific phase of its initialization. - * + * * @param phase the phase to wait for completion. * @throws InterruptedException if this wait was interrupted for some * reason. @@ -156,7 +158,7 @@ public class RSECorePlugin extends Plugin { /** * Check whether the initialization of the RSE model is complete for a given * phase. - * + * * @param phase the phase identifier. * @return true if the initialization for the given phase has * completed regardless of its status of that completion. @@ -175,7 +177,7 @@ public class RSECorePlugin extends Plugin { * initialization phases complete. If the listener is added after the phase * has completed it will not be invoked. If the listener is already in the * set it will not be added again. Listeners may be notified in any order. - * + * * @param listener the listener to be added * @since org.eclipse.rse.core 3.0 */ @@ -186,7 +188,7 @@ public class RSECorePlugin extends Plugin { /** * Removes a listener to the set of listeners to be notified when phases * complete. If the listener is not in the set this does nothing. - * + * * @param listener the listener to be removed * @since org.eclipse.rse.core 3.0 */ @@ -214,7 +216,7 @@ public class RSECorePlugin extends Plugin { /** * Return the master profile manager singleton. - * + * * @return the RSE Profile Manager Singleton. * @since org.eclipse.rse.core 3.0 */ @@ -226,7 +228,7 @@ public class RSECorePlugin extends Plugin { * Check if the SystemRegistry has been instantiated already. Use this when * you don't want to start the system registry as a side effect of * retrieving it. - * + * * @return true if the System Registry has been instantiated * already. * @since org.eclipse.rse.core 3.0 @@ -398,6 +400,36 @@ public class RSECorePlugin extends Plugin { getLogger().logError("Unexpected Exception", t); //$NON-NLS-1$ } + /** + * Set the default interaction provider. + * + * When RSE is run with UI, the UI plugins need to set an UI-based + * interaction provider for showing dialogs from Core operations. Non-UI + * headless operations can use an Interaction Provider that just logs its + * messages and works without other UI. + * + * @param p the interaction provider to set. + * @since org.eclipse.rse.core 3.0 + */ + public void setDefaultInteractionProvider(IRSEInteractionProvider p) { + synchronized (this) { + _interactionProvider = p; + } + } + + /** + * Get the default interface for interacting with the user or other outside + * world. + * + * @return the default interaction provider. + * @since org.eclipse.rse.core 3.0 + */ + public IRSEInteractionProvider getDefaultInteractionProvider() { + synchronized (this) { + return _interactionProvider; + } + } + /** * Register declared keystore providers. */ diff --git a/rse/plugins/org.eclipse.rse.ui/UI/org/eclipse/rse/internal/ui/DefaultUIInteractionProvider.java b/rse/plugins/org.eclipse.rse.ui/UI/org/eclipse/rse/internal/ui/DefaultUIInteractionProvider.java new file mode 100644 index 00000000000..8fb5858b5a4 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.ui/UI/org/eclipse/rse/internal/ui/DefaultUIInteractionProvider.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2002, 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Martin Oberhuber (Wind River) - [190231] initial API and implementation + * Martin Oberhuber (Wind River) - brought in methods from SubSystem (c) IBM + *******************************************************************************/ +package org.eclipse.rse.internal.ui; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableContext; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.rse.core.IRSEInteractionProvider; +import org.eclipse.rse.core.IRSERunnableWithProgress; +import org.eclipse.rse.services.clientserver.messages.SystemMessage; +import org.eclipse.rse.ui.RSEUIPlugin; +import org.eclipse.rse.ui.SystemBasePlugin; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +/** + * A Default Interaction Provider that runs in the Eclipse / SWT UI. + * Meant to provide the same functionality as it was there before + * UI / Non-UI Splitting. + * @since org.eclipse.rse.ui 3.0 + */ +public class DefaultUIInteractionProvider implements IRSEInteractionProvider { + + private Shell shell = null; + + private class NullRunnableContext implements IRunnableContext { + public void run(boolean fork, boolean cancelable, IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException { + IProgressMonitor monitor = new NullProgressMonitor(); + runnable.run(monitor); + } + } + + /** + * Get the progress monitor dialog for this operation. We try to use one for + * all phases of a single operation, such as connecting and resolving. + * + * @deprecated this is scheduled to be removed since we want to avoid UI + * components in SubSystem. + */ + protected IRunnableContext getRunnableContext(/* Shell rshell */) { + if (Display.getCurrent() == null) { + return new NullRunnableContext(); + } + // for wizards and dialogs use the specified context that was placed in + // the registry + IRunnableContext irc = RSEUIPlugin.getTheSystemRegistryUI().getRunnableContext(); + if (irc != null) { + SystemBasePlugin.logInfo("Got runnable context from system registry"); //$NON-NLS-1$ + return irc; + } else { + // for other cases, use statusbar + IWorkbenchWindow win = SystemBasePlugin.getActiveWorkbenchWindow(); + if (win != null) { + Shell winShell = getActiveWorkbenchShell(); + if (winShell != null && !winShell.isDisposed() && winShell.isVisible()) { + SystemBasePlugin.logInfo("Using active workbench window as runnable context"); //$NON-NLS-1$ + shell = winShell; + return win; + // dwd } else { + // dwd win = null; + } + } + // dwd if (shell == null || shell.isDisposed() || + // !shell.isVisible()) { + // dwd SystemBasePlugin.logInfo("Using progress monitor dialog with + // given shell as parent"); + // dwd shell = rshell; + // dwd } + // dwd IRunnableContext dlg = new ProgressMonitorDialog(rshell); + IRunnableContext dlg = new ProgressMonitorDialog(shell); + return dlg; + } + } + + /** + * Helper/convenience method. Return shell of active window. + */ + public static Shell getActiveWorkbenchShell() { + Shell result = null; + if (PlatformUI.isWorkbenchRunning()) { + try { + IWorkbenchWindow window = getActiveWorkbenchWindow(); + if (window != null) { + result = window.getShell(); + } + } catch (Exception e) { + return null; + } + } else // workbench has not been loaded yet! + { + return null; + } + return result; + } + + /** + * Helper/convenience method. Return active window + */ + public static IWorkbenchWindow getActiveWorkbenchWindow() { + return RSEUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow(); + } + + public void runInDefaultContext(boolean fork, boolean cancellable, IRSERunnableWithProgress runnable) throws InvocationTargetException, + InterruptedException { + // TODO Auto-generated method stub + } + + private Display getDefaultDisplay() { + Display d = Display.getCurrent(); + if (d == null) { + d = SystemBasePlugin.getActiveWorkbenchShell().getDisplay(); + if (d == null) { + d = Display.getDefault(); + } + } + return d; + } + + public void asyncExec(Runnable runnable) { + getDefaultDisplay().asyncExec(runnable); + } + + public void flushRunnableQueue() { + Display d = Display.getCurrent(); + if (d == null) { + getDefaultDisplay().syncExec(new Runnable() { + public void run() { + flushRunnableQueue(); + } + }); + } else { + while (d.readAndDispatch()) { + // flush the event queue + } + } + } + + public IProgressMonitor getDefaultProgressMonitor() { + // TODO Auto-generated method stub + return null; + } + + public void showMessage(SystemMessage msg) { + // TODO Auto-generated method stub + + } + +} diff --git a/rse/plugins/org.eclipse.rse.ui/subsystems/org/eclipse/rse/core/subsystems/SubSystem.java b/rse/plugins/org.eclipse.rse.ui/subsystems/org/eclipse/rse/core/subsystems/SubSystem.java index aa8b7f3a22b..ff723b9259a 100644 --- a/rse/plugins/org.eclipse.rse.ui/subsystems/org/eclipse/rse/core/subsystems/SubSystem.java +++ b/rse/plugins/org.eclipse.rse.ui/subsystems/org/eclipse/rse/core/subsystems/SubSystem.java @@ -36,6 +36,7 @@ * David McKnight (IBM) - [220547] [api][breaking] SimpleSystemMessage needs to specify a message id and some messages should be shared * David Dykstal (IBM) - [225089][ssh][shells][api] Canceling connection leads to exception * Martin Oberhuber (Wind River) - [218304] Improve deferred adapter loading + * Martin Oberhuber (Wind River) - [190231] Prepare API for UI/Non-UI Splitting ********************************************************************************/ package org.eclipse.rse.core.subsystems; @@ -62,6 +63,7 @@ import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.osgi.util.NLS; +import org.eclipse.rse.core.IRSEInteractionProvider; import org.eclipse.rse.core.RSECorePlugin; import org.eclipse.rse.core.RSEPreferencesManager; import org.eclipse.rse.core.events.ISystemModelChangeEvent; @@ -101,7 +103,6 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbenchWindow; -import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.PropertyPage; import org.eclipse.ui.progress.UIJob; import org.eclipse.ui.progress.WorkbenchJob; @@ -164,8 +165,9 @@ implements IAdaptable, ISubSystem, ISystemFilterPoolReferenceManagerProvider protected ISubSystemConfiguration parentSubSystemConfiguration; protected String previousUserIdKey; - + private IRSEInteractionProvider _interactionProvider = null; protected Shell shell = null; + protected boolean supportsConnecting = true; protected boolean sortResults = true; protected boolean runInThread = true; @@ -184,7 +186,6 @@ implements IAdaptable, ISubSystem, ISystemFilterPoolReferenceManagerProvider protected String _name = null; protected String _subsystemConfigurationId = null; protected boolean _hidden = false; - private boolean _isInitialized = false; @@ -225,6 +226,37 @@ implements IAdaptable, ISubSystem, ISystemFilterPoolReferenceManagerProvider _connectorService.registerSubSystem(this); } + /** + * Set an Interaction Provider specific for this subsystem. + * + * @param p the new interaction provider to use, or null to + * fall back to the default interaction provider (from + * RSECorePlugin). + * @since 3.0 + */ + public void setInteractionProvider(IRSEInteractionProvider p) { + synchronized (this) { + _interactionProvider = p; + } + } + + /** + * Get the current Interaction Provider. Returns a specific one for this + * subsystem if it has been set, or falls back to the default one from + * RSECorePlugin otherwise. + * + * @return the interaction provider to use. + * @since 3.0 + */ + public IRSEInteractionProvider getInteractionProvider() { + synchronized (this) { + if (_interactionProvider != null) { + return _interactionProvider; + } + } + return RSECorePlugin.getDefault().getDefaultInteractionProvider(); + } + /** * Internal method to select the appropriate command subsystem when there are multiple defined for this connection. * The default implementation is to return the first, but child classes can refine this. Input is always an array of @@ -2908,7 +2940,7 @@ implements IAdaptable, ISubSystem, ISystemFilterPoolReferenceManagerProvider // for other cases, use statusbar IWorkbenchWindow win = SystemBasePlugin.getActiveWorkbenchWindow(); if (win != null) { - Shell winShell = getActiveWorkbenchShell(); + Shell winShell = SystemBasePlugin.getActiveWorkbenchShell(); if (winShell != null && !winShell.isDisposed() && winShell.isVisible()) { SystemBasePlugin.logInfo("Using active workbench window as runnable context"); //$NON-NLS-1$ shell = winShell; @@ -2935,41 +2967,6 @@ implements IAdaptable, ISubSystem, ISystemFilterPoolReferenceManagerProvider return shell; } - /** - * Helper/convenience method. Return shell of active window. - */ - public static Shell getActiveWorkbenchShell() - { - Shell result = null; - if (PlatformUI.isWorkbenchRunning()) - { - try - { - IWorkbenchWindow window = getActiveWorkbenchWindow(); - if (window != null) - { - result = window.getShell(); - } - } - catch (Exception e) - { - return null; - } - } - else // workbench has not been loaded yet! - { - return null; - } - return result; - } - /** - * Helper/convenience method. Return active window - */ - public static IWorkbenchWindow getActiveWorkbenchWindow() - { - return RSEUIPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow(); - } - /** * Private. Do not override. * @generated This field/method will be replaced during code generation