C:\Documents and Settings\chakkerz.STORMCROW\Desktop\naiv_development\naiv_0.4\src\test_code\DragFileToJAIDemo.java |
/* * For the original version of this file see: * http://java.sun.com/docs/books/tutorial/index.htm * * About this modification: * * This is file (and the three classes) are based extremely heavily on the * DragFileDemo.java (and associated files found at: * http://java.sun.com/docs/books/tutorial/uiswing/misc/examples/index.html * * It was customized and such during the development of NAIV 0.4.0 pre13 and is * NOT subject to any licensing restrictions (just as the original file was not * subject to any such restrictions, unless i missed it, in which case the same * license applies). Let's face it ... this doesn't do much, so i think it is * safe to assume that Sun doesn't have restrictions on its tutorials :P . * * This is a proof of concept only and as such is not necessarily pretty code, * nor do i claim it makes a lot of sense. That said, at the time of writing * this, i'm definitly planning to do more documentation so it should be * prettier and make more sense. But i don't promise anything :) * * This does require JAI to be installed, so if you haven't got it, download it * and make it happen. The reason this is released is ... well ... i couldn't * find a code snippet that showed me how to make this happen, and based on the * tutorial example it took me a fair while to work out what to do, especially * for a non text based application. So this is really really stripped down, * and for JAI. * * How to use this: * -> start the program * -> select a file or a few files (in explorer or something) and drag into the * frame; * -> IF everything worked the way it was supposed to, there should be a (number * of) tab(s) displaying your file(s). * -> Hit the clear button and try again, or drag more. I don't really care :) * * I hope this helps someone out there at some stage. * * Christian chakkerz Unger */ package test_code; import java.awt.BorderLayout; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JComponent; import javax.swing.TransferHandler; import javax.media.jai.JAI; import javax.media.jai.PlanarImage; import com.sun.media.jai.widget.DisplayJAI; public class DragFileToJAIDemo extends JPanel implements ActionListener { JButton clear = new JButton("Clear Tabs"); TabbedPaneController tpc; /** * constructor */ public DragFileToJAIDemo() { //setup the frame super(new BorderLayout()); //create a listener for the clear button clear.addActionListener(this); //setup button and panel for it JPanel buttonPanel = new JPanel(new BorderLayout()); buttonPanel.add(clear); this.add(buttonPanel, BorderLayout.SOUTH); //And setup the TabbedPane and related, including the TabbedPaneController JTabbedPane tabbedPane = new JTabbedPane(); JPanel tabPanel = new JPanel(new BorderLayout()); tpc = new TabbedPaneController(tabbedPane, tabPanel); this.add(tabPanel, BorderLayout.CENTER); } /** * what to do when the button is pressed */ public void actionPerformed(ActionEvent e) { if (e.getSource() == clear) { tpc.clearAll(); } } /** * createAndShowGUI() * * creates the frame, sets it up and displays it ... */ private static void createAndShowGUI() { //Create and set up the window. JFrame frame = new JFrame("DragFileDemo"); frame.setSize(500,500); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the menu bar and content pane. DragFileToJAIDemo demo = new DragFileToJAIDemo(); demo.setOpaque(true); frame.setContentPane(demo); frame.setVisible(true); } /** * main() */ public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } } //****************************************************************************** class TabbedPaneController { JPanel tabbedPanel = null; JTabbedPane tabbedPane; JPanel emptyFilePanel = null; DisplayJAI emptyFileArea = null; FileToDisplayJAITransferHandler transferHandler; boolean noFiles = true; String fileSeparator; /** * constructor */ public TabbedPaneController(JTabbedPane tb, JPanel tp) { tabbedPane = tb; tabbedPanel = tp; transferHandler = new FileToDisplayJAITransferHandler(this); fileSeparator = System.getProperty("file.separator"); if ("\\".equals(fileSeparator)) { fileSeparator = "\\\\"; } this.init(); } public DisplayJAI addTab(String filename) { if (noFiles) { tabbedPanel.remove(emptyFilePanel); tabbedPanel.add(tabbedPane, BorderLayout.CENTER); noFiles = false; } String[] str = filename.split(fileSeparator); return this.makeDisplayJAIPanel(str[str.length-1], filename); } /** * clearAll() * * removes all ... not much more to it */ public void clearAll() { if (!noFiles) { tabbedPane.removeAll(); tabbedPanel.remove(tabbedPane); } init(); } /** * init() * * initalizes the startup frame contents. */ private void init() { noFiles = true; if (emptyFilePanel == null) { emptyFileArea = new DisplayJAI(); emptyFileArea.setTransferHandler(transferHandler); JScrollPane fileScrollPane = new JScrollPane(emptyFileArea); emptyFilePanel = new JPanel(new BorderLayout(), false); emptyFilePanel.add(fileScrollPane, BorderLayout.CENTER); } tabbedPanel.add(emptyFilePanel, BorderLayout.CENTER); tabbedPanel.repaint(); } /** * makeDisplayJAIPanel() * * creates a new tab (containing a scrollable displayJAI) */ protected DisplayJAI makeDisplayJAIPanel(String name, String toolTip) { DisplayJAI fileArea = new DisplayJAI(); fileArea.setTransferHandler(transferHandler); JScrollPane fileScrollPane = new JScrollPane(fileArea); tabbedPane.addTab(name, null, (JComponent)fileScrollPane, toolTip); tabbedPane.setSelectedComponent((JComponent)fileScrollPane); return fileArea; } } //****************************************************************************** class FileToDisplayJAITransferHandler extends TransferHandler { private TabbedPaneController tpc; private DisplayJAI source; //local instances of the variables (well aliases) to save looking up and //writing long(er) code. private DataFlavor fileListFlavor; private DataFlavor imageFlavor; /** * Constructor */ FileToDisplayJAITransferHandler(TabbedPaneController t) { tpc = t; fileListFlavor = DataFlavor.javaFileListFlavor; imageFlavor = DataFlavor.imageFlavor; } /** * importData() * * Overrides TransferHandler.importData() ... this is another function that * does not strictly make sense to me * * * */ public boolean importData(JComponent c, Transferable t) { DisplayJAI tc; //check to see if the dragged in files can be imported and if not fails if (!canImport(c, t.getTransferDataFlavors())) { //fail return false; } //if the return above was not triggered importing must be possible. try { //so this has flavor that can be imported, which means it can be either // file list flavor OR if (this.hasFlavor(this.fileListFlavor, t.getTransferDataFlavors())) { //generate a list of the selected files (can of course be just the one //file to be loaded) java.util.List files = (java.util.List)t.getTransferData(this.fileListFlavor); for (int i = 0; i < files.size(); i++) { //for each file get the file, add a tab with the filename as the tab File file = (File)files.get(i); tc = tpc.addTab(file.toString()); //and try to load the file try { //Sun's documentation highlights that this should be a separate thread. //bur for simplicity reasons they and i did not do this. PlanarImage image = JAI.create("fileload", file.toString()); tc.set(image, 0, 0); } catch (Exception x) { System.out.println("importData: Unable to read from file " + file.toString()); } } return true; } //... an image flavor else if (this.hasFlavor(this.imageFlavor, t.getTransferDataFlavors())) { //not sure what this section does (well besides the obvious cast thing) //my guess is allow dragging from one panel to another tc = (DisplayJAI)c; return true; } } catch (UnsupportedFlavorException ufe) { System.out.println("importData: unsupported data flavor"); } catch (IOException ieo) { System.out.println("importData: I/O exception"); } return false; } /** * canImport() * * Overrides TransferHandler.canImport() - which is why the JComponent is not * used in this class. Which means the test is really broken (from the doc): * "Indicates whether a component would accept an import of the given set of * data flavors prior to actually attempting to import it." However since * what the component can take is never checked. This does of course seem * silly but consider this from the stance of the developer (of the * application) - s/he knows what container the program has so assumptions * can safely be made. * The language designer (or the application designer with more nack for * customizations) focuses on fault tolerance, so i guess a check what the * component can actually take, based on what it is or some property would * make more sense ... sadly i have yet to find any markers in my Display JAI * and JComponent has not got a function that does this... at least not that * i can see. * * Oh, and after writing the doc on the last function (hasFlavor())) i * noticed that this functions also has a logic error in the sun version: * * if (hasFlavor(this.fileListFlavor, flavors)) * { * return true; * } * if (hasFlavor(this.imageFlavor, flavors)) * { * return true; * } * return false; * * Which returns a true if the first flavour of the type first checked * returns a true. I should mention that i don't really know that it needs * all this checking, but seeing as they bothered, one would assume yes. * Mind you this flaw runs quite deep, because it doesn't need to succeed on * both tests as the importData() function above caters for both flavors. * */ public boolean canImport(JComponent c, DataFlavor[] flavors) { if ( (hasFlavor(this.fileListFlavor, flavors)) || (hasFlavor(this.imageFlavor, flavors)) ) { return true; } return false; } /** * hasFlavor() * * gets the flavor you want to check against (shouldHave) and the flavors * that you actually have. Then it looks if the flavors you passed in. The * example from the Sun page has a logic bug at this point: * * for (int i = 0; i < flavors.length; i++) * { * if (shouldHave.equals(flavors[i])) * { * return true; * } * } * return false; * * Granted i've dropped my shouldHave in there instead of a specific flavor, * but this does not change the logic flow. The Sun sample will do a return * true IF the first flavor passed in matches and ignore all subsequent ones. * Clearly that isn't ... fault resistant. Most of the time this isn't an * issue; but that's hardly the point. * * So this is a more flexible function, and is (more) fault resistant. It * only returns true if ALL flavors passed are ok, and even a single one will * cause a false; * */ private boolean hasFlavor(DataFlavor shouldHave, DataFlavor[] flavors) { for (int i = 0; i < flavors.length; i++) { if (!shouldHave.equals(flavors[i])) { return false; } } return true; } }