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