*/
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/";
--- /dev/null
+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); }
+}
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;
* 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) {
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} が移動または変形したときにケーブルを再描画するためのリスナー
*/
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;
}
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;
* 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デバイスダイアログを開くアクション
}}, 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() {{
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() {{
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が
// 呼ばれなくなってしまうので、選択を解除する。
/**
* 実体のない新規{@link Transmitter}を表すインターフェース
*/
- public interface NewTransmitter extends Transmitter {};
+ interface NewTransmitter extends Transmitter {};
/**
* {@link Transmitter} のリストを表す {@link javax.swing.ListModel}
*/
* 見つからなかった場合は -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();
+ }
+ }
}
/**
* {@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;
/**
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;
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
+}
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Synthesizer;
+import javax.sound.midi.Transmitter;
import camidion.chordhelper.ChordHelperApplet;
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(); }
}
}
MidiDeviceModel deviceModel = (MidiDeviceModel)source;
try {
- deviceModel.getMidiDevice().open();
- deviceModel.openReceiver();
+ deviceModel.open();
} catch( MidiUnavailableException e ) {
//
// デバイスを開くのに失敗した場合
//
// トランスミッタリストモデルが変化したときに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);
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;
setEnabled(list.isEnabled());
setFont(list.getFont());
setOpaque(true);
- setIcon(MidiDeviceDialog.MIDI_CONNECTER_ICON);
- setToolTipText("ドラッグ&ドロップしてTxに接続");
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
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);
//
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();
};
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);
- }
}
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.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.ListCellRenderer;
import javax.swing.ListSelectionModel;
-import camidion.chordhelper.mididevice.MidiDeviceModel.NewTransmitter;
-
/**
* MIDIトランスミッタ({@link 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());
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);
//
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();
};
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);
- }
}