/* * RHQ Management Platform * Copyright 2010-2014, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.coregui.client.util.message; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Timer; import com.smartgwt.client.types.Overflow; import com.smartgwt.client.types.Positioning; import com.smartgwt.client.util.SC; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.HTMLFlow; import com.smartgwt.client.widgets.events.DoubleClickEvent; import com.smartgwt.client.widgets.events.DoubleClickHandler; import com.smartgwt.client.widgets.events.RightMouseDownEvent; import com.smartgwt.client.widgets.events.RightMouseDownHandler; import com.smartgwt.client.widgets.menu.Menu; import com.smartgwt.client.widgets.menu.MenuItem; import com.smartgwt.client.widgets.menu.MenuItemIfFunction; import com.smartgwt.client.widgets.menu.events.ClickHandler; import com.smartgwt.client.widgets.menu.events.MenuItemClickEvent; import org.rhq.coregui.client.CoreGUI; import org.rhq.coregui.client.menu.MenuBarView; import org.rhq.coregui.client.util.enhanced.Enhanced; import org.rhq.coregui.client.util.message.Message.Severity; /** * A bar for displaying a message at the top of a page - the equivalent of the JSF h:messages component. * The message will be displayed for 30 seconds and then will be automatically cleared unless * it is a sticky message. * * @author Ian Springer * @author Jay Shaughnessy * @author Libor Zoubek */ public class MessageBar extends Canvas implements MessageCenter.MessageListener, Enhanced { public static final int Z_INDEX = 999998; private static final int AUTO_HIDE_DELAY_MILLIS = 30000; private static final String NON_BREAKING_SPACE = " "; private HTMLFlow content; private Message currentMessage; private Message stickyMessage; // this message will always be shown until dismissed by user. private Menu showDetailsMenu; private Timer messageClearingTimer; public MessageBar() { super(); setOverflow(Overflow.VISIBLE); setHeight(1); setWidth(1); content = new HTMLFlow(); content.setPosition(Positioning.ABSOLUTE); injectFunctions(this); showDetailsMenu = new Menu(); MenuItem showDetailsMenuItem = new MenuItem(MSG.view_messageCenter_messageBarShowDetails()); showDetailsMenuItem.addClickHandler(new ClickHandler() { @Override public void onClick(MenuItemClickEvent event) { MessageCenterView.showDetails(MessageBar.this.currentMessage); } }); MenuItem showRootCauseMenuItem = new MenuItem(MSG.view_messageCenter_messageRootCause()); showRootCauseMenuItem.addClickHandler(new ClickHandler() { @Override public void onClick(MenuItemClickEvent event) { Message msg = MessageBar.this.currentMessage; if (msg != null) { String rootCause = msg.getRootCauseMessage(); if (rootCause != null) { SC.say(MSG.view_messageCenter_messageRootCause(), rootCause); } } } }); showRootCauseMenuItem.setEnableIfCondition(new MenuItemIfFunction() { public boolean execute(Canvas target, Menu menu, MenuItem item) { Message msg = MessageBar.this.currentMessage; return msg != null && msg.getRootCauseMessage() != null; } }); showDetailsMenu.setItems(showRootCauseMenuItem, showDetailsMenuItem); } // This is our JSNI method that will be called on form submit private native void injectFunctions(MessageBar self) /*-{ $wnd.__gwt_messageBarDismiss = $entry(function(){ self.@org.rhq.coregui.client.util.message.MessageBar::reset()(); }); }-*/; @Override protected void onDraw() { super.onDraw(); setLabelEmpty(); // sometimes it's annoying to have the error message hang around for too long; // let the user click the message so it goes away on demand content.addDoubleClickHandler(new DoubleClickHandler() { @Override public void onDoubleClick(DoubleClickEvent event) { clearMessage(true); } }); content.addRightMouseDownHandler(new RightMouseDownHandler() { @Override public void onRightMouseDown(RightMouseDownEvent event) { if (MessageBar.this.currentMessage != null) { showDetailsMenu.showContextMenu(); } } }); CoreGUI.getMessageCenter().addMessageListener(this); } @Override public void onMessage(Message message) { if (!message.isBackgroundJobResult()) { if (this.messageClearingTimer != null) { this.messageClearingTimer.cancel(); } this.currentMessage = message; updateLabel(message); // Auto-clear the message after some time unless it's been designated as sticky. if (message.isSticky()) { this.stickyMessage = message; } else { this.messageClearingTimer = new Timer() { public void run() { clearMessage(false); // if we had a sticky message before, show it again, now that our more recent message has gone away if (stickyMessage != null) { updateLabel(stickyMessage); } } }; this.messageClearingTimer.schedule(AUTO_HIDE_DELAY_MILLIS); } } } public void reset() { clearMessage(true); } public void clearMessage(boolean clearSticky) { this.currentMessage = null; setLabelEmpty(); setZIndex(0); markForRedraw(); if (clearSticky) { this.stickyMessage = null; } } private void setLabelEmpty() { content.setContents(""); } private String messageContent(String message, Severity severity) { final String closeBtn = "<button type='button' class='close' onclick='__gwt_messageBarDismiss();'>" +"<span class='pficon pficon-close'></span>" +"</button>"; StringBuilder sb = new StringBuilder(); switch (severity) { case Blank: { sb.append("<div class='alert alert-success' style='float:right; z-index: " + Z_INDEX + ";'>"); sb.append("<span class='pficon pficon-ok'></span>"); break; } case Info: { sb.append("<div class='alert alert-info' style='float:right; z-index: " + Z_INDEX + ";'>"); sb.append(closeBtn); sb.append("<span class='pficon pficon-info'></span>"); break; } case Warning: { sb.append("<div class='alert alert-warning' style='float:right; z-index: " + Z_INDEX + ";'>"); sb.append(closeBtn); sb.append("<span class='pficon-layered'>"); sb.append(" <span class='pficon pficon-warning-triangle'></span>"); sb.append(" <span class='pficon pficon-warning-exclamation'></span>"); sb.append("</span>"); break; } case Fatal: case Error: { sb.append("<div class='alert alert-danger' style='float:right; z-index: " + Z_INDEX + ";'>"); sb.append(closeBtn); sb.append("<span class='pficon-layered'>"); sb.append(" <span class='pficon pficon-error-octagon'></span>"); sb.append(" <span class='pficon pficon-error-exclamation'></span>"); sb.append("</span>"); break; } default: { sb.append("<div class='alert alert-info' style='z-index: " + Z_INDEX + ";'>"); sb.append(closeBtn); sb.append("<span class='pficon pficon-info'></span>"); } } sb.append(message); sb.append("</div>"); return sb.toString(); } private void updateLabel(Message message) { content.hide(); String contents; if (message.getConciseMessage() != null) { contents = message.getConciseMessage(); } else if (message.getRootCauseMessage() != null) { contents = message.getRootCauseMessage(); } else { contents = message.getDetailedMessage(); } content.setContents(messageContent(contents, message.getSeverity())); int left = MenuBarView.getUlLeftCoordinate(); int ulWidth = MenuBarView.getUlWidth(); content.setLeft(left); content.setWidth((ulWidth - left - 10) + "px"); content.setTop("34px"); content.redraw(); content.show(); } }