/*******************************************************************************
*
* Copyright 2011-2014 Spiffy UI Team
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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 org.spiffyui.client;
import java.util.Date;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
/**
* <p>
* This class is a set of static utility methods for showing messages and errors
* in the browser and handle them all in a consistent way.
* </p>
*
* <p>
* Applications have a large variety of messages they show to users. They can vary
* from "That name is already taken" to "Your database server crashed." These
* messages have a very different level of severity. To support that the Spiffy
* UI framework supports four levels of user messages.
* </p>
*
* <p>
* <b>Informational messages</b> tell the user something they need to know but don't
* need to respond to. "Your changes are saved" is a common example of this type
* of message.
* </p>
*
* <p>
* <b>Warning messages</b> tell the user something they need to respond to like
* "That username is already taken."
* </p>
*
* <p>
* <b>Error messages</b> tell the user something went wrong. For example,
* "Unable to contact your email server."
* </p>
*
* <p>
* <b>Fatal error messages</b> tell the user something went so wrong the system
* probably can't continue. "Unable to contact your server" is a typical fatal
* error message.
* </p>
*
* <p>
* The first three types of messages are transient. The UI follows the Humanized
* Messages idiom layed out by <a href="http://en.wikipedia.org/wiki/Jef_Raskin">
* Jef Raskin</a>. They show up on top of the content and fade in a small amount
* of time. Wiggling your mouse on them will make them fade faster.
* </p>
*
* <p>
* Error messages and some warnings will also show up in the error log at the bottom
* of the page. This makes it easy to find them again if the user needs to.
* </p>
*
* <p>
* Fatal errors are different since they normally prevent the program from continuing.
* These errors show up on top of the screen and do not move until the user clicks on
* them.
* </p>
*
* <p>
* Each of these messages can be seen on the Widgets page of the Spiffy UI Application.
* </p>
*
* <p>
* Many of the methods use the Humanized Message Panels and require the Spiffy UI
* JavaScript libraries. This class also depends on the Spiffy UI HTML structure.
* </p>
*/
public final class MessageUtil
{
private static boolean g_shouldShow = true;
/**
* Making sure this class can't be instantiated.
*/
private MessageUtil()
{
}
static {
createJSFunctions();
}
/**
* This is the singleton instance of the error panel.
*/
public static final ErrorPanel ERROR_PANEL = new ErrorPanel();
/**
* This is the singleton instance of the page warning panel.
*/
public static final PageWarningPanel PAGE_WARNING_PANEL = new PageWarningPanel();
static {
setLogTitleJS("Error Log");
}
/**
* Show a fatal error message in the error panel with the ID errorPanel.
*
* This message has a default style of
*
* @param msg the message to show in HTML
*/
public static void showFatalError(String msg)
{
if (g_shouldShow) {
ERROR_PANEL.setErrorMessage(msg);
}
logError(msg);
}
/**
* This method shows a page level warning for the page. These warnings
* are meant to indicate that the page is fundamentally broken or unavailable.
* The message shows up large in the middle of the page and hide all of
* the contents of the page except for the header and footer.
*
* @param msg the message to show in HTML
*/
public static void showPageLevelWarning(String msg)
{
PAGE_WARNING_PANEL.setErrorMessage(msg);
}
/**
* <p>
* Show a warning message.
* </p>
*
* <p>
* This message has a default style of white text with a red background.
* </p>
*
* <h3>CSS Style Ryles</h3>
*
* <ul>
* <li>.humanMsgErr</li>
* </ul>
*
* @param msg the message to show in HTML
*/
public static void showWarning(String msg)
{
showWarning(msg, true);
}
private static void showWarning(String msg, Boolean shouldLog)
{
showWarning(msg, shouldLog.booleanValue());
}
/**
* <p>
* Show a warning message.
* </p>
*
* <p>
* This message has a default style of black text with a yellow background.
* </p>
*
* <h3>CSS Style Ryles</h3>
*
* <ul>
* <li>.humanMsgWarn</li>
* </ul>
*
* @param msg the message to show in HTML
* @param shouldLog indicates if this warning should be sent to the in-browser error log
*/
public static void showWarning(String msg, boolean shouldLog)
{
showWarningJS(msg);
if (shouldLog) {
logWarning(msg);
}
}
/**
* <p>
* Show a warning message.
* </p>
*
* <p>
* This message has a default style of black text with a yellow background.
* </p>
*
* <h3>CSS Style Ryles</h3>
*
* <ul>
* <li>.humanMsgWarn</li>
* </ul>
*
* @param msg the message to show in HTML
* @param shouldLog indicates if this warning should be sent to the in-browser error log
* @param isSafe if this field is true then this just calls showMessage, otherwise it
* runs the specified message through the GWT SaveHtmlUtils
*/
public static void showWarning(String msg, boolean shouldLog, boolean isSafe)
{
if (isSafe) {
showWarning(msg, shouldLog);
} else {
showWarning(SafeHtmlUtils.fromString(msg).asString(), shouldLog);
}
}
/**
* Sets if the message helper should show messages at all.
*
* @param shouldShow true if it should and false otherwise
*/
public static void setShouldShowMessages(boolean shouldShow)
{
g_shouldShow = shouldShow;
setShouldShowMessagesJS(shouldShow);
}
/**
* Gets if the message util is showing messages.
*
* @return true if messages are shown and false otherwise
*/
public static boolean getShouldShowMessages()
{
return g_shouldShow;
}
private static native void setShouldShowMessagesJS(boolean shouldShow) /*-{
$wnd.humanMsg.shouldShow = shouldShow;
}-*/;
private static native void showWarningJS(String msg) /*-{
$wnd.humanMsg.setup();
$wnd.jQuery("#humanMsg").removeClass('humanMsgErr').removeClass('humanMsgInfo').addClass('humanMsgWarn');
$wnd.humanMsg.displayMsg(msg, false);
}-*/;
/**
* <p>
* Show an information message.
* </p>
*
* <p>
* This message has a default style of white text with a black background.
* </p>
*
* <h3>CSS Style Ryles</h3>
*
* <ul>
* <li>.humanMsgInfo</li>
* </ul>
*
* @param msg the message to show in HTML
*/
public static native void showMessage(String msg) /*-{
$wnd.humanMsg.setup();
$wnd.jQuery("#humanMsg").removeClass('humanMsgErr').removeClass('humanMsgWarn').addClass('humanMsgInfo');
$wnd.humanMsg.displayMsg(msg, false);
}-*/;
/**
* <p>
* Show an information message.
* </p>
*
* <p>
* This message has a default style of white text with a black background.
* </p>
*
* <h3>CSS Style Ryles</h3>
*
* <ul>
* <li>.humanMsgInfo</li>
* </ul>
*
* @param msg the message to show in HTML
* @param isSafe if this field is true then this just calls showMessage, otherwise it
* runs the specified message through the GWT SaveHtmlUtils
*/
public static void showMessage(String msg, boolean isSafe)
{
if (isSafe) {
showMessage(msg);
} else {
showMessage(SafeHtmlUtils.fromString(msg).asString());
}
}
/**
* <p>
* Show an warning message.
* </p>
*
* <p>
* This message has a default style of white text with a black background.
* </p>
*
* <h3>CSS Style Ryles</h3>
*
* <ul>
* <li>.humanMsgInfo</li>
* </ul>
*
* @param msg the message to show in HTML
*
* @param className
* the name of the class to apply
*/
public static native void showMessage(String msg, String className) /*-{
$wnd.humanMsg.setup();
$wnd.jQuery("#humanMsg").removeClass('humanMsgErr').removeClass('humanMsgWarn').removeClass('humanMsgInfo').addClass(className);
$wnd.humanMsg.displayMsg(msg, false);
}-*/;
/**
* Show a temporary error message and logs it to the client-side error log
*
* @param msg the message to show in HTML
*/
public static void showError(String msg)
{
showErrorJS(msg);
logError(msg);
}
/**
* <p>
* Show aan error message.
* </p>
*
* <p>
* This message has a default style of black text with a red background.
* </p>
*
* <h3>CSS Style Ryles</h3>
*
* <ul>
* <li>.humanMsgErr</li>
* </ul>
*
* @param errorMsg the error message for the alert in HTML
* @param logMsg the message for the error log in HTML
*/
public static void showError(String errorMsg, String logMsg)
{
showErrorJS(errorMsg);
logError(logMsg);
}
/**
* <p>
* Show aan error message.
* </p>
*
* <p>
* This message has a default style of black text with a red background.
* </p>
*
* <h3>CSS Style Ryles</h3>
*
* <ul>
* <li>.humanMsgErr</li>
* </ul>
*
* @param errorMsg the error message for the alert in HTML
* @param logMsg the message for the error log in HTML
* @param isSafe if this field is true then this just calls showMessage, otherwise it
* runs the specified message through the GWT SaveHtmlUtils
*/
public static void showError(String errorMsg, String logMsg, boolean isSafe)
{
if (isSafe) {
showError(errorMsg, logMsg);
} else {
showError(SafeHtmlUtils.fromString(errorMsg).asString(),
SafeHtmlUtils.fromString(logMsg).asString());
}
}
private static native void showErrorJS(String msg) /*-{
$wnd.humanMsg.setup();
$wnd.jQuery("#humanMsg").removeClass('humanMsgInfo').removeClass('humanMsgWarn').addClass('humanMsgErr');
$wnd.humanMsg.displayMsg(msg, false);
}-*/;
/**
* Write a message to the error log
*
* @param msg the message to show in HTML
*/
public static void logError(String msg)
{
logErrorJS(escapeString(msg));
}
/**
* Write a message to the error log
*
* @param msg the message to show in HTML
*/
public static void logWarning(String msg)
{
logErrorJS(escapeString(msg));
}
private static String escapeString(String s)
{
if (s == null) {
return "";
}
return "<span class=\"weak\">" + JSDateUtil.getShortTime(new Date()) + "</span> " +
s.replaceAll("\\<", "<").replaceAll("\\>", ">");
}
private static native void logErrorJS(String msg) /*-{
$wnd.humanMsg.log(msg);
}-*/;
/**
* Set the title of the error log. It may not contain HTML
*
* @param title the error log title
*/
public static native void setLogTitleJS(String title) /*-{
$wnd.humanMsg.setLogTitle(title);
}-*/;
private static native void createJSFunctions() /*-{
$wnd.spiffyui.showPageLevelWarning = function(msg) {
@org.spiffyui.client.MessageUtil::showPageLevelWarning(Ljava/lang/String;)(msg);
}
$wnd.spiffyui.showFatalError = function(msg) {
@org.spiffyui.client.MessageUtil::showFatalError(Ljava/lang/String;)(msg);
}
$wnd.spiffyui.showError = function(msg) {
@org.spiffyui.client.MessageUtil::showError(Ljava/lang/String;)(msg);
}
$wnd.spiffyui.showWarning = function(msg, shouldLog) {
if (shouldLog === null) {
shouldLog = true;
}
@org.spiffyui.client.MessageUtil::showWarning(Ljava/lang/String;Ljava/lang/Boolean;)(msg,shouldLog);
}
$wnd.spiffyui.showMessage = function(msg) {
@org.spiffyui.client.MessageUtil::showMessage(Ljava/lang/String;)(msg);
}
}-*/;
}
/**
* The error panel show fatal errors in the UI
*/
class ErrorPanel extends Composite implements Event.NativePreviewHandler
{
private Label m_label;
private FlowPanel m_panel;
public ErrorPanel()
{
RootPanel root = RootPanel.get("mainContent");
if (root == null) {
throw new IllegalStateException("Unable to locate the errorpanel element. You must import spiffyui.min.js before using the MessageUtil.");
}
m_panel = new FlowPanel();
m_panel.getElement().setId("errorpanel");
m_label = new Label("", true);
m_panel.add(m_label);
Anchor clear = new Anchor("X");
clear.getElement().setId("errorpanel_hide");
clear.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event)
{
event.preventDefault();
JSUtil.slideUp("#" + m_panel.getElement().getId(), "fast");
}
});
m_panel.add(clear);
m_panel.setVisible(false);
root.insert(m_panel, 0);
//Any click anywhere will close
Event.addNativePreviewHandler(this);
}
/**
* Sets a message in the error panel and makes it visible
*
* @param message
* the message
*/
public void setErrorMessage(String message)
{
makeVisible();
m_label.setText(message);
}
/**
* Appends a message to the error panel and makes it visible
*
* @param message
* the message
*/
public void appendErrorMessage(String message)
{
makeVisible();
m_label.setText(m_label.getText() + message);
}
/**
* Clears the error panel. This method will make the panel invisible.
*/
public void clear()
{
m_label.setText("");
m_panel.setVisible(false);
}
private void makeVisible()
{
if (!m_panel.isVisible()) {
JSUtil.slideDown("#" + m_panel.getElement().getId(), "normal");
}
}
@Override
public void onPreviewNativeEvent(NativePreviewEvent event)
{
if (event.getTypeInt() != Event.ONCLICK) {
return;
}
Element target = Element.as(event.getNativeEvent().getEventTarget());
if (null == target) {
return;
}
//any click on this will dismiss the panel
if (m_panel.getElement().isOrHasChild(target)) {
JSUtil.slideUp("#" + m_panel.getElement().getId(), "fast");
}
}
}
/**
* The page warning shows page level warnings in the UI
*/
class PageWarningPanel extends Composite
{
private Label m_label;
private FlowPanel m_panel;
public PageWarningPanel()
{
RootPanel root = RootPanel.get("main");
if (root == null) {
throw new IllegalStateException("Unable to locate the warning panel element. You must import spiffyui.min.js before using the MessageUtil.");
}
m_panel = new FlowPanel();
m_panel.getElement().setId("pagewarningpanel");
m_label = new Label("", true);
m_panel.add(m_label);
m_panel.setVisible(false);
root.add(m_panel);
}
/**
* Sets a message in the error panel and makes it visible
*
* @param message
* the message
*/
public void setErrorMessage(String message)
{
makeVisible();
m_label.setText(message);
}
/**
* Appends a message to the error panel and makes it visible
*
* @param message
* the message
*/
public void appendErrorMessage(String message)
{
makeVisible();
m_label.setText(m_label.getText() + message);
}
/**
* Clears the error panel. This method will make the panel invisible.
*/
public void clear()
{
m_label.setText("");
m_panel.setVisible(false);
}
private void makeVisible()
{
if (!m_panel.isVisible()) {
JSUtil.slideDown("#" + m_panel.getElement().getId(), "normal");
JSUtil.hide("mainBody");
}
}
}