mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 17:47:32 -05:00
#90 [WIP] Adds support for attribute monitors to all of the decoder states. Updates color scheme in 'Now Playing' view for channel states. Wires selection listener for selected channel metadata to the Events and Messages views. Finalizes format for horizontal audio panels, font and coloration.
This commit is contained in:
99
src/channel/metadata/AliasedIntegerAttributeMonitor.java
Normal file
99
src/channel/metadata/AliasedIntegerAttributeMonitor.java
Normal file
@@ -0,0 +1,99 @@
|
||||
/*******************************************************************************
|
||||
* 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 alias.Alias;
|
||||
import alias.AliasList;
|
||||
import alias.id.AliasIDType;
|
||||
import sample.Listener;
|
||||
|
||||
import static alias.id.AliasIDType.*;
|
||||
|
||||
public class AliasedIntegerAttributeMonitor extends AttributeMonitor<Integer>
|
||||
{
|
||||
private static final AliasIDType[] VALID_ID_TYPES = {STATUS, LTR_NET_UID};
|
||||
|
||||
private AliasList mAliasList;
|
||||
private AliasIDType mAliasIDType;
|
||||
|
||||
/**
|
||||
* Provides monitoring of a String attribute's values with occurrence heuristics enabled and alias lookup with each
|
||||
* change in the attribute's value.
|
||||
*
|
||||
* @param attribute to monitor
|
||||
* @param listener to receive change requests
|
||||
* @param aliasList to lookup alias from
|
||||
* @param aliasIDType to determine correct alias lookup method in alias list
|
||||
*/
|
||||
public AliasedIntegerAttributeMonitor(Attribute attribute, Listener<AttributeChangeRequest> listener, AliasList aliasList,
|
||||
AliasIDType aliasIDType)
|
||||
{
|
||||
super(attribute, listener);
|
||||
|
||||
if(!isValidIDType(aliasIDType))
|
||||
{
|
||||
throw new IllegalArgumentException("Alias ID Type [" + aliasIDType.name() + "] is not supported");
|
||||
}
|
||||
mAliasList = aliasList;
|
||||
mAliasIDType = aliasIDType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the alias ID type is a supported/valid type for this monitor.
|
||||
*/
|
||||
public static boolean isValidIDType(AliasIDType type)
|
||||
{
|
||||
for(AliasIDType validType: VALID_ID_TYPES)
|
||||
{
|
||||
if(type == validType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup of the alias that corresponds to the value's alias ID type
|
||||
*/
|
||||
@Override
|
||||
protected Alias getAlias()
|
||||
{
|
||||
Alias alias = null;
|
||||
|
||||
if(mAliasList != null)
|
||||
{
|
||||
if(hasValue())
|
||||
{
|
||||
switch(mAliasIDType)
|
||||
{
|
||||
case STATUS:
|
||||
alias = mAliasList.getStatus(getValue());
|
||||
break;
|
||||
case LTR_NET_UID:
|
||||
alias = mAliasList.getUniqueID(getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
@@ -51,13 +51,15 @@ public class AttributeMonitor<T>
|
||||
* different from the current value, has a higher occurrence count than the current value. If heuristics are
|
||||
* disabled, then a change is emitted at each change in the value.
|
||||
* @param t
|
||||
*
|
||||
* @return true if the value was changed after processing
|
||||
*/
|
||||
public void process(T t)
|
||||
public boolean process(T t)
|
||||
{
|
||||
boolean changed = false;
|
||||
|
||||
if(t != null && !mIllegalValues.contains(t))
|
||||
{
|
||||
boolean changed = false;
|
||||
|
||||
if(mHeuristicsEnabled)
|
||||
{
|
||||
if(mOccurrenceCounts.containsKey(t))
|
||||
@@ -103,6 +105,8 @@ public class AttributeMonitor<T>
|
||||
mListener.receive(new AttributeChangeRequest(mAttribute, getValue(), getAlias()));
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,11 +18,13 @@
|
||||
******************************************************************************/
|
||||
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;
|
||||
@@ -30,22 +32,28 @@ import java.util.Map;
|
||||
|
||||
public class ChannelMetadataModel extends AbstractTableModel implements Listener<MutableMetadataChangeEvent>
|
||||
{
|
||||
public static final int COLUMN_STATE = 0;
|
||||
public static final int COLUMN_FREQUENCY = 1;
|
||||
public static final int COLUMN_PRIMARY = 2;
|
||||
public static final int COLUMN_SECONDARY = 3;
|
||||
public static final int COLUMN_MESSAGE = 4;
|
||||
public static final int COLUMN_NETWORK = 5;
|
||||
public static final int COLUMN_CONFIGURATION = 6;
|
||||
private final DecimalFormat FREQUENCY_FORMATTER = new DecimalFormat( "#.0000" );
|
||||
|
||||
private static final String[] COLUMNS =
|
||||
{"State", "Frequency", "Primary", "Secondary", "Message", "Network", "Configuration"};
|
||||
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
|
||||
@@ -65,6 +73,7 @@ public class ChannelMetadataModel extends AbstractTableModel implements Listener
|
||||
|
||||
public void remove(MutableMetadata metadata)
|
||||
{
|
||||
//Execute on the swing thread to avoid threading issues
|
||||
EventQueue.invokeLater(new Runnable()
|
||||
{
|
||||
@Override
|
||||
@@ -82,6 +91,27 @@ public class ChannelMetadataModel extends AbstractTableModel implements Listener
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
@@ -103,7 +133,27 @@ public class ChannelMetadataModel extends AbstractTableModel implements Listener
|
||||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex)
|
||||
{
|
||||
return MutableMetadata.class;
|
||||
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
|
||||
@@ -111,7 +161,57 @@ public class ChannelMetadataModel extends AbstractTableModel implements Listener
|
||||
{
|
||||
if(rowIndex <= mChannelMetadata.size())
|
||||
{
|
||||
return mChannelMetadata.get(rowIndex);
|
||||
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.getChannelConfigurationLabel1();
|
||||
case COLUMN_PRIMARY_TO:
|
||||
case COLUMN_PRIMARY_FROM:
|
||||
case COLUMN_SECONDARY_TO:
|
||||
case COLUMN_SECONDARY_FROM:
|
||||
return metadata;
|
||||
|
||||
default:
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -120,6 +220,7 @@ public class ChannelMetadataModel extends AbstractTableModel implements Listener
|
||||
@Override
|
||||
public void receive(MutableMetadataChangeEvent mutableMetadataChangeEvent)
|
||||
{
|
||||
//Execute on the swing thread to avoid threading issues
|
||||
EventQueue.invokeLater(new Runnable()
|
||||
{
|
||||
@Override
|
||||
@@ -132,13 +233,16 @@ public class ChannelMetadataModel extends AbstractTableModel implements Listener
|
||||
switch(mutableMetadataChangeEvent.getAttribute())
|
||||
{
|
||||
case CHANNEL_CONFIGURATION_LABEL_1:
|
||||
break;
|
||||
case CHANNEL_CONFIGURATION_LABEL_2:
|
||||
fireTableCellUpdated(rowIndex, COLUMN_CONFIGURATION);
|
||||
fireTableCellUpdated(rowIndex, COLUMN_CONFIGURATION_NAME);
|
||||
break;
|
||||
case CHANNEL_FREQUENCY:
|
||||
case CHANNEL_FREQUENCY_LABEL:
|
||||
fireTableCellUpdated(rowIndex, COLUMN_FREQUENCY);
|
||||
break;
|
||||
case CHANNEL_FREQUENCY_LABEL:
|
||||
fireTableCellUpdated(rowIndex, COLUMN_CHANNEL);
|
||||
break;
|
||||
case CHANNEL_STATE:
|
||||
fireTableCellUpdated(rowIndex, COLUMN_STATE);
|
||||
break;
|
||||
@@ -146,17 +250,20 @@ public class ChannelMetadataModel extends AbstractTableModel implements Listener
|
||||
case MESSAGE_TYPE:
|
||||
fireTableCellUpdated(rowIndex, COLUMN_MESSAGE);
|
||||
break;
|
||||
case NETWORK_ID_1:
|
||||
case NETWORK_ID_2:
|
||||
fireTableCellUpdated(rowIndex, COLUMN_NETWORK);
|
||||
break;
|
||||
case PRIMARY_ADDRESS_FROM:
|
||||
fireTableCellUpdated(rowIndex, COLUMN_PRIMARY_FROM);
|
||||
break;
|
||||
case PRIMARY_ADDRESS_TO:
|
||||
fireTableCellUpdated(rowIndex, COLUMN_PRIMARY);
|
||||
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);
|
||||
fireTableCellUpdated(rowIndex, COLUMN_SECONDARY_TO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,26 +19,39 @@
|
||||
package channel.metadata;
|
||||
|
||||
import alias.Alias;
|
||||
import channel.state.State;
|
||||
import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
|
||||
import controller.channel.Channel;
|
||||
import controller.channel.ChannelProcessingManager;
|
||||
import icon.IconManager;
|
||||
import icon.IconTableModel;
|
||||
import module.ProcessingChain;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import properties.SystemProperties;
|
||||
import sample.Broadcaster;
|
||||
import sample.Listener;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import java.awt.*;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public class ChannelMetadataPanel extends JPanel
|
||||
public class ChannelMetadataPanel extends JPanel implements ListSelectionListener
|
||||
{
|
||||
private ChannelMetadataModel mChannelMetadataModel;
|
||||
private static final String PROPERTY_PREFIX_BACKGROUND = "channel.metadata.panel.state.color.";
|
||||
private static final String PROPERTY_PREFIX_FOREGROUND = "channel.metadata.panel.text.color.";
|
||||
private ChannelProcessingManager mChannelProcessingManager;
|
||||
private IconManager mIconManager;
|
||||
private JTable mTable;
|
||||
private Broadcaster<ProcessingChain> mSelectedProcessingChainBroadcaster = new Broadcaster<>();
|
||||
|
||||
public ChannelMetadataPanel(ChannelMetadataModel channelMetadataModel, IconManager iconManager)
|
||||
/**
|
||||
* Table view for currently decoding channel metadata
|
||||
*/
|
||||
public ChannelMetadataPanel(ChannelProcessingManager channelProcessingManager, IconManager iconManager)
|
||||
{
|
||||
mChannelMetadataModel = channelMetadataModel;
|
||||
mIconManager = iconManager;
|
||||
mChannelProcessingManager = channelProcessingManager;
|
||||
|
||||
init();
|
||||
}
|
||||
@@ -50,199 +63,165 @@ public class ChannelMetadataPanel extends JPanel
|
||||
{
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[grow,fill]") );
|
||||
|
||||
mTable = new JTable(mChannelMetadataModel);
|
||||
mTable.setRowHeight(35);
|
||||
mTable = new JTable(mChannelProcessingManager.getChannelMetadataModel());
|
||||
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_STATE).setCellRenderer(new StateCellRenderer());
|
||||
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer)mTable.getDefaultRenderer(String.class);
|
||||
renderer.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_FREQUENCY)
|
||||
.setCellRenderer(new FrequencyCellRenderer());
|
||||
mTable.getSelectionModel().addListSelectionListener(this);
|
||||
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_PRIMARY)
|
||||
.setCellRenderer(new AliasedValueCellRenderer(Attribute.PRIMARY_ADDRESS_TO, Attribute.PRIMARY_ADDRESS_FROM));
|
||||
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_SECONDARY)
|
||||
.setCellRenderer(new AliasedValueCellRenderer(Attribute.SECONDARY_ADDRESS_TO, Attribute.SECONDARY_ADDRESS_FROM));
|
||||
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_MESSAGE)
|
||||
.setCellRenderer(new AliasedValueCellRenderer(Attribute.MESSAGE, Attribute.MESSAGE_TYPE));
|
||||
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_NETWORK)
|
||||
.setCellRenderer(new AliasedValueCellRenderer(Attribute.NETWORK_ID_1, Attribute.NETWORK_ID_2));
|
||||
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_CONFIGURATION)
|
||||
.setCellRenderer(new AliasedValueCellRenderer(Attribute.CHANNEL_CONFIGURATION_LABEL_1,
|
||||
Attribute.CHANNEL_CONFIGURATION_LABEL_2));
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_STATE)
|
||||
.setCellRenderer(new ColoredStateCellRenderer());
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_PRIMARY_TO)
|
||||
.setCellRenderer(new AliasedValueCellRenderer(Attribute.PRIMARY_ADDRESS_TO));
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_PRIMARY_FROM)
|
||||
.setCellRenderer(new AliasedValueCellRenderer(Attribute.PRIMARY_ADDRESS_FROM));
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_SECONDARY_TO)
|
||||
.setCellRenderer(new AliasedValueCellRenderer(Attribute.SECONDARY_ADDRESS_TO));
|
||||
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_SECONDARY_FROM)
|
||||
.setCellRenderer(new AliasedValueCellRenderer(Attribute.SECONDARY_ADDRESS_FROM));
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(mTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
|
||||
add(scrollPane);
|
||||
|
||||
// new TableColumnWidthMonitor(mTable, PROPERTY_PREFIX, new int[] {15,15,15,15,25,25,25,25,15,40});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a selection listener to the contained metadata JTable
|
||||
*/
|
||||
public void addListSelectionListener(ListSelectionListener listener)
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e)
|
||||
{
|
||||
mTable.getSelectionModel().addListSelectionListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the selection listener from the contained metadata JTable
|
||||
*/
|
||||
public void removeListSelectionListener(ListSelectionListener listener)
|
||||
{
|
||||
mTable.getSelectionModel().removeListSelectionListener(listener);
|
||||
}
|
||||
|
||||
public class AliasedValueCellRenderer extends JPanel implements TableCellRenderer
|
||||
{
|
||||
private JLabel mLabel1;
|
||||
private JLabel mAlias1;
|
||||
private JLabel mLabel2;
|
||||
private JLabel mAlias2;
|
||||
|
||||
private Attribute mAttribute1;
|
||||
private Attribute mAttribute2;
|
||||
|
||||
public AliasedValueCellRenderer(Attribute attribute1, Attribute attribute2)
|
||||
if(!mTable.getSelectionModel().getValueIsAdjusting())
|
||||
{
|
||||
mAttribute1 = attribute1;
|
||||
mAttribute2 = attribute2;
|
||||
ProcessingChain processingChain = null;
|
||||
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[12][grow,fill]", "[grow,fill]0[grow,fill]") );
|
||||
int selectedViewRow = mTable.getSelectedRow();
|
||||
|
||||
mAlias1 = new JLabel();
|
||||
add(mAlias1);
|
||||
mLabel1 = new JLabel("---");
|
||||
mLabel1.setFont(mTable.getFont());
|
||||
add(mLabel1,"wrap");
|
||||
mAlias2 = new JLabel();
|
||||
add(mAlias2);
|
||||
mLabel2 = new JLabel("---");
|
||||
mLabel2.setFont(mTable.getFont());
|
||||
add(mLabel2,"wrap");
|
||||
if(selectedViewRow >= 0)
|
||||
{
|
||||
int selectedModelRow = mTable.convertRowIndexToModel(selectedViewRow);
|
||||
|
||||
Metadata selectedMetadata = mChannelProcessingManager.getChannelMetadataModel()
|
||||
.getMetadata(selectedModelRow);
|
||||
|
||||
if(selectedMetadata != null)
|
||||
{
|
||||
Channel selectedChannel = mChannelProcessingManager.getChannelMetadataModel()
|
||||
.getChannelFromMetadata(selectedMetadata);
|
||||
|
||||
processingChain = mChannelProcessingManager.getProcessingChain(selectedChannel);
|
||||
}
|
||||
}
|
||||
|
||||
mSelectedProcessingChainBroadcaster.broadcast(processingChain);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the listener to receive the processing chain associated with the metadata selected in the
|
||||
* metadata table.
|
||||
*/
|
||||
public void addProcessingChainSelectionListener(Listener<ProcessingChain> listener)
|
||||
{
|
||||
mSelectedProcessingChainBroadcaster.addListener(listener);
|
||||
}
|
||||
|
||||
public class AliasedValueCellRenderer extends DefaultTableCellRenderer
|
||||
{
|
||||
private Attribute mAttribute;
|
||||
|
||||
public AliasedValueCellRenderer(Attribute attribute)
|
||||
{
|
||||
assert(attribute != null);
|
||||
mAttribute = attribute;
|
||||
setHorizontalAlignment(JLabel.CENTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
|
||||
int row, int column)
|
||||
{
|
||||
MutableMetadata metadata = (MutableMetadata)value;
|
||||
JLabel label = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
|
||||
if(mAttribute1 != null)
|
||||
{
|
||||
String value1 = metadata.getValue(mAttribute1);
|
||||
mLabel1.setText(value1);
|
||||
Metadata metadata = (Metadata)value;
|
||||
String value1 = metadata.getValue(mAttribute);
|
||||
Alias alias = metadata.getAlias(mAttribute);
|
||||
|
||||
Alias alias1 = metadata.getAlias(mAttribute1);
|
||||
label.setText(alias != null ? alias.getName() : value1);
|
||||
label.setIcon(alias != null ? mIconManager.getIcon(alias.getIconName(), IconManager.DEFAULT_ICON_SIZE) : null);
|
||||
label.setForeground(alias != null ? alias.getDisplayColor() : table.getForeground());
|
||||
|
||||
if(alias1 != null)
|
||||
{
|
||||
mAlias1.setIcon(mIconManager.getIcon(alias1.getIconName(), IconManager.DEFAULT_ICON_SIZE));
|
||||
mLabel1.setForeground(alias1.getDisplayColor());
|
||||
}
|
||||
else
|
||||
{
|
||||
mAlias1.setIcon(null);
|
||||
mLabel1.setForeground(mTable.getForeground());
|
||||
}
|
||||
}
|
||||
|
||||
if(mAttribute2 != null)
|
||||
{
|
||||
String value2 = metadata.getValue(mAttribute2);
|
||||
mLabel2.setText(value2);
|
||||
|
||||
Alias alias2 = metadata.getAlias(mAttribute2);
|
||||
|
||||
if(alias2 != null)
|
||||
{
|
||||
mAlias2.setIcon(mIconManager.getIcon(alias2.getIconName(), IconManager.DEFAULT_ICON_SIZE));
|
||||
mLabel2.setForeground(alias2.getDisplayColor());
|
||||
}
|
||||
else
|
||||
{
|
||||
mAlias2.setIcon(null);
|
||||
mLabel2.setForeground(mTable.getForeground());
|
||||
}
|
||||
}
|
||||
|
||||
setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
|
||||
|
||||
return this;
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
public class FrequencyCellRenderer extends JPanel implements TableCellRenderer
|
||||
public class ColoredStateCellRenderer extends DefaultTableCellRenderer
|
||||
{
|
||||
private final DecimalFormat FREQUENCY_FORMATTER = new DecimalFormat( "#.000000" );
|
||||
|
||||
private JLabel mLabel1;
|
||||
private JLabel mLabel2;
|
||||
|
||||
public FrequencyCellRenderer()
|
||||
public ColoredStateCellRenderer()
|
||||
{
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill,align center]", "[grow,fill]0[grow,fill]") );
|
||||
|
||||
mLabel1 = new JLabel();
|
||||
mLabel1.setFont(mTable.getFont());
|
||||
add(mLabel1,"wrap");
|
||||
mLabel2 = new JLabel();
|
||||
mLabel2.setFont(mTable.getFont());
|
||||
add(mLabel2);
|
||||
setHorizontalAlignment(SwingConstants.CENTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
|
||||
int row, int column)
|
||||
{
|
||||
MutableMetadata metadata = (MutableMetadata)value;
|
||||
JLabel label = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
|
||||
if(metadata.hasChannelFrequency())
|
||||
Color background = table.getBackground();
|
||||
Color foreground = table.getForeground();
|
||||
|
||||
if(value instanceof State)
|
||||
{
|
||||
mLabel1.setText(FREQUENCY_FORMATTER.format((double)metadata.getChannelFrequency() / 1E6d));
|
||||
State state = (State)value;
|
||||
label.setText(state.getDisplayValue());
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case CALL:
|
||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "call", Color.BLUE);
|
||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "call", Color.YELLOW);
|
||||
break;
|
||||
case CONTROL:
|
||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "control", Color.ORANGE);
|
||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "control", Color.BLUE);
|
||||
break;
|
||||
case DATA:
|
||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "data", Color.GREEN);
|
||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "data", Color.BLUE);
|
||||
break;
|
||||
case ENCRYPTED:
|
||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "encrypted", Color.MAGENTA);
|
||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "encrypted", Color.WHITE);
|
||||
break;
|
||||
case FADE:
|
||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "fade", Color.LIGHT_GRAY.BLUE);
|
||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "fade", Color.YELLOW);
|
||||
break;
|
||||
case IDLE:
|
||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "idle", Color.WHITE);
|
||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "idle", Color.BLUE);
|
||||
break;
|
||||
case RESET:
|
||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "reset", Color.PINK);
|
||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "reset", Color.YELLOW);
|
||||
break;
|
||||
case TEARDOWN:
|
||||
background = SystemProperties.getInstance().get(PROPERTY_PREFIX_BACKGROUND + "teardown", Color.DARK_GRAY);
|
||||
foreground = SystemProperties.getInstance().get(PROPERTY_PREFIX_FOREGROUND + "teardown", Color.WHITE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLabel1.setText(null);
|
||||
setText("");
|
||||
}
|
||||
|
||||
mLabel2.setText(metadata.getChannelFrequencyLabel());
|
||||
setBackground(background);
|
||||
setForeground(foreground);
|
||||
|
||||
setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
|
||||
|
||||
return this;
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
public class StateCellRenderer extends JPanel implements TableCellRenderer
|
||||
{
|
||||
private JLabel mLabel1;
|
||||
|
||||
public StateCellRenderer()
|
||||
{
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill,align center]", "[grow,fill,align center]") );
|
||||
|
||||
mLabel1 = new JLabel();
|
||||
mLabel1.setFont(mTable.getFont());
|
||||
add(mLabel1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
|
||||
int row, int column)
|
||||
{
|
||||
MutableMetadata metadata = (MutableMetadata)value;
|
||||
|
||||
mLabel1.setText(metadata.getState().getDisplayValue());
|
||||
|
||||
setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.jidesoft.swing.JideSplitPane;
|
||||
import com.jidesoft.swing.JideTabbedPane;
|
||||
import controller.channel.ChannelProcessingManager;
|
||||
import icon.IconManager;
|
||||
import icon.IconTableModel;
|
||||
import module.decode.event.CallEventPanel;
|
||||
import module.decode.event.MessageActivityPanel;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
@@ -30,6 +29,7 @@ import settings.SettingsManager;
|
||||
import spectrum.ChannelSpectrumPanel;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
public class ChannelMetadataViewer extends JPanel
|
||||
{
|
||||
@@ -45,11 +45,10 @@ public class ChannelMetadataViewer extends JPanel
|
||||
public ChannelMetadataViewer(ChannelProcessingManager channelProcessingManager, IconManager iconManager,
|
||||
SettingsManager settingsManager)
|
||||
{
|
||||
mCallEventPanel = new CallEventPanel(iconManager, channelProcessingManager);
|
||||
mCallEventPanel = new CallEventPanel(iconManager);
|
||||
mMessageActivityPanel = new MessageActivityPanel(channelProcessingManager);
|
||||
mChannelSpectrumPanel = new ChannelSpectrumPanel(settingsManager, channelProcessingManager);
|
||||
mChannelMetadataPanel = new ChannelMetadataPanel(channelProcessingManager.getChannelMetadataModel(),
|
||||
iconManager);
|
||||
mChannelMetadataPanel = new ChannelMetadataPanel(channelProcessingManager, iconManager);
|
||||
|
||||
init();
|
||||
}
|
||||
@@ -59,49 +58,20 @@ public class ChannelMetadataViewer extends JPanel
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[grow,fill]") );
|
||||
|
||||
JideTabbedPane tabbedPane = new JideTabbedPane();
|
||||
tabbedPane.addTab("Details", new JPanel());
|
||||
// tabbedPane.addTab("Details", new JPanel());
|
||||
tabbedPane.addTab("Events", mCallEventPanel);
|
||||
tabbedPane.addTab("Messages", mMessageActivityPanel);
|
||||
tabbedPane.addTab("Spectrum", mChannelSpectrumPanel);
|
||||
// tabbedPane.addTab("Spectrum", mChannelSpectrumPanel);
|
||||
tabbedPane.setFont(this.getFont());
|
||||
tabbedPane.setForeground(Color.BLACK);
|
||||
|
||||
JideSplitPane splitPane = new JideSplitPane(JideSplitPane.VERTICAL_SPLIT);
|
||||
splitPane.setShowGripper(true);
|
||||
splitPane.add(mChannelMetadataPanel);
|
||||
splitPane.add(tabbedPane);
|
||||
add(splitPane);
|
||||
|
||||
//TODO: move this change listener to the metadata table view
|
||||
// /**
|
||||
// * Change listener to enable/disable the channel spectrum display
|
||||
// * only when the tab is visible, and a channel has been selected
|
||||
// */
|
||||
// mTabbedPane.addChangeListener(new ChangeListener()
|
||||
// {
|
||||
// @Override
|
||||
// public void stateChanged(ChangeEvent event)
|
||||
// {
|
||||
// int index = mTabbedPane.getSelectedIndex();
|
||||
//
|
||||
// Component component = mTabbedPane.getComponentAt(index);
|
||||
//
|
||||
// if(component instanceof ChannelSpectrumPanel)
|
||||
// {
|
||||
// mChannelSpectrumPanel.setEnabled(true);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// mChannelSpectrumPanel.setEnabled(false);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
//TODO: call, message and spectrum should listen to the metadata table now
|
||||
//
|
||||
//
|
||||
// /* Register each of the components to receive channel events when the
|
||||
// * channels are selected or change */
|
||||
// mChannelModel.addListener(mCallEventPanel);
|
||||
// mChannelModel.addListener(mChannelSpectrumPanel);
|
||||
// mChannelModel.addListener(mMessageActivityPanel);
|
||||
|
||||
mChannelMetadataPanel.addProcessingChainSelectionListener(mCallEventPanel);
|
||||
mChannelMetadataPanel.addProcessingChainSelectionListener(mMessageActivityPanel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,30 +18,10 @@
|
||||
******************************************************************************/
|
||||
package channel.traffic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import channel.state.DecoderStateEvent;
|
||||
import channel.state.IDecoderStateEventListener;
|
||||
import module.Module;
|
||||
import module.decode.config.DecodeConfiguration;
|
||||
import module.decode.event.CallEvent;
|
||||
import module.decode.event.CallEvent.CallEventType;
|
||||
import module.decode.event.ICallEventProvider;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import record.config.RecordConfiguration;
|
||||
import sample.Listener;
|
||||
import source.config.SourceConfigTuner;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.TunerChannel.Type;
|
||||
import alias.Alias;
|
||||
import alias.id.priority.Priority;
|
||||
import channel.state.DecoderStateEvent;
|
||||
import channel.state.IDecoderStateEventListener;
|
||||
import controller.channel.Channel;
|
||||
import controller.channel.Channel.ChannelType;
|
||||
import controller.channel.ChannelEvent;
|
||||
@@ -49,203 +29,211 @@ import controller.channel.ChannelEvent.Event;
|
||||
import controller.channel.ChannelModel;
|
||||
import controller.channel.ChannelProcessingManager;
|
||||
import controller.channel.TrafficChannelEvent;
|
||||
import module.Module;
|
||||
import module.decode.config.DecodeConfiguration;
|
||||
import module.decode.event.CallEvent;
|
||||
import module.decode.event.CallEvent.CallEventType;
|
||||
import module.decode.event.ICallEventProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import record.config.RecordConfiguration;
|
||||
import sample.Listener;
|
||||
import source.config.SourceConfigTuner;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.TunerChannel.Type;
|
||||
|
||||
public class TrafficChannelManager extends Module
|
||||
implements ICallEventProvider, IDecoderStateEventListener
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
public class TrafficChannelManager extends Module implements ICallEventProvider, IDecoderStateEventListener
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger( TrafficChannelManager.class );
|
||||
private final static Logger mLog = LoggerFactory.getLogger(TrafficChannelManager.class);
|
||||
public static final String CHANNEL_START_REJECTED = "CHANNEL START REJECTED";
|
||||
public static final String NO_TUNER_AVAILABLE = "NO TUNER AVAILABLE";
|
||||
public static final String UNKNOWN_FREQUENCY = "UNKNOWN FREQUENCY";
|
||||
|
||||
private int mTrafficChannelPoolMaximumSize =
|
||||
DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT;
|
||||
private List<Channel> mTrafficChannelPool = new ArrayList<Channel>();
|
||||
private Map<String,Channel> mTrafficChannelsInUse = new ConcurrentHashMap<String,Channel>();
|
||||
private int mTrafficChannelPoolMaximumSize = DecodeConfiguration.TRAFFIC_CHANNEL_LIMIT_DEFAULT;
|
||||
private List<Channel> mTrafficChannelPool = new ArrayList<Channel>();
|
||||
private Map<String,Channel> mTrafficChannelsInUse = new ConcurrentHashMap<String,Channel>();
|
||||
|
||||
private DecoderStateEventListener mEventListener = new DecoderStateEventListener();
|
||||
private Listener<CallEvent> mCallEventListener;
|
||||
private DecoderStateEventListener mEventListener = new DecoderStateEventListener();
|
||||
private Listener<CallEvent> mCallEventListener;
|
||||
|
||||
private ChannelModel mChannelModel;
|
||||
private ChannelProcessingManager mChannelProcessingManager;
|
||||
private DecodeConfiguration mDecodeConfiguration;
|
||||
private RecordConfiguration mRecordConfiguration;
|
||||
private String mSystem;
|
||||
private String mSite;
|
||||
private String mAliasListName;
|
||||
private CallEvent mPreviousDoNotMonitorCallEvent;
|
||||
private ChannelModel mChannelModel;
|
||||
private ChannelProcessingManager mChannelProcessingManager;
|
||||
private DecodeConfiguration mDecodeConfiguration;
|
||||
private RecordConfiguration mRecordConfiguration;
|
||||
private String mSystem;
|
||||
private String mSite;
|
||||
private String mAliasListName;
|
||||
private CallEvent mPreviousDoNotMonitorCallEvent;
|
||||
|
||||
/**
|
||||
* Monitors call events and allocates traffic decoder channels in response
|
||||
* to traffic channel allocation call events. Manages a pool of reusable
|
||||
* traffic channel allocations.
|
||||
*
|
||||
/**
|
||||
* Monitors call events and allocates traffic decoder channels in response
|
||||
* to traffic channel allocation call events. Manages a pool of reusable
|
||||
* traffic channel allocations.
|
||||
*
|
||||
* @param channelModel containing channels currently in use
|
||||
*
|
||||
* @param channelProcessingManager
|
||||
*
|
||||
* @param decodeConfiguration - decoder configuration to use for each
|
||||
* traffic channel allocation.
|
||||
*
|
||||
* @param recordConfiguration - recording options for each traffic channel
|
||||
*
|
||||
* @param decodeConfiguration - decoder configuration to use for each
|
||||
* traffic channel allocation.
|
||||
* @param recordConfiguration - recording options for each traffic channel
|
||||
* @param system label to use to describe the system
|
||||
*
|
||||
* @param site label to use to describe the site
|
||||
*
|
||||
* @param aliasListName designated for the channel
|
||||
*
|
||||
* @param trafficChannelTimeout - millisecond call timer limit used when an
|
||||
* end of call signalling event is not decoded.
|
||||
*
|
||||
* @param trafficChannelPoolSize - maximum number of allocated traffic channels
|
||||
* in the pool
|
||||
*/
|
||||
public TrafficChannelManager( ChannelModel channelModel,
|
||||
ChannelProcessingManager channelProcessingManager,
|
||||
DecodeConfiguration decodeConfiguration,
|
||||
RecordConfiguration recordConfiguration,
|
||||
String system,
|
||||
String site,
|
||||
String aliasListName,
|
||||
long trafficChannelTimeout,
|
||||
int trafficChannelPoolSize )
|
||||
{
|
||||
mChannelModel = channelModel;
|
||||
mChannelProcessingManager = channelProcessingManager;
|
||||
mDecodeConfiguration = decodeConfiguration;
|
||||
mRecordConfiguration = recordConfiguration;
|
||||
mSystem = system;
|
||||
mSite = site;
|
||||
mAliasListName = aliasListName;
|
||||
mTrafficChannelPoolMaximumSize = trafficChannelPoolSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
for( Channel trafficChannel: mTrafficChannelPool )
|
||||
{
|
||||
mChannelModel.broadcast( new ChannelEvent( trafficChannel, Event.REQUEST_DISABLE ) );
|
||||
}
|
||||
* @param trafficChannelTimeout - millisecond call timer limit used when an
|
||||
* end of call signalling event is not decoded.
|
||||
* @param trafficChannelPoolSize - maximum number of allocated traffic channels
|
||||
* in the pool
|
||||
*/
|
||||
public TrafficChannelManager(ChannelModel channelModel,
|
||||
ChannelProcessingManager channelProcessingManager,
|
||||
DecodeConfiguration decodeConfiguration,
|
||||
RecordConfiguration recordConfiguration,
|
||||
String system,
|
||||
String site,
|
||||
String aliasListName,
|
||||
long trafficChannelTimeout,
|
||||
int trafficChannelPoolSize)
|
||||
{
|
||||
mChannelModel = channelModel;
|
||||
mChannelProcessingManager = channelProcessingManager;
|
||||
mDecodeConfiguration = decodeConfiguration;
|
||||
mRecordConfiguration = recordConfiguration;
|
||||
mSystem = system;
|
||||
mSite = site;
|
||||
mAliasListName = aliasListName;
|
||||
mTrafficChannelPoolMaximumSize = trafficChannelPoolSize;
|
||||
}
|
||||
|
||||
mTrafficChannelPool.clear();
|
||||
|
||||
mTrafficChannelsInUse.clear();
|
||||
|
||||
mCallEventListener = null;
|
||||
mDecodeConfiguration = null;
|
||||
mPreviousDoNotMonitorCallEvent = null;
|
||||
}
|
||||
@Override
|
||||
public void dispose()
|
||||
{
|
||||
for(Channel trafficChannel : mTrafficChannelPool)
|
||||
{
|
||||
mChannelModel.broadcast(new ChannelEvent(trafficChannel, Event.REQUEST_DISABLE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a channel by either reusing an existing channel or constructing
|
||||
* a new one, limited by the total number of constructed channels allowed.
|
||||
*
|
||||
* Note: you must enforce thread safety on the mTrafficChannelsInUse
|
||||
* external to this method.
|
||||
*
|
||||
* @param channelNumber
|
||||
* @param tunerChannel
|
||||
* @return
|
||||
*/
|
||||
private Channel getChannel( String channelNumber, TunerChannel tunerChannel )
|
||||
{
|
||||
Channel channel = null;
|
||||
|
||||
if( !mTrafficChannelsInUse.containsKey( channelNumber ) )
|
||||
{
|
||||
for( Channel configuredChannel: mTrafficChannelPool )
|
||||
{
|
||||
if( !configuredChannel.getEnabled() )
|
||||
{
|
||||
channel = configuredChannel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( channel == null && mTrafficChannelPool.size() < mTrafficChannelPoolMaximumSize )
|
||||
{
|
||||
channel = new Channel( "Traffic", ChannelType.TRAFFIC );
|
||||
|
||||
channel.setDecodeConfiguration( mDecodeConfiguration );
|
||||
|
||||
channel.setRecordConfiguration( mRecordConfiguration );
|
||||
|
||||
channel.setAliasListName( mAliasListName );
|
||||
|
||||
mChannelModel.addChannel( channel );
|
||||
|
||||
mTrafficChannelPool.add( channel );
|
||||
}
|
||||
mTrafficChannelPool.clear();
|
||||
|
||||
mTrafficChannelsInUse.clear();
|
||||
|
||||
mCallEventListener = null;
|
||||
mDecodeConfiguration = null;
|
||||
mPreviousDoNotMonitorCallEvent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a channel by either reusing an existing channel or constructing
|
||||
* a new one, limited by the total number of constructed channels allowed.
|
||||
*
|
||||
* Note: you must enforce thread safety on the mTrafficChannelsInUse
|
||||
* external to this method.
|
||||
*
|
||||
* @param channelNumber
|
||||
* @param tunerChannel
|
||||
* @return
|
||||
*/
|
||||
private Channel getChannel(String channelNumber, TunerChannel tunerChannel)
|
||||
{
|
||||
Channel channel = null;
|
||||
|
||||
if(!mTrafficChannelsInUse.containsKey(channelNumber))
|
||||
{
|
||||
for(Channel configuredChannel : mTrafficChannelPool)
|
||||
{
|
||||
if(!configuredChannel.getEnabled())
|
||||
{
|
||||
channel = configuredChannel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(channel == null && mTrafficChannelPool.size() < mTrafficChannelPoolMaximumSize)
|
||||
{
|
||||
channel = new Channel("Traffic", ChannelType.TRAFFIC);
|
||||
|
||||
channel.setDecodeConfiguration(mDecodeConfiguration);
|
||||
|
||||
channel.setRecordConfiguration(mRecordConfiguration);
|
||||
|
||||
channel.setAliasListName(mAliasListName);
|
||||
|
||||
mChannelModel.addChannel(channel);
|
||||
|
||||
mTrafficChannelPool.add(channel);
|
||||
}
|
||||
|
||||
/* If we have a configured channel, update metadata */
|
||||
if( channel != null )
|
||||
{
|
||||
channel.setSourceConfiguration( new SourceConfigTuner( tunerChannel ) );
|
||||
channel.setSystem( mSystem );
|
||||
channel.setSite( mSite );
|
||||
channel.setName( channelNumber );
|
||||
if(channel != null)
|
||||
{
|
||||
channel.setSourceConfiguration(new SourceConfigTuner(tunerChannel));
|
||||
channel.setSystem(mSystem);
|
||||
channel.setSite(mSite);
|
||||
channel.setName(channelNumber);
|
||||
|
||||
mChannelModel.broadcast( new ChannelEvent( channel, Event.NOTIFICATION_CONFIGURATION_CHANGE ) );
|
||||
}
|
||||
}
|
||||
mChannelModel.broadcast(new ChannelEvent(channel, Event.NOTIFICATION_CONFIGURATION_CHANGE));
|
||||
}
|
||||
}
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the event and creates a traffic channel is resources are
|
||||
* available
|
||||
*/
|
||||
private void process( TrafficChannelAllocationEvent event )
|
||||
{
|
||||
CallEvent callEvent = event.getCallEvent();
|
||||
return channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the event and creates a traffic channel is resources are
|
||||
* available
|
||||
*/
|
||||
private void process(TrafficChannelAllocationEvent event)
|
||||
{
|
||||
CallEvent callEvent = event.getCallEvent();
|
||||
|
||||
/* Check for duplicate events and suppress */
|
||||
synchronized( mTrafficChannelsInUse )
|
||||
{
|
||||
if( mTrafficChannelsInUse.containsKey( callEvent.getChannel() ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
synchronized(mTrafficChannelsInUse)
|
||||
{
|
||||
if(mTrafficChannelsInUse.containsKey(callEvent.getChannel()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long frequency = callEvent.getFrequency();
|
||||
|
||||
long frequency = callEvent.getFrequency();
|
||||
|
||||
/* Check the from/to aliases for do not monitor priority */
|
||||
if( isDoNotMonitor( callEvent ) )
|
||||
{
|
||||
callEvent.setCallEventType( CallEventType.CALL_DO_NOT_MONITOR );
|
||||
if(isDoNotMonitor(callEvent))
|
||||
{
|
||||
callEvent.setCallEventType(CallEventType.CALL_DO_NOT_MONITOR);
|
||||
|
||||
if( isSameCallEvent( mPreviousDoNotMonitorCallEvent, callEvent ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPreviousDoNotMonitorCallEvent = callEvent;
|
||||
}
|
||||
}
|
||||
else if( frequency > 0 )
|
||||
{
|
||||
Channel channel = getChannel( callEvent.getChannel(), new TunerChannel( Type.TRAFFIC,
|
||||
frequency, mDecodeConfiguration.getDecoderType().getChannelBandwidth() ) );
|
||||
if(isSameCallEvent(mPreviousDoNotMonitorCallEvent, callEvent))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPreviousDoNotMonitorCallEvent = callEvent;
|
||||
}
|
||||
}
|
||||
else if(frequency > 0)
|
||||
{
|
||||
Channel channel = getChannel(callEvent.getChannel(), new TunerChannel(Type.TRAFFIC,
|
||||
frequency, mDecodeConfiguration.getDecoderType().getChannelBandwidth()));
|
||||
|
||||
if( channel != null )
|
||||
{
|
||||
TrafficChannelEvent trafficChannelEvent =
|
||||
new TrafficChannelEvent( this, channel, Event.REQUEST_ENABLE, callEvent );
|
||||
|
||||
//Request to enable the channel
|
||||
mChannelModel.broadcast( trafficChannelEvent );
|
||||
if(channel != null)
|
||||
{
|
||||
TrafficChannelEvent trafficChannelEvent =
|
||||
new TrafficChannelEvent(this, channel, Event.REQUEST_ENABLE, callEvent);
|
||||
|
||||
if( channel.getEnabled() )
|
||||
{
|
||||
mTrafficChannelsInUse.put( callEvent.getChannel(), channel );
|
||||
}
|
||||
else
|
||||
{
|
||||
callEvent.setCallEventType( CallEventType.CALL_DETECT );
|
||||
//Request to enable the channel
|
||||
mChannelModel.broadcast(trafficChannelEvent);
|
||||
|
||||
if(channel.getEnabled())
|
||||
{
|
||||
mTrafficChannelsInUse.put(callEvent.getChannel(), channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
callEvent.setCallEventType(CallEventType.CALL_DETECT);
|
||||
|
||||
String details = callEvent.getDetails();
|
||||
|
||||
@@ -255,15 +243,14 @@ public class TrafficChannelManager extends Module
|
||||
}
|
||||
else if(!details.contains(CHANNEL_START_REJECTED))
|
||||
{
|
||||
callEvent.setDetails(new StringBuilder(CHANNEL_START_REJECTED)
|
||||
.append(" : ")
|
||||
.append(callEvent.getDetails()).toString());
|
||||
callEvent.setDetails(new StringBuilder(CHANNEL_START_REJECTED).append(" : ")
|
||||
.append(callEvent.getDetails()).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
callEvent.setCallEventType( CallEventType.CALL_DETECT );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
callEvent.setCallEventType(CallEventType.CALL_DETECT);
|
||||
|
||||
String details = callEvent.getDetails();
|
||||
|
||||
@@ -273,15 +260,14 @@ public class TrafficChannelManager extends Module
|
||||
}
|
||||
else if(!details.contains(NO_TUNER_AVAILABLE))
|
||||
{
|
||||
callEvent.setDetails(new StringBuilder(NO_TUNER_AVAILABLE)
|
||||
.append(" : ")
|
||||
.append(callEvent.getDetails()).toString());
|
||||
callEvent.setDetails(new StringBuilder(NO_TUNER_AVAILABLE).append(" : ")
|
||||
.append(callEvent.getDetails()).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
callEvent.setCallEventType( CallEventType.CALL_DETECT );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
callEvent.setCallEventType(CallEventType.CALL_DETECT);
|
||||
|
||||
String details = callEvent.getDetails();
|
||||
|
||||
@@ -291,187 +277,171 @@ public class TrafficChannelManager extends Module
|
||||
}
|
||||
else if(!details.contains(UNKNOWN_FREQUENCY))
|
||||
{
|
||||
callEvent.setDetails(new StringBuilder(UNKNOWN_FREQUENCY)
|
||||
.append(" : ")
|
||||
.append(callEvent.getDetails()).toString());
|
||||
callEvent.setDetails(new StringBuilder(UNKNOWN_FREQUENCY).append(" : ")
|
||||
.append(callEvent.getDetails()).toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Listener<CallEvent> listener = mCallEventListener;
|
||||
|
||||
if( listener != null )
|
||||
{
|
||||
listener.receive( callEvent );
|
||||
}
|
||||
}
|
||||
}
|
||||
final Listener<CallEvent> listener = mCallEventListener;
|
||||
|
||||
/**
|
||||
* Compares the call type, channel and to fields for equivalence and the
|
||||
* from field for either both null, or equivalence.
|
||||
*
|
||||
* @param e1
|
||||
* @param e2
|
||||
* @return
|
||||
*/
|
||||
public static boolean isSameCallEvent( CallEvent e1, CallEvent e2 )
|
||||
{
|
||||
if( e1 == null || e2 == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(listener != null)
|
||||
{
|
||||
listener.receive(callEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( e1.getCallEventType() != e2.getCallEventType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Compares the call type, channel and to fields for equivalence and the
|
||||
* from field for either both null, or equivalence.
|
||||
*
|
||||
* @param e1
|
||||
* @param e2
|
||||
* @return
|
||||
*/
|
||||
public static boolean isSameCallEvent(CallEvent e1, CallEvent e2)
|
||||
{
|
||||
if(e1 == null || e2 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( e1.getChannel() == null ||
|
||||
e2.getChannel() == null ||
|
||||
!e1.getChannel().contentEquals( e2.getChannel() ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( e1.getToID() == null ||
|
||||
e2.getToID() == null ||
|
||||
!e1.getToID().contentEquals( e2.getToID() ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(e1.getCallEventType() != e2.getCallEventType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( e1.getFromID() == null || e2.getFromID() == null )
|
||||
{
|
||||
if( e1.getFromID() == null && e2.getFromID() == null )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( e1.getFromID().contentEquals( e2.getFromID() ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for aliases that contain a do not follow/process priority.
|
||||
*
|
||||
* @param event
|
||||
* @return - true if there is an alias that has a do not process alias id
|
||||
*/
|
||||
private boolean isDoNotMonitor( CallEvent event )
|
||||
{
|
||||
Alias to = event.getToIDAlias();
|
||||
if(e1.getChannel() == null || e2.getChannel() == null || !e1.getChannel().contentEquals(e2.getChannel()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( to != null &&
|
||||
to.hasCallPriority() &&
|
||||
to.getCallPriority() == Priority.DO_NOT_MONITOR )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Alias from = event.getFromIDAlias();
|
||||
if(e1.getToID() == null || e2.getToID() == null || !e1.getToID().contentEquals(e2.getToID()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( from != null &&
|
||||
from.hasCallPriority() &&
|
||||
from.getCallPriority() == Priority.DO_NOT_MONITOR )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if(e1.getFromID() == null || e2.getFromID() == null)
|
||||
{
|
||||
return (e1.getFromID() == null && e2.getFromID() == null);
|
||||
}
|
||||
else if(e1.getFromID().contentEquals(e2.getFromID()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<DecoderStateEvent> getDecoderStateListener()
|
||||
{
|
||||
return mEventListener;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallEventListener( Listener<CallEvent> listener )
|
||||
{
|
||||
mCallEventListener = listener;
|
||||
}
|
||||
/**
|
||||
* Checks for aliases that contain a do not follow/process priority.
|
||||
*
|
||||
* @param event
|
||||
* @return - true if there is an alias that has a do not process alias id
|
||||
*/
|
||||
private boolean isDoNotMonitor(CallEvent event)
|
||||
{
|
||||
Alias to = event.getToIDAlias();
|
||||
|
||||
@Override
|
||||
public void removeCallEventListener( Listener<CallEvent> listener )
|
||||
{
|
||||
mCallEventListener = null;
|
||||
}
|
||||
if(to != null && to.hasCallPriority() && to.getCallPriority() == Priority.DO_NOT_MONITOR)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start( ScheduledExecutorService executor )
|
||||
{
|
||||
}
|
||||
Alias from = event.getFromIDAlias();
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if( !mTrafficChannelsInUse.isEmpty() )
|
||||
{
|
||||
List<String> channels = new ArrayList<>();
|
||||
if(from != null && from.hasCallPriority() && from.getCallPriority() == Priority.DO_NOT_MONITOR)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Listener<DecoderStateEvent> getDecoderStateListener()
|
||||
{
|
||||
return mEventListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallEventListener(Listener<CallEvent> listener)
|
||||
{
|
||||
mCallEventListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCallEventListener(Listener<CallEvent> listener)
|
||||
{
|
||||
mCallEventListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(ScheduledExecutorService executor)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if(!mTrafficChannelsInUse.isEmpty())
|
||||
{
|
||||
List<String> channels = new ArrayList<>();
|
||||
|
||||
/* Copy the keyset so we don't get concurrent modification of the map */
|
||||
channels.addAll( mTrafficChannelsInUse.keySet() );
|
||||
|
||||
for( String channel: channels )
|
||||
{
|
||||
callEnd( channel );
|
||||
}
|
||||
}
|
||||
}
|
||||
channels.addAll(mTrafficChannelsInUse.keySet());
|
||||
|
||||
/**
|
||||
* Callback used by the TrafficChannelStatusListener class to signal the
|
||||
* end of a an allocated traffic channel call event
|
||||
*
|
||||
* @param channelNumber - channel number from the call event that signaled
|
||||
* the start of a traffic channel allocation
|
||||
*/
|
||||
public void callEnd( String channelNumber )
|
||||
{
|
||||
synchronized( mTrafficChannelsInUse )
|
||||
{
|
||||
if( channelNumber != null && mTrafficChannelsInUse.containsKey( channelNumber ) )
|
||||
{
|
||||
Channel channel = mTrafficChannelsInUse.get( channelNumber );
|
||||
for(String channel : channels)
|
||||
{
|
||||
callEnd(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mChannelModel.broadcast( new ChannelEvent( channel, Event.REQUEST_DISABLE ) );
|
||||
|
||||
mTrafficChannelsInUse.remove( channelNumber );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for the decoder state event listener interface to catch
|
||||
* traffic channel allocation requests
|
||||
*/
|
||||
public class DecoderStateEventListener implements Listener<DecoderStateEvent>
|
||||
{
|
||||
@Override
|
||||
public void receive( DecoderStateEvent event )
|
||||
{
|
||||
switch( event.getEvent() )
|
||||
{
|
||||
case TRAFFIC_CHANNEL_ALLOCATION:
|
||||
process( (TrafficChannelAllocationEvent)event );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Callback used by the TrafficChannelStatusListener class to signal the
|
||||
* end of a an allocated traffic channel call event
|
||||
*
|
||||
* @param channelNumber - channel number from the call event that signaled
|
||||
* the start of a traffic channel allocation
|
||||
*/
|
||||
public void callEnd(String channelNumber)
|
||||
{
|
||||
synchronized(mTrafficChannelsInUse)
|
||||
{
|
||||
if(channelNumber != null && mTrafficChannelsInUse.containsKey(channelNumber))
|
||||
{
|
||||
Channel channel = mTrafficChannelsInUse.get(channelNumber);
|
||||
|
||||
mChannelModel.broadcast(new ChannelEvent(channel, Event.REQUEST_DISABLE));
|
||||
|
||||
mTrafficChannelsInUse.remove(channelNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper class for the decoder state event listener interface to catch
|
||||
* traffic channel allocation requests
|
||||
*/
|
||||
public class DecoderStateEventListener implements Listener<DecoderStateEvent>
|
||||
{
|
||||
@Override
|
||||
public void receive(DecoderStateEvent event)
|
||||
{
|
||||
switch(event.getEvent())
|
||||
{
|
||||
case TRAFFIC_CHANNEL_ALLOCATION:
|
||||
process((TrafficChannelAllocationEvent) event);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user