| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Eclipse Public License, Version 1.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.eclipse.org/org/documents/epl-v10.php |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.ide.eclipse.adt.internal.preferences; |
| |
| import com.android.ide.eclipse.adt.AdtPlugin; |
| import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler; |
| import com.android.ide.eclipse.adt.internal.sdk.Sdk; |
| import com.android.ide.eclipse.adt.internal.sdk.Sdk.ITargetChangeListener; |
| import com.android.sdklib.IAndroidTarget; |
| import com.android.sdkstats.DdmsPreferenceStore; |
| import com.android.sdkstats.SdkStatsService; |
| import com.android.sdkuilib.internal.widgets.SdkTargetSelector; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.jface.preference.DirectoryFieldEditor; |
| import org.eclipse.jface.preference.FieldEditorPreferencePage; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| import org.eclipse.ui.IWorkbench; |
| import org.eclipse.ui.IWorkbenchPreferencePage; |
| |
| import java.io.File; |
| |
| /** |
| * This class represents a preference page that is contributed to the |
| * Preferences dialog. By subclassing <samp>FieldEditorPreferencePage</samp>, |
| * we can use the field support built into JFace that allows us to create a page |
| * that is small and knows how to save, restore and apply itself. |
| * <p> |
| * This page is used to modify preferences only. They are stored in the |
| * preference store that belongs to the main plug-in class. That way, |
| * preferences can be accessed directly via the preference store. |
| */ |
| |
| public class AndroidPreferencePage extends FieldEditorPreferencePage implements |
| IWorkbenchPreferencePage { |
| |
| private SdkDirectoryFieldEditor mDirectoryField; |
| |
| public AndroidPreferencePage() { |
| super(GRID); |
| setPreferenceStore(AdtPlugin.getDefault().getPreferenceStore()); |
| setDescription(Messages.AndroidPreferencePage_Title); |
| } |
| |
| /** |
| * Creates the field editors. Field editors are abstractions of the common |
| * GUI blocks needed to manipulate various types of preferences. Each field |
| * editor knows how to save and restore itself. |
| */ |
| @Override |
| public void createFieldEditors() { |
| |
| mDirectoryField = new SdkDirectoryFieldEditor(AdtPrefs.PREFS_SDK_DIR, |
| Messages.AndroidPreferencePage_SDK_Location_, getFieldEditorParent()); |
| |
| addField(mDirectoryField); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) |
| */ |
| @Override |
| public void init(IWorkbench workbench) { |
| } |
| |
| @Override |
| public void dispose() { |
| super.dispose(); |
| |
| if (mDirectoryField != null) { |
| mDirectoryField.dispose(); |
| mDirectoryField = null; |
| } |
| } |
| |
| /** |
| * Custom version of DirectoryFieldEditor which validates that the directory really |
| * contains an SDK. |
| * |
| * There's a known issue here, which is really a rare edge-case: if the pref dialog is open |
| * which a given sdk directory and the *content* of the directory changes such that the sdk |
| * state changed (i.e. from valid to invalid or vice versa), the pref panel will display or |
| * hide the error as appropriate but the pref panel will fail to validate the apply/ok buttons |
| * appropriately. The easy workaround is to cancel the pref panel and enter it again. |
| */ |
| private static class SdkDirectoryFieldEditor extends DirectoryFieldEditor { |
| |
| private SdkTargetSelector mTargetSelector; |
| private TargetChangedListener mTargetChangeListener; |
| |
| public SdkDirectoryFieldEditor(String name, String labelText, Composite parent) { |
| super(name, labelText, parent); |
| setEmptyStringAllowed(false); |
| } |
| |
| /** |
| * Method declared on StringFieldEditor and overridden in DirectoryFieldEditor. |
| * Checks whether the text input field contains a valid directory. |
| * |
| * @return True if the apply/ok button should be enabled in the pref panel |
| */ |
| @Override |
| protected boolean doCheckState() { |
| String fileName = getTextControl().getText(); |
| fileName = fileName.trim(); |
| |
| if (fileName.indexOf(',') >= 0 || fileName.indexOf(';') >= 0) { |
| setErrorMessage(Messages.AndroidPreferencePage_ERROR_Reserved_Char); |
| return false; // Apply/OK must be disabled |
| } |
| |
| File file = new File(fileName); |
| if (!file.isDirectory()) { |
| setErrorMessage(JFaceResources.getString( |
| "DirectoryFieldEditor.errorMessage")); //$NON-NLS-1$ |
| return false; |
| } |
| |
| boolean ok = AdtPlugin.getDefault().checkSdkLocationAndId(fileName, |
| new AdtPlugin.CheckSdkErrorHandler() { |
| @Override |
| public boolean handleError( |
| CheckSdkErrorHandler.Solution solution, |
| String message) { |
| setErrorMessage(message.replaceAll("\n", " ")); //$NON-NLS-1$ //$NON-NLS-2$ |
| return false; // Apply/OK must be disabled |
| } |
| |
| @Override |
| public boolean handleWarning( |
| CheckSdkErrorHandler.Solution solution, |
| String message) { |
| showMessage(message.replaceAll("\n", " ")); //$NON-NLS-1$ //$NON-NLS-2$ |
| return true; // Apply/OK must be enabled |
| } |
| }); |
| if (ok) clearMessage(); |
| return ok; |
| } |
| |
| @Override |
| protected void doStore() { |
| super.doStore(); |
| |
| // Also sync the value to the ~/.android preference settings such that we can |
| // share it with future new workspaces |
| String path = AdtPrefs.getPrefs().getOsSdkFolder(); |
| if (path != null && path.length() > 0 && new File(path).exists()) { |
| DdmsPreferenceStore ddmsStore = new DdmsPreferenceStore(); |
| ddmsStore.setLastSdkPath(path); |
| } |
| } |
| |
| @Override |
| public Text getTextControl(Composite parent) { |
| setValidateStrategy(VALIDATE_ON_KEY_STROKE); |
| return super.getTextControl(parent); |
| } |
| |
| /* (non-Javadoc) |
| * Method declared on StringFieldEditor (and FieldEditor). |
| */ |
| @Override |
| protected void doFillIntoGrid(Composite parent, int numColumns) { |
| super.doFillIntoGrid(parent, numColumns); |
| |
| GridData gd; |
| Label l = new Label(parent, SWT.NONE); |
| l.setText("Note: The list of SDK Targets below is only reloaded once you hit 'Apply' or 'OK'."); |
| gd = new GridData(GridData.FILL_HORIZONTAL); |
| gd.horizontalSpan = numColumns; |
| l.setLayoutData(gd); |
| |
| try { |
| // We may not have an sdk if the sdk path pref is empty or not valid. |
| Sdk sdk = Sdk.getCurrent(); |
| IAndroidTarget[] targets = sdk != null ? sdk.getTargets() : null; |
| |
| mTargetSelector = new SdkTargetSelector(parent, |
| targets, |
| false /*allowSelection*/); |
| gd = (GridData) mTargetSelector.getLayoutData(); |
| gd.horizontalSpan = numColumns; |
| |
| if (mTargetChangeListener == null) { |
| mTargetChangeListener = new TargetChangedListener(); |
| AdtPlugin.getDefault().addTargetListener(mTargetChangeListener); |
| |
| // Trigger a check to see if the SDK needs to be reloaded (which will |
| // invoke onSdkLoaded asynchronously as needed). |
| AdtPlugin.getDefault().refreshSdk(); |
| } |
| } catch (Exception e) { |
| // We need to catch *any* exception that arises here, otherwise it disables |
| // the whole pref panel. We can live without the Sdk target selector but |
| // not being able to actually set an sdk path. |
| AdtPlugin.log(e, "SdkTargetSelector failed"); |
| } |
| } |
| |
| @Override |
| public void dispose() { |
| super.dispose(); |
| if (mTargetChangeListener != null) { |
| AdtPlugin.getDefault().removeTargetListener(mTargetChangeListener); |
| mTargetChangeListener = null; |
| } |
| } |
| |
| private class TargetChangedListener implements ITargetChangeListener { |
| @Override |
| public void onSdkLoaded() { |
| if (mTargetSelector != null) { |
| // We may not have an sdk if the sdk path pref is empty or not valid. |
| Sdk sdk = Sdk.getCurrent(); |
| IAndroidTarget[] targets = sdk != null ? sdk.getTargets() : null; |
| |
| mTargetSelector.setTargets(targets); |
| } |
| } |
| |
| @Override |
| public void onProjectTargetChange(IProject changedProject) { |
| // do nothing. |
| } |
| |
| @Override |
| public void onTargetLoaded(IAndroidTarget target) { |
| // do nothing. |
| } |
| } |
| } |
| |
| @Override |
| public void setVisible(boolean visible) { |
| super.setVisible(visible); |
| |
| /* When the ADT preferences page is made visible, display the dialog to obtain |
| * permissions for the ping service. */ |
| SdkStatsService stats = new SdkStatsService(); |
| Shell parent = getShell(); |
| stats.checkUserPermissionForPing(parent); |
| } |
| } |