Merges #34 Major redesign of Tuner, Channel and Alias management.

Changes to model, view and controller components and updates all gui
editors.  Removes the configuration panel and tree and replaces with 3
new panels.  Updates playlist.xml to a new playlist_v2.xml format.
This commit is contained in:
denny
2016-04-01 08:23:49 -04:00
450 changed files with 19560 additions and 22805 deletions

View File

@@ -1,196 +0,0 @@
/*******************************************************************************
* 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.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
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 Color getBackgroundColor()
{
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 )
{
TreeNode parent = getParent();
if( parent != null )
{
return ((BaseNode)parent).getModel();
}
else
{
return null;
}
}
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()
{
if( getModel() != null )
{
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() );
}
}
}
}

View File

@@ -1,44 +0,0 @@
/*******************************************************************************
* 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();
}
}
}

View File

@@ -1,285 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014,2015 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 module.decode.DecoderType;
import module.decode.config.DecodeConfigFactory;
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.ChannelEvent;
import controller.channel.ChannelEvent.Event;
import controller.channel.ChannelNode;
import controller.site.Site;
import controller.system.System;
import controller.system.SystemListNode;
import controller.system.SystemNode;
public class ConfigurationControllerModel extends DefaultTreeModel
{
private static final long serialVersionUID = 1L;
private JTree mTree;
private ResourceManager mResourceManager;
private ArrayList<TunerSelectionListener> mTunerSelectionListeners =
new ArrayList<TunerSelectionListener>();
private PlaylistNode mPlaylistNode;
private TunerGroupNode mTunerGroupNode;
// private RecordingGroupNode mRecordingGroupNode;
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 tuner group node
*/
mTunerGroupNode = new TunerGroupNode();
insertNodeInto( mTunerGroupNode, (MutableTreeNode)root, 0 );
addTuners( mTunerGroupNode );
/**
* Add the recording group node
*/
// mRecordingGroupNode = new RecordingGroupNode();
// insertNodeInto( mRecordingGroupNode, (MutableTreeNode)root, 1 );
// mRecordingGroupNode.loadRecordings();
/**
* 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( long 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 );
mResourceManager.getChannelManager().channelChanged( new ChannelEvent( channel, Event.CHANNEL_ADDED ) );
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;
}
}

View File

@@ -1,74 +0,0 @@
/*******************************************************************************
* 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.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() );
}
}
}

View File

@@ -1,117 +0,0 @@
/*******************************************************************************
* 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 MouseHandler() );
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 MouseHandler implements MouseListener
{
public MouseHandler()
{
}
@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 ){}
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,63 +33,75 @@ import module.decode.event.CallEventPanel;
import module.decode.event.MessageActivityPanel;
import module.decode.state.ChannelList;
import net.miginfocom.swing.MigLayout;
import playlist.PlaylistManager;
import settings.SettingsManager;
import source.SourceManager;
import source.tuner.TunerModel;
import source.tuner.TunerViewPanel;
import spectrum.ChannelSpectrumPanel;
import alias.AliasController;
import alias.AliasModel;
import audio.AudioManager;
import audio.AudioPanel;
import com.jidesoft.swing.JideSplitPane;
import com.jidesoft.swing.JideTabbedPane;
import controller.channel.ChannelManager;
import controller.channel.ChannelController;
import controller.channel.ChannelModel;
import controller.channel.ChannelProcessingManager;
import controller.channel.map.ChannelMapModel;
public class ControllerPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private ChannelList mChannelStateList;
private CallEventPanel mCallEventPanel;
private MessageActivityPanel mMessageActivityPanel =
new MessageActivityPanel();
private ChannelSpectrumPanel mChannelSpectrumPanel;
private JideTabbedPane mTabbedPane;
protected ConfigurationTreePanel mSystemControlViewPanel;
protected ConfigurationEditor mConfigurationEditor;
protected JideSplitPane mSystemControlSplitPane;
protected JTable mChannelActivityTable = new JTable();
private AliasController mAliasController;
private AudioPanel mAudioPanel;
private CallEventPanel mCallEventPanel;
private ChannelController mChannelController;
private ChannelList mChannelStateList;
private ChannelModel mChannelModel;
private ChannelSpectrumPanel mChannelSpectrumPanel;
private MapPanel mMapPanel;
private MessageActivityPanel mMessageActivityPanel;
private TunerViewPanel mTunerManagerPanel;
private ChannelManager mChannelManager;
private ConfigurationControllerModel mController;
protected SettingsManager mSettingsManager;
private JideTabbedPane mTabbedPane;
protected JTable mChannelActivityTable = new JTable();
public ControllerPanel( AudioManager audioManager,
ConfigurationControllerModel controller,
ChannelManager channelManager,
AliasModel aliasModel,
ChannelModel channelModel,
ChannelMapModel channelMapModel,
ChannelProcessingManager channelProcessingManager,
MapService mapService,
PlaylistManager playlistManager,
SettingsManager settingsManager )
SettingsManager settingsManager,
SourceManager sourceManager,
TunerModel tunerModel )
{
mChannelManager = channelManager;
mController = controller;
mSettingsManager = settingsManager;
mChannelModel = channelModel;
mAudioPanel = new AudioPanel( mSettingsManager, audioManager );
mAudioPanel = new AudioPanel( settingsManager, sourceManager, audioManager );
mMapPanel = new MapPanel( mapService, mSettingsManager, mChannelManager );
mMapPanel = new MapPanel( mapService, settingsManager );
mCallEventPanel = new CallEventPanel( mSettingsManager );
mChannelStateList = new ChannelList( playlistManager, mSettingsManager );
mMessageActivityPanel = new MessageActivityPanel( channelProcessingManager );
mCallEventPanel = new CallEventPanel( settingsManager, channelProcessingManager );
mChannelSpectrumPanel = new ChannelSpectrumPanel( settingsManager,
channelProcessingManager );
mChannelStateList = new ChannelList( channelModel, channelProcessingManager,
settingsManager, mAudioPanel );
mChannelController = new ChannelController( channelModel, channelMapModel,
sourceManager, aliasModel );
mAliasController = new AliasController( aliasModel, settingsManager );
mTunerManagerPanel = new TunerViewPanel( tunerModel );
init();
}
@@ -99,27 +111,17 @@ public class ControllerPanel extends JPanel
"[grow,fill]",
"[grow,fill]") );
//System Configuration View and Editor
mConfigurationEditor = new ConfigurationEditor();
mSystemControlViewPanel = new ConfigurationTreePanel( mController );
mSystemControlViewPanel.addTreeSelectionListener( mConfigurationEditor );
mSystemControlSplitPane = new JideSplitPane( JideSplitPane.HORIZONTAL_SPLIT );
mSystemControlSplitPane.setDividerSize( 5 );
mSystemControlSplitPane.add( mSystemControlViewPanel );
mSystemControlSplitPane.add( mConfigurationEditor );
mChannelSpectrumPanel = new ChannelSpectrumPanel( mSettingsManager );
//Tabbed View - configuration, calls, messages, map
mTabbedPane = new JideTabbedPane();
mTabbedPane.setFont( this.getFont() );
mTabbedPane.setForeground( Color.BLACK );
mTabbedPane.addTab( "Configuration", mSystemControlSplitPane );
mTabbedPane.addTab( "Tuners", mTunerManagerPanel );
mTabbedPane.addTab( "Channels", mChannelController );
mTabbedPane.addTab( "Aliases", mAliasController );
mTabbedPane.addTab( "Channel Spectrum", mChannelSpectrumPanel );
mTabbedPane.addTab( "Events", mCallEventPanel );
mTabbedPane.addTab( "Messages", mMessageActivityPanel );
mTabbedPane.addTab( "Map", mMapPanel );
/**
* Change listener to enable/disable the channel spectrum display
@@ -145,38 +147,31 @@ public class ControllerPanel extends JPanel
}
} );
/**
* Add mapping services and map panel to a new tab
*/
mTabbedPane.addTab( "Map", mMapPanel );
/* Register each of the components to receive channel events when the
* channels are selected or change */
mChannelManager.addListener( mCallEventPanel );
mChannelManager.addListener( mChannelStateList );
mChannelManager.addListener( mChannelSpectrumPanel );
mChannelManager.addListener( mMessageActivityPanel );
mChannelModel.addListener( mCallEventPanel );
mChannelModel.addListener( mChannelStateList );
mChannelModel.addListener( mChannelSpectrumPanel );
mChannelModel.addListener( mMessageActivityPanel );
JScrollPane channelStateListScroll = new JScrollPane();
channelStateListScroll.getViewport().setView( mChannelStateList );
channelStateListScroll.setPreferredSize( new Dimension( 200, 300 ) );
channelStateListScroll.setPreferredSize( new Dimension( 400, 500 ) );
// JideSplitPane audioChannelListSplit = new JideSplitPane( JideSplitPane.VERTICAL_SPLIT );
// audioChannelListSplit.setDividerSize( 5 );
// audioChannelListSplit.add( mAudioPanel );
// audioChannelListSplit.add( channelStateListScroll );
JideSplitPane audioChannelListSplit = new JideSplitPane( JideSplitPane.VERTICAL_SPLIT );
audioChannelListSplit.setDividerSize( 5 );
audioChannelListSplit.add( mAudioPanel );
audioChannelListSplit.add( channelStateListScroll );
//Set preferred size to influence the split between these panels
// audioChannelListSplit.setPreferredSize( new Dimension( 400, 500 ) );
mTabbedPane.setPreferredSize( new Dimension( 880, 500 ) );
JideSplitPane channelSplit = new JideSplitPane( JideSplitPane.HORIZONTAL_SPLIT );
channelSplit.setDividerSize( 5 );
channelSplit.add( audioChannelListSplit );
channelSplit.add( channelStateListScroll );
channelSplit.add( mTabbedPane );
add( channelSplit );
}
public ConfigurationControllerModel getController()
{
return mController;
}
}

View File

@@ -1,127 +0,0 @@
/*******************************************************************************
* 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.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 )
{
BaseNode node = (BaseNode)value;
ImageIcon icon = getIcon( node );
setIcon( icon );
Color background = node.getBackgroundColor();
if( background != null )
{
setBackground( background );
setOpaque( true );
if( selected )
{
if( background == Color.CYAN )
{
setForeground( Color.ORANGE );
}
else if( background == Color.GREEN )
{
setForeground( Color.MAGENTA );
}
else if( background == Color.RED )
{
setForeground( Color.YELLOW );
}
}
}
else
{
setOpaque( false );
}
}
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;
}
}

View File

@@ -1,51 +0,0 @@
/*******************************************************************************
* 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;
import controller.channel.ChannelValidationException;
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();
/**
* Override this method to allow the editor to inspect the argument for
* valid configuration
*
* @param editor - any editor
*
* @throws ChannelValidationException if the configuration is not compatible
* with this editor's configuration. Supplies a validation text value for
* display to the user
*/
public void validate( Editor editor ) throws ChannelValidationException
{
}
}

View File

@@ -1,59 +0,0 @@
/*******************************************************************************
* 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 );
}
}

View File

@@ -1,183 +0,0 @@
/*******************************************************************************
* 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 module.log.EventLogManager;
import playlist.PlaylistManager;
import record.RecorderManager;
import settings.SettingsManager;
import source.SourceManager;
import source.recording.RecordingSourceManager;
import source.tuner.TunerManager;
import audio.AudioManager;
import controller.channel.ChannelManager;
/**
* Manager for system wide resources
*/
public class ResourceManager
{
private AudioManager mAudioManager;
private ChannelManager mChannelManager;
private EventLogManager mEventLogManager;
private PlaylistManager mPlaylistManager;
private RecorderManager mRecorderManager;
private RecordingSourceManager mRecordingSourceManager;
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() );
}
public ResourceManager( SettingsManager settingsManager,
PlaylistManager playlistManager,
EventLogManager eventLogManager )
{
mSettingsManager = settingsManager;
mPlaylistManager = playlistManager;
mEventLogManager = eventLogManager;
/**
* ChannelManager requires a reference to the ResourceManager so that
* channel processing chains can access system wide resources
*/
mThreadPoolManager = new ThreadPoolManager();
mAudioManager = new AudioManager( mThreadPoolManager );
mRecorderManager = new RecorderManager( mThreadPoolManager );
mChannelManager = new ChannelManager( this );
mSourceManager = new SourceManager( this );
mRecordingSourceManager = new RecordingSourceManager( this );
mTunerManager = new TunerManager( this );
mController = new ConfigurationControllerModel( this );
mMapService = new MapService( this );
}
public AudioManager getAudioManager()
{
return mAudioManager;
}
public void setAudioManager( AudioManager audioManager )
{
mAudioManager = audioManager;
}
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 RecordingSourceManager getRecordingSourceManager()
{
return mRecordingSourceManager;
}
public void setRecordingSourceManager( RecordingSourceManager manager )
{
mRecordingSourceManager = manager;
}
public ChannelManager getChannelManager()
{
return mChannelManager;
}
public void setChannelManager( ChannelManager channelManager )
{
mChannelManager = channelManager;
}
}

View File

@@ -36,20 +36,29 @@ public class ThreadPoolManager
private HashMap<ScheduledFuture<?>,ThreadType> mTasks =
new HashMap<ScheduledFuture<?>,ThreadType>();
private ScheduledExecutorService mExecutor =
Executors.newScheduledThreadPool( THREAD_POOL_SIZE,
new NamingThreadFactory( "sdrtrunk" ) );
private ScheduledExecutorService mExecutor;
public ThreadPoolManager()
{
}
public ScheduledExecutorService getScheduledExecutorService()
{
return mExecutor;
}
public ScheduledFuture<?> scheduleFixedRate( ThreadType type,
Runnable command,
long period,
TimeUnit unit )
throws RejectedExecutionException
{
if( mExecutor == null )
{
mExecutor = Executors.newScheduledThreadPool( THREAD_POOL_SIZE,
new NamingThreadFactory( "sdrtrunk" ) );
}
ScheduledFuture<?> task =
mExecutor.scheduleAtFixedRate( command, 0, period, unit );
@@ -61,6 +70,12 @@ public class ThreadPoolManager
public void scheduleOnce( Runnable command, long delay, TimeUnit unit )
throws RejectedExecutionException
{
if( mExecutor == null )
{
mExecutor = Executors.newScheduledThreadPool( THREAD_POOL_SIZE,
new NamingThreadFactory( "sdrtrunk" ) );
}
mExecutor.schedule( command, delay, unit );
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,279 @@
package controller.channel;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import net.coderazzi.filters.gui.AutoChoices;
import net.coderazzi.filters.gui.TableFilterHeader;
import net.miginfocom.swing.MigLayout;
import source.SourceManager;
import alias.AliasModel;
import com.jidesoft.swing.JideSplitPane;
import controller.channel.map.ChannelMapModel;
public class ChannelController extends JPanel
implements ActionListener, ListSelectionListener
{
private static final long serialVersionUID = 1L;
private ChannelModel mChannelModel;
private JTable mChannelTable;
private TableFilterHeader mTableFilterHeader;
private ChannelEditor mEditor;
private static final String NEW_CHANNEL = "New";
private static final String COPY_CHANNEL = "Copy";
private static final String DELETE_CHANNEL = "Delete";
private JButton mNewChannelButton = new JButton( NEW_CHANNEL );
private JButton mCopyChannelButton = new JButton( COPY_CHANNEL );
private JButton mDeleteChannelButton = new JButton( DELETE_CHANNEL );
public ChannelController( ChannelModel channelModel,
ChannelMapModel channelMapModel,
SourceManager sourceManager,
AliasModel aliasModel )
{
mChannelModel = channelModel;
mEditor = new ChannelEditor( channelModel, channelMapModel, sourceManager, aliasModel );
mChannelModel.addListener( mEditor );
init();
}
private void init()
{
setLayout( new MigLayout( "", "[grow,fill]", "[grow,fill]") );
//System Configuration View and Editor
mChannelTable = new JTable( mChannelModel );
mChannelTable.setDefaultRenderer( String.class, new ChannelTableCellRenderer() );
mChannelTable.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
mChannelTable.getSelectionModel().addListSelectionListener( this );
mChannelTable.setAutoCreateRowSorter( true );
mTableFilterHeader = new TableFilterHeader( mChannelTable, AutoChoices.ENABLED );
mTableFilterHeader.setFilterOnUpdates( true );
JScrollPane channelScroller = new JScrollPane( mChannelTable );
JPanel buttonsPanel = new JPanel();
buttonsPanel.setLayout(
new MigLayout( "insets 0 0 0 0", "[grow,fill][grow,fill][grow,fill]", "[]") );
mNewChannelButton.addActionListener( this );
mNewChannelButton.setToolTipText( "Create a new channel configuration" );
buttonsPanel.add( mNewChannelButton );
mCopyChannelButton.addActionListener( this );
mCopyChannelButton.setEnabled( false );
mCopyChannelButton.setToolTipText( "Create a copy of the currently selected channel configuration" );
buttonsPanel.add( mCopyChannelButton );
mDeleteChannelButton.addActionListener( this );
mDeleteChannelButton.setEnabled( false );
mDeleteChannelButton.setToolTipText( "Delete the currently selected channel configuration" );
buttonsPanel.add( mDeleteChannelButton );
JPanel listAndButtonsPanel = new JPanel();
listAndButtonsPanel.setLayout(
new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[grow,fill][]") );
listAndButtonsPanel.add( channelScroller, "wrap" );
listAndButtonsPanel.add( buttonsPanel );
JideSplitPane splitPane = new JideSplitPane( JideSplitPane.VERTICAL_SPLIT );
splitPane.setDividerSize( 5 );
splitPane.setShowGripper( true );
//Shrink this guy so that he'll eventually be expanded to the scroller preferred size
listAndButtonsPanel.setPreferredSize( new Dimension( 10, 10 ) );
//Attempt to get a 60:40 vertical sizing preference
JScrollPane listScroller = new JScrollPane( listAndButtonsPanel );
listScroller.setPreferredSize( new Dimension( 800, 58 ) );
JScrollPane editorScroller = new JScrollPane( mEditor );
editorScroller.setPreferredSize( new Dimension( 800, 42 ) );
splitPane.add( listScroller );
splitPane.add( editorScroller );
add( splitPane );
}
@Override
public void valueChanged( ListSelectionEvent event )
{
//This limits event firing to only when selection is complete
if( !event.getValueIsAdjusting() )
{
int selectedRow = mChannelTable.getSelectedRow();
if( selectedRow != -1 )
{
int index = mChannelTable.convertRowIndexToModel( mChannelTable.getSelectedRow() );
Channel channel = mChannelModel.getChannelAtIndex( index );
if( channel != null )
{
mEditor.setItem( channel );
mCopyChannelButton.setEnabled( true );
mDeleteChannelButton.setEnabled( true );
}
}
else
{
mEditor.setItem( null );
mCopyChannelButton.setEnabled( false );
mDeleteChannelButton.setEnabled( false );
}
}
}
/**
* Adds the channel to the channel model/table and scrolls to view it
*/
private void addChannel( Channel channel )
{
//HACK: when inserting a row to the model, the JTable gets
//notified and attempts to tell the coderazzi table filter
//adaptive choices filter to refresh before the table filter is
//notified of the row additions, causing an index out of bounds
//exception. We turn off adaptive choices temporarily, add the
//channel, and turn on adaptive choices again.
mTableFilterHeader.setAdaptiveChoices( false );
int index = mChannelModel.addChannel( channel );
mTableFilterHeader.setAdaptiveChoices( true );
if( index >= 0 )
{
int translatedIndex = mChannelTable.convertRowIndexToView( index );
mChannelTable.setRowSelectionInterval( translatedIndex, translatedIndex );
mChannelTable.scrollRectToVisible(
new Rectangle( mChannelTable.getCellRect( translatedIndex, 0, true ) ) );
}
}
private Channel getSelectedChannel()
{
int index = mChannelTable.getSelectedRow();
if( index >= 0 )
{
return mChannelModel.getChannelAtIndex(
mChannelTable.convertRowIndexToModel( index ) );
}
return null;
}
/**
* Responds to New, Copy and Delete Channel button invocations
*/
@Override
public void actionPerformed( ActionEvent event )
{
switch( event.getActionCommand() )
{
case NEW_CHANNEL:
addChannel( new Channel( "New Channel" ) );
break;
case COPY_CHANNEL:
Channel selected = getSelectedChannel();
if( selected != null )
{
addChannel( selected.copyOf() );
}
break;
case DELETE_CHANNEL:
Channel toDelete = getSelectedChannel();
if( toDelete != null )
{
int choice = JOptionPane.showConfirmDialog( ChannelController.this,
"Do you want to delete this channel?", "Delete Channel?",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE );
if( choice == JOptionPane.YES_OPTION )
{
mChannelModel.removeChannel( toDelete );
}
}
break;
default:
break;
}
}
public class ChannelTableCellRenderer extends DefaultTableCellRenderer
{
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellRendererComponent( JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column )
{
Component component = super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, column );
ChannelModel model = (ChannelModel)table.getModel();
int index = table.convertRowIndexToModel( row );
Channel channel = model.getChannelAtIndex( index );
boolean enabled = channel.getEnabled();
if( isSelected )
{
if( enabled )
{
component.setBackground( Color.YELLOW );
}
else
{
component.setBackground( table.getSelectionBackground() );
}
}
else
{
if( enabled )
{
component.setBackground( Color.GREEN );
}
else
{
component.setBackground( table.getBackground() );
}
}
return component;
}
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,147 +17,145 @@
******************************************************************************/
package controller.channel;
import gui.editor.Editor;
import gui.editor.EditorValidationException;
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.JOptionPane;
import javax.swing.JTextField;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import module.decode.AuxDecodeComponentEditor;
import module.decode.DecodeComponentEditor;
import module.log.EventLogComponentEditor;
import module.decode.AuxDecodeConfigurationEditor;
import module.decode.DecodeConfigurationEditor;
import module.log.EventLogConfigurationEditor;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import playlist.PlaylistManager;
import record.RecordComponentEditor;
import source.SourceComponentEditor;
import alias.AliasList;
import record.RecordConfigurationEditor;
import source.SourceConfigurationEditor;
import source.SourceManager;
import alias.AliasModel;
import com.jidesoft.swing.JideTabbedPane;
import controller.Editor;
import controller.channel.ChannelEvent.Event;
import controller.channel.map.ChannelMapModel;
public class ChannelEditor extends Editor implements ActionListener
public class ChannelEditor extends Editor<Channel> implements ActionListener, ChannelEventListener
{
private final static Logger mLog = LoggerFactory.getLogger( ChannelEditor.class );
private static final long serialVersionUID = 1L;
private DefaultTreeModel mTreeModel;
private ChannelNode mChannelNode;
private NameConfigurationEditor mNameConfigurationEditor;
private SourceConfigurationEditor mSourceConfigurationEditor;
private DecodeConfigurationEditor mDecodeConfigurationEditor;
private AuxDecodeConfigurationEditor mAuxDecodeConfigurationEditor;
private EventLogConfigurationEditor mEventLogConfigurationEditor;
private RecordConfigurationEditor mRecordConfigurationEditor;
private DecodeComponentEditor mDecodeEditor;
private AuxDecodeComponentEditor mAuxDecodeEditor;
private EventLogComponentEditor mEventLogEditor;
private RecordComponentEditor mRecordEditor;
private SourceComponentEditor mSourceEditor;
private JButton mEnableButton = new JButton( "Enable" );
private JLabel mChannelName = new JLabel( "Channel:" );
private JTextField mChannelName;
private JCheckBox mChannelEnabled = new JCheckBox();
private JComboBox<AliasList> mComboAliasLists;
private ChannelModel mChannelModel;
private ChannelMapModel mChannelMapModel;
private SourceManager mSourceManager;
private PlaylistManager mPlaylistManager;
private boolean mChannelEnableRequested = false;
public ChannelEditor( ChannelNode channel, PlaylistManager playlistManager )
public ChannelEditor( ChannelModel channelModel,
ChannelMapModel channelMapModel,
SourceManager sourceManager,
AliasModel aliasModel )
{
super();
mChannelModel = channelModel;
mChannelMapModel = channelMapModel;
mSourceManager = sourceManager;
mNameConfigurationEditor = new NameConfigurationEditor( aliasModel, mChannelModel );
mChannelNode = channel;
mPlaylistManager = playlistManager;
initGUI();
init();
}
private void initGUI()
private void init()
{
setLayout( new MigLayout( "fill,wrap 2", "[right,grow][grow]", "[][][][][grow][]" ) );
setLayout( new MigLayout( "fill,wrap 3", "[grow,fill][grow,fill][grow,fill]", "[grow,fill][]" ) );
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( "Alias List:" ) );
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 );
tabs.setTabTrailingComponent( mChannelName );
mNameConfigurationEditor.setSaveRequestListener( this );
tabs.addTab( "Name/Alias", mNameConfigurationEditor );
mSourceConfigurationEditor = new SourceConfigurationEditor( mSourceManager );
mSourceConfigurationEditor.setSaveRequestListener( this );
tabs.addTab( "Source", mSourceConfigurationEditor );
mDecodeEditor = new DecodeComponentEditor( mChannelNode, mPlaylistManager );
tabs.addTab( "Decoder", mDecodeEditor );
mDecodeConfigurationEditor = new DecodeConfigurationEditor( mChannelMapModel );
mDecodeConfigurationEditor.setSaveRequestListener( this );
tabs.addTab( "Decoder", mDecodeConfigurationEditor );
mAuxDecodeEditor = new AuxDecodeComponentEditor( mChannelNode );
tabs.addTab( "Aux", mAuxDecodeEditor );
mAuxDecodeConfigurationEditor = new AuxDecodeConfigurationEditor();
mAuxDecodeConfigurationEditor.setSaveRequestListener( this );
tabs.addTab( "Aux Decoders", mAuxDecodeConfigurationEditor );
mEventLogEditor = new EventLogComponentEditor( mChannelNode );
tabs.addTab( "Event Log", mEventLogEditor );
mEventLogConfigurationEditor = new EventLogConfigurationEditor();
mEventLogConfigurationEditor.setSaveRequestListener( this );
tabs.addTab( "Logging", mEventLogConfigurationEditor );
mRecordEditor = new RecordComponentEditor( mChannelNode );
tabs.addTab( "Record", mRecordEditor );
mRecordConfigurationEditor = new RecordConfigurationEditor();
mRecordConfigurationEditor.setSaveRequestListener( this );
tabs.addTab( "Recording", mRecordConfigurationEditor );
add( tabs, "span" );
mEnableButton.addActionListener( this );
mEnableButton.setEnabled( false );
mEnableButton.setToolTipText( "Start the currently selected channel running/decoding" );
add( mEnableButton );
add( tabs, "span,grow,push" );
JButton btnSave = new JButton( "Save" );
btnSave.setToolTipText( "Save changes to the currently selected channel" );
btnSave.addActionListener( ChannelEditor.this );
add( btnSave, "growx,push" );
add( btnSave );
JButton btnReset = new JButton( "Reset" );
btnReset.setToolTipText( "Reload the currently selected channel" );
btnReset.addActionListener( ChannelEditor.this );
add( btnReset, "growx,push" );
add( btnReset );
}
@Override
public void channelChanged( ChannelEvent event )
{
if( hasItem() && getItem() == event.getChannel() )
{
switch( event.getEvent() )
{
case NOTIFICATION_CONFIGURATION_CHANGE:
case NOTIFICATION_PROCESSING_START:
case NOTIFICATION_PROCESSING_STOP:
setItem( getItem() );
mChannelEnableRequested = false;
break;
case NOTIFICATION_DELETE:
setItem( null );
break;
case NOTIFICATION_ENABLE_REJECTED:
if( mChannelEnableRequested )
{
JOptionPane.showMessageDialog( ChannelEditor.this, "Channel could not be "
+ "enabled. This is likely because there are no tuner channels "
+ "available", "Couldn't enable channel", JOptionPane.INFORMATION_MESSAGE );
mChannelEnableRequested = false;
}
break;
default:
break;
}
}
}
@Override
@@ -165,115 +163,95 @@ public class ChannelEditor extends Editor implements ActionListener
{
String command = e.getActionCommand();
if( command.contentEquals( "Save" ) )
if( command.contentEquals( "Enable" ) )
{
if( hasItem() )
{
save();
mChannelEnableRequested = true;
mChannelModel.broadcast( new ChannelEvent( getItem(), Event.REQUEST_ENABLE ) );
}
}
else if( command.contentEquals( "Disable" ) )
{
if( hasItem() )
{
mChannelModel.broadcast( new ChannelEvent( getItem(), Event.REQUEST_DISABLE ) );
}
}
else if( command.contentEquals( "Save" ) )
{
save();
}
else if( command.contentEquals( "Reset" ) )
{
reset();
setItem( getItem() );
}
if( mTreeModel != null )
{
mTreeModel.nodeChanged( mChannelNode );
}
}
@Override
public void save()
{
try
{
/**
* Validate the source configuration against the other component
* configuration editors
*/
validate( mSourceEditor.getSourceEditor() );
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 ) );
}
}
catch ( ChannelValidationException validationException )
{
/* ChannelValidationException can be thrown by any of the component
* editors. Show the validation error text in a popup menu to the
* user */
JOptionPane.showMessageDialog( ChannelEditor.this,
validationException.getMessage(),
"Channel Configuration Error",
JOptionPane.ERROR_MESSAGE );
}
}
@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();
}
/**
* Validate the specified editor against each of the component editors
* Sets the channel configuration in each of the channel editor components
* Note: this method must be invoked on the swing event dispatch thread
*/
@Override
public void validate( Editor editor ) throws ChannelValidationException
public void setItem( final Channel channel )
{
mSourceEditor.validate( editor );
mDecodeEditor.validate( editor );
mAuxDecodeEditor.validate( editor );
mEventLogEditor.validate( editor );
mRecordEditor.validate( editor );
super.setItem( channel );
mNameConfigurationEditor.setItem( channel );
mSourceConfigurationEditor.setItem( channel );
mDecodeConfigurationEditor.setItem( channel );
mAuxDecodeConfigurationEditor.setItem( channel );
mEventLogConfigurationEditor.setItem( channel );
mRecordConfigurationEditor.setItem( channel );
if( channel != null )
{
mChannelName.setText( "Channel: " + channel.getName() );
mEnableButton.setText( channel.getEnabled() ? "Disable" : "Enable" );
mEnableButton.setEnabled( true );
mEnableButton.setBackground( channel.getEnabled() ? Color.GREEN : getBackground() );
}
else
{
mChannelName.setText( "Channel: " );
mEnableButton.setText( "Enable" );
mEnableButton.setEnabled( false );
mEnableButton.setBackground( getBackground() );
}
}
public void save()
{
if( hasItem() )
{
mNameConfigurationEditor.save();
mSourceConfigurationEditor.save();
mDecodeConfigurationEditor.save();
mAuxDecodeConfigurationEditor.save();
mEventLogConfigurationEditor.save();
mRecordConfigurationEditor.save();
try
{
mDecodeConfigurationEditor.validate( mSourceConfigurationEditor );
mDecodeConfigurationEditor.validate( mAuxDecodeConfigurationEditor );
}
catch( EditorValidationException e )
{
e.getEditor().requestFocus();
JOptionPane.showMessageDialog( e.getEditor(), e.getReason(),
"Configuration Error", JOptionPane.ERROR_MESSAGE );
return;
}
mChannelModel.broadcast( new ChannelEvent( getItem(),
Event.NOTIFICATION_CONFIGURATION_CHANGE ) );
}
setModified( false );
}
}

View File

@@ -1,3 +1,20 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package controller.channel;
public class ChannelEvent
@@ -27,33 +44,35 @@ public class ChannelEvent
}
/**
* Channel Events - used to specify channel events and changes to channel
* configurations and settings.
* Channel events to describe the specific event
*/
public enum Event
{
CHANGE_ALIAS_LIST,
CHANGE_DECODER,
CHANGE_EVENT_LOGGER,
CHANGE_NAME,
CHANGE_SELECTED,
CHANGE_SITE,
CHANGE_RECORDER,
CHANGE_SOURCE,
CHANGE_SYSTEM,
CHANNEL_ADDED,
CHANNEL_DELETED,
CHANNEL_ENABLED,
CHANNEL_DISABLED,
CHANNEL_PROCESSING_STARTED,
CHANNEL_PROCESSING_STOPPED,
CHANNEL_STATE_RESET,
TRAFFIC_CHANNEL_ADDED,
TRAFFIC_CHANNEL_DELETED;
//Channel is added
NOTIFICATION_ADD,
//Channel configuration has changed
NOTIFICATION_CONFIGURATION_CHANGE,
//Channel is deleted/removed
NOTIFICATION_DELETE,
//Channel enable request was rejected
NOTIFICATION_ENABLE_REJECTED,
//Channel has started processing/decoding
NOTIFICATION_PROCESSING_START,
//Channel has stopped processing/decoding
NOTIFICATION_PROCESSING_STOP,
//Channel's selection state has changed
NOTIFICATION_SELECTION_CHANGE,
//Channel's channel-state has been reset
NOTIFICATION_STATE_RESET,
//Request to delete the channel
REQUEST_DELETE,
//Request to deselect the channel
REQUEST_DESELECT,
//Request to disable a channel - response will be a PROCESSING_STOP_NOTIFICATION
REQUEST_DISABLE,
//Request to enable a channel - response will be a PROCESSING_START_NOTIFICATION
REQUEST_ENABLE,
//Request to select the channel
REQUEST_SELECT;
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,143 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014,2015 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 java.util.List;
import message.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import alias.action.AliasActionManager;
import controller.ResourceManager;
public class ChannelManager implements ChannelEventListener
{
private final static Logger mLog = LoggerFactory.getLogger( ChannelManager.class );
private List<Channel> mChannels = new ArrayList<>();
private List<ChannelEventListener> mChannelListeners = new ArrayList<>();
private List<Listener<Message>> mMessageListeners = new ArrayList<>();
private AliasActionManager mAliasActionManager;
public ChannelManager( ResourceManager resourceManager )
{
mAliasActionManager = new AliasActionManager( resourceManager );
mChannelListeners.add( this );
/* Add alias action manager as listener to all channels/messages */
mMessageListeners.add( mAliasActionManager );
}
/**
* 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 channelChanged( ChannelEvent event )
{
switch( event.getEvent() )
{
case CHANNEL_ADDED:
if( !mChannels.contains( event.getChannel() ) )
{
mChannels.add( event.getChannel() );
}
break;
case CHANNEL_DELETED:
mChannels.remove( event.getChannel() );
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( ChannelEventListener listener )
{
mChannelListeners.add( listener );
for( Channel channel: mChannels )
{
channel.addListener( listener );
}
}
public List<Channel> getChannels()
{
return mChannels;
}
/**
* Removes a channel listener from being automatically added to all channels
* to receive channel change events.
*/
public void removeListener( ChannelEventListener 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 List<ChannelEventListener> getChannelListeners()
{
return mChannelListeners;
}
/**
* Returns the list of channel change listeners that will be automatically
* added to all channels to receive channel change events
*/
public List<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 );
}
}

View File

@@ -0,0 +1,343 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package controller.channel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.table.AbstractTableModel;
import module.decode.DecoderType;
import controller.channel.Channel.ChannelType;
import controller.channel.ChannelEvent.Event;
/**
* Channel Model
*/
public class ChannelModel extends AbstractTableModel implements IChannelEventBroadcaster
{
private static final long serialVersionUID = 1L;
private List<Channel> mChannels = new CopyOnWriteArrayList<>();
private List<Channel> mTrafficChannels = new CopyOnWriteArrayList<>();
private List<ChannelEventListener> mListeners = new CopyOnWriteArrayList<>();
public ChannelModel()
{
}
/**
* Unmodifiable list of non-traffic channels currently in the model
*/
public List<Channel> getChannels()
{
return Collections.unmodifiableList( mChannels );
}
public Channel getChannelAtIndex( int row )
{
if( mChannels.size() >= row )
{
return mChannels.get( row );
}
return null;
}
/**
* Returns a list of unique system values from across the channel set
*/
public List<String> getSystems()
{
List<String> systems = new ArrayList<>();
for( Channel channel: mChannels )
{
if( channel.hasSystem() && !systems.contains( channel.getSystem() ) )
{
systems.add( channel.getSystem() );
}
}
Collections.sort( systems );
return systems;
}
/**
* Returns a list of unique site values for all channels that have a matching
* system value
*/
public List<String> getSites( String system )
{
List<String> sites = new ArrayList<>();
if( system != null )
{
for( Channel channel: mChannels )
{
if( channel.hasSystem() &&
system.equals( channel.getSystem() ) &&
channel.hasSite() &&
!sites.contains( channel.getSite() ) )
{
sites.add( channel.getSite() );
}
}
}
Collections.sort( sites );
return sites;
}
/**
* Broadcasts the channel event to all registered listeners
*/
@Override
public void broadcast( ChannelEvent event )
{
for( ChannelEventListener listener: mListeners )
{
listener.channelChanged( event );
}
if( event.getChannel().getChannelType() == ChannelType.STANDARD )
{
switch( event.getEvent() )
{
case NOTIFICATION_CONFIGURATION_CHANGE:
case NOTIFICATION_PROCESSING_START:
case NOTIFICATION_PROCESSING_STOP:
case NOTIFICATION_SELECTION_CHANGE:
int index = mChannels.indexOf( event.getChannel() );
fireTableRowsUpdated( index, index );
break;
default:
break;
}
}
if( event.getEvent() == Event.REQUEST_DELETE )
{
removeChannel( event.getChannel() );
}
}
/**
* Bulk loading of channel list. Each channel is added and a channel add
* event is broadcast.
*/
public void addChannels( List<Channel> channels )
{
for( Channel channel: channels )
{
addChannel( channel );
}
}
/**
* Adds the channel to the model and broadcasts a channel add event
*/
public int addChannel( Channel channel )
{
int index = -1;
switch( channel.getChannelType() )
{
case STANDARD:
mChannels.add( channel );
index = mChannels.size() - 1;
fireTableRowsInserted( index, index );
break;
case TRAFFIC:
mTrafficChannels.add( channel );
index = mChannels.size() - 1;
break;
default:
break;
}
broadcast( new ChannelEvent( channel, Event.NOTIFICATION_ADD ) );
if( channel.getEnabled() )
{
broadcast( new ChannelEvent( channel, Event.REQUEST_ENABLE ) );
}
return index;
}
/**
* Removes the channel from the model and broadcasts a channel remove event
*/
public void removeChannel( Channel channel )
{
if( channel != null )
{
switch( channel.getChannelType() )
{
case STANDARD:
int index = mChannels.indexOf( channel );
mChannels.remove( channel );
if( index >= 0 )
{
fireTableRowsDeleted( index, index );
}
break;
case TRAFFIC:
mTrafficChannels.remove( channel );
break;
default:
break;
}
broadcast( new ChannelEvent( channel, Event.NOTIFICATION_DELETE ) );
}
}
/**
* Returns a list of channels that fall within the frequency range
*
* @param start frequency of the range
* @param stop frequency of the range
*
* @return list of channels or an empty list if none fall within the range
*/
public List<Channel> getChannelsInFrequencyRange( long start, long stop )
{
List<Channel> channels = new ArrayList<>();
for( Channel channel: mChannels )
{
if( channel.isWithin( start, stop ) )
{
channels.add( channel );
}
}
for( Channel channel: mTrafficChannels )
{
if( channel.isWithin( start, stop ) )
{
channels.add( channel );
}
}
return channels;
}
public void addListener( ChannelEventListener listener )
{
mListeners.add( listener );
}
public void removeListener( ChannelEventListener listener )
{
mListeners.remove( listener );
}
//Table Model Interface Methods - standard channels only
@Override
public int getRowCount()
{
return mChannels.size();
}
@Override
public int getColumnCount()
{
return 6;
}
@Override
public String getColumnName( int columnIndex )
{
switch( columnIndex )
{
case 0:
return "System";
case 1:
return "Site";
case 2:
return "Name";
case 3:
return "Alias List";
case 4:
return "Source";
case 5:
return "Decoder";
}
return null;
}
@Override
public Class<?> getColumnClass( int columnIndex )
{
return String.class;
}
@Override
public boolean isCellEditable( int rowIndex, int columnIndex )
{
return false;
}
@Override
public Object getValueAt( int rowIndex, int columnIndex )
{
Channel channel = mChannels.get( rowIndex );
switch( columnIndex )
{
case 0:
return channel.getSystem();
case 1:
return channel.getSite();
case 2:
return channel.getName();
case 3:
return channel.getAliasListName();
case 4:
return channel.getSourceConfiguration().getDescription();
case 5:
return channel.getDecodeConfiguration()
.getDecoderType().getShortDisplayString();
}
return null;
}
@Override
public void setValueAt( Object aValue, int rowIndex, int columnIndex )
{
throw new IllegalArgumentException( "Not yet implemented" );
}
public void createChannel( DecoderType decoderType, long frequency )
{
throw new UnsupportedOperationException( "Not yet implemented" );
}
}

View File

@@ -1,187 +0,0 @@
/*******************************************************************************
* 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.text.DecimalFormat;
import javax.swing.JMenu;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import source.tuner.TunerChannel;
import controller.ConfigurableNode;
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 ChannelEventListener
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( ChannelNode.class );
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 channelChanged( ChannelEvent event )
{
switch( event.getEvent() )
{
/* Refresh the node for each of these events */
case CHANGE_DECODER:
case CHANGE_NAME:
case CHANGE_SELECTED:
case CHANGE_SITE:
case CHANGE_SYSTEM:
case CHANNEL_ENABLED:
case CHANNEL_DISABLED:
case CHANNEL_PROCESSING_STARTED:
case CHANNEL_PROCESSING_STOPPED:
this.refresh();
break;
/* We're being deleted, so cleanup */
case CHANNEL_DELETED:
delete();
break;
default:
break;
}
}
@Override
public String getIconPath()
{
return getChannel().getDecodeConfiguration().getDecoderType()
.getIconFilename();
}
@Override
public Color getBackgroundColor()
{
if( getChannel().getEnabled() )
{
if( getChannel().isProcessing() )
{
return Color.GREEN;
}
else
{
return Color.RED;
}
}
return null;
}
@Override
public JPanel getEditor()
{
return new ChannelEditor( this,
getChannel().getResourceManager() == null ? null :
getChannel().getResourceManager().getPlaylistManager() );
}
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();
JMenu channelMenu = ChannelUtils.getContextMenu(
getModel().getResourceManager().getPlaylistManager(),
getChannel(), getModel().getTree() );
if( channelMenu != null )
{
popupMenu.add( channelMenu );
}
return popupMenu;
}
public void delete()
{
((SiteNode)getParent()).getSite().removeChannel( getChannel() );
save();
getModel().removeNodeFromParent( ChannelNode.this );
}
}

View File

@@ -0,0 +1,334 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package controller.channel;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import message.Message;
import module.Module;
import module.ProcessingChain;
import module.decode.DecoderFactory;
import module.decode.event.MessageActivityModel;
import module.log.EventLogManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import record.RecorderManager;
import record.RecorderType;
import sample.Listener;
import source.Source;
import source.SourceException;
import source.SourceManager;
import alias.AliasModel;
import audio.AudioPacket;
import audio.metadata.Metadata;
import audio.metadata.MetadataType;
import controller.channel.Channel.ChannelType;
import controller.channel.ChannelEvent.Event;
import controller.channel.map.ChannelMapModel;
import filter.FilterSet;
public class ChannelProcessingManager implements ChannelEventListener
{
private final static Logger mLog = LoggerFactory.getLogger( ChannelProcessingManager.class );
private Map<Integer,ProcessingChain> mProcessingChains = new HashMap<>();
private List<Listener<AudioPacket>> mAudioPacketListeners = new CopyOnWriteArrayList<>();
private List<Listener<Message>> mMessageListeners = new CopyOnWriteArrayList<>();
private ChannelModel mChannelModel;
private ChannelMapModel mChannelMapModel;
private AliasModel mAliasModel;
private EventLogManager mEventLogManager;
private RecorderManager mRecorderManager;
private SourceManager mSourceManager;
public ChannelProcessingManager( ChannelModel channelModel,
ChannelMapModel channelMapModel,
AliasModel aliasModel,
EventLogManager eventLogManager,
RecorderManager recorderManager,
SourceManager sourceManager )
{
mChannelModel = channelModel;
mChannelMapModel = channelMapModel;
mAliasModel = aliasModel;
mEventLogManager = eventLogManager;
mRecorderManager = recorderManager;
mSourceManager = sourceManager;
}
/**
* Indicates if a processing chain is constructed for the channel and that
* the processing chain is currently processing.
*/
public boolean isProcessing( Channel channel )
{
if( mProcessingChains.containsKey( channel.getChannelID() ) )
{
return mProcessingChains.get( channel.getChannelID() ).isProcessing();
}
return false;
}
/**
* Returns the current processing chain associated with the channel, or
* null if a processing chain is not currently setup for the channel
*/
public ProcessingChain getProcessingChain( Channel channel )
{
return mProcessingChains.get( channel.getChannelID() );
}
@Override
public synchronized void channelChanged( ChannelEvent event )
{
Channel channel = event.getChannel();
switch( event.getEvent() )
{
case REQUEST_ENABLE:
if( !mProcessingChains.containsKey( channel.getChannelID() ) ||
!mProcessingChains.get( channel.getChannelID() ).isProcessing() )
{
startProcessing( event );
}
break;
case REQUEST_DISABLE:
if( channel.getEnabled() )
{
switch( channel.getChannelType() )
{
case STANDARD:
stopProcessing( channel, true );
break;
case TRAFFIC:
//Don't remove traffic channel processing chains
//until explicitly deleted, so that we can reuse them
stopProcessing( channel, false );
default:
break;
}
}
case NOTIFICATION_DELETE:
if( channel.getEnabled() )
{
stopProcessing( channel, true );
}
break;
case NOTIFICATION_CONFIGURATION_CHANGE:
if( isProcessing( channel ) )
{
stopProcessing( channel, false );
startProcessing( event );
}
break;
default:
break;
}
}
private void startProcessing( ChannelEvent event )
{
Channel channel = event.getChannel();
ProcessingChain processingChain = mProcessingChains.get( channel.getChannelID() );
//If we're already processing, ignore the request
if( processingChain != null && processingChain.isProcessing() )
{
return;
}
//Ensure that we can get a source before we construct a new processing chain
Source source = null;
try
{
source = mSourceManager.getSource( channel.getSourceConfiguration(),
channel.getDecodeConfiguration().getDecoderType().getChannelBandwidth() );
}
catch( SourceException se )
{
mLog.debug( "Error obtaining source for channel [" + channel.getName() + "]", se );
}
if( source == null )
{
channel.setEnabled( false );
mChannelModel.broadcast(
new ChannelEvent( channel, Event.NOTIFICATION_ENABLE_REJECTED ) );
return;
}
if( processingChain == null )
{
processingChain = new ProcessingChain( channel.getName(),
channel.getChannelType() );
/* Register global listeners */
for( Listener<AudioPacket> listener: mAudioPacketListeners )
{
processingChain.addAudioPacketListener( listener );
}
for( Listener<Message> listener: mMessageListeners )
{
processingChain.addMessageListener( listener );
}
/* Processing Modules */
List<Module> modules = DecoderFactory.getModules( mChannelModel,
mChannelMapModel, this, mAliasModel, channel );
processingChain.addModules( modules );
/* Setup message activity model with filtering */
FilterSet<Message> messageFilter = DecoderFactory.getMessageFilters( modules );
MessageActivityModel messageModel = new MessageActivityModel( messageFilter );
processingChain.setMessageActivityModel( messageModel );
/* Setup event logging */
List<Module> loggers = mEventLogManager.getLoggers(
channel.getEventLogConfiguration(), channel.getName() );
if( !loggers.isEmpty() )
{
processingChain.addModules( loggers );
}
/* Setup recorders */
List<RecorderType> recorders = channel.getRecordConfiguration().getRecorders();
if( !recorders.isEmpty() )
{
if( recorders.contains( RecorderType.AUDIO ) )
{
processingChain.addAudioPacketListener( mRecorderManager );
}
/* Add baseband recorder */
if( ( recorders.contains( RecorderType.BASEBAND ) &&
channel.getChannelType() == ChannelType.STANDARD ) )
{
processingChain.addModule( mRecorderManager.getBasebandRecorder(
channel.toString() ) );
}
/* Add traffic channel baseband recorder */
if( recorders.contains( RecorderType.TRAFFIC_BASEBAND ) &&
channel.getChannelType() == ChannelType.TRAFFIC )
{
processingChain.addModule( mRecorderManager
.getBasebandRecorder( channel.toString() ) );
}
}
/* Inject channel metadata that will be inserted into audio packets
* for the recorder manager and streaming */
processingChain.broadcast(
new Metadata( MetadataType.SYSTEM, channel.getSystem() ) );
processingChain.broadcast(
new Metadata( MetadataType.SITE_ID, channel.getSite() ) );
processingChain.broadcast(
new Metadata( MetadataType.CHANNEL_NAME, channel.getName() ) );
}
processingChain.setSource( source );
if( event instanceof TrafficChannelEvent )
{
TrafficChannelEvent trafficChannelEvent = (TrafficChannelEvent)event;
processingChain.getChannelState().configureAsTrafficChannel(
trafficChannelEvent.getTrafficChannelManager(),
trafficChannelEvent.getCallEvent() );
}
processingChain.start();
channel.setEnabled( true );
mProcessingChains.put( channel.getChannelID(), processingChain );
mChannelModel.broadcast(
new ChannelEvent( channel, Event.NOTIFICATION_PROCESSING_START ) );
}
private void stopProcessing( Channel channel, boolean remove )
{
channel.setEnabled( false );
if( mProcessingChains.containsKey( channel.getChannelID() ) )
{
ProcessingChain chain = mProcessingChains.get( channel.getChannelID() );
chain.stop();
mChannelModel.broadcast( new ChannelEvent( channel, Event.NOTIFICATION_PROCESSING_STOP ) );
if( remove )
{
mProcessingChains.remove( channel.getChannelID() );
chain.dispose();
}
}
}
/**
* Adds a message listener that will be added to all channels to receive
* any messages.
*/
public void addAudioPacketListener( Listener<AudioPacket> listener )
{
mAudioPacketListeners.add( listener );
}
/**
* Removes a message listener.
*/
public void removeAudioPacketListener( Listener<AudioPacket> listener )
{
mAudioPacketListeners.remove( listener );
}
/**
* Adds a message listener that will be added to all channels to receive
* any messages.
*/
public void addMessageListener( Listener<Message> listener )
{
mMessageListeners.add( listener );
}
/**
* Removes a message listener.
*/
public void removeMessageListener( Listener<Message> listener )
{
mMessageListeners.remove( listener );
}
}

View File

@@ -0,0 +1,71 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2015 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.ChannelEvent.Event;
public class ChannelSelectionManager implements ChannelEventListener
{
private IChannelEventBroadcaster mChannelEventBroadcaster;
private Channel mSelectedChannel = null;
/**
* Manages channel selection state to ensure that only one channel is ever
* in a selected state.
*/
public ChannelSelectionManager( IChannelEventBroadcaster broadcaster )
{
mChannelEventBroadcaster = broadcaster;
}
@Override
public void channelChanged( ChannelEvent event )
{
switch( event.getEvent() )
{
case REQUEST_SELECT:
if( mSelectedChannel != null )
{
mSelectedChannel.setSelected( false );
mChannelEventBroadcaster.broadcast( new ChannelEvent( mSelectedChannel,
Event.NOTIFICATION_SELECTION_CHANGE ) );
mSelectedChannel = null;
}
mSelectedChannel = event.getChannel();
mSelectedChannel.setSelected( true );
mChannelEventBroadcaster.broadcast( new ChannelEvent( event.getChannel(),
Event.NOTIFICATION_SELECTION_CHANGE ) );
break;
case NOTIFICATION_PROCESSING_STOP:
case REQUEST_DESELECT:
if( mSelectedChannel != null &&
mSelectedChannel == event.getChannel() )
{
mSelectedChannel.setSelected( false );
mSelectedChannel = null;
mChannelEventBroadcaster.broadcast( new ChannelEvent( event.getChannel(),
Event.NOTIFICATION_SELECTION_CHANGE ) );
}
break;
default:
break;
}
}
}

View File

@@ -9,23 +9,20 @@ import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JSeparator;
import module.ProcessingChain;
import module.decode.event.ActivitySummaryFrame;
import module.decode.state.DecoderState;
import playlist.PlaylistManager;
import controller.channel.ChannelEvent.Event;
public class ChannelUtils
{
private static final boolean ENABLED = true;
private static final boolean DISABLED = false;
private static final boolean BROADCAST_CHANGE = true;
/**
* Creates a context menu for the channel argument
*/
public static JMenu getContextMenu( final PlaylistManager playlistManager,
final Channel channel,
final Component anchor )
public static JMenu getContextMenu( final ChannelModel channelModel,
final ChannelProcessingManager channelProcessingManager,
final Channel channel,
final Component anchor )
{
if( channel != null )
{
@@ -39,12 +36,8 @@ public class ChannelUtils
@Override
public void actionPerformed( ActionEvent e )
{
channel.setEnabled( DISABLED, BROADCAST_CHANGE );
if( playlistManager != null )
{
playlistManager.save();
}
channelModel.broadcast(
new ChannelEvent( channel, Event.REQUEST_DISABLE ) );
}
} );
@@ -62,10 +55,14 @@ public class ChannelUtils
{
StringBuilder sb = new StringBuilder();
for( DecoderState decoderState: channel
.getProcessingChain().getDecoderStates() )
ProcessingChain chain = channelProcessingManager.getProcessingChain( channel );
if( chain != null )
{
sb.append( decoderState.getActivitySummary() );
for( DecoderState decoderState: chain.getDecoderStates() )
{
sb.append( decoderState.getActivitySummary() );
}
}
new ActivitySummaryFrame( sb.toString(), anchor );
@@ -82,12 +79,8 @@ public class ChannelUtils
@Override
public void actionPerformed( ActionEvent e )
{
channel.setEnabled( ENABLED, BROADCAST_CHANGE );
if( playlistManager != null )
{
playlistManager.save();
}
channelModel.broadcast(
new ChannelEvent( channel, Event.REQUEST_ENABLE ) );
}
} );
@@ -108,16 +101,8 @@ public class ChannelUtils
if( response == JOptionPane.YES_OPTION )
{
/* Disable the channel */
channel.setEnabled( DISABLED, BROADCAST_CHANGE );
/* Broadcast channel deleted event */
channel.fireChannelEvent( Event.CHANNEL_DELETED );
if( playlistManager != null )
{
playlistManager.save();
}
channelModel.broadcast(
new ChannelEvent( channel, Event.REQUEST_DELETE ) );
}
}
} );

View File

@@ -1,11 +0,0 @@
package controller.channel;
public class ChannelValidationException extends Exception
{
private static final long serialVersionUID = 1L;
public ChannelValidationException( String validationMessage )
{
super( validationMessage );
}
}

View File

@@ -0,0 +1,23 @@
package controller.channel;
import java.awt.Component;
public class ConfigurationValidationException extends Exception
{
private static final long serialVersionUID = 1L;
private Component mComponent;
public ConfigurationValidationException( Component component,
String validationMessage )
{
super( validationMessage );
mComponent = component;
}
public Component getComponent()
{
return mComponent;
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,26 +17,13 @@
******************************************************************************/
package controller.channel;
import controller.Editor;
public abstract class AbstractChannelEditor extends Editor
/**
* Provides channel event broadcasting capability.
*/
public interface IChannelEventBroadcaster
{
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();
/**
* Broadcasts the channel event
*/
public void broadcast( ChannelEvent event );
}

View File

@@ -0,0 +1,269 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package controller.channel;
import gui.editor.Editor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collections;
import java.util.List;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.miginfocom.swing.MigLayout;
import alias.AliasModel;
public class NameConfigurationEditor extends Editor<Channel> implements DocumentListener
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger( NameConfigurationEditor.class );
private static ComboBoxModel<String> EMPTY_MODEL = new DefaultComboBoxModel<>();
private AliasModel mAliasModel;
private ChannelModel mChannelModel;
private JTextField mChannelName;
private JComboBox<String> mSystemNameCombo;
private JComboBox<String> mSiteNameCombo;
private JComboBox<String> mAliasListCombo;
public NameConfigurationEditor( AliasModel aliasModel, ChannelModel model )
{
mAliasModel = aliasModel;
mChannelModel = model;
init();
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]", "[][][grow]" ) );
mChannelName = new JTextField( "" );
mChannelName.getDocument().addDocumentListener( this );
mChannelName.setEnabled( false );
add( new JLabel( "Name:" ) );
add( mChannelName );
mSystemNameCombo = new JComboBox<>( EMPTY_MODEL );
mSystemNameCombo.setEnabled( false );
mSystemNameCombo.setEditable( true );
mSystemNameCombo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
Object selected = mSystemNameCombo.getSelectedItem();
if( selected != null )
{
String system = (String)selected;
List<String> sites = mChannelModel.getSites( system );
if( !sites.contains( getItem().getSite() ) )
{
sites.add( getItem().getSite() );
}
if( sites.isEmpty() )
{
mSiteNameCombo.setModel( EMPTY_MODEL );
}
else
{
mSiteNameCombo.setModel( new DefaultComboBoxModel<String>(
sites.toArray( new String[ sites.size() ] ) ) );;
}
mSiteNameCombo.setSelectedItem( getItem().getSite() );
}
setModified( true );
}
} );
add( new JLabel( "System:" ) );
add( mSystemNameCombo );
mAliasListCombo = new JComboBox<String>();
mAliasListCombo.setEnabled( false );
mAliasListCombo.setEditable( true );
mAliasListCombo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( new JLabel( "Alias List:" ) );
add( mAliasListCombo );
mSiteNameCombo = new JComboBox<>( EMPTY_MODEL );
mSiteNameCombo.setEnabled( false );
mSiteNameCombo.setEditable( true );
mSiteNameCombo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( new JLabel( "Site:" ) );
add( mSiteNameCombo );
}
@Override
public void save()
{
if( hasItem() && isModified() )
{
getItem().setName( mChannelName.getText() );
Object system = mSystemNameCombo.getSelectedItem();
getItem().setSystem( ( system == null ? null : (String)system ) );
Object site = mSiteNameCombo.getSelectedItem();
getItem().setSite( ( site == null ? null : (String)site ) );
Object aliasList = mAliasListCombo.getSelectedItem();
getItem().setAliasListName( aliasList == null ? null : (String)aliasList );
}
setModified( false );
}
private void setControlsEnabled( boolean enabled )
{
if( mChannelName.isEnabled() != enabled )
{
mChannelName.setEnabled( enabled );
}
if( mAliasListCombo.isEnabled() != enabled )
{
mAliasListCombo.setEnabled( enabled );
}
if( mSystemNameCombo.isEnabled() != enabled )
{
mSystemNameCombo.setEnabled( enabled );
}
if( mSiteNameCombo.isEnabled() != enabled )
{
mSiteNameCombo.setEnabled( enabled );
}
}
@Override
public void setItem( Channel channel )
{
super.setItem( channel );
if( hasItem() )
{
setControlsEnabled( true );
mChannelName.setText( channel.getName() );
List<String> systems = mChannelModel.getSystems();
if( systems.isEmpty() )
{
mSystemNameCombo.setModel( EMPTY_MODEL );
}
else
{
mSystemNameCombo.setModel( new DefaultComboBoxModel<String>(
systems.toArray( new String[ systems.size() ] ) ) );;
}
mSystemNameCombo.setSelectedItem( channel.getSystem() );
List<String> sites = mChannelModel.getSites( channel.getSystem() );
if( sites.isEmpty() )
{
mSiteNameCombo.setModel( EMPTY_MODEL );
}
else
{
mSiteNameCombo.setModel( new DefaultComboBoxModel<String>(
sites.toArray( new String[ sites.size() ] ) ) );;
}
if( channel.getSite() != null )
{
mSiteNameCombo.setSelectedItem( channel.getSite() );
}
List<String> lists = mAliasModel.getListNames();
Collections.sort( lists );
mAliasListCombo.setModel( new DefaultComboBoxModel<String>(
lists.toArray( new String[ lists.size() ] ) ) );
if( channel.getAliasListName() != null )
{
mAliasListCombo.setSelectedItem( channel.getAliasListName() );
}
}
else
{
setControlsEnabled( false );
mChannelName.setText( null );
}
setModified( false );
}
@Override
public void insertUpdate( DocumentEvent e )
{
setModified( true );
}
@Override
public void changedUpdate( DocumentEvent e )
{
setModified( true );
}
@Override
public void removeUpdate( DocumentEvent e )
{
setModified( true );
}
}

View File

@@ -0,0 +1,34 @@
package controller.channel;
import module.decode.event.CallEvent;
import module.decode.state.TrafficChannelManager;
public class TrafficChannelEvent extends ChannelEvent
{
private TrafficChannelManager mTrafficChannelManager;
private CallEvent mCallEvent;
/**
* Call event with traffic channel manager for call back, and original creation event.
*/
public TrafficChannelEvent( TrafficChannelManager trafficChannelManager,
Channel channel,
Event event,
CallEvent callEvent )
{
super( channel, event );
mTrafficChannelManager = trafficChannelManager;
mCallEvent = callEvent;
}
public TrafficChannelManager getTrafficChannelManager()
{
return mTrafficChannelManager;
}
public CallEvent getCallEvent()
{
return mCallEvent;
}
}

View File

@@ -18,17 +18,20 @@
package controller.channel.map;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
@XmlSeeAlso( { ChannelRange.class } )
public class ChannelMap
{
private String mName;
private boolean mInvalid = false;
private ArrayList<ChannelRange> mRanges = new ArrayList<ChannelRange>();
private List<ChannelRange> mRanges = new ArrayList<ChannelRange>();
public ChannelMap()
{
@@ -39,17 +42,10 @@ public class ChannelMap
{
mName = name;
}
public String toString()
{
return mName;
}
/**
* Creates a copy of this channel map
*/
public ChannelMap copyOf()
{
ChannelMap map = new ChannelMap( mName );
ChannelMap map = new ChannelMap( new String( mName ) );
for( ChannelRange range: mRanges )
{
@@ -58,29 +54,29 @@ public class ChannelMap
return map;
}
public int getInvalidRange()
@XmlTransient
public boolean isInvalid()
{
for( int x = 0; x < mRanges.size(); x++ )
{
if( !mRanges.get( x ).isValid() )
{
return x;
}
}
return -1;
return mInvalid;
}
public String toString()
{
return mName + ( mInvalid ? " - Error" : "" );
}
public ArrayList<ChannelRange> getRanges()
@XmlElement( name = "range" )
public List<ChannelRange> getRanges()
{
return mRanges;
}
@XmlElement( name = "range" )
public void setRanges( ArrayList<ChannelRange> ranges )
public void setRanges( List<ChannelRange> ranges )
{
mRanges = ranges;
validate();
}
@XmlAttribute
@@ -106,15 +102,44 @@ public class ChannelMap
return 0;
}
/**
* Validates each of the channel ranges for overlap
*/
private void validate()
{
mInvalid = false;
for( int x = 0; x < mRanges.size(); x++ )
{
if( !mRanges.get( x ).isValid() )
{
mInvalid = true;
}
for( int y = x + 1; y < mRanges.size(); y++ )
{
if( mRanges.get( x ).overlaps( mRanges.get( y ) ) )
{
mInvalid = true;
}
}
}
}
public void addRange( ChannelRange range )
{
mRanges.add( range );
validate();
}
public void deleteRange( ChannelRange range )
public void removeRange( ChannelRange range )
{
mRanges.remove( range );
validate();
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,75 +17,112 @@
******************************************************************************/
package controller.channel.map;
import gui.editor.DocumentListenerEditor;
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.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableCellEditor;
import javax.swing.text.InternationalFormatter;
import net.miginfocom.swing.MigLayout;
import controller.channel.map.ChannelMapEvent.Event;
import controller.channel.map.ChannelRangeModel.ChannelRangeEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ChannelMapEditor extends JPanel implements ActionListener
public class ChannelMapEditor extends DocumentListenerEditor<ChannelMap>
implements ListSelectionListener, ChannelRangeEventListener
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( ChannelMapEditor.class );
private ChannelMapNode mChannelMapNode;
private JLabel mNameLabel;
private JTextField mNameText;
private ChannelMapModel mRangeModel;
private ChannelRangeModel mRangeModel;
private JTable mRangeTable;
private JButton mDelete;
private ChannelMap mChannelMapCopy;
private JButton mNewButton;
private JButton mDeleteButton;
private JButton mSaveButton;
private JLabel mRangeDescription;
private ChannelMapModel mChannelMapModel;
public ChannelMapEditor( ChannelMapNode ChannelMap )
public ChannelMapEditor( ChannelMapModel channelMapModel )
{
mChannelMapNode = ChannelMap;
mChannelMapCopy = mChannelMapNode.getChannelMap().copyOf();
initGUI();
mChannelMapModel = channelMapModel;
init();
}
private void initGUI()
public ChannelMap getChannelMap()
{
setLayout( new MigLayout( "fill,wrap 2", "[right][grow]", "[][][grow][][]" ) );
if( hasItem() )
{
return (ChannelMap)getItem();
}
add( new JLabel( "Channel Map" ), "span, align center" );
return null;
}
@Override
public void setItem( ChannelMap item )
{
super.setItem( item );
mNameLabel = new JLabel( "Name:" );
if( hasItem() )
{
ChannelMap map = getChannelMap();
mNameText.setText( map.getName() );
mRangeModel.clear();
mRangeModel.addRanges( map.getRanges() );
mNewButton.setEnabled( true );
}
else
{
mNameText.setText( "" );
mRangeModel.clear();
mNewButton.setEnabled( false );
}
setModified( false );
}
@Override
public void setModified( boolean modified )
{
super.setModified( modified );
mSaveButton.setEnabled( modified );
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 3",
"[grow,fill][grow,fill][grow,fill]", "[][grow][][]" ) );
mNameLabel = new JLabel( "Channel Map:" );
add( mNameLabel );
mNameText = new JTextField( mChannelMapCopy.getName() );
mNameText.addFocusListener( new FocusListener()
{
@Override public void focusGained( FocusEvent arg0 ) {}
mNameText = new JTextField();
mNameText.getDocument().addDocumentListener( this );
add( mNameText, "span" );
@Override
public void focusLost( FocusEvent arg0 )
{
mChannelMapCopy.setName( mNameText.getText() );
}
} );
add( mNameText, "growx, push" );
mRangeModel = new ChannelMapModel( mChannelMapCopy );
mRangeModel = new ChannelRangeModel();
mRangeModel.setListener( this );
mRangeTable = new JTable( mRangeModel );
mRangeTable.setPreferredScrollableViewportSize( new Dimension( 300, 150 ) );
@@ -96,129 +133,201 @@ public class ChannelMapEditor extends JPanel implements ActionListener
mRangeTable.getColumnModel().getColumn( x )
.setCellEditor( new RangeTableEditor() );
}
mRangeTable.getSelectionModel().addListSelectionListener( new ListSelectionListener()
{
@Override
public void valueChanged( ListSelectionEvent event )
{
if( !event.getValueIsAdjusting() )
{
int index = event.getFirstIndex();
mDeleteButton.setEnabled( index >= 0 );
if( index >= 0 )
{
int modelIndex = mRangeTable.convertRowIndexToModel( index );
if( modelIndex >= 0 )
{
ChannelRange selected = mRangeModel.getChannelRange( modelIndex );
if( selected != null )
{
mRangeDescription.setText( selected.getDescription() );
}
else
{
mRangeDescription.setText( "" );
}
}
}
}
}
} );
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;
}
mRangeDescription = new JLabel( " " );
add( mRangeDescription, "span" );
return true;
mSaveButton = new JButton( "Save" );
mSaveButton.setEnabled( false );
mSaveButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
save();
}
} );
add( mSaveButton );
mNewButton = new JButton( "New Range" );
mNewButton.setEnabled( false );
mNewButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
mRangeModel.addRange( new ChannelRange() );
}
} );
add( mNewButton );
mDeleteButton = new JButton( "DeleteRange" );
mDeleteButton.setEnabled( false );
mDeleteButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
int selectedRow = mRangeTable.getSelectedRow();
if( selectedRow >= 0 )
{
int modelRow = mRangeTable.convertRowIndexToModel( selectedRow );
ChannelRange selectedRange = mRangeModel.getChannelRange( modelRow );
if( selectedRange != null )
{
int choice = JOptionPane.showConfirmDialog( mRangeTable,
"Do you want to delete this channel range?",
"Delete Channel Range?", JOptionPane.YES_NO_OPTION );
if( choice == JOptionPane.YES_OPTION )
{
mRangeModel.removeRange( selectedRange );
mDeleteButton.setEnabled( false );
}
}
}
}
} );
add( mDeleteButton, "wrap" );
}
@Override
public void actionPerformed( ActionEvent e )
{
String command = e.getActionCommand();
switch( command )
public void save()
{
if( isModified() && hasItem() )
{
case "New Range":
mRangeModel.addRange( new ChannelRange() );
break;
case "Save":
if( checkForValidRanges() )
ChannelMap channelMap = getChannelMap();
channelMap.setName( mNameText.getText() );
channelMap.setRanges( mRangeModel.getChannelRanges() );
mChannelMapModel.broadcast( new ChannelMapEvent( getChannelMap(), Event.CHANGE ) );
setModified( false );
}
}
@Override
public void valueChanged( ListSelectionEvent e )
{
if( !e.getValueIsAdjusting() )
{
if( e.getSource() instanceof JList )
{
JList<?> list = (JList<?>)e.getSource();
if( list.getSelectedValue() instanceof ChannelMap )
{
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 );
setItem( (ChannelMap)list.getSelectedValue() );
}
else
{
mRangeModel.removeRange(
mRangeTable.convertRowIndexToModel( row ) );
setItem( null );
}
break;
}
}
}
}
@Override
public void channelRangesChanged()
{
setModified( true );
//Update description
int index = mRangeTable.getSelectedRow();
if( index >= 0 )
{
ChannelRange selected = mRangeModel.getChannelRange(
mRangeTable.convertRowIndexToModel( index ) );
if( selected != null )
{
mRangeDescription.setText( selected.getDescription() );
}
else
{
mRangeDescription.setText( "" );
}
}
}
public class RangeTableEditor extends AbstractCellEditor
implements TableCellEditor, ActionListener
implements TableCellEditor, ActionListener
{
private static final long serialVersionUID = 1L;
JFormattedTextField mEditor;
public RangeTableEditor()
{
InternationalFormatter nf = new InternationalFormatter();
nf.setMinimum( 1 );
nf.setAllowsInvalid( false );
nf.setAllowsInvalid( true );
mEditor = new JFormattedTextField( nf );
}
@Override
public Object getCellEditorValue()
{
return mEditor.getText();
}
public Object getCellEditorValue()
{
return mEditor.getText();
}
@Override
public void actionPerformed( ActionEvent e )
{
}
public void actionPerformed( ActionEvent e )
{
}
@Override
public Component getTableCellEditorComponent( JTable table,
Object value,
boolean isSelected,
int row,
int column )
{
public Component getTableCellEditorComponent( JTable table,
Object value,
boolean isSelected,
int row,
int column )
{
mEditor.setValue( value );
return mEditor;
}
}
}
}
}

View File

@@ -0,0 +1,76 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package controller.channel.map;
public class ChannelMapEvent
{
private ChannelMap mChannelMap;
private Event mEvent;
private String mPreviousChannelMapName;
/**
* ChannelMapEvent - event describing any changes to a channel map
*
* @param channelMap that changed
* @param event describing the change
*/
public ChannelMapEvent( ChannelMap channelMap, Event event )
{
mChannelMap = channelMap;
mEvent = event;
}
/**
* ChannelMapEvent - channel map renaming event.
*
* @param channelMap that changed
* @param previousName of the channel map
*/
public ChannelMapEvent( ChannelMap channelMap, String previousName )
{
this( channelMap, Event.RENAME );
mPreviousChannelMapName = previousName;
}
public ChannelMap getChannelMap()
{
return mChannelMap;
}
public String getPreviousChannelMapName()
{
return mPreviousChannelMapName;
}
public Event getEvent()
{
return mEvent;
}
/**
* Events
*/
public enum Event
{
ADD,
CHANGE,
RENAME,
DELETE;
}
}

View File

@@ -1,76 +0,0 @@
/*******************************************************************************
* 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.map;
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();
}
}

View File

@@ -1,87 +0,0 @@
/*******************************************************************************
* 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.map;
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;
}
}

View File

@@ -0,0 +1,135 @@
package controller.channel.map;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import net.miginfocom.swing.MigLayout;
import com.jidesoft.swing.JideSplitPane;
public class ChannelMapManager extends JPanel
{
private static final long serialVersionUID = 1L;
private ChannelMapModel mChannelMapModel;
private JList<ChannelMap> mChannelMapList;
private ChannelMapEditor mChannelMapEditor;
private JButton mDeleteMapButton;
private JButton mCloneMapButton;
public ChannelMapManager( ChannelMapModel channelMapModel )
{
mChannelMapModel = channelMapModel;
mChannelMapList = new JList<>( mChannelMapModel );
mChannelMapEditor = new ChannelMapEditor( mChannelMapModel );
init();
}
private void init()
{
setLayout( new MigLayout( "insets 1 1 1 1", "[fill,grow]", "[fill,grow]" ) );
JPanel listPanel = new JPanel();
listPanel.setLayout( new MigLayout( "",
"[fill,grow][fill,grow][fill,grow]", "[fill,grow][]" ) );
mChannelMapList.addListSelectionListener( mChannelMapEditor );
mChannelMapList.addListSelectionListener( new ListSelectionListener()
{
@Override
public void valueChanged( ListSelectionEvent e )
{
if( mChannelMapList.getSelectedValue() != null )
{
mCloneMapButton.setEnabled( true );
mDeleteMapButton.setEnabled( true );
}
else
{
mCloneMapButton.setEnabled( false );
mDeleteMapButton.setEnabled( false );
}
}
} );
mChannelMapList.setLayoutOrientation( JList.VERTICAL );
mChannelMapList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
JScrollPane listScroller = new JScrollPane( mChannelMapList );
listPanel.add( listScroller, "span" );
JButton newMapButton = new JButton( "New" );
newMapButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
ChannelMap channelMap = new ChannelMap( "New Channel Map" );
mChannelMapModel.addChannelMap( channelMap );
mChannelMapList.setSelectedValue( channelMap, true );
}
} );
listPanel.add( newMapButton );
mCloneMapButton = new JButton( "Clone" );
mCloneMapButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
ChannelMap selected = mChannelMapList.getSelectedValue();
if( selected != null )
{
ChannelMap copy = selected.copyOf();
mChannelMapModel.addChannelMap( copy );
mChannelMapList.setSelectedValue( copy, true );
}
}
} );
listPanel.add( mCloneMapButton );
mDeleteMapButton = new JButton( "Delete" );
mDeleteMapButton.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
ChannelMap channelMap = mChannelMapList.getSelectedValue();
if( channelMap != null )
{
int choice = JOptionPane.showConfirmDialog( mChannelMapList,
"Do you want to delete this channel map?",
"Delete Channel Map?", JOptionPane.YES_NO_OPTION );
if( choice == JOptionPane.YES_OPTION )
{
mChannelMapModel.removeChannelMap( channelMap );
}
}
}
} );
listPanel.add( mDeleteMapButton );
JScrollPane editorScroller = new JScrollPane( mChannelMapEditor );
JideSplitPane splitPane = new JideSplitPane();
splitPane.setOrientation( JideSplitPane.HORIZONTAL_SPLIT );
splitPane.add( listPanel );
splitPane.add( editorScroller );
add( splitPane );
}
}

View File

@@ -0,0 +1,61 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package controller.channel.map;
import java.awt.EventQueue;
import javax.swing.JFrame;
import net.miginfocom.swing.MigLayout;
public class ChannelMapManagerFrame extends JFrame
{
private static final long serialVersionUID = 1L;
public ChannelMapManagerFrame( ChannelMapModel channelMapModel )
{
init( new ChannelMapManager( channelMapModel ) );
}
private void init( ChannelMapManager channelMapManager )
{
setTitle( "Channel Map Manager" );
setSize( 800, 400 );
setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
setLayout( new MigLayout( "", "[grow,fill]", "[grow,fill]" ) );
add( channelMapManager );
setLocationRelativeTo( null );
}
public static void main( String[] args )
{
ChannelMapModel channelMapModel = new ChannelMapModel();
final ChannelMapManagerFrame frame =
new ChannelMapManagerFrame( channelMapModel );
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
frame.setVisible( true );
}
} );
}
}

View File

@@ -1,171 +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.channel.map;
import javax.swing.table.AbstractTableModel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.AbstractListModel;
public class ChannelMapModel extends AbstractTableModel
import controller.channel.map.ChannelMapEvent.Event;
import sample.Broadcaster;
import sample.Listener;
public class ChannelMapModel extends AbstractListModel<ChannelMap>
{
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( ChannelMapModel.class );
private static final long serialVersionUID = 1L;
private List<ChannelMap> mChannelMaps = new ArrayList<>();
private Broadcaster<ChannelMapEvent> mEventBroadcaster = new Broadcaster<>();
private static final int sSTART = 0;
private static final int sSTOP = 1;
private static final int sBASE = 2;
private static final int sSIZE = 3;
public ChannelMapModel()
{
}
protected int[] mColumnWidths = { 110, 110, 110, -1 };
/**
* Returns an unmodifiable list of channel maps currently in the model
*/
public List<ChannelMap> getChannelMaps()
{
return Collections.unmodifiableList( mChannelMaps );
}
protected String[] mHeaders = new String[] { "Begin",
"End",
"Base",
"Size" };
private ChannelMap mChannelMap;
public ChannelMapModel( ChannelMap map )
/**
* Returns the channel map with a matching name or null
*/
public ChannelMap getChannelMap( String name )
{
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() )
for( ChannelMap channelMap: mChannelMaps )
{
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();
if( channelMap.getName().equalsIgnoreCase( name ) )
{
return channelMap;
}
}
return null;
}
public boolean isCellEditable( int row, int column )
{
return true;
}
public void setValueAt( Object value, int row, int column )
/**
* Adds a listener to receive notifications when channel map updates occur
*/
public void addListener( Listener<ChannelMapEvent> listener )
{
try
mEventBroadcaster.addListener( listener );
}
/**
* Removes the channel map update notification listener
*/
public void removeListener( Listener<ChannelMapEvent> listener )
{
mEventBroadcaster.removeListener( listener );
}
/**
* Broadcasts a channel map change.
*
* Note: use the add/remove methods to add or remove channel maps from this
* model. When using those methods, an add or delete event will automatically
* be generated.
*/
public void broadcast( ChannelMapEvent event )
{
if( event.getEvent() == ChannelMapEvent.Event.CHANGE ||
event.getEvent() == ChannelMapEvent.Event.RENAME )
{
int parsedValue = Integer.parseInt( (String)value );
int index = mChannelMaps.indexOf( event.getChannelMap() );
ChannelRange range = mChannelMap.getRanges().get( row );
switch( column )
if( index >= 0 )
{
case sSTART:
range.setFirstChannelNumber( parsedValue );
break;
case sSTOP:
range.setLastChannelNumber( parsedValue );
break;
case sBASE:
range.setBase( parsedValue );
break;
case sSIZE:
range.setSize( parsedValue );
break;
fireContentsChanged( this, index, index );
}
}
catch( Exception e )
mEventBroadcaster.broadcast( event );
}
/**
* Adds a list of channel maps to this model
*/
public void addChannelMaps( List<ChannelMap> channelMaps )
{
for( ChannelMap channelMap: channelMaps )
{
mLog.error( "ChannelMapModel - couldn't parse integer value "
+ "for [" + value + "]", e );
addChannelMap( channelMap );
}
}
/**
* Adds the channel map to this model
*/
public void addChannelMap( ChannelMap channelMap )
{
if( !mChannelMaps.contains( channelMap ) )
{
mChannelMaps.add( channelMap );
int index = mChannelMaps.indexOf( channelMap );
fireIntervalAdded( this, index, index );
broadcast( new ChannelMapEvent( channelMap, Event.ADD ) );
}
}
/**
* Removes the channel map from this model
*/
public void removeChannelMap( ChannelMap channelMap )
{
if( mChannelMaps.contains( channelMap ) )
{
int index = mChannelMaps.indexOf( channelMap );
mChannelMaps.remove( channelMap );
fireIntervalRemoved( this, index, index );
broadcast( new ChannelMapEvent( channelMap, Event.DELETE ) );
}
}
/**
* Size/Number of channel maps in this model
*/
@Override
public int getSize()
{
return mChannelMaps.size();
}
/**
* Returns the channel map at the specified index
*/
@Override
public ChannelMap getElementAt( int index )
{
if( index <= mChannelMaps.size() )
{
return mChannelMaps.get( index );
}
return null;
}
}

View File

@@ -1,102 +0,0 @@
/*******************************************************************************
* 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.map;
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;
}
}

View File

@@ -1,6 +1,6 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
* Copyright (C) 2014-2016 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,21 +17,29 @@
******************************************************************************/
package controller.channel.map;
import java.text.DecimalFormat;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
@XmlRootElement
@XmlType( name = "range" )
public class ChannelRange
{
private static final DecimalFormat FREQUENCY_FORMATTER = new DecimalFormat( "#.0000" );
private int mFirst = 1;
private int mLast = 1023;
private int mBase = 450000000;
private int mSize = 12500;
private boolean mOverlapping = false;
/* JAXB requirement - do not remove */
public ChannelRange() {}
public ChannelRange()
{
}
public ChannelRange( int first, int last, int base, int size )
{
@@ -46,11 +54,67 @@ public class ChannelRange
return new ChannelRange( mFirst, mLast, mBase, mSize );
}
public String getDescription()
{
StringBuilder sb = new StringBuilder();
if( isValid() )
{
sb.append( "First: " );
sb.append( mFirst + "=" );
long frequency = getFrequency( mFirst );
sb.append( FREQUENCY_FORMATTER.format( (double)frequency / 1E6D ) );
sb.append( " Last: " );
sb.append( mLast + "=" );
frequency = getFrequency( mLast );
sb.append( FREQUENCY_FORMATTER.format( (double)frequency / 1E6D ) );
sb.append( " MHz" );
}
else
{
sb.append( "First channel must be smaller than last channel" );
}
if( isOverlapping() )
{
if( sb.length() > 0 )
{
sb.append( ", " );
}
sb.append( "Overlap!" );
}
return sb.toString();
}
public boolean isValid()
{
return mFirst < mLast;
}
public boolean overlaps( ChannelRange other )
{
return ( mFirst <= other.mFirst && other.mFirst <= mLast ) ||
( mFirst <= other.mLast && other.mLast <= mLast ) ||
( mFirst <= other.mFirst && other.mLast <= mLast ) ||
( other.mFirst <= mFirst && mLast <= other.mLast );
}
@XmlTransient
public boolean isOverlapping()
{
return mOverlapping;
}
public void setOverlapping( boolean overlapping )
{
mOverlapping = overlapping;
}
public boolean hasChannel( int channel )
{
return mFirst <= channel && channel <= mLast;

View File

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

View File

@@ -1,86 +0,0 @@
/*******************************************************************************
* 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();
}
}

View File

@@ -1,101 +0,0 @@
/*******************************************************************************
* 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 site name" );
}
}
else if( command.contentEquals( "Reset" ) )
{
mTextSite.setText( mSiteNode.getSite().getName() );
}
}
}

View File

@@ -1,168 +0,0 @@
/*******************************************************************************
* 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.Color;
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()
{
return "images/site.png";
}
@Override
public Color getBackgroundColor()
{
@SuppressWarnings( "unchecked" )
Enumeration<DefaultMutableTreeNode> nodes = children();
while( nodes.hasMoreElements() )
{
ChannelNode child = (ChannelNode)nodes.nextElement();
if( child.getBackgroundColor() != null )
{
return Color.CYAN;
}
}
return null;
}
@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;
}
}

View File

@@ -1,85 +0,0 @@
/*******************************************************************************
* 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;
}
}

View File

@@ -1,101 +0,0 @@
/*******************************************************************************
* 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() );
}
}
}

View File

@@ -1,60 +0,0 @@
/*******************************************************************************
* 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();
}
}

View File

@@ -1,85 +0,0 @@
/*******************************************************************************
* 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;
}
}

View File

@@ -1,166 +0,0 @@
/*******************************************************************************
* 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.Color;
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()
{
return "images/system.png";
}
@Override
public Color getBackgroundColor()
{
@SuppressWarnings( "unchecked" )
Enumeration<DefaultMutableTreeNode> nodes = children();
while( nodes.hasMoreElements() )
{
SiteNode child = (SiteNode)nodes.nextElement();
if( child.getBackgroundColor() != null )
{
return Color.CYAN;
}
}
return null;
}
@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;
}
}