blob: a879c8af4973cc4ec96ca9f6a712257fa9e9d29e [file] [log] [blame]
package org.eclipse.jface.preference;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.jface.dialogs.*;
import org.eclipse.jface.resource.*;
import org.eclipse.jface.util.Assert;
import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import java.util.*;
/**
* Abstract base implementation for all preference page implementations.
* <p>
* Subclasses must implement the <code>createControl</code> framework
* method to supply the page's main control.
* </p>
* <p>
* Subclasses should extend the <code>doComputeSize</code> framework
* method to compute the size of the page's control.
* </p>
* <p>
* Subclasses may override the <code>performOk</code>, <code>performApply</code>,
* <code>performDefaults</code>, <code>performCancel</code>, and <code>performHelp</code>
* framework methods to react to the standard button events.
* </p>
* <p>
* Subclasses may call the <code>noDefaultAndApplyButton</code> framework
* method before the page's control has been created to suppress
* the standard Apply and Defaults buttons.
* </p>
*/
public abstract class PreferencePage extends DialogPage implements IPreferencePage {
/**
* Preference store, or <code>null</code>.
*/
private IPreferenceStore preferenceStore;
/**
* Valid state for this page; <code>true</code> by default.
*
* @see #isValid
*/
private boolean isValid = true;
/**
* Body of page.
*/
private Control body;
/**
* Whether this page has the standard Apply and Defaults buttons;
* <code>true</code> by default.
*
* @see #noDefaultAndApplyButton
*/
private boolean createDefaultAndApplyButton = true;
/**
* Standard Defaults button, or <code>null</code> if none.
* This button has id <code>DEFAULTS_ID</code>.
*/
private Button defaultsButton = null;
/**
* The container this preference page belongs to; <code>null</code>
* if none.
*/
private IPreferencePageContainer container = null;
/**
* Standard Apply button, or <code>null</code> if none.
* This button has id <code>APPLY_ID</code>.
*/
private Button applyButton = null;
/**
* Description label.
*
* @see #createDescriptionLabel.
*/
private Label descriptionLabel;
/**
* Caches size of page.
*/
private Point size = null;
/**
* Creates a new preference page with an empty title and no image.
*/
protected PreferencePage() {
this("");//$NON-NLS-1$
}
/**
* Creates a new preference page with the given title and no image.
*
* @param title the title of this preference page
*/
protected PreferencePage(String title) {
super(title);
}
/**
* Creates a new abstract preference page with the given title and image.
*
* @param title the title of this preference page
* @param image the image for this preference page,
* or <code>null</code> if none
*/
protected PreferencePage(String title, ImageDescriptor image) {
super(title, image);
}
/**
* Computes the size for this page's UI control.
* <p>
* The default implementation of this <code>IPreferencePage</code>
* method returns the size set by <code>setSize</code>; if no size
* has been set, but the page has a UI control, the framework
* method <code>doComputeSize</code> is called to compute the size.
* </p>
*
* @return the size of the preference page encoded as
* <code>new Point(width,height)</code>, or
* <code>(0,0)</code> if the page doesn't currently have any UI component
*/
public Point computeSize() {
if (size != null)
return size;
Control control = getControl();
if (control != null) {
size = doComputeSize();
return size;
}
return new Point(0, 0);
}
/**
* Contributes additional buttons to the given composite.
* <p>
* The default implementation of this framework hook method does
* nothing. Subclasses should override this method to contribute buttons
* to this page's button bar. For each button a subclass contributes,
* it must also increase the parent's grid layout number of columns
* by one; that is,
* <pre>
* ((GridLayout) parent.getLayout()).numColumns++);
* </pre>
* </p>
*
* @param parent the button bar
*/
protected void contributeButtons(Composite parent) {
}
/**
* Creates and returns the SWT control for the customized body
* of this preference page under the given parent composite.
* <p>
* This framework method must be implemented by concrete
* subclasses.
* </p>
*
* @param parent the parent composite
* @return the new control
*/
protected abstract Control createContents(Composite parent);
/**
* The <code>PreferencePage</code> implementation of this
* <code>IDialogPage</code> method creates a description label
* and button bar for the page. It calls <code>createContents</code>
* to create the custom contents of the page.
*/
public void createControl(Composite parent) {
GridData gd;
Composite content= new Composite(parent, SWT.NULL);
setControl(content);
Font font = parent.getFont();
GridLayout layout= new GridLayout();
layout.marginWidth = 0;
content.setLayout(layout);
// initialize the dialog units
initializeDialogUnits(content);
descriptionLabel= createDescriptionLabel(content);
if (descriptionLabel != null) {
descriptionLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
}
body = createContents(content);
body.setLayoutData(new GridData(GridData.FILL_BOTH));
Composite buttonBar= new Composite(content, SWT.NULL);
layout= new GridLayout();
layout.numColumns= 0; layout.makeColumnsEqualWidth= true;
layout.marginHeight= 0; layout.marginWidth= 0;
buttonBar.setLayout(layout);
gd= new GridData(); gd.horizontalAlignment= gd.END;
buttonBar.setLayoutData(gd);
contributeButtons(buttonBar);
if (createDefaultAndApplyButton) {
layout.numColumns= layout.numColumns + 2;
String[] labels= JFaceResources.getStrings(new String[] {"defaults", "apply"});//$NON-NLS-2$//$NON-NLS-1$
int heightHint = convertVerticalDLUsToPixels(IDialogConstants.BUTTON_HEIGHT);
int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
defaultsButton= new Button(buttonBar, SWT.PUSH);
defaultsButton.setFont(font);
defaultsButton.setText(labels[0]);
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
data.heightHint = heightHint;
data.widthHint = Math.max(widthHint, defaultsButton.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
defaultsButton.setLayoutData(data);
defaultsButton.addSelectionListener(
new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
performDefaults();
}
}
);
applyButton= new Button(buttonBar, SWT.PUSH);
applyButton.setFont(font);
applyButton.setText(labels[1]);
data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
data.heightHint = heightHint;
data.widthHint = Math.max(widthHint, applyButton.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
applyButton.setLayoutData(data);
applyButton.addSelectionListener(
new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
performApply();
}
}
);
applyButton.setEnabled(isValid());
}
}
/**
* Creates and returns an SWT label under the given composite.
*
* @param parent the parent composite
* @return the new label
*/
protected Label createDescriptionLabel(Composite parent) {
Label result = null;
String description = getDescription();
if (description != null) {
result = new Label(parent, SWT.WRAP);
result.setFont(getFont());
result.setText(description);
}
return result;
}
/**
* Computes the size needed by this page's UI control.
* <p>
* All pages should override this method and set the appropriate sizes
* of their widgets, and then call <code>super.doComputeSize</code>.
* </p>
*
* @return the size of the preference page encoded as
* <code>new Point(width,height)</code>
*/
protected Point doComputeSize() {
if (descriptionLabel != null) {
Point size = body.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
GridData gd = (GridData) descriptionLabel.getLayoutData();
gd.widthHint = size.x;
}
return getControl().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
}
/**
* Returns the preference store of this preference page.
* <p>
* This is a framework hook method for subclasses to return a
* a a page-specific preference store. The default implementation
* returns <code>null</code>.
* </p>
*
* @return the preference store, or <code>null</code> if none
*/
protected IPreferenceStore doGetPreferenceStore() {
return null;
}
/**
* Returns the container of this page.
*
* @return the preference page container, or <code>null</code> if this
* page has yet to be added to a container
*/
public IPreferencePageContainer getContainer() {
return (IPreferencePageContainer)container;
}
/**
* Returns the preference store of this preference page.
*
* @return the preference store , or <code>null</code> if none
*/
public IPreferenceStore getPreferenceStore() {
if (preferenceStore == null)
preferenceStore = doGetPreferenceStore();
if (preferenceStore != null)
return preferenceStore;
else
if (container != null)
return container.getPreferenceStore();
return null;
}
/**
* The preference page implementation of an <code>IPreferencePage</code>
* method returns whether this preference page is valid. Preference
* pages are considered valid by default; call <code>setValid(false)</code>
* to make a page invalid.
*/
public boolean isValid() {
return isValid;
}
/**
* Suppresses creation of the standard Default and Apply buttons
* for this page.
* <p>
* Subclasses wishing a preference page wihthout these buttons
* should call this framework method before the page's control
* has been created.
* </p>
*/
protected void noDefaultAndApplyButton() {
createDefaultAndApplyButton = false;
}
/**
* The <code>PreferencePage</code> implementation of this
* <code>IPreferencePage</code> method returns <code>true</code>
* if the page is valid.
*/
public boolean okToLeave() {
return isValid();
}
/**
* Performs special processing when this page's Apply button has been pressed.
* <p>
* This is a framework hook method for sublcasses to do special things when
* the Apply button has been pressed.
* The default implementation of this framework method simply calls
* <code>performOk</code> to simulate the pressing of the page's OK button.
* </p>
*
* @see #performOk
*/
protected void performApply() {
performOk();
}
/**
* The preference page implementation of an <code>IPreferencePage</code>
* method performs special processing when this page's Cancel button has
* been pressed.
* <p>
* This is a framework hook method for sublcasses to do special things when
* the Cancel button has been pressed. The default implementation of this
* framework method does nothing and returns <code>true</code>.
*/
public boolean performCancel() {
return true;
}
/**
* Performs special processing when this page's Defaults button has been pressed.
* <p>
* This is a framework hook method for sublcasses to do special things when
* the Defaults button has been pressed.
* Subclasses may override, but should call <code>super.performDefaults</code>.
* </p>
*/
protected void performDefaults() {
updateApplyButton();
}
/**
* Method declared on IPreferencePage.
* Subclasses should override
*/
public boolean performOk() {
return true;
}
/** (non-Javadoc)
* Method declared on IPreferencePage.
*/
public void setContainer(IPreferencePageContainer container) {
this.container = container;
}
/**
* Sets or clears the error message for this page.
*
* @param newMessage the message, or <code>null</code> to clear
* the error message
*/
public void setErrorMessage(String newMessage) {
super.setErrorMessage(newMessage);
if (getContainer() != null) {
getContainer().updateMessage();
}
}
/**
* Sets or clears the message for this page.
*
* @param newMessage the message, or <code>null</code> to clear
* the message
*/
public void setMessage(String newMessage) {
super.setMessage(newMessage);
if (getContainer() != null) {
getContainer().updateMessage();
}
}
/**
* Sets the preference store for this preference page.
* <p>
* If preferenceStore is set to null, getPreferenceStore
* will invoke doGetPreferenceStore the next time it is called.
* </p>
*
* @param store the preference store, or <code>null</code>
* @see #getPreferenceStore
*/
public void setPreferenceStore(IPreferenceStore store) {
preferenceStore = store;
}
/* (non-Javadoc)
* Method declared on IPreferencePage.
*/
public void setSize(Point uiSize) {
Control control = getControl();
if (control != null) {
control.setSize(uiSize);
size = uiSize;
}
}
/**
* The <code>PreferencePage</code> implementation of this <code>IDialogPage</code>
* method extends the <code>DialogPage</code> implementation to update
* the preference page container title. Subclasses may extend.
*/
public void setTitle(String title) {
super.setTitle(title);
if (getContainer() != null)
getContainer().updateTitle();
}
/**
* Sets whether this page is valid.
* The enable state of the container buttons and the
* apply button is updated when a page's valid state
* changes.
* <p>
*
* @param b the new valid state
*/
public void setValid(boolean b) {
boolean oldValue = isValid;
isValid = b;
if (oldValue != isValid) {
// update container state
getContainer().updateButtons();
// update page state
updateApplyButton();
}
}
/**
* Returns a string suitable for debugging purpose only.
*/
public String toString() {
return getTitle();
}
/**
* Updates the enabled state of the Apply button to reflect whether
* this page is valid.
*/
protected void updateApplyButton() {
if (applyButton != null)
applyButton.setEnabled(isValid());
}
}