View Javadoc
1   package com.nilhcem.fakesmtp.gui.tab;
2   
3   import com.nilhcem.fakesmtp.core.ArgsHandler;
4   import com.nilhcem.fakesmtp.core.Configuration;
5   import com.nilhcem.fakesmtp.core.I18n;
6   import com.nilhcem.fakesmtp.gui.info.ClearAllButton;
7   import com.nilhcem.fakesmtp.model.EmailModel;
8   import com.nilhcem.fakesmtp.model.UIModel;
9   import com.nilhcem.fakesmtp.server.MailSaver;
10  import org.slf4j.Logger;
11  import org.slf4j.LoggerFactory;
12  
13  import javax.mail.internet.MimeUtility;
14  import javax.swing.JOptionPane;
15  import javax.swing.JScrollPane;
16  import javax.swing.JTable;
17  import javax.swing.table.DefaultTableModel;
18  import java.awt.Desktop;
19  import java.awt.Rectangle;
20  import java.awt.event.ComponentAdapter;
21  import java.awt.event.ComponentEvent;
22  import java.awt.event.MouseEvent;
23  import java.awt.event.MouseListener;
24  import java.io.File;
25  import java.io.IOException;
26  import java.io.UnsupportedEncodingException;
27  import java.text.SimpleDateFormat;
28  import java.util.Observable;
29  import java.util.Observer;
30  
31  /**
32   * Scrolled table where will be displayed every received email (one line for each email).
33   * <p>
34   * The user can double-click on any row to see the selected email.
35   * </p>
36   *
37   * @author Nilhcem
38   * @since 1.0
39   */
40  public final class MailsListPane implements Observer {
41  
42  	private int nbElements = 0;
43  	private Desktop desktop = null;
44  	private static final Logger LOGGER = LoggerFactory.getLogger(MailsListPane.class);
45  	private final I18n i18n = I18n.INSTANCE;
46  	private final JScrollPane mailsListPane = new JScrollPane();
47  	private final SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm:ss a");
48  	private final int[] widths = new int[] {85, 140, 140}; // widths of columns in tab
49  
50  	/**
51  	 * Table with non-editable cells.
52  	 */
53  	private final JTable table = new JTable() {
54  		private static final long serialVersionUID = 6332956458868628779L;
55  
56  		@Override
57  		public boolean isCellEditable(int row, int column) {
58  			return false;
59  		}
60  	};
61  
62  	/**
63  	 * Table model with non-editable cells.
64  	 */
65  	private final DefaultTableModel model = new DefaultTableModel() {
66  		private static final long serialVersionUID = -6716294637919469299L;
67  
68  		public boolean isCellEditable(int rowIndex, int mColIndex) {
69  			return false;
70  		}
71  	};
72  
73  	/**
74  	 * Creates the table and sets its cells as non editable.
75  	 * <p>
76  	 * Adds some mouse events on the table, to display emails, when a user clicks on
77  	 * a specific row.<br>
78  	 * If the email can't be found, an error message will be displayed.<br>
79  	 * The table will reset the size of its column every time the size of the table changed
80  	 * (for example when the user maximizes the window).
81  	 * </p>
82  	 */
83  	public MailsListPane() {
84  		// Init desktop (Java 6 Desktop API)
85  		if (Desktop.isDesktopSupported()) {
86  			desktop = Desktop.getDesktop();
87  		}
88  
89  		if (!ArgsHandler.INSTANCE.memoryModeEnabled()) {
90  			table.addMouseListener(new MouseListener() {
91  				@Override
92  				public void mouseReleased(MouseEvent e) {
93  				}
94  
95  				@Override
96  				public void mousePressed(MouseEvent e) {
97  				}
98  
99  				@Override
100 				public void mouseExited(MouseEvent e) {
101 				}
102 
103 				@Override
104 				public void mouseEntered(MouseEvent e) {
105 				}
106 
107 				@Override
108 				public void mouseClicked(MouseEvent e) {
109 
110 					String emlViewer = ArgsHandler.INSTANCE.getEmlViewer();
111 
112 					if (e.getClickCount() == 2 && (emlViewer != null || desktop != null)) {
113 						File file = null;
114 						JTable target = (JTable) e.getSource();
115 						String fileName = UIModel.INSTANCE.getListMailsMap().get(target.getSelectedRow());
116 						if (fileName == null) {
117 							LOGGER.error("Can't find any associated email for row #{}", target.getSelectedRow());
118 						} else {
119 							file = new File(fileName);
120 						}
121 
122 						if (file != null && file.exists()) {
123 							try {
124 								if (emlViewer != null) {
125 									Runtime.getRuntime().exec(emlViewer + " " + file.getAbsolutePath());
126 								} else {
127 									desktop.open(file);
128 								}
129 							} catch (IOException ioe) {
130 								LOGGER.error("", ioe);
131 								displayError(String.format(i18n.get("mailslist.err.open"), file.getAbsolutePath()));
132 							}
133 						} else {
134 							displayError(String.format(i18n.get("mailslist.err.find"), file.getAbsolutePath()));
135 						}
136 					}
137 				}
138 			});
139         }
140 
141 		// Auto scroll tab to bottom when a new element is inserted
142 		table.addComponentListener(new ComponentAdapter() {
143 			public void componentResized(ComponentEvent e) {
144 				table.scrollRectToVisible(new Rectangle(table.getCellRect(nbElements, 0, true)));
145 			}
146 		});
147 
148 		model.addColumn(i18n.get("mailslist.col.received"));
149 		model.addColumn(i18n.get("mailslist.col.from"));
150 		model.addColumn(i18n.get("mailslist.col.to"));
151 		model.addColumn(i18n.get("mailslist.col.subject"));
152 		table.setModel(model);
153 
154 		mailsListPane.addComponentListener(new ComponentAdapter() {
155 			public void componentResized(ComponentEvent e) {
156 				// When the width of a column is changed, only the columns to the left and right of the margin change
157 				table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
158 
159 				// Set width for each column
160 				int total = 0;
161 				int length = widths.length;
162 				for (int i = 0; i < length; i++) {
163 					table.getColumnModel().getColumn(i).setPreferredWidth(widths[i]);
164 					total += widths[i];
165 				}
166 				table.getColumnModel().getColumn(length).setPreferredWidth(table.getWidth() - total);
167 			}
168 		});
169 		mailsListPane.getViewport().add(table, null);
170 	}
171 
172 	/**
173 	 * Returns the JScrollPane object.
174 	 *
175 	 * @return the JScrollPane object.
176 	 */
177 	public JScrollPane get() {
178 		return mailsListPane;
179 	}
180 
181 	/**
182 	 * Updates the content of the table.
183 	 * <p>
184 	 * This method will be called by an observable element.
185      * </p>
186 	 * <ul>
187 	 *   <li>If the observable is a {@link MailSaver} object, a new row will be added
188 	 *   to the table, and the {@link UIModel} will be updated;</li>
189 	 *   <li>If the observable is a {@link ClearAllButton} object, all the cells
190 	 *   of the table will be removed, and the {@link UIModel} will be updated.</li>
191 	 * </ul>
192 	 *
193 	 * @param o the observable element which will notify this class.
194 	 * @param arg optional parameters (an {@code EmailModel} object, for the case of
195 	 * a {@code MailSaver} observable) containing all the information about the email.
196 	 */
197 	@Override
198 	public void update(Observable o, Object arg) {
199 		if (o instanceof MailSaver) {
200 			EmailModel email = (EmailModel) arg;
201 			String subject;
202 			try {
203 				subject = MimeUtility.decodeText(email.getSubject());
204 			} catch (UnsupportedEncodingException e) {
205 				LOGGER.error("", e);
206 				subject = email.getSubject();
207 			}
208 
209 			model.addRow(new Object[] {dateFormat.format(email.getReceivedDate()), email.getFrom(), email.getTo(), subject});
210 			UIModel.INSTANCE.getListMailsMap().put(nbElements++, email.getFilePath());
211 		} else if (o instanceof ClearAllButton) {
212 			// Delete information from the map
213 			UIModel.INSTANCE.getListMailsMap().clear();
214 
215 			// Remove elements from the list
216 			try {
217 				while (nbElements > 0) {
218 					model.removeRow(--nbElements);
219 				}
220 			} catch (ArrayIndexOutOfBoundsException e) {
221 				LOGGER.error("", e);
222 			}
223 		}
224 	}
225 
226 	/**
227 	 * Displays a message dialog containing the error specified in parameter.
228 	 *
229 	 * @param error a String representing an error message to display.
230 	 */
231 	private void displayError(String error) {
232 		JOptionPane.showMessageDialog(mailsListPane.getParent(), error,
233 			String.format(i18n.get("mailslist.err.title"), Configuration.INSTANCE.get("application.name")),
234 			JOptionPane.ERROR_MESSAGE);
235 	}
236 }