1 /* 2 * Copyright (C) 2009 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 20 import com.android.ide.eclipse.adt.AdtPlugin; 21 import com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatStyle; 22 import com.android.prefs.AndroidLocation.AndroidLocationException; 23 import com.android.sdklib.internal.build.DebugKeyProvider; 24 import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException; 25 import com.android.sdkstats.DdmsPreferenceStore; 26 27 import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; 28 import org.eclipse.jface.preference.IPreferenceStore; 29 import org.eclipse.jface.util.PropertyChangeEvent; 30 31 import java.io.File; 32 33 public final class AdtPrefs extends AbstractPreferenceInitializer { 34 public final static String PREFS_SDK_DIR = AdtPlugin.PLUGIN_ID + ".sdk"; //$NON-NLS-1$ 35 36 public final static String PREFS_BUILD_RES_AUTO_REFRESH = AdtPlugin.PLUGIN_ID + ".resAutoRefresh"; //$NON-NLS-1$ 37 38 public final static String PREFS_BUILD_FORCE_ERROR_ON_NATIVELIB_IN_JAR = AdtPlugin.PLUGIN_ID + ".forceErrorNativeLibInJar"; //$NON-NLS-1$ 39 40 public final static String PREFS_BUILD_SKIP_POST_COMPILE_ON_FILE_SAVE = AdtPlugin.PLUGIN_ID + ".skipPostCompileOnFileSave"; //$NON-NLS-1$ 41 42 public final static String PREFS_BUILD_VERBOSITY = AdtPlugin.PLUGIN_ID + ".buildVerbosity"; //$NON-NLS-1$ 43 44 public final static String PREFS_DEFAULT_DEBUG_KEYSTORE = AdtPlugin.PLUGIN_ID + ".defaultDebugKeyStore"; //$NON-NLS-1$ 45 46 public final static String PREFS_CUSTOM_DEBUG_KEYSTORE = AdtPlugin.PLUGIN_ID + ".customDebugKeyStore"; //$NON-NLS-1$ 47 48 public final static String PREFS_HOME_PACKAGE = AdtPlugin.PLUGIN_ID + ".homePackage"; //$NON-NLS-1$ 49 50 public final static String PREFS_EMU_OPTIONS = AdtPlugin.PLUGIN_ID + ".emuOptions"; //$NON-NLS-1$ 51 52 public final static String PREFS_MONITOR_DENSITY = AdtPlugin.PLUGIN_ID + ".monitorDensity"; //$NON-NLS-1$ 53 54 public final static String PREFS_FORMAT_GUI_XML = AdtPlugin.PLUGIN_ID + ".formatXml"; //$NON-NLS-1$ 55 public final static String PREFS_USE_CUSTOM_XML_FORMATTER = AdtPlugin.PLUGIN_ID + ".androidForm"; //$NON-NLS-1$ 56 57 public final static String PREFS_PALETTE_MODE = AdtPlugin.PLUGIN_ID + ".palette"; //$NON-NLS-1$ 58 59 public final static String PREFS_USE_ECLIPSE_INDENT = AdtPlugin.PLUGIN_ID + ".eclipseIndent"; //$NON-NLS-1$ 60 public final static String PREVS_REMOVE_EMPTY_LINES = AdtPlugin.PLUGIN_ID + ".removeEmpty"; //$NON-NLS-1$ 61 public final static String PREFS_ONE_ATTR_PER_LINE = AdtPlugin.PLUGIN_ID + ".oneAttrPerLine"; //$NON-NLS-1$ 62 public final static String PREFS_SPACE_BEFORE_CLOSE = AdtPlugin.PLUGIN_ID + ".spaceBeforeClose"; //$NON-NLS-1$ 63 public final static String PREFS_FORMAT_ON_SAVE = AdtPlugin.PLUGIN_ID + ".formatOnSave"; //$NON-NLS-1$ 64 public final static String PREFS_ATTRIBUTE_SORT = AdtPlugin.PLUGIN_ID + ".attrSort"; //$NON-NLS-1$ 65 66 /** singleton instance */ 67 private final static AdtPrefs sThis = new AdtPrefs(); 68 69 /** default store, provided by eclipse */ 70 private IPreferenceStore mStore; 71 72 /** cached location for the sdk folder */ 73 private String mOsSdkLocation; 74 75 /** Verbosity of the build */ 76 private BuildVerbosity mBuildVerbosity = BuildVerbosity.NORMAL; 77 78 private boolean mBuildForceResResfresh = false; 79 private boolean mBuildForceErrorOnNativeLibInJar = true; 80 private boolean mBuildSkipPostCompileOnFileSave = true; 81 private float mMonitorDensity = 0.f; 82 private String mPalette; 83 84 private boolean mFormatGuiXml; 85 private boolean mCustomXmlFormatter; 86 private boolean mUseEclipseIndent; 87 private boolean mRemoveEmptyLines; 88 private boolean mOneAttributeOnFirstLine; 89 private boolean mSpaceBeforeClose; 90 private boolean mFormatOnSave; 91 private AttributeSortOrder mAttributeSort; 92 93 public static enum BuildVerbosity { 94 /** Build verbosity "Always". Those messages are always displayed, even in silent mode */ 95 ALWAYS(0), 96 /** Build verbosity level "Normal" */ 97 NORMAL(1), 98 /** Build verbosity level "Verbose". Those messages are only displayed in verbose mode */ 99 VERBOSE(2); 100 101 private int mLevel; 102 103 BuildVerbosity(int level) { 104 mLevel = level; 105 } 106 107 public int getLevel() { 108 return mLevel; 109 } 110 111 /** 112 * Finds and returns a {@link BuildVerbosity} whose {@link #name()} matches a given name. 113 * <p/>This is different from {@link Enum#valueOf(Class, String)} in that it returns null 114 * if no matches are found. 115 * 116 * @param name the name to look up. 117 * @return returns the matching enum or null of no match where found. 118 */ 119 public static BuildVerbosity find(String name) { 120 for (BuildVerbosity v : values()) { 121 if (v.name().equals(name)) { 122 return v; 123 } 124 } 125 126 return null; 127 } 128 } 129 130 public static void init(IPreferenceStore preferenceStore) { 131 sThis.mStore = preferenceStore; 132 } 133 134 public static AdtPrefs getPrefs() { 135 return sThis; 136 } 137 138 public synchronized void loadValues(PropertyChangeEvent event) { 139 // get the name of the property that changed, if any 140 String property = event != null ? event.getProperty() : null; 141 142 if (property == null || PREFS_SDK_DIR.equals(property)) { 143 mOsSdkLocation = mStore.getString(PREFS_SDK_DIR); 144 145 // Make it possible to override the SDK path using an environment variable. 146 // The value will only be used if it matches an existing directory. 147 // Useful for testing from Eclipse. 148 // Note: this is a hack that does not change the preferences, so if the user 149 // looks at Window > Preferences > Android, the path will be the preferences 150 // one and not the overridden one. 151 String override = System.getenv("ADT_TEST_SDK_PATH"); //$NON-NLS-1$ 152 if (override != null && override.length() > 0 && new File(override).isDirectory()) { 153 mOsSdkLocation = override; 154 } 155 156 // make sure it ends with a separator. Normally this is done when the preference 157 // is set. But to make sure older version still work, we fix it here as well. 158 if (mOsSdkLocation.length() > 0 && mOsSdkLocation.endsWith(File.separator) == false) { 159 mOsSdkLocation = mOsSdkLocation + File.separator; 160 } 161 } 162 163 if (property == null || PREFS_BUILD_VERBOSITY.equals(property)) { 164 mBuildVerbosity = BuildVerbosity.find(mStore.getString(PREFS_BUILD_VERBOSITY)); 165 if (mBuildVerbosity == null) { 166 mBuildVerbosity = BuildVerbosity.NORMAL; 167 } 168 } 169 170 if (property == null || PREFS_BUILD_RES_AUTO_REFRESH.equals(property)) { 171 mBuildForceResResfresh = mStore.getBoolean(PREFS_BUILD_RES_AUTO_REFRESH); 172 } 173 174 if (property == null || PREFS_BUILD_FORCE_ERROR_ON_NATIVELIB_IN_JAR.equals(property)) { 175 mBuildForceErrorOnNativeLibInJar = mStore.getBoolean(PREFS_BUILD_RES_AUTO_REFRESH); 176 } 177 178 if (property == null || PREFS_BUILD_SKIP_POST_COMPILE_ON_FILE_SAVE.equals(property)) { 179 mBuildSkipPostCompileOnFileSave = 180 mStore.getBoolean(PREFS_BUILD_SKIP_POST_COMPILE_ON_FILE_SAVE); 181 } 182 183 if (property == null || PREFS_MONITOR_DENSITY.equals(property)) { 184 mMonitorDensity = mStore.getFloat(PREFS_MONITOR_DENSITY); 185 } 186 187 if (property == null || PREFS_FORMAT_GUI_XML.equals(property)) { 188 mFormatGuiXml = mStore.getBoolean(PREFS_FORMAT_GUI_XML); 189 } 190 191 if (property == null || PREFS_USE_CUSTOM_XML_FORMATTER.equals(property)) { 192 mCustomXmlFormatter = mStore.getBoolean(PREFS_USE_CUSTOM_XML_FORMATTER); 193 } 194 195 if (property == null || PREFS_PALETTE_MODE.equals(property)) { 196 mPalette = mStore.getString(PREFS_PALETTE_MODE); 197 } 198 199 if (property == null || PREFS_USE_ECLIPSE_INDENT.equals(property)) { 200 mUseEclipseIndent = mStore.getBoolean(PREFS_USE_ECLIPSE_INDENT); 201 } 202 203 if (property == null || PREVS_REMOVE_EMPTY_LINES.equals(property)) { 204 mRemoveEmptyLines = mStore.getBoolean(PREVS_REMOVE_EMPTY_LINES); 205 } 206 207 if (property == null || PREFS_ONE_ATTR_PER_LINE.equals(property)) { 208 mOneAttributeOnFirstLine = mStore.getBoolean(PREFS_ONE_ATTR_PER_LINE); 209 } 210 211 if (property == null || PREFS_ATTRIBUTE_SORT.equals(property)) { 212 String order = mStore.getString(PREFS_ATTRIBUTE_SORT); 213 mAttributeSort = AttributeSortOrder.LOGICAL; 214 if (AttributeSortOrder.ALPHABETICAL.key.equals(order)) { 215 mAttributeSort = AttributeSortOrder.ALPHABETICAL; 216 } else if (AttributeSortOrder.NO_SORTING.key.equals(order)) { 217 mAttributeSort = AttributeSortOrder.NO_SORTING; 218 } 219 } 220 221 if (property == null || PREFS_SPACE_BEFORE_CLOSE.equals(property)) { 222 mSpaceBeforeClose = mStore.getBoolean(PREFS_SPACE_BEFORE_CLOSE); 223 } 224 225 if (property == null || PREFS_FORMAT_ON_SAVE.equals(property)) { 226 mFormatOnSave = mStore.getBoolean(PREFS_FORMAT_ON_SAVE); 227 } 228 } 229 230 /** 231 * Returns the SDK folder. 232 * Guaranteed to be terminated by a platform-specific path separator. 233 */ 234 public synchronized String getOsSdkFolder() { 235 return mOsSdkLocation; 236 } 237 238 public synchronized BuildVerbosity getBuildVerbosity() { 239 return mBuildVerbosity; 240 } 241 242 public boolean getBuildForceResResfresh() { 243 return mBuildForceResResfresh; 244 } 245 246 /** 247 * Should changes made by GUI editors automatically format the corresponding XML nodes 248 * affected by the edit? 249 * 250 * @return true if the GUI editors should format affected XML regions 251 */ 252 public boolean getFormatGuiXml() { 253 // The format-GUI-editors flag only applies when the custom formatter is used, 254 // since the built-in formatter has problems editing partial documents 255 return mFormatGuiXml && mCustomXmlFormatter; 256 } 257 258 /** 259 * Should the XML formatter use a custom Android XML formatter (following 260 * Android code style) or use the builtin Eclipse XML formatter? 261 * 262 * @return true if the Android formatter should be used instead of the 263 * default Eclipse one 264 */ 265 public boolean getUseCustomXmlFormatter() { 266 return mCustomXmlFormatter; 267 } 268 269 /** 270 * Should the Android XML formatter use the Eclipse XML indentation settings 271 * (usually one tab character) instead of the default 4 space character 272 * indent? 273 * 274 * @return true if the Eclipse XML indentation settings should be use 275 */ 276 public boolean isUseEclipseIndent() { 277 return mUseEclipseIndent; 278 } 279 280 /** 281 * Should the Android XML formatter try to avoid inserting blank lines to 282 * make the format as compact as possible (no blank lines between elements, 283 * no blank lines surrounding comments, etc). 284 * 285 * @return true to remove blank lines 286 */ 287 public boolean isRemoveEmptyLines() { 288 return mRemoveEmptyLines; 289 } 290 291 /** 292 * Should the Android XML formatter attempt to place a single attribute on 293 * the same line as the element open tag? 294 * 295 * @return true if single-attribute elements should place the attribute on 296 * the same line as the element open tag 297 */ 298 public boolean isOneAttributeOnFirstLine() { 299 return mOneAttributeOnFirstLine; 300 } 301 302 /** 303 * Returns the sort order to be applied to the attributes (one of which can 304 * be {@link AttributeSortOrder#NO_SORTING}). 305 * 306 * @return the sort order to apply to the attributes 307 */ 308 public AttributeSortOrder getAttributeSort() { 309 if (mAttributeSort == null) { 310 return AttributeSortOrder.LOGICAL; 311 } 312 return mAttributeSort; 313 } 314 315 /** 316 * Returns whether a space should be inserted before the closing {@code >} 317 * character in open tags and before the closing {@code />} characters in 318 * empty tag. Note that the {@link XmlFormatStyle#RESOURCE} style overrides 319 * this setting to make it more compact for the {@code <item>} elements. 320 * 321 * @return true if an empty space should be inserted before {@code >} or 322 * {@code />}. 323 */ 324 public boolean isSpaceBeforeClose() { 325 return mSpaceBeforeClose; 326 } 327 328 /** 329 * Returns whether the file should be automatically formatted on save. 330 * 331 * @return true if the XML files should be formatted on save. 332 */ 333 public boolean isFormatOnSave() { 334 return mFormatOnSave; 335 } 336 337 public boolean getBuildForceErrorOnNativeLibInJar() { 338 return mBuildForceErrorOnNativeLibInJar; 339 } 340 341 public boolean getBuildSkipPostCompileOnFileSave() { 342 return mBuildSkipPostCompileOnFileSave; 343 } 344 345 public String getPaletteModes() { 346 return mPalette; 347 } 348 349 public void setPaletteModes(String palette) { 350 mPalette = palette; 351 352 // need to save this new value to the store 353 IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 354 store.setValue(PREFS_PALETTE_MODE, palette); 355 } 356 357 public float getMonitorDensity() { 358 return mMonitorDensity; 359 } 360 361 public void setMonitorDensity(float density) { 362 mMonitorDensity = density; 363 364 // need to save this new value to the store 365 IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 366 store.setValue(PREFS_MONITOR_DENSITY, density); 367 } 368 369 /** 370 * Sets the new location of the SDK 371 * 372 * @param location the location of the SDK 373 */ 374 public void setSdkLocation(File location) { 375 mOsSdkLocation = location != null ? location.getPath() : null; 376 377 // TODO: Also store this location in the .android settings directory 378 // such that we can support using multiple workspaces without asking 379 // over and over. 380 if (mOsSdkLocation != null && mOsSdkLocation.length() > 0) { 381 DdmsPreferenceStore ddmsStore = new DdmsPreferenceStore(); 382 ddmsStore.setLastSdkPath(mOsSdkLocation); 383 } 384 385 // need to save this new value to the store 386 IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 387 store.setValue(PREFS_SDK_DIR, mOsSdkLocation); 388 } 389 390 @Override 391 public void initializeDefaultPreferences() { 392 IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 393 initializeStoreWithDefaults(store); 394 } 395 396 public void initializeStoreWithDefaults(IPreferenceStore store) { 397 store.setDefault(PREFS_BUILD_RES_AUTO_REFRESH, true); 398 store.setDefault(PREFS_BUILD_FORCE_ERROR_ON_NATIVELIB_IN_JAR, true); 399 store.setDefault(PREFS_BUILD_SKIP_POST_COMPILE_ON_FILE_SAVE, true); 400 401 store.setDefault(PREFS_BUILD_VERBOSITY, BuildVerbosity.ALWAYS.name()); 402 403 store.setDefault(PREFS_HOME_PACKAGE, "android.process.acore"); //$NON-NLS-1$ 404 405 store.setDefault(PREFS_MONITOR_DENSITY, 0.f); 406 store.setDefault(PREFS_FORMAT_GUI_XML, true); 407 store.setDefault(PREFS_USE_CUSTOM_XML_FORMATTER, true); 408 store.setDefault(PREFS_ONE_ATTR_PER_LINE, true); 409 store.setDefault(PREFS_SPACE_BEFORE_CLOSE, true); 410 411 // Defaults already handled; no need to write into map: 412 //store.setDefault(PREFS_ATTRIBUTE_SORT, AttributeSortOrder.LOGICAL.key); 413 //store.setDefault(PREFS_USE_ECLIPSE_INDENT, false); 414 //store.setDefault(PREVS_REMOVE_EMPTY_LINES, false); 415 //store.setDefault(PREFS_FORMAT_ON_SAVE, false); 416 417 try { 418 store.setDefault(PREFS_DEFAULT_DEBUG_KEYSTORE, 419 DebugKeyProvider.getDefaultKeyStoreOsPath()); 420 } catch (KeytoolException e) { 421 AdtPlugin.log(e, "Get default debug keystore path failed"); //$NON-NLS-1$ 422 } catch (AndroidLocationException e) { 423 AdtPlugin.log(e, "Get default debug keystore path failed"); //$NON-NLS-1$ 424 } 425 } 426 } 427