OSDN Git Service

・Java8 VM 環境対応
[midichordhelper/MIDIChordHelper.git] / src / camidion / chordhelper / mididevice / MidiCablePane.java
1 package camidion.chordhelper.mididevice;
2
3 import java.awt.BasicStroke;
4 import java.awt.Color;
5 import java.awt.Graphics;
6 import java.awt.Graphics2D;
7 import java.awt.Point;
8 import java.awt.Rectangle;
9 import java.awt.Stroke;
10 import java.awt.dnd.DragSourceAdapter;
11 import java.awt.dnd.DragSourceDragEvent;
12 import java.awt.dnd.DragSourceDropEvent;
13 import java.awt.dnd.DragSourceListener;
14 import java.awt.dnd.DragSourceMotionListener;
15 import java.awt.event.ComponentAdapter;
16 import java.awt.event.ComponentEvent;
17 import java.awt.event.ComponentListener;
18 import java.util.Arrays;
19 import java.util.Hashtable;
20 import java.util.List;
21
22 import javax.sound.midi.Receiver;
23 import javax.sound.midi.Transmitter;
24 import javax.swing.JComponent;
25 import javax.swing.JInternalFrame;
26 import javax.swing.JLayeredPane;
27 import javax.swing.event.InternalFrameAdapter;
28 import javax.swing.event.InternalFrameEvent;
29 import javax.swing.event.InternalFrameListener;
30 import javax.swing.event.ListDataEvent;
31 import javax.swing.event.ListDataListener;
32
33 /**
34  * MIDI ケーブル描画面
35  */
36 public class MidiCablePane extends JComponent implements DragSourceMotionListener {
37         static DraggingTransceiver dragging = new DraggingTransceiver();
38         private Point draggingPoint;
39         /**
40          * ドラッグしている最中に再描画するためのソースモーションリスナー
41          */
42         @Override
43         public void dragMouseMoved(DragSourceDragEvent dsde) {
44                 Point origin = getLocationOnScreen();
45                 draggingPoint = dsde.getLocation();
46                 draggingPoint.translate(-origin.x, -origin.y);
47                 repaint();
48         }
49         /**
50          * ドラッグ終了時に再描画するためのソースリスナー
51          */
52         public final DragSourceListener dragSourceListener = new DragSourceAdapter() {
53                 @Override
54                 public void dragDropEnd(DragSourceDropEvent dsde) {
55                         dragging.setData(null);
56                         draggingPoint = null;
57                         repaint();
58                 }
59         };
60         /**
61          * {@link MidiDeviceFrame} が移動または変形したときにケーブルを再描画するためのリスナー
62          */
63         public final ComponentListener midiDeviceFrameComponentListener = new ComponentAdapter() {
64                 @Override
65                 public void componentMoved(ComponentEvent e) { repaint(); }
66                 @Override
67                 public void componentResized(ComponentEvent e) { repaint(); }
68         };
69         /**
70          * {@link MidiDeviceFrame} が閉じたときにケーブルを再描画するためのリスナー
71          */
72         public final InternalFrameListener midiDeviceFrameListener = new InternalFrameAdapter() {
73                 @Override
74                 public void internalFrameClosed(InternalFrameEvent e) { repaint(); }
75                 @Override
76                 public void internalFrameDeactivated(InternalFrameEvent e) { repaint(); }
77                 @Override
78                 public void internalFrameClosing(InternalFrameEvent e) {
79                         JInternalFrame frame = e.getInternalFrame();
80                         if( ! (frame instanceof MidiDeviceFrame) ) return;
81                         MidiDeviceFrame f = (MidiDeviceFrame)frame;
82                         MidiDeviceModel m = f.getMidiDeviceModel();
83                         List<Receiver> rxList = m.getMidiDevice().getReceivers();
84                         for( Receiver rx : rxList ) colorMap.remove(rx);
85                         repaint();
86                 }
87         };
88         /**
89          * {@link MidiDeviceModel} における {@link Transmitter}
90          * の増減や状態変更があった場合にケーブルを再描画するためのリスナー
91          */
92         public final ListDataListener midiConnecterListDataListener = new ListDataListener() {
93                 @Override
94                 public void contentsChanged(ListDataEvent e) { repaint(); }
95                 @Override
96                 public void intervalAdded(ListDataEvent e) { repaint(); }
97                 @Override
98                 public void intervalRemoved(ListDataEvent e) { repaint(); }
99         };
100
101         private MidiOpenedDevicesView desktopPane;
102         public MidiCablePane(MidiOpenedDevicesView desktopPane) {
103                 this.desktopPane = desktopPane;
104                 setOpaque(false);
105                 setVisible(true);
106         }
107
108         private static final Stroke CABLE_STROKE = new BasicStroke(
109                         3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
110         private static final List<Color> CABLE_COLORS = Arrays.asList(
111                 new Color(255, 0, 0,144),
112                 new Color(0, 255, 0,144),
113                 new Color(0, 0, 255,144),
114                 new Color(191,191,0,144),
115                 new Color(0,191,191,144),
116                 new Color(191,0,191,144)
117         );
118         private static final Color ADDING_CABLE_COLOR = new Color(0, 0, 0, 144);
119         private static final Color REMOVING_CABLE_COLOR = new Color(128, 128, 128, 144);
120         private Hashtable<Receiver,Color> colorMap = new Hashtable<>();
121         private Color colorOf(Receiver rx) {
122                 Color color = colorMap.get(rx);
123                 if( color == null ) {
124                         for( Color c : CABLE_COLORS ) {
125                                 if( ! colorMap.containsValue(c) ) {
126                                         colorMap.put(rx, c);
127                                         return c;
128                                 }
129                         }
130                         color = CABLE_COLORS.get((int)( Math.random() * CABLE_COLORS.size() ));
131                         colorMap.put(rx, color);
132                 }
133                 return color;
134         }
135         @Override
136         public void paint(Graphics g) {
137                 super.paint(g);
138                 Graphics2D g2 = (Graphics2D)g;
139                 g2.setStroke(CABLE_STROKE);
140                 JInternalFrame[] frames = desktopPane.getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER);
141                 for( JInternalFrame frame : frames ) {
142                         if( ! (frame instanceof MidiDeviceFrame) ) continue;
143                         MidiDeviceFrame fromFrame = (MidiDeviceFrame)frame;
144                         MidiDeviceModel fromDeviceModel = fromFrame.getMidiDeviceModel();
145                         //
146                         // Receiverからドラッグされている線を描画
147                         if( draggingPoint != null && fromDeviceModel.getMidiDevice().getReceivers().contains(dragging.getData()) ) {
148                                 Receiver rx = (Receiver)dragging.getData();
149                                 Rectangle rxBounds = fromFrame.getBoundsOf(rx);
150                                 if( rxBounds == null ) continue;
151                                 int r = (rxBounds.height - 5) / 2;
152                                 rxBounds.translate(r+4, r+4);
153                                 g2.setColor(colorOf(rx));
154                                 g2.drawLine(rxBounds.x, rxBounds.y, draggingPoint.x, draggingPoint.y);
155                         }
156                         // Transmitterを全部スキャン
157                         TransmitterListModel txListModel = fromDeviceModel.getTransmitterListModel();
158                         int ntx = txListModel == null ? 0 : txListModel.getSize();
159                         for( int index=0 ; index < ntx; index++ ) {
160                                 Transmitter tx = txListModel.getElementAt(index);
161                                 //
162                                 // Transmitterの場所を特定
163                                 Rectangle txBounds = fromFrame.getBoundsOf(tx);
164                                 if( txBounds == null ) continue;
165                                 int r = (txBounds.height - 5) / 2;
166                                 txBounds.translate(r+4, r+4);
167                                 //
168                                 // Transmitterに現在接続されているReceiverを把握
169                                 Receiver rx = tx.getReceiver();
170                                 if( draggingPoint != null && tx.equals(dragging.getData()) ) {
171                                         //
172                                         // Transmitterからドラッグされている線を描画
173                                         g2.setColor(rx == null ? ADDING_CABLE_COLOR : colorOf(rx));
174                                         g2.drawLine(txBounds.x, txBounds.y, draggingPoint.x, draggingPoint.y);
175                                 }
176                                 if( rx == null ) continue;
177                                 for( JInternalFrame toFrame : frames ) {
178                                         if( ! (toFrame instanceof MidiDeviceFrame) ) continue;
179                                         //
180                                         // Receiverの場所を特定
181                                         Rectangle rxBounds = ((MidiDeviceFrame)toFrame).getBoundsOf(rx);
182                                         if( rxBounds == null ) continue;
183                                         r = (rxBounds.height - 5) / 2;
184                                         rxBounds.translate(r+4, r+4);
185                                         //
186                                         // Transmitter⇔Receiver間の線を描画
187                                         g2.setColor(tx.equals(dragging.getData()) ? REMOVING_CABLE_COLOR : colorOf(rx));
188                                         g2.drawLine(txBounds.x, txBounds.y, rxBounds.x, rxBounds.y);
189                                         break;
190                                 }
191                         }
192                 }
193         }
194 }