package open.dolphin.client; import java.awt.Toolkit; import java.awt.datatransfer.*; import java.io.IOException; import javax.swing.ActionMap; import javax.swing.JComponent; import javax.swing.TransferHandler; import javax.swing.event.CaretEvent; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import javax.swing.text.Position; import open.dolphin.infomodel.BundleDolphin; import open.dolphin.infomodel.ModuleModel; /** * BundleTransferHandler * @author Minagawa,Kazushi. Digital Globe, Inc. */ public class BundleTransferHandler extends TransferHandler implements IKarteTransferHandler { private ChartMediator mediator; private JTextComponent textCompo; private boolean hasSelection; // Start and end position in the source text. // We need this information when performing a MOVE // in order to remove the dragged text from the source. Position p0 = null, p1 = null; public BundleTransferHandler(ChartMediator med, JTextComponent tc) { this.textCompo = tc; this.textCompo.putClientProperty("karteCompositor", this.textCompo); this.mediator = med; textCompo.addCaretListener((CaretEvent ce) -> { boolean newSelection = (ce.getDot() != ce.getMark()); if (newSelection != hasSelection) { hasSelection = newSelection; if (hasSelection) { mediator.getAction(GUIConst.ACTION_COPY).setEnabled(true); mediator.getAction(GUIConst.ACTION_CUT).setEnabled(textCompo.isEditable()); } else { mediator.getAction(GUIConst.ACTION_COPY).setEnabled(false); mediator.getAction(GUIConst.ACTION_CUT).setEnabled(false); } } }); } /** * DropされたFlavorをインポートする。 * @return */ @Override public boolean importData(TransferHandler.TransferSupport support) { if (!canImport(support)) { return false; } JTextComponent tc = (JTextComponent) support.getComponent(); try { if (support.getTransferable().isDataFlavorSupported(OrderListTransferable.orderListFlavor)) { return doStampDrop(tc, support.getTransferable()); } else if (support.getTransferable().isDataFlavorSupported(DataFlavor.stringFlavor)) { String str = (String) support.getTransferable().getTransferData(DataFlavor.stringFlavor); tc.replaceSelection(str); return true; } } catch (UnsupportedFlavorException | IOException ufe) { } return false; } // Create a Transferable implementation that contains the // selected text. @Override protected Transferable createTransferable(JComponent c) { JTextComponent source = (JTextComponent) c; int start = source.getSelectionStart(); int end = source.getSelectionEnd(); Document doc = source.getDocument(); if (start == end) { return null; } try { p0 = doc.createPosition(start); p1 = doc.createPosition(end); } catch (BadLocationException e) { } String data = source.getSelectedText(); return new StringSelection(data); } @Override public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } // Remove the old text if the action is a MOVE. // However, we do not allow dropping on top of the selected text, // so in that case do nothing. @Override protected void exportDone(JComponent c, Transferable data, int action) { if (action != MOVE) { return; } JTextComponent tc = (JTextComponent) c; if (tc.isEditable()) { if ((p0 != null) && (p1 != null) && (p0.getOffset() != p1.getOffset())) { try { tc.getDocument().remove(p0.getOffset(), p1.getOffset() - p0.getOffset()); } catch (BadLocationException e) { System.out.println("Can't remove text from source."); } } } } /** * インポート可能かどうかを返す。 * @return */ @Override public boolean canImport(TransferHandler.TransferSupport support) { JTextComponent tc = (JTextComponent) support.getComponent(); boolean canImport = true; canImport = canImport && tc.isEditable(); canImport = canImport && (support.isDataFlavorSupported(DataFlavor.stringFlavor) || support.isDataFlavorSupported(OrderListTransferable.orderListFlavor)); return canImport; } /** * DropされたStamp(ModuleModel)をインポートする。 * @param tr Transferable * @return インポートに成功した時 true */ private boolean doStampDrop(JTextComponent tc, Transferable tr) { try { // スタンプのリストを取得する OrderList list = (OrderList) tr.getTransferData(OrderListTransferable.orderListFlavor); ModuleModel[] stamps = list.orderList; // pPaneにスタンプを挿入する for (int i = 0; i < stamps.length; i++) { if (stamps[i].getModel() instanceof BundleDolphin) { BundleDolphin bd = (BundleDolphin)stamps[i].getModel(); tc.replaceSelection(bd.toString()); } } return true; } catch (UnsupportedFlavorException | IOException e) { e.printStackTrace(System.err); } return false; } /** * クリップボードへデータを転送する。 */ @Override public void exportToClipboard(JComponent comp, Clipboard clip, int action) { super.exportToClipboard(comp, clip, action); // cut の場合を処理する if (action == MOVE) { JTextComponent pane = (JTextComponent) comp; if (pane.isEditable()) { pane.replaceSelection(""); } } } @Override public JComponent getComponent() { return textCompo; } @Override public void enter(ActionMap map) { if (textCompo.isEditable()) { map.get(GUIConst.ACTION_PASTE).setEnabled(canPaste()); } } @Override public void exit(ActionMap map) { } private boolean canPaste() { if (!textCompo.isEditable()) { return false; } Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null); if (t == null) { return false; } boolean canImport = true; canImport = canImport && (t.isDataFlavorSupported(DataFlavor.stringFlavor) || t.isDataFlavorSupported(OrderListTransferable.orderListFlavor)); return canImport; } }