mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
Updates pull request from Roman Tsypuk to convert the build system from
ant to gradle. Removes linux and windows application launch scripts and produces an executable jar with all resources included.
This commit is contained in:
@@ -0,0 +1,946 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.spectrum;
|
||||
|
||||
import com.jidesoft.swing.JideSplitPane;
|
||||
import io.github.dsheirer.controller.channel.Channel;
|
||||
import io.github.dsheirer.controller.channel.ChannelModel;
|
||||
import io.github.dsheirer.controller.channel.ChannelProcessingManager;
|
||||
import io.github.dsheirer.controller.channel.ChannelUtils;
|
||||
import io.github.dsheirer.properties.SystemProperties;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
import io.github.dsheirer.sample.SampleType;
|
||||
import io.github.dsheirer.sample.complex.ComplexBuffer;
|
||||
import io.github.dsheirer.settings.ColorSetting.ColorSettingName;
|
||||
import io.github.dsheirer.settings.ColorSettingMenuItem;
|
||||
import io.github.dsheirer.settings.SettingsManager;
|
||||
import io.github.dsheirer.source.tuner.Tuner;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent;
|
||||
import io.github.dsheirer.source.tuner.frequency.FrequencyChangeEvent.Event;
|
||||
import io.github.dsheirer.source.tuner.frequency.IFrequencyChangeProcessor;
|
||||
import io.github.dsheirer.spectrum.OverlayPanel.ChannelDisplay;
|
||||
import io.github.dsheirer.spectrum.converter.ComplexDecibelConverter;
|
||||
import io.github.dsheirer.spectrum.converter.DFTResultsConverter;
|
||||
import io.github.dsheirer.spectrum.menu.AveragingItem;
|
||||
import io.github.dsheirer.spectrum.menu.DFTSizeItem;
|
||||
import io.github.dsheirer.spectrum.menu.FFTWindowTypeItem;
|
||||
import io.github.dsheirer.spectrum.menu.FrameRateItem;
|
||||
import io.github.dsheirer.spectrum.menu.SmoothingItem;
|
||||
import io.github.dsheirer.spectrum.menu.SmoothingTypeItem;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import io.github.dsheirer.dsp.filter.Window.WindowType;
|
||||
import io.github.dsheirer.dsp.filter.smoothing.SmoothingFilter.SmoothingType;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.event.MouseInputAdapter;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class SpectralDisplayPanel extends JPanel implements Listener<ComplexBuffer>, IFrequencyChangeProcessor, IDFTWidthChangeProcessor
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final static Logger mLog = LoggerFactory.getLogger(SpectralDisplayPanel.class);
|
||||
|
||||
private static DecimalFormat sCURSOR_FORMAT = new DecimalFormat("000.00000");
|
||||
|
||||
public static final String FFT_SIZE_PROPERTY = "spectral.display.dft.size";
|
||||
public static final int NO_ZOOM = 0;
|
||||
public static final int MAX_ZOOM = 6;
|
||||
|
||||
private DFTSize mDFTSize = DFTSize.FFT04096;
|
||||
private int mZoom = 0;
|
||||
private int mDFTZoomWindowOffset = 0;
|
||||
|
||||
private JScrollPane mScrollPane;
|
||||
private JLayeredPane mLayeredPanel;
|
||||
private SpectrumPanel mSpectrumPanel;
|
||||
private WaterfallPanel mWaterfallPanel;
|
||||
private OverlayPanel mOverlayPanel;
|
||||
private DFTProcessor mDFTProcessor;
|
||||
private DFTResultsConverter mDFTConverter;
|
||||
private ChannelModel mChannelModel;
|
||||
private ChannelProcessingManager mChannelProcessingManager;
|
||||
private SettingsManager mSettingsManager;
|
||||
private Tuner mTuner;
|
||||
|
||||
/**
|
||||
* Spectral Display Panel provides a frequency component display with a
|
||||
* historical waterfall display and a transparent overlay to show frequency,
|
||||
* cursor and channel information.
|
||||
*
|
||||
* Mouse scrolling and zooming are supported and the waterfall display can
|
||||
* be paused.
|
||||
*
|
||||
* Complex sample buffers are processed by a DFTProcessor and the output of
|
||||
* the DFT is translated to decibels for display in the spectrum and
|
||||
* waterfall components.
|
||||
*/
|
||||
public SpectralDisplayPanel(ChannelModel channelModel,
|
||||
ChannelProcessingManager channelProcessingManager,
|
||||
SettingsManager settingsManager)
|
||||
{
|
||||
mChannelModel = channelModel;
|
||||
mChannelProcessingManager = channelProcessingManager;
|
||||
mSettingsManager = settingsManager;
|
||||
|
||||
mSpectrumPanel = new SpectrumPanel(mSettingsManager);
|
||||
mOverlayPanel = new OverlayPanel(mSettingsManager, mChannelModel);
|
||||
mWaterfallPanel = new WaterfallPanel(mSettingsManager);
|
||||
|
||||
init();
|
||||
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
private void loadSettings()
|
||||
{
|
||||
SystemProperties properties = SystemProperties.getInstance();
|
||||
|
||||
String rawSize = properties.get(FFT_SIZE_PROPERTY, DFTSize.FFT04096.name());
|
||||
|
||||
DFTSize size = null;
|
||||
|
||||
if(rawSize != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
size = DFTSize.valueOf(rawSize);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
if(size == null)
|
||||
{
|
||||
size = DFTSize.FFT04096;
|
||||
}
|
||||
|
||||
setDFTSize(size, false);
|
||||
}
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
/* De-register from receiving samples when the window closes */
|
||||
clearTuner();
|
||||
|
||||
mSettingsManager = null;
|
||||
|
||||
mDFTProcessor.dispose();
|
||||
mDFTProcessor = null;
|
||||
|
||||
mDFTConverter.dispose();
|
||||
mDFTConverter = null;
|
||||
|
||||
mSpectrumPanel.dispose();
|
||||
mSpectrumPanel = null;
|
||||
|
||||
mWaterfallPanel.dispose();
|
||||
mWaterfallPanel = null;
|
||||
|
||||
mOverlayPanel.dispose();
|
||||
mOverlayPanel = null;
|
||||
|
||||
|
||||
mTuner = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues an FFT size change request. The scheduled executor will apply
|
||||
* the change when it runs.
|
||||
*/
|
||||
public void setDFTSize(DFTSize size, boolean save)
|
||||
{
|
||||
mDFTProcessor.setDFTSize(size);
|
||||
mOverlayPanel.setDFTSize(size);
|
||||
mDFTSize = size;
|
||||
|
||||
if(save)
|
||||
{
|
||||
SystemProperties.getInstance().set(FFT_SIZE_PROPERTY, size.name());
|
||||
}
|
||||
|
||||
setZoom(0, 0, 0);
|
||||
}
|
||||
|
||||
public void setDFTSize(DFTSize size)
|
||||
{
|
||||
setDFTSize(size, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DFTSize getDFTSize()
|
||||
{
|
||||
return mDFTSize;
|
||||
}
|
||||
|
||||
public int getZoom()
|
||||
{
|
||||
return mZoom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current zoom level which will be 2 to the power of zoom (2^zoom)
|
||||
*
|
||||
* 0 No Zoom
|
||||
* 1 2x Zoom
|
||||
* 2 4x Zoom
|
||||
* 3 8x Zoom
|
||||
* 4 16x Zoom
|
||||
* 5 32x Zoom
|
||||
* 6 64x Zoom
|
||||
*
|
||||
* @param zoom level, 0 - 6.
|
||||
* @param frequency under the mouse to maintain while zooming
|
||||
* @param xAxisOffset where to maintain the frequency under the mouse
|
||||
*/
|
||||
public void setZoom(int zoom, long frequency, double windowOffset)
|
||||
{
|
||||
if(zoom < NO_ZOOM)
|
||||
{
|
||||
zoom = NO_ZOOM;
|
||||
}
|
||||
else if(zoom > MAX_ZOOM)
|
||||
{
|
||||
zoom = MAX_ZOOM;
|
||||
}
|
||||
|
||||
if(zoom != mZoom)
|
||||
{
|
||||
mZoom = zoom;
|
||||
|
||||
//Calculate the bin offset that would place the reference frequency
|
||||
//at the left edge of the zoom window.
|
||||
double binOffsetToFrequency = getBinOffset(frequency);
|
||||
|
||||
//Calculate the bin offset into the newly sized zoom window that
|
||||
//would place the frequency in the same proportional window location
|
||||
//that it was in the previous zoom size
|
||||
double windowBinOffset = (double) getZoomWindowSizeInBins() * windowOffset;
|
||||
|
||||
//Set the overall offset to place the reference frequency in the
|
||||
//same location in the newly zoomed window
|
||||
double offset = binOffsetToFrequency - windowBinOffset;
|
||||
|
||||
mSpectrumPanel.setZoom(mZoom);
|
||||
mOverlayPanel.setZoom(mZoom);
|
||||
mWaterfallPanel.setZoom(mZoom);
|
||||
|
||||
setZoomWindowOffset(offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the offset (in DFT bins) to the first bin that the zoom window displays
|
||||
*/
|
||||
public void setZoomWindowOffset(double offset)
|
||||
{
|
||||
if(offset < 0)
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if(offset > (mDFTSize.getSize() - getZoomWindowSizeInBins()))
|
||||
{
|
||||
offset = mDFTSize.getSize() - getZoomWindowSizeInBins();
|
||||
}
|
||||
|
||||
mDFTZoomWindowOffset = (int) offset;
|
||||
|
||||
mSpectrumPanel.setZoomWindowOffset(mDFTZoomWindowOffset);
|
||||
mOverlayPanel.setZoomWindowOffset(mDFTZoomWindowOffset);
|
||||
mWaterfallPanel.setZoomWindowOffset(mDFTZoomWindowOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the size of the current zoom window in DFT bins
|
||||
*/
|
||||
private int getZoomWindowSizeInBins()
|
||||
{
|
||||
return mDFTSize.getSize() / getZoomMultiplier();
|
||||
}
|
||||
|
||||
|
||||
public int getZoomMultiplier()
|
||||
{
|
||||
return (int) Math.pow(2.0, mZoom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the overall offset of the frequency from the current minimum
|
||||
* frequency in terms of total FFT width
|
||||
*
|
||||
* @param frequency
|
||||
* @return
|
||||
*/
|
||||
private double getBinOffset(long frequency)
|
||||
{
|
||||
double offset = 0.0;
|
||||
|
||||
if(mOverlayPanel.containsFrequency(frequency))
|
||||
{
|
||||
offset = (double) mDFTSize.getSize() *
|
||||
((double) (frequency - mOverlayPanel.getMinFrequency()) /
|
||||
(double) mOverlayPanel.getBandwidth());
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides JComponent method to return false, since we have overlapping
|
||||
* panels with the spectrum and channel panels
|
||||
*/
|
||||
public boolean isOptimizedDrawingEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
setLayout(new MigLayout("insets 0 0 0 0", "[grow]", "[grow]"));
|
||||
|
||||
/**
|
||||
* The layered pane holds the overlapping spectrum and channel panels
|
||||
* and manages the sizing of each panel with the resize listener
|
||||
*/
|
||||
mLayeredPanel = new JLayeredPane();
|
||||
mLayeredPanel.addComponentListener(new ResizeListener());
|
||||
|
||||
/**
|
||||
* Create a mouse adapter to handle mouse events over the spectrum
|
||||
* and waterfall panels
|
||||
*/
|
||||
MouseEventProcessor mouser = new MouseEventProcessor();
|
||||
|
||||
mOverlayPanel.addMouseListener(mouser);
|
||||
mOverlayPanel.addMouseMotionListener(mouser);
|
||||
mOverlayPanel.addMouseWheelListener(mouser);
|
||||
|
||||
//Add the spectrum and channel panels to the layered panel
|
||||
mLayeredPanel.add(mSpectrumPanel, new Integer(0), 0);
|
||||
mLayeredPanel.add(mOverlayPanel, new Integer(1), 0);
|
||||
|
||||
//Create the waterfall
|
||||
mWaterfallPanel.addMouseListener(mouser);
|
||||
mWaterfallPanel.addMouseMotionListener(mouser);
|
||||
mWaterfallPanel.addMouseWheelListener(mouser);
|
||||
|
||||
/* Attempt to set a 50/50 split preferred size for the split pane */
|
||||
double totalHeight = mLayeredPanel.getPreferredSize().getHeight() +
|
||||
mWaterfallPanel.getPreferredSize().getHeight();
|
||||
|
||||
mLayeredPanel.setPreferredSize(new Dimension((int) mLayeredPanel
|
||||
.getPreferredSize().getWidth(), (int) (totalHeight / 2.0d)));
|
||||
|
||||
mWaterfallPanel.setPreferredSize(new Dimension((int) mWaterfallPanel
|
||||
.getPreferredSize().getWidth(), (int) (totalHeight / 2.0d)));
|
||||
|
||||
//Create the split pane to hold the layered pane and the waterfall
|
||||
JideSplitPane splitPane = new JideSplitPane(JSplitPane.VERTICAL_SPLIT);
|
||||
splitPane.setDividerSize(5);
|
||||
splitPane.add(mLayeredPanel);
|
||||
splitPane.add(mWaterfallPanel);
|
||||
|
||||
mScrollPane = new JScrollPane(splitPane);
|
||||
|
||||
add(mScrollPane, "grow");
|
||||
|
||||
/**
|
||||
* Setup DFTProcessor to process samples and register the waterfall and
|
||||
* spectrum panel to receive the processed dft results
|
||||
*/
|
||||
mDFTProcessor = new DFTProcessor(SampleType.COMPLEX);
|
||||
mDFTConverter = new ComplexDecibelConverter();
|
||||
mDFTProcessor.addConverter(mDFTConverter);
|
||||
|
||||
mDFTConverter.addListener((DFTResultsListener) mSpectrumPanel);
|
||||
mDFTConverter.addListener((DFTResultsListener) mWaterfallPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives frequency change events -- primarily from tuner components.
|
||||
*/
|
||||
public void frequencyChanged(FrequencyChangeEvent event)
|
||||
{
|
||||
mOverlayPanel.frequencyChanged(event);
|
||||
mDFTProcessor.frequencyChanged(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Complex sample buffer receive method
|
||||
*/
|
||||
@Override
|
||||
public void receive(ComplexBuffer sampleBuffer)
|
||||
{
|
||||
mDFTProcessor.receive(sampleBuffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to tuner event by deregistering from the current
|
||||
* complex sample buffer source and registering with the tuner argument.
|
||||
*/
|
||||
public void showTuner(Tuner tuner)
|
||||
{
|
||||
clearTuner();
|
||||
|
||||
mDFTProcessor.clearBuffer();
|
||||
|
||||
mTuner = tuner;
|
||||
|
||||
if(mTuner != null)
|
||||
{
|
||||
//Register to receive frequency change events
|
||||
mTuner.getTunerController().addListener(this);
|
||||
|
||||
//Register the dft processor to receive samples from the tuner
|
||||
mTuner.addListener((Listener<ComplexBuffer>) mDFTProcessor);
|
||||
|
||||
mSpectrumPanel.setSampleSize(mTuner.getSampleSize());
|
||||
|
||||
//Fire frequency and sample rate change events so that the spectrum
|
||||
//and overlay panels can synchronize
|
||||
frequencyChanged(new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_FREQUENCY_CHANGE,
|
||||
mTuner.getTunerController().getFrequency()));
|
||||
|
||||
frequencyChanged(new FrequencyChangeEvent(
|
||||
Event.NOTIFICATION_SAMPLE_RATE_CHANGE,
|
||||
mTuner.getTunerController().getSampleRate()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tuner de-selection cleanup method
|
||||
*/
|
||||
public void clearTuner()
|
||||
{
|
||||
if(mTuner != null)
|
||||
{
|
||||
//Deregister for frequency change events from the tuner
|
||||
mTuner.getTunerController().removeListener(this);
|
||||
|
||||
//Deregister the dft processor from receiving samples
|
||||
mTuner.removeListener((Listener<ComplexBuffer>) mDFTProcessor);
|
||||
mTuner = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors the sizing of the layered pane and resizes the spectrum and
|
||||
* channel panels whenever the layered pane is resized
|
||||
*/
|
||||
public class ResizeListener implements ComponentListener
|
||||
{
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e)
|
||||
{
|
||||
Component c = e.getComponent();
|
||||
|
||||
mSpectrumPanel.setBounds(0, 0, c.getWidth(), c.getHeight());
|
||||
mOverlayPanel.setBounds(0, 0, c.getWidth(), c.getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent arg0)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent arg0)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentShown(ComponentEvent arg0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mouse event handler for the spectral display panel.
|
||||
*/
|
||||
public class MouseEventProcessor extends MouseInputAdapter
|
||||
{
|
||||
private int mDFTZoomWindowOffsetAtDragStart = 0;
|
||||
private int mDragStartX = 0;
|
||||
private double mPixelsPerBin;
|
||||
|
||||
public MouseEventProcessor()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(MouseWheelEvent e)
|
||||
{
|
||||
int zoom = mZoom - e.getWheelRotation();
|
||||
|
||||
long frequency = mOverlayPanel.getFrequencyFromAxis(e.getX());
|
||||
|
||||
double windowOffset = (double) e.getX() / (double) getWidth();
|
||||
|
||||
setZoom(zoom, frequency, windowOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent event)
|
||||
{
|
||||
update(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent event)
|
||||
{
|
||||
update(event);
|
||||
|
||||
int dragDistance = mDragStartX - event.getX();
|
||||
|
||||
double binDistance = (double) dragDistance / mPixelsPerBin;
|
||||
|
||||
int offset = (int) (mDFTZoomWindowOffsetAtDragStart + binDistance);
|
||||
|
||||
if(offset < 0)
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
int maxOffset = mDFTSize.getSize() - (mDFTSize.getSize() / getZoomMultiplier());
|
||||
|
||||
if(offset > maxOffset)
|
||||
{
|
||||
offset = maxOffset;
|
||||
}
|
||||
|
||||
setZoomWindowOffset(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e)
|
||||
{
|
||||
mDragStartX = e.getX();
|
||||
|
||||
mDFTZoomWindowOffsetAtDragStart = mDFTZoomWindowOffset;
|
||||
|
||||
mPixelsPerBin = (double) getWidth() /
|
||||
((double) (mDFTSize.getSize()) /
|
||||
(double) getZoomMultiplier());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the cursor display while the mouse is performing actions
|
||||
*/
|
||||
private void update(MouseEvent event)
|
||||
{
|
||||
if(event.getComponent() == mOverlayPanel)
|
||||
{
|
||||
mOverlayPanel.setCursorLocation(event.getPoint());
|
||||
}
|
||||
else
|
||||
{
|
||||
mWaterfallPanel.setCursorLocation(event.getPoint());
|
||||
mWaterfallPanel.setCursorFrequency(
|
||||
mOverlayPanel.getFrequencyFromAxis(event.getPoint().x));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e)
|
||||
{
|
||||
if(e.getComponent() == mOverlayPanel)
|
||||
{
|
||||
mOverlayPanel.setCursorVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
mWaterfallPanel.setCursorVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e)
|
||||
{
|
||||
mOverlayPanel.setCursorVisible(false);
|
||||
mWaterfallPanel.setCursorVisible(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the context menu.
|
||||
*/
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent event)
|
||||
{
|
||||
if(SwingUtilities.isRightMouseButton(event))
|
||||
{
|
||||
JPopupMenu contextMenu = new JPopupMenu();
|
||||
|
||||
if(event.getComponent() == mWaterfallPanel)
|
||||
{
|
||||
contextMenu.add(new PauseItem(mWaterfallPanel, "Pause"));
|
||||
}
|
||||
|
||||
long frequency =
|
||||
mOverlayPanel.getFrequencyFromAxis(event.getX());
|
||||
|
||||
if(event.getComponent() == mOverlayPanel)
|
||||
{
|
||||
ArrayList<Channel> channels =
|
||||
mOverlayPanel.getChannelsAtFrequency(frequency);
|
||||
|
||||
for(Channel channel : channels)
|
||||
{
|
||||
JMenu channelMenu = ChannelUtils.getContextMenu(mChannelModel,
|
||||
mChannelProcessingManager, channel,
|
||||
SpectralDisplayPanel.this);
|
||||
|
||||
if(channelMenu != null)
|
||||
{
|
||||
contextMenu.add(channelMenu);
|
||||
}
|
||||
}
|
||||
|
||||
if(!channels.isEmpty())
|
||||
{
|
||||
contextMenu.add(new JSeparator());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// JMenu frequencyMenu = new JMenu(
|
||||
// sCURSOR_FORMAT.format((float) frequency / 1000000.0f));
|
||||
//
|
||||
// JMenu decoderMenu = new JMenu("Add Decoder");
|
||||
//
|
||||
// for(DecoderType type : DecoderType.getPrimaryDecoders())
|
||||
// {
|
||||
// decoderMenu.add(new DecoderItem(type, frequency));
|
||||
// }
|
||||
//
|
||||
// frequencyMenu.add(decoderMenu);
|
||||
//
|
||||
// contextMenu.add(frequencyMenu);
|
||||
//
|
||||
// contextMenu.add(new JSeparator());
|
||||
|
||||
/**
|
||||
* Color Menus
|
||||
*/
|
||||
JMenu colorMenu = new JMenu("Color");
|
||||
|
||||
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
|
||||
ColorSettingName.CHANNEL_CONFIG));
|
||||
|
||||
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
|
||||
ColorSettingName.CHANNEL_CONFIG_PROCESSING));
|
||||
|
||||
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
|
||||
ColorSettingName.CHANNEL_CONFIG_SELECTED));
|
||||
|
||||
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_CURSOR));
|
||||
|
||||
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_LINE));
|
||||
|
||||
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_BACKGROUND));
|
||||
|
||||
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_GRADIENT_BOTTOM));
|
||||
|
||||
colorMenu.add(new ColorSettingMenuItem(mSettingsManager,
|
||||
ColorSettingName.SPECTRUM_GRADIENT_TOP));
|
||||
|
||||
contextMenu.add(colorMenu);
|
||||
|
||||
/**
|
||||
* Display items: fft and frame rate
|
||||
*/
|
||||
JMenu displayMenu = new JMenu("Display");
|
||||
contextMenu.add(displayMenu);
|
||||
|
||||
if(event.getComponent() != mWaterfallPanel)
|
||||
{
|
||||
/**
|
||||
* Averaging menu
|
||||
*/
|
||||
JMenu averagingMenu = new JMenu("Averaging");
|
||||
averagingMenu.add(
|
||||
new AveragingItem(mSpectrumPanel, 4));
|
||||
displayMenu.add(averagingMenu);
|
||||
|
||||
/**
|
||||
* Channel Display setting menu
|
||||
*/
|
||||
JMenu channelDisplayMenu = new JMenu("Channel");
|
||||
|
||||
channelDisplayMenu.add(new ChannelDisplayItem(
|
||||
mOverlayPanel, ChannelDisplay.ALL));
|
||||
channelDisplayMenu.add(new ChannelDisplayItem(
|
||||
mOverlayPanel, ChannelDisplay.ENABLED));
|
||||
channelDisplayMenu.add(new ChannelDisplayItem(
|
||||
mOverlayPanel, ChannelDisplay.NONE));
|
||||
|
||||
displayMenu.add(channelDisplayMenu);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FFT width
|
||||
*/
|
||||
JMenu fftWidthMenu = new JMenu("FFT Width");
|
||||
displayMenu.add(fftWidthMenu);
|
||||
|
||||
for(DFTSize width : DFTSize.values())
|
||||
{
|
||||
fftWidthMenu.add(new DFTSizeItem(SpectralDisplayPanel.this, width));
|
||||
}
|
||||
|
||||
/**
|
||||
* DFT Processor Frame Rate
|
||||
*/
|
||||
JMenu frameRateMenu = new JMenu("Frame Rate");
|
||||
displayMenu.add(frameRateMenu);
|
||||
|
||||
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 14));
|
||||
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 16));
|
||||
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 18));
|
||||
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 20));
|
||||
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 25));
|
||||
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 30));
|
||||
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 40));
|
||||
frameRateMenu.add(new FrameRateItem(mDFTProcessor, 50));
|
||||
|
||||
/**
|
||||
* FFT Window Type
|
||||
*/
|
||||
JMenu fftWindowType = new JMenu("Window Type");
|
||||
displayMenu.add(fftWindowType);
|
||||
|
||||
for(WindowType type : WindowType.values())
|
||||
{
|
||||
fftWindowType.add(
|
||||
new FFTWindowTypeItem(mDFTProcessor, type));
|
||||
}
|
||||
|
||||
if(event.getComponent() != mWaterfallPanel)
|
||||
{
|
||||
/**
|
||||
* Smoothing menu
|
||||
*/
|
||||
JMenu smoothingMenu = new JMenu("Smoothing");
|
||||
|
||||
if(mSpectrumPanel.getSmoothingType() != SmoothingType.NONE)
|
||||
{
|
||||
smoothingMenu.add(new SmoothingItem(mSpectrumPanel, 5));
|
||||
smoothingMenu.add(new JSeparator());
|
||||
}
|
||||
smoothingMenu.add(new SmoothingTypeItem(mSpectrumPanel, SmoothingType.GAUSSIAN));
|
||||
smoothingMenu.add(new SmoothingTypeItem(mSpectrumPanel, SmoothingType.TRIANGLE));
|
||||
smoothingMenu.add(new SmoothingTypeItem(mSpectrumPanel, SmoothingType.RECTANGLE));
|
||||
smoothingMenu.add(new SmoothingTypeItem(mSpectrumPanel, SmoothingType.NONE));
|
||||
|
||||
displayMenu.add(smoothingMenu);
|
||||
}
|
||||
|
||||
/*
|
||||
* Zoom menu
|
||||
*/
|
||||
JMenuItem zoomMenu = new JMenu("Zoom");
|
||||
|
||||
double windowOffset = (double) event.getX() / (double) getWidth();
|
||||
|
||||
zoomMenu.add(new ZoomItem(frequency, windowOffset));
|
||||
|
||||
contextMenu.add(zoomMenu);
|
||||
|
||||
|
||||
if(contextMenu != null)
|
||||
{
|
||||
if(event.getComponent() == mOverlayPanel)
|
||||
{
|
||||
contextMenu.show(mOverlayPanel,
|
||||
event.getX(),
|
||||
event.getY());
|
||||
}
|
||||
else
|
||||
{
|
||||
contextMenu.show(mWaterfallPanel,
|
||||
event.getX(),
|
||||
event.getY());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PauseItem extends JCheckBoxMenuItem
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Pausable mPausable;
|
||||
|
||||
public PauseItem(Pausable pausable, String label)
|
||||
{
|
||||
super(label);
|
||||
|
||||
final boolean paused = pausable.isPaused();
|
||||
|
||||
setSelected(paused);
|
||||
|
||||
mPausable = pausable;
|
||||
|
||||
addActionListener(new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e)
|
||||
{
|
||||
EventQueue.invokeLater(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mPausable.setPaused(!paused);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ZoomItem extends JSlider
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private long mFrequency;
|
||||
private double mWindowOffset;
|
||||
|
||||
public ZoomItem(long frequency, double windowOffset)
|
||||
{
|
||||
super(NO_ZOOM, MAX_ZOOM, mZoom);
|
||||
|
||||
mFrequency = frequency;
|
||||
mWindowOffset = windowOffset;
|
||||
|
||||
Hashtable<Integer,JComponent> labels = new Hashtable<>();
|
||||
labels.put(new Integer(0), new JLabel("1x"));
|
||||
labels.put(new Integer(1), new JLabel("2x"));
|
||||
labels.put(new Integer(2), new JLabel("4x"));
|
||||
labels.put(new Integer(3), new JLabel("8x"));
|
||||
labels.put(new Integer(4), new JLabel("16x"));
|
||||
labels.put(new Integer(5), new JLabel("32x"));
|
||||
labels.put(new Integer(6), new JLabel("64x"));
|
||||
|
||||
setLabelTable(labels);
|
||||
|
||||
setMajorTickSpacing(1);
|
||||
setMinorTickSpacing(1);
|
||||
setPaintTicks(true);
|
||||
setPaintLabels(true);
|
||||
|
||||
this.addChangeListener(new ChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e)
|
||||
{
|
||||
setZoom(getValue(), mFrequency, mWindowOffset);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ChannelDisplayItem extends JCheckBoxMenuItem
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private OverlayPanel mOverlayPanel;
|
||||
private ChannelDisplay mChannelDisplay;
|
||||
|
||||
public ChannelDisplayItem(OverlayPanel panel, ChannelDisplay display)
|
||||
{
|
||||
super(display.name());
|
||||
|
||||
mOverlayPanel = panel;
|
||||
|
||||
mChannelDisplay = display;
|
||||
|
||||
setSelected(mOverlayPanel.getChannelDisplay() == mChannelDisplay);
|
||||
|
||||
addActionListener(new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e)
|
||||
{
|
||||
EventQueue.invokeLater(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mOverlayPanel.setChannelDisplay(mChannelDisplay);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Context menu item to provide one-click access to starting a channel
|
||||
* processing with the selected decoder
|
||||
*/
|
||||
public class DecoderItem extends JMenuItem
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ChannelModel mChannelModel;
|
||||
private long mFrequency;
|
||||
private DecoderType mDecoder;
|
||||
|
||||
public DecoderItem(DecoderType type, long frequency)
|
||||
{
|
||||
super(type.getDisplayString());
|
||||
|
||||
mFrequency = frequency;
|
||||
mDecoder = type;
|
||||
|
||||
addActionListener(new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e)
|
||||
{
|
||||
mChannelModel.createChannel(mDecoder, mFrequency);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user