blob: 8578a4d84f0eec2b003649710cd398df05a1718c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Greg Watson - Initial API and implementation
*******************************************************************************/
package org.eclipse.remote.ui.widgets;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteConnectionType;
import org.eclipse.remote.core.IRemoteConnectionWorkingCopy;
import org.eclipse.remote.core.IRemotePreferenceConstants;
import org.eclipse.remote.core.IRemoteServicesManager;
import org.eclipse.remote.internal.core.preferences.Preferences;
import org.eclipse.remote.internal.ui.RemoteUIPlugin;
import org.eclipse.remote.internal.ui.messages.Messages;
import org.eclipse.remote.ui.IRemoteUIConnectionService;
import org.eclipse.remote.ui.IRemoteUIConnectionWizard;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
/**
* Widget to allow the user to select a service provider and connection. Provides a "New" button to create a new connection.
*
* If title is supplied then the widget will be placed in a group.
*
* @since 5.0
*
*/
public class RemoteConnectionWidget extends Composite {
/**
* Listener for widget selected events. Allows the events to be enabled/disabled.
*
*/
protected class WidgetListener implements SelectionListener {
/** State of the listener (enabled/disabled). */
private boolean listenerEnabled = true;
/**
* Disable listener, received events shall be ignored.
*/
public void disable() {
setEnabled(false);
}
protected void doWidgetDefaultSelected(SelectionEvent e) {
// Default empty implementation.
}
/**
* Enable the listener to handle events.
*/
public void enable() {
setEnabled(true);
}
/**
* Test if the listener is enabled.
*/
public synchronized boolean isEnabled() {
return listenerEnabled;
}
/**
* Set listener enabled state
*
* @param enabled
*/
public synchronized void setEnabled(boolean enabled) {
listenerEnabled = enabled;
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
if (isEnabled()) {
widgetSelected(e);
}
}
@Override
public void widgetSelected(SelectionEvent e) {
if (isEnabled()) {
Object source = e.getSource();
if (source == fConnectionTypeCombo) {
handleConnectionTypeSelected(null);
} else if (source == fConnectionCombo) {
handleConnectionSelected();
} else if (source == fNewConnectionButton) {
handleNewRemoteConnectionSelected();
} else if (source == fLocalButton) {
handleButtonSelected();
} else if (source == fRemoteButton) {
handleButtonSelected();
}
}
}
}
public static final String DEFAULT_CONNECTION_NAME = "Remote Host"; //$NON-NLS-1$
/**
* Force the use of the connection type combo, regardless of the PREF_CONNECTION_TYPE preference setting.
*
* @since 2.0
*/
public static int FLAG_FORCE_CONNECTION_TYPE_SELECTION = 1 << 0;
/**
* Do not provide a selection for local services.
*/
public static int FLAG_NO_LOCAL_SELECTION = 1 << 1;
private Combo fConnectionTypeCombo;
private Button fLocalButton;
private Button fRemoteButton;
private final Combo fConnectionCombo;
private final Button fNewConnectionButton;
private List<IRemoteConnectionType> fConnectionTypes;
private IRemoteConnection fSelectedConnection;
private IRemoteServicesManager fRemoteServicesManager = RemoteUIPlugin.getService(IRemoteServicesManager.class);
private IRemoteConnectionType fDefaultConnectionType;
private boolean fSelectionListernersEnabled = true;
private boolean fEnabled = true;
private final ListenerList fSelectionListeners = new ListenerList();
private final WidgetListener fWidgetListener = new WidgetListener();
/**
* Constructor
*
* @param parent
* parent composite
* @param style
* style or SWT.NONE
* @param title
* if a title is supplied then the widget will be placed in a group. Can be null.
* @param flags
* a combination of flags that modify the behavior of the widget.
*/
public RemoteConnectionWidget(Composite parent, int style, String title, int flags) {
this(parent, style, title, flags, null, null);
}
/**
* Constructor
*
* @param parent
* parent composite
* @param style
* style or SWT.NONE
* @param title
* if a title is supplied then the widget will be placed in a group. Can be null.
* @param flags
* a combination of flags that modify the behavior of the widget.
* @param context
* runnable context, or null
* @since 2.0
*/
public RemoteConnectionWidget(Composite parent, int style, String title, int flags, IRunnableContext context) {
this(parent, style, title, flags, context, null);
}
/**
* Constructor
*
* @param parent
* parent composite
* @param style
* style or SWT.NONE
* @param title
* if a title is supplied then the widget will be placed in a group. Can be null.
* @param flags
* a combination of flags that modify the behavior of the widget.
* @param connnectionTypes
* list of connection types to select from
* @since 2.0
*/
public RemoteConnectionWidget(Composite parent, int style, String title, int flags,
List<IRemoteConnectionType> connectionTypes) {
this(parent, style, title, flags, null, connectionTypes);
}
/**
* Constructor
*
* @param parent
* parent composite
* @param style
* style or SWT.NONE
* @param title
* if a title is supplied then the widget will be placed in a group. Can be null.
* @param flags
* a combination of flags that modify the behavior of the widget.
* @param context
* runnable context, or null
* @param connectionTypes
* list of connection types to select from
* @since 2.0
*/
public RemoteConnectionWidget(Composite parent, int style, String title, int flags, IRunnableContext context,
List<IRemoteConnectionType> connectionTypes) {
super(parent, style);
if (connectionTypes != null) {
// Just present the connections that are provided
flags |= FLAG_FORCE_CONNECTION_TYPE_SELECTION | FLAG_NO_LOCAL_SELECTION;
}
Composite body = this;
GridLayout layout = new GridLayout(1, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 4;
setLayout(layout);
setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
if (title != null) {
Group group = new Group(this, SWT.NONE);
group.setText(title);
GridLayout groupLayout = new GridLayout(1, false);
groupLayout.marginHeight = 0;
groupLayout.marginWidth = 0;
groupLayout.numColumns = 4;
group.setLayout(groupLayout);
group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
layout.numColumns = 1;
body = group;
}
fRemoteServicesManager = RemoteUIPlugin.getService(IRemoteServicesManager.class);
if (connectionTypes != null) {
// No default if the list of connection types was supplied
fConnectionTypes = connectionTypes;
} else {
fConnectionTypes = fRemoteServicesManager.getRemoteConnectionTypes();
String id = Preferences.getString(IRemotePreferenceConstants.PREF_CONNECTION_TYPE_ID);
if (id != null) {
fDefaultConnectionType = fRemoteServicesManager.getConnectionType(id);
}
}
/*
* Check if we need a connection type combo, or we should just use the default provider
*/
if ((flags & FLAG_FORCE_CONNECTION_TYPE_SELECTION) != 0) {
Label label = new Label(body, SWT.NONE);
label.setText(Messages.RemoteConnectionWidget_Connection_Type);
label.setLayoutData(new GridData());
fConnectionTypeCombo = new Combo(body, SWT.DROP_DOWN | SWT.READ_ONLY);
GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
gd.horizontalSpan = 3;
fConnectionTypeCombo.setLayoutData(gd);
fConnectionTypeCombo.addSelectionListener(fWidgetListener);
fConnectionTypeCombo.setFocus();
}
if ((flags & FLAG_NO_LOCAL_SELECTION) == 0 && (flags & FLAG_FORCE_CONNECTION_TYPE_SELECTION) == 0) {
fLocalButton = new Button(body, SWT.RADIO);
fLocalButton.setText(Messages.RemoteConnectionWidget_Local);
fLocalButton.setLayoutData(new GridData());
fLocalButton.addSelectionListener(fWidgetListener);
fLocalButton.setSelection(false);
fRemoteButton = new Button(body, SWT.RADIO);
fRemoteButton.setText(Messages.RemoteConnectionWidget_Remote);
fRemoteButton.setLayoutData(new GridData());
fRemoteButton.addSelectionListener(fWidgetListener);
} else {
Label remoteLabel = new Label(body, SWT.NONE);
remoteLabel.setText(Messages.RemoteConnectionWidget_Connection_Name);
remoteLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
}
fConnectionCombo = new Combo(body, SWT.DROP_DOWN | SWT.READ_ONLY);
fConnectionCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
fConnectionCombo.addSelectionListener(fWidgetListener);
if (fDefaultConnectionType != null) {
fConnectionCombo.setFocus();
}
fConnectionCombo.setEnabled(false);
fNewConnectionButton = new Button(body, SWT.PUSH);
fNewConnectionButton.setText(Messages.RemoteConnectionWidget_New);
fNewConnectionButton.setLayoutData(new GridData());
fNewConnectionButton.addSelectionListener(fWidgetListener);
if (fConnectionTypeCombo != null) {
initializeConnectionTypeCombo();
}
handleConnectionTypeSelected(null);
if (fLocalButton != null) {
handleButtonSelected();
}
}
/**
* Adds the listener to the collection of listeners who will be notified when the user changes the receiver's selection, by
* sending it one of the messages defined in the <code>SelectionListener</code> interface.
* <p>
* <code>widgetSelected</code> is called when the user changes the service provider or connection.
* </p>
*
* @param listener
* the listener which should be notified
*/
public void addSelectionListener(SelectionListener listener) {
fSelectionListeners.add(listener);
}
/**
* Limit the connection types that will be used when displaying valid connections. Only connection types that support
* connections with supplied services will be displayed in the connection type combo, and only connections from these connection
* types will be displayed in the connection combo.
*
* @param services
* list of services {@link IRemoteConnection.Service}
* @since 2.0
*/
@SafeVarargs
public final void filterConnections(Class<? extends IRemoteConnection.Service>... services) {
fConnectionTypes = fRemoteServicesManager.getConnectionTypesSupporting(services);
if (fConnectionTypeCombo != null) {
initializeConnectionTypeCombo();
}
handleConnectionTypeSelected(null);
}
/**
* Get the new button from the widget
*
* @return button
* @since 7.0
*/
public Button getButton() {
return fNewConnectionButton;
}
/**
* Get the connection that is currently selected in the widget, or null if there is no selected connection.
*
* @return selected connection
*/
public IRemoteConnection getConnection() {
return fSelectedConnection;
}
private IRemoteConnectionType getSelectedConnectionType() {
if (fConnectionTypeCombo != null) {
int selectionIndex = fConnectionTypeCombo.getSelectionIndex();
if (fConnectionTypes.size() > 0 && selectionIndex > 0) {
return fConnectionTypes.get(selectionIndex - 1);
}
}
if (fDefaultConnectionType != null) {
return fDefaultConnectionType;
}
return null;
}
private IRemoteUIConnectionService getUIConnectionManager() {
IRemoteConnectionType services = getSelectedConnectionType();
if (services != null) {
return services.getService(IRemoteUIConnectionService.class);
}
return null;
}
private void handleButtonSelected() {
fRemoteButton.setSelection(!fLocalButton.getSelection());
updateEnablement();
handleConnectionSelected();
}
/**
* Handle the section of a new connection. Update connection option buttons appropriately.
*/
protected void handleConnectionSelected() {
final boolean enabled = fWidgetListener.isEnabled();
fWidgetListener.disable();
IRemoteConnection selectedConnection = null;
if (fLocalButton != null && fLocalButton.getSelection()) {
selectedConnection = fRemoteServicesManager.getLocalConnectionType().getConnections().get(0);
} else {
int currentSelection = fConnectionCombo.getSelectionIndex();
if (currentSelection > 0) {
String connectionName = fConnectionCombo.getItem(currentSelection);
selectedConnection = getSelectedConnectionType().getConnection(connectionName);
}
}
if (selectedConnection == null || fSelectedConnection == null
|| !selectedConnection.getName().equals(fSelectedConnection.getName())) {
fSelectedConnection = selectedConnection;
Event evt = new Event();
evt.widget = this;
notifyListeners(new SelectionEvent(evt));
}
fWidgetListener.setEnabled(enabled);
}
/**
* Handle creation of a new connection by pressing the 'New...' button. Calls handleRemoteServicesSelected() to update the
* connection combo with the new connection.
*
* TODO should probably select the new connection
*/
protected void handleNewRemoteConnectionSelected() {
if (getUIConnectionManager() != null) {
IRemoteUIConnectionWizard wizard = getUIConnectionManager().getConnectionWizard(getShell());
if (wizard != null) {
wizard.setConnectionName(initialConnectionName());
IRemoteConnectionWorkingCopy conn = wizard.open();
if (conn != null) {
try {
handleConnectionTypeSelected(conn.save());
handleConnectionSelected();
} catch (CoreException e) {
RemoteUIPlugin.log(e);
}
}
}
}
}
/**
* Handle selection of a new connection type from the connection type combo. Handles the special case where the
* connection type combo is null and a local connection is supplied. In this case, the selected connection type is not changed.
*
* The assumption is that this will trigger a call to the selection handler for the connection combo.
*
* @param conn
* connection to select as current. If conn is null, select the first item in the list.
* @since 2.0
*/
protected void handleConnectionTypeSelected(IRemoteConnection conn) {
final boolean enabled = fWidgetListener.isEnabled();
fWidgetListener.disable();
try {
IRemoteConnectionType selectedConnectionType = getSelectedConnectionType();
if (conn != null) {
selectedConnectionType = conn.getConnectionType();
}
/*
* If a connection was supplied, set its connection type in the combo. Otherwise use the currently selected
* service.
*/
if (fDefaultConnectionType == null && conn != null) {
for (int index = 0; index < fConnectionTypes.size(); index++) {
if (fConnectionTypes.get(index).getId().equals(selectedConnectionType.getId())) {
fConnectionTypeCombo.select(index + 1);
break;
}
}
}
fConnectionCombo.removeAll();
fConnectionCombo.add(Messages.RemoteConnectionWidget_selectConnection);
if (selectedConnectionType == null) {
fConnectionCombo.select(0);
fConnectionCombo.setEnabled(false);
fNewConnectionButton.setEnabled(false);
handleConnectionSelected();
} else {
fConnectionCombo.setEnabled(true);
/*
* Populate the connection combo and select the connection
*/
int selected = 0;
int offset = 1;
List<IRemoteConnection> sorted = selectedConnectionType.getConnections();
Collections.sort(sorted, new Comparator<IRemoteConnection>() {
@Override
public int compare(IRemoteConnection o1, IRemoteConnection o2) {
return o1.getName().compareTo(o2.getName());
}
});
for (IRemoteConnection s : sorted) {
fConnectionCombo.add(s.getName());
if (conn != null && s.getName().equals(conn.getName())) {
selected = offset;
}
offset++;
}
fConnectionCombo.select(selected);
handleConnectionSelected();
/*
* Enable 'new' button if new connections are supported
*/
fNewConnectionButton.setEnabled(selectedConnectionType.canAdd());
}
} finally {
fWidgetListener.setEnabled(enabled);
}
}
private String initialConnectionName() {
String name = DEFAULT_CONNECTION_NAME;
int count = 1;
while (getSelectedConnectionType().getConnection(name) != null) {
name = DEFAULT_CONNECTION_NAME + " " + count++; //$NON-NLS-1$
}
return name;
}
/**
* Initialize the contents of the connection type combo. Keeps an array of connection types that matches the combo elements.
*
* @since 2.0
*/
protected void initializeConnectionTypeCombo() {
final boolean enabled = fWidgetListener.isEnabled();
fWidgetListener.disable();
fConnectionTypeCombo.removeAll();
int offset = 1;
int defIndex = 0;
fConnectionTypeCombo.add(Messages.RemoteConnectionWidget_selectConnectionType);
for (int i = 0; i < fConnectionTypes.size(); i++) {
fConnectionTypeCombo.add(fConnectionTypes.get(i).getName());
if (fDefaultConnectionType != null && fConnectionTypes.get(i).equals(fDefaultConnectionType)) {
defIndex = i + offset;
}
}
if (fConnectionTypes.size() > 0) {
fConnectionTypeCombo.select(defIndex);
}
fWidgetListener.setEnabled(enabled);
}
@Override
public boolean isEnabled() {
return fEnabled;
}
private void notifyListeners(SelectionEvent e) {
if (fSelectionListernersEnabled) {
for (Object listener : fSelectionListeners.getListeners()) {
((SelectionListener) listener).widgetSelected(e);
}
}
}
/**
* Remove a listener that will be notified when one of the widget's controls are selected
*
* @param listener
* listener to remove
*/
public void removeSelectionListener(SelectionListener listener) {
fSelectionListeners.remove(listener);
}
/**
* Set the connection that should be selected in the widget.
*
* @param connection
* connection to select
* @throws CoreException
*/
public void setConnection(IRemoteConnection connection) {
fSelectionListernersEnabled = false;
if (fLocalButton != null && connection != null
&& connection.getConnectionType() == fRemoteServicesManager.getLocalConnectionType()) {
fLocalButton.setSelection(true);
handleButtonSelected();
} else {
handleConnectionTypeSelected(connection);
}
handleConnectionSelected();
updateEnablement();
fSelectionListernersEnabled = true;
}
/**
* Set the connection that should be selected in the widget.
*
* @param id
* connection type id
* @param name
* connection name
* @since 6.0
*/
public void setConnection(String id, String name) {
IRemoteConnectionType connectionType = fRemoteServicesManager.getConnectionType(id);
if (connectionType != null) {
IRemoteConnection connection = connectionType.getConnection(name);
if (connection != null) {
setConnection(connection);
}
}
}
@Override
public void setEnabled(boolean enabled) {
fEnabled = enabled;
updateEnablement();
}
private void updateEnablement() {
if (fDefaultConnectionType != null) {
boolean isRemote = true;
if (fLocalButton != null) {
fLocalButton.setEnabled(fEnabled);
fRemoteButton.setEnabled(fEnabled);
isRemote = !fLocalButton.getSelection();
}
fConnectionCombo.setEnabled(fEnabled && isRemote);
fNewConnectionButton.setEnabled(fEnabled && isRemote && fDefaultConnectionType.canAdd());
} else {
IRemoteConnectionType services = getSelectedConnectionType();
fConnectionCombo.setEnabled(fEnabled && services != null);
fNewConnectionButton.setEnabled(fEnabled && services != null && services.canAdd());
if (fConnectionTypeCombo != null) {
fConnectionTypeCombo.setEnabled(fEnabled);
}
}
}
}