OSDN Git Service

060727eb3086ced824104672b2530a084b41bcfb
[midichordhelper/MIDIChordHelper.git] / src / camidion / chordhelper / mididevice / MidiOpenedDevicesView.java
1 package camidion.chordhelper.mididevice;
2
3 import java.awt.datatransfer.Transferable;
4 import java.awt.dnd.DnDConstants;
5 import java.awt.dnd.DropTarget;
6 import java.awt.dnd.DropTargetAdapter;
7 import java.awt.dnd.DropTargetDragEvent;
8 import java.awt.dnd.DropTargetDropEvent;
9 import java.awt.dnd.DropTargetListener;
10 import java.awt.event.ComponentAdapter;
11 import java.awt.event.ComponentEvent;
12 import java.beans.PropertyVetoException;
13 import java.util.HashMap;
14 import java.util.Map;
15
16 import javax.sound.midi.MidiUnavailableException;
17 import javax.swing.JDesktopPane;
18 import javax.swing.JInternalFrame;
19 import javax.swing.JLayeredPane;
20 import javax.swing.JOptionPane;
21 import javax.swing.event.TreeSelectionEvent;
22 import javax.swing.event.TreeSelectionListener;
23 import javax.swing.tree.TreePath;
24
25 /**
26  * 開いている MIDI デバイスを置くためのデスクトップビュー
27  */
28 public class MidiOpenedDevicesView extends JDesktopPane implements TreeSelectionListener {
29
30         private Map<MidiTransceiverListModel, MidiDeviceFrame> modelToFrame = new HashMap<>();
31
32         /**
33          * ツリー上で選択状態が変わったとき、このデスクトップ上のフレームの選択状態に反映します。
34          */
35         @Override
36         public void valueChanged(TreeSelectionEvent tse) {
37                 TreePath treePath = tse.getNewLeadSelectionPath();
38                 if( treePath != null ) {
39                         Object lastSelected = treePath.getLastPathComponent();
40                         if( lastSelected instanceof MidiTransceiverListModel ) {
41                                 MidiTransceiverListModel deviceModel = (MidiTransceiverListModel)lastSelected;
42                                 if( deviceModel.getMidiDevice().isOpen() ) {
43                                         // 開いているMIDIデバイスがツリー上で選択されたら、対応するフレームを選択
44                                         MidiDeviceFrame deviceFrame = modelToFrame.get(deviceModel);
45                                         deviceFrame.toFront();
46                                         try {
47                                                 deviceFrame.setSelected(true);
48                                         } catch( PropertyVetoException ex ) {
49                                                 ex.printStackTrace();
50                                         }
51                                         return;
52                                 }
53                         }
54                 }
55                 // それ以外が選択されたら、現在選択されているフレームを非選択
56                 JInternalFrame frame = getSelectedFrame();
57                 if( ! (frame instanceof MidiDeviceFrame) ) return;
58                 try {
59                         ((MidiDeviceFrame)frame).setSelected(false);
60                 } catch( PropertyVetoException ex ) {
61                         ex.printStackTrace();
62                 }
63         }
64         /**
65          * ツリー表示からこのデスクトップにドロップされたMIDIデバイスモデルに対応するフレームを表示するためのリスナー
66          */
67         private DropTargetListener dropTargetListener = new DropTargetAdapter() {
68                 @Override
69                 public void dragEnter(DropTargetDragEvent dtde) {
70                         if( dtde.getTransferable().isDataFlavorSupported(MidiDeviceTreeView.LIST_MODEL_FLAVOR) ) {
71                                 dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
72                         }
73                 }
74                 @Override
75                 public void drop(DropTargetDropEvent dtde) {
76                         dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
77                         try {
78                                 int maskedBits = dtde.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE;
79                                 if( maskedBits == 0 ) {
80                                         dtde.dropComplete(false);
81                                         return;
82                                 }
83                                 Transferable t = dtde.getTransferable();
84                                 if( ! t.isDataFlavorSupported(MidiDeviceTreeView.LIST_MODEL_FLAVOR) ) {
85                                         dtde.dropComplete(false);
86                                         return;
87                                 }
88                                 Object data = t.getTransferData(MidiDeviceTreeView.LIST_MODEL_FLAVOR);
89                                 if( ! (data instanceof MidiTransceiverListModel) ) {
90                                         dtde.dropComplete(false);
91                                         return;
92                                 }
93                                 MidiTransceiverListModel deviceModel = (MidiTransceiverListModel)data;
94                                 try {
95                                         deviceModel.getMidiDevice().open();
96                                         deviceModel.openReceiver();
97                                 } catch( MidiUnavailableException e ) {
98                                         //
99                                         // デバイスを開くのに失敗した場合
100                                         //
101                                         //   例えば、「Microsort MIDI マッパー」と
102                                         //   「Microsoft GS Wavetable SW Synth」を
103                                         //   同時に開こうとするとここに来る。
104                                         //
105                                         String title = "Cannot open MIDI device";
106                                         String message = "MIDIデバイス "+deviceModel+" はすでに使用中です。\n"
107                                                 +"他のデバイスが連動して開いている可能性があります。\n\n"
108                                                 + e.getMessage();
109                                         dtde.dropComplete(false);
110                                         JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE);
111                                         return;
112                                 }
113                                 if( ! deviceModel.getMidiDevice().isOpen() ) {
114                                         // 例外が出なかったにも関わらずデバイスが開かれていない場合
115                                         String title = "Cannot open MIDI device";
116                                         String message = "MIDIデバイス "+deviceModel+" はすでに使用中です。\n"
117                                                         +"他のデバイスが連動して開いている可能性があります。\n\n" ;
118                                         dtde.dropComplete(false);
119                                         JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE);
120                                         return;
121                                 }
122                                 dtde.dropComplete(true);
123                                 //
124                                 // デバイスが正常に開かれたことを確認できたら
125                                 // ドロップした場所へフレームを配置して可視化する。
126                                 //
127                                 MidiDeviceFrame deviceFrame = modelToFrame.get(deviceModel);
128                                 deviceFrame.setLocation(dtde.getLocation());
129                                 deviceFrame.setVisible(true);
130                         }
131                         catch (Exception ex) {
132                                 ex.printStackTrace();
133                                 dtde.dropComplete(false);
134                         }
135                 }
136         };
137
138         private MidiCablePane cablePane = new MidiCablePane(this);
139
140         public MidiOpenedDevicesView(
141                         MidiDeviceTreeView deviceTreeView,
142                         MidiDeviceInfoPane deviceInfoPane,
143                         MidiDeviceDialog dialog
144         ) {
145                 add(cablePane, JLayeredPane.PALETTE_LAYER);
146                 addComponentListener(new ComponentAdapter() {
147                         @Override
148                         public void componentResized(ComponentEvent e) { cablePane.setSize(getSize()); }
149                 });
150                 int toX = 10;
151                 int toY = 10;
152                 MidiTransceiverListModelList deviceModels = deviceTreeView.getModel().getTransceiverListModelList();
153                 for( MidiTransceiverListModel deviceModel : deviceModels ) {
154                         MidiDeviceFrame frame = new MidiDeviceFrame(new MidiTransceiverListView(deviceModel, cablePane));
155                         modelToFrame.put(deviceModel, frame);
156                         //
157                         // MIDIデバイスモデルのMIDIコネクタリストが変化したときにMIDIケーブルを再描画
158                         deviceModel.addListDataListener(cablePane.midiConnecterListDataListener);
159                         //
160                         // デバイスフレームが開閉したときの動作
161                         frame.addInternalFrameListener(cablePane.midiDeviceFrameListener);
162                         frame.addInternalFrameListener(deviceTreeView.midiDeviceFrameListener);
163                         frame.addInternalFrameListener(deviceInfoPane.midiDeviceFrameListener);
164                         //
165                         // 移動または変形時の動作
166                         frame.addComponentListener(cablePane.midiDeviceFrameComponentListener);
167                         //
168                         // ダイアログが閉じたときの動作
169                         dialog.addWindowListener(frame.windowListener);
170                         //
171                         frame.setSize(250, 90);
172                         add(frame);
173                         if( deviceModel.getMidiDevice().isOpen() ) {
174                                 frame.setLocation(toX, toY);
175                                 frame.setVisible(true);
176                                 toX = (toX == 10 ? 270 : 10);
177                                 toY += 50;
178                         }
179                 }
180                 new DropTarget( this, DnDConstants.ACTION_COPY_OR_MOVE, dropTargetListener, true );
181         }
182
183 }