package tmcsim.client.cadscreens.view; import java.awt.Color; import java.util.Observable; import java.util.Observer; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JTextPane; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; import tmcsim.common.CADEnums.CADScreenNum; import tmcsim.common.CADEnums.TEXT_STYLES; /** * CADFooterView is the base view class for the footer information displayed on * all CAD Screens. The footer is used to display the following information to * the user: *
* *
* The refreshView() method is used to add text/style pairs for the footer to the * local Document object. Update methods are provided to modify values from the * previous list. These updates only modify the portion of the footer that has * changed. This reduces redraw of the entire footer everytime a single value * changes. * * * @author Matthew Cechini * @version */ public class CADFooterView implements Observer { /** Error Logger. */ private static Logger viewLogger = Logger.getLogger("tmcsim.client.cadscreens"); /** Font size for text displayed on CAD Screen */ private static final int FONT_SIZE = 15; /** Maximum information message length */ private static final int MAX_INFO_MESSAGE_LENGTH = 50; /** * Enumeration containing document position values for specific text items. * @author Matthew Cechini */ private static enum DOCUMENT_POSITIONS { /** Document position of the screen update status. */ UPDATE_STATUS_DOC_POS (260), /** Document position of the CAD date. */ CAD_DATE_DOC_POS (245), /** Document position of the CAD time. */ CAD_TIME_DOC_POS (250), /** Document position of the routed messages count. */ ROUTED_MESSAGE_DOC_POS (297), /** Document position of the page scrolling text. */ PAGE_SCROLLING_DOC_POS (272), /** Document position of the information message text. */ INFO_MESSAGE_DOC_POS (81); public int pos; private DOCUMENT_POSITIONS(int p) { pos = p; } } /** Document displaying CAD Screen text. */ private Document theDoc = null; /** JTextPane displaying CAD Screen text. */ private JTextPane stylePane = null; /** Current page scrolling text. */ private String pageScrolling = null; /** Current CAD Date text. */ private String theCADDate = null; /** Current CAD Time text. */ private String theCADTime = null; /** Current number of routed messages. */ private int numberRoutedMessages; /** Current flag of whether there are unread routed messages. */ private boolean unreadRoutedMessages; /** Current CAD Screen number. */ private CADScreenNum currentCADScreenNum; /** Current update status for all CAD screens. */ private TreeMap screenUpdateMap; /** * Constructor. Initialize data elements and styles. * * @param viewDoc Target Document for text display. */ public CADFooterView(Document viewDoc) { numberRoutedMessages = 0; currentCADScreenNum = CADScreenNum.ONE; unreadRoutedMessages = false; screenUpdateMap = new TreeMap(); for(CADScreenNum screen : CADScreenNum.orderedList()) { screenUpdateMap.put(screen, false); } theDoc = viewDoc; initStyles(); } /** * This method implements the Observer interface method. The footer * is set up to observe the main cad screen and listen for page * scrolling text updates. The update Object argument is cast * to a string and the page scrolling text is replaced in the * footer's display Document. */ public void update(Observable o, Object arg) { pageScrolling = (String)arg; try { if(theDoc.getLength() > 0) { theDoc.remove( DOCUMENT_POSITIONS.PAGE_SCROLLING_DOC_POS.pos, pageScrolling.length()); theDoc.insertString( DOCUMENT_POSITIONS.PAGE_SCROLLING_DOC_POS.pos, pageScrolling, stylePane.getStyle(TEXT_STYLES.YELLOW.style)); } } catch( BadLocationException ble) { viewLogger.log(Level.SEVERE, "Exception in updating view document.", ble); } } /** * Sets the footer's current CADScreen number. * * @param screenNum New CADScreen number. */ public void setCADScreenNum(CADScreenNum screenNum) { currentCADScreenNum = screenNum; } /** * This method updates the CAD Screen update portion of the footer. * The screenUpdateMap is updated with the new update boolean * values from the parameter map. The footer text is then * updated with the new updates. Screens with an update appear * in yellow text, those without in green. * * @param newStatus Map of CADScreenNum objects and their boolean update * values. Map entries for all CADScreenNum values are not needed. */ public void updateStatus(TreeMap newUpdates) { for(CADScreenNum screen : CADScreenNum.orderedList()) { if(newUpdates.get(screen) != null) { screenUpdateMap.put(screen, newUpdates.get(screen)); } } try { if(theDoc.getLength() > 0) { for(CADScreenNum screen : CADScreenNum.orderedList()) { if(newUpdates.get(screen) != null && newUpdates.get(screen)) { theDoc.remove( DOCUMENT_POSITIONS.UPDATE_STATUS_DOC_POS.pos + ((screen.intNum-1)*3), 1); theDoc.insertString( DOCUMENT_POSITIONS.UPDATE_STATUS_DOC_POS.pos + ((screen.intNum-1)*3), String.valueOf(screen.intNum), stylePane.getStyle(TEXT_STYLES.YELLOW.style)); } } } } catch (BadLocationException ble) { viewLogger.log(Level.SEVERE, "Exception in updating view document.", ble); } } /** * This method updates the date portion of the footer. Only * those digits in the date that have changed are changed. * * @param newDate The new date with format: MMYY */ public void updateDate(String newDate) { try { if(theDoc.getLength() > 0) { for(int i = 0; i < 4; i++) { if(theCADDate.charAt(i) != newDate.charAt(i)) { theDoc.remove( DOCUMENT_POSITIONS.CAD_DATE_DOC_POS.pos+(i), 1); theDoc.insertString( DOCUMENT_POSITIONS.CAD_DATE_DOC_POS.pos + (i), String.valueOf(newDate.charAt(i)), stylePane.getStyle(TEXT_STYLES.GREEN.style)); } } } } catch (BadLocationException ble) { viewLogger.log(Level.SEVERE, "Exception in updating view document.", ble); } finally { theCADDate = newDate; } } /** * This method updates the time portion of the footer. Only * those digits in the time that have changed are changed. * * @param newTime The new time with format: HHMM */ public void updateTime(String newTime) { try { if(theDoc.getLength() > 0) { for(int i = 0; i < 4; i++) { if(theCADTime.charAt(i) != newTime.charAt(i)) { theDoc.remove( DOCUMENT_POSITIONS.CAD_TIME_DOC_POS.pos +(i), 1); theDoc.insertString( DOCUMENT_POSITIONS.CAD_TIME_DOC_POS.pos + (i), String.valueOf(newTime.charAt(i)), stylePane.getStyle(TEXT_STYLES.GREEN.style)); } } } } catch (BadLocationException ble) { viewLogger.log(Level.SEVERE, "Exception in updating view document.", ble); } finally { theCADTime = newTime; } } /** * This method updates the queued messages portion of the footer. The * parameter boolean value specifies whether there are unread messages * or not. If unread messages exist, the number of messages is highlighted * with green and the text is displayed yellow. If there are no unread * messages, the text is displayed unhighlighted and with green text. * * @param unread Boolean flag to toggle unread message highlighting. true * if unread messages exist, false if not. */ public void updateUnreadMessages(Boolean unread) { unreadRoutedMessages = unread; try { if(theDoc.getLength() > 0) { theDoc.remove( DOCUMENT_POSITIONS.ROUTED_MESSAGE_DOC_POS.pos, String.valueOf(numberRoutedMessages).length()); if(unreadRoutedMessages) { theDoc.insertString( DOCUMENT_POSITIONS.ROUTED_MESSAGE_DOC_POS.pos, String.valueOf(numberRoutedMessages), stylePane.getStyle(TEXT_STYLES.GREEN_HIGHLIGHT.style)); } else { theDoc.insertString( DOCUMENT_POSITIONS.ROUTED_MESSAGE_DOC_POS.pos, String.valueOf(numberRoutedMessages), stylePane.getStyle(TEXT_STYLES.GREEN.style)); } } } catch (BadLocationException ble) { viewLogger.log(Level.SEVERE, "Exception in updating view document.", ble); } } /** * This method updates the queued messages portion of the footer. The * parameter value is used to update the number of received routed * messages to this CAD position. The current number of messages is * removed from the document and replaced with the new number. If the * number of messages is 0, the text is written in yellow, else the text * is written in green. * * @param newMessageCount Number of routed messages. */ public void updateRoutedMessageCount(Integer newMessageCount) { numberRoutedMessages = newMessageCount; try { if(theDoc.getLength() > 0) { theDoc.remove( DOCUMENT_POSITIONS.ROUTED_MESSAGE_DOC_POS.pos, newMessageCount.toString().length()); if(numberRoutedMessages > 0) { theDoc.insertString( DOCUMENT_POSITIONS.ROUTED_MESSAGE_DOC_POS.pos, String.valueOf(numberRoutedMessages), stylePane.getStyle(TEXT_STYLES.YELLOW.style)); } else { theDoc.insertString( DOCUMENT_POSITIONS.ROUTED_MESSAGE_DOC_POS.pos, String.valueOf(numberRoutedMessages), stylePane.getStyle(TEXT_STYLES.GREEN.style)); } } } catch (BadLocationException ble) { viewLogger.log(Level.SEVERE, "Exception in updating view document.", ble); } } /** * This method displays an informational message on the info line of the * footer. The message to be displayed will be truncated to the maximum * length which specified by the final static MAX_INFO_MESSAGE_LENGTH. * Text output is written in white. * * @param message Message to display. */ public void displayInfoMessage(String message) { try { theDoc.remove( DOCUMENT_POSITIONS.INFO_MESSAGE_DOC_POS.pos, MAX_INFO_MESSAGE_LENGTH); //TODO test truncation if(message.length() > MAX_INFO_MESSAGE_LENGTH) message = message.substring(0, MAX_INFO_MESSAGE_LENGTH); while(message.length() < MAX_INFO_MESSAGE_LENGTH) message += " "; theDoc.insertString( DOCUMENT_POSITIONS.INFO_MESSAGE_DOC_POS.pos, message, stylePane.getStyle(TEXT_STYLES.WHITE.style)); } catch (BadLocationException ble) { viewLogger.log(Level.SEVERE, "Exception in updating view document.", ble); } } /** * This method clears the display Document object and then adds text/style * pairs to create the footer display document. A leading line of 80 '=' * characters in aqua is added for CAD Screen formatting, followed by a * blank line used to display info messages. The footer items then added in * the following order: * *
    *
  • CAD Date
  • *
  • CAD Time
  • *
  • Screen Updates
  • *
  • Page Scrolling
  • *
  • Queued Message Count/Update
  • *
  • Current CAD Screen Number
  • *
*/ public void refreshView() { try { theDoc.remove(0, theDoc.getLength()); //Load the text pane with styled text. theDoc.insertString(theDoc.getLength(), "==========================" + "======================================================\n", stylePane.getStyle(TEXT_STYLES.AQUA.style)); theDoc.insertString(theDoc.getLength(), rPad("", 80) + "\n", stylePane.getStyle(TEXT_STYLES.BLACK.style)); theDoc.insertString(theDoc.getLength(), rPad("", 80) + "\n", stylePane.getStyle(TEXT_STYLES.AQUA.style)); theDoc.insertString(theDoc.getLength(), theCADDate +"/", stylePane.getStyle(TEXT_STYLES.GREEN.style)); theDoc.insertString(theDoc.getLength(), rPad(theCADTime, 5), stylePane.getStyle(TEXT_STYLES.GREEN.style)); theDoc.insertString(theDoc.getLength(), "REF: ", stylePane.getStyle(TEXT_STYLES.GREEN.style)); for(CADScreenNum screen : CADScreenNum.orderedList()) { if(screenUpdateMap.get(screen)) { theDoc.insertString(theDoc.getLength(), String.valueOf(screen.intNum), stylePane.getStyle(TEXT_STYLES.YELLOW.style)); } else { theDoc.insertString(theDoc.getLength(), String.valueOf(screen.intNum), stylePane.getStyle(TEXT_STYLES.GREEN.style)); } theDoc.insertString(theDoc.getLength(), " ", stylePane.getStyle(TEXT_STYLES.GREEN.style)); } theDoc.insertString(theDoc.getLength(), pageScrolling, stylePane.getStyle(TEXT_STYLES.YELLOW.style)); theDoc.insertString(theDoc.getLength(), rPad(lPad("CAD: 0 0 0", 18), 20), stylePane.getStyle(TEXT_STYLES.GREEN.style)); if(unreadRoutedMessages) theDoc.insertString(theDoc.getLength(), String.valueOf(numberRoutedMessages), stylePane.getStyle(TEXT_STYLES.GREEN_HIGHLIGHT.style)); else theDoc.insertString(theDoc.getLength(), String.valueOf(numberRoutedMessages), stylePane.getStyle(TEXT_STYLES.GREEN.style)); theDoc.insertString(theDoc.getLength(), lPad("CLETS: 0 0", 13), stylePane.getStyle(TEXT_STYLES.GREEN.style)); theDoc.insertString(theDoc.getLength(), rPad(lPad("MIS: 0", 8), 10), stylePane.getStyle(TEXT_STYLES.GREEN.style)); theDoc.insertString(theDoc.getLength(), String.valueOf(currentCADScreenNum.intNum), stylePane.getStyle("red")); } catch (BadLocationException ble) { viewLogger.log(Level.SEVERE, "Exception in updating view document.", ble); } } /** * Method pads the parameter string with spaces to the right * of the string until the string length is equal to the parameter * length. If the parameter width is less than the length of the * parameter String, no action is taken. * * @param str String to pad. * @param width Desired string length. * @return Padded string. */ protected String rPad(String str, int width) { StringBuffer buf = new StringBuffer(str); while(buf.length() < width) buf.append(" "); return buf.toString(); } /** * Method pads the parameter string with spaces to the left * of the string until the string length is equal to the parameter * length. If the parameter width is less than the length of the * parameter String, no action is taken. * * @param str String to pad. * @param width Desired string length. * @return Padded string. */ protected String lPad(String str, int width) { StringBuffer buf = new StringBuffer(str); while(buf.length() < width) buf.insert(0, " "); return buf.toString(); } /** * This method intializes the stylePane with the styles found in the * TEXT_STYLES enumeration that are needed for footer display. * The value of the static FONT_SIZE is used for text sizing, along * with the COURIER font style. */ private void initStyles() { stylePane = new JTextPane(); Style def = StyleContext.getDefaultStyleContext(). getStyle(StyleContext.DEFAULT_STYLE); Style regular = stylePane.addStyle(TEXT_STYLES.REGULAR.style, def); StyleConstants.setFontFamily(def, TEXT_STYLES.COURIER.style); Style s = stylePane.addStyle(TEXT_STYLES.ITALIC.style, regular); StyleConstants.setItalic(s, true); s = stylePane.addStyle(TEXT_STYLES.BOLD.style, regular); StyleConstants.setBold(s, true); s = stylePane.addStyle(TEXT_STYLES.BLUE.style, regular); StyleConstants.ColorConstants.setForeground(s, Color.blue); StyleConstants.setFontSize(s, FONT_SIZE); s = stylePane.addStyle(TEXT_STYLES.AQUA.style, regular); StyleConstants.ColorConstants.setForeground(s, new Color(0,128,128)); StyleConstants.setFontSize(s, FONT_SIZE); s = stylePane.addStyle(TEXT_STYLES.RED.style, regular); StyleConstants.ColorConstants.setForeground(s, Color.red); StyleConstants.setFontSize(s, FONT_SIZE); s = stylePane.addStyle(TEXT_STYLES.GRAY.style, regular); StyleConstants.ColorConstants.setForeground(s, Color.gray); StyleConstants.setFontSize(s, FONT_SIZE); s = stylePane.addStyle(TEXT_STYLES.CYAN.style, regular); StyleConstants.ColorConstants.setForeground(s, Color.cyan); StyleConstants.setFontSize(s, FONT_SIZE); s = stylePane.addStyle(TEXT_STYLES.YELLOW.style, regular); StyleConstants.ColorConstants.setForeground(s, Color.yellow); StyleConstants.setFontSize(s, FONT_SIZE); s = stylePane.addStyle(TEXT_STYLES.WHITE.style, regular); StyleConstants.ColorConstants.setForeground(s, Color.white); StyleConstants.setFontSize(s, FONT_SIZE); s = stylePane.addStyle(TEXT_STYLES.GREEN.style, regular); StyleConstants.ColorConstants.setForeground(s, Color.green); StyleConstants.setFontSize(s, FONT_SIZE); s = stylePane.addStyle(TEXT_STYLES.REVERSE_GREEN.style, regular); StyleConstants.ColorConstants.setBackground(s, Color.green); StyleConstants.ColorConstants.setForeground(s, Color.black); StyleConstants.setFontSize(s, FONT_SIZE); s = stylePane.addStyle(TEXT_STYLES.GREEN_HIGHLIGHT.style, regular); StyleConstants.ColorConstants.setBackground(s, Color.green); StyleConstants.ColorConstants.setForeground(s, Color.yellow); StyleConstants.setFontSize(s, FONT_SIZE); } }