| /******************************************************************************* |
| * Copyright (c) 2005, 2011 BEA Systems, 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: |
| * wharley@bea.com - initial API and implementation |
| * IBM Corporation - fix deprecation warnings |
| *******************************************************************************/ |
| |
| package org.eclipse.jdt.apt.ui.internal.preferences; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.IdentityHashMap; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.ProjectScope; |
| import org.eclipse.core.runtime.preferences.DefaultScope; |
| import org.eclipse.core.runtime.preferences.IEclipsePreferences; |
| import org.eclipse.core.runtime.preferences.IScopeContext; |
| import org.eclipse.core.runtime.preferences.InstanceScope; |
| import org.eclipse.jdt.apt.core.internal.AptPlugin; |
| import org.eclipse.jdt.apt.core.internal.AptProject; |
| import org.eclipse.jdt.apt.ui.internal.util.ExceptionHandler; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.preferences.ScrolledPageContent; |
| import org.eclipse.jdt.internal.ui.util.CoreUtility; |
| import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener; |
| import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField; |
| import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.jface.resource.JFaceResources; |
| 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.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.Scrollable; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.swt.widgets.Widget; |
| import org.eclipse.ui.forms.events.ExpansionAdapter; |
| import org.eclipse.ui.forms.events.ExpansionEvent; |
| import org.eclipse.ui.forms.widgets.ExpandableComposite; |
| import org.eclipse.ui.preferences.WorkingCopyManager; |
| import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer; |
| import org.eclipse.ui.preferences.IWorkingCopyManager; |
| import org.osgi.service.prefs.BackingStoreException; |
| |
| /** |
| * The ConfigurationBlock hierarchy is used to organize controls and keys |
| * within a property/preference page. The implementor derives from this |
| * class and creates dialog controls, layout, and response code. |
| * <p> |
| * This code is largely a copy of OptionsConfigurationBlock (JDT UI), modified |
| * to fix bugs and to improve extensibility for preference pages that contain |
| * a mix of preference-based and externally serialized data. |
| */ |
| public abstract class BaseConfigurationBlock { |
| |
| protected static class ControlData { |
| private Key fKey; |
| private String[] fValues; |
| |
| public ControlData(Key key, String[] values) { |
| fKey= key; |
| fValues= values; |
| } |
| |
| public Key getKey() { |
| return fKey; |
| } |
| |
| public int getSelection(String value) { |
| if (value != null) { |
| for (int i= 0; i < fValues.length; i++) { |
| if (value.equals(fValues[i])) { |
| return i; |
| } |
| } |
| } |
| return fValues.length -1; // assume the last option is the least severe |
| } |
| |
| public String getValue(boolean selection) { |
| int index= selection ? 0 : 1; |
| return fValues[index]; |
| } |
| |
| public String getValue(int index) { |
| return fValues[index]; |
| } |
| } |
| |
| public static final class Key { |
| |
| private String fKey; |
| private String fQualifier; |
| |
| public Key(String qualifier, String key) { |
| fQualifier= qualifier; |
| fKey= key; |
| } |
| |
| public String getName() { |
| return fKey; |
| } |
| |
| private IEclipsePreferences getNode(IScopeContext context, IWorkingCopyManager manager) { |
| IEclipsePreferences node= context.getNode(fQualifier); |
| if (manager != null) { |
| return manager.getWorkingCopy(node); |
| } |
| return node; |
| } |
| |
| public String getQualifier() { |
| return fQualifier; |
| } |
| |
| public String getStoredValue(IScopeContext context, IWorkingCopyManager manager) { |
| return getNode(context, manager).get(fKey, null); |
| } |
| |
| public String getStoredValue(IScopeContext[] lookupOrder, boolean ignoreTopScope, IWorkingCopyManager manager) { |
| for (int i= ignoreTopScope ? 1 : 0; i < lookupOrder.length; i++) { |
| String value= getStoredValue(lookupOrder[i], manager); |
| if (value != null) { |
| return value; |
| } |
| } |
| return null; |
| } |
| |
| public void setStoredValue(IScopeContext context, String value, IWorkingCopyManager manager) { |
| if (value != null) { |
| getNode(context, manager).put(fKey, value); |
| } else { |
| getNode(context, manager).remove(fKey); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see java.lang.Object#toString() |
| */ |
| public String toString() { |
| return fQualifier + '/' + fKey; |
| } |
| |
| } |
| |
| protected class UpdateAdapter implements IDialogFieldListener { |
| |
| public void dialogFieldChanged(DialogField field) { |
| updateModel(field); |
| } |
| } |
| |
| private static final String SETTINGS_EXPANDED= "expanded"; //$NON-NLS-1$ |
| |
| protected final Key[] fAllKeys; |
| private boolean fOriginallyHadProjectSettings; // updated in cacheOriginalValues |
| private Map<Key, String> fDisabledProjectSettings; // null when project specific settings are turned off |
| protected IScopeContext[] fLookupOrder; |
| protected final IWorkingCopyManager fManager; |
| |
| protected final ArrayList<Button> fCheckBoxes; |
| protected final ArrayList<Combo> fComboBoxes; |
| protected final ArrayList<ExpandableComposite> fExpandedComposites; |
| protected final HashMap<Scrollable, Label> fLabels; |
| protected final ArrayList<Text> fTextBoxes; |
| |
| private ModifyListener fTextModifyListener; |
| protected IStatusChangeListener fContext; |
| private SelectionListener fSelectionListener; |
| |
| protected final IProject fProject; // project or null |
| protected final AptProject fAptProject; // null for workspace prefs |
| |
| private IWorkbenchPreferenceContainer fContainer; |
| private Shell fShell; |
| |
| private Control fBlockControl; |
| |
| protected static Key getKey(String plugin, String name) { |
| return new Key(plugin, name); |
| } |
| |
| public BaseConfigurationBlock(IStatusChangeListener context, IProject project, Key[] keys, IWorkbenchPreferenceContainer container) { |
| fContext= context; |
| fProject= project; |
| fAllKeys= keys; |
| fContainer= container; |
| /* |
| if (container == null) { |
| fManager= new WorkingCopyManager(); |
| } else { |
| fManager= container.getWorkingCopyManager(); |
| } |
| */ |
| // Workaround for Bugzilla 115731 - always use our own WCM. |
| fManager = new WorkingCopyManager(); |
| |
| if (fProject != null) { |
| fLookupOrder= new IScopeContext[] { |
| new ProjectScope(fProject), |
| InstanceScope.INSTANCE, |
| DefaultScope.INSTANCE |
| }; |
| fAptProject = AptPlugin.getAptProject(JavaCore.create(fProject)); |
| } else { |
| fLookupOrder= new IScopeContext[] { |
| InstanceScope.INSTANCE, |
| DefaultScope.INSTANCE |
| }; |
| fAptProject = null; |
| } |
| |
| testIfOptionsComplete(keys); |
| if (fProject == null || hasProjectSpecificOptionsNoCache(fProject)) { |
| fDisabledProjectSettings= null; |
| } else { |
| fDisabledProjectSettings= new IdentityHashMap<Key, String>(); |
| for (int i= 0; i < keys.length; i++) { |
| Key curr= keys[i]; |
| fDisabledProjectSettings.put(curr, curr.getStoredValue(fLookupOrder, false, fManager)); |
| } |
| } |
| |
| settingsUpdated(); |
| |
| fCheckBoxes= new ArrayList<Button>(); |
| fComboBoxes= new ArrayList<Combo>(); |
| fTextBoxes= new ArrayList<Text>(2); |
| fLabels= new HashMap<Scrollable, Label>(); |
| fExpandedComposites= new ArrayList<ExpandableComposite>(); |
| } |
| |
| protected Button addCheckBox(Composite parent, String label, Key key, String[] values, int indent) { |
| ControlData data= new ControlData(key, values); |
| |
| GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL); |
| gd.horizontalSpan= 3; |
| gd.horizontalIndent= indent; |
| |
| Button checkBox= new Button(parent, SWT.CHECK); |
| checkBox.setFont(JFaceResources.getDialogFont()); |
| checkBox.setText(label); |
| checkBox.setData(data); |
| checkBox.setLayoutData(gd); |
| checkBox.addSelectionListener(getSelectionListener()); |
| |
| makeScrollableCompositeAware(checkBox); |
| |
| String currValue= getValue(key); |
| checkBox.setSelection(data.getSelection(currValue) == 0); |
| |
| fCheckBoxes.add(checkBox); |
| |
| return checkBox; |
| } |
| |
| protected Combo addComboBox(Composite parent, String label, Key key, String[] values, String[] valueLabels, int indent) { |
| GridData gd= new GridData(GridData.FILL, GridData.CENTER, true, false, 2, 1); |
| gd.horizontalIndent= indent; |
| |
| Label labelControl= new Label(parent, SWT.LEFT); |
| labelControl.setFont(JFaceResources.getDialogFont()); |
| labelControl.setText(label); |
| labelControl.setLayoutData(gd); |
| |
| Combo comboBox= newComboControl(parent, key, values, valueLabels); |
| comboBox.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); |
| |
| fLabels.put(comboBox, labelControl); |
| |
| return comboBox; |
| } |
| |
| protected Combo addInversedComboBox(Composite parent, String label, Key key, String[] values, String[] valueLabels, int indent) { |
| GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); |
| gd.horizontalIndent= indent; |
| gd.horizontalSpan= 3; |
| |
| Composite composite= new Composite(parent, SWT.NONE); |
| GridLayout layout= new GridLayout(); |
| layout.marginHeight= 0; |
| layout.marginWidth= 0; |
| layout.numColumns= 2; |
| composite.setLayout(layout); |
| composite.setLayoutData(gd); |
| |
| Combo comboBox= newComboControl(composite, key, values, valueLabels); |
| comboBox.setFont(JFaceResources.getDialogFont()); |
| comboBox.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL)); |
| |
| Label labelControl= new Label(composite, SWT.LEFT | SWT.WRAP); |
| labelControl.setText(label); |
| labelControl.setLayoutData(new GridData()); |
| |
| fLabels.put(comboBox, labelControl); |
| return comboBox; |
| } |
| |
| protected Text addTextField(Composite parent, String label, Key key, int indent, int widthHint) { |
| Label labelControl= new Label(parent, SWT.WRAP); |
| labelControl.setText(label); |
| labelControl.setFont(JFaceResources.getDialogFont()); |
| labelControl.setLayoutData(new GridData()); |
| |
| Text textBox= new Text(parent, SWT.BORDER | SWT.SINGLE); |
| textBox.setData(key); |
| textBox.setLayoutData(new GridData()); |
| |
| makeScrollableCompositeAware(textBox); |
| |
| fLabels.put(textBox, labelControl); |
| |
| String currValue= getValue(key); |
| if (currValue != null) { |
| textBox.setText(currValue); |
| } |
| textBox.addModifyListener(getTextModifyListener()); |
| |
| GridData data= new GridData(GridData.HORIZONTAL_ALIGN_FILL); |
| if (widthHint != 0) { |
| data.widthHint= widthHint; |
| } |
| data.horizontalIndent= indent; |
| data.horizontalSpan= 2; |
| textBox.setLayoutData(data); |
| |
| fTextBoxes.add(textBox); |
| return textBox; |
| } |
| |
| protected boolean checkValue(Key key, String value) { |
| return value.equals(getValue(key)); |
| } |
| |
| protected void controlChanged(Widget widget) { |
| ControlData data= (ControlData) widget.getData(); |
| String newValue= null; |
| if (widget instanceof Button) { |
| newValue= data.getValue(((Button)widget).getSelection()); |
| } else if (widget instanceof Combo) { |
| newValue= data.getValue(((Combo)widget).getSelectionIndex()); |
| } else { |
| return; |
| } |
| String oldValue= setValue(data.getKey(), newValue); |
| validateSettings(data.getKey(), oldValue, newValue); |
| } |
| |
| /** |
| * Called from BasePreferencePage#createPreferenceContent. |
| */ |
| public final Control createPreferenceContent(Composite parent) { |
| fBlockControl = createContents(parent); |
| if (fBlockControl != null) { |
| cacheOriginalValues(); |
| initContents(); |
| } |
| return fBlockControl; |
| } |
| |
| /** |
| * Derived classes must override this in order to create |
| * their visual content. After this is called, initContents() |
| * will be called. |
| * @return a Composite representing the entire pane. |
| */ |
| protected abstract Control createContents(Composite parent); |
| |
| /** |
| * This will be called when settings are first loaded and |
| * whenever changes are applied. |
| * Derived classes may use this to cache the saved settings |
| * values, for later comparison to see if anything changed. |
| */ |
| protected void cacheOriginalValues() { |
| fOriginallyHadProjectSettings= hasProjectSpecificOptionsNoCache(fProject); |
| } |
| |
| /** |
| * This will be called exactly once during initialization, after |
| * createContents() and cacheOriginalValues(). |
| * Derived classes may override this to initialize any fields |
| * that are not based on a Key. |
| */ |
| protected void initContents() { |
| // Base method does nothing. |
| } |
| |
| protected ExpandableComposite createStyleSection(Composite parent, String label, int nColumns) { |
| ExpandableComposite excomposite= new ExpandableComposite(parent, SWT.NONE, ExpandableComposite.TWISTIE | ExpandableComposite.CLIENT_INDENT); |
| excomposite.setText(label); |
| excomposite.setExpanded(false); |
| excomposite.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT)); |
| excomposite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false, nColumns, 1)); |
| excomposite.addExpansionListener(new ExpansionAdapter() { |
| public void expansionStateChanged(ExpansionEvent e) { |
| expandedStateChanged((ExpandableComposite) e.getSource()); |
| } |
| }); |
| fExpandedComposites.add(excomposite); |
| makeScrollableCompositeAware(excomposite); |
| return excomposite; |
| } |
| |
| /** |
| * Called from BasePreferencePage#dispose(). |
| * Derived classes may override. |
| */ |
| public void dispose() { |
| } |
| |
| protected final void expandedStateChanged(ExpandableComposite expandable) { |
| ScrolledPageContent parentScrolledComposite= getParentScrolledComposite(expandable); |
| if (parentScrolledComposite != null) { |
| parentScrolledComposite.reflow(true); |
| } |
| } |
| |
| protected Control findControl(Key key) { |
| Combo comboBox= getComboBox(key); |
| if (comboBox != null) { |
| return comboBox; |
| } |
| Button checkBox= getCheckBox(key); |
| if (checkBox != null) { |
| return checkBox; |
| } |
| Text text= getTextControl(key); |
| if (text != null) { |
| return text; |
| } |
| return null; |
| } |
| |
| protected boolean getBooleanValue(Key key) { |
| return Boolean.valueOf(getValue(key)).booleanValue(); |
| } |
| |
| protected Button getCheckBox(Key key) { |
| for (int i= fCheckBoxes.size() - 1; i >= 0; i--) { |
| Button curr= fCheckBoxes.get(i); |
| ControlData data= (ControlData) curr.getData(); |
| if (key.equals(data.getKey())) { |
| return curr; |
| } |
| } |
| return null; |
| } |
| |
| protected Combo getComboBox(Key key) { |
| for (int i= fComboBoxes.size() - 1; i >= 0; i--) { |
| Combo curr= fComboBoxes.get(i); |
| ControlData data= (ControlData) curr.getData(); |
| if (key.equals(data.getKey())) { |
| return curr; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Provide the strings needed to ask the user whether to rebuild. |
| * Derived classes can override this to change the strings, or to |
| * return null, in which case the dialog will not be shown and the |
| * rebuild will not be triggered. |
| * @param workspaceSettings true if workspace settings have changed, |
| * false if only project-specific settings have changed. |
| * @return an array whose first entry is the dialog title, and whose |
| * second entry is a query asking the user whether to rebuild. |
| */ |
| protected String[] getFullBuildDialogStrings(boolean workspaceSettings) { |
| String[] strings= new String[2]; |
| strings[0] = Messages.BaseConfigurationBlock_settingsChanged; |
| if (workspaceSettings) { |
| strings[1]= Messages.BaseConfigurationBlock_fullRebuildRequired; |
| } |
| else { |
| strings[1]= Messages.BaseConfigurationBlock_rebuildRequired; |
| } |
| return strings; |
| } |
| |
| protected ExpandableComposite getParentExpandableComposite(Control control) { |
| Control parent= control.getParent(); |
| while (!(parent instanceof ExpandableComposite) && parent != null) { |
| parent= parent.getParent(); |
| } |
| if (parent instanceof ExpandableComposite) { |
| return (ExpandableComposite) parent; |
| } |
| return null; |
| } |
| |
| protected ScrolledPageContent getParentScrolledComposite(Control control) { |
| Control parent= control.getParent(); |
| while (!(parent instanceof ScrolledPageContent) && parent != null) { |
| parent= parent.getParent(); |
| } |
| if (parent instanceof ScrolledPageContent) { |
| return (ScrolledPageContent) parent; |
| } |
| return null; |
| } |
| |
| protected final IWorkbenchPreferenceContainer getPreferenceContainer() { |
| return fContainer; |
| } |
| |
| protected SelectionListener getSelectionListener() { |
| if (fSelectionListener == null) { |
| fSelectionListener= new SelectionListener() { |
| public void widgetDefaultSelected(SelectionEvent e) {} |
| |
| public void widgetSelected(SelectionEvent e) { |
| controlChanged(e.widget); |
| } |
| }; |
| } |
| return fSelectionListener; |
| } |
| |
| protected Shell getShell() { |
| return fShell; |
| } |
| |
| /** |
| * Retuens the value as actually stored in the preference store. |
| * @param key |
| * @return the value as actually stored in the preference store. |
| */ |
| protected String getStoredValue(Key key) { |
| return key.getStoredValue(fLookupOrder, false, fManager); |
| } |
| |
| protected Text getTextControl(Key key) { |
| for (int i= fTextBoxes.size() - 1; i >= 0; i--) { |
| Text curr= fTextBoxes.get(i); |
| ControlData data= (ControlData) curr.getData(); |
| if (key.equals(data.getKey())) { |
| return curr; |
| } |
| } |
| return null; |
| } |
| |
| protected ModifyListener getTextModifyListener() { |
| if (fTextModifyListener == null) { |
| fTextModifyListener= new ModifyListener() { |
| public void modifyText(ModifyEvent e) { |
| textChanged((Text) e.widget); |
| } |
| }; |
| } |
| return fTextModifyListener; |
| } |
| |
| protected String[] getTokens(String text, String separator) { |
| StringTokenizer tok= new StringTokenizer(text, separator); |
| int nTokens= tok.countTokens(); |
| String[] res= new String[nTokens]; |
| for (int i= 0; i < res.length; i++) { |
| res[i]= tok.nextToken().trim(); |
| } |
| return res; |
| } |
| |
| protected String getValue(Key key) { |
| if (fDisabledProjectSettings != null) { |
| return fDisabledProjectSettings.get(key); |
| } |
| return key.getStoredValue(fLookupOrder, false, fManager); |
| } |
| |
| /** |
| * TODO: this method is a workaround for Bugzilla 111144 and 106111. When |
| * 111144 is fixed, remove this method and call hasProjectSpecificOptions() |
| * instead. The difference is that this one does not cause project prefs nodes |
| * to be cached in the WorkingCopyManager. |
| * @return true if the project has project-specific options. |
| */ |
| public boolean hasProjectSpecificOptionsNoCache(IProject project) { |
| if (project != null) { |
| IScopeContext projectContext= new ProjectScope(project); |
| Key[] allKeys= fAllKeys; |
| for (int i= 0; i < allKeys.length; i++) { |
| if (allKeys[i].getStoredValue(projectContext, null) != null) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| private void makeScrollableCompositeAware(Control control) { |
| ScrolledPageContent parentScrolledComposite= getParentScrolledComposite(control); |
| if (parentScrolledComposite != null) { |
| parentScrolledComposite.adaptChild(control); |
| } |
| } |
| |
| protected Combo newComboControl(Composite composite, Key key, String[] values, String[] valueLabels) { |
| ControlData data= new ControlData(key, values); |
| |
| Combo comboBox= new Combo(composite, SWT.READ_ONLY); |
| comboBox.setItems(valueLabels); |
| comboBox.setData(data); |
| comboBox.addSelectionListener(getSelectionListener()); |
| comboBox.setFont(JFaceResources.getDialogFont()); |
| |
| makeScrollableCompositeAware(comboBox); |
| |
| String currValue= getValue(key); |
| comboBox.select(data.getSelection(currValue)); |
| |
| fComboBoxes.add(comboBox); |
| return comboBox; |
| } |
| |
| public boolean performApply() { |
| return processChanges(null); // apply directly |
| } |
| |
| |
| public void performDefaults() { |
| IScopeContext[] lookupOrder; // not same as fLookupOrder! Starts one layer deeper. |
| if (fProject != null) { |
| lookupOrder= new IScopeContext[] { |
| InstanceScope.INSTANCE, |
| DefaultScope.INSTANCE |
| }; |
| } else { |
| lookupOrder= new IScopeContext[] { |
| DefaultScope.INSTANCE |
| }; |
| } |
| |
| for (int i= 0; i < fAllKeys.length; i++) { |
| Key curr= fAllKeys[i]; |
| String defValue= curr.getStoredValue(lookupOrder, false, null); |
| setValue(curr, defValue); |
| } |
| |
| settingsUpdated(); |
| updateControls(); |
| validateSettings(null, null, null); |
| } |
| |
| public boolean performOk() { |
| return processChanges(fContainer); |
| } |
| |
| /** |
| * @since 3.1 |
| */ |
| public void performRevert() { |
| for (int i= 0; i < fAllKeys.length; i++) { |
| Key curr= fAllKeys[i]; |
| String origValue= curr.getStoredValue(fLookupOrder, false, null); |
| setValue(curr, origValue); |
| } |
| |
| settingsUpdated(); |
| updateControls(); |
| validateSettings(null, null, null); |
| } |
| |
| /** |
| * If there are changed settings, save them and ask user whether to rebuild. |
| * This is called by performOk() and performApply(). |
| * @param container null when called from performApply(). |
| * @return false to abort exiting the preference pane. |
| */ |
| protected boolean processChanges(IWorkbenchPreferenceContainer container) { |
| |
| boolean projectSpecificnessChanged = false; |
| boolean isProjectSpecific= (fProject != null) && fBlockControl.getEnabled(); |
| if (fOriginallyHadProjectSettings ^ isProjectSpecific) { |
| // the project-specificness changed. |
| projectSpecificnessChanged= true; |
| } else if ((fProject != null) && !isProjectSpecific) { |
| // no project specific data, and there never was, and this |
| // is a project preferences pane, so nothing could have changed. |
| return true; |
| } |
| |
| if (!projectSpecificnessChanged && !settingsChanged(fLookupOrder[0])) { |
| return true; |
| } |
| |
| int response= 1; // "NO" rebuild unless we put up the dialog. |
| String[] strings= getFullBuildDialogStrings(fProject == null); |
| if (strings != null) { |
| MessageDialog dialog= new MessageDialog( |
| getShell(), |
| strings[0], |
| null, |
| strings[1], |
| MessageDialog.QUESTION, |
| new String[] { |
| IDialogConstants.YES_LABEL, |
| IDialogConstants.NO_LABEL, |
| IDialogConstants.CANCEL_LABEL |
| }, |
| 2); |
| response= dialog.open(); |
| } |
| if (response == 0 || response == 1) { // "YES" or "NO" - either way, save. |
| saveSettings(); |
| if (container == null) { |
| // we're doing an Apply, so update the reference values. |
| cacheOriginalValues(); |
| } |
| } |
| if (response == 0) { // "YES", rebuild |
| if (container != null) { |
| // build after dialog exits |
| container.registerUpdateJob(CoreUtility.getBuildJob(fProject)); |
| } else { |
| // build immediately |
| CoreUtility.getBuildJob(fProject).schedule(); |
| } |
| } else if (response != 1) { // "CANCEL" - no save, no rebuild. |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Save dialog information to persistent storage. |
| * Derived classes should override this if they have settings |
| * that are managed using means other than the Key infrastructure. |
| */ |
| protected void saveSettings() { |
| try { |
| fManager.applyChanges(); |
| } catch (BackingStoreException e) { |
| ExceptionHandler.log(e, "Unable to save preferences"); //$NON-NLS-1$ |
| } |
| } |
| |
| protected void restoreSectionExpansionStates(IDialogSettings settings) { |
| for (int i= 0; i < fExpandedComposites.size(); i++) { |
| ExpandableComposite excomposite= fExpandedComposites.get(i); |
| if (settings == null) { |
| excomposite.setExpanded(i == 0); // only expand the first node by default |
| } else { |
| excomposite.setExpanded(settings.getBoolean(SETTINGS_EXPANDED + String.valueOf(i))); |
| } |
| } |
| } |
| |
| public void selectOption(Key key) { |
| Control control= findControl(key); |
| if (control != null) { |
| if (!fExpandedComposites.isEmpty()) { |
| ExpandableComposite expandable= getParentExpandableComposite(control); |
| if (expandable != null) { |
| for (int i= 0; i < fExpandedComposites.size(); i++) { |
| ExpandableComposite curr= fExpandedComposites.get(i); |
| curr.setExpanded(curr == expandable); |
| } |
| expandedStateChanged(expandable); |
| } |
| } |
| control.setFocus(); |
| } |
| } |
| |
| public void selectOption(String key, String qualifier) { |
| for (int i= 0; i < fAllKeys.length; i++) { |
| Key curr= fAllKeys[i]; |
| if (curr.getName().equals(key) && curr.getQualifier().equals(qualifier)) { |
| selectOption(curr); |
| } |
| } |
| } |
| |
| protected void setComboEnabled(Key key, boolean enabled) { |
| Combo combo= getComboBox(key); |
| Label label= fLabels.get(combo); |
| combo.setEnabled(enabled); |
| label.setEnabled(enabled); |
| } |
| |
| protected void setShell(Shell shell) { |
| fShell= shell; |
| } |
| |
| /** |
| * Checks the state of all Keys in the dialog to see whether there have been changes. |
| * Derived classes which include settings managed outside of the Key infrastructure |
| * should override this method, in order to check whether the additional settings have changed. |
| * @return true if there is anything that needs to be saved. |
| */ |
| protected boolean settingsChanged(IScopeContext currContext) { |
| boolean needsBuild= false; |
| for (int i= 0; i < fAllKeys.length; i++) { |
| Key key= fAllKeys[i]; |
| String oldVal= key.getStoredValue(currContext, null); |
| String val= key.getStoredValue(currContext, fManager); |
| if (val == null) { |
| if (oldVal != null) { |
| needsBuild |= !oldVal.equals(key.getStoredValue(fLookupOrder, true, fManager)); |
| } |
| } else if (!val.equals(oldVal)) { |
| needsBuild |= oldVal != null || !val.equals(key.getStoredValue(fLookupOrder, true, fManager)); |
| } |
| } |
| return needsBuild; |
| } |
| |
| protected void settingsUpdated() { |
| } |
| |
| protected String setValue(Key key, boolean value) { |
| return setValue(key, String.valueOf(value)); |
| } |
| |
| protected String setValue(Key key, String value) { |
| if (fDisabledProjectSettings != null) { |
| return fDisabledProjectSettings.put(key, value); |
| } |
| String oldValue= getValue(key); |
| key.setStoredValue(fLookupOrder[0], value, fManager); |
| return oldValue; |
| } |
| |
| protected void storeSectionExpansionStates(IDialogSettings settings) { |
| for (int i= 0; i < fExpandedComposites.size(); i++) { |
| ExpandableComposite curr= fExpandedComposites.get(i); |
| settings.put(SETTINGS_EXPANDED + String.valueOf(i), curr.isExpanded()); |
| } |
| } |
| |
| private void testIfOptionsComplete(Key[] allKeys) { |
| for (int i= 0; i < allKeys.length; i++) { |
| if (allKeys[i].getStoredValue(fLookupOrder, false, fManager) == null) { |
| JavaPlugin.logErrorMessage("preference option missing: " + allKeys[i] + " (" + this.getClass().getName() +')'); //$NON-NLS-1$//$NON-NLS-2$ |
| } |
| } |
| } |
| |
| protected void textChanged(Text textControl) { |
| Key key= (Key) textControl.getData(); |
| String number= textControl.getText(); |
| String oldValue= setValue(key, number); |
| validateSettings(key, oldValue, number); |
| } |
| |
| protected void updateCheckBox(Button curr) { |
| ControlData data= (ControlData) curr.getData(); |
| |
| String currValue= getValue(data.getKey()); |
| curr.setSelection(data.getSelection(currValue) == 0); |
| } |
| |
| protected void updateCombo(Combo curr) { |
| ControlData data= (ControlData) curr.getData(); |
| |
| String currValue= getValue(data.getKey()); |
| curr.select(data.getSelection(currValue)); |
| } |
| |
| protected void updateControls() { |
| // update the UI |
| for (int i= fCheckBoxes.size() - 1; i >= 0; i--) { |
| updateCheckBox(fCheckBoxes.get(i)); |
| } |
| for (int i= fComboBoxes.size() - 1; i >= 0; i--) { |
| updateCombo(fComboBoxes.get(i)); |
| } |
| for (int i= fTextBoxes.size() - 1; i >= 0; i--) { |
| updateText(fTextBoxes.get(i)); |
| } |
| } |
| |
| protected abstract void updateModel(DialogField field); |
| |
| protected void updateText(Text curr) { |
| Key key= (Key) curr.getData(); |
| |
| String currValue= getValue(key); |
| if (currValue != null) { |
| curr.setText(currValue); |
| } |
| } |
| |
| public void useProjectSpecificSettings(boolean enable) { |
| boolean hasProjectSpecificOption= fDisabledProjectSettings == null; |
| if (enable != hasProjectSpecificOption && fProject != null) { |
| if (enable) { |
| for (int i= 0; i < fAllKeys.length; i++) { |
| Key curr= fAllKeys[i]; |
| String val= fDisabledProjectSettings.get(curr); |
| curr.setStoredValue(fLookupOrder[0], val, fManager); |
| } |
| fDisabledProjectSettings= null; |
| updateControls(); |
| } else { |
| fDisabledProjectSettings= new IdentityHashMap<Key, String>(); |
| for (int i= 0; i < fAllKeys.length; i++) { |
| Key curr= fAllKeys[i]; |
| String oldSetting= curr.getStoredValue(fLookupOrder, false, fManager); |
| fDisabledProjectSettings.put(curr, oldSetting); |
| curr.setStoredValue(fLookupOrder[0], null, fManager); // clear project settings |
| } |
| } |
| } |
| } |
| |
| /* (non-javadoc) |
| * Update fields and validate. |
| * @param changedKey Key that changed, or null, if all changed. |
| */ |
| protected abstract void validateSettings(Key changedKey, String oldValue, String newValue); |
| } |