/[svn]/jsampler/trunk/src/org/jsampler/view/std/JSMidiInstrumentTree.java
ViewVC logotype

Contents of /jsampler/trunk/src/org/jsampler/view/std/JSMidiInstrumentTree.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1329 - (show annotations) (download)
Sat Sep 8 18:33:05 2007 UTC (16 years, 7 months ago) by iliev
File size: 12646 byte(s)
* Implemented some UI enhancements for speeding up
  the MIDI instrument mapping process
* some minor bugfixes

1 /*
2 * JSampler - a java front-end for LinuxSampler
3 *
4 * Copyright (C) 2005-2007 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.event.ActionEvent;
26 import java.awt.event.ActionListener;
27 import java.awt.event.MouseAdapter;
28 import java.awt.event.MouseEvent;
29
30 import javax.swing.JMenuItem;
31 import javax.swing.JPopupMenu;
32 import javax.swing.JTree;
33
34 import javax.swing.event.TreeSelectionEvent;
35 import javax.swing.event.TreeSelectionListener;
36
37 import javax.swing.tree.DefaultMutableTreeNode;
38 import javax.swing.tree.DefaultTreeModel;
39 import javax.swing.tree.TreeSelectionModel;
40
41 import org.jsampler.CC;
42 import org.jsampler.HF;
43 import org.jsampler.MidiInstrument;
44 import org.jsampler.MidiInstrumentMap;
45
46 import org.jsampler.event.MidiInstrumentEvent;
47 import org.jsampler.event.MidiInstrumentListener;
48 import org.jsampler.event.MidiInstrumentMapEvent;
49 import org.jsampler.event.MidiInstrumentMapListener;
50
51 import org.linuxsampler.lscp.MidiInstrumentInfo;
52 import org.linuxsampler.lscp.MidiInstrumentMapInfo;
53
54 import static org.jsampler.view.std.StdI18n.i18n;
55
56
57 /**
58 *
59 * @author Grigor Iliev
60 */
61 public class JSMidiInstrumentTree extends JTree {
62 private DefaultTreeModel model;
63 private MidiInstrumentMap midiInstrumentMap;
64
65 /**
66 * Creates a new instance of <code>JSMidiInstrumentTree</code>
67 */
68 public
69 JSMidiInstrumentTree() {
70 setRootVisible(false);
71 setShowsRootHandles(true);
72 setEditable(false);
73
74 addMouseListener(new MouseAdapter() {
75 public void
76 mousePressed(MouseEvent e) {
77 if(e.getButton() != e.BUTTON3) return;
78 setSelectionPath(getClosestPathForLocation(e.getX(), e.getY()));
79 }
80
81 public void
82 mouseClicked(MouseEvent e) {
83 if(e.getButton() != e.BUTTON1) return;
84 if(e.getClickCount() > 1) editSelectedInstrument();
85 }
86 });
87
88 setMidiInstrumentMap(null);
89
90 getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
91 ContextMenu contextMenu = new ContextMenu();
92 addMouseListener(contextMenu);
93 addTreeSelectionListener(contextMenu);
94 }
95
96 /**
97 * Gets the MIDI instrument map that is represented by this MIDI instrument tree.
98 * @return The MIDI instrument map that is represented by this MIDI instrument tree.
99 */
100 public MidiInstrumentMap
101 getMidiInstrumentMap() { return midiInstrumentMap; }
102
103 /**
104 * Sets the MIDI instrument map to be represented by this MIDI instrument tree.
105 * @param map The MIDI instrument map to be represented by this MIDI instrument tree.
106 */
107 public void
108 setMidiInstrumentMap(MidiInstrumentMap map) {
109 if(getMidiInstrumentMap() != null) {
110 for(MidiInstrument instr : getMidiInstrumentMap().getAllMidiInstruments()) {
111 instr.removeMidiInstrumentListener(getHandler());
112 }
113
114 getMidiInstrumentMap().removeMidiInstrumentMapListener(getHandler());
115 }
116
117 midiInstrumentMap = map;
118
119 DefaultMutableTreeNode root = new DefaultMutableTreeNode() {
120 public boolean
121 isLeaf() { return false; }
122
123 public Object
124 getUserObject() { return "/"; }
125 };
126
127 model = new DefaultTreeModel(root);
128
129 if(map != null) {
130 for(MidiInstrument instr : map.getAllMidiInstruments()) {
131 mapInstrument(instr);
132 instr.addMidiInstrumentListener(getHandler());
133 }
134
135 map.addMidiInstrumentMapListener(getHandler());
136 }
137
138 setEnabled(map != null);
139
140 setModel(model);
141 }
142
143 /**
144 * Adds the specified MIDI instrument to this tree.
145 * @param instr The MIDI instrument to add.
146 */
147 public void
148 mapInstrument(MidiInstrument instr) {
149 MidiBank bank = new MidiBank(instr.getInfo().getMidiBank());
150 DefaultMutableTreeNode bankNode = findBank(bank);
151
152 if(bankNode == null) {
153 bankNode = new BankTreeNode(bank);
154
155 model.insertNodeInto (
156 bankNode,
157 (DefaultMutableTreeNode)model.getRoot(),
158 findBankPosition(bank.getID())
159 );
160 }
161
162 model.insertNodeInto (
163 new InstrTreeNode(instr),
164 bankNode,
165 removeProgram(bankNode, instr.getInfo().getMidiProgram())
166 );
167 }
168
169 /**
170 * Removes the specified MIDI instrument from the tree.
171 * @param instr The MIDI instrument to remove.
172 * @throws IllegalArgumentException If the specified instrument is not found.
173 */
174 public void
175 unmapInstrument(MidiInstrument instr) {
176 MidiBank bank = new MidiBank(instr.getInfo().getMidiBank());
177 DefaultMutableTreeNode bankNode = findBank(bank);
178
179 if(bankNode == null)
180 throw new IllegalArgumentException("Missing MIDI bank: " + bank.getID());
181
182 removeProgram(bankNode, instr.getInfo().getMidiProgram());
183 if(bankNode.getChildCount() == 0) model.removeNodeFromParent(bankNode);
184 }
185
186 /**
187 * Gets the selected MIDI instrument.
188 * @return The selected MIDI instrument, or
189 * <code>null</code> if there is no MIDI instrument selected.
190 */
191 public MidiInstrument
192 getSelectedInstrument() {
193 if(getSelectionCount() == 0) return null;
194 Object obj = getSelectionPath().getLastPathComponent();
195 if(!(obj instanceof InstrTreeNode)) return null;
196 obj = ((InstrTreeNode)obj).getUserObject();
197 return (MidiInstrument)obj;
198 }
199
200 /**
201 * Removes (on the backend side) the selected MIDI instrument or MIDI bank.
202 */
203 public void
204 removeSelectedInstrumentOrBank() {
205 if(getSelectionCount() == 0) return;
206
207 Object obj = getSelectionPath().getLastPathComponent();
208 if(obj instanceof InstrTreeNode) {
209 obj = ((InstrTreeNode)obj).getUserObject();
210 removeInstrument((MidiInstrument)obj);
211 } else if(obj instanceof BankTreeNode) {
212 BankTreeNode n = (BankTreeNode)obj;
213 int c = n.getChildCount();
214 if(c > 1) {
215 String s;
216 s = i18n.getMessage("JSMidiInstrumentTree.removeInstruments?", c);
217 if(!HF.showYesNoDialog(CC.getMainFrame(), s)) return;
218 }
219
220 for(int i = c - 1; i >= 0; i--) {
221 obj = ((InstrTreeNode)n.getChildAt(i)).getUserObject();
222 removeInstrument((MidiInstrument)obj);
223 }
224 }
225 }
226
227 /**
228 * Removes (on the backend side) the specified MIDI instrument.
229 */
230 private void
231 removeInstrument(MidiInstrument instr) {
232 MidiInstrumentInfo i = instr.getInfo();
233 CC.getSamplerModel().unmapBackendMidiInstrument (
234 i.getMapId(), i.getMidiBank(), i.getMidiProgram()
235 );
236 }
237
238 /**
239 * Returns the position, where the specified bank should be inserted.
240 */
241 private int
242 findBankPosition(int bankID) {
243 DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot();
244
245 for(int i = 0; i < root.getChildCount(); i++) {
246 DefaultMutableTreeNode node = (DefaultMutableTreeNode)root.getChildAt(i);
247 MidiBank bank = (MidiBank)node.getUserObject();
248 if(bank.getID() > bankID) return i;
249 }
250
251 return root.getChildCount();
252 }
253
254 /**
255 * If there is already an instrument with MIDI program <code>program</code>,
256 * those instrument is removed from the tree.
257 * @return The position, where the instrument of the specified program should be inserted.
258 */
259 private int
260 removeProgram(DefaultMutableTreeNode bankNode, int program) {
261
262 for(int i = 0; i < bankNode.getChildCount(); i++) {
263 DefaultMutableTreeNode n = (DefaultMutableTreeNode)bankNode.getChildAt(i);
264 MidiInstrument instr = (MidiInstrument)n.getUserObject();
265
266 if(instr.getInfo().getMidiProgram() == program) {
267 model.removeNodeFromParent(n);
268 return i;
269 }
270
271 if(instr.getInfo().getMidiProgram() > program) return i;
272 }
273
274 return bankNode.getChildCount();
275 }
276
277 private DefaultMutableTreeNode
278 findNode(DefaultMutableTreeNode parent, Object obj) {
279 for(int i = 0; i < parent.getChildCount(); i++) {
280 DefaultMutableTreeNode node = (DefaultMutableTreeNode)parent.getChildAt(i);
281 if(node.getUserObject().equals(obj)) return node;
282 }
283
284 return null;
285 }
286
287 private DefaultMutableTreeNode
288 findBank(Object obj) {
289 return findNode((DefaultMutableTreeNode)model.getRoot(), obj);
290 }
291
292 private DefaultMutableTreeNode
293 findInstrument(Object obj) {
294 if(obj == null || !(obj instanceof MidiInstrument)) return null;
295 MidiInstrument i = (MidiInstrument) obj;
296 DefaultMutableTreeNode bank = findBank(new MidiBank(i.getInfo().getMidiBank()));
297 if(bank == null) return null;
298 return findNode(bank, obj);
299 }
300
301
302 private class MidiBank {
303 int id;
304
305 MidiBank(int id) {
306 this.id = id;
307 }
308
309 public int
310 getID() { return id; }
311
312 public boolean
313 equals(Object obj) {
314 if(obj == null) return false;
315 if(!(obj instanceof MidiBank)) return false;
316 if(getID() == ((MidiBank)obj).getID()) return true;
317 return false;
318 }
319
320 public String
321 toString() { return i18n.getLabel("JSMidiInstrumentTree.MidiBank.name", id); }
322 }
323
324 protected class BankTreeNode extends DefaultMutableTreeNode {
325 BankTreeNode(Object obj) {
326 super(obj);
327 }
328
329 public void
330 setUserObject(Object userObject) {
331 if(userObject instanceof MidiBank) {
332 super.setUserObject(userObject);
333 return;
334 }
335
336 // If we are here, this means that tree editing occurs.
337 CC.getLogger().info("MidiInstrumentTree: editing not supported");
338 }
339
340 public boolean
341 isLeaf() { return false; }
342 }
343
344 protected class InstrTreeNode extends DefaultMutableTreeNode {
345 InstrTreeNode(Object obj) {
346 super(obj);
347 }
348
349 public void
350 setUserObject(Object userObject) {
351 if(userObject instanceof MidiInstrument) {
352 super.setUserObject(userObject);
353 return;
354 }
355
356 // If we are here, this means that tree editing occurs.
357 CC.getLogger().info("MidiInstrumentTree: editing not supported");
358 }
359
360 public boolean
361 isLeaf() { return true; }
362 }
363
364 private void
365 editSelectedInstrument() {
366 MidiInstrument i = getSelectedInstrument();
367 if(i == null) return;
368 JSEditMidiInstrumentDlg dlg = new JSEditMidiInstrumentDlg(i.getInfo());
369 dlg.setVisible(true);
370
371 if(dlg.isCancelled()) return;
372
373 MidiInstrumentInfo info = dlg.getInstrument();
374 CC.getSamplerModel().mapBackendMidiInstrument (
375 info.getMapId(), info.getMidiBank(), info.getMidiProgram(), info
376 );
377 }
378
379 private final EventHandler eventHandler = new EventHandler();
380
381 private EventHandler
382 getHandler() { return eventHandler; }
383
384 private class EventHandler implements MidiInstrumentListener, MidiInstrumentMapListener {
385
386 /** Invoked when a MIDI instrument in a MIDI instrument map is changed. */
387 public void
388 instrumentInfoChanged(MidiInstrumentEvent e) {
389 DefaultMutableTreeNode n = findInstrument(e.getSource());
390 if(n != null) model.nodeChanged(n);
391 }
392
393 /** Invoked when the name of MIDI instrument map is changed. */
394 public void nameChanged(MidiInstrumentMapEvent e) { }
395
396 /** Invoked when an instrument is added to a MIDI instrument map. */
397 public void
398 instrumentAdded(MidiInstrumentMapEvent e) {
399 e.getInstrument().addMidiInstrumentListener(getHandler());
400 mapInstrument(e.getInstrument());
401
402 }
403
404 /** Invoked when an instrument is removed from a MIDI instrument map. */
405 public void
406 instrumentRemoved(MidiInstrumentMapEvent e) {
407 unmapInstrument(e.getInstrument());
408 e.getInstrument().removeMidiInstrumentListener(getHandler());
409 }
410 }
411
412 class ContextMenu extends MouseAdapter implements TreeSelectionListener {
413 private final JPopupMenu cmenu = new JPopupMenu();
414 JMenuItem miEdit = new JMenuItem(i18n.getMenuLabel("ContextMenu.edit"));
415
416 ContextMenu() {
417 cmenu.add(miEdit);
418 miEdit.addActionListener(new ActionListener() {
419 public void
420 actionPerformed(ActionEvent e) {
421 editSelectedInstrument();
422 }
423 });
424
425 JMenuItem mi = new JMenuItem(i18n.getMenuLabel("ContextMenu.delete"));
426 cmenu.add(mi);
427 mi.addActionListener(new ActionListener() {
428 public void
429 actionPerformed(ActionEvent e) {
430 removeSelectedInstrumentOrBank();
431 }
432 });
433
434 }
435
436 public void
437 mousePressed(MouseEvent e) {
438 if(e.isPopupTrigger()) show(e);
439 }
440
441 public void
442 mouseReleased(MouseEvent e) {
443 if(e.isPopupTrigger()) show(e);
444 }
445
446 void
447 show(MouseEvent e) {
448 if(getSelectionCount() == 0) return;
449 cmenu.show(e.getComponent(), e.getX(), e.getY());
450 }
451
452 public void
453 valueChanged(TreeSelectionEvent e) {
454 miEdit.setVisible(getSelectedInstrument() != null);
455 }
456 }
457 }

  ViewVC Help
Powered by ViewVC