Home | History | Annotate | Download | only in preferences
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ide.eclipse.adt.internal.preferences;
     18 
     19 import com.android.ide.eclipse.adt.AdtPlugin;
     20 import com.android.ide.eclipse.adt.internal.sdk.Sdk;
     21 import com.android.ide.eclipse.adt.internal.sdk.Sdk.ITargetChangeListener;
     22 import com.android.sdklib.IAndroidTarget;
     23 import com.android.sdkuilib.internal.widgets.SdkTargetSelector;
     24 
     25 import org.eclipse.core.resources.IProject;
     26 import org.eclipse.jface.preference.DirectoryFieldEditor;
     27 import org.eclipse.jface.preference.FieldEditorPreferencePage;
     28 import org.eclipse.jface.resource.JFaceResources;
     29 import org.eclipse.swt.SWT;
     30 import org.eclipse.swt.layout.GridData;
     31 import org.eclipse.swt.widgets.Composite;
     32 import org.eclipse.swt.widgets.Label;
     33 import org.eclipse.swt.widgets.Text;
     34 import org.eclipse.ui.IWorkbench;
     35 import org.eclipse.ui.IWorkbenchPreferencePage;
     36 
     37 import java.io.File;
     38 
     39 /**
     40  * This class represents a preference page that is contributed to the
     41  * Preferences dialog. By subclassing <samp>FieldEditorPreferencePage</samp>,
     42  * we can use the field support built into JFace that allows us to create a page
     43  * that is small and knows how to save, restore and apply itself.
     44  * <p>
     45  * This page is used to modify preferences only. They are stored in the
     46  * preference store that belongs to the main plug-in class. That way,
     47  * preferences can be accessed directly via the preference store.
     48  */
     49 
     50 public class AndroidPreferencePage extends FieldEditorPreferencePage implements
     51         IWorkbenchPreferencePage {
     52 
     53     private SdkDirectoryFieldEditor mDirectoryField;
     54 
     55     public AndroidPreferencePage() {
     56         super(GRID);
     57         setPreferenceStore(AdtPlugin.getDefault().getPreferenceStore());
     58         setDescription(Messages.AndroidPreferencePage_Title);
     59     }
     60 
     61     /**
     62      * Creates the field editors. Field editors are abstractions of the common
     63      * GUI blocks needed to manipulate various types of preferences. Each field
     64      * editor knows how to save and restore itself.
     65      */
     66     @Override
     67     public void createFieldEditors() {
     68 
     69         mDirectoryField = new SdkDirectoryFieldEditor(AdtPrefs.PREFS_SDK_DIR,
     70                 Messages.AndroidPreferencePage_SDK_Location_, getFieldEditorParent());
     71 
     72         addField(mDirectoryField);
     73     }
     74 
     75     /*
     76      * (non-Javadoc)
     77      *
     78      * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
     79      */
     80     public void init(IWorkbench workbench) {
     81     }
     82 
     83     @Override
     84     public void dispose() {
     85         super.dispose();
     86 
     87         if (mDirectoryField != null) {
     88             mDirectoryField.dispose();
     89             mDirectoryField = null;
     90         }
     91     }
     92 
     93     /**
     94      * Custom version of DirectoryFieldEditor which validates that the directory really
     95      * contains an SDK.
     96      *
     97      * There's a known issue here, which is really a rare edge-case: if the pref dialog is open
     98      * which a given sdk directory and the *content* of the directory changes such that the sdk
     99      * state changed (i.e. from valid to invalid or vice versa), the pref panel will display or
    100      * hide the error as appropriate but the pref panel will fail to validate the apply/ok buttons
    101      * appropriately. The easy workaround is to cancel the pref panel and enter it again.
    102      */
    103     private static class SdkDirectoryFieldEditor extends DirectoryFieldEditor {
    104 
    105         private SdkTargetSelector mTargetSelector;
    106         private TargetChangedListener mTargetChangeListener;
    107 
    108         public SdkDirectoryFieldEditor(String name, String labelText, Composite parent) {
    109             super(name, labelText, parent);
    110             setEmptyStringAllowed(false);
    111         }
    112 
    113         /**
    114          * Method declared on StringFieldEditor and overridden in DirectoryFieldEditor.
    115          * Checks whether the text input field contains a valid directory.
    116          *
    117          * @return True if the apply/ok button should be enabled in the pref panel
    118          */
    119         @Override
    120         protected boolean doCheckState() {
    121             String fileName = getTextControl().getText();
    122             fileName = fileName.trim();
    123 
    124             if (fileName.indexOf(',') >= 0 || fileName.indexOf(';') >= 0) {
    125                 setErrorMessage(Messages.AndroidPreferencePage_ERROR_Reserved_Char);
    126                 return false;  // Apply/OK must be disabled
    127             }
    128 
    129             File file = new File(fileName);
    130             if (!file.isDirectory()) {
    131                 setErrorMessage(JFaceResources.getString(
    132                     "DirectoryFieldEditor.errorMessage")); //$NON-NLS-1$
    133                 return false;
    134             }
    135 
    136             boolean ok = AdtPlugin.getDefault().checkSdkLocationAndId(fileName,
    137                     new AdtPlugin.CheckSdkErrorHandler() {
    138                 @Override
    139                 public boolean handleError(String message) {
    140                     setErrorMessage(message.replaceAll("\n", " ")); //$NON-NLS-1$ //$NON-NLS-2$
    141                     return false;  // Apply/OK must be disabled
    142                 }
    143 
    144                 @Override
    145                 public boolean handleWarning(String message) {
    146                     showMessage(message.replaceAll("\n", " ")); //$NON-NLS-1$ //$NON-NLS-2$
    147                     return true;  // Apply/OK must be enabled
    148                 }
    149             });
    150             if (ok) clearMessage();
    151             return ok;
    152         }
    153 
    154         @Override
    155         public Text getTextControl(Composite parent) {
    156             setValidateStrategy(VALIDATE_ON_KEY_STROKE);
    157             return super.getTextControl(parent);
    158         }
    159 
    160         /* (non-Javadoc)
    161          * Method declared on StringFieldEditor (and FieldEditor).
    162          */
    163         @Override
    164         protected void doFillIntoGrid(Composite parent, int numColumns) {
    165             super.doFillIntoGrid(parent, numColumns);
    166 
    167             GridData gd;
    168             Label l = new Label(parent, SWT.NONE);
    169             l.setText("Note: The list of SDK Targets below is only reloaded once you hit 'Apply' or 'OK'.");
    170             gd = new GridData(GridData.FILL_HORIZONTAL);
    171             gd.horizontalSpan = numColumns;
    172             l.setLayoutData(gd);
    173 
    174             try {
    175                 // We may not have an sdk if the sdk path pref is empty or not valid.
    176                 Sdk sdk = Sdk.getCurrent();
    177                 IAndroidTarget[] targets = sdk != null ? sdk.getTargets() : null;
    178 
    179                 mTargetSelector = new SdkTargetSelector(parent,
    180                         targets,
    181                         false /*allowSelection*/);
    182                 gd = (GridData) mTargetSelector.getLayoutData();
    183                 gd.horizontalSpan = numColumns;
    184 
    185                 if (mTargetChangeListener == null) {
    186                     mTargetChangeListener = new TargetChangedListener();
    187                     AdtPlugin.getDefault().addTargetListener(mTargetChangeListener);
    188                 }
    189             } catch (Exception e) {
    190                 // We need to catch *any* exception that arises here, otherwise it disables
    191                 // the whole pref panel. We can live without the Sdk target selector but
    192                 // not being able to actually set an sdk path.
    193                 AdtPlugin.log(e, "SdkTargetSelector failed");
    194             }
    195         }
    196 
    197         @Override
    198         public void dispose() {
    199             super.dispose();
    200             if (mTargetChangeListener != null) {
    201                 AdtPlugin.getDefault().removeTargetListener(mTargetChangeListener);
    202                 mTargetChangeListener = null;
    203             }
    204         }
    205 
    206         private class TargetChangedListener implements ITargetChangeListener {
    207             public void onSdkLoaded() {
    208                 if (mTargetSelector != null) {
    209                     // We may not have an sdk if the sdk path pref is empty or not valid.
    210                     Sdk sdk = Sdk.getCurrent();
    211                     IAndroidTarget[] targets = sdk != null ? sdk.getTargets() : null;
    212 
    213                     mTargetSelector.setTargets(targets);
    214                 }
    215             }
    216 
    217             public void onProjectTargetChange(IProject changedProject) {
    218                 // do nothing.
    219             }
    220 
    221             public void onTargetLoaded(IAndroidTarget target) {
    222                 // do nothing.
    223             }
    224         }
    225     }
    226 }
    227