*/
public static class VersionInfo {
public static final String NAME = "MIDI Chord Helper";
- public static final String VERSION = "Ver.20160502.1";
+ public static final String VERSION = "Ver.20160504.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/";
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
+import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
+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;
import java.util.Hashtable;
import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
+import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
import javax.swing.event.ListDataEvent;
/**
* MIDI ケーブル描画面
*/
-public class MidiCablePane extends JComponent
- implements ListDataListener, ComponentListener, InternalFrameListener
-{
+public class MidiCablePane extends JComponent {
+ private Point draggingPoint;
+ /**
+ * {@link MidiConnecterListModel} の {@link Transmitter}
+ * をドラッグしている最中に再描画するためのリスナー
+ */
+ public final DragSourceMotionListener midiConnecterMotionListener = new DragSourceMotionListener() {
+ @Override
+ public void dragMouseMoved(DragSourceDragEvent dsde) {
+ Point origin = MidiCablePane.this.getLocationOnScreen();
+ draggingPoint = dsde.getLocation();
+ draggingPoint.translate(-origin.x, -origin.y);
+ repaint();
+ }
+ };
+ /**
+ * ドラッグ&ドロップの終了時にこのメソッドを呼び出します。
+ */
+ public void dragDropEnd() { draggingPoint = null; repaint(); }
+ /**
+ * {@link MidiDeviceFrame} の移動や変形を監視して再描画するためのリスナー
+ */
+ public final ComponentListener midiDeviceFrameComponentListener = new ComponentAdapter() {
+ @Override
+ public void componentMoved(ComponentEvent e) { repaint(); }
+ @Override
+ public void componentResized(ComponentEvent e) { repaint(); }
+ };
+ /**
+ * {@link MidiDeviceFrame} が閉じたタイミングで再描画するためのリスナー
+ */
+ public final InternalFrameListener midiDeviceFrameListener = new InternalFrameAdapter() {
+ @Override
+ public void internalFrameClosed(InternalFrameEvent e) { repaint(); }
+ @Override
+ public void internalFrameDeactivated(InternalFrameEvent e) { repaint(); }
+ @Override
+ public void internalFrameClosing(InternalFrameEvent e) {
+ JInternalFrame frame = e.getInternalFrame();
+ if( ! (frame instanceof MidiDeviceFrame) ) return;
+ MidiConnecterListModel devModel = ((MidiDeviceFrame)frame).listView.getModel();
+ if( ! devModel.rxSupported() ) return;
+ colorMap.remove(devModel.getMidiDevice().getReceivers().get(0));
+ repaint();
+ }
+ };
+ /**
+ * {@link MidiConnecterListModel} における {@link Transmitter}
+ * の増減や状態変更があった場合に再描画するためのリスナー
+ */
+ public final ListDataListener midiConnecterListDataListener = new ListDataListener() {
+ @Override
+ public void contentsChanged(ListDataEvent e) { repaint(); }
+ @Override
+ public void intervalAdded(ListDataEvent e) { repaint(); }
+ @Override
+ public void intervalRemoved(ListDataEvent e) { repaint(); }
+ };
+
private JDesktopPane desktopPane;
- //private JTree tree;
public MidiCablePane(JDesktopPane desktopPane) {
this.desktopPane = desktopPane;
setOpaque(false);
setVisible(true);
}
- //
- // MidiDeviceFrame の開閉を検出
- public void internalFrameActivated(InternalFrameEvent e) {}
- public void internalFrameClosed(InternalFrameEvent e) { repaint(); }
- public void internalFrameClosing(InternalFrameEvent e) {
- JInternalFrame frame = e.getInternalFrame();
- if( ! (frame instanceof MidiDeviceFrame) )
- return;
- MidiDeviceFrame devFrame = (MidiDeviceFrame)frame;
- MidiConnecterListModel devModel = devFrame.listView.getModel();
- if( ! devModel.rxSupported() )
- return;
- colorMap.remove(devModel.getMidiDevice().getReceivers().get(0));
- repaint();
- }
- public void internalFrameDeactivated(InternalFrameEvent e) { repaint(); }
- public void internalFrameDeiconified(InternalFrameEvent e) {}
- public void internalFrameIconified(InternalFrameEvent e) {}
- public void internalFrameOpened(InternalFrameEvent e) {}
- //
- // ウィンドウオペレーションの検出
- public void componentHidden(ComponentEvent e) {}
- public void componentMoved(ComponentEvent e) { repaint(); }
- public void componentResized(ComponentEvent e) { repaint(); }
- public void componentShown(ComponentEvent e) {}
- //
- // MidiConnecterListModel における Transmitter リストの更新を検出
- public void contentsChanged(ListDataEvent e) { repaint(); }
- public void intervalAdded(ListDataEvent e) { repaint(); }
- public void intervalRemoved(ListDataEvent e) { repaint(); }
- //
- // ケーブル描画用
+
private static final Stroke CABLE_STROKE = new BasicStroke(
- 3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND
- );
+ 3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
private static final Color[] CABLE_COLORS = {
new Color(255, 0, 0,144),
new Color(0, 255, 0,144),
super.paint(g);
Graphics2D g2 = (Graphics2D)g;
g2.setStroke(CABLE_STROKE);
- JInternalFrame[] frames =
- desktopPane.getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER);
+ JInternalFrame[] frames = desktopPane.getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER);
for( JInternalFrame frame : frames ) {
- if( ! (frame instanceof MidiDeviceFrame) )
- continue;
+ if( ! (frame instanceof MidiDeviceFrame) ) continue;
MidiDeviceFrame txDeviceFrame = (MidiDeviceFrame)frame;
- List<Transmitter> txList = txDeviceFrame.listView.getModel().getMidiDevice().getTransmitters();
+ MidiConnecterListView txView = txDeviceFrame.listView;
+ Transmitter draggingTx = txView.getDraggingTransmitter();
+ List<Transmitter> txList = txView.getModel().getMidiDevice().getTransmitters();
for( Transmitter tx : txList ) {
//
- // 送信端子から接続されている受信端子の存在を確認
- Receiver rx = tx.getReceiver();
- if( rx == null )
- continue;
+ // 送信端子の場所を特定
+ Rectangle txRect = txView.getCellBounds(tx);
+ if( txRect == null ) continue;
+ txRect.translate(
+ txDeviceFrame.getRootPane().getX() +
+ txDeviceFrame.getContentPane().getX() + txDeviceFrame.getX(),
+ txDeviceFrame.getRootPane().getY() +
+ txDeviceFrame.getContentPane().getY() + txDeviceFrame.getY()
+ );
+ int d = txRect.height - 5;
+ int r = d / 2;
+ int fromX = txRect.x + r + 4;
+ int fromY = txRect.y + r + 4;
//
- // 送信端子の矩形を特定
- Rectangle txRect = txDeviceFrame.getListCellBounds(tx);
- if( txRect == null )
+ // ドラッグ中であれば、マウスカーソルのある所まで線を引く
+ if( tx.equals(draggingTx) && draggingPoint != null ) {
+ g2.setColor(Color.BLACK);
+ g2.drawLine(fromX, fromY, draggingPoint.x, draggingPoint.y);
continue;
- //
- // 受信端子のあるMIDIデバイスを探す
+ }
+ // 受信端子の場所を特定
+ Receiver rx = tx.getReceiver();
+ if( rx == null ) continue;
Rectangle rxRect = null;
for( JInternalFrame anotherFrame : frames ) {
- if( ! (anotherFrame instanceof MidiDeviceFrame) )
- continue;
- //
- // 受信端子の矩形を探す
+ if( ! (anotherFrame instanceof MidiDeviceFrame) ) continue;
MidiDeviceFrame rxDeviceFrame = (MidiDeviceFrame)anotherFrame;
- if((rxRect = rxDeviceFrame.getListCellBounds(rx)) == null)
- continue;
- rxRect.translate(rxDeviceFrame.getX(), rxDeviceFrame.getY());
+ if( (rxRect = rxDeviceFrame.listView.getCellBounds(rx)) == null ) continue;
+ rxRect.translate(
+ rxDeviceFrame.getRootPane().getX() +
+ rxDeviceFrame.getContentPane().getX() + rxDeviceFrame.getX(),
+ rxDeviceFrame.getRootPane().getY() +
+ rxDeviceFrame.getContentPane().getY() + rxDeviceFrame.getY()
+ );
break;
}
- if( rxRect == null )
- continue;
- txRect.translate(txDeviceFrame.getX(), txDeviceFrame.getY());
+ if( rxRect == null ) continue;
//
- // 色を探す
+ // 受信端子まで線を引く
Color color = colorMap.get(rx);
if( color == null ) {
colorMap.put(rx, color=CABLE_COLORS[nextColorIndex++]);
- if( nextColorIndex >= CABLE_COLORS.length )
- nextColorIndex = 0;
+ if( nextColorIndex >= CABLE_COLORS.length ) nextColorIndex = 0;
}
g2.setColor(color);
- //
- // Tx 始点
- int fromX = txRect.x;
- int fromY = txRect.y + 2;
- int d = txRect.height - 5;
- g2.fillOval(fromX, fromY, d, d);
- //
- // Tx → Rx 線
- int r = d / 2;
- fromX += r;
- fromY += r;
d = rxRect.height - 5;
r = d / 2;
- int toX = rxRect.x + r;
- int toY = rxRect.y + r + 2;
+ int toX = rxRect.x + r + 4;
+ int toY = rxRect.y + r + 4;
g2.drawLine(fromX, fromY, toX, toY);
}
}
}
-}
\ No newline at end of file
+}
public void close() { }
};
/**
- * 指定のMIDIデバイスに属する
- * {@link Transmitter}/{@link Receiver} のリストモデルを構築します。
+ * 指定のMIDIデバイスに属する {@link Transmitter}/{@link Receiver} のリストモデルを構築します。
*
* @param device 対象MIDIデバイス
- * @param modelList ã\83ªã\82¹ã\83\88ã\83¢ã\83\87ã\83«ã\81®リスト
+ * @param modelList ã\83ªã\82¹ã\83\88ã\83¢ã\83\87ã\83«ã\82\92æ ¼ç´\8dã\81\97ã\81¦ã\81\84ã\82\8b親リスト
*/
public MidiConnecterListModel(MidiDevice device, List<MidiConnecterListModel> modelList) {
this.device = device;
package camidion.chordhelper.mididevice;
import java.awt.Component;
+import java.awt.Point;
+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.DragSourceDragEvent;
+import java.awt.dnd.DragSourceAdapter;
import java.awt.dnd.DragSourceDropEvent;
-import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
+import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
-import java.awt.dnd.DropTargetEvent;
-import java.awt.dnd.DropTargetListener;
import javax.sound.midi.Receiver;
import javax.sound.midi.Transmitter;
* 仮想MIDI端子リストです。
* </p>
*/
-public class MidiConnecterListView extends JList<AutoCloseable>
- implements DragGestureListener, DragSourceListener, Transferable, DropTargetListener
-{
- public static final Icon MIDI_CONNECTER_ICON =
- new ButtonIcon(ButtonIcon.MIDI_CONNECTOR_ICON);
- private class CellRenderer extends JLabel implements ListCellRenderer<AutoCloseable> {
+public class MidiConnecterListView extends JList<AutoCloseable> {
+ public static final Icon MIDI_CONNECTER_ICON = new ButtonIcon(ButtonIcon.MIDI_CONNECTOR_ICON);
+ /**
+ * リストに登録されている仮想MIDI端子の描画ツール
+ */
+ private static class CellRenderer extends JLabel implements ListCellRenderer<AutoCloseable> {
public Component getListCellRendererComponent(
- JList<? extends AutoCloseable> list,
- AutoCloseable value,
- int index,
- boolean isSelected,
- boolean cellHasFocus
- ) {
+ JList<? extends AutoCloseable> list, AutoCloseable value, int index,
+ boolean isSelected, boolean cellHasFocus)
+ {
String text;
- if( value instanceof Receiver ) text = "Rx";
+ if( value == null ) text = null;
+ else if( value instanceof Receiver ) text = "Rx";
else if( value instanceof Transmitter ) text = "Tx";
- else if( value == null ) text = null;
else text = value.toString();
setText(text);
setIcon(MIDI_CONNECTER_ICON);
return this;
}
}
+
+ private static final DataFlavor transmitterFlavor = new DataFlavor(Transmitter.class, "Transmitter");
+ /**
+ * ドラッグ対象を表すクラス
+ */
+ private static class DraggingObject implements Transferable {
+ private static final DataFlavor flavors[] = {transmitterFlavor};
+ private Transmitter tx;
+ @Override
+ public Object getTransferData(DataFlavor flavor) { return tx; }
+ @Override
+ public DataFlavor[] getTransferDataFlavors() { return flavors; }
+ @Override
+ public boolean isDataFlavorSupported(DataFlavor flavor) {
+ return flavor.equals(transmitterFlavor);
+ }
+ };
+ private static DraggingObject draggingObject = new DraggingObject();
+
+ /**
+ * 現在ドラッグされているトランスミッタを返します。
+ * @return 現在ドラッグされているトランスミッタ(ドラッグ中でなければnull)
+ */
+ public Transmitter getDraggingTransmitter() { return draggingObject.tx; }
+
+ private MidiCablePane cablePane;
+ private DragSourceListener dragSourceListener = new DragSourceAdapter() {
+ @Override
+ public void dragDropEnd(DragSourceDropEvent dsde) {
+ if( ! dsde.getDropSuccess() ) getModel().closeTransmitter(getDraggingTransmitter());
+ draggingObject.tx = null;
+ cablePane.dragDropEnd();
+ }
+ };
+
/**
* 仮想MIDI端子リストビューを生成します。
* @param model このビューから参照されるデータモデル
+ * @param cablePane MIDIケーブル描画面
*/
- public MidiConnecterListView(MidiConnecterListModel model) {
+ public MidiConnecterListView(MidiConnecterListModel model, MidiCablePane cablePane) {
super(model);
+ this.cablePane = cablePane;
setCellRenderer(new CellRenderer());
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
setLayoutOrientation(JList.HORIZONTAL_WRAP);
setVisibleRowCount(0);
- (new DragSource()).createDefaultDragGestureRecognizer(
- this, DnDConstants.ACTION_COPY_OR_MOVE, this
- );
- new DropTarget( this, DnDConstants.ACTION_COPY_OR_MOVE, this, true );
- }
-
- @Override
- public void dragGestureRecognized(DragGestureEvent dge) {
- if( (dge.getDragAction() & DnDConstants.ACTION_COPY_OR_MOVE) == 0 ) return;
- AutoCloseable e = getModel().getElementAt(locationToIndex(dge.getDragOrigin()));
- if( e instanceof Transmitter ) {
- if( e instanceof MidiConnecterListModel.NewTransmitter ) {
- transferringTx = getModel().getTransmitter();
+ DragSource dragSource = new DragSource();
+ 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 dragStartPoint = dge.getDragOrigin();
+ AutoCloseable transceiver = getModel().getElementAt(locationToIndex(dragStartPoint));
+ if( transceiver instanceof Transmitter ) {
+ if( transceiver instanceof MidiConnecterListModel.NewTransmitter ) {
+ draggingObject.tx = getModel().getTransmitter();
+ }
+ else {
+ draggingObject.tx = (Transmitter)transceiver;
+ }
+ dge.startDrag(DragSource.DefaultLinkDrop, draggingObject, dragSourceListener);
+ }
+ }
}
- else {
- transferringTx = (Transmitter)e;
+ );
+ dragSource.addDragSourceMotionListener(cablePane.midiConnecterMotionListener);
+ DropTargetAdapter dta= new DropTargetAdapter() {
+ @Override
+ public void dragEnter(DropTargetDragEvent event) {
+ if( event.isDataFlavorSupported(transmitterFlavor) )
+ event.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
}
- dge.startDrag(DragSource.DefaultLinkDrop, this, this);
- }
- }
-
- @Override
- public void dragEnter(DragSourceDragEvent dsde) {}
- @Override
- public void dragOver(DragSourceDragEvent dsde) {}
- @Override
- public void dropActionChanged(DragSourceDragEvent dsde) {}
- @Override
- public void dragExit(DragSourceEvent dse) {}
- @Override
- public void dragDropEnd(DragSourceDropEvent dsde) {
- if( ! dsde.getDropSuccess() ) getModel().closeTransmitter(transferringTx);
- transferringTx = null;
- }
-
- private Transmitter transferringTx = null;
- private static final DataFlavor transmitterFlavor =
- new DataFlavor(Transmitter.class, "Transmitter");
- private static final DataFlavor transmitterFlavors[] = {transmitterFlavor};
- @Override
- public Object getTransferData(DataFlavor flavor) { return transferringTx; }
- @Override
- public DataFlavor[] getTransferDataFlavors() { return transmitterFlavors; }
- @Override
- public boolean isDataFlavorSupported(DataFlavor flavor) {
- return flavor.equals(transmitterFlavor);
- }
-
- @Override
- public void dragEnter(DropTargetDragEvent event) {
- if( event.isDataFlavorSupported(transmitterFlavor) )
- event.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
- }
- @Override
- public void dragExit(DropTargetEvent dte) {}
- @Override
- public void dragOver(DropTargetDragEvent dtde) {}
- @Override
- public void dropActionChanged(DropTargetDragEvent dtde) {}
- @Override
- public void drop(DropTargetDropEvent event) {
- event.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
- try {
- int maskedBits = event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE;
- if( maskedBits == 0 || ! getModel().rxSupported() ) {
- event.dropComplete(false);
- return;
+ @Override
+ public void drop(DropTargetDropEvent event) {
+ event.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+ try {
+ int maskedBits = event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE;
+ if( maskedBits == 0 || ! getModel().rxSupported() ) {
+ event.dropComplete(false);
+ return;
+ }
+ int index = locationToIndex(event.getLocation());
+ AutoCloseable destination = getModel().getElementAt(index);
+ if( ! (destination instanceof Receiver) ) {
+ event.dropComplete(false);
+ return;
+ }
+ Transferable draggedObject = event.getTransferable();
+ Transmitter sourceTx = (Transmitter)draggedObject.getTransferData(transmitterFlavor);
+ if( getModel().ConnectToReceiver(sourceTx, (Receiver)destination) == null ) {
+ event.dropComplete(false);
+ return;
+ }
+ event.dropComplete(true);
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ event.dropComplete(false);
+ }
}
- AutoCloseable destination = getModel().getElementAt(locationToIndex(event.getLocation()));
- if( ! (destination instanceof Receiver) ) {
- event.dropComplete(false);
- return;
- }
- Transmitter sourceTx = (Transmitter)event.getTransferable().getTransferData(transmitterFlavor);
- if( getModel().ConnectToReceiver(sourceTx, (Receiver)destination) == null ) {
- event.dropComplete(false);
- return;
- }
- event.dropComplete(true);
- }
- catch (Exception ex) {
- ex.printStackTrace();
- event.dropComplete(false);
- }
+ };
+ new DropTarget( this, DnDConstants.ACTION_COPY_OR_MOVE, dta, true );
}
@Override
- public MidiConnecterListModel getModel() {
- return (MidiConnecterListModel)super.getModel();
- }
+ public MidiConnecterListModel getModel() { return (MidiConnecterListModel)super.getModel(); }
/**
- * 選択項目がトランスミッタの実体であれば、それを閉じます。
+ * 指定されたMIDI端子(Transmitter または Receiver)が仮想MIDI端子リスト上にあれば、
+ * そのセル範囲の矩形を返します。
+ *
+ * @param transceiver MIDI端子
+ * @return セル範囲の矩形(ない場合はnull)
*/
- public void closeSelectedTransmitter() {
- AutoCloseable ac = getSelectedValue();
- if( ac instanceof Transmitter )
- getModel().closeTransmitter((Transmitter)ac);
+ public Rectangle getCellBounds(AutoCloseable transceiver) {
+ int index = getModel().indexOf(transceiver);
+ Rectangle rect = getCellBounds(index,index);
+ return rect == null ? null : rect;
}
-}
\ No newline at end of file
+}
+++ /dev/null
-package camidion.chordhelper.mididevice;
-
-import java.awt.Point;
-import java.awt.datatransfer.Transferable;
-import java.awt.dnd.DnDConstants;
-import java.awt.dnd.DropTarget;
-import java.awt.dnd.DropTargetDragEvent;
-import java.awt.dnd.DropTargetDropEvent;
-import java.awt.dnd.DropTargetEvent;
-import java.awt.dnd.DropTargetListener;
-import java.awt.event.ComponentAdapter;
-import java.awt.event.ComponentEvent;
-
-import javax.sound.midi.MidiUnavailableException;
-import javax.swing.JDesktopPane;
-import javax.swing.JInternalFrame;
-import javax.swing.JLayeredPane;
-import javax.swing.JOptionPane;
-import javax.swing.Timer;
-
-/**
- * 開いている MIDI デバイスを置くためのデスクトップビュー
- */
-public class MidiDesktopPane extends JDesktopPane implements DropTargetListener {
- private MidiCablePane cablePane = new MidiCablePane(this);
- public MidiDesktopPane(MidiDeviceTree deviceTree) {
- add(cablePane, JLayeredPane.PALETTE_LAYER);
- int i=0;
- MidiDeviceTreeModel treeModel = (MidiDeviceTreeModel)deviceTree.getModel();
- for( MidiConnecterListModel deviceModel : treeModel.deviceModelList ) {
- MidiDeviceFrame frame = new MidiDeviceFrame(deviceModel) {
- {
- addInternalFrameListener(cablePane);
- addComponentListener(cablePane);
- }
- };
- frame.addInternalFrameListener(deviceTree);
- deviceModel.addListDataListener(cablePane);
- add(frame);
- if( deviceModel.getMidiDevice().isOpen() ) {
- frame.setBounds( 10+(i%2)*260, 10+i*55, 250, 100 );
- frame.setVisible(true);
- i++;
- }
- }
- addComponentListener(new ComponentAdapter() {
- @Override
- public void componentResized(ComponentEvent e) {
- cablePane.setSize(getSize());
- }
- });
- new DropTarget( this, DnDConstants.ACTION_COPY_OR_MOVE, this, true );
- }
- @Override
- public void dragEnter(DropTargetDragEvent dtde) {
- Transferable trans = dtde.getTransferable();
- if( trans.isDataFlavorSupported(MidiDeviceTree.TREE_MODEL_FLAVOR) ) {
- dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
- }
- }
- @Override
- public void dragExit(DropTargetEvent dte) {}
- @Override
- public void dragOver(DropTargetDragEvent dtde) {}
- @Override
- public void dropActionChanged(DropTargetDragEvent dtde) {}
- @Override
- public void drop(DropTargetDropEvent dtde) {
- dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
- try {
- int action = dtde.getDropAction() ;
- if( (action & DnDConstants.ACTION_COPY_OR_MOVE) != 0 ) {
- Transferable trans = dtde.getTransferable();
- Object data = trans.getTransferData(MidiDeviceTree.TREE_MODEL_FLAVOR);
- if( data instanceof MidiConnecterListModel ) {
- MidiConnecterListModel deviceModel = (MidiConnecterListModel)data;
- try {
- deviceModel.openDevice();
- } catch( MidiUnavailableException e ) {
- //
- // デバイスを開くのに失敗した場合
- //
- // 例えば、「Microsort MIDI マッパー」と
- // 「Microsoft GS Wavetable SW Synth」を
- // 同時に開こうとするとここに来る。
- //
- dtde.dropComplete(false);
- String message = "MIDIデバイス "
- + deviceModel
- +" を開けません。\n"
- + "すでに開かれているデバイスが"
- + "このデバイスを連動して開いていないか確認してください。\n\n"
- + e.getMessage();
- JOptionPane.showMessageDialog(
- null, message,
- "Cannot open MIDI device",
- JOptionPane.ERROR_MESSAGE
- );
- return;
- }
- if( deviceModel.getMidiDevice().isOpen() ) {
- dtde.dropComplete(true);
- //
- // デバイスが正常に開かれたことを確認できたら
- // ドロップした場所へフレームを配置して可視化する。
- //
- JInternalFrame frame = getFrameOf(deviceModel);
- if( frame != null ) {
- Point loc = dtde.getLocation();
- loc.translate( -frame.getWidth()/2, 0 );
- frame.setLocation(loc);
- frame.setVisible(true);
- }
- return;
- }
- }
- }
- }
- catch (Exception ex) {
- ex.printStackTrace();
- }
- dtde.dropComplete(false);
- }
- /**
- * 指定されたMIDIデバイスモデルに対するMIDIデバイスフレームを返します。
- *
- * @param deviceModel MIDIデバイスモデル
- * @return 対応するMIDIデバイスフレーム(ない場合 null)
- */
- public MidiDeviceFrame getFrameOf(MidiConnecterListModel deviceModel) {
- JInternalFrame[] frames = getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER);
- for( JInternalFrame frame : frames ) {
- if( ! (frame instanceof MidiDeviceFrame) )
- continue;
- MidiDeviceFrame deviceFrame = (MidiDeviceFrame)frame;
- if( deviceFrame.listView.getModel() == deviceModel )
- return deviceFrame;
- }
- return null;
- }
- private boolean isTimerStarted;
- /**
- * タイムスタンプを更新するタイマーを開始または停止します。
- * @param toStart trueで開始、falseで停止
- */
- public void setAllDeviceTimestampTimers(boolean toStart) {
- if( isTimerStarted == toStart ) return;
- isTimerStarted = toStart;
- JInternalFrame[] frames = getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER);
- for( JInternalFrame frame : frames ) {
- if( ! (frame instanceof MidiDeviceFrame) )
- continue;
- MidiDeviceFrame deviceFrame = (MidiDeviceFrame)frame;
- Timer timer = deviceFrame.timer;
- if( toStart ) timer.start(); else timer.stop();
- }
- }
-}
\ No newline at end of file
/**
* MIDIデバイスダイアログ (View)
*/
-public class MidiDeviceDialog extends JDialog
- implements ActionListener, TreeSelectionListener
+public class MidiDeviceDialog extends JDialog implements ActionListener
{
+ private MidiDeviceTreeView deviceTree;
private JEditorPane deviceInfoPane;
- private MidiDesktopPane desktopPane;
- private MidiDeviceTree deviceTree;
+ private MidiOpenedDevicesView desktopPane;
+ @Override
+ public void actionPerformed(ActionEvent event) { setVisible(true); }
+
public MidiDeviceDialog(List<MidiConnecterListModel> deviceModelList) {
setTitle("MIDI device connection");
setBounds( 300, 300, 800, 500 );
- deviceTree = new MidiDeviceTree(new MidiDeviceTreeModel(deviceModelList));
- deviceTree.addTreeSelectionListener(this);
- deviceInfoPane = new JEditorPane("text/html","<html></html>") {
- {
- setEditable(false);
- }
- };
- desktopPane = new MidiDesktopPane(deviceTree);
+ deviceTree = new MidiDeviceTreeView(new MidiDeviceTreeModel(deviceModelList)) {{
+ addTreeSelectionListener(new TreeSelectionListener() {
+ @Override
+ public void valueChanged(TreeSelectionEvent e) {
+ Object lastSelected = deviceTree.getLastSelectedPathComponent();
+ String html = "<html><head></head><body>";
+ if( lastSelected instanceof MidiConnecterListModel ) {
+ MidiConnecterListModel deviceModel = (MidiConnecterListModel)lastSelected;
+ MidiDevice.Info info = deviceModel.getMidiDevice().getDeviceInfo();
+ html += "<b>"+deviceModel+"</b><br/>"
+ + "<table border=\"1\"><tbody>"
+ + "<tr><th>Version</th><td>"+info.getVersion()+"</td></tr>"
+ + "<tr><th>Description</th><td>"+info.getDescription()+"</td></tr>"
+ + "<tr><th>Vendor</th><td>"+info.getVendor()+"</td></tr>"
+ + "</tbody></table>";
+ MidiDeviceFrame deviceFrame = desktopPane.getMidiDeviceFrameOf(deviceModel);
+ if( deviceFrame != null ) {
+ try {
+ deviceFrame.setSelected(true);
+ } catch( PropertyVetoException ex ) {
+ ex.printStackTrace();
+ }
+ }
+ }
+ else if( lastSelected instanceof MidiDeviceInOutType ) {
+ MidiDeviceInOutType ioType = (MidiDeviceInOutType)lastSelected;
+ html += "<b>"+ioType+"</b><br/>";
+ html += ioType.getDescription()+"<br/>";
+ }
+ else if( lastSelected != null ) {
+ html += lastSelected.toString();
+ }
+ html += "</body></html>";
+ deviceInfoPane.setText(html);
+ }
+ });
+ }};
+ deviceInfoPane = new JEditorPane("text/html","<html></html>") {{ setEditable(false); }};
+ desktopPane = new MidiOpenedDevicesView(deviceTree);
add(new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT,
new JSplitPane(
setDividerLocation(250);
}});
addWindowListener(new WindowAdapter() {
+ private void setTimer(boolean flag) { desktopPane.setAllDeviceTimestampTimers(flag); }
@Override
- public void windowClosing(WindowEvent e) {
- desktopPane.setAllDeviceTimestampTimers(false);
- }
+ public void windowClosing(WindowEvent e) { setTimer(false); }
@Override
- public void windowActivated(WindowEvent e) {
- desktopPane.setAllDeviceTimestampTimers(true);
- }
+ public void windowActivated(WindowEvent e) { setTimer(true); }
});
}
- @Override
- public void actionPerformed(ActionEvent event) {
- setVisible(true);
- }
- @Override
- public void valueChanged(TreeSelectionEvent e) {
- Object lastSelected = deviceTree.getLastSelectedPathComponent();
- String html = "<html><head></head><body>";
- if( lastSelected instanceof MidiConnecterListModel ) {
- MidiConnecterListModel deviceModel = (MidiConnecterListModel)lastSelected;
- MidiDevice.Info info = deviceModel.getMidiDevice().getDeviceInfo();
- html += "<b>"+deviceModel+"</b><br/>"
- + "<table border=\"1\"><tbody>"
- + "<tr><th>Version</th><td>"+info.getVersion()+"</td></tr>"
- + "<tr><th>Description</th><td>"+info.getDescription()+"</td></tr>"
- + "<tr><th>Vendor</th><td>"+info.getVendor()+"</td></tr>"
- + "</tbody></table>";
- MidiDeviceFrame frame = desktopPane.getFrameOf(deviceModel);
- if( frame != null ) {
- try {
- frame.setSelected(true);
- } catch( PropertyVetoException ex ) {
- ex.printStackTrace();
- }
- }
- }
- else if( lastSelected instanceof MidiDeviceInOutType ) {
- MidiDeviceInOutType ioType = (MidiDeviceInOutType)lastSelected;
- html += "<b>"+ioType+"</b><br/>";
- html += ioType.getDescription()+"<br/>";
- }
- else if( lastSelected != null ) {
- html += lastSelected.toString();
- }
- html += "</body></html>";
- deviceInfoPane.setText(html);
- }
}
package camidion.chordhelper.mididevice;
-import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* MIDIデバイスのモデルからフレームビューを構築します。
* @param model MIDIデバイスのTransmitter/Receiverリストモデル
+ * @param cablePane MIDIケーブル描画面
*/
- public MidiDeviceFrame(MidiConnecterListModel model) {
+ public MidiDeviceFrame(MidiConnecterListModel model, MidiCablePane cablePane) {
super( null, true, true, false, false );
//
// タイトルの設定
title = (model.rxSupported()?"[OUT] ":"[No I/O] ")+title;
}
setTitle(title);
- listView = new MidiConnecterListView(model);
+ listView = new MidiConnecterListView(model, cablePane);
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addInternalFrameListener(
new InternalFrameAdapter() {
public void internalFrameOpened(InternalFrameEvent e) {
- if( ! listView.getModel().getMidiDevice().isOpen() )
- setVisible(false);
+ boolean isOpen = listView.getModel().getMidiDevice().isOpen();
+ if( ! isOpen ) setVisible(isOpen);
}
public void internalFrameClosing(InternalFrameEvent e) {
MidiConnecterListModel m = listView.getModel();
m.closeDevice();
- if( ! m.getMidiDevice().isOpen() )
- setVisible(false);
+ boolean isOpen = m.getMidiDevice().isOpen();
+ if( isVisible() != isOpen ) setVisible(isOpen);
}
}
);
}});
}});
}
- /**
- * 指定されたインデックスが示す仮想MIDI端子リストの要素のセル範囲を返します。
- *
- * @param index リスト要素のインデックス
- * @return セル範囲の矩形
- */
- public Rectangle getListCellBounds(int index) {
- Rectangle rect = listView.getCellBounds(index,index);
- if( rect == null )
- return null;
- rect.translate(
- getRootPane().getX() + getContentPane().getX(),
- getRootPane().getY() + getContentPane().getY()
- );
- return rect;
- }
- /**
- * 仮想MIDI端子リストの指定された要素のセル範囲を返します。
- *
- * @param transciver 要素となるMIDI端子(Transmitter または Receiver)
- * @return セル範囲の矩形
- */
- public Rectangle getListCellBounds(AutoCloseable transciver) {
- return getListCellBounds(listView.getModel().indexOf(transciver));
- }
-}
\ No newline at end of file
+}
private MidiConnecterListModel firstMidiOutModel;
/**
* MIDIデバイスモデルリストを生成します。
- * @param vmdList 仮想MIDIデバイスのリスト
+ * @param guiVirtualDeviceList GUI仮想MIDIデバイスのリスト
*/
- public MidiDeviceModelList(List<VirtualMidiDevice> vmdList) {
- MidiDevice.Info[] devInfos = MidiSystem.getMidiDeviceInfo();
- MidiConnecterListModel guiModels[] = new MidiConnecterListModel[vmdList.size()];
+ public MidiDeviceModelList(List<VirtualMidiDevice> guiVirtualDeviceList) {
+ MidiDevice.Info[] deviceInfos = MidiSystem.getMidiDeviceInfo();
+ MidiConnecterListModel guiModels[] = new MidiConnecterListModel[guiVirtualDeviceList.size()];
MidiConnecterListModel firstMidiInModel = null;
- for( int i=0; i<vmdList.size(); i++ )
- guiModels[i] = addMidiDevice(vmdList.get(i));
+ //
+ // GUI仮想MIDIデバイスリストの構築
+ for( int i=0; i<guiVirtualDeviceList.size(); i++ )
+ guiModels[i] = addMidiDevice(guiVirtualDeviceList.get(i));
+ //
+ // シーケンサの取得
Sequencer sequencer;
try {
sequencer = MidiSystem.getSequencer(false);
sequencerModel = (MidiSequencerModel)addMidiDevice(sequencer);
} catch( MidiUnavailableException e ) {
- System.out.println(
- ChordHelperApplet.VersionInfo.NAME +
- " : MIDI sequencer unavailable"
- );
+ System.out.println(ChordHelperApplet.VersionInfo.NAME +" : MIDI sequencer unavailable");
e.printStackTrace();
}
+ // MIDIエディタの生成
editorDialog = new MidiSequenceEditor(sequencerModel);
editorDialogModel = addMidiDevice(editorDialog.getVirtualMidiDevice());
- for( MidiDevice.Info info : devInfos ) {
+ for( MidiDevice.Info info : deviceInfos ) {
+ // MIDIデバイスの取得
MidiDevice device;
try {
device = MidiSystem.getMidiDevice(info);
} catch( MidiUnavailableException e ) {
e.printStackTrace(); continue;
}
+ // シーケンサの場合はすでに取得済みなのでスキップ
if( device instanceof Sequencer ) continue;
+ //
+ // Java内蔵シンセサイザ
if( device instanceof Synthesizer ) {
try {
synthModel = addMidiDevice(MidiSystem.getSynthesizer());
} catch( MidiUnavailableException e ) {
- System.out.println(
- ChordHelperApplet.VersionInfo.NAME +
- " : Java internal MIDI synthesizer unavailable"
- );
+ System.out.println(ChordHelperApplet.VersionInfo.NAME +
+ " : Java internal MIDI synthesizer unavailable");
e.printStackTrace();
}
continue;
}
+ // MIDIデバイスを追加し、最初のエントリを覚えておく
MidiConnecterListModel m = addMidiDevice(device);
- if( m.rxSupported() && firstMidiOutModel == null )
- firstMidiOutModel = m;
- if( m.txSupported() && firstMidiInModel == null )
- firstMidiInModel = m;
+ if( m.rxSupported() && firstMidiOutModel == null ) firstMidiOutModel = m;
+ if( m.txSupported() && firstMidiInModel == null ) firstMidiInModel = m;
}
- // デバイスを開く。
+ // MIDIデバイスを開く。
// NOTE: 必ず MIDI OUT Rx デバイスを先に開くこと。
//
// そうすれば、後から開いた MIDI IN Tx デバイスからの
firstMidiInModel,
editorDialogModel,
};
- for( MidiConnecterListModel m : openModels ) {
- if( m != null ) m.openDevice();
- }
- for( MidiConnecterListModel m : guiModels ) {
- m.openDevice();
- }
+ for( MidiConnecterListModel m : openModels ) if( m != null ) m.openDevice();
+ for( MidiConnecterListModel m : guiModels ) m.openDevice();
} catch( MidiUnavailableException ex ) {
ex.printStackTrace();
}
// 初期接続
//
for( MidiConnecterListModel mtx : guiModels ) {
- for( MidiConnecterListModel mrx : guiModels )
- mtx.connectToReceiverOf(mrx);
+ for( MidiConnecterListModel mrx : guiModels ) mtx.connectToReceiverOf(mrx);
mtx.connectToReceiverOf(sequencerModel);
mtx.connectToReceiverOf(synthModel);
mtx.connectToReceiverOf(firstMidiOutModel);
}
if( firstMidiInModel != null ) {
- for( MidiConnecterListModel m : guiModels )
- firstMidiInModel.connectToReceiverOf(m);
+ for( MidiConnecterListModel m : guiModels ) firstMidiInModel.connectToReceiverOf(m);
firstMidiInModel.connectToReceiverOf(sequencerModel);
firstMidiInModel.connectToReceiverOf(synthModel);
firstMidiInModel.connectToReceiverOf(firstMidiOutModel);
}
if( sequencerModel != null ) {
- for( MidiConnecterListModel m : guiModels )
- sequencerModel.connectToReceiverOf(m);
+ for( MidiConnecterListModel m : guiModels ) sequencerModel.connectToReceiverOf(m);
sequencerModel.connectToReceiverOf(synthModel);
sequencerModel.connectToReceiverOf(firstMidiOutModel);
}
+++ /dev/null
-package camidion.chordhelper.mididevice;
-
-import java.awt.Component;
-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 javax.swing.JTree;
-import javax.swing.event.InternalFrameEvent;
-import javax.swing.event.InternalFrameListener;
-import javax.swing.tree.DefaultTreeCellRenderer;
-import javax.swing.tree.TreeModel;
-
-/**
- * MIDIデバイスツリービュー
- */
-public class MidiDeviceTree extends JTree
- implements Transferable, DragGestureListener, InternalFrameListener
-{
- /**
- * MIDIデバイスツリービューを構築します。
- * @param model このビューにデータを提供するモデル
- */
- public MidiDeviceTree(MidiDeviceTreeModel model) {
- super(model);
- (new DragSource()).createDefaultDragGestureRecognizer(
- this, DnDConstants.ACTION_COPY_OR_MOVE, this
- );
- setCellRenderer(new DefaultTreeCellRenderer() {
- @Override
- public Component getTreeCellRendererComponent(
- JTree tree, Object value,
- boolean selected, boolean expanded, boolean leaf, int row,
- boolean hasFocus
- ) {
- super.getTreeCellRendererComponent(
- tree, value, selected, expanded, leaf, row, hasFocus
- );
- if(leaf) {
- setIcon(MidiConnecterListView.MIDI_CONNECTER_ICON);
- setDisabledIcon(MidiConnecterListView.MIDI_CONNECTER_ICON);
- MidiConnecterListModel listModel = (MidiConnecterListModel)value;
- setEnabled( ! listModel.getMidiDevice().isOpen() );
- }
- return this;
- }
- });
- }
- /**
- * このデバイスツリーからドラッグされるデータフレーバ
- */
- public static final DataFlavor
- TREE_MODEL_FLAVOR = new DataFlavor(TreeModel.class, "TreeModel");
- private static final DataFlavor
- TREE_MODE_FLAVORS[] = {TREE_MODEL_FLAVOR};
- @Override
- public Object getTransferData(DataFlavor flavor) {
- return getLastSelectedPathComponent();
- }
- @Override
- public DataFlavor[] getTransferDataFlavors() {
- return TREE_MODE_FLAVORS;
- }
- @Override
- public boolean isDataFlavorSupported(DataFlavor flavor) {
- return flavor.equals(TREE_MODEL_FLAVOR);
- }
- @Override
- public void dragGestureRecognized(DragGestureEvent dge) {
- int action = dge.getDragAction();
- if( (action & DnDConstants.ACTION_COPY_OR_MOVE) != 0 ) {
- dge.startDrag(DragSource.DefaultMoveDrop, this, null);
- }
- }
- @Override
- public void internalFrameOpened(InternalFrameEvent e) {}
- /**
- * MidiDeviceFrame のクローズ処理中に再描画リクエストを送ります。
- */
- @Override
- public void internalFrameClosing(InternalFrameEvent e) {
- repaint();
- }
- @Override
- public void internalFrameClosed(InternalFrameEvent e) {}
- @Override
- public void internalFrameIconified(InternalFrameEvent e) {}
- @Override
- public void internalFrameDeiconified(InternalFrameEvent e) {}
- @Override
- public void internalFrameActivated(InternalFrameEvent e) {}
- @Override
- public void internalFrameDeactivated(InternalFrameEvent e) {}
-}
\ No newline at end of file
--- /dev/null
+package camidion.chordhelper.mididevice;
+
+import java.awt.Component;
+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 javax.swing.JTree;
+import javax.swing.event.InternalFrameAdapter;
+import javax.swing.event.InternalFrameEvent;
+import javax.swing.event.InternalFrameListener;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.TreeModel;
+
+/**
+ * MIDIデバイスツリービュー
+ */
+public class MidiDeviceTreeView extends JTree
+{
+ /**
+ * {@link MidiDeviceFrame} を閉じたことを検知して再描画するためのリスナー
+ */
+ public final InternalFrameListener midiDeviceFrameListener = new InternalFrameAdapter() {
+ @Override
+ public void internalFrameClosing(InternalFrameEvent e) { repaint(); }
+ };
+
+ public static final DataFlavor TREE_MODEL_FLAVOR = new DataFlavor(TreeModel.class, "TreeModel");
+
+ private Transferable draggingObject = new Transferable() {
+ private DataFlavor flavors[] = {TREE_MODEL_FLAVOR};
+ @Override
+ public Object getTransferData(DataFlavor flavor) { return getLastSelectedPathComponent(); }
+ @Override
+ public DataFlavor[] getTransferDataFlavors() { return flavors; }
+ @Override
+ public boolean isDataFlavorSupported(DataFlavor flavor) {
+ return flavor.equals(TREE_MODEL_FLAVOR);
+ }
+ };
+ /**
+ * MIDIデバイスツリービューを構築します。
+ * @param model このビューにデータを提供するモデル
+ */
+ 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 ) {
+ dge.startDrag(DragSource.DefaultMoveDrop, draggingObject, null);
+ }
+ }
+ }
+ );
+ setCellRenderer(new DefaultTreeCellRenderer() {
+ @Override
+ public Component getTreeCellRendererComponent(JTree tree, Object value,
+ boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus)
+ {
+ super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
+ if(leaf) {
+ setIcon(MidiConnecterListView.MIDI_CONNECTER_ICON);
+ setDisabledIcon(MidiConnecterListView.MIDI_CONNECTER_ICON);
+ MidiConnecterListModel listModel = (MidiConnecterListModel)value;
+ setEnabled( ! listModel.getMidiDevice().isOpen() );
+ }
+ return this;
+ }
+ });
+ }
+}
\ No newline at end of file
--- /dev/null
+package camidion.chordhelper.mididevice;
+
+import java.awt.Point;
+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.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+
+import javax.sound.midi.MidiUnavailableException;
+import javax.swing.JDesktopPane;
+import javax.swing.JInternalFrame;
+import javax.swing.JLayeredPane;
+import javax.swing.JOptionPane;
+import javax.swing.Timer;
+
+/**
+ * 開いている MIDI デバイスを置くためのデスクトップビュー
+ */
+public class MidiOpenedDevicesView extends JDesktopPane {
+ private MidiCablePane cablePane = new MidiCablePane(this);
+ private DropTargetAdapter dropTargetListener = new DropTargetAdapter() {
+ @Override
+ public void dragEnter(DropTargetDragEvent dtde) {
+ if( dtde.getTransferable().isDataFlavorSupported(MidiDeviceTreeView.TREE_MODEL_FLAVOR) ) {
+ dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
+ }
+ }
+ @Override
+ public void drop(DropTargetDropEvent dtde) {
+ dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+ try {
+ int action = dtde.getDropAction() ;
+ if( (action & DnDConstants.ACTION_COPY_OR_MOVE) != 0 ) {
+ Object data = dtde.getTransferable().getTransferData(MidiDeviceTreeView.TREE_MODEL_FLAVOR);
+ if( data instanceof MidiConnecterListModel ) {
+ MidiConnecterListModel deviceModel = (MidiConnecterListModel)data;
+ try {
+ deviceModel.openDevice();
+ } 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"
+ +"他のデバイスが連動して開いていないか確認してください。";
+ dtde.dropComplete(false);
+ JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ dtde.dropComplete(true);
+ //
+ // デバイスが正常に開かれたことを確認できたら
+ // ドロップした場所へフレームを配置して可視化する。
+ //
+ MidiDeviceFrame deviceFrame = getMidiDeviceFrameOf(deviceModel);
+ if( deviceFrame == null ) return;
+ Point loc = dtde.getLocation();
+ loc.translate( -deviceFrame.getWidth()/2, 0 );
+ deviceFrame.setLocation(loc);
+ deviceFrame.setVisible(true);
+ return;
+ }
+ }
+ }
+ catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ dtde.dropComplete(false);
+ }
+ };
+ public MidiOpenedDevicesView(MidiDeviceTreeView deviceTree) {
+ add(cablePane, JLayeredPane.PALETTE_LAYER);
+ int frameIndex = 0;
+ MidiDeviceTreeModel treeModel = (MidiDeviceTreeModel)deviceTree.getModel();
+ for( MidiConnecterListModel deviceModel : treeModel.deviceModelList ) {
+ deviceModel.addListDataListener(cablePane.midiConnecterListDataListener);
+ MidiDeviceFrame frame = new MidiDeviceFrame(deviceModel, cablePane) {{
+ addInternalFrameListener(cablePane.midiDeviceFrameListener);
+ addComponentListener(cablePane.midiDeviceFrameComponentListener);
+ }};
+ frame.addInternalFrameListener(deviceTree.midiDeviceFrameListener);
+ add(frame);
+ if( deviceModel.getMidiDevice().isOpen() ) {
+ frame.setBounds( 10+(frameIndex%2)*260, 10+frameIndex*55, 250, 100 );
+ frame.setVisible(true);
+ frameIndex++;
+ }
+ }
+ addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentResized(ComponentEvent e) { cablePane.setSize(getSize()); }
+ });
+ new DropTarget( this, DnDConstants.ACTION_COPY_OR_MOVE, dropTargetListener, true );
+ }
+ /**
+ * 指定されたMIDIデバイスモデルに対するMIDIデバイスフレームを返します。
+ *
+ * @param deviceModel MIDIデバイスモデル
+ * @return 対応するMIDIデバイスフレーム(ない場合 null)
+ */
+ public MidiDeviceFrame getMidiDeviceFrameOf(MidiConnecterListModel deviceModel) {
+ JInternalFrame[] frames = getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER);
+ for( JInternalFrame frame : frames ) {
+ if( ! (frame instanceof MidiDeviceFrame) ) continue;
+ MidiDeviceFrame deviceFrame = (MidiDeviceFrame)frame;
+ if( deviceFrame.listView.getModel() == deviceModel ) return deviceFrame;
+ }
+ return null;
+ }
+ private boolean isTimerStarted;
+ /**
+ * タイムスタンプを更新するタイマーを開始または停止します。
+ * @param toStart trueで開始、falseで停止
+ */
+ public void setAllDeviceTimestampTimers(boolean toStart) {
+ if( isTimerStarted == toStart ) return;
+ isTimerStarted = toStart;
+ JInternalFrame[] frames = getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER);
+ for( JInternalFrame frame : frames ) {
+ if( ! (frame instanceof MidiDeviceFrame) ) continue;
+ Timer timer = ((MidiDeviceFrame)frame).timer;
+ if( toStart ) timer.start(); else timer.stop();
+ }
+ }
+}