/*
* IOSetupFrame.java
* Eisenkraut
*
* Copyright (c) 2004-2016 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU General Public License v3+
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de
*/
package de.sciss.eisenkraut.gui;
import de.sciss.app.AbstractApplication;
import de.sciss.app.Application;
import de.sciss.app.GraphicsHandler;
import de.sciss.common.AppWindow;
import de.sciss.common.BasicWindowHandler;
import de.sciss.eisenkraut.Main;
import de.sciss.eisenkraut.io.AudioBoxConfig;
import de.sciss.eisenkraut.io.RoutingConfig;
import de.sciss.eisenkraut.util.PrefsUtil;
import de.sciss.gui.CoverGrowBox;
import de.sciss.gui.HelpButton;
import de.sciss.gui.ModificationButton;
import de.sciss.gui.SortedTableModel;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
/**
* This is the frame that
* displays the user adjustable
* input/output configuration
*/
public class IOSetupFrame extends AppWindow {
private static class Tab {
public Tab() {}
final List<RoutingConfig> collConfig = new ArrayList<RoutingConfig>();
final Set<String> setConfigID = new HashSet<String>();
final Set<String> setConfigName = new HashSet<String>();
final Set<String> setDirtyConfig = new HashSet<String>();
}
private static final int NUM_TABS = 2;
private final Tab[] tabs = new Tab[] { new Tab(), new Tab() };
private final Preferences audioPrefs;
private final int[] audioHwChannels = new int[ NUM_TABS ];
private static final String[] staticColNames = { "ioConfig", "ioNumChannels", "ioStartAngle" };
private static final int[] staticColWidths = { 160, 54, 54 };
private static final int MAPPING_WIDTH = 48; // 40; // 36;
// private static final Font fnt = GraphicsUtil.smallGUIFont;
private static final int[] pntMapNormGradPixLight = {
0xFFF4F4F4, 0xFFF1F1F1, 0xFFEEEEEE, 0xFFECECEC,
0xFFECECEC, 0xFFECECEC, 0xFFEDEDED, 0xFFDADADA,
0xFFDFDFDF, 0xFFE3E3E3, 0xFFE7E7E7, 0xFFEBEBEB,
0xFFF0F0F0, 0xFFF3F3F3, 0xFFF9F9F9};
private static final int[] pntMapNormGradPixDark = {
0xFF747474, 0xFF717171, 0xFF6E6E6E, 0xFF6C6C6C,
0xFF6C6C6C, 0xFF6C6C6C, 0xFF6D6D6D, 0xFF5A5A5A,
0xFF5F5F5F, 0xFF636363, 0xFF676767, 0xFF6B6B6B,
0xFF707070, 0xFF737373, 0xFF797979 };
private static final int pntMapSize = 15;
private static final int[] pntMapSelGradPixLight = {
0xFFD8DBE0, 0xFFCAD0D5, 0xFFC2C9CE, 0xFFBEC4CB,
0xFFBBC2C8, 0xFFB8BEC6, 0xFFB6BCC6, 0xFF9EA8B4,
0xFFA4ADB9, 0xFFAAB4BF, 0xFFAFB9C6, 0xFFB8C2CE,
0xFFBBC5D0, 0xFFBFCAD4, 0xFFC7D1DD};
private static final int[] pntMapSelGradPixDark = {
0xFF585B70, 0xFF4A5065, 0xFF42495E, 0xFF3E445B,
0xFF3B4258, 0xFF383E56, 0xFF363C56, 0xFF1E2844,
0xFF242D49, 0xFF2A344F, 0xFF2F3956, 0xFF38425E,
0xFF3B4560, 0xFF3F4A64, 0xFF47516D};
private static final Paint pntMapNormLight, pntMapSelLight, pntMapNormDark, pntMapSelDark;
private final Paint pntMapNormal, pntMapSelected;
private static final DataFlavor mapFlavor = new DataFlavor(MapTransferable.class, "io_mapping");
private static final DataFlavor[] mapFlavors = {mapFlavor};
private static final String[] KEY_INFOTEXT = { "ioInputInfo", "ioOutputInfo" };
private static final String[] KEY_DEFAULTNAME = { "ioDefaultInName", "ioDefaultOutName" };
private static final String[] KEY_PREFSNODE = { PrefsUtil.NODE_INPUTCONFIGS, PrefsUtil.NODE_OUTPUTCONFIGS };
// private final Paint pntMapEmpty;
static {
BufferedImage img;
img = new BufferedImage(1, pntMapSize, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, 1, pntMapSize, pntMapNormGradPixLight, 0, 1);
pntMapNormLight = new TexturePaint(img, new Rectangle(0, 0, 1, pntMapSize));
img = new BufferedImage(1, pntMapSize, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, 1, pntMapSize, pntMapSelGradPixLight, 0, 1);
pntMapSelLight = new TexturePaint(img, new Rectangle(0, 0, 1, pntMapSize));
img = new BufferedImage(1, pntMapSize, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, 1, pntMapSize, pntMapNormGradPixDark, 0, 1);
pntMapNormDark = new TexturePaint(img, new Rectangle(0, 0, 1, pntMapSize));
img = new BufferedImage(1, pntMapSize, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, 1, pntMapSize, pntMapSelGradPixDark, 0, 1);
pntMapSelDark = new TexturePaint(img, new Rectangle(0, 0, 1, pntMapSize));
}
/**
* Creates a new i/o setup frame
*/
public IOSetupFrame() {
super(SUPPORT);
setTitle(getResourceString("frameIOSetup"));
final Container cp = getContentPane();
final Application app = AbstractApplication.getApplication();
final Box buttonPanel;
final JTabbedPane ggTabPane;
final String abCfgID;
final AudioBoxConfig abCfg;
final boolean isDark = UIManager.getBoolean("dark-skin");
pntMapNormal = isDark ? pntMapNormDark : pntMapNormLight;
pntMapSelected = isDark ? pntMapSelDark : pntMapSelLight;
audioPrefs = app.getUserPrefs().node(PrefsUtil.NODE_AUDIO);
abCfgID = audioPrefs.get(PrefsUtil.KEY_AUDIOBOX, AudioBoxConfig.ID_DEFAULT);
abCfg = new AudioBoxConfig(audioPrefs.node(PrefsUtil.NODE_AUDIOBOXES).node(abCfgID));
audioHwChannels[0] = abCfg.numInputChannels;
audioHwChannels[1] = abCfg.numOutputChannels;
ggTabPane = new JTabbedPane();
ggTabPane.putClientProperty("styleId", "attached");
// ---------- tabs ----------
for (int i = 0; i < NUM_TABS; i++) { // input + output tabs
fromPrefs(i);
ggTabPane.addTab(app.getResourceString(i == 0 ? "labelInputs" : "labelOutputs"), null,
createTab(i), null);
}
// ---------- generic gadgets ----------
buttonPanel = Box.createHorizontalBox(); // new JPanel( new FlowLayout( FlowLayout.RIGHT, 4, 4 ));
// pntMapEmpty = buttonPanel.getBackground();
buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0));
buttonPanel.add(new HelpButton("IOSetup"));
buttonPanel.add(Box.createHorizontalGlue());
final JButton ggOk = new JButton(app.getResourceString("buttonOk"));
ggOk.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final ControlRoomFrame f;
for (int i = 0; i < NUM_TABS; i++) {
if (!toPrefs(i)) return;
}
disposeAndClose();
// XXX ControlRoomFrame cannot rely on prefs since childAdded is
// never fired (probably bug in java or spi)
f = (ControlRoomFrame) app.getComponent(Main.COMP_CTRLROOM);
if (f != null) f.refillIOConfigs();
}
});
buttonPanel.add(ggOk);
final JButton ggCancel = new JButton(app.getResourceString("buttonCancel"));
buttonPanel.add(ggCancel);
ggCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
disposeAndClose();
}
});
buttonPanel.add(CoverGrowBox.create());
final Dimension d1 = ggOk .getPreferredSize();
final Dimension d2 = ggCancel.getPreferredSize();
d1.width = Math.max(d1.width , d2.width );
d1.height = Math.max(d1.height, d2.height);
ggOk .setPreferredSize(d1);
ggCancel.setPreferredSize(d1);
cp.add(ggTabPane , BorderLayout.CENTER);
cp.add(buttonPanel, BorderLayout.SOUTH );
// ---------- ----------
ggTabPane.setSelectedIndex(NUM_TABS - 1);
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
init();
app.addComponent(Main.COMP_IOSETUP, this);
}
protected boolean autoUpdatePrefs() {
return true;
}
private JComponent createTab(final int id) {
final JPanel tab;
final LayoutManager lay;
final JTable table;
final AbstractTableModel tm;
final SortedTableModel stm;
final JTableHeader th;
final TableCellRenderer tcr;
final JScrollPane scroll;
final JTextArea lbTextArea;
final Box b;
final AbstractButton ggPlus, ggMinus;
tab = new JPanel();
lay = new BorderLayout();
tab.setLayout(lay);
lbTextArea = new JTextArea(getResourceString(KEY_INFOTEXT[id]));
lbTextArea.setEditable(false);
lbTextArea.setBackground(null);
lbTextArea.setColumns(32);
lbTextArea.setLineWrap(true);
lbTextArea.setWrapStyleWord(true);
tab.add(lbTextArea, BorderLayout.NORTH);
lbTextArea.setBorder(BorderFactory.createEmptyBorder(8, 2, 8, 2));
tm = new TableModel(id);
stm = new SortedTableModel(tm);
table = new JTable(stm);
th = table.getTableHeader();
stm.setTableHeader(th);
th.setReorderingAllowed(false);
th.setResizingAllowed(true);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.setCellSelectionEnabled(true);
table.setColumnSelectionAllowed(false);
table.setDragEnabled(true);
table.setShowGrid(true);
table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
table.setTransferHandler(new MapTransferHandler(id));
stm.setSortedColumn(0, SortedTableModel.ASCENDING);
tcr = new MappingRenderer();
setColumnRenderersAndWidths(table, stm, tcr);
scroll = new JScrollPane(table, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
tab.add(scroll, BorderLayout.CENTER);
final Tab t = tabs[id];
b = Box.createHorizontalBox();
ggPlus = new ModificationButton(ModificationButton.SHAPE_PLUS );
ggMinus = new ModificationButton(ModificationButton.SHAPE_MINUS);
ggMinus.setEnabled(false);
ggPlus.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// int row = table.getSelectedRow() + table.getSelectedRowCount();
// if( row <= 0 ) row = collConfigs[ ID ].size();
final int modelIndex = t.collConfig.size();
final int viewIndex;
final RoutingConfig cfg = createUniqueConfig(id);
// collConfigs[ ID ].add( row, cfg );
t.collConfig.add(cfg);
t.setConfigID.add(cfg.id);
t.setConfigName.add(cfg.name);
t.setDirtyConfig.add(cfg.id);
tm.fireTableRowsInserted(modelIndex, modelIndex);
viewIndex = stm.getViewIndex(modelIndex);
table.setRowSelectionInterval(viewIndex, viewIndex);
}
});
ggMinus.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent e )
{
final int firstRow = Math.max( 0, table.getSelectedRow() );
final int lastRow = Math.min( table.getRowCount(), firstRow + table.getSelectedRowCount() ) - 1;
RoutingConfig cfg;
final int[] modelIndices;
if( firstRow <= lastRow ) {
modelIndices = new int[ lastRow - firstRow + 1 ];
for( int i = 0, viewIndex = firstRow; viewIndex <= lastRow; i++, viewIndex++ ) {
modelIndices[ i ] = stm.getModelIndex( viewIndex );
}
Arrays.sort( modelIndices );
for (int i = modelIndices.length - 1; i >= 0; i--) {
cfg = t.collConfig.remove(modelIndices[i]);
t.setConfigName.remove(cfg.name);
// never remove the id during one editing session,
// because that will confuse the prefs listeners
// and the setDirtyConfigs approach
// setConfigIDs[ id ].remove( cfg.id );
t.setDirtyConfig.add(cfg.id);
}
// tm.fireTableRowsDeleted( firstRow, lastRow );
tm.fireTableDataChanged();
}
}
});
b.add( ggPlus );
b.add( ggMinus );
b.add( Box.createHorizontalGlue() );
table.getSelectionModel().addListSelectionListener( new ListSelectionListener() {
public void valueChanged( ListSelectionEvent e )
{
ggMinus.setEnabled( table.getSelectedRowCount() > 0 );
}
});
tab.add( b, BorderLayout.SOUTH );
return tab;
}
private void disposeAndClose() {
AbstractApplication.getApplication().removeComponent(Main.COMP_IOSETUP); // needs to re-created each time!
setVisible(false);
dispose();
}
private void fromPrefs(int id) {
final Tab t = tabs[id];
t.collConfig.clear();
t.setConfigName.clear();
t.setConfigID.clear();
final Preferences ocPrefs = audioPrefs.node( KEY_PREFSNODE[ id ]);
final String[] arrayNames;
RoutingConfig cfg;
Preferences cfgPrefs;
try {
arrayNames = ocPrefs.childrenNames();
//System.err.println( "Got "+arrayNames.length+" children . " );
}
catch( BackingStoreException e1 ) {
BasicWindowHandler.showErrorDialog( getWindow(), e1, getResourceString( "errLoadPrefs" ));
return;
}
for (String arrayName : arrayNames) {
cfgPrefs = ocPrefs.node(arrayName);
try {
cfg = new RoutingConfig(cfgPrefs);
t.collConfig .add(cfg);
t.setConfigID .add(arrayName);
t.setConfigName.add(cfg.name);
} catch (NumberFormatException e1) {
System.err.println("IOSetupFrame - fromPrefs:");
e1.printStackTrace();
}
}
}
private boolean toPrefs(int id) {
final Preferences ocPrefs = audioPrefs.node(KEY_PREFSNODE[id]);
RoutingConfig cfg;
Preferences cfgPrefs;
String cfgID;
final Tab t = tabs[id];
try {
for( int i = 0; i < t.collConfig.size(); i++ ) {
cfg = t.collConfig.get(i);
if( t.setDirtyConfig.remove(cfg.id)) {
cfgPrefs = ocPrefs.node( cfg.id );
cfg.toPrefs( cfgPrefs );
}
}
for (String aSetDirtyConfig : t.setDirtyConfig) {
cfgID = aSetDirtyConfig;
cfgPrefs = ocPrefs.node(cfgID);
cfgPrefs.removeNode();
}
ocPrefs.flush();
}
catch( BackingStoreException e1 ) {
BasicWindowHandler.showErrorDialog( getWindow(), e1, getResourceString( "errSavePrefs" ));
return false;
}
return true;
}
private RoutingConfig createUniqueConfig(int id) {
final Tab t = tabs[id];
final String test = getResourceString(KEY_DEFAULTNAME[id]);
String name = test;
for (int i = 1; t.setConfigName.contains(name); i++) {
name = test + " " + i;
}
String cfgID = "user1";
for (int i = 2; t.setConfigID.contains(cfgID); i++) {
cfgID = "user" + i;
}
return new RoutingConfig(cfgID, name);
}
private void setColumnRenderersAndWidths(JTable table, SortedTableModel stm, TableCellRenderer tcr) {
final TableColumnModel tcm = table.getColumnModel();
TableColumn col;
int i;
for (i = 0; i < staticColNames.length; i++) {
col = tcm.getColumn(i);
col.setMinWidth(staticColWidths[i]);
}
for (; i < table.getColumnCount(); i++) {
stm.setSortingAllowed(i, false);
col = tcm.getColumn(i);
col.setPreferredWidth(MAPPING_WIDTH);
col.setMinWidth(MAPPING_WIDTH);
col.setMaxWidth(MAPPING_WIDTH);
col.setCellRenderer(tcr);
}
}
protected static String getResourceString(String key) {
return AbstractApplication.getApplication().getResourceString(key);
}
// ----------- internal classes -----------
@SuppressWarnings("serial")
private class MapTransferHandler extends TransferHandler {
private final int id;
MapTransferHandler(int id)
{
this.id = id;
}
/**
* Overridden to import a MapTransferable if it is available.
*/
public boolean importData(JComponent c, Transferable trans) {
MapTransferable mt;
final JTable table = (JTable) c;
final SortedTableModel stm = (SortedTableModel) table.getModel();
final int row = table.getSelectedRow();
final int mapCh = table.getSelectedColumn() - staticColNames.length;
final int modelIndex;
RoutingConfig cfg;
int temp;
final Tab t = tabs[id];
try {
if( mapCh >= 0 && (row < table.getRowCount()) && trans.isDataFlavorSupported( mapFlavor )) {
modelIndex = stm.getModelIndex( row );
cfg = t.collConfig.get(modelIndex);
mt = (MapTransferable) trans.getTransferData( mapFlavor );
// only allowed within same config
if( mt.cfg == cfg ) {
//System.err.println( "original mapping : "+(mt.idx+1)+"->"+(mt.cfg.mapping[ mt.idx ]+1)+"; new target " +(mapCh+1));
for( int i = 0; i < cfg.numChannels; i++ ) {
// dragged onto already mapped spot
if (cfg.mapping[i] == mapCh) {
if( i == mt.idx ) return false; // source == target, no action
temp = cfg.mapping[ mt.idx ];
cfg.mapping[ mt.idx ] = mapCh;
cfg.mapping[ i ] = temp; // simply swapped for now
((AbstractTableModel) stm.getTableModel()).fireTableRowsUpdated( modelIndex, modelIndex );
return true;
}
}
// dragged onto empty spot
cfg.mapping[ mt.idx ] = mapCh;
t.setDirtyConfig.add(cfg.id);
((AbstractTableModel) stm.getTableModel()).fireTableRowsUpdated( modelIndex, modelIndex );
return true;
}
}
}
catch( UnsupportedFlavorException e1 ) { e1.printStackTrace(); }
catch( IOException e2 ) { e2.printStackTrace(); }
return false;
}
public int getSourceActions( JComponent c )
{
return MOVE;
}
protected Transferable createTransferable( JComponent c )
{
final JTable table = (JTable) c;
final SortedTableModel stm = (SortedTableModel) table.getModel();
final int row = table.getSelectedRow();
final int mapCh = table.getSelectedColumn() - staticColNames.length;
final int modelIndex;
RoutingConfig cfg;
final Tab t = tabs[id];
if( mapCh >= 0 && (row < table.getRowCount()) ) {
modelIndex = stm.getModelIndex( row );
cfg = t.collConfig.get(modelIndex);
for( int i = 0; i < cfg.numChannels; i++ ) {
if( cfg.mapping[ i ] == mapCh ) {
return new MapTransferable( cfg, i );
}
}
}
return null;
}
protected void exportDone(JComponent source, Transferable data, int action) {
// System.err.println( "exportDone. Action == "+action );
}
public boolean canImport(JComponent c, DataFlavor[] flavors) {
for (DataFlavor flavor : flavors) {
for (DataFlavor mapFlavor1 : mapFlavors) {
if (flavor.equals(mapFlavor1)) return true;
}
}
return false;
}
} // class MapTransferHandler
private static class MapTransferable
implements Transferable {
final RoutingConfig cfg;
protected final int idx;
MapTransferable(RoutingConfig cfg, int idx) {
this.cfg = cfg;
this.idx = idx;
}
public DataFlavor[] getTransferDataFlavors()
{
return mapFlavors;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
for (DataFlavor mapFlavor1 : mapFlavors) {
if (mapFlavor1.equals(flavor)) return true;
}
return false;
}
public Object getTransferData( DataFlavor flavor )
throws UnsupportedFlavorException, IOException
{
if( flavor.equals( mapFlavor )) {
return this;
}
throw new UnsupportedFlavorException( flavor );
}
}
@SuppressWarnings("serial")
private class MappingRenderer
extends JComponent
implements TableCellRenderer {
private Paint pntFilled = pntMapNormal;
private String value = null;
MappingRenderer() {
super();
setOpaque(true);
setFont(AbstractApplication.getApplication().getGraphicsHandler().getFont(GraphicsHandler.FONT_SMALL));
}
public Component getTableCellRendererComponent(JTable table, Object v,
boolean isSelected, boolean hasFocus,
int row, int column) {
pntFilled = hasFocus ? pntMapSelected : pntMapNormal;
value = v == null ? null : v.toString();
return this;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (value == null) {
g2.setPaint(getBackground());
g2.fillRect(0, 0, getWidth(), getHeight());
} else {
final FontMetrics fm = g2.getFontMetrics(g2.getFont());
g2.setPaint(pntFilled);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor(getForeground());
g2.drawString(value, (getWidth() - fm.stringWidth(value)) * 0.5f, fm.getAscent());
}
}
}
@SuppressWarnings("serial")
private class TableModel
extends AbstractTableModel {
private final int id;
TableModel(int id) {
this.id = id;
}
public String getColumnName(int col) {
if (col < staticColNames.length) {
return getResourceString(staticColNames[col]);
} else {
return String.valueOf(col - staticColNames.length + 1);
}
}
public int getRowCount()
{
return tabs[id].collConfig.size();
}
public int getColumnCount()
{
return audioHwChannels[ id ] + staticColNames.length;
}
public Object getValueAt( int row, int col )
{
final Tab t = tabs[id];
if( row > t.collConfig.size() ) return null;
final RoutingConfig c = t.collConfig.get(row);
switch( col ) {
case 0:
return c.name;
case 1:
return c.numChannels;
case 2:
return c.startAngle;
default:
col -= staticColNames.length;
for( int i = 0; i < c.mapping.length; i++ ) {
if( c.mapping[ i ] == col ) return i + 1;
}
return null;
}
}
public Class<?> getColumnClass( int col )
{
switch( col ) {
case 0:
return String.class;
case 1:
return Integer.class;
case 2:
return Float.class;
default:
return Integer.class;
}
}
public boolean isCellEditable( int row, int col )
{
return col < staticColNames.length;
}
public void setValueAt(Object value, int row, int col) {
final Tab t = tabs[id];
if( (row > t.collConfig.size()) || (value == null) ) return;
final RoutingConfig cfg = t.collConfig.get(row);
final int oldChannels = cfg.numChannels;
int[] newMapping;
String name;
RoutingConfig newCfg = null;
int newChannels;
float newStartAngle;
switch( col ) {
case 0:
name = value.toString();
if( (name.length() > 0) &&
!t.setConfigName.contains(name)) {
newCfg = new RoutingConfig( cfg.id, name, cfg.mapping, cfg.startAngle );
}
break;
case 1:
if( value instanceof Number ) {
newChannels = Math.max( 0, ((Number) value).intValue() );
} else if( value instanceof String ) {
try {
newChannels = Math.max( 0, Integer.parseInt( value.toString() ));
}
catch( NumberFormatException e1 ) {
break;
}
} else {
assert false : value;
break;
}
if( newChannels < oldChannels ) {
newMapping = new int[ newChannels ];
System.arraycopy( cfg.mapping, 0, newMapping, 0, newChannels );
} else if( newChannels > oldChannels ) {
newMapping = new int[ newChannels ];
System.arraycopy( cfg.mapping, 0, newMapping, 0, oldChannels );
for( int i = oldChannels, minCh = 0; i < newChannels; i++ ) {
chanLp:
for( int ch = minCh; true; ch++ ) {
for( int j = 0; j < i; j++ ) {
if( newMapping[ j ] == ch ) continue chanLp;
}
newMapping[ i ] = ch;
minCh = ch + 1;
break;
}
}
} else break;
newCfg = new RoutingConfig( cfg.id, cfg.name, newMapping, cfg.startAngle );
break;
case 2:
if( value instanceof Number ) {
newStartAngle = Math.max( -360f, Math.min( 360f, ((Number) value).floatValue() ));
} else if( value instanceof String ) {
try {
newStartAngle = Math.max( -360f, Math.min( 360f, Float.parseFloat( value.toString() )));
}
catch( NumberFormatException e1 ) {
break;
}
} else {
assert false : value;
break;
}
if( newStartAngle != cfg.startAngle ) {
newCfg = new RoutingConfig( cfg.id, cfg.name, cfg.mapping, newStartAngle );
}
break;
default:
// set by changing numChannels and drag+drop
break;
}
if (newCfg != null) {
t.collConfig.set(row, newCfg);
t.setConfigName .remove(cfg.name);
t.setConfigName .add(newCfg.name);
t.setDirtyConfig.add(newCfg.id);
}
if (col <= 2) fireTableRowsUpdated(row, row); // updates sorting!
}
}
}