mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 16:47:31 -05:00
Initial code check in continued
This commit is contained in:
177
src/controller/BaseNode.java
Normal file
177
src/controller/BaseNode.java
Normal file
@@ -0,0 +1,177 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
public class BaseNode extends DefaultMutableTreeNode
|
||||
implements Comparable<BaseNode>
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Model backing the JTree and nodes. Since we're primarily interacting
|
||||
* with the model via JTree tree nodes via context menus, injecting a
|
||||
* reference to the model facilitates nodal access to the model's methods
|
||||
*/
|
||||
protected ConfigurationControllerModel mModel = null;
|
||||
|
||||
/**
|
||||
* Implements a base node that has a reference to the underlying
|
||||
* tree data model to facilitate tree node operations from nodal context
|
||||
* menus.
|
||||
*/
|
||||
public BaseNode( Object object )
|
||||
{
|
||||
super( object );
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to return a custom icon for the node
|
||||
* @return
|
||||
*/
|
||||
public String getIconPath()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
if( getUserObject() != null )
|
||||
{
|
||||
return (String)getUserObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
return "SDRTrunk";
|
||||
}
|
||||
}
|
||||
|
||||
public JPanel getEditor()
|
||||
{
|
||||
return new EmptyEditor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparator to support nodal sorting/ordering
|
||||
*/
|
||||
@Override
|
||||
public int compareTo( BaseNode node )
|
||||
{
|
||||
return toString().compareTo( node.toString() );
|
||||
}
|
||||
|
||||
/**
|
||||
* This method only needs to be called once on the root node and all nodes
|
||||
* in the tree will then have a reference to the model via getModel()
|
||||
*/
|
||||
public void setModel( ConfigurationControllerModel model )
|
||||
{
|
||||
mModel = model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns reference to the SystemTreeModel. Only ConfigurableNode types
|
||||
* or children are allowed in this tree, so this method assumes that the
|
||||
* node or parent is of ConfigurableNode class or subclass.
|
||||
*
|
||||
* Reference to the model is required to enable node context operations
|
||||
* like adding/deleting/stopping/starting.
|
||||
*/
|
||||
public ConfigurationControllerModel getModel()
|
||||
{
|
||||
if( mModel == null )
|
||||
{
|
||||
return ((BaseNode)getParent()).getModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
return mModel;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports a context menu for any children of the BaseNode. Override the
|
||||
* method in the child node to provide a custom context menu for that node.
|
||||
*/
|
||||
public JPopupMenu getContextMenu()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes a recursive delete() on all children to perform any cleanup
|
||||
* operations prior to deleting. Override this method to perform cleanup
|
||||
* operations specific to the node. Remember to also either invoke
|
||||
* super.delete(), or specifically call .delete() on any children of the
|
||||
* node with the custom delete method.
|
||||
*/
|
||||
public void delete()
|
||||
{
|
||||
for( int x = 0; x < getChildCount(); x++ )
|
||||
{
|
||||
BaseNode node = (BaseNode)getChildAt( x );
|
||||
|
||||
//Tell the node to delete its children
|
||||
node.delete();
|
||||
|
||||
//Delete the child node
|
||||
getModel().deleteNode( node );
|
||||
}
|
||||
}
|
||||
|
||||
public void show()
|
||||
{
|
||||
getModel().showNode( this );
|
||||
}
|
||||
|
||||
public void refresh()
|
||||
{
|
||||
getModel().nodeChanged( this );
|
||||
}
|
||||
|
||||
public void sort()
|
||||
{
|
||||
List<BaseNode> nodesToSort = new ArrayList<BaseNode>();
|
||||
|
||||
while( children().hasMoreElements() )
|
||||
{
|
||||
BaseNode child = (BaseNode)children().nextElement();
|
||||
|
||||
nodesToSort.add( child );
|
||||
|
||||
getModel().removeNodeFromParent( child );
|
||||
}
|
||||
|
||||
if( !nodesToSort.isEmpty() )
|
||||
{
|
||||
Collections.sort( nodesToSort );
|
||||
|
||||
for( BaseNode node: nodesToSort )
|
||||
{
|
||||
getModel().insertNodeInto( node, this, getChildCount() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
src/controller/ConfigurableNode.java
Normal file
44
src/controller/ConfigurableNode.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
|
||||
public abstract class ConfigurableNode extends BaseNode
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ConfigurableNode( Object object )
|
||||
{
|
||||
super( object );
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves changes to the node
|
||||
*/
|
||||
public void save()
|
||||
{
|
||||
getModel().getResourceManager().getPlaylistManager().save();
|
||||
|
||||
BaseNode parent = (BaseNode)getParent();
|
||||
|
||||
if( parent instanceof ConfigurableNode )
|
||||
{
|
||||
((ConfigurableNode)parent).sort();
|
||||
}
|
||||
}
|
||||
}
|
||||
280
src/controller/ConfigurationControllerModel.java
Normal file
280
src/controller/ConfigurationControllerModel.java
Normal file
@@ -0,0 +1,280 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.MutableTreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import map.IconManager;
|
||||
import playlist.PlaylistNode;
|
||||
import source.config.SourceConfigTuner;
|
||||
import source.tuner.Tuner;
|
||||
import source.tuner.TunerGroupNode;
|
||||
import source.tuner.TunerNode;
|
||||
import source.tuner.TunerSelectionListener;
|
||||
import controller.channel.Channel;
|
||||
import controller.channel.ChannelListener;
|
||||
import controller.channel.ChannelNode;
|
||||
import controller.site.Site;
|
||||
import controller.system.System;
|
||||
import controller.system.SystemListNode;
|
||||
import controller.system.SystemNode;
|
||||
import decode.DecoderType;
|
||||
import decode.config.DecodeConfigFactory;
|
||||
|
||||
public class ConfigurationControllerModel extends DefaultTreeModel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private JTree mTree;
|
||||
|
||||
private ResourceManager mResourceManager;
|
||||
|
||||
private ArrayList<ChannelListener> mChannelConfigChangeListeners =
|
||||
new ArrayList<ChannelListener>();
|
||||
|
||||
private ArrayList<TunerSelectionListener> mTunerSelectionListeners =
|
||||
new ArrayList<TunerSelectionListener>();
|
||||
|
||||
|
||||
private PlaylistNode mPlaylistNode;
|
||||
|
||||
private TunerGroupNode mTunerGroupNode;
|
||||
|
||||
private IconManager mIconManagerFrame;
|
||||
|
||||
/**
|
||||
* Implements a merged system controller and (tree) model. The user will
|
||||
* primarily interact with the system nodes via the tree view, so from a
|
||||
* design perspective, the model and the control are necessarily merged to
|
||||
* work well with the JTree as the system view.
|
||||
*/
|
||||
public ConfigurationControllerModel( ResourceManager resourceManager )
|
||||
{
|
||||
super( new BaseNode( null ) );
|
||||
|
||||
mResourceManager = resourceManager;
|
||||
|
||||
/**
|
||||
* Give the root node a reference to this model, so that all nodes can
|
||||
* invoke add/delete operations on the tree via context menu
|
||||
*/
|
||||
((BaseNode)getRoot()).setModel( this );
|
||||
}
|
||||
|
||||
public JTree getTree()
|
||||
{
|
||||
return mTree;
|
||||
}
|
||||
|
||||
public void showIconManager()
|
||||
{
|
||||
if( mIconManagerFrame == null )
|
||||
{
|
||||
mIconManagerFrame = new IconManager( mResourceManager, mTree );
|
||||
|
||||
mResourceManager.getSettingsManager().addListener( mIconManagerFrame );
|
||||
}
|
||||
|
||||
if( !mIconManagerFrame.isVisible() )
|
||||
{
|
||||
mIconManagerFrame.setVisible( true );
|
||||
}
|
||||
|
||||
mIconManagerFrame.toFront();
|
||||
}
|
||||
|
||||
/**
|
||||
* init() gets invoked manually/externally, after all of the references
|
||||
* are established in the constructor
|
||||
*/
|
||||
public void init()
|
||||
{
|
||||
/**
|
||||
* Add the root tuner group node
|
||||
*/
|
||||
mTunerGroupNode = new TunerGroupNode();
|
||||
insertNodeInto( mTunerGroupNode, (MutableTreeNode)root, 0 );
|
||||
addTuners( mTunerGroupNode );
|
||||
|
||||
/**
|
||||
* Add the playlist node
|
||||
*/
|
||||
mPlaylistNode = new PlaylistNode();
|
||||
insertNodeInto( mPlaylistNode, (MutableTreeNode)root, 1 );
|
||||
mPlaylistNode.loadPlaylist();
|
||||
}
|
||||
|
||||
public void showNode( DefaultMutableTreeNode node )
|
||||
{
|
||||
if( mTree != null && node != null )
|
||||
{
|
||||
mTree.setSelectionPath( new TreePath( node.getPath() ) );
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceManager getResourceManager()
|
||||
{
|
||||
return mResourceManager;
|
||||
}
|
||||
|
||||
public void setTree( JTree tree )
|
||||
{
|
||||
mTree = tree;
|
||||
}
|
||||
|
||||
private void addTuners( TunerGroupNode parent )
|
||||
{
|
||||
List<Tuner> tuners = mResourceManager.getTunerManager().getTuners();
|
||||
|
||||
for( Tuner tuner: tuners )
|
||||
{
|
||||
TunerNode child = new TunerNode( tuner );
|
||||
|
||||
insertNodeInto( child, parent, parent.getChildCount() );
|
||||
|
||||
parent.sort();
|
||||
|
||||
show( child );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add a new default system, site and channel to
|
||||
* the tree
|
||||
*/
|
||||
public void createChannel( int frequency, DecoderType decoder )
|
||||
{
|
||||
System system = new System();
|
||||
|
||||
Site site = new Site();
|
||||
system.addSite( site );
|
||||
|
||||
Channel channel = new Channel();
|
||||
channel.setDecodeConfiguration(
|
||||
DecodeConfigFactory.getDecodeConfiguration( decoder ) );
|
||||
SourceConfigTuner sourceConfig = new SourceConfigTuner();
|
||||
sourceConfig.setFrequency( frequency );
|
||||
channel.setSourceConfiguration( sourceConfig );
|
||||
channel.setEnabled( true, true );
|
||||
site.addChannel( channel );
|
||||
|
||||
mPlaylistNode.getPlaylist().getSystemList().addSystem( system );
|
||||
|
||||
SystemNode systemNode = new SystemNode( system );
|
||||
SystemListNode systemListNode = mPlaylistNode.getSystemListNode();
|
||||
addNode( systemNode, systemListNode, systemListNode.getChildCount() );
|
||||
systemNode.init();
|
||||
|
||||
systemNode.save();
|
||||
}
|
||||
|
||||
public void addNode( BaseNode child, BaseNode parent, int index )
|
||||
{
|
||||
insertNodeInto( child, parent, index );
|
||||
show( child );
|
||||
}
|
||||
|
||||
public void deleteNode( BaseNode node )
|
||||
{
|
||||
node.delete();
|
||||
}
|
||||
|
||||
private void show( BaseNode node )
|
||||
{
|
||||
if( mTree != null )
|
||||
{
|
||||
mTree.scrollPathToVisible( new TreePath( node.getPath() ) );
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener( TunerSelectionListener listener )
|
||||
{
|
||||
mTunerSelectionListeners.add( listener );
|
||||
}
|
||||
|
||||
public void removeListener( TunerSelectionListener listener )
|
||||
{
|
||||
mTunerSelectionListeners.remove( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies registered listeners that the tuner has been selected
|
||||
*/
|
||||
public void fireTunerSelectedEvent( Tuner tuner )
|
||||
{
|
||||
Iterator<TunerSelectionListener> it =
|
||||
mTunerSelectionListeners.iterator();
|
||||
|
||||
while( it.hasNext() )
|
||||
{
|
||||
it.next().tunerSelected( tuner );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires a tuner selection event for the first tuner listed in the tree.
|
||||
* This is mainly used on application startup to show the spectral display
|
||||
* of the first tuner in the spectrum panel.
|
||||
*/
|
||||
public void fireFirstTunerSelected()
|
||||
{
|
||||
if( mTunerGroupNode.getChildCount() > 0 )
|
||||
{
|
||||
TunerNode node = (TunerNode)mTunerGroupNode.getChildAt( 0 );
|
||||
|
||||
fireTunerSelectedEvent( node.getTuner() );
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<Channel> getCurrentChannelConfigs()
|
||||
{
|
||||
return getChannelConfigs( mPlaylistNode );
|
||||
}
|
||||
|
||||
private ArrayList<Channel> getChannelConfigs( DefaultMutableTreeNode parent )
|
||||
{
|
||||
ArrayList<Channel> configs = new ArrayList<Channel>();
|
||||
|
||||
Enumeration<DefaultMutableTreeNode> nodes = parent.children();
|
||||
|
||||
while( nodes.hasMoreElements() )
|
||||
{
|
||||
DefaultMutableTreeNode node = nodes.nextElement();
|
||||
|
||||
if( node instanceof ChannelNode )
|
||||
{
|
||||
configs.add( ((ChannelNode)node).getChannel() );
|
||||
}
|
||||
|
||||
//Recursive call
|
||||
configs.addAll( getChannelConfigs( node ) );
|
||||
}
|
||||
|
||||
return configs;
|
||||
}
|
||||
}
|
||||
75
src/controller/ConfigurationEditor.java
Normal file
75
src/controller/ConfigurationEditor.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
|
||||
public class ConfigurationEditor extends JPanel
|
||||
implements TreeSelectionListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Host for configuration editor display panels
|
||||
*/
|
||||
public ConfigurationEditor()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
setPanel( new EmptyEditor() );
|
||||
}
|
||||
|
||||
public void setPanel( JPanel display )
|
||||
{
|
||||
removeAll();
|
||||
|
||||
setLayout( new BorderLayout() );
|
||||
|
||||
JScrollPane scroll = new JScrollPane( display );
|
||||
|
||||
add( scroll, BorderLayout.CENTER );
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChanged( TreeSelectionEvent e )
|
||||
{
|
||||
JTree tree = (JTree)e.getSource();
|
||||
|
||||
BaseNode node =
|
||||
(BaseNode)tree.getLastSelectedPathComponent();
|
||||
|
||||
if( node != null )
|
||||
{
|
||||
setPanel( node.getEditor() );
|
||||
}
|
||||
}
|
||||
}
|
||||
117
src/controller/ConfigurationTreePanel.java
Normal file
117
src/controller/ConfigurationTreePanel.java
Normal file
@@ -0,0 +1,117 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
import javax.swing.tree.TreeSelectionModel;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
public class ConfigurationTreePanel extends JPanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected JTree mSystemTree;
|
||||
protected ConfigurationControllerModel mTreeModel;
|
||||
|
||||
public ConfigurationTreePanel( ConfigurationControllerModel model )
|
||||
{
|
||||
mTreeModel = model;
|
||||
|
||||
initGUI();
|
||||
}
|
||||
|
||||
private void initGUI()
|
||||
{
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[grow,fill][]") );
|
||||
|
||||
mSystemTree = new JTree( mTreeModel );
|
||||
mSystemTree.getSelectionModel().setSelectionMode(
|
||||
TreeSelectionModel.SINGLE_TREE_SELECTION );
|
||||
mSystemTree.setShowsRootHandles( true );
|
||||
mSystemTree.addMouseListener( new Handler() );
|
||||
mSystemTree.setCellRenderer( new ControllerTreeCellRenderer() );
|
||||
|
||||
//Give the model a reference to the tree, so that it can force newly
|
||||
//added nodes to be displayed
|
||||
mTreeModel.setTree( mSystemTree );
|
||||
|
||||
JScrollPane treeScroll = new JScrollPane( mSystemTree );
|
||||
add( treeScroll, "cell 0 0,span,grow" );
|
||||
}
|
||||
|
||||
public void addTreeSelectionListener( TreeSelectionListener listener )
|
||||
{
|
||||
mSystemTree.addTreeSelectionListener( listener );
|
||||
}
|
||||
|
||||
public class Handler implements MouseListener
|
||||
{
|
||||
public Handler()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked( MouseEvent event )
|
||||
{
|
||||
if( SwingUtilities.isRightMouseButton( event ) )
|
||||
{
|
||||
int row = mSystemTree.getRowForLocation( event.getX(),
|
||||
event.getY() );
|
||||
|
||||
if( row != -1 )
|
||||
{
|
||||
mSystemTree.setSelectionRow( row );
|
||||
|
||||
Object selectedNode =
|
||||
mSystemTree.getLastSelectedPathComponent();
|
||||
|
||||
if( selectedNode instanceof BaseNode )
|
||||
{
|
||||
JPopupMenu contextMenu =
|
||||
((BaseNode)selectedNode).getContextMenu();
|
||||
|
||||
if( contextMenu != null )
|
||||
{
|
||||
contextMenu.show( mSystemTree,
|
||||
event.getX(),
|
||||
event.getY() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ){}
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ){}
|
||||
@Override
|
||||
public void mouseEntered( MouseEvent e ){}
|
||||
@Override
|
||||
public void mouseExited( MouseEvent e ){}
|
||||
}
|
||||
}
|
||||
134
src/controller/ControllerPanel.java
Normal file
134
src/controller/ControllerPanel.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
|
||||
import map.MapPanel;
|
||||
import message.Message;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import sample.Listener;
|
||||
|
||||
import com.jidesoft.swing.JideSplitPane;
|
||||
import com.jidesoft.swing.JideTabbedPane;
|
||||
|
||||
import controller.activity.CallEventPanel;
|
||||
import controller.activity.MessageActivityPanel;
|
||||
import controller.state.ChannelStateList;
|
||||
|
||||
public class ControllerPanel extends JPanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ChannelStateList mChannelStateList;
|
||||
|
||||
private CallEventPanel mCallEventPanel = new CallEventPanel();
|
||||
|
||||
private MessageActivityPanel mMessageActivityPanel =
|
||||
new MessageActivityPanel();
|
||||
|
||||
private JideTabbedPane mTabbedPane;
|
||||
|
||||
protected ConfigurationTreePanel mSystemControlViewPanel;
|
||||
protected ConfigurationEditor mConfigurationEditor;
|
||||
protected JideSplitPane mSystemControlSplitPane;
|
||||
|
||||
protected JTable mChannelActivityTable = new JTable();
|
||||
protected ResourceManager mResourceManager;
|
||||
|
||||
public ControllerPanel( ResourceManager resourceManager )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "insets 0 0 0 0 ",
|
||||
"[grow,fill]",
|
||||
"[grow,fill]") );
|
||||
|
||||
//System Configuration View and Editor
|
||||
mConfigurationEditor = new ConfigurationEditor();
|
||||
mSystemControlViewPanel =
|
||||
new ConfigurationTreePanel( mResourceManager.getController() );
|
||||
mSystemControlViewPanel.addTreeSelectionListener( mConfigurationEditor );
|
||||
|
||||
mSystemControlSplitPane = new JideSplitPane( JideSplitPane.HORIZONTAL_SPLIT );
|
||||
mSystemControlSplitPane.setDividerSize( 5 );
|
||||
mSystemControlSplitPane.add( mSystemControlViewPanel );
|
||||
mSystemControlSplitPane.add( mConfigurationEditor );
|
||||
|
||||
//Tabbed View - configuration, calls, messages, map
|
||||
mTabbedPane = new JideTabbedPane();
|
||||
mTabbedPane.setFont( this.getFont() );
|
||||
mTabbedPane.setForeground( Color.BLACK );
|
||||
mTabbedPane.addTab( "Configuration", mSystemControlSplitPane );
|
||||
mTabbedPane.addTab( "Calls", mCallEventPanel );
|
||||
mTabbedPane.addTab( "Messages", mMessageActivityPanel );
|
||||
|
||||
/**
|
||||
* Add mapping services and map panel to a new tab
|
||||
*/
|
||||
|
||||
/* Add Map Service as message listener to receive all messages */
|
||||
mResourceManager.getChannelManager().addListener(
|
||||
(Listener<Message>)mResourceManager.getMapService() );
|
||||
|
||||
MapPanel mapPanel = new MapPanel( mResourceManager );
|
||||
mTabbedPane.addTab( "Map", mapPanel );
|
||||
|
||||
|
||||
/* Channel state list */
|
||||
mChannelStateList = new ChannelStateList( mResourceManager.getSettingsManager() );
|
||||
|
||||
/* Add message activity panel to receive channel selection events so
|
||||
* that we can display the correct message listings */
|
||||
mResourceManager.getChannelManager().addListener( mMessageActivityPanel );
|
||||
|
||||
/* Add call event panel to receive channel selection events so
|
||||
* that we can display the correct call event listings */
|
||||
mResourceManager.getChannelManager().addListener( mCallEventPanel );
|
||||
|
||||
/* Register ChannelStateList as a listener on the channel manager to
|
||||
* receive channel starts and stops and deletes */
|
||||
mResourceManager.getChannelManager().addListener( mChannelStateList );
|
||||
|
||||
JScrollPane channelStateListScroll = new JScrollPane();
|
||||
channelStateListScroll.getViewport().setView( mChannelStateList );
|
||||
channelStateListScroll.setPreferredSize( new Dimension( 150,
|
||||
(int)channelStateListScroll.getPreferredSize().getHeight() ) );
|
||||
|
||||
JideSplitPane channelSplit = new JideSplitPane( JideSplitPane.HORIZONTAL_SPLIT );
|
||||
channelSplit.setDividerSize( 5 );
|
||||
channelSplit.add( channelStateListScroll );
|
||||
channelSplit.add( mTabbedPane );
|
||||
|
||||
add( channelSplit );
|
||||
}
|
||||
|
||||
public ConfigurationControllerModel getController()
|
||||
{
|
||||
return mResourceManager.getController();
|
||||
}
|
||||
}
|
||||
106
src/controller/ControllerTreeCellRenderer.java
Normal file
106
src/controller/ControllerTreeCellRenderer.java
Normal file
@@ -0,0 +1,106 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Image;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
|
||||
public class ControllerTreeCellRenderer extends DefaultTreeCellRenderer
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final int MAX_ICON_HEIGHT = 16;
|
||||
private HashMap<String,ImageIcon> mIcons = new HashMap<String,ImageIcon>();
|
||||
|
||||
public ControllerTreeCellRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent( JTree tree,
|
||||
Object value, boolean selected, boolean expanded, boolean isLeaf,
|
||||
int row, boolean focused )
|
||||
{
|
||||
Component c = super.getTreeCellRendererComponent( tree, value, selected,
|
||||
expanded, isLeaf, row, focused );
|
||||
|
||||
if( value instanceof BaseNode )
|
||||
{
|
||||
ImageIcon icon = getIcon( (BaseNode)value );
|
||||
|
||||
if( icon != null )
|
||||
{
|
||||
if( icon.getIconHeight() > 16 )
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
setIcon( icon );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
private ImageIcon getIcon( BaseNode node )
|
||||
{
|
||||
ImageIcon icon = null;
|
||||
|
||||
String filepath = node.getIconPath();
|
||||
|
||||
if( filepath != null )
|
||||
{
|
||||
if( mIcons.containsKey( filepath ) )
|
||||
{
|
||||
icon = mIcons.get( filepath );
|
||||
}
|
||||
else
|
||||
{
|
||||
icon = new ImageIcon( filepath );
|
||||
|
||||
if( icon.getIconHeight() > MAX_ICON_HEIGHT )
|
||||
{
|
||||
Image image = icon.getImage();
|
||||
|
||||
double scale = (double)icon.getIconHeight() / (double)MAX_ICON_HEIGHT;
|
||||
|
||||
int scaledWidth = (int)( (double)icon.getIconWidth() / scale );
|
||||
|
||||
Image scaledImage = image.getScaledInstance( scaledWidth,
|
||||
MAX_ICON_HEIGHT, java.awt.Image.SCALE_SMOOTH );
|
||||
|
||||
mIcons.put( filepath, new ImageIcon( scaledImage ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mIcons.put( filepath, icon );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
36
src/controller/Editor.java
Normal file
36
src/controller/Editor.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
public abstract class Editor extends JPanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public Editor()
|
||||
{
|
||||
setLayout( new MigLayout() );
|
||||
}
|
||||
|
||||
public abstract void save();
|
||||
|
||||
public abstract void reset();
|
||||
}
|
||||
59
src/controller/EmptyEditor.java
Normal file
59
src/controller/EmptyEditor.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class EmptyEditor extends JPanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public EmptyEditor()
|
||||
{
|
||||
setLayout( new BorderLayout() );
|
||||
setPreferredSize( new Dimension( 200, (int)getPreferredSize().getHeight() ) );
|
||||
|
||||
String text = "<html>"
|
||||
+ "<p>SDR Trunk</p>"
|
||||
+ "<br>"
|
||||
+ "<p>Use the tree structure to the left to configure SDRTrunk"
|
||||
+ " to use multiple SDR tuners and sound card sources to"
|
||||
+ " decode multiple trunked and digital radio channels.</p>"
|
||||
+ "<br>"
|
||||
+ "<p>Each tree branch can be accessed by clicking on the branch"
|
||||
+ " and a configuration editor will appear here.</p>"
|
||||
+ "<br>"
|
||||
+ "<p>Many of the branches contain context sensitive menus that "
|
||||
+ " you can access by right-clicking on the node.</p>"
|
||||
+ "<br>"
|
||||
+ "<p>To begin, right-click on the 'Systems' branch under 'Playlist'"
|
||||
+ "and create a new 'System'. Right-click the 'System' node to create "
|
||||
+ "a new 'Site'. Right-click on the 'Site' node to create a new Channel.</p>"
|
||||
+ "<br>"
|
||||
+ "<p>In the new channel, select a channel source and decoder "
|
||||
+ "and select event logging and recording options. Check 'Enabled'"
|
||||
+ " and hit the 'Save' button to begin decoding.</p>"
|
||||
+ "</html>";
|
||||
|
||||
add( new JLabel( text ), BorderLayout.NORTH );
|
||||
}
|
||||
}
|
||||
159
src/controller/ResourceManager.java
Normal file
159
src/controller/ResourceManager.java
Normal file
@@ -0,0 +1,159 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import map.MapService;
|
||||
import playlist.PlaylistManager;
|
||||
import record.RecorderManager;
|
||||
import settings.SettingsManager;
|
||||
import source.SourceManager;
|
||||
import source.tuner.TunerManager;
|
||||
import controller.channel.ChannelManager;
|
||||
import eventlog.EventLogManager;
|
||||
|
||||
/**
|
||||
* Manager for system wide resources
|
||||
*/
|
||||
public class ResourceManager
|
||||
{
|
||||
private ChannelManager mChannelManager;
|
||||
private EventLogManager mEventLogManager;
|
||||
private PlaylistManager mPlaylistManager;
|
||||
private RecorderManager mRecorderManager;
|
||||
private SettingsManager mSettingsManager;
|
||||
private SourceManager mSourceManager;
|
||||
private TunerManager mTunerManager;
|
||||
private ConfigurationControllerModel mController;
|
||||
private MapService mMapService;
|
||||
private ThreadPoolManager mThreadPoolManager;
|
||||
|
||||
public ResourceManager()
|
||||
{
|
||||
this( new SettingsManager(),
|
||||
new PlaylistManager(),
|
||||
new EventLogManager(),
|
||||
new RecorderManager() );
|
||||
}
|
||||
|
||||
public ResourceManager( SettingsManager settingsManager,
|
||||
PlaylistManager playlistManager,
|
||||
EventLogManager eventLogManager,
|
||||
RecorderManager recorderManager )
|
||||
{
|
||||
mSettingsManager = settingsManager;
|
||||
mPlaylistManager = playlistManager;
|
||||
mEventLogManager = eventLogManager;
|
||||
mRecorderManager = recorderManager;
|
||||
|
||||
/**
|
||||
* ChannelManager requires a reference to the ResourceManager so that
|
||||
* channel processing chains can access system wide resources
|
||||
*/
|
||||
mChannelManager = new ChannelManager( this );
|
||||
mSourceManager = new SourceManager( this );
|
||||
mTunerManager = new TunerManager( this );
|
||||
mController = new ConfigurationControllerModel( this );
|
||||
mMapService = new MapService( this );
|
||||
mThreadPoolManager = new ThreadPoolManager();
|
||||
}
|
||||
|
||||
public ConfigurationControllerModel getController()
|
||||
{
|
||||
return mController;
|
||||
}
|
||||
|
||||
public ThreadPoolManager getThreadPoolManager()
|
||||
{
|
||||
return mThreadPoolManager;
|
||||
}
|
||||
|
||||
public void setController( ConfigurationControllerModel controller )
|
||||
{
|
||||
mController = controller;
|
||||
}
|
||||
|
||||
public TunerManager getTunerManager()
|
||||
{
|
||||
return mTunerManager;
|
||||
}
|
||||
|
||||
public MapService getMapService()
|
||||
{
|
||||
return mMapService;
|
||||
}
|
||||
|
||||
public SettingsManager getSettingsManager()
|
||||
{
|
||||
return mSettingsManager;
|
||||
}
|
||||
|
||||
public void setSettingsManager( SettingsManager manager )
|
||||
{
|
||||
mSettingsManager = manager;
|
||||
}
|
||||
|
||||
public PlaylistManager getPlaylistManager()
|
||||
{
|
||||
return mPlaylistManager;
|
||||
}
|
||||
|
||||
public void setPlaylistManager( PlaylistManager aliasManager )
|
||||
{
|
||||
mPlaylistManager = aliasManager;
|
||||
}
|
||||
|
||||
public EventLogManager getEventLogManager()
|
||||
{
|
||||
return mEventLogManager;
|
||||
}
|
||||
|
||||
public void setEventLogManager( EventLogManager eventLogManager )
|
||||
{
|
||||
mEventLogManager = eventLogManager;
|
||||
}
|
||||
|
||||
public RecorderManager getRecorderManager()
|
||||
{
|
||||
return mRecorderManager;
|
||||
}
|
||||
|
||||
public void setRecorderManager( RecorderManager recorderManager )
|
||||
{
|
||||
mRecorderManager = recorderManager;
|
||||
}
|
||||
|
||||
public SourceManager getSourceManager()
|
||||
{
|
||||
return mSourceManager;
|
||||
}
|
||||
|
||||
public void setSourceManager( SourceManager sourceManager )
|
||||
{
|
||||
mSourceManager = sourceManager;
|
||||
}
|
||||
|
||||
public ChannelManager getChannelManager()
|
||||
{
|
||||
return mChannelManager;
|
||||
}
|
||||
|
||||
public void setChannelManager( ChannelManager channelManager )
|
||||
{
|
||||
mChannelManager = channelManager;
|
||||
}
|
||||
}
|
||||
97
src/controller/ThreadPoolManager.java
Normal file
97
src/controller/ThreadPoolManager.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ThreadPoolManager
|
||||
{
|
||||
private int THREAD_POOL_SIZE = 10;
|
||||
private int MAX_TASK_COUNT = 24;
|
||||
|
||||
private HashMap<ScheduledFuture<?>,ThreadType> mTasks =
|
||||
new HashMap<ScheduledFuture<?>,ThreadType>();
|
||||
|
||||
private ScheduledExecutorService mExecutor;
|
||||
|
||||
public ThreadPoolManager()
|
||||
{
|
||||
}
|
||||
|
||||
public ScheduledFuture<?> schedule( ThreadType type,
|
||||
Runnable command,
|
||||
long period,
|
||||
TimeUnit unit )
|
||||
throws RejectedExecutionException
|
||||
{
|
||||
if( mExecutor == null )
|
||||
{
|
||||
mExecutor = Executors.newScheduledThreadPool( THREAD_POOL_SIZE );
|
||||
}
|
||||
|
||||
if( mTasks.size() <= MAX_TASK_COUNT )
|
||||
{
|
||||
ScheduledFuture<?> task =
|
||||
mExecutor.scheduleAtFixedRate( command, 0, period, unit );
|
||||
|
||||
mTasks.put( task, type );
|
||||
|
||||
return task;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RejectedExecutionException( "Cannot schedule task - at "
|
||||
+ "max task count [" + mTasks.size() + "]" );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void cancel( ScheduledFuture<?> task )
|
||||
{
|
||||
task.cancel( true );
|
||||
|
||||
ThreadType type = mTasks.remove( task );
|
||||
}
|
||||
|
||||
public int getTaskCount( ThreadType type )
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for( ThreadType current: mTasks.values() )
|
||||
{
|
||||
if( current == type )
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public enum ThreadType
|
||||
{
|
||||
SOURCE_SAMPLE_PROCESSING,
|
||||
DECIMATION,
|
||||
DECODER;
|
||||
}
|
||||
}
|
||||
69
src/controller/activity/ActivitySummaryFrame.java
Normal file
69
src/controller/activity/ActivitySummaryFrame.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.activity;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
public class ActivitySummaryFrame extends JFrame
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ActivitySummaryFrame( String summary )
|
||||
{
|
||||
this( summary, null );
|
||||
}
|
||||
|
||||
public ActivitySummaryFrame( String summary, Component displayOver )
|
||||
{
|
||||
setTitle( "Activity Summary" );
|
||||
setLocationRelativeTo( displayOver );
|
||||
setSize( 400, 400 );
|
||||
setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
|
||||
setLayout( new MigLayout( "", "[grow,fill]", "[grow,fill][]" ) );
|
||||
|
||||
JTextArea summaryText = new JTextArea( summary );
|
||||
|
||||
JScrollPane scroller = new JScrollPane( summaryText );
|
||||
scroller.setViewportView( summaryText );
|
||||
|
||||
add( scroller, "wrap" );
|
||||
|
||||
JButton close = new JButton( "Close" );
|
||||
close.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
dispose();
|
||||
}
|
||||
} );
|
||||
|
||||
add( close );
|
||||
|
||||
setVisible( true );
|
||||
}
|
||||
}
|
||||
26
src/controller/activity/ActivitySummaryProvider.java
Normal file
26
src/controller/activity/ActivitySummaryProvider.java
Normal file
@@ -0,0 +1,26 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.activity;
|
||||
|
||||
import message.Message;
|
||||
import sample.Listener;
|
||||
|
||||
public interface ActivitySummaryProvider extends Listener<Message>
|
||||
{
|
||||
public String getSummary();
|
||||
}
|
||||
226
src/controller/activity/CallEvent.java
Normal file
226
src/controller/activity/CallEvent.java
Normal file
@@ -0,0 +1,226 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.activity;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import alias.Alias;
|
||||
import alias.AliasList;
|
||||
import decode.DecoderType;
|
||||
|
||||
public abstract class CallEvent
|
||||
{
|
||||
protected long mEventTime = System.currentTimeMillis();
|
||||
|
||||
private SimpleDateFormat mSDF = new SimpleDateFormat( "yyyyMMdd','HHmmss" );
|
||||
|
||||
protected DecoderType mDecoderType;
|
||||
protected CallEventType mCallEventType;
|
||||
protected AliasList mAliasList;
|
||||
protected String mFromID;
|
||||
protected String mToID;
|
||||
protected String mDetails;
|
||||
|
||||
public CallEvent( DecoderType decoder,
|
||||
CallEventType callEventType,
|
||||
AliasList aliasList,
|
||||
String fromID,
|
||||
String toID,
|
||||
String details )
|
||||
{
|
||||
mDecoderType = decoder;
|
||||
mCallEventType = callEventType;
|
||||
mAliasList = aliasList;
|
||||
mFromID = fromID;
|
||||
mToID = toID;
|
||||
mDetails = details;
|
||||
}
|
||||
|
||||
public DecoderType getDecoderType()
|
||||
{
|
||||
return mDecoderType;
|
||||
}
|
||||
|
||||
public CallEventType getCallEventType()
|
||||
{
|
||||
return mCallEventType;
|
||||
}
|
||||
|
||||
public AliasList getAliasList()
|
||||
{
|
||||
return mAliasList;
|
||||
}
|
||||
|
||||
public void setAliasList( AliasList aliasList )
|
||||
{
|
||||
mAliasList = aliasList;
|
||||
}
|
||||
|
||||
public boolean hasAliasList()
|
||||
{
|
||||
return mAliasList != null;
|
||||
}
|
||||
|
||||
public long getEventTime()
|
||||
{
|
||||
return mEventTime;
|
||||
}
|
||||
|
||||
public String getFromID()
|
||||
{
|
||||
return mFromID;
|
||||
}
|
||||
|
||||
public void setFromID( String id )
|
||||
{
|
||||
mFromID = id;
|
||||
}
|
||||
|
||||
public String getToID()
|
||||
{
|
||||
return mToID;
|
||||
}
|
||||
|
||||
public void setToID( String id )
|
||||
{
|
||||
mToID = id;
|
||||
}
|
||||
|
||||
public String getDetails()
|
||||
{
|
||||
return mDetails;
|
||||
}
|
||||
|
||||
public void setDetails( String details )
|
||||
{
|
||||
mDetails = details;
|
||||
}
|
||||
|
||||
public abstract Alias getFromIDAlias();
|
||||
|
||||
public abstract Alias getToIDAlias();
|
||||
|
||||
public abstract int getChannel();
|
||||
|
||||
public abstract int getFrequency();
|
||||
|
||||
public static String getCSVHeader()
|
||||
{
|
||||
return "DATE,TIME,DECODER,EVENT,FROM,FROM_ALIAS,TO,TO_ALIAS,"
|
||||
+ "CHANNEL,FREQUENCY,DETAILS";
|
||||
}
|
||||
|
||||
public String toCSV()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( "'" );
|
||||
sb.append( mSDF.format( new Date( getEventTime() ) ) );
|
||||
sb.append( "','" );
|
||||
sb.append( getDecoderType().toString() );
|
||||
sb.append( "','" );
|
||||
sb.append( getCallEventType().toString() );
|
||||
sb.append( "'," );
|
||||
if( getFromID() != null )
|
||||
{
|
||||
sb.append( "'" );
|
||||
sb.append( getFromID() );
|
||||
sb.append( "'" );
|
||||
}
|
||||
sb.append( "," );
|
||||
|
||||
Alias fromAlias = getFromIDAlias();
|
||||
|
||||
if( fromAlias != null )
|
||||
{
|
||||
sb.append( "'" );
|
||||
sb.append( fromAlias.getName() );
|
||||
sb.append( "'" );
|
||||
}
|
||||
sb.append( "," );
|
||||
|
||||
if( getToID() != null )
|
||||
{
|
||||
sb.append( "'" );
|
||||
sb.append( getToID() );
|
||||
sb.append( "'" );
|
||||
}
|
||||
sb.append( "," );
|
||||
|
||||
Alias toAlias = getToIDAlias();
|
||||
|
||||
if( toAlias != null )
|
||||
{
|
||||
sb.append( "'" );
|
||||
sb.append( toAlias.getName() );
|
||||
sb.append( "'" );
|
||||
}
|
||||
sb.append( ",'" );
|
||||
sb.append( getChannel() );
|
||||
sb.append( "','" );
|
||||
sb.append( getFrequency() );
|
||||
sb.append( "'," );
|
||||
if( getDetails() != null )
|
||||
{
|
||||
sb.append( "'" );
|
||||
sb.append( getDetails() );
|
||||
sb.append( "'" );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public enum CallEventType
|
||||
{
|
||||
ACKNOWLEDGE( "Acknowledge" ),
|
||||
CALL_DETECT( "Call Detect" ),
|
||||
CALL_START( "Call Start" ),
|
||||
CALL_START_UNIQUE_ID( "Call Start" ),
|
||||
CALL_START_NO_TUNER( "Call - No Tuner" ),
|
||||
CALL_END( "Call End" ),
|
||||
CALL_TIMEOUT( "Call Timeout" ),
|
||||
EMERGENCY( "EMERGENCY" ),
|
||||
GPS( "GPS" ),
|
||||
ID_ANI( "ANI" ),
|
||||
ID_UNIQUE( "Unique ID" ),
|
||||
PAGE( "Page" ),
|
||||
REGISTER( "Register" ),
|
||||
REGISTER_ESN( "ESN" ),
|
||||
SDM( "SDM" ),
|
||||
STATUS( "Status" ),
|
||||
UNKNOWN( "Unknown" );
|
||||
|
||||
private String mLabel;
|
||||
|
||||
private CallEventType( String label )
|
||||
{
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
72
src/controller/activity/CallEventAliasCellRenderer.java
Normal file
72
src/controller/activity/CallEventAliasCellRenderer.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.activity;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
|
||||
import settings.SettingsManager;
|
||||
import alias.Alias;
|
||||
|
||||
/**
|
||||
* Custom renderer for JTable cells that contain Alias objects. Renders the
|
||||
* alias name, and if there is an icon name, attempts to get that icon from
|
||||
* the settings manager and render it.
|
||||
*/
|
||||
public class CallEventAliasCellRenderer extends DefaultTableCellRenderer
|
||||
{
|
||||
private SettingsManager mSettingsManager;
|
||||
|
||||
public CallEventAliasCellRenderer( SettingsManager settingsManager )
|
||||
{
|
||||
super();
|
||||
mSettingsManager = settingsManager;
|
||||
}
|
||||
|
||||
public void setValue( Object obj )
|
||||
{
|
||||
if( obj != null && obj instanceof Alias )
|
||||
{
|
||||
Alias alias = (Alias)obj;
|
||||
|
||||
setText( alias.getName() );
|
||||
|
||||
ImageIcon icon = getIcon( alias, 12 );
|
||||
|
||||
if( icon != null )
|
||||
{
|
||||
setIcon( icon );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
setText( " " );
|
||||
setIcon( null );
|
||||
}
|
||||
}
|
||||
|
||||
private ImageIcon getIcon( Alias alias, int height )
|
||||
{
|
||||
if( mSettingsManager != null && alias != null )
|
||||
{
|
||||
return mSettingsManager.getImageIcon( alias.getIconName(), height );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
176
src/controller/activity/CallEventModel.java
Normal file
176
src/controller/activity/CallEventModel.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.activity;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
import log.Log;
|
||||
import sample.Broadcaster;
|
||||
import sample.Listener;
|
||||
|
||||
public class CallEventModel extends AbstractTableModel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int DEFAULT_ICON_HEIGHT = 14;
|
||||
|
||||
private static final int sTIME = 0;
|
||||
private static final int sEVENT = 1;
|
||||
private static final int sFROM_ID = 2;
|
||||
private static final int sFROM_ALIAS = 3;
|
||||
private static final int sTO_ID = 4;
|
||||
private static final int sTO_ALIAS =5;
|
||||
private static final int sCHANNEL = 6;
|
||||
private static final int sFREQUENCY = 7;
|
||||
private static final int sDETAILS = 8;
|
||||
|
||||
protected int mMaxMessages = 500;
|
||||
|
||||
protected LinkedList<CallEvent> mEvents = new LinkedList<CallEvent>();
|
||||
|
||||
protected String[] mHeaders = new String[] { "Time",
|
||||
"Event",
|
||||
"From",
|
||||
"From Alias",
|
||||
"To",
|
||||
"To Alias",
|
||||
"Channel",
|
||||
"Frequency",
|
||||
"Details" };
|
||||
|
||||
private SimpleDateFormat mSDFTime = new SimpleDateFormat( "HH:mm:ss" );
|
||||
|
||||
private Broadcaster<CallEvent> mBroadcaster = new Broadcaster<CallEvent>();
|
||||
private boolean mNewMessagesFirst = true;
|
||||
|
||||
public CallEventModel()
|
||||
{
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mEvents.clear();
|
||||
mBroadcaster.dispose();
|
||||
}
|
||||
|
||||
public void flush()
|
||||
{
|
||||
/* Flush all events to listeners ( normally the call event logger ) */
|
||||
for( CallEvent event: mEvents )
|
||||
{
|
||||
mBroadcaster.receive( event );
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxMessageCount()
|
||||
{
|
||||
return mMaxMessages;
|
||||
}
|
||||
|
||||
public void setMaxMessageCount( int count )
|
||||
{
|
||||
mMaxMessages = count;
|
||||
}
|
||||
|
||||
public void add( final CallEvent event )
|
||||
{
|
||||
EventQueue.invokeLater( new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mEvents.addFirst( event );
|
||||
|
||||
CallEventModel.this.fireTableRowsInserted( 0, 0 );
|
||||
|
||||
prune();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
private void prune()
|
||||
{
|
||||
while( mEvents.size() > mMaxMessages )
|
||||
{
|
||||
CallEvent event = mEvents.removeLast();
|
||||
|
||||
mBroadcaster.receive( event );
|
||||
|
||||
super.fireTableRowsDeleted( mEvents.size(), mEvents.size() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount()
|
||||
{
|
||||
return mEvents.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount()
|
||||
{
|
||||
return mHeaders.length;
|
||||
}
|
||||
|
||||
public String getColumnName( int column )
|
||||
{
|
||||
return mHeaders[ column ];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt( int rowIndex, int columnIndex )
|
||||
{
|
||||
switch( columnIndex )
|
||||
{
|
||||
case sTIME:
|
||||
return mSDFTime.format( mEvents.get( rowIndex ).getEventTime() );
|
||||
case sEVENT:
|
||||
return mEvents.get( rowIndex ).getCallEventType();
|
||||
case sFROM_ID:
|
||||
return mEvents.get( rowIndex ).getFromID();
|
||||
case sFROM_ALIAS:
|
||||
return mEvents.get( rowIndex ).getFromIDAlias();
|
||||
case sTO_ID:
|
||||
return mEvents.get( rowIndex ).getToID();
|
||||
case sTO_ALIAS:
|
||||
return mEvents.get( rowIndex ).getToIDAlias();
|
||||
case sCHANNEL:
|
||||
return mEvents.get( rowIndex ).getChannel();
|
||||
case sFREQUENCY:
|
||||
return mEvents.get( rowIndex ).getFrequency();
|
||||
case sDETAILS:
|
||||
return mEvents.get( rowIndex ).getDetails();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void addListener( Listener<CallEvent> listener )
|
||||
{
|
||||
mBroadcaster.addListener( listener );
|
||||
}
|
||||
|
||||
public void removeListener( Listener<CallEvent> listener )
|
||||
{
|
||||
mBroadcaster.removeListener( listener );
|
||||
}
|
||||
}
|
||||
84
src/controller/activity/CallEventPanel.java
Normal file
84
src/controller/activity/CallEventPanel.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.activity;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import controller.channel.Channel;
|
||||
import controller.channel.Channel.ChannelEvent;
|
||||
import controller.channel.ChannelListener;
|
||||
|
||||
public class CallEventPanel extends JPanel implements ChannelListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private JScrollPane mEmptyScroller;
|
||||
private Channel mDisplayedChannel;
|
||||
|
||||
public CallEventPanel()
|
||||
{
|
||||
setLayout( new MigLayout("insets 0 0 0 0 ", "[grow,fill]", "[grow,fill]") );
|
||||
|
||||
JTable table = new JTable( new CallEventModel() );
|
||||
table.setAutoCreateRowSorter( true );
|
||||
table.setAutoResizeMode( JTable.AUTO_RESIZE_LAST_COLUMN );
|
||||
mEmptyScroller = new JScrollPane( table );
|
||||
|
||||
add( mEmptyScroller );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void occurred( Channel channel, ChannelEvent event )
|
||||
{
|
||||
if( event == ChannelEvent.CHANGE_SELECTED && channel.getSelected() )
|
||||
{
|
||||
if( mDisplayedChannel == null ||
|
||||
( mDisplayedChannel != null && mDisplayedChannel != channel ) )
|
||||
{
|
||||
removeAll();
|
||||
|
||||
JScrollPane scroller = new JScrollPane(
|
||||
channel.getProcessingChain().getChannelState()
|
||||
.getCallEventTable() );
|
||||
|
||||
add( scroller );
|
||||
|
||||
mDisplayedChannel = channel;
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
else if( event == ChannelEvent.PROCESSING_STOPPED ||
|
||||
event == ChannelEvent.CHANNEL_DELETED )
|
||||
{
|
||||
if( mDisplayedChannel != null && mDisplayedChannel == channel )
|
||||
{
|
||||
mDisplayedChannel = null;
|
||||
removeAll();
|
||||
add( mEmptyScroller );
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
155
src/controller/activity/MessageActivityModel.java
Normal file
155
src/controller/activity/MessageActivityModel.java
Normal file
@@ -0,0 +1,155 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.activity;
|
||||
|
||||
import java.awt.EventQueue;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
import message.Message;
|
||||
import sample.Listener;
|
||||
|
||||
public class MessageActivityModel extends AbstractTableModel
|
||||
implements Listener<Message>
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final int sTIME = 0;
|
||||
private static final int sPROTOCOL = 1;
|
||||
private static final int sERROR_STATUS = 2;
|
||||
private static final int sMESSAGE = 3;
|
||||
private static final int sMESSAGE_BITS = 4;
|
||||
|
||||
protected int mMaxMessages = 500;
|
||||
protected LinkedList<Message> mMessages = new LinkedList<Message>();
|
||||
|
||||
protected int[] mColumnWidths = { 110, 110, 110, -1, -1 };
|
||||
|
||||
protected String[] mHeaders = new String[] { "Time",
|
||||
"Protocol",
|
||||
"Error Check",
|
||||
"Message",
|
||||
"Binary" };
|
||||
|
||||
private SimpleDateFormat mSDFTime = new SimpleDateFormat( "HH:mm:ss" );
|
||||
|
||||
private boolean mNewMessagesFirst = true;
|
||||
|
||||
public MessageActivityModel()
|
||||
{
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mMessages.clear();
|
||||
}
|
||||
|
||||
public int[] getColumnWidths()
|
||||
{
|
||||
return mColumnWidths;
|
||||
}
|
||||
|
||||
public void setColumnWidths( int[] widths )
|
||||
{
|
||||
if( widths.length != 5 )
|
||||
{
|
||||
throw new IllegalArgumentException( "MessageActivityModel - "
|
||||
+ "column widths array should have 5 elements" );
|
||||
}
|
||||
else
|
||||
{
|
||||
mColumnWidths = widths;
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxMessageCount()
|
||||
{
|
||||
return mMaxMessages;
|
||||
}
|
||||
|
||||
public void setMaxMessageCount( int count )
|
||||
{
|
||||
mMaxMessages = count;
|
||||
}
|
||||
|
||||
public void receive( final Message message )
|
||||
{
|
||||
EventQueue.invokeLater( new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mMessages.addFirst( message );
|
||||
|
||||
MessageActivityModel.this.fireTableRowsInserted( 0, 0 );
|
||||
|
||||
prune();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
private void prune()
|
||||
{
|
||||
while( mMessages.size() > mMaxMessages )
|
||||
{
|
||||
mMessages.removeLast();
|
||||
|
||||
super.fireTableRowsDeleted( mMessages.size() - 1, mMessages.size() - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount()
|
||||
{
|
||||
return mMessages.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount()
|
||||
{
|
||||
return mHeaders.length;
|
||||
}
|
||||
|
||||
public String getColumnName( int column )
|
||||
{
|
||||
return mHeaders[ column ];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt( int rowIndex, int columnIndex )
|
||||
{
|
||||
Message message = mMessages.get( rowIndex );
|
||||
|
||||
switch( columnIndex )
|
||||
{
|
||||
case sTIME:
|
||||
return mSDFTime.format( message.getDateReceived() );
|
||||
case sPROTOCOL:
|
||||
return message.getProtocol();
|
||||
case sERROR_STATUS:
|
||||
return message.getErrorStatus();
|
||||
case sMESSAGE:
|
||||
return message.getMessage();
|
||||
case sMESSAGE_BITS:
|
||||
return message.getBinaryMessage();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
82
src/controller/activity/MessageActivityPanel.java
Normal file
82
src/controller/activity/MessageActivityPanel.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.activity;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import controller.channel.Channel;
|
||||
import controller.channel.Channel.ChannelEvent;
|
||||
import controller.channel.ChannelListener;
|
||||
|
||||
public class MessageActivityPanel extends JPanel implements ChannelListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private JScrollPane mEmptyScrollPane;
|
||||
private Channel mDisplayedChannel;
|
||||
|
||||
public MessageActivityPanel()
|
||||
{
|
||||
setLayout( new MigLayout("insets 0 0 0 0 ", "[grow,fill]", "[grow,fill]") );
|
||||
|
||||
mEmptyScrollPane =
|
||||
new JScrollPane( new JTable( new MessageActivityModel() ) );
|
||||
|
||||
add( mEmptyScrollPane );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void occurred( Channel channel, ChannelEvent event )
|
||||
{
|
||||
if( event == ChannelEvent.CHANGE_SELECTED && channel.getSelected() )
|
||||
{
|
||||
if( mDisplayedChannel == null ||
|
||||
( mDisplayedChannel != null && mDisplayedChannel != channel ) )
|
||||
{
|
||||
removeAll();
|
||||
|
||||
JScrollPane scroll =
|
||||
new JScrollPane( channel.getProcessingChain()
|
||||
.getChannelState().getMessageActivityTable() );
|
||||
|
||||
add( scroll );
|
||||
|
||||
mDisplayedChannel = channel;
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
else if( event == ChannelEvent.PROCESSING_STOPPED ||
|
||||
event == ChannelEvent.CHANNEL_DELETED )
|
||||
{
|
||||
if( mDisplayedChannel != null && mDisplayedChannel == channel )
|
||||
{
|
||||
mDisplayedChannel = null;
|
||||
removeAll();
|
||||
add( mEmptyScrollPane );
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
82
src/controller/activity/MessageDetailsProvider.java
Normal file
82
src/controller/activity/MessageDetailsProvider.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.activity;
|
||||
|
||||
import alias.Alias;
|
||||
|
||||
/**
|
||||
* Getter methods to support the Message Activity Table/Model
|
||||
* @author denny
|
||||
*
|
||||
*/
|
||||
public interface MessageDetailsProvider
|
||||
{
|
||||
/**
|
||||
* Indicates if the message is valid and has passed crc/integrity checks
|
||||
*/
|
||||
public abstract boolean isValid();
|
||||
|
||||
/**
|
||||
* Status of the CRC check of the message
|
||||
*/
|
||||
public abstract String getErrorStatus();
|
||||
|
||||
/**
|
||||
* Parsed Message
|
||||
* @return
|
||||
*/
|
||||
public abstract String getMessage();
|
||||
|
||||
/**
|
||||
* Raw ( 0 & 1 ) message bits
|
||||
*/
|
||||
public abstract String getBinaryMessage();
|
||||
|
||||
|
||||
/**
|
||||
* Decoded protocol
|
||||
*/
|
||||
public abstract String getProtocol();
|
||||
|
||||
/**
|
||||
* Event - call, data, idle, etc.
|
||||
*/
|
||||
public abstract String getEventType();
|
||||
|
||||
/**
|
||||
* Formatted from identifier
|
||||
*/
|
||||
public abstract String getFromID();
|
||||
|
||||
/**
|
||||
* From identifier alias (from AliasManager)
|
||||
*/
|
||||
public abstract Alias getFromIDAlias();
|
||||
|
||||
/**
|
||||
* Formatted to identifier
|
||||
*/
|
||||
public abstract String getToID();
|
||||
|
||||
/**
|
||||
* To identifier alias (from AliasManager)
|
||||
* @return
|
||||
*/
|
||||
public abstract Alias getToIDAlias();
|
||||
|
||||
}
|
||||
42
src/controller/channel/AbstractChannelEditor.java
Normal file
42
src/controller/channel/AbstractChannelEditor.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import controller.Editor;
|
||||
|
||||
public abstract class AbstractChannelEditor extends Editor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected ChannelNode mChannelNode;
|
||||
|
||||
public AbstractChannelEditor( ChannelNode channel )
|
||||
{
|
||||
super();
|
||||
mChannelNode = channel;
|
||||
}
|
||||
|
||||
public ChannelNode getChannelNode()
|
||||
{
|
||||
return mChannelNode;
|
||||
}
|
||||
|
||||
public abstract void save();
|
||||
|
||||
public abstract void reset();
|
||||
}
|
||||
902
src/controller/channel/Channel.java
Normal file
902
src/controller/channel/Channel.java
Normal file
@@ -0,0 +1,902 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
import log.Log;
|
||||
import message.Message;
|
||||
import record.config.RecordConfiguration;
|
||||
import sample.Listener;
|
||||
import source.SourceType;
|
||||
import source.config.SourceConfigFactory;
|
||||
import source.config.SourceConfigTuner;
|
||||
import source.config.SourceConfiguration;
|
||||
import source.tuner.TunerChannel;
|
||||
import source.tuner.TunerChannel.Type;
|
||||
import controller.ResourceManager;
|
||||
import controller.activity.ActivitySummaryFrame;
|
||||
import controller.config.Configuration;
|
||||
import controller.site.Site;
|
||||
import controller.state.ChannelState;
|
||||
import controller.state.ChannelState.State;
|
||||
import controller.system.System;
|
||||
import decode.config.AuxDecodeConfiguration;
|
||||
import decode.config.DecodeConfigFactory;
|
||||
import decode.config.DecodeConfiguration;
|
||||
import eventlog.config.EventLogConfiguration;
|
||||
|
||||
@XmlSeeAlso( { Configuration.class } )
|
||||
@XmlRootElement( name = "channel" )
|
||||
public class Channel extends Configuration
|
||||
{
|
||||
public enum ChannelType
|
||||
{
|
||||
STANDARD,
|
||||
TRAFFIC
|
||||
};
|
||||
|
||||
private static final boolean ENABLED = true;
|
||||
private static final boolean DISABLED = false;
|
||||
private static final boolean BROADCAST_CHANGE = true;
|
||||
|
||||
private CopyOnWriteArrayList<ChannelListener> mChannelListeners =
|
||||
new CopyOnWriteArrayList<ChannelListener>();
|
||||
|
||||
private CopyOnWriteArrayList<Listener<Message>> mMessageListeners =
|
||||
new CopyOnWriteArrayList<Listener<Message>>();
|
||||
|
||||
private HashMap<Integer,Channel> mTrafficChannels =
|
||||
new HashMap<Integer,Channel>();
|
||||
|
||||
private DecodeConfiguration mDecodeConfiguration =
|
||||
DecodeConfigFactory.getDefaultDecodeConfiguration();
|
||||
private AuxDecodeConfiguration mAuxDecodeConfiguration =
|
||||
new AuxDecodeConfiguration();
|
||||
private SourceConfiguration mSourceConfiguration =
|
||||
SourceConfigFactory.getDefaultSourceConfiguration();
|
||||
private EventLogConfiguration mEventLogConfiguration =
|
||||
new EventLogConfiguration();
|
||||
private RecordConfiguration mRecordConfiguration = new RecordConfiguration();
|
||||
|
||||
private ResourceManager mResourceManager;
|
||||
private String mAliasListName;
|
||||
private System mSystem;
|
||||
private Site mSite;
|
||||
private String mName;
|
||||
private boolean mEnabled;
|
||||
private boolean mSelected;
|
||||
private ChannelType mChannelType;
|
||||
private ProcessingChain mProcessingChain;
|
||||
|
||||
/**
|
||||
* Constructs a new standard channel with a default name of "New Channel"
|
||||
*/
|
||||
public Channel()
|
||||
{
|
||||
this( "New Channel", ChannelType.STANDARD );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new standard channel with the specified channel name
|
||||
*/
|
||||
public Channel( String channelName )
|
||||
{
|
||||
this( channelName, ChannelType.STANDARD );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new channel with the specified channel name and type.
|
||||
*
|
||||
* @param channelName
|
||||
* @param channelType
|
||||
*/
|
||||
public Channel( String channelName, ChannelType channelType )
|
||||
{
|
||||
mName = channelName;
|
||||
mChannelType = channelType;
|
||||
}
|
||||
|
||||
public ChannelType getChannelType()
|
||||
{
|
||||
return mChannelType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the resource manager responsible for this channel and registers
|
||||
* the channel manager as a listener to this channel. Fires channel add
|
||||
* channel event to the newly added channel manager channel listener.
|
||||
*/
|
||||
public void setResourceManager( ResourceManager resourceManager )
|
||||
{
|
||||
mResourceManager = resourceManager;
|
||||
|
||||
/* Add system-wide channel listeners onto this channel */
|
||||
addListeners( mResourceManager.getChannelManager().getChannelListeners() );
|
||||
|
||||
/* If we're enabled, fire enable changed event to get processing started */
|
||||
if( mEnabled )
|
||||
{
|
||||
enableChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
public ResourceManager getResourceManager()
|
||||
{
|
||||
return mResourceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the processing chain for this channel. If the processing chain
|
||||
* is not currently constructed and running, this method will return null.
|
||||
*/
|
||||
@XmlTransient
|
||||
public ProcessingChain getProcessingChain()
|
||||
{
|
||||
return mProcessingChain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this channel has a processing chain constructed and it
|
||||
* is processing.
|
||||
*/
|
||||
public boolean isProcessing()
|
||||
{
|
||||
return mProcessingChain != null && mProcessingChain.isProcessing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this channel has been selected for audio output
|
||||
*/
|
||||
@XmlTransient
|
||||
public boolean getSelected()
|
||||
{
|
||||
return mSelected;
|
||||
}
|
||||
|
||||
public void setSelected( boolean selected )
|
||||
{
|
||||
mSelected = selected;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isProcessing() )
|
||||
{
|
||||
mProcessingChain.getAudioOutput().setAudioPlaybackEnabled( selected );
|
||||
}
|
||||
|
||||
fireChannelEvent( ChannelEvent.CHANGE_SELECTED );
|
||||
}
|
||||
|
||||
public JMenu getContextMenu()
|
||||
{
|
||||
JMenu menu = new JMenu( mSite + "-" + mName );
|
||||
|
||||
if( mEnabled )
|
||||
{
|
||||
JMenuItem disable = new JMenuItem( "Disable" );
|
||||
disable.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
setEnabled( DISABLED, BROADCAST_CHANGE );
|
||||
getResourceManager().getPlaylistManager().save();
|
||||
}
|
||||
} );
|
||||
|
||||
menu.add( disable );
|
||||
|
||||
menu.add( new JSeparator() );
|
||||
|
||||
JMenuItem actySummaryItem =
|
||||
new JMenuItem( "Activity Summary" );
|
||||
|
||||
actySummaryItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
if( mResourceManager != null )
|
||||
{
|
||||
ProcessingChain chain = getProcessingChain();
|
||||
|
||||
if( chain != null )
|
||||
{
|
||||
ChannelState state = chain.getChannelState();
|
||||
|
||||
if( state != null )
|
||||
{
|
||||
String summary = state.getActivitySummary();
|
||||
|
||||
new ActivitySummaryFrame( summary,
|
||||
mResourceManager.getController().getTree() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
menu.add( actySummaryItem );
|
||||
}
|
||||
else
|
||||
{
|
||||
JMenuItem enable = new JMenuItem( "Enable" );
|
||||
enable.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
setEnabled( ENABLED, BROADCAST_CHANGE );
|
||||
getResourceManager().getPlaylistManager().save(); }
|
||||
} );
|
||||
|
||||
menu.add( enable );
|
||||
}
|
||||
|
||||
menu.add( new JSeparator() );
|
||||
|
||||
JMenuItem deleteItem = new JMenuItem( "Delete" );
|
||||
deleteItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
dispose();
|
||||
getResourceManager().getPlaylistManager().save(); }
|
||||
} );
|
||||
|
||||
menu.add( deleteItem );
|
||||
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Orderly shutdown method when this channel is going to be deleted.
|
||||
*/
|
||||
public void dispose()
|
||||
{
|
||||
setEnabled( DISABLED, BROADCAST_CHANGE );
|
||||
|
||||
/* Broadcast channel deleted event */
|
||||
fireChannelEvent( ChannelEvent.CHANNEL_DELETED );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a full channel name containing the system, site and channel name.
|
||||
*/
|
||||
public String getChannelDisplayName()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if( mSystem != null )
|
||||
{
|
||||
sb.append( mSystem.getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "-" );
|
||||
}
|
||||
|
||||
sb.append( "/" );
|
||||
|
||||
if( mSite != null )
|
||||
{
|
||||
sb.append( mSite.getName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append( "-" );
|
||||
}
|
||||
|
||||
sb.append( "/" );
|
||||
|
||||
sb.append( mName );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tuner channel requirement for this channel when the source
|
||||
* configuration specifies a tuner and frequency as the source for this
|
||||
* channel.
|
||||
*
|
||||
* If the source configuration is anything else, this method returns null.
|
||||
*/
|
||||
public TunerChannel getTunerChannel()
|
||||
{
|
||||
TunerChannel retVal = null;
|
||||
|
||||
if( mSourceConfiguration.getSourceType() == SourceType.TUNER )
|
||||
{
|
||||
SourceConfigTuner config = (SourceConfigTuner)mSourceConfiguration;
|
||||
|
||||
retVal = new TunerChannel( Type.LOCKED, config.getFrequency(),
|
||||
mDecodeConfiguration.getDecoderType().getChannelBandwidth() );
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owning system for this channel.
|
||||
*/
|
||||
public System getSystem()
|
||||
{
|
||||
return mSystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the owning system for this channel and optionally broadcasts a
|
||||
* system change channel event.
|
||||
*/
|
||||
public void setSystem( System system, boolean fireChangeEvent )
|
||||
{
|
||||
mSystem = system;
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_SYSTEM );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owning site for this channel.
|
||||
*/
|
||||
public Site getSite()
|
||||
{
|
||||
return mSite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the owning site for this channel and optionally broadcasts a site
|
||||
* change channel event.
|
||||
*/
|
||||
public void setSite( Site site, boolean fireChangeEvent )
|
||||
{
|
||||
mSite = site;
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_SITE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default display string for this channel -- the channel name.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this channel is enabled for processing.
|
||||
*/
|
||||
@XmlAttribute
|
||||
public boolean getEnabled()
|
||||
{
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disables this channel for processing. Automatically starts or
|
||||
* stops channel processing in response to this change.
|
||||
*/
|
||||
public void setEnabled( boolean enabled )
|
||||
{
|
||||
mEnabled = enabled;
|
||||
|
||||
enableChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disables this channel for processing. Automatically starts or
|
||||
* stops channel processing in response to this change. Optionally
|
||||
* broadcasts a enabled change channel event.
|
||||
*/
|
||||
public void setEnabled( boolean enabled, boolean fireChannelEvent )
|
||||
{
|
||||
setEnabled( enabled );
|
||||
|
||||
if( fireChannelEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_ENABLED );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alias list that is used by this channel for looking up alias
|
||||
* values for the various identifiers produced by the decoder.
|
||||
*/
|
||||
@XmlElement( name = "alias_list_name" )
|
||||
public String getAliasListName()
|
||||
{
|
||||
return mAliasListName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alias list to be used for looking up the alias values for the
|
||||
* various identifiers produced by the decoder
|
||||
*/
|
||||
public void setAliasListName( String name )
|
||||
{
|
||||
mAliasListName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alias list to be used for looking up the alias values for the
|
||||
* various identifiers produced by the decoder. This method is the same
|
||||
* as setAliasName(name) and optionally broadcasts an alias list change
|
||||
* channel event.
|
||||
*/
|
||||
public void setAliasListName( String name, boolean fireChangeEvent )
|
||||
{
|
||||
mAliasListName = name;
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_ALIAS_LIST );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the decoder configuration used by this channel
|
||||
*/
|
||||
@XmlElement( name = "decode_configuration" )
|
||||
public DecodeConfiguration getDecodeConfiguration()
|
||||
{
|
||||
return mDecodeConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the decoder configuration used by this channel
|
||||
*/
|
||||
public void setDecodeConfiguration( DecodeConfiguration config )
|
||||
{
|
||||
mDecodeConfiguration = config;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isRunning() )
|
||||
{
|
||||
mProcessingChain.updateDecoder();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the aux decoder configuration used by this channel
|
||||
*/
|
||||
@XmlElement( name = "aux_decode_configuration" )
|
||||
public AuxDecodeConfiguration getAuxDecodeConfiguration()
|
||||
{
|
||||
return mAuxDecodeConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the decoder configuration used by this channel
|
||||
*/
|
||||
public void setAuxDecodeConfiguration( AuxDecodeConfiguration config )
|
||||
{
|
||||
mAuxDecodeConfiguration = config;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isRunning() )
|
||||
{
|
||||
mProcessingChain.updateDecoder();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the decoder configuration used by this channel and optionally
|
||||
* broadcasts a decoder change channel event.
|
||||
*/
|
||||
public void setDecodeConfiguration( DecodeConfiguration config,
|
||||
boolean fireChangeEvent )
|
||||
{
|
||||
setDecodeConfiguration( config );
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_DECODER );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source configuration for this channel.
|
||||
*/
|
||||
@XmlElement( name = "source_configuration" )
|
||||
public SourceConfiguration getSourceConfiguration()
|
||||
{
|
||||
return mSourceConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source configuration for this channel.
|
||||
*/
|
||||
public void setSourceConfiguration( SourceConfiguration config )
|
||||
{
|
||||
mSourceConfiguration = config;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isRunning() )
|
||||
{
|
||||
mProcessingChain.updateSource();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source configuration for this channel and optionally broadcasts
|
||||
* a source change channel event.
|
||||
*/
|
||||
public void setSourceConfiguration( SourceConfiguration config,
|
||||
boolean fireChangeEvent )
|
||||
{
|
||||
setSourceConfiguration( config );
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_SOURCE );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event logger configuration for this channel.
|
||||
*/
|
||||
@XmlElement( name = "event_log_configuration" )
|
||||
public EventLogConfiguration getEventLogConfiguration()
|
||||
{
|
||||
return mEventLogConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event logger configuration for this channel.
|
||||
*/
|
||||
public void setEventLogConfiguration( EventLogConfiguration config )
|
||||
{
|
||||
mEventLogConfiguration = config;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isRunning() )
|
||||
{
|
||||
mProcessingChain.updateEventLogging();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event logger configuration for this channel and optionally
|
||||
* broadcasts an event logger change channel event.
|
||||
*/
|
||||
public void setEventLogConfiguration( EventLogConfiguration config,
|
||||
boolean fireChangeEvent )
|
||||
{
|
||||
setEventLogConfiguration( config );
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_EVENT_LOGGER );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the recorder configuration for this channel.
|
||||
*/
|
||||
@XmlElement( name = "record_configuration" )
|
||||
public RecordConfiguration getRecordConfiguration()
|
||||
{
|
||||
return mRecordConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the recorder configuration for this channel.
|
||||
*/
|
||||
public void setRecordConfiguration( RecordConfiguration config )
|
||||
{
|
||||
mRecordConfiguration = config;
|
||||
|
||||
if( mProcessingChain != null && mProcessingChain.isRunning() )
|
||||
{
|
||||
mProcessingChain.updateRecording();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the recorder configuration for this channel and optionally broadcasts
|
||||
* a recorder configuration change channel event.
|
||||
*/
|
||||
public void setRecordConfiguration( RecordConfiguration config,
|
||||
boolean fireChangeEvent )
|
||||
{
|
||||
setRecordConfiguration( config );
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_RECORDER );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this channel.
|
||||
*/
|
||||
@XmlAttribute
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this channel.
|
||||
*/
|
||||
public void setName( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this channel and optionally broadcasts a name change
|
||||
* channel event.
|
||||
*/
|
||||
public void setName( String name, boolean fireChangeEvent )
|
||||
{
|
||||
mName = name;
|
||||
|
||||
if( fireChangeEvent )
|
||||
{
|
||||
fireChannelEvent( ChannelEvent.CHANGE_NAME );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to changes in the enabled setting by starting the processing
|
||||
* change if the channel is now enabled, or stopping the procesing chain
|
||||
* if it was already started.
|
||||
*/
|
||||
private void enableChanged()
|
||||
{
|
||||
if( mEnabled )
|
||||
{
|
||||
start();
|
||||
}
|
||||
else
|
||||
{
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the channel processing chain.
|
||||
*/
|
||||
private void start()
|
||||
{
|
||||
if( mEnabled && mProcessingChain == null && mResourceManager != null )
|
||||
{
|
||||
mProcessingChain = new ProcessingChain( this, mResourceManager );
|
||||
|
||||
/* Add system-wide message listeners */
|
||||
mProcessingChain.addListeners(
|
||||
mResourceManager.getChannelManager().getMessageListeners() );
|
||||
|
||||
/* Add individual message listeners */
|
||||
mProcessingChain.addListeners( mMessageListeners );
|
||||
|
||||
mProcessingChain.start();
|
||||
|
||||
fireChannelEvent( ChannelEvent.PROCESSING_STARTED );
|
||||
}
|
||||
|
||||
/* If this is a traffic channel, override the call fade timeout before
|
||||
* we set the state to call, so that it will auto-expire after the
|
||||
* fade timeout and be auto deleted */
|
||||
if( mChannelType == ChannelType.TRAFFIC )
|
||||
{
|
||||
if( mProcessingChain.isProcessing() )
|
||||
{
|
||||
mProcessingChain.getChannelState().setCallFadeTimeout( 40000 );
|
||||
mProcessingChain.getChannelState().setState( State.CALL );
|
||||
}
|
||||
else
|
||||
{
|
||||
mProcessingChain.getChannelState().setCallFadeTimeout( 5000 );
|
||||
/* Channel state should already be no_tuner */
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the channel processing chain
|
||||
*/
|
||||
private void stop()
|
||||
{
|
||||
/* Stop and remove any traffic channels */
|
||||
for( Channel traffic: mTrafficChannels.values() )
|
||||
{
|
||||
traffic.stop();
|
||||
traffic.dispose();
|
||||
}
|
||||
|
||||
mTrafficChannels.clear();
|
||||
|
||||
if( !mEnabled && mProcessingChain != null )
|
||||
{
|
||||
mProcessingChain.stop();
|
||||
|
||||
mProcessingChain.dispose();
|
||||
|
||||
mProcessingChain = null;
|
||||
|
||||
mSelected = false;
|
||||
}
|
||||
|
||||
fireChannelEvent( ChannelEvent.PROCESSING_STOPPED );
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts a channel change event to all registered listeners
|
||||
*/
|
||||
public void fireChannelEvent( ChannelEvent event )
|
||||
{
|
||||
for( ChannelListener listener: mChannelListeners )
|
||||
{
|
||||
listener.occurred( this, event );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a channel listener to receive all channel events from this channel
|
||||
* and automatically sends the listener a channel add event.
|
||||
*/
|
||||
public void addListener( ChannelListener listener )
|
||||
{
|
||||
if( !mChannelListeners.contains( listener ) )
|
||||
{
|
||||
mChannelListeners.add( listener );
|
||||
|
||||
listener.occurred( this, ChannelEvent.CHANNEL_ADDED );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error( "Channel - attempt to add already existing channel listener [" + listener.getClass() + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list of channel listeners to receive all channel events from this
|
||||
* channel and automatically sends each one a channel add event.
|
||||
*/
|
||||
public void addListeners( List<ChannelListener> listeners )
|
||||
{
|
||||
for( ChannelListener listener: listeners )
|
||||
{
|
||||
addListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a channel listener from receiving channel events from this channel
|
||||
*/
|
||||
public void removeListener( ChannelListener listener )
|
||||
{
|
||||
mChannelListeners.remove( listener );
|
||||
}
|
||||
|
||||
public void addListener( Listener<Message> listener )
|
||||
{
|
||||
mMessageListeners.add( listener );
|
||||
|
||||
if( isProcessing() )
|
||||
{
|
||||
mProcessingChain.addListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener( Listener<Message> listener )
|
||||
{
|
||||
mMessageListeners.remove( listener );
|
||||
|
||||
if( isProcessing() )
|
||||
{
|
||||
mProcessingChain.removeListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if any part of this channel is contained within the
|
||||
* minimum and maximum frequency values.
|
||||
*/
|
||||
public boolean isWithin( int minimum, int maximum )
|
||||
{
|
||||
return getTunerChannel() != null &&
|
||||
getTunerChannel().isWithin( minimum, maximum );
|
||||
}
|
||||
|
||||
public void addTrafficChannel( int channelNumber, Channel channel )
|
||||
{
|
||||
mTrafficChannels.put( channelNumber, channel );
|
||||
}
|
||||
|
||||
public boolean hasTrafficChannel( Channel channel )
|
||||
{
|
||||
return mTrafficChannels.containsValue( channel );
|
||||
}
|
||||
|
||||
public void removeTrafficChannel( Channel channel )
|
||||
{
|
||||
int keyToRemove = -1;
|
||||
|
||||
if( mTrafficChannels.values().contains( channel ) )
|
||||
{
|
||||
for( Integer channelNumber: mTrafficChannels.keySet() )
|
||||
{
|
||||
if( mTrafficChannels.get( channelNumber ).equals( channel ) )
|
||||
{
|
||||
keyToRemove = channelNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( keyToRemove != -1 )
|
||||
{
|
||||
mTrafficChannels.remove( keyToRemove );
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Channel> getTrafficChannels()
|
||||
{
|
||||
return Collections.unmodifiableCollection( mTrafficChannels.values() );
|
||||
}
|
||||
|
||||
public boolean hasTrafficChannel( int channelNumber )
|
||||
{
|
||||
return mTrafficChannels.containsKey( channelNumber );
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel Events - used to specify channel events and changes to channel
|
||||
* configurations and settings.
|
||||
*/
|
||||
public enum ChannelEvent
|
||||
{
|
||||
CHANGE_ALIAS_LIST,
|
||||
CHANGE_DECODER,
|
||||
CHANGE_ENABLED,
|
||||
CHANGE_EVENT_LOGGER,
|
||||
CHANGE_NAME,
|
||||
CHANGE_SITE,
|
||||
CHANGE_RECORDER,
|
||||
CHANGE_SELECTED,
|
||||
CHANGE_SOURCE,
|
||||
CHANGE_SYSTEM,
|
||||
|
||||
CHANNEL_ADDED,
|
||||
CHANNEL_DELETED,
|
||||
|
||||
PROCESSING_STARTED,
|
||||
PROCESSING_STOPPED,
|
||||
}
|
||||
}
|
||||
235
src/controller/channel/ChannelEditor.java
Normal file
235
src/controller/channel/ChannelEditor.java
Normal file
@@ -0,0 +1,235 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.ComponentOrientation;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import record.RecordComponentEditor;
|
||||
import source.SourceComponentEditor;
|
||||
import alias.AliasList;
|
||||
|
||||
import com.jidesoft.swing.JideTabbedPane;
|
||||
|
||||
import controller.Editor;
|
||||
import decode.AuxDecodeComponentEditor;
|
||||
import decode.DecodeComponentEditor;
|
||||
import eventlog.EventLogComponentEditor;
|
||||
|
||||
public class ChannelEditor extends Editor implements ActionListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private DefaultTreeModel mTreeModel;
|
||||
private ChannelNode mChannelNode;
|
||||
|
||||
private DecodeComponentEditor mDecodeEditor;
|
||||
private AuxDecodeComponentEditor mAuxDecodeEditor;
|
||||
private EventLogComponentEditor mEventLogEditor;
|
||||
private RecordComponentEditor mRecordEditor;
|
||||
private SourceComponentEditor mSourceEditor;
|
||||
|
||||
private JTextField mChannelName;
|
||||
private JCheckBox mChannelEnabled = new JCheckBox();
|
||||
private JComboBox<AliasList> mComboAliasLists;
|
||||
|
||||
public ChannelEditor( ChannelNode channel )
|
||||
{
|
||||
super();
|
||||
|
||||
mChannelNode = channel;
|
||||
|
||||
initGUI();
|
||||
}
|
||||
|
||||
private void initGUI()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 2", "[right,grow][grow]", "[][][][][grow][]" ) );
|
||||
|
||||
add( new JLabel( "Channel Configuration" ), "span, align center" );
|
||||
|
||||
add( new JLabel( "Enabled:" ) );
|
||||
|
||||
mChannelEnabled.setSelected(
|
||||
mChannelNode.getChannel().getEnabled() );
|
||||
mChannelEnabled.setComponentOrientation( ComponentOrientation.RIGHT_TO_LEFT );
|
||||
add( mChannelEnabled );
|
||||
|
||||
add( new JLabel( "Name:" ) );
|
||||
|
||||
mChannelName = new JTextField( mChannelNode.getChannel().getName() );
|
||||
add( mChannelName, "growx,push" );
|
||||
|
||||
/**
|
||||
* ComboBox: Alias Lists
|
||||
*/
|
||||
add( new JLabel( "Aliases:" ) );
|
||||
|
||||
mComboAliasLists = new JComboBox<AliasList>();
|
||||
|
||||
List<AliasList> lists = mChannelNode.getModel().getResourceManager()
|
||||
.getPlaylistManager().getPlayist().getAliasDirectory().getAliasList();
|
||||
|
||||
Collections.sort( lists );
|
||||
|
||||
mComboAliasLists.setModel( new DefaultComboBoxModel<AliasList>(
|
||||
lists.toArray( new AliasList[ lists.size() ] ) ) );
|
||||
|
||||
String aliasListName =
|
||||
mChannelNode.getChannel().getAliasListName();
|
||||
|
||||
if( aliasListName != null )
|
||||
{
|
||||
AliasList selected = mChannelNode.getModel().getResourceManager()
|
||||
.getPlaylistManager().getPlayist().getAliasDirectory()
|
||||
.getAliasList( aliasListName );
|
||||
|
||||
mComboAliasLists.setSelectedItem( selected );
|
||||
}
|
||||
|
||||
add( mComboAliasLists, "growx,push" );
|
||||
|
||||
JideTabbedPane tabs = new JideTabbedPane();
|
||||
tabs.setFont( this.getFont() );
|
||||
tabs.setForeground( Color.BLACK );
|
||||
|
||||
mSourceEditor = new SourceComponentEditor( mChannelNode );
|
||||
tabs.addTab( "Source", mSourceEditor );
|
||||
|
||||
mDecodeEditor = new DecodeComponentEditor( mChannelNode );
|
||||
tabs.addTab( "Decoder", mDecodeEditor );
|
||||
|
||||
mAuxDecodeEditor = new AuxDecodeComponentEditor( mChannelNode );
|
||||
tabs.addTab( "Aux", mAuxDecodeEditor );
|
||||
|
||||
mEventLogEditor = new EventLogComponentEditor( mChannelNode );
|
||||
tabs.addTab( "Event Log", mEventLogEditor );
|
||||
|
||||
mRecordEditor = new RecordComponentEditor( mChannelNode );
|
||||
tabs.addTab( "Record", mRecordEditor );
|
||||
|
||||
add( tabs, "span,grow,push" );
|
||||
|
||||
JButton btnSave = new JButton( "Save" );
|
||||
btnSave.addActionListener( ChannelEditor.this );
|
||||
add( btnSave, "growx,push" );
|
||||
|
||||
JButton btnReset = new JButton( "Reset" );
|
||||
btnReset.addActionListener( ChannelEditor.this );
|
||||
add( btnReset, "growx,push" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
String command = e.getActionCommand();
|
||||
|
||||
if( command.contentEquals( "Save" ) )
|
||||
{
|
||||
save();
|
||||
}
|
||||
else if( command.contentEquals( "Reset" ) )
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
if( mTreeModel != null )
|
||||
{
|
||||
mTreeModel.nodeChanged( mChannelNode );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save()
|
||||
{
|
||||
boolean expanded = mChannelNode.getModel().getTree()
|
||||
.isExpanded( new TreePath( mChannelNode ) );
|
||||
|
||||
mSourceEditor.save();
|
||||
mDecodeEditor.save();
|
||||
mAuxDecodeEditor.save();
|
||||
mEventLogEditor.save();
|
||||
mRecordEditor.save();
|
||||
|
||||
mChannelNode.getChannel().setName( mChannelName.getText(), false );
|
||||
mChannelNode.getChannel().setEnabled( mChannelEnabled.isSelected(), false );
|
||||
|
||||
AliasList selected = mComboAliasLists.getItemAt(
|
||||
mComboAliasLists.getSelectedIndex() );
|
||||
if( selected != null )
|
||||
{
|
||||
mChannelNode.getChannel().setAliasListName( selected.getName(), false );
|
||||
}
|
||||
|
||||
|
||||
mChannelNode.save();
|
||||
mChannelNode.show();
|
||||
|
||||
if( expanded )
|
||||
{
|
||||
mChannelNode.getModel().getTree().expandPath( new TreePath( mChannelNode ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
mChannelName.setText(
|
||||
mChannelNode.getChannel().getName() );
|
||||
mChannelName.requestFocus();
|
||||
mChannelName.requestFocusInWindow();
|
||||
|
||||
mChannelEnabled.setSelected(
|
||||
mChannelNode.getChannel().getEnabled() );
|
||||
mChannelEnabled.requestFocus();
|
||||
mChannelEnabled.requestFocusInWindow();
|
||||
|
||||
String aliasListName =
|
||||
mChannelNode.getChannel().getAliasListName();
|
||||
|
||||
if( aliasListName != null )
|
||||
{
|
||||
AliasList selected = mChannelNode.getModel().getResourceManager()
|
||||
.getPlaylistManager().getPlayist().getAliasDirectory()
|
||||
.getAliasList( aliasListName );
|
||||
|
||||
mComboAliasLists.setSelectedItem( selected );
|
||||
}
|
||||
|
||||
|
||||
mSourceEditor.reset();
|
||||
mDecodeEditor.reset();
|
||||
mAuxDecodeEditor.reset();
|
||||
mEventLogEditor.reset();
|
||||
mRecordEditor.reset();
|
||||
}
|
||||
}
|
||||
32
src/controller/channel/ChannelListener.java
Normal file
32
src/controller/channel/ChannelListener.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import controller.channel.Channel.ChannelEvent;
|
||||
|
||||
/**
|
||||
* Interface for receiving channel events. Each listener will receive
|
||||
* notification of all channel events.
|
||||
*/
|
||||
public interface ChannelListener
|
||||
{
|
||||
/**
|
||||
* Notifies the listener that a channel has changed and what has changed
|
||||
*/
|
||||
public void occurred( Channel channel, ChannelEvent event );
|
||||
}
|
||||
127
src/controller/channel/ChannelManager.java
Normal file
127
src/controller/channel/ChannelManager.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import message.Message;
|
||||
import sample.Listener;
|
||||
import controller.ResourceManager;
|
||||
import controller.channel.Channel.ChannelEvent;
|
||||
|
||||
public class ChannelManager implements ChannelListener
|
||||
{
|
||||
private ArrayList<Channel> mChannels = new ArrayList<Channel>();
|
||||
|
||||
private ArrayList<ChannelListener> mChannelListeners =
|
||||
new ArrayList<ChannelListener>();
|
||||
private ArrayList<Listener<Message>> mMessageListeners =
|
||||
new ArrayList<Listener<Message>>();
|
||||
|
||||
public ChannelManager( ResourceManager resourceManager )
|
||||
{
|
||||
mChannelListeners.add( this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that a channel has been added or deleted, so that we can
|
||||
* keep track of all channels and manage system-wide listeners for each
|
||||
* of those channels
|
||||
*/
|
||||
@SuppressWarnings( "incomplete-switch" )
|
||||
@Override
|
||||
public void occurred( Channel channel, ChannelEvent component )
|
||||
{
|
||||
switch( component )
|
||||
{
|
||||
case CHANNEL_ADDED:
|
||||
if( !mChannels.contains( channel ) )
|
||||
{
|
||||
mChannels.add( channel );
|
||||
}
|
||||
break;
|
||||
case CHANNEL_DELETED:
|
||||
mChannels.remove( channel );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a channel listener that will be added to all channels to receive
|
||||
* any channel change events. This listener will automatically receive
|
||||
* a channel add event as it is added to each of the existing channels.
|
||||
*/
|
||||
public void addListener( ChannelListener listener )
|
||||
{
|
||||
mChannelListeners.add( listener );
|
||||
|
||||
for( Channel channel: mChannels )
|
||||
{
|
||||
channel.addListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a channel listener from being automatically added to all channels
|
||||
* to receive channel change events.
|
||||
*/
|
||||
public void removeListener( ChannelListener listener )
|
||||
{
|
||||
mChannelListeners.remove( listener );
|
||||
|
||||
for( Channel channel: mChannels )
|
||||
{
|
||||
channel.removeListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of channel change listeners that will be automatically
|
||||
* added to all channels to receive channel change events
|
||||
*/
|
||||
public ArrayList<ChannelListener> getChannelListeners()
|
||||
{
|
||||
return mChannelListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of channel change listeners that will be automatically
|
||||
* added to all channels to receive channel change events
|
||||
*/
|
||||
public ArrayList<Listener<Message>> getMessageListeners()
|
||||
{
|
||||
return mMessageListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a message listener that will be added to all channels to receive
|
||||
* any messages.
|
||||
*/
|
||||
public void addListener( Listener<Message> listener )
|
||||
{
|
||||
mMessageListeners.add( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a message listener.
|
||||
*/
|
||||
public void removeListener( Listener<Message> listener )
|
||||
{
|
||||
mMessageListeners.remove( listener );
|
||||
}
|
||||
}
|
||||
120
src/controller/channel/ChannelMap.java
Normal file
120
src/controller/channel/ChannelMap.java
Normal file
@@ -0,0 +1,120 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
@XmlSeeAlso( { ChannelRange.class } )
|
||||
public class ChannelMap
|
||||
{
|
||||
private String mName;
|
||||
|
||||
private ArrayList<ChannelRange> mRanges = new ArrayList<ChannelRange>();
|
||||
|
||||
public ChannelMap()
|
||||
{
|
||||
this( "New Channel Map" );
|
||||
}
|
||||
|
||||
public ChannelMap( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
/**
|
||||
* Creates a copy of this channel map
|
||||
*/
|
||||
public ChannelMap copyOf()
|
||||
{
|
||||
ChannelMap map = new ChannelMap( mName );
|
||||
|
||||
for( ChannelRange range: mRanges )
|
||||
{
|
||||
map.addRange( range.copyOf() );
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public int getInvalidRange()
|
||||
{
|
||||
for( int x = 0; x < mRanges.size(); x++ )
|
||||
{
|
||||
if( !mRanges.get( x ).isValid() )
|
||||
{
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public ArrayList<ChannelRange> getRanges()
|
||||
{
|
||||
return mRanges;
|
||||
}
|
||||
|
||||
@XmlElement( name = "range" )
|
||||
public void setRanges( ArrayList<ChannelRange> ranges )
|
||||
{
|
||||
mRanges = ranges;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
public void setName( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public int getFrequency( int channelNumber )
|
||||
{
|
||||
for( ChannelRange range: mRanges )
|
||||
{
|
||||
if( range.hasChannel( channelNumber ) )
|
||||
{
|
||||
return range.getFrequency( channelNumber );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void addRange( ChannelRange range )
|
||||
{
|
||||
mRanges.add( range );
|
||||
}
|
||||
|
||||
public void deleteRange( ChannelRange range )
|
||||
{
|
||||
mRanges.remove( range );
|
||||
}
|
||||
|
||||
}
|
||||
223
src/controller/channel/ChannelMapEditor.java
Normal file
223
src/controller/channel/ChannelMapEditor.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
|
||||
import javax.swing.AbstractCellEditor;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.table.TableCellEditor;
|
||||
import javax.swing.text.InternationalFormatter;
|
||||
|
||||
import log.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
public class ChannelMapEditor extends JPanel implements ActionListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private ChannelMapNode mChannelMapNode;
|
||||
|
||||
private JLabel mNameLabel;
|
||||
private JTextField mNameText;
|
||||
private ChannelMapModel mRangeModel;
|
||||
private JTable mRangeTable;
|
||||
private JButton mDelete;
|
||||
private ChannelMap mChannelMapCopy;
|
||||
|
||||
public ChannelMapEditor( ChannelMapNode ChannelMap )
|
||||
{
|
||||
mChannelMapNode = ChannelMap;
|
||||
mChannelMapCopy = mChannelMapNode.getChannelMap().copyOf();
|
||||
initGUI();
|
||||
}
|
||||
|
||||
private void initGUI()
|
||||
{
|
||||
setLayout( new MigLayout( "fill,wrap 2", "[right][grow]", "[][][grow][][]" ) );
|
||||
|
||||
add( new JLabel( "Channel Map" ), "span, align center" );
|
||||
|
||||
mNameLabel = new JLabel( "Name:" );
|
||||
add( mNameLabel );
|
||||
|
||||
mNameText = new JTextField( mChannelMapCopy.getName() );
|
||||
mNameText.addFocusListener( new FocusListener()
|
||||
{
|
||||
@Override public void focusGained( FocusEvent arg0 ) {}
|
||||
|
||||
@Override
|
||||
public void focusLost( FocusEvent arg0 )
|
||||
{
|
||||
Log.info( "text field action event fired, new value:" + mNameText.getText() );
|
||||
mChannelMapCopy.setName( mNameText.getText() );
|
||||
}
|
||||
} );
|
||||
add( mNameText, "growx, push" );
|
||||
|
||||
mRangeModel = new ChannelMapModel( mChannelMapCopy );
|
||||
|
||||
mRangeTable = new JTable( mRangeModel );
|
||||
mRangeTable.setPreferredScrollableViewportSize( new Dimension( 300, 150 ) );
|
||||
mRangeTable.setFillsViewportHeight( true );
|
||||
mRangeTable.setAutoCreateRowSorter( true );
|
||||
for( int x = 0; x < mRangeTable.getColumnCount(); x++ )
|
||||
{
|
||||
mRangeTable.getColumnModel().getColumn( x )
|
||||
.setCellEditor( new RangeTableEditor() );
|
||||
}
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane( mRangeTable );
|
||||
add( scrollPane, "span,grow,push");
|
||||
|
||||
JButton btnNew = new JButton( "New Range" );
|
||||
btnNew.addActionListener( ChannelMapEditor.this );
|
||||
add( btnNew );
|
||||
|
||||
mDelete = new JButton( "Delete" );
|
||||
mDelete.addActionListener( ChannelMapEditor.this );
|
||||
add( mDelete, "wrap" );
|
||||
|
||||
JButton btnSave = new JButton( "Save" );
|
||||
btnSave.addActionListener( ChannelMapEditor.this );
|
||||
add( btnSave, "growx" );
|
||||
|
||||
JButton btnReset = new JButton( "Reset " );
|
||||
btnReset.addActionListener( ChannelMapEditor.this );
|
||||
add( btnReset, "wrap" );
|
||||
}
|
||||
|
||||
private boolean checkForValidRanges()
|
||||
{
|
||||
int invalidRow = mChannelMapCopy.getInvalidRange();
|
||||
|
||||
if( invalidRow != -1 && invalidRow <= mRangeTable.getRowCount() )
|
||||
{
|
||||
mRangeTable.setRowSelectionInterval( invalidRow, invalidRow );
|
||||
|
||||
JOptionPane.showMessageDialog( this,
|
||||
"Starting channel number must be less than ending channel number",
|
||||
"Channel number range error",
|
||||
JOptionPane.WARNING_MESSAGE );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
String command = e.getActionCommand();
|
||||
|
||||
switch( command )
|
||||
{
|
||||
case "New Range":
|
||||
mRangeModel.addRange( new ChannelRange() );
|
||||
break;
|
||||
case "Save":
|
||||
if( checkForValidRanges() )
|
||||
{
|
||||
mChannelMapNode.getChannelMap()
|
||||
.setName( mChannelMapCopy.getName() );
|
||||
mChannelMapNode.getChannelMap()
|
||||
.setRanges( mChannelMapCopy.getRanges() );
|
||||
|
||||
mChannelMapNode.save();
|
||||
|
||||
mChannelMapNode.refresh();
|
||||
|
||||
mChannelMapNode.show();
|
||||
}
|
||||
case "Reset":
|
||||
mChannelMapCopy = mChannelMapNode.getChannelMap();
|
||||
mRangeModel.setChannelMap( mChannelMapCopy );
|
||||
mNameText.setText( mChannelMapCopy.getName() );
|
||||
break;
|
||||
case "Delete":
|
||||
int row = mRangeTable.getSelectedRow();
|
||||
|
||||
if( row < 0 )
|
||||
{
|
||||
JOptionPane.showMessageDialog( this,
|
||||
"Please select a channel range to delete",
|
||||
"Select a range",
|
||||
JOptionPane.WARNING_MESSAGE );
|
||||
}
|
||||
else
|
||||
{
|
||||
mRangeModel.removeRange(
|
||||
mRangeTable.convertRowIndexToModel( row ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public class RangeTableEditor extends AbstractCellEditor
|
||||
implements TableCellEditor, ActionListener
|
||||
{
|
||||
JFormattedTextField mEditor;
|
||||
|
||||
public RangeTableEditor()
|
||||
{
|
||||
InternationalFormatter nf = new InternationalFormatter();
|
||||
nf.setMinimum( 1 );
|
||||
nf.setAllowsInvalid( false );
|
||||
|
||||
mEditor = new JFormattedTextField( nf );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCellEditorValue()
|
||||
{
|
||||
Log.info( "getCellEditorValue - I've been invoked!" );
|
||||
return mEditor.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
Log.info( "Action Performed:" + e.getActionCommand() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellEditorComponent( JTable table,
|
||||
Object value,
|
||||
boolean isSelected,
|
||||
int row,
|
||||
int column )
|
||||
{
|
||||
mEditor.setValue( value );
|
||||
|
||||
return mEditor;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/controller/channel/ChannelMapList.java
Normal file
76
src/controller/channel/ChannelMapList.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
@XmlSeeAlso( ChannelMap.class )
|
||||
public class ChannelMapList
|
||||
{
|
||||
private ArrayList<ChannelMap> mChannelMap = new ArrayList<ChannelMap>();
|
||||
|
||||
public ChannelMapList()
|
||||
{
|
||||
/* Empty constructor for JAXB */
|
||||
}
|
||||
|
||||
@XmlElement( name = "channel_map" )
|
||||
public ArrayList<ChannelMap> getChannelMap()
|
||||
{
|
||||
return mChannelMap;
|
||||
}
|
||||
|
||||
public void setChannelMap( ArrayList<ChannelMap> ChannelMaps )
|
||||
{
|
||||
mChannelMap = ChannelMaps;
|
||||
}
|
||||
|
||||
public void addChannelMap( ChannelMap ChannelMap )
|
||||
{
|
||||
mChannelMap.add( ChannelMap );
|
||||
}
|
||||
|
||||
public void removeChannelMap( ChannelMap ChannelMap )
|
||||
{
|
||||
mChannelMap.remove( ChannelMap );
|
||||
}
|
||||
|
||||
public void clearChannelMaps()
|
||||
{
|
||||
mChannelMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the named channel map, or returns an empty map
|
||||
*/
|
||||
public ChannelMap getChannelMap( String name )
|
||||
{
|
||||
for( ChannelMap map: mChannelMap )
|
||||
{
|
||||
if( map.getName().equalsIgnoreCase( name ) )
|
||||
{
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
return new ChannelMap();
|
||||
}
|
||||
}
|
||||
87
src/controller/channel/ChannelMapListNode.java
Normal file
87
src/controller/channel/ChannelMapListNode.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import controller.ConfigurableNode;
|
||||
|
||||
public class ChannelMapListNode extends ConfigurableNode
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ChannelMapListNode( ChannelMapList list )
|
||||
{
|
||||
super( list );
|
||||
}
|
||||
|
||||
public ChannelMapList getChannelMapList()
|
||||
{
|
||||
return (ChannelMapList)getUserObject();
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
for( ChannelMap channelMap: getChannelMapList().getChannelMap() )
|
||||
{
|
||||
ChannelMapNode node = new ChannelMapNode( channelMap );
|
||||
|
||||
getModel().addNode( node, ChannelMapListNode.this, getChildCount() );
|
||||
|
||||
node.init();
|
||||
}
|
||||
|
||||
sort();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "Channel Maps [" + this.getChildCount() + "]";
|
||||
}
|
||||
|
||||
public JPopupMenu getContextMenu()
|
||||
{
|
||||
JPopupMenu retVal = new JPopupMenu();
|
||||
|
||||
JMenuItem addSystemItem = new JMenuItem( "Add Channel Map" );
|
||||
addSystemItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
ChannelMap channelMap = new ChannelMap();
|
||||
|
||||
getChannelMapList().addChannelMap( channelMap );
|
||||
|
||||
getModel().addNode( new ChannelMapNode( channelMap ),
|
||||
ChannelMapListNode.this,
|
||||
ChannelMapListNode.this.getChildCount() );
|
||||
|
||||
save();
|
||||
}
|
||||
} );
|
||||
|
||||
retVal.add( addSystemItem );
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
167
src/controller/channel/ChannelMapModel.java
Normal file
167
src/controller/channel/ChannelMapModel.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
import log.Log;
|
||||
|
||||
public class ChannelMapModel extends AbstractTableModel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final int sSTART = 0;
|
||||
private static final int sSTOP = 1;
|
||||
private static final int sBASE = 2;
|
||||
private static final int sSIZE = 3;
|
||||
|
||||
protected int[] mColumnWidths = { 110, 110, 110, -1 };
|
||||
|
||||
protected String[] mHeaders = new String[] { "Begin",
|
||||
"End",
|
||||
"Base",
|
||||
"Size" };
|
||||
|
||||
private ChannelMap mChannelMap;
|
||||
|
||||
public ChannelMapModel( ChannelMap map )
|
||||
{
|
||||
mChannelMap = map;
|
||||
}
|
||||
|
||||
public ChannelMap getChannelMap()
|
||||
{
|
||||
return mChannelMap;
|
||||
}
|
||||
|
||||
public void setChannelMap( ChannelMap map )
|
||||
{
|
||||
mChannelMap = map;
|
||||
|
||||
fireTableDataChanged();
|
||||
}
|
||||
|
||||
public void addRange( ChannelRange range )
|
||||
{
|
||||
mChannelMap.addRange( range );
|
||||
|
||||
int index = mChannelMap.getRanges().size() - 1;
|
||||
|
||||
fireTableRowsInserted( index, index );
|
||||
}
|
||||
|
||||
public void removeRange( int rangeIndex )
|
||||
{
|
||||
if( rangeIndex < mChannelMap.getRanges().size() )
|
||||
{
|
||||
mChannelMap.getRanges().remove( rangeIndex );
|
||||
}
|
||||
|
||||
fireTableRowsDeleted( rangeIndex, rangeIndex );
|
||||
}
|
||||
|
||||
public int[] getColumnWidths()
|
||||
{
|
||||
return mColumnWidths;
|
||||
}
|
||||
|
||||
public void setColumnWidths( int[] widths )
|
||||
{
|
||||
if( widths.length != 4 )
|
||||
{
|
||||
throw new IllegalArgumentException( "ChannelMapRangeModel - "
|
||||
+ "column widths array should have 5 elements" );
|
||||
}
|
||||
else
|
||||
{
|
||||
mColumnWidths = widths;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount()
|
||||
{
|
||||
return mChannelMap.getRanges().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount()
|
||||
{
|
||||
return mHeaders.length;
|
||||
}
|
||||
|
||||
public String getColumnName( int column )
|
||||
{
|
||||
return mHeaders[ column ];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt( int rowIndex, int columnIndex )
|
||||
{
|
||||
ChannelRange range = mChannelMap.getRanges().get( rowIndex );
|
||||
|
||||
switch( columnIndex )
|
||||
{
|
||||
case sSTART:
|
||||
return range.getFirstChannelNumber();
|
||||
case sSTOP:
|
||||
return range.getLastChannelNumber();
|
||||
case sBASE:
|
||||
return range.getBase();
|
||||
case sSIZE:
|
||||
return range.getSize();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isCellEditable( int row, int column )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setValueAt( Object value, int row, int column )
|
||||
{
|
||||
try
|
||||
{
|
||||
int parsedValue = Integer.parseInt( (String)value );
|
||||
|
||||
ChannelRange range = mChannelMap.getRanges().get( row );
|
||||
|
||||
switch( column )
|
||||
{
|
||||
case sSTART:
|
||||
range.setFirstChannelNumber( parsedValue );
|
||||
break;
|
||||
case sSTOP:
|
||||
range.setLastChannelNumber( parsedValue );
|
||||
break;
|
||||
case sBASE:
|
||||
range.setBase( parsedValue );
|
||||
break;
|
||||
case sSIZE:
|
||||
range.setSize( parsedValue );
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
Log.info( "ChannelMapModel - couldn't parse integer value "
|
||||
+ "for [" + value + "] - " + e.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
102
src/controller/channel/ChannelMapNode.java
Normal file
102
src/controller/channel/ChannelMapNode.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import controller.ConfigurableNode;
|
||||
|
||||
public class ChannelMapNode extends ConfigurableNode
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ChannelMapNode( ChannelMap ChannelMap )
|
||||
{
|
||||
super( ChannelMap );
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
//For consistency, but not used
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIconPath()
|
||||
{
|
||||
return "images/ChannelMap.png";
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getEditor()
|
||||
{
|
||||
return new ChannelMapEditor( this );
|
||||
}
|
||||
|
||||
public ChannelMap getChannelMap()
|
||||
{
|
||||
return (ChannelMap)getUserObject();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getChannelMap().getName();
|
||||
}
|
||||
|
||||
public void delete()
|
||||
{
|
||||
ChannelMapListNode parent = (ChannelMapListNode)getParent();
|
||||
|
||||
parent.getChannelMapList().removeChannelMap( getChannelMap() );
|
||||
|
||||
save();
|
||||
|
||||
getModel().removeNodeFromParent( ChannelMapNode.this );
|
||||
|
||||
/* Show the first child, if one exists so that we don't have a
|
||||
* collapsed list */
|
||||
if( parent.getChildCount() > 0 )
|
||||
{
|
||||
((ConfigurableNode)parent.getFirstChild()).show();
|
||||
}
|
||||
}
|
||||
|
||||
public JPopupMenu getContextMenu()
|
||||
{
|
||||
JPopupMenu retVal = new JPopupMenu();
|
||||
|
||||
JMenuItem deleteItem = new JMenuItem( "Delete" );
|
||||
deleteItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
delete();
|
||||
}
|
||||
} );
|
||||
|
||||
retVal.add( deleteItem );
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
168
src/controller/channel/ChannelNode.java
Normal file
168
src/controller/channel/ChannelNode.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import log.Log;
|
||||
import source.tuner.TunerChannel;
|
||||
import controller.ConfigurableNode;
|
||||
import controller.channel.Channel.ChannelEvent;
|
||||
import controller.site.SiteNode;
|
||||
import controller.system.SystemNode;
|
||||
|
||||
/**
|
||||
* A channel has all of the pieces needed to wire together a source, decoder,
|
||||
* event logger and recorder and be started and stopped.
|
||||
*/
|
||||
public class ChannelNode extends ConfigurableNode implements ChannelListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static DecimalFormat sFORMAT = new DecimalFormat( "0.0000" );
|
||||
|
||||
public ChannelNode( Channel channel )
|
||||
{
|
||||
super( channel );
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
/* Set the owning system and site names for the channel */
|
||||
SiteNode siteNode = (SiteNode)getParent();
|
||||
|
||||
if( siteNode != null )
|
||||
{
|
||||
getChannel().setSite( siteNode.getSite(), false );
|
||||
|
||||
SystemNode systemNode = (SystemNode)siteNode.getParent();
|
||||
|
||||
if( systemNode != null )
|
||||
{
|
||||
getChannel().setSystem( systemNode.getSystem(), false );
|
||||
}
|
||||
}
|
||||
|
||||
/* Add this node as listener to receive changes from underlying channel */
|
||||
getChannel().addListener( this );
|
||||
|
||||
/* Add the resource manager to the channel so that the channel
|
||||
* can provide channel change events to all system resources */
|
||||
getChannel().setResourceManager( getModel().getResourceManager() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener method to receive channel changes from the underlying chnannel
|
||||
*/
|
||||
@Override
|
||||
public void occurred( Channel channel, ChannelEvent event )
|
||||
{
|
||||
switch( event )
|
||||
{
|
||||
/* Refresh the node for each of these events */
|
||||
case CHANGE_DECODER:
|
||||
case CHANGE_ENABLED:
|
||||
case CHANGE_NAME:
|
||||
case CHANGE_SELECTED:
|
||||
case CHANGE_SITE:
|
||||
case CHANGE_SYSTEM:
|
||||
case PROCESSING_STARTED:
|
||||
case PROCESSING_STOPPED:
|
||||
this.refresh();
|
||||
break;
|
||||
/* We're being deleted, so cleanup */
|
||||
case CHANNEL_DELETED:
|
||||
delete();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIconPath()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
Channel channel = getChannel();
|
||||
|
||||
sb.append( channel.getDecodeConfiguration().getDecoderType().getIconPrefix() );
|
||||
|
||||
if( channel.getEnabled() )
|
||||
{
|
||||
sb.append( channel.isProcessing() ? "_green" : "_red" );
|
||||
}
|
||||
|
||||
sb.append( ".png" );
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getEditor()
|
||||
{
|
||||
return new ChannelEditor( this );
|
||||
}
|
||||
|
||||
public Channel getChannel()
|
||||
{
|
||||
return (Channel)this.getUserObject();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append( getChannel().getName() );
|
||||
|
||||
TunerChannel channel = getChannel().getTunerChannel();
|
||||
|
||||
if( channel != null )
|
||||
{
|
||||
sb.append( " (" );
|
||||
sb.append( sFORMAT.format( (double)channel.getFrequency() / 1000000.0d ) + " MHz" );
|
||||
sb.append( ")" );
|
||||
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public JPopupMenu getContextMenu()
|
||||
{
|
||||
JPopupMenu popupMenu = new JPopupMenu( "Channel Menu" );
|
||||
popupMenu.add( getChannel().getContextMenu() );
|
||||
|
||||
return popupMenu;
|
||||
}
|
||||
|
||||
public void delete()
|
||||
{
|
||||
Log.info( "Channel Node - deleting ..." );
|
||||
((SiteNode)getParent()).getSite().removeChannel( getChannel() );
|
||||
|
||||
Log.info( "Channel Node - saving after channel delete" );
|
||||
save();
|
||||
|
||||
Log.info( "Channel Node - removing from site node" );
|
||||
getModel().removeNodeFromParent( ChannelNode.this );
|
||||
}
|
||||
}
|
||||
122
src/controller/channel/ChannelRange.java
Normal file
122
src/controller/channel/ChannelRange.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
@XmlRootElement
|
||||
@XmlType( name = "range" )
|
||||
public class ChannelRange
|
||||
{
|
||||
private int mFirst = 1;
|
||||
private int mLast = 1023;
|
||||
private int mBase = 450000000;
|
||||
private int mSize = 12500;
|
||||
|
||||
/* JAXB requirement - do not remove */
|
||||
public ChannelRange() {}
|
||||
|
||||
public ChannelRange( int first, int last, int base, int size )
|
||||
{
|
||||
mFirst = first;
|
||||
mLast = last;
|
||||
mBase = base;
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
public ChannelRange copyOf()
|
||||
{
|
||||
return new ChannelRange( mFirst, mLast, mBase, mSize );
|
||||
}
|
||||
|
||||
public boolean isValid()
|
||||
{
|
||||
return mFirst < mLast;
|
||||
}
|
||||
|
||||
public boolean hasChannel( int channel )
|
||||
{
|
||||
return mFirst <= channel && channel <= mLast;
|
||||
}
|
||||
|
||||
public int getFrequency( int channel )
|
||||
{
|
||||
if( hasChannel( channel ) )
|
||||
{
|
||||
return mBase + ( ( channel - mFirst ) * mSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "first" )
|
||||
public int getFirstChannelNumber()
|
||||
{
|
||||
return mFirst;
|
||||
}
|
||||
|
||||
public void setFirstChannelNumber( int first )
|
||||
{
|
||||
mFirst = first;
|
||||
}
|
||||
|
||||
@XmlAttribute( name = "last" )
|
||||
public void setLastChannelNumber( int last )
|
||||
{
|
||||
mLast = last;
|
||||
}
|
||||
|
||||
public int getLastChannelNumber()
|
||||
{
|
||||
return mLast;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base frequency
|
||||
* @param base frequency in hertz
|
||||
*/
|
||||
@XmlAttribute( name = "base" )
|
||||
public void setBase( int base )
|
||||
{
|
||||
mBase = base;
|
||||
}
|
||||
|
||||
public int getBase()
|
||||
{
|
||||
return mBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the channel size
|
||||
* @param size in hertz
|
||||
*/
|
||||
@XmlAttribute( name = "size" )
|
||||
public void setSize( int size )
|
||||
{
|
||||
mSize = size;
|
||||
}
|
||||
|
||||
public int getSize()
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
}
|
||||
23
src/controller/channel/ChannelSelectionListener.java
Normal file
23
src/controller/channel/ChannelSelectionListener.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
public interface ChannelSelectionListener
|
||||
{
|
||||
public void channelSelected( ProcessingChain channel );
|
||||
}
|
||||
721
src/controller/channel/ProcessingChain.java
Normal file
721
src/controller/channel/ProcessingChain.java
Normal file
@@ -0,0 +1,721 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedTransferQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import log.Log;
|
||||
import message.Message;
|
||||
import record.Recorder;
|
||||
import record.wave.ComplexWaveRecorder;
|
||||
import record.wave.FloatWaveRecorder;
|
||||
import sample.Broadcaster;
|
||||
import sample.Listener;
|
||||
import sample.Provider;
|
||||
import sample.complex.ComplexSample;
|
||||
import source.ComplexSource;
|
||||
import source.FloatArraySource;
|
||||
import source.FloatSource;
|
||||
import source.Source;
|
||||
import source.Source.SampleType;
|
||||
import source.config.SourceConfigMixer;
|
||||
import source.tuner.Tuner;
|
||||
import source.tuner.TunerChannelSource;
|
||||
import alias.AliasList;
|
||||
import audio.AudioOutput;
|
||||
import audio.AudioTypeListener;
|
||||
import audio.SquelchListener;
|
||||
import controller.ResourceManager;
|
||||
import controller.ThreadPoolManager.ThreadType;
|
||||
import controller.activity.CallEvent;
|
||||
import controller.channel.Channel.ChannelType;
|
||||
import controller.state.ChannelState;
|
||||
import controller.state.ChannelState.State;
|
||||
import decode.Decoder;
|
||||
import decode.DecoderFactory;
|
||||
import eventlog.EventLogType;
|
||||
import eventlog.EventLogger;
|
||||
|
||||
/**
|
||||
* A channel has all of the pieces needed to wire together a source, decoder,
|
||||
* event logger and recorder and be started and stopped.
|
||||
*/
|
||||
public class ProcessingChain implements Listener<Message>
|
||||
{
|
||||
protected AtomicBoolean mRunning = new AtomicBoolean();
|
||||
protected Channel mChannel;
|
||||
protected Source mSource;
|
||||
protected Decoder mDecoder;
|
||||
protected List<Recorder> mRecorders = new ArrayList<Recorder>();
|
||||
protected ArrayList<EventLogger> mEventLoggers = new ArrayList<EventLogger>();
|
||||
protected AudioOutput mAudioOutput;
|
||||
protected ChannelState mChannelState;
|
||||
protected ResourceManager mResourceManager;
|
||||
private ScheduledFuture<?> mProcessorTask;
|
||||
private AliasList mAliasList;
|
||||
|
||||
private ComplexListener mComplexListener = new ComplexListener();
|
||||
private LinkedTransferQueue<List<ComplexSample>> mComplexBuffer =
|
||||
new LinkedTransferQueue<List<ComplexSample>>();
|
||||
|
||||
private FloatListener mFloatListener = new FloatListener();
|
||||
private FloatArrayListener mFloatArrayListener = new FloatArrayListener();
|
||||
private LinkedTransferQueue<Float> mFloatBuffer =
|
||||
new LinkedTransferQueue<Float>();
|
||||
|
||||
protected Broadcaster<Message> mBroadcaster = new Broadcaster<Message>();
|
||||
|
||||
public ProcessingChain( Channel channel, ResourceManager resourceManager )
|
||||
{
|
||||
mChannel = channel;
|
||||
mResourceManager = resourceManager;
|
||||
|
||||
if( mResourceManager != null )
|
||||
{
|
||||
mAliasList = mResourceManager.getPlaylistManager()
|
||||
.getPlayist().getAliasDirectory().getAliasList(
|
||||
mChannel.getAliasListName() );
|
||||
}
|
||||
}
|
||||
|
||||
public Listener<List<ComplexSample>> getComplexListener()
|
||||
{
|
||||
return mComplexListener;
|
||||
}
|
||||
|
||||
public Listener<Float> getFloatListener()
|
||||
{
|
||||
return mFloatListener;
|
||||
}
|
||||
|
||||
public Listener<Float[]> getFloatArrayListener()
|
||||
{
|
||||
return mFloatArrayListener;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mChannel.getName();
|
||||
}
|
||||
|
||||
public AliasList getAliasList()
|
||||
{
|
||||
return mAliasList;
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
if( mProcessorTask != null )
|
||||
{
|
||||
mResourceManager.getThreadPoolManager().cancel( mProcessorTask );
|
||||
}
|
||||
|
||||
if( mChannelState != null )
|
||||
{
|
||||
mChannelState.dispose();
|
||||
}
|
||||
|
||||
mChannelState = null;
|
||||
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.dispose();
|
||||
}
|
||||
|
||||
mBroadcaster.dispose();
|
||||
mEventLoggers.clear();
|
||||
mRecorders.clear();
|
||||
|
||||
|
||||
if( mAudioOutput != null )
|
||||
{
|
||||
mAudioOutput.dispose();
|
||||
}
|
||||
|
||||
mResourceManager = null;
|
||||
}
|
||||
|
||||
public ResourceManager getResourceManager()
|
||||
{
|
||||
return mResourceManager;
|
||||
}
|
||||
|
||||
public void start()
|
||||
{
|
||||
if( !mRunning.get() && mChannel.getEnabled() )
|
||||
{
|
||||
updateSource();
|
||||
|
||||
updateDecoder();
|
||||
|
||||
updateEventLogging();
|
||||
|
||||
updateRecording();
|
||||
|
||||
mRunning.set( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.info( getLogPrefix() + "start() invoked, but processing chain is "
|
||||
+ "already started" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs closeout operations to prepare for channel deletion
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
if( mRunning.get() )
|
||||
{
|
||||
updateSource();
|
||||
|
||||
updateDecoder();
|
||||
|
||||
updateRecording();
|
||||
|
||||
/* Flush call events to the logger */
|
||||
if( getChannel().getChannelType() == ChannelType.STANDARD )
|
||||
{
|
||||
getChannelState().getCallEventModel().flush();
|
||||
}
|
||||
|
||||
updateEventLogging();
|
||||
|
||||
if( mAudioOutput != null )
|
||||
{
|
||||
mAudioOutput.setAudioPlaybackEnabled( false );
|
||||
}
|
||||
|
||||
mRunning.set( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.info( getLogPrefix() + "stop() invoked, but processing chain was "
|
||||
+ "already stopped" );
|
||||
}
|
||||
}
|
||||
|
||||
private String getLogPrefix()
|
||||
{
|
||||
return "Channel [" + mChannel.getName() + "] - ";
|
||||
}
|
||||
|
||||
public void updateSource()
|
||||
{
|
||||
/* Cleanup existing source */
|
||||
if( mSource != null )
|
||||
{
|
||||
if( mSource instanceof ComplexSource )
|
||||
{
|
||||
((ComplexSource)mSource).removeListener( this.getComplexListener() );
|
||||
}
|
||||
else if( mSource instanceof FloatSource )
|
||||
{
|
||||
((FloatSource)mSource).removeListener( this.getFloatListener() );
|
||||
}
|
||||
else if( mSource instanceof FloatArraySource )
|
||||
{
|
||||
((FloatArraySource)mSource)
|
||||
.removeListener( this.getFloatArrayListener() );
|
||||
}
|
||||
|
||||
if( mProcessorTask != null )
|
||||
{
|
||||
mResourceManager.getThreadPoolManager().cancel( mProcessorTask );
|
||||
}
|
||||
|
||||
mSource.dispose();
|
||||
|
||||
mSource = null;
|
||||
}
|
||||
|
||||
/* Get a new source if needed and start the sample processor thread */
|
||||
if( mChannel.getEnabled() && mResourceManager != null )
|
||||
{
|
||||
mSource = mResourceManager.getSourceManager()
|
||||
.getSource( ProcessingChain.this );
|
||||
|
||||
if( mSource != null )
|
||||
{
|
||||
if( mSource instanceof ComplexSource )
|
||||
{
|
||||
try
|
||||
{
|
||||
mProcessorTask =
|
||||
mResourceManager.getThreadPoolManager()
|
||||
.schedule( ThreadType.DECODER,
|
||||
new ComplexProcessor(),
|
||||
50, TimeUnit.MILLISECONDS );
|
||||
|
||||
((ComplexSource)mSource)
|
||||
.setListener( this.getComplexListener() );
|
||||
}
|
||||
catch( RejectedExecutionException ree )
|
||||
{
|
||||
Log.error( getLogPrefix() + "ProcessingChain - "
|
||||
+ "error scheduling complex sample processing "
|
||||
+ "thread - " + ree.getLocalizedMessage() );
|
||||
|
||||
mSource.dispose();
|
||||
}
|
||||
}
|
||||
else if( mSource instanceof FloatSource )
|
||||
{
|
||||
try
|
||||
{
|
||||
mProcessorTask =
|
||||
mResourceManager.getThreadPoolManager()
|
||||
.schedule( ThreadType.DECODER,
|
||||
new FloatProcessor(),
|
||||
50, TimeUnit.MILLISECONDS );
|
||||
|
||||
((FloatSource)mSource)
|
||||
.setListener( this.getFloatListener() );
|
||||
}
|
||||
catch( RejectedExecutionException ree )
|
||||
{
|
||||
Log.error( getLogPrefix() + "ProcessingChain - "
|
||||
+ "error scheduling float sample processing "
|
||||
+ "thread - " + ree.getLocalizedMessage() );
|
||||
|
||||
mSource.dispose();
|
||||
}
|
||||
}
|
||||
else if( mSource instanceof FloatArraySource )
|
||||
{
|
||||
try
|
||||
{
|
||||
mProcessorTask =
|
||||
mResourceManager.getThreadPoolManager()
|
||||
.schedule( ThreadType.DECODER,
|
||||
new FloatProcessor(),
|
||||
50, TimeUnit.MILLISECONDS );
|
||||
|
||||
((FloatArraySource)mSource)
|
||||
.setListener( this.getFloatArrayListener() );
|
||||
}
|
||||
catch( RejectedExecutionException ree )
|
||||
{
|
||||
Log.error( getLogPrefix() + "ProcessingChain - "
|
||||
+ "error scheduling float sample processing "
|
||||
+ "thread - " + ree.getLocalizedMessage() );
|
||||
|
||||
mSource.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDecoder()
|
||||
{
|
||||
if( mChannel.getEnabled() )
|
||||
{
|
||||
AliasList aliasList = null;
|
||||
|
||||
if( mResourceManager != null )
|
||||
{
|
||||
aliasList = mResourceManager.getPlaylistManager()
|
||||
.getPlayist().getAliasDirectory().getAliasList(
|
||||
mChannel.getAliasListName() );
|
||||
}
|
||||
|
||||
/* Setup the channel state */
|
||||
mChannelState = DecoderFactory.getChannelStateNew( this, aliasList );
|
||||
|
||||
if( mSource == null )
|
||||
{
|
||||
mChannelState.setState( State.NO_TUNER );
|
||||
}
|
||||
else
|
||||
{
|
||||
mDecoder = DecoderFactory.
|
||||
getDecoder( this, mSource.getSampleType(), aliasList );
|
||||
|
||||
if( mDecoder != null )
|
||||
{
|
||||
/* Register to receive decoded messages and auxiliary messages */
|
||||
mDecoder.addMessageListener( ProcessingChain.this );
|
||||
|
||||
/* Setup the audio output processing thread */
|
||||
String threadName = "SDRTrunk Audio - " +
|
||||
mChannel.getSite().getName() +
|
||||
"-" + mChannel.getName();
|
||||
|
||||
mAudioOutput = new AudioOutput( threadName );
|
||||
addFloatListener( mAudioOutput );
|
||||
}
|
||||
}
|
||||
|
||||
if( mAudioOutput != null )
|
||||
{
|
||||
/* Register audio output to be controlled by the channel state */
|
||||
mChannelState.addListener( (SquelchListener)mAudioOutput );
|
||||
mChannelState.setListener( (AudioTypeListener)mAudioOutput );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts, stops or changes event logging
|
||||
*/
|
||||
public void updateEventLogging()
|
||||
{
|
||||
/* Shutdown and remove existing event loggers */
|
||||
if( mEventLoggers != null )
|
||||
{
|
||||
for( EventLogger logger: mEventLoggers )
|
||||
{
|
||||
logger.stop();
|
||||
}
|
||||
|
||||
mEventLoggers.clear();
|
||||
}
|
||||
|
||||
/* Construct event loggers and add as message listeners */
|
||||
if( mChannel.getEnabled() &&
|
||||
mResourceManager != null )
|
||||
{
|
||||
//Get the event loggers
|
||||
ArrayList<EventLogType> types = getChannel()
|
||||
.getEventLogConfiguration().getLoggers();
|
||||
|
||||
for( EventLogType type: types )
|
||||
{
|
||||
EventLogger logger;
|
||||
|
||||
if( type == EventLogType.CALL_EVENT )
|
||||
{
|
||||
logger = mResourceManager.getEventLogManager()
|
||||
.getLogger( this, type );
|
||||
|
||||
getChannelState().getCallEventModel()
|
||||
.addListener( (Listener<CallEvent>)logger );
|
||||
}
|
||||
else
|
||||
{
|
||||
logger = mResourceManager.getEventLogManager()
|
||||
.getLogger( this, type );
|
||||
|
||||
addListener( (Listener<Message>)logger );
|
||||
}
|
||||
|
||||
logger.start();
|
||||
|
||||
mEventLoggers.add( logger );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts, stops or changes data recording
|
||||
*/
|
||||
public void updateRecording()
|
||||
{
|
||||
/* Remove any existing recorders */
|
||||
if( mRecorders != null )
|
||||
{
|
||||
for( Recorder recorder: mRecorders )
|
||||
{
|
||||
if( recorder != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
recorder.stop();
|
||||
}
|
||||
catch ( IOException ioe )
|
||||
{
|
||||
Log.error( getLogPrefix() + "Couldn't stop recorder [" +
|
||||
recorder.getFileName() + "] " +
|
||||
ioe.getLocalizedMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Start any new recorders */
|
||||
if( mChannel.getEnabled() &&
|
||||
mResourceManager != null &&
|
||||
mDecoder != null )
|
||||
{
|
||||
mRecorders = mResourceManager.getRecorderManager()
|
||||
.getRecorder( this );
|
||||
|
||||
/* Iterate any returned recorders and start/add them */
|
||||
for( Recorder recorder: mRecorders )
|
||||
{
|
||||
try
|
||||
{
|
||||
recorder.start();
|
||||
|
||||
if( recorder instanceof FloatWaveRecorder )
|
||||
{
|
||||
Log.info( getLogPrefix() + "- started audio recording [" +
|
||||
recorder.getFileName() + "]" );
|
||||
|
||||
mDecoder.addFloatListener( (FloatWaveRecorder)recorder );
|
||||
}
|
||||
else if( recorder instanceof ComplexWaveRecorder )
|
||||
{
|
||||
Log.info( getLogPrefix() + "- started baseband recording [" +
|
||||
recorder.getFileName() + "]" );
|
||||
|
||||
mDecoder.addComplexListener( (ComplexWaveRecorder )recorder );
|
||||
}
|
||||
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
Log.error( getLogPrefix() + "Unable to start recorder [" +
|
||||
recorder.getFileName() + "]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Channel getChannel()
|
||||
{
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
public AudioOutput getAudioOutput()
|
||||
{
|
||||
return mAudioOutput;
|
||||
}
|
||||
|
||||
public Source getSource()
|
||||
{
|
||||
return mSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tuner that is sourcing this channel, or null if it's being
|
||||
* sourced from some other source
|
||||
*/
|
||||
public Tuner getTuner()
|
||||
{
|
||||
Tuner retVal = null;
|
||||
|
||||
if( mSource instanceof TunerChannelSource )
|
||||
{
|
||||
retVal = ((TunerChannelSource)mSource).getTuner();
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public Decoder getDecoder()
|
||||
{
|
||||
return mDecoder;
|
||||
}
|
||||
|
||||
public ChannelState getChannelState()
|
||||
{
|
||||
return mChannelState;
|
||||
}
|
||||
|
||||
public boolean isRunning()
|
||||
{
|
||||
return mRunning.get();
|
||||
}
|
||||
|
||||
public boolean isProcessing()
|
||||
{
|
||||
return isRunning() && mSource != null;
|
||||
}
|
||||
|
||||
private source.mixer.MixerChannel getMixerChannel()
|
||||
{
|
||||
source.mixer.MixerChannel retVal = null;
|
||||
|
||||
if( mChannel.getSourceConfiguration() instanceof SourceConfigMixer )
|
||||
{
|
||||
SourceConfigMixer mixer = (SourceConfigMixer)mChannel.getSourceConfiguration();
|
||||
|
||||
retVal = mixer.getChannel();
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive( Message message )
|
||||
{
|
||||
if( message.isValid() )
|
||||
{
|
||||
mBroadcaster.receive( message );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void addFloatListener( Listener<Float> listener )
|
||||
{
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.addFloatListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFloatListener( Listener<Float> listener )
|
||||
{
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.removeFloatListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
public void addComplexListener( Listener<ComplexSample> listener )
|
||||
{
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.addComplexListener( listener );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error( getLogPrefix() + "attempt to add a complex sample "
|
||||
+ "listener, but the decoder is null" );
|
||||
}
|
||||
}
|
||||
|
||||
public void removeComplexListener( Listener<ComplexSample> listener )
|
||||
{
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.removeComplexListener( listener );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error( getLogPrefix() + "attempt to remove a complex sample "
|
||||
+ "listener, but the decoder is null" );
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener( Listener<Message> listener )
|
||||
{
|
||||
mBroadcaster.addListener( listener );
|
||||
}
|
||||
|
||||
public void addListeners( List<Listener<Message>> listeners )
|
||||
{
|
||||
for( Listener<Message> listener: listeners )
|
||||
{
|
||||
addListener( listener );
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener( Listener<Message> listener )
|
||||
{
|
||||
mBroadcaster.removeListener( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Runnable float sample processing task. Schedule this task to run 20
|
||||
* times a second when we're receiving complex samples from our source.
|
||||
* Schedule execution via the thread pool manager, obtainable from the
|
||||
* resource manager,
|
||||
*/
|
||||
private class FloatProcessor implements Runnable
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
List<Float> samples = new ArrayList<Float>();
|
||||
|
||||
mFloatBuffer.drainTo( samples, 48000 );
|
||||
|
||||
for( Float sample: samples )
|
||||
{
|
||||
if( mDecoder != null )
|
||||
{
|
||||
mDecoder.getFloatReceiver().receive( sample );
|
||||
}
|
||||
}
|
||||
|
||||
samples.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runnable complex sample processing task. Schedule this task to run 20
|
||||
* times a second when we're receiving complex samples from our source.
|
||||
* Schedule execution via the thread pool manager, obtainable from the
|
||||
* resource manager,
|
||||
*/
|
||||
private class ComplexProcessor implements Runnable
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
List<List<ComplexSample>> sampleSets =
|
||||
new ArrayList<List<ComplexSample>>();
|
||||
|
||||
mComplexBuffer.drainTo( sampleSets, 16 );
|
||||
|
||||
for( List<ComplexSample> samples: sampleSets )
|
||||
{
|
||||
for( ComplexSample sample: samples )
|
||||
{
|
||||
if( sample != null && mDecoder != null )
|
||||
{
|
||||
mDecoder.getComplexReceiver().receive( sample );
|
||||
}
|
||||
}
|
||||
|
||||
samples.clear();
|
||||
}
|
||||
|
||||
sampleSets.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public class ComplexListener implements Listener<List<ComplexSample>>
|
||||
{
|
||||
@Override
|
||||
public void receive( List<ComplexSample> samples )
|
||||
{
|
||||
mComplexBuffer.add( samples );
|
||||
}
|
||||
}
|
||||
|
||||
public class FloatListener implements Listener<Float>
|
||||
{
|
||||
@Override
|
||||
public void receive( Float sample )
|
||||
{
|
||||
mFloatBuffer.add( sample );
|
||||
}
|
||||
}
|
||||
|
||||
public class FloatArrayListener implements Listener<Float[]>
|
||||
{
|
||||
@Override
|
||||
public void receive( Float[] samples )
|
||||
{
|
||||
mFloatBuffer.addAll( Arrays.asList( samples ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
40
src/controller/config/Configuration.java
Normal file
40
src/controller/config/Configuration.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.config;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
import record.config.RecordConfiguration;
|
||||
import source.config.SourceConfiguration;
|
||||
import decode.config.AuxDecodeConfiguration;
|
||||
import decode.config.DecodeConfiguration;
|
||||
import eventlog.config.EventLogConfiguration;
|
||||
|
||||
@XmlSeeAlso( { AuxDecodeConfiguration.class,
|
||||
DecodeConfiguration.class,
|
||||
EventLogConfiguration.class,
|
||||
RecordConfiguration.class,
|
||||
SourceConfiguration.class } )
|
||||
@XmlRootElement( name = "configuration" )
|
||||
public abstract class Configuration
|
||||
{
|
||||
public Configuration()
|
||||
{
|
||||
}
|
||||
}
|
||||
86
src/controller/site/Site.java
Normal file
86
src/controller/site/Site.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.site;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
import controller.channel.Channel;
|
||||
|
||||
@XmlSeeAlso( { Channel.class } )
|
||||
@XmlRootElement( name = "site" )
|
||||
public class Site
|
||||
{
|
||||
private String mName;
|
||||
|
||||
private ArrayList<Channel> mChannel = new ArrayList<Channel>();
|
||||
|
||||
public Site()
|
||||
{
|
||||
this( "New Site" );
|
||||
}
|
||||
|
||||
public Site( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
public void setName( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public ArrayList<Channel> getChannel()
|
||||
{
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
public void setChannel( ArrayList<Channel> configs )
|
||||
{
|
||||
mChannel = configs;
|
||||
}
|
||||
|
||||
public void addChannel( Channel channel )
|
||||
{
|
||||
mChannel.add( channel );
|
||||
}
|
||||
|
||||
public void removeChannel( Channel channel )
|
||||
{
|
||||
mChannel.remove( channel );
|
||||
}
|
||||
|
||||
public void removeAllChannels()
|
||||
{
|
||||
mChannel.clear();
|
||||
}
|
||||
}
|
||||
101
src/controller/site/SiteEditor.java
Normal file
101
src/controller/site/SiteEditor.java
Normal file
@@ -0,0 +1,101 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.site;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
public class SiteEditor extends JPanel implements ActionListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private SiteNode mSiteNode;
|
||||
|
||||
private JLabel mLabelName;
|
||||
private JTextField mTextSite;
|
||||
|
||||
public SiteEditor( SiteNode site )
|
||||
{
|
||||
mSiteNode = site;
|
||||
initGUI();
|
||||
}
|
||||
|
||||
private void initGUI()
|
||||
{
|
||||
setLayout( new MigLayout() );
|
||||
|
||||
setBorder( BorderFactory.createTitledBorder( "Site" ) );
|
||||
|
||||
mLabelName = new JLabel( "Name:" );
|
||||
add( mLabelName, "align right" );
|
||||
|
||||
mTextSite = new JTextField( mSiteNode.getSite().getName() );
|
||||
add( mTextSite, "grow, wrap" );
|
||||
|
||||
JButton btnSave = new JButton( "Save" );
|
||||
btnSave.addActionListener( SiteEditor.this );
|
||||
add( btnSave );
|
||||
|
||||
JButton btnReset = new JButton( "Reset" );
|
||||
btnReset.addActionListener( SiteEditor.this );
|
||||
add( btnReset, "wrap" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
String command = e.getActionCommand();
|
||||
|
||||
if( command.contentEquals( "Save" ) )
|
||||
{
|
||||
boolean expanded = mSiteNode.getModel().getTree()
|
||||
.isExpanded( new TreePath( mSiteNode ) );
|
||||
|
||||
String name = mTextSite.getText();
|
||||
|
||||
if( name != null )
|
||||
{
|
||||
mSiteNode.getSite().setName( name );
|
||||
mSiteNode.save();
|
||||
mSiteNode.show();
|
||||
|
||||
if( expanded )
|
||||
{
|
||||
mSiteNode.getModel().getTree().expandPath( new TreePath( mSiteNode ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JOptionPane.showMessageDialog( SiteEditor.this, "Please enter a system name" );
|
||||
}
|
||||
}
|
||||
else if( command.contentEquals( "Reset" ) )
|
||||
{
|
||||
mTextSite.setText( mSiteNode.getSite().getName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
167
src/controller/site/SiteNode.java
Normal file
167
src/controller/site/SiteNode.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.site;
|
||||
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
import controller.ConfigurableNode;
|
||||
import controller.channel.Channel;
|
||||
import controller.channel.ChannelNode;
|
||||
import controller.system.System;
|
||||
import controller.system.SystemNode;
|
||||
|
||||
public class SiteNode extends ConfigurableNode
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SiteNode( Site site )
|
||||
{
|
||||
super( site );
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
for( Channel channel: getSite().getChannel() )
|
||||
{
|
||||
ChannelNode node = new ChannelNode( channel );
|
||||
|
||||
getModel().insertNodeInto( node, SiteNode.this, getChildCount() );
|
||||
|
||||
node.init();
|
||||
}
|
||||
|
||||
sort();
|
||||
}
|
||||
|
||||
public String getIconPath()
|
||||
{
|
||||
String retVal = "images/site.png";
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
Enumeration<DefaultMutableTreeNode> nodes = children();
|
||||
|
||||
while( nodes.hasMoreElements() )
|
||||
{
|
||||
ChannelNode child = (ChannelNode)nodes.nextElement();
|
||||
|
||||
if( child.getIconPath().contains( "green.png" ) )
|
||||
{
|
||||
return "images/site_green.png";
|
||||
}
|
||||
else if( child.getIconPath().contains( "red.png" ) )
|
||||
{
|
||||
retVal = "images/site_red.png";
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getEditor()
|
||||
{
|
||||
return new SiteEditor( this );
|
||||
}
|
||||
|
||||
public Site getSite()
|
||||
{
|
||||
return (Site)getUserObject();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getSite().getName();
|
||||
}
|
||||
|
||||
public void delete()
|
||||
{
|
||||
for( int x = 0; x < getChildCount(); x++ )
|
||||
{
|
||||
((ChannelNode)getChildAt( x )).delete();
|
||||
}
|
||||
|
||||
((SystemNode)getParent()).getSystem().removeSite( getSite() );
|
||||
|
||||
save();
|
||||
|
||||
getModel().removeNodeFromParent( SiteNode.this );
|
||||
}
|
||||
|
||||
public JPopupMenu getContextMenu()
|
||||
{
|
||||
JPopupMenu retVal = new JPopupMenu();
|
||||
|
||||
JMenuItem addChannelItem = new JMenuItem( "Add Channel" );
|
||||
addChannelItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
System system = ((SystemNode)getParent()).getSystem();
|
||||
|
||||
Channel channel = new Channel();
|
||||
channel.setSystem( system, false );
|
||||
channel.setSite( getSite(), false );
|
||||
|
||||
getSite().addChannel( channel );
|
||||
|
||||
ChannelNode node = new ChannelNode( channel );
|
||||
|
||||
getModel().addNode( node,
|
||||
SiteNode.this,
|
||||
SiteNode.this.getChildCount() );
|
||||
|
||||
sort();
|
||||
save();
|
||||
node.show();
|
||||
|
||||
/* Give channel reference to the resource manager and the
|
||||
* channel will register the listeners and send a channel
|
||||
* add event */
|
||||
channel.setResourceManager( getModel().getResourceManager() );
|
||||
}
|
||||
} );
|
||||
|
||||
retVal.add( addChannelItem );
|
||||
|
||||
retVal.add( new JSeparator() );
|
||||
|
||||
JMenuItem deleteItem = new JMenuItem( "Delete" );
|
||||
deleteItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
delete();
|
||||
}
|
||||
} );
|
||||
|
||||
retVal.add( deleteItem );
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
80
src/controller/state/AuxChannelState.java
Normal file
80
src/controller/state/AuxChannelState.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.state;
|
||||
|
||||
import message.Message;
|
||||
import sample.Broadcaster;
|
||||
import sample.Listener;
|
||||
import controller.state.ChannelState.ChangedAttribute;
|
||||
|
||||
/**
|
||||
* ChannelState for auxiliary decoders.
|
||||
*/
|
||||
public abstract class AuxChannelState implements Listener<Message>
|
||||
{
|
||||
protected ChannelState mParentChannelState;
|
||||
protected Broadcaster<ChangedAttribute> mChangeBroadcaster =
|
||||
new Broadcaster<ChangedAttribute>();
|
||||
|
||||
public AuxChannelState( ChannelState parentState )
|
||||
{
|
||||
mParentChannelState = parentState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare for garbage collect
|
||||
*/
|
||||
public void dispose()
|
||||
{
|
||||
mChangeBroadcaster.dispose();
|
||||
mParentChannelState = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call fade - change display and await a call to reset()
|
||||
*/
|
||||
public abstract void fade();
|
||||
|
||||
/**
|
||||
* Activity summary for this decoder
|
||||
*/
|
||||
public abstract String getActivitySummary();
|
||||
|
||||
/**
|
||||
* Call end - cleanup the display
|
||||
*/
|
||||
public abstract void reset();
|
||||
|
||||
public void addListener( Listener<ChangedAttribute> listener )
|
||||
{
|
||||
mChangeBroadcaster.addListener( listener );
|
||||
}
|
||||
|
||||
public void removeListener( Listener<ChangedAttribute> listener )
|
||||
{
|
||||
mChangeBroadcaster.removeListener( listener );
|
||||
}
|
||||
|
||||
public void broadcastChange( ChangedAttribute attribute )
|
||||
{
|
||||
if( mChangeBroadcaster != null )
|
||||
{
|
||||
mChangeBroadcaster.broadcast( attribute );
|
||||
}
|
||||
}
|
||||
}
|
||||
143
src/controller/state/AuxStatePanel.java
Normal file
143
src/controller/state/AuxStatePanel.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.state;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import sample.Listener;
|
||||
import settings.ColorSetting;
|
||||
import settings.ColorSetting.ColorSettingName;
|
||||
import settings.Setting;
|
||||
import settings.SettingChangeListener;
|
||||
import settings.SettingsManager;
|
||||
import alias.Alias;
|
||||
import controller.state.ChannelState.ChangedAttribute;
|
||||
|
||||
public abstract class AuxStatePanel extends JPanel
|
||||
implements Listener<ChangedAttribute>,
|
||||
SettingChangeListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected Font mFontDetails = new Font( Font.MONOSPACED, Font.PLAIN, 10 );
|
||||
protected Font mFontAuxDecoder = new Font( Font.MONOSPACED, Font.PLAIN, 10 );
|
||||
|
||||
protected Color mColorLabelDetails;
|
||||
protected Color mColorLabelAuxDecoder;
|
||||
|
||||
protected SettingsManager mSettingsManager;
|
||||
protected AuxChannelState mAuxChannelState;
|
||||
|
||||
public AuxStatePanel( SettingsManager settingsManager,
|
||||
AuxChannelState auxChannelState )
|
||||
{
|
||||
mSettingsManager = settingsManager;
|
||||
mAuxChannelState = auxChannelState;
|
||||
|
||||
/* Register to receive event updates */
|
||||
mAuxChannelState.addListener( this );
|
||||
|
||||
/* Register to receive settings updates */
|
||||
mSettingsManager.addListener( this );
|
||||
|
||||
getColors();
|
||||
|
||||
setLayout( new MigLayout( "insets 1 0 0 0", "[grow,fill]", "[]0[]0[]") );
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
/* Deregister from changed settings events */
|
||||
mSettingsManager.removeListener( this );
|
||||
mSettingsManager = null;
|
||||
|
||||
mAuxChannelState = null;
|
||||
}
|
||||
|
||||
protected void addLabel( JLabel label, boolean wrap )
|
||||
{
|
||||
label.setFont( mFontAuxDecoder );
|
||||
label.setForeground( mColorLabelAuxDecoder );
|
||||
|
||||
if( wrap )
|
||||
{
|
||||
add( label, "wrap" );
|
||||
}
|
||||
else
|
||||
{
|
||||
add( label );
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateAliasLabel( JLabel label, Alias alias )
|
||||
{
|
||||
if( alias != null )
|
||||
{
|
||||
label.setText( alias.getName() );
|
||||
|
||||
String iconName = alias.getIconName();
|
||||
|
||||
ImageIcon icon = mSettingsManager.getImageIcon( iconName, 12 );
|
||||
|
||||
label.setIcon( icon );
|
||||
}
|
||||
else
|
||||
{
|
||||
label.setText( null );
|
||||
label.setIcon( null );
|
||||
}
|
||||
}
|
||||
|
||||
private void getColors()
|
||||
{
|
||||
mColorLabelDetails = mSettingsManager.getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_LABEL_DETAILS ).getColor();
|
||||
mColorLabelAuxDecoder = mSettingsManager.getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_LABEL_AUX_DECODER ).getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settingChanged( Setting setting )
|
||||
{
|
||||
if( setting instanceof ColorSetting )
|
||||
{
|
||||
ColorSetting colorSetting = (ColorSetting)setting;
|
||||
|
||||
switch( colorSetting.getColorSettingName() )
|
||||
{
|
||||
case CHANNEL_STATE_LABEL_AUX_DECODER:
|
||||
mColorLabelAuxDecoder = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_LABEL_DETAILS:
|
||||
mColorLabelDetails = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settingDeleted( Setting setting ) {}
|
||||
}
|
||||
664
src/controller/state/ChannelState.java
Normal file
664
src/controller/state/ChannelState.java
Normal file
@@ -0,0 +1,664 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.state;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.JTable;
|
||||
|
||||
import log.Log;
|
||||
import message.Message;
|
||||
import properties.SystemProperties;
|
||||
import sample.Broadcaster;
|
||||
import sample.Listener;
|
||||
import alias.AliasList;
|
||||
import audio.AudioType;
|
||||
import audio.AudioTypeListener;
|
||||
import audio.SquelchListener;
|
||||
import audio.SquelchListener.SquelchState;
|
||||
import controller.activity.CallEvent;
|
||||
import controller.activity.CallEvent.CallEventType;
|
||||
import controller.activity.CallEventAliasCellRenderer;
|
||||
import controller.activity.CallEventModel;
|
||||
import controller.activity.MessageActivityModel;
|
||||
import controller.channel.Channel.ChannelType;
|
||||
import controller.channel.ProcessingChain;
|
||||
|
||||
/**
|
||||
* ChannelState provides a state machine for tracking a voice or data call
|
||||
* through it's life cycle of CALL/DATA, FADE, and then END, and then back to
|
||||
* an IDLE state. This class also provides squelch control for unsquelching
|
||||
* sound to the speakers, and/or sound to an audio recorder
|
||||
*
|
||||
* State Descriptions:
|
||||
* IDLE No voice or data call activity
|
||||
* CALL/DATA A voice or data call has started, or is continuing
|
||||
* CONTROL Control channel
|
||||
* FADE The phase after a voice or data call when either an explicit
|
||||
* call end has been received, or when no new signalling updates
|
||||
* have been received, and the fade timer has expired. This phase
|
||||
* allows for gui updates to signal to the user that the call is
|
||||
* ended, while continuing to display the call details for the user
|
||||
* END The phase after the voice or data call FADE, when the call is
|
||||
* now over, and the gui should be reset to IDLE.
|
||||
*
|
||||
* When a call is started, invoke mTimerService.startFadeTimer() to start the
|
||||
* call fade monitoring timer process that will automatically signal a call end
|
||||
* once no more call signalling has been detected after the fade timeout has
|
||||
* occurred, by invoking the fade() method.
|
||||
*
|
||||
* When a call ends, invoke the mTimerService.stopFadeTimer() and then invoke
|
||||
* the mTimerService.startResetTimer(). Once the reset timeout occurs,
|
||||
* the reset() method will be called, allowing the channel state to perform
|
||||
* any reset actions, like clearing status and id labels on any view panels.
|
||||
*
|
||||
* AuxChannelState class allows for auxiliary decoders like Fleetsync to both
|
||||
* have a state and leverage the state machine of the parent ChannelState.
|
||||
* This allows a non-squelching channel state like for conventional fm to have
|
||||
* an aux decoder like fleetsync, and allow the fleetsync auxchannelstate to
|
||||
* leverage the call/end states of the parent conventional channelstate.
|
||||
*
|
||||
*/
|
||||
public abstract class ChannelState implements Listener<Message>
|
||||
{
|
||||
private State mState = State.IDLE;
|
||||
private Object mCallFadeLock = new Object();
|
||||
private Object mCallResetLock = new Object();
|
||||
private long mFadeTimeout = -1;
|
||||
private long mResetTimeout = -1;
|
||||
|
||||
protected long mCallFadeTimeout;
|
||||
protected long mCallResetTimeout;
|
||||
protected TimerService mTimerService = new TimerService();
|
||||
protected ArrayList<SquelchListener> mSquelchListeners =
|
||||
new ArrayList<SquelchListener>();
|
||||
protected ArrayList<AuxChannelState> mAuxChannelStates =
|
||||
new ArrayList<AuxChannelState>();
|
||||
protected Broadcaster<ChangedAttribute> mChangeBroadcaster =
|
||||
new Broadcaster<ChangedAttribute>();
|
||||
protected AudioTypeListener mAudioTypeListener;
|
||||
protected AudioType mAudioType = AudioType.NORMAL;
|
||||
|
||||
|
||||
protected CallEventModel mCallEventModel = new CallEventModel();
|
||||
|
||||
protected JTable mCallEventTable;
|
||||
|
||||
protected MessageActivityModel mMessageActivityModel =
|
||||
new MessageActivityModel();
|
||||
protected JTable mMessageActivityTable;
|
||||
|
||||
protected ProcessingChain mProcessingChain;
|
||||
|
||||
protected AliasList mAliasList;
|
||||
|
||||
public ChannelState( ProcessingChain processingChain, AliasList aliasList )
|
||||
{
|
||||
mProcessingChain = processingChain;
|
||||
mAliasList = aliasList;
|
||||
|
||||
|
||||
/* Register to receive decoded messages from the processing chain */
|
||||
mProcessingChain.addListener( this );
|
||||
|
||||
SystemProperties props = SystemProperties.getInstance();
|
||||
mCallFadeTimeout = props.get( "call.fade.timeout", 2000 );
|
||||
mCallResetTimeout = props.get( "call.reset.timeout", 4000 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows setting the call event model to use for traffic channels, so that
|
||||
* all traffic channels can share the parent control channel call event
|
||||
* model.
|
||||
* @param model
|
||||
*/
|
||||
public void setCallEventModel( CallEventModel model )
|
||||
{
|
||||
mCallEventModel = model;
|
||||
}
|
||||
|
||||
public CallEventModel getCallEventModel()
|
||||
{
|
||||
return mCallEventModel;
|
||||
}
|
||||
|
||||
public void receiveCallEvent( CallEvent event )
|
||||
{
|
||||
mCallEventModel.add( event );
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mTimerService.dispose();
|
||||
|
||||
mAuxChannelStates.clear();
|
||||
mSquelchListeners.clear();
|
||||
mChangeBroadcaster.dispose();
|
||||
mChangeBroadcaster = null;
|
||||
|
||||
if( mProcessingChain.getChannel().getChannelType() == ChannelType.STANDARD )
|
||||
{
|
||||
mCallEventModel.dispose();
|
||||
}
|
||||
/* If we're a traffic channel, set the call event model to null so that
|
||||
* we don't dispose the parent control channel's call event model */
|
||||
else
|
||||
{
|
||||
mCallEventModel = null;
|
||||
}
|
||||
|
||||
mMessageActivityModel.dispose();
|
||||
mMessageActivityModel = null;
|
||||
|
||||
mAliasList = null;
|
||||
mAudioTypeListener = null;
|
||||
mCallEventModel = null;
|
||||
mProcessingChain = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel Activity Summary - implemented by the sub-class.
|
||||
*/
|
||||
public abstract String getActivitySummary();
|
||||
|
||||
public AliasList getAliasList()
|
||||
{
|
||||
return mAliasList;
|
||||
}
|
||||
|
||||
public boolean hasAliasList()
|
||||
{
|
||||
return mAliasList != null;
|
||||
}
|
||||
|
||||
public void broadcastChange( ChangedAttribute attribute )
|
||||
{
|
||||
if( mChangeBroadcaster != null )
|
||||
{
|
||||
mChangeBroadcaster.broadcast( attribute );
|
||||
}
|
||||
}
|
||||
|
||||
public void setCallFadeTimeout( long milliseconds )
|
||||
{
|
||||
mCallFadeTimeout = milliseconds;
|
||||
}
|
||||
|
||||
public JTable getCallEventTable()
|
||||
{
|
||||
if( mCallEventTable == null )
|
||||
{
|
||||
mCallEventTable = new JTable( mCallEventModel );
|
||||
mCallEventTable.setAutoCreateRowSorter( true );
|
||||
mCallEventTable.setAutoResizeMode( JTable.AUTO_RESIZE_LAST_COLUMN );
|
||||
|
||||
CallEventAliasCellRenderer renderer =
|
||||
new CallEventAliasCellRenderer( mProcessingChain
|
||||
.getResourceManager().getSettingsManager() );
|
||||
|
||||
mCallEventTable.getColumnModel().getColumn( 3 )
|
||||
.setCellRenderer( renderer );
|
||||
|
||||
mCallEventTable.getColumnModel().getColumn( 5 )
|
||||
.setCellRenderer( renderer );
|
||||
}
|
||||
|
||||
return mCallEventTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public JTable getMessageActivityTable()
|
||||
{
|
||||
if( mMessageActivityTable == null )
|
||||
{
|
||||
mMessageActivityTable = new JTable( mMessageActivityModel );
|
||||
mMessageActivityTable.setAutoResizeMode( JTable.AUTO_RESIZE_LAST_COLUMN );
|
||||
}
|
||||
|
||||
return mMessageActivityTable;
|
||||
}
|
||||
|
||||
public void addAuxChannelState( AuxChannelState state )
|
||||
{
|
||||
mAuxChannelStates.add( state );
|
||||
}
|
||||
|
||||
public ArrayList<AuxChannelState> getAuxChannelStates()
|
||||
{
|
||||
return mAuxChannelStates;
|
||||
}
|
||||
|
||||
public void receive( Message message )
|
||||
{
|
||||
if( mMessageActivityModel != null )
|
||||
{
|
||||
mMessageActivityModel.receive( message );
|
||||
}
|
||||
|
||||
for( AuxChannelState state: mAuxChannelStates )
|
||||
{
|
||||
if( state != null )
|
||||
{
|
||||
state.receive( message );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ProcessingChain getProcessingChain()
|
||||
{
|
||||
return mProcessingChain;
|
||||
}
|
||||
|
||||
public State getState()
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
public void setState( State state )
|
||||
{
|
||||
/* Let all CALL state changes go through in order to update the fade
|
||||
* timer, otherwise, don't update the state if it hasn't changed */
|
||||
if( mState != state || state == State.CALL )
|
||||
{
|
||||
if( mState.canChangeTo( state ) )
|
||||
{
|
||||
mState = state;
|
||||
|
||||
switch( state )
|
||||
{
|
||||
case CALL:
|
||||
setSquelchState( SquelchState.UNSQUELCH );
|
||||
case DATA:
|
||||
mTimerService.stopResetTimer();
|
||||
mTimerService.startFadeTimer();
|
||||
break;
|
||||
case NO_TUNER:
|
||||
mTimerService.stopResetTimer();
|
||||
if( getProcessingChain().getChannel()
|
||||
.getChannelType() == ChannelType.TRAFFIC )
|
||||
{
|
||||
mTimerService.startFadeTimer();
|
||||
}
|
||||
break;
|
||||
case FADE:
|
||||
mTimerService.stopFadeTimer();
|
||||
mTimerService.startResetTimer();
|
||||
setSquelchState( SquelchState.SQUELCH );
|
||||
if( mAudioTypeListener != null )
|
||||
{
|
||||
mAudioTypeListener.setAudioType( mAudioType );
|
||||
}
|
||||
break;
|
||||
case END:
|
||||
mTimerService.stopResetTimer();
|
||||
mTimerService.stopFadeTimer();
|
||||
setSquelchState( SquelchState.SQUELCH );
|
||||
if( mAudioTypeListener != null )
|
||||
{
|
||||
mAudioTypeListener.setAudioType( mAudioType );
|
||||
}
|
||||
|
||||
/* If this is a traffic channel, stop it */
|
||||
if( mProcessingChain.getChannel()
|
||||
.getChannelType() == ChannelType.TRAFFIC )
|
||||
{
|
||||
mProcessingChain.getChannel().setEnabled( false );
|
||||
}
|
||||
break;
|
||||
case IDLE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
broadcastChange( ChangedAttribute.CHANNEL_STATE );
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error( "Channel State - can't change from [" +
|
||||
mState.toString() + "] to [" + state.toString() + "]" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* End method to reset the channel state once a call has completely
|
||||
* ended and now you want to return the channel state to idle
|
||||
*/
|
||||
protected void reset()
|
||||
{
|
||||
setState( State.END );
|
||||
|
||||
for( AuxChannelState state: mAuxChannelStates )
|
||||
{
|
||||
state.reset();
|
||||
}
|
||||
|
||||
//Reset the state to idle
|
||||
setState( State.IDLE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to perform any call fade actions. On fade, you should change the
|
||||
* channel state to fading, and construct a call-reset timer to execute a few
|
||||
* seconds later. This allows the view to signal to the user that the call
|
||||
* has faded/ended, and display faded information to the user, until the
|
||||
* cleanup() task is run.
|
||||
*/
|
||||
protected void fade( CallEventType type )
|
||||
{
|
||||
for( AuxChannelState state: mAuxChannelStates )
|
||||
{
|
||||
state.fade();
|
||||
}
|
||||
|
||||
setState( State.FADE );
|
||||
}
|
||||
|
||||
public void setListener( AudioTypeListener listener )
|
||||
{
|
||||
mAudioTypeListener = listener;
|
||||
}
|
||||
|
||||
public void addListener( SquelchListener listener )
|
||||
{
|
||||
mSquelchListeners.add( listener );
|
||||
}
|
||||
|
||||
public void removeListener( SquelchListener listener )
|
||||
{
|
||||
mSquelchListeners.remove( listener );
|
||||
}
|
||||
|
||||
protected void setSquelchState( SquelchState state )
|
||||
{
|
||||
Iterator<SquelchListener> it = mSquelchListeners.iterator();
|
||||
|
||||
while( it.hasNext() )
|
||||
{
|
||||
it.next().setSquelch( state );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer service
|
||||
*/
|
||||
public class TimerService extends ScheduledThreadPoolExecutor
|
||||
{
|
||||
private long mTimerMonitorRevisitRate = 100; //100 milliseconds
|
||||
|
||||
private ScheduledFuture<?> mTimerMonitor;
|
||||
|
||||
public TimerService()
|
||||
{
|
||||
super( 1 );
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
if( mTimerMonitor != null )
|
||||
{
|
||||
mTimerMonitor.cancel( true );
|
||||
}
|
||||
|
||||
this.shutdownNow();
|
||||
}
|
||||
|
||||
private void checkMonitor()
|
||||
{
|
||||
boolean createTimer = false;
|
||||
|
||||
synchronized( mCallFadeLock )
|
||||
{
|
||||
if( mFadeTimeout != -1 )
|
||||
{
|
||||
createTimer = true;
|
||||
}
|
||||
}
|
||||
|
||||
synchronized( mCallResetLock )
|
||||
{
|
||||
if( mResetTimeout != -1 )
|
||||
{
|
||||
createTimer = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( createTimer )
|
||||
{
|
||||
//Check to see if the timer is already running, if not, start it
|
||||
|
||||
if( mTimerMonitor == null || mTimerMonitor.isDone() )
|
||||
{
|
||||
scheduleAtFixedRate( new StateTimeoutMonitor(),
|
||||
mTimerMonitorRevisitRate,
|
||||
mTimerMonitorRevisitRate,
|
||||
TimeUnit.MILLISECONDS );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( mTimerMonitor != null )
|
||||
{
|
||||
mTimerMonitor.cancel( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startFadeTimer()
|
||||
{
|
||||
synchronized( mCallFadeLock )
|
||||
{
|
||||
mFadeTimeout = System.currentTimeMillis() + mCallFadeTimeout;
|
||||
}
|
||||
|
||||
checkMonitor();
|
||||
}
|
||||
|
||||
public void resetFadeTimer()
|
||||
{
|
||||
startFadeTimer();
|
||||
}
|
||||
|
||||
public void stopFadeTimer()
|
||||
{
|
||||
synchronized( mCallFadeLock )
|
||||
{
|
||||
mFadeTimeout = -1;
|
||||
}
|
||||
|
||||
checkMonitor();
|
||||
}
|
||||
|
||||
public void startResetTimer()
|
||||
{
|
||||
synchronized( mCallResetLock )
|
||||
{
|
||||
mResetTimeout = System.currentTimeMillis() + mCallResetTimeout;
|
||||
}
|
||||
|
||||
checkMonitor();
|
||||
}
|
||||
|
||||
public void stopResetTimer()
|
||||
{
|
||||
synchronized( mCallResetLock )
|
||||
{
|
||||
mResetTimeout = -1;
|
||||
}
|
||||
|
||||
checkMonitor();
|
||||
}
|
||||
}
|
||||
|
||||
public class StateTimeoutMonitor implements Runnable
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
synchronized( mCallFadeLock )
|
||||
{
|
||||
if( mFadeTimeout != -1 && now >= mFadeTimeout )
|
||||
{
|
||||
mFadeTimeout = -1;
|
||||
|
||||
fade( CallEventType.CALL_TIMEOUT );
|
||||
}
|
||||
}
|
||||
|
||||
synchronized( mCallResetLock )
|
||||
{
|
||||
if( mResetTimeout != -1 && now >= mResetTimeout )
|
||||
{
|
||||
mResetTimeout = -1;
|
||||
|
||||
reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum State
|
||||
{
|
||||
IDLE( "IDLE" ) {
|
||||
@Override
|
||||
public boolean canChangeTo( State state )
|
||||
{
|
||||
return state == IDLE ||
|
||||
state == CALL ||
|
||||
state == CONTROL ||
|
||||
state == DATA ||
|
||||
state == FADE ||
|
||||
state == NO_TUNER;
|
||||
}
|
||||
},
|
||||
CALL( "CALL" ) {
|
||||
@Override
|
||||
public boolean canChangeTo( State state )
|
||||
{
|
||||
return state == CALL ||
|
||||
state == CONTROL ||
|
||||
state == DATA ||
|
||||
state == FADE;
|
||||
}
|
||||
},
|
||||
DATA( "DATA" ) {
|
||||
@Override
|
||||
public boolean canChangeTo( State state )
|
||||
{
|
||||
return state == CALL ||
|
||||
state == CONTROL ||
|
||||
state == DATA ||
|
||||
state == FADE;
|
||||
}
|
||||
},
|
||||
CONTROL( "CONTROL" )
|
||||
{
|
||||
@Override
|
||||
public boolean canChangeTo( State state )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
},
|
||||
FADE( "FADE" ) {
|
||||
@Override
|
||||
public boolean canChangeTo( State state )
|
||||
{
|
||||
return state != FADE; //All states except fade allowed
|
||||
}
|
||||
},
|
||||
END( "END" ) {
|
||||
@Override
|
||||
public boolean canChangeTo( State state )
|
||||
{
|
||||
return state != FADE; //Fade is only disallowed state
|
||||
}
|
||||
},
|
||||
NO_TUNER( "NO TUNER" ) {
|
||||
@Override
|
||||
public boolean canChangeTo( State state )
|
||||
{
|
||||
return state == FADE || state == END;
|
||||
}
|
||||
};
|
||||
|
||||
private String mDisplayValue;
|
||||
|
||||
private State( String displayValue )
|
||||
{
|
||||
mDisplayValue = displayValue;
|
||||
}
|
||||
|
||||
public abstract boolean canChangeTo( State state );
|
||||
|
||||
public String getDisplayValue()
|
||||
{
|
||||
return mDisplayValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener to receive channel state attribute changes
|
||||
*/
|
||||
public void addListener( Listener<ChangedAttribute> listener )
|
||||
{
|
||||
mChangeBroadcaster.addListener( listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from receiving channel state attribute changes
|
||||
*/
|
||||
public void removeListener( Listener<ChangedAttribute> listener )
|
||||
{
|
||||
mChangeBroadcaster.removeListener( listener );
|
||||
}
|
||||
|
||||
public enum ChangedAttribute
|
||||
{
|
||||
AUDIO_TYPE,
|
||||
CHANNEL_NUMBER,
|
||||
CHANNEL_NAME,
|
||||
CHANNEL_SITE_NUMBER,
|
||||
CHANNEL_SITE_NUMBER_ALIAS,
|
||||
CHANNEL_STATE,
|
||||
FROM_TALKGROUP,
|
||||
FROM_TALKGROUP_ALIAS,
|
||||
FROM_TALKGROUP_TYPE,
|
||||
MESSAGE,
|
||||
MESSAGE_TYPE,
|
||||
SITE_NAME,
|
||||
SOURCE,
|
||||
SYSTEM_NAME,
|
||||
SQUELCH,
|
||||
TO_TALKGROUP,
|
||||
TO_TALKGROUP_ALIAS,
|
||||
TO_TALKGROUP_TYPE;
|
||||
}
|
||||
}
|
||||
442
src/controller/state/ChannelStateList.java
Normal file
442
src/controller/state/ChannelStateList.java
Normal file
@@ -0,0 +1,442 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.state;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import settings.ColorSetting.ColorSettingName;
|
||||
import settings.ColorSettingMenuItem;
|
||||
import settings.ColorSettingResetMenuItem;
|
||||
import settings.SettingsManager;
|
||||
import controller.channel.Channel;
|
||||
import controller.channel.Channel.ChannelEvent;
|
||||
import controller.channel.Channel.ChannelType;
|
||||
import controller.channel.ChannelListener;
|
||||
import decode.fleetsync2.FleetsyncChannelState;
|
||||
import decode.fleetsync2.FleetsyncPanel;
|
||||
import decode.ltrnet.LTRNetChannelState;
|
||||
import decode.ltrnet.LTRNetPanel;
|
||||
import decode.ltrstandard.LTRChannelState;
|
||||
import decode.ltrstandard.LTRPanel;
|
||||
import decode.mdc1200.MDCChannelState;
|
||||
import decode.mdc1200.MDCPanel;
|
||||
import decode.mpt1327.MPT1327ChannelState;
|
||||
import decode.mpt1327.MPT1327Panel;
|
||||
import decode.nbfm.NBFMChannelState;
|
||||
import decode.nbfm.NBFMPanel;
|
||||
import decode.passport.PassportChannelState;
|
||||
import decode.passport.PassportPanel;
|
||||
|
||||
public class ChannelStateList extends JPanel implements ChannelListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private HashMap<Channel,ChannelStatePanel> mDisplayedPanels =
|
||||
new HashMap<Channel,ChannelStatePanel>();
|
||||
|
||||
private SettingsManager mSettingsManager;
|
||||
|
||||
public ChannelStateList( SettingsManager settingsManager )
|
||||
{
|
||||
mSettingsManager = settingsManager;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout( new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[]0[]") );
|
||||
setBackground( Color.BLACK );
|
||||
|
||||
addMouseListener( new ListSelectionListener() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void occurred( Channel channel, ChannelEvent event )
|
||||
{
|
||||
ChannelType type = channel.getChannelType();
|
||||
|
||||
switch( event )
|
||||
{
|
||||
case PROCESSING_STARTED:
|
||||
if( type == ChannelType.STANDARD )
|
||||
{
|
||||
channelStarted( channel );
|
||||
}
|
||||
else if( type == ChannelType.TRAFFIC )
|
||||
{
|
||||
for( Channel parent: mDisplayedPanels.keySet() )
|
||||
{
|
||||
if( parent.hasTrafficChannel( channel ) )
|
||||
{
|
||||
mDisplayedPanels.get( parent ).trafficChannelAdded( channel );
|
||||
validate();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROCESSING_STOPPED:
|
||||
if( type == ChannelType.STANDARD )
|
||||
{
|
||||
channelStopped( channel );
|
||||
}
|
||||
/* Since we don't have a reference to the parent channel that
|
||||
* owns the traffic channel, iterate all channels to find the
|
||||
* parent */
|
||||
else if( type == ChannelType.TRAFFIC )
|
||||
{
|
||||
for( Channel control: mDisplayedPanels.keySet() )
|
||||
{
|
||||
if( control.hasTrafficChannel( channel ) )
|
||||
{
|
||||
control.removeTrafficChannel( channel );
|
||||
|
||||
mDisplayedPanels.get( control ).trafficChannelDeleted( channel );
|
||||
|
||||
validate();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void channelStarted( Channel channel )
|
||||
{
|
||||
if( !mDisplayedPanels.containsKey( channel ) )
|
||||
{
|
||||
ChannelState state = channel.getProcessingChain().getChannelState();
|
||||
|
||||
ChannelStatePanel panel = null;
|
||||
|
||||
if( state instanceof NBFMChannelState )
|
||||
{
|
||||
NBFMChannelState convState =
|
||||
(NBFMChannelState)state;
|
||||
|
||||
panel = new NBFMPanel( channel );
|
||||
|
||||
for( AuxChannelState aux: convState.getAuxChannelStates() )
|
||||
{
|
||||
if( aux instanceof FleetsyncChannelState )
|
||||
{
|
||||
FleetsyncPanel fsPanel =
|
||||
new FleetsyncPanel( mSettingsManager,
|
||||
(FleetsyncChannelState)aux );
|
||||
|
||||
panel.addPanel( fsPanel );
|
||||
}
|
||||
else if( aux instanceof MDCChannelState )
|
||||
{
|
||||
MDCPanel mdsPanel = new MDCPanel( mSettingsManager,
|
||||
(MDCChannelState)aux );
|
||||
|
||||
panel.addPanel( mdsPanel );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( state instanceof LTRChannelState )
|
||||
{
|
||||
LTRChannelState ltrState = (LTRChannelState)state;
|
||||
|
||||
panel = new LTRPanel( mSettingsManager, channel );
|
||||
|
||||
for( AuxChannelState aux: ltrState.getAuxChannelStates() )
|
||||
{
|
||||
if( aux instanceof FleetsyncChannelState )
|
||||
{
|
||||
FleetsyncPanel fsPanel = new FleetsyncPanel( mSettingsManager,
|
||||
(FleetsyncChannelState)aux );
|
||||
|
||||
panel.addPanel( fsPanel );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( state instanceof LTRNetChannelState )
|
||||
{
|
||||
LTRNetChannelState ltrState = (LTRNetChannelState)state;
|
||||
|
||||
panel = new LTRNetPanel( channel );
|
||||
|
||||
for( AuxChannelState aux: ltrState.getAuxChannelStates() )
|
||||
{
|
||||
if( aux instanceof FleetsyncChannelState )
|
||||
{
|
||||
FleetsyncPanel fsPanel = new FleetsyncPanel( mSettingsManager,
|
||||
(FleetsyncChannelState)aux );
|
||||
|
||||
panel.addPanel( fsPanel );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( state instanceof MPT1327ChannelState )
|
||||
{
|
||||
MPT1327ChannelState mptState = (MPT1327ChannelState)state;
|
||||
|
||||
panel = new MPT1327Panel( channel );
|
||||
}
|
||||
else if( state instanceof PassportChannelState )
|
||||
{
|
||||
PassportChannelState passportState = (PassportChannelState)state;
|
||||
|
||||
panel = new PassportPanel( mSettingsManager, channel );
|
||||
|
||||
for( AuxChannelState aux: passportState.getAuxChannelStates() )
|
||||
{
|
||||
if( aux instanceof FleetsyncChannelState )
|
||||
{
|
||||
FleetsyncPanel fsPanel = new FleetsyncPanel( mSettingsManager,
|
||||
(FleetsyncChannelState)aux );
|
||||
|
||||
panel.addPanel( fsPanel );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( panel != null )
|
||||
{
|
||||
add( panel, "wrap" );
|
||||
|
||||
mDisplayedPanels.put( channel, panel );
|
||||
|
||||
validate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void channelStopped( Channel channel )
|
||||
{
|
||||
if( mDisplayedPanels.containsKey( channel ) )
|
||||
{
|
||||
ChannelStatePanel panel = mDisplayedPanels.get( channel );
|
||||
|
||||
if( panel != null )
|
||||
{
|
||||
remove( panel );
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
mDisplayedPanels.remove( channel );
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelectedChannel( ChannelStatePanel selectedPanel )
|
||||
{
|
||||
boolean current = selectedPanel.getSelected();
|
||||
|
||||
for( ChannelStatePanel panel: mDisplayedPanels.values() )
|
||||
{
|
||||
//Turn selected off
|
||||
panel.setSelected( false );
|
||||
}
|
||||
|
||||
selectedPanel.setSelected( !current );
|
||||
}
|
||||
|
||||
public class ListSelectionListener implements MouseListener
|
||||
{
|
||||
@Override
|
||||
public void mouseClicked( MouseEvent e )
|
||||
{
|
||||
Component component = getComponentAt( e.getPoint() );
|
||||
|
||||
if( component instanceof ChannelStatePanel )
|
||||
{
|
||||
ChannelStatePanel panel = (ChannelStatePanel)component;
|
||||
|
||||
/* If the panel has child traffic channels, attempt to get
|
||||
* one of them for the mouse event */
|
||||
if( panel.getChannel().getTrafficChannels().size() > 0 )
|
||||
{
|
||||
for( ChannelStatePanel trafficPanel: panel.getTrafficPanels().values() )
|
||||
{
|
||||
Point translatedPoint = SwingUtilities
|
||||
.convertPoint( e.getComponent(), e.getPoint(),
|
||||
trafficPanel );
|
||||
|
||||
if( trafficPanel.contains( translatedPoint ) )
|
||||
{
|
||||
panel = trafficPanel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( e.getButton() == MouseEvent.BUTTON1 )
|
||||
{
|
||||
setSelectedChannel( panel );
|
||||
}
|
||||
else if( e.getButton() == MouseEvent.BUTTON3 )
|
||||
{
|
||||
JPopupMenu popupMenu = new JPopupMenu();
|
||||
JMenu menu = panel.getChannel().getContextMenu();
|
||||
|
||||
popupMenu.add( menu );
|
||||
|
||||
JMenu colorMenu = new JMenu( "Color" );
|
||||
popupMenu.add( colorMenu );
|
||||
|
||||
JMenu backgroundMenu = new JMenu( "Background" );
|
||||
colorMenu.add( backgroundMenu );
|
||||
|
||||
backgroundMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_BACKGROUND ) );
|
||||
backgroundMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_BACKGROUND ) );
|
||||
|
||||
JMenu channelsMenu = new JMenu( "Channel State" );
|
||||
colorMenu.add( channelsMenu );
|
||||
|
||||
JMenu callMenu = new JMenu( "Call" );
|
||||
channelsMenu.add( callMenu );
|
||||
|
||||
callMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_CALL ) );
|
||||
callMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_CALL ) );
|
||||
callMenu.add( new JSeparator() );
|
||||
|
||||
callMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_CALL ) );
|
||||
callMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_CALL ) );
|
||||
|
||||
JMenu controlMenu = new JMenu( "Control" );
|
||||
channelsMenu.add( controlMenu );
|
||||
|
||||
controlMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_CONTROL ) );
|
||||
controlMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_CONTROL ) );
|
||||
controlMenu.add( new JSeparator() );
|
||||
|
||||
controlMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_CONTROL ) );
|
||||
controlMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_CONTROL ) );
|
||||
|
||||
JMenu dataMenu = new JMenu( "Data" );
|
||||
channelsMenu.add( dataMenu );
|
||||
|
||||
dataMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_DATA ) );
|
||||
dataMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_DATA ) );
|
||||
dataMenu.add( new JSeparator() );
|
||||
|
||||
dataMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_DATA ) );
|
||||
dataMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_DATA ) );
|
||||
|
||||
JMenu fadeMenu = new JMenu( "Fade" );
|
||||
channelsMenu.add( fadeMenu );
|
||||
|
||||
fadeMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_FADE ) );
|
||||
fadeMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_FADE ) );
|
||||
fadeMenu.add( new JSeparator() );
|
||||
|
||||
fadeMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_FADE ) );
|
||||
fadeMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_FADE ) );
|
||||
|
||||
JMenu idleMenu = new JMenu( "Idle" );
|
||||
channelsMenu.add( idleMenu );
|
||||
|
||||
idleMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_IDLE ) );
|
||||
idleMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_IDLE ) );
|
||||
idleMenu.add( new JSeparator() );
|
||||
|
||||
idleMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_IDLE ) );
|
||||
idleMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_IDLE ) );
|
||||
|
||||
JMenu noTunerMenu = new JMenu( "No Tuner" );
|
||||
channelsMenu.add( noTunerMenu );
|
||||
|
||||
noTunerMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_NO_TUNER ) );
|
||||
noTunerMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_NO_TUNER ) );
|
||||
noTunerMenu.add( new JSeparator() );
|
||||
|
||||
noTunerMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_NO_TUNER ) );
|
||||
noTunerMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_NO_TUNER ) );
|
||||
|
||||
JMenu labelMenu = new JMenu( "Labels" );
|
||||
colorMenu.add( labelMenu );
|
||||
|
||||
labelMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_LABEL_AUX_DECODER ) );
|
||||
labelMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_LABEL_AUX_DECODER ) );
|
||||
labelMenu.add( new JSeparator() );
|
||||
|
||||
labelMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_LABEL_DECODER ) );
|
||||
labelMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_LABEL_DECODER ) );
|
||||
labelMenu.add( new JSeparator() );
|
||||
|
||||
labelMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_LABEL_DETAILS ) );
|
||||
labelMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_LABEL_DETAILS ) );
|
||||
|
||||
JMenu selectedMenu = new JMenu( "Selected" );
|
||||
colorMenu.add( selectedMenu );
|
||||
|
||||
selectedMenu.add( new ColorSettingMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_SELECTED_CHANNEL ) );
|
||||
selectedMenu.add( new ColorSettingResetMenuItem( mSettingsManager,
|
||||
ColorSettingName.CHANNEL_STATE_SELECTED_CHANNEL ) );
|
||||
|
||||
popupMenu.show( ChannelStateList.this, e.getX(), e.getY() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void mousePressed( MouseEvent e ) {}
|
||||
public void mouseReleased( MouseEvent e ) {}
|
||||
public void mouseEntered( MouseEvent e ) {}
|
||||
public void mouseExited( MouseEvent e ) {}
|
||||
}
|
||||
}
|
||||
386
src/controller/state/ChannelStatePanel.java
Normal file
386
src/controller/state/ChannelStatePanel.java
Normal file
@@ -0,0 +1,386 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.state;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Font;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Paint;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import log.Log;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import sample.Listener;
|
||||
import settings.ColorSetting;
|
||||
import settings.ColorSetting.ColorSettingName;
|
||||
import settings.Setting;
|
||||
import settings.SettingChangeListener;
|
||||
import settings.SettingsManager;
|
||||
import controller.channel.Channel;
|
||||
import controller.state.ChannelState.ChangedAttribute;
|
||||
import controller.state.ChannelState.State;
|
||||
|
||||
public abstract class ChannelStatePanel extends JPanel
|
||||
implements Listener<ChangedAttribute>,
|
||||
SettingChangeListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected Font mFontDetails = new Font( Font.MONOSPACED, Font.PLAIN, 10 );
|
||||
protected Font mFontDecoder = new Font( Font.MONOSPACED, Font.PLAIN, 10 );
|
||||
protected Font mFontAuxDecoder = new Font( Font.MONOSPACED, Font.PLAIN, 10 );
|
||||
|
||||
protected Color mColorChannelBackground;
|
||||
protected Color mColorChannelSelected;
|
||||
protected Color mColorTopCall;
|
||||
protected Color mColorMiddleCall;
|
||||
protected Color mColorTopControl;
|
||||
protected Color mColorMiddleControl;
|
||||
protected Color mColorTopData;
|
||||
protected Color mColorMiddleData;
|
||||
protected Color mColorTopFade;
|
||||
protected Color mColorMiddleFade;
|
||||
protected Color mColorTopIdle;
|
||||
protected Color mColorMiddleIdle;
|
||||
protected Color mColorTopNoTuner;
|
||||
protected Color mColorMiddleNoTuner;
|
||||
protected Color mColorLabelDetails;
|
||||
protected Color mColorLabelDecoder;
|
||||
protected Color mColorLabelAuxDecoder;
|
||||
|
||||
private HashMap<Channel,ChannelStatePanel> mTrafficPanels =
|
||||
new HashMap<Channel,ChannelStatePanel>();
|
||||
|
||||
protected Channel mChannel;
|
||||
|
||||
public ChannelStatePanel( Channel channel )
|
||||
{
|
||||
mChannel = channel;
|
||||
|
||||
/* Register to receive settings updates */
|
||||
getSettingsManager().addListener( this );
|
||||
|
||||
/* Register to receive channel updates */
|
||||
mChannel.getProcessingChain().getChannelState().addListener( this );
|
||||
|
||||
getColors();
|
||||
|
||||
setLayout( new MigLayout( "insets 3 2 2 2", "[grow,fill]", "[]0[]0[]") );
|
||||
}
|
||||
|
||||
public SettingsManager getSettingsManager()
|
||||
{
|
||||
return mChannel.getResourceManager().getSettingsManager();
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
mTrafficPanels.clear();
|
||||
mChannel = null;
|
||||
}
|
||||
|
||||
private void getColors()
|
||||
{
|
||||
mColorChannelBackground = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_BACKGROUND ).getColor();
|
||||
mColorChannelSelected = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_SELECTED_CHANNEL ).getColor();
|
||||
mColorTopCall = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_CALL ).getColor();
|
||||
mColorMiddleCall = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_CALL ).getColor();
|
||||
mColorTopControl = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_CONTROL ).getColor();
|
||||
mColorMiddleControl = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_CONTROL ).getColor();
|
||||
mColorTopData = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_DATA ).getColor();
|
||||
mColorMiddleData = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_DATA ).getColor();
|
||||
mColorTopFade = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_FADE ).getColor();
|
||||
mColorMiddleFade = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_FADE ).getColor();
|
||||
mColorTopIdle = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_IDLE ).getColor();
|
||||
mColorMiddleIdle = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_IDLE ).getColor();
|
||||
mColorTopNoTuner = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_TOP_NO_TUNER ).getColor();
|
||||
mColorMiddleNoTuner = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_GRADIENT_MIDDLE_NO_TUNER ).getColor();
|
||||
|
||||
mColorLabelDetails = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_LABEL_DETAILS ).getColor();
|
||||
mColorLabelDecoder = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_LABEL_DECODER ).getColor();
|
||||
mColorLabelAuxDecoder = getSettingsManager().getColorSetting(
|
||||
ColorSettingName.CHANNEL_STATE_LABEL_AUX_DECODER ).getColor();
|
||||
}
|
||||
|
||||
public HashMap<Channel,ChannelStatePanel> getTrafficPanels()
|
||||
{
|
||||
return mTrafficPanels;
|
||||
}
|
||||
|
||||
public JMenu getContextMenu()
|
||||
{
|
||||
return mChannel.getContextMenu();
|
||||
}
|
||||
|
||||
public Channel getChannel()
|
||||
{
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
public ChannelState getChannelState()
|
||||
{
|
||||
if( mChannel.getProcessingChain() != null )
|
||||
{
|
||||
return mChannel.getProcessingChain().getChannelState();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean getSelected()
|
||||
{
|
||||
return mChannel.getSelected();
|
||||
}
|
||||
|
||||
public void addPanel( final JPanel panel )
|
||||
{
|
||||
EventQueue.invokeLater( new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
add( panel, "span,wrap" );
|
||||
validate();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public void removePanel( final JPanel panel )
|
||||
{
|
||||
EventQueue.invokeLater( new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
remove( panel );
|
||||
|
||||
validate();
|
||||
|
||||
getParent().validate();
|
||||
|
||||
if( panel instanceof ChannelStatePanel )
|
||||
{
|
||||
((ChannelStatePanel)panel).dispose();
|
||||
}
|
||||
else if( panel instanceof AuxStatePanel )
|
||||
{
|
||||
((AuxStatePanel)panel).dispose();
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public void trafficChannelAdded( Channel traffic )
|
||||
{
|
||||
//Disregard -- sub class can override and implement
|
||||
}
|
||||
|
||||
public void trafficChannelDeleted( Channel traffic )
|
||||
{
|
||||
ChannelStatePanel panelToRemove =
|
||||
getTrafficPanels().remove( traffic );
|
||||
|
||||
removePanel( panelToRemove );
|
||||
}
|
||||
|
||||
public void setSelected( boolean selected )
|
||||
{
|
||||
mChannel.setSelected( selected );
|
||||
|
||||
for( ChannelStatePanel traffic: getTrafficPanels().values() )
|
||||
{
|
||||
traffic.setSelected( false );
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
private GradientPaint getGradient( Color top, Color middle )
|
||||
{
|
||||
return new GradientPaint( 0f, -50.0f, top,
|
||||
0f, (float)getHeight() / 2.2f, middle, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g)
|
||||
{
|
||||
super.paintComponent( g );
|
||||
|
||||
setBackground( mColorChannelBackground );
|
||||
|
||||
Graphics2D g2 = (Graphics2D)g.create();
|
||||
|
||||
Paint p = null;
|
||||
|
||||
ChannelState channelState = getChannelState();
|
||||
|
||||
if( channelState != null )
|
||||
{
|
||||
State state = channelState.getState();
|
||||
|
||||
if( state != null )
|
||||
{
|
||||
switch( state )
|
||||
{
|
||||
case CALL:
|
||||
p = getGradient( mColorTopCall, mColorMiddleCall );
|
||||
break;
|
||||
case CONTROL:
|
||||
p = getGradient( mColorTopControl, mColorMiddleControl );
|
||||
break;
|
||||
case DATA:
|
||||
p = getGradient( mColorTopData, mColorMiddleData );
|
||||
break;
|
||||
case FADE:
|
||||
p = getGradient( mColorTopFade, mColorMiddleFade );
|
||||
break;
|
||||
case NO_TUNER:
|
||||
p = getGradient( mColorTopNoTuner, mColorMiddleNoTuner );
|
||||
break;
|
||||
case END:
|
||||
case IDLE:
|
||||
default:
|
||||
p = getGradient( mColorTopIdle, mColorMiddleIdle );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g2.setPaint( p );
|
||||
g2.fillRect( 0, 0, getWidth(), getHeight() );
|
||||
|
||||
/* Draw bottom separator line */
|
||||
g2.setColor( Color.LIGHT_GRAY );
|
||||
g2.drawLine( 0, getHeight() - 1, getWidth(), getHeight() - 1 );
|
||||
|
||||
/* Draw channel selected box */
|
||||
if( mChannel.getSelected() )
|
||||
{
|
||||
g2.setColor( mColorChannelSelected );
|
||||
g2.drawRect( 1, 1, getWidth() - 2, getHeight() - 2 );
|
||||
}
|
||||
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settingChanged( Setting setting )
|
||||
{
|
||||
if( setting instanceof ColorSetting )
|
||||
{
|
||||
ColorSetting colorSetting = (ColorSetting)setting;
|
||||
|
||||
switch( colorSetting.getColorSettingName() )
|
||||
{
|
||||
case CHANNEL_STATE_BACKGROUND:
|
||||
mColorChannelBackground = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_MIDDLE_CALL:
|
||||
mColorMiddleCall = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_TOP_CALL:
|
||||
mColorTopCall = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_MIDDLE_CONTROL:
|
||||
mColorMiddleControl = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_TOP_CONTROL:
|
||||
mColorTopControl = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_MIDDLE_DATA:
|
||||
mColorMiddleData = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_TOP_DATA:
|
||||
mColorTopData = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_MIDDLE_FADE:
|
||||
mColorMiddleFade = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_TOP_FADE:
|
||||
mColorTopFade = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_MIDDLE_IDLE:
|
||||
mColorMiddleIdle = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_TOP_IDLE:
|
||||
mColorTopIdle = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_MIDDLE_NO_TUNER:
|
||||
mColorMiddleNoTuner = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_GRADIENT_TOP_NO_TUNER:
|
||||
mColorTopNoTuner = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_LABEL_AUX_DECODER:
|
||||
mColorLabelAuxDecoder = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_LABEL_DECODER:
|
||||
mColorLabelDecoder = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_LABEL_DETAILS:
|
||||
mColorLabelDetails = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
case CHANNEL_STATE_SELECTED_CHANNEL:
|
||||
mColorChannelSelected = colorSetting.getColor();
|
||||
repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settingDeleted( Setting setting ) {}
|
||||
}
|
||||
24
src/controller/state/ChannelStateSelectionListener.java
Normal file
24
src/controller/state/ChannelStateSelectionListener.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.state;
|
||||
|
||||
|
||||
public interface ChannelStateSelectionListener
|
||||
{
|
||||
public void selected( ChannelState channelState );
|
||||
}
|
||||
85
src/controller/system/System.java
Normal file
85
src/controller/system/System.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.system;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
import controller.site.Site;
|
||||
|
||||
@XmlSeeAlso( { Site.class } )
|
||||
@XmlRootElement( name = "system" )
|
||||
public class System
|
||||
{
|
||||
private String mName;
|
||||
private ArrayList<Site> mSite = new ArrayList<Site>();
|
||||
|
||||
public System()
|
||||
{
|
||||
this( "New System" );
|
||||
}
|
||||
|
||||
public System( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
public void setName( String name )
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public ArrayList<Site> getSite()
|
||||
{
|
||||
return mSite;
|
||||
}
|
||||
|
||||
public void setSite( ArrayList<Site> sites )
|
||||
{
|
||||
mSite = sites;
|
||||
}
|
||||
|
||||
public void addSite( Site site )
|
||||
{
|
||||
mSite.add( site );
|
||||
}
|
||||
|
||||
public void removeSite( Site site )
|
||||
{
|
||||
mSite.remove( site );
|
||||
}
|
||||
|
||||
public void clearSites()
|
||||
{
|
||||
mSite.clear();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
}
|
||||
101
src/controller/system/SystemEditor.java
Normal file
101
src/controller/system/SystemEditor.java
Normal file
@@ -0,0 +1,101 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.system;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
|
||||
public class SystemEditor extends JPanel implements ActionListener
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private SystemNode mSystemNode;
|
||||
|
||||
private JLabel mLabelSystem;
|
||||
private JTextField mTextSystem;
|
||||
|
||||
public SystemEditor( SystemNode system )
|
||||
{
|
||||
mSystemNode = system;
|
||||
initGUI();
|
||||
}
|
||||
|
||||
private void initGUI()
|
||||
{
|
||||
setLayout( new MigLayout() );
|
||||
|
||||
setBorder( BorderFactory.createTitledBorder( "System" ) );
|
||||
|
||||
mLabelSystem = new JLabel( "Name:" );
|
||||
add( mLabelSystem, "align right" );
|
||||
|
||||
mTextSystem = new JTextField( mSystemNode.getSystem().getName() );
|
||||
add( mTextSystem, "grow, wrap" );
|
||||
|
||||
JButton btnSave = new JButton( "Save" );
|
||||
btnSave.addActionListener( SystemEditor.this );
|
||||
add( btnSave );
|
||||
|
||||
JButton btnReset = new JButton( "Reset" );
|
||||
btnReset.addActionListener( SystemEditor.this );
|
||||
add( btnReset, "wrap" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
String command = e.getActionCommand();
|
||||
|
||||
if( command.contentEquals( "Save" ) )
|
||||
{
|
||||
boolean expanded = mSystemNode.getModel().getTree()
|
||||
.isExpanded( new TreePath( mSystemNode ) );
|
||||
|
||||
String name = mTextSystem.getText();
|
||||
|
||||
if( name != null )
|
||||
{
|
||||
mSystemNode.getSystem().setName( name );
|
||||
mSystemNode.save();
|
||||
mSystemNode.show();
|
||||
|
||||
if( expanded )
|
||||
{
|
||||
mSystemNode.getModel().getTree().expandPath( new TreePath( mSystemNode ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JOptionPane.showMessageDialog( SystemEditor.this, "Please enter a system name" );
|
||||
}
|
||||
}
|
||||
else if( command.contentEquals( "Reset" ) )
|
||||
{
|
||||
mTextSystem.setText( mSystemNode.getSystem().getName() );
|
||||
}
|
||||
}
|
||||
}
|
||||
60
src/controller/system/SystemList.java
Normal file
60
src/controller/system/SystemList.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.system;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
@XmlSeeAlso( { controller.system.System.class } )
|
||||
|
||||
@XmlRootElement( name = "system_list" )
|
||||
public class SystemList
|
||||
{
|
||||
private ArrayList<System> mSystem = new ArrayList<System>();
|
||||
|
||||
public SystemList()
|
||||
{
|
||||
}
|
||||
|
||||
public ArrayList<System> getSystem()
|
||||
{
|
||||
return mSystem;
|
||||
}
|
||||
|
||||
public void setSystem( ArrayList<System> systems )
|
||||
{
|
||||
mSystem = systems;
|
||||
}
|
||||
|
||||
public void addSystem( System system )
|
||||
{
|
||||
mSystem.add( system );
|
||||
}
|
||||
|
||||
public void removeSystem( System system )
|
||||
{
|
||||
mSystem.remove( system );
|
||||
}
|
||||
|
||||
public void clearSystems()
|
||||
{
|
||||
mSystem.clear();
|
||||
}
|
||||
}
|
||||
85
src/controller/system/SystemListNode.java
Normal file
85
src/controller/system/SystemListNode.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.system;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import controller.ConfigurableNode;
|
||||
|
||||
public class SystemListNode extends ConfigurableNode
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SystemListNode( SystemList list )
|
||||
{
|
||||
super( list );
|
||||
}
|
||||
|
||||
public SystemList getSystemList()
|
||||
{
|
||||
return (SystemList)getUserObject();
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
for( System system: getSystemList().getSystem() )
|
||||
{
|
||||
SystemNode node = new SystemNode( system );
|
||||
|
||||
getModel().addNode( node, SystemListNode.this, getChildCount() );
|
||||
|
||||
node.init();
|
||||
}
|
||||
|
||||
sort();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "Systems [" + this.getChildCount() + "]";
|
||||
}
|
||||
|
||||
public JPopupMenu getContextMenu()
|
||||
{
|
||||
JPopupMenu retVal = new JPopupMenu();
|
||||
|
||||
JMenuItem addSystemItem = new JMenuItem( "Add System" );
|
||||
addSystemItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
System system = new System();
|
||||
|
||||
getSystemList().addSystem( system );
|
||||
|
||||
getModel().addNode( new SystemNode( system ),
|
||||
SystemListNode.this,
|
||||
SystemListNode.this.getChildCount() );
|
||||
}
|
||||
} );
|
||||
|
||||
retVal.add( addSystemItem );
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
165
src/controller/system/SystemNode.java
Normal file
165
src/controller/system/SystemNode.java
Normal file
@@ -0,0 +1,165 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014 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.system;
|
||||
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.Enumeration;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
import controller.ConfigurableNode;
|
||||
import controller.site.Site;
|
||||
import controller.site.SiteNode;
|
||||
|
||||
public class SystemNode extends ConfigurableNode
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SystemNode( System system )
|
||||
{
|
||||
super( system );
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
for( Site site: getSystem().getSite() )
|
||||
{
|
||||
SiteNode node = new SiteNode( site );
|
||||
|
||||
getModel().insertNodeInto( node, SystemNode.this, getChildCount() );
|
||||
|
||||
node.init();
|
||||
}
|
||||
|
||||
sort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIconPath()
|
||||
{
|
||||
String retVal = "images/system.png";
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
Enumeration<DefaultMutableTreeNode> nodes = children();
|
||||
|
||||
while( nodes.hasMoreElements() )
|
||||
{
|
||||
SiteNode child = (SiteNode)nodes.nextElement();
|
||||
|
||||
if( child.getIconPath().contains( "green.png" ) )
|
||||
{
|
||||
return "images/system_green.png";
|
||||
}
|
||||
else if( child.getIconPath().contains( "red.png" ) )
|
||||
{
|
||||
retVal = "images/system_red.png";
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getEditor()
|
||||
{
|
||||
return new SystemEditor( this );
|
||||
}
|
||||
|
||||
public System getSystem()
|
||||
{
|
||||
return (System)getUserObject();
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return getSystem().getName();
|
||||
}
|
||||
|
||||
public void delete()
|
||||
{
|
||||
for( int x = 0; x < getChildCount(); x++ )
|
||||
{
|
||||
((SiteNode)getChildAt( x )).delete();
|
||||
}
|
||||
|
||||
SystemListNode parent = (SystemListNode)getParent();
|
||||
|
||||
parent.getSystemList().removeSystem( getSystem() );
|
||||
|
||||
save();
|
||||
|
||||
getModel().removeNodeFromParent( SystemNode.this );
|
||||
|
||||
/* Show the first child, if one exists so that we don't have a
|
||||
* collapsed list */
|
||||
if( parent.getChildCount() > 0 )
|
||||
{
|
||||
((ConfigurableNode)parent.getFirstChild()).show();
|
||||
}
|
||||
}
|
||||
|
||||
public JPopupMenu getContextMenu()
|
||||
{
|
||||
JPopupMenu retVal = new JPopupMenu();
|
||||
|
||||
JMenuItem addSiteItem = new JMenuItem( "Add Site" );
|
||||
addSiteItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
Site site = new Site();
|
||||
getSystem().addSite( site );
|
||||
|
||||
SiteNode node = new SiteNode( site );
|
||||
|
||||
getModel().addNode( node,
|
||||
SystemNode.this,
|
||||
SystemNode.this.getChildCount() );
|
||||
|
||||
sort();
|
||||
|
||||
node.show();
|
||||
}
|
||||
} );
|
||||
|
||||
retVal.add( addSiteItem );
|
||||
|
||||
retVal.add( new JSeparator() );
|
||||
|
||||
JMenuItem deleteItem = new JMenuItem( "Delete" );
|
||||
deleteItem.addActionListener( new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed( ActionEvent e )
|
||||
{
|
||||
delete();
|
||||
}
|
||||
} );
|
||||
|
||||
retVal.add( deleteItem );
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user