From 030fc1617c517cba81e3ef8af9f5ee17331a4942 Mon Sep 17 00:00:00 2001 From: Denny Date: Sat, 10 Feb 2018 08:09:43 -0500 Subject: [PATCH 1/2] 328 Channel Auto-Start capability. Adds auto-start and auto-start ordering to each channel configuration to provide the user with greater control over initial application startup configuration. Adds new dialog window that displays on startup that allows the user to invoke/cancel auto-start, or simply allow the timer to expire whereby the channels will be auto-started. Updates channel table model to include an auto-start column and relabels the 'Enabled' column to read 'Playing'. Updates channel editor to change the 'Enable/Disable' button to read 'Start/Stop'. Changes the 'enabled' property of the channel configuration to indicate the current 'processing' status - isProcessing(). Channel's XML configuration re-purposes the 'enabled' property to indicate auto-start and adds a new (optional) auto-start 'order' attribute. --- .../traffic/TrafficChannelManager.java | 4 +- .../channel/AutoStartChannelModel.java | 105 +++++ .../dsheirer/controller/channel/Channel.java | 107 ++++- .../channel/ChannelAutoStartFrame.java | 286 +++++++++++++ .../controller/channel/ChannelController.java | 14 +- .../controller/channel/ChannelEditor.java | 402 +++++++++--------- .../controller/channel/ChannelEvent.java | 9 +- .../controller/channel/ChannelModel.java | 69 ++- .../channel/ChannelProcessingManager.java | 12 +- .../controller/channel/ChannelUtils.java | 9 +- .../channel/NameConfigurationEditor.java | 78 +++- .../java/io/github/dsheirer/gui/SDRTrunk.java | 74 +++- .../spectrum/ChannelSpectrumPanel.java | 13 +- .../dsheirer/spectrum/OverlayPanel.java | 16 +- 14 files changed, 926 insertions(+), 272 deletions(-) create mode 100644 src/main/java/io/github/dsheirer/controller/channel/AutoStartChannelModel.java create mode 100644 src/main/java/io/github/dsheirer/controller/channel/ChannelAutoStartFrame.java 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); } From 05eea44f7e1ddd50e61c0a0b38920a283f96638a Mon Sep 17 00:00:00 2001 From: Denny Date: Sat, 10 Feb 2018 08:14:00 -0500 Subject: [PATCH 2/2] Cleanup --- .../channel/ChannelAutoStartFrame.java | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/src/main/java/io/github/dsheirer/controller/channel/ChannelAutoStartFrame.java b/src/main/java/io/github/dsheirer/controller/channel/ChannelAutoStartFrame.java index 0fe0481c..92dbc945 100644 --- a/src/main/java/io/github/dsheirer/controller/channel/ChannelAutoStartFrame.java +++ b/src/main/java/io/github/dsheirer/controller/channel/ChannelAutoStartFrame.java @@ -15,7 +15,6 @@ ******************************************************************************/ 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; @@ -33,7 +32,6 @@ 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; @@ -245,42 +243,4 @@ public class ChannelAutoStartFrame extends JFrame } } } - - 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); - } }