1 package camidion.chordhelper.mididevice;
3 import java.awt.dnd.DnDConstants;
4 import java.awt.dnd.DropTarget;
5 import java.awt.dnd.DropTargetAdapter;
6 import java.awt.dnd.DropTargetDragEvent;
7 import java.awt.dnd.DropTargetDropEvent;
8 import java.awt.event.ComponentAdapter;
9 import java.awt.event.ComponentEvent;
10 import java.beans.PropertyVetoException;
12 import javax.sound.midi.MidiUnavailableException;
13 import javax.swing.JDesktopPane;
14 import javax.swing.JInternalFrame;
15 import javax.swing.JLayeredPane;
16 import javax.swing.JOptionPane;
17 import javax.swing.Timer;
18 import javax.swing.event.TreeSelectionEvent;
19 import javax.swing.event.TreeSelectionListener;
22 * 開いている MIDI デバイスを置くためのデスクトップビュー
24 public class MidiOpenedDevicesView extends JDesktopPane {
28 * このデスクトップ上のフレームの選択状態に反映するためのリスナー
30 private TreeSelectionListener treeSelectionListener = new TreeSelectionListener() {
32 public void valueChanged(TreeSelectionEvent e) {
33 Object lastSelected = e.getNewLeadSelectionPath().getLastPathComponent();
34 if( lastSelected instanceof MidiConnecterListModel ) {
35 MidiConnecterListModel deviceModel = (MidiConnecterListModel)lastSelected;
36 if( deviceModel.getMidiDevice().isOpen() ) {
37 // 開いているMIDIデバイスがツリー上で選択されたら
40 getMidiDeviceFrameOf(deviceModel).setSelected(true);
41 } catch( PropertyVetoException ex ) {
47 // 閉じているMIDIデバイス、またはMIDIデバイス以外のノードがツリー上で選択されたら
48 // このデスクトップ上のMIDIデバイスフレームをすべて非選択にする
49 MidiDeviceFrame selectedDeviceFrame = getSelectedMidiDeviceFrame();
50 if( selectedDeviceFrame == null ) return;
52 selectedDeviceFrame.setSelected(false);
53 } catch( PropertyVetoException ex ) {
60 * ツリー表示からこのデスクトップにドロップされたMIDIデバイスモデルに対応するフレームを表示するためのリスナー
62 private DropTargetAdapter dropTargetListener = new DropTargetAdapter() {
64 public void dragEnter(DropTargetDragEvent dtde) {
65 if( dtde.getTransferable().isDataFlavorSupported(MidiDeviceTreeView.TREE_MODEL_FLAVOR) ) {
66 dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
70 public void drop(DropTargetDropEvent dtde) {
71 dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
73 int maskedBits = dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE;
74 if( maskedBits == 0 ) {
75 dtde.dropComplete(false);
78 Object data = dtde.getTransferable().getTransferData(MidiDeviceTreeView.TREE_MODEL_FLAVOR);
79 if( ! (data instanceof MidiConnecterListModel) ) {
80 dtde.dropComplete(false);
83 MidiConnecterListModel deviceModel = (MidiConnecterListModel)data;
85 deviceModel.openDevice();
86 } catch( MidiUnavailableException e ) {
90 // 例えば、「Microsort MIDI マッパー」と
91 // 「Microsoft GS Wavetable SW Synth」を
94 String title = "Cannot open MIDI device";
95 String message = "MIDIデバイス "+deviceModel+" はすでに使用中です。\n"
96 +"他のデバイスが連動して開いていないか確認してください。\n\n"
98 dtde.dropComplete(false);
99 JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE);
102 if( ! deviceModel.getMidiDevice().isOpen() ) {
103 // 例外が出なかったにも関わらずデバイスが開かれていない場合
104 String title = "Cannot open MIDI device";
105 String message = "MIDIデバイス "+deviceModel+" はすでに使用中です。\n"
106 +"他のデバイスが連動して開いていないか確認してください。";
107 dtde.dropComplete(false);
108 JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE);
111 dtde.dropComplete(true);
113 // デバイスが正常に開かれたことを確認できたら
114 // ドロップした場所へフレームを配置して可視化する。
116 MidiDeviceFrame deviceFrame = getMidiDeviceFrameOf(deviceModel);
117 deviceFrame.setLocation(dtde.getLocation());
118 deviceFrame.setVisible(true);
120 catch (Exception ex) {
121 ex.printStackTrace();
122 dtde.dropComplete(false);
127 private MidiCablePane cablePane = new MidiCablePane(this);
129 public MidiOpenedDevicesView(MidiDeviceTreeView deviceTree) {
130 deviceTree.addTreeSelectionListener(treeSelectionListener);
131 add(cablePane, JLayeredPane.PALETTE_LAYER);
132 int openedFrameIndex = 0;
133 MidiDeviceTreeModel treeModel = (MidiDeviceTreeModel)deviceTree.getModel();
134 for( MidiConnecterListModel deviceModel : treeModel.deviceModelList ) {
135 deviceModel.addListDataListener(cablePane.midiConnecterListDataListener);
136 MidiDeviceFrame frame = new MidiDeviceFrame(deviceModel, cablePane);
137 frame.setSize(250, 90);
138 frame.addInternalFrameListener(deviceTree.midiDeviceFrameListener);
140 if( ! deviceModel.getMidiDevice().isOpen() ) continue;
141 frame.setLocation( 10+(openedFrameIndex%2)*260, 10+openedFrameIndex*50 );
142 frame.setVisible(true);
145 // このデスクトップがリサイズされたらケーブル面もリサイズする
146 addComponentListener(new ComponentAdapter() {
148 public void componentResized(ComponentEvent e) { cablePane.setSize(getSize()); }
150 new DropTarget( this, DnDConstants.ACTION_COPY_OR_MOVE, dropTargetListener, true );
154 * 指定されたMIDIデバイスモデルに対するMIDIデバイスフレームを返します。
156 * @param deviceModel MIDIデバイスモデル
157 * @return 対応するMIDIデバイスフレーム(ない場合 null)
159 public MidiDeviceFrame getMidiDeviceFrameOf(MidiConnecterListModel deviceModel) {
160 JInternalFrame[] frames = getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER);
161 for( JInternalFrame frame : frames ) {
162 if( ! (frame instanceof MidiDeviceFrame) ) continue;
163 MidiDeviceFrame deviceFrame = (MidiDeviceFrame)frame;
164 if( deviceModel.equals(deviceFrame.getMidiConnecterListView().getModel()) ) {
172 * このビュー上にある現在アクティブな{@link MidiDeviceFrame}を返します。
173 * アクティブな{@link MidiDeviceFrame}がない場合は null を返します。
174 * @return 現在アクティブな{@link MidiDeviceFrame}、または null
176 public MidiDeviceFrame getSelectedMidiDeviceFrame() {
177 JInternalFrame frame = getSelectedFrame();
178 return frame instanceof MidiDeviceFrame ? (MidiDeviceFrame)frame : null;
181 private boolean isTimerStarted;
183 * タイムスタンプを更新するタイマーを開始または停止します。
184 * @param toStart trueで開始、falseで停止
186 public void setAllDeviceTimestampTimers(boolean toStart) {
187 if( isTimerStarted == toStart ) return;
188 isTimerStarted = toStart;
189 JInternalFrame[] frames = getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER);
190 for( JInternalFrame frame : frames ) {
191 if( ! (frame instanceof MidiDeviceFrame) ) continue;
192 Timer timer = ((MidiDeviceFrame)frame).getTimer();
193 if( toStart ) timer.start(); else timer.stop();