From 58d5c30dad96737df20294d3d51ee39136d69e82 Mon Sep 17 00:00:00 2001 From: Akiyoshi Kamide Date: Sun, 3 Jul 2016 01:10:43 +0900 Subject: [PATCH] =?utf8?q?=E3=83=89=E3=83=A9=E3=83=83=E3=82=B0=EF=BC=86?= =?utf8?q?=E3=83=89=E3=83=AD=E3=83=83=E3=83=97=E5=87=A6=E7=90=86=E3=82=92T?= =?utf8?q?ransferHandler=E3=81=AB=E5=88=87=E3=82=8A=E6=9B=BF=E3=81=88?= =?utf8?q?=E3=81=A6MIDI=E3=83=87=E3=83=90=E3=82=A4=E3=82=B9=E6=8E=A5?= =?utf8?q?=E7=B6=9A=E3=81=AE=E3=82=B1=E3=83=BC=E3=83=96=E3=83=AB=E6=8F=8F?= =?utf8?q?=E7=94=BB=E3=82=92=E6=94=B9=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- src/camidion/chordhelper/ChordHelperApplet.java | 6 +- .../mididevice/AbstractTransceiverListView.java | 5 +- .../mididevice/DraggingTransceiver.java | 29 ---- .../chordhelper/mididevice/MidiCablePane.java | 82 +++++++++--- .../chordhelper/mididevice/MidiDeviceFrame.java | 6 +- .../chordhelper/mididevice/MidiDeviceTreeView.java | 80 +++++------ .../mididevice/MidiOpenedDevicesView.java | 147 +++++++++------------ .../chordhelper/mididevice/ReceiverListView.java | 116 +++++++--------- .../mididevice/TransmitterListView.java | 144 +++++++++----------- .../chordhelper/midieditor/MidiSequenceEditor.java | 42 ++---- 10 files changed, 286 insertions(+), 371 deletions(-) delete mode 100644 src/camidion/chordhelper/mididevice/DraggingTransceiver.java diff --git a/src/camidion/chordhelper/ChordHelperApplet.java b/src/camidion/chordhelper/ChordHelperApplet.java index 38c2e0b..27563f1 100644 --- a/src/camidion/chordhelper/ChordHelperApplet.java +++ b/src/camidion/chordhelper/ChordHelperApplet.java @@ -5,8 +5,6 @@ import java.awt.Desktop; import java.awt.Dimension; import java.awt.Image; import java.awt.Insets; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DropTarget; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; @@ -285,7 +283,7 @@ public class ChordHelperApplet extends JApplet { */ public static class VersionInfo { public static final String NAME = "MIDI Chord Helper"; - public static final String VERSION = "Ver.20160630.1"; + public static final String VERSION = "Ver.20160702.1"; public static final String COPYRIGHT = "Copyright (C) 2004-2016"; public static final String AUTHER = "@きよし - Akiyoshi Kamide"; public static final String URL = "http://www.yk.rim.or.jp/~kamide/music/chordhelper/"; @@ -478,7 +476,7 @@ public class ChordHelperApplet extends JApplet { (midiEditor = new MidiSequenceEditor(playlistModel, guiMidiDevice)).setIconImage(iconImage); // // メイン画面へのMIDIファイルのドラッグ&ドロップ受付開始 - new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, midiEditor.dropTargetListener, true); + setTransferHandler(midiEditor.transferHandler); // // MIDIエディタのイベントダイアログを、ピアノ鍵盤のイベント送出ダイアログと共用 keyboardPanel.setEventDialog(midiEditor.eventDialog); diff --git a/src/camidion/chordhelper/mididevice/AbstractTransceiverListView.java b/src/camidion/chordhelper/mididevice/AbstractTransceiverListView.java index 4a71351..9def514 100644 --- a/src/camidion/chordhelper/mididevice/AbstractTransceiverListView.java +++ b/src/camidion/chordhelper/mididevice/AbstractTransceiverListView.java @@ -6,6 +6,7 @@ import java.awt.Rectangle; import javax.sound.midi.Receiver; import javax.sound.midi.Transmitter; +import javax.swing.DropMode; import javax.swing.JList; import javax.swing.ListSelectionModel; @@ -22,7 +23,7 @@ public abstract class AbstractTransceiverListView extends JList { return (AbstractTransceiverListModel) super.getModel(); } /** - * このリストの座標系内の指定された位置にある要素を返します。 + * このリストの座標系内の指定された位置にある最寄りの要素を返します。 * @param p 位置 */ public E getElementAt(Point p) { @@ -62,5 +63,7 @@ public abstract class AbstractTransceiverListView extends JList { return this; } }); + setDragEnabled(true); + setDropMode(DropMode.ON); } } diff --git a/src/camidion/chordhelper/mididevice/DraggingTransceiver.java b/src/camidion/chordhelper/mididevice/DraggingTransceiver.java deleted file mode 100644 index 1b81470..0000000 --- a/src/camidion/chordhelper/mididevice/DraggingTransceiver.java +++ /dev/null @@ -1,29 +0,0 @@ -package camidion.chordhelper.mididevice; - -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.Transferable; -import java.util.Arrays; -import java.util.List; - -import javax.sound.midi.Receiver; -import javax.sound.midi.Transmitter; - -/** - * ドラッグ&ドロップで転送する{@link Transmitter}または{@link Receiver}の収容箱 - */ -public class DraggingTransceiver implements Transferable { - public static final DataFlavor receiverFlavor = new DataFlavor(Receiver.class, "Receiver"); - public static final DataFlavor transmitterFlavor = new DataFlavor(Transmitter.class, "Transmitter"); - private static final List flavors = Arrays.asList(transmitterFlavor, receiverFlavor); - private Object data; - public Object getData() { return data; } - public void setData(Object data) { this.data = data; } - @Override - public Object getTransferData(DataFlavor flavor) { - return flavor.getRepresentationClass().isInstance(data) ? data : null; - } - @Override - public DataFlavor[] getTransferDataFlavors() { return (DataFlavor[]) flavors.toArray(); } - @Override - public boolean isDataFlavorSupported(DataFlavor flavor) { return flavors.contains(flavor); } -} diff --git a/src/camidion/chordhelper/mididevice/MidiCablePane.java b/src/camidion/chordhelper/mididevice/MidiCablePane.java index c6186de..681bd25 100644 --- a/src/camidion/chordhelper/mididevice/MidiCablePane.java +++ b/src/camidion/chordhelper/mididevice/MidiCablePane.java @@ -7,6 +7,9 @@ import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.Stroke; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceMotionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; @@ -29,22 +32,37 @@ import javax.swing.event.ListDataListener; * MIDI ケーブル描画面 */ public class MidiCablePane extends JComponent { - static DraggingTransceiver dragging = new DraggingTransceiver(); + private Object dragSourceTransceiver; + private Object dragDestinationTransceiver; private Point draggingPoint; /** - * ドラッグ中の場所を更新し、再描画を予約します。 - * @param p ドラッグ中の場所(ドラッグ&ドロップ終了時はnullを指定) + * ドラッグ元の{@link Transmitter}または{@link Receiver}を設定します。 + * + * @param trx ドラッグ元 */ - public void updateDraggingLocation(Point p) { - if( (draggingPoint = p) == null ) { - dragging.setData(null); - } else { - Point origin = getLocationOnScreen(); - draggingPoint.translate(-origin.x, -origin.y); + public void setDragSourceTransceiver(Object trx) { + if( (dragSourceTransceiver = trx) == null ) { + draggingPoint = null; + dragDestinationTransceiver = null; } repaint(); } /** + * ドラッグ元の{@link Transmitter}または{@link Receiver}を返します。 + */ + public Object getDragSourceTransceiver() { return dragSourceTransceiver; } + /** + * ドラッグ先の{@link Transmitter}または{@link Receiver}を設定します。 + * @param dragDestinationTransceiver 設定するドラッグ先 + */ + public void setDragDestinationTransceiver(Object dragDestinationTransceiver) { + this.dragDestinationTransceiver = dragDestinationTransceiver; + } + /** + * ドラッグ先の{@link Transmitter}または{@link Receiver}を返します。 + */ + public Object getDragDestinationTranceiver() { return dragDestinationTransceiver; } + /** * {@link MidiDeviceFrame} が移動または変形したときにケーブルを再描画するためのリスナー */ public final ComponentListener midiDeviceFrameComponentListener = new ComponentAdapter() { @@ -90,10 +108,22 @@ public class MidiCablePane extends JComponent { this.desktopPane = desktopPane; setOpaque(false); setVisible(true); + DragSource.getDefaultDragSource().addDragSourceMotionListener(new DragSourceMotionListener() { + @Override + public void dragMouseMoved(DragSourceDragEvent dsde) { + // OSのスクリーン座標系から、このケーブル画面の座標系に変換する + Point origin = getLocationOnScreen(); + (draggingPoint = dsde.getLocation()).translate(-origin.x, -origin.y); + repaint(); + } + }); } private static final Stroke CABLE_STROKE = new BasicStroke( 3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); + private static final float dash[] = {1.0f, 5.0f}; + private static final Stroke VIRTUAL_CABLE_STROKE = new BasicStroke( + 3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, dash, 0.0f); private static final List CABLE_COLORS = Arrays.asList( new Color(255, 0, 0,144), new Color(0, 255, 0,144), @@ -102,8 +132,7 @@ public class MidiCablePane extends JComponent { new Color(0,191,191,144), new Color(191,0,191,144) ); - private static final Color ADDING_CABLE_COLOR = new Color(0, 0, 0, 144); - private static final Color REMOVING_CABLE_COLOR = new Color(128, 128, 128, 144); + private static final Color NEW_CABLE_COLOR = new Color(0, 0, 0, 144); private Hashtable colorMap = new Hashtable<>(); private Color colorOf(Receiver rx) { Color color = colorMap.get(rx); @@ -123,7 +152,6 @@ public class MidiCablePane extends JComponent { public void paint(Graphics g) { super.paint(g); Graphics2D g2 = (Graphics2D)g; - g2.setStroke(CABLE_STROKE); JInternalFrame[] frames = desktopPane.getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER); for( JInternalFrame frame : frames ) { if( ! (frame instanceof MidiDeviceFrame) ) continue; @@ -131,12 +159,17 @@ public class MidiCablePane extends JComponent { MidiDeviceModel fromDeviceModel = fromFrame.getMidiDeviceModel(); // // Receiverからドラッグされている線を描画 - if( draggingPoint != null && fromDeviceModel.getMidiDevice().getReceivers().contains(dragging.getData()) ) { - Receiver rx = (Receiver)dragging.getData(); + if( draggingPoint != null && fromDeviceModel.getMidiDevice().getReceivers().contains(dragSourceTransceiver) ) { + Receiver rx = (Receiver)dragSourceTransceiver; Rectangle rxBounds = fromFrame.getBoundsOf(rx); if( rxBounds == null ) continue; int r = (rxBounds.height - 5) / 2; rxBounds.translate(r+4, r+4); + if( dragDestinationTransceiver instanceof Transmitter ) { + g2.setStroke(CABLE_STROKE); + } else { + g2.setStroke(VIRTUAL_CABLE_STROKE); + } g2.setColor(colorOf(rx)); g2.drawLine(rxBounds.x, rxBounds.y, draggingPoint.x, draggingPoint.y); } @@ -151,27 +184,32 @@ public class MidiCablePane extends JComponent { if( txBounds == null ) continue; int r = (txBounds.height - 5) / 2; txBounds.translate(r+4, r+4); - // - // Transmitterに現在接続されているReceiverを把握 - Receiver rx = tx.getReceiver(); - if( draggingPoint != null && tx.equals(dragging.getData()) ) { + if( draggingPoint != null && tx.equals(dragSourceTransceiver) ) { // // Transmitterからドラッグされている線を描画 - g2.setColor(rx == null ? ADDING_CABLE_COLOR : colorOf(rx)); + if( dragDestinationTransceiver instanceof Receiver ) { + g2.setStroke(CABLE_STROKE); + g2.setColor(colorOf((Receiver)dragDestinationTransceiver)); + } else { + g2.setStroke(VIRTUAL_CABLE_STROKE); + g2.setColor(NEW_CABLE_COLOR); + } g2.drawLine(txBounds.x, txBounds.y, draggingPoint.x, draggingPoint.y); } + // + // スキャン中のTransmitterに現在接続されているReceiverを把握 + Receiver rx = tx.getReceiver(); if( rx == null ) continue; for( JInternalFrame toFrame : frames ) { if( ! (toFrame instanceof MidiDeviceFrame) ) continue; - // - // Receiverの場所を特定 Rectangle rxBounds = ((MidiDeviceFrame)toFrame).getBoundsOf(rx); if( rxBounds == null ) continue; r = (rxBounds.height - 5) / 2; rxBounds.translate(r+4, r+4); // // Transmitter⇔Receiver間の線を描画 - g2.setColor(tx.equals(dragging.getData()) ? REMOVING_CABLE_COLOR : colorOf(rx)); + g2.setStroke(tx.equals(dragSourceTransceiver) ? VIRTUAL_CABLE_STROKE : CABLE_STROKE); + g2.setColor(colorOf(rx)); g2.drawLine(txBounds.x, txBounds.y, rxBounds.x, rxBounds.y); break; } diff --git a/src/camidion/chordhelper/mididevice/MidiDeviceFrame.java b/src/camidion/chordhelper/mididevice/MidiDeviceFrame.java index 90785e8..6402788 100644 --- a/src/camidion/chordhelper/mididevice/MidiDeviceFrame.java +++ b/src/camidion/chordhelper/mididevice/MidiDeviceFrame.java @@ -13,7 +13,6 @@ import javax.sound.midi.Receiver; import javax.sound.midi.Transmitter; import javax.swing.JInternalFrame; import javax.swing.JLabel; -import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.Timer; @@ -106,6 +105,7 @@ public class MidiDeviceFrame extends JInternalFrame { public Rectangle getBoundsOf(Transmitter tx) { if( transmitterListView == null ) return null; Rectangle rect = transmitterListView.getCellBounds(tx); + if( rect == null ) return null; translate(rect, txPanel, transmitterListView); return rect; } @@ -117,11 +117,11 @@ public class MidiDeviceFrame extends JInternalFrame { public Rectangle getBoundsOf(Receiver rx) { if( receiverListView == null ) return null; Rectangle rect = receiverListView.getCellBounds(rx); + if( rect == null ) return null; translate(rect, rxPanel, receiverListView); return rect; } - private void translate(Rectangle rect, JPanel panel, JList list) { - if( rect == null ) return; + private void translate(Rectangle rect, JPanel panel, AbstractTransceiverListView list) { int x = getX() + getRootPane().getX() + getContentPane().getX() + scrollPane.getX() + trxPanel.getX() + panel.getX() + list.getX(); diff --git a/src/camidion/chordhelper/mididevice/MidiDeviceTreeView.java b/src/camidion/chordhelper/mididevice/MidiDeviceTreeView.java index 9bcda1a..2099151 100644 --- a/src/camidion/chordhelper/mididevice/MidiDeviceTreeView.java +++ b/src/camidion/chordhelper/mididevice/MidiDeviceTreeView.java @@ -1,19 +1,14 @@ package camidion.chordhelper.mididevice; import java.awt.Component; -import java.awt.Point; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DragGestureEvent; -import java.awt.dnd.DragGestureListener; -import java.awt.dnd.DragSource; -import java.awt.dnd.DragSourceAdapter; -import java.awt.dnd.DragSourceDropEvent; +import javax.swing.JComponent; import javax.swing.JInternalFrame; import javax.swing.JTree; import javax.swing.ToolTipManager; +import javax.swing.TransferHandler; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; import javax.swing.event.InternalFrameListener; @@ -23,24 +18,8 @@ import javax.swing.tree.DefaultTreeCellRenderer; * MIDIデバイスツリービュー */ public class MidiDeviceTreeView extends JTree { - - public static final DataFlavor DEVICE_MODEL_FLAVOR = new DataFlavor(MidiDeviceModel.class,"MidiDeviceModel"); - - public class DraggingDevice implements Transferable { - private DataFlavor flavors[] = {DEVICE_MODEL_FLAVOR}; - private MidiDeviceModel midiDeviceModel; - @Override - public Object getTransferData(DataFlavor flavor) { - return flavor.getRepresentationClass().isInstance(midiDeviceModel) ? midiDeviceModel : null; - } - @Override - public DataFlavor[] getTransferDataFlavors() { return flavors; } - @Override - public boolean isDataFlavorSupported(DataFlavor flavor) { - return flavors[0].equals(flavor); - } - }; - private DraggingDevice draggingDevice = new DraggingDevice(); + public static final DataFlavor deviceModelFlavor = new DataFlavor(MidiDeviceModel.class,"MidiDeviceModel"); + private static final DataFlavor flavors[] = {deviceModelFlavor}; /** * {@link MidiDeviceFrame} が閉じられたり、選択されたりしたときに再描画するリスナー */ @@ -62,24 +41,6 @@ public class MidiDeviceTreeView extends JTree { */ public MidiDeviceTreeView(MidiDeviceTreeModel model) { super(model); - (new DragSource()).createDefaultDragGestureRecognizer( - this, DnDConstants.ACTION_COPY_OR_MOVE, new DragGestureListener() { - @Override - public void dragGestureRecognized(DragGestureEvent dge) { - if( (dge.getDragAction() & DnDConstants.ACTION_COPY_OR_MOVE) == 0 ) return; - Point origin = dge.getDragOrigin(); - Object leaf = getPathForLocation(origin.x, origin.y).getLastPathComponent(); - if( ! (leaf instanceof MidiDeviceModel) ) return; - draggingDevice.midiDeviceModel = (MidiDeviceModel)leaf; - dge.startDrag(DragSource.DefaultMoveDrop, draggingDevice, new DragSourceAdapter() { - @Override - public void dragDropEnd(DragSourceDropEvent dsde) { - if( dsde.getDropSuccess() ) repaint(); - } - }); - } - } - ); setCellRenderer(new DefaultTreeCellRenderer() { @Override public Component getTreeCellRendererComponent(JTree tree, Object value, @@ -107,6 +68,37 @@ public class MidiDeviceTreeView extends JTree { // // ツリーノードのToolTipを有効化 ToolTipManager.sharedInstance().registerComponent(this); - + // + // ドラッグを有効化 + setDragEnabled(true); + setTransferHandler(new TransferHandler() { + @Override + public int getSourceActions(JComponent c) { return COPY_OR_MOVE; } + @Override + protected Transferable createTransferable(JComponent c) { + JTree tree = (JTree) c; + Object node = tree.getLastSelectedPathComponent(); + if( node instanceof MidiDeviceModel ) { + MidiDeviceModel midiDeviceModel = (MidiDeviceModel)node; + if( ! midiDeviceModel.getMidiDevice().isOpen() ) return new Transferable() { + @Override + public Object getTransferData(DataFlavor flavor) { + return flavor.getRepresentationClass().isInstance(midiDeviceModel) ? midiDeviceModel : null; + } + @Override + public DataFlavor[] getTransferDataFlavors() { return flavors; } + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + return flavors[0].equals(flavor); + } + }; + } + return null; + } + @Override + protected void exportDone(JComponent source, Transferable data, int action) { + if( action != NONE ) repaint(); + } + }); } } diff --git a/src/camidion/chordhelper/mididevice/MidiOpenedDevicesView.java b/src/camidion/chordhelper/mididevice/MidiOpenedDevicesView.java index 1234078..093d49f 100644 --- a/src/camidion/chordhelper/mididevice/MidiOpenedDevicesView.java +++ b/src/camidion/chordhelper/mididevice/MidiOpenedDevicesView.java @@ -1,12 +1,5 @@ package camidion.chordhelper.mididevice; -import java.awt.datatransfer.Transferable; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DropTarget; -import java.awt.dnd.DropTargetAdapter; -import java.awt.dnd.DropTargetDragEvent; -import java.awt.dnd.DropTargetDropEvent; -import java.awt.dnd.DropTargetListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.beans.PropertyVetoException; @@ -18,17 +11,19 @@ import javax.swing.JDesktopPane; import javax.swing.JInternalFrame; import javax.swing.JLayeredPane; import javax.swing.JOptionPane; +import javax.swing.TransferHandler; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.TreePath; /** - * 開いている MIDI デバイスを置くためのデスクトップビュー + * 開いているMIDIデバイスを置くためのデスクトップビュー */ public class MidiOpenedDevicesView extends JDesktopPane implements TreeSelectionListener { - + /** + * MIDIデバイスモデルからフレームを割り出すためのマップ + */ private Map modelToFrame = new HashMap<>(); - /** * ツリー上で選択状態が変わったとき、このデスクトップ上のフレームの選択状態に反映します。 */ @@ -61,84 +56,11 @@ public class MidiOpenedDevicesView extends JDesktopPane implements TreeSelection ex.printStackTrace(); } } - /** - * ツリー表示からこのデスクトップにドロップされたMIDIデバイスモデルに対応するフレームを表示するためのリスナー - */ - private DropTargetListener dropTargetListener = new DropTargetAdapter() { - @Override - public void dragEnter(DropTargetDragEvent dtde) { - if( dtde.getTransferable().isDataFlavorSupported(MidiDeviceTreeView.DEVICE_MODEL_FLAVOR) ) { - dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE); - } - } - @Override - public void drop(DropTargetDropEvent dtde) { - dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); - try { - int maskedBits = dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE; - if( maskedBits == 0 ) { - dtde.dropComplete(false); - return; - } - Transferable t = dtde.getTransferable(); - if( ! t.isDataFlavorSupported(MidiDeviceTreeView.DEVICE_MODEL_FLAVOR) ) { - dtde.dropComplete(false); - return; - } - Object source = t.getTransferData(MidiDeviceTreeView.DEVICE_MODEL_FLAVOR); - if( ! (source instanceof MidiDeviceModel) ) { - dtde.dropComplete(false); - return; - } - MidiDeviceModel deviceModel = (MidiDeviceModel)source; - try { - deviceModel.open(); - } catch( MidiUnavailableException e ) { - // - // デバイスを開くのに失敗した場合 - // - // 例えば、「Microsort MIDI マッパー」と - // 「Microsoft GS Wavetable SW Synth」を - // 同時に開こうとするとここに来る。 - // - String title = "Cannot open MIDI device"; - String message = "MIDIデバイス "+deviceModel+" はすでに使用中です。\n" - +"他のデバイスが連動して開いている可能性があります。\n\n" - + e.getMessage(); - dtde.dropComplete(false); - JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE); - return; - } - if( ! deviceModel.getMidiDevice().isOpen() ) { - // 例外が出なかったにも関わらずデバイスが開かれていない場合 - String title = "Cannot open MIDI device"; - String message = "MIDIデバイス "+deviceModel+" はすでに使用中です。\n" - +"他のデバイスが連動して開いている可能性があります。\n\n" ; - dtde.dropComplete(false); - JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE); - return; - } - // - // デバイスが正常に開かれたことを確認できたら - // ドロップした場所へフレームを配置して可視化する。 - // - MidiDeviceFrame deviceFrame = modelToFrame.get(deviceModel); - deviceFrame.setLocation(dtde.getLocation()); - deviceFrame.setVisible(true); - dtde.dropComplete(true); - } - catch (Exception ex) { - ex.printStackTrace(); - dtde.dropComplete(false); - } - } - }; - - MidiCablePane cablePane = new MidiCablePane(this); public MidiOpenedDevicesView(MidiDeviceTreeView deviceTreeView, MidiDeviceInfoPane deviceInfoPane, MidiDeviceDialog dialog) { + MidiCablePane cablePane = new MidiCablePane(this); add(cablePane, JLayeredPane.PALETTE_LAYER); addComponentListener(new ComponentAdapter() { @Override @@ -184,7 +106,62 @@ public class MidiOpenedDevicesView extends JDesktopPane implements TreeSelection toY += 50; } } - new DropTarget( this, DnDConstants.ACTION_COPY_OR_MOVE, dropTargetListener, true ); + setTransferHandler(new TransferHandler() { + @Override + public boolean canImport(TransferSupport support) { + if( ! support.isDrop() ) return false; + if( support.isDataFlavorSupported(MidiDeviceTreeView.deviceModelFlavor) ) { + // MIDIデバイスを開くためのドロップを受け付ける + return true; + } + if( support.isDataFlavorSupported(TransmitterListView.elementFlavor) ) { + cablePane.setDragDestinationTransceiver(null); + // Transmitterの切り離しができるよう、ドロップを容認 + return true; + } + if( support.isDataFlavorSupported(ReceiverListView.elementFlavor) ) { + cablePane.setDragDestinationTransceiver(null); + // Receiverはドロップ不可 + } + return false; + } + @Override + public boolean importData(TransferSupport support) { + MidiDeviceModel deviceModel = null; + Object from; + try { + from = support.getTransferable().getTransferData(MidiDeviceTreeView.deviceModelFlavor); + if( ! (from instanceof MidiDeviceModel) ) return false; + deviceModel = (MidiDeviceModel)from; + deviceModel.open(); + if( ! deviceModel.getMidiDevice().isOpen() ) { + throw new MidiUnavailableException("開いたはずなのに、開かれた状態になっていません。"); + } + MidiDeviceFrame deviceFrame = modelToFrame.get(deviceModel); + if( ! deviceFrame.isVisible() ) { + deviceFrame.setLocation(support.getDropLocation().getDropPoint()); + deviceFrame.setVisible(true); + } + return true; + } catch( MidiUnavailableException e ) { + // + // デバイスを開くのに失敗した場合 + // + // 例えば、「Microsort MIDI マッパー」と「Microsoft GS Wavetable SW Synth」は + // 連動して開かれるため、同時に開こうとすると、ここにたどり着く。 + // + String title = "Cannot open MIDI device"; + String message = "MIDIデバイス "+deviceModel+" はすでに使用中です。\n" + +"他のデバイスが連動して開いている可能性があります。\n\n" + + e.getMessage(); + JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE); + return false; + } catch (Exception ex) { + ex.printStackTrace(); + return false; + } + } + }); } } diff --git a/src/camidion/chordhelper/mididevice/ReceiverListView.java b/src/camidion/chordhelper/mididevice/ReceiverListView.java index 31788fa..40cdc3a 100644 --- a/src/camidion/chordhelper/mididevice/ReceiverListView.java +++ b/src/camidion/chordhelper/mididevice/ReceiverListView.java @@ -1,33 +1,27 @@ package camidion.chordhelper.mididevice; +import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DragGestureEvent; -import java.awt.dnd.DragGestureListener; -import java.awt.dnd.DragSource; -import java.awt.dnd.DragSourceAdapter; -import java.awt.dnd.DragSourceDragEvent; -import java.awt.dnd.DragSourceDropEvent; -import java.awt.dnd.DragSourceMotionListener; -import java.awt.dnd.DropTarget; -import java.awt.dnd.DropTargetAdapter; -import java.awt.dnd.DropTargetDragEvent; -import java.awt.dnd.DropTargetDropEvent; -import java.awt.dnd.DropTargetListener; +import java.util.Arrays; +import java.util.List; import javax.sound.midi.Receiver; import javax.sound.midi.Transmitter; +import javax.swing.JComponent; +import javax.swing.TransferHandler; /** * {@link Receiver}のリストビュー */ public class ReceiverListView extends AbstractTransceiverListView { - @Override - public ReceiverListModel getModel() { return (ReceiverListModel) super.getModel(); } + public static final DataFlavor elementFlavor = new DataFlavor(Receiver.class, "Receiver"); + protected static final List flavors = Arrays.asList(elementFlavor); @Override protected String toolTipTextFor(Receiver rx) { return "受信端子(Rx):ドラッグ&ドロップしてTxに接続できます。"; } + @Override + public ReceiverListModel getModel() { return (ReceiverListModel) super.getModel(); } /** * 仮想MIDI端子リストビューを生成します。 * @param model このビューから参照されるデータモデル @@ -35,73 +29,55 @@ public class ReceiverListView extends AbstractTransceiverListView { */ public ReceiverListView(ReceiverListModel model, MidiCablePane cablePane) { super(model); - setupDrag(cablePane); - setupDrop(); - } - /** - * {@link Receiver}をドラッグできるようにします。 - * @param cablePane MIDIケーブル描画面 - */ - private void setupDrag(MidiCablePane cablePane) { - DragSource dragSource = new DragSource(); - DragGestureListener dgl = new DragGestureListener() { + setTransferHandler(new TransferHandler() { + @Override + public int getSourceActions(JComponent compo) { return COPY_OR_MOVE; } @Override - public void dragGestureRecognized(DragGestureEvent event) { - if( (event.getDragAction() & DnDConstants.ACTION_COPY_OR_MOVE) == 0 ) return; - MidiCablePane.dragging.setData(getElementAt(event.getDragOrigin())); - event.startDrag(DragSource.DefaultLinkDrop, MidiCablePane.dragging, new DragSourceAdapter() { + protected Transferable createTransferable(JComponent compo) { + cablePane.setDragSourceTransceiver(getSelectedValue()); + return new Transferable() { + @Override + public Object getTransferData(DataFlavor flavor) { + return cablePane.getDragSourceTransceiver(); + } @Override - public void dragDropEnd(DragSourceDropEvent dsde) { - cablePane.updateDraggingLocation(null); + public DataFlavor[] getTransferDataFlavors() { + return (DataFlavor[]) flavors.toArray(); } - }); + @Override + public boolean isDataFlavorSupported(DataFlavor flavor) { + return flavors.contains(flavor); + } + }; } - }; - dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, dgl); - dragSource.addDragSourceMotionListener(new DragSourceMotionListener() { @Override - public void dragMouseMoved(DragSourceDragEvent dsde) { - cablePane.updateDraggingLocation(dsde.getLocation()); + protected void exportDone(JComponent source, Transferable data, int action) { + cablePane.setDragSourceTransceiver(null); } - }); - } - /** - * {@link Transmitter}のドロップを受け付けます。 - */ - private void setupDrop() { - DropTargetListener dtl = new DropTargetAdapter() { @Override - public void dragEnter(DropTargetDragEvent event) { - if( event.isDataFlavorSupported(DraggingTransceiver.transmitterFlavor) ) { - event.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE); + public boolean canImport(TransferSupport support) { + if( ! support.isDrop() ) return false; + if( support.isDataFlavorSupported(TransmitterListView.elementFlavor) ) { + Receiver to = getElementAt(support.getDropLocation().getDropPoint()); + cablePane.setDragDestinationTransceiver(to); + return true; } + cablePane.setDragDestinationTransceiver(null); + return false; } @Override - public void drop(DropTargetDropEvent event) { - event.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); - if( (event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) == 0 ) { - event.dropComplete(false); - return; - } - Transferable t = event.getTransferable(); - if( ! t.isDataFlavorSupported(DraggingTransceiver.transmitterFlavor) ) { - event.dropComplete(false); - return; - } + public boolean importData(TransferSupport support) { try { - Object tx = t.getTransferData(DraggingTransceiver.transmitterFlavor); - if( tx != null ) { - ((Transmitter)tx).setReceiver(getElementAt(event.getLocation())); - event.dropComplete(true); - return; - } + Object from = support.getTransferable().getTransferData(TransmitterListView.elementFlavor); + if( ! (from instanceof Transmitter) ) return false; + Receiver to = getElementAt(support.getDropLocation().getDropPoint()); + ((Transmitter)from).setReceiver(to); + return true; + } catch (Exception exception) { + exception.printStackTrace(); + return false; } - catch (Exception ex) { - ex.printStackTrace(); - } - event.dropComplete(false); } - }; - new DropTarget( this, DnDConstants.ACTION_COPY_OR_MOVE, dtl, true ); + }); } } diff --git a/src/camidion/chordhelper/mididevice/TransmitterListView.java b/src/camidion/chordhelper/mididevice/TransmitterListView.java index c30d71c..383ca45 100644 --- a/src/camidion/chordhelper/mididevice/TransmitterListView.java +++ b/src/camidion/chordhelper/mididevice/TransmitterListView.java @@ -1,29 +1,21 @@ package camidion.chordhelper.mididevice; +import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; -import java.awt.dnd.DnDConstants; -import java.awt.dnd.DragGestureEvent; -import java.awt.dnd.DragGestureListener; -import java.awt.dnd.DragSource; -import java.awt.dnd.DragSourceAdapter; -import java.awt.dnd.DragSourceDragEvent; -import java.awt.dnd.DragSourceDropEvent; -import java.awt.dnd.DragSourceMotionListener; -import java.awt.dnd.DropTarget; -import java.awt.dnd.DropTargetAdapter; -import java.awt.dnd.DropTargetDragEvent; -import java.awt.dnd.DropTargetDropEvent; -import java.awt.dnd.DropTargetListener; +import java.util.Arrays; +import java.util.List; import javax.sound.midi.Receiver; import javax.sound.midi.Transmitter; +import javax.swing.JComponent; +import javax.swing.TransferHandler; /** * {@link Transmitter}のリストビュー */ public class TransmitterListView extends AbstractTransceiverListView { - @Override - public TransmitterListModel getModel() { return (TransmitterListModel) super.getModel(); } + public static final DataFlavor elementFlavor = new DataFlavor(Transmitter.class, "Transmitter"); + protected static final List flavors = Arrays.asList(elementFlavor); @Override protected String toolTipTextFor(Transmitter tx) { if( tx instanceof DummyTransmitter ) { @@ -32,6 +24,8 @@ public class TransmitterListView extends AbstractTransceiverListView)t.getTransferData(DataFlavor.javaFileListFlavor)); - event.dropComplete(true); - return; - } - } - } - catch (Exception ex) { - ex.printStackTrace(); + loadAndPlay((List)support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor)); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; } - event.dropComplete(false); } }; @@ -1155,7 +1139,7 @@ public class MidiSequenceEditor extends JDialog { setTitle("MIDI Editor/Playlist - MIDI Chord Helper"); setBounds( 150, 200, 900, 500 ); setLayout(new FlowLayout()); - new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, dropTargetListener, true); + setTransferHandler(transferHandler); // // パネルレイアウト JPanel playlistPanel = new JPanel() {{ -- 2.11.0