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_DISABLED_ISSUES = AdtPlugin.PLUGIN_ID + ".disabedIssues"; //$NON-NLS-1$ 68 public final static String PREFS_LINT_SEVERITIES = AdtPlugin.PLUGIN_ID + ".lintSeverities"; //$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 = mStore.getBoolean(PREFS_BUILD_RES_AUTO_REFRESH); 182 } 183 184 if (property == null || PREFS_BUILD_SKIP_POST_COMPILE_ON_FILE_SAVE.equals(property)) { 185 mBuildSkipPostCompileOnFileSave = 186 mStore.getBoolean(PREFS_BUILD_SKIP_POST_COMPILE_ON_FILE_SAVE); 187 } 188 189 if (property == null || PREFS_MONITOR_DENSITY.equals(property)) { 190 mMonitorDensity = mStore.getFloat(PREFS_MONITOR_DENSITY); 191 } 192 193 if (property == null || PREFS_FORMAT_GUI_XML.equals(property)) { 194 mFormatGuiXml = mStore.getBoolean(PREFS_FORMAT_GUI_XML); 195 } 196 197 if (property == null || PREFS_USE_CUSTOM_XML_FORMATTER.equals(property)) { 198 mCustomXmlFormatter = mStore.getBoolean(PREFS_USE_CUSTOM_XML_FORMATTER); 199 } 200 201 if (property == null || PREFS_PALETTE_MODE.equals(property)) { 202 mPalette = mStore.getString(PREFS_PALETTE_MODE); 203 } 204 205 if (property == null || PREFS_USE_ECLIPSE_INDENT.equals(property)) { 206 mUseEclipseIndent = mStore.getBoolean(PREFS_USE_ECLIPSE_INDENT); 207 } 208 209 if (property == null || PREVS_REMOVE_EMPTY_LINES.equals(property)) { 210 mRemoveEmptyLines = mStore.getBoolean(PREVS_REMOVE_EMPTY_LINES); 211 } 212 213 if (property == null || PREFS_ONE_ATTR_PER_LINE.equals(property)) { 214 mOneAttributeOnFirstLine = mStore.getBoolean(PREFS_ONE_ATTR_PER_LINE); 215 } 216 217 if (property == null || PREFS_ATTRIBUTE_SORT.equals(property)) { 218 String order = mStore.getString(PREFS_ATTRIBUTE_SORT); 219 mAttributeSort = AttributeSortOrder.LOGICAL; 220 if (AttributeSortOrder.ALPHABETICAL.key.equals(order)) { 221 mAttributeSort = AttributeSortOrder.ALPHABETICAL; 222 } else if (AttributeSortOrder.NO_SORTING.key.equals(order)) { 223 mAttributeSort = AttributeSortOrder.NO_SORTING; 224 } 225 } 226 227 if (property == null || PREFS_SPACE_BEFORE_CLOSE.equals(property)) { 228 mSpaceBeforeClose = mStore.getBoolean(PREFS_SPACE_BEFORE_CLOSE); 229 } 230 231 if (property == null || PREFS_FORMAT_ON_SAVE.equals(property)) { 232 mFormatOnSave = mStore.getBoolean(PREFS_FORMAT_ON_SAVE); 233 } 234 235 if (property == null || PREFS_LINT_ON_SAVE.equals(property)) { 236 mLintOnSave = mStore.getBoolean(PREFS_LINT_ON_SAVE); 237 } 238 239 if (property == null || PREFS_LINT_ON_EXPORT.equals(property)) { 240 mLintOnExport = mStore.getBoolean(PREFS_LINT_ON_EXPORT); 241 } 242 } 243 244 /** 245 * Returns the SDK folder. 246 * Guaranteed to be terminated by a platform-specific path separator. 247 */ 248 public synchronized String getOsSdkFolder() { 249 return mOsSdkLocation; 250 } 251 252 public synchronized BuildVerbosity getBuildVerbosity() { 253 return mBuildVerbosity; 254 } 255 256 public boolean getBuildForceResResfresh() { 257 return mBuildForceResResfresh; 258 } 259 260 /** 261 * Should changes made by GUI editors automatically format the corresponding XML nodes 262 * affected by the edit? 263 * 264 * @return true if the GUI editors should format affected XML regions 265 */ 266 public boolean getFormatGuiXml() { 267 // The format-GUI-editors flag only applies when the custom formatter is used, 268 // since the built-in formatter has problems editing partial documents 269 return mFormatGuiXml && mCustomXmlFormatter; 270 } 271 272 /** 273 * Should the XML formatter use a custom Android XML formatter (following 274 * Android code style) or use the builtin Eclipse XML formatter? 275 * 276 * @return true if the Android formatter should be used instead of the 277 * default Eclipse one 278 */ 279 public boolean getUseCustomXmlFormatter() { 280 return mCustomXmlFormatter; 281 } 282 283 /** 284 * Should the Android XML formatter use the Eclipse XML indentation settings 285 * (usually one tab character) instead of the default 4 space character 286 * indent? 287 * 288 * @return true if the Eclipse XML indentation settings should be use 289 */ 290 public boolean isUseEclipseIndent() { 291 return mUseEclipseIndent; 292 } 293 294 /** 295 * Should the Android XML formatter try to avoid inserting blank lines to 296 * make the format as compact as possible (no blank lines between elements, 297 * no blank lines surrounding comments, etc). 298 * 299 * @return true to remove blank lines 300 */ 301 public boolean isRemoveEmptyLines() { 302 return mRemoveEmptyLines; 303 } 304 305 /** 306 * Should the Android XML formatter attempt to place a single attribute on 307 * the same line as the element open tag? 308 * 309 * @return true if single-attribute elements should place the attribute on 310 * the same line as the element open tag 311 */ 312 public boolean isOneAttributeOnFirstLine() { 313 return mOneAttributeOnFirstLine; 314 } 315 316 /** 317 * Returns the sort order to be applied to the attributes (one of which can 318 * be {@link AttributeSortOrder#NO_SORTING}). 319 * 320 * @return the sort order to apply to the attributes 321 */ 322 public AttributeSortOrder getAttributeSort() { 323 if (mAttributeSort == null) { 324 return AttributeSortOrder.LOGICAL; 325 } 326 return mAttributeSort; 327 } 328 329 /** 330 * Returns whether a space should be inserted before the closing {@code >} 331 * character in open tags and before the closing {@code />} characters in 332 * empty tag. Note that the {@link XmlFormatStyle#RESOURCE} style overrides 333 * this setting to make it more compact for the {@code <item>} elements. 334 * 335 * @return true if an empty space should be inserted before {@code >} or 336 * {@code />}. 337 */ 338 public boolean isSpaceBeforeClose() { 339 return mSpaceBeforeClose; 340 } 341 342 /** 343 * Returns whether the file should be automatically formatted on save. 344 * 345 * @return true if the XML files should be formatted on save. 346 */ 347 public boolean isFormatOnSave() { 348 return mFormatOnSave; 349 } 350 351 public boolean isLintOnSave() { 352 return mLintOnSave; 353 } 354 355 public void setLintOnSave(boolean on) { 356 mLintOnSave = on; 357 IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 358 store.setValue(PREFS_LINT_ON_SAVE, on); 359 } 360 361 public boolean isLintOnExport() { 362 return mLintOnExport; 363 } 364 365 public void setLintOnExport(boolean on) { 366 mLintOnExport = on; 367 IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 368 store.setValue(PREFS_LINT_ON_EXPORT, on); 369 } 370 371 public boolean getBuildForceErrorOnNativeLibInJar() { 372 return mBuildForceErrorOnNativeLibInJar; 373 } 374 375 public boolean getBuildSkipPostCompileOnFileSave() { 376 return mBuildSkipPostCompileOnFileSave; 377 } 378 379 public String getPaletteModes() { 380 return mPalette; 381 } 382 383 public void setPaletteModes(String palette) { 384 mPalette = palette; 385 386 // need to save this new value to the store 387 IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 388 store.setValue(PREFS_PALETTE_MODE, palette); 389 } 390 391 public float getMonitorDensity() { 392 return mMonitorDensity; 393 } 394 395 public void setMonitorDensity(float density) { 396 mMonitorDensity = density; 397 398 // need to save this new value to the store 399 IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 400 store.setValue(PREFS_MONITOR_DENSITY, density); 401 } 402 403 /** 404 * Sets the new location of the SDK 405 * 406 * @param location the location of the SDK 407 */ 408 public void setSdkLocation(File location) { 409 mOsSdkLocation = location != null ? location.getPath() : null; 410 411 // TODO: Also store this location in the .android settings directory 412 // such that we can support using multiple workspaces without asking 413 // over and over. 414 if (mOsSdkLocation != null && mOsSdkLocation.length() > 0) { 415 DdmsPreferenceStore ddmsStore = new DdmsPreferenceStore(); 416 ddmsStore.setLastSdkPath(mOsSdkLocation); 417 } 418 419 // need to save this new value to the store 420 IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 421 store.setValue(PREFS_SDK_DIR, mOsSdkLocation); 422 } 423 424 @Override 425 public void initializeDefaultPreferences() { 426 IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); 427 initializeStoreWithDefaults(store); 428 } 429 430 public void initializeStoreWithDefaults(IPreferenceStore store) { 431 store.setDefault(PREFS_BUILD_RES_AUTO_REFRESH, true); 432 store.setDefault(PREFS_BUILD_FORCE_ERROR_ON_NATIVELIB_IN_JAR, true); 433 store.setDefault(PREFS_BUILD_SKIP_POST_COMPILE_ON_FILE_SAVE, true); 434 435 store.setDefault(PREFS_BUILD_VERBOSITY, BuildVerbosity.ALWAYS.name()); 436 437 store.setDefault(PREFS_HOME_PACKAGE, "android.process.acore"); //$NON-NLS-1$ 438 439 store.setDefault(PREFS_MONITOR_DENSITY, 0.f); 440 store.setDefault(PREFS_FORMAT_GUI_XML, true); 441 store.setDefault(PREFS_USE_CUSTOM_XML_FORMATTER, true); 442 store.setDefault(PREFS_ONE_ATTR_PER_LINE, true); 443 store.setDefault(PREFS_SPACE_BEFORE_CLOSE, true); 444 store.setDefault(PREFS_LINT_ON_SAVE, true); 445 store.setDefault(PREFS_LINT_ON_EXPORT, true); 446 447 // Defaults already handled; no need to write into map: 448 //store.setDefault(PREFS_ATTRIBUTE_SORT, AttributeSortOrder.LOGICAL.key); 449 //store.setDefault(PREFS_USE_ECLIPSE_INDENT, false); 450 //store.setDefault(PREVS_REMOVE_EMPTY_LINES, false); 451 //store.setDefault(PREFS_FORMAT_ON_SAVE, false); 452 453 try { 454 store.setDefault(PREFS_DEFAULT_DEBUG_KEYSTORE, 455 DebugKeyProvider.getDefaultKeyStoreOsPath()); 456 } catch (KeytoolException e) { 457 AdtPlugin.log(e, "Get default debug keystore path failed"); //$NON-NLS-1$ 458 } catch (AndroidLocationException e) { 459 AdtPlugin.log(e, "Get default debug keystore path failed"); //$NON-NLS-1$ 460 } 461 } 462 } 463