001: /*
002: * Copyright 2001-2006 C:1 Financial Services GmbH
003: *
004: * This software is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License Version 2.1, as published by the Free Software Foundation.
007: *
008: * This software is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
011: * Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public
014: * License along with this library; if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
016: */
017:
018: package de.finix.contelligent.client.gui.file;
019:
020: import java.awt.BorderLayout;
021: import java.awt.Color;
022: import java.awt.datatransfer.DataFlavor;
023: import java.awt.datatransfer.Transferable;
024: import java.awt.datatransfer.UnsupportedFlavorException;
025: import java.awt.dnd.DropTarget;
026: import java.awt.dnd.DropTargetDragEvent;
027: import java.awt.dnd.DropTargetDropEvent;
028: import java.awt.dnd.DropTargetEvent;
029: import java.awt.dnd.DropTargetListener;
030: import java.awt.event.ActionEvent;
031: import java.awt.event.FocusAdapter;
032: import java.awt.event.FocusEvent;
033: import java.awt.event.MouseAdapter;
034: import java.awt.event.MouseEvent;
035: import java.io.File;
036: import java.io.IOException;
037: import java.io.Serializable;
038: import java.util.List;
039: import java.util.logging.Level;
040: import java.util.logging.Logger;
041:
042: import javax.swing.AbstractAction;
043: import javax.swing.Action;
044: import javax.swing.JComboBox;
045: import javax.swing.JComponent;
046: import javax.swing.JDialog;
047: import javax.swing.JFileChooser;
048: import javax.swing.JLabel;
049: import javax.swing.JOptionPane;
050: import javax.swing.JPanel;
051: import javax.swing.JTextField;
052: import javax.swing.TransferHandler;
053: import javax.swing.border.BevelBorder;
054: import javax.swing.border.Border;
055:
056: import de.finix.contelligent.client.ContelligentClient;
057: import de.finix.contelligent.client.base.ComponentFactory;
058: import de.finix.contelligent.client.base.ComponentNotFoundException;
059: import de.finix.contelligent.client.base.ContelligentComponent;
060: import de.finix.contelligent.client.base.category.ContelligentCategoryManager;
061: import de.finix.contelligent.client.base.resource.ContelligentBinaryResource;
062: import de.finix.contelligent.client.event.ContelligentEvent;
063: import de.finix.contelligent.client.event.ResourceModifiedEvent;
064: import de.finix.contelligent.client.gui.AbstractComponentResourceEditor;
065: import de.finix.contelligent.client.gui.ContelligentAction;
066: import de.finix.contelligent.client.i18n.Resources;
067: import de.finix.contelligent.client.modules.preferences.PreferencesModule;
068: import de.finix.contelligent.client.util.SwingWorker;
069:
070: public class FileEditor extends AbstractComponentResourceEditor {
071:
072: private static Logger logger = Logger.getLogger(FileEditor.class
073: .getName());
074:
075: protected JComponent borderPane = new JPanel();
076:
077: protected Border defaultBorder;
078:
079: protected Color defaultBackground, highlightBackground;
080:
081: private JLabel fileLabel = new JLabel();
082:
083: private UploadFileAction uploadFileAction = new UploadFileAction(
084: "upload_file_action");
085:
086: public void init() {
087: setResourceComponent(fileLabel);
088:
089: borderPane.setOpaque(false);
090:
091: update();
092:
093: setDnD(isEditable());
094:
095: addFocusListener(new FocusAdapter() {
096: public void focusGained(FocusEvent event) {
097: borderPane.setBorder(new BevelBorder(
098: BevelBorder.LOWERED));
099: getView().setActions(getActions());
100: }
101:
102: public void focusLost(FocusEvent event) {
103: borderPane.setBorder(defaultBorder);
104: }
105: });
106: borderPane.add(fileLabel, BorderLayout.NORTH);
107: defaultBorder = borderPane.getBorder();
108: borderPane.addMouseListener(new MouseAdapter() {
109: public void mousePressed(MouseEvent event) {
110: requestFocus();
111: }
112: });
113: add(borderPane, BorderLayout.CENTER);
114: defaultBackground = getBackground();
115: highlightBackground = defaultBackground.brighter();
116: }
117:
118: protected void initDnD() {
119: setDropTarget(new DropTarget(this , new DropHandler()));
120: setTransferHandler(new FileTransferHandler());
121: }
122:
123: protected void dropDnD() {
124: setDropTarget(null);
125: setTransferHandler(null);
126: }
127:
128: protected void setDnD(boolean editable) {
129: if (editable) {
130: initDnD();
131: } else {
132: dropDnD();
133: }
134: }
135:
136: public void setEditable(boolean editable) {
137: super .setEditable(editable);
138: setDnD(isEditable());
139: }
140:
141: public boolean isFocusable() {
142: return true;
143: }
144:
145: public void displayResource() {
146: ContelligentBinaryResource resource = (ContelligentBinaryResource) getGUI()
147: .getResource();
148: if (resource != null) {
149: fileLabel.setBorder(null);
150: String filename;
151: filename = resource.getExtension() + " ["
152: + resource.getContentType() + "]";
153: fileLabel.setText(filename);
154: fileLabel.setIcon(Utils.getIconForMimeType(resource
155: .getContentType()));
156: } else {
157: ContelligentComponent component = getGUI().getComponent();
158: if (component.getType()
159: .instanceOf("contelligent.core.File")) {
160:
161: String contentType = component
162: .getPropertyValue("contentType");
163: String extension = component
164: .getPropertyValue("extension");
165: if (contentType.length() > 0) {
166: fileLabel.setBorder(null);
167: String filename;
168: filename = extension + " [" + contentType + "]";
169: fileLabel.setText(filename);
170: fileLabel.setIcon(Utils
171: .getIconForMimeType(contentType));
172: return;
173: }
174: }
175: fileLabel.setText("");
176: fileLabel.setIcon(null);
177: }
178: }
179:
180: public Action[] getActions() {
181: if (isEditable()) {
182: return new Action[] { uploadFileAction };
183: } else {
184: return new Action[] {};
185: }
186: }
187:
188: protected void updateResource(File file, String contentType,
189: String extension) {
190: ContelligentBinaryResource resource = (ContelligentBinaryResource) getGUI()
191: .getResource();
192: if (resource == null || getGUI().isResourceInherited()) {
193: resource = new ContelligentBinaryResource(getGUI()
194: .getResourceCategoryMap(), file.getPath(),
195: contentType, extension);
196: resource.setReferencedFile(file);
197: getGUI().setResource(resource);
198: ContelligentCategoryManager.getInstance()
199: .completeCategoryToResourceMapping(
200: getGUI().getSensitiveCategories(),
201: getGUI().getResourceMap());
202: } else {
203: resource.setSource(file.getPath());
204: resource.setReferencedFile(file);
205: resource.setContentType(contentType);
206: resource.setExtension(extension);
207: }
208: ComponentFactory.getInstance().fireResourceModifyEvent(
209: new ResourceModifiedEvent(this , getComponent()
210: .getPath(), getGUI().getResourceIdentifier(),
211: getGUI().getResource(), getGUI()
212: .getResourceMode()));
213: }
214:
215: protected void updateComponent() {
216: ContelligentBinaryResource resource = (ContelligentBinaryResource) getGUI()
217: .getResource();
218: if (resource != null && !getGUI().isResourceInherited()) {
219: if (resource.isModified()) {
220: getComponent().setResourceModified(true);
221: }
222: }
223: }
224:
225: protected void componentChanged(ContelligentEvent event) {
226: update();
227: }
228:
229: protected void childComponentAdded(ContelligentEvent event) {
230: }
231:
232: protected void childComponentRemoved(ContelligentEvent event) {
233: }
234:
235: protected void childComponentChanged(ContelligentEvent event) {
236: }
237:
238: protected void descendentComponentChanged(ContelligentEvent event) {
239: }
240:
241: protected void setFile(File file, String contentType,
242: String extension) {
243: if (file != null) {
244: if (file.exists()) {
245: updateResource(file, contentType, extension);
246: update();
247: } else {
248: JOptionPane.showMessageDialog(null, Resources
249: .getLocalString("file_not_found"));
250: }
251: }
252: }
253:
254: private void fileSelected(File file) {
255: String ext = Utils.getExtension(file);
256: String mime = Utils.getMimeForExtension(ext);
257: setMimeTypeAndExtension(getSupportedMimeTypes(), mime, ext,
258: file);
259: }
260:
261: protected String[] getSupportedMimeTypes() {
262: return Utils.BASIC_MIME_TYPES;
263: }
264:
265: private void setMimeTypeAndExtension(final String[] mimeTypes,
266: final String defaultMimeType,
267: final String defaultExtension, final File file) {
268:
269: SwingWorker worker = new SwingWorker("Mime-Set-Thread") {
270: private FileOptionPane fop;
271:
272: public Object construct() {
273: fop = new FileOptionPane(mimeTypes, defaultMimeType,
274: defaultExtension);
275: return new Integer(fop.showFileDialog("MIME/Extension",
276: "MIME-type", "extension"));
277: }
278:
279: public void finished() {
280: int value = ((Integer) getValue()).intValue();
281: if (value == FileOptionPane.OK_OPTION) {
282: setFile(file, fop.getMimeType(), fop.getExtension());
283: }
284: }
285: };
286: worker.start();
287: }
288:
289: protected void prepareFileChooser(JFileChooser fc) {
290: String fileDirectory = PreferencesModule
291: .getDirectoryPreferences().get(
292: PreferencesModule.FILE_DIRECTORY,
293: PreferencesModule.DEFAULT_FILE_DIRECTORY);
294: fc.setCurrentDirectory(new File(fileDirectory));
295: }
296:
297: protected void evalFileChooser(JFileChooser fc) {
298: PreferencesModule.getDirectoryPreferences().put(
299: PreferencesModule.FILE_DIRECTORY,
300: fc.getCurrentDirectory().getAbsolutePath());
301: }
302:
303: private void selectFile() {
304: JFileChooser fc = new JFileChooser();
305: prepareFileChooser(fc);
306:
307: int returnVal = fc.showDialog(this , Resources
308: .getLocalString("upload"));
309: if (returnVal == JFileChooser.APPROVE_OPTION) {
310: fileSelected(fc.getSelectedFile());
311: evalFileChooser(fc);
312: }
313: }
314:
315: protected class FileTransferHandler extends TransferHandler {
316:
317: public boolean canImport(JComponent component,
318: DataFlavor[] transferFlavors) {
319: for (int i = 0; i < transferFlavors.length; i++) {
320: logger.log(Level.FINE, "Flavor: " + transferFlavors[i]);
321: if (transferFlavors[i]
322: .equals(DataFlavor.javaFileListFlavor)) {
323: return true;
324: }
325: }
326: return false;
327: }
328: }
329:
330: protected class DropHandler implements DropTargetListener,
331: Serializable {
332:
333: private boolean canImport;
334:
335: private boolean actionSupported(int action) {
336: return true;
337: }
338:
339: // --- DropTargetListener methods -----------------------------------
340:
341: public void dragEnter(DropTargetDragEvent e) {
342: logger.log(Level.FINE, "Drag enter");
343: DataFlavor[] flavors = e.getCurrentDataFlavors();
344: for (int i = 0; i < flavors.length; i++) {
345: logger.log(Level.FINE, "Flavor: " + flavors[i]);
346: }
347:
348: JComponent c = (JComponent) e.getDropTargetContext()
349: .getComponent();
350: TransferHandler importer = c.getTransferHandler();
351:
352: if (importer != null && importer.canImport(c, flavors)) {
353: canImport = true;
354: } else {
355: canImport = false;
356: }
357:
358: int dropAction = e.getDropAction();
359:
360: if (canImport && actionSupported(dropAction)) {
361: e.acceptDrag(dropAction);
362: setBackground(highlightBackground);
363: } else {
364: e.rejectDrag();
365: }
366: }
367:
368: public void dragOver(DropTargetDragEvent e) {
369: logger.log(Level.FINE, "Drag oer");
370: int dropAction = e.getDropAction();
371:
372: if (canImport && actionSupported(dropAction)) {
373: e.acceptDrag(dropAction);
374: } else {
375: e.rejectDrag();
376: }
377: }
378:
379: public void dragExit(DropTargetEvent e) {
380: setBackground(defaultBackground);
381: }
382:
383: public void drop(DropTargetDropEvent e) {
384: final int dropAction = e.getDropAction();
385:
386: JComponent c = (JComponent) e.getDropTargetContext()
387: .getComponent();
388: TransferHandler importer = c.getTransferHandler();
389:
390: setBackground(defaultBackground);
391:
392: if (canImport && importer != null
393: && actionSupported(dropAction)) {
394: try {
395: e.acceptDrop(dropAction);
396: Transferable transferable = e.getTransferable();
397: final List draggedFiles = (List) transferable
398: .getTransferData(DataFlavor.javaFileListFlavor);
399: for (int i = 0; i < draggedFiles.size(); i++) {
400: logger.log(Level.FINE, "File: "
401: + draggedFiles.get(i));
402: }
403: fileSelected((File) draggedFiles.get(0));
404: e.dropComplete(true);
405: } catch (UnsupportedFlavorException ufe) {
406: e.dropComplete(false);
407: logger
408: .log(
409: Level.WARNING,
410: "Unsupported transferable was dropped on a panel",
411: ufe);
412: } catch (IOException ioe) {
413: e.dropComplete(false);
414: logger.log(Level.WARNING,
415: "Transferable could not be imported", ioe);
416: }
417: } else {
418: e.rejectDrop();
419: }
420: }
421:
422: public void dropActionChanged(DropTargetDragEvent e) {
423: int dropAction = e.getDropAction();
424:
425: if (canImport && actionSupported(dropAction)) {
426: e.acceptDrag(dropAction);
427: } else {
428: e.rejectDrag();
429: }
430: }
431: }
432:
433: protected class UploadFileAction extends AbstractAction implements
434: ContelligentAction {
435:
436: public UploadFileAction(String descriptionKey) {
437: super (descriptionKey, Resources.uploadIcon);
438: putValue(ROLLOVER_ICON, Resources.uploadIconRollOver);
439: putValue(TYPE, PUSH_ACTION);
440: putValue(ACTION_TYPE, EDIT_ACTION);
441: putValue(MENU_TARGET, MENU);
442: putValue(BUTTON_TARGET, TOOLBAR);
443: }
444:
445: public void actionPerformed(ActionEvent e) {
446: selectFile();
447: }
448: }
449:
450: public void rollback() {
451: // For a file, just always reload on rollback
452: try {
453: ComponentFactory.getInstance().reload(getComponent());
454: } catch (ComponentNotFoundException cnfe) {
455: logger.log(Level.SEVERE, "Could not rollback: ", cnfe);
456: }
457: update();
458: }
459:
460: // FIX for bug #164: made it static to avoid reference to FileEditor
461: // XXX actually dialog is only set invisible, but still is referenced by
462: // AppContext via FocusManager
463: // maybe dialog.dispose(); should be called?!
464: private static class FileOptionPane extends JOptionPane {
465:
466: private JTextField extensionField;
467:
468: private JComboBox mimeBox;
469:
470: public FileOptionPane(String[] mimeTypes, String mimeType,
471: String extension) {
472: mimeBox = new JComboBox(mimeTypes);
473: mimeBox.setSelectedItem(mimeType);
474: mimeBox.setEditable(true);
475: extensionField = new JTextField(extension);
476: }
477:
478: public int showFileDialog(String title, String mimeLabel,
479: String extensionLabel) {
480: Object[] array = { extensionLabel, extensionField,
481: mimeLabel, mimeBox };
482:
483: setMessage(array);
484: setMessageType(QUESTION_MESSAGE);
485: setOptionType(JOptionPane.OK_CANCEL_OPTION);
486:
487: JDialog dialog = createDialog(ContelligentClient
488: .getActiveFrame(), title);
489: dialog.setVisible(true);
490: if (getValue() instanceof Integer) {
491: return ((Integer) getValue()).intValue();
492: }
493: return CANCEL_OPTION;
494: }
495:
496: public String getExtension() {
497: return extensionField.getText();
498: }
499:
500: public String getMimeType() {
501: return (String) mimeBox.getSelectedItem();
502: }
503: }
504: }
|