/* * JSampler - a java front-end for LinuxSampler * * Copyright (C) 2005 Grigor Kirilov Iliev * * This file is part of JSampler. * * JSampler is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * JSampler is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JSampler; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ package org.jsampler.view.classic; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.MediaTracker; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.URL; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JToolBar; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; import net.sf.juife.InformationDialog; import net.sf.juife.JuifeUtils; import net.sf.juife.NavigationPage; import org.jsampler.CC; import org.jsampler.MidiDeviceModel; import org.jsampler.event.MidiDeviceEvent; import org.jsampler.event.MidiDeviceListEvent; import org.jsampler.event.MidiDeviceListListener; import org.jsampler.event.MidiDeviceListener; import org.jsampler.event.ParameterEvent; import org.jsampler.event.ParameterListener; import org.jsampler.task.DestroyMidiDevice; import org.jsampler.task.EnableMidiDevice; import org.jsampler.task.SetMidiInputPortCount; import org.jsampler.task.SetMidiPortParameter; import org.jsampler.view.NumberCellEditor; import org.jsampler.view.ParameterTable; import org.linuxsampler.lscp.MidiInputDevice; import org.linuxsampler.lscp.MidiPort; import org.linuxsampler.lscp.Parameter; import static org.jsampler.view.classic.ClassicI18n.i18n; import static org.jsampler.view.classic.MidiDevicesTableModel.*; /** * * @author Grigor Iliev */ public class MidiDevicesPage extends NavigationPage { private final Action duplicateMidiDevice = new DuplicateMidiDevice(); private final Action removeMidiDevice = new RemoveMidiDevice(); private final Action midiDeviceProps = new MidiDeviceProps(); private final ToolbarButton btnNewDevice = new ToolbarButton(A4n.addMidiDevice); private final ToolbarButton btnDuplicateDevice = new ToolbarButton(duplicateMidiDevice); private final ToolbarButton btnRemoveDevice = new ToolbarButton(removeMidiDevice); private final ToolbarButton btnDeviceProps = new ToolbarButton(midiDeviceProps); private final JTable devicesTable = new JTable(new MidiDevicesTableModel()); private final JLabel lPorts = new JLabel(i18n.getLabel("MidiDevicesPage.lPorts")); private final JComboBox cbPorts = new JComboBox(); ParameterTable portParamTable = new ParameterTable(); /** Creates a new instance of MidiDevicesPage */ public MidiDevicesPage() { setTitle(i18n.getLabel("MidiDevicesPage.title")); cbPorts.setEnabled(false); TableColumn tc = devicesTable.getColumnModel().getColumn(ACTIVE_COLUMN_INDEX); tc.setPreferredWidth(tc.getMinWidth()); NumberCellEditor nce = new NumberCellEditor(); nce.setMinimum(0); nce.setMaximum(255); tc = devicesTable.getColumnModel().getColumn(PORTS_COLUMN_INDEX); tc.setCellEditor(nce); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); JToolBar tb = new JToolBar(); tb.setMaximumSize(new Dimension(Short.MAX_VALUE, tb.getPreferredSize().height)); tb.setFloatable(false); tb.setAlignmentX(JPanel.RIGHT_ALIGNMENT); tb.add(btnNewDevice); tb.add(btnDuplicateDevice); tb.add(btnRemoveDevice); tb.addSeparator(); tb.add(btnDeviceProps); add(tb); JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); devicesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); JScrollPane sp = new JScrollPane(devicesTable); JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); p.add(sp); p.add(Box.createRigidArea(new Dimension(0, 8))); splitPane.setTopComponent(p); //add(Box.createRigidArea(new Dimension(0, 12))); JPanel portsPane = new JPanel(); portsPane.setLayout(new BoxLayout(portsPane, BoxLayout.Y_AXIS)); p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); p.add(lPorts); p.add(Box.createRigidArea(new Dimension(5, 0))); p.add(cbPorts); p.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); portsPane.add(p); p = new JPanel(); p.setLayout(new BorderLayout()); p.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); p.add(new JScrollPane(portParamTable)); portsPane.add(p); portsPane.setBorder ( BorderFactory.createTitledBorder(i18n.getLabel("MidiDevicesPage.ports")) ); p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); p.add(Box.createRigidArea(new Dimension(0, 5))); p.add(portsPane); splitPane.setBottomComponent(p); splitPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); splitPane.setAlignmentX(JPanel.RIGHT_ALIGNMENT); splitPane.setDividerSize(3); add(splitPane); splitPane.setDividerLocation(150); cbPorts.addActionListener(getHandler()); devicesTable.getSelectionModel().addListSelectionListener(getHandler()); portParamTable.getModel().addParameterListener(getHandler()); } private MidiDeviceModel getSelectedMidiDeviceModel() { ListSelectionModel lsm = devicesTable.getSelectionModel(); if(lsm.isSelectionEmpty()) return null; return ((MidiDevicesTableModel)devicesTable.getModel()).getMidiDeviceModel ( lsm.getMinSelectionIndex() ); } private final Handler handler = new Handler(); private Handler getHandler() { return handler; } private class Handler implements ActionListener, ListSelectionListener, MidiDeviceListener, ParameterListener { public void actionPerformed(ActionEvent e) { Object obj = cbPorts.getSelectedItem(); if(obj == null) { portParamTable.getModel().setParameters(new Parameter[0]); return; } MidiPort port = (MidiPort)obj; portParamTable.getModel().setParameters(port.getAllParameters()); } public void valueChanged(ListSelectionEvent e) { if(e.getValueIsAdjusting()) return; for(MidiDeviceModel m : CC.getSamplerModel().getMidiDeviceModels()) { m.removeMidiDeviceListener(this); } ListSelectionModel lsm = (ListSelectionModel)e.getSource(); if(lsm.isSelectionEmpty()) { duplicateMidiDevice.setEnabled(false); removeMidiDevice.setEnabled(false); midiDeviceProps.setEnabled(false); cbPorts.removeAllItems(); cbPorts.setEnabled(false); return; } duplicateMidiDevice.setEnabled(true); removeMidiDevice.setEnabled(true); midiDeviceProps.setEnabled(true); MidiDeviceModel m; m = ((MidiDevicesTableModel)devicesTable.getModel()).getMidiDeviceModel ( lsm.getMinSelectionIndex() ); cbPorts.removeAllItems(); for(MidiPort port : m.getDeviceInfo().getMidiPorts()) cbPorts.addItem(port); cbPorts.setEnabled(true); m.addMidiDeviceListener(this); } /** Invoked when when the settings of a particular MIDI device have changed. */ public void settingsChanged(MidiDeviceEvent e) { MidiInputDevice d = e.getMidiDeviceModel().getDeviceInfo(); int idx = cbPorts.getSelectedIndex(); cbPorts.removeAllItems(); for(MidiPort port : d.getMidiPorts()) cbPorts.addItem(port); if(idx >= cbPorts.getModel().getSize()) idx = 0; if(cbPorts.getModel().getSize() > 0) cbPorts.setSelectedIndex(idx); } /** Invoked when when the value of a particular parameter is changed. */ public void parameterChanged(ParameterEvent e) { MidiDeviceModel m = getSelectedMidiDeviceModel(); if(m == null) { CC.getLogger().warning("Unexpected null MidiDeviceModel!"); return; } int port = cbPorts.getSelectedIndex(); if(port == -1) { CC.getLogger().warning("There is no MIDI port selected!"); return; } CC.getTaskQueue().add ( new SetMidiPortParameter(m.getDeviceID(), port, e.getParameter()) ); } } private class DuplicateMidiDevice extends AbstractAction { DuplicateMidiDevice() { super(""); putValue(SHORT_DESCRIPTION, i18n.getMenuLabel("ttDuplicateMidiDevice")); try { URL url = ClassLoader.getSystemClassLoader().getResource ( "org/jsampler/view/classic/res/icons/Copy16.gif" ); ImageIcon icon = new ImageIcon(url); if(icon.getImageLoadStatus() == MediaTracker.COMPLETE) putValue(Action.SMALL_ICON, icon); } catch(Exception x) { CC.getLogger().log(Level.INFO, x.getMessage(), x); } setEnabled(false); } public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog ( CC.getMainFrame(), "Not implemented yet", "", JOptionPane.INFORMATION_MESSAGE ); } } private class RemoveMidiDevice extends AbstractAction { RemoveMidiDevice() { super(""); putValue(SHORT_DESCRIPTION, i18n.getMenuLabel("ttRemoveMidiDevice")); try { URL url = ClassLoader.getSystemClassLoader().getResource ( "org/jsampler/view/classic/res/icons/Delete16.gif" ); ImageIcon icon = new ImageIcon(url); if(icon.getImageLoadStatus() == MediaTracker.COMPLETE) putValue(Action.SMALL_ICON, icon); } catch(Exception x) { CC.getLogger().log(Level.INFO, x.getMessage(), x); } setEnabled(false); } public void actionPerformed(ActionEvent e) { MidiDeviceModel m = getSelectedMidiDeviceModel(); if(m == null) { CC.getLogger().warning("No selected MIDI device to remove!"); return; } CC.getTaskQueue().add(new DestroyMidiDevice(m.getDeviceID())); } } private class MidiDeviceProps extends AbstractAction { MidiDeviceProps() { super(""); putValue(SHORT_DESCRIPTION, i18n.getMenuLabel("ttMidiDeviceProps")); try { URL url = ClassLoader.getSystemClassLoader().getResource ( "org/jsampler/view/classic/res/icons/Properties16.gif" ); ImageIcon icon = new ImageIcon(url); if(icon.getImageLoadStatus() == MediaTracker.COMPLETE) putValue(Action.SMALL_ICON, icon); } catch(Exception x) { CC.getLogger().log(Level.INFO, x.getMessage(), x); } setEnabled(false); } public void actionPerformed(ActionEvent e) { new DevicePropsDlg().setVisible(true); } } private class DevicePropsDlg extends InformationDialog { DevicePropsDlg() { super(CC.getMainFrame(), i18n.getLabel("MidiDevicesPage.DevicePropsDlg")); MidiDeviceModel m = getSelectedMidiDeviceModel(); ParameterTable table = new ParameterTable(); table.getModel().setParameters ( m.getDeviceInfo().getAdditionalParameters() ); JScrollPane sp = new JScrollPane(table); sp.setPreferredSize(JuifeUtils.getUnionSize ( sp.getMinimumSize(), new Dimension(200, 200) )); setMainPane(sp); } } } class MidiDevicesTableModel extends AbstractTableModel { protected final static int ACTIVE_COLUMN_INDEX = 0; protected final static int DEVICE_ID_COLUMN_INDEX = 1; protected final static int PORTS_COLUMN_INDEX = 2; private final String[] columnNames = { "", i18n.getLabel("MidiDevicesTableModel.deviceID"), i18n.getLabel("MidiDevicesTableModel.ports") }; private MidiDeviceModel[] deviceList; MidiDevicesTableModel() { CC.getSamplerModel().addMidiDeviceListListener(getHandler()); deviceList = CC.getSamplerModel().getMidiDeviceModels(); for(MidiDeviceModel m : deviceList) m.addMidiDeviceListener(getHandler()); } public MidiDeviceModel getMidiDeviceModel(int index) { return deviceList[index]; } // The Table Model implementation /** * Gets the number of columns in the model. * @return The number of columns in the model. */ public int getColumnCount() { return columnNames.length; } /** * Gets the number of rows in the model. * @return The number of rows in the model. */ public int getRowCount() { return deviceList.length; } /** * Gets the name of the column at columnIndex. * @return The name of the column at columnIndex. */ public String getColumnName(int col) { return columnNames[col]; } /** * Gets the value for the cell at columnIndex and * rowIndex. * @param row The row whose value is to be queried. * @param col The column whose value is to be queried. * @return The value for the cell at columnIndex and * rowIndex. */ public Object getValueAt(int row, int col) { switch(col) { case ACTIVE_COLUMN_INDEX: return deviceList[row].getDeviceInfo().isActive(); case DEVICE_ID_COLUMN_INDEX: return deviceList[row].getDeviceID(); case PORTS_COLUMN_INDEX: return deviceList[row].getDeviceInfo().getMidiPortCount(); } return null; } /** * Sets the value in the cell at columnIndex * and rowIndex to value. */ public void setValueAt(Object value, int row, int col) { switch(col) { case ACTIVE_COLUMN_INDEX: boolean active = (Boolean)value; deviceList[row].getDeviceInfo().setActive(active); CC.getTaskQueue().add ( new EnableMidiDevice(deviceList[row].getDeviceID(), active) ); break; case PORTS_COLUMN_INDEX: int deviceID = getMidiDeviceModel(row).getDeviceID(); int ports = (Integer)value; CC.getTaskQueue().add(new SetMidiInputPortCount(deviceID, ports)); break; default: return; } fireTableCellUpdated(row, col); } /** * Returns true if the cell at * rowIndex and columnIndex is editable. */ public boolean isCellEditable(int row, int col) { switch(col) { case ACTIVE_COLUMN_INDEX: return true; case DEVICE_ID_COLUMN_INDEX: return false; case PORTS_COLUMN_INDEX: return true; default: return false; } } /** * Returns the most specific superclass for all the cell values * in the column. This is used by the JTable to set up a * default renderer and editor for the column. * @param columnIndex The index of the column. * @return The common ancestor class of the object values in the model. */ public Class getColumnClass(int columnIndex) { return getValueAt(0, columnIndex).getClass(); } /////// private final Handler handler = new Handler(); private Handler getHandler() { return handler; } private class Handler implements MidiDeviceListener, MidiDeviceListListener { /** * Invoked when a new MIDI device is created. * @param e A MidiDeviceListEvent * instance providing the event information. */ public void deviceAdded(MidiDeviceListEvent e) { for(MidiDeviceModel m : deviceList) m.removeMidiDeviceListener(this); deviceList = CC.getSamplerModel().getMidiDeviceModels(); for(MidiDeviceModel m : deviceList) m.addMidiDeviceListener(this); fireTableDataChanged(); } /** * Invoked when a MIDI device is removed. * @param e A MidiDeviceListEvent * instance providing the event information. */ public void deviceRemoved(MidiDeviceListEvent e) { for(MidiDeviceModel m : deviceList) m.removeMidiDeviceListener(this); deviceList = CC.getSamplerModel().getMidiDeviceModels(); for(MidiDeviceModel m : deviceList) m.addMidiDeviceListener(this); fireTableDataChanged(); } /** Invoked when when the settings of a particular MIDI device have changed. */ public void settingsChanged(MidiDeviceEvent e) { MidiInputDevice d = e.getMidiDeviceModel().getDeviceInfo(); for(int i = 0; i < deviceList.length; i++) { MidiInputDevice d2 = deviceList[i].getDeviceInfo(); if(d.getDeviceID() == d2.getDeviceID()) { fireTableRowsUpdated(i, i); } } } } }