1 /*******************************************************************************
 
   2  * Copyright (c) 2000, 2003 IBM Corporation and others.
 
   3  * All rights reserved. This program and the accompanying materials 
 
   4  * are made available under the terms of the Common Public License v1.0
 
   5  * which accompanies this distribution, and is available at
 
   6  * http://www.eclipse.org/legal/cpl-v10.html
 
   9  *     IBM Corporation - initial API and implementation
 
  10  *******************************************************************************/
 
  12 package net.sourceforge.phpdt.internal.ui.preferences;
 
  15 import java.util.HashMap;
 
  16 import java.util.Iterator;
 
  17 import java.util.Locale;
 
  21 import org.eclipse.core.runtime.IStatus;
 
  23 import org.eclipse.swt.SWT;
 
  24 import org.eclipse.swt.events.SelectionAdapter;
 
  25 import org.eclipse.swt.events.SelectionEvent;
 
  26 import org.eclipse.swt.events.SelectionListener;
 
  27 import org.eclipse.swt.layout.GridData;
 
  28 import org.eclipse.swt.layout.GridLayout;
 
  29 import org.eclipse.swt.widgets.Button;
 
  30 import org.eclipse.swt.widgets.Combo;
 
  31 import org.eclipse.swt.widgets.Composite;
 
  32 import org.eclipse.swt.widgets.Control;
 
  33 import org.eclipse.swt.widgets.FileDialog;
 
  34 import org.eclipse.swt.widgets.Group;
 
  35 import org.eclipse.swt.widgets.Label;
 
  36 import org.eclipse.swt.widgets.Text;
 
  38 import org.eclipse.jface.preference.IPreferenceStore;
 
  40 import net.sourceforge.phpdt.core.IJavaProject;
 
  42 import net.sourceforge.phpdt.ui.PreferenceConstants;
 
  44 import net.sourceforge.phpdt.internal.ui.dialogs.StatusInfo;
 
  45 import net.sourceforge.phpdt.internal.ui.dialogs.StatusUtil;
 
  46 import net.sourceforge.phpdt.internal.ui.text.spelling.SpellCheckEngine;
 
  47 import net.sourceforge.phpdt.internal.ui.util.PixelConverter;
 
  48 import net.sourceforge.phpdt.internal.ui.util.SWTUtil;
 
  49 import net.sourceforge.phpdt.internal.ui.wizards.IStatusChangeListener;
 
  52  * Options configuration block for spell-check related settings.
 
  56 public class SpellingConfigurationBlock extends OptionsConfigurationBlock {
 
  58         /** Preference keys for the preferences in this block */
 
  59         private static final String PREF_SPELLING_CHECK_SPELLING= PreferenceConstants.SPELLING_CHECK_SPELLING;
 
  60         private static final String PREF_SPELLING_IGNORE_DIGITS= PreferenceConstants.SPELLING_IGNORE_DIGITS;
 
  61         private static final String PREF_SPELLING_IGNORE_MIXED= PreferenceConstants.SPELLING_IGNORE_MIXED;
 
  62         private static final String PREF_SPELLING_IGNORE_SENTENCE= PreferenceConstants.SPELLING_IGNORE_SENTENCE;
 
  63         private static final String PREF_SPELLING_IGNORE_UPPER= PreferenceConstants.SPELLING_IGNORE_UPPER;
 
  64         private static final String PREF_SPELLING_IGNORE_URLS= PreferenceConstants.SPELLING_IGNORE_URLS;
 
  65         private static final String PREF_SPELLING_LOCALE= PreferenceConstants.SPELLING_LOCALE;
 
  66         private static final String PREF_SPELLING_PROPOSAL_THRESHOLD= PreferenceConstants.SPELLING_PROPOSAL_THRESHOLD;
 
  67         private static final String PREF_SPELLING_USER_DICTIONARY= PreferenceConstants.SPELLING_USER_DICTIONARY;
 
  68         private static final String PREF_SPELLING_ENABLE_CONTENTASSIST= PreferenceConstants.SPELLING_ENABLE_CONTENTASSIST;
 
  71          * Creates a selection dependency between a master and a slave control.
 
  74          *                   The master button that controls the state of the slave
 
  76          *                   The slave control that is enabled only if the master is
 
  79         protected static void createSelectionDependency(final Button master, final Control slave) {
 
  81                 master.addSelectionListener(new SelectionListener() {
 
  83                         public void widgetDefaultSelected(SelectionEvent event) {
 
  87                         public void widgetSelected(SelectionEvent event) {
 
  88                                 slave.setEnabled(master.getSelection());
 
  91                 slave.setEnabled(master.getSelection());
 
  95          * Returns the locale codes for the locale list.
 
  99          * @return Array of locale codes for the list
 
 101         protected static String[] getDictionaryCodes(final Set locales) {
 
 106                 final String[] codes= new String[locales.size()];
 
 107                 for (final Iterator iterator= locales.iterator(); iterator.hasNext();) {
 
 109                         locale= (Locale)iterator.next();
 
 110                         codes[index++]= locale.toString();
 
 116          * Returns the display labels for the locale list.
 
 119          *                   The list of locales
 
 120          * @return Array of display labels for the list
 
 122         protected static String[] getDictionaryLabels(final Set locales) {
 
 127                 final String[] labels= new String[locales.size()];
 
 128                 for (final Iterator iterator= locales.iterator(); iterator.hasNext();) {
 
 130                         locale= (Locale)iterator.next();
 
 131                         labels[index++]= locale.getDisplayName(SpellCheckEngine.getDefaultLocale());
 
 137          * Validates that the file with the specified absolute path exists and can
 
 141          *                   The path of the file to validate
 
 142          * @return <code>true</code> iff the file exists and can be opened,
 
 143          *               <code>false</code> otherwise
 
 145         protected static IStatus validateAbsoluteFilePath(final String path) {
 
 147                 final StatusInfo status= new StatusInfo();
 
 148                 if (path.length() > 0) {
 
 150                         final File file= new File(path);
 
 151                         if (!file.isFile() || !file.isAbsolute() || !file.exists() || !file.canRead() || !file.canWrite())
 
 152                                 status.setError(PreferencesMessages.getString("SpellingPreferencePage.dictionary.error")); //$NON-NLS-1$
 
 159          * Validates that the specified locale is available.
 
 162          *                   The locale to validate
 
 163          * @return The status of the validation
 
 165         protected static IStatus validateLocale(final String locale) {
 
 167                 final StatusInfo status= new StatusInfo(IStatus.ERROR, PreferencesMessages.getString("SpellingPreferencePage.locale.error")); //$NON-NLS-1$
 
 168                 final Set locales= SpellCheckEngine.getAvailableLocales();
 
 170                 Locale current= null;
 
 171                 for (final Iterator iterator= locales.iterator(); iterator.hasNext();) {
 
 173                         current= (Locale)iterator.next();
 
 174                         if (current.toString().equals(locale))
 
 175                                 return new StatusInfo();
 
 181          * Validates that the specified number is positive.
 
 184          *                   The number to validate
 
 185          * @return The status of the validation
 
 187         protected static IStatus validatePositiveNumber(final String number) {
 
 189                 final StatusInfo status= new StatusInfo();
 
 190                 if (number.length() == 0) {
 
 191                         status.setError(PreferencesMessages.getString("SpellingPreferencePage.empty_threshold")); //$NON-NLS-1$
 
 194                                 final int value= Integer.parseInt(number);
 
 196                                         status.setError(PreferencesMessages.getFormattedString("SpellingPreferencePage.invalid_threshold", number)); //$NON-NLS-1$
 
 198                         } catch (NumberFormatException exception) {
 
 199                                 status.setError(PreferencesMessages.getFormattedString("SpellingPreferencePage.invalid_threshold", number)); //$NON-NLS-1$
 
 205         /** The dictionary path field */
 
 206         private Text fDictionaryPath= null;
 
 208         /** The status for the workspace dictionary file */
 
 209         private IStatus fFileStatus= new StatusInfo();
 
 211         /** The status for the platform locale */
 
 212         private IStatus fLocaleStatus= new StatusInfo();
 
 214         /** The status for the proposal threshold */
 
 215         private IStatus fThresholdStatus= new StatusInfo();
 
 218          * Creates a new spelling configuration block.
 
 221          *                   The status change listener
 
 225         public SpellingConfigurationBlock(final IStatusChangeListener context, final IJavaProject project) {
 
 226                 super(context, project, getAllKeys());
 
 228                 IStatus status= validateAbsoluteFilePath((String)fWorkingValues.get(PREF_SPELLING_USER_DICTIONARY));
 
 229                 if (status.getSeverity() != IStatus.OK)
 
 230                         fWorkingValues.put(PREF_SPELLING_USER_DICTIONARY, ""); //$NON-NLS-1$
 
 232                 status= validateLocale((String)fWorkingValues.get(PREF_SPELLING_LOCALE));
 
 233                 if (status.getSeverity() != IStatus.OK)
 
 234                         fWorkingValues.put(PREF_SPELLING_LOCALE, SpellCheckEngine.getDefaultLocale().toString());
 
 237         protected Combo addComboBox(Composite parent, String label, String key, String[] values, String[] valueLabels, int indent) {
 
 238                 ControlData data= new ControlData(key, values);
 
 240                 GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
 
 241                 gd.horizontalIndent= indent;
 
 243                 Label labelControl= new Label(parent, SWT.LEFT | SWT.WRAP);
 
 244                 labelControl.setText(label);
 
 245                 labelControl.setLayoutData(gd);
 
 247                 Combo comboBox= new Combo(parent, SWT.READ_ONLY);
 
 248                 comboBox.setItems(valueLabels);
 
 249                 comboBox.setData(data);
 
 250                 gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
 
 251                 gd.horizontalSpan= 2;
 
 252                 comboBox.setLayoutData(gd);
 
 253                 comboBox.addSelectionListener(getSelectionListener());
 
 255                 fLabels.put(comboBox, labelControl);
 
 257                 String currValue= (String)fWorkingValues.get(key);      
 
 258                 comboBox.select(data.getSelection(currValue));
 
 260                 fComboBoxes.add(comboBox);
 
 265          * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#createContents(org.eclipse.swt.widgets.Composite)
 
 267         protected Control createContents(final Composite parent) {
 
 269                 Composite composite= new Composite(parent, SWT.NONE);
 
 270                 GridLayout layout= new GridLayout(); layout.numColumns= 1;
 
 271                 composite.setLayout(layout);
 
 273                 final PixelConverter converter= new PixelConverter(parent);
 
 275                 layout= new GridLayout();
 
 276                 layout.numColumns= 3;
 
 278                 final String[] trueFalse= new String[] { IPreferenceStore.TRUE, IPreferenceStore.FALSE };
 
 280                 Group user= new Group(composite, SWT.NONE);
 
 281                 user.setText(PreferencesMessages.getString("SpellingPreferencePage.preferences.user")); //$NON-NLS-1$
 
 282                 user.setLayout(new GridLayout());               
 
 283                 user.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 
 285                 String label= PreferencesMessages.getString("SpellingPreferencePage.enable.label"); //$NON-NLS-1$
 
 286                 final Button master= addCheckBox(user, label, PREF_SPELLING_CHECK_SPELLING, trueFalse, 0);
 
 288                 label= PreferencesMessages.getString("SpellingPreferencePage.ignore.digits.label"); //$NON-NLS-1$
 
 289                 Control slave= addCheckBox(user, label, PREF_SPELLING_IGNORE_DIGITS, trueFalse, 20);
 
 290                 createSelectionDependency(master, slave);
 
 292                 label= PreferencesMessages.getString("SpellingPreferencePage.ignore.mixed.label"); //$NON-NLS-1$
 
 293                 slave= addCheckBox(user, label, PREF_SPELLING_IGNORE_MIXED, trueFalse, 20);
 
 294                 createSelectionDependency(master, slave);
 
 296                 label= PreferencesMessages.getString("SpellingPreferencePage.ignore.sentence.label"); //$NON-NLS-1$
 
 297                 slave= addCheckBox(user, label, PREF_SPELLING_IGNORE_SENTENCE, trueFalse, 20);
 
 298                 createSelectionDependency(master, slave);
 
 300                 label= PreferencesMessages.getString("SpellingPreferencePage.ignore.upper.label"); //$NON-NLS-1$
 
 301                 slave= addCheckBox(user, label, PREF_SPELLING_IGNORE_UPPER, trueFalse, 20);
 
 302                 createSelectionDependency(master, slave);
 
 304                 label= PreferencesMessages.getString("SpellingPreferencePage.ignore.url.label"); //$NON-NLS-1$
 
 305                 slave= addCheckBox(user, label, PREF_SPELLING_IGNORE_URLS, trueFalse, 20);
 
 306                 createSelectionDependency(master, slave);
 
 308                 final Group engine= new Group(composite, SWT.NONE);
 
 309                 engine.setText(PreferencesMessages.getString("SpellingPreferencePage.preferences.engine")); //$NON-NLS-1$
 
 310                 layout= new GridLayout();
 
 311                 layout.numColumns= 4;
 
 312                 engine.setLayout(layout);
 
 313                 engine.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 
 315                 label= PreferencesMessages.getString("SpellingPreferencePage.dictionary.label"); //$NON-NLS-1$
 
 316                 final Set locales= SpellCheckEngine.getAvailableLocales();
 
 318                 Combo combo= addComboBox(engine, label, PREF_SPELLING_LOCALE, getDictionaryCodes(locales), getDictionaryLabels(locales), 0);
 
 319                 combo.setEnabled(locales.size() > 1);
 
 321                 new Label(engine, SWT.NONE); // placeholder
 
 323                 label= PreferencesMessages.getString("SpellingPreferencePage.workspace.dictionary.label"); //$NON-NLS-1$
 
 324                 fDictionaryPath= addTextField(engine, label, PREF_SPELLING_USER_DICTIONARY, 0, 0);
 
 327                 Button button= new Button(engine, SWT.PUSH);
 
 328                 button.setText(PreferencesMessages.getString("SpellingPreferencePage.browse.label")); //$NON-NLS-1$
 
 329                 button.addSelectionListener(new SelectionAdapter() {
 
 331                         public void widgetSelected(final SelectionEvent event) {
 
 332                                 handleBrowseButtonSelected();
 
 335                 button.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
 
 336                 SWTUtil.setButtonDimensionHint(button);
 
 338                 layout= new GridLayout();
 
 339                 layout.numColumns= 3;
 
 341                 Group advanced= new Group(composite, SWT.NONE);
 
 342                 advanced.setText(PreferencesMessages.getString("SpellingPreferencePage.preferences.advanced")); //$NON-NLS-1$
 
 343                 layout= new GridLayout();
 
 344                 layout.numColumns= 3;
 
 345                 advanced.setLayout(layout);             
 
 346                 advanced.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 
 348                 label= PreferencesMessages.getString("SpellingPreferencePage.proposals.threshold"); //$NON-NLS-1$
 
 349                 Text text= addTextField(advanced, label, PREF_SPELLING_PROPOSAL_THRESHOLD, 0, 0);
 
 350                 text.setTextLimit(3);
 
 351                 GridData data= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
 
 352                 data.widthHint= converter.convertWidthInCharsToPixels(4);
 
 353                 text.setLayoutData(data);
 
 355                 label= PreferencesMessages.getString("SpellingPreferencePage.enable.contentassist.label"); //$NON-NLS-1$
 
 356                 addCheckBox(advanced, label, PREF_SPELLING_ENABLE_CONTENTASSIST, trueFalse, 0);
 
 361         private static String[] getAllKeys() {
 
 362                 return new String[] { PREF_SPELLING_USER_DICTIONARY, PREF_SPELLING_CHECK_SPELLING, PREF_SPELLING_IGNORE_DIGITS, PREF_SPELLING_IGNORE_MIXED, PREF_SPELLING_IGNORE_SENTENCE, PREF_SPELLING_IGNORE_UPPER, PREF_SPELLING_IGNORE_URLS, PREF_SPELLING_LOCALE, PREF_SPELLING_PROPOSAL_THRESHOLD, PREF_SPELLING_ENABLE_CONTENTASSIST };
 
 366          * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#getDefaultOptions()
 
 368         protected Map getDefaultOptions() {
 
 370                 final String[] keys= fAllKeys;
 
 371                 final Map options= new HashMap();
 
 372                 final IPreferenceStore store= PreferenceConstants.getPreferenceStore();
 
 374                 for (int index= 0; index < keys.length; index++)
 
 375                         options.put(keys[index], store.getDefaultString(keys[index]));
 
 381          * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#getFullBuildDialogStrings(boolean)
 
 383         protected final String[] getFullBuildDialogStrings(final boolean workspace) {
 
 388          * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#getOptions(boolean)
 
 390         protected Map getOptions(final boolean inherit) {
 
 392                 final String[] keys= fAllKeys;
 
 393                 final Map options= new HashMap();
 
 394                 final IPreferenceStore store= PreferenceConstants.getPreferenceStore();
 
 396                 for (int index= 0; index < keys.length; index++)
 
 397                         options.put(keys[index], store.getString(keys[index]));
 
 403          * Handles selections of the browse button.
 
 405         protected void handleBrowseButtonSelected() {
 
 407                 final FileDialog dialog= new FileDialog(fDictionaryPath.getShell(), SWT.OPEN);
 
 408                 dialog.setText(PreferencesMessages.getString("SpellingPreferencePage.filedialog.title")); //$NON-NLS-1$
 
 409                 dialog.setFilterExtensions(new String[] { PreferencesMessages.getString("SpellingPreferencePage.filter.dictionary.extension"), PreferencesMessages.getString("SpellingPreferencePage.filter.all.extension") }); //$NON-NLS-1$ //$NON-NLS-2$
 
 410                 dialog.setFilterNames(new String[] { PreferencesMessages.getString("SpellingPreferencePage.filter.dictionary.label"), PreferencesMessages.getString("SpellingPreferencePage.filter.all.label") }); //$NON-NLS-1$ //$NON-NLS-2$
 
 412                 final String path= dialog.open();
 
 414                         fDictionaryPath.setText(path);
 
 418          * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#setOptions(java.util.Map)
 
 420         protected void setOptions(final Map options) {
 
 422                 final String[] keys= fAllKeys;
 
 423                 final IPreferenceStore store= PreferenceConstants.getPreferenceStore();
 
 425                 for (int index= 0; index < keys.length; index++)
 
 426                         store.setValue(keys[index], (String)fWorkingValues.get(keys[index]));
 
 430          * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#validateSettings(java.lang.String,java.lang.String)
 
 432         protected void validateSettings(final String key, final String value) {
 
 434                 if (key == null || PREF_SPELLING_PROPOSAL_THRESHOLD.equals(key))
 
 435                         fThresholdStatus= validatePositiveNumber((String)fWorkingValues.get(PREF_SPELLING_PROPOSAL_THRESHOLD));
 
 437                 if (key == null || PREF_SPELLING_USER_DICTIONARY.equals(key))
 
 438                         fFileStatus= validateAbsoluteFilePath((String)fWorkingValues.get(PREF_SPELLING_USER_DICTIONARY));
 
 440                 if (key == null || PREF_SPELLING_LOCALE.equals(key))
 
 441                         fLocaleStatus= validateLocale((String)fWorkingValues.get(PREF_SPELLING_LOCALE));
 
 443                 fContext.statusChanged(StatusUtil.getMostSevere(new IStatus[] { fThresholdStatus, fFileStatus, fLocaleStatus }));