OSDN Git Service

ドラッグ&ドロップ周りのリファクタリング
authorAkiyoshi Kamide <kamide@yk.rim.or.jp>
Sat, 18 Jun 2016 17:46:38 +0000 (02:46 +0900)
committerAkiyoshi Kamide <kamide@yk.rim.or.jp>
Sat, 18 Jun 2016 17:46:38 +0000 (02:46 +0900)
src/camidion/chordhelper/ChordHelperApplet.java
src/camidion/chordhelper/mididevice/DraggingTransceiver.java [new file with mode: 0644]
src/camidion/chordhelper/mididevice/MidiCablePane.java
src/camidion/chordhelper/mididevice/MidiDeviceDialog.java
src/camidion/chordhelper/mididevice/MidiDeviceFrame.java
src/camidion/chordhelper/mididevice/MidiDeviceInfoPane.java
src/camidion/chordhelper/mididevice/MidiDeviceModel.java
src/camidion/chordhelper/mididevice/MidiDeviceModelList.java
src/camidion/chordhelper/mididevice/MidiOpenedDevicesView.java
src/camidion/chordhelper/mididevice/MidiReceiverListView.java
src/camidion/chordhelper/mididevice/MidiTransmitterListView.java

index a6d8fbc..436862d 100644 (file)
@@ -285,7 +285,7 @@ public class ChordHelperApplet extends JApplet {
         */
        public static class VersionInfo {
                public static final String      NAME = "MIDI Chord Helper";
-               public static final String      VERSION = "Ver.20160617.1";
+               public static final String      VERSION = "Ver.20160618.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/";
diff --git a/src/camidion/chordhelper/mididevice/DraggingTransceiver.java b/src/camidion/chordhelper/mididevice/DraggingTransceiver.java
new file mode 100644 (file)
index 0000000..1b81470
--- /dev/null
@@ -0,0 +1,29 @@
+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<DataFlavor> 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); }
+}
index 6f8ecf9..949be78 100644 (file)
@@ -7,7 +7,10 @@ import java.awt.Graphics2D;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.Stroke;
+import java.awt.dnd.DragSourceAdapter;
 import java.awt.dnd.DragSourceDragEvent;
+import java.awt.dnd.DragSourceDropEvent;
+import java.awt.dnd.DragSourceListener;
 import java.awt.dnd.DragSourceMotionListener;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
@@ -32,10 +35,10 @@ import javax.swing.event.ListDataListener;
  * MIDI ケーブル描画面
  */
 public class MidiCablePane extends JComponent implements DragSourceMotionListener {
+       static DraggingTransceiver dragging = new DraggingTransceiver();
        private Point draggingPoint;
        /**
-        * {@link MidiDeviceModel} の {@link Transmitter}
-        * をドラッグしている最中に再描画するためのリスナー
+        * ドラッグしている最中に再描画するためのソースモーションリスナー
         */
        @Override
        public void dragMouseMoved(DragSourceDragEvent dsde) {
@@ -45,9 +48,16 @@ public class MidiCablePane extends JComponent implements DragSourceMotionListene
                repaint();
        }
        /**
-        * ドラッグ&ドロップの終了時に必要な再描画を行います。
+        * ドラッグ終了時に再描画するためのソースリスナー
         */
-       public void dragDropEnd() { draggingPoint = null; repaint(); }
+       public final DragSourceListener dragSourceListener = new DragSourceAdapter() {
+               @Override
+               public void dragDropEnd(DragSourceDropEvent dsde) {
+                       dragging.setData(null);
+                       draggingPoint = null;
+                       repaint();
+               }
+       };
        /**
         * {@link MidiDeviceFrame} が移動または変形したときにケーブルを再描画するためのリスナー
         */
@@ -133,44 +143,47 @@ public class MidiCablePane extends JComponent implements DragSourceMotionListene
                        if( ! (frame instanceof MidiDeviceFrame) ) continue;
                        MidiDeviceFrame fromFrame = (MidiDeviceFrame)frame;
                        MidiDevice fromDevice = fromFrame.getMidiDeviceModel().getMidiDevice();
-                       if( draggingPoint != null ) {
-                               // Receiverからドラッグされた線を描画
-                               MidiReceiverListView rxView = fromFrame.getMidiReceiverListView();
-                               List<Receiver> rxList = fromDevice.getReceivers();
-                               for( Receiver rx : rxList ) {
-                                       if( ! rx.equals(rxView.getDraggingReceiver()) ) continue;
-                                       Rectangle rxBounds = fromFrame.getBoundsOf(rx);
-                                       if( rxBounds == null ) continue;
-                                       int r = (rxBounds.height - 5) / 2;
-                                       rxBounds.translate(r+4, r+4);
-                                       g2.setColor(colorOf(rx));
-                                       g2.drawLine(rxBounds.x, rxBounds.y, draggingPoint.x, draggingPoint.y);
-                                       break;
-                               }
+                       //
+                       // Receiverからドラッグされている線を描画
+                       if( draggingPoint != null && fromDevice.getReceivers().indexOf(dragging.getData()) >= 0 ) {
+                               Receiver rx = (Receiver)dragging.getData();
+                               Rectangle rxBounds = fromFrame.getBoundsOf(rx);
+                               if( rxBounds == null ) continue;
+                               int r = (rxBounds.height - 5) / 2;
+                               rxBounds.translate(r+4, r+4);
+                               g2.setColor(colorOf(rx));
+                               g2.drawLine(rxBounds.x, rxBounds.y, draggingPoint.x, draggingPoint.y);
                        }
-                       MidiTransmitterListView txView = fromFrame.getMidiTransmitterListView();
+                       // Transmitterを全部スキャン
                        List<Transmitter> txList = fromDevice.getTransmitters();
                        for( Transmitter tx : txList ) {
+                               //
                                // Transmitterの場所を特定
                                Rectangle txBounds = fromFrame.getBoundsOf(tx);
                                if( txBounds == null ) continue;
                                int r = (txBounds.height - 5) / 2;
                                txBounds.translate(r+4, r+4);
-                               Transmitter draggingTx = txView.getDraggingTransmitter();
+                               //
+                               // Transmitterに現在接続されているReceiverを把握
                                Receiver rx = tx.getReceiver();
-                               if( draggingPoint != null && tx.equals(draggingTx) ) {
-                                       // Transmitterからドラッグされた線を描画
+                               if( draggingPoint != null && tx.equals(dragging.getData()) ) {
+                                       //
+                                       // Transmitterからドラッグされている線を描画
                                        g2.setColor(rx == null ? ADDING_CABLE_COLOR : colorOf(rx));
                                        g2.drawLine(txBounds.x, txBounds.y, draggingPoint.x, draggingPoint.y);
                                }
-                               // TransmitterからReceiverへの接続線を描画
-                               if( rx != null ) for( JInternalFrame toFrame : frames ) {
+                               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);
-                                       g2.setColor(draggingTx == tx ? REMOVING_CABLE_COLOR : colorOf(rx));
+                                       //
+                                       // Transmitter⇔Receiver間の線を描画
+                                       g2.setColor(tx.equals(dragging.getData()) ? REMOVING_CABLE_COLOR : colorOf(rx));
                                        g2.drawLine(txBounds.x, txBounds.y, rxBounds.x, rxBounds.y);
                                        break;
                                }
index 818326c..085ef24 100644 (file)
@@ -1,11 +1,8 @@
 package camidion.chordhelper.mididevice;
 
-import java.awt.datatransfer.DataFlavor;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 
-import javax.sound.midi.Receiver;
-import javax.sound.midi.Transmitter;
 import javax.swing.AbstractAction;
 import javax.swing.Action;
 import javax.swing.BoxLayout;
@@ -22,8 +19,6 @@ import camidion.chordhelper.ButtonIcon;
  * MIDIデバイスダイアログ (View)
  */
 public class MidiDeviceDialog extends JDialog {
-       public static final DataFlavor receiverFlavor = new DataFlavor(Receiver.class, "Receiver");
-       public static final DataFlavor transmitterFlavor = new DataFlavor(Transmitter.class, "Transmitter");
        public static final Icon MIDI_CONNECTER_ICON = new ButtonIcon(ButtonIcon.MIDI_CONNECTOR_ICON);
        /**
         * MIDIデバイスダイアログを開くアクション
index 4fde422..8399c9a 100644 (file)
@@ -78,7 +78,7 @@ public class MidiDeviceFrame extends JInternalFrame {
                }}, BorderLayout.SOUTH);
                add(scrollPane = new JScrollPane(trxPanel = new JPanel() {{
                        setLayout(new BorderLayout());
-                       MidiDeviceModel.ReceiverListModel rxListModel = getMidiDeviceModel().getReceiverList();
+                       MidiDeviceModel.ReceiverListModel rxListModel = getMidiDeviceModel().getReceiverListModel();
                        if( rxListModel != null ) {
                                receiverListView = new MidiReceiverListView(rxListModel, cablePane);
                                add(rxPanel = new JPanel() {{
@@ -87,7 +87,7 @@ public class MidiDeviceFrame extends JInternalFrame {
                                        add(receiverListView);
                                }}, BorderLayout.NORTH);
                        }
-                       MidiDeviceModel.TransmitterListModel txListModel = getMidiDeviceModel().getTransmitterList();
+                       MidiDeviceModel.TransmitterListModel txListModel = getMidiDeviceModel().getTransmitterListModel();
                        if( txListModel != null ) {
                                transmitterListView = new MidiTransmitterListView(txListModel, cablePane);
                                add(txPanel = new JPanel() {{
index 450ab33..c5a33f3 100644 (file)
@@ -60,10 +60,8 @@ public class MidiDeviceInfoPane extends JEditorPane implements TreeSelectionList
                        JInternalFrame frame = e.getInternalFrame();
                        if( ! (frame instanceof MidiDeviceFrame ) ) return;
                        MidiDeviceModel m = ((MidiDeviceFrame)frame).getMidiDeviceModel();
-                       m.closeReceiver();
-                       MidiDevice device = m.getMidiDevice();
-                       device.close();
-                       if( ! device.isOpen() ) {
+                       m.close();
+                       if( ! m.getMidiDevice().isOpen() ) {
                                try {
                                        // 選択されたまま閉じると、次に開いたときにinternalFrameActivatedが
                                        // 呼ばれなくなってしまうので、選択を解除する。
index ba07a58..4c257fc 100644 (file)
@@ -36,7 +36,7 @@ public class MidiDeviceModel {
        /**
         * 実体のない新規{@link Transmitter}を表すインターフェース
         */
-       public interface NewTransmitter extends Transmitter {};
+       interface NewTransmitter extends Transmitter {};
        /**
         * {@link Transmitter} のリストを表す {@link javax.swing.ListModel}
         */
@@ -64,42 +64,124 @@ public class MidiDeviceModel {
                 * 見つからなかった場合は -1 を返します。
                 *
                 * @param element 探したい要素
-                * @return 位置のインデックス
+                * @return 位置
                 */
                public int indexOf(Transmitter element) {
                        List<Transmitter> txList = device.getTransmitters();
                        return element.equals(newTransmitter) ? txList.size() : txList.indexOf(element);
                }
                /**
-                * レシーバに未接続の最初の{@link Transmitter}を開いて返します。
-                * ない場合は {@link MidiDevice#getTransmitter} で新たに取得して返します。
+                * レシーバに未接続の最初の{@link Transmitter}を返します。
+                * ない場合は{@link MidiDevice#getTransmitter}で新たに取得して返します。
                 *
-                * @return 新しく開かれた未接続の{@link Transmitter}
+                * @return 未接続の{@link Transmitter}
+                * @throws MidiUnavailableException リソースの制約のためにトランスミッタを使用できない場合にスローされる
                 */
-               public Transmitter openTransmitter() {
+               public Transmitter getUnconnectedTransmitter() throws MidiUnavailableException {
                        List<Transmitter> txList = device.getTransmitters();
                        for( Transmitter tx : txList ) if( tx.getReceiver() == null ) return tx;
                        Transmitter tx;
-                       try {
-                               tx = device.getTransmitter();
-                       } catch( MidiUnavailableException e ) {
-                               e.printStackTrace();
-                               return null;
-                       }
+                       tx = device.getTransmitter();
                        fireIntervalAdded(this, 0, getSize());
                        return tx;
                }
                /**
+                * 指定の位置にある接続可能な{@link Transmitter}を返します。
+                * 新規Transmitterの場合、{@link #getUnconnectedTransmitter()}からの値を返します。
+                * @param index 位置(0が先頭、最後が新規)
+                * @return
+                * @throws MidiUnavailableException リソースの制約のためにトランスミッタを使用できない場合にスローされる
+                */
+               public Transmitter getConnectableTransmitterAt(int index) throws MidiUnavailableException {
+                       Transmitter tx = getElementAt(index);
+                       if( tx instanceof NewTransmitter ) tx = getUnconnectedTransmitter();
+                       return tx;
+               }
+               /**
                 * このリストモデルで開いている指定の{@link Transmitter}があれば、
                 * それを閉じて表示を更新します。
                 * ない場合は無視されます。
-                * @param txToClose このリストモデルで開いている{@link Transmitter}
+                * @param tx このリストモデルで開いている{@link Transmitter}
                 */
-               public void closeTransmitter(Transmitter txToClose) {
-                       if( ! device.getTransmitters().contains(txToClose) ) return;
-                       txToClose.close();
+               public void close(Transmitter tx) {
+                       if( ! device.getTransmitters().contains(tx) ) return;
+                       tx.close();
                        fireIntervalRemoved(this, 0, getSize());
                }
+               /**
+                * このリストモデルの{@link #getUnconnectedTransmitter()}が返した{@link Transmitter}を、
+                * 相手のMIDIデバイスが持つ最初の{@link Receiver}に接続します。
+                *
+                * @param anotherDeviceModel 接続相手のMIDIデバイス
+                * @throws MidiUnavailableException リソースの制約のためにトランスミッタを使用できない場合にスローされる
+                */
+               public void connectToFirstReceiverOfDevice(MidiDeviceModel anotherDeviceModel) throws MidiUnavailableException {
+                       if( ! anotherDeviceModel.rxSupported() ) return;
+                       List<Receiver> rxList = anotherDeviceModel.device.getReceivers();
+                       if( rxList.isEmpty() ) return;
+                       txListModel.getUnconnectedTransmitter().setReceiver(rxList.get(0));
+               }
+               /**
+                * このリストモデルにある{@link Transmitter}のうち、
+                * 引数で指定された{@link Receiver}へデータを送信しているものを全て閉じます。
+                */
+               private void closePeerTransmitterOf(Receiver rx) {
+                       List<Transmitter> originalTxList = device.getTransmitters();
+                       List<Transmitter> closingTxList = new Vector<Transmitter>();
+                       for( Transmitter tx : originalTxList ) if( tx.getReceiver() == rx ) closingTxList.add(tx);
+                       if( closingTxList.isEmpty() ) return;
+                       int length = getSize();
+                       for( Transmitter tx : closingTxList ) tx.close();
+                       fireIntervalRemoved(this, 0, length);
+               }
+               /**
+                * マイクロ秒位置をリセットします。
+                * <p>マイクロ秒位置はMIDIデバイスを開いてからの時間で表されます。
+                * このメソッドではMIDIデバイスをいったん閉じて再び開くことによって
+                * 時間位置をリセットします。
+                * 接続相手のデバイスがあった場合、元通りに接続を復元します。
+                * </p>
+                * <p>MIDIデバイスからリアルタイムレコーディングを開始するときは、
+                * 必ずマイクロ秒位置をリセットする必要があります。
+                * (リセットされていないマイクロ秒位置がそのままシーケンサに記録されると、
+                * 大幅に後ろのほうにずれて記録されてしまいます)
+                * </p>
+                */
+               public void resetMicrosecondPosition() {
+                       //
+                       // シーケンサはこのメソッドでのリセット対象外
+                       if( device instanceof Sequencer ) return;
+                       //
+                       // デバイスを閉じる前に接続状態を把握
+                       List<Transmitter> myTxList = device.getTransmitters();
+                       List<Receiver> peerRxList = new Vector<Receiver>();
+                       for( Transmitter tx : myTxList ) {
+                               Receiver rx = tx.getReceiver();
+                               if( rx != null ) peerRxList.add(rx);
+                       }
+                       List<Receiver> myRxList = device.getReceivers();
+                       List<Transmitter> peerTxList = new Vector<Transmitter>();
+                       for( Receiver rx : myRxList ) {
+                               for( MidiDeviceModel m : deviceModelList ) {
+                                       if( m == MidiDeviceModel.this ) continue;
+                                       List<Transmitter> peerSourceTxList = m.getMidiDevice().getTransmitters();
+                                       for( Transmitter tx : peerSourceTxList ) if( tx.getReceiver() == rx ) peerTxList.add(tx);
+                               }
+                       }
+                       // いったん閉じて開く(ここでマイクロ秒位置がリセットされる)
+                       // その後、元通りに接続し直す
+                       device.close();
+                       try {
+                               device.open();
+                               for( Receiver peerRx : peerRxList ) getUnconnectedTransmitter().setReceiver(peerRx);
+                               if( ! myRxList.isEmpty() ) {
+                                       Receiver rx = myRxList.get(0);
+                                       for( Transmitter peerTx : peerTxList ) peerTx.setReceiver(rx);
+                               }
+                       } catch( MidiUnavailableException e ) {
+                               e.printStackTrace();
+                       }
+               }
        }
 
        /**
@@ -142,14 +224,14 @@ public class MidiDeviceModel {
         * {@link Transmitter} のリストモデルを返します。サポートしていない場合はnullを返します。
         * @return リストモデルまたはnull
         */
-       public TransmitterListModel getTransmitterList() { return transmitterList; }
-       private TransmitterListModel transmitterList;
+       public TransmitterListModel getTransmitterListModel() { return txListModel; }
+       private TransmitterListModel txListModel;
        /**
         * {@link Receiver} のリストモデルを返します。サポートしていない場合はnullを返します。
         * @return リストモデルまたはnull
         */
-       public ReceiverListModel getReceiverList() { return receiverList; }
-       private ReceiverListModel receiverList;
+       public ReceiverListModel getReceiverListModel() { return rxListModel; }
+       private ReceiverListModel rxListModel;
 
        protected MidiDeviceModelList deviceModelList;
        /**
@@ -162,11 +244,11 @@ public class MidiDeviceModel {
                this.device = device;
                this.deviceModelList = deviceModelList;
                if( txSupported() ) {
-                       transmitterList = new TransmitterListModel();
+                       txListModel = new TransmitterListModel();
                }
                if( rxSupported() ) {
                        ioType = txSupported() ? MidiDeviceInOutType.MIDI_IN_OUT :MidiDeviceInOutType.MIDI_OUT;
-                       receiverList = new ReceiverListModel();
+                       rxListModel = new ReceiverListModel();
                }
                else {
                        ioType = txSupported() ? MidiDeviceInOutType.MIDI_IN :MidiDeviceInOutType.MIDI_NONE;
@@ -174,90 +256,31 @@ public class MidiDeviceModel {
                treePath = new TreePath(new Object[] {deviceModelList, ioType ,this});
        }
        /**
-        * 未接続の{@link Transmitter}を、引数で指定されたリストモデルの最初の{@link Receiver}に接続します。
-        * @param anotherDeviceModel 接続可能な{@link Receiver}を持つリストモデル
-        */
-       public void connectToReceiverOf(MidiDeviceModel anotherDeviceModel) {
-               if( ! txSupported() || anotherDeviceModel == null || ! anotherDeviceModel.rxSupported() ) return;
-               List<Receiver> rxList = anotherDeviceModel.device.getReceivers();
-               if( rxList.isEmpty() ) return;
-               transmitterList.openTransmitter().setReceiver(rxList.get(0));
-       }
-       /**
-        * {@link Receiver}を1個だけ開きます。サポートしていない場合は無視されます。
-        *
-        * @throws MidiUnavailableException デバイスを開くことができない場合
-        */
-       public void openReceiver() throws MidiUnavailableException {
-               if( rxSupported() && device.getReceivers().isEmpty() ) device.getReceiver();
-       }
-       /**
-        * {@link MidiDevice}を閉じる前に、{@link Receiver}を閉じます。
+        * このMIDIデバイスモデルを開きます。
+        * MIDIデバイスを {@link MidiDevice#open()} で開き、
+        * レシーバをサポートしている場合は {@link MidiDevice#getReceiver()} でレシーバを1個開きます。
         *
-        * 閉じようとしている{@link Receiver}を他デバイスの{@link Transmitter}が使用していた場合は
-        * ã\81\9dã\81®{@link Transmitter}ã\82\82é\96\89ã\81\98ã\81¾ã\81\99
+        * @throws MidiUnavailableException リソースの制約のためにデバイス開けない
+        * ã\81¾ã\81\9fã\81¯ã\83¬ã\82·ã\83¼ã\83\90ã\82\92使ç\94¨ã\81§ã\81\8dã\81ªã\81\84å ´å\90\88ã\81«ã\82¹ã\83­ã\83¼ã\81\95ã\82\8cã\82\8b
         */
-       public void closeReceiver() {
-               List<Receiver> rxList = device.getReceivers();
-               for( Receiver rx : rxList ) {
-                       for( MidiDeviceModel m : deviceModelList ) {
-                               if( m == this || ! m.txSupported() ) continue;
-                               for( int i=0; i<m.transmitterList.getSize(); i++ ) {
-                                       Transmitter tx = m.transmitterList.getElementAt(i);
-                                       if( tx.getReceiver() == rx ) m.transmitterList.closeTransmitter(tx);
-                               }
-                       }
-                       rx.close();
-               }
+       public void open() throws MidiUnavailableException {
+               device.open();
+               if( rxListModel != null && device.getReceivers().isEmpty() ) device.getReceiver();
        }
        /**
-        * マイクロ秒位置をリセットします。
-        * <p>マイクロ秒位置はMIDIデバイスを開いてからの時間で表されます。
-        * このメソッドではMIDIデバイスをいったん閉じて再び開くことによって
-        * 時間位置をリセットします。
-        * 接続相手のデバイスがあった場合、元通りに接続を復元します。
-        * </p>
-        * <p>MIDIデバイスからリアルタイムレコーディングを開始するときは、
-        * 必ずマイクロ秒位置をリセットする必要があります。
-        * (リセットされていないマイクロ秒位置がそのままシーケンサに記録されると、
-        * 大幅に後ろのほうにずれて記録されてしまいます)
-        * </p>
+        * このMIDIデバイスを {@link MidiDevice#close()} で閉じます。
+        * このMIDIデバイスの{@link Receiver}に接続している他デバイスの{@link Transmitter}があれば、
+        * それらも全て閉じます。
         */
-       public void resetMicrosecondPosition() {
-               if( ! txSupported() || device instanceof Sequencer ) return;
-               //
-               // デバイスを閉じる前に接続相手の情報を保存
-               List<Transmitter> myTxList = device.getTransmitters();
-               List<Receiver> peerRxList = new Vector<Receiver>();
-               Receiver rx;
-               for( Transmitter tx : myTxList ) if( (rx = tx.getReceiver()) != null ) peerRxList.add(rx);
-               List<Transmitter> peerTxList = null;
-               if( rxSupported() ) {
-                       rx = device.getReceivers().get(0);
-                       peerTxList = new Vector<Transmitter>();
-                       for( MidiDeviceModel m : deviceModelList ) {
-                               if( m == this || ! m.txSupported() ) continue;
-                               for( int i=0; i<m.transmitterList.getSize(); i++ ) {
-                                       Transmitter tx = m.transmitterList.getElementAt(i);
-                                       if( tx.getReceiver() == rx ) peerTxList.add(tx);
+       public void close() {
+               if( rxListModel != null ) {
+                       List<Receiver> rxList = device.getReceivers();
+                       for( Receiver rx : rxList ) {
+                               for( MidiDeviceModel m : deviceModelList ) {
+                                       if( m != this && m.txListModel != null ) m.txListModel.closePeerTransmitterOf(rx);
                                }
                        }
                }
-               // いったん閉じて開く(ここでマイクロ秒位置がリセットされる)
                device.close();
-               try {
-                       device.open();
-               } catch( MidiUnavailableException e ) {
-                       e.printStackTrace();
-               }
-               // 元通りに接続し直す
-               for( Receiver peerRx : peerRxList ) {
-                       Transmitter tx = transmitterList.openTransmitter();
-                       if( tx != null ) tx.setReceiver(peerRx);
-               }
-               if( peerTxList != null ) {
-                       rx = device.getReceivers().get(0);
-                       for( Transmitter peerTx : peerTxList ) peerTx.setReceiver(rx);
-               }
        }
-}
\ No newline at end of file
+}
index 6de3c5f..22f21dd 100644 (file)
@@ -8,6 +8,7 @@ import javax.sound.midi.MidiSystem;
 import javax.sound.midi.MidiUnavailableException;
 import javax.sound.midi.Sequencer;
 import javax.sound.midi.Synthesizer;
+import javax.sound.midi.Transmitter;
 
 import camidion.chordhelper.ChordHelperApplet;
 
@@ -87,48 +88,46 @@ public class MidiDeviceModelList extends Vector<MidiDeviceModel> {
                                sequencerModel,
                                firstMidiInModel,
                        };
-                       for( MidiDeviceModel m : openModels ) if( m != null ) {
-                               m.getMidiDevice().open();
-                               m.openReceiver();
+                       for( MidiDeviceModel m : openModels ) if( m != null ) m.open();
+                       for( MidiDeviceModel m : guiModels ) m.open();
+                       //
+                       // 初期接続
+                       MidiDeviceModel.TransmitterListModel txListModel;
+                       for( MidiDeviceModel mtx : guiModels ) {
+                               if( (txListModel = mtx.getTransmitterListModel() ) != null) {
+                                       for( MidiDeviceModel m : guiModels ) txListModel.connectToFirstReceiverOfDevice(m);
+                                       txListModel.connectToFirstReceiverOfDevice(sequencerModel);
+                                       txListModel.connectToFirstReceiverOfDevice(synthModel);
+                                       txListModel.connectToFirstReceiverOfDevice(firstMidiOutModel);
+                               }
+                       }
+                       if( firstMidiInModel != null && (txListModel = firstMidiInModel.getTransmitterListModel()) != null) {
+                               for( MidiDeviceModel m : guiModels ) txListModel.connectToFirstReceiverOfDevice(m);
+                               txListModel.connectToFirstReceiverOfDevice(sequencerModel);
+                               txListModel.connectToFirstReceiverOfDevice(synthModel);
+                               txListModel.connectToFirstReceiverOfDevice(firstMidiOutModel);
                        }
-                       for( MidiDeviceModel m : guiModels ) {
-                               m.getMidiDevice().open();
-                               m.openReceiver();
+                       if( sequencerModel != null && (txListModel = sequencerModel.getTransmitterListModel()) != null) {
+                               for( MidiDeviceModel m : guiModels ) txListModel.connectToFirstReceiverOfDevice(m);
+                               txListModel.connectToFirstReceiverOfDevice(synthModel);
+                               txListModel.connectToFirstReceiverOfDevice(firstMidiOutModel);
                        }
                } catch( MidiUnavailableException ex ) {
                        ex.printStackTrace();
                }
-               // 初期接続
-               //
-               for( MidiDeviceModel mtx : guiModels ) {
-                       for( MidiDeviceModel mrx : guiModels ) mtx.connectToReceiverOf(mrx);
-                       mtx.connectToReceiverOf(sequencerModel);
-                       mtx.connectToReceiverOf(synthModel);
-                       mtx.connectToReceiverOf(firstMidiOutModel);
-               }
-               if( firstMidiInModel != null ) {
-                       for( MidiDeviceModel m : guiModels ) firstMidiInModel.connectToReceiverOf(m);
-                       firstMidiInModel.connectToReceiverOf(sequencerModel);
-                       firstMidiInModel.connectToReceiverOf(synthModel);
-                       firstMidiInModel.connectToReceiverOf(firstMidiOutModel);
-               }
-               if( sequencerModel != null ) {
-                       for( MidiDeviceModel m : guiModels ) sequencerModel.connectToReceiverOf(m);
-                       sequencerModel.connectToReceiverOf(synthModel);
-                       sequencerModel.connectToReceiverOf(firstMidiOutModel);
-               }
        }
        /**
-        * すべてのデバイスについて、{@link MidiDeviceModel#resetMicrosecondPosition()}
-        * でマイクロ秒位置をリセットします。
+        * {@link Transmitter}を持つすべてのデバイス(例:MIDIキーボードなど)について、
+        * {@link MidiDeviceModel#resetMicrosecondPosition()}でマイクロ秒位置をリセットします。
         */
        public void resetMicrosecondPosition() {
-               for(MidiDeviceModel m : this) m.resetMicrosecondPosition();
+               for(MidiDeviceModel m : this) {
+                       MidiDeviceModel.TransmitterListModel txListModel = m.getTransmitterListModel();
+                       if( txListModel != null ) txListModel.resetMicrosecondPosition();
+               }
        }
        /**
         * すべてのMIDIデバイスを閉じます。
         */
-       public void closeAllDevices() {
-               for(MidiDeviceModel m : this) m.device.close();
-       }
+       public void closeAllDevices() { for(MidiDeviceModel m : this) m.getMidiDevice().close(); }
 }
index d35a2db..deb6bbc 100644 (file)
@@ -92,8 +92,7 @@ public class MidiOpenedDevicesView extends JDesktopPane implements TreeSelection
                                }
                                MidiDeviceModel deviceModel = (MidiDeviceModel)source;
                                try {
-                                       deviceModel.getMidiDevice().open();
-                                       deviceModel.openReceiver();
+                                       deviceModel.open();
                                } catch( MidiUnavailableException e ) {
                                        //
                                        // デバイスを開くのに失敗した場合
@@ -159,11 +158,11 @@ public class MidiOpenedDevicesView extends JDesktopPane implements TreeSelection
                        //
                        // トランスミッタリストモデルが変化したときにMIDIケーブルを再描画
                        if( deviceModel.txSupported() ) {
-                               deviceModel.getTransmitterList().addListDataListener(cablePane.midiConnecterListDataListener);
+                               deviceModel.getTransmitterListModel().addListDataListener(cablePane.midiConnecterListDataListener);
                        }
                        // レシーバリストモデルが変化したときにMIDIケーブルを再描画
                        if( deviceModel.rxSupported() ) {
-                               deviceModel.getReceiverList().addListDataListener(cablePane.midiConnecterListDataListener);
+                               deviceModel.getReceiverListModel().addListDataListener(cablePane.midiConnecterListDataListener);
                        }
                        // デバイスフレームが開閉したときの動作
                        frame.addInternalFrameListener(cablePane.midiDeviceFrameListener);
index e75d2a8..8883372 100644 (file)
@@ -2,21 +2,16 @@ package camidion.chordhelper.mididevice;
 
 import java.awt.Component;
 import java.awt.Rectangle;
-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 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;
@@ -41,8 +36,6 @@ public class MidiReceiverListView extends JList<Receiver> {
                        setEnabled(list.isEnabled());
                        setFont(list.getFont());
                        setOpaque(true);
-                       setIcon(MidiDeviceDialog.MIDI_CONNECTER_ICON);
-                       setToolTipText("ドラッグ&ドロップしてTxに接続");
                        if (isSelected) {
                                setBackground(list.getSelectionBackground());
                                setForeground(list.getSelectionForeground());
@@ -50,62 +43,52 @@ public class MidiReceiverListView extends JList<Receiver> {
                                setBackground(list.getBackground());
                                setForeground(list.getForeground());
                        }
+                       setIcon(MidiDeviceDialog.MIDI_CONNECTER_ICON);
+                       setToolTipText("受信端子(Rx):ドラッグ&ドロップしてTxに接続できます。");
                        return this;
                }
        }
        /**
-        * ドラッグ対象レシーバを表すクラス
+        * 引数で指定された{@link Receiver}のセル範囲を示す、
+        * リストの座標系内の境界の矩形を返します。対応するセルがない場合はnullを返します。
+        * @return セル範囲を示す境界の矩形、またはnull
         */
-       private static class DraggingReceiver implements Transferable {
-               private static final List<DataFlavor> flavors = Arrays.asList(MidiDeviceDialog.receiverFlavor);
-               private Receiver rx;
-               @Override
-               public Object getTransferData(DataFlavor flavor) {
-                       return flavor.getRepresentationClass().isInstance(rx) ? rx : null;
-               }
-               @Override
-               public DataFlavor[] getTransferDataFlavors() { return (DataFlavor[]) flavors.toArray(); }
-               @Override
-               public boolean isDataFlavorSupported(DataFlavor flavor) { return flavors.contains(flavor); }
-       };
-       private static DraggingReceiver draggingReceiver = new DraggingReceiver();
-
+       public Rectangle getCellBounds(Receiver rx) {
+               int index = getModel().indexOf(rx);
+               return getCellBounds(index,index);
+       }
        /**
-        * 現在ドラッグされている{@link Receiver}を返します。
-        * ドラッグ中でなければnullを返します。
+        * このリストによって表示される{@link Receiver}のリストを保持するデータモデルを返します。
+        * @return 表示される{@link Receiver}のリストを提供するデータモデル
         */
-       public Receiver getDraggingReceiver() { return draggingReceiver.rx; }
-
-       private MidiCablePane cablePane;
+       @Override
+       public MidiDeviceModel.ReceiverListModel getModel() {
+               return (MidiDeviceModel.ReceiverListModel) super.getModel();
+       }
        /**
         * 仮想MIDI端子リストビューを生成します。
         * @param model このビューから参照されるデータモデル
         * @param cablePane MIDIケーブル描画面
         */
-       public MidiReceiverListView(MidiDeviceModel.ReceiverListModel model, MidiCablePane cablePane) {
+       public MidiReceiverListView(MidiDeviceModel.ReceiverListModel model, final MidiCablePane cablePane) {
                super(model);
-               this.cablePane = cablePane;
                setCellRenderer(new CellRenderer());
                setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
                setLayoutOrientation(JList.HORIZONTAL_WRAP);
                setVisibleRowCount(0);
                //
                // レシーバのドラッグを受け付ける
-               DragSource dragSource = new DragSource();
                DragGestureListener dgl = new DragGestureListener() {
                        @Override
                        public void dragGestureRecognized(DragGestureEvent event) {
                                if( (event.getDragAction() & DnDConstants.ACTION_COPY_OR_MOVE) == 0 ) return;
-                               draggingReceiver.rx = getModel().getElementAt(locationToIndex(event.getDragOrigin()));
-                               event.startDrag(DragSource.DefaultLinkDrop, draggingReceiver, new DragSourceAdapter() {
-                                       @Override
-                                       public void dragDropEnd(DragSourceDropEvent event) {
-                                               draggingReceiver.rx = null;
-                                               MidiReceiverListView.this.cablePane.dragDropEnd();
-                                       }
-                               });
+                               int draggingIndex = locationToIndex(event.getDragOrigin());
+                               MidiCablePane.dragging.setData(getModel().getElementAt(draggingIndex));
+                               event.startDrag(DragSource.DefaultLinkDrop,
+                                               MidiCablePane.dragging, cablePane.dragSourceListener);
                        }
                };
+               DragSource dragSource = new DragSource();
                dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, dgl);
                dragSource.addDragSourceMotionListener(cablePane);
                //
@@ -113,33 +96,31 @@ public class MidiReceiverListView extends JList<Receiver> {
                DropTargetListener dtl = new DropTargetAdapter() {
                        @Override
                        public void dragEnter(DropTargetDragEvent event) {
-                               if( event.isDataFlavorSupported(MidiDeviceDialog.transmitterFlavor) ) {
+                               if( event.isDataFlavorSupported(DraggingTransceiver.transmitterFlavor) ) {
                                        event.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
                                }
                        }
                        @Override
                        public void drop(DropTargetDropEvent event) {
                                event.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+                               int maskedBits = event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE;
+                               if( maskedBits == 0 ) {
+                                       event.dropComplete(false);
+                                       return;
+                               }
+                               Transferable t = event.getTransferable();
+                               if( ! t.isDataFlavorSupported(DraggingTransceiver.transmitterFlavor) ) {
+                                       event.dropComplete(false);
+                                       return;
+                               }
                                try {
-                                       int maskedBits = event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE;
-                                       if( maskedBits == 0 ) {
-                                               event.dropComplete(false);
-                                               return;
-                                       }
-                                       Transferable t = event.getTransferable();
-                                       if( ! t.isDataFlavorSupported(MidiDeviceDialog.transmitterFlavor) ) {
-                                               event.dropComplete(false);
-                                               return;
-                                       }
-                                       Object source = t.getTransferData(MidiDeviceDialog.transmitterFlavor);
-                                       if( ! (source instanceof Transmitter) ) {
-                                               event.dropComplete(false);
+                                       Object sourceTx = t.getTransferData(DraggingTransceiver.transmitterFlavor);
+                                       if( sourceTx != null ) {
+                                               int targetRxIndex = locationToIndex(event.getLocation());
+                                               ((Transmitter)sourceTx).setReceiver(getModel().getElementAt(targetRxIndex));
+                                               event.dropComplete(true);
                                                return;
                                        }
-                                       Receiver destRx = getModel().getElementAt(locationToIndex(event.getLocation()));
-                                       ((Transmitter)source).setReceiver(destRx);
-                                       event.dropComplete(true);
-                                       return;
                                }
                                catch (Exception ex) {
                                        ex.printStackTrace();
@@ -149,17 +130,4 @@ public class MidiReceiverListView extends JList<Receiver> {
                };
                new DropTarget( this, DnDConstants.ACTION_COPY_OR_MOVE, dtl, true );
        }
-       @Override
-       public MidiDeviceModel.ReceiverListModel getModel() {
-               return (MidiDeviceModel.ReceiverListModel) super.getModel();
-       }
-       /**
-        * 引数で指定された{@link Receiver}のセル範囲を示す、
-        * リストの座標系内の境界の矩形を返します。対応するセルがない場合はnullを返します。
-        * @return セル範囲を示す境界の矩形、またはnull
-        */
-       public Rectangle getCellBounds(Receiver rx) {
-               int index = getModel().indexOf(rx);
-               return getCellBounds(index,index);
-       }
 }
index 7423d2b..1c27951 100644 (file)
@@ -2,7 +2,6 @@ package camidion.chordhelper.mididevice;
 
 import java.awt.Component;
 import java.awt.Rectangle;
-import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.Transferable;
 import java.awt.dnd.DnDConstants;
 import java.awt.dnd.DragGestureEvent;
@@ -15,8 +14,6 @@ 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;
@@ -25,8 +22,6 @@ import javax.swing.JList;
 import javax.swing.ListCellRenderer;
 import javax.swing.ListSelectionModel;
 
-import camidion.chordhelper.mididevice.MidiDeviceModel.NewTransmitter;
-
 /**
  * MIDIトランスミッタ({@link Transmitter})のリストビューです。
  * トランスミッタをこのビューからドラッグし、
@@ -43,16 +38,6 @@ public class MidiTransmitterListView extends JList<Transmitter> {
                        setEnabled(list.isEnabled());
                        setFont(list.getFont());
                        setOpaque(true);
-                       setIcon(MidiDeviceDialog.MIDI_CONNECTER_ICON);
-                       if( value == null ) {
-                               setToolTipText(null);
-                       } else {
-                               if( value instanceof NewTransmitter ) {
-                                       setToolTipText("ドラッグ&ドロップしてRxに接続");
-                               } else {
-                                       setToolTipText("ドラッグ&ドロップして切断、またはRx切替");
-                               }
-                       }
                        if (isSelected) {
                                setBackground(list.getSelectionBackground());
                                setForeground(list.getSelectionForeground());
@@ -60,67 +45,66 @@ public class MidiTransmitterListView extends JList<Transmitter> {
                                setBackground(list.getBackground());
                                setForeground(list.getForeground());
                        }
+                       setIcon(MidiDeviceDialog.MIDI_CONNECTER_ICON);
+                       if( value instanceof MidiDeviceModel.NewTransmitter ) {
+                               setToolTipText("未接続の送信端子(Tx):ドラッグ&ドロップしてRxに接続できます。");
+                       } else {
+                               setToolTipText("接続済の送信端子(Tx):ドラッグ&ドロップして接続先Rxを変更、または切断できます。");
+                       }
                        return this;
                }
        }
        /**
-        * ドラッグ対象トランスミッタを表すクラス
+        * 引数で指定された{@link Transmitter}のセル範囲を示す、
+        * リストの座標系内の境界の矩形を返します。対応するセルがない場合はnullを返します。
+        * @return セル範囲を示す境界の矩形、またはnull
         */
-       private static class DraggingTransmitter implements Transferable {
-               private static final List<DataFlavor> flavors = Arrays.asList(MidiDeviceDialog.transmitterFlavor);
-               private Transmitter tx;
-               @Override
-               public Object getTransferData(DataFlavor flavor) {
-                       return flavor.getRepresentationClass().isInstance(tx) ? tx : null;
-               }
-               @Override
-               public DataFlavor[] getTransferDataFlavors() { return (DataFlavor[]) flavors.toArray(); }
-               @Override
-               public boolean isDataFlavorSupported(DataFlavor flavor) { return flavors.contains(flavor); }
-       };
-       private static DraggingTransmitter draggingTransmitter = new DraggingTransmitter();
-
+       public Rectangle getCellBounds(Transmitter tx) {
+               int index = getModel().indexOf(tx);
+               return getCellBounds(index,index);
+       }
        /**
-        * 現在ドラッグされている{@link Transmitter}を返します。
-        * ドラッグ中でなければnullを返します。
+        * このリストによって表示される{@link Transmitter}のリストを保持するデータモデルを返します。
+        * @return 表示される{@link Transmitter}のリストを提供するデータモデル
         */
-       public Transmitter getDraggingTransmitter() { return draggingTransmitter.tx; }
-
-       private MidiCablePane cablePane;
-
+       @Override
+       public MidiDeviceModel.TransmitterListModel getModel() {
+               return (MidiDeviceModel.TransmitterListModel) super.getModel();
+       }
        /**
         * 仮想MIDI端子リストビューを生成します。
         * @param model このビューから参照されるデータモデル
         * @param cablePane MIDIケーブル描画面
         */
-       public MidiTransmitterListView(MidiDeviceModel.TransmitterListModel model, MidiCablePane cablePane) {
+       public MidiTransmitterListView(MidiDeviceModel.TransmitterListModel model, final MidiCablePane cablePane) {
                super(model);
-               this.cablePane = cablePane;
                setCellRenderer(new CellRenderer());
                setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
                setLayoutOrientation(JList.HORIZONTAL_WRAP);
                setVisibleRowCount(0);
                //
                // トランスミッタのドラッグを受け付ける
-               DragSource dragSource = new DragSource();
                DragGestureListener dgl = new DragGestureListener() {
                        @Override
                        public void dragGestureRecognized(DragGestureEvent event) {
                                if( (event.getDragAction() & DnDConstants.ACTION_COPY_OR_MOVE) == 0 ) return;
-                               draggingTransmitter.tx = getModel().getElementAt(locationToIndex(event.getDragOrigin()));
-                               if( draggingTransmitter.tx instanceof NewTransmitter ) {
-                                       draggingTransmitter.tx = getModel().openTransmitter();
+                               int draggingIndex = locationToIndex(event.getDragOrigin());
+                               try {
+                                       MidiCablePane.dragging.setData(getModel().getConnectableTransmitterAt(draggingIndex));
+                               } catch (Exception exception) {
+                                       exception.printStackTrace();
+                                       return;
                                }
-                               event.startDrag(DragSource.DefaultLinkDrop, draggingTransmitter, new DragSourceAdapter() {
+                               event.startDrag(DragSource.DefaultLinkDrop, MidiCablePane.dragging, new DragSourceAdapter() {
                                        @Override
                                        public void dragDropEnd(DragSourceDropEvent event) {
-                                               if( ! event.getDropSuccess() ) getModel().closeTransmitter((Transmitter)draggingTransmitter.tx);
-                                               draggingTransmitter.tx = null;
-                                               MidiTransmitterListView.this.cablePane.dragDropEnd();
+                                               if( ! event.getDropSuccess() ) getModel().close((Transmitter)MidiCablePane.dragging.getData());
+                                               cablePane.dragSourceListener.dragDropEnd(event);
                                        }
                                });
                        }
                };
+               DragSource dragSource = new DragSource();
                dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, dgl);
                dragSource.addDragSourceMotionListener(cablePane);
                //
@@ -128,34 +112,31 @@ public class MidiTransmitterListView extends JList<Transmitter> {
                DropTargetListener dtl = new DropTargetAdapter() {
                        @Override
                        public void dragEnter(DropTargetDragEvent event) {
-                               if( event.isDataFlavorSupported(MidiDeviceDialog.receiverFlavor) ) {
+                               if( event.isDataFlavorSupported(DraggingTransceiver.receiverFlavor) ) {
                                        event.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
                                }
                        }
                        @Override
                        public void drop(DropTargetDropEvent event) {
                                event.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+                               int maskedBits = event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE;
+                               if( maskedBits == 0 ) {
+                                       event.dropComplete(false);
+                                       return;
+                               }
+                               Transferable t = event.getTransferable();
+                               if( ! t.isDataFlavorSupported(DraggingTransceiver.receiverFlavor) ) {
+                                       event.dropComplete(false);
+                                       return;
+                               }
                                try {
-                                       int maskedBits = event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE;
-                                       if( maskedBits == 0 ) {
-                                               event.dropComplete(false);
+                                       Object sourceRx = t.getTransferData(DraggingTransceiver.receiverFlavor);
+                                       if( sourceRx != null ) {
+                                               int targetTxIndex = locationToIndex(event.getLocation());
+                                               getModel().getConnectableTransmitterAt(targetTxIndex).setReceiver((Receiver)sourceRx);
+                                               event.dropComplete(true);
                                                return;
                                        }
-                                       Transferable t = event.getTransferable();
-                                       if( ! t.isDataFlavorSupported(MidiDeviceDialog.receiverFlavor) ) {
-                                               event.dropComplete(false);
-                                               return;
-                                       }
-                                       Object source = t.getTransferData(MidiDeviceDialog.receiverFlavor);
-                                       if( ! (source instanceof Receiver) ) {
-                                               event.dropComplete(false);
-                                               return;
-                                       }
-                                       Transmitter destTx = getModel().getElementAt(locationToIndex(event.getLocation()));
-                                       if( destTx instanceof NewTransmitter ) destTx = getModel().openTransmitter();
-                                       destTx.setReceiver((Receiver)source);
-                                       event.dropComplete(true);
-                                       return;
                                }
                                catch (Exception ex) {
                                        ex.printStackTrace();
@@ -165,17 +146,4 @@ public class MidiTransmitterListView extends JList<Transmitter> {
                };
                new DropTarget( this, DnDConstants.ACTION_COPY_OR_MOVE, dtl, true );
        }
-       @Override
-       public MidiDeviceModel.TransmitterListModel getModel() {
-               return (MidiDeviceModel.TransmitterListModel) super.getModel();
-       }
-       /**
-        * 引数で指定された{@link Transmitter}のセル範囲を示す、
-        * リストの座標系内の境界の矩形を返します。対応するセルがない場合はnullを返します。
-        * @return セル範囲を示す境界の矩形、またはnull
-        */
-       public Rectangle getCellBounds(Transmitter tx) {
-               int index = getModel().indexOf(tx);
-               return getCellBounds(index,index);
-       }
 }