/*******************************************************************************
* Copyright (c) 2012 Google, 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:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.eclipse.ui.target;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
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.DirectoryDialog;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import com.windowtester.eclipse.ui.UiPlugin;
import com.windowtester.internal.debug.LogHandler;
import com.windowtester.runtime.swt.internal.display.DisplayExec;
import com.windowtester.runtime.swt.internal.display.RunnableWithResult;
@SuppressWarnings({"deprecation", "unchecked"})
public class NewTargetProvisionerPage extends WizardPage implements Listener {
private static final String DESCRIPTION = "Create a new WindowTester File System Target Provisioner.";
private static final String TITLE = "WindowTester Target Provisioner";
protected static final int COMBO_HISTORY_LENGTH = 5;
private static final String SELECT_DESTINATION_MESSAGE = "Select a parent directory.";
private static final String SELECT_DESTINATION_TITLE = "Provisioner Destination";
private static final String STORE_DESTINATION_NAMES_ID = "destination.names";
private static final String STORE_RECORDING_CONTENT = "recording.content";
private static final String STORE_RUNTIME_CONTENT = "runtime.content";
private static final String CREATION_ERROR_MSG = "Creation Error";
private static final String HELP_CONTEXT_ID = "com.windowtester.eclipse.help.wt_ui_context";
private Combo destination;
private Button recordingButton;
private Button runtimeButton;
private Button browseButton;
private final SettingsManager settings = new SettingsManager();
private final ITargetProvisionerFileProvider fileProvider;
private Button gefSupportButton;
private class SettingsManager {
protected void restoreWidgetValues() {
IDialogSettings settings = getDialogSettings();
if (settings == null)
return;
restoreDestinations(settings);
restoreContents(settings);
}
private void restoreContents(IDialogSettings settings) {
recordingButton.setSelection(settings
.getBoolean(STORE_RECORDING_CONTENT));
runtimeButton.setSelection(settings
.getBoolean(STORE_RUNTIME_CONTENT));
}
private void restoreDestinations(IDialogSettings settings) {
String[] directoryNames = settings.getArray(STORE_DESTINATION_NAMES_ID);
if (directoryNames == null || directoryNames.length == 0) {
return;
}
for (int i = 0; i < directoryNames.length; i++) {
destination.add(directoryNames[i], i);
}
destination.select(0);
}
protected void saveWidgetValues() {
IDialogSettings settings = getDialogSettings();
if (settings == null)
return;
saveDestinationHistory(settings);
saveContentTypes(settings);
}
private void saveContentTypes(IDialogSettings settings) {
// options
settings.put(STORE_RECORDING_CONTENT,
recordingButton.getSelection());
settings.put(STORE_RUNTIME_CONTENT,
runtimeButton.getSelection());
}
private void saveDestinationHistory(IDialogSettings settings) {
String[] directoryNames = settings.getArray(STORE_DESTINATION_NAMES_ID);
if (directoryNames == null) {
directoryNames = new String[0];
}
directoryNames = addToHistory(directoryNames, getDestinationValue());
settings.put(STORE_DESTINATION_NAMES_ID, directoryNames);
}
/**
* Adds an entry to a history, while taking care of duplicate history items
* and excessively long histories. The assumption is made that all histories
* should be of length <code>WizardDataTransferPage.COMBO_HISTORY_LENGTH</code>.
*
* @param history the current history
* @param newEntry the entry to add to the history
*/
protected String[] addToHistory(String[] history, String newEntry) {
java.util.ArrayList l = new java.util.ArrayList(Arrays.asList(history));
addToHistory(l, newEntry);
String[] r = new String[l.size()];
l.toArray(r);
return r;
}
/**
* Adds an entry to a history, while taking care of duplicate history items
* and excessively long histories. The assumption is made that all histories
* should be of length <code>WizardDataTransferPage.COMBO_HISTORY_LENGTH</code>.
*
* @param history the current history
* @param newEntry the entry to add to the history
*/
protected void addToHistory(List history, String newEntry) {
history.remove(newEntry);
history.add(0, newEntry);
// since only one new item was added, we can be over the limit
// by at most one item
if (history.size() > COMBO_HISTORY_LENGTH) {
history.remove(COMBO_HISTORY_LENGTH);
}
}
}
/**
* Create the wizard
* @param structuredSelection
* @param string
*/
public NewTargetProvisionerPage(String string, IStructuredSelection structuredSelection, ITargetProvisionerFileProvider fileProvider) {
super("wizardPage");
this.fileProvider = fileProvider;
setTitle(TITLE);
setDescription(DESCRIPTION);
setImageDescriptor(getPageImageDescriptor());
}
private ImageDescriptor getPageImageDescriptor() {
return UiPlugin.imageDescriptor("icons/full/wizban/newTargetProvisioner.png");
}
/**
* Create contents of the wizard
* @param parent
*/
public void createControl(Composite parent) {
doCreateComposite(parent);
addListeners();
setInitialWidgetValues();
validatePage(); //does validation
}
/*
* @see org.eclipse.jface.window.Window#configureShell(Shell)
*/
protected void configureShell(Shell newShell) {
PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell, HELP_CONTEXT_ID);
}
private void doCreateComposite(Composite parent) {
Composite container = new Composite(parent, SWT.NULL);
container.setLayout(new GridLayout());
//
setControl(container);
final Composite contentsComposite = new Composite(container, SWT.NONE);
contentsComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
contentsComposite.setLayout(new GridLayout());
final Group targetContentGroup = new Group(contentsComposite, SWT.NONE);
final GridData gd_targetContentGroup = new GridData(SWT.FILL, SWT.CENTER, true, false);
targetContentGroup.setLayoutData(gd_targetContentGroup);
targetContentGroup.setText("Target Content");
final GridLayout gridLayout_1 = new GridLayout();
gridLayout_1.numColumns = 2;
targetContentGroup.setLayout(gridLayout_1);
final Label targetContentDescriptionLabel = new Label(targetContentGroup, SWT.NONE);
final GridData gd_targetContentDescriptionLabel = new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1);
gd_targetContentDescriptionLabel.verticalIndent = 5;
targetContentDescriptionLabel.setLayoutData(gd_targetContentDescriptionLabel);
targetContentDescriptionLabel.setText("This target provisioner provides support for");
final Label spacer = new Label(targetContentGroup, SWT.NONE);
final GridData gd_spacer = new GridData(10, SWT.DEFAULT);
spacer.setLayoutData(gd_spacer);
recordingButton = new Button(targetContentGroup, SWT.RADIO);
final GridData gd_recordingButton = new GridData();
gd_recordingButton.verticalIndent = 5;
recordingButton.setLayoutData(gd_recordingButton);
recordingButton.setText("&Recording and Execution of WindowTester Tests");
final Label spacer2 = new Label(targetContentGroup, SWT.NONE);
final GridData gd_spacer2 = new GridData(10, SWT.DEFAULT);
spacer2.setLayoutData(gd_spacer2);
runtimeButton = new Button(targetContentGroup, SWT.RADIO);
final GridData gd_runtimeButton = new GridData();
runtimeButton.setLayoutData(gd_runtimeButton);
runtimeButton.setText("E&xecution of WindowTester Tests");
final Label optionalSupportLabel = new Label(targetContentGroup, SWT.NONE);
final GridData gd_optionalSupportLabel = new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1);
gd_optionalSupportLabel.verticalIndent = 5;
optionalSupportLabel.setLayoutData(gd_optionalSupportLabel);
optionalSupportLabel.setText("Include support for");
final Label spacer3 = new Label(targetContentGroup, SWT.NONE);
final GridData gd_spacer3 = new GridData(10, SWT.DEFAULT);
spacer3.setLayoutData(gd_spacer3);
gefSupportButton = new Button(targetContentGroup, SWT.CHECK);
final GridData gd_gefButton = new GridData();
gd_gefButton.verticalIndent = 5;
gefSupportButton.setLayoutData(gd_gefButton);
gefSupportButton.setText("Graphical Editing Framework (GEF) Components");
final Composite desinationComposite = new Composite(container, SWT.NONE);
final GridData gd_desinationComposite = new GridData(SWT.FILL, SWT.CENTER, true, false);
gd_desinationComposite.widthHint = 461;
desinationComposite.setLayoutData(gd_desinationComposite);
final GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 3;
desinationComposite.setLayout(gridLayout);
final Label destinationLabel = new Label(desinationComposite, SWT.NONE);
destinationLabel.setText("Provisioner &directory:");
destination = new Combo(desinationComposite, SWT.NONE);
final GridData gd_combo = new GridData(SWT.FILL, SWT.CENTER, true, false);
gd_combo.widthHint = 156;
destination.setLayoutData(gd_combo);
browseButton = new Button(desinationComposite, SWT.NONE);
browseButton.setText("B&rowse...");
final Label label = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL);
final GridData gd_label = new GridData(SWT.FILL, SWT.TOP, true, false);
gd_label.verticalIndent = 8;
label.setLayoutData(gd_label);
}
private void addListeners() {
browseButton.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
browseForProvisionerDestination();
}
public void widgetSelected(SelectionEvent e) {
browseForProvisionerDestination();
}
});
recordingButton.addListener(SWT.Selection, this);
runtimeButton.addListener(SWT.Selection, this);
destination.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
//System.out.println("combo modified");
validatePage();
}
});
}
private void setInitialWidgetValues() {
settings.restoreWidgetValues();
/*
* In case this is the first time, ensure there is a default set
*/
if (!isRecordingContentSelected() && !runtimeButton.getSelection())
recordingButton.setSelection(true);
}
private void browseForProvisionerDestination() {
DirectoryDialog dialog = new DirectoryDialog(getContainer().getShell(), SWT.SAVE);
dialog.setMessage(SELECT_DESTINATION_MESSAGE);
dialog.setText(SELECT_DESTINATION_TITLE);
//dialog.setFilterPath(getDestinationValue());
String selectedDirectoryName = dialog.open();
if (selectedDirectoryName != null) {
setErrorMessage(null);
setDestination(selectedDirectoryName);
}
}
public void handleEvent(Event event) {
validatePage();
}
private void validatePage() {
setPageComplete(isPageValid());
}
private boolean isPageValid() {
//System.out.println("validating page");
if (!isRecordingContentSelected() && !runtimeButton.getSelection()) {
setError("Please select a content type.");
return false;
}
String text = destination.getText();
if (text == null || text.trim().length() == 0) {
setError("Please enter a destination directory.");
return false;
}
setError(null);
return true;
}
private void setError(String msg) {
setErrorMessage(msg);
setMessage(msg);
}
private void setDestination(String browsedDestination) {
destination.add(browsedDestination, 0);
destination.select(0);
}
//there is no next page!
/* (non-Javadoc)
* @see org.eclipse.jface.wizard.WizardPage#canFlipToNextPage()
*/
public boolean canFlipToNextPage() {
return false;
}
/**
* Returns a boolean indicating whether the directory portion of the
* passed pathname is valid and available for use.
*/
protected boolean ensureTargetDirectoryIsValid(String fullPathname) {
int separatorIndex = fullPathname.lastIndexOf(File.separator);
if (separatorIndex == -1) {
return true;
}
return ensureTargetIsValid(new File(fullPathname.substring(0,
separatorIndex)));
}
protected boolean ensureTargetIsValid(File targetDirectory) {
if (targetDirectory.exists() && !targetDirectory.isDirectory()) {
displayErrorDialog("The destination directory must exist.");
giveFocusToDestination();
return false;
}
return ensureDirectoryExists(targetDirectory);
}
protected boolean ensureDirectoryExists(File directory) {
if (!directory.exists()) {
if (!queryYesNoQuestion("The destination directory does not exist. Would you like to create it?")) {
return false;
}
if (!directory.mkdirs()) {
displayErrorDialog("An error was encountered creating the provisioner directory.");
giveFocusToDestination();
return false;
}
}
return true;
}
protected boolean queryYesNoQuestion(String message) {
MessageDialog dialog = new MessageDialog(getContainer().getShell(),
"Question",
(Image) null, message, MessageDialog.NONE,
new String[] { IDialogConstants.YES_LABEL,
IDialogConstants.NO_LABEL }, 0);
// ensure yes is the default
return dialog.open() == 0;
}
protected void displayErrorDialog(String message) {
MessageDialog.openError(getContainer().getShell(),
"Provisioner Creation Error", message);
}
protected void giveFocusToDestination() {
destination.setFocus();
}
public boolean finish() {
if (!ensureTargetIsValid(getTargetDestination()))
return false;
boolean created = createProvisioner();
if (!created)
return false;
settings.saveWidgetValues();
return true;
}
public static IAdaptable getUIInfoAdapter(final Shell shell) {
return new IAdaptable() {
public Object getAdapter(Class clazz) {
if (clazz == Shell.class) {
return shell;
}
return null;
}
};
}
private boolean createProvisioner() {
IRunnableWithProgress op = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) {
try {
CreateTargetProvisionerOperation op = new CreateTargetProvisionerOperation(getTargetFiles(), getTargetDestination());
PlatformUI.getWorkbench().getOperationSupport().getOperationHistory().execute(
op, monitor, getUIInfoAdapter(getShell()));
} catch (final Exception e) {
getContainer().getShell().getDisplay().syncExec(
new Runnable() {
public void run() {
if (e.getCause() instanceof CoreException) {
ErrorDialog.openError(getContainer().getShell(),
CREATION_ERROR_MSG, null, ((CoreException) e.getCause()).getStatus());
} else {
LogHandler.log(e);
MessageDialog.openError(getContainer().getShell(),
CREATION_ERROR_MSG, e.getCause().getMessage());
}
}
});
}
}
};
try {
getContainer().run(true, true, op);
return true;
} catch (InterruptedException e) {
//do nothing
} catch (InvocationTargetException e) {
LogHandler.log(e);
MessageDialog.openError(getContainer().getShell(),
CREATION_ERROR_MSG, e.getCause().getMessage());
}
return false;
}
protected File getTargetDestination() {
String dest = (String) DisplayExec.sync(new RunnableWithResult() {
public Object runWithResult() {
return getDestinationValue();
}
});
return new File(dest);
}
protected File[] getTargetFiles() throws IOException {
return fileProvider.getTargetFiles(getTargetSpecification());
}
private TargetSpecification getTargetSpecification() {
TargetSpecification spec = getBaseSpec();
if (isGEFSupportSelected())
return spec.withBundles(RequiredPlugins.GEF_SUPPORT);
return spec;
}
/**
* @since 3.8.1
*/
private boolean isGEFSupportSelected() {
return ((Boolean)DisplayExec.sync(new RunnableWithResult() {
public Object runWithResult() {
return Boolean.valueOf(gefSupportButton.getSelection());
}
})).booleanValue();
}
private TargetSpecification getBaseSpec() {
if (isRecordingContentSelected())
return TargetSpecification.RECORDING.withBundles(RequiredPlugins.RUNTIME); //notice this includes both
return TargetSpecification.EXECUTION;
}
private boolean isRecordingContentSelected() {
return ((Boolean)DisplayExec.sync(new RunnableWithResult() {
public Object runWithResult() {
return Boolean.valueOf(recordingButton.getSelection());
}
})).booleanValue();
}
private String getDestinationValue() {
return destination.getText().trim();
}
}