Adds message filtering, message history clear, and message history size features to the 'Messages' tab. Filter window dynamically constructs a list of filters from the primary filter and each of the auxiliary filters enabled within the currently selected/enabled processing channel.

This commit is contained in:
dennis.sheirer
2014-12-12 04:30:31 +00:00
parent 33d18b1186
commit 0d8da161e1
28 changed files with 1693 additions and 53 deletions

View File

@@ -52,7 +52,7 @@ public class ConfigurationTreePanel extends JPanel
mSystemTree.getSelectionModel().setSelectionMode(
TreeSelectionModel.SINGLE_TREE_SELECTION );
mSystemTree.setShowsRootHandles( true );
mSystemTree.addMouseListener( new Handler() );
mSystemTree.addMouseListener( new MouseHandler() );
mSystemTree.setCellRenderer( new ControllerTreeCellRenderer() );
//Give the model a reference to the tree, so that it can force newly
@@ -68,9 +68,9 @@ public class ConfigurationTreePanel extends JPanel
mSystemTree.addTreeSelectionListener( listener );
}
public class Handler implements MouseListener
public class MouseHandler implements MouseListener
{
public Handler()
public MouseHandler()
{
}

View File

@@ -21,6 +21,7 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
@@ -131,7 +132,7 @@ public class ControllerPanel extends JPanel
MapPanel mapPanel = new MapPanel( mResourceManager );
mTabbedPane.addTab( "Map", mapPanel );
/* Channel state list */
mChannelStateList = new ChannelStateList( mResourceManager.getSettingsManager() );

View File

@@ -18,8 +18,10 @@
package controller.activity;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JButton;
import javax.swing.JFrame;
@@ -63,7 +65,13 @@ public class ActivitySummaryFrame extends JFrame
} );
add( close );
setVisible( true );
EventQueue.invokeLater( new Runnable()
{
public void run()
{
setVisible( true );
}
} );
}
}

View File

@@ -25,6 +25,7 @@ import javax.swing.table.AbstractTableModel;
import message.Message;
import sample.Listener;
import filter.FilterSet;
public class MessageActivityModel extends AbstractTableModel
implements Listener<Message>
@@ -51,10 +52,41 @@ public class MessageActivityModel extends AbstractTableModel
private boolean mNewMessagesFirst = true;
private FilterSet mMessageFilter;
public MessageActivityModel( FilterSet messageFilter )
{
mMessageFilter = messageFilter;
}
public MessageActivityModel()
{
}
/**
* Clears all messages from history
*/
public void clear()
{
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
int messageCount = mMessages.size();
mMessages.clear();
fireTableRowsDeleted( 0, messageCount - 1 );
}
});
}
public FilterSet getMessageFilter()
{
return mMessageFilter;
}
public void dispose()
{
mMessages.clear();
@@ -90,18 +122,21 @@ public class MessageActivityModel extends AbstractTableModel
public void receive( final Message message )
{
EventQueue.invokeLater( new Runnable()
if( mMessageFilter.passes( message ) )
{
@Override
public void run()
{
mMessages.addFirst( message );
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
mMessages.addFirst( message );
MessageActivityModel.this.fireTableRowsInserted( 0, 0 );
MessageActivityModel.this.fireTableRowsInserted( 0, 0 );
prune();
}
} );
prune();
}
} );
}
}
private void prune()

View File

@@ -17,11 +17,37 @@
******************************************************************************/
package controller.activity;
import filter.FilterEditorPanel;
import filter.FilterSet;
import gui.SDRTrunk;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import message.Message;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jidesoft.swing.JideButton;
import com.jidesoft.swing.JideSplitButton;
import controller.channel.Channel;
import controller.channel.ChannelEvent;
import controller.channel.ChannelEvent.Event;
@@ -30,23 +56,33 @@ import controller.channel.ChannelEventListener;
public class MessageActivityPanel extends JPanel implements ChannelEventListener
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( SDRTrunk.class );
private static MessageActivityModel EMPTY_MODEL = new MessageActivityModel();
private JTable mMessageTable;
private JScrollPane mEmptyScrollPane;
private Channel mDisplayedChannel;
private MessageManagementPanel mManagementPanel = new MessageManagementPanel();
public MessageActivityPanel()
{
setLayout( new MigLayout("insets 0 0 0 0 ", "[grow,fill]", "[grow,fill]") );
setLayout( new MigLayout("insets 0 0 0 0", "[][grow,fill]", "[]0[grow,fill]") );
mEmptyScrollPane =
new JScrollPane( new JTable( new MessageActivityModel() ) );
add( mManagementPanel, "span,growx" );
mMessageTable = new JTable( EMPTY_MODEL );
add( mEmptyScrollPane );
add( new JScrollPane( mMessageTable ), "span,grow" );
}
@Override
public void channelChanged( ChannelEvent event )
{
boolean changed = false;
if( event.getEvent() == Event.CHANGE_SELECTED &&
event.getChannel().isSelected() )
{
@@ -54,18 +90,21 @@ public class MessageActivityPanel extends JPanel implements ChannelEventListener
( mDisplayedChannel != null &&
mDisplayedChannel != event.getChannel() ) )
{
removeAll();
JScrollPane scroll =
new JScrollPane( event.getChannel().getProcessingChain()
.getChannelState().getMessageActivityTable() );
add( scroll );
mDisplayedChannel = event.getChannel();
mMessageTable.setModel( event.getChannel().getProcessingChain()
.getChannelState().getMessageActivityModel() );
if( mDisplayedChannel != null )
{
mManagementPanel.enable();
}
else
{
mManagementPanel.disable();
}
revalidate();
repaint();
changed = true;
}
}
else if( event.getEvent() == Event.PROCESSING_STOPPED ||
@@ -75,12 +114,203 @@ public class MessageActivityPanel extends JPanel implements ChannelEventListener
mDisplayedChannel == event.getChannel() )
{
mDisplayedChannel = null;
removeAll();
add( mEmptyScrollPane );
revalidate();
repaint();
mMessageTable.setModel( EMPTY_MODEL );
mManagementPanel.disable();
changed = true;
}
}
if( changed )
{
revalidate();
repaint();
}
}
public class MessageManagementPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private MessageHistoryButton mHistoryButton = new MessageHistoryButton();
private MessageFilterButton mFilterButton = new MessageFilterButton();
public MessageManagementPanel()
{
setLayout( new MigLayout("insets 2 2 5 5", "[]5[left,grow]", "") );
disable();
add( mFilterButton );
add( mHistoryButton );
}
public void enable()
{
mHistoryButton.setEnabled( true );
mFilterButton.setEnabled( true );
}
public void disable()
{
mHistoryButton.setEnabled( false );
mFilterButton.setEnabled( false );
}
}
public class MessageHistoryButton extends JideSplitButton
{
private static final long serialVersionUID = 1L;
public MessageHistoryButton()
{
super( "Clear" );
JPanel historyPanel = new JPanel();
historyPanel.add( new JLabel( "Message History:" ) );
final JSlider slider = new JSlider();
slider.setMinimum( 0 );
slider.setMaximum( 2000 );
slider.setMajorTickSpacing( 500 );
slider.setPaintTicks( true );
slider.setPaintLabels( true );
slider.addMouseListener( new MouseListener()
{
@Override
public void mouseClicked( MouseEvent arg0 )
{
if( SwingUtilities.isLeftMouseButton( arg0 ) &&
arg0.getClickCount() == 2 )
{
slider.setValue( 500 ); //default
}
}
public void mouseEntered( MouseEvent arg0 ) {}
public void mouseExited( MouseEvent arg0 ) {}
public void mousePressed( MouseEvent arg0 ) {}
public void mouseReleased( MouseEvent arg0 ) {}
} );
if( mDisplayedChannel != null )
{
slider.setValue( mDisplayedChannel.getProcessingChain()
.getChannelState().getMessageActivityModel()
.getMaxMessageCount() );
}
else
{
slider.setValue( 500 );
}
slider.addChangeListener( new ChangeListener()
{
@Override
public void stateChanged( ChangeEvent arg0 )
{
if( mDisplayedChannel != null )
{
mDisplayedChannel.getProcessingChain().getChannelState()
.getMessageActivityModel()
.setMaxMessageCount( slider.getValue() );
}
}
});
historyPanel.add( slider );
add( historyPanel );
/* Clear messages */
addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
if( mDisplayedChannel != null )
{
mDisplayedChannel.getProcessingChain().getChannelState()
.getMessageActivityModel().clear();
}
}
} );
}
}
public class MessageFilterButton extends JideButton
{
private static final long serialVersionUID = 1L;
public MessageFilterButton()
{
super( "Filter" );
addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
if( mDisplayedChannel == null )
{
JOptionPane.showMessageDialog( MessageFilterButton.this,
"Please enable and select a decoding channel to "
+ "adjust the channel's message display filter" );
}
else
{
final JFrame editor = new JFrame();
editor.setTitle( "Message Filter Editor" );
editor.setSize( 600, 400 );
editor.setLocationRelativeTo( MessageFilterButton.this );
editor.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
editor.setLayout( new MigLayout( "", "[grow,fill]",
"[grow,fill][][]" ) );
@SuppressWarnings( "unchecked" )
FilterSet<Message> filter =
mDisplayedChannel
.getProcessingChain().getChannelState()
.getMessageActivityModel().getMessageFilter();
FilterEditorPanel<Message> panel =
new FilterEditorPanel<Message>( filter );
JScrollPane scroller = new JScrollPane( panel );
scroller.setViewportView( panel );
editor.add( scroller, "wrap" );
editor.add( new JLabel( "Right-click to select/deselect "
+ "all nodes" ), "wrap" );
JButton close = new JButton( "Close" );
close.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
editor.dispose();
}
} );
editor.add( close );
EventQueue.invokeLater( new Runnable()
{
public void run()
{
editor.setVisible( true );
}
} );
}
}
} );
}
}
}

View File

@@ -26,6 +26,7 @@ import java.util.concurrent.TimeUnit;
import javax.swing.JTable;
import message.Message;
import message.MessageFilterFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -45,6 +46,7 @@ import controller.activity.CallEventModel;
import controller.activity.MessageActivityModel;
import controller.channel.Channel.ChannelType;
import controller.channel.ProcessingChain;
import filter.FilterSet;
/**
* ChannelState provides a state machine for tracking a voice or data call
@@ -108,8 +110,7 @@ public abstract class ChannelState implements Listener<Message>
protected JTable mCallEventTable;
protected MessageActivityModel mMessageActivityModel =
new MessageActivityModel();
protected MessageActivityModel mMessageActivityModel;
protected JTable mMessageActivityTable;
protected ProcessingChain mProcessingChain;
@@ -130,6 +131,12 @@ public abstract class ChannelState implements Listener<Message>
SystemProperties props = SystemProperties.getInstance();
mCallFadeTimeout = props.get( "call.fade.timeout", 2000 );
mCallResetTimeout = props.get( "call.reset.timeout", 4000 );
/* Get a message filter for the primary decoder and aux decoders */
FilterSet messageFilter = MessageFilterFactory
.getMessageFilter( mProcessingChain.getChannel() );
mMessageActivityModel = new MessageActivityModel( messageFilter );
}
public void setCurrentCallEvent( CallEvent callEvent )
@@ -240,20 +247,11 @@ public abstract class ChannelState implements Listener<Message>
}
/**
* Returns the message activity model wrapped in a JTable. Although this
* may seem to violate separation between model and view, it simplifies
* retaining the JTable state for each channel by keeping a local reference
* to reuse
* Returns the message activity model.
*/
public JTable getMessageActivityTable()
public MessageActivityModel getMessageActivityModel()
{
if( mMessageActivityTable == null )
{
mMessageActivityTable = new JTable( mMessageActivityModel );
mMessageActivityTable.setAutoResizeMode( JTable.AUTO_RESIZE_LAST_COLUMN );
}
return mMessageActivityTable;
return mMessageActivityModel;
}
public void addAuxChannelState( AuxChannelState state )