blob: 10bde19d084d5ef0ada6dd8bffe1b09be34149b9 [file] [log] [blame]
package org.eclipse.jpt.ui.internal.properties;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jpt.core.JptCorePlugin;
import org.eclipse.jpt.utility.internal.ArrayTools;
import org.eclipse.jpt.utility.internal.CollectionTools;
import org.eclipse.jpt.utility.internal.model.value.BufferedWritablePropertyValueModel;
import org.eclipse.jpt.utility.internal.model.value.SimplePropertyValueModel;
import org.eclipse.jpt.utility.model.Model;
import org.eclipse.jpt.utility.model.listener.ChangeListener;
import org.eclipse.jpt.utility.model.listener.SimpleChangeListener;
import org.eclipse.jpt.utility.model.value.PropertyValueModel;
import org.eclipse.jpt.utility.model.value.WritablePropertyValueModel;
import org.eclipse.jst.common.project.facet.core.libprov.IPropertyChangeListener;
import org.eclipse.jst.common.project.facet.core.libprov.LibraryInstallDelegate;
import org.eclipse.jst.common.project.facet.ui.libprov.LibraryFacetPropertyPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Point;
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.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
import org.eclipse.wst.common.project.facet.core.IFacetedProject;
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
import org.eclipse.wst.common.project.facet.ui.internal.FacetsPropertyPage;
public abstract class JptProjectPropertiesPage
extends LibraryFacetPropertyPage {
protected final WritablePropertyValueModel<IProject> projectModel;
protected final BufferedWritablePropertyValueModel.Trigger trigger;
protected final ChangeListener validationListener;
public JptProjectPropertiesPage() {
super();
this.projectModel = new SimplePropertyValueModel<IProject>();
this.trigger = new BufferedWritablePropertyValueModel.Trigger();
buildModels();
this.validationListener = this.buildValidationListener();
}
/**
* Build any additional models needed by this page. The project model has been created at this
* point.
*/
protected abstract void buildModels();
// ********** convenience methods **********
protected static boolean flagIsSet(PropertyValueModel<Boolean> flagModel) {
Boolean flag = flagModel.getValue();
return (flag != null) && flag.booleanValue();
}
// ********** LibraryFacetPropertyPage implementation **********
@Override
protected LibraryInstallDelegate createLibraryInstallDelegate(IFacetedProject project, IProjectFacetVersion fv) {
LibraryInstallDelegate lid = new LibraryInstallDelegate(project, fv, null);
lid.addListener(buildLibraryProviderListener());
return lid;
}
protected IPropertyChangeListener buildLibraryProviderListener() {
return new IPropertyChangeListener() {
public void propertyChanged(String property, Object oldValue, Object newValue ) {
if (LibraryInstallDelegate.PROP_AVAILABLE_PROVIDERS.equals(property)) {
adjustLibraryProviders();
}
}
};
}
protected abstract void adjustLibraryProviders();
// ********** page **********
@Override
protected Control createPageContents(Composite parent) {
if (this.projectModel.getValue() != null) {
disengageListeners();
}
this.projectModel.setValue(getProject());
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
composite.setLayout(layout);
createWidgets(composite);
Dialog.applyDialogFont(composite);
adjustLibraryProviders();
engageListeners();
updateValidation();
return composite;
}
/**
* Build specific widgets. Layout and validation will be taken care of.
*/
protected abstract void createWidgets(Composite parent);
protected void engageListeners() {
engageValidationListener();
}
protected void disengageListeners() {
disengageValidationListener();
}
protected Link buildFacetsPageLink(Composite parent, String text) {
Link facetsPageLink = buildLink(parent, text);
facetsPageLink.addSelectionListener(buildFacetsPageLinkListener()); // the link will be GCed
return facetsPageLink;
}
private SelectionListener buildFacetsPageLinkListener() {
return new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
openProjectFacetsPage();
}
@Override
public String toString() {
return "facets page link listener"; //$NON-NLS-1$
}
};
}
protected void openProjectFacetsPage() {
((IWorkbenchPreferenceContainer)getContainer()).openPage(FacetsPropertyPage.ID, null);
}
/**
* Don't allow {@link org.eclipse.jface.preference.PreferencePage#computeSize()}
* to cache the page's size, since the size of the "Library" panel can
* change depending on the user's selection from the drop-down list.
*/
@Override
public Point computeSize() {
return this.doComputeSize();
}
// ********** widgets **********
protected Button buildCheckBox(Composite parent, int horizontalSpan, String text) {
return buildButton(parent, horizontalSpan, text, SWT.CHECK);
}
protected Button buildRadioButton(Composite parent, int horizontalSpan, String text) {
return buildButton(parent, horizontalSpan, text, SWT.RADIO);
}
protected Button buildButton(Composite parent, int horizontalSpan, String text, int style) {
Button button = new Button(parent, SWT.NONE | style);
button.setText(text);
GridData gd = new GridData();
gd.horizontalSpan = horizontalSpan;
button.setLayoutData(gd);
return button;
}
protected Combo buildDropDown(Composite parent) {
return buildDropDown(parent, 1);
}
protected Combo buildDropDown(Composite parent, int horizontalSpan) {
Combo combo = new Combo(parent, SWT.READ_ONLY);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
gd.horizontalSpan = horizontalSpan;
combo.setLayoutData(gd);
return combo;
}
protected Label buildLabel(Composite parent, String text) {
Label label = new Label(parent, SWT.LEFT);
label.setText(text);
GridData gd = new GridData();
gd.horizontalSpan = 1;
label.setLayoutData(gd);
return label;
}
protected Link buildLink(Composite parent, String text) {
Link link = new Link(parent, SWT.NONE);
GridData data = new GridData(GridData.END, GridData.CENTER, false, false);
data.horizontalSpan = 2;
link.setLayoutData(data);
link.setText(text);
return link;
}
// ********** OK/Revert/Apply behavior **********
@Override
public boolean performOk() {
super.performOk();
try {
// true=fork; false=uncancellable
this.buildOkProgressMonitorDialog().run(true, false, this.buildOkRunnableWithProgress());
}
catch (InterruptedException ex) {
return false;
}
catch (InvocationTargetException ex) {
throw new RuntimeException(ex.getTargetException());
}
return true;
}
private IRunnableContext buildOkProgressMonitorDialog() {
return new ProgressMonitorDialog(this.getShell());
}
private IRunnableWithProgress buildOkRunnableWithProgress() {
return new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
IWorkspace ws = ResourcesPlugin.getWorkspace();
try {
// the build we execute in #performOk_() locks the workspace root,
// so we need to use the workspace root as our scheduling rule here
ws.run(
buildOkWorkspaceRunnable(),
ws.getRoot(),
IWorkspace.AVOID_UPDATE,
monitor);
}
catch (CoreException ex) {
throw new InvocationTargetException(ex);
}
}
};
}
/* private */ IWorkspaceRunnable buildOkWorkspaceRunnable() {
return new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
performOk_(monitor);
}
};
}
// ********** OK/Revert/Apply behavior **********
void performOk_(IProgressMonitor monitor) throws CoreException {
if (isBuffering()) {
boolean rebuild = projectRebuildRequired();
this.trigger.accept();
if (rebuild) {
rebuildProject();
}
this.getProject().build(IncrementalProjectBuilder.FULL_BUILD, monitor);
}
}
protected abstract boolean projectRebuildRequired();
protected abstract void rebuildProject();
/**
* Return whether any of the models are buffering a change.
*/
private boolean isBuffering() {
for (BufferedWritablePropertyValueModel<?> model : buildBufferedModels()) {
if (model.isBuffering()) {
return true;
}
}
return false;
}
protected abstract BufferedWritablePropertyValueModel<?>[] buildBufferedModels();
@Override
protected void performDefaults() {
super.performDefaults();
this.trigger.reset();
}
// ********** dispose **********
@Override
public void dispose() {
disengageListeners();
super.dispose();
}
// ********** validation **********
private ChangeListener buildValidationListener() {
return new SimpleChangeListener() {
@Override
protected void modelChanged() {
validate();
}
@Override
public String toString() {
return "validation listener"; //$NON-NLS-1$
}
};
}
protected void validate() {
if ( ! getControl().isDisposed()) {
updateValidation();
}
}
private void engageValidationListener() {
for (Model model : buildValidationModels()) {
model.addChangeListener(this.validationListener);
}
}
protected abstract Model[] buildValidationModels();
private void disengageValidationListener() {
for (Model model : buildReverseValidationModels()) {
model.removeChangeListener(this.validationListener);
}
}
protected Model[] buildReverseValidationModels() {
return ArrayTools.reverse(buildValidationModels());
}
protected static final Integer ERROR_STATUS = Integer.valueOf(IStatus.ERROR);
protected static final Integer WARNING_STATUS = Integer.valueOf(IStatus.WARNING);
protected static final Integer INFO_STATUS = Integer.valueOf(IStatus.INFO);
protected static final Integer OK_STATUS = Integer.valueOf(IStatus.OK);
protected IStatus buildInfoStatus(String message) {
return this.buildStatus(IStatus.INFO, message);
}
protected IStatus buildWarningStatus(String message) {
return this.buildStatus(IStatus.WARNING, message);
}
protected IStatus buildErrorStatus(String message) {
return this.buildStatus(IStatus.ERROR, message);
}
protected IStatus buildStatus(int severity, String message) {
return new Status(severity, JptCorePlugin.PLUGIN_ID, message);
}
@Override
protected IStatus performValidation() {
HashMap<Integer, ArrayList<IStatus>> statuses = new HashMap<Integer, ArrayList<IStatus>>();
statuses.put(ERROR_STATUS, new ArrayList<IStatus>());
statuses.put(WARNING_STATUS, new ArrayList<IStatus>());
statuses.put(INFO_STATUS, new ArrayList<IStatus>());
statuses.put(OK_STATUS, CollectionTools.list(Status.OK_STATUS));
performValidation(statuses);
if ( ! statuses.get(ERROR_STATUS).isEmpty()) {
return statuses.get(ERROR_STATUS).get(0);
}
else if ( ! statuses.get(WARNING_STATUS).isEmpty()) {
return statuses.get(WARNING_STATUS).get(0);
}
else if ( ! statuses.get(INFO_STATUS).isEmpty()) {
return statuses.get(INFO_STATUS).get(0);
}
else {
return statuses.get(OK_STATUS).get(0);
}
}
protected void performValidation(Map<Integer, ArrayList<IStatus>> statuses) {
/* library provider */
IStatus lpStatus = super.performValidation();
statuses.get(Integer.valueOf(lpStatus.getSeverity())).add(lpStatus);
}
}