components/visual-panels/core/src/java/util/com/oracle/solaris/vp/util/swing/EditableTableTransferHandler.java
changeset 827 0944d8c0158b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/visual-panels/core/src/java/util/com/oracle/solaris/vp/util/swing/EditableTableTransferHandler.java	Thu May 24 04:16:47 2012 -0400
@@ -0,0 +1,345 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+
+package com.oracle.solaris.vp.util.swing;
+
+import java.awt.datatransfer.*;
+import java.io.IOException;
+import java.util.Arrays;
+import javax.swing.*;
+import javax.swing.table.TableModel;
+import com.oracle.solaris.vp.util.misc.ArrayUtil;
+
+@SuppressWarnings({"serial"})
+public class EditableTableTransferHandler extends TransferHandler {
+    //
+    // Inner classes
+    //
+
+    public static class TableRow {
+	//
+	// Instance data
+	//
+
+	public int index;
+	public Object[] data;
+
+	// Whether this row was successfully imported or not
+	public boolean success = true;
+
+	//
+	// Constructors
+	//
+
+	public TableRow(int index, Object[] data) {
+	    this.index = index;
+	    this.data = data;
+	}
+    }
+
+    public static class TableData {
+	//
+	// Instance data
+	//
+
+	private int tableHashCode;
+	private TableRow[] rows;
+
+	//
+	// Constructors
+	//
+
+	public TableData(int tableHashCode, TableRow[] rows) {
+	    this.tableHashCode = tableHashCode;
+	    this.rows = rows;
+	}
+
+	//
+	// TableData methods
+	//
+
+	public int getTableHashCode() {
+	    return tableHashCode;
+	}
+
+	public TableRow[] getRows() {
+	    return rows;
+	}
+    }
+
+    public class EditableTableTransferable implements Transferable {
+	//
+	// Instance data
+	//
+
+	private TableData data;
+
+	//
+	// Constructors
+	//
+
+	public EditableTableTransferable(TableData data) {
+	    this.data = data;
+	}
+
+	//
+	// Transferable methods
+	//
+
+	@Override
+	public Object getTransferData(DataFlavor flavor)
+	    throws UnsupportedFlavorException {
+
+	    if (!isDataFlavorSupported(flavor)) {
+		throw new UnsupportedFlavorException(flavor);
+	    }
+
+	    return data;
+	}
+
+	@Override
+	public DataFlavor[] getTransferDataFlavors() {
+	    return new DataFlavor[] {
+		localFlavor, serialFlavor
+	    };
+	}
+
+	@Override
+	public boolean isDataFlavorSupported(DataFlavor flavor) {
+	    return localFlavor.equals(flavor) || serialFlavor.equals(flavor);
+	}
+    }
+
+    //
+    // Static data
+    //
+
+    protected static DataFlavor localFlavor;
+    static {
+	String localType = DataFlavor.javaJVMLocalObjectMimeType +
+	    ";class=\"" + TableData.class.getName() + "\"";
+
+	try {
+	    localFlavor = new DataFlavor(localType);
+	} catch (ClassNotFoundException ignore) {
+	}
+    }
+
+    protected static final DataFlavor serialFlavor =
+	new DataFlavor(TableData.class, "TableData");
+
+    //
+    // TransferHandler methods
+    //
+
+    @Override
+    public boolean canImport(JComponent c, DataFlavor[] flavors) {
+	return c instanceof JTable &&
+	    ((JTable)c).getModel() instanceof EditableTableModel &&
+	    (hasLocalFlavor(flavors) || hasSerialFlavor(flavors));
+    }
+
+    @Override
+    protected Transferable createTransferable(JComponent c) {
+	EditableTableTransferable transferable = null;
+
+	if (c instanceof JTable) {
+	    JTable table = (JTable)c;
+	    int[] selectedRows = table.getSelectedRows();
+
+	    if (selectedRows.length != 0) {
+
+		int nCols = table.getColumnCount();
+		if (nCols != 0) {
+
+		    Arrays.sort(selectedRows);
+		    TableModel model = table.getModel();
+		    TableRow[] rows = new TableRow[selectedRows.length];
+
+		    for (int i = 0; i < selectedRows.length; i++) {
+			int row = selectedRows[i];
+			Object[] data = new Object[nCols];
+
+			for (int col = 0; col < nCols; col++) {
+			    data[col] = model.getValueAt(row, col);
+			}
+
+			rows[i] = new TableRow(row, data);
+		    }
+
+		    transferable = new EditableTableTransferable(
+			new TableData(table.hashCode(), rows));
+		}
+	    }
+	}
+
+	return transferable;
+    }
+
+    @Override
+    protected void exportDone(JComponent c, Transferable t, int action) {
+	if (action == MOVE) {
+
+	    if (c instanceof JTable) {
+		JTable table = (JTable)c;
+
+		DataFlavor[] flavors = t.getTransferDataFlavors();
+
+		DataFlavor flavor = null;
+		if (hasLocalFlavor(flavors)) {
+		    flavor = localFlavor;
+		} else if (hasSerialFlavor(flavors)) {
+		    flavor = serialFlavor;
+		}
+
+		if (flavor != null) {
+		    try {
+			TableData data = (TableData)t.getTransferData(flavor);
+			TableRow[] rows = data.getRows();
+			TableModel model = table.getModel();
+			if (model instanceof EditableTableModel) {
+			    EditableTableModel editModel =
+				(EditableTableModel)model;
+
+			    for (int i = rows.length - 1; i >= 0; i--) {
+				TableRow row = rows[i];
+				if (row.success) {
+				    editModel.removeRow(row.index);
+				}
+			    }
+			}
+
+		    // Thrown by getTransferData
+		    } catch (IOException e) {
+
+		    // Thrown by getTransferData
+		    } catch (UnsupportedFlavorException e) {
+		    }
+		}
+	    }
+	}
+    }
+
+    @Override
+    public int getSourceActions(JComponent c) {
+	return COPY_OR_MOVE;
+    }
+
+    @Override
+    public boolean importData(JComponent c, Transferable t) {
+	boolean dropped = false;
+
+	if (c instanceof JTable) {
+
+	    JTable target = (JTable)c;
+	    DataFlavor[] flavors = t.getTransferDataFlavors();
+
+	    DataFlavor flavor = null;
+	    if (hasLocalFlavor(flavors)) {
+		flavor = localFlavor;
+	    } else if (hasSerialFlavor(flavors)) {
+		flavor = serialFlavor;
+	    }
+
+	    if (flavor != null) {
+		JTable.DropLocation dropLoc = target.getDropLocation();
+
+		if (dropLoc != null) {
+		    int insertRow = dropLoc.getRow();
+
+		    try {
+			TableData data = (TableData)t.getTransferData(flavor);
+			TableRow[] rows = data.getRows();
+
+			// Is the source table the same as the target table?
+			boolean isSame = flavor == localFlavor &&
+			    data.getTableHashCode() == target.hashCode();
+
+			// Rows cannot be dropped onto any row in selected range
+			// if the source and target are the same table
+			if (!isSame || insertRow <= rows[0].index ||
+			    insertRow > rows[rows.length -1].index) {
+
+			    TableModel model = target.getModel();
+			    if (model instanceof EditableTableModel) {
+				EditableTableModel editModel =
+				    (EditableTableModel)model;
+
+				int selectStart = insertRow;
+
+				for (TableRow row : rows) {
+				    row.success = editModel.attemptInsertRow(
+					insertRow, row.data);
+
+				    if (row.success) {
+					if (isSame) {
+					    for (TableRow r : rows) {
+						if (r.index >= insertRow) {
+						    r.index++;
+						}
+					    }
+					}
+					insertRow++;
+				    }
+				}
+
+				int selectEnd = insertRow - 1;
+
+				if (selectEnd >= selectStart) {
+				    target.setRowSelectionInterval(
+					selectStart, selectEnd);
+				}
+
+				target.requestFocusInWindow();
+
+				dropped = true;
+			    }
+			}
+
+		    // Thrown by getTransferData
+		    } catch (IOException e) {
+
+		    // Thrown by getTransferData
+		    } catch (UnsupportedFlavorException e) {
+		    }
+		}
+	    }
+	}
+
+	return dropped;
+    }
+
+    //
+    // Private methods
+    //
+
+    private boolean hasLocalFlavor(DataFlavor[] flavors) {
+	return ArrayUtil.indexOf(flavors, localFlavor) != -1;
+    }
+
+    private boolean hasSerialFlavor(DataFlavor[] flavors) {
+	return ArrayUtil.indexOf(flavors, serialFlavor) != -1;
+    }
+}