001: // The contents of this file are subject to the Mozilla Public License Version
002: // 1.1
003: //(the "License"); you may not use this file except in compliance with the
004: //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
005: //
006: //Software distributed under the License is distributed on an "AS IS" basis,
007: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
008: //for the specific language governing rights and
009: //limitations under the License.
010: //
011: //The Original Code is "The Columba Project"
012: //
013: //The Initial Developers of the Original Code are Frederik Dietz and Timo
014: // Stich.
015: //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
016: //
017: //All Rights Reserved.
018: package org.columba.mail.gui.message.viewer;
019:
020: import java.awt.datatransfer.DataFlavor;
021: import java.awt.event.MouseAdapter;
022: import java.awt.event.MouseEvent;
023: import java.awt.event.MouseListener;
024: import java.io.File;
025: import java.io.IOException;
026: import java.util.List;
027:
028: import javax.swing.Icon;
029: import javax.swing.ImageIcon;
030: import javax.swing.JComponent;
031: import javax.swing.JPopupMenu;
032: import javax.swing.TransferHandler;
033: import javax.swing.UIManager;
034:
035: import org.columba.core.command.CommandProcessor;
036: import org.columba.core.gui.menu.ExtendablePopupMenu;
037: import org.columba.core.gui.menu.MenuXMLDecoder;
038: import org.columba.core.resourceloader.ImageLoader;
039: import org.columba.mail.command.IMailFolderCommandReference;
040: import org.columba.mail.command.MailFolderCommandReference;
041: import org.columba.mail.folder.IMailbox;
042: import org.columba.mail.gui.frame.MailFrameMediator;
043: import org.columba.mail.gui.message.IMessageController;
044: import org.columba.mail.gui.message.action.OpenAttachmentAction;
045: import org.columba.mail.gui.message.action.SaveAsAttachmentAction;
046: import org.columba.mail.gui.message.command.SaveAttachmentTemporaryCommand;
047: import org.columba.ristretto.message.MimeHeader;
048: import org.columba.ristretto.message.MimeTree;
049: import org.columba.ristretto.message.MimeType;
050: import org.columba.ristretto.message.StreamableMimePart;
051: import org.frapuccino.iconpanel.IconPanel;
052: import org.frapuccino.swing.DynamicFileFactory;
053: import org.frapuccino.swing.DynamicFileTransferHandler;
054:
055: /**
056: * @author fdietz
057: *
058: */
059:
060: public class AttachmentsViewer extends IconPanel implements
061: ICustomViewer {
062:
063: private MimeTree mimePartTree;
064:
065: private ExtendablePopupMenu menu;
066:
067: private AttachmentModel model;
068:
069: private IMessageController mediator;
070:
071: private MailFolderCommandReference ref;
072:
073: public AttachmentsViewer(IMessageController mediator) {
074: super ();
075:
076: this .mediator = mediator;
077:
078: model = new AttachmentModel();
079:
080: setOpaque(true);
081: setBackground(UIManager.getColor("List.background"));
082:
083: setDragEnabled(true);
084: setTransferHandler(new AttachmentTransferHandler(
085: new FileGenerator()));
086:
087: MouseListener popupListener = new PopupListener();
088: addMouseListener(popupListener);
089:
090: // set double-click action for attachment viewer
091: setDoubleClickAction(new OpenAttachmentAction(mediator, this ));
092: }
093:
094: /**
095: * Sets the mime part. Adds icons to the view.
096: *
097: * @param collection
098: * collection containing mime parts.
099: * @return true if there was any mime parts added to the view; false
100: * otherwise.
101: */
102: private boolean setMimePartTree(MimeTree collection) {
103: String contentType;
104: String contentSubtype;
105: String text = null;
106: boolean output = false;
107:
108: removeAll();
109:
110: model.setCollection(collection);
111:
112: List displayedMimeParts = model.getDisplayedMimeParts();
113:
114: // Display resulting MimeParts
115: for (int i = 0; i < displayedMimeParts.size(); i++) {
116: StreamableMimePart mp = (StreamableMimePart) displayedMimeParts
117: .get(i);
118:
119: MimeHeader header = mp.getHeader();
120: MimeType type = header.getMimeType();
121:
122: contentType = type.getType();
123: contentSubtype = type.getSubtype();
124:
125: // Get Text for Icon
126: if (header.getFileName() != null) {
127: text = header.getFileName();
128: } else {
129: text = contentType + "/" + contentSubtype;
130: }
131:
132: // Get Tooltip for Icon
133: StringBuffer tooltip = new StringBuffer();
134: tooltip.append("<html><body>");
135:
136: if (header.getFileName() != null) {
137: tooltip.append(header.getFileName());
138: tooltip.append(" - ");
139: }
140:
141: tooltip.append("<i>");
142:
143: if (header.getContentDescription() != null) {
144: tooltip.append(header.getContentDescription());
145: } else {
146: tooltip.append(contentType);
147: tooltip.append("/");
148: tooltip.append(contentSubtype);
149: }
150:
151: tooltip.append("</i></body></html>");
152:
153: ImageIcon icon = null;
154:
155: icon = new AttachmentImageIconLoader().getImageIcon(type
156: .getType(), type.getSubtype());
157:
158: add(icon, text, tooltip.toString());
159:
160: output = true;
161: }
162:
163: return output;
164: }
165:
166: /**
167: * @see org.columba.mail.gui.message.viewer.IViewer#view(org.columba.mail.folder.IMailbox,
168: * java.lang.Object, org.columba.mail.gui.frame.MailFrameMediator)
169: */
170: public void view(IMailbox folder, Object uid,
171: MailFrameMediator mediator) throws Exception {
172:
173: setLocalReference(new MailFolderCommandReference(folder,
174: new Object[] { uid }));
175:
176: mimePartTree = folder.getMimePartTree(uid);
177:
178: }
179:
180: /**
181: * @see org.columba.mail.gui.message.viewer.IViewer#updateGUI()
182: */
183: public void updateGUI() throws Exception {
184: if (mimePartTree == null)
185: return;
186:
187: setMimePartTree(mimePartTree);
188: }
189:
190: /**
191: * @see org.columba.mail.gui.message.viewer.IViewer#getView()
192: */
193: public JComponent getView() {
194: return this ;
195: }
196:
197: private JPopupMenu getPopupMenu() {
198: // bug #999990 (fdietz): make sure popup menu is created correctly
199: if (menu == null) {
200: menu = new ExtendablePopupMenu("mail.attachmentviewer");
201: menu.add(new OpenAttachmentAction(mediator, this ));
202: menu.add(new SaveAsAttachmentAction(mediator, this ));
203: }
204:
205: return menu;
206: }
207:
208: public void setLocalReference(MailFolderCommandReference ref) {
209: this .ref = ref;
210: }
211:
212: public MailFolderCommandReference getLocalReference() {
213: Integer[] address = getSelectedMimePart().getAddress();
214: ref.setAddress(address);
215:
216: return ref;
217: }
218:
219: class PopupListener extends MouseAdapter {
220: public void mousePressed(MouseEvent e) {
221: maybeShowPopup(e);
222: }
223:
224: public void mouseReleased(MouseEvent e) {
225: maybeShowPopup(e);
226: }
227:
228: private void maybeShowPopup(MouseEvent e) {
229: if (e.isPopupTrigger()) {
230:
231: if (countSelected() >= 1) {
232: getPopupMenu().show(e.getComponent(), e.getX(),
233: e.getY());
234: }
235: }
236: }
237: }
238:
239: private class FileGenerator implements DynamicFileFactory {
240:
241: /** {@inheritDoc} */
242: public File[] createFiles(JComponent arg0) throws IOException {
243: File[] files = new File[1];
244:
245: IMailFolderCommandReference ref = mediator
246: .getSelectedReference();
247: ref.setAddress(getSelected());
248:
249: SaveAttachmentTemporaryCommand command = new SaveAttachmentTemporaryCommand(
250: ref);
251:
252: CommandProcessor.getInstance().addOp(command);
253:
254: command.waitForCommandToComplete();
255:
256: files[0] = command.getTempAttachmentFile();
257:
258: return files;
259: }
260: }
261:
262: /**
263: * Returns the selected mime part from the model.
264: *
265: * @return the selected mime part.
266: */
267: private StreamableMimePart getSelectedMimePart() {
268: return (StreamableMimePart) model.getDisplayedMimeParts().get(
269: getSelectedIndex());
270: }
271:
272: public Integer[] getSelected() {
273: StreamableMimePart mp = getSelectedMimePart();
274: return mp.getAddress();
275: }
276:
277: /**
278: * Transfer handler for the attachment view.
279: *
280: * The Sun DnD integration with the the native platform, requires that the
281: * file is already exists on the disk, when a File DnD is issued. This
282: * TransferHandler will create the files locally when the
283: *
284: * @linkplain java.awt.datatransfer.Transferable#getTransferData(java.awt.datatransfer.DataFlavor)
285: * method is called. That method is the last method called before
286: * the DnD has completed. The actual extraction is done through
287: * the SaveAttachmentTemporaryCommand, and there might be
288: * problems waiting for other commands to finish before it. The
289: * method does not complete until the file has been created, ie
290: * locks up the DnD action.
291: * <p>
292: * @author redsolo
293: * @see org.columba.mail.gui.message.command.SaveAttachmentTemporaryCommand
294: * @see org.frappucino.swing.DynamicFileTransferHandler
295: */
296:
297: public class AttachmentTransferHandler extends
298: DynamicFileTransferHandler {
299:
300: /**
301: * Setup the dynamic transfer handler.
302: *
303: * @param factory
304: * the factory that creates the file for the DnD action.
305: */
306: public AttachmentTransferHandler(DynamicFileFactory factory) {
307: super (factory, DynamicFileTransferHandler.LATE_GENERATION);
308: }
309:
310: /**
311: * Returns the COPY action.
312: *
313: * @param c
314: * ignored.
315: * @return the
316: * @link TransferHandler#COPY COPY action.
317: */
318: public int getSourceActions(JComponent c) {
319: return TransferHandler.COPY;
320: }
321:
322: /**
323: * Returns always false. The attachment transfer handler can only export
324: * data flavors, and not import them.
325: *
326: * @param comp
327: * ignored.
328: * @param transferFlavors
329: * ignored.
330: * @return false.
331: */
332: public boolean canImport(JComponent comp,
333: DataFlavor[] transferFlavors) {
334: return false;
335: }
336: }
337:
338: /**
339: * Imageloader using a content-type and subtype to determine the image name.
340: * <p>
341: * Automatically falls back to the default icon.
342: *
343: * @author fdietz
344: */
345: class AttachmentImageIconLoader {
346:
347: /**
348: * Utility constructor.
349: */
350: private AttachmentImageIconLoader() {
351: }
352:
353: /**
354: * Returns the image icon for the content type.
355: *
356: * @param contentType
357: * content type
358: * @param contentSubtype
359: * content sub type
360: * @return an Image Icon for the content type.
361: */
362: public ImageIcon getImageIcon(String contentType,
363: String contentSubtype) {
364: StringBuffer buf = new StringBuffer();
365: buf.append("gnome-");
366: buf.append(contentType);
367: buf.append("-");
368: buf.append(contentSubtype);
369: buf.append(".png");
370:
371: ImageIcon icon = ImageLoader
372: .getMimetypeIcon(buf.toString());
373:
374: if (icon == null) {
375: icon = ImageLoader.getMimetypeIcon("gnome-"
376: + contentType + ".png");
377: }
378:
379: if (icon == null) {
380: icon = ImageLoader.getMimetypeIcon("gnome-text.png");
381: }
382:
383: return icon;
384: }
385: }
386:
387: public JComponent add(Icon image, String text, String tooltip) {
388: JComponent comp = super.add(image, text, tooltip);
389: return comp;
390: }
391:
392: }
|