/*******************************************************************************
* 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.frameworks.ui.internal.wizard;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizardContainer;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbench;
import org.springsource.ide.eclipse.commons.frameworks.core.internal.commands.CommandFactory;
import org.springsource.ide.eclipse.commons.frameworks.core.internal.commands.ICommandListener;
import org.springsource.ide.eclipse.commons.frameworks.core.internal.commands.ICommandParameter;
import org.springsource.ide.eclipse.commons.frameworks.core.internal.commands.IFrameworkCommand;
import org.springsource.ide.eclipse.commons.frameworks.core.internal.commands.IFrameworkCommandDescriptor;
import org.springsource.ide.eclipse.commons.frameworks.core.internal.commands.JavaParameterDescriptor;
import org.springsource.ide.eclipse.commons.frameworks.ui.FrameworkUIActivator;
import org.springsource.ide.eclipse.commons.frameworks.ui.internal.contentassist.JavaContentAssistUIAdapter;
import org.springsource.ide.eclipse.commons.frameworks.ui.internal.utils.ProjectFilter;
import org.springsource.ide.eclipse.commons.frameworks.ui.internal.utils.SelectionUtils;
/**
* A generic wizard that lists commands to execute and configure before
* executing. It contains at least 2 pages, the first has a list of commands
* that can be executed or configured, and the second contains the parameters
* page for a selected command
* <p>
* If a selected command has no parameters, the wizard will only have one page,
* and will indicate to the user that the wizard can be finished directly from
* the command list page.
* </p>
* <p>
* If a selected command has mandatory parameters, the wizard cannot be
* completed from the first page, and instead the user must click next to the
* parameters page of that command to fill in any mandatory values. The wizard
* will only complete after all mandatory values have been filed.
* </p>
* <p>
* If a selected command has option parameters, the user has the option to
* complete the wizard directly from the first page, or proceed to the second
* page to set optional parameter values.
* </p>
* <p>
* Commands can be added prior to opening the wizard, as well as after the
* wizard opens, meaning that the list of commands in the command list page can
* potentially increase even after the wizard opens.
* </p>
* <p>
* The wizard also has the option of being created with a command argument. In
* this case, when the wizard opens, if the command is already present in the
* list of commands that appear in the command list page, the wizard will open
* directly to the
* @author Nieraj Singh
* @author Christian Dupuis
* @author Kris De Volder
*/
public abstract class GenericCommandWizard extends Wizard implements ICommandListener {
protected GenericWizardCommandListPage commandListPage;
protected GenericWizardCommandParametersPage parameterPage;
private String wizardTitle;
private boolean orderRequiredParameters = true;
/**
* This is the command instance with values set that can be executed.
*/
private IFrameworkCommand commandInstance;
private Collection<IProject> projects;
private IProject selectedProject;
/**
* This constructor accepts a pre-filled command instance. The title,
* description, and image location refer to the wizard properties that
* should be set by the caller.
* <p>
* The list of projects indicates the selection of projects that are
* available for the commands. The first selection in the project will
* always be selected. To pre-select a particular project, be sure that
* project appears as the first selection in the list.
* </p>
*
* @param command
* @param title
* @param description
* @param imageLocation
* @param projects
*/
public GenericCommandWizard(IFrameworkCommand command, String title,
String description, String imageLocation,
Collection<IProject> projects) {
super();
this.commandInstance = command;
this.projects = projects;
wizardTitle = title;
setWindowTitle(wizardTitle);
setDefaultPageImageDescriptor(FrameworkUIActivator
.getImageDescriptor(imageLocation));
setNeedsProgressMonitor(true);
// Create the page now as it may be accessed before the wizard opens
commandListPage = createCommandListPage();
commandListPage.setWizard(this);
setForcePreviousAndNextButtons(true);
}
/**
* This method is called by a 'newWizard' action (action inside the 'new' menu). Default implementation
* sets the selected project based on the selection. Subclasses may override to initialize some of
* the command parameters based on the selection.
*/
public void init(IWorkbench workbench, IStructuredSelection selection) {
List<IProject> selectedProjects = SelectionUtils.getProjects(selection, getProjectFilter());
if (selectedProjects.size()>0) {
setSelectedProject(selectedProjects.get(0));
}
}
/**
* Project filter is used to determine whether a project selected by the user is 'interesting' to
* the wizard. Subclasses should override this if they wish to use the wizard in a 'newWizards'
* extension point. The default implementation considers any project interesting.
* <p>
* Typically only some projects should be interesting to a particular type of wizard.
* For example, grails wizards are only interested in Grails projects.
*/
protected ProjectFilter getProjectFilter() {
return ProjectFilter.anyProject;
}
/**
* This constructor accepts a pre-filled command instance. The title,
* description, and image location refer to the wizard properties that
* should be set by the caller.
* <p>
* The list of projects indicates the selection of projects that are
* available for the commands. The first selection in the project will
* always be selected. To pre-select a particular project, be sure that
* project appears as the first selection in the list.
* </p>
*
* @param command
* @param title
* @param description
* @param imageLocation
* @param projects
* @param orderRequiredParameters
* true if required paramters should appear grouped together and
* appear first. Default is false
*/
public GenericCommandWizard(IFrameworkCommand command, String title,
String description, String imageLocation,
Collection<IProject> projects, boolean orderRequiredParameters) {
this(command, title, description, imageLocation, projects);
this.orderRequiredParameters = orderRequiredParameters;
}
protected GenericWizardCommandListPage createCommandListPage() {
return new GenericWizardCommandListPage(getWindowTitle());
}
public void setSelectedProject(IProject project) {
if (project.equals(selectedProject)) return;
selectedProject = project;
if (this.commandListPage!=null) {
commandListPage.setProjectSelectionInPage();
}
if (this.parameterPage!=null) {
parameterPage.setProjectSelectionInPage();
}
}
public IProject getSelectedProject() {
return selectedProject;
}
public Collection<IProject> getProjectList() {
return projects;
}
public GenericCommandWizard(String title, String description,
String imageLocation) {
this(null, title, description, imageLocation, null);
}
public GenericCommandWizard(String title, String description,
String imageLocation, Collection<IProject> projects) {
this(null, title, description, imageLocation, projects);
}
/**
* Get command instance selected whose parameter values have been
* configured.
* <p>
* This is what is needed to execute the command
* </p>
*
* @return
*/
public IFrameworkCommand getCommandInstance() {
return commandInstance;
}
public void addPages() {
addPage(commandListPage);
}
public IWizardPage getStartingPage() {
// If a command instance already exists, open the second page first
if (commandListPage != null && commandInstance != null) {
IFrameworkCommandDescriptor descriptor = commandInstance
.getCommandDescriptor();
commandListPage.addCommandDescriptor(descriptor);
commandListPage.selectCommandInViewer(descriptor);
parameterPage = createParameterPage(commandInstance);
return parameterPage;
}
return super.getStartingPage();
}
protected void resizeWizard(Control control) {
Point size = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);
IWizardContainer container = getContainer();
if (container != null) {
container.getShell().setSize(size);
}
}
/**
* Requires an instance of the command, as the parameters page may fill the
* editor controls with a pre-filled version of a command instance.
*
* @param command
* instance to edit in the parameters page
* @return parameter page or null if unable to create.
*/
protected GenericWizardCommandParametersPage createParameterPage(
IFrameworkCommand command) {
if (command == null) {
return null;
}
GenericWizardCommandParametersPage page = new GenericWizardCommandParametersPage(
command);
page.setWizard(this);
return page;
}
public boolean canFinish() {
// Handle the case of the parameter Page, as it is not permanently
// added to the wizard
if (parameterPage != null
&& getContainer().getCurrentPage() == parameterPage) {
return parameterPage.isPageComplete();
} else if (isConfiguredCommandSelected()) {
return true;
} else {
return super.canFinish();
}
}
/**
* True if command instance is selected and configured, meaning any
* mandatory values are entered. False otherwise
*
* @return true if command is selected and configured, false otherwise
*/
protected boolean isConfiguredCommandSelected() {
if (commandInstance == null) {
return false;
}
List<ICommandParameter> parameters = commandInstance.getParameters();
if (parameters != null) {
for (ICommandParameter parameter : parameters) {
if (parameter.getParameterDescriptor().isMandatory()
&& !parameter.hasValue()) {
return false;
}
}
}
return true;
}
public IWizardPage getNextPage(IWizardPage page) {
if (page == commandListPage) {
if (parameterPage != null
&& parameterPage.getCommand() == commandInstance) {
return parameterPage;
} else if (commandInstance != null) {
parameterPage = createParameterPage(commandInstance);
return parameterPage;
}
}
return super.getNextPage(page);
}
/**
* Internal call only for wizard pages only. Should not be called outside
* the wizard. Sets a command instance only if there is no command instance
* currently present in the wizard OR the descriptor for the current command
* instance does not equal the descriptor argument.
* <p>
* If a command instance for the descriptor already exists, nothing happens
* and false is returned
* </p>
*
* @param descriptor
* create and set CommandInstance for the given descriptor, if
* one does not already exist for the given descriptor.
* @return true if new command instance set. False otherwise
*/
public boolean setCommandInstance(IFrameworkCommandDescriptor descriptor) {
if (commandInstance != null
&& commandInstance.getCommandDescriptor().equals(descriptor)) {
return false;
}
commandInstance = createCommand(descriptor);
return true;
}
/**
* Create the command instance based on the given descriptor. Users can
* override to return a domain-specific command instance, or further
* configure the created command.
*
* @param descriptor
* to create a command instance
* @return Command instance. If null, parameter page is disabled.
*/
protected IFrameworkCommand createCommand(
IFrameworkCommandDescriptor descriptor) {
return CommandFactory.createCommandInstance(descriptor);
}
public IWizardPage getPreviousPage(IWizardPage page) {
if (page == parameterPage) {
return commandListPage;
}
return super.getPreviousPage(page);
}
/**
* Add a command descriptor to the wizard. If the wizard already has a
* command of the same type, the wizard will use the existing command. It is
* not possible to override an existing command already present in the
* wizard
*/
public void addCommandDescriptor(
IFrameworkCommandDescriptor commandDescriptor) {
// Make sure this always executes in UI thread
final IFrameworkCommandDescriptor commandDesc = commandDescriptor;
Display.getDefault().syncExec(new Runnable() {
public void run() {
if (commandListPage != null
&& !commandListPage
.containsCommandDescriptor(commandDesc)) {
commandListPage.addCommandDescriptor(commandDesc);
}
}
});
}
/**
* Subclasses can override to implement command execution while the wizard
* is finishing. This method ONLY gets called if all required parameter
* values for a given command have values and the wizard can complete
* successfully. The list of all values, option or required, are passed as
* an argument to this method.
*
* @param command
* @param parameterValues
*/
protected void executeCommand(IFrameworkCommand command) {
// do nothing. Subclasses can override
}
public boolean performFinish() {
boolean canFinish = canFinish();
if (canFinish) {
executeCommand(commandInstance);
}
return canFinish;
}
/**
* Answers a request for a java content assist UI adapter given a Java
* parameter. If null, no Java content assist is added to the corresponding
* UI controls for the parameter.
*
* @param parameter
* Java parameter requiring content assist and Java type browsing
* @return content assist adapter. If null, no content assist support is
* added to editor controls
*/
public JavaContentAssistUIAdapter getJavaContentAssistUIAdapter(
JavaParameterDescriptor parameter) {
return new JavaContentAssistUIAdapter(parameter);
}
/**
* If true group mandatory/required parameters first. If false create the
* parameter controls in the order that they appear in the command
* descriptor. This does NOT rearrange the order of the parameters in the
* command. It only affects the order of the controls in the UI, but the
* order of the parameters in the command itself is unchanged.
* <p>
* Default value is true.
* </p>
*
* @return true if group mandatory parameters. False if parameter order is
* to be preserved.
*/
protected boolean groupRequiredParameters() {
return orderRequiredParameters;
}
}