blob: 38208230ae0de4b51cd26a81874b8f7f6eb99d7f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.debug.ui.jres;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.internal.ui.SWTFactory;
import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
import org.eclipse.jdt.internal.debug.ui.actions.ControlAccessibleListener;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.IVMInstallType;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.launching.VMStandin;
import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.osgi.util.NLS;
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.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
/**
* A composite that displays installed JREs in a combo box, with a 'manage...'
* button to modify installed JREs.
* <p>
* This block implements ISelectionProvider - it sends selection change events
* when the checked JRE in the table changes, or when the "use default" button
* check state changes.
* </p>
*/
public class JREsComboBlock {
public static final String PROPERTY_JRE = "PROPERTY_JRE"; //$NON-NLS-1$
/**
* This block's control
*/
private Composite fControl;
/**
* VMs being displayed
*/
private List<Object> fVMs = new ArrayList<>();
/**
* The main control
*/
private Combo fCombo;
// Action buttons
private Button fManageButton;
/**
* JRE change listeners
*/
private ListenerList<IPropertyChangeListener> fListeners = new ListenerList<>();
/**
* Whether the default JRE should be in first position (if <code>false</code>, it becomes last).
*/
private boolean fDefaultFirst;
/**
* Default JRE descriptor or <code>null</code> if none.
*/
private JREDescriptor fDefaultDescriptor = null;
/**
* Specific JRE descriptor or <code>null</code> if none.
*/
private JREDescriptor fSpecificDescriptor = null;
/**
* Default JRE radio button or <code>null</code> if none
*/
private Button fDefaultButton = null;
/**
* Selected JRE radio button
*/
private Button fSpecificButton = null;
/**
* The title used for the JRE block
*/
private String fTitle = null;
/**
* Selected JRE profile radio button
*/
private Button fEnvironmentsButton = null;
/**
* Combo box of JRE profiles
*/
private Combo fEnvironmentsCombo = null;
private Button fManageEnvironmentsButton = null;
// a path to an unavailable JRE
private IPath fErrorPath;
/**
* List of execution environments
*/
private List<Object> fEnvironments = new ArrayList<>();
private IStatus fStatus = OK_STATUS;
private static IStatus OK_STATUS = new Status(IStatus.OK, JDIDebugUIPlugin.getUniqueIdentifier(), 0, "", null); //$NON-NLS-1$
/**
* Creates a JREs combo block.
*
* @param defaultFirst whether the default JRE should be in first position (if <code>false</code>, it becomes last)
*/
public JREsComboBlock(boolean defaultFirst) {
fDefaultFirst= defaultFirst;
}
public void addPropertyChangeListener(IPropertyChangeListener listener) {
fListeners.add(listener);
}
public void removePropertyChangeListener(IPropertyChangeListener listener) {
fListeners.remove(listener);
}
private void firePropertyChange() {
PropertyChangeEvent event = new PropertyChangeEvent(this, PROPERTY_JRE, null, getPath());
for (IPropertyChangeListener listener : fListeners) {
listener.propertyChange(event);
}
}
/**
* Creates this block's control in the given control.
*
* @param anscestor containing control
*/
public void createControl(Composite ancestor) {
fControl = SWTFactory.createComposite(ancestor, 1, 1, GridData.FILL_BOTH);
if (fTitle == null) {
fTitle = JREMessages.JREsComboBlock_3;
}
Group group = SWTFactory.createGroup(fControl, fTitle, 1, 1, GridData.FILL_HORIZONTAL);
Composite comp = SWTFactory.createComposite(group, group.getFont(), 3, 1, GridData.FILL_BOTH, 0, 0);
if (fDefaultFirst) {
createDefaultJREControls(comp);
}
createEEControls(comp);
createAlternateJREControls(comp);
if (!fDefaultFirst) {
createDefaultJREControls(comp);
}
}
private void createEEControls(Composite comp) {
fEnvironmentsButton = SWTFactory.createRadioButton(comp, JREMessages.JREsComboBlock_4);
fEnvironmentsButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (fEnvironmentsButton.getSelection()) {
fCombo.setEnabled(false);
if (fEnvironmentsCombo.getText().length() == 0 && !fEnvironments.isEmpty()) {
fEnvironmentsCombo.select(0);
}
fEnvironmentsCombo.setEnabled(true);
if (fEnvironments.isEmpty()) {
setError(JREMessages.JREsComboBlock_5);
} else {
setStatus(OK_STATUS);
}
firePropertyChange();
}
}
});
fEnvironmentsCombo = SWTFactory.createCombo(comp, SWT.DROP_DOWN | SWT.READ_ONLY, 1, null);
fEnvironmentsCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
setPath(JavaRuntime.newJREContainerPath(getEnvironment()));
firePropertyChange();
}
});
fManageEnvironmentsButton = SWTFactory.createPushButton(comp, JREMessages.JREsComboBlock_14, null);
fManageEnvironmentsButton.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event event) {
showPrefPage(ExecutionEnvironmentsPreferencePage.ID);
}
});
fillWithWorkspaceProfiles();
}
private void createAlternateJREControls(Composite comp) {
String text = JREMessages.JREsComboBlock_1;
if (fSpecificDescriptor != null) {
text = fSpecificDescriptor.getDescription();
}
fSpecificButton = SWTFactory.createRadioButton(comp, text, 1);
fSpecificButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (fSpecificButton.getSelection()) {
fCombo.setEnabled(true);
if (fCombo.getText().length() == 0 && !fVMs.isEmpty()) {
fCombo.select(0);
}
if (fVMs.isEmpty()) {
setError(JREMessages.JREsComboBlock_0);
} else {
setStatus(OK_STATUS);
}
fEnvironmentsCombo.setEnabled(false);
firePropertyChange();
}
}
});
fCombo = SWTFactory.createCombo(comp, SWT.DROP_DOWN | SWT.READ_ONLY, 1, null);
ControlAccessibleListener.addListener(fCombo, fSpecificButton.getText());
fCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
setStatus(OK_STATUS);
firePropertyChange();
}
});
fManageButton = SWTFactory.createPushButton(comp, JREMessages.JREsComboBlock_2, null);
fManageButton.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event event) {
showPrefPage(JREsPreferencePage.ID);
}
});
fillWithWorkspaceJREs();
}
private void createDefaultJREControls(Composite comp) {
if (fDefaultDescriptor != null) {
fDefaultButton = SWTFactory.createRadioButton(comp, fDefaultDescriptor.getDescription(), 3);
fDefaultButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (fDefaultButton.getSelection()) {
setUseDefaultJRE();
setStatus(OK_STATUS);
firePropertyChange();
}
}
});
}
}
/**
* Opens the given preference page, and updates when closed.
*
* @param id pref page id
* @param page pref page
*/
private void showPrefPage(String id/*, IPreferencePage page*/) {
IVMInstall prevJRE = getJRE();
IExecutionEnvironment prevEnv = getEnvironment();
JDIDebugUIPlugin.showPreferencePage(id);
fillWithWorkspaceJREs();
fillWithWorkspaceProfiles();
restoreCombo(fVMs, prevJRE, fCombo);
restoreCombo(fEnvironments, prevEnv, fEnvironmentsCombo);
// update text
setDefaultJREDescriptor(fDefaultDescriptor);
if (isDefaultJRE()) {
// reset in case default has changed
setUseDefaultJRE();
}
setPath(getPath());
firePropertyChange();
}
private void restoreCombo(List<Object> elements, Object element, Combo combo) {
int index = -1;
if (element != null) {
index = elements.indexOf(element);
}
if (index >= 0) {
combo.select(index);
} else {
combo.select(0);
}
}
/**
* Returns this block's control
*
* @return control
*/
public Control getControl() {
return fControl;
}
/**
* Sets the JREs to be displayed in this block
*
* @param vms JREs to be displayed
*/
protected void setJREs(List<VMStandin> jres) {
fVMs.clear();
fVMs.addAll(jres);
// sort by name
Collections.sort(fVMs, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
IVMInstall left = (IVMInstall)o1;
IVMInstall right = (IVMInstall)o2;
return left.getName().compareToIgnoreCase(right.getName());
}
@Override
public boolean equals(Object obj) {
return obj == this;
}
});
// now make an array of names
String[] names = new String[fVMs.size()];
Iterator<Object> iter = fVMs.iterator();
int i = 0;
while (iter.hasNext()) {
IVMInstall vm = (IVMInstall)iter.next();
names[i] = vm.getName();
i++;
}
fCombo.setItems(names);
fCombo.setVisibleItemCount(Math.min(names.length, 20));
}
protected Shell getShell() {
return getControl().getShell();
}
/**
* Selects a specific JRE based on type/name.
*
* @param vm JRE or <code>null</code>
*/
private void selectJRE(IVMInstall vm) {
fSpecificButton.setSelection(true);
fDefaultButton.setSelection(false);
fEnvironmentsButton.setSelection(false);
fCombo.setEnabled(true);
fEnvironmentsCombo.setEnabled(false);
if (vm != null) {
int index = fVMs.indexOf(vm);
if (index >= 0) {
fCombo.select(index);
}
}
firePropertyChange();
}
/**
* Selects a JRE based environment.
*
* @param env environment or <code>null</code>
*/
private void selectEnvironment(IExecutionEnvironment env) {
fSpecificButton.setSelection(false);
fDefaultButton.setSelection(false);
fCombo.setEnabled(false);
fEnvironmentsButton.setSelection(true);
fEnvironmentsCombo.setEnabled(true);
if (env != null) {
int index = fEnvironments.indexOf(env);
if (index >= 0) {
fEnvironmentsCombo.select(index);
}
}
firePropertyChange();
}
/**
* Returns the selected JRE or <code>null</code> if none.
*
* @return the selected JRE or <code>null</code> if none
*/
public IVMInstall getJRE() {
int index = fCombo.getSelectionIndex();
if (index >= 0) {
return (IVMInstall)fVMs.get(index);
}
return null;
}
/**
* Returns the selected Environment or <code>null</code> if none.
*
* @return the selected Environment or <code>null</code> if none
*/
private IExecutionEnvironment getEnvironment() {
int index = fEnvironmentsCombo.getSelectionIndex();
if (index >= 0) {
return (IExecutionEnvironment)fEnvironments.get(index);
}
return null;
}
/**
* Populates the JRE table with existing JREs defined in the workspace.
*/
protected void fillWithWorkspaceJREs() {
// fill with JREs
List<VMStandin> standins = new ArrayList<>();
IVMInstallType[] types = JavaRuntime.getVMInstallTypes();
for (int i = 0; i < types.length; i++) {
IVMInstallType type = types[i];
IVMInstall[] installs = type.getVMInstalls();
for (int j = 0; j < installs.length; j++) {
IVMInstall install = installs[j];
standins.add(new VMStandin(install));
}
}
setJREs(standins);
}
/**
* Populates the JRE profile combo with profiles defined in the workspace.
*/
protected void fillWithWorkspaceProfiles() {
fEnvironments.clear();
IExecutionEnvironment[] environments = JavaRuntime.getExecutionEnvironmentsManager().getExecutionEnvironments();
for (int i = 0; i < environments.length; i++) {
fEnvironments.add(environments[i]);
}
String[] names = new String[fEnvironments.size()];
Iterator<Object> iter = fEnvironments.iterator();
int i = 0;
while (iter.hasNext()) {
IExecutionEnvironment env = (IExecutionEnvironment)iter.next();
IPath path = JavaRuntime.newJREContainerPath(env);
IVMInstall install = JavaRuntime.getVMInstall(path);
if (install != null) {
names[i] = NLS.bind(JREMessages.JREsComboBlock_15, new String[]{env.getId(), install.getName()});
} else {
names[i] = NLS.bind(JREMessages.JREsComboBlock_16, new String[]{env.getId()});
}
i++;
}
fEnvironmentsCombo.setItems(names);
fEnvironmentsCombo.setVisibleItemCount(Math.min(names.length, 20));
}
/**
* Sets the Default JRE Descriptor for this block.
*
* @param descriptor default JRE descriptor
*/
public void setDefaultJREDescriptor(JREDescriptor descriptor) {
fDefaultDescriptor = descriptor;
setButtonTextFromDescriptor(fDefaultButton, descriptor);
}
private void setButtonTextFromDescriptor(Button button, JREDescriptor descriptor) {
if (button != null) {
//update the description & JRE in case it has changed
String currentText = button.getText();
String newText = descriptor.getDescription();
if (!newText.equals(currentText)) {
button.setText(newText);
fControl.layout();
}
}
}
/**
* Sets the specific JRE Descriptor for this block.
*
* @param descriptor specific JRE descriptor
*/
public void setSpecificJREDescriptor(JREDescriptor descriptor) {
fSpecificDescriptor = descriptor;
setButtonTextFromDescriptor(fSpecificButton, descriptor);
}
/**
* Returns whether the 'use default JRE' button is checked.
*
* @return whether the 'use default JRE' button is checked
*/
public boolean isDefaultJRE() {
if (fDefaultButton != null) {
return fDefaultButton.getSelection();
}
return false;
}
/**
* Sets this control to use the 'default' JRE.
*/
private void setUseDefaultJRE() {
if (fDefaultDescriptor != null) {
fDefaultButton.setSelection(true);
fSpecificButton.setSelection(false);
fEnvironmentsButton.setSelection(false);
fCombo.setEnabled(false);
fEnvironmentsCombo.setEnabled(false);
firePropertyChange();
}
}
/**
* Sets the title used for this JRE block
*
* @param title title for this JRE block
*/
public void setTitle(String title) {
fTitle = title;
}
/**
* Refresh the default JRE description.
*/
public void refresh() {
setDefaultJREDescriptor(fDefaultDescriptor);
}
/**
* Returns a classpath container path identifying the selected JRE.
*
* @return classpath container path or <code>null</code>
* @since 3.2
*/
public IPath getPath() {
if (!getStatus().isOK() && fErrorPath != null) {
return fErrorPath;
}
if (fEnvironmentsButton.getSelection()) {
int index = fEnvironmentsCombo.getSelectionIndex();
if (index >= 0) {
IExecutionEnvironment env = (IExecutionEnvironment) fEnvironments.get(index);
return JavaRuntime.newJREContainerPath(env);
}
return null;
}
if (fSpecificButton.getSelection()) {
int index = fCombo.getSelectionIndex();
if (index >= 0) {
IVMInstall vm = (IVMInstall) fVMs.get(index);
return JavaRuntime.newJREContainerPath(vm);
}
return null;
}
return JavaRuntime.newDefaultJREContainerPath();
}
/**
* Sets the selection based on the given container path and returns
* a status indicating if the selection was successful.
*
* @param containerPath
* @return status
*/
public void setPath(IPath containerPath) {
fErrorPath = null;
setStatus(OK_STATUS);
if (JavaRuntime.newDefaultJREContainerPath().equals(containerPath)) {
setUseDefaultJRE();
} else {
String envId = JavaRuntime.getExecutionEnvironmentId(containerPath);
if (envId != null) {
IExecutionEnvironmentsManager manager = JavaRuntime.getExecutionEnvironmentsManager();
IExecutionEnvironment environment = manager.getEnvironment(envId);
if (environment == null) {
fErrorPath = containerPath;
selectEnvironment(environment);
setError(NLS.bind(JREMessages.JREsComboBlock_6, new String[]{envId}));
} else {
selectEnvironment(environment);
IVMInstall[] installs = environment.getCompatibleVMs();
if (installs.length == 0) {
setError(NLS.bind(JREMessages.JREsComboBlock_7, new String[]{environment.getId()}));
}
}
} else {
IVMInstall install = JavaRuntime.getVMInstall(containerPath);
if (install == null) {
selectJRE(install);
fErrorPath = containerPath;
String installTypeId = JavaRuntime.getVMInstallTypeId(containerPath);
if (installTypeId == null) {
setError(JREMessages.JREsComboBlock_8);
} else {
IVMInstallType installType = JavaRuntime.getVMInstallType(installTypeId);
if (installType == null) {
setError(NLS.bind(JREMessages.JREsComboBlock_9, new String[]{installTypeId}));
} else {
String installName = JavaRuntime.getVMInstallName(containerPath);
if (installName == null) {
setError(NLS.bind(JREMessages.JREsComboBlock_10, new String[]{installType.getName()}));
} else {
setError(NLS.bind(JREMessages.JREsComboBlock_11, new String[]{installName, installType.getName()}));
}
}
}
} else {
selectJRE(install);
File location = install.getInstallLocation();
if (location == null) {
setError(JREMessages.JREsComboBlock_12);
} else if (!location.exists()) {
setError(JREMessages.JREsComboBlock_13);
}
}
}
}
}
private void setError(String message) {
setStatus(new Status(IStatus.ERROR, JDIDebugUIPlugin.getUniqueIdentifier(),
IJavaDebugUIConstants.INTERNAL_ERROR, message, null));
}
/**
* Returns the status of the JRE selection.
*
* @return status
*/
public IStatus getStatus() {
return fStatus;
}
private void setStatus(IStatus status) {
fStatus = status;
}
}