package com.onaro.util.jfc; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.font.TextAttribute; import java.util.HashMap; import java.util.Map; import javax.swing.JLabel; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * Factory that creates labels various fonts based on type and value status. * * TODO: Currently this class is geared fairly specifically to summary * or landing pages. For example, the choice of font family and sizes. * We should consider changing its name to something more summary page-specific, * or parameterizing in some way the pre-defined fonts, and/or splitting * up this class in some general-purpose and summary page-specific classes. */ public enum TextComponentFactory { // Our single instance INSTANCE; private static final Logger logger = LogManager.getLogger (TextComponentFactory.class); // Note: other contenders: "Verdana", "Trebuchet MS", "Tahoma" and "Lucida Sans"; //$NON-NLS-1$ static final String LABEL_FONT_NAME = Font.DIALOG; /* * TODO: Determine final colors when problem indicator work is done. * Ideally use platform look and feel settings. */ public static final Color NORMAL_VALUE_COLOR = Color.BLACK; public static final Color ERROR_VALUE_COLOR = Color.RED; public static final Color WARNING_VALUE_COLOR = new Color (160, 96, 32); // Brown // public static final Color WARNING_VALUE_COLOR = NORMAL_VALUE_COLOR; // public static final Color WARNING_VALUE_COLOR = ERROR_VALUE_COLOR; public static final Color BACKGROUND_COLOR = Color.WHITE; public static final Color LABEL_TEXT_COLOR = new Color (112, 112, 112); // A tad darker than GRAY ~ 44% public static final Color HEADING_TEXT_COLOR = LABEL_TEXT_COLOR; // Not used in anything visible right now, but keeping the same as label text // Create underline text attribute for underlining a font. private static final Map UNDERSCORE_ATTRIBUTE = new HashMap(); static { UNDERSCORE_ATTRIBUTE.put (TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); } /** * Styles that can be applied to LabelFonts. */ public enum LabelStyle { PLAIN, BOLD, ITALIC, BOLD_ITALIC, UNDERSCORE } /** * Fonts to use for labels or other fields. */ public enum LabelFont { TITLE (18, Font.PLAIN), HEADING (16, Font.PLAIN), SUBHEADING (13, Font.PLAIN), BODY (13, Font.PLAIN), BODY_WARNING (13, Font.ITALIC), FOOTNOTE (11, Font.PLAIN); private final Font font; private LabelFont (int size, int style) { font = new Font (LABEL_FONT_NAME, style, size); } /** * Gets the pre-defined font. * @return the plain-defined font */ public Font getFont() { return font; } /** * Derives a font from the plain font. * @param style {@link TextComponentFactory.LabelStyle} * @return the derived font * @see Font#deriveFont (int) * @see Font#deriveFont (float) */ public Font deriveFont (LabelStyle style) { /* * Note derived fonts are cached automatically by * sun.font.FontManager. */ switch (style) { case PLAIN: return font.deriveFont (Font.PLAIN); case BOLD: return font.deriveFont (Font.BOLD); case ITALIC: return font.deriveFont (Font.ITALIC); case BOLD_ITALIC: return font.deriveFont (Font.BOLD + Font.ITALIC); case UNDERSCORE: return font.deriveFont (UNDERSCORE_ATTRIBUTE); } logger.warn ("Unsupported LabelStyle " + style); //$NON-NLS-1$ return font; } } /** * Colors to use for values, depending on their health status. */ public enum ValueStatus { /** * ERROR_VALUE is used to highlight a specific value, * such as -1 (indicating no data) for capacity values. */ ERROR_VALUE (ERROR_VALUE_COLOR), /** * WARNING_VALUE is used to highlight a specific value, * such as a value used when auto tiering is in effect. * NOTE: Not currently highlighting warning values. */ WARNING_VALUE (NORMAL_VALUE_COLOR), /** * ERROR_UNDER is used to highlight values below a * threshold. */ ERROR_UNDER (ERROR_VALUE_COLOR), /** * WARNING_UNDER is used to highlight values below a * threshold, but at or above the threshold for * ERROR_UNDER. */ WARNING_UNDER (WARNING_VALUE_COLOR), /** * NORMAL is used to for values that should not * be highlighted. */ NORMAL (NORMAL_VALUE_COLOR), /** * WARNING_OVER is used to highlight values above a * threshold, but at or below the threshold for * ERROR_OVER. */ WARNING_OVER (WARNING_VALUE_COLOR), /** * ERROR_OVER is used to highlight values above a * threshold. */ ERROR_OVER (ERROR_VALUE_COLOR); private Color color; private ValueStatus (Color color) { this.color = color; } /** * Gets the color of a ValueStatus. * @return {@link Color} */ public Color getColor() { return (color); } /** * Indicates if status represents an error. * @return {@code true} if status is an error status; * {@code false} otherwise */ public boolean isError() { // TODO: Shouldn't rely on color assignments. return color == ERROR_VALUE_COLOR; } /** * Indicates if status represents a warning. * @return {@code true} if status is a warning status; * {@code false} otherwise */ public boolean isWarning() { // TODO: Shouldn't rely on color assignments. return color == WARNING_VALUE_COLOR; } /** * Indicates if status represents normal state, * not a warning or error. * @return {@code true} if status is normal; * {@code false} otherwise */ public boolean isNormal() { // TODO: Shouldn't rely on color assignments. return color == NORMAL_VALUE_COLOR; } } /** * Changes appearance of component to indicate its highlight state. * @param comp {@link Component} * @param isHighlighted */ public static void renderHighlight (Component comp, boolean isHighlighted) { if (isHighlighted) { comp.setForeground (ERROR_VALUE_COLOR); } else { comp.setForeground (NORMAL_VALUE_COLOR); } } /** * Changes appearance of component to indicate its status. * @param comp * @param status {@link ValueStatus} */ public static void renderHighlight (Component comp, ValueStatus status) { comp.setForeground (status.getColor()); } /** * Makes a component use a plain (roman) font. Has no effect if * the font is already plain. * @param comp */ public static void makeFontPlain (Component comp) { Font font = comp.getFont(); if (font.getStyle() != Font.PLAIN) { comp.setFont (font.deriveFont (Font.PLAIN)); } } /** * Makes a component use a bold roman font. Has no effect if * the font is already bold and non-italic. * @param comp */ public static void makeFontBold (Component comp) { Font font = comp.getFont(); if (font.getStyle() != Font.BOLD) { comp.setFont (font.deriveFont (Font.BOLD)); } } /** * Makes a component use an italic roman font. Has no effect if * the font is already italic. * @param comp */ public static void makeFontItalic (Component comp) { Font font = comp.getFont(); if (font.getStyle() != Font.ITALIC) { comp.setFont (font.deriveFont (Font.ITALIC)); } } /** * An enumeration of values that represent null data. The * {@link #getDisplayText} method may be used to display * a more specific reason why there's no data, rather * than just displaying nothing when the value is null. *

* TODO: Extend this with methods to get a help context * that might contain a more detailed explanation. Might * also add a getDescription method to get a slightly * longer description useful for display in a tooltip. *

* TODO: Consider integrating this with NumberValue, for * use in addressing * * US4133: Display "not available", "indeterminate", "incomplete", * "irrelevant", "not acquired", and "invalid" values consistently. */ public enum NullValue { INCOMPLETE (Messages.INSTANCE.getIncompleteValue()), INDETERMINATE (Messages.INSTANCE.getIndeterminateValue()), INVALID (Messages.INSTANCE.getInvalidValue()), IRRELEVANT (Messages.INSTANCE.getIrrelevantValue()), NONE (Messages.INSTANCE.getNoneValue()), NOT_ACQUIRED (Messages.INSTANCE.getNotAcquiredValue()), UNDEFINED (Messages.INSTANCE.getUndefinedValue()); private final String displayText; private NullValue (String displayText) { this.displayText = displayText; } /** * Gets a short explanation of the null value, * suitable for display in a field or table cell. * @return explanation */ public String getDisplayText() { return displayText; } } /** * Creates a label. * @param text displayed in label * @param font {@link LabelFont} * @return {@link JLabel} */ public static JLabel createLabel (String text, LabelFont font) { JLabel label = new JLabel (text); label.setName (text); label.setFont (font.getFont()); label.setForeground (LABEL_TEXT_COLOR); return label; } /** * Creates a label for a field component. * @param text displayed in label * @param font {@link LabelFont} * @param comp {@link Component} to be labeled * @return {@link JLabel} * @see JLabel#setLabelFor */ public static JLabel createLabel (String text, LabelFont font, Component comp) { final JLabel label = createLabel (text, font); label.setLabelFor (comp); // Hide label if field component is hidden. if (! comp.isVisible()) { label.setVisible (false); } // Hide or show label when field component is shown or hidden. comp.addComponentListener (new ComponentAdapter() { @Override public void componentHidden (ComponentEvent event) { label.setVisible (false); } @Override public void componentShown (ComponentEvent event) { label.setVisible (true); } }); return label; } /** * Creates an accordion label. * @param text displayed in label * @param font {@link LabelFont} * @return {@link JLabel} */ public static Accordion createAccordionLabel (String text, LabelFont font) { ButtonField button = new ButtonField (text, font); button.setForeground (LABEL_TEXT_COLOR); return new Accordion (button); } }