/*
* 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.Component;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import net.sf.juife.ComponentList;
import net.sf.juife.ComponentListModel;
import net.sf.juife.DefaultComponentListModel;
import org.jsampler.CC;
import org.jsampler.SamplerChannelModel;
import org.jsampler.view.JSChannel;
import org.jsampler.view.JSChannelsPane;
import org.linuxsampler.lscp.SamplerChannel;
import static org.jsampler.view.classic.ClassicI18n.i18n;
/**
*
* @author Grigor Iliev
*/
public class ChannelsPane extends JSChannelsPane implements ListSelectionListener {
private final ComponentList chnList = new ComponentList();
private final DefaultComponentListModel listModel = new DefaultComponentListModel();
/**
* Creates a new instance of ChannelsPane
with
* the specified title
.
* @param title The title of this ChannelsPane
*/
public
ChannelsPane(String title) {
super(title);
setLayout(new BorderLayout());
chnList.setOpaque(false);
//chnList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
chnList.setModel(listModel);
chnList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
chnList.addListSelectionListener(this);
chnList.addMouseListener(new ContextMenu());
//chnList.setDragEnabled(true);
JScrollPane sp = new JScrollPane(chnList);
sp.setBorder(BorderFactory.createEmptyBorder());
add(sp);
setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
}
/**
* Adds new channel to this channels pane.
* @param channelModel The sampler channel model to be used by the new channel.
*/
public void
addChannel(SamplerChannelModel channelModel) {
Channel channel = new Channel(channelModel);
listModel.add(channel);
if(channel.getChannelInfo().getEngine() == null) channel.expandChannel();
chnList.setSelectedComponent(channel, true);
}
/**
* Adds the specified channels to this channels pane.
* @param chns The channels to be added.
*/
public void
addChannels(JSChannel[] chns) {
if(chns == null || chns.length == 0) return;
for(JSChannel c : chns) listModel.add(c);
chnList.setSelectionInterval (
listModel.getSize() - chns.length, listModel.getSize() - 1
);
chnList.ensureIndexIsVisible(listModel.getSize() - 1);
}
/**
* Removes the specified channel from this channels pane.
* This method is invoked when a sampler channel is removed in the back-end.
* @param chn The channel to be removed from this channels pane.
*/
public void
removeChannel(JSChannel chn) { listModel.remove(chn); }
/**
* Gets the first channel in this channels pane.
* @return The first channel in this channels pane or null
if
* the channels pane is empty.
*/
public JSChannel
getFirstChannel() { return listModel.size() == 0 ? null : (JSChannel)listModel.get(0); }
/**
* Gets the last channel in this channels pane.
* @return The last channel in this channels pane or null
if
* the channels pane is empty.
*/
public JSChannel
getLastChannel() {
return listModel.size() == 0 ? null : (JSChannel)listModel.get(listModel.size()-1);
}
/**
* Gets the channel at the specified index.
* @return The channel at the specified index.
* @throws ArrayIndexOutOfBoundsException If the index is out of range.
*/
public JSChannel
getChannel(int idx) { return (JSChannel)listModel.get(idx); }
/**
* Gets an array with all channels in this channels pane.
* @return An array with all channels in this channels pane.
*/
public JSChannel[]
getChannels() {
JSChannel[] chns = new JSChannel[listModel.size()];
for(int i = 0; i < listModel.size(); i++) chns[i] = (JSChannel)listModel.get(i);
return chns;
}
/**
* Gets the number of channels in this channels pane.
* @return The number of channels in this channels pane.
*/
public int
getChannelCount() { return listModel.size(); }
/**
* Determines whether there is at least one selected channel.
* @return true
if there is at least one selected channel,
* false
otherwise.
*/
public boolean
hasSelectedChannel() { return !chnList.isSelectionEmpty(); }
/**
* Gets the number of the selected channels.
* @return The number of the selected channels.
*/
public int
getSelectedChannelCount() { return chnList.getSelectedIndices().length; }
/**
* Gets an array with all selected channels.
* The channels are sorted in increasing index order.
* @return The selected channels or an empty array if nothing is selected.
*/
public JSChannel[]
getSelectedChannels() {
Component[] cS = chnList.getSelectedComponents();
JSChannel[] chns = new JSChannel[cS.length];
for(int i = 0; i < cS.length; i++) chns[i] = (JSChannel)cS[i];
return chns;
}
/**
* Removes all selected channels in this channels pane.
* Notice that this method does not remove any channels in the back-end.
* It is invoked after the channels are already removed in the back-end.
* @return The number of removed channels.
*/
public int
removeSelectedChannels() {
int[] l = chnList.getSelectedIndices();
ComponentListModel model = chnList.getModel();
for(;;) {
int i = chnList.getMinSelectionIndex();
if(i == -1) break;
model.remove(i);
}
return l.length;
}
/** Selects all channels. */
public void
selectAllChannels() { chnList.selectAll(); }
/** Deselects all selected channels. */
public void
deselectChannels() { chnList.clearSelection(); }
/**
* Registers the specified listener for receiving list selection events.
* @param listener The ListSelectionListener
to register.
*/
public void
addListSelectionListener(ListSelectionListener listener) {
listenerList.add(ListSelectionListener.class, listener);
}
/**
* Removes the specified listener.
* @param listener The ListSelectionListener
to remove.
*/
public void
removeListSelectionListener(ListSelectionListener listener) {
listenerList.remove(ListSelectionListener.class, listener);
}
/**
* Invoked when the selection has changed.
* This method implements valueChanged
* method of the ListSelectionListener
interface.
* @param e A ListSelectionEvent
* instance providing the event information.
*/
public void
valueChanged(ListSelectionEvent e) {
ListSelectionEvent e2 = null;
Object[] listeners = listenerList.getListenerList();
for(int i = listeners.length - 2; i >= 0; i -= 2) {
if(listeners[i] == ListSelectionListener.class) {
if(e2 == null) e2 = new ListSelectionEvent (
this,
e.getFirstIndex(),
e.getLastIndex(),
e.getValueIsAdjusting()
);
((ListSelectionListener)listeners[i + 1]).valueChanged(e2);
}
}
}
public void
moveSelectedChannelsOnTop() {
JSChannel[] chns = getSelectedChannels();
if(chns.length == 0) {
CC.getLogger().info("Can't move channel(s) at the beginning");
return;
}
for(int i = chns.length - 1; i >= 0; i--) {
listModel.remove(chns[i]);
listModel.insert(chns[i], 0);
}
chnList.setSelectionInterval(0, chns.length - 1);
chnList.ensureIndexIsVisible(0);
}
public void
moveSelectedChannelsUp() {
JSChannel[] chns = getSelectedChannels();
if(chns.length == 0 || chns[0] == getFirstChannel()) {
CC.getLogger().info("Can't move channel(s) up");
return;
}
for(int i = 0; i < chns.length; i++) listModel.moveUp(chns[i]);
int[] si = chnList.getSelectedIndices();
for(int i = 0; i < si.length; i++) si[i] -= 1;
chnList.setSelectedIndices(si);
chnList.ensureIndexIsVisible(si[0]);
}
public void
moveSelectedChannelsDown() {
JSChannel[] chns = getSelectedChannels();
if(chns.length == 0 || chns[chns.length - 1] == getLastChannel()) {
CC.getLogger().info("Can't move channel(s) down");
return;
}
for(int i = chns.length - 1; i >= 0; i--) listModel.moveDown(chns[i]);
int[] si = chnList.getSelectedIndices();
for(int i = 0; i < si.length; i++) si[i] += 1;
chnList.setSelectedIndices(si);
chnList.ensureIndexIsVisible(si[si.length - 1]);
}
public void
moveSelectedChannelsAtBottom() {
JSChannel[] chns = getSelectedChannels();
if(chns.length == 0) {
CC.getLogger().info("Can't move channel(s) at the end");
return;
}
for(int i = 0; i < chns.length; i++) {
listModel.remove(chns[i]);
listModel.add(chns[i]);
}
chnList.setSelectionInterval (
listModel.getSize() - chns.length, listModel.getSize() - 1
);
chnList.ensureIndexIsVisible(listModel.getSize() - 1);
}
class ContextMenu extends MouseAdapter {
private final JPopupMenu cmenu = new JPopupMenu();
private final JMenu submenu = new JMenu(i18n.getMenuLabel("channels.MoveToTab"));
ContextMenu() {
JMenuItem mi = new JMenuItem(A4n.moveChannelsOnTop);
mi.setIcon(null);
cmenu.add(mi);
mi = new JMenuItem(A4n.moveChannelsUp);
mi.setIcon(null);
cmenu.add(mi);
mi = new JMenuItem(A4n.moveChannelsDown);
mi.setIcon(null);
cmenu.add(mi);
mi = new JMenuItem(A4n.moveChannelsAtBottom);
mi.setIcon(null);
cmenu.add(mi);
cmenu.add(submenu);
cmenu.addSeparator();
mi = new JMenuItem(A4n.removeChannels);
mi.setIcon(null);
cmenu.add(mi);
}
public void
mousePressed(MouseEvent e) {
if(e.isPopupTrigger()) show(e);
}
public void
mouseReleased(MouseEvent e) {
if(e.isPopupTrigger()) show(e);
}
void
show(MouseEvent e) {
/*int idx = chnList.locationToIndex(e.getPoint());
if(!chnList.isSelectedIndex(idx)) chnList.setSelectedIndex(idx);
if(idx != -1 && CC.getMainFrame().getChannelsPaneCount() > 1) {
updateMenu();
submenu.setEnabled(true);
} else submenu.setEnabled(false);
cmenu.show(e.getComponent(), e.getX(), e.getY());*/
}
private void
updateMenu() {
submenu.removeAll();
Vector v = CC.getMainFrame().getChannelsPaneList();
for(JSChannelsPane p : v)
if(p != CC.getMainFrame().getSelectedChannelsPane())
submenu.add(new JMenuItem(new A4n.MoveChannelsTo(p)));
}
}
}