/[svn]/jsampler/trunk/src/org/jsampler/view/classic/MidiInstrumentTree.java
ViewVC logotype

Contents of /jsampler/trunk/src/org/jsampler/view/classic/MidiInstrumentTree.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1204 - (show annotations) (download)
Thu May 24 21:43:45 2007 UTC (16 years, 10 months ago) by iliev
File size: 12886 byte(s)
upgrading to version 0.5a

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

  ViewVC Help
Powered by ViewVC