diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderLogger.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderLogger.java | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderLogger.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderLogger.java new file mode 100644 index 000000000..8548830bd --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderLogger.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.ide.eclipse.adt.internal.editors.layout.gle2; + +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; +import com.android.ide.common.rendering.RenderSecurityManager; +import com.android.ide.common.rendering.api.LayoutLog; +import com.android.ide.eclipse.adt.AdtPlugin; + +import org.eclipse.core.runtime.IStatus; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * A {@link LayoutLog} which records the problems it encounters and offers them as a + * single summary at the end + */ +public class RenderLogger extends LayoutLog { + static final String TAG_MISSING_DIMENSION = "missing.dimension"; //$NON-NLS-1$ + + private final String mName; + private List<String> mFidelityWarnings; + private List<String> mWarnings; + private List<String> mErrors; + private boolean mHaveExceptions; + private List<String> mTags; + private List<Throwable> mTraces; + private static Set<String> sIgnoredFidelityWarnings; + private final Object mCredential; + + /** Construct a logger for the given named layout */ + RenderLogger(String name, Object credential) { + mName = name; + mCredential = credential; + } + + /** + * Are there any logged errors or warnings during the render? + * + * @return true if there were problems during the render + */ + public boolean hasProblems() { + return mFidelityWarnings != null || mErrors != null || mWarnings != null || + mHaveExceptions; + } + + /** + * Returns a list of traces encountered during rendering, or null if none + * + * @return a list of traces encountered during rendering, or null if none + */ + @Nullable + public List<Throwable> getFirstTrace() { + return mTraces; + } + + /** + * Returns a (possibly multi-line) description of all the problems + * + * @param includeFidelityWarnings if true, include fidelity warnings in the problem + * summary + * @return a string describing the rendering problems + */ + @NonNull + public String getProblems(boolean includeFidelityWarnings) { + StringBuilder sb = new StringBuilder(); + + if (mErrors != null) { + for (String error : mErrors) { + sb.append(error).append('\n'); + } + } + + if (mWarnings != null) { + for (String warning : mWarnings) { + sb.append(warning).append('\n'); + } + } + + if (includeFidelityWarnings && mFidelityWarnings != null) { + sb.append("The graphics preview in the layout editor may not be accurate:\n"); + for (String warning : mFidelityWarnings) { + sb.append("* "); + sb.append(warning).append('\n'); + } + } + + if (mHaveExceptions) { + sb.append("Exception details are logged in Window > Show View > Error Log"); + } + + return sb.toString(); + } + + /** + * Returns the fidelity warnings + * + * @return the fidelity warnings + */ + @Nullable + public List<String> getFidelityWarnings() { + return mFidelityWarnings; + } + + // ---- extends LayoutLog ---- + + @Override + public void error(String tag, String message, Object data) { + String description = describe(message); + + appendToIdeLog(null, IStatus.ERROR, description); + + // Workaround: older layout libraries don't provide a tag for this error + if (tag == null && message != null + && message.startsWith("Failed to find style ")) { //$NON-NLS-1$ + tag = LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR; + } + + addError(tag, description); + } + + @Override + public void error(String tag, String message, Throwable throwable, Object data) { + String description = describe(message); + appendToIdeLog(throwable, IStatus.ERROR, description); + + if (throwable != null) { + if (throwable instanceof ClassNotFoundException) { + // The project callback is given a chance to resolve classes, + // and when it fails, it will record it in its own list which + // is displayed in a special way (with action hyperlinks etc). + // Therefore, include these messages in the visible render log, + // especially since the user message from a ClassNotFoundException + // is really not helpful (it just lists the class name without + // even mentioning that it is a class-not-found exception.) + return; + } + + if (description.equals(throwable.getLocalizedMessage()) || + description.equals(throwable.getMessage())) { + description = "Exception raised during rendering: " + description; + } + recordThrowable(throwable); + mHaveExceptions = true; + } + + addError(tag, description); + } + + /** + * Record that the given exception was encountered during rendering + * + * @param throwable the exception that was raised + */ + public void recordThrowable(@NonNull Throwable throwable) { + if (mTraces == null) { + mTraces = new ArrayList<Throwable>(); + } + mTraces.add(throwable); + } + + @Override + public void warning(String tag, String message, Object data) { + String description = describe(message); + + boolean log = true; + if (TAG_RESOURCES_FORMAT.equals(tag)) { + if (description.equals("You must supply a layout_width attribute.") //$NON-NLS-1$ + || description.equals("You must supply a layout_height attribute.")) {//$NON-NLS-1$ + tag = TAG_MISSING_DIMENSION; + log = false; + } + } + + if (log) { + appendToIdeLog(null, IStatus.WARNING, description); + } + + addWarning(tag, description); + } + + @Override + public void fidelityWarning(String tag, String message, Throwable throwable, Object data) { + if (sIgnoredFidelityWarnings != null && sIgnoredFidelityWarnings.contains(message)) { + return; + } + + String description = describe(message); + appendToIdeLog(throwable, IStatus.ERROR, description); + + if (throwable != null) { + mHaveExceptions = true; + } + + addFidelityWarning(tag, description); + } + + /** + * Ignore the given render fidelity warning for the current session + * + * @param message the message to be ignored for this session + */ + public static void ignoreFidelityWarning(String message) { + if (sIgnoredFidelityWarnings == null) { + sIgnoredFidelityWarnings = new HashSet<String>(); + } + sIgnoredFidelityWarnings.add(message); + } + + @NonNull + private String describe(@Nullable String message) { + if (message == null) { + return ""; + } else { + return message; + } + } + + private void addWarning(String tag, String description) { + if (mWarnings == null) { + mWarnings = new ArrayList<String>(); + } else if (mWarnings.contains(description)) { + // Avoid duplicates + return; + } + mWarnings.add(description); + addTag(tag); + } + + private void addError(String tag, String description) { + if (mErrors == null) { + mErrors = new ArrayList<String>(); + } else if (mErrors.contains(description)) { + // Avoid duplicates + return; + } + mErrors.add(description); + addTag(tag); + } + + private void addFidelityWarning(String tag, String description) { + if (mFidelityWarnings == null) { + mFidelityWarnings = new ArrayList<String>(); + } else if (mFidelityWarnings.contains(description)) { + // Avoid duplicates + return; + } + mFidelityWarnings.add(description); + addTag(tag); + } + + // ---- Tags ---- + + private void addTag(String tag) { + if (tag != null) { + if (mTags == null) { + mTags = new ArrayList<String>(); + } + mTags.add(tag); + } + } + + /** + * Returns true if the given tag prefix has been seen + * + * @param prefix the tag prefix to look for + * @return true iff any tags with the given prefix was seen during the render + */ + public boolean seenTagPrefix(String prefix) { + if (mTags != null) { + for (String tag : mTags) { + if (tag.startsWith(prefix)) { + return true; + } + } + } + + return false; + } + + /** + * Returns true if the given tag has been seen + * + * @param tag the tag to look for + * @return true iff the tag was seen during the render + */ + public boolean seenTag(String tag) { + if (mTags != null) { + return mTags.contains(tag); + } else { + return false; + } + } + + // Append the given message to the ADT log. Bypass the sandbox if necessary + // such that we can write to the log file. + private void appendToIdeLog(Throwable throwable, int severity, String description) { + boolean token = RenderSecurityManager.enterSafeRegion(mCredential); + try { + if (throwable != null) { + AdtPlugin.log(throwable, "%1$s: %2$s", mName, description); + } else { + AdtPlugin.log(severity, "%1$s: %2$s", mName, description); + } + } finally { + RenderSecurityManager.exitSafeRegion(token); + } + } +} |