-package camidion.chordhelper.mididevice;\r
-\r
-import java.awt.Insets;\r
-import java.awt.Rectangle;\r
-import java.awt.event.ActionEvent;\r
-import java.awt.event.ActionListener;\r
-\r
-import javax.sound.midi.MidiDevice;\r
-import javax.swing.BoxLayout;\r
-import javax.swing.JButton;\r
-import javax.swing.JInternalFrame;\r
-import javax.swing.JLabel;\r
-import javax.swing.JPanel;\r
-import javax.swing.JScrollPane;\r
-import javax.swing.Timer;\r
-import javax.swing.event.InternalFrameAdapter;\r
-import javax.swing.event.InternalFrameEvent;\r
-\r
-/**\r
- * MIDIデバイスフレームビュー\r
- */\r
-public class MidiDeviceFrame extends JInternalFrame {\r
- private static Insets ZERO_INSETS = new Insets(0,0,0,0);\r
- /**\r
- * デバイスの仮想MIDI端子リストビュー\r
- */\r
- MidiConnecterListView listView;\r
- /**\r
- * デバイスのタイムスタンプを更新するタイマー\r
- */\r
- Timer timer;\r
- /**\r
- * MIDIデバイスのモデルからフレームビューを構築します。\r
- * @param model MIDIデバイスのTransmitter/Receiverリストモデル\r
- */\r
- public MidiDeviceFrame(MidiConnecterListModel model) {\r
- super( null, true, true, false, false );\r
- //\r
- // タイトルの設定\r
- String title = model.toString();\r
- if( model.txSupported() ) {\r
- title = (model.rxSupported()?"[I/O] ":"[IN] ")+title;\r
- }\r
- else {\r
- title = (model.rxSupported()?"[OUT] ":"[No I/O] ")+title;\r
- }\r
- setTitle(title);\r
- listView = new MidiConnecterListView(model);\r
- setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);\r
- addInternalFrameListener(\r
- new InternalFrameAdapter() {\r
- public void internalFrameOpened(InternalFrameEvent e) {\r
- if( ! listView.getModel().getMidiDevice().isOpen() )\r
- setVisible(false);\r
- }\r
- public void internalFrameClosing(InternalFrameEvent e) {\r
- MidiConnecterListModel m = listView.getModel();\r
- m.closeDevice();\r
- if( ! m.getMidiDevice().isOpen() )\r
- setVisible(false);\r
- }\r
- }\r
- );\r
- setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));\r
- add(new JScrollPane(listView));\r
- add(new JPanel() {{\r
- if( listView.getModel().txSupported() ) {\r
- add(new JButton("New Tx") {{\r
- setMargin(ZERO_INSETS);\r
- addActionListener(new ActionListener() {\r
- @Override\r
- public void actionPerformed(ActionEvent event) {\r
- listView.getModel().getUnconnectedTransmitter();\r
- }\r
- });\r
- }});\r
- add(new JButton("Close Tx") {{\r
- setMargin(ZERO_INSETS);\r
- addActionListener(new ActionListener() {\r
- @Override\r
- public void actionPerformed(ActionEvent event) {\r
- listView.closeSelectedTransmitter();\r
- }\r
- });\r
- }});\r
- }\r
- add(new JLabel() {{\r
- timer = new Timer(50, new ActionListener() {\r
- private long sec = -2;\r
- private MidiDevice dev = listView.getModel().getMidiDevice();\r
- @Override\r
- public void actionPerformed(ActionEvent e) {\r
- long usec = dev.getMicrosecondPosition();\r
- long sec = (usec == -1 ? -1 : usec/1000000);\r
- if( sec == this.sec ) return;\r
- String text;\r
- if( (this.sec = sec) == -1 )\r
- text = "No TimeStamp";\r
- else\r
- text = String.format("TimeStamp: %02d:%02d", sec/60, sec%60);\r
- setText(text);\r
- }\r
- });\r
- }});\r
- }});\r
- setSize(250,100);\r
- }\r
- /**\r
- * 指定されたインデックスが示す仮想MIDI端子リストの要素のセル範囲を返します。\r
- *\r
- * @param index リスト要素のインデックス\r
- * @return セル範囲の矩形\r
- */\r
- public Rectangle getListCellBounds(int index) {\r
- Rectangle rect = listView.getCellBounds(index,index);\r
- if( rect == null )\r
- return null;\r
- rect.translate(\r
- getRootPane().getX() + getContentPane().getX(),\r
- getRootPane().getY() + getContentPane().getY()\r
- );\r
- return rect;\r
- }\r
- /**\r
- * 仮想MIDI端子リストの指定された要素のセル範囲を返します。\r
- *\r
- * @param transciver 要素となるMIDI端子(Transmitter または Receiver)\r
- * @return セル範囲の矩形\r
- */\r
- public Rectangle getListCellBounds(AutoCloseable transciver) {\r
- return getListCellBounds(listView.getModel().indexOf(transciver));\r
- }\r
-}
\ No newline at end of file
+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.JInternalFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.Timer;
+
+/**
+ * MIDIデバイスフレームビュー
+ */
+public class MidiDeviceFrame extends JInternalFrame {
+ private MidiDeviceModel deviceModel;
+ private TransmitterListView transmitterListView;
+ private ReceiverListView receiverListView;
+ private JScrollPane scrollPane;
+ private JPanel trxPanel, txPanel, rxPanel;
+ private Timer timer;
+ /**
+ * このデバイスフレームに表示内容を提供しているMIDIデバイスモデルを取得します。
+ * @return MIDIデバイスモデル
+ */
+ public MidiDeviceModel getMidiDeviceModel() { return deviceModel; }
+ /**
+ * このデバイスフレームに貼り付けられたMIDIトランスミッタリストビューを取得します。
+ * @return MIDIトランスミッタリストビュー
+ */
+ public TransmitterListView getMidiTransmitterListView() { return transmitterListView; }
+ /**
+ * このデバイスフレームに貼り付けられたMIDIトランシーバリストビューを取得します。
+ * @return MIDIトランシーバリストビュー
+ */
+ 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 );
+ this.deviceModel = deviceModel;
+ setTitle("[" + deviceModel.getMidiDeviceInOutType().getShortName() + "] " + deviceModel);
+ setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+ setLayout(new BorderLayout());
+ add(new JLabel("--:--") {{
+ timer = new Timer(50, new ActionListener() {
+ private long sec = -2;
+ private MidiDevice device = getMidiDeviceModel().getMidiDevice();
+ @Override
+ 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();
+ }
+ });
+ }}, 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);
+ }
+ }}));
+ }
+ /**
+ * 引数で指定された{@link Transmitter}のセル範囲を示す、
+ * デスクトップの座標系内の境界の矩形を返します。対応するセルがない場合はnullを返します。
+ * @return セル範囲を示す境界の矩形、またはnull
+ */
+ 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);
+ }
+}