1 /* 2 * Copyright (C) 2010 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.editors.layout.gle2; 18 19 import com.android.ide.common.rendering.api.LayoutLog; 20 import com.android.ide.eclipse.adt.AdtPlugin; 21 22 import org.eclipse.core.runtime.IStatus; 23 24 import java.util.ArrayList; 25 import java.util.HashSet; 26 import java.util.List; 27 import java.util.Set; 28 29 /** 30 * A {@link LayoutLog} which records the problems it encounters and offers them as a 31 * single summary at the end 32 */ 33 class RenderLogger extends LayoutLog { 34 static final String TAG_MISSING_DIMENSION = "missing.dimension"; //$NON-NLS-1$ 35 36 private final String mName; 37 private List<String> mFidelityWarnings; 38 private List<String> mWarnings; 39 private List<String> mErrors; 40 private boolean mHaveExceptions; 41 private List<String> mTags; 42 private static Set<String> sIgnoredFidelityWarnings; 43 44 /** Construct a logger for the given named layout */ 45 RenderLogger(String name) { 46 mName = name; 47 } 48 49 /** 50 * Are there any logged errors or warnings during the render? 51 * 52 * @return true if there were problems during the render 53 */ 54 public boolean hasProblems() { 55 return mFidelityWarnings != null || mErrors != null || mWarnings != null || 56 mHaveExceptions; 57 } 58 59 /** 60 * Returns a (possibly multi-line) description of all the problems 61 * 62 * @param includeFidelityWarnings if true, include fidelity warnings in the problem 63 * summary 64 * @return a string describing the rendering problems 65 */ 66 public String getProblems(boolean includeFidelityWarnings) { 67 StringBuilder sb = new StringBuilder(); 68 69 if (mErrors != null) { 70 for (String error : mErrors) { 71 sb.append(error).append('\n'); 72 } 73 } 74 75 if (mWarnings != null) { 76 for (String warning : mWarnings) { 77 sb.append(warning).append('\n'); 78 } 79 } 80 81 if (includeFidelityWarnings && mFidelityWarnings != null) { 82 sb.append("The graphics preview in the layout editor may not be accurate:\n"); 83 for (String warning : mFidelityWarnings) { 84 sb.append("* "); 85 sb.append(warning).append('\n'); 86 } 87 } 88 89 if (mHaveExceptions) { 90 sb.append("Exception details are logged in Window > Show View > Error Log"); 91 } 92 93 return sb.toString(); 94 } 95 96 /** 97 * Returns the fidelity warnings 98 * 99 * @return the fidelity warnings 100 */ 101 public List<String> getFidelityWarnings() { 102 return mFidelityWarnings; 103 } 104 105 // ---- extends LayoutLog ---- 106 107 @Override 108 public void error(String tag, String message, Object data) { 109 String description = describe(message); 110 111 AdtPlugin.log(IStatus.ERROR, "%1$s: %2$s", mName, description); 112 113 // Workaround: older layout libraries don't provide a tag for this error 114 if (tag == null && message != null 115 && message.startsWith("Failed to find style ")) { //$NON-NLS-1$ 116 tag = LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR; 117 } 118 119 addError(tag, description); 120 } 121 122 @Override 123 public void error(String tag, String message, Throwable throwable, Object data) { 124 String description = describe(message); 125 AdtPlugin.log(throwable, "%1$s: %2$s", mName, description); 126 if (throwable != null) { 127 if (throwable instanceof ClassNotFoundException) { 128 // The project callback is given a chance to resolve classes, 129 // and when it fails, it will record it in its own list which 130 // is displayed in a special way (with action hyperlinks etc). 131 // Therefore, include these messages in the visible render log, 132 // especially since the user message from a ClassNotFoundException 133 // is really not helpful (it just lists the class name without 134 // even mentioning that it is a class-not-found exception.) 135 return; 136 } 137 138 mHaveExceptions = true; 139 } 140 141 addError(tag, description); 142 } 143 144 @Override 145 public void warning(String tag, String message, Object data) { 146 String description = describe(message); 147 AdtPlugin.log(IStatus.WARNING, "%1$s: %2$s", mName, description); 148 149 if (TAG_RESOURCES_FORMAT.equals(tag)) { 150 if (description.equals("You must supply a layout_width attribute.") //$NON-NLS-1$ 151 || description.equals("You must supply a layout_height attribute.")) {//$NON-NLS-1$ 152 tag = TAG_MISSING_DIMENSION; 153 } 154 } 155 156 addWarning(tag, description); 157 } 158 159 @Override 160 public void fidelityWarning(String tag, String message, Throwable throwable, Object data) { 161 if (sIgnoredFidelityWarnings != null && sIgnoredFidelityWarnings.contains(message)) { 162 return; 163 } 164 165 String description = describe(message); 166 AdtPlugin.log(throwable, "%1$s: %2$s", mName, description); 167 if (throwable != null) { 168 mHaveExceptions = true; 169 } 170 171 addFidelityWarning(tag, description); 172 } 173 174 /** 175 * Ignore the given render fidelity warning for the current session 176 * 177 * @param message the message to be ignored for this session 178 */ 179 public static void ignoreFidelityWarning(String message) { 180 if (sIgnoredFidelityWarnings == null) { 181 sIgnoredFidelityWarnings = new HashSet<String>(); 182 } 183 sIgnoredFidelityWarnings.add(message); 184 } 185 186 private String describe(String message) { 187 StringBuilder sb = new StringBuilder(); 188 if (message != null) { 189 if (sb.length() > 0) { 190 sb.append(": "); 191 } 192 sb.append(message); 193 } 194 return sb.toString(); 195 } 196 197 private void addWarning(String tag, String description) { 198 if (mWarnings == null) { 199 mWarnings = new ArrayList<String>(); 200 } else if (mWarnings.contains(description)) { 201 // Avoid duplicates 202 return; 203 } 204 mWarnings.add(description); 205 addTag(tag); 206 } 207 208 private void addError(String tag, String description) { 209 if (mErrors == null) { 210 mErrors = new ArrayList<String>(); 211 } else if (mErrors.contains(description)) { 212 // Avoid duplicates 213 return; 214 } 215 mErrors.add(description); 216 addTag(tag); 217 } 218 219 private void addFidelityWarning(String tag, String description) { 220 if (mFidelityWarnings == null) { 221 mFidelityWarnings = new ArrayList<String>(); 222 } else if (mFidelityWarnings.contains(description)) { 223 // Avoid duplicates 224 return; 225 } 226 mFidelityWarnings.add(description); 227 addTag(tag); 228 } 229 230 // ---- Tags ---- 231 232 private void addTag(String tag) { 233 if (tag != null) { 234 if (mTags == null) { 235 mTags = new ArrayList<String>(); 236 } 237 mTags.add(tag); 238 } 239 } 240 241 /** 242 * Returns true if the given tag prefix has been seen 243 * 244 * @param prefix the tag prefix to look for 245 * @return true iff any tags with the given prefix was seen during the render 246 */ 247 public boolean seenTagPrefix(String prefix) { 248 if (mTags != null) { 249 for (String tag : mTags) { 250 if (tag.startsWith(prefix)) { 251 return true; 252 } 253 } 254 } 255 256 return false; 257 } 258 259 /** 260 * Returns true if the given tag has been seen 261 * 262 * @param tag the tag to look for 263 * @return true iff the tag was seen during the render 264 */ 265 public boolean seenTag(String tag) { 266 if (mTags != null) { 267 return mTags.contains(tag); 268 } else { 269 return false; 270 } 271 } 272 } 273