package com.ibm.nmon.gui.dnd; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.io.File; import java.util.List; import javax.swing.JComponent; import javax.swing.JTree; import javax.swing.TransferHandler; import javax.swing.tree.TreePath; import org.slf4j.Logger; import com.ibm.nmon.data.DataSet; import com.ibm.nmon.data.DataTuple; import com.ibm.nmon.data.DataType; import com.ibm.nmon.data.Process; import com.ibm.nmon.data.ProcessDataSet; import com.ibm.nmon.data.ProcessDataType; import com.ibm.nmon.file.CombinedFileFilter; import com.ibm.nmon.gui.file.ParserRunner; import com.ibm.nmon.gui.main.NMONVisualizerGui; import com.ibm.nmon.gui.tree.TreePathParser; import com.ibm.nmon.util.FileHelper; /** * Support dragging data from a tree. Does not support exporting / copying tree data. Currently only * supports DataTypes and fields; entire DataSets cannot be dragged. */ public final class TreeTransferHandler extends TransferHandler { private static final long serialVersionUID = -2072907261684848635L; private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(TreeTransferHandler.class); private final TreeTransferPathParser pathParser; private final NMONVisualizerGui gui; public TreeTransferHandler(NMONVisualizerGui gui) { super(); pathParser = new TreeTransferPathParser(gui); this.gui = gui; } @Override protected Transferable createTransferable(JComponent c) { if (!c.getClass().equals(JTree.class)) { return null; } TreePath[] paths = ((JTree) c).getSelectionPaths(); if (paths.length != 0) { try { for (TreePath path : paths) { pathParser.parse(path); } return pathParser.getTransferable(); } finally { // prevent a memory leak since the transferable is holding a reference to the whole // data set pathParser.clearTransferable(); } } else { return null; } } @Override public int getSourceActions(JComponent c) { return COPY; } @Override public void exportToClipboard(JComponent comp, Clipboard clip, int action) throws IllegalStateException { // disable return; } @Override public boolean canImport(TransferSupport support) { DataFlavor[] flavors = support.getDataFlavors(); for (DataFlavor flavor : flavors) { if (flavor.isFlavorJavaFileListType()) { return true; } } return false; } @Override @SuppressWarnings("unchecked") public boolean importData(TransferSupport support) { try { List<java.io.File> files = (List<File>) support.getTransferable().getTransferData( DataFlavor.javaFileListFlavor); List<String> toParse = new java.util.ArrayList<String>(files.size()); FileHelper.recurseDirectories(files, CombinedFileFilter.getInstance(false), toParse); new Thread(new ParserRunner(gui, toParse, gui.getDisplayTimeZone()), getClass().getName() + " Parser") .start(); return true; } catch (Exception e) { LOGGER.warn("cannot import data", e); return false; } } private static final class TreeTransferPathParser extends TreePathParser { private NMONVisualizerGui gui; private DataTransferable transferable; public TreeTransferPathParser(NMONVisualizerGui gui) { this.gui = gui; } protected void onTypePath(DataSet dataSet, DataType type) { if (transferable == null) { transferable = new DataTransferable(); } // optimization if adding the whole Type, leave the field null and add 1 tuple // this will allow the importers to fire less events / do less work matchByCommandLine(dataSet, type, null); } protected void onFieldPath(DataSet dataSet, DataType type, String field) { if (transferable == null) { transferable = new DataTransferable(); } matchByCommandLine(dataSet, type, field); } public DataTransferable getTransferable() { return transferable; } public void clearTransferable() { transferable = null; } private void matchByCommandLine(DataSet dataSet, DataType type, String field) { // for process types, add all types with the same command line if (type instanceof ProcessDataType) { String command = ((ProcessDataType) type).getProcess().getCommandLine(); for (DataSet data : gui.getDataSets()) { if (data instanceof ProcessDataSet) { ProcessDataSet processData = (ProcessDataSet) data; for (Process process : processData.getProcesses()) { if (process.getCommandLine().equals(command)) { transferable.addTuple(new DataTuple(processData, processData.getType(process), field)); } } } } } else { transferable.addTuple(new DataTuple(dataSet, type, field)); } } }; }