diff --git a/src/main/java/io/github/dsheirer/channel/traffic/TrafficChannelManager.java b/src/main/java/io/github/dsheirer/channel/traffic/TrafficChannelManager.java index dcd12ce5..efd9e52c 100644 --- a/src/main/java/io/github/dsheirer/channel/traffic/TrafficChannelManager.java +++ b/src/main/java/io/github/dsheirer/channel/traffic/TrafficChannelManager.java @@ -137,7 +137,7 @@ public class TrafficChannelManager extends Module implements ICallEventProvider, { for(Channel configuredChannel : mTrafficChannelPool) { - if(!configuredChannel.getEnabled()) + if(!configuredChannel.isProcessing()) { channel = configuredChannel; break; @@ -207,7 +207,7 @@ public class TrafficChannelManager extends Module implements ICallEventProvider, //Request to enable the channel mChannelModel.broadcast(trafficChannelEvent); - if(channel.getEnabled()) + if(channel.isProcessing()) { mTrafficChannelsInUse.put(callEvent.getChannel(), channel); } diff --git a/src/main/java/io/github/dsheirer/controller/channel/AutoStartChannelModel.java b/src/main/java/io/github/dsheirer/controller/channel/AutoStartChannelModel.java new file mode 100644 index 00000000..403a2fc7 --- /dev/null +++ b/src/main/java/io/github/dsheirer/controller/channel/AutoStartChannelModel.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * sdr-trunk + * Copyright (C) 2014-2018 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 + * + ******************************************************************************/ +package io.github.dsheirer.controller.channel; + +import javax.swing.table.AbstractTableModel; +import java.util.List; + +/** + * Auto-Start Channel Model + */ +public class AutoStartChannelModel extends AbstractTableModel +{ + private static final long serialVersionUID = 1L; + + public static final int COLUMN_ORDER = 0; + public static final int COLUMN_SYSTEM = 1; + public static final int COLUMN_SITE = 2; + public static final int COLUMN_NAME = 3; + public static final int COLUMN_DECODER = 4; + + private static final String[] COLUMN_NAMES = new String[] {"Order", "System", "Site", "Name", "Decoder"}; + + private List mChannels; + + public AutoStartChannelModel(List autoStartChannels) + { + mChannels = autoStartChannels; + } + + @Override + public int getRowCount() + { + return mChannels.size(); + } + + @Override + public int getColumnCount() + { + return COLUMN_NAMES.length; + } + + @Override + public String getColumnName(int columnIndex) + { + if(columnIndex < COLUMN_NAMES.length) + { + return COLUMN_NAMES[columnIndex]; + } + + 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 COLUMN_ORDER: + return channel.getAutoStartOrder(); + case COLUMN_SYSTEM: + return channel.getSystem(); + case COLUMN_SITE: + return channel.getSite(); + case COLUMN_NAME: + return channel.getName(); + case COLUMN_DECODER: + return channel.getDecodeConfiguration().getDecoderType().getShortDisplayString(); + } + + return null; + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) + { + throw new IllegalArgumentException("Not yet implemented"); + } +} diff --git a/src/main/java/io/github/dsheirer/controller/channel/Channel.java b/src/main/java/io/github/dsheirer/controller/channel/Channel.java index 9c0cee7f..4927f68d 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/Channel.java +++ b/src/main/java/io/github/dsheirer/controller/channel/Channel.java @@ -1,6 +1,6 @@ /******************************************************************************* * sdrtrunk - * Copyright (C) 2014-2017 Dennis Sheirer + * Copyright (C) 2014-2018 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 @@ -45,18 +45,18 @@ import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent.Event; public class Channel extends Configuration implements Listener { // Standard channels are persisted and traffic channels are temporary - public enum ChannelType {STANDARD, TRAFFIC} + public enum ChannelType + { + STANDARD, TRAFFIC + } // Static unique channel identifier tracking private static int UNIQUE_ID = 0; private DecodeConfiguration mDecodeConfiguration = DecoderFactory.getDefaultDecodeConfiguration(); - private AuxDecodeConfiguration mAuxDecodeConfiguration = - new AuxDecodeConfiguration(); - private SourceConfiguration mSourceConfiguration = - SourceConfigFactory.getDefaultSourceConfiguration(); - private EventLogConfiguration mEventLogConfiguration = - new EventLogConfiguration(); + private AuxDecodeConfiguration mAuxDecodeConfiguration = new AuxDecodeConfiguration(); + private SourceConfiguration mSourceConfiguration = SourceConfigFactory.getDefaultSourceConfiguration(); + private EventLogConfiguration mEventLogConfiguration = new EventLogConfiguration(); private RecordConfiguration mRecordConfiguration = new RecordConfiguration(); private String mAliasListName; @@ -64,7 +64,9 @@ public class Channel extends Configuration implements Listener + * + ******************************************************************************/ +package io.github.dsheirer.controller.channel; + +import io.github.dsheirer.module.decode.p25.DecodeConfigP25Phase1; +import io.github.dsheirer.util.ThreadPool; +import net.miginfocom.swing.MigLayout; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +public class ChannelAutoStartFrame extends JFrame +{ + private final static Logger mLog = LoggerFactory.getLogger(ChannelAutoStartFrame.class); + + private static final int COUNTDOWN_SECONDS = 10; + private ChannelEventListener mChannelEventListener; + private List mChannels; + + private JLabel mCountdownLabel; + private JButton mStartButton; + private JButton mCancelButton; + private JTable mChannelTable; + private AtomicBoolean mChannelsStarted = new AtomicBoolean(); + + private ScheduledFuture mTimerFuture; + + /** + * Creates and displays a channel auto-start gui for presenting the user with a list of channels that + * will be automatically started once the countdown timer reaches zero, or the user chooses to start + * now or cancel. + * + * @param listener to receive channel start/enable request(s) + * @param channels to auto-start + */ + public ChannelAutoStartFrame(ChannelEventListener listener, List channels) + { + mChannelEventListener = listener; + mChannels = channels; + init(); + + EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + setVisible(true); + startTimer(); + } + }); + } + + private void init() + { + setTitle("Auto-Start Channels"); + setSize(new Dimension(400,300)); + setLocationRelativeTo(null); + addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent event) + { + mLog.info("Channel auto-start canceled by user - window closed"); + stopTimer(); + super.windowClosing(event); + } + }); + + JPanel panel = new JPanel(); + panel.setLayout(new MigLayout("","[grow,fill][grow,fill]", + "[][][grow,fill][]")); + panel.add(new JLabel("The following channels will be automatically"), "span"); + + mCountdownLabel = new JLabel(getCountdownText(COUNTDOWN_SECONDS)); + panel.add(mCountdownLabel, "span"); + + panel.add(new JScrollPane(getChannelTable()), "span"); + + mStartButton = new JButton("Start Now"); + mStartButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + mLog.info("Starting [" + mChannels.size() + "] channels now - user invoked"); + startChannels(); + stopTimer(); + } + }); + panel.add(mStartButton); + + mCancelButton = new JButton("Cancel"); + mCancelButton.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + mLog.info("Channel auto-start canceled by user"); + stopTimer(); + } + }); + panel.add(mCancelButton); + setContentPane(panel); + } + + private String getCountdownText(int value) + { + return "started in: " + value + " seconds."; + } + + /** + * Updates the countdown text label on the swing event thread + * @param value for the countdown + */ + private void updateCountdownText(final int value) + { + EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + mCountdownLabel.setText(getCountdownText(value)); + } + }); + } + + /** + * Creates (once) a table of auto-start channels + */ + private JTable getChannelTable() + { + if(mChannelTable == null) + { + AutoStartChannelModel model = new AutoStartChannelModel(mChannels); + mChannelTable = new JTable(model); + } + + return mChannelTable; + } + + /** + * Sends an enable (ie start) request for each of the auto start channels. + * + * This method is thread-safe and will only be executed once. + * + * Although the redundant channel-start request would be ignored, this once-only will prevent the chance + * that both the timer and the user would attempt to start the channels at the same time. + */ + private void startChannels() + { + if(mChannelsStarted.compareAndSet(false, true)) + { + if(mChannelEventListener != null) + { + for(Channel channel: mChannels) + { + mChannelEventListener.channelChanged(new ChannelEvent(channel, ChannelEvent.Event.REQUEST_ENABLE)); + } + } + } + } + + /** + * Starts the countdown timer to fire once a second. + */ + private void startTimer() + { + if(mTimerFuture == null) + { + mTimerFuture = ThreadPool.SCHEDULED.scheduleAtFixedRate(new CountdownTimer(), 0, 1, TimeUnit.SECONDS); + } + } + + /** + * Stops the countdown timer and disposes this frame + */ + private void stopTimer() + { + if(mTimerFuture != null) + { + mTimerFuture.cancel(true); + mTimerFuture = null; + } + + EventQueue.invokeLater(new Runnable() + { + @Override + public void run() + { + dispose(); + } + }); + } + + /** + * Updates the countdown text and auto-starts the channels once the timer falls below zero. + */ + public class CountdownTimer implements Runnable + { + private int mCount = COUNTDOWN_SECONDS; + + @Override + public void run() + { + if(mCount >= 0) + { + updateCountdownText(mCount); + mCount--; + } + else + { + mLog.info("Starting [" + mChannels.size() + "] now - timer invoked"); + startChannels(); + stopTimer(); + } + } + } + + public static void main(String[] args) + { + List channels = new ArrayList<>(); + Channel channel1 = new Channel(); + channel1.setSystem("A System"); + channel1.setSite("My Site"); + channel1.setName("Channel 1 Name"); + channel1.setDecodeConfiguration(new DecodeConfigP25Phase1()); + channels.add(channel1); + + Channel channel2 = new Channel(); + channel2.setSystem("B System"); + channel2.setSite("My Site2"); + channel2.setName("Channel 2 Name"); + channel2.setDecodeConfiguration(new DecodeConfigP25Phase1()); + channel2.setAutoStartOrder(2); + channels.add(channel2); + + Channel channel3 = new Channel(); + channel3.setSystem("C System"); + channel3.setSite("My Site3"); + channel3.setName("Channel 3 Name"); + channel3.setDecodeConfiguration(new DecodeConfigP25Phase1()); + channel3.setAutoStartOrder(1); + channels.add(channel3); + + ChannelEventListener listener = new ChannelEventListener() + { + @Override + public void channelChanged(ChannelEvent event) + { + mLog.debug("Channel Event: " + event); + } + }; + + ChannelAutoStartFrame frame = new ChannelAutoStartFrame(listener, channels); + } +} diff --git a/src/main/java/io/github/dsheirer/controller/channel/ChannelController.java b/src/main/java/io/github/dsheirer/controller/channel/ChannelController.java index 24ae4915..de1b7cde 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/ChannelController.java +++ b/src/main/java/io/github/dsheirer/controller/channel/ChannelController.java @@ -8,11 +8,19 @@ import net.coderazzi.filters.gui.AutoChoices; import net.coderazzi.filters.gui.TableFilterHeader; import net.miginfocom.swing.MigLayout; -import javax.swing.*; +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 java.awt.*; +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; @@ -236,7 +244,7 @@ public class ChannelController extends JPanel Channel channel = model.getChannelAtIndex( index ); - boolean enabled = channel.getEnabled(); + boolean enabled = channel.isProcessing(); if( isSelected ) { diff --git a/src/main/java/io/github/dsheirer/controller/channel/ChannelEditor.java b/src/main/java/io/github/dsheirer/controller/channel/ChannelEditor.java index 9f28bf69..65d2cade 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/ChannelEditor.java +++ b/src/main/java/io/github/dsheirer/controller/channel/ChannelEditor.java @@ -1,17 +1,17 @@ /******************************************************************************* * 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 ******************************************************************************/ @@ -30,221 +30,227 @@ import io.github.dsheirer.source.SourceConfigurationEditor; import io.github.dsheirer.source.SourceManager; import net.miginfocom.swing.MigLayout; -import javax.swing.*; -import java.awt.*; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class ChannelEditor extends Editor implements ActionListener, ChannelEventListener { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; + private static final String ACTION_START = "Start"; + private static final String ACTION_STOP = "Stop"; + private static final String ACTION_SAVE = "Save"; + private static final String ACTION_RESET = "Reset"; - private NameConfigurationEditor mNameConfigurationEditor; + private NameConfigurationEditor mNameConfigurationEditor; private SourceConfigurationEditor mSourceConfigurationEditor; private DecodeConfigurationEditor mDecodeConfigurationEditor; private AuxDecodeConfigurationEditor mAuxDecodeConfigurationEditor; private EventLogConfigurationEditor mEventLogConfigurationEditor; private RecordConfigurationEditor mRecordConfigurationEditor; - - private JButton mEnableButton = new JButton( "Enable" ); - private JLabel mChannelName = new JLabel( "Channel:" ); - - private ChannelModel mChannelModel; - private ChannelMapModel mChannelMapModel; + + private JButton mProcessingStateButton = new JButton(ACTION_START); + private JLabel mChannelName = new JLabel("Channel:"); + + private ChannelModel mChannelModel; + private ChannelMapModel mChannelMapModel; private SourceManager mSourceManager; - - private boolean mChannelEnableRequested = false; - - public ChannelEditor( ChannelModel channelModel, - ChannelMapModel channelMapModel, - SourceManager sourceManager, - AliasModel aliasModel ) - { - mChannelModel = channelModel; - mChannelMapModel = channelMapModel; - mSourceManager = sourceManager; - mNameConfigurationEditor = new NameConfigurationEditor( aliasModel, mChannelModel ); - - init(); - } - - private void init() - { - setLayout( new MigLayout( "fill,wrap 3", "[grow,fill][grow,fill][grow,fill]", "[grow,fill][]" ) ); - - JideTabbedPane tabs = new JideTabbedPane(); - tabs.setFont( this.getFont() ); - tabs.setForeground( Color.BLACK ); - tabs.setTabTrailingComponent( mChannelName ); - - mNameConfigurationEditor.setSaveRequestListener( this ); - tabs.addTab( "Name/Alias", mNameConfigurationEditor ); - - mSourceConfigurationEditor = new SourceConfigurationEditor( mSourceManager ); - mSourceConfigurationEditor.setSaveRequestListener( this ); - tabs.addTab( "Source", mSourceConfigurationEditor ); - - mDecodeConfigurationEditor = new DecodeConfigurationEditor( mChannelMapModel ); - mDecodeConfigurationEditor.setSaveRequestListener( this ); - tabs.addTab( "Decoder", mDecodeConfigurationEditor ); + private boolean mChannelStartRequested = false; - mAuxDecodeConfigurationEditor = new AuxDecodeConfigurationEditor(); - mAuxDecodeConfigurationEditor.setSaveRequestListener( this ); - tabs.addTab( "Aux Decoders", mAuxDecodeConfigurationEditor ); - - mEventLogConfigurationEditor = new EventLogConfigurationEditor(); - mEventLogConfigurationEditor.setSaveRequestListener( this ); - tabs.addTab( "Logging", mEventLogConfigurationEditor ); - - 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 ); - - JButton btnSave = new JButton( "Save" ); - btnSave.setToolTipText( "Save changes to the currently selected channel" ); - btnSave.addActionListener( ChannelEditor.this ); - add( btnSave ); - - JButton btnReset = new JButton( "Reset" ); - btnReset.setToolTipText( "Reload the currently selected channel" ); - btnReset.addActionListener( ChannelEditor.this ); - 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 - public void actionPerformed( ActionEvent e ) + public ChannelEditor(ChannelModel channelModel, + ChannelMapModel channelMapModel, + SourceManager sourceManager, + AliasModel aliasModel) { - String command = e.getActionCommand(); - - if( command.contentEquals( "Enable" ) ) - { - if( hasItem() ) - { - save(); - - mChannelEnableRequested = true; - mChannelModel.broadcast( new ChannelEvent( getItem(), ChannelEvent.Event.REQUEST_ENABLE ) ); - } - } - else if( command.contentEquals( "Disable" ) ) - { - if( hasItem() ) - { - mChannelModel.broadcast( new ChannelEvent( getItem(), ChannelEvent.Event.REQUEST_DISABLE ) ); - } - } - else if( command.contentEquals( "Save" ) ) - { - save(); - } - else if( command.contentEquals( "Reset" ) ) - { - setItem( getItem() ); - } + mChannelModel = channelModel; + mChannelMapModel = channelMapModel; + mSourceManager = sourceManager; + mNameConfigurationEditor = new NameConfigurationEditor(aliasModel, mChannelModel); + + init(); + } + + private void init() + { + setLayout(new MigLayout("fill,wrap 3", "[grow,fill][grow,fill][grow,fill]", "[grow,fill][]")); + + JideTabbedPane tabs = new JideTabbedPane(); + tabs.setFont(this.getFont()); + tabs.setForeground(Color.BLACK); + + tabs.setTabTrailingComponent(mChannelName); + + mNameConfigurationEditor.setSaveRequestListener(this); + tabs.addTab("Name/Alias", mNameConfigurationEditor); + + mSourceConfigurationEditor = new SourceConfigurationEditor(mSourceManager); + mSourceConfigurationEditor.setSaveRequestListener(this); + tabs.addTab("Source", mSourceConfigurationEditor); + + mDecodeConfigurationEditor = new DecodeConfigurationEditor(mChannelMapModel); + mDecodeConfigurationEditor.setSaveRequestListener(this); + tabs.addTab("Decoder", mDecodeConfigurationEditor); + + mAuxDecodeConfigurationEditor = new AuxDecodeConfigurationEditor(); + mAuxDecodeConfigurationEditor.setSaveRequestListener(this); + tabs.addTab("Aux Decoders", mAuxDecodeConfigurationEditor); + + mEventLogConfigurationEditor = new EventLogConfigurationEditor(); + mEventLogConfigurationEditor.setSaveRequestListener(this); + tabs.addTab("Logging", mEventLogConfigurationEditor); + + mRecordConfigurationEditor = new RecordConfigurationEditor(); + mRecordConfigurationEditor.setSaveRequestListener(this); + tabs.addTab("Recording", mRecordConfigurationEditor); + + add(tabs, "span"); + + mProcessingStateButton.addActionListener(this); + mProcessingStateButton.setEnabled(false); + mProcessingStateButton.setToolTipText("Start/Stop the currently selected channel"); + add(mProcessingStateButton); + + JButton btnSave = new JButton(ACTION_SAVE); + btnSave.setToolTipText("Save changes to the currently selected channel"); + btnSave.addActionListener(ChannelEditor.this); + add(btnSave); + + JButton btnReset = new JButton(ACTION_RESET); + btnReset.setToolTipText("Reload the currently selected channel"); + btnReset.addActionListener(ChannelEditor.this); + 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()); + mChannelStartRequested = false; + break; + case NOTIFICATION_DELETE: + setItem(null); + break; + case NOTIFICATION_START_PROCESSING_REJECTED: + if(mChannelStartRequested) + { + JOptionPane.showMessageDialog(ChannelEditor.this, "Channel could not be " + + "started. This is likely because there are no tuner channels " + + "available", "Couldn't start channel", JOptionPane.INFORMATION_MESSAGE); + + mChannelStartRequested = false; + } + break; + default: + break; + } + } + } + + @Override + public void actionPerformed(ActionEvent e) + { + String command = e.getActionCommand(); + + if(command.contentEquals(ACTION_START)) + { + if(hasItem()) + { + save(); + + mChannelStartRequested = true; + mChannelModel.broadcast(new ChannelEvent(getItem(), ChannelEvent.Event.REQUEST_ENABLE)); + } + } + else if(command.contentEquals(ACTION_STOP)) + { + if(hasItem()) + { + mChannelModel.broadcast(new ChannelEvent(getItem(), ChannelEvent.Event.REQUEST_DISABLE)); + } + } + else if(command.contentEquals(ACTION_SAVE)) + { + save(); + } + else if(command.contentEquals(ACTION_RESET)) + { + setItem(getItem()); + } + } + + /** + * Sets the channel configuration in each of the channel editor components + * Note: this method must be invoked on the swing event dispatch thread + */ + public void setItem(final Channel channel) + { + 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()); + mProcessingStateButton.setText(channel.isProcessing() ? ACTION_STOP : ACTION_START); + mProcessingStateButton.setEnabled(true); + mProcessingStateButton.setBackground(channel.isProcessing() ? Color.GREEN : getBackground()); + } + else + { + mChannelName.setText("Channel: "); + mProcessingStateButton.setText(ACTION_START); + mProcessingStateButton.setEnabled(false); + mProcessingStateButton.setBackground(getBackground()); + } } - /** - * Sets the channel configuration in each of the channel editor components - * Note: this method must be invoked on the swing event dispatch thread - */ - public void setItem( final Channel channel ) - { - 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; - } - + if(hasItem()) + { + mNameConfigurationEditor.save(); + mSourceConfigurationEditor.save(); + mDecodeConfigurationEditor.save(); + mAuxDecodeConfigurationEditor.save(); + mEventLogConfigurationEditor.save(); + mRecordConfigurationEditor.save(); - mChannelModel.broadcast( new ChannelEvent( getItem(), - ChannelEvent.Event.NOTIFICATION_CONFIGURATION_CHANGE ) ); - } + try + { + mDecodeConfigurationEditor.validate(mSourceConfigurationEditor); + mDecodeConfigurationEditor.validate(mAuxDecodeConfigurationEditor); + } + catch(EditorValidationException e) + { + e.getEditor().requestFocus(); - setModified( false ); + JOptionPane.showMessageDialog(e.getEditor(), e.getReason(), + "Configuration Error", JOptionPane.ERROR_MESSAGE); + + return; + } + + + mChannelModel.broadcast(new ChannelEvent(getItem(), + ChannelEvent.Event.NOTIFICATION_CONFIGURATION_CHANGE)); + } + + setModified(false); } } diff --git a/src/main/java/io/github/dsheirer/controller/channel/ChannelEvent.java b/src/main/java/io/github/dsheirer/controller/channel/ChannelEvent.java index fc778521..42679a38 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/ChannelEvent.java +++ b/src/main/java/io/github/dsheirer/controller/channel/ChannelEvent.java @@ -1,6 +1,6 @@ /******************************************************************************* * SDR Trunk - * Copyright (C) 2014-2016 Dennis Sheirer + * Copyright (C) 2014-2018 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 @@ -42,6 +42,11 @@ public class ChannelEvent { return mEvent; } + + public String toString() + { + return getEvent().name() + " Channel:" + getChannel().getName(); + } /** * Channel events to describe the specific event @@ -55,7 +60,7 @@ public class ChannelEvent //Channel is deleted/removed NOTIFICATION_DELETE, //Channel enable request was rejected - NOTIFICATION_ENABLE_REJECTED, + NOTIFICATION_START_PROCESSING_REJECTED, //Channel has started processing/decoding NOTIFICATION_PROCESSING_START, //Channel has stopped processing/decoding diff --git a/src/main/java/io/github/dsheirer/controller/channel/ChannelModel.java b/src/main/java/io/github/dsheirer/controller/channel/ChannelModel.java index 8b0d2516..30939c9c 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/ChannelModel.java +++ b/src/main/java/io/github/dsheirer/controller/channel/ChannelModel.java @@ -25,6 +25,7 @@ import io.github.dsheirer.module.decode.DecoderType; import javax.swing.table.AbstractTableModel; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -42,9 +43,11 @@ public class ChannelModel extends AbstractTableModel implements IChannelEventBro public static final int COLUMN_ALIAS_LIST = 4; public static final int COLUMN_SOURCE = 5; public static final int COLUMN_DECODER = 6; + public static final int COLUMN_AUTO_START = 7; - private static final String[] COLUMN_NAMES = new String[] {"Enabled", "System", "Site", "Name", "Alias List", - "Source", "Decoder"}; + private static final String[] COLUMN_NAMES = new String[] {"Playing", "System", "Site", "Name", "Alias List", + "Source", "Decoder", "Auto-Start"}; + private static final String VALUE_YES = "Yes"; private List mChannels = new CopyOnWriteArrayList<>(); private List mTrafficChannels = new CopyOnWriteArrayList<>(); @@ -209,11 +212,6 @@ public class ChannelModel extends AbstractTableModel implements IChannelEventBro broadcast(new ChannelEvent(channel, Event.NOTIFICATION_ADD)); - if(channel.getEnabled()) - { - broadcast(new ChannelEvent(channel, Event.REQUEST_ENABLE)); - } - return index; } @@ -247,6 +245,48 @@ public class ChannelModel extends AbstractTableModel implements IChannelEventBro } } + /** + * List of channels that have the auto-start flag set. + * + * @return auto-start channels sorted by the channel order value. + */ + public List getAutoStartChannels() + { + List autoStartChannels = new ArrayList<>(); + + for(Channel channel: getChannels()) + { + if(channel.isAutoStart()) + { + autoStartChannels.add(channel); + } + } + + Collections.sort(autoStartChannels, new Comparator() + { + @Override + public int compare(Channel channel1, Channel channel2) + { + if(channel1.hasAutoStartOrder() && channel2.hasAutoStartOrder()) + { + return Integer.compare(channel1.getAutoStartOrder(), channel2.getAutoStartOrder()); + } + else if(channel1.hasAutoStartOrder()) + { + return -1; + } + else if(channel2.hasAutoStartOrder()) + { + return 1; + } + + return 0; + } + }); + + return autoStartChannels; + } + /** * Returns a list of channels that fall within the frequency range * @@ -331,7 +371,7 @@ public class ChannelModel extends AbstractTableModel implements IChannelEventBro switch(columnIndex) { case COLUMN_ENABLED: - return channel.getEnabled() ? "Enabled" : null; + return channel.isProcessing() ? VALUE_YES : null; case COLUMN_SYSTEM: return channel.getSystem(); case COLUMN_SITE: @@ -344,6 +384,19 @@ public class ChannelModel extends AbstractTableModel implements IChannelEventBro return channel.getSourceConfiguration().getDescription(); case COLUMN_DECODER: return channel.getDecodeConfiguration().getDecoderType().getShortDisplayString(); + case COLUMN_AUTO_START: + if(channel.isAutoStart()) + { + if(channel.hasAutoStartOrder()) + { + return channel.getAutoStartOrder(); + } + else + { + return VALUE_YES; + } + } + break; } return null; diff --git a/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java b/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java index ee4a232d..c456b8e6 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java +++ b/src/main/java/io/github/dsheirer/controller/channel/ChannelProcessingManager.java @@ -159,7 +159,7 @@ public class ChannelProcessingManager implements ChannelEventListener } break; case REQUEST_DISABLE: - if(channel.getEnabled()) + if(channel.isProcessing()) { switch(channel.getChannelType()) { @@ -176,7 +176,7 @@ public class ChannelProcessingManager implements ChannelEventListener } } case NOTIFICATION_DELETE: - if(channel.getEnabled()) + if(channel.isProcessing()) { stopProcessing(channel, true); } @@ -220,9 +220,9 @@ public class ChannelProcessingManager implements ChannelEventListener if(source == null) { - channel.setEnabled(false); + channel.setProcessing(false); - mChannelModel.broadcast(new ChannelEvent(channel, ChannelEvent.Event.NOTIFICATION_ENABLE_REJECTED)); + mChannelModel.broadcast(new ChannelEvent(channel, ChannelEvent.Event.NOTIFICATION_START_PROCESSING_REJECTED)); return; } @@ -325,7 +325,7 @@ public class ChannelProcessingManager implements ChannelEventListener getChannelMetadataModel().add(processingChain.getChannelState().getMutableMetadata(), channel); - channel.setEnabled(true); + channel.setProcessing(true); mProcessingChains.put(channel.getChannelID(), processingChain); @@ -334,7 +334,7 @@ public class ChannelProcessingManager implements ChannelEventListener private void stopProcessing(Channel channel, boolean remove) { - channel.setEnabled(false); + channel.setProcessing(false); if(mProcessingChains.containsKey(channel.getChannelID())) { diff --git a/src/main/java/io/github/dsheirer/controller/channel/ChannelUtils.java b/src/main/java/io/github/dsheirer/controller/channel/ChannelUtils.java index 657b65e4..69cff222 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/ChannelUtils.java +++ b/src/main/java/io/github/dsheirer/controller/channel/ChannelUtils.java @@ -4,8 +4,11 @@ import io.github.dsheirer.channel.state.DecoderState; import io.github.dsheirer.module.ProcessingChain; import io.github.dsheirer.module.decode.event.ActivitySummaryFrame; -import javax.swing.*; -import java.awt.*; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JSeparator; +import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -23,7 +26,7 @@ public class ChannelUtils { JMenu menu = new JMenu( "Channel: " + channel.getName() ); - if( channel.getEnabled() ) + if( channel.isProcessing() ) { JMenuItem disable = new JMenuItem( "Disable" ); disable.addActionListener( new ActionListener() diff --git a/src/main/java/io/github/dsheirer/controller/channel/NameConfigurationEditor.java b/src/main/java/io/github/dsheirer/controller/channel/NameConfigurationEditor.java index 9d07aa73..94e0090d 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/NameConfigurationEditor.java +++ b/src/main/java/io/github/dsheirer/controller/channel/NameConfigurationEditor.java @@ -23,9 +23,21 @@ import net.miginfocom.swing.MigLayout; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.swing.*; +import javax.swing.ComboBoxModel; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.JTextField; +import javax.swing.SpinnerModel; +import javax.swing.SpinnerNumberModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; +import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collections; @@ -48,6 +60,8 @@ public class NameConfigurationEditor extends Editor implements Document private JComboBox mSystemNameCombo; private JComboBox mSiteNameCombo; private JComboBox mAliasListCombo; + private JCheckBox mAutoStartCheckBox; + private JSpinner mAutoStartOrder; public NameConfigurationEditor(AliasModel aliasModel, ChannelModel model) { @@ -139,6 +153,40 @@ public class NameConfigurationEditor extends Editor implements Document add(new JLabel("Site:")); add(mSiteNameCombo); + + JPanel autoStartPanel = new JPanel(); + + mAutoStartCheckBox = new JCheckBox("Auto-Start"); + mAutoStartCheckBox.setToolTipText("Automatically start this channel each time the application runs."); + mAutoStartCheckBox.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + mAutoStartOrder.setEnabled(mAutoStartCheckBox.isSelected()); + setModified(true); + } + }); + autoStartPanel.add(mAutoStartCheckBox); + + SpinnerModel model = new SpinnerNumberModel(0,0,500,1); + mAutoStartOrder = new JSpinner(model); + mAutoStartOrder.setEnabled(false); + mAutoStartOrder.setPreferredSize(new Dimension(60, mAutoStartOrder.getPreferredSize().height)); + mAutoStartOrder.setToolTipText("Auto-start order: 1 (high) <> 500 (low). 0 = no ordering"); + mAutoStartOrder.addChangeListener(new ChangeListener() + { + @Override + public void stateChanged(ChangeEvent e) + { + setModified(true); + } + }); + + autoStartPanel.add(new JLabel("Order:")); + autoStartPanel.add(mAutoStartOrder); + add(new JLabel()); //Empty space holder + add(autoStartPanel); } @Override @@ -156,6 +204,11 @@ public class NameConfigurationEditor extends Editor implements Document Object aliasList = mAliasListCombo.getSelectedItem(); getItem().setAliasListName(aliasList == null ? null : (String)aliasList); + + getItem().setAutoStart(mAutoStartCheckBox.isSelected()); + + int order = ((Number)mAutoStartOrder.getValue()).intValue(); + getItem().setAutoStartOrder((order > 0 ? order : null)); } setModified(false); @@ -182,6 +235,16 @@ public class NameConfigurationEditor extends Editor implements Document { mSiteNameCombo.setEnabled(enabled); } + + if(mAutoStartCheckBox.isEnabled() != enabled) + { + mAutoStartCheckBox.setEnabled(enabled); + } + + if(mAutoStartOrder.isEnabled() != enabled) + { + mAutoStartOrder.setEnabled(enabled); + } } @Override @@ -244,6 +307,19 @@ public class NameConfigurationEditor extends Editor implements Document mChannelName.setText(null); } + if(channel.isAutoStart()) + { + mAutoStartCheckBox.setSelected(channel.isAutoStart()); + mAutoStartOrder.setEnabled(true); + } + else + { + mAutoStartCheckBox.setSelected(false); + mAutoStartOrder.setEnabled(false); + } + + mAutoStartOrder.setValue(channel.hasAutoStartOrder() ? channel.getAutoStartOrder() : 0); + setModified(false); } diff --git a/src/main/java/io/github/dsheirer/gui/SDRTrunk.java b/src/main/java/io/github/dsheirer/gui/SDRTrunk.java index 79cedda4..b6d6b6d8 100644 --- a/src/main/java/io/github/dsheirer/gui/SDRTrunk.java +++ b/src/main/java/io/github/dsheirer/gui/SDRTrunk.java @@ -25,6 +25,8 @@ import io.github.dsheirer.audio.AudioManager; import io.github.dsheirer.audio.broadcast.BroadcastModel; import io.github.dsheirer.audio.broadcast.BroadcastStatusPanel; import io.github.dsheirer.controller.ControllerPanel; +import io.github.dsheirer.controller.channel.Channel; +import io.github.dsheirer.controller.channel.ChannelAutoStartFrame; import io.github.dsheirer.controller.channel.ChannelModel; import io.github.dsheirer.controller.channel.ChannelProcessingManager; import io.github.dsheirer.controller.channel.ChannelSelectionManager; @@ -51,8 +53,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.imageio.ImageIO; -import javax.swing.*; -import java.awt.*; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JSeparator; +import javax.swing.KeyStroke; +import java.awt.AWTException; +import java.awt.Desktop; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Robot; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; @@ -61,6 +74,7 @@ import java.io.IOException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; public class SDRTrunk implements Listener { @@ -72,6 +86,8 @@ public class SDRTrunk implements Listener private BroadcastStatusPanel mBroadcastStatusPanel; private BroadcastModel mBroadcastModel; private ControllerPanel mControllerPanel; + private ChannelModel mChannelModel; + private ChannelProcessingManager mChannelProcessingManager; private SettingsManager mSettingsManager; private SpectralDisplayPanel mSpectralPanel; private JFrame mMainGui = new JFrame(); @@ -117,7 +133,7 @@ public class SDRTrunk implements Listener AliasModel aliasModel = new AliasModel(); - ChannelModel channelModel = new ChannelModel(); + mChannelModel = new ChannelModel(); ChannelMapModel channelMapModel = new ChannelMapModel(); @@ -127,43 +143,42 @@ public class SDRTrunk implements Listener SourceManager sourceManager = new SourceManager(tunerModel, mSettingsManager); - ChannelProcessingManager channelProcessingManager = new ChannelProcessingManager( - channelModel, channelMapModel, aliasModel, eventLogManager, recorderManager, sourceManager); - channelProcessingManager.addAudioPacketListener(recorderManager); + mChannelProcessingManager = new ChannelProcessingManager(mChannelModel, channelMapModel, aliasModel, + eventLogManager, recorderManager, sourceManager); + mChannelProcessingManager.addAudioPacketListener(recorderManager); - channelModel.addListener(channelProcessingManager); + mChannelModel.addListener(mChannelProcessingManager); ChannelSelectionManager channelSelectionManager = - new ChannelSelectionManager(channelModel); - channelModel.addListener(channelSelectionManager); + new ChannelSelectionManager(mChannelModel); + mChannelModel.addListener(channelSelectionManager); AliasActionManager aliasActionManager = new AliasActionManager(); - channelProcessingManager.addMessageListener(aliasActionManager); + mChannelProcessingManager.addMessageListener(aliasActionManager); AudioManager audioManager = new AudioManager(sourceManager.getMixerManager()); - channelProcessingManager.addAudioPacketListener(audioManager); + mChannelProcessingManager.addAudioPacketListener(audioManager); mBroadcastModel = new BroadcastModel(mIconManager); - channelProcessingManager.addAudioPacketListener(mBroadcastModel); + mChannelProcessingManager.addAudioPacketListener(mBroadcastModel); MapService mapService = new MapService(mIconManager); - channelProcessingManager.addMessageListener(mapService); + mChannelProcessingManager.addMessageListener(mapService); mControllerPanel = new ControllerPanel(audioManager, aliasModel, mBroadcastModel, - channelModel, channelMapModel, channelProcessingManager, mIconManager, + mChannelModel, channelMapModel, mChannelProcessingManager, mIconManager, mapService, mSettingsManager, sourceManager, tunerModel); - mSpectralPanel = new SpectralDisplayPanel(channelModel, - channelProcessingManager, mSettingsManager); + mSpectralPanel = new SpectralDisplayPanel(mChannelModel, + mChannelProcessingManager, mSettingsManager); - TunerSpectralDisplayManager tunerSpectralDisplayManager = - new TunerSpectralDisplayManager(mSpectralPanel, - channelModel, channelProcessingManager, mSettingsManager); + TunerSpectralDisplayManager tunerSpectralDisplayManager = new TunerSpectralDisplayManager(mSpectralPanel, + mChannelModel, mChannelProcessingManager, mSettingsManager); tunerModel.addListener(tunerSpectralDisplayManager); tunerModel.addListener(this); - PlaylistManager playlistManager = new PlaylistManager(aliasModel, mBroadcastModel, channelModel, + PlaylistManager playlistManager = new PlaylistManager(aliasModel, mBroadcastModel, mChannelModel, channelMapModel); playlistManager.init(); @@ -183,6 +198,7 @@ public class SDRTrunk implements Listener try { mMainGui.setVisible(true); + autoStartChannels(); } catch(Exception e) { @@ -192,6 +208,21 @@ public class SDRTrunk implements Listener }); } + /** + * Shows a dialog that lists the channels that have been designated for auto-start, sorted by auto-start order and + * allows the user to start now, cancel, or allow the timer to expire and then start the channels. The dialog will + * only show if there are one ore more channels designated for auto-start. + */ + private void autoStartChannels() + { + List channels = mChannelModel.getAutoStartChannels(); + + if(channels.size() > 0) + { + ChannelAutoStartFrame autoStartFrame = new ChannelAutoStartFrame(mChannelProcessingManager, channels); + } + } + /** * Launch the application. */ @@ -212,7 +243,8 @@ public class SDRTrunk implements Listener */ mTitle = SystemProperties.getInstance().getApplicationName(); mMainGui.setTitle(mTitle); - mMainGui.setBounds(100, 100, 1280, 800); + mMainGui.setSize(new Dimension(1280,800)); + mMainGui.setLocationRelativeTo(null); mMainGui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Set preferred sizes to influence the split diff --git a/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java b/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java index 7b7bf9d0..ff383ac1 100644 --- a/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java +++ b/src/main/java/io/github/dsheirer/spectrum/ChannelSpectrumPanel.java @@ -30,8 +30,13 @@ import io.github.dsheirer.spectrum.menu.SmoothingItem; import io.github.dsheirer.spectrum.menu.SmoothingTypeItem; import net.miginfocom.swing.MigLayout; -import javax.swing.*; -import java.awt.*; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JSeparator; +import javax.swing.SwingUtilities; +import java.awt.Component; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; @@ -193,7 +198,7 @@ public class ChannelSpectrumPanel extends JPanel private void start() { - if( mEnabled.get() && mCurrentChannel != null && mCurrentChannel.getEnabled() ) + if( mEnabled.get() && mCurrentChannel != null && mCurrentChannel.isProcessing() ) { ProcessingChain processingChain = mChannelProcessingManager .getProcessingChain( mCurrentChannel ); @@ -209,7 +214,7 @@ public class ChannelSpectrumPanel extends JPanel private void stop() { - if( mCurrentChannel != null && mCurrentChannel.getEnabled() ) + if( mCurrentChannel != null && mCurrentChannel.isProcessing() ) { ProcessingChain processingChain = mChannelProcessingManager .getProcessingChain( mCurrentChannel ); diff --git a/src/main/java/io/github/dsheirer/spectrum/OverlayPanel.java b/src/main/java/io/github/dsheirer/spectrum/OverlayPanel.java index d1317e11..3647a047 100644 --- a/src/main/java/io/github/dsheirer/spectrum/OverlayPanel.java +++ b/src/main/java/io/github/dsheirer/spectrum/OverlayPanel.java @@ -34,8 +34,16 @@ import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.swing.*; -import java.awt.*; +import javax.swing.JPanel; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.Stroke; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.geom.Line2D; @@ -517,14 +525,14 @@ public class OverlayPanel extends JPanel implements ChannelEventListener, IFrequ for(Channel channel : mVisibleChannels) { if(mChannelDisplay == ChannelDisplay.ALL || - (mChannelDisplay == ChannelDisplay.ENABLED && channel.getEnabled())) + (mChannelDisplay == ChannelDisplay.ENABLED && channel.isProcessing())) { //Choose the correct background color to use if(channel.isSelected()) { graphics.setColor(mColorChannelConfigSelected); } - else if(channel.getEnabled()) + else if(channel.isProcessing()) { graphics.setColor(mColorChannelConfigProcessing); }