blob: 69c48b0069abe59cc3d0ab5705185a075b07c8bd [file] [log] [blame]
/* //device/tools/ddms/src/com/android/ddms/PrefsDialog.java
**
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
**
** 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.ddms;
import com.android.ddmlib.DdmPreferences;
import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
import com.android.ddmuilib.DdmUiPreferences;
import com.android.ddmuilib.PortFieldEditor;
import com.android.sdkstats.SdkStatsService;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.DirectoryFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.FontFieldEditor;
import org.eclipse.jface.preference.IntegerFieldEditor;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.preference.PreferenceManager;
import org.eclipse.jface.preference.PreferenceNode;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.preference.PreferenceStore;
import org.eclipse.jface.preference.RadioGroupFieldEditor;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Shell;
import java.io.File;
import java.io.IOException;
/**
* Preferences dialog.
*/
public final class PrefsDialog {
// Preference store.
private static PreferenceStore mPrefStore;
// public const values for storage
public final static String SHELL_X = "shellX"; //$NON-NLS-1$
public final static String SHELL_Y = "shellY"; //$NON-NLS-1$
public final static String SHELL_WIDTH = "shellWidth"; //$NON-NLS-1$
public final static String SHELL_HEIGHT = "shellHeight"; //$NON-NLS-1$
public final static String EXPLORER_SHELL_X = "explorerShellX"; //$NON-NLS-1$
public final static String EXPLORER_SHELL_Y = "explorerShellY"; //$NON-NLS-1$
public final static String EXPLORER_SHELL_WIDTH = "explorerShellWidth"; //$NON-NLS-1$
public final static String EXPLORER_SHELL_HEIGHT = "explorerShellHeight"; //$NON-NLS-1$
public final static String SHOW_NATIVE_HEAP = "native"; //$NON-NLS-1$
public final static String LOGCAT_COLUMN_MODE = "ddmsLogColumnMode"; //$NON-NLS-1$
public final static String LOGCAT_FONT = "ddmsLogFont"; //$NON-NLS-1$
public final static String LOGCAT_COLUMN_MODE_AUTO = "auto"; //$NON-NLS-1$
public final static String LOGCAT_COLUMN_MODE_MANUAL = "manual"; //$NON-NLS-1$
private final static String PREFS_DEBUG_PORT_BASE = "adbDebugBasePort"; //$NON-NLS-1$
private final static String PREFS_SELECTED_DEBUG_PORT = "debugSelectedPort"; //$NON-NLS-1$
private final static String PREFS_DEFAULT_THREAD_UPDATE = "defaultThreadUpdateEnabled"; //$NON-NLS-1$
private final static String PREFS_DEFAULT_HEAP_UPDATE = "defaultHeapUpdateEnabled"; //$NON-NLS-1$
private final static String PREFS_THREAD_REFRESH_INTERVAL = "threadStatusInterval"; //$NON-NLS-1$
private final static String PREFS_LOG_LEVEL = "ddmsLogLevel"; //$NON-NLS-1$
/**
* Private constructor -- do not instantiate.
*/
private PrefsDialog() {}
/**
* Return the PreferenceStore that holds our values.
*/
public static PreferenceStore getStore() {
return mPrefStore;
}
/**
* Save the prefs to the config file.
*/
public static void save() {
try {
mPrefStore.save();
}
catch (IOException ioe) {
Log.w("ddms", "Failed saving prefs file: " + ioe.getMessage());
}
}
/**
* Do some one-time prep.
*
* The original plan was to let the individual classes define their
* own defaults, which we would get and then override with the config
* file. However, PreferencesStore.load() doesn't trigger the "changed"
* events, which means we have to pull the loaded config values out by
* hand.
*
* So, we set the defaults, load the values from the config file, and
* then run through and manually export the values. Then we duplicate
* the second part later on for the "changed" events.
*/
public static void init() {
assert mPrefStore == null;
mPrefStore = SdkStatsService.getPreferenceStore();
if (mPrefStore == null) {
// we have a serious issue here...
Log.e("ddms",
"failed to access both the user HOME directory and the system wide temp folder. Quitting.");
System.exit(1);
}
// configure default values
setDefaults(System.getProperty("user.home")); //$NON-NLS-1$
// listen for changes
mPrefStore.addPropertyChangeListener(new ChangeListener());
// Now we initialize the value of the preference, from the values in the store.
// First the ddm lib.
DdmPreferences.setDebugPortBase(mPrefStore.getInt(PREFS_DEBUG_PORT_BASE));
DdmPreferences.setSelectedDebugPort(mPrefStore.getInt(PREFS_SELECTED_DEBUG_PORT));
DdmPreferences.setLogLevel(mPrefStore.getString(PREFS_LOG_LEVEL));
DdmPreferences.setInitialThreadUpdate(mPrefStore.getBoolean(PREFS_DEFAULT_THREAD_UPDATE));
DdmPreferences.setInitialHeapUpdate(mPrefStore.getBoolean(PREFS_DEFAULT_HEAP_UPDATE));
// some static values
String out = System.getenv("ANDROID_PRODUCT_OUT"); //$NON-NLS-1$
DdmUiPreferences.setSymbolsLocation(out + File.separator + "symbols"); //$NON-NLS-1$
DdmUiPreferences.setAddr2LineLocation("arm-eabi-addr2line"); //$NON-NLS-1$
String traceview = System.getProperty("com.android.ddms.bindir"); //$NON-NLS-1$
if (traceview != null && traceview.length() != 0) {
traceview += File.separator + "traceview"; //$NON-NLS-1$
} else {
traceview = "traceview"; //$NON-NLS-1$
}
DdmUiPreferences.setTraceviewLocation(traceview);
// Now the ddmui lib
DdmUiPreferences.setStore(mPrefStore);
DdmUiPreferences.setThreadRefreshInterval(mPrefStore.getInt(PREFS_THREAD_REFRESH_INTERVAL));
}
/*
* Set default values for all preferences. These are either defined
* statically or are based on the values set by the class initializers
* in other classes.
*
* The other threads (e.g. VMWatcherThread) haven't been created yet,
* so we want to use static values rather than reading fields from
* class.getInstance().
*/
private static void setDefaults(String homeDir) {
mPrefStore.setDefault(PREFS_DEBUG_PORT_BASE, DdmPreferences.DEFAULT_DEBUG_PORT_BASE);
mPrefStore.setDefault(PREFS_SELECTED_DEBUG_PORT,
DdmPreferences.DEFAULT_SELECTED_DEBUG_PORT);
mPrefStore.setDefault(PREFS_DEFAULT_THREAD_UPDATE, true);
mPrefStore.setDefault(PREFS_DEFAULT_HEAP_UPDATE, false);
mPrefStore.setDefault(PREFS_THREAD_REFRESH_INTERVAL,
DdmUiPreferences.DEFAULT_THREAD_REFRESH_INTERVAL);
mPrefStore.setDefault("textSaveDir", homeDir); //$NON-NLS-1$
mPrefStore.setDefault("imageSaveDir", homeDir); //$NON-NLS-1$
mPrefStore.setDefault(PREFS_LOG_LEVEL, "info"); //$NON-NLS-1$
// choose a default font for the text output
FontData fdat = new FontData("Courier", 10, SWT.NORMAL); //$NON-NLS-1$
mPrefStore.setDefault("textOutputFont", fdat.toString()); //$NON-NLS-1$
// layout information.
mPrefStore.setDefault(SHELL_X, 100);
mPrefStore.setDefault(SHELL_Y, 100);
mPrefStore.setDefault(SHELL_WIDTH, 800);
mPrefStore.setDefault(SHELL_HEIGHT, 600);
mPrefStore.setDefault(EXPLORER_SHELL_X, 50);
mPrefStore.setDefault(EXPLORER_SHELL_Y, 50);
mPrefStore.setDefault(SHOW_NATIVE_HEAP, false);
}
/*
* Create a "listener" to take action when preferences change. These are
* required for ongoing activities that don't check prefs on each use.
*
* This is only invoked when something explicitly changes the value of
* a preference (e.g. not when the prefs file is loaded).
*/
private static class ChangeListener implements IPropertyChangeListener {
public void propertyChange(PropertyChangeEvent event) {
String changed = event.getProperty();
if (changed.equals(PREFS_DEBUG_PORT_BASE)) {
DdmPreferences.setDebugPortBase(mPrefStore.getInt(PREFS_DEBUG_PORT_BASE));
} else if (changed.equals(PREFS_SELECTED_DEBUG_PORT)) {
DdmPreferences.setSelectedDebugPort(mPrefStore.getInt(PREFS_SELECTED_DEBUG_PORT));
} else if (changed.equals(PREFS_LOG_LEVEL)) {
DdmPreferences.setLogLevel((String)event.getNewValue());
} else if (changed.equals("textSaveDir")) {
mPrefStore.setValue("lastTextSaveDir",
(String) event.getNewValue());
} else if (changed.equals("imageSaveDir")) {
mPrefStore.setValue("lastImageSaveDir",
(String) event.getNewValue());
} else {
Log.v("ddms", "Preference change: " + event.getProperty()
+ ": '" + event.getOldValue()
+ "' --> '" + event.getNewValue() + "'");
}
}
}
/**
* Create and display the dialog.
*/
public static void run(Shell shell) {
assert mPrefStore != null;
PreferenceManager prefMgr = new PreferenceManager();
PreferenceNode node, subNode;
// this didn't work -- got NPE, possibly from class lookup:
//PreferenceNode app = new PreferenceNode("app", "Application", null,
// AppPrefs.class.getName());
node = new PreferenceNode("client", new ClientPrefs());
prefMgr.addToRoot(node);
subNode = new PreferenceNode("panel", new PanelPrefs());
//prefMgr.addTo(node.getId(), subNode);
prefMgr.addToRoot(subNode);
node = new PreferenceNode("device", new DevicePrefs());
prefMgr.addToRoot(node);
node = new PreferenceNode("LogCat", new LogCatPrefs());
prefMgr.addToRoot(node);
node = new PreferenceNode("app", new AppPrefs());
prefMgr.addToRoot(node);
node = new PreferenceNode("stats", new UsageStatsPrefs());
prefMgr.addToRoot(node);
PreferenceDialog dlg = new PreferenceDialog(shell, prefMgr);
dlg.setPreferenceStore(mPrefStore);
// run it
dlg.open();
// save prefs
try {
mPrefStore.save();
}
catch (IOException ioe) {
}
// discard the stuff we created
//prefMgr.dispose();
//dlg.dispose();
}
/**
* "Client Scan" prefs page.
*/
private static class ClientPrefs extends FieldEditorPreferencePage {
/**
* Basic constructor.
*/
public ClientPrefs() {
super(GRID); // use "grid" layout so edit boxes line up
setTitle("Client Scan");
}
/**
* Create field editors.
*/
@Override
protected void createFieldEditors() {
IntegerFieldEditor ife;
ife = new PortFieldEditor(PREFS_DEBUG_PORT_BASE,
"ADB debugger base:", getFieldEditorParent());
addField(ife);
ife = new PortFieldEditor(PREFS_SELECTED_DEBUG_PORT,
"Debug selected VM:", getFieldEditorParent());
addField(ife);
}
}
/**
* "Panel" prefs page.
*/
private static class PanelPrefs extends FieldEditorPreferencePage {
/**
* Basic constructor.
*/
public PanelPrefs() {
super(FLAT); // use "flat" layout
setTitle("Info Panels");
}
/**
* Create field editors.
*/
@Override
protected void createFieldEditors() {
BooleanFieldEditor bfe;
IntegerFieldEditor ife;
bfe = new BooleanFieldEditor(PREFS_DEFAULT_THREAD_UPDATE,
"Thread updates enabled by default", getFieldEditorParent());
addField(bfe);
bfe = new BooleanFieldEditor(PREFS_DEFAULT_HEAP_UPDATE,
"Heap updates enabled by default", getFieldEditorParent());
addField(bfe);
ife = new IntegerFieldEditor(PREFS_THREAD_REFRESH_INTERVAL,
"Thread status interval (seconds):", getFieldEditorParent());
ife.setValidRange(1, 60);
addField(ife);
}
}
/**
* "Device" prefs page.
*/
private static class DevicePrefs extends FieldEditorPreferencePage {
/**
* Basic constructor.
*/
public DevicePrefs() {
super(FLAT); // use "flat" layout
setTitle("Device");
}
/**
* Create field editors.
*/
@Override
protected void createFieldEditors() {
DirectoryFieldEditor dfe;
FontFieldEditor ffe;
dfe = new DirectoryFieldEditor("textSaveDir",
"Default text save dir:", getFieldEditorParent());
addField(dfe);
dfe = new DirectoryFieldEditor("imageSaveDir",
"Default image save dir:", getFieldEditorParent());
addField(dfe);
ffe = new FontFieldEditor("textOutputFont", "Text output font:",
getFieldEditorParent());
addField(ffe);
}
}
/**
* "logcat" prefs page.
*/
private static class LogCatPrefs extends FieldEditorPreferencePage {
/**
* Basic constructor.
*/
public LogCatPrefs() {
super(FLAT); // use "flat" layout
setTitle("Logcat");
}
/**
* Create field editors.
*/
@Override
protected void createFieldEditors() {
RadioGroupFieldEditor rgfe;
rgfe = new RadioGroupFieldEditor(PrefsDialog.LOGCAT_COLUMN_MODE,
"Message Column Resizing Mode", 1, new String[][] {
{ "Manual", PrefsDialog.LOGCAT_COLUMN_MODE_MANUAL },
{ "Automatic", PrefsDialog.LOGCAT_COLUMN_MODE_AUTO },
},
getFieldEditorParent(), true);
addField(rgfe);
FontFieldEditor ffe = new FontFieldEditor(PrefsDialog.LOGCAT_FONT, "Text output font:",
getFieldEditorParent());
addField(ffe);
}
}
/**
* "Application" prefs page.
*/
private static class AppPrefs extends FieldEditorPreferencePage {
/**
* Basic constructor.
*/
public AppPrefs() {
super(FLAT); // use "flat" layout
setTitle("DDMS");
}
/**
* Create field editors.
*/
@Override
protected void createFieldEditors() {
RadioGroupFieldEditor rgfe;
rgfe = new RadioGroupFieldEditor(PREFS_LOG_LEVEL,
"Logging Level", 1, new String[][] {
{ "Verbose", LogLevel.VERBOSE.getStringValue() },
{ "Debug", LogLevel.DEBUG.getStringValue() },
{ "Info", LogLevel.INFO.getStringValue() },
{ "Warning", LogLevel.WARN.getStringValue() },
{ "Error", LogLevel.ERROR.getStringValue() },
{ "Assert", LogLevel.ASSERT.getStringValue() },
},
getFieldEditorParent(), true);
addField(rgfe);
}
}
/**
* "Device" prefs page.
*/
private static class UsageStatsPrefs extends PreferencePage {
private BooleanFieldEditor mOptInCheckbox;
private Composite mTop;
/**
* Basic constructor.
*/
public UsageStatsPrefs() {
setTitle("Usage Stats");
}
@Override
protected Control createContents(Composite parent) {
mTop = new Composite(parent, SWT.NONE);
mTop.setLayout(new GridLayout(1, false));
mTop.setLayoutData(new GridData(GridData.FILL_BOTH));
Link text = new Link(mTop, SWT.WRAP);
text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
text.setText(SdkStatsService.BODY_TEXT);
text.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
SdkStatsService.openUrl(event.text);
}
});
mOptInCheckbox = new BooleanFieldEditor(SdkStatsService.PING_OPT_IN,
SdkStatsService.CHECKBOX_TEXT, mTop);
mOptInCheckbox.setPage(this);
mOptInCheckbox.setPreferenceStore(getPreferenceStore());
mOptInCheckbox.load();
return null;
}
@Override
protected Point doComputeSize() {
if (mTop != null) {
return mTop.computeSize(450, SWT.DEFAULT, true);
}
return super.doComputeSize();
}
@Override
protected void performDefaults() {
if (mOptInCheckbox != null) {
mOptInCheckbox.loadDefault();
}
super.performDefaults();
}
@Override
public void performApply() {
if (mOptInCheckbox != null) {
mOptInCheckbox.store();
}
super.performApply();
}
@Override
public boolean performOk() {
if (mOptInCheckbox != null) {
mOptInCheckbox.store();
}
return super.performOk();
}
}
}