/*******************************************************************************
* 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.commons.internal.configurator.ui;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.mylyn.commons.ui.CommonImages;
import org.eclipse.osgi.util.NLS;
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.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.statushandlers.StatusManager;
import org.springframework.util.StringUtils;
import org.springsource.ide.eclipse.commons.configurator.ConfigurableExtension;
import org.springsource.ide.eclipse.commons.core.StatusHandler;
import org.springsource.ide.eclipse.commons.internal.configurator.Activator;
import org.springsource.ide.eclipse.commons.internal.configurator.ConfiguratorImporter;
import org.springsource.ide.eclipse.commons.ui.ICoreRunnable;
import org.springsource.ide.eclipse.commons.ui.UiStatusHandler;
import org.springsource.ide.eclipse.commons.ui.UiUtil;
/**
* @author Steffen Pingel
* @author Leo Dos Santos
*/
public class ConfiguratorPreferencesPage extends PreferencePage implements IWorkbenchPreferencePage {
private Button browseButton;
private Button configureButton;
private TableViewer extensionViewer;
private ConfiguratorImporter importer;
private Button installButton;
private boolean installEnabled;
private Label searchLocationsLabel;
private Button useDefaultUserLocationButton;
private Text userLocationText;
List<ConfigurableExtension> elements;
public void init(IWorkbench workbench) {
updateElements();
}
public boolean isInstallEnabled() {
return installEnabled;
}
@Override
public boolean performOk() {
if (useDefaultUserLocationButton.getSelection()) {
Activator.getDefault().getPreferenceStore().setToDefault(Activator.PROPERTY_USER_INSTALL_PATH);
}
else {
Activator.getDefault().getPreferenceStore()
.setValue(Activator.PROPERTY_USER_INSTALL_PATH, userLocationText.getText());
}
return super.performOk();
}
public void setInstallEnabled(boolean installEnabled) {
this.installEnabled = installEnabled;
updateSelection(extensionViewer.getSelection());
if (!installEnabled) {
setMessage("Install Location is not set to a writeable directory. Installations are disabled.",
IMessageProvider.WARNING);
}
else {
setMessage(null);
}
}
private void doRefresh() {
updateElements();
extensionViewer.setInput(elements.toArray());
}
private ConfigurableExtension getSelectedExtension(ISelection selection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
ConfigurableExtension extension = (ConfigurableExtension) structuredSelection.getFirstElement();
return extension;
}
private void handleResult(final ConfigurableExtension extension, final IStatus[] status) {
if (status[0] != null) {
if (!status[0].isOK()) {
StatusManager.getManager().handle(status[0], StatusManager.SHOW | StatusManager.LOG);
}
else {
MessageDialog.openInformation(UiUtil.getShell(), "Auto Configuration", status[0].getMessage());
}
extension.postConfiguration(status[0]);
}
}
private void initWidgets() {
resetUserLocation();
useDefaultUserLocationButton.setSelection(userLocationText.getText().equals(
getPreferenceStore().getDefaultString(Activator.PROPERTY_USER_INSTALL_PATH)));
userLocationText.setEnabled(!useDefaultUserLocationButton.getSelection());
browseButton.setEnabled(!useDefaultUserLocationButton.getSelection());
if (searchLocationsLabel != null) {
searchLocationsLabel.setText(StringUtils.collectionToDelimitedString(importer.getSearchLocations(), ", "));
}
}
private void resetUserLocation() {
File location = importer.getInstallLocation();
if (location != null) {
userLocationText.setText(location.getAbsolutePath());
}
else {
userLocationText.setText("");
setInstallEnabled(false);
}
}
private void updateElements() {
elements = new ArrayList<ConfigurableExtension>();
importer = new ConfiguratorImporter();
importer.setFirstMatchOnly(false);
try {
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
elements.addAll(importer.detectExtensions(monitor));
}
});
}
catch (InvocationTargetException e) {
StatusHandler.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
"An error occurred loading configurable items", e));
}
catch (InterruptedException e) {
// ignore
}
}
@Override
protected Control createContents(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(composite);
Label label = new Label(composite, SWT.WRAP);
label.setText("Configurable Extensions:");
GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(label);
extensionViewer = new TableViewer(composite, SWT.BORDER | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.SINGLE);
extensionViewer.getTable().setHeaderVisible(true);
extensionViewer.getTable().setLinesVisible(true);
extensionViewer.setSorter(new ViewerSorter() {
@SuppressWarnings("unchecked")
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
String name1 = ((ConfigurableExtension) e1).getLabel();
String name2 = ((ConfigurableExtension) e2).getLabel();
return getComparator().compare(name1, name2);
}
});
extensionViewer.setContentProvider(new IStructuredContentProvider() {
Object[] elements;
public void dispose() {
// ignore
}
public Object[] getElements(Object inputElement) {
return elements;
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
this.elements = (Object[]) newInput;
}
});
GridDataFactory.fillDefaults().grab(true, true).applyTo(extensionViewer.getControl());
TableViewerColumn statusColumn = new TableViewerColumn(extensionViewer, SWT.LEFT);
statusColumn.getColumn().setText("");
statusColumn.getColumn().setToolTipText("Configured");
statusColumn.getColumn().setWidth(20);
statusColumn.setLabelProvider(new ColumnLabelProvider() {
@Override
public Image getImage(Object element) {
if (((ConfigurableExtension) element).isConfigured()) {
return CommonImages.getImage(CommonImages.COMPLETE);
}
return null;
}
@Override
public String getText(Object element) {
return "";
}
});
TableViewerColumn extensionColumn = new TableViewerColumn(extensionViewer, SWT.LEFT);
extensionColumn.getColumn().setText("Extension");
extensionColumn.getColumn().setWidth(250);
extensionColumn.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
return ((ConfigurableExtension) element).getLabel();
}
});
TableViewerColumn locationColumn = new TableViewerColumn(extensionViewer, SWT.LEFT);
locationColumn.getColumn().setText("Location");
locationColumn.getColumn().setWidth(150);
locationColumn.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
return ((ConfigurableExtension) element).getLocation();
}
});
extensionViewer.setInput(elements.toArray());
Composite buttonComposite = new Composite(composite, SWT.NONE);
GridDataFactory.fillDefaults().grab(false, true).applyTo(buttonComposite);
RowLayout layout = new RowLayout(SWT.VERTICAL);
layout.fill = true;
layout.marginLeft = 0;
layout.marginTop = 0;
layout.marginRight = 0;
layout.marginBottom = 0;
buttonComposite.setLayout(layout);
configureButton = new Button(buttonComposite, SWT.NONE);
configureButton.setText(" &Configure ");
configureButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
ConfigurableExtension extension = getSelectedExtension(extensionViewer.getSelection());
if (extension != null) {
doConfigure(extension);
}
}
});
installButton = new Button(buttonComposite, SWT.NONE);
installButton.setText(" &Install ");
installButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
IStructuredSelection selection = (IStructuredSelection) extensionViewer.getSelection();
ConfigurableExtension extension = (ConfigurableExtension) selection.getFirstElement();
if (extension != null) {
doInstall(extension);
}
}
});
Button refreshButton = new Button(buttonComposite, SWT.NONE);
refreshButton.setText(" &Refresh ");
refreshButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
doRefresh();
}
});
extensionViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
updateSelection(event.getSelection());
}
});
updateSelection(extensionViewer.getSelection());
Group locationGroup = new Group(composite, SWT.NONE);
GridDataFactory.fillDefaults().grab(true, false).span(2, 1).applyTo(locationGroup);
locationGroup.setText("Runtime Locations");
GridLayoutFactory.swtDefaults().numColumns(3).applyTo(locationGroup);
File systemLocation = importer.getSystemLocation();
if (systemLocation != null) {
label = new Label(locationGroup, SWT.WRAP);
label.setText("Search path for runtimes:");
GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).span(3, 1).applyTo(label);
searchLocationsLabel = new Label(locationGroup, SWT.NONE);
GridDataFactory.fillDefaults().grab(true, false).hint(100, SWT.DEFAULT).span(3, 1)
.applyTo(searchLocationsLabel);
}
useDefaultUserLocationButton = new Button(locationGroup, SWT.CHECK);
GridDataFactory.fillDefaults().grab(true, false).span(3, 1).applyTo(useDefaultUserLocationButton);
useDefaultUserLocationButton.setText("Use Default");
useDefaultUserLocationButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
userLocationText.setEnabled(!useDefaultUserLocationButton.getSelection());
browseButton.setEnabled(!useDefaultUserLocationButton.getSelection());
if (useDefaultUserLocationButton.getSelection()) {
resetUserLocation();
}
}
});
label = new Label(locationGroup, SWT.WRAP);
label.setText("Install Location:");
userLocationText = new Text(locationGroup, SWT.BORDER);
userLocationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
userLocationText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent event) {
try {
File file = new File(userLocationText.getText());
if (!file.canWrite()) {
setErrorMessage(NLS.bind("''{0}'' is not writeable. Please select a different directory.",
userLocationText.getText()));
setInstallEnabled(false);
}
else {
setErrorMessage(null);
setInstallEnabled(true);
}
}
catch (Exception e) {
setErrorMessage(NLS.bind("''{0}'' is not a valid path.", userLocationText.getText()));
setInstallEnabled(false);
}
}
});
browseButton = new Button(locationGroup, SWT.NONE);
browseButton.setText("Directory...");
browseButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
DirectoryDialog dialog = new DirectoryDialog(getShell());
dialog.setMessage("Select the root directory for installing extensions.");
String path = userLocationText.getText();
path = path.replaceAll("\\\\", "/");
dialog.setFilterPath(path);
path = dialog.open();
if (path == null || path.equals("")) { //$NON-NLS-1$
return;
}
path = path.replaceAll("\\\\", "/");
userLocationText.setText(path);
}
});
initWidgets();
return composite;
}
protected void doConfigure(final ConfigurableExtension extension) {
try {
final IStatus[] status = new IStatus[1];
UiUtil.busyCursorWhile(new ICoreRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
status[0] = extension.configure(monitor);
}
});
handleResult(extension, status);
doRefresh();
}
catch (OperationCanceledException ignored) {
// cancelled
}
catch (CoreException e) {
UiStatusHandler.logAndDisplay(e.getStatus());
}
}
@Override
protected IPreferenceStore doGetPreferenceStore() {
return Activator.getDefault().getPreferenceStore();
}
protected void doInstall(final ConfigurableExtension extension) {
// FIXME use directory where extension is installed
final File installDirectory = new File(userLocationText.getText());
if (!installDirectory.canWrite()) {
UiStatusHandler.logAndDisplay(new Status(IStatus.ERROR, Activator.PLUGIN_ID, NLS.bind(
"Installation failed. The directory ''{0}'' is not writeable.", userLocationText.getText())));
return;
}
try {
final IStatus[] status = new IStatus[1];
UiUtil.busyCursorWhile(new ICoreRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
status[0] = extension.install(installDirectory, monitor);
if (status[0].getSeverity() != IStatus.ERROR) {
IStatus configurationStatus = extension.configure(monitor);
if (status[0].getSeverity() != IStatus.OK) {
MultiStatus result = new MultiStatus(Activator.PLUGIN_ID, 0, NLS.bind(
"The installation of {0} generated warning. See error log for details.",
extension.getLabel()), null);
result.add(status[0]);
result.add(configurationStatus);
status[0] = result;
}
else {
status[0] = configurationStatus;
}
}
}
});
handleResult(extension, status);
doRefresh();
}
catch (OperationCanceledException ignored) {
// cancelled
}
catch (CoreException e) {
UiStatusHandler.logAndDisplay(e.getStatus());
}
}
@Override
protected void performApply() {
super.performApply();
doRefresh();
initWidgets();
}
@Override
protected void performDefaults() {
super.performDefaults();
Activator.getDefault().getPreferenceStore().setToDefault(Activator.PROPERTY_USER_INSTALL_PATH);
doRefresh();
initWidgets();
}
protected void updateSelection(ISelection selection) {
configureButton.setEnabled(!selection.isEmpty());
ConfigurableExtension extension = getSelectedExtension(selection);
installButton.setEnabled(extension != null && extension.isInstallable() && isInstallEnabled());
}
}