| /******************************************************************************* |
| * Copyright (c) 2011, 2012 Oracle. 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: |
| * Oracle - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.jpt.common.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.common.core.JptCommonCorePlugin; |
| import org.eclipse.jpt.common.utility.internal.ArrayTools; |
| import org.eclipse.jpt.common.utility.internal.StringTools; |
| import org.eclipse.jpt.common.utility.internal.model.value.BufferedWritablePropertyValueModel; |
| import org.eclipse.jpt.common.utility.internal.model.value.SimplePropertyValueModel; |
| import org.eclipse.jpt.common.utility.model.Model; |
| import org.eclipse.jpt.common.utility.model.listener.ChangeListener; |
| import org.eclipse.jpt.common.utility.model.listener.AbstractChangeListener; |
| import org.eclipse.jpt.common.utility.model.value.PropertyValueModel; |
| import org.eclipse.jpt.common.utility.model.value.ModifiablePropertyValueModel; |
| 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.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.ui.internal.FacetsPropertyPage; |
| |
| |
| public abstract class JptProjectPropertiesPage |
| extends LibraryFacetPropertyPage { |
| |
| protected final ModifiablePropertyValueModel<IProject> projectModel; |
| protected final BufferedWritablePropertyValueModel.Trigger trigger; |
| |
| protected final ChangeListener validationListener; |
| |
| |
| public JptProjectPropertiesPage() { |
| super(); |
| |
| this.projectModel = new SimplePropertyValueModel<IProject>(); |
| this.trigger = new BufferedWritablePropertyValueModel.Trigger(); |
| |
| this.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 ********** |
| |
| public static boolean flagIsSet(PropertyValueModel<Boolean> flagModel) { |
| Boolean flag = flagModel.getValue(); |
| return (flag != null) && flag.booleanValue(); |
| } |
| |
| |
| // ********** LibraryFacetPropertyPage implementation ********** |
| |
| protected IPropertyChangeListener buildLibraryProviderListener() { |
| return new LibraryProviderListener(); |
| } |
| |
| protected class LibraryProviderListener |
| implements IPropertyChangeListener |
| { |
| public void propertyChanged(String property, Object oldValue, Object newValue ) { |
| if (LibraryInstallDelegate.PROP_AVAILABLE_PROVIDERS.equals(property)) { |
| JptProjectPropertiesPage.this.adjustLibraryProviders(); |
| } |
| } |
| @Override |
| public String toString() { |
| return StringTools.buildToStringFor(this); |
| } |
| } |
| |
| protected abstract void adjustLibraryProviders(); |
| |
| |
| // ********** page ********** |
| |
| @Override |
| protected Control createPageContents(Composite parent) { |
| if (this.projectModel.getValue() != null) { |
| this.disengageListeners(); |
| } |
| |
| this.projectModel.setValue(this.getProject()); |
| |
| Composite composite = new Composite(parent, SWT.NONE); |
| GridLayout layout = new GridLayout(); |
| layout.marginWidth = 0; |
| layout.marginHeight = 0; |
| composite.setLayout(layout); |
| |
| this.createWidgets(composite); |
| |
| Dialog.applyDialogFont(composite); |
| |
| this.adjustLibraryProviders(); |
| |
| this.engageListeners(); |
| this.updateValidation(); |
| |
| return composite; |
| } |
| |
| /** |
| * Build specific widgets. Layout and validation will be taken care of. |
| */ |
| protected abstract void createWidgets(Composite parent); |
| |
| protected void engageListeners() { |
| this.engageValidationListener(); |
| } |
| |
| protected void disengageListeners() { |
| this.disengageValidationListener(); |
| } |
| |
| protected Link buildFacetsPageLink(Composite parent, String text) { |
| Link facetsPageLink = this.buildLink(parent, text); |
| facetsPageLink.addSelectionListener(new FacetsPageLinkListener()); // the link will be GCed |
| return facetsPageLink; |
| } |
| |
| /* CU private */ class FacetsPageLinkListener |
| extends SelectionAdapter |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| JptProjectPropertiesPage.this.openProjectFacetsPage(); |
| } |
| @Override |
| public String toString() { |
| return StringTools.buildToStringFor(this); |
| } |
| } |
| |
| protected void openProjectFacetsPage() { |
| ((IWorkbenchPreferenceContainer)this.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 this.buildButton(parent, horizontalSpan, text, SWT.CHECK); |
| } |
| |
| protected Button buildRadioButton(Composite parent, int horizontalSpan, String text) { |
| return this.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 this.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) { |
| // should *not* happen... |
| Thread.currentThread().interrupt(); |
| return false; |
| } |
| catch (InvocationTargetException ex) { |
| throw new RuntimeException(ex.getTargetException()); |
| } |
| |
| return true; |
| } |
| |
| protected IRunnableContext buildOkProgressMonitorDialog() { |
| return new ProgressMonitorDialog(this.getShell()); |
| } |
| |
| protected IRunnableWithProgress buildOkRunnableWithProgress() { |
| return new OkRunnableWithProgress(); |
| } |
| |
| protected class OkRunnableWithProgress |
| implements 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( |
| new OkWorkspaceRunnable(), |
| ws.getRoot(), |
| IWorkspace.AVOID_UPDATE, |
| monitor |
| ); |
| } catch (CoreException ex) { |
| throw new InvocationTargetException(ex); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return StringTools.buildToStringFor(this); |
| } |
| |
| /* class private */ class OkWorkspaceRunnable |
| implements IWorkspaceRunnable |
| { |
| public void run(IProgressMonitor monitor) throws CoreException { |
| JptProjectPropertiesPage.this.performOk_(monitor); |
| } |
| @Override |
| public String toString() { |
| return StringTools.buildToStringFor(this); |
| } |
| } |
| } |
| |
| |
| // ********** OK/Revert/Apply behavior ********** |
| |
| /* CU private */ void performOk_(IProgressMonitor monitor) throws CoreException { |
| if (this.isBuffering()) { |
| boolean rebuild = this.projectRebuildRequired(); |
| this.trigger.accept(); |
| if (rebuild) { |
| this.rebuildProject(); |
| } |
| this.getProject().build(IncrementalProjectBuilder.FULL_BUILD, monitor); |
| } |
| } |
| |
| protected abstract boolean projectRebuildRequired(); |
| |
| protected abstract void rebuildProject() throws CoreException; |
| |
| /** |
| * Return whether any of the models are buffering a change. |
| */ |
| private boolean isBuffering() { |
| for (BufferedWritablePropertyValueModel<?> model : this.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() { |
| this.disengageListeners(); |
| super.dispose(); |
| } |
| |
| |
| // ********** validation ********** |
| |
| private ChangeListener buildValidationListener() { |
| return new ValidationListener(); |
| } |
| |
| /* CU private */ class ValidationListener |
| extends AbstractChangeListener |
| { |
| @Override |
| protected void modelChanged() { |
| JptProjectPropertiesPage.this.validate(); |
| } |
| } |
| |
| protected void validate() { |
| if ( ! this.getControl().isDisposed()) { |
| this.updateValidation(); |
| } |
| } |
| |
| private void engageValidationListener() { |
| for (Model model : this.buildValidationModels()) { |
| model.addChangeListener(this.validationListener); |
| } |
| } |
| |
| protected abstract Model[] buildValidationModels(); |
| |
| private void disengageValidationListener() { |
| for (Model model : this.buildReverseValidationModels()) { |
| model.removeChangeListener(this.validationListener); |
| } |
| } |
| |
| protected Model[] buildReverseValidationModels() { |
| return ArrayTools.reverse(this.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, JptCommonCorePlugin.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, new ArrayList<IStatus>()); |
| |
| /* library provider */ |
| this.addStatus(super.performValidation(), statuses); |
| this.performValidation(statuses); |
| |
| ArrayList<IStatus> list = statuses.get(ERROR_STATUS); |
| if ( ! list.isEmpty()) { |
| return list.get(0); |
| } |
| list = statuses.get(WARNING_STATUS); |
| if ( ! list.isEmpty()) { |
| return list.get(0); |
| } |
| list = statuses.get(INFO_STATUS); |
| if ( ! list.isEmpty()) { |
| return list.get(0); |
| } |
| return Status.OK_STATUS; |
| } |
| |
| protected abstract void performValidation(Map<Integer, ArrayList<IStatus>> statuses); |
| |
| protected void addStatus(IStatus status, Map<Integer, ArrayList<IStatus>> statuses) { |
| statuses.get(Integer.valueOf(status.getSeverity())).add(status); |
| } |
| } |