/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package controller.channel.map;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.table.AbstractTableModel;
public class ChannelRangeModel extends AbstractTableModel
{
private static final long serialVersionUID = 1L;
private static final int START = 0;
private static final int STOP = 1;
private static final int BASE = 2;
private static final int SIZE = 3;
private static final int ERROR = 4;
protected int[] mColumnWidths = { 110, 110, 110, -1, 80 };
protected String[] mHeaders = new String[] { "Begin",
"End",
"Base",
"Size",
"Error" };
private List<ChannelRange> mRanges = new CopyOnWriteArrayList<>();
private ChannelRangeEventListener mListener;
public ChannelRangeModel()
{
}
public void setListener( ChannelRangeEventListener listener )
{
mListener = listener;
}
private void broadcastChange()
{
if( mListener != null )
{
mListener.channelRangesChanged();
}
}
public void clear()
{
for( ChannelRange range: mRanges )
{
removeRange( range );
}
broadcastChange();
}
public List<ChannelRange> getChannelRanges()
{
return mRanges;
}
public void addRanges( List<ChannelRange> ranges )
{
for( ChannelRange range: ranges )
{
addRange( range );
}
broadcastChange();
}
public void addRange( ChannelRange range )
{
if( range != null && !mRanges.contains( range ) )
{
mRanges.add( range );
int index = mRanges.indexOf( range );
fireTableRowsInserted( index, index );
}
validate();
broadcastChange();
}
public void removeRange( ChannelRange range )
{
if( range != null && mRanges.contains( range ) )
{
int index = mRanges.indexOf( range );
mRanges.remove( range );
fireTableRowsDeleted( index, index );
}
validate();
broadcastChange();
}
public int[] getColumnWidths()
{
return mColumnWidths;
}
public void setColumnWidths( int[] widths )
{
if( widths.length != mHeaders.length )
{
throw new IllegalArgumentException( "ChannelMapRangeModel - "
+ "column widths array should have " +
mHeaders.length + " elements" );
}
else
{
mColumnWidths = widths;
}
}
@Override
public int getRowCount()
{
return mRanges.size();
}
@Override
public int getColumnCount()
{
return mHeaders.length;
}
public String getColumnName( int column )
{
return mHeaders[ column ];
}
public ChannelRange getChannelRange( int index )
{
if( index < mRanges.size() )
{
return mRanges.get( index );
}
return null;
}
@Override
public Object getValueAt( int rowIndex, int columnIndex )
{
ChannelRange range = getChannelRange( rowIndex );
if( range != null )
{
switch( columnIndex )
{
case START:
return range.getFirstChannelNumber();
case STOP:
return range.getLastChannelNumber();
case BASE:
return range.getBase();
case SIZE:
return range.getSize();
case ERROR:
StringBuilder sb = new StringBuilder();
if( !range.isValid() )
{
sb.append( "Sequence" );
}
if( range.isOverlapping() )
{
if( sb.length() > 0 )
{
sb.append( "," );
}
sb.append( "Overlap" );
}
return sb.toString();
default:
break;
}
}
return null;
}
/**
* Validates each of the channel ranges for overlap
*/
private void validate()
{
for( int x = 0; x < mRanges.size(); x++ )
{
mRanges.get( x ).setOverlapping( false );
fireTableCellUpdated( x, ERROR );
}
for( int x = 0; x < mRanges.size(); x++ )
{
for( int y = x + 1; y < mRanges.size(); y++ )
{
if( mRanges.get( x ).overlaps( mRanges.get( y ) ) )
{
mRanges.get( x ).setOverlapping( true );
fireTableCellUpdated( x, ERROR );
mRanges.get( y ).setOverlapping( true );
fireTableCellUpdated( y, ERROR );
}
}
}
}
public boolean isCellEditable( int row, int column )
{
return row < mRanges.size() && column != ERROR;
}
public void setValueAt( Object value, int row, int column )
{
int parsedValue = -1;
try
{
parsedValue = Integer.parseInt( (String)value );
}
catch( Exception e )
{
//Do nothing ... we'll use 0
}
if( parsedValue >= 0 )
{
ChannelRange range = getChannelRange( row );
if( range != null )
{
switch( column )
{
case START:
range.setFirstChannelNumber( parsedValue );
break;
case STOP:
range.setLastChannelNumber( parsedValue );
break;
case BASE:
range.setBase( parsedValue );
break;
case SIZE:
range.setSize( parsedValue );
break;
}
validate();
broadcastChange();
}
else
{
throw new IllegalArgumentException( "Invalid channel range row index" );
}
}
}
public interface ChannelRangeEventListener
{
public void channelRangesChanged();
}
}