2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.eclipse.org/org/documents/epl-v10.php
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.
17 package com.android.ide.eclipse.adt.internal.preferences;
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;
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;
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.
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.
50 public class AndroidPreferencePage extends FieldEditorPreferencePage implements
51 IWorkbenchPreferencePage {
53 private SdkDirectoryFieldEditor mDirectoryField;
55 public AndroidPreferencePage() {
57 setPreferenceStore(AdtPlugin.getDefault().getPreferenceStore());
58 setDescription(Messages.AndroidPreferencePage_Title);
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.
67 public void createFieldEditors() {
69 mDirectoryField = new SdkDirectoryFieldEditor(AdtPrefs.PREFS_SDK_DIR,
70 Messages.AndroidPreferencePage_SDK_Location_, getFieldEditorParent());
72 addField(mDirectoryField);
78 * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
80 public void init(IWorkbench workbench) {
84 public void dispose() {
87 if (mDirectoryField != null) {
88 mDirectoryField.dispose();
89 mDirectoryField = null;
94 * Custom version of DirectoryFieldEditor which validates that the directory really
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.
103 private static class SdkDirectoryFieldEditor extends DirectoryFieldEditor {
105 private SdkTargetSelector mTargetSelector;
106 private TargetChangedListener mTargetChangeListener;
108 public SdkDirectoryFieldEditor(String name, String labelText, Composite parent) {
109 super(name, labelText, parent);
110 setEmptyStringAllowed(false);
114 * Method declared on StringFieldEditor and overridden in DirectoryFieldEditor.
115 * Checks whether the text input field contains a valid directory.
117 * @return True if the apply/ok button should be enabled in the pref panel
120 protected boolean doCheckState() {
121 String fileName = getTextControl().getText();
122 fileName = fileName.trim();
124 if (fileName.indexOf(',') >= 0 || fileName.indexOf(';') >= 0) {
125 setErrorMessage(Messages.AndroidPreferencePage_ERROR_Reserved_Char);
126 return false; // Apply/OK must be disabled
129 File file = new File(fileName);
130 if (!file.isDirectory()) {
131 setErrorMessage(JFaceResources.getString(
132 "DirectoryFieldEditor.errorMessage")); //$NON-NLS-1$
136 boolean ok = AdtPlugin.getDefault().checkSdkLocationAndId(fileName,
137 new AdtPlugin.CheckSdkErrorHandler() {
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
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
150 if (ok) clearMessage();
155 public Text getTextControl(Composite parent) {
156 setValidateStrategy(VALIDATE_ON_KEY_STROKE);
157 return super.getTextControl(parent);
161 * Method declared on StringFieldEditor (and FieldEditor).
164 protected void doFillIntoGrid(Composite parent, int numColumns) {
165 super.doFillIntoGrid(parent, numColumns);
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;
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;
179 mTargetSelector = new SdkTargetSelector(parent,
181 false /*allowSelection*/);
182 gd = (GridData) mTargetSelector.getLayoutData();
183 gd.horizontalSpan = numColumns;
185 if (mTargetChangeListener == null) {
186 mTargetChangeListener = new TargetChangedListener();
187 AdtPlugin.getDefault().addTargetListener(mTargetChangeListener);
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");
198 public void dispose() {
200 if (mTargetChangeListener != null) {
201 AdtPlugin.getDefault().removeTargetListener(mTargetChangeListener);
202 mTargetChangeListener = null;
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;
213 mTargetSelector.setTargets(targets);
217 public void onProjectTargetChange(IProject changedProject) {
221 public void onTargetLoaded(IAndroidTarget target) {