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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1329 - (hide annotations) (download)
Sat Sep 8 18:33:05 2007 UTC (16 years, 8 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 iliev 1286 /*
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 iliev 1329 if(getSelectionCount() == 0) return;
449 iliev 1286 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