package camidion.chordhelper.mididevice;
+import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
import javax.sound.midi.MidiDevice;
import javax.sound.midi.Receiver;
import javax.sound.midi.Transmitter;
-import javax.swing.BoxLayout;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
+import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;
-import javax.swing.event.InternalFrameAdapter;
-import javax.swing.event.InternalFrameEvent;
/**
* MIDIデバイスフレームビュー
*/
public class MidiDeviceFrame extends JInternalFrame {
-
- private MidiConnecterListView listView;
+ private MidiDeviceModel deviceModel;
+ private TransmitterListView transmitterListView;
+ private ReceiverListView receiverListView;
private JScrollPane scrollPane;
+ private JPanel trxPanel, txPanel, rxPanel;
private Timer timer;
-
/**
- * ã\81\93ã\81®ã\83\87ã\83\90ã\82¤ã\82¹ã\83\95ã\83¬ã\83¼ã\83 ã\81«è²¼ã\82\8aä»\98ã\81\91ã\82\89ã\82\8cã\81\9fä»®æ\83³MIDI端å\90ã\83ªã\82¹ã\83\88ã\83\93ã\83¥ã\83¼を取得します。
- * @return 仮想MIDI端子リストビュー
+ * ã\81\93ã\81®ã\83\87ã\83\90ã\82¤ã\82¹ã\83\95ã\83¬ã\83¼ã\83 ã\81«è¡¨ç¤ºå\86\85容ã\82\92æ\8f\90ä¾\9bã\81\97ã\81¦ã\81\84ã\82\8bMIDIã\83\87ã\83\90ã\82¤ã\82¹ã\83¢ã\83\87ã\83«を取得します。
+ * @return MIDIデバイスモデル
*/
- public MidiConnecterListView getMidiConnecterListView() { return listView; }
-
+ public MidiDeviceModel getMidiDeviceModel() { return deviceModel; }
/**
- * ã\81\93ã\81®ã\83\87ã\83\90ã\82¤ã\82¹ã\83\95ã\83¬ã\83¼ã\83 ã\81®ã\82¿ã\82¤ã\83 ã\82¹ã\82¿ã\83³ã\83\97表示æ\9b´æ\96°ç\94¨ã\82¿ã\82¤ã\83\9eーを取得します。
- * @return タイムスタンプ表示更新用タイマー
+ * ã\81\93ã\81®ã\83\87ã\83\90ã\82¤ã\82¹ã\83\95ã\83¬ã\83¼ã\83 ã\81«è²¼ã\82\8aä»\98ã\81\91ã\82\89ã\82\8cã\81\9fMIDIã\83\88ã\83©ã\83³ã\82¹ã\83\9fã\83\83ã\82¿ã\83ªã\82¹ã\83\88ã\83\93ã\83¥ーを取得します。
+ * @return MIDIトランスミッタリストビュー
*/
- public Timer getTimer() { return timer; }
-
+ public TransmitterListView getMidiTransmitterListView() { return transmitterListView; }
/**
- * MIDIデバイスのモデルからフレームビューを構築します。
- * @param model MIDIデバイスのTransmitter/Receiverリストモデル
- * @param cablePane MIDIケーブル描画面
+ * このデバイスフレームに貼り付けられたMIDIトランシーバリストビューを取得します。
+ * @return MIDIトランシーバリストビュー
*/
- public MidiDeviceFrame(MidiConnecterListModel model, MidiCablePane cablePane) {
+ public ReceiverListView getMidiReceiverListView() { return receiverListView; }
+ /**
+ * ダイアログウィンドウがアクティブなときだけタイムスタンプ更新を有効にするためのリスナー
+ */
+ public final WindowListener windowListener = new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) { timer.stop(); }
+ @Override
+ public void windowActivated(WindowEvent e) { timer.start(); }
+ };
+ /**
+ * MIDIデバイスモデルからフレームビューを構築します。
+ */
+ public MidiDeviceFrame(MidiDeviceModel deviceModel, MidiCablePane cablePane) {
super( null, true, true, false, false );
- listView = new MidiConnecterListView(model, cablePane);
- addInternalFrameListener(cablePane.midiDeviceFrameListener);
- addComponentListener(cablePane.midiDeviceFrameComponentListener);
- setTitle("[" + model.getMidiDeviceInOutType().getShortName() + "] " + model);
+ this.deviceModel = deviceModel;
+ setTitle("[" + deviceModel.getMidiDeviceInOutType().getShortName() + "] " + deviceModel);
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
- addInternalFrameListener(new InternalFrameAdapter() {
- @Override
- public void internalFrameClosing(InternalFrameEvent e) {
- MidiConnecterListModel m = listView.getModel();
- m.closeDevice();
- setVisible(m.getMidiDevice().isOpen());
- }
- });
+ setLayout(new BorderLayout());
add(new JLabel("--:--") {{
timer = new Timer(50, new ActionListener() {
private long sec = -2;
- private MidiDevice dev = listView.getModel().getMidiDevice();
+ private MidiDevice device = getMidiDeviceModel().getMidiDevice();
@Override
- public void actionPerformed(ActionEvent e) {
- long usec = dev.getMicrosecondPosition();
+ public void actionPerformed(ActionEvent event) {
+ long usec = device.getMicrosecondPosition();
long sec = (usec == -1 ? -1 : usec/1000000);
if( sec == this.sec ) return;
this.sec = sec;
setText(sec == -1?"--:--":String.format("%02d:%02d",sec/60,sec%60));
+ cablePane.repaint();
}
});
- }});
- add(scrollPane = new JScrollPane(listView));
- setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
+ }}, BorderLayout.SOUTH);
+ add(scrollPane = new JScrollPane(trxPanel = new JPanel() {{
+ setLayout(new BorderLayout());
+ ReceiverListModel rxListModel = getMidiDeviceModel().getReceiverListModel();
+ if( rxListModel != null ) {
+ receiverListView = new ReceiverListView(rxListModel, cablePane);
+ add(rxPanel = new JPanel() {{
+ setLayout(new BorderLayout());
+ add(new JLabel("Rx") {{ setVerticalAlignment(TOP); }}, BorderLayout.WEST);
+ add(receiverListView);
+ }}, BorderLayout.NORTH);
+ }
+ TransmitterListModel txListModel = getMidiDeviceModel().getTransmitterListModel();
+ if( txListModel != null ) {
+ transmitterListView = new TransmitterListView(txListModel, cablePane);
+ add(txPanel = new JPanel() {{
+ setLayout(new BorderLayout());
+ add(new JLabel("Tx") {{ setVerticalAlignment(TOP); }}, BorderLayout.WEST);
+ add(transmitterListView);
+ }}, rxListModel == null ? BorderLayout.NORTH : BorderLayout.SOUTH);
+ }
+ }}));
}
/**
- * å¼\95æ\95°ã\81§æ\8c\87å®\9aã\81\95ã\82\8cã\81\9f{@link Transmitter}ã\81¾ã\81\9fã\81¯{@link Receiver}ã\81®ã\82»ã\83«ç¯\84å\9b²ã\82\92示ã\81\99ã\80\81
+ * 引数で指定された{@link Transmitter}のセル範囲を示す、
* デスクトップの座標系内の境界の矩形を返します。対応するセルがない場合はnullを返します。
- * @param transceiver {@link Transmitter}または{@link Receiver}
* @return セル範囲を示す境界の矩形、またはnull
*/
- public Rectangle getBoundsOf(AutoCloseable transceiver) {
- Rectangle rect = listView.getCellBounds(transceiver);
- if( rect != null ) rect.translate(
- getRootPane().getX() + getContentPane().getX() + scrollPane.getX() + getX(),
- getRootPane().getY() + getContentPane().getY() + scrollPane.getY() + getY()
- );
+ public Rectangle getBoundsOf(Transmitter tx) {
+ if( transmitterListView == null ) return null;
+ Rectangle rect = transmitterListView.getCellBounds(tx);
+ if( rect == null ) return null;
+ translate(rect, txPanel, transmitterListView);
return rect;
}
+ /**
+ * 引数で指定された{@link Receiver}のセル範囲を示す、
+ * デスクトップの座標系内の境界の矩形を返します。対応するセルがない場合はnullを返します。
+ * @return セル範囲を示す境界の矩形、またはnull
+ */
+ public Rectangle getBoundsOf(Receiver rx) {
+ if( receiverListView == null ) return null;
+ Rectangle rect = receiverListView.getCellBounds(rx);
+ if( rect == null ) return null;
+ translate(rect, rxPanel, receiverListView);
+ return rect;
+ }
+ private void translate(Rectangle rect, JPanel panel, AbstractTransceiverListView<?> list) {
+ int x = getX() + getRootPane().getX() + getContentPane().getX() +
+ scrollPane.getX() + trxPanel.getX() +
+ panel.getX() + list.getX();
+ int y = getY() + getRootPane().getY() + getContentPane().getY() +
+ scrollPane.getY() + trxPanel.getY() +
+ panel.getY() + list.getY();
+ rect.translate(x,y);
+ }
}