/*******************************************************************************
* Copyright (c) 2012 Pivotal Software, Inc.
* 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:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.springsource.ide.eclipse.gradle.ui;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.preference.IPreferenceNode;
import org.eclipse.jface.preference.IPreferencePage;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.preference.PreferenceManager;
import org.eclipse.jface.preference.PreferenceNode;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.springsource.ide.eclipse.gradle.core.preferences.IJavaHomePreferences;
import org.springsource.ide.eclipse.gradle.core.util.JavaRuntimeUtils;
import org.springsource.ide.eclipse.gradle.core.util.expression.LiveExpression;
import org.springsource.ide.eclipse.gradle.core.validators.JavaHomeValidator;
import org.springsource.ide.eclipse.gradle.core.validators.JavaHomeValidatorContext;
import org.springsource.ide.eclipse.gradle.core.validators.ValidationResult;
/**
* Section on a preferences page that allows user to pick a specific Gradle distribution.
* <p>
* Here we implement/extend neither PageWithSection nor LaunchTabSection because we
* need to be able to use it in the implementation of either of these two.
* <p>
* Essentially, this implementation provides the widgets, validation logic and
* methods to copy preferences from/to the widgets to/from a IJavaHomePreferences object.
*
* @author Kris De Volder
*/
public class JavaHomeSectionImpl implements JavaHomeValidatorContext, IJavaHomePreferences {
private static final String TITLE = "Java Home (requires Gradle 1.0.RC1 or later)";
public interface IWidgetRefreshListener {
void widgetsRefreshed();
}
private IPageWithSections owner;
private IWidgetRefreshListener widgetListener; // Clients that need to be able to respond to any changes in the widgets
// to update some state can attach an instance via the constructor.
protected static final String JRE_PREF_PAGE_ID = "org.eclipse.jdt.debug.ui.preferences.VMPreferencePage";
private LiveExpression<ValidationResult> validator;
//////// alternative 1: Use wrapper default ///////////////////////
private Button defaultButton;
//////// alternative 2: Local JVM install folder ///////////////////////
private Button customHomeButton;
private Combo customJRECombo;
private Button configureJREsButton;
/////// alternative 3: Execution environment ///////////////////////////
private Button customExecutionEnvButton;
private Combo customExecutionEnvCombo;
private Button configureExecEnvsButton;
////////////
private JavaRuntimeUtils jres = new JavaRuntimeUtils();
private boolean border = false;
public JavaHomeSectionImpl(IPageWithSections owner, IWidgetRefreshListener widgetListener) {
this.owner = owner;
this.validator = new JavaHomeValidator(this);
this.widgetListener = widgetListener;
}
private void doRefresh() {
validator.refresh();
if (widgetListener!=null) {
widgetListener.widgetsRefreshed();
}
}
/**
* If set to true, a border will be create around the widgets.
* This method must be called before createWidgets.
*/
public JavaHomeSectionImpl setBorder(boolean enable) {
this.border = enable;
return this;
}
/**
* This does more or less what a PageSection implementation of createContents should do (i.e.
* create the widgets on the page).
* <p>
* However, it does not fill the widget contents with the contents of the preferences because
* this implementation may not yet be connected to a preferences store yet when the widgets
* are being created. It is up to the caller/client to make sure a to call copyFrom method
* to (re)initialise the widget contents at an appropriate time.
*
* @param page
*/
public void createWidgets(Composite page) {
GridDataFactory grabHor = GridDataFactory.fillDefaults().grab(true, false);
Group group = null;
if (!border) {
Label label = new Label(page, SWT.NONE);
label.setText(TITLE);
} else {
group = new Group(page, SWT.BORDER);
group.setText(TITLE);
}
//Alternative 1
Composite composite = border ? group : new Composite(page, SWT.NONE);
GridLayout layout = new GridLayout(3, false);
composite.setLayout(layout);
grabHor.applyTo(composite);
defaultButton = new Button(composite, SWT.RADIO);
defaultButton.setText("Use Gradle wrapper's default");
GridDataFactory span = GridDataFactory.fillDefaults().span(3, 1);
span.applyTo(defaultButton);
//Alternative 2: choose a workspace JRE
customHomeButton = new Button(composite, SWT.RADIO);
customHomeButton.setText("Workspace JRE: ");
customHomeButton.setToolTipText("Use a specific Java installation configured in this workspace");
customJRECombo = new Combo(composite, SWT.DROP_DOWN+SWT.READ_ONLY);
configureJREsButton = new Button(composite, SWT.PUSH);
configureJREsButton.setText("Configure JREs");
grabHor.applyTo(configureJREsButton);
grabHor.applyTo(customJRECombo);
//Alternative 3: choose an execution environment
customExecutionEnvButton = new Button(composite, SWT.RADIO);
customExecutionEnvButton.setText("Execution Environment");
customExecutionEnvButton.setToolTipText("Specify a JRE indirectly via an execution environment");
customExecutionEnvCombo = new Combo(composite, SWT.DROP_DOWN+SWT.READ_ONLY);
configureExecEnvsButton = new Button(composite, SWT.PUSH);
configureExecEnvsButton.setText("Configure EEs");
grabHor.applyTo(configureExecEnvsButton);
grabHor.applyTo(customExecutionEnvCombo);
refreshJREs();
customHomeButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
enableDisableWidgets(customHomeButton, customJRECombo, configureJREsButton);
doRefresh();
}
});
customExecutionEnvButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
enableDisableWidgets(customExecutionEnvButton,
customExecutionEnvCombo, configureExecEnvsButton);
doRefresh();
}
});
configureJREsButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
@SuppressWarnings("restriction")
IPreferencePage page = new org.eclipse.jdt.internal.debug.ui.jres.JREsPreferencePage();
PreferenceManager mgr = new PreferenceManager();
IPreferenceNode node = new PreferenceNode("1", page);
mgr.addToRoot(node);
PreferenceDialog dialog = new PreferenceDialog(owner.getShell(), mgr);
dialog.create();
dialog.setMessage(page.getTitle());
dialog.open();
refreshJREs();
}
});
configureExecEnvsButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
@SuppressWarnings("restriction")
IPreferencePage page = new org.eclipse.jdt.internal.debug.ui.jres.ExecutionEnvironmentsPreferencePage();
PreferenceManager mgr = new PreferenceManager();
IPreferenceNode node = new PreferenceNode("1", page);
mgr.addToRoot(node);
PreferenceDialog dialog = new PreferenceDialog(owner.getShell(), mgr);
dialog.create();
dialog.setMessage(page.getTitle());
dialog.open();
refreshJREs();
}
});
customJRECombo.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
doRefresh();
}
});
customExecutionEnvCombo.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
doRefresh();
}
});
grabHor.applyTo(customJRECombo);
}
private void refreshJREs() {
jres = new JavaRuntimeUtils();
setItems(customJRECombo, jres.getWorkspaceJVMNames());
setItems(customExecutionEnvCombo, jres.getExecutionEnvNames());
}
private static void setItems(Combo combo, String[] items) {
String oldSelection = combo.getText();
combo.setItems(items);
combo.setText(oldSelection); //Otherwise the selection gets cleared which is annoying.
}
/**
* Enable/disable a number of controls depending on whether given radio button is enabled/disabled.
*/
public void enableDisableWidgets(Button radio, Control... controlls) {
boolean enable = radio.getSelection();
for (Control control : controlls) {
control.setEnabled(enable);
}
}
public String getJavaHomeJRENameInPage() {
if (customHomeButton.getSelection()) {
String name = customJRECombo.getText();
if (!"".equals(name)) {
return name;
}
}
return null;
}
public String getExecutionEnvNameInPage() {
if (customExecutionEnvButton.getSelection()) {
String name = customExecutionEnvCombo.getText();
if (!"".equals(name)) {
return name;
}
}
return null;
}
public LiveExpression<ValidationResult> getValidator() {
return validator;
}
public JavaRuntimeUtils getJREUtils() {
return jres;
}
/////////////////////////////////////////////////////////////////////////////////////
// The methods below are here so that JavaHomeSection instance can be more easily
// adapted to be usable as a LaunchTabSection
// Important: setter methods which directly put contents into widgets need to
// call 'doRefresh' because the SWT widgets only seem to fire off listeners
// when the changes are triggered by users, not when they are directly set by
// calling methods on the widgets.
/**
* Copy widget contents into some place where the preferences can be stored.
*/
public void copyTo(IJavaHomePreferences preferences) {
if (defaultButton.getSelection()) {
preferences.unsetJavaHome();
} else if (customHomeButton.getSelection()) {
preferences.setJavaHomeJREName(getText(customJRECombo));
} else if (customExecutionEnvButton.getSelection()) {
preferences.setJavaHomeEEName(getText(customExecutionEnvCombo));
}
}
public void setDefaults(IJavaHomePreferences preferences) {
preferences.unsetJavaHome();
}
/**
* Fill the widget contents based on GradlePreferences. This should only be called after
* the widgets have been created.
*/
public void copyFrom(IJavaHomePreferences preferences) {
Button enable = defaultButton;
String jreName = preferences.getJavaHomeJREName();
if (jreName!=null) {
customJRECombo.setText(jreName);
if (customJRECombo.getText().equals(jreName)) {
enable = customHomeButton;
}
}
String eeName = preferences.getJavaHomeEEName();
if (eeName!=null) {
customExecutionEnvCombo.setText(eeName);
if (customExecutionEnvCombo.getText().equals(eeName)) {
enable = customExecutionEnvButton;
}
}
radioEnable(enable);
doRefresh();
}
/**
* Enable one of the three radio buttons and also update all the corresponding other widgets
* enablement state accordingly.
*/
private void radioEnable(Button enable) {
for (Button b : new Button[] {defaultButton, customHomeButton, customExecutionEnvButton}) {
b.setSelection(b==enable);
}
enableDisableWidgets();
}
///////////////////////////////////////////////////////////////////////////////////
// implement IJavaHomePreferences /////////////////////////////////
//
// This implementation treats the widgets themselves as a place where we can
// store the preferences (this is used by 'setDefaults' in the context of a preferences page)
public String getJavaHomeJREName() {
return getText(customJRECombo);
}
private static String getText(Combo combo) {
if (combo!=null) {
String txt = combo.getText();
if (!"".equals(txt)) {
return txt;
}
}
return null;
}
public String getJavaHomeEEName() {
return getText(customExecutionEnvCombo);
}
public void setJavaHomeJREName(String name) {
radioEnable(customHomeButton);
customJRECombo.setText(name);
doRefresh();
}
public void setJavaHomeEEName(String name) {
radioEnable(customExecutionEnvButton);
customExecutionEnvCombo.setText(name);
doRefresh();
}
public void unsetJavaHome() {
radioEnable(defaultButton);
doRefresh();
}
private void enableDisableWidgets() {
enableDisableWidgets(customHomeButton, customJRECombo, configureJREsButton);
enableDisableWidgets(customExecutionEnvButton, customExecutionEnvCombo, configureExecEnvsButton);
}
}