001: /*
002: * This file is part of the Echo Web Application Framework (hereinafter "Echo").
003: * Copyright (C) 2002-2005 NextApp, Inc.
004: *
005: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
006: *
007: * The contents of this file are subject to the Mozilla Public License Version
008: * 1.1 (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: * http://www.mozilla.org/MPL/
011: *
012: * Software distributed under the License is distributed on an "AS IS" basis,
013: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
014: * for the specific language governing rights and limitations under the
015: * License.
016: *
017: * Alternatively, the contents of this file may be used under the terms of
018: * either the GNU General Public License Version 2 or later (the "GPL"), or
019: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
020: * in which case the provisions of the GPL or the LGPL are applicable instead
021: * of those above. If you wish to allow use of your version of this file only
022: * under the terms of either the GPL or the LGPL, and not to allow others to
023: * use your version of this file under the terms of the MPL, indicate your
024: * decision by deleting the provisions above and replace them with the notice
025: * and other provisions required by the GPL or the LGPL. If you do not delete
026: * the provisions above, a recipient may use your version of this file under
027: * the terms of any one of the MPL, the GPL or the LGPL.
028: */
029:
030: package echo2example.email;
031:
032: import java.io.IOException;
033: import java.text.CharacterIterator;
034: import java.text.StringCharacterIterator;
035: import java.util.ArrayList;
036: import java.util.Iterator;
037: import java.util.List;
038:
039: import javax.mail.Address;
040: import javax.mail.BodyPart;
041: import javax.mail.Message;
042: import javax.mail.MessagingException;
043: import javax.mail.Multipart;
044:
045: import nextapp.echo2.app.Column;
046: import nextapp.echo2.app.Component;
047: import nextapp.echo2.app.Extent;
048: import nextapp.echo2.app.Font;
049: import nextapp.echo2.app.Grid;
050: import nextapp.echo2.app.Insets;
051: import nextapp.echo2.app.Label;
052: import nextapp.echo2.app.layout.ColumnLayoutData;
053:
054: /**
055: * A <code>Component</code> which displays a single <code>Message</code>.
056: */
057: public class MessagePane extends Column {
058:
059: private static final ColumnLayoutData SPACER_COLUMN_LAYOUT_DATA;
060: static {
061: SPACER_COLUMN_LAYOUT_DATA = new ColumnLayoutData();
062: SPACER_COLUMN_LAYOUT_DATA.setHeight(new Extent(15));
063: }
064:
065: private Label toFieldPromptLabel;
066: private Label toFieldValueLabel;
067: private Label ccFieldPromptLabel;
068: private Label ccFieldValueLabel;
069: private Label bccFieldPromptLabel;
070: private Label bccFieldValueLabel;
071: private Label subjectFieldValueLabel;
072: private Column messageColumn;
073:
074: /**
075: * Creates a new <code>MessagePane</code>.
076: */
077: public MessagePane() {
078: super ();
079: setVisible(false);
080:
081: setCellSpacing(new Extent(10));
082: setInsets(new Insets(3));
083:
084: Grid headerGrid = new Grid();
085: headerGrid.setStyleName("Message.HeaderGrid");
086: add(headerGrid);
087:
088: toFieldPromptLabel = new Label(Messages
089: .getString("Message.PromptLabel.To"));
090: toFieldPromptLabel.setStyleName("Message.HeaderGridPrompt");
091: headerGrid.add(toFieldPromptLabel);
092:
093: toFieldValueLabel = new Label();
094: headerGrid.add(toFieldValueLabel);
095:
096: ccFieldPromptLabel = new Label(Messages
097: .getString("Message.PromptLabel.Cc"));
098: ccFieldPromptLabel.setStyleName("Message.HeaderGridPrompt");
099: headerGrid.add(ccFieldPromptLabel);
100:
101: ccFieldValueLabel = new Label();
102: headerGrid.add(ccFieldValueLabel);
103:
104: bccFieldPromptLabel = new Label(Messages
105: .getString("Message.PromptLabel.Bcc"));
106: bccFieldPromptLabel.setStyleName("Message.HeaderGridPrompt");
107: headerGrid.add(bccFieldPromptLabel);
108:
109: bccFieldValueLabel = new Label();
110: headerGrid.add(bccFieldValueLabel);
111:
112: Label subjectFieldPromptLabel = new Label(Messages
113: .getString("Message.PromptLabel.Subject"));
114: subjectFieldPromptLabel
115: .setStyleName("Message.HeaderGridPrompt");
116: headerGrid.add(subjectFieldPromptLabel);
117:
118: subjectFieldValueLabel = new Label();
119: headerGrid.add(subjectFieldValueLabel);
120:
121: messageColumn = new Column();
122: messageColumn
123: .setFont(new Font(Font.MONOSPACE, Font.PLAIN, null));
124: add(messageColumn);
125: }
126:
127: /**
128: * Returns the recipients of a message as a comma-delimited String.
129: *
130: * @param message the <code>Message</code>
131: * @param type the recipient type
132: */
133: private String formatRecipients(Message message,
134: Message.RecipientType type) throws MessagingException {
135: Address[] recipients = message.getRecipients(type);
136: if (recipients == null || recipients.length == 0) {
137: return null;
138: }
139: StringBuffer sb = new StringBuffer();
140: for (int recipientIndex = 0; recipientIndex < recipients.length; ++recipientIndex) {
141: sb.append(recipients[recipientIndex].toString());
142: if (recipientIndex < recipients.length - 1) {
143: // Separate recipient names with a comma.
144: sb.append(", ");
145: }
146: }
147: return sb.toString();
148: }
149:
150: /**
151: * Returns an array of components containing the parts of a multipart
152: * message.
153: *
154: * @param message The message to parse.
155: * @return An array of components, each containing a part of the message.
156: */
157: private Component[] renderMessageContent(Message message)
158: throws MessagingException {
159: try {
160: Object content = message.getContent();
161: if (content instanceof String) {
162: // Content is a string, return it enclosed in a Label.
163: return new Component[] { renderMessageText((String) content) };
164: } else if (content instanceof Multipart) {
165: // Content is multi-part, parse each part.
166: Multipart multipart = (Multipart) content;
167: Component[] data = new Component[multipart.getCount()];
168: // Iterate through parts.
169: for (int index = 0; index < data.length; ++index) {
170: BodyPart part = multipart.getBodyPart(index);
171: Object partContent = part.getContent();
172: if (partContent instanceof String) {
173: // Part content is a string, add it to returned array of Components as a Label.
174: data[index] = renderMessageText((String) partContent);
175: } else {
176: // Part content is not a string, add it to returned array as a Label containing its content type.
177: data[index] = new Label(part.getContentType());
178: }
179: }
180: return data;
181: } else {
182: // Unhandled type, should not generally occur.
183: return new Component[] { new Label(Messages
184: .getString("Messages.UnableToParseError")) };
185: }
186: } catch (IOException ex) {
187: // Generally should not occur.
188: return new Component[] { new Label(Messages
189: .getString("Messages.UnableToParseError")) };
190: }
191: }
192:
193: /**
194: * Renders a portion of message text into a <code>Component</code>s.
195: * If the text contains newlines, the returned <code>Component is
196: * a <code>Column</code> containing <code>Label</code>s. If the text
197: * does not contain newlines, a single <code>Label</code> is returned.
198: *
199: * @param text the text to render
200: * @return a <code>Component</code> representation of the text
201: */
202: private Component renderMessageText(String text) {
203: List componentList = new ArrayList();
204: StringBuffer out = new StringBuffer();
205: CharacterIterator ci = new StringCharacterIterator(text);
206: char ch = ci.first();
207: while (ch != CharacterIterator.DONE) {
208: if (ch == '\n') {
209: String labelText = out.toString();
210: Label label = new Label(labelText);
211: if (labelText.trim().length() == 0) {
212: label.setLayoutData(SPACER_COLUMN_LAYOUT_DATA);
213: }
214: componentList.add(label);
215: out = new StringBuffer();
216: } else if (ch >= 0x20) {
217: out.append(ch);
218: }
219: ch = ci.next();
220: }
221: Label label = new Label(out.toString());
222: componentList.add(label);
223:
224: if (componentList.size() == 1) {
225: return label;
226: } else {
227: Column column = new Column();
228: Iterator it = componentList.iterator();
229: while (it.hasNext()) {
230: column.add((Component) it.next());
231: }
232: return column;
233: }
234: }
235:
236: /**
237: * Sets the displayed <code>Message</code>.
238: *
239: * @param message the <code>Message</code> to display
240: */
241: public void setMessage(Message message) throws MessagingException {
242: if (message == null) {
243: setVisible(false);
244: } else {
245: setVisible(true);
246: updateRecipientData(message, Message.RecipientType.TO,
247: toFieldPromptLabel, toFieldValueLabel);
248: updateRecipientData(message, Message.RecipientType.CC,
249: ccFieldPromptLabel, ccFieldValueLabel);
250: updateRecipientData(message, Message.RecipientType.BCC,
251: bccFieldPromptLabel, bccFieldValueLabel);
252: subjectFieldValueLabel.setText(MessageUtil.clean(message
253: .getSubject(), -1, -1));
254: }
255:
256: messageColumn.removeAll();
257: if (message != null) {
258: Component[] messageComponents = renderMessageContent(message);
259: for (int i = 0; i < messageComponents.length; ++i) {
260: messageColumn.add(messageComponents[i]);
261: }
262: }
263: }
264:
265: /**
266: * Updates the visual presentation of recipient information,
267: * showing recipient types that are present and hiding those
268: * which are not.
269: */
270: private void updateRecipientData(Message message,
271: Message.RecipientType type, Label promptLabel,
272: Label valueLabel) throws MessagingException {
273: String recipients = MessageUtil.clean(formatRecipients(message,
274: type), -1, -1);
275: if (recipients == null) {
276: promptLabel.setVisible(false);
277: valueLabel.setVisible(false);
278: valueLabel.setText(null);
279: } else {
280: promptLabel.setVisible(true);
281: valueLabel.setVisible(true);
282: valueLabel.setText(recipients);
283: }
284: }
285: }
|