1 |
/* |
2 |
* JSampler - a java front-end for LinuxSampler |
3 |
* |
4 |
* Copyright (C) 2005-2008 Grigor Iliev <grigor@grigoriliev.com> |
5 |
* |
6 |
* This file is part of JSampler. |
7 |
* |
8 |
* JSampler is free software; you can redistribute it and/or modify |
9 |
* it under the terms of the GNU General Public License version 2 |
10 |
* as published by the Free Software Foundation. |
11 |
* |
12 |
* JSampler is distributed in the hope that it will be useful, |
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
* GNU General Public License for more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License |
18 |
* along with JSampler; if not, write to the Free Software |
19 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
20 |
* MA 02111-1307 USA |
21 |
*/ |
22 |
|
23 |
package org.jsampler.view.std; |
24 |
|
25 |
import java.awt.Dimension; |
26 |
|
27 |
import java.beans.PropertyChangeEvent; |
28 |
import java.beans.PropertyChangeListener; |
29 |
|
30 |
import java.awt.event.ActionEvent; |
31 |
import java.awt.event.ActionListener; |
32 |
import java.awt.event.KeyEvent; |
33 |
import java.awt.event.MouseAdapter; |
34 |
import java.awt.event.MouseEvent; |
35 |
|
36 |
import java.util.Vector; |
37 |
|
38 |
import javax.swing.AbstractAction; |
39 |
import javax.swing.Action; |
40 |
import javax.swing.Box; |
41 |
import javax.swing.BoxLayout; |
42 |
import javax.swing.JComponent; |
43 |
import javax.swing.JLabel; |
44 |
import javax.swing.JMenu; |
45 |
import javax.swing.JMenuItem; |
46 |
import javax.swing.JPanel; |
47 |
import javax.swing.JPopupMenu; |
48 |
import javax.swing.JScrollPane; |
49 |
import javax.swing.JTable; |
50 |
import javax.swing.JTree; |
51 |
import javax.swing.KeyStroke; |
52 |
|
53 |
import javax.swing.event.TreeSelectionEvent; |
54 |
import javax.swing.event.TreeSelectionListener; |
55 |
|
56 |
import javax.swing.tree.DefaultMutableTreeNode; |
57 |
import javax.swing.tree.DefaultTreeModel; |
58 |
import javax.swing.tree.TreeSelectionModel; |
59 |
|
60 |
import org.jsampler.CC; |
61 |
import org.jsampler.HF; |
62 |
import org.jsampler.MidiInstrument; |
63 |
import org.jsampler.MidiInstrumentMap; |
64 |
|
65 |
import org.jsampler.event.MidiInstrumentEvent; |
66 |
import org.jsampler.event.MidiInstrumentListener; |
67 |
import org.jsampler.event.MidiInstrumentMapEvent; |
68 |
import org.jsampler.event.MidiInstrumentMapListener; |
69 |
|
70 |
import org.linuxsampler.lscp.MidiInstrumentInfo; |
71 |
import org.linuxsampler.lscp.MidiInstrumentMapInfo; |
72 |
|
73 |
import net.sf.juife.OkCancelDialog; |
74 |
|
75 |
import static org.jsampler.JSPrefs.FIRST_MIDI_BANK_NUMBER; |
76 |
import static org.jsampler.JSPrefs.FIRST_MIDI_PROGRAM_NUMBER; |
77 |
import static org.jsampler.view.std.StdI18n.i18n; |
78 |
|
79 |
|
80 |
/** |
81 |
* |
82 |
* @author Grigor Iliev |
83 |
*/ |
84 |
public class JSMidiInstrumentTree extends JTree { |
85 |
private DefaultTreeModel model; |
86 |
private MidiInstrumentMap midiInstrumentMap; |
87 |
private final ContextMenu contextMenu; |
88 |
|
89 |
/** |
90 |
* Creates a new instance of <code>JSMidiInstrumentTree</code> |
91 |
*/ |
92 |
public |
93 |
JSMidiInstrumentTree() { |
94 |
setRootVisible(false); |
95 |
setShowsRootHandles(true); |
96 |
setEditable(false); |
97 |
|
98 |
addMouseListener(new MouseAdapter() { |
99 |
public void |
100 |
mousePressed(MouseEvent e) { |
101 |
if(e.getButton() != e.BUTTON3) return; |
102 |
setSelectionPath(getClosestPathForLocation(e.getX(), e.getY())); |
103 |
} |
104 |
|
105 |
public void |
106 |
mouseClicked(MouseEvent e) { |
107 |
if(e.getButton() != e.BUTTON1) return; |
108 |
if(e.getClickCount() > 1) editSelectedInstrument(); |
109 |
} |
110 |
}); |
111 |
|
112 |
setMidiInstrumentMap(null); |
113 |
|
114 |
getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); |
115 |
contextMenu = new ContextMenu(); |
116 |
addMouseListener(contextMenu); |
117 |
|
118 |
addTreeSelectionListener(getHandler()); |
119 |
|
120 |
Action a = new AbstractAction() { |
121 |
public void |
122 |
actionPerformed(ActionEvent e) { |
123 |
removeSelectedInstrumentOrBank(); |
124 |
} |
125 |
}; |
126 |
|
127 |
KeyStroke k = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0); |
128 |
getInputMap(JComponent.WHEN_FOCUSED).put(k, "removeSelectedInstrumentOrBank"); |
129 |
getActionMap().put("removeSelectedInstrumentOrBank", a); |
130 |
|
131 |
String s = FIRST_MIDI_BANK_NUMBER; |
132 |
CC.preferences().addPropertyChangeListener(s, new PropertyChangeListener() { |
133 |
public void |
134 |
propertyChange(PropertyChangeEvent e) { |
135 |
model.reload(); |
136 |
} |
137 |
}); |
138 |
|
139 |
s = FIRST_MIDI_PROGRAM_NUMBER; |
140 |
CC.preferences().addPropertyChangeListener(s, new PropertyChangeListener() { |
141 |
public void |
142 |
propertyChange(PropertyChangeEvent e) { |
143 |
model.reload(); |
144 |
contextMenu.updateChangeProgramMenu(); |
145 |
} |
146 |
}); |
147 |
} |
148 |
|
149 |
/** |
150 |
* Gets the MIDI instrument map that is represented by this MIDI instrument tree. |
151 |
* @return The MIDI instrument map that is represented by this MIDI instrument tree. |
152 |
*/ |
153 |
public MidiInstrumentMap |
154 |
getMidiInstrumentMap() { return midiInstrumentMap; } |
155 |
|
156 |
/** |
157 |
* Sets the MIDI instrument map to be represented by this MIDI instrument tree. |
158 |
* @param map The MIDI instrument map to be represented by this MIDI instrument tree. |
159 |
*/ |
160 |
public void |
161 |
setMidiInstrumentMap(MidiInstrumentMap map) { |
162 |
if(getMidiInstrumentMap() != null) { |
163 |
for(MidiInstrument instr : getMidiInstrumentMap().getAllMidiInstruments()) { |
164 |
instr.removeMidiInstrumentListener(getHandler()); |
165 |
} |
166 |
|
167 |
getMidiInstrumentMap().removeMidiInstrumentMapListener(getHandler()); |
168 |
} |
169 |
|
170 |
midiInstrumentMap = map; |
171 |
|
172 |
DefaultMutableTreeNode root = new DefaultMutableTreeNode() { |
173 |
public boolean |
174 |
isLeaf() { return false; } |
175 |
|
176 |
public Object |
177 |
getUserObject() { return "/"; } |
178 |
}; |
179 |
|
180 |
model = new DefaultTreeModel(root); |
181 |
|
182 |
if(map != null) { |
183 |
for(MidiInstrument instr : map.getAllMidiInstruments()) { |
184 |
mapInstrument(instr); |
185 |
instr.addMidiInstrumentListener(getHandler()); |
186 |
} |
187 |
|
188 |
map.addMidiInstrumentMapListener(getHandler()); |
189 |
} |
190 |
|
191 |
setEnabled(map != null); |
192 |
|
193 |
setModel(model); |
194 |
} |
195 |
|
196 |
/** |
197 |
* Adds the specified MIDI instrument to this tree. |
198 |
* @param instr The MIDI instrument to add. |
199 |
*/ |
200 |
public void |
201 |
mapInstrument(MidiInstrument instr) { |
202 |
MidiBank bank = new MidiBank(instr.getInfo().getMidiBank()); |
203 |
DefaultMutableTreeNode bankNode = findBank(bank); |
204 |
|
205 |
if(bankNode == null) { |
206 |
bankNode = new BankTreeNode(bank); |
207 |
|
208 |
model.insertNodeInto ( |
209 |
bankNode, |
210 |
(DefaultMutableTreeNode)model.getRoot(), |
211 |
findBankPosition(bank.getId()) |
212 |
); |
213 |
} |
214 |
|
215 |
model.insertNodeInto ( |
216 |
new InstrTreeNode(instr), |
217 |
bankNode, |
218 |
removeProgram(bankNode, instr.getInfo().getMidiProgram()) |
219 |
); |
220 |
} |
221 |
|
222 |
/** |
223 |
* Removes the specified MIDI instrument from the tree. |
224 |
* @param instr The MIDI instrument to remove. |
225 |
* @throws IllegalArgumentException If the specified instrument is not found. |
226 |
*/ |
227 |
public void |
228 |
unmapInstrument(MidiInstrument instr) { |
229 |
MidiBank bank = new MidiBank(instr.getInfo().getMidiBank()); |
230 |
DefaultMutableTreeNode bankNode = findBank(bank); |
231 |
|
232 |
if(bankNode == null) |
233 |
throw new IllegalArgumentException("Missing MIDI bank: " + bank.getId()); |
234 |
|
235 |
removeProgram(bankNode, instr.getInfo().getMidiProgram()); |
236 |
if(bankNode.getChildCount() == 0) model.removeNodeFromParent(bankNode); |
237 |
} |
238 |
|
239 |
/** |
240 |
* Gets the selected MIDI instrument. |
241 |
* @return The selected MIDI instrument, or |
242 |
* <code>null</code> if there is no MIDI instrument selected. |
243 |
*/ |
244 |
public MidiInstrument |
245 |
getSelectedInstrument() { |
246 |
if(getSelectionCount() == 0) return null; |
247 |
Object obj = getSelectionPath().getLastPathComponent(); |
248 |
if(!(obj instanceof InstrTreeNode)) return null; |
249 |
obj = ((InstrTreeNode)obj).getUserObject(); |
250 |
return (MidiInstrument)obj; |
251 |
} |
252 |
|
253 |
/** |
254 |
* Gets the selected MIDI bank. |
255 |
* @return The selected MIDI bank, or |
256 |
* <code>null</code> if there is no MIDI bank selected. |
257 |
*/ |
258 |
public MidiBank |
259 |
getSelectedMidiBank() { |
260 |
if(getSelectionCount() == 0) return null; |
261 |
|
262 |
Object obj = getSelectionPath().getLastPathComponent(); |
263 |
if(!(obj instanceof BankTreeNode)) return null; |
264 |
|
265 |
BankTreeNode n = (BankTreeNode)obj; |
266 |
return (MidiBank)n.getUserObject(); |
267 |
} |
268 |
|
269 |
/** |
270 |
* Removes (on the backend side) the selected MIDI instrument or MIDI bank. |
271 |
*/ |
272 |
public void |
273 |
removeSelectedInstrumentOrBank() { |
274 |
if(getSelectionCount() == 0) return; |
275 |
|
276 |
Object obj = getSelectionPath().getLastPathComponent(); |
277 |
if(obj instanceof InstrTreeNode) { |
278 |
obj = ((InstrTreeNode)obj).getUserObject(); |
279 |
removeInstrument((MidiInstrument)obj); |
280 |
} else if(obj instanceof BankTreeNode) { |
281 |
BankTreeNode n = (BankTreeNode)obj; |
282 |
int c = n.getChildCount(); |
283 |
if(c > 1) { |
284 |
String s; |
285 |
s = i18n.getMessage("JSMidiInstrumentTree.removeInstruments?", c); |
286 |
if(!HF.showYesNoDialog(CC.getMainFrame(), s)) return; |
287 |
} |
288 |
|
289 |
for(int i = c - 1; i >= 0; i--) { |
290 |
obj = ((InstrTreeNode)n.getChildAt(i)).getUserObject(); |
291 |
removeInstrument((MidiInstrument)obj); |
292 |
} |
293 |
} |
294 |
} |
295 |
|
296 |
/** |
297 |
* Removes (on the backend side) the specified MIDI instrument. |
298 |
*/ |
299 |
private void |
300 |
removeInstrument(MidiInstrument instr) { |
301 |
MidiInstrumentInfo i = instr.getInfo(); |
302 |
CC.getSamplerModel().unmapBackendMidiInstrument ( |
303 |
i.getMapId(), i.getMidiBank(), i.getMidiProgram() |
304 |
); |
305 |
} |
306 |
|
307 |
/** |
308 |
* Returns the position, where the specified bank should be inserted. |
309 |
*/ |
310 |
private int |
311 |
findBankPosition(int bankID) { |
312 |
DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot(); |
313 |
|
314 |
for(int i = 0; i < root.getChildCount(); i++) { |
315 |
DefaultMutableTreeNode node = (DefaultMutableTreeNode)root.getChildAt(i); |
316 |
MidiBank bank = (MidiBank)node.getUserObject(); |
317 |
if(bank.getId() > bankID) return i; |
318 |
} |
319 |
|
320 |
return root.getChildCount(); |
321 |
} |
322 |
|
323 |
/** |
324 |
* If there is already an instrument with MIDI program <code>program</code>, |
325 |
* those instrument is removed from the tree. |
326 |
* @return The position, where the instrument of the specified program should be inserted. |
327 |
*/ |
328 |
private int |
329 |
removeProgram(DefaultMutableTreeNode bankNode, int program) { |
330 |
|
331 |
for(int i = 0; i < bankNode.getChildCount(); i++) { |
332 |
DefaultMutableTreeNode n = (DefaultMutableTreeNode)bankNode.getChildAt(i); |
333 |
MidiInstrument instr = (MidiInstrument)n.getUserObject(); |
334 |
|
335 |
if(instr.getInfo().getMidiProgram() == program) { |
336 |
model.removeNodeFromParent(n); |
337 |
return i; |
338 |
} |
339 |
|
340 |
if(instr.getInfo().getMidiProgram() > program) return i; |
341 |
} |
342 |
|
343 |
return bankNode.getChildCount(); |
344 |
} |
345 |
|
346 |
private DefaultMutableTreeNode |
347 |
findNode(DefaultMutableTreeNode parent, Object obj) { |
348 |
for(int i = 0; i < parent.getChildCount(); i++) { |
349 |
DefaultMutableTreeNode node = (DefaultMutableTreeNode)parent.getChildAt(i); |
350 |
if(node.getUserObject().equals(obj)) return node; |
351 |
} |
352 |
|
353 |
return null; |
354 |
} |
355 |
|
356 |
private DefaultMutableTreeNode |
357 |
findBank(Object obj) { |
358 |
return findNode((DefaultMutableTreeNode)model.getRoot(), obj); |
359 |
} |
360 |
|
361 |
private DefaultMutableTreeNode |
362 |
findInstrument(Object obj) { |
363 |
if(obj == null || !(obj instanceof MidiInstrument)) return null; |
364 |
MidiInstrument i = (MidiInstrument) obj; |
365 |
DefaultMutableTreeNode bank = findBank(new MidiBank(i.getInfo().getMidiBank())); |
366 |
if(bank == null) return null; |
367 |
return findNode(bank, obj); |
368 |
} |
369 |
|
370 |
|
371 |
private class MidiBank { |
372 |
private int id; |
373 |
|
374 |
MidiBank(int id) { |
375 |
this.id = id; |
376 |
} |
377 |
|
378 |
public int |
379 |
getId() { return id; } |
380 |
|
381 |
public boolean |
382 |
equals(Object obj) { |
383 |
if(obj == null) return false; |
384 |
if(!(obj instanceof MidiBank)) return false; |
385 |
if(getId() == ((MidiBank)obj).getId()) return true; |
386 |
return false; |
387 |
} |
388 |
|
389 |
public String |
390 |
toString() { |
391 |
int i = CC.getViewConfig().getFirstMidiBankNumber(); |
392 |
return i18n.getLabel("JSMidiInstrumentTree.MidiBank.name", i + id); |
393 |
} |
394 |
} |
395 |
|
396 |
protected class BankTreeNode extends DefaultMutableTreeNode { |
397 |
BankTreeNode(Object obj) { |
398 |
super(obj); |
399 |
} |
400 |
|
401 |
public void |
402 |
setUserObject(Object userObject) { |
403 |
if(userObject instanceof MidiBank) { |
404 |
super.setUserObject(userObject); |
405 |
return; |
406 |
} |
407 |
|
408 |
// If we are here, this means that tree editing occurs. |
409 |
CC.getLogger().info("MidiInstrumentTree: editing not supported"); |
410 |
} |
411 |
|
412 |
public boolean |
413 |
isLeaf() { return false; } |
414 |
} |
415 |
|
416 |
protected class InstrTreeNode extends DefaultMutableTreeNode { |
417 |
InstrTreeNode(Object obj) { |
418 |
super(obj); |
419 |
} |
420 |
|
421 |
public void |
422 |
setUserObject(Object userObject) { |
423 |
if(userObject instanceof MidiInstrument) { |
424 |
super.setUserObject(userObject); |
425 |
return; |
426 |
} |
427 |
|
428 |
// If we are here, this means that tree editing occurs. |
429 |
CC.getLogger().info("MidiInstrumentTree: editing not supported"); |
430 |
} |
431 |
|
432 |
public boolean |
433 |
isLeaf() { return true; } |
434 |
} |
435 |
|
436 |
private void |
437 |
editSelectedInstrument() { |
438 |
MidiInstrument i = getSelectedInstrument(); |
439 |
if(i == null) return; |
440 |
JSEditMidiInstrumentDlg dlg = new JSEditMidiInstrumentDlg(i.getInfo()); |
441 |
dlg.setVisible(true); |
442 |
|
443 |
if(dlg.isCancelled()) return; |
444 |
|
445 |
MidiInstrumentInfo info = dlg.getInstrument(); |
446 |
CC.getSamplerModel().mapBackendMidiInstrument ( |
447 |
info.getMapId(), info.getMidiBank(), info.getMidiProgram(), info |
448 |
); |
449 |
} |
450 |
|
451 |
private void |
452 |
copyMidiBankTo() { copyOrMoveMidiBankTo(true); } |
453 |
|
454 |
private void |
455 |
moveMidiBankTo() { copyOrMoveMidiBankTo(false); } |
456 |
|
457 |
private void |
458 |
copyOrMoveMidiBankTo(boolean copy) { |
459 |
MidiBank bank = getSelectedMidiBank(); |
460 |
if(bank == null) return; |
461 |
|
462 |
JSMidiBankChooser dlg = new JSMidiBankChooser(); |
463 |
|
464 |
if(copy) dlg.setTitle(i18n.getLabel("JSMidiInstrumentTree.copyTo")); |
465 |
else dlg.setTitle(i18n.getLabel("JSMidiInstrumentTree.moveTo")); |
466 |
|
467 |
dlg.setSelectedMidiInstrumentMap(getMidiInstrumentMap()); |
468 |
dlg.setVisible(true); |
469 |
if(dlg.isCancelled()) return; |
470 |
|
471 |
MidiInstrumentMap smap = dlg.getSelectedMidiInstrumentMap(); |
472 |
|
473 |
if(smap == null) { |
474 |
HF.showErrorMessage(i18n.getMessage("JSMidiInstrumentTree.noMap!"), this); |
475 |
return; |
476 |
} |
477 |
|
478 |
if(dlg.getMidiBank() == bank.getId() && smap.getMapId() == getMidiInstrumentMap().getMapId()) { |
479 |
String s = "JSMidiInstrumentTree.sameSourceAndDestination!"; |
480 |
HF.showErrorMessage(i18n.getMessage(s), this); |
481 |
return; |
482 |
} |
483 |
|
484 |
MidiInstrument[] instrs = getMidiInstrumentMap().getMidiInstruments(bank.getId()); |
485 |
int mapId = smap.getMapId(); |
486 |
int bnkId = dlg.getMidiBank(); |
487 |
|
488 |
Vector<MidiInstrument> v = new Vector<MidiInstrument>(); |
489 |
for(MidiInstrument i : instrs) { |
490 |
MidiInstrument instr; |
491 |
instr = smap.getMidiInstrument(bnkId, i.getInfo().getMidiProgram()); |
492 |
if(instr != null) v.add(instr); |
493 |
} |
494 |
|
495 |
if(!v.isEmpty()) { |
496 |
String[] instrumentNames = new String[v.size()]; |
497 |
for(int i = 0; i < v.size(); i++) { |
498 |
int base = CC.getViewConfig().getFirstMidiProgramNumber(); |
499 |
int p = v.get(i).getInfo().getMidiProgram(); |
500 |
instrumentNames[i] = (base + p) + ". " + v.get(i).getName(); |
501 |
} |
502 |
JSOverrideInstrumentsConfirmDlg dlg2; |
503 |
dlg2 = new JSOverrideInstrumentsConfirmDlg(instrumentNames); |
504 |
dlg2.setVisible(true); |
505 |
if(dlg2.isCancelled()) return; |
506 |
} |
507 |
|
508 |
for(MidiInstrument i : instrs) { |
509 |
int p = i.getInfo().getMidiProgram(); |
510 |
CC.getSamplerModel().mapBackendMidiInstrument(mapId, bnkId, p, i.getInfo()); |
511 |
} |
512 |
|
513 |
if(copy) return; |
514 |
|
515 |
mapId = getMidiInstrumentMap().getMapId(); |
516 |
bnkId = bank.getId(); |
517 |
|
518 |
for(MidiInstrument i : instrs) { |
519 |
int p = i.getInfo().getMidiProgram(); |
520 |
CC.getSamplerModel().unmapBackendMidiInstrument(mapId, bnkId, p); |
521 |
} |
522 |
} |
523 |
|
524 |
private void |
525 |
copyMidiInstrumentTo() { copyOrMoveMidiInstrumentTo(true); } |
526 |
|
527 |
private void |
528 |
moveMidiInstrumentTo() { copyOrMoveMidiInstrumentTo(false); } |
529 |
|
530 |
private void |
531 |
copyOrMoveMidiInstrumentTo(boolean copy) { |
532 |
MidiInstrument instr = getSelectedInstrument(); |
533 |
if(instr == null) return; |
534 |
|
535 |
JSMidiBankChooser dlg = new JSMidiBankChooser(); |
536 |
|
537 |
if(copy) dlg.setTitle(i18n.getLabel("JSMidiInstrumentTree.copyTo")); |
538 |
else dlg.setTitle(i18n.getLabel("JSMidiInstrumentTree.moveTo")); |
539 |
|
540 |
dlg.setSelectedMidiInstrumentMap(getMidiInstrumentMap()); |
541 |
dlg.setVisible(true); |
542 |
if(dlg.isCancelled()) return; |
543 |
|
544 |
MidiInstrumentMap smap = dlg.getSelectedMidiInstrumentMap(); |
545 |
|
546 |
if(smap == null) { |
547 |
HF.showErrorMessage(i18n.getMessage("JSMidiInstrumentTree.noMap!"), this); |
548 |
return; |
549 |
} |
550 |
|
551 |
int bank = instr.getInfo().getMidiBank(); |
552 |
if(dlg.getMidiBank() == bank && smap.getMapId() == getMidiInstrumentMap().getMapId()) { |
553 |
String s = "JSMidiInstrumentTree.sameSourceAndDestination!"; |
554 |
HF.showErrorMessage(i18n.getMessage(s), this); |
555 |
return; |
556 |
} |
557 |
|
558 |
int mapId = smap.getMapId(); |
559 |
int bnkId = dlg.getMidiBank(); |
560 |
int prgId = instr.getInfo().getMidiProgram(); |
561 |
MidiInstrument oldInstr = smap.getMidiInstrument(bnkId, prgId); |
562 |
|
563 |
if(oldInstr != null) { |
564 |
String[] iS = new String [1]; |
565 |
int base = CC.getViewConfig().getFirstMidiProgramNumber(); |
566 |
iS[0] = (base + prgId) + ". " + oldInstr.getName(); |
567 |
JSOverrideInstrumentsConfirmDlg dlg2; |
568 |
dlg2 = new JSOverrideInstrumentsConfirmDlg(iS); |
569 |
dlg2.setVisible(true); |
570 |
if(dlg2.isCancelled()) return; |
571 |
} |
572 |
|
573 |
CC.getSamplerModel().mapBackendMidiInstrument(mapId, bnkId, prgId, instr.getInfo()); |
574 |
|
575 |
if(copy) return; |
576 |
|
577 |
mapId = getMidiInstrumentMap().getMapId(); |
578 |
|
579 |
CC.getSamplerModel().unmapBackendMidiInstrument(mapId, bank, prgId); |
580 |
} |
581 |
|
582 |
private void |
583 |
moveSelectedInstrumentUp() { |
584 |
MidiInstrument instr = getSelectedInstrument(); |
585 |
if(instr == null) return; |
586 |
moveSelectedInstrument(instr.getInfo().getMidiProgram() - 1); |
587 |
} |
588 |
|
589 |
private void |
590 |
moveSelectedInstrumentDown() { |
591 |
MidiInstrument instr = getSelectedInstrument(); |
592 |
if(instr == null) return; |
593 |
moveSelectedInstrument(instr.getInfo().getMidiProgram() + 1); |
594 |
} |
595 |
|
596 |
private void |
597 |
moveSelectedInstrument(int newProgram) { |
598 |
if(newProgram < 0 || newProgram > 127) return; |
599 |
MidiInstrument instr = getSelectedInstrument(); |
600 |
if(instr == null) return; |
601 |
|
602 |
int bnk = instr.getInfo().getMidiBank(); |
603 |
int prg = instr.getInfo().getMidiProgram(); |
604 |
|
605 |
MidiInstrument oldInstr = getMidiInstrumentMap().getMidiInstrument(bnk, newProgram); |
606 |
if(oldInstr != null) { |
607 |
String[] iS = new String [1]; |
608 |
int base = CC.getViewConfig().getFirstMidiProgramNumber(); |
609 |
iS[0] = (base + prg) + ". " + oldInstr.getName(); |
610 |
JSOverrideInstrumentsConfirmDlg dlg; |
611 |
dlg = new JSOverrideInstrumentsConfirmDlg(iS); |
612 |
dlg.setVisible(true); |
613 |
if(dlg.isCancelled()) return; |
614 |
} |
615 |
|
616 |
int map = this.getMidiInstrumentMap().getMapId(); |
617 |
CC.getSamplerModel().mapBackendMidiInstrument(map, bnk, newProgram, instr.getInfo()); |
618 |
CC.getSamplerModel().unmapBackendMidiInstrument(map, bnk, prg); |
619 |
} |
620 |
|
621 |
private final EventHandler eventHandler = new EventHandler(); |
622 |
|
623 |
private EventHandler |
624 |
getHandler() { return eventHandler; } |
625 |
|
626 |
private class EventHandler implements MidiInstrumentListener, MidiInstrumentMapListener, |
627 |
TreeSelectionListener { |
628 |
|
629 |
/** Invoked when a MIDI instrument in a MIDI instrument map is changed. */ |
630 |
public void |
631 |
instrumentInfoChanged(MidiInstrumentEvent e) { |
632 |
DefaultMutableTreeNode n = findInstrument(e.getSource()); |
633 |
if(n != null) model.nodeChanged(n); |
634 |
} |
635 |
|
636 |
/** Invoked when the name of MIDI instrument map is changed. */ |
637 |
public void nameChanged(MidiInstrumentMapEvent e) { } |
638 |
|
639 |
/** Invoked when an instrument is added to a MIDI instrument map. */ |
640 |
public void |
641 |
instrumentAdded(MidiInstrumentMapEvent e) { |
642 |
e.getInstrument().addMidiInstrumentListener(getHandler()); |
643 |
mapInstrument(e.getInstrument()); |
644 |
|
645 |
} |
646 |
|
647 |
/** Invoked when an instrument is removed from a MIDI instrument map. */ |
648 |
public void |
649 |
instrumentRemoved(MidiInstrumentMapEvent e) { |
650 |
unmapInstrument(e.getInstrument()); |
651 |
e.getInstrument().removeMidiInstrumentListener(getHandler()); |
652 |
} |
653 |
|
654 |
public void |
655 |
valueChanged(TreeSelectionEvent e) { |
656 |
MidiInstrument instr = getSelectedInstrument(); |
657 |
if(instr != null) { |
658 |
int p = instr.getInfo().getMidiProgram(); |
659 |
contextMenu.miMoveInstrumentDown.setEnabled(p < 127); |
660 |
contextMenu.miMoveInstrumentUp.setEnabled(p > 0); |
661 |
} |
662 |
} |
663 |
} |
664 |
|
665 |
class ContextMenu extends MouseAdapter { |
666 |
private final JPopupMenu bankMenu = new JPopupMenu(); |
667 |
|
668 |
private final JPopupMenu instrumentMenu = new JPopupMenu(); |
669 |
|
670 |
private final JMenu changeProgramMenu = |
671 |
new JMenu(i18n.getMenuLabel("JSMidiInstrumentTree.ContextMenu.changeProgram")); |
672 |
|
673 |
private final JMenuItem miMoveInstrumentUp = |
674 |
new JMenuItem(i18n.getMenuLabel("JSMidiInstrumentTree.ContextMenu.moveUp")); |
675 |
|
676 |
private final JMenuItem miMoveInstrumentDown = |
677 |
new JMenuItem(i18n.getMenuLabel("JSMidiInstrumentTree.ContextMenu.moveDown")); |
678 |
|
679 |
private final JMenu programGroup1Menu = new JMenu(); |
680 |
private final JMenu programGroup2Menu = new JMenu(); |
681 |
private final JMenu programGroup3Menu = new JMenu(); |
682 |
private final JMenu programGroup4Menu = new JMenu(); |
683 |
private final JMenu programGroup5Menu = new JMenu(); |
684 |
private final JMenu programGroup6Menu = new JMenu(); |
685 |
private final JMenu programGroup7Menu = new JMenu(); |
686 |
private final JMenu programGroup8Menu = new JMenu(); |
687 |
|
688 |
|
689 |
ContextMenu() { |
690 |
JMenuItem mi = new JMenuItem(i18n.getMenuLabel("JSMidiInstrumentTree.ContextMenu.moveTo")); |
691 |
bankMenu.add(mi); |
692 |
mi.addActionListener(new ActionListener() { |
693 |
public void |
694 |
actionPerformed(ActionEvent e) { |
695 |
moveMidiBankTo(); |
696 |
} |
697 |
}); |
698 |
|
699 |
mi = new JMenuItem(i18n.getMenuLabel("JSMidiInstrumentTree.ContextMenu.copyTo")); |
700 |
bankMenu.add(mi); |
701 |
mi.addActionListener(new ActionListener() { |
702 |
public void |
703 |
actionPerformed(ActionEvent e) { |
704 |
copyMidiBankTo(); |
705 |
} |
706 |
}); |
707 |
|
708 |
bankMenu.addSeparator(); |
709 |
|
710 |
mi = new JMenuItem(i18n.getMenuLabel("ContextMenu.delete")); |
711 |
bankMenu.add(mi); |
712 |
mi.addActionListener(new ActionListener() { |
713 |
public void |
714 |
actionPerformed(ActionEvent e) { |
715 |
removeSelectedInstrumentOrBank(); |
716 |
} |
717 |
}); |
718 |
|
719 |
// MIDI Instrument Menu |
720 |
|
721 |
mi = new JMenuItem(i18n.getMenuLabel("ContextMenu.edit")); |
722 |
instrumentMenu.add(mi); |
723 |
mi.addActionListener(new ActionListener() { |
724 |
public void |
725 |
actionPerformed(ActionEvent e) { |
726 |
editSelectedInstrument(); |
727 |
} |
728 |
}); |
729 |
|
730 |
instrumentMenu.addSeparator(); |
731 |
|
732 |
mi = new JMenuItem(i18n.getMenuLabel("JSMidiInstrumentTree.ContextMenu.moveTo")); |
733 |
instrumentMenu.add(mi); |
734 |
mi.addActionListener(new ActionListener() { |
735 |
public void |
736 |
actionPerformed(ActionEvent e) { |
737 |
moveMidiInstrumentTo(); |
738 |
} |
739 |
}); |
740 |
|
741 |
mi = new JMenuItem(i18n.getMenuLabel("JSMidiInstrumentTree.ContextMenu.copyTo")); |
742 |
instrumentMenu.add(mi); |
743 |
mi.addActionListener(new ActionListener() { |
744 |
public void |
745 |
actionPerformed(ActionEvent e) { |
746 |
copyMidiInstrumentTo(); |
747 |
} |
748 |
}); |
749 |
|
750 |
instrumentMenu.add(changeProgramMenu); |
751 |
|
752 |
changeProgramMenu.add(miMoveInstrumentUp); |
753 |
miMoveInstrumentUp.addActionListener(new ActionListener() { |
754 |
public void |
755 |
actionPerformed(ActionEvent e) { |
756 |
moveSelectedInstrumentUp(); |
757 |
} |
758 |
}); |
759 |
|
760 |
changeProgramMenu.add(miMoveInstrumentDown); |
761 |
miMoveInstrumentDown.addActionListener(new ActionListener() { |
762 |
public void |
763 |
actionPerformed(ActionEvent e) { |
764 |
moveSelectedInstrumentDown(); |
765 |
} |
766 |
}); |
767 |
|
768 |
changeProgramMenu.addSeparator(); |
769 |
|
770 |
changeProgramMenu.add(programGroup1Menu); |
771 |
addProgramMenuItems(programGroup1Menu, 0, 15); |
772 |
changeProgramMenu.add(programGroup2Menu); |
773 |
addProgramMenuItems(programGroup2Menu, 16, 31); |
774 |
changeProgramMenu.add(programGroup3Menu); |
775 |
addProgramMenuItems(programGroup3Menu, 32, 47); |
776 |
changeProgramMenu.add(programGroup4Menu); |
777 |
addProgramMenuItems(programGroup4Menu, 48, 63); |
778 |
changeProgramMenu.add(programGroup5Menu); |
779 |
addProgramMenuItems(programGroup5Menu, 64, 79); |
780 |
changeProgramMenu.add(programGroup6Menu); |
781 |
addProgramMenuItems(programGroup6Menu, 80, 95); |
782 |
changeProgramMenu.add(programGroup7Menu); |
783 |
addProgramMenuItems(programGroup7Menu, 96, 111); |
784 |
changeProgramMenu.add(programGroup8Menu); |
785 |
addProgramMenuItems(programGroup8Menu, 112, 127); |
786 |
|
787 |
instrumentMenu.addSeparator(); |
788 |
updateChangeProgramMenu(); |
789 |
|
790 |
mi = new JMenuItem(i18n.getMenuLabel("ContextMenu.delete")); |
791 |
instrumentMenu.add(mi); |
792 |
mi.addActionListener(new ActionListener() { |
793 |
public void |
794 |
actionPerformed(ActionEvent e) { |
795 |
removeSelectedInstrumentOrBank(); |
796 |
} |
797 |
}); |
798 |
|
799 |
} |
800 |
|
801 |
private void |
802 |
addProgramMenuItems(JMenu menu, int prgStart, int prgEnd) { |
803 |
for(int i = prgStart; i <= prgEnd; i++) { |
804 |
menu.add(new ProgramMenuItem(i)); |
805 |
} |
806 |
} |
807 |
|
808 |
private void |
809 |
updateChangeProgramMenu() { |
810 |
updateProgramGroupMenu(programGroup1Menu, 0, 15); |
811 |
updateProgramGroupMenu(programGroup2Menu, 16, 31); |
812 |
updateProgramGroupMenu(programGroup3Menu, 32, 47); |
813 |
updateProgramGroupMenu(programGroup4Menu, 48, 63); |
814 |
updateProgramGroupMenu(programGroup5Menu, 64, 79); |
815 |
updateProgramGroupMenu(programGroup6Menu, 80, 95); |
816 |
updateProgramGroupMenu(programGroup7Menu, 96, 111); |
817 |
updateProgramGroupMenu(programGroup8Menu, 112, 127); |
818 |
} |
819 |
|
820 |
private void |
821 |
updateProgramGroupMenu(JMenu menu, int prgStart, int prgEnd) { |
822 |
int base = CC.getViewConfig().getFirstMidiProgramNumber(); |
823 |
String s = "JSMidiInstrumentTree.ContextMenu.programGroup"; |
824 |
String grp = "(" + (base + prgStart) + "-" + (base + prgEnd) + ")"; |
825 |
menu.setText(i18n.getMenuLabel(s, grp)); |
826 |
|
827 |
updateProgramGroupMenuItems(menu); |
828 |
} |
829 |
|
830 |
private void |
831 |
updateProgramGroupMenuItems(JMenu menu) { |
832 |
for(int i = 0; i < menu.getItemCount(); i++) { |
833 |
((ProgramMenuItem)menu.getItem(i)).updateProgramNumber(); |
834 |
} |
835 |
} |
836 |
|
837 |
public void |
838 |
mousePressed(MouseEvent e) { |
839 |
if(e.isPopupTrigger()) show(e); |
840 |
} |
841 |
|
842 |
public void |
843 |
mouseReleased(MouseEvent e) { |
844 |
if(e.isPopupTrigger()) show(e); |
845 |
} |
846 |
|
847 |
void |
848 |
show(MouseEvent e) { |
849 |
if(getSelectionCount() == 0) return; |
850 |
|
851 |
if(getSelectedInstrument() != null) { |
852 |
instrumentMenu.show(e.getComponent(), e.getX(), e.getY()); |
853 |
} else { |
854 |
bankMenu.show(e.getComponent(), e.getX(), e.getY()); |
855 |
} |
856 |
} |
857 |
|
858 |
private class ProgramMenuItem extends JMenuItem implements ActionListener { |
859 |
int program; |
860 |
|
861 |
ProgramMenuItem(int program) { |
862 |
this.program = program; |
863 |
updateProgramNumber(); |
864 |
addActionListener(this); |
865 |
} |
866 |
|
867 |
public void |
868 |
updateProgramNumber() { |
869 |
int base = CC.getViewConfig().getFirstMidiProgramNumber(); |
870 |
setText(String.valueOf(base + program)); |
871 |
} |
872 |
|
873 |
public void |
874 |
actionPerformed(ActionEvent e) { |
875 |
moveSelectedInstrument(program); |
876 |
} |
877 |
} |
878 |
} |
879 |
} |
880 |
|
881 |
class JSOverrideInstrumentsConfirmDlg extends OkCancelDialog { |
882 |
private final JLabel lMsg = new JLabel(i18n.getMessage("JSOverrideInstrumentsConfirmDlg.lMsg")); |
883 |
private final JTable table; |
884 |
|
885 |
JSOverrideInstrumentsConfirmDlg(String[] instrumentNames) { |
886 |
super(CC.getMainFrame()); |
887 |
|
888 |
JPanel mainPane = new JPanel(); |
889 |
mainPane.setLayout(new BoxLayout(mainPane, BoxLayout.Y_AXIS)); |
890 |
|
891 |
lMsg.setIcon(CC.getViewConfig().getBasicIconSet().getWarning32Icon()); |
892 |
lMsg.setAlignmentX(LEFT_ALIGNMENT); |
893 |
mainPane.add(lMsg); |
894 |
|
895 |
mainPane.add(Box.createRigidArea(new Dimension(0, 12))); |
896 |
|
897 |
String[][] instrs = new String[instrumentNames.length][1]; |
898 |
for(int i = 0; i < instrumentNames.length; i++) { |
899 |
instrs[i][0] = instrumentNames[i]; |
900 |
} |
901 |
|
902 |
String[] columns = new String[1]; |
903 |
columns[0] = ""; |
904 |
|
905 |
table = new JTable(instrs, columns); |
906 |
JScrollPane sp = new JScrollPane(table); |
907 |
Dimension d = new Dimension(200, 200); |
908 |
sp.setMinimumSize(d); |
909 |
sp.setPreferredSize(d); |
910 |
sp.setAlignmentX(LEFT_ALIGNMENT); |
911 |
mainPane.add(sp); |
912 |
|
913 |
setMainPane(mainPane); |
914 |
setMinimumSize(getPreferredSize()); |
915 |
setResizable(true); |
916 |
} |
917 |
|
918 |
protected void |
919 |
onOk() { |
920 |
if(!btnOk.isEnabled()) return; |
921 |
|
922 |
setVisible(false); |
923 |
setCancelled(false); |
924 |
} |
925 |
|
926 |
protected void |
927 |
onCancel() { setVisible(false); } |
928 |
} |