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