content: /*******************************************************************************
   * Copyright (c) 2000, 2008 IBM Corporation and others.
   * 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:
   *     IBM Corporation - initial API and implementation
   *******************************************************************************/
  package org.eclipse.wst.jsdt.internal.ui.preferences.formatter;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Observable;
  import java.util.Observer;
  
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.core.runtime.Status;
  import org.eclipse.jface.dialogs.IDialogConstants;
  import org.eclipse.jface.dialogs.IDialogSettings;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.custom.SashForm;
  import org.eclipse.swt.events.FocusAdapter;
  import org.eclipse.swt.events.FocusEvent;
  import org.eclipse.swt.events.FocusListener;
  import org.eclipse.swt.events.ModifyEvent;
  import org.eclipse.swt.events.ModifyListener;
  import org.eclipse.swt.events.SelectionAdapter;
  import org.eclipse.swt.events.SelectionEvent;
  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.Group;
  import org.eclipse.swt.widgets.Label;
  import org.eclipse.swt.widgets.Text;
  import org.eclipse.wst.jsdt.internal.corext.util.Messages;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.internal.ui.util.PixelConverter;
  import org.eclipse.wst.jsdt.ui.JavaScriptUI;
  
  
  public abstract class ModifyDialogTabPage {
  	
  	public interface IModificationListener {
  
  		void updateStatus(IStatus status);
  
  		void valuesModified();
  
      }
  
  	/**
  	 * This is the default listener for any of the Preference
  	 * classes. It is added by the respective factory methods and
  	 * updates the page's preview on each change. 
  	 */
  	protected final Observer fUpdater= new Observer() {
  		public void update(Observable o, Object arg) {
  			doUpdatePreview();
  			notifyValuesModified();
  		}
  	};
  	
  	
  	/**
  	 * The base class of all Preference classes. A preference class provides a wrapper
  	 * around one or more SWT widgets and handles the input of values for some key.
  	 * On each change, the new value is written to the map and the listeners are notified.
  	 */
  	protected abstract class Preference extends Observable {
  	    private final Map fPreferences;
  	    private boolean fEnabled;
  	    private String fKey;
  	    
  	    /**
  	     * Create a new Preference.
  	     * @param preferences The map where the value is written.
  	     * @param key The key for which a value is managed.
  	     */
  	    public Preference(Map preferences, String key) {
  	        fPreferences= preferences;
  	        fEnabled= true;
  	        fKey= key;
  	    }
  	    /**
  	     * @return Gets the map of this Preference.
  	     */
  	    protected final Map getPreferences() {
  	        return fPreferences;
  	    }
  
  	    /**
  	     * Set the enabled state of all SWT widgets of this preference. 
  	     * @param enabled new value
  	     */
  	    public final void setEnabled(boolean enabled) {
  	        fEnabled= enabled;
  	        updateWidget();
  	    }
  	    
  	    /**
  	     * @return Gets the enabled state of all SWT widgets of this Preference.
  	     */
  	    public final boolean getEnabled() {
  	        return fEnabled;
  	    }
  	    
  	    /**
  	     * Set the key which is used to store the value.
  	     * @param key New value
  	     */
  	    public final void setKey(String key) {
  	        if (key == null || !fKey.equals(key)) {
  	            fKey= key;
  	            updateWidget();
  	        }
  	    }
  	    /**
  	     * @return Gets the currently used key which is used to store the value.
  	     */	    
  	    public final String getKey() {
  	        return fKey;
  	    }
  	    
  	    /**
  	     * Returns the main control of a preference, which is mainly used to 
  	     * manage the focus. This may be <code>null</code> if the preference doesn't
  	     * have a control which is able to have the focus. 
  	     * @return The main control
  	     */
  	    public abstract Control getControl();
  	    
  	    /**
  	     * To be implemented in subclasses. Update the SWT widgets when the state 
  	     * of this object has changed (enabled, key, ...).
  	     */
  	    protected abstract void updateWidget();
  	}
  	
  	/**
  	 * Wrapper around a checkbox and a label. 
  	 */	
  	protected class ButtonPreference extends Preference {
  		private final String[] fValues;
  		private final Button fCheckbox;
  		
  		/**
  		 * Create a new CheckboxPreference.
  		 * @param composite The composite on which the SWT widgets are added.
  		 * @param numColumns The number of columns in the composite's GridLayout.
  		 * @param preferences The map to store the values.
  		 * @param key The key to store the values.
  		 * @param values An array of two elements indicating the values to store on unchecked/checked.
  		 * @param text The label text for this Preference.
  		 * @param style SWT style flag for the button
  		 */
  		public ButtonPreference(Composite composite, int numColumns,
  								  Map preferences, String key, 
  								  String [] values, String text, int style) {
  		    super(preferences, key);
  		    if (values == null || text == null) 
  		        throw new IllegalArgumentException(FormatterMessages.ModifyDialogTabPage_error_msg_values_text_unassigned); 
  			fValues= values;
  
  			fCheckbox= new Button(composite, style);
  			fCheckbox.setText(text);
  			fCheckbox.setLayoutData(createGridData(numColumns, GridData.FILL_HORIZONTAL, SWT.DEFAULT));
  			fCheckbox.setFont(composite.getFont());
  			
  			updateWidget();
  
  			fCheckbox.addSelectionListener(new SelectionAdapter() {
  				public void widgetSelected(SelectionEvent e) {
  					checkboxChecked(((Button)e.widget).getSelection());
  				}
  			});
  		}
  		
  		protected void checkboxChecked(boolean state) {
  			getPreferences().put(getKey(), state ? fValues[1] : fValues[0]);
  			setChanged();
  			notifyObservers();
  		}
  		
  		protected void updateWidget() {
  			if (getKey() != null) {
  				fCheckbox.setEnabled(getEnabled());
  				fCheckbox.setSelection(getChecked());
  			} else {
  				fCheckbox.setSelection(false);
  				fCheckbox.setEnabled(false);
  			}
  		}
  		
  		public boolean getChecked() {
  			return fValues[1].equals(getPreferences().get(getKey()));
  		}
  		
  		public void setChecked(boolean checked) {
  			getPreferences().put(getKey(), checked ? fValues[1] : fValues[0]);
  			updateWidget();
  			checkboxChecked(checked);	
  		}
  		
  		public Control getControl() {
  			return fCheckbox;
  		}
  	}
  	
  	protected final class CheckboxPreference extends ButtonPreference {
  		public CheckboxPreference(Composite composite, int numColumns, Map preferences, String key, String[] values, String text) {
  	        super(composite, numColumns, preferences, key, values, text, SWT.CHECK);
          }
  	}
  	
  	protected final class RadioPreference extends ButtonPreference {
  		public RadioPreference(Composite composite, int numColumns, Map preferences, String key, String[] values, String text) {
  	        super(composite, numColumns, preferences, key, values, text, SWT.RADIO);
          }	
  	}
  	
  	/**
  	 * Wrapper around a Combo box.
  	 */
  	protected final class ComboPreference extends Preference {
  		private final String [] fItems;
  		private final String[] fValues;
  		private final Combo fCombo;
  		
  		/**
  		 * Create a new ComboPreference.
  		 * @param composite The composite on which the SWT widgets are added.
  		 * @param numColumns The number of columns in the composite's GridLayout.
  		 * @param preferences The map to store the values.
  		 * @param key The key to store the values.
  		 * @param values An array of n elements indicating the values to store for each selection.
  		 * @param text The label text for this Preference.
  		 * @param items An array of n elements indicating the text to be written in the combo box.
  		 */
  		public ComboPreference(Composite composite, int numColumns,
  								  Map preferences, String key, 
  								  String [] values, String text, String [] items) {
  		    super(preferences, key);
  		    if (values == null || items == null || text == null) 
  		        throw new IllegalArgumentException(FormatterMessages.ModifyDialogTabPage_error_msg_values_items_text_unassigned); 
  			fValues= values;
  			fItems= items;
  			createLabel(numColumns - 1, composite, text);
  			fCombo= new Combo(composite, SWT.SINGLE | SWT.READ_ONLY);
  			fCombo.setFont(composite.getFont());
  			fCombo.setItems(items);
  			
  			int max= 0;
  			for (int i= 0; i < items.length; i++)
  			    if (items[i].length() > max) max= items[i].length();
  			
  			fCombo.setLayoutData(createGridData(1, GridData.HORIZONTAL_ALIGN_FILL, fCombo.computeSize(SWT.DEFAULT, SWT.DEFAULT).x));			
  
  			updateWidget();
  
  			fCombo.addSelectionListener(new SelectionAdapter() {
  				public void widgetSelected(SelectionEvent e) {
  					comboSelected(((Combo)e.widget).getSelectionIndex());
  				}
  			});
  		}
  		
  		protected void comboSelected(int index) {
  			getPreferences().put(getKey(), fValues[index]);
  			setChanged();
  			notifyObservers(fValues[index]);
  		}
  		
  		protected void updateWidget() {
  			if (getKey() != null) {
  				fCombo.setEnabled(getEnabled());
  				fCombo.setText(getSelectedItem());
  			} else {
  				fCombo.setText(""); //$NON-NLS-1$
  				fCombo.setEnabled(false);
  			}
  		}
  		
  		public String getSelectedItem() {
  			final String selected= (String)getPreferences().get(getKey());
  			for (int i= 0; i < fValues.length; i++) {
  				if (fValues[i].equals(selected)) {
  					return fItems[i];
  				}
  			}
  			return ""; //$NON-NLS-1$
  		}
  		
  		public boolean hasValue(String value) {
  			return value.equals(getPreferences().get(getKey()));
  		}
  		
  		public Control getControl() {
  			return fCombo;
  		}
  	}
  	
  	/**
  	 * Wrapper around a textfied which requests an integer input of a given range.
  	 */
  	protected final class NumberPreference extends Preference {
  		
  		private final int fMinValue, fMaxValue;
  		private final Label fNumberLabel;
  		private final Text fNumberText;
  
  		protected int fSelected;
          protected int fOldSelected;
          
          
  		/**
  		 * Create a new NumberPreference.
  		 * @param composite The composite on which the SWT widgets are added.
  		 * @param numColumns The number of columns in the composite's GridLayout.
  		 * @param preferences The map to store the values.
  		 * @param key The key to store the values.
  		 * @param minValue The minimum value which is valid input.
  		 * @param maxValue The maximum value which is valid input.
  		 * @param text The label text for this Preference.
  		 */
  		public NumberPreference(Composite composite, int numColumns,
  							   Map preferences, String key, 
  							   int minValue, int maxValue, String text) {
  		    super(preferences, key);
  		    
  			fNumberLabel= createLabel(numColumns - 1, composite, text, GridData.FILL_HORIZONTAL);
  			fNumberText= new Text(composite, SWT.SINGLE | SWT.BORDER | SWT.RIGHT);
  			fNumberText.setFont(composite.getFont());
  
  			final int length= Integer.toString(maxValue).length() + 3; 
  			fNumberText.setLayoutData(createGridData(1, GridData.HORIZONTAL_ALIGN_END, fPixelConverter.convertWidthInCharsToPixels(length)));
  			
  			fMinValue= minValue;
  			fMaxValue= maxValue;
  			
  			updateWidget();
  			
  			fNumberText.addFocusListener(new FocusListener() {
  				public void focusGained(FocusEvent e) {
  				    NumberPreference.this.focusGained();
  				}
                  public void focusLost(FocusEvent e) {
  				    NumberPreference.this.focusLost();
  				}
  			});
  			
  			fNumberText.addModifyListener(new ModifyListener() {
  				public void modifyText(ModifyEvent e) {
  					fieldModified();
  				}
  			});
  		}
  		
  		private IStatus createErrorStatus() {
  		    return new Status(IStatus.ERROR, JavaScriptPlugin.getPluginId(), 0, Messages.format(FormatterMessages.ModifyDialogTabPage_NumberPreference_error_invalid_value, new String [] {Integer.toString(fMinValue), Integer.toString(fMaxValue)}), null); 
  		    
  		}
  
  		protected void focusGained() {
  		    fOldSelected= fSelected;
  		    fNumberText.setSelection(0, fNumberText.getCharCount());
  		}
  		
  		protected void focusLost() {
  		    updateStatus(null);
  		    final String input= fNumberText.getText();
  		    if (!validInput(input))
  		        fSelected= fOldSelected;
  		    else
  		        fSelected= Integer.parseInt(input);
  		    if (fSelected != fOldSelected) {
  		    	saveSelected();
  		    	fNumberText.setText(Integer.toString(fSelected));
  		    }
  		}
  		
  		
  		protected void fieldModified() {
  		    final String trimInput= fNumberText.getText().trim();
  		    final boolean valid= validInput(trimInput);
  		    
  		    updateStatus(valid ? null : createErrorStatus());
  
  		    if (valid) {
  		        final int number= Integer.parseInt(trimInput);
  		        if (fSelected != number) {
  		            fSelected= number;
  		            saveSelected();
  		        }
  		    }
  		}
  		
  		private boolean validInput(String trimInput) {
  		    int number;
  		    
  		    try {
  		        number= Integer.parseInt(trimInput);
  		    } catch (NumberFormatException x) {
  		        return false;
  		    }
  		    
  		    if (number < fMinValue) return false;
  		    if (number > fMaxValue) return false;
  		    return true;
  		}
  		
  		private void saveSelected() {
  			getPreferences().put(getKey(), Integer.toString(fSelected));
  			setChanged();
  			notifyObservers();
  		}
  		
  		protected void updateWidget() {
  		    final boolean hasKey= getKey() != null;
  
  		    fNumberLabel.setEnabled(hasKey && getEnabled());
  			fNumberText.setEnabled(hasKey && getEnabled());
  
  			if (hasKey) {
  			    String s= (String)getPreferences().get(getKey());
  			    try {
  			        fSelected= Integer.parseInt(s);
  			    } catch (NumberFormatException e) {
  			        final String message= Messages.format(FormatterMessages.ModifyDialogTabPage_NumberPreference_error_invalid_key, getKey()); 
  			        JavaScriptPlugin.log(new Status(IStatus.ERROR, JavaScriptPlugin.getPluginId(), IStatus.OK, message, e));
  			        s= ""; //$NON-NLS-1$
  			    }
  			    fNumberText.setText(s);
  			} else {
  			    fNumberText.setText(""); //$NON-NLS-1$
  			}
  		}
  		
  		public Control getControl() {
  			return fNumberText;
  		}
  	}
  
  	
  	/**
  	 * This class provides the default way to preserve and re-establish the focus
  	 * over multiple modify sessions. Each ModifyDialogTabPage has its own instance,
  	 * and it should add all relevant controls upon creation, always in the same sequence.
  	 * This established a mapping of controls to indexes, which allows to restore the focus
  	 * in a later session. 
  	 * The index is saved in the dialog settings, and there is only one common preference for 
  	 * all tab pages. It is always the currently active tab page which stores its focus
  	 * index. 
  	 */
  	protected final static class DefaultFocusManager extends FocusAdapter {
  		
  		private final static String PREF_LAST_FOCUS_INDEX= JavaScriptUI.ID_PLUGIN + "formatter_page.modify_dialog_tab_page.last_focus_index"; //$NON-NLS-1$ 
  		
  		private final IDialogSettings fDialogSettings;
  		
  		private final Map fItemMap;
  		private final List fItemList;
  		
  		private int fIndex;
  		
  		public DefaultFocusManager() {
  			fDialogSettings= JavaScriptPlugin.getDefault().getDialogSettings();
  			fItemMap= new HashMap();
  			fItemList= new ArrayList();
  			fIndex= 0;
  		}
  
  		public void focusGained(FocusEvent e) {
  			fDialogSettings.put(PREF_LAST_FOCUS_INDEX, ((Integer)fItemMap.get(e.widget)).intValue());
  		}
  		
  		public void add(Control control) {
  			control.addFocusListener(this);
  			fItemList.add(fIndex, control);
  			fItemMap.put(control, Integer.valueOf(fIndex++));
  		}
  		
  		public void add(Preference preference) {
  			final Control control= preference.getControl();
  			if (control != null) 
  				add(control);
  		}
  		
  		public boolean isUsed() {
  			return fIndex != 0;
  		}
  		
  		public void restoreFocus() {
  			int index= 0;
  			try {
  				index= fDialogSettings.getInt(PREF_LAST_FOCUS_INDEX);
  				// make sure the value is within the range
  				if ((index >= 0) && (index <= fItemList.size() - 1)) {
  					((Control)fItemList.get(index)).setFocus();
  				}
  			} catch (NumberFormatException ex) {
  				// this is the first time
  			}
  		}
  		
  		public void resetFocus() {
  			fDialogSettings.put(PREF_LAST_FOCUS_INDEX, -1);
  		}
  	}
  
  	/**
  	 * The default focus manager. This widget knows all widgets which can have the focus
  	 * and listens for focusGained events, on which it stores the index of the current
  	 * focus holder. When the dialog is restarted, <code>restoreFocus()</code> sets the 
  	 * focus to the last control which had it.
  	 * 
  	 * The standard Preference object are managed by this focus manager if they are created
  	 * using the respective factory methods. Other SWT widgets can be added in subclasses 
  	 * when they are created.
  	 */
  	protected final DefaultFocusManager fDefaultFocusManager;
  
  	/**
  	 * A pixel converter for layout calculations
  	 */
  	protected PixelConverter fPixelConverter;
  	
  	
  	/**
  	 * The map where the current settings are stored.
  	 */
  	protected final Map fWorkingValues;
  	
  	/**
  	 * The modify dialog where we can display status messages.
  	 */
  	private final IModificationListener fModifyListener;
  
  
  	/*
  	 * Create a new <code>ModifyDialogTabPage</code>
  	 */
  	public ModifyDialogTabPage(IModificationListener modifyListener, Map workingValues) {
  		fWorkingValues= workingValues;
  		fModifyListener= modifyListener;
  		fDefaultFocusManager= new DefaultFocusManager();
  	}
  	
  	/**
  	 * Create the contents of this tab page. Subclasses cannot override this, 
  	 * instead they must implement <code>doCreatePreferences</code>. <code>doCreatePreview</code> may also
  	 * be overridden as necessary.
  	 * @param parent The parent composite
  	 * @return Created content control
  	 */
  	public final Composite createContents(Composite parent) {
  		final int numColumns= 4;
  		
  		if (fPixelConverter == null) {
  		    fPixelConverter= new PixelConverter(parent);
  		}
  		
  		final SashForm fSashForm = new SashForm(parent, SWT.HORIZONTAL);
  		fSashForm.setFont(parent.getFont());
  		
  		final Composite settingsPane= new Composite(fSashForm, SWT.NONE);
  		settingsPane.setFont(fSashForm.getFont());
  		
  		final GridLayout layout= new GridLayout(numColumns, false);
  		layout.verticalSpacing= (int)(1.5 * fPixelConverter.convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING));
  		layout.horizontalSpacing= fPixelConverter.convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
  		layout.marginHeight= fPixelConverter.convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
  		layout.marginWidth= fPixelConverter.convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
  		settingsPane.setLayout(layout);
  		doCreatePreferences(settingsPane, numColumns);
  
  		final Composite previewPane= new Composite(fSashForm, SWT.NONE);
  		previewPane.setLayout(createGridLayout(numColumns, true));
  		previewPane.setFont(fSashForm.getFont());
  		doCreatePreviewPane(previewPane, numColumns);
  
  		initializePage();
  	
  		fSashForm.setWeights(new int [] {3, 3});
  		return fSashForm;
  	}
  	
  	/**
  	 * This method is called after all controls have been alloated, including the preview. 
  	 * It can be used to set the preview text and to create listeners.
  	 *
  	 */
  	protected abstract void initializePage();
  	
  
  	/**
  	 * Create the left side of the modify dialog. This is meant to be implemented by subclasses. 
  	 * @param composite Composite to create in
  	 * @param numColumns Number of columns to use
  	 */
  	protected abstract void doCreatePreferences(Composite composite, int numColumns);
  	
  
  	/**
  	 * Create the right side of the modify dialog. By default, the preview is displayed there.
  	 * Subclasses can override this method in order to customize the right-hand side of the 
  	 * dialog.
  	 * @param composite Composite to create in
  	 * @param numColumns Number of columns to use
  	 * @return Created composite
  	 */
  	protected Composite doCreatePreviewPane(Composite composite, int numColumns) {
  		
  		createLabel(numColumns, composite, FormatterMessages.ModifyDialogTabPage_preview_label_text);  
  		
  		final JavaPreview preview= doCreateJavaPreview(composite);
  		fDefaultFocusManager.add(preview.getControl());
  		
  		final GridData gd= createGridData(numColumns, GridData.FILL_BOTH, 0);
  		gd.widthHint= 0;
  		gd.heightHint=0;
  		preview.getControl().setLayoutData(gd);
  		
  		return composite;
  	}
  
  
  	/**
  	 * To be implemented by subclasses. This method should return an instance of JavaPreview.
  	 * Currently, the choice is between CompilationUnitPreview which contains a valid compilation
  	 * unit, or a SnippetPreview which formats several independent code snippets and displays them 
  	 * in the same window.
  	 * @param parent Parent composite
  	 * @return Created preview
  	 */
  	protected abstract JavaPreview doCreateJavaPreview(Composite parent);
  
  	
  	/**
  	 * This is called when the page becomes visible. 
  	 * Common tasks to do include:
  	 * <ul><li>Updating the preview.</li>
  	 * <li>Setting the focus</li>
  	 * </ul>
  	 */
  	final public void makeVisible() {
  		fDefaultFocusManager.resetFocus();
  		doUpdatePreview();
  	}
  	
  	/**
  	 * Update the preview. To be implemented by subclasses.
  	 */
  	protected abstract void doUpdatePreview();
  	
  	protected void notifyValuesModified() {
  		fModifyListener.valuesModified();
  	}
      /**
       * Each tab page should remember where its last focus was, and reset it
       * correctly within this method. This method is only called after
       * initialization on the first tab page to be displayed in order to restore
       * the focus of the last session.
       */
      public void setInitialFocus() {
  		if (fDefaultFocusManager.isUsed()) {
  			fDefaultFocusManager.restoreFocus();
  		}
  	}
  	
  
      /**
       * Set the status field on the dialog. This can be used by tab pages to report 
       * inconsistent input. The OK button is disabled if the kind is IStatus.ERROR. 
       * @param status Status describing the current page error state
       */
  	protected void updateStatus(IStatus status) {
  		fModifyListener.updateStatus(status);
  	}
  	
  	/*
  	 * Factory methods to make GUI construction easier
  	 */
  	
  	/*
  	 * Create a GridLayout with the default margin and spacing settings, as
  	 * well as the specified number of columns.
  	 */
  	protected GridLayout createGridLayout(int numColumns, boolean margins) {
  		final GridLayout layout= new GridLayout(numColumns, false);
  		layout.verticalSpacing= fPixelConverter.convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
  		layout.horizontalSpacing= fPixelConverter.convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
  		if (margins) {
  			layout.marginHeight= fPixelConverter.convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
  			layout.marginWidth= fPixelConverter.convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
  		} else {
  			layout.marginHeight= 0;
  			layout.marginWidth= 0;
  		}
  		return layout;
  	}
  
  	/*
  	 * Convenience method to create a GridData.
  	 */
  	protected static GridData createGridData(int numColumns, int style, int widthHint) {
  		final GridData gd= new GridData(style);
  		gd.horizontalSpan= numColumns;
  		gd.widthHint= widthHint;
  		return gd;		
  	}
  
  
  	/* 
  	 * Convenience method to create a label.  
  	 */
  	protected static Label createLabel(int numColumns, Composite parent, String text) {
  		return createLabel(numColumns, parent, text, GridData.FILL_HORIZONTAL);
  	}
  	
  	/*
  	 * Convenience method to create a label
  	 */
  	protected static Label createLabel(int numColumns, Composite parent, String text, int gridDataStyle) {
  		final Label label= new Label(parent, SWT.WRAP);
  		label.setFont(parent.getFont());
  		label.setText(text);
  		
  		PixelConverter pixelConverter= new PixelConverter(parent);
  		label.setLayoutData(createGridData(numColumns, gridDataStyle, pixelConverter.convertHorizontalDLUsToPixels(150)));
  		return label;
  	}
  
  	/*
  	 * Convenience method to create a group
  	 */
  	protected Group createGroup(int numColumns, Composite parent, String text ) {
  		final Group group= new Group(parent, SWT.NONE);
  		group.setFont(parent.getFont());
  		group.setLayoutData(createGridData(numColumns, GridData.FILL_HORIZONTAL, SWT.DEFAULT));
  		
  		final GridLayout layout= new GridLayout(numColumns, false);
  		layout.verticalSpacing=  fPixelConverter.convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
  		layout.horizontalSpacing= fPixelConverter.convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
  		layout.marginHeight=  fPixelConverter.convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
  
  		//layout.marginHeight= fPixelConverter.convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
  		//layout.marginWidth= fPixelConverter.convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
  		
  		group.setLayout(layout);//createGridLayout(numColumns, true));
  		group.setText(text);
  		return group;
  	}
  	
  
  	/*
  	 * Convenience method to create a NumberPreference. The widget is registered as 
  	 * a potential focus holder, and the default updater is added.
  	 */
  	protected NumberPreference createNumberPref(Composite composite, int numColumns, String name, String key,
  												int minValue, int maxValue) {
  		final NumberPreference pref= new NumberPreference(composite, numColumns, fWorkingValues, 
  			key, minValue, maxValue, name);
  		fDefaultFocusManager.add(pref);
  		pref.addObserver(fUpdater);
  		return pref;
  	}
  	
  	/*
  	 * Convenience method to create a ComboPreference. The widget is registered as 
  	 * a potential focus holder, and the default updater is added.
  	 */
  	protected ComboPreference createComboPref(Composite composite, int numColumns, String name, 
  											  String key, String [] values, String [] items) {
  		final ComboPreference pref= new ComboPreference(composite, numColumns, 
  			fWorkingValues, key, values, name, items);
  		fDefaultFocusManager.add(pref);
  		pref.addObserver(fUpdater);
  		return pref;
  	}
  
  	/*
  	 * Convenience method to create a CheckboxPreference. The widget is registered as 
  	 * a potential focus holder, and the default updater is added.
  	 */
  	protected CheckboxPreference createCheckboxPref(Composite composite, int numColumns, String name, String key,
  													String [] values) {
  		final CheckboxPreference pref= new CheckboxPreference(composite, numColumns, 
  			fWorkingValues, key, values, name);
  		fDefaultFocusManager.add(pref);
  		pref.addObserver(fUpdater);
  		return pref;
  	}
  	
  	protected RadioPreference createRadioPref(Composite composite, int numColumns, String name, String key,
  			String [] values) {
  		final RadioPreference pref= new RadioPreference(composite, numColumns, 
  				fWorkingValues, key, values, name);
  		fDefaultFocusManager.add(pref);
  		pref.addObserver(fUpdater);
  		return pref;
  	}
  	
  
  	/*
  	 * Create a nice javadoc comment for some string.
  	 */
  	protected static String createPreviewHeader(String title) {
  		return "/**\n* " + title + "\n*/\n"; //$NON-NLS-1$ //$NON-NLS-2$
  	}	
  }
  