blob: 4fbc013518e41887c332d4d95e75187599290f3f [file] [log] [blame]
/*
* 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);
}
}