diff options
author | Uwe Stieber | 2011-10-05 07:38:18 +0000 |
---|---|---|
committer | Uwe Stieber | 2011-10-05 07:38:18 +0000 |
commit | ffd30a64e731f52e747c759c6617b4ad8d362025 (patch) | |
tree | 1f9471bb1c01085ee8f7497d0fa32b8d61c6b736 /target_explorer | |
parent | d1b1ad8267e77c46a5f1c17d36b219d35fbc1e00 (diff) | |
download | org.eclipse.tcf-ffd30a64e731f52e747c759c6617b4ad8d362025.tar.gz org.eclipse.tcf-ffd30a64e731f52e747c759c6617b4ad8d362025.tar.xz org.eclipse.tcf-ffd30a64e731f52e747c759c6617b4ad8d362025.zip |
Target Explorer: Terminals view contribution
Diffstat (limited to 'target_explorer')
49 files changed, 5064 insertions, 89 deletions
diff --git a/target_explorer/features/org.eclipse.tm.te.feature/feature.xml b/target_explorer/features/org.eclipse.tm.te.feature/feature.xml index b6c5dbf8a..4763ec7bf 100644 --- a/target_explorer/features/org.eclipse.tm.te.feature/feature.xml +++ b/target_explorer/features/org.eclipse.tm.te.feature/feature.xml @@ -97,7 +97,7 @@ unpack="false"/>
<plugin
- id="org.eclipse.tm.te.ui.terminal"
+ id="org.eclipse.tm.te.ui.terminals"
download-size="0"
install-size="0"
version="0.0.0"
diff --git a/target_explorer/features/org.eclipse.tm.te.sdk.feature/feature.xml b/target_explorer/features/org.eclipse.tm.te.sdk.feature/feature.xml index 9795d2a94..272c3f5c7 100644 --- a/target_explorer/features/org.eclipse.tm.te.sdk.feature/feature.xml +++ b/target_explorer/features/org.eclipse.tm.te.sdk.feature/feature.xml @@ -92,7 +92,7 @@ unpack="false"/>
<plugin
- id="org.eclipse.tm.te.ui.terminal.source"
+ id="org.eclipse.tm.te.ui.terminals.source"
download-size="0"
install-size="0"
version="0.0.0"
diff --git a/target_explorer/plugins/org.eclipse.tm.te.rcp.application/src/org/eclipse/tm/te/rcp/application/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tm.te.rcp.application/src/org/eclipse/tm/te/rcp/application/nls/Messages.properties index 338e09e2a..fb56c2f1e 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.rcp.application/src/org/eclipse/tm/te/rcp/application/nls/Messages.properties +++ b/target_explorer/plugins/org.eclipse.tm.te.rcp.application/src/org/eclipse/tm/te/rcp/application/nls/Messages.properties @@ -1,5 +1,5 @@ # -# com.windriver.vtl +# org.eclipse.tm.te.rcp.application # Externalized Strings. # diff --git a/target_explorer/plugins/org.eclipse.tm.te.runtime/src/org/eclipse/tm/te/runtime/events/DisposedEvent.java b/target_explorer/plugins/org.eclipse.tm.te.runtime/src/org/eclipse/tm/te/runtime/events/DisposedEvent.java new file mode 100644 index 000000000..fc8eee27c --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.runtime/src/org/eclipse/tm/te/runtime/events/DisposedEvent.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.runtime.events; + +import java.util.EventObject; + +import org.eclipse.tm.te.runtime.activator.CoreBundleActivator; +import org.eclipse.tm.te.runtime.interfaces.tracing.ITraceIds; + +/** + * Event used to signal the disposal of an element. + */ +public class DisposedEvent extends EventObject { + private static final long serialVersionUID = -8900361742097122798L; + + private final Object data; + + /** + * Constructor. + * + * @param source The event source. Must not be <code>null</code>. + * <p> + * The event source is expected to be of type {@link CTabItem}. + * + * @param data The custom data object or <code>null</code>. + */ + public DisposedEvent(Object source, Object data) { + super(source); + this.data = data; + } + + /** + * Returns the custom data object associated with the disposed terminal console. + * + * @return The custom data object or <code>null</code>. + */ + public final Object getData() { + return data; + } + + /* (non-Javadoc) + * @see java.util.EventObject#toString() + */ + @Override + public String toString() { + StringBuffer toString = new StringBuffer(getClass().getName()); + + String prefix = ""; //$NON-NLS-1$ + // if debugging the event, formating them a little bit better readable. + if (CoreBundleActivator.getTraceHandler().isSlotEnabled(1, ITraceIds.TRACE_EVENTS)) + prefix = "\n\t\t"; //$NON-NLS-1$ + + toString.append(prefix + "{source="); //$NON-NLS-1$ + toString.append(source); + toString.append("}"); //$NON-NLS-1$ + + return toString.toString(); + } + +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractCheckBoxCellPaintListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractCheckBoxCellPaintListener.java index e5f5ecb6e..23f6902aa 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractCheckBoxCellPaintListener.java +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractCheckBoxCellPaintListener.java @@ -46,7 +46,7 @@ public abstract class AbstractCheckBoxCellPaintListener extends AbstractCellPain } /* (non-Javadoc) - * @see com.windriver.ui.swt.listener.AbstractCellPaintListener#getPaintOrigin(org.eclipse.swt.widgets.Event, org.eclipse.swt.graphics.Image) + * @see org.eclipse.tm.te.ui.swt.listener.AbstractCellPaintListener#getPaintOrigin(org.eclipse.swt.widgets.Event, org.eclipse.swt.graphics.Image) */ @Override protected Point getPaintOrigin(Event event, Image image) { @@ -60,7 +60,7 @@ public abstract class AbstractCheckBoxCellPaintListener extends AbstractCellPain } /* (non-Javadoc) - * @see com.windriver.ui.swt.listener.AbstractCellPaintListener#getImageToDraw(org.eclipse.swt.widgets.Item, int) + * @see org.eclipse.tm.te.ui.swt.listener.AbstractCellPaintListener#getImageToDraw(org.eclipse.swt.widgets.Item, int) */ @Override protected Image getImageToDraw(Item item, int columnIndex) { diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractDecorationCellPaintListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractDecorationCellPaintListener.java index 94f4cd916..84fac2862 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractDecorationCellPaintListener.java +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractDecorationCellPaintListener.java @@ -40,7 +40,7 @@ public abstract class AbstractDecorationCellPaintListener extends AbstractCellPa } /* (non-Javadoc) - * @see com.windriver.ui.swt.listener.AbstractCellPaintListener#getPaintOrigin(org.eclipse.swt.widgets.Event, org.eclipse.swt.graphics.Image) + * @see org.eclipse.tm.te.ui.swt.listener.AbstractCellPaintListener#getPaintOrigin(org.eclipse.swt.widgets.Event, org.eclipse.swt.graphics.Image) */ @Override protected Point getPaintOrigin(Event event, Image image) { @@ -48,7 +48,7 @@ public abstract class AbstractDecorationCellPaintListener extends AbstractCellPa } /* (non-Javadoc) - * @see com.windriver.ui.swt.listener.AbstractCellPaintListener#getImageToDraw(org.eclipse.swt.widgets.Item, int) + * @see org.eclipse.tm.te.ui.swt.listener.AbstractCellPaintListener#getImageToDraw(org.eclipse.swt.widgets.Item, int) */ @Override protected Image getImageToDraw(Item item, int columnIndex) { diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/META-INF/MANIFEST.MF b/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/META-INF/MANIFEST.MF deleted file mode 100644 index 2ce09397a..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/META-INF/MANIFEST.MF +++ /dev/null @@ -1,12 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: %pluginName -Bundle-SymbolicName: org.eclipse.tm.te.ui.terminal;singleton:=true -Bundle-Version: 1.0.0.qualifier -Bundle-Activator: org.eclipse.tm.te.ui.terminal.activator.UIPlugin -Bundle-Vendor: %providerName -Require-Bundle: org.eclipse.core.runtime;bundle-version="3.7.0", - org.eclipse.ui;bundle-version="3.7.0" -Bundle-RequiredExecutionEnvironment: JavaSE-1.6 -Bundle-ActivationPolicy: lazy -Bundle-Localization: plugin diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/src/org/eclipse/tm/te/ui/terminal/activator/UIPlugin.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/src/org/eclipse/tm/te/ui/terminal/activator/UIPlugin.java deleted file mode 100644 index 9b6449e37..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/src/org/eclipse/tm/te/ui/terminal/activator/UIPlugin.java +++ /dev/null @@ -1,64 +0,0 @@ -/*******************************************************************************
- * Copyright (c) 2011 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:
- * Wind River Systems - initial API and implementation
- *******************************************************************************/
-package org.eclipse.tm.te.ui.terminal.activator;
-
-import org.eclipse.ui.plugin.AbstractUIPlugin;
-import org.osgi.framework.BundleContext;
-
-/**
- * The activator class controls the plug-in life cycle
- */
-public class UIPlugin extends AbstractUIPlugin {
- // The shared instance
- private static UIPlugin plugin;
-
- /**
- * The constructor
- */
- public UIPlugin() {
- }
-
- /**
- * Returns the shared instance
- *
- * @return the shared instance
- */
- public static UIPlugin getDefault() {
- return plugin;
- }
-
- /**
- * Convenience method which returns the unique identifier of this plugin.
- */
- public static String getUniqueIdentifier() {
- if (getDefault() != null && getDefault().getBundle() != null) {
- return getDefault().getBundle().getSymbolicName();
- }
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
- */
- @Override
- public void start(BundleContext context) throws Exception {
- super.start(context);
- plugin = this;
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
- */
- @Override
- public void stop(BundleContext context) throws Exception {
- plugin = null;
- super.stop(context);
- }
-}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/.classpath b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.classpath index 8a8f1668c..8a8f1668c 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/.classpath +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.classpath diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.options b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.options new file mode 100644 index 000000000..2ad378b66 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.options @@ -0,0 +1 @@ +org.eclipse.tm.te.ui.terminals/debugmode = 0 diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/.project b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.project index d76249909..ad1ea71d6 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/.project +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.project @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>org.eclipse.tm.te.ui.terminal</name>
+ <name>org.eclipse.tm.te.ui.terminals</name>
<comment></comment>
<projects>
</projects>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/.settings/org.eclipse.jdt.core.prefs b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.settings/org.eclipse.jdt.core.prefs index ea56f8105..ea56f8105 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/.settings/org.eclipse.jdt.core.prefs +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.settings/org.eclipse.jdt.core.prefs diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/META-INF/MANIFEST.MF b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/META-INF/MANIFEST.MF new file mode 100644 index 000000000..dd35637dc --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/META-INF/MANIFEST.MF @@ -0,0 +1,22 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.te.ui.terminals;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.eclipse.tm.te.ui.terminals.activator.UIPlugin +Bundle-Vendor: %providerName +Require-Bundle: org.eclipse.core.runtime;bundle-version="3.7.0", + org.eclipse.core.expressions;bundle-version="3.4.300", + org.eclipse.core.resources;bundle-version="3.7.100";resolution:=optional, + org.eclipse.ui;bundle-version="3.7.0", + org.eclipse.ui.ide;bundle-version="3.7.0", + org.eclipse.tm.terminal;bundle-version="3.1.1", + org.eclipse.tm.terminal.telnet;bundle-version="2.1.0", + org.eclipse.tm.terminal.view;bundle-version="2.2.0", + org.eclipse.tm.te.runtime;bundle-version="1.0.0", + org.eclipse.tm.te.ui;bundle-version="1.0.0", + org.eclipse.tm.te.ui.swt;bundle-version="1.0.0", + org.eclipse.cdt.core;bundle-version="5.3.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Bundle-Localization: plugin diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/build.properties b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/build.properties index f4ae97015..73a5119ed 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/build.properties +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/build.properties @@ -2,4 +2,5 @@ source.. = src/ output.. = bin/
bin.includes = META-INF/,\
.,\
- plugin.properties
+ plugin.properties,\
+ plugin.xml
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/plugin.properties b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.properties index c09addda0..faf90fdb0 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/plugin.properties +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.properties @@ -8,5 +8,16 @@ # Wind River Systems - initial API and implementation ################################################################################## -pluginName = Target Explorer, Terminal Consoles +pluginName = Target Explorer, Terminals providerName = Eclipse.org + +# ----- Terminals View ----- + +TerminalsView.name=Terminals + +# ----- Terminal Connectors ----- + +TerminalConnector.process=Process +TerminalConnector.streams=Streams Connector (hidden) + +# ----- Commands and Menu contributions ----- diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.xml b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.xml new file mode 100644 index 000000000..31dc3d21b --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+<!-- View contributions -->
+ <extension point="org.eclipse.ui.views">
+ <view
+ category="org.eclipse.tm.te.ui.views.category"
+ class="org.eclipse.tm.te.ui.terminals.view.TerminalsView"
+ icon="platform:/plugin/org.eclipse.ui.console/icons/full/eview16/console_view.gif"
+ id="org.eclipse.tm.te.ui.terminals.TerminalsView"
+ name="%TerminalsView.name">
+ </view>
+ </extension>
+
+<!-- Perspective extension contributions -->
+ <extension point="org.eclipse.ui.perspectiveExtensions">
+ <perspectiveExtension targetID="*">
+ <view
+ id="org.eclipse.tm.te.ui.terminals.TerminalsView"
+ minimized="false"
+ relationship="stack"
+ relative="org.eclipse.ui.views.TaskList"
+ visible="false">
+ </view>
+ </perspectiveExtension>
+ </extension>
+
+<!-- Terminal connector contributions -->
+ <extension point="org.eclipse.tm.terminal.terminalConnectors">
+ <connector
+ name="%TerminalConnector.process"
+ id="org.eclipse.tm.te.ui.terminals.ProcessConnector"
+ class="org.eclipse.tm.te.ui.terminals.process.ProcessConnector"/>
+
+ <connector
+ name="%TerminalConnector.streams"
+ id="org.eclipse.tm.te.ui.terminals.StreamsConnector"
+ hidden="true"
+ class="org.eclipse.tm.te.ui.terminals.streams.StreamsConnector"/>
+ </extension>
+
+<!-- Preferences contributions -->
+ <extension point="org.eclipse.core.runtime.preferences">
+ <initializer class="org.eclipse.tm.te.ui.terminals.internal.PreferenceInitializer"/>
+ </extension>
+
+</plugin>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/pom.xml b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/pom.xml index b9a9b00ec..26a4b4bbd 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.ui.terminal/pom.xml +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/pom.xml @@ -12,6 +12,6 @@ </parent> <version>1.0.0.qualifier</version> - <artifactId>org.eclipse.tm.te.ui.terminal</artifactId> + <artifactId>org.eclipse.tm.te.ui.terminals</artifactId> <packaging>eclipse-plugin</packaging> </project> diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/AbstractAction.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/AbstractAction.java new file mode 100644 index 000000000..54d2ecee4 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/AbstractAction.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.actions; + +import java.util.Collections; + +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.expressions.EvaluationContext; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction; +import org.eclipse.tm.te.ui.terminals.activator.UIPlugin; +import org.eclipse.tm.te.ui.terminals.nls.Messages; +import org.eclipse.tm.te.ui.terminals.tabs.TabFolderManager; +import org.eclipse.tm.te.ui.terminals.tabs.TabFolderToolbarHandler; +import org.eclipse.ui.ISources; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; + +/** + * Abstract terminal action wrapper implementation. + */ +@SuppressWarnings("restriction") +public abstract class AbstractAction extends AbstractTerminalAction { + // Reference to the parent toolbar handler + private final TabFolderToolbarHandler parent; + + /** + * Constructor. + * + * @param parent + * The parent toolbar handler instance. Must not be + * <code>null</code>. + * @param id + * The terminal action id. Must not be <code>null</code>. + */ + public AbstractAction(TabFolderToolbarHandler parent, String id) { + super(id); + + Assert.isNotNull(parent); + this.parent = parent; + } + + /** + * Returns the parent toolbar handler. + * + * @return The parent toolbar handler. + */ + protected final TabFolderToolbarHandler getParent() { + return parent; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getParent().getActiveTerminalViewControl(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#run() + */ + @Override + public void run() { + // Get the active tab item from the tab folder manager + TabFolderManager manager = (TabFolderManager)getParent().getAdapter(TabFolderManager.class); + if (manager != null) { + // If we have the active tab item, we can get the active terminal control + CTabItem activeTabItem = manager.getActiveTabItem(); + if (activeTabItem != null) { + // And execute the command + executeCommand(activeTabItem.getData("customData")); //$NON-NLS-1$ + } + } + } + + /** + * Executes the command for the given data node as current and active menu selection. + * <p> + * <b>Node:</b> If the provided data node is <code>null</code>, the method will trigger + * the command with an empty selection. + * + * @param data The terminal custom data node or <code>null</code>. + */ + protected void executeCommand(Object data) { + // Get the command service from the workbench + ICommandService service = (ICommandService)PlatformUI.getWorkbench().getAdapter(ICommandService.class); + if (service != null && getCommandId() != null) { + // Get the command + final Command command = service.getCommand(getCommandId()); + if (command != null && command.isDefined()) { + // Construct a selection element + IStructuredSelection selection = data != null ? new StructuredSelection(data) : new StructuredSelection(); + // Construct the application context + EvaluationContext context = new EvaluationContext(null, selection); + // Apply the selection to the "activeMenuSelection" and "selection" variable too + context.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection); + context.addVariable(ISources.ACTIVE_MENU_SELECTION_NAME, selection); + // Construct the execution event + ExecutionEvent execEvent = new ExecutionEvent(command, Collections.EMPTY_MAP, this, context); + // And execute the event + try { + command.executeWithChecks(execEvent); + } catch (Exception e) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + NLS.bind(Messages.AbstractAction_error_commandExecutionFailed, getCommandId(), e.getLocalizedMessage()), + e); + UIPlugin.getDefault().getLog().log(status); + } + } + } + } + + /** + * Returns the command id of the command to execute. + * + * @return The command id. Must be never <code>null</code>. + */ + protected abstract String getCommandId(); + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#updateAction(boolean) + */ + @Override + public void updateAction(boolean aboutToShow) { + // Ignore the flag given from outside. We have to decide ourself + // what the enabled state of the action is + boolean enabled = getTarget() != null; + + // If a target terminal control is available, we need to find the corresponding + // VLM target object which we need to trigger the handler + if (enabled) { + // The action will be enabled if we can determine the VLM target object + enabled = false; + // Get the active tab item from the tab folder manager + TabFolderManager manager = (TabFolderManager)getParent().getAdapter(TabFolderManager.class); + if (manager != null) { + // If we have the active tab item, we can get the active terminal control + CTabItem activeTabItem = manager.getActiveTabItem(); + if (activeTabItem != null) { + enabled = checkEnableAction(activeTabItem.getData("customData")); //$NON-NLS-1$ + } + } + } + + setEnabled(enabled); + } + + /** + * Checks if the action should be enabled based on the given terminal data object. + * + * @param data The terminal data node or <code>null</code>. + * @return <code>True</code> to enable the action, <code>false</code> otherwise. + */ + protected boolean checkEnableAction(Object data) { + return data != null; + } + + /** + * Returns if the action is a separator. Returning <code>true</code> here + * means that an additional separator toolbar element is added right or + * above of the action. + * + * @return <code>True</code> if the action is separating the parent contribution manager, <code>false</code> otherwise. + */ + public boolean isSeparator() { + return false; + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/TabScrollLockAction.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/TabScrollLockAction.java new file mode 100644 index 000000000..73d9fd237 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/TabScrollLockAction.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.tm.internal.terminal.actions.ActionMessages; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction; +import org.eclipse.tm.te.ui.terminals.activator.UIPlugin; +import org.eclipse.tm.te.ui.terminals.interfaces.ImageConsts; + +/** + * Terminal console tab scroll lock action. + */ +@SuppressWarnings("restriction") +public class TabScrollLockAction extends AbstractTerminalAction { + + /** + * Constructor. + */ + public TabScrollLockAction() { + super(null, TabScrollLockAction.class.getName(), IAction.AS_RADIO_BUTTON); + + setupAction(ActionMessages.SCROLL_LOCK_0, + ActionMessages.SCROLL_LOCK_1, + UIPlugin.getImageDescriptor(ImageConsts.ACTION_ScrollLock_Hover), + UIPlugin.getImageDescriptor(ImageConsts.ACTION_ScrollLock_Enabled), + UIPlugin.getImageDescriptor(ImageConsts.ACTION_ScrollLock_Disabled), + true); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#run() + */ + @Override + public void run() { + ITerminalViewControl target = getTarget(); + if (target != null) { + target.setScrollLock(!target.isScrollLock()); + setChecked(target.isScrollLock()); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#updateAction(boolean) + */ + @Override + public void updateAction(boolean aboutToShow) { + setEnabled(getTarget() != null && aboutToShow); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/activator/UIPlugin.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/activator/UIPlugin.java new file mode 100644 index 000000000..a919f570e --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/activator/UIPlugin.java @@ -0,0 +1,143 @@ +/*******************************************************************************
+ * Copyright (c) 2011 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.activator;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.tm.te.runtime.preferences.ScopedEclipsePreferences;
+import org.eclipse.tm.te.runtime.tracing.TraceHandler;
+import org.eclipse.tm.te.ui.terminals.interfaces.ImageConsts;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class UIPlugin extends AbstractUIPlugin {
+ // The shared instance
+ private static UIPlugin plugin;
+
+ private static ScopedEclipsePreferences scopedPreferences = null;
+ // The trace handler instance
+ private static TraceHandler traceHandler;
+
+ /**
+ * The constructor
+ */
+ public UIPlugin() {
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static UIPlugin getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Convenience method which returns the unique identifier of this plugin.
+ */
+ public static String getUniqueIdentifier() {
+ if (getDefault() != null && getDefault().getBundle() != null) {
+ return getDefault().getBundle().getSymbolicName();
+ }
+ return null;
+ }
+
+ /**
+ * Return the scoped preferences for this plugin.
+ */
+ public static ScopedEclipsePreferences getScopedPreferences() {
+ if (scopedPreferences == null) {
+ scopedPreferences = new ScopedEclipsePreferences(getUniqueIdentifier());
+ }
+ return scopedPreferences;
+ }
+
+ /**
+ * Returns the bundles trace handler.
+ *
+ * @return The bundles trace handler.
+ */
+ public static TraceHandler getTraceHandler() {
+ if (traceHandler == null) {
+ traceHandler = new TraceHandler(getUniqueIdentifier());
+ }
+ return traceHandler;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ scopedPreferences = null;
+ traceHandler = null;
+ super.stop(context);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#initializeImageRegistry(org.eclipse.jface.resource.ImageRegistry)
+ */
+ @Override
+ protected void initializeImageRegistry(ImageRegistry registry) {
+ Bundle bundle = Platform.getBundle("org.eclipse.ui.console"); //$NON-NLS-1$
+ if (bundle != null && (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.ACTIVE)) {
+ URL url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + "full/" + ImageConsts.IMAGE_DIR_EVIEW + "console_view.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ registry.put(ImageConsts.VIEW_Terminals, ImageDescriptor.createFromURL(url));
+
+ url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + "full/" + ImageConsts.IMAGE_DIR_CLCL + "lock_co.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ registry.put(ImageConsts.ACTION_ScrollLock_Hover, ImageDescriptor.createFromURL(url));
+ url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + "full/" + ImageConsts.IMAGE_DIR_ELCL + "lock_co.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ registry.put(ImageConsts.ACTION_ScrollLock_Enabled, ImageDescriptor.createFromURL(url));
+ url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + "full/" + ImageConsts.IMAGE_DIR_DLCL + "lock_co.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ registry.put(ImageConsts.ACTION_ScrollLock_Disabled, ImageDescriptor.createFromURL(url));
+ }
+ }
+
+ /**
+ * Loads the image registered under the specified key from the image
+ * registry and returns the <code>Image</code> object instance.
+ *
+ * @param key The key the image is registered with.
+ * @return The <code>Image</code> object instance or <code>null</code>.
+ */
+ public static Image getImage(String key) {
+ return getDefault().getImageRegistry().get(key);
+ }
+
+ /**
+ * Loads the image registered under the specified key from the image
+ * registry and returns the <code>ImageDescriptor</code> object instance.
+ *
+ * @param key The key the image is registered with.
+ * @return The <code>ImageDescriptor</code> object instance or <code>null</code>.
+ */
+ public static ImageDescriptor getImageDescriptor(String key) {
+ return getDefault().getImageRegistry().getDescriptor(key);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/events/SelectionChangedBroadcastEvent.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/events/SelectionChangedBroadcastEvent.java new file mode 100644 index 000000000..1eb267f5d --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/events/SelectionChangedBroadcastEvent.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.events; + +import java.util.EventObject; + +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.tm.te.runtime.events.EventManager; +import org.eclipse.tm.te.ui.terminals.tabs.TabFolderManager; + +/** + * Terminal console selection changed broadcast event. The event is typically fired + * by a terminal console tab folder manager to signal a tab switch to all listeners. + */ +public class SelectionChangedBroadcastEvent extends EventObject { + private static final long serialVersionUID = -4970244776543572896L; + + // The selection changed event to broadcast + private final SelectionChangedEvent selectionChangedEvent; + + /** + * Constructor. + * + * @param source The event source. Must not be <code>null</code>. + * @param selectionChangedEvent The selection changed event or <code>null</code>. + */ + public SelectionChangedBroadcastEvent(TabFolderManager source, SelectionChangedEvent selectionChangedEvent) { + super(source); + this.selectionChangedEvent = selectionChangedEvent; + } + + /** + * Convenience method to return the source tab folder manager. + * + * @return The source tab folder manager. + */ + public TabFolderManager getSourceTabFolderManager() { + return (TabFolderManager)getSource(); + } + + /** + * Returns the broadcasted selection changed event. + * + * @return The broadcasted selection changed event or <code>null</code>. + */ + public SelectionChangedEvent getSelectionChangedEvent() { + return selectionChangedEvent; + } + + /* (non-Javadoc) + * @see java.util.EventObject#toString() + */ + @Override + public String toString() { + StringBuilder toString = new StringBuilder(getClass().getName()); + + String prefix = ""; //$NON-NLS-1$ + // if debugging the event, formating them a little bit better readable. + if (EventManager.isTracingEnabled()) + prefix = "\n\t\t"; //$NON-NLS-1$ + + toString.append(prefix + "source="); //$NON-NLS-1$ + toString.append(source); + toString.append("," + prefix + "selectionChangedEvent="); //$NON-NLS-1$ //$NON-NLS-2$ + toString.append(selectionChangedEvent); + toString.append("}"); //$NON-NLS-1$ + + return toString.toString(); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IPreferenceKeys.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IPreferenceKeys.java new file mode 100644 index 000000000..b07359704 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IPreferenceKeys.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.interfaces; + +/** + * Terminals plug-in preference key definitions. + */ +public interface IPreferenceKeys { + /** + * Preference keys family prefix. + */ + public final String PREF_TERMINAL = "terminals"; //$NON-NLS-1$ + + /** + * Preference key: Remove terminated terminals when a new terminal is created. + */ + public final String PREF_REMOVE_TERMINATED_TERMINALS = PREF_TERMINAL + ".removeTerminatedTerminals"; //$NON-NLS-1$ +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ITerminalsView.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ITerminalsView.java new file mode 100644 index 000000000..3c856f0c1 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ITerminalsView.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.interfaces; + +import org.eclipse.ui.IViewPart; + +/** + * Terminals view public interface. + */ +public interface ITerminalsView extends IViewPart { + + /** + * Switch to the empty page control. + */ + public void switchToEmptyPageControl(); + + /** + * Switch to the tab folder control. + */ + public void switchToTabFolderControl(); + + /** + * Returns the context help id associated with the terminal + * console view instance. + * + * @return The context help id or <code>null</code> if none is associated. + */ + public String getContextHelpId(); +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IUIConstants.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IUIConstants.java new file mode 100644 index 000000000..87fc1307c --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IUIConstants.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.interfaces; + +/** + * Terminals common UI constants. + */ +public interface IUIConstants { + /** + * The view id of the terminals view. + */ + public static final String ID = "org.eclipse.tm.te.ui.terminals.TerminalsView"; //$NON-NLS-1$ + +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ImageConsts.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ImageConsts.java new file mode 100644 index 000000000..0934c14c8 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ImageConsts.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.interfaces; + +/** + * Target Explorer: Image registry constants. + */ +public interface ImageConsts { + /** + * The root directory where to load the images from, relative to + * the bundle directory. + */ + public final static String IMAGE_DIR_ROOT = "icons/"; //$NON-NLS-1$ + + /** + * The directory where to load colored local toolbar images from, + * relative to the image root directory. + */ + public final static String IMAGE_DIR_CLCL = "clcl16/"; //$NON-NLS-1$ + + /** + * The directory where to load disabled local toolbar images from, + * relative to the image root directory. + */ + public final static String IMAGE_DIR_DLCL = "dlcl16/"; //$NON-NLS-1$ + + /** + * The directory where to load enabled local toolbar images from, + * relative to the image root directory. + */ + public final static String IMAGE_DIR_ELCL = "elcl16/"; //$NON-NLS-1$ + + /** + * The directory where to load view related images from, relative to + * the image root directory. + */ + public final static String IMAGE_DIR_EVIEW = "eview16/"; //$NON-NLS-1$ + + /** + * The key to access the terminal consoles view image. + */ + public static final String VIEW_Terminals = "TerminalsView"; //$NON-NLS-1$ + + /** + * The key to access the scroll lock action image (enabled). + */ + public static final String ACTION_ScrollLock_Enabled = "ScrollLockAction_enabled"; //$NON-NLS-1$ + + /** + * The key to access the scroll lock action image (disabled). + */ + public static final String ACTION_ScrollLock_Disabled = "ScrollLockAction_disabled"; //$NON-NLS-1$ + + /** + * The key to access the scroll lock action image (hover). + */ + public static final String ACTION_ScrollLock_Hover = "ScrollLockAction_hover"; //$NON-NLS-1$ +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/PreferenceInitializer.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/PreferenceInitializer.java new file mode 100644 index 000000000..8cb06cc34 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/PreferenceInitializer.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.internal; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.tm.te.runtime.preferences.ScopedEclipsePreferences; +import org.eclipse.tm.te.ui.terminals.activator.UIPlugin; +import org.eclipse.tm.te.ui.terminals.interfaces.IPreferenceKeys; + +/** + * Terminals default preferences initializer. + */ +public class PreferenceInitializer extends AbstractPreferenceInitializer { + + /** + * Constructor. + */ + public PreferenceInitializer() { + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences() + */ + @Override + public void initializeDefaultPreferences() { + ScopedEclipsePreferences prefs = UIPlugin.getScopedPreferences(); + + prefs.putDefaultBoolean(IPreferenceKeys.PREF_REMOVE_TERMINATED_TERMINALS, true); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/SettingsStore.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/SettingsStore.java new file mode 100644 index 000000000..250776a6d --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/SettingsStore.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.internal; + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.te.runtime.properties.PropertiesContainer; + +/** + * Simple default Terminal settings store implementation keeping the settings + * within memory. + */ +@SuppressWarnings("restriction") +public class SettingsStore extends PropertiesContainer implements ISettingsStore { + + /** + * Constructor. + */ + public SettingsStore() { + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore#get(java.lang.String, java.lang.String) + */ + @Override + public String get(String key, String defaultValue) { + String value = getStringProperty(key); + return value != null ? value : defaultValue; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore#get(java.lang.String) + */ + @Override + public String get(String key) { + return getStringProperty(key); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore#put(java.lang.String, java.lang.String) + */ + @Override + public void put(String key, String value) { + setProperty(key, value); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConnectorManager.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConnectorManager.java new file mode 100644 index 000000000..3fd6ffc32 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConnectorManager.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.manager; + +import java.io.InputStream; +import java.io.OutputStream; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalConnectorExtension; +import org.eclipse.tm.internal.terminal.telnet.TelnetSettings; +import org.eclipse.tm.te.ui.terminals.internal.SettingsStore; +import org.eclipse.tm.te.ui.terminals.process.ProcessSettings; +import org.eclipse.tm.te.ui.terminals.streams.StreamsSettings; + + +/** + * Terminal connector manager implementation. + */ +@SuppressWarnings("restriction") +public class ConnectorManager { + + /* + * Thread save singleton instance creation. + */ + private static class LazyInstanceHolder { + public static ConnectorManager instance = new ConnectorManager(); + } + + /** + * Returns the singleton instance for the terminal connector manager. + */ + public static ConnectorManager getInstance() { + return LazyInstanceHolder.instance; + } + + /** + * Constructor. + */ + ConnectorManager() { + super(); + } + + /** + * Creates a terminal connector object based on the given telnet server attributes. + * <p> + * The telnet server attributes must contain 2 elements: + * <ul> + * <li>attributes[0] --> telnet server host name</li> + * <li>attributes[1] --> telnet port</li> + * <li>attributes[2] --> timeout</li> + * </ul> + * + * @param attributes The telnet server attributes. Must not be <code>null</code> and must have at least two elements. + * @param portOffset Offset to add to the port. + * + * @return The terminal connector object instance or <code>null</code>. + */ + public ITerminalConnector createTelnetConnector(String[] attributes) { + return createTelnetConnector(attributes, 0); + } + + /** + * Creates a terminal connector object based on the given telnet server attributes. + * <p> + * The telnet server attributes must contain at least 2 elements: + * <ul> + * <li>attributes[0] --> telnet server host name</li> + * <li>attributes[1] --> telnet port</li> + * <li>attributes[2] --> timeout (optional)</li> + * </ul> + * + * @param attributes The telnet server attributes. Must not be <code>null</code> and must have at least two elements. + * @param portOffset Offset to add to the port. + * + * @return The terminal connector object instance or <code>null</code>. + */ + public ITerminalConnector createTelnetConnector(String[] attributes, int portOffset) { + assert attributes != null && attributes.length >= 2; + + final String serverName = attributes[0]; + final String serverPort = Integer.toString(Integer.decode(attributes[1]).intValue() + portOffset); + final String timeout = attributes.length >= 3 ? attributes[2] : null; + + // Construct the terminal settings store + ISettingsStore store = new SettingsStore(); + + // Construct the telnet settings + TelnetSettings telnetSettings = new TelnetSettings(); + telnetSettings.setHost(serverName); + telnetSettings.setNetworkPort(serverPort); + if (timeout != null) { + telnetSettings.setTimeout(timeout); + } + // And save the settings to the store + telnetSettings.save(store); + + // Construct the terminal connector instance + ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector("org.eclipse.tm.internal.terminal.telnet.TelnetConnector"); //$NON-NLS-1$ + if (connector != null) { + // Apply default settings + connector.makeSettingsPage(); + // And load the real settings + connector.load(store); + } + + return connector; + } + + /** + * Creates a terminal connector object based on the given process image + * and the corresponding process object. + * + * @param connectorTypeId Optional ID of the specific process connector implementation to use. + * If <code>null</code>, the default process connector will be used. + * @param image The process image path. Must not be <code>null</code>. + * @param arguments The process arguments or <code>null</code>. + * @param process The process. Must not be <code>null</code>. + * @param pty The pseudo terminal or <code>null</code>. + * @param localEcho <code>True</code> if the terminal widget local echo shall be enabled, <code>false</code> otherwise. + * + * @return The terminal connector object instance or <code>null</code>. + */ + public ITerminalConnector createProcessConnector(String connectorTypeId, final String image, final String arguments, final Process process, PTY pty, boolean localEcho) { + assert image != null || process != null; + + // Normalize the process connector id + if (connectorTypeId == null) connectorTypeId = "org.eclipse.tm.te.ui.terminals.ProcessConnector"; //$NON-NLS-1$ + + // Construct the terminal settings store + ISettingsStore store = new SettingsStore(); + + // Construct the process settings + ProcessSettings processSettings = new ProcessSettings(); + processSettings.setImage(image); + processSettings.setArguments(arguments); + processSettings.setProcess(process); + processSettings.setPTY(pty); + processSettings.setLocalEcho(localEcho); + // And save the settings to the store + processSettings.save(store); + + // Construct the terminal connector instance + ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector(connectorTypeId); + if (connector != null) { + // Apply default settings + connector.makeSettingsPage(); + // And load the real settings + connector.load(store); + } + + return connector; + } + + /** + * Creates a terminal connector object based on the given stream objects. + * + * @param stdin The stdin stream or <code>null</code>. + * @param stdout The stdout stream or <code>null</code>. + * @param stderr The stderr stream or <code>null</code>. + * @param localEcho <code>True</code> if the terminal widget local echo shall be enabled, <code>false</code> otherwise. + * + * @return The terminal connector object instance or <code>null</code>. + */ + public ITerminalConnector createStreamsConnector(OutputStream stdin, InputStream stdout, InputStream stderr, boolean localEcho) { + + // Construct the terminal settings store + ISettingsStore store = new SettingsStore(); + + // Construct the streams settings + StreamsSettings streamsSettings = new StreamsSettings(); + streamsSettings.setStdinStream(stdin); + streamsSettings.setStdoutStream(stdout); + streamsSettings.setStderrStream(stderr); + streamsSettings.setLocalEcho(localEcho); + // And save the settings to the store + streamsSettings.save(store); + + // Construct the terminal connector instance + ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector("org.eclipse.tm.te.ui.terminals.StreamsConnector"); //$NON-NLS-1$ + if (connector != null) { + // Apply default settings + connector.makeSettingsPage(); + // And load the real settings + connector.load(store); + } + + return connector; + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConsoleManager.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConsoleManager.java new file mode 100644 index 000000000..e2ee3c91d --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConsoleManager.java @@ -0,0 +1,300 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.manager; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.te.ui.terminals.activator.UIPlugin; +import org.eclipse.tm.te.ui.terminals.interfaces.IPreferenceKeys; +import org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView; +import org.eclipse.tm.te.ui.terminals.interfaces.IUIConstants; +import org.eclipse.tm.te.ui.terminals.tabs.TabFolderManager; +import org.eclipse.tm.te.ui.terminals.view.TerminalsView; +import org.eclipse.ui.IPerspectiveDescriptor; +import org.eclipse.ui.IPerspectiveListener; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IViewReference; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PerspectiveAdapter; +import org.eclipse.ui.PlatformUI; + +/** + * Terminals console manager. + */ +@SuppressWarnings("restriction") +public class ConsoleManager { + // Reference to the perspective listener instance + private final IPerspectiveListener perspectiveListener; + + // Internal perspective listener implementation + static class TerminalConsoleManagerPerspectiveListener extends PerspectiveAdapter { + private final List<IViewReference> references = new ArrayList<IViewReference>(); + + /* (non-Javadoc) + * @see org.eclipse.ui.PerspectiveAdapter#perspectiveActivated(org.eclipse.ui.IWorkbenchPage, org.eclipse.ui.IPerspectiveDescriptor) + */ + @Override + public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) { + // If the old references list is empty, just return + if (references.isEmpty()) return; + // Create a copy of the old view references list + List<IViewReference> oldReferences = new ArrayList<IViewReference>(references); + + // Get the current list of view references + List<IViewReference> references = new ArrayList<IViewReference>(Arrays.asList(page.getViewReferences())); + for (IViewReference reference : oldReferences) { + if (references.contains(reference)) continue; + // Previous visible terminal console view reference, make visible again + try { + page.showView(reference.getId(), reference.getSecondaryId(), IWorkbenchPage.VIEW_VISIBLE); + } catch (PartInitException e) { /* Failure on part instantiation is ignored */ } + } + + } + + /* (non-Javadoc) + * @see org.eclipse.ui.PerspectiveAdapter#perspectivePreDeactivate(org.eclipse.ui.IWorkbenchPage, org.eclipse.ui.IPerspectiveDescriptor) + */ + @Override + public void perspectivePreDeactivate(IWorkbenchPage page, IPerspectiveDescriptor perspective) { + references.clear(); + for (IViewReference reference : page.getViewReferences()) { + IViewPart part = reference.getView(false); + if (part instanceof TerminalsView && !references.contains(reference)) { + references.add(reference); + } + } + } + } + + /* + * Thread save singleton instance creation. + */ + private static class LazyInstanceHolder { + public static ConsoleManager fInstance = new ConsoleManager(); + } + + /** + * Returns the singleton instance for the console manager. + */ + public static ConsoleManager getInstance() { + return LazyInstanceHolder.fInstance; + } + + /** + * Constructor. + */ + ConsoleManager() { + super(); + + // Attach the perspective listener + perspectiveListener = new TerminalConsoleManagerPerspectiveListener(); + if (PlatformUI.isWorkbenchRunning() && PlatformUI.getWorkbench() != null && PlatformUI.getWorkbench().getActiveWorkbenchWindow() != null) { + PlatformUI.getWorkbench().getActiveWorkbenchWindow().addPerspectiveListener(perspectiveListener); + } + } + + /** + * Returns the active workbench window page if the workbench is still running. + * + * @return The active workbench window page or <code>null</code> + */ + private final IWorkbenchPage getActiveWorkbenchPage() { + // To lookup the console view, the workbench must be still running + if (PlatformUI.isWorkbenchRunning() && PlatformUI.getWorkbench() != null && PlatformUI.getWorkbench().getActiveWorkbenchWindow() != null) { + return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + } + return null; + } + + /** + * Returns the console view if available within the active workbench window page. + * <p> + * <b>Note:</b> The method must be called within the UI thread. + * + * @param id The terminal console view id or <code>null</code> to show the default terminal console view. + * @return The console view instance if available or <code>null</code> otherwise. + */ + public ITerminalsView findConsoleView(String id) { + assert Display.findDisplay(Thread.currentThread()) != null; + + ITerminalsView view = null; + + // Get the active workbench page + IWorkbenchPage page = getActiveWorkbenchPage(); + if (page != null) { + // Look for the view + IViewPart part = page.findView(id != null ? id : IUIConstants.ID); + // Check the interface + if (part instanceof ITerminalsView) { + view = (ITerminalsView)part; + } + } + + return view; + } + + /** + * Show the terminal console view specified by the given id. + * <p> + * <b>Note:</b> The method must be called within the UI thread. + * + * @param id The terminal console view id or <code>null</code> to show the default terminal console view. + */ + public void showConsoleView(String id) { + assert Display.findDisplay(Thread.currentThread()) != null; + + // Get the active workbench page + IWorkbenchPage page = getActiveWorkbenchPage(); + if (page != null) { + try { + // show the view + IViewPart part = page.showView(id != null ? id : IUIConstants.ID); + // and force the view to the foreground + page.bringToTop(part); + } catch (PartInitException e) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + e.getLocalizedMessage(), e); + UIPlugin.getDefault().getLog().log(status); + } + } + } + + /** + * Bring the terminal console view, specified by the given id, to the top of the view stack. + * + * @param id The terminal console view id or <code>null</code> to show the default terminal console view. + * @param activate If <code>true</code> activate the console view. + */ + private void bringToTop(String id, boolean activate) { + // Get the active workbench page + IWorkbenchPage page = getActiveWorkbenchPage(); + if (page != null) { + // Look for the view + IViewPart part = page.findView(id != null ? id : IUIConstants.ID); + if (part != null) { + if (activate) { + page.activate(part); + } + else { + page.bringToTop(part); + } + } else if (activate) showConsoleView(id != null ? id : IUIConstants.ID); + } + } + + /** + * Opens the console with the given title and connector. + * <p> + * <b>Note:</b> The method must be called within the UI thread. + * + * @param id The terminal console view id or <code>null</code> to show the default terminal console view. + * @param title The console title. Must not be <code>null</code>. + * @param connector The terminal connector. Must not be <code>null</code>. + * @param data The custom terminal data node or <code>null</code>. + * @param activate If <code>true</code> activate the console view. + */ + public void openConsole(String id, String title, ITerminalConnector connector, Object data, boolean activate) { + assert title != null && connector != null; + assert Display.findDisplay(Thread.currentThread()) != null; + + // make the consoles view visible + bringToTop(id, activate); + + // Get the console view + ITerminalsView view = findConsoleView(id); + if (view == null) return; + + // Get the tab folder manager associated with the view + TabFolderManager manager = (TabFolderManager)view.getAdapter(TabFolderManager.class); + if (manager == null) return; + + // Lookup an existing console first + CTabItem item = findConsole(id, title, connector, data); + + // If no existing console exist -> Create the tab item + if (item == null) { + // If configured, check all existing tab items if they are associated + // with terminated consoles + if (UIPlugin.getScopedPreferences().getBoolean(IPreferenceKeys.PREF_REMOVE_TERMINATED_TERMINALS)) { + manager.removeTerminatedItems(); + } + + // Create a new tab item + item = manager.createTabItem(title, connector, data); + } + // If still null, something went wrong + if (item == null) { + return; + } + + // Make the item the active console + manager.bringToTop(item); + + // Show the tab folder page + view.switchToTabFolderControl(); + } + + /** + * Lookup a console with the given title and the given terminal connector. + * <p> + * <b>Note:</b> The method must be called within the UI thread. + * <b>Note:</b> The method will handle unified console titles itself. + * + * @param id The terminal console view id or <code>null</code> to show the default terminal console view. + * @param title The console title. Must not be <code>null</code>. + * @param connector The terminal connector. Must not be <code>null</code>. + * @param data The custom terminal data node or <code>null</code>. + * + * @return The corresponding console tab item or <code>null</code>. + */ + public CTabItem findConsole(String id, String title, ITerminalConnector connector, Object data) { + assert title != null && connector != null; + assert Display.findDisplay(Thread.currentThread()) != null; + + // Get the console view + ITerminalsView view = findConsoleView(id); + if (view == null) return null; + + // Get the tab folder manager associated with the view + TabFolderManager manager = (TabFolderManager)view.getAdapter(TabFolderManager.class); + if (manager == null) return null; + + return manager.findTabItem(title, connector, data); + } + + /** + * Close the console with the given title and the given terminal connector. + * <p> + * <b>Note:</b> The method must be called within the UI thread. + * <b>Note:</b> The method will handle unified console titles itself. + * + * @param title The console title. Must not be <code>null</code>. + * @param connector The terminal connector. Must not be <code>null</code>. + * @param data The custom terminal data node or <code>null</code>. + */ + public void closeConsole(String id, String title, ITerminalConnector connector, Object data) { + assert title != null && connector != null; + assert Display.findDisplay(Thread.currentThread()) != null; + + // Lookup the console + CTabItem console = findConsole(id, title, connector, data); + // If found, dispose the console + if (console != null) console.dispose(); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.java new file mode 100644 index 000000000..c5cf6b22f --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.nls; + +import org.eclipse.osgi.util.NLS; + +/** + * Terminals plug-in externalized strings management. + */ +public class Messages extends NLS { + + // The plug-in resource bundle name + private static final String BUNDLE_NAME = "org.eclipse.tm.te.ui.terminals.nls.Messages"; //$NON-NLS-1$ + + /** + * Static constructor. + */ + static { + // Load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + // **** Declare externalized string id's down here ***** + + public static String AbstractAction_error_commandExecutionFailed; + + public static String TabTerminalListener_consoleTerminated; + + public static String ProcessSettingsPage_dialogTitle; + public static String ProcessSettingsPage_processImagePathSelectorControl_label; + public static String ProcessSettingsPage_processImagePathSelectorControl_button; + public static String ProcessSettingsPage_processArgumentsControl_label; + public static String ProcessSettingsPage_localEchoSelectorControl_label; + + public static String OutputStreamMonitor_error_readingFromStream; + + public static String InputStreamMonitor_error_writingToStream; + + public static String ProcessConnector_error_creatingProcess; +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.properties new file mode 100644 index 000000000..992eeb80e --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.properties @@ -0,0 +1,20 @@ +# +# org.eclipse.tm.te.ui.terminals +# Externalized Strings. +# + +AbstractAction_error_commandExecutionFailed="Failed to execute command (id = {0}). Possibly caused by: {1} + +TabTerminalListener_consoleTerminated=<terminated> {0} + +ProcessSettingsPage_dialogTitle=Select Process Image +ProcessSettingsPage_processImagePathSelectorControl_label=Image Path: +ProcessSettingsPage_processImagePathSelectorControl_button=Browse +ProcessSettingsPage_processArgumentsControl_label=Arguments: +ProcessSettingsPage_localEchoSelectorControl_label=Local Echo + +OutputStreamMonitor_error_readingFromStream=Exception when reading from stream. Possibly caused by: {0} + +InputStreamMonitor_error_writingToStream=Exception when writing to stream. Possibly caused by: {0} + +ProcessConnector_error_creatingProcess=Exception when creating process. Possibly caused by: {0} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessConnector.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessConnector.java new file mode 100644 index 000000000..84f9df3c0 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessConnector.java @@ -0,0 +1,425 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.process; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StreamTokenizer; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.cdt.utils.spawner.ProcessFactory; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.service.environment.Constants; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.te.ui.terminals.activator.UIPlugin; +import org.eclipse.tm.te.ui.terminals.nls.Messages; +import org.eclipse.tm.te.ui.terminals.streams.AbstractStreamsConnector; + +/** + * Process connector implementation. + */ +@SuppressWarnings("restriction") +public class ProcessConnector extends AbstractStreamsConnector { + // Reference to the process settings + private final ProcessSettings settings; + + // Reference to the PTY instance. + private PTY pty; + // Reference to the launched process instance. + private Process process; + // Reference to the process monitor + private ProcessMonitor monitor; + + // The terminal width and height. Initially unknown. + private int width = -1; + private int height = -1; + + /** + * Constructor. + */ + public ProcessConnector() { + this(new ProcessSettings()); + } + + /** + * Constructor. + * + * @param settings The process settings. Must not be <code>null</code> + */ + public ProcessConnector(ProcessSettings settings) { + super(); + + Assert.isNotNull(settings); + this.settings = settings; + } + + /** + * Returns the process object or <code>null</code> if the + * connector is connector. + * + * @return The process object or <code>null</code>. + */ + public Process getProcess() { + return process; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#connect(org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl) + */ + @Override + public void connect(ITerminalControl control) { + assert control != null; + super.connect(control); + + pty = null; + width = -1; + height = -1; + + try { + // Try to determine process and PTY instance from the process settings + process = settings.getProcess(); + pty = settings.getPTY(); + + // No process -> create PTY on supported platforms and execute + // process image. + if (process == null) { + if (PTY.isSupported()) { + try { + pty = new PTY(false); + } catch (IOException e) { + // PTY not supported on windows + } + } + + // Build up the command + StringBuilder command = new StringBuilder(settings.getImage()); + String arguments = settings.getArguments(); + if (arguments != null && !"".equals(arguments.trim())) { //$NON-NLS-1$ + // Append to the command now + command.append(" "); //$NON-NLS-1$ + command.append(arguments.trim()); + } + + if (pty != null) { + // A PTY is available -> can use the ProcessFactory. + + // Tokenize the command (ProcessFactory takes an array) + StreamTokenizer st = new StreamTokenizer(new StringReader(command.toString())); + st.resetSyntax(); + st.whitespaceChars(0, 32); + st.whitespaceChars(0xa0, 0xa0); + st.wordChars(33, 255); + st.quoteChar('"'); + st.quoteChar('\''); + + List<String> argv = new ArrayList<String>(); + int ttype = st.nextToken(); + while (ttype != StreamTokenizer.TT_EOF) { + argv.add(st.sval); + ttype = st.nextToken(); + } + + // Execute the process + process = ProcessFactory.getFactory().exec(argv.toArray(new String[argv.size()]), getProcessEnvironment(), null, pty); + } else { + // No PTY -> just execute via the standard Java Runtime implementation. + process = Runtime.getRuntime().exec(command.toString()); + } + } + + // connect the streams + connectStreams(control, process.getOutputStream(), process.getInputStream(), (pty == null ? process.getErrorStream() : null)); + + // Set the terminal control state to CONNECTED + control.setState(TerminalState.CONNECTED); + + // Create the process monitor + monitor = new ProcessMonitor(this); + monitor.startMonitoring(); + } catch (Exception e) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + NLS.bind(Messages.ProcessConnector_error_creatingProcess, e.getLocalizedMessage()), e); + UIPlugin.getDefault().getLog().log(status); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#isLocalEcho() + */ + @Override + public boolean isLocalEcho() { + return settings.isLocalEcho(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#doDisconnect() + */ + @Override + public void doDisconnect() { + // Dispose the process + if (process != null) { process.destroy(); process = null; } + + // Dispose the streams + super.doDisconnect(); + + // Set the terminal control state to CLOSED. + fControl.setState(TerminalState.CLOSED); + } + + // ***** Process Connector settings handling ***** + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#makeSettingsPage() + */ + @Override + public ISettingsPage makeSettingsPage() { + return new ProcessSettingsPage(settings); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#getSettingsSummary() + */ + @Override + public String getSettingsSummary() { + return settings.getImage() != null ? settings.getImage() : ""; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#load(org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore) + */ + @Override + public void load(ISettingsStore store) { + settings.load(store); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#save(org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore) + */ + @Override + public void save(ISettingsStore store) { + settings.save(store); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#setTerminalSize(int, int) + */ + @Override + public void setTerminalSize(int newWidth, int newHeight) { + if (width != newWidth || height != newHeight) { + width = newWidth; + height = newHeight; + if (pty != null) { + pty.setTerminalSize(newWidth, newHeight); + } + } + } + + // ***** Process Environment Handling ***** + + // Reference to the monitor to lock if determining the native environment + private final static Object ENV_GET_MONITOR = new Object(); + + // Reference to the native environment once retrieved + private static Map<String, String> nativeEnvironment = null; + // Reference to the native environment with the case of the variable names preserved + private static Map<String, String> nativeEnvironmentCasePreserved = null; + + /** + * Returns the specific environment to set for the process to be launched. + * + * @return The process environment. + */ + private static String[] getProcessEnvironment() { + Map<String, String> env = getNativeEnvironment(); + + env.put("TERM", "vt100"); //$NON-NLS-1$ //$NON-NLS-2$ + + Iterator<Map.Entry<String, String>> iter = env.entrySet().iterator(); + List<String> strings = new ArrayList<String>(env.size()); + StringBuffer buffer = null; + while (iter.hasNext()) { + Map.Entry<String, String>entry = iter.next(); + buffer = new StringBuffer(entry.getKey()); + buffer.append('=').append(entry.getValue()); + strings.add(buffer.toString()); + } + + return strings.toArray(new String[strings.size()]); + } + + /** + * Determine the native environment, but returns all environment variable + * names in upper case. + * + * @return The native environment with upper case variable names, or an empty map. + */ + private static Map<String, String> getNativeEnvironment() { + synchronized (ENV_GET_MONITOR) { + if (nativeEnvironment == null) { + Map<String, String> casePreserved = getNativeEnvironmentCasePreserved(); + if (Platform.getOS().equals(org.eclipse.osgi.service.environment.Constants.OS_WIN32)) { + nativeEnvironment = new HashMap<String, String>(); + Iterator<Map.Entry<String, String>> entries = casePreserved.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry<String, String> entry = entries.next(); + nativeEnvironment.put(entry.getKey().toUpperCase(), entry.getValue()); + } + } else { + nativeEnvironment = new HashMap<String, String>(casePreserved); + } + } + return new HashMap<String, String>(nativeEnvironment); + } + } + + /** + * Determine the native environment. + * + * @return The native environment, or an empty map. + */ + private static Map<String, String> getNativeEnvironmentCasePreserved() { + synchronized (ENV_GET_MONITOR) { + if (nativeEnvironmentCasePreserved == null) { + nativeEnvironmentCasePreserved= new HashMap<String, String>(); + cacheNativeEnvironment(nativeEnvironmentCasePreserved); + } + return new HashMap<String, String>(nativeEnvironmentCasePreserved); + } + } + + /** + * Query the native environment and store it to the specified cache. + * + * @param cache The environment cache. Must not be <code>null</code>. + */ + private static void cacheNativeEnvironment(Map<String, String> cache) { + Assert.isNotNull(cache); + + try { + String nativeCommand = null; + boolean isWin9xME = false; // see bug 50567 + String fileName = null; + if (Platform.getOS().equals(Constants.OS_WIN32)) { + String osName = System.getProperty("os.name"); //$NON-NLS-1$ + isWin9xME = osName != null && (osName.startsWith("Windows 9") || osName.startsWith("Windows ME")); //$NON-NLS-1$ //$NON-NLS-2$ + if (isWin9xME) { + // Win 95, 98, and ME + // SET might not return therefore we pipe into a file + IPath stateLocation = UIPlugin.getDefault().getStateLocation(); + fileName = stateLocation.toOSString() + File.separator + "env.txt"; //$NON-NLS-1$ + nativeCommand = "command.com /C set > " + fileName; //$NON-NLS-1$ + } else { + // Win NT, 2K, XP + nativeCommand = "cmd.exe /C set"; //$NON-NLS-1$ + } + } else if (!Platform.getOS().equals(Constants.OS_UNKNOWN)) { + nativeCommand = "env"; //$NON-NLS-1$ + } + if (nativeCommand == null) { return; } + Process process = Runtime.getRuntime().exec(nativeCommand); + if (isWin9xME) { + // read piped data on Win 95, 98, and ME + Properties p = new Properties(); + File file = new File(fileName); + InputStream stream = new BufferedInputStream(new FileInputStream(file)); + p.load(stream); + stream.close(); + if (!file.delete()) { + file.deleteOnExit(); // if delete() fails try again on VM close + } + for (Enumeration<Object> enumeration = p.keys(); enumeration.hasMoreElements();) { + // Win32's environment variables are case insensitive. Put everything + // to upper case so that (for example) the "PATH" variable will match + // "pAtH" correctly on Windows. + String key = (String)enumeration.nextElement(); + cache.put(key, (String)p.get(key)); + } + } else { + // read process directly on other platforms + // we need to parse out matching '{' and '}' for function declarations in .bash environments + // pattern is [function name]=() { and we must find the '}' on its own line with no trailing ';' + InputStream stream = process.getInputStream(); + InputStreamReader isreader = new InputStreamReader(stream); + BufferedReader reader = new BufferedReader(isreader); + String line = reader.readLine(); + String key = null; + String value = null; + while (line != null) { + int func = line.indexOf("=()"); //$NON-NLS-1$ + if (func > 0) { + key = line.substring(0, func); + // scan until we find the closing '}' with no following chars + value = line.substring(func + 1); + while (line != null && !line.equals("}")) { //$NON-NLS-1$ + line = reader.readLine(); + if (line != null) { + value += line; + } + } + line = reader.readLine(); + } else { + int separator = line.indexOf('='); + if (separator > 0) { + key = line.substring(0, separator); + value = line.substring(separator + 1); + line = reader.readLine(); + if (line != null) { + // this line has a '=' read ahead to check next line for '=', might be broken on more + // than one line + separator = line.indexOf('='); + while (separator < 0) { + value += line.trim(); + line = reader.readLine(); + if (line == null) { + // if next line read is the end of the file quit the loop + break; + } + separator = line.indexOf('='); + } + } + } + } + if (key != null) { + cache.put(key, value); + key = null; + value = null; + } else { + line = reader.readLine(); + } + } + reader.close(); + } + } catch (IOException e) { + // Native environment-fetching code failed. + // This can easily happen and is not useful to log. + } + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessMonitor.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessMonitor.java new file mode 100644 index 000000000..98c9d6073 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessMonitor.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.process; + +import org.eclipse.core.runtime.Assert; + + +/** + * Process monitor implementation. + */ +public class ProcessMonitor { + // Reference to the parent process connector + private final ProcessConnector processConnector; + // Reference to the monitored process + private final Process process; + // Reference to the monitor thread + private Thread thread; + // Flag to mark the monitor disposed + private boolean disposed; + + + /** + * Constructor. + * + * @param processConnector The parent process connector. Must not be <code>null</code>. + */ + public ProcessMonitor(ProcessConnector processConnector) { + super(); + + Assert.isNotNull(processConnector); + this.processConnector = processConnector; + + // Query the monitored process for easier access + this.process = processConnector.getProcess(); + } + + /** + * Dispose the process monitor. + */ + public void dispose() { + // Set the disposed status + disposed = true; + // Not initialized -> return immediately + if (thread == null) return; + + // Copy the reference + final Thread oldThread = thread; + // Unlink the monitor from the thread + thread = null; + // And interrupt the writer thread + oldThread.interrupt(); + } + + /** + * Starts the terminal output stream monitor. + */ + public void startMonitoring() { + // If already initialized -> return immediately + if (thread != null) return; + + // Create a new runnable which is constantly reading from the stream + Runnable runnable = new Runnable() { + @Override + public void run() { + monitorProcess(); + } + }; + + // Create the monitor thread + thread = new Thread(runnable, "Terminal Process Monitor Thread"); //$NON-NLS-1$ + + // Configure the monitor thread + thread.setDaemon(true); + + // Start the processing + thread.start(); + } + + /** + * Monitors the associated system process, waiting for it to terminate, + * and notifies the associated process monitor's. + */ + @SuppressWarnings("restriction") + public void monitorProcess() { + // If already disposed -> return immediately + if (disposed) return; + + try { + // Wait for the monitored process to terminate + process.waitFor(); + } catch (InterruptedException ie) { + // clear interrupted state + Thread.interrupted(); + } finally { + // Dispose the parent process connector + processConnector.disconnect(); + } + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettings.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettings.java new file mode 100644 index 000000000..5976fdfed --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettings.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.process; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.te.runtime.interfaces.properties.IPropertiesContainer; + +/** + * Process connector settings implementation. + */ +@SuppressWarnings("restriction") +public class ProcessSettings { + // Reference to the process image + private String image; + // Reference to the process arguments (space separated string) + private String arguments; + // Reference to the process object + private Process process; + // Reference to the pseudo terminal object + private PTY pty; + // Flag to control the local echo (defaults to true if + // the PTY is not supported on the current host platform) + private boolean localEcho = !PTY.isSupported(); + + /** + * Sets the process image. + * + * @param image The process image or <code>null</code>. + */ + public void setImage(String image) { + this.image = image; + } + + /** + * Returns the process image. + * + * @return The process image or <code>null</code>. + */ + public String getImage() { + return image; + } + + /** + * Sets the process arguments. + * <p> + * The arguments are space separated. The caller is responsible for + * correct quoting. + * + * @param arguments The process arguments or <code>null</code>. + */ + public void setArguments(String arguments) { + this.arguments = arguments; + } + + /** + * Returns the process arguments. + * + * @return The process arguments as space separated list or <code>null</code>. + */ + public String getArguments() { + return arguments; + } + + /** + * Sets the process object. + * + * @param image The process object or <code>null</code>. + */ + public void setProcess(Process process) { + this.process = process; + } + + /** + * Returns the process object. + * + * @return The process object or <code>null</code>. + */ + public Process getProcess() { + return process; + } + + /** + * Sets the pseudo terminal object. + * + * @param pty The pseudo terminal or <code>null</code>. + */ + public void setPTY(PTY pty) { + this.pty = pty; + // If the PTY is set to "null", the local echo will be set to "true" + if (pty == null) setLocalEcho(true); + } + + /** + * Returns the pseudo terminal object. + * + * @return The pseudo terminal or <code>null</code>. + */ + public PTY getPTY() { + return pty; + } + + /** + * Sets if the process requires a local echo from the + * terminal widget. + * + * @param value Specify <code>true</code> to enable the local echo, <code>false</code> otherwise. + */ + public void setLocalEcho(boolean value) { + this.localEcho = value; + } + + /** + * Returns <code>true</code> if the process requires a local echo + * from the terminal widget. + * + * @return <code>True</code> if local echo is enabled, <code>false</code> otherwise. + */ + public boolean isLocalEcho() { + return localEcho; + } + + /** + * Loads the process settings from the given settings store. + * + * @param store The settings store. Must not be <code>null</code>. + */ + public void load(ISettingsStore store) { + Assert.isNotNull(store); + image = store.get("Path", null);//$NON-NLS-1$ + arguments = store.get("Arguments", null); //$NON-NLS-1$ + localEcho = Boolean.parseBoolean(store.get("LocalEcho", Boolean.FALSE.toString())); //$NON-NLS-1$ + if (store instanceof IPropertiesContainer) { + process = (Process)((IPropertiesContainer)store).getProperty("Process"); //$NON-NLS-1$ + pty = (PTY)((IPropertiesContainer)store).getProperty("PTY"); //$NON-NLS-1$ + } + } + + /** + * Saves the process settings to the given settings store. + * + * @param store The settings store. Must not be <code>null</code>. + */ + public void save(ISettingsStore store) { + Assert.isNotNull(store); + store.put("Path", image);//$NON-NLS-1$ + store.put("Arguments", arguments); //$NON-NLS-1$ + store.put("LocalEcho", Boolean.toString(localEcho)); //$NON-NLS-1$ + if (store instanceof IPropertiesContainer) { + ((IPropertiesContainer)store).setProperty("Process", process); //$NON-NLS-1$ + ((IPropertiesContainer)store).setProperty("PTY", pty); //$NON-NLS-1$ + } + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettingsPage.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettingsPage.java new file mode 100644 index 000000000..af7a4e60b --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettingsPage.java @@ -0,0 +1,187 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.process; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage; +import org.eclipse.tm.te.ui.swt.SWTControlUtil; +import org.eclipse.tm.te.ui.terminals.nls.Messages; +import org.eclipse.ui.PlatformUI; +import org.osgi.framework.Bundle; + +/** + * Process connector settings page implementation. + */ +@SuppressWarnings("restriction") +public class ProcessSettingsPage implements ISettingsPage { + private Text processImageSelectorControl; + private Button processImageSelectorControlButton; + private Text processArgumentsControl; + private Button localEchoSelectorControl; + + private final ProcessSettings settings; + + /** + * Constructor. + * + * @param settings + */ + public ProcessSettingsPage(ProcessSettings settings) { + super(); + + Assert.isNotNull(settings); + this.settings = settings; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#createControl(org.eclipse.swt.widgets.Composite) + */ + @Override + public void createControl(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayout(new GridLayout()); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + + // The entry fields shall be properly aligned + Composite panel = new Composite(composite, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.marginWidth = 0; layout.marginHeight = 0; + panel.setLayout(layout); + panel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + // Create the process image selector control + Label label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.ProcessSettingsPage_processImagePathSelectorControl_label); + + // Text field and browse button are aligned it their own panel + Composite innerPanel = new Composite(panel, SWT.NONE); + layout = new GridLayout(2, false); + layout.marginWidth = 0; layout.marginHeight = 0; + innerPanel.setLayout(layout); + innerPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + processImageSelectorControl = new Text(innerPanel, SWT.SINGLE | SWT.BORDER); + processImageSelectorControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + processImageSelectorControlButton = new Button(innerPanel, SWT.PUSH); + processImageSelectorControlButton.setText(Messages.ProcessSettingsPage_processImagePathSelectorControl_button); + processImageSelectorControlButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + onBrowseButtonSelected(e); + } + }); + + // Create the process arguments control + label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.ProcessSettingsPage_processArgumentsControl_label); + + processArgumentsControl = new Text(panel, SWT.SINGLE | SWT.BORDER); + processArgumentsControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + // Create the local echo check box + localEchoSelectorControl = new Button(composite, SWT.CHECK); + localEchoSelectorControl.setText(Messages.ProcessSettingsPage_localEchoSelectorControl_label); + localEchoSelectorControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + localEchoSelectorControl.setSelection(!PTY.isSupported()); + + // Initialize the control content + loadSettings(); + } + + /** + * Called once the user pressed the browse button. + * + * @param e The selection event or <code>null</code>. + */ + protected void onBrowseButtonSelected(SelectionEvent e) { + // Determine the shell + Shell shell = e != null ? e.widget.getDisplay().getActiveShell() : PlatformUI.getWorkbench().getDisplay().getActiveShell(); + + // create a standard file dialog + FileDialog dialog = new FileDialog(shell, SWT.OPEN); + dialog.setText(Messages.ProcessSettingsPage_dialogTitle); + + // the dialog should open within the directory of the currently selected + // file. If no file has been currently selected, it should open within the + // last browsed directory. + String selectedFile = SWTControlUtil.getText(processImageSelectorControl); + if (selectedFile != null && selectedFile.trim().length() > 0) { + IPath filePath = new Path(selectedFile); + // If the selected file points to an directory, use the directory as is + IPath filterPath = filePath.toFile().isDirectory() ? filePath : filePath.removeLastSegments(1); + String filterFileName = filePath.toFile().isDirectory() || !filePath.toFile().exists() ? null : filePath.lastSegment(); + + if (!filterPath.isEmpty()) { + dialog.setFilterPath(filterPath.toString()); + } + if (filterFileName != null) { + dialog.setFileName(filterFileName); + } + } else { + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.ACTIVE)) { + dialog.setFilterPath(org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString()); + } + } + + // Open the dialog + selectedFile = dialog.open(); + if (selectedFile != null) { + SWTControlUtil.setText(processImageSelectorControl, selectedFile); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#saveSettings() + */ + @Override + public void saveSettings() { + settings.setImage(SWTControlUtil.getText(processImageSelectorControl)); + settings.setArguments(SWTControlUtil.getText(processArgumentsControl)); + settings.setLocalEcho(SWTControlUtil.getSelection(localEchoSelectorControl)); + settings.setProcess(null); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#loadSettings() + */ + @Override + public void loadSettings() { + SWTControlUtil.setText(processImageSelectorControl, settings.getImage()); + SWTControlUtil.setText(processArgumentsControl, settings.getArguments()); + SWTControlUtil.setSelection(localEchoSelectorControl, settings.isLocalEcho()); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#validateSettings() + */ + @Override + public boolean validateSettings() { + // The settings are considered valid if the selected process image can be read. + String selectedFile = SWTControlUtil.getText(processImageSelectorControl); + return selectedFile != null && !"".equals(selectedFile.trim()) && new Path(selectedFile).toFile().canRead(); //$NON-NLS-1$ + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/AbstractStreamsConnector.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/AbstractStreamsConnector.java new file mode 100644 index 000000000..18e14fcfc --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/AbstractStreamsConnector.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.streams; + +import java.io.InputStream; +import java.io.OutputStream; + +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; +import org.eclipse.ui.services.IDisposable; + +/** + * Streams connector implementation. + */ +@SuppressWarnings("restriction") +public abstract class AbstractStreamsConnector extends TerminalConnectorImpl { + // Reference to the stdin monitor + private InputStreamMonitor stdInMonitor; + // Reference to the stdout monitor + private OutputStreamMonitor stdOutMonitor; + // Reference to the stderr monitor + private OutputStreamMonitor stdErrMonitor; + + /** + * Connect the given streams. The streams connector will wrap each stream + * with a corresponding terminal stream monitor. + * + * @param terminalControl The terminal control. Must not be <code>null</code>. + * @param stdin The stdin stream or <code>null</code>. + * @param stdout The stdout stream or <code>null</code>. + * @param stderr The stderr stream or <code>null</code>. + */ + protected void connectStreams(ITerminalControl terminalControl, OutputStream stdin, InputStream stdout, InputStream stderr) { + assert terminalControl != null; + + // Create the input stream monitor + if (stdin != null) { + stdInMonitor = createStdInMonitor(terminalControl, stdin); + // Register the connector if it implements IDisposable and stdout/stderr are not monitored + if (stdout == null && stderr == null && this instanceof IDisposable) stdInMonitor.addDisposable((IDisposable)this); + // Start the monitoring + stdInMonitor.startMonitoring(); + } + + // Create the output stream monitor + if (stdout != null) { + stdOutMonitor = createStdOutMonitor(terminalControl, stdout); + // Register the connector if it implements IDisposable + if (this instanceof IDisposable) stdOutMonitor.addDisposable((IDisposable)this); + // Start the monitoring + stdOutMonitor.startMonitoring(); + } + + // Create the error stream monitor + if (stderr != null) { + stdErrMonitor = createStdErrMonitor(terminalControl, stderr); + // Register the connector if it implements IDisposable and stdout is not monitored + if (stdout == null && this instanceof IDisposable) stdErrMonitor.addDisposable((IDisposable)this); + // Start the monitoring + stdErrMonitor.startMonitoring(); + } + } + + /** + * Creates an stdin monitor for the given terminal control and stdin stream. + * Subclasses may override to create a specialized stream monitor. + * + * @param terminalControl The terminal control. Must not be <code>null</code>. + * @param stdin The stdin stream or <code>null</code>. + * @return input stream monitor + */ + protected InputStreamMonitor createStdInMonitor(ITerminalControl terminalControl, OutputStream stdin) { + return new InputStreamMonitor(terminalControl, stdin); + } + + /** + * Creates an stdout monitor for the given terminal control and stdout stream. + * Subclasses may override to create a specialized stream monitor. + * + * @param terminalControl The terminal control. Must not be <code>null</code>. + * @param stdout The stdout stream or <code>null</code>. + * @return output stream monitor + */ + protected OutputStreamMonitor createStdOutMonitor(ITerminalControl terminalControl, InputStream stdout) { + return new OutputStreamMonitor(terminalControl, stdout); + } + + /** + * Creates an stderr monitor for the given terminal control and stderr stream. + * Subclasses may override to create a specialized stream monitor. + * + * @param terminalControl The terminal control. Must not be <code>null</code>. + * @param stderr The stderr stream or <code>null</code>. + * @return output stream monitor + */ + protected OutputStreamMonitor createStdErrMonitor(ITerminalControl terminalControl, InputStream stderr) { + return new OutputStreamMonitor(terminalControl, stderr); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#doDisconnect() + */ + @Override + protected void doDisconnect() { + // Dispose the streams + if (stdInMonitor != null) { stdInMonitor.dispose(); stdInMonitor = null; } + if (stdOutMonitor != null) { stdOutMonitor.dispose(); stdOutMonitor = null; } + if (stdErrMonitor != null) { stdErrMonitor.dispose(); stdErrMonitor = null; } + + super.doDisconnect(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#getTerminalToRemoteStream() + */ + @Override + public OutputStream getTerminalToRemoteStream() { + return stdInMonitor; + } + +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/InputStreamMonitor.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/InputStreamMonitor.java new file mode 100644 index 000000000..d47c53319 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/InputStreamMonitor.java @@ -0,0 +1,215 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.streams; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.te.ui.terminals.activator.UIPlugin; +import org.eclipse.tm.te.ui.terminals.nls.Messages; +import org.eclipse.ui.services.IDisposable; + +/** + * Input stream monitor implementation. + * <p> + * <b>Note:</b> The input is coming <i>from</i> the terminal. Therefore, the input + * stream monitor is attached to the stdin stream of the monitored (remote) process. + */ +@SuppressWarnings("restriction") +public class InputStreamMonitor extends OutputStream implements IDisposable { + // Reference to the parent terminal control + @SuppressWarnings("unused") + private final ITerminalControl terminalControl; + + // Reference to the monitored (output) stream + private final OutputStream stream; + + // Reference to the thread writing the stream + private Thread thread; + + // Flag to mark the monitor disposed. When disposed, + // no further data is written from the monitored stream. + private boolean disposed; + + // A list of object to dispose if this monitor is disposed + private final List<IDisposable> disposables = new ArrayList<IDisposable>(); + + // Queue to buffer the data to write to the output stream + private final Queue<byte[]> queue = new LinkedList<byte[]>(); + + /** + * Constructor. + * + * @param terminalControl The parent terminal control. Must not be <code>null</code>. + * @param stream The stream. Must not be <code>null</code>. + */ + public InputStreamMonitor(ITerminalControl terminalControl, OutputStream stream) { + super(); + + Assert.isNotNull(terminalControl); + this.terminalControl = terminalControl; + Assert.isNotNull(stream); + this.stream = stream; + } + + /** + * Adds the given disposable object to the list. The method will do nothing + * if either the disposable object is already part of the list or the monitor + * is disposed. + * + * @param disposable The disposable object. Must not be <code>null</code>. + */ + public final void addDisposable(IDisposable disposable) { + assert disposable != null; + if (!disposed && !disposables.contains(disposable)) disposables.add(disposable); + } + + /** + * Removes the disposable object from the list. + * + * @param disposable The disposable object. Must not be <code>null</code>. + */ + public final void removeDisposable(IDisposable disposable) { + assert disposable != null; + disposables.remove(disposable); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.services.IDisposable#dispose() + */ + @Override + public void dispose() { + // If already disposed --> return immediately + if (disposed) return; + + // Mark the monitor disposed + disposed = true; + + // Close the stream (ignore exceptions on close) + try { stream.close(); } catch (IOException e) { /* ignored on purpose */ } + // And interrupt the thread + close(); + + // Dispose all registered disposable objects + for (IDisposable disposable : disposables) disposable.dispose(); + // Clear the list + disposables.clear(); + } + + /** + * Close the terminal input stream monitor. + */ + @Override + public void close() { + // Not initialized -> return immediately + if (thread == null) return; + + // Copy the reference + final Thread oldThread = thread; + // Unlink the monitor from the thread + thread = null; + // And interrupt the writer thread + oldThread.interrupt(); + } + + /** + * Starts the terminal output stream monitor. + */ + public void startMonitoring() { + // If already initialized -> return immediately + if (thread != null) return; + + // Create a new runnable which is constantly reading from the stream + Runnable runnable = new Runnable() { + @Override + public void run() { + writeStream(); + } + }; + + // Create the writer thread + thread = new Thread(runnable, "Terminal Input Stream Monitor Thread"); //$NON-NLS-1$ + + // Configure the writer thread + thread.setDaemon(true); + + // Start the processing + thread.start(); + } + + + /** + * Reads from the queue and writes the read content to the stream. + */ + protected void writeStream() { + // Read from the queue and write to the stream until disposed + while (thread != null && !disposed) { + // If the queue is empty, wait until notified + if (queue.isEmpty()) { + synchronized(queue) { + try { queue.wait(); } catch (InterruptedException e) { /* ignored on purpose */ } + } + } + + // If the queue is not empty, take the first element + // and write the data to the stream + while (!queue.isEmpty() && !disposed) { + // Retrieves the queue head (is null if queue is empty (should never happen)) + byte[] data = queue.poll(); + if (data != null) { + try { + // Write the data to the stream + stream.write(data); + // Flush the stream immediately + stream.flush(); + } catch (IOException e) { + // IOException received. If this is happening when already disposed -> ignore + if (!disposed) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + NLS.bind(Messages.InputStreamMonitor_error_writingToStream, e.getLocalizedMessage()), e); + UIPlugin.getDefault().getLog().log(status); + } + } + } + } + } + + // Dispose the stream + dispose(); + } + + /* (non-Javadoc) + * @see java.io.OutputStream#write(int) + */ + @Override + public void write(int b) throws IOException { + synchronized(queue) { + queue.add(new byte[] { (byte)b }); + queue.notifyAll(); + } + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + // Make sure that the written block is not interlaced with other input. + synchronized(queue) { + super.write(b, off, len); + } + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/OutputStreamMonitor.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/OutputStreamMonitor.java new file mode 100644 index 000000000..ea8ab62fc --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/OutputStreamMonitor.java @@ -0,0 +1,222 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.streams; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.te.ui.terminals.activator.UIPlugin; +import org.eclipse.tm.te.ui.terminals.nls.Messages; +import org.eclipse.ui.services.IDisposable; + +/** + * Output stream monitor implementation. + * <p> + * <b>Note:</b> The output is going <i>to</i> the terminal. Therefore, the output + * stream monitor is attached to the stdout and/or stderr stream of the monitored + * (remote) process. + */ +@SuppressWarnings("restriction") +public class OutputStreamMonitor implements IDisposable { + // The default buffer size to use + private static final int BUFFER_SIZE = 8192; + + // Reference to the parent terminal control + private final ITerminalControl terminalControl; + + // Reference to the monitored (input) stream + private final InputStream stream; + + // Reference to the thread reading the stream + private Thread thread; + + // Flag to mark the monitor disposed. When disposed, + // no further data is read from the monitored stream. + private boolean disposed; + + // A list of object to dispose if this monitor is disposed + private final List<IDisposable> disposables = new ArrayList<IDisposable>(); + + /** + * Constructor. + * + * @param terminalControl The parent terminal control. Must not be <code>null</code>. + * @param stream The stream. Must not be <code>null</code>. + */ + public OutputStreamMonitor(ITerminalControl terminalControl, InputStream stream) { + super(); + + Assert.isNotNull(terminalControl); + this.terminalControl = terminalControl; + Assert.isNotNull(stream); + this.stream = new BufferedInputStream(stream, BUFFER_SIZE); + } + + /** + * Adds the given disposable object to the list. The method will do nothing + * if either the disposable object is already part of the list or the monitor + * is disposed. + * + * @param disposable The disposable object. Must not be <code>null</code>. + */ + public final void addDisposable(IDisposable disposable) { + assert disposable != null; + if (!disposed && !disposables.contains(disposable)) disposables.add(disposable); + } + + /** + * Removes the disposable object from the list. + * + * @param disposable The disposable object. Must not be <code>null</code>. + */ + public final void removeDisposable(IDisposable disposable) { + assert disposable != null; + disposables.remove(disposable); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.services.IDisposable#dispose() + */ + @Override + public void dispose() { + // If already disposed --> return immediately + if (disposed) return; + + // Mark the monitor disposed + disposed = true; + + // Close the stream (ignore exceptions on close) + try { stream.close(); } catch (IOException e) { /* ignored on purpose */ } + + // Dispose all registered disposable objects + for (IDisposable disposable : disposables) disposable.dispose(); + // Clear the list + disposables.clear(); + } + + /** + * Starts the terminal output stream monitor. + */ + protected void startMonitoring() { + // If already initialized -> return immediately + if (thread != null) return; + + // Create a new runnable which is constantly reading from the stream + Runnable runnable = new Runnable() { + @Override + public void run() { + readStream(); + } + }; + + // Create the reader thread + thread = new Thread(runnable, "Terminal Output Stream Monitor Thread"); //$NON-NLS-1$ + + // Configure the reader thread + thread.setDaemon(true); + thread.setPriority(Thread.MIN_PRIORITY); + + // Start the processing + thread.start(); + } + + /** + * Returns the terminal control that this stream monitor is associated with. + */ + protected ITerminalControl getTerminalControl() { + return terminalControl; + } + + /** + * Reads from the output stream and write the read content + * to the terminal control output stream. + */ + void readStream() { + // Creates the read buffer + byte[] readBuffer = new byte[BUFFER_SIZE]; + + // We need to maintain UI responsiveness but still stream the content + // to the terminal control fast. Put the thread to a short sleep each second. + long sleepMarker = System.currentTimeMillis(); + + // Read from the stream until EOS is reached or the + // monitor is marked disposed. + int read = 0; + while (read >= 0 && !disposed) { + try { + // Read from the stream + read = stream.read(readBuffer); + // If some data has been read, append to the terminal + // control output stream + if (read > 0) { + // Allow for post processing the read content before appending + byte[] processedReadBuffer = onContentReadFromStream(readBuffer, read); + if (processedReadBuffer != readBuffer) { + read = processedReadBuffer.length; + } + terminalControl.getRemoteToTerminalOutputStream().write(processedReadBuffer, 0, read); + } + } catch (IOException e) { + // IOException received. If this is happening when already disposed -> ignore + if (!disposed) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + NLS.bind(Messages.OutputStreamMonitor_error_readingFromStream, e.getLocalizedMessage()), e); + UIPlugin.getDefault().getLog().log(status); + } + break; + } catch (NullPointerException e) { + // killing the stream monitor while reading can cause an NPE + // when reading from the stream + if (!disposed && thread != null) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + NLS.bind(Messages.OutputStreamMonitor_error_readingFromStream, e.getLocalizedMessage()), e); + UIPlugin.getDefault().getLog().log(status); + } + break; + } + + // See above -> Thread will go to sleep each second + if (System.currentTimeMillis() - sleepMarker > 1000) { + sleepMarker = System.currentTimeMillis(); + try { Thread.sleep(1); } catch (InterruptedException e) { /* ignored on purpose */ } + } + } + + // Dispose ourself + dispose(); + } + + /** + * Allow for processing of data from byte stream after it is read from + * client but before it is appended to the terminal. If the returned byte + * array is different than the one that was passed in with the byteBuffer + * argument, then the bytesRead value will be ignored and the full + * returned array will be written out. + * <p> + * The default implementation is returning the byte stream unmodified. + * + * @param byteBuffer The byte stream. Must not be <code>null</code>. + * @param bytesRead The number of bytes that were read into the read buffer. + * @return The processed byte stream. + * + */ + protected byte[] onContentReadFromStream(byte[] byteBuffer, int bytesRead) { + assert byteBuffer != null; + return byteBuffer; + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsConnector.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsConnector.java new file mode 100644 index 000000000..0bc89e64c --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsConnector.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.streams; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.ui.services.IDisposable; + +/** + * Streams connector implementation. + */ +@SuppressWarnings("restriction") +public class StreamsConnector extends AbstractStreamsConnector implements IDisposable { + // Reference to the streams settings + private final StreamsSettings settings; + + /** + * Constructor. + */ + public StreamsConnector() { + this(new StreamsSettings()); + } + + /** + * Constructor. + * + * @param settings The streams settings. Must not be <code>null</code> + */ + public StreamsConnector(StreamsSettings settings) { + super(); + + Assert.isNotNull(settings); + this.settings = settings; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#connect(org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl) + */ + @Override + public void connect(ITerminalControl control) { + Assert.isNotNull(control); + super.connect(control); + + // connect the streams + connectStreams(control, settings.getStdinStream(), settings.getStdoutStream(), settings.getStderrStream()); + + // Set the terminal control state to CONNECTED + control.setState(TerminalState.CONNECTED); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#isLocalEcho() + */ + @Override + public boolean isLocalEcho() { + return settings.isLocalEcho(); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.services.IDisposable#dispose() + */ + @Override + public void dispose() { + disconnect(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#doDisconnect() + */ + @Override + public void doDisconnect() { + // Dispose the streams + super.doDisconnect(); + + // Set the terminal control state to CLOSED. + fControl.setState(TerminalState.CLOSED); + } + + // ***** Process Connector settings handling ***** + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#getSettingsSummary() + */ + @Override + public String getSettingsSummary() { + return ""; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#load(org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore) + */ + @Override + public void load(ISettingsStore store) { + settings.load(store); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#save(org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore) + */ + @Override + public void save(ISettingsStore store) { + settings.save(store); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsSettings.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsSettings.java new file mode 100644 index 000000000..a3ef45196 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsSettings.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.streams; + +import java.io.InputStream; +import java.io.OutputStream; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.te.runtime.interfaces.properties.IPropertiesContainer; + +/** + * Streams connector settings implementation. + */ +@SuppressWarnings("restriction") +public class StreamsSettings { + // Reference to the stdin stream + private OutputStream stdin; + // Reference to the stdout stream + private InputStream stdout; + // Reference to the stderr stream + private InputStream stderr; + // Flag to control the local echo + private boolean localEcho = true; + + /** + * Sets the stdin stream instance. + * + * @param stdin The stream instance or <code>null</code>. + */ + public void setStdinStream(OutputStream stdin) { + this.stdin = stdin; + } + + /** + * Returns the stdin stream instance. + * + * @return The stream instance or <code>null</code>. + */ + public OutputStream getStdinStream() { + return stdin; + } + + /** + * Sets the stdout stream instance. + * + * @param stdout The stream instance or <code>null</code>. + */ + public void setStdoutStream(InputStream stdout) { + this.stdout = stdout; + } + + /** + * Returns the stdout stream instance. + * + * @return The stream instance or <code>null</code>. + */ + public InputStream getStdoutStream() { + return stdout; + } + + /** + * Sets the stderr stream instance. + * + * @param stderr The stream instance or <code>null</code>. + */ + public void setStderrStream(InputStream stderr) { + this.stderr = stderr; + } + + /** + * Returns the stderr stream instance. + * + * @return The stream instance or <code>null</code>. + */ + public InputStream getStderrStream() { + return stderr; + } + + /** + * Sets if the process requires a local echo from the terminal widget. + * + * @param value Specify <code>true</code> to enable the local echo, <code>false</code> otherwise. + */ + public void setLocalEcho(boolean value) { + this.localEcho = value; + } + + /** + * Returns <code>true</code> if the process requires a local echo + * from the terminal widget. + * + * @return <code>True</code> if local echo is enabled, <code>false</code> otherwise. + */ + public boolean isLocalEcho() { + return localEcho; + } + + /** + * Loads the streams settings from the given settings store. + * + * @param store The settings store. Must not be <code>null</code>. + */ + public void load(ISettingsStore store) { + Assert.isNotNull(store); + localEcho = Boolean.parseBoolean(store.get("LocalEcho", Boolean.FALSE.toString())); //$NON-NLS-1$ + if (store instanceof IPropertiesContainer) { + stdin = (OutputStream)((IPropertiesContainer)store).getProperty("stdin"); //$NON-NLS-1$ + stdout = (InputStream)((IPropertiesContainer)store).getProperty("stdout"); //$NON-NLS-1$ + stderr = (InputStream)((IPropertiesContainer)store).getProperty("stderr"); //$NON-NLS-1$ + } + } + + /** + * Saves the process settings to the given settings store. + * + * @param store The settings store. Must not be <code>null</code>. + */ + public void save(ISettingsStore store) { + Assert.isNotNull(store); + store.put("LocalEcho", Boolean.toString(localEcho)); //$NON-NLS-1$ + if (store instanceof IPropertiesContainer) { + ((IPropertiesContainer)store).setProperty("stdin", stdin); //$NON-NLS-1$ + ((IPropertiesContainer)store).setProperty("stdout", stdout); //$NON-NLS-1$ + ((IPropertiesContainer)store).setProperty("stderr", stderr); //$NON-NLS-1$ + } + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabDisposeListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabDisposeListener.java new file mode 100644 index 000000000..09f7783a8 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabDisposeListener.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.tabs; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.te.runtime.events.DisposedEvent; +import org.eclipse.tm.te.runtime.events.EventManager; + +/** + * Terminals tab default dispose listener implementation. + */ +@SuppressWarnings("restriction") +public class TabDisposeListener implements DisposeListener { + private final TabFolderManager parentTabFolderManager; + + /** + * Constructor. + * + * @param parentTabFolderManager The parent tab folder manager. Must be not <code>null</code> + */ + public TabDisposeListener(TabFolderManager parentTabFolderManager) { + Assert.isNotNull(parentTabFolderManager); + this.parentTabFolderManager = parentTabFolderManager; + } + + /** + * Returns the parent terminal console tab folder manager instance. + * + * @return The parent terminal console tab folder manager instance. + */ + protected final TabFolderManager getParentTabFolderManager() { + return parentTabFolderManager; + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent) + */ + @Override + public void widgetDisposed(DisposeEvent e) { + // If a tab item gets disposed, we have to dispose the terminal as well + if (e.getSource() instanceof CTabItem) { + // Get the terminal control (if any) from the tab item + Object candidate = ((CTabItem)e.getSource()).getData(); + if (candidate instanceof ITerminalViewControl) ((ITerminalViewControl)candidate).disposeTerminal(); + + // If all items got removed, we have to switch back to the empty page control + if (parentTabFolderManager.getTabFolder() != null && parentTabFolderManager.getTabFolder().getItemCount() == 0) { + parentTabFolderManager.getParentView().switchToEmptyPageControl(); + } + // Fire selection changed event + parentTabFolderManager.fireSelectionChanged(); + // Fire the terminal console disposed event + EventManager.getInstance().fireEvent(new DisposedEvent(e.getSource(), ((CTabItem)e.getSource()).getData("customData"))); //$NON-NLS-1$ + } + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderManager.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderManager.java new file mode 100644 index 000000000..491548ec4 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderManager.java @@ -0,0 +1,720 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.tabs; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.EventObject; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.tm.internal.terminal.control.ITerminalListener; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.TerminalViewControlFactory; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.te.runtime.events.EventManager; +import org.eclipse.tm.te.ui.events.AbstractEventListener; +import org.eclipse.tm.te.ui.swt.DisplayUtil; +import org.eclipse.tm.te.ui.terminals.activator.UIPlugin; +import org.eclipse.tm.te.ui.terminals.events.SelectionChangedBroadcastEvent; +import org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView; +import org.eclipse.tm.te.ui.terminals.interfaces.ImageConsts; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.ide.IDEEncoding; + +/** + * Terminals tab folder manager. + */ +@SuppressWarnings("restriction") +public class TabFolderManager extends PlatformObject implements ISelectionProvider { + // Reference to the parent terminal consoles view + private final ITerminalsView parentView; + // Reference to the selection listener instance + private final SelectionListener selectionListener; + // Reference to the broadcasted selection changed event listener instance + private final BroadcastedSelectionChangedEventListener broadcastedSelectionChangedEventListener; + + /** + * List of selection changed listeners. + */ + private final List<ISelectionChangedListener> selectionChangedListeners = new ArrayList<ISelectionChangedListener>(); + + /** + * The terminal control selection listener implementation. + */ + private class TerminalControlSelectionListener implements DisposeListener, MouseListener { + private final ITerminalViewControl terminal; + private boolean selectMode; + + /** + * Constructor. + * + * @param terminal The terminal control. Must be not <code>null</code>. + */ + public TerminalControlSelectionListener(ITerminalViewControl terminal) { + Assert.isNotNull(terminal); + this.terminal = terminal; + + // Register ourself as the required listener + terminal.getControl().addDisposeListener(this); + terminal.getControl().addMouseListener(this); + } + + /** + * Returns the associated terminal view control. + * + * @return The terminal view control. + */ + protected final ITerminalViewControl getTerminal() { + return terminal; + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent) + */ + @Override + public void widgetDisposed(DisposeEvent e) { + // Widget got disposed, check if it is ours + // If a tab item gets disposed, we have to dispose the terminal as well + if (e.getSource().equals(terminal.getControl())) { + // Remove as listener + getTerminal().getControl().removeDisposeListener(this); + getTerminal().getControl().removeMouseListener(this); + } + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseDown(MouseEvent e) { + // Left button down -> select mode starts + if (e.button == 1) selectMode = true; + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseUp(MouseEvent e) { + if (e.button == 1 && selectMode) { + selectMode = false; + // Fire a selection changed event with the terminal controls selection + DisplayUtil.safeAsyncExec(new Runnable() { + @Override + public void run() { + fireSelectionChanged(new StructuredSelection(getTerminal().getSelection())); + } + }); + } + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseDoubleClick(MouseEvent e) { + } + } + + /** + * The event listener to process broadcasted selection changed events + */ + private class BroadcastedSelectionChangedEventListener extends AbstractEventListener { + private final TabFolderManager parent; + + /** + * Constructor. + * + * @param parent The parent tab folder manager. Must not be <code>null</code>. + */ + public BroadcastedSelectionChangedEventListener(TabFolderManager parent) { + super(); + + Assert.isNotNull(parent); + this.parent = parent; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.runtime.interfaces.events.IEventListener#eventFired(java.util.EventObject) + */ + @Override + public void eventFired(EventObject event) { + if (event instanceof SelectionChangedBroadcastEvent && !event.getSource().equals(parent)) { + // Don't need to do anything if the parent tab folder is disposed or does not have a open tab + CTabFolder tabFolder = parent.getTabFolder(); + if (tabFolder == null || tabFolder.isDisposed() || tabFolder.getItemCount() == 0) return; + + // Received a broadcasted selection changed event from another tab folder manager. + SelectionChangedEvent selectionChangedEvent = ((SelectionChangedBroadcastEvent)event).getSelectionChangedEvent(); + if (selectionChangedEvent != null && selectionChangedEvent.getSelection() instanceof IStructuredSelection && !selectionChangedEvent.getSelection().isEmpty()) { + // Extract the selection from the selection changed event + IStructuredSelection selection = (IStructuredSelection)selectionChangedEvent.getSelection(); + // Determine the first element in the selection being a CTabItem + CTabItem item = null; + Iterator<?> iterator = selection.iterator(); + while (iterator.hasNext()) { + Object candidate = iterator.next(); + if (candidate instanceof CTabItem) { item = (CTabItem)candidate; break; } + } + // If we got an CTabItem from the selection, try to find a CTabItem in our own tab folder manager + // which is associated with the exact same data object. + if (item != null && item.getData("customData") != null) { //$NON-NLS-1$ + Object data = item.getData("customData"); //$NON-NLS-1$ + + CTabItem[] ourItems = tabFolder.getItems(); + for (CTabItem ourItem : ourItems) { + Object ourData = ourItem.getData("customData"); //$NON-NLS-1$ + if (data.equals(ourData) && !ourItem.equals(parent.getActiveTabItem())) { + // Select this item and we are done + parent.setSelection(new StructuredSelection(ourItem)); + break; + } + } + } + } + } + } + + } + + /** + * Constructor. + * + * @param parentView The parent terminal console view. Must be not <code>null</code>. + */ + public TabFolderManager(ITerminalsView parentView) { + super(); + Assert.isNotNull(parentView); + this.parentView = parentView; + + // Attach a selection listener to the tab folder + selectionListener = doCreateTabFolderSelectionListener(this); + if (getTabFolder() != null) getTabFolder().addSelectionListener(selectionListener); + + + // Create and register the broadcasted selection changed event listener + broadcastedSelectionChangedEventListener = doCreateBroadcastedSelectionChangedEventListener(this); + if (isListeningToBroadcastedSelectionChangedEvent() && broadcastedSelectionChangedEventListener != null) { + EventManager.getInstance().addEventListener(broadcastedSelectionChangedEventListener, SelectionChangedBroadcastEvent.class); + } + } + + /** + * Creates the terminal console tab folder selection listener instance. + * + * @param parent The parent terminal console tab folder manager. Must be not <code>null</code>. + * @return The selection listener instance. + */ + protected TabFolderSelectionListener doCreateTabFolderSelectionListener(TabFolderManager parent) { + Assert.isNotNull(parent); + return new TabFolderSelectionListener(parent); + } + + /** + * Returns the parent terminal consoles view. + * + * @return The terminal consoles view instance. + */ + protected final ITerminalsView getParentView() { + return parentView; + } + + /** + * Returns the tab folder associated with the parent view. + * + * @return The tab folder or <code>null</code>. + */ + protected final CTabFolder getTabFolder() { + return (CTabFolder)getParentView().getAdapter(CTabFolder.class); + } + + /** + * Returns the selection changed listeners currently registered. + * + * @return The registered selection changed listeners or an empty array. + */ + protected final ISelectionChangedListener[] getSelectionChangedListeners() { + return selectionChangedListeners.toArray(new ISelectionChangedListener[selectionChangedListeners.size()]); + } + + /** + * Dispose the tab folder manager instance. + */ + public void dispose() { + // Dispose the selection listener + if (getTabFolder() != null && !getTabFolder().isDisposed()) getTabFolder().removeSelectionListener(selectionListener); + // Remove the broadcasted selection changed event listener from the notification manager + if (broadcastedSelectionChangedEventListener != null) { + EventManager.getInstance().removeEventListener(broadcastedSelectionChangedEventListener); + } + } + + /** + * Creates a new tab item with the given title and connector. + * + * @param title The tab title. Must be not <code>null</code>. + * @param connector The terminal connector. Must be not <code>null</code>. + * @param data The custom terminal data node or <code>null</code>. + * + * @return The created tab item or <code>null</code> if failed. + */ + @SuppressWarnings("unused") + public CTabItem createTabItem(String title, ITerminalConnector connector, Object data) { + Assert.isNotNull(title); + Assert.isNotNull(connector); + + // The result tab item + CTabItem item = null; + + // Get the tab folder from the parent viewer + CTabFolder tabFolder = getTabFolder(); + if (tabFolder != null) { + // Generate a unique title string for the new tab item (must be called before creating the item itself) + title = makeUniqueTitle(title, tabFolder); + // Create the tab item + item = new CTabItem(tabFolder, SWT.CLOSE); + // Set the tab item title + item.setText(title); + // Set the tab icon + Image image = getTabItemImage(connector, data); + if (image != null) item.setImage(image); + + // Setup the tab item listeners + setupTerminalTabListeners(item); + + // Create the composite to create the terminal control within + Composite composite = new Composite(tabFolder, SWT.NONE); + composite.setLayout(new FillLayout()); + // Associate the composite with the tab item + item.setControl(composite); + + // Refresh the layout + tabFolder.getParent().layout(true); + + // Create the terminal control + ITerminalViewControl terminal = TerminalViewControlFactory.makeControl(doCreateTerminalTabTerminalListener(item), composite, new ITerminalConnector[] { connector }); + // Add the "selection" listener to the terminal control + new TerminalControlSelectionListener(terminal); + // Use the default Eclipse IDE encoding setting to configure the terminals encoding + try { terminal.setEncoding(IDEEncoding.getResourceEncoding()); } catch (UnsupportedEncodingException e) { /* ignored on purpose */ } + // Associated the terminal with the tab item + item.setData(terminal); + // Associated the custom data node with the tab item (if any) + if (data != null) item.setData("customData", data); //$NON-NLS-1$ + + // Overwrite the text canvas help id + String contextHelpId = getParentView().getContextHelpId(); + if (contextHelpId != null) { + PlatformUI.getWorkbench().getHelpSystem().setHelp(terminal.getControl(), contextHelpId); + } + + // Set the context menu + TabFolderMenuHandler menuHandler = (TabFolderMenuHandler)getParentView().getAdapter(TabFolderMenuHandler.class); + if (menuHandler != null) { + Menu menu = (Menu)menuHandler.getAdapter(Menu.class); + if (menu != null) { + // One weird occurrence of IllegalArgumentException: Widget has wrong parent. + // Inspecting the code, this seem extremely unlikely. The terminal is created + // from a composite parent, the composite parent from the tab folder and the menu + // from the tab folder. Means, at the end all should have the same menu shell, shouldn't they? + try { + terminal.getControl().setMenu(menu); + } catch (IllegalArgumentException e) { + // Log exception only if debug mode is set to 1. + if (UIPlugin.getTraceHandler().isSlotEnabled(1, null)) { + e.printStackTrace(); + } + } + } + } + + // Select the created item within the tab folder + tabFolder.setSelection(item); + + // Set the connector + terminal.setConnector(connector); + + // And connect the terminal + terminal.connectTerminal(); + + // Fire selection changed event + fireSelectionChanged(); + } + + // Return the create tab item finally. + return item; + } + + /** + * Generate a unique title string based on the given proposal. + * + * @param proposal The proposal. Must be not <code>null</code>. + * @return The unique title string. + */ + protected String makeUniqueTitle(String proposal, CTabFolder tabFolder) { + Assert.isNotNull(proposal); + Assert.isNotNull(tabFolder); + + String title = proposal; + int index = 0; + + // Loop all existing tab items and check the titles. We have to remember + // all found titles as modifying the proposal might in turn conflict again + // with the title of a tab already checked. + List<String> titles = new ArrayList<String>(); + for (CTabItem item : tabFolder.getItems()) { + // Get the tab item title + titles.add(item.getText()); + // Make the proposal unique be appending (<n>) against all known titles. + while (titles.contains(title)) title = proposal + " (" + index++ + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + return title; + } + + /** + * Setup the terminal console tab item listeners. + * + * @param item The tab item. Must be not <code>null</code>. + */ + protected void setupTerminalTabListeners(CTabItem item) { + Assert.isNotNull(item); + + // Create and associate the disposal listener + item.addDisposeListener(doCreateTerminalTabDisposeListener(this)); + + // Create and register the property change listener + final IPropertyChangeListener propertyChangeListener = doCreateTerminalTabPropertyChangeListener(item); + // Register to the JFace font registry + JFaceResources.getFontRegistry().addListener(propertyChangeListener); + // Remove the listener from the JFace font registry if the tab gets disposed + item.addDisposeListener(new DisposeListener() { + @Override + public void widgetDisposed(DisposeEvent e) { + JFaceResources.getFontRegistry().removeListener(propertyChangeListener); + } + }); + } + + /** + * Creates a new terminal console tab terminal listener instance. + * + * @param item The tab item. Must be not <code>null</code>. + * @return The terminal listener instance. + */ + protected ITerminalListener doCreateTerminalTabTerminalListener(CTabItem item) { + Assert.isNotNull(item); + return new TabTerminalListener(item); + } + + /** + * Creates a new terminal console tab dispose listener instance. + * + * @param parent The parent terminal console tab folder manager. Must be not <code>null</code>. + * @return The dispose listener instance. + */ + protected DisposeListener doCreateTerminalTabDisposeListener(TabFolderManager parent) { + Assert.isNotNull(parent); + return new TabDisposeListener(parent); + } + + /** + * Creates a new terminal console tab property change listener instance. + * + * @param item The tab item. Must be not <code>null</code>. + * @return The property change listener instance. + */ + protected IPropertyChangeListener doCreateTerminalTabPropertyChangeListener(CTabItem item) { + Assert.isNotNull(item); + return new TabPropertyChangeListener(item); + } + + /** + * Returns the tab item image. + * + * @param connector The terminal connector. Must be not <code>null</code>. + * @param data The custom terminal data node or <code>null</code>. + * + * @return The tab item image or <code>null</code>. + */ + protected Image getTabItemImage(ITerminalConnector connector, Object data) { + Assert.isNotNull(connector); + return UIPlugin.getImage(ImageConsts.VIEW_Terminals); + } + + /** + * Lookup a tab item with the given title and the given terminal connector. + * <p> + * <b>Note:</b> The method will handle unified tab item titles itself. + * + * @param title The tab item title. Must be not <code>null</code>. + * @param connector The terminal connector. Must be not <code>null</code>. + * @param data The custom terminal data node or <code>null</code>. + * + * @return The corresponding tab item or <code>null</code>. + */ + public CTabItem findTabItem(String title, ITerminalConnector connector, Object data) { + Assert.isNotNull(title); + Assert.isNotNull(connector); + + // Get the tab folder + CTabFolder tabFolder = getTabFolder(); + if (tabFolder == null) return null; + + // Loop all existing tab items and try to find a matching title + for (CTabItem item : tabFolder.getItems()) { + // Disposed items cannot be matched + if (item.isDisposed()) continue; + // Get the title from the current tab item + String itemTitle = item.getText(); + // The terminal console state might be signaled to the user via the + // terminal console tab title. Filter out any prefix "<.*>\s*". + itemTitle = itemTitle.replaceFirst("^<.*>\\s*", ""); //$NON-NLS-1$ //$NON-NLS-2$ + if (itemTitle.startsWith(title)) { + // The title string matches -> double check with the terminal connector + ITerminalViewControl terminal = (ITerminalViewControl)item.getData(); + ITerminalConnector connector2 = terminal.getTerminalConnector(); + // If the connector id and name matches -> check on the settings + if (connector.getId().equals(connector2.getId()) && connector.getName().equals(connector2.getName())) { + if (!connector.isInitialized()) { + // an uninitialized connector does not yield a sensible summary + return item; + } + String summary = connector.getSettingsSummary(); + String summary2 = connector2.getSettingsSummary(); + // If we have matching settings -> we've found the matching item + if (summary.equals(summary2)) return item; + } + } + } + + return null; + } + + /** + * Make the given tab item the active tab and bring the tab to the top. + * + * @param item The tab item. Must be not <code>null</code>. + */ + public void bringToTop(CTabItem item) { + Assert.isNotNull(item); + + // Get the tab folder + CTabFolder tabFolder = getTabFolder(); + if (tabFolder == null) return; + + // Set the given tab item as selection to the tab folder + tabFolder.setSelection(item); + // Fire selection changed event + fireSelectionChanged(); + } + + /** + * Returns the currently active tab. + * + * @return The active tab item or <code>null</code> if none. + */ + public CTabItem getActiveTabItem() { + // Get the tab folder + CTabFolder tabFolder = getTabFolder(); + if (tabFolder == null) return null; + + return tabFolder.getSelection(); + } + + /** + * Remove all terminated tab items. + */ + public void removeTerminatedItems() { + // Get the tab folder + CTabFolder tabFolder = getTabFolder(); + if (tabFolder == null) return; + + // Loop the items and check for terminated status + for (CTabItem item: tabFolder.getItems()) { + // Disposed items cannot be matched + if (item.isDisposed()) continue; + // Check if the item is terminated + if (isTerminatedTabItem(item)) { + // item is terminated -> dispose + item.dispose(); + } + } + } + + /** + * Checks if the given tab item represents a terminated console. Subclasses may + * overwrite this method to extend the definition of terminated. + * + * @param item The tab item or <code>null</code>. + * @return <code>True</code> if the tab item represents a terminated console, <code>false</code> otherwise. + */ + protected boolean isTerminatedTabItem(CTabItem item) { + // Null items or disposed items cannot be matched + if (item == null || item.isDisposed()) return false; + + // First, match the item title. If it contains "<terminated>", the item can be removed + String itemTitle = item.getText(); + if (itemTitle != null && itemTitle.contains("<terminated>")) { //$NON-NLS-1$ + return true; + } + // Second, check if the associated terminal control is closed + // The title string matches -> double check with the terminal connector + ITerminalViewControl terminal = (ITerminalViewControl)item.getData(); + if (terminal != null && terminal.getState() == TerminalState.CLOSED) { + return true; + } + + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) + */ + @Override + public void addSelectionChangedListener(ISelectionChangedListener listener) { + if (listener != null && !selectionChangedListeners.contains(listener)) selectionChangedListeners.add(listener); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) + */ + @Override + public void removeSelectionChangedListener(ISelectionChangedListener listener) { + if (listener != null) selectionChangedListeners.remove(listener); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection() + */ + @Override + public ISelection getSelection() { + CTabItem activeTabItem = getActiveTabItem(); + return activeTabItem != null ? new StructuredSelection(activeTabItem) : new StructuredSelection(); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection) + */ + @Override + public void setSelection(ISelection selection) { + if (selection instanceof IStructuredSelection && !selection.isEmpty()) { + // The first selection element which is a CTabItem will become the active item + Iterator<?> iterator = ((IStructuredSelection)selection).iterator(); + while (iterator.hasNext()) { + Object candidate = iterator.next(); + if (candidate instanceof CTabItem) { bringToTop((CTabItem)candidate); return; } + } + } + // fire a changed event in any case + fireSelectionChanged(selection); + } + + /** + * Fire the selection changed event to the registered listeners. + */ + protected void fireSelectionChanged() { + fireSelectionChanged(getSelection()); + } + + /** + * Fire the selection changed event to the registered listeners. + */ + protected final void fireSelectionChanged(ISelection selection) { + // Create the selection changed event + SelectionChangedEvent event = new SelectionChangedEvent(TabFolderManager.this, selection); + + // First, invoke the registered listeners and let them do their job + for (ISelectionChangedListener listener : selectionChangedListeners) { + listener.selectionChanged(event); + } + + // Second, broadcast the event if desired + if (isBroadcastSelectionChangedEvent()) onBroadcastSelectionChangedEvent(event); + } + + /** + * Controls if or if not a selection changed event, processed by this tab + * folder manager shall be broadcasted to via the global Workbench notification + * mechanism. + * + * @return <code>True</code> to broadcast the selection changed event, <code>false</code> otherwise. + */ + protected boolean isBroadcastSelectionChangedEvent() { + return false; + } + + /** + * Broadcasts the given selection changed event via the global Workbench notification mechanism. + * + * @param selectionChangedEvent The selection changed event or <code>null</code>. + */ + protected void onBroadcastSelectionChangedEvent(SelectionChangedEvent selectionChangedEvent) { + SelectionChangedBroadcastEvent event = doCreateSelectionChangedBroadcastEvent(this, selectionChangedEvent); + if (event != null) EventManager.getInstance().fireEvent(event); + } + + /** + * Creates the selection changed broadcast event. + * + * @param source The event source. Must not be <code>null</code>. + * @param selectionChangedEvent The selection changed event or <code>null</code>. + * + * @return The selection changed broadcast event or <code>null</code>. + */ + protected SelectionChangedBroadcastEvent doCreateSelectionChangedBroadcastEvent(TabFolderManager source, SelectionChangedEvent selectionChangedEvent) { + return new SelectionChangedBroadcastEvent(source, selectionChangedEvent); + } + + /** + * Returns if or if not this tab folder manager is listening to broadcasted selection + * changed events. Broadcasted events by the same tab folder manager are ignored independent + * of the methods return value. + * + * @return <code>True</code> to listen to broadcasted selection changed events, <code>false</code> to not listen. + */ + protected boolean isListeningToBroadcastedSelectionChangedEvent() { + return false; + } + + /** + * Creates a new broadcasted selection changed event listener instance. + * + * @param parent The parent tab folder manager. Must not be <code>null</code>. + * @return The event listener instance or <code>null</code>. + */ + protected BroadcastedSelectionChangedEventListener doCreateBroadcastedSelectionChangedEventListener(TabFolderManager parent) { + return new BroadcastedSelectionChangedEventListener(parent); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderMenuHandler.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderMenuHandler.java new file mode 100644 index 000000000..91d6fb19a --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderMenuHandler.java @@ -0,0 +1,297 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.tabs; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.jface.action.IMenuListener2; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionClearAll; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionCopy; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionPaste; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionSelectAll; +import org.eclipse.tm.te.ui.terminals.actions.TabScrollLockAction; +import org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView; +import org.eclipse.ui.IWorkbenchActionConstants; + +/** + * Terminals tab folder menu handler. + */ +@SuppressWarnings("restriction") +public class TabFolderMenuHandler extends PlatformObject { + // Reference to the parent terminal console view + private final ITerminalsView parentView; + // Reference to the tab folder context menu manager + private MenuManager contextMenuManager; + // Reference to the tab folder context menu + private Menu contextMenu; + // The list of actions available within the context menu + private final List<AbstractTerminalAction> contextMenuActions = new ArrayList<AbstractTerminalAction>(); + + /** + * Default menu listener implementation. + */ + protected class MenuListener implements IMenuListener2 { + + /* (non-Javadoc) + * @see org.eclipse.jface.action.IMenuListener2#menuAboutToHide(org.eclipse.jface.action.IMenuManager) + */ + @Override + public void menuAboutToHide(IMenuManager manager) { + // CQ:WIND00192293 and CQ:WIND194204 - don't update actions on menuAboutToHide + // See also http://bugs.eclipse.org/296212 + // updateMenuItems(false); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.action.IMenuListener#menuAboutToShow(org.eclipse.jface.action.IMenuManager) + */ + @Override + public void menuAboutToShow(IMenuManager manager) { + updateMenuItems(true); + } + + } + + /** + * Constructor. + * + * @param parentView The parent terminal console view. Must not be <code>null</code>. + */ + public TabFolderMenuHandler(ITerminalsView parentView) { + super(); + Assert.isNotNull(parentView); + this.parentView = parentView; + } + + /** + * Returns the parent terminal console view. + * + * @return The parent terminal console view instance. + */ + protected final ITerminalsView getParentView() { + return parentView; + } + + /** + * Returns the tab folder associated with the parent view. + * + * @return The tab folder or <code>null</code>. + */ + protected final CTabFolder getTabFolder() { + return (CTabFolder)getParentView().getAdapter(CTabFolder.class); + } + + /** + * Dispose the tab folder menu handler instance. + */ + public void dispose() { + // Dispose the context menu + if (contextMenu != null) { contextMenu.dispose(); contextMenu = null; } + // Dispose the context menu manager + if (contextMenuManager != null) { contextMenuManager.dispose(); contextMenuManager = null; } + // Clear all actions + contextMenuActions.clear(); + } + + /** + * Setup the context menu for the tab folder. The method will return + * immediately if the menu handler had been initialized before. + * + * @param tabFolder The tab folder control. Must not be <code>null</code>. + */ + public void initialize() { + // Return immediately if the menu manager and menu got initialized already + if (contextMenuManager != null && contextMenu != null) { + return; + } + + // Get the tab folder + CTabFolder tabFolder = getTabFolder(); + if (tabFolder == null) { + return; + } + + // Create the menu manager if not done before + contextMenuManager = new MenuManager("#PopupMenu"); //$NON-NLS-1$ + // Create and associated the menu listener + contextMenuManager.addMenuListener(new MenuListener()); + // Create the context menu + contextMenu = contextMenuManager.createContextMenu(tabFolder); + + // Create the context menu action instances + doCreateContextMenuActions(); + + // Fill the context menu + doFillContextMenu(contextMenuManager); + + // Register to the view site to open the menu for contributions + getParentView().getSite().registerContextMenu(contextMenuManager, getParentView().getSite().getSelectionProvider()); + } + + /** + * Adds the given action to the context menu actions list. + * + * @param action The action instance. Must be not <code>null</code>. + */ + protected final void add(AbstractTerminalAction action) { + Assert.isNotNull(action); + contextMenuActions.add(action); + } + + /** + * Create the context menu actions. + */ + protected void doCreateContextMenuActions() { + // Create and add the copy action + add(new TerminalActionCopy() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the paste action + add(new TerminalActionPaste() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the clear all action + add(new TerminalActionClearAll() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the select all action + add(new TerminalActionSelectAll() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the scroll lock action + add (new TabScrollLockAction() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + } + + /** + * Returns the currently active terminal control. + * + * @return The currently active terminal control or <code>null</code>. + */ + protected ITerminalViewControl getActiveTerminalViewControl() { + ITerminalViewControl terminal = null; + + // Get the active tab item from the tab folder manager + TabFolderManager manager = (TabFolderManager)getParentView().getAdapter(TabFolderManager.class); + if (manager != null) { + // If we have the active tab item, we can get the active terminal control + CTabItem activeTabItem = manager.getActiveTabItem(); + if (activeTabItem != null) { + terminal = (ITerminalViewControl)activeTabItem.getData(); + } + } + + return terminal; + } + + /** + * Fill in the context menu content within the given manager. + * + * @param manager The menu manager. Must not be <code>null</code>. + */ + protected void doFillContextMenu(MenuManager manager) { + assert manager != null; + + // Loop all actions and add them to the menu manager + for (AbstractTerminalAction action : contextMenuActions) { + manager.add(action); + // Add a separator after the paste action + if (action instanceof TerminalActionPaste) { + manager.add(new Separator()); + } + // Add a separator after the select all action + if (action instanceof TerminalActionSelectAll) { + manager.add(new Separator()); + } + } + + // Menu contributions will end up here + manager.add(new Separator()); + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + } + + /** + * Update the context menu items on showing or hiding the context menu. + * + * @param aboutToShow <code>True</code> if the menu is about to show, <code>false</code> otherwise. + */ + protected void updateMenuItems(boolean aboutToShow) { + // Loop all actions and update the status + for (AbstractTerminalAction action : contextMenuActions) { + action.updateAction(aboutToShow); + } + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class) + */ + @Override + public Object getAdapter(Class adapter) { + if (MenuManager.class.isAssignableFrom(adapter)) { + return contextMenuManager; + } else if (Menu.class.isAssignableFrom(adapter)) { + return contextMenu; + } + + // Try the parent view + Object adapted = getParentView().getAdapter(adapter); + if (adapted != null) { + return adapted; + } + + return super.getAdapter(adapter); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderSelectionListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderSelectionListener.java new file mode 100644 index 000000000..de25ec3ea --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderSelectionListener.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.tabs; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; + +/** + * Terminals tab folder default selection listener implementation. + */ +public class TabFolderSelectionListener implements SelectionListener { + private final TabFolderManager parentTabFolderManager; + + /** + * Constructor. + * + * @param parentTabFolderManager The parent tab folder manager. Must be not <code>null</code> + */ + public TabFolderSelectionListener(TabFolderManager parentTabFolderManager) { + Assert.isNotNull(parentTabFolderManager); + this.parentTabFolderManager = parentTabFolderManager; + } + + /** + * Returns the parent terminal console tab folder manager instance. + * + * @return The parent terminal console tab folder manager instance. + */ + protected final TabFolderManager getParentTabFolderManager() { + return parentTabFolderManager; + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void widgetSelected(SelectionEvent e) { + parentTabFolderManager.fireSelectionChanged(); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderToolbarHandler.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderToolbarHandler.java new file mode 100644 index 000000000..4215771c9 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderToolbarHandler.java @@ -0,0 +1,304 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.tabs; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionClearAll; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionCopy; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionPaste; +import org.eclipse.tm.te.ui.terminals.actions.AbstractAction; +import org.eclipse.tm.te.ui.terminals.actions.TabScrollLockAction; +import org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IWorkbenchActionConstants; + + +/** + * Terminals tab folder toolbar handler. + */ +@SuppressWarnings("restriction") +public class TabFolderToolbarHandler extends PlatformObject { + // Reference to the parent terminal console view + private final ITerminalsView parentView; + // Reference to the toolbar manager + private IToolBarManager toolbarManager; + // Reference to the selection listener + private ToolbarSelectionChangedListener selectionChangedListener; + // The list of actions available within the toolbar + private final List<AbstractTerminalAction> toolbarActions = new ArrayList<AbstractTerminalAction>(); + + /** + * Default selection listener implementation. + */ + protected class ToolbarSelectionChangedListener implements ISelectionChangedListener { + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) + */ + @Override + public void selectionChanged(SelectionChangedEvent event) { + boolean enable = event != null; + + // The VlmConsoleTabFolderManager is listening to the selection changes of the + // TabFolder and fires selection changed events. + if (enable && event.getSource() instanceof TabFolderManager) { + enable = event.getSelection() instanceof StructuredSelection + && !event.getSelection().isEmpty() + && (((StructuredSelection)event.getSelection()).getFirstElement() instanceof CTabItem + || ((StructuredSelection)event.getSelection()).getFirstElement() instanceof String); + } + + updateToolbarItems(enable); + } + } + + /** + * Constructor. + * + * @param parentView The parent terminal console view. Must not be <code>null</code>. + */ + public TabFolderToolbarHandler(ITerminalsView parentView) { + super(); + Assert.isNotNull(parentView); + this.parentView = parentView; + } + + /** + * Returns the parent terminal console view. + * + * @return The terminal console view instance. + */ + protected final ITerminalsView getParentView() { + return parentView; + } + + /** + * Returns the tab folder associated with the parent view. + * + * @return The tab folder or <code>null</code>. + */ + protected final CTabFolder getTabFolder() { + return (CTabFolder)getParentView().getAdapter(CTabFolder.class); + } + + /** + * Returns the currently active terminal control. + * + * @return The currently active terminal control or <code>null</code>. + */ + public ITerminalViewControl getActiveTerminalViewControl() { + ITerminalViewControl terminal = null; + + // Get the active tab item from the tab folder manager + TabFolderManager manager = (TabFolderManager)getParentView().getAdapter(TabFolderManager.class); + if (manager != null) { + // If we have the active tab item, we can get the active terminal control + CTabItem activeTabItem = manager.getActiveTabItem(); + if (activeTabItem != null && !activeTabItem.isDisposed()) { + terminal = (ITerminalViewControl)activeTabItem.getData(); + } + } + + return terminal; + } + + /** + * Dispose the tab folder menu handler instance. + */ + public void dispose() { + // Dispose the selection changed listener + if (selectionChangedListener != null) { + getParentView().getViewSite().getSelectionProvider().removeSelectionChangedListener(selectionChangedListener); + selectionChangedListener = null; + } + + // Clear all actions + toolbarActions.clear(); + } + + /** + * Setup the context menu for the tab folder. The method will return + * immediately if the toolbar handler had been initialized before. + * + * @param tabFolder The tab folder control. Must not be <code>null</code>. + */ + public void initialize() { + // Return immediately if the toolbar manager got initialized already + if (toolbarManager != null) { + return; + } + + // Register ourself as selection listener to the tab folder + selectionChangedListener = doCreateSelectionChangedListener(); + assert selectionChangedListener != null; + getParentView().getViewSite().getSelectionProvider().addSelectionChangedListener(selectionChangedListener); + + // Get the parent view action bars + IActionBars bars = getParentView().getViewSite().getActionBars(); + + // From the action bars, get the toolbar manager + toolbarManager = bars.getToolBarManager(); + + // Create the toolbar action instances + doCreateToolbarActions(); + + // Fill the toolbar + doFillToolbar(toolbarManager); + + // Update actions + updateToolbarItems(false); + } + + /** + * Creates a new selection changed listener instance. + * + * @return The new selection changed listener instance. + */ + protected ToolbarSelectionChangedListener doCreateSelectionChangedListener() { + return new ToolbarSelectionChangedListener(); + } + + /** + * Adds the given action to the toolbar actions list. + * + * @param action The action instance. Must be not <code>null</code>. + */ + protected final void add(AbstractTerminalAction action) { + Assert.isNotNull(action); + toolbarActions.add(action); + } + + /** + * Create the toolbar actions. + */ + protected void doCreateToolbarActions() { + // Create and add the paste action + add(new TerminalActionPaste() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the copy action + add(new TerminalActionCopy() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the scroll lock action + add (new TabScrollLockAction() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the clear all action + add(new TerminalActionClearAll() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + } + + /** + * Fill in the context menu content within the given manager. + * + * @param manager The menu manager. Must not be <code>null</code>. + */ + protected void doFillToolbar(IToolBarManager manager) { + assert manager != null; + + // Note: For the toolbar, the actions are added from left to right! + // So we start with the additions marker here which is the most + // left contribution item. + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + manager.add(new Separator("anchor")); //$NON-NLS-1$ + + // Loop all actions and add them to the menu manager + for (AbstractTerminalAction action : toolbarActions) { + // Add a separator before the clear all action or if the action is a separator + if (action instanceof TabScrollLockAction + || (action instanceof AbstractAction && ((AbstractAction)action).isSeparator())) { + manager.insertAfter("anchor", new Separator()); //$NON-NLS-1$ + } + // Add the action itself + manager.insertAfter("anchor", action); //$NON-NLS-1$ + } + } + + /** + * Update the toolbar items. + * + * @param enabled <code>True</code> if the items shall be enabled, <code>false</code> otherwise. + */ + protected void updateToolbarItems(boolean enabled) { + // Determine the currently active terminal control + ITerminalViewControl control = getActiveTerminalViewControl(); + // Loop all actions and update the status + for (AbstractTerminalAction action : toolbarActions) { + // If the terminal control is not available, the updateAction + // method of certain actions enable the action (bugzilla #260372). + // Workaround by forcing the action to get disabled with setEnabled. + if (control == null) { + action.setEnabled(false); + } + else { + action.updateAction(enabled); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class) + */ + @Override + public Object getAdapter(Class adapter) { + if (IToolBarManager.class.isAssignableFrom(adapter)) { + return toolbarManager; + } + // Try the parent view + Object adapted = getParentView().getAdapter(adapter); + if (adapted != null) { + return adapted; + } + + return super.getAdapter(adapter); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabPropertyChangeListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabPropertyChangeListener.java new file mode 100644 index 000000000..b84b8ee83 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabPropertyChangeListener.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.tabs; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.graphics.Font; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.view.TerminalView; + +/** + * Terminals tab default property change listener implementation. + */ +@SuppressWarnings("restriction") +public class TabPropertyChangeListener implements IPropertyChangeListener { + /** + * Default terminal font property key. + * + * @see TerminalView#FONT_DEFINITION + */ + public static final String FONT_DEFINITION = "terminal.views.view.font.definition"; //$NON-NLS-1$ + + // Reference to the parent tab item + private final CTabItem tabItem; + + /** + * Constructor. + * + * @param tabItem The parent tab item. Must not be <code>null</code>. + */ + public TabPropertyChangeListener(CTabItem tabItem) { + super(); + Assert.isNotNull(tabItem); + this.tabItem = tabItem; + } + + /** + * Returns the associated parent tab item. + * + * @return The parent tab item. + */ + protected final CTabItem getTabItem() { + return tabItem; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) + */ + @Override + public void propertyChange(PropertyChangeEvent event) { + // In case we are called once after the tab item got disposed + // --> Do nothing + if (getTabItem() == null || getTabItem().isDisposed()) return; + + // Listen to changes of the Font settings + if (event.getProperty().equals(FONT_DEFINITION)) { + onFontDefinitionProperyChanged(); + } + } + + /** + * Called if a property change event for the terminal font + * definition is received. + */ + protected void onFontDefinitionProperyChanged() { + // Get the current font from JFace + Font font = JFaceResources.getFont(FONT_DEFINITION); + // Get the terminal control from the tab item + if (getTabItem().getData() instanceof ITerminalViewControl) { + ITerminalViewControl terminal = (ITerminalViewControl)getTabItem().getData(); + terminal.setFont(font); + } + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabTerminalListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabTerminalListener.java new file mode 100644 index 000000000..4d3824fca --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabTerminalListener.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.tabs; + +import java.util.regex.Pattern; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.internal.terminal.control.ITerminalListener; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.te.ui.terminals.nls.Messages; + +/** + * Terminals tab default terminal listener implementation. + */ +@SuppressWarnings("restriction") +public class TabTerminalListener implements ITerminalListener { + private final CTabItem tabItem; + + /** + * Constructor. + * + * @param tabItem The parent tab item. Must not be <code>null</code>. + */ + public TabTerminalListener(CTabItem tabItem) { + super(); + Assert.isNotNull(tabItem); + this.tabItem = tabItem; + } + + /** + * Returns the associated parent tab item. + * + * @return The parent tab item. + */ + protected final CTabItem getTabItem() { + return tabItem; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.ITerminalListener#setState(org.eclipse.tm.internal.terminal.provisional.api.TerminalState) + */ + @Override + public void setState(final TerminalState state) { + // The tab item must have been not yet disposed + final CTabItem item = getTabItem(); + if (item == null || item.isDisposed()) return; + + // Update the tab item title + item.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + String newTitle = getTerminalConsoleTabTitle(state); + if (newTitle != null) item.setText(newTitle); + } + }); + } + + // The pattern will not change over the session life-time + private static final Pattern TERMINAL_TITLE_TERMINATED_PATTERN = Pattern.compile(Messages.TabTerminalListener_consoleTerminated.replaceAll("\\{[0-9]+\\}", ".*")); //$NON-NLS-1$ //$NON-NLS-2$ + + /** + * Returns the title to set to the terminal console tab for the given state. + * <p> + * <b>Note:</b> This method is called from {@link #setState(TerminalState)} and + * is expected to by called within the UI thread. + * + * @param state The terminal state. Must be not <code>null</code>. + * @return The terminal console tab title to set or <code>null</code> to leave the title unchanged. + */ + protected String getTerminalConsoleTabTitle(TerminalState state) { + assert state != null && Display.findDisplay(Thread.currentThread()) != null; + + // The tab item must have been not yet disposed + CTabItem item = getTabItem(); + if (item == null || item.isDisposed()) return null; + + // Get the current tab title + String oldTitle = item.getText(); + + // Construct the new title + String newTitle = null; + + if (TerminalState.CLOSED.equals(state)) { + // Avoid multiple decorations of the closed state + if (!TERMINAL_TITLE_TERMINATED_PATTERN.matcher(oldTitle).matches()) { + newTitle = NLS.bind(Messages.TabTerminalListener_consoleTerminated, oldTitle); + } else { + newTitle = oldTitle; + } + } + + return newTitle != null && !newTitle.equals(oldTitle) ? newTitle : null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.ITerminalListener#setTerminalTitle(java.lang.String) + */ + @Override + public void setTerminalTitle(String title) { + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/view/TerminalsView.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/view/TerminalsView.java new file mode 100644 index 000000000..29445d972 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/view/TerminalsView.java @@ -0,0 +1,309 @@ +/******************************************************************************* + * Copyright (c) 2011 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: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.te.ui.terminals.view; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView; +import org.eclipse.tm.te.ui.terminals.tabs.TabFolderManager; +import org.eclipse.tm.te.ui.terminals.tabs.TabFolderMenuHandler; +import org.eclipse.tm.te.ui.terminals.tabs.TabFolderToolbarHandler; +import org.eclipse.ui.IWorkbenchPreferenceConstants; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.part.PageBook; +import org.eclipse.ui.part.ViewPart; + +/** + * Terminals view. + */ +public class TerminalsView extends ViewPart implements ITerminalsView { + + // Reference to the main page book control + private PageBook pageBookControl; + // Reference to the tab folder maintaining the consoles + private CTabFolder tabFolderControl; + // Reference to the tab folder manager + private TabFolderManager tabFolderManager; + // Reference to the tab folder menu handler + private TabFolderMenuHandler tabFolderMenuHandler; + // Reference to the tab folder toolbar handler + private TabFolderToolbarHandler tabFolderToolbarHandler; + // Reference to the empty page control (to be show if no console is open) + private Control emptyPageControl; + + /** + * Constructor. + */ + public TerminalsView() { + super(); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#dispose() + */ + @Override + public void dispose() { + // Dispose the tab folder manager + if (tabFolderManager != null) { tabFolderManager.dispose(); tabFolderManager = null; } + // Dispose the tab folder menu handler + if (tabFolderMenuHandler != null) { tabFolderMenuHandler.dispose(); tabFolderMenuHandler = null; } + // Dispose the tab folder toolbar handler + if (tabFolderToolbarHandler != null) { tabFolderToolbarHandler.dispose(); tabFolderToolbarHandler = null; } + + super.dispose(); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) + */ + @Override + public void createPartControl(Composite parent) { + // Create the page book control + pageBookControl = doCreatePageBookControl(parent); + Assert.isNotNull(pageBookControl); + // Configure the page book control + doConfigurePageBookControl(pageBookControl); + + // Create the empty page control + emptyPageControl = doCreateEmptyPageControl(pageBookControl); + Assert.isNotNull(emptyPageControl); + // Configure the empty page control + doConfigureEmptyPageControl(emptyPageControl); + + // Create the tab folder control (empty) + tabFolderControl = doCreateTabFolderControl(pageBookControl); + Assert.isNotNull(tabFolderControl); + // Configure the tab folder control + doConfigureTabFolderControl(tabFolderControl); + + // Create the tab folder manager + tabFolderManager = doCreateTabFolderManager(this); + Assert.isNotNull(tabFolderManager); + // Set the tab folder manager as the selection provider + getSite().setSelectionProvider(tabFolderManager); + + // Setup the tab folder menu handler + tabFolderMenuHandler = doCreateTabFolderMenuHandler(this); + Assert.isNotNull(tabFolderMenuHandler); + doConfigureTabFolderMenuHandler(tabFolderMenuHandler); + + // Setup the tab folder toolbar handler + tabFolderToolbarHandler = doCreateTabFolderToolbarHandler(this); + Assert.isNotNull(tabFolderToolbarHandler); + doConfigureTabFolderToolbarHandler(tabFolderToolbarHandler); + + // Show the empty page control by default + switchToEmptyPageControl(); + } + + /** + * Creates the {@link PageBook} instance. + * + * @param parent The parent composite. Must not be <code>null</code>. + * @return The page book instance. Must never be <code>null</code>. + */ + protected PageBook doCreatePageBookControl(Composite parent) { + return new PageBook(parent, SWT.NONE); + } + + /** + * Configure the given page book control. + * + * @param pagebook The page book control. Must not be <code>null</code>. + */ + protected void doConfigurePageBookControl(PageBook pagebook) { + Assert.isNotNull(pagebook); + + if (getContextHelpId() != null) + PlatformUI.getWorkbench().getHelpSystem().setHelp(pagebook, getContextHelpId()); + } + + /** + * Returns the context help id associated with the terminal console view instance. + * <p> + * <b>Note:</b> The default implementation returns the view id as context help id. + * + * @return The context help id or <code>null</code> if none is associated. + */ + @Override + public String getContextHelpId() { + return getViewSite().getId(); + } + + /** + * Creates the empty page control instance. + * + * @param parent The parent composite. Must not be <code>null</code>. + * @return The empty page control instance. Must never be <code>null</code>. + */ + protected Control doCreateEmptyPageControl(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayout(new GridLayout()); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + return composite; + } + + /** + * Configures the empty page control. + * + * @param control The empty page control. Must not be <code>null</code>. + */ + protected void doConfigureEmptyPageControl(Control control) { + Assert.isNotNull(control); + } + + /** + * Creates the tab folder control instance. + * + * @param parent The parent composite. Must not be <code>null</code>. + * @return The tab folder control instance. Must never be <code>null</code>. + */ + protected CTabFolder doCreateTabFolderControl(Composite parent) { + return new CTabFolder(parent, SWT.NO_REDRAW_RESIZE | SWT.NO_TRIM | SWT.FLAT | SWT.BORDER); + } + + /** + * Configures the tab folder control. + * + * @param tabFolder The tab folder control. Must not be <code>null</code>. + */ + protected void doConfigureTabFolderControl(CTabFolder tabFolder) { + Assert.isNotNull(tabFolder); + + // Set the layout data + tabFolder.setLayoutData(new GridData(GridData.FILL_BOTH)); + + // Set the tab gradient coloring from the global preferences + if (useGradientTabBackgroundColor()) { + tabFolder.setSelectionBackground(new Color[] { + JFaceResources.getColorRegistry().get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_START"), //$NON-NLS-1$ + JFaceResources.getColorRegistry().get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_END") //$NON-NLS-1$ + }, + new int[] {100}, true); + } + // Apply the tab folder selection foreground color + tabFolder.setSelectionForeground(JFaceResources.getColorRegistry().get("org.eclipse.ui.workbench.ACTIVE_TAB_TEXT_COLOR")); //$NON-NLS-1$ + + // Set the tab style from the global preferences + tabFolder.setSimple(PlatformUI.getPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS)); + } + + /** + * If <code>True</code> is returned, the inner tabs are colored with + * gradient coloring set in the Eclipse workbench color settings. + * + * @return <code>True</code> to use gradient tab colors, <code>false</code> otherwise. + */ + protected boolean useGradientTabBackgroundColor() { + return false; + } + + /** + * Creates the tab folder manager. + * + * @param parentView The parent view instance. Must be not <code>null</code>. + * @return The tab folder manager. Must never be <code>null</code>. + */ + protected TabFolderManager doCreateTabFolderManager(ITerminalsView parentView) { + Assert.isNotNull(parentView); + return new TabFolderManager(parentView); + } + + /** + * Creates the tab folder menu handler. + * + * @param parentView The parent view instance. Must be not <code>null</code>. + * @return The tab folder menu handler. Must never be <code>null</code>. + */ + protected TabFolderMenuHandler doCreateTabFolderMenuHandler(ITerminalsView parentView) { + Assert.isNotNull(parentView); + return new TabFolderMenuHandler(parentView); + } + + /** + * Configure the tab folder menu handler + * + * @param menuHandler The tab folder menu handler. Must not be <code>null</code>. + */ + protected void doConfigureTabFolderMenuHandler(TabFolderMenuHandler menuHandler) { + Assert.isNotNull(menuHandler); + menuHandler.initialize(); + } + + /** + * Creates the tab folder toolbar handler. + * + * @param parentView The parent view instance. Must be not <code>null</code>. + * @return The tab folder toolbar handler. Must never be <code>null</code>. + */ + protected TabFolderToolbarHandler doCreateTabFolderToolbarHandler(ITerminalsView parentView) { + Assert.isNotNull(parentView); + return new TabFolderToolbarHandler(parentView); + } + + /** + * Configure the tab folder toolbar handler + * + * @param toolbarHandler The tab folder toolbar handler. Must not be <code>null</code>. + */ + protected void doConfigureTabFolderToolbarHandler(TabFolderToolbarHandler toolbarHandler) { + Assert.isNotNull(toolbarHandler); + toolbarHandler.initialize(); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#setFocus() + */ + @Override + public void setFocus() { + pageBookControl.setFocus(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView#switchToEmptyPageControl() + */ + @Override + public void switchToEmptyPageControl() { + if (!pageBookControl.isDisposed() && !emptyPageControl.isDisposed()) pageBookControl.showPage(emptyPageControl); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView#switchToTabFolderControl() + */ + @Override + public void switchToTabFolderControl() { + if (!pageBookControl.isDisposed() && !tabFolderControl.isDisposed()) pageBookControl.showPage(tabFolderControl); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class) + */ + @Override + public Object getAdapter(Class adapter) { + if (CTabFolder.class.isAssignableFrom(adapter)) { + return tabFolderControl; + } else if (TabFolderManager.class.isAssignableFrom(adapter)) { + return tabFolderManager; + } else if (TabFolderMenuHandler.class.isAssignableFrom(adapter)) { + return tabFolderMenuHandler; + } else if (TabFolderToolbarHandler.class.isAssignableFrom(adapter)) { + return tabFolderToolbarHandler; + } + + return super.getAdapter(adapter); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/IUIConstants.java b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/IUIConstants.java index d5170d922..9ac6f85f5 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/IUIConstants.java +++ b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/IUIConstants.java @@ -13,8 +13,6 @@ import org.eclipse.tm.te.ui.activator.UIPlugin; /** * Target Explorer: Common UI constants. - * - * @author uwe.stieber@windriver.com */ public interface IUIConstants { |