// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.client.output;
import com.google.appinventor.client.BugReport;
import com.google.appinventor.client.Ode;
import static com.google.appinventor.client.Ode.MESSAGES;
import com.google.appinventor.common.utils.StringUtils;
import com.google.appinventor.common.version.AppInventorFeatures;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.shared.UmbrellaException;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.VerticalPanel;
import java.util.Set;
/**
* Output panel for displaying ODE internal logging messages.
*
* <p>Note that logging is only active in hosted mode.
*
*/
// TODO(user): Make this mesh with the new Logger interface.
public final class OdeLog extends Composite {
// Singleton logging instance
private static class SingletonHolder {
private static final OdeLog INSTANCE = new OdeLog();
}
// Message style
private static final String messageStyle = "style=\"font-size:small\"";
// UI elements
private final HTML text;
/**
* Returns singleton ODE logging instance.
*
* @return ODE logging instance
*/
public static OdeLog getOdeLog() {
if (isLogAvailable()) {
return SingletonHolder.INSTANCE;
}
throw new UnsupportedOperationException("logging not available");
}
/**
* Creates a new output panel for displaying internal messages.
*/
private OdeLog() {
// Initialize UI
Button clearButton = new Button(MESSAGES.clearButton());
clearButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
clear();
}
});
text = new HTML();
text.setWidth("100%");
VerticalPanel panel = new VerticalPanel();
panel.add(clearButton);
panel.add(text);
panel.setSize("100%", "100%");
panel.setCellHeight(text, "100%");
panel.setCellWidth(text, "100%");
initWidget(panel);
}
/**
* Indicates whether logging is available.
*
* @return logging availability
*/
public static final boolean isLogAvailable() {
return AppInventorFeatures.hasDebuggingView();
}
/**
* Prints a log message.
*
* @param message message to print
*/
public static void log(String message) {
if (isLogAvailable() && !Ode.isWindowClosing()) {
getOdeLog().println(StringUtils.escape(message));
}
}
/**
* Prints a log warning message.
*
* @param message message to print
*/
public static void wlog(String message) {
if (isLogAvailable() && !Ode.isWindowClosing()) {
getOdeLog().wprintln(StringUtils.escape(message));
}
}
/**
* Prints a log error message.
*
* @param message message to print
*/
public static void elog(String message) {
if (isLogAvailable() && !Ode.isWindowClosing()) {
getOdeLog().eprintln(StringUtils.escape(message));
}
}
/**
* Prints a log message for an exception.
*
* @param throwable exception thrown
*/
public static void xlog(Throwable throwable) {
if (isLogAvailable() && !Ode.isWindowClosing()) {
getOdeLog().eprintln(StringUtils.escape(throwable.toString()) + prepareStackTrace(throwable));
if (AppInventorFeatures.sendBugReports()) {
// For this message, we don't escape. We want the bug report link to show as a link.
getOdeLog().eprintln("File a <a href=\"" + BugReport.getBugReportLink(throwable)
+ "\" target=\"_blank\">bug report</a> for this error.");
}
}
}
private static String prepareStackTrace(Throwable throwable) {
StringBuilder html = new StringBuilder();
html.append("<ul>");
for (StackTraceElement element : throwable.getStackTrace()) {
html.append("<li>").append(StringUtils.escape(element.toString())).append("</li>");
}
html.append(prepareCause(throwable.getCause()));
if (throwable instanceof UmbrellaException) {
Set<Throwable> causes = ((UmbrellaException) throwable).getCauses();
if (causes != null && !causes.isEmpty()) {
for (Throwable cause : causes) {
html.append(prepareCause(cause));
}
}
}
html.append("</ul>");
return html.toString();
}
private static String prepareCause(Throwable cause) {
StringBuilder html = new StringBuilder();
if (cause != null) {
html.append("<li>Caused by ").append(StringUtils.escape(cause.toString())).append("</li>")
.append(prepareStackTrace(cause));
}
return html.toString();
}
/*
* Prints a log message.
*/
private void println(String message) {
text.setHTML(text.getHTML() + "<div " + messageStyle + ">" +
"<span style=\"color:green\">[INFO] </span>" + message + "</div>");
}
/*
* Prints a log warning message.
*/
private void wprintln(String message) {
text.setHTML(text.getHTML() + "<div " + messageStyle + ">" +
"<span style=\"color:orange\">[WARNING] </span>" + message +
"</div>");
}
/*
* Prints a log error message.
*/
private void eprintln(String message) {
text.setHTML(text.getHTML() + "<div " + messageStyle + ">" +
"<span style=\"color:red\">[ERROR] </span>" + message + "</div>");
}
/*
* Clears all messages.
*/
private void clear() {
if (!Ode.isWindowClosing()) {
text.setText("");
}
}
}