package org.expeditee.auth.mail.gui; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.expeditee.auth.AuthenticatorBrowser; import org.expeditee.core.Clip; import org.expeditee.core.Colour; import org.expeditee.core.Dimension; import org.expeditee.core.Font; import org.expeditee.core.Image; import org.expeditee.gio.EcosystemManager; import org.expeditee.gio.GraphicsManager; import org.expeditee.gui.DisplayController; import org.expeditee.gui.FrameCreator; import org.expeditee.gui.FrameGraphics; import org.expeditee.gui.FrameIO; import org.expeditee.gui.MessageBay; import org.expeditee.items.Item; import org.expeditee.items.Text; import org.expeditee.settings.UserSettings; public class MailBay { public static final String EXPEDITEE_MAIL_FRAMESET_NAME = "expediteemail"; /** The y position of the header to the mail bay. */ private static final int HEADER_OFFSET_Y = 15; /** Space between mail messages */ private static final int SPACING = 25; /** The (x,y) of the top message. */ private static final int MESSAGE_OFFSET_Y = 15 + SPACING; private static final int OFFSET_X = 20; /** Buffer image of the mail window. */ private static Image _mailBuffer; /** The list of messages shown in the mail bay. */ private static List _previewMessages = new LinkedList(); private static List _messages = new LinkedList(); /** Font used for mail messages. */ private static Font _messageFont = new Font("Serif-Plain-16"); /** Used to number messages. */ private static int _messageCount; /** Creator for creating the mail frames. */ private static FrameCreator _creator = null; /** The currently logged in user, consulted when deciding if a new FrameCreator is needed. */ private static String _forUser = UserSettings.UserName.get(); /** The link that the preview pane displays pointing towards unprocessed messages. */ private static Text _mailLink = new Text(-2, "@Mail", Colour.BLACK, Colour.WHITE); /** Wether the link has been drawn before. */ private static boolean isLinkInitialized = false; /** The position of the mail link. */ private static int MAIL_LINK_Y_OFFSET = 100; private static int MAIL_LINK_X = 50; /** * Obtain the two messages shown at the bottom of the screen as a preview to the entire collection of mail. * @return */ public static List getPreviewMessages() { return _previewMessages; } /** * An item is a 'preview mail item' if it is currently being previewed at the bottom of the screen. * @param i * @return */ public static boolean isPreviewMailItem(Item i) { return _previewMessages.contains(i) || i == _mailLink; } public static void disconnect() { if (_forUser != UserSettings.UserName.get()) { _creator = null; _forUser = UserSettings.UserName.get(); } } /** * Adds a message to the MailBay. * @param message The basic text of the message, what is displayed in the bay window down the bottom. * @options A map describing the buttons to be provided as reply options (Button Text, Action to run) * @return */ public synchronized static Text addMessage(String timestamp, String message, String message2, Map options) { // Invalidate whole area DisplayController.invalidateArea(DisplayController.getMessageBayPaintArea()); // Ensure frame creator if (_creator == null || _forUser != UserSettings.UserName.get()) { _forUser = UserSettings.UserName.get(); _creator = new FrameCreator(EXPEDITEE_MAIL_FRAMESET_NAME, FrameIO.MAIL_PATH, EXPEDITEE_MAIL_FRAMESET_NAME, FrameCreator.ExistingFramesetOptions.AppendAfterLastItem, false, AuthenticatorBrowser.PROFILEENCRYPTIONLABEL); } // We have enough space for the header + 2 preview messages if (_previewMessages.size() >= 2) { _previewMessages.remove(0); for (Item i : _previewMessages) { i.setY(i.getY() - SPACING); } } // Add new message Mail mail = new Mail(message, message2, options); Text t = mail.getPreviewMessage(true); _messages.add(t); _creator.addText(timestamp, Colour.BLACK, null, null, false); for (Text line: mail.getMessage()) { _creator.addItem(line.copy(), false); } t.setLink(_creator.getCurrentFrame().getName()); _previewMessages.add(t); _creator.addSpace(SPACING); _creator.save(); // Make sure the link points to the latest frame _mailLink.setLink(_creator.getCurrent()); DisplayController.requestRefresh(true); return t; } /** * Obtains the image item that is drawn to display the mail bay. * @param clip * @param size * @return */ public static Image getImage(Clip clip, Dimension size) { // Can't get an image with an invalid size if (size == null || size.width <= 0 || size.height <= 0) { return null; } // Update the buffer updateBuffer(Item.DEFAULT_BACKGROUND, clip, size); // Return the image buffer return _mailBuffer; } public static void clear() { getPreviewMessages().clear(); _messageCount = 0; } public static Item getMailLink() { return _mailLink; } public static void ensureLink() { if (_mailLink.getLink() == null && FrameIO.canAccessFrame(MailBay.EXPEDITEE_MAIL_FRAMESET_NAME + 1)) { _mailLink.setLink(MailBay.EXPEDITEE_MAIL_FRAMESET_NAME + 1); } } /** Updates the image buffer to reflect the current state of the mail bay. */ private synchronized static void updateBuffer(Colour background, Clip clip, Dimension size) { // If the buffer doesn't exist or is the wrong size, recreate it if (_mailBuffer == null || !_mailBuffer.getSize().equals(size)) { _mailBuffer = Image.createImage(size, true); clip = null; // Need to recreate the entire image; updateSize(); } // Prepare graphics GraphicsManager g = EcosystemManager.getGraphicsManager(); g.pushDrawingSurface(_mailBuffer); if (clip != null) { g.pushClip(clip); } g.setAntialiasing(true); g.clear(background); g.setFont(_messageFont); // Paint header FrameGraphics.PaintItem(getHeader(Colour.BLACK)); // Paint the mail messages to the screen (preview) for (Item message : _previewMessages) { if (message != null) { if (clip == null || clip.isNotClipped() || message.isInDrawingArea(clip.getBounds())) { FrameGraphics.PaintItem(message); } } } // Paint the status from the MessageBay Item status = MessageBay.getStatus(); if (status != null) { FrameGraphics.PaintItem(status); } // Paint the link to the mail frame if (clip == null || clip.isNotClipped() || _mailLink.isInDrawingArea(clip.getBounds())) { FrameGraphics.PaintItem(_mailLink); } g.popDrawingSurface(); } /** Syncs message bay size according to FrameGraphics max size. */ private static void updateSize() { for (Item i : _previewMessages) { if (i != null) { i.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY()); } } _mailLink.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY()); updateLink(); } private static void updateLink() { if (!isLinkInitialized && DisplayController.getFramePaintArea() != null && DisplayController.getFramePaintAreaWidth() > 0) { // set up 'Messages' link on the right hand side _mailLink.setPosition(DisplayController.getMessageBayPaintArea().getWidth() - MAIL_LINK_Y_OFFSET, MAIL_LINK_X); _mailLink.setOffset(0, -DisplayController.getMessageBayPaintArea().getMinY()); isLinkInitialized = true; } else { _mailLink.setPosition(DisplayController.getMessageBayPaintArea().getWidth() - MAIL_LINK_Y_OFFSET, MAIL_LINK_X); } } private static Text getHeader(Colour fontColor) { Text t = new Text("You have [" + _messages.size() + "] unprocessed messages waiting."); if (_messages.size() >= 2) { t.setText(t.getText() + " Two latest below:"); } t.setPosition(OFFSET_X, HEADER_OFFSET_Y); t.setOffset(0, -DisplayController.getFramePaintAreaHeight()); t.setColor(fontColor); t.setFont(_messageFont.clone()); return t; } private static String getMessagePrefix() { _messageCount++; return "@" + _messageCount + ": "; } private static class Mail { private String message; private Map options; private String message2; private Mail(String message, String message2, Map options) { this.message = message; this.message2 = message2; this.options = options; } private Text getPreviewMessage(boolean usePrefix) { Text t = usePrefix ? new Text(getMessagePrefix() + message) : new Text(message); int y = MESSAGE_OFFSET_Y + _previewMessages.size() * SPACING; t.setPosition(OFFSET_X, y); t.setColor(Colour.BLACK); t.setFont(_messageFont.clone()); return t; } private Text getDetailLine() { if (message2 == null || message2.isEmpty()) { return null; } Text t = new Text(message2); int y = MESSAGE_OFFSET_Y + _previewMessages.size() * SPACING; t.setPosition(OFFSET_X, y); t.setColor(Colour.BLACK); t.setFont(_messageFont.clone()); return t; } private Text[] getMessage() { List items = new LinkedList(); items.add(getPreviewMessage(false)); Text detail = getDetailLine(); if (detail != null) { items.add(detail); } int i = items.size(); for (String content: options.keySet()) { String[] split = content.split(":::"); String action = options.get(content); Text t = new Text(split[0]); for (int o = 1; o < split.length; o++) { t.addToData(split[o]); } int y = MESSAGE_OFFSET_Y + (_previewMessages.size() + i) * SPACING; t.setPosition(OFFSET_X, y); t.setColor(Colour.BLUE); t.setFont(_messageFont.clone()); t.setAction(action); items.add(t); i++; } return items.toArray(new Text[] {}); } } }