/*******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 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 channel.metadata;
import channel.state.State;
import controller.channel.Channel;
import sample.Listener;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ChannelMetadataModel extends AbstractTableModel implements Listener<MutableMetadataChangeEvent>
{
private final DecimalFormat FREQUENCY_FORMATTER = new DecimalFormat( "#.00000" );
public static final int COLUMN_STATE = 0;
public static final int COLUMN_DECODER = 1;
public static final int COLUMN_CHANNEL = 2;
public static final int COLUMN_FREQUENCY = 3;
public static final int COLUMN_PRIMARY_FROM = 4;
public static final int COLUMN_PRIMARY_TO = 5;
public static final int COLUMN_SECONDARY_FROM = 6;
public static final int COLUMN_SECONDARY_TO = 7;
public static final int COLUMN_CONFIGURATION_NAME = 8;
public static final int COLUMN_MESSAGE = 9;
private static final String[] COLUMNS = {"State", "Decoder", "Channel", "Frequency", "Primary From", "Primary To",
"Secondary From", "Secondary To", "Channel Name", "Message"};
private List<MutableMetadata> mChannelMetadata = new ArrayList();
private Map<MutableMetadata,Channel> mMetadataChannelMap = new HashMap();
public void add(MutableMetadata metadata, Channel channel)
{
//Execute on the swing thread to avoid threading issues
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
mChannelMetadata.add(metadata);
mMetadataChannelMap.put(metadata, channel);
int index = mChannelMetadata.indexOf(metadata);
fireTableRowsInserted(index, index);
metadata.addListener(ChannelMetadataModel.this);
}
});
}
public void remove(MutableMetadata metadata)
{
//Execute on the swing thread to avoid threading issues
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
metadata.removeListener(ChannelMetadataModel.this);
int index = mChannelMetadata.indexOf(metadata);
mChannelMetadata.remove(metadata);
mMetadataChannelMap.remove(metadata);
fireTableRowsDeleted(index, index);
}
});
}
/**
* Get the channel metadata at the specified model row index
*/
public Metadata getMetadata(int row)
{
if(row < mChannelMetadata.size())
{
return mChannelMetadata.get(row);
}
return null;
}
/**
* Returns the channel that matches the metadata or null
*/
public Channel getChannelFromMetadata(Metadata metadata)
{
return mMetadataChannelMap.get(metadata);
}
@Override
public int getRowCount()
{
return mChannelMetadata.size();
}
@Override
public int getColumnCount()
{
return COLUMNS.length;
}
@Override
public String getColumnName(int column)
{
return COLUMNS[column];
}
@Override
public Class<?> getColumnClass(int columnIndex)
{
switch(columnIndex)
{
case COLUMN_STATE:
return State.class;
case COLUMN_DECODER:
case COLUMN_CHANNEL:
case COLUMN_FREQUENCY:
case COLUMN_MESSAGE:
case COLUMN_CONFIGURATION_NAME:
return String.class;
case COLUMN_PRIMARY_TO:
case COLUMN_PRIMARY_FROM:
case COLUMN_SECONDARY_TO:
case COLUMN_SECONDARY_FROM:
return MutableMetadata.class;
default:
return String.class;
}
}
@Override
public Object getValueAt(int rowIndex, int columnIndex)
{
if(rowIndex <= mChannelMetadata.size())
{
Metadata metadata = mChannelMetadata.get(rowIndex);
switch(columnIndex)
{
case COLUMN_STATE:
return metadata.getState();
case COLUMN_DECODER:
if(metadata.hasPrimaryDecoderType())
{
return metadata.getPrimaryDecoderType().getShortDisplayString();
}
return null;
case COLUMN_CHANNEL:
return metadata.getChannelFrequencyLabel();
case COLUMN_FREQUENCY:
if(metadata.hasChannelFrequency())
{
return FREQUENCY_FORMATTER.format((double)metadata.getChannelFrequency() / 1E6d);
}
return null;
case COLUMN_MESSAGE:
if(metadata.hasMessageType() | metadata.hasMessage())
{
StringBuilder sb = new StringBuilder();
if(metadata.hasMessageType())
{
sb.append(metadata.getMessageType()).append(" ");
}
if(metadata.hasMessage())
{
sb.append(metadata.getMessage());
}
return sb.toString();
}
return null;
case COLUMN_CONFIGURATION_NAME:
return metadata.getChannelConfigurationName();
case COLUMN_PRIMARY_TO:
case COLUMN_PRIMARY_FROM:
case COLUMN_SECONDARY_TO:
case COLUMN_SECONDARY_FROM:
return metadata;
default:
return String.class;
}
}
return null;
}
@Override
public void receive(MutableMetadataChangeEvent mutableMetadataChangeEvent)
{
//Execute on the swing thread to avoid threading issues
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
int rowIndex = mChannelMetadata.indexOf(mutableMetadataChangeEvent.getMetadata());
if(rowIndex >= 0)
{
switch(mutableMetadataChangeEvent.getAttribute())
{
case CHANNEL_CONFIGURATION_SYSTEM:
break;
case CHANNEL_CONFIGURATION_SITE:
break;
case CHANNEL_CONFIGURATION_NAME:
fireTableCellUpdated(rowIndex, COLUMN_CONFIGURATION_NAME);
break;
case CHANNEL_FREQUENCY:
fireTableCellUpdated(rowIndex, COLUMN_FREQUENCY);
break;
case CHANNEL_FREQUENCY_LABEL:
fireTableCellUpdated(rowIndex, COLUMN_CHANNEL);
break;
case CHANNEL_STATE:
fireTableCellUpdated(rowIndex, COLUMN_STATE);
break;
case MESSAGE:
case MESSAGE_TYPE:
fireTableCellUpdated(rowIndex, COLUMN_MESSAGE);
break;
case PRIMARY_ADDRESS_FROM:
fireTableCellUpdated(rowIndex, COLUMN_PRIMARY_FROM);
break;
case PRIMARY_ADDRESS_TO:
fireTableCellUpdated(rowIndex, COLUMN_PRIMARY_TO);
break;
case PRIMARY_DECODER_TYPE:
fireTableCellUpdated(rowIndex, COLUMN_DECODER);
break;
case SECONDARY_ADDRESS_FROM:
fireTableCellUpdated(rowIndex, COLUMN_SECONDARY_FROM);
break;
case SECONDARY_ADDRESS_TO:
fireTableCellUpdated(rowIndex, COLUMN_SECONDARY_TO);
break;
}
}
}
});
}
}