513 persist application layout across restarts (#514)

* Stores minimal main application window location and size/layout settings
to allow application to be restored to the same size/location on
restart.

* Adds column width monitor to all tables in application that stores the
column width settings in the user preferences so that on restarting
the application the table column widths are restored to the previous
widths.
This commit is contained in:
Denny Sheirer
2019-01-27 12:05:20 +00:00
committed by GitHub
parent c05aff0768
commit 34235382fb
14 changed files with 512 additions and 127 deletions

View File

@@ -24,6 +24,8 @@ import com.jidesoft.swing.JideSplitPane;
import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.icon.IconManager;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
import net.coderazzi.filters.gui.AutoChoices;
import net.coderazzi.filters.gui.TableFilterHeader;
import net.miginfocom.swing.MigLayout;
@@ -48,17 +50,18 @@ import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
public class AliasController extends JPanel
implements ActionListener, ListSelectionListener
public class AliasController extends JPanel implements ActionListener, ListSelectionListener
{
private static final long serialVersionUID = 1L;
private static final String TABLE_PREFERENCE_KEY = "alias.controller";
private AliasModel mAliasModel;
private JTable mAliasTable;
private TableFilterHeader mTableFilterHeader;
private AliasEditor mAliasEditor;
private MultipleAliasEditor mMultipleAliasEditor;
private JideSplitPane mSplitPane;
private UserPreferences mUserPreferences;
private static final String NEW_ALIAS = "New";
private static final String COPY_ALIAS = "Copy";
@@ -69,15 +72,16 @@ public class AliasController extends JPanel
private JButton mDeleteButton = new JButton(DELETE_ALIAS);
private IconCellRenderer mIconCellRenderer;
private JTableColumnWidthMonitor mColumnWidthMonitor;
public AliasController(AliasModel aliasModel, BroadcastModel broadcastModel, IconManager iconManager)
public AliasController(AliasModel aliasModel, BroadcastModel broadcastModel, IconManager iconManager,
UserPreferences userPreferences)
{
mAliasModel = aliasModel;
mAliasEditor = new AliasEditor(mAliasModel, broadcastModel, iconManager);
mMultipleAliasEditor = new MultipleAliasEditor(mAliasModel, broadcastModel, iconManager);
mIconCellRenderer = new IconCellRenderer(iconManager);
mUserPreferences = userPreferences;
init();
@@ -86,9 +90,7 @@ public class AliasController extends JPanel
private void init()
{
setLayout(new MigLayout("insets 0 0 0 0",
"[grow,fill]",
"[grow,fill]"));
setLayout(new MigLayout("insets 0 0 0 0", "[grow,fill]", "[grow,fill]"));
//System Configuration View and Editor
mAliasTable = new JTable(mAliasModel);
@@ -96,11 +98,11 @@ public class AliasController extends JPanel
mAliasTable.getSelectionModel().addListSelectionListener(this);
mAliasTable.setAutoCreateRowSorter(true);
mAliasTable.getColumnModel().getColumn(AliasModel.COLUMN_COLOR)
.setCellRenderer(new ColorCellRenderer());
mAliasTable.getColumnModel().getColumn(AliasModel.COLUMN_COLOR).setCellRenderer(new ColorCellRenderer());
mAliasTable.getColumnModel().getColumn(AliasModel.COLUMN_ICON)
.setCellRenderer(mIconCellRenderer);
mAliasTable.getColumnModel().getColumn(AliasModel.COLUMN_ICON).setCellRenderer(mIconCellRenderer);
mColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mAliasTable, TABLE_PREFERENCE_KEY);
mTableFilterHeader = new TableFilterHeader(mAliasTable, AutoChoices.ENABLED);
mTableFilterHeader.setFilterOnUpdates(true);
@@ -109,8 +111,8 @@ public class AliasController extends JPanel
JPanel buttonsPanel = new JPanel();
buttonsPanel.setLayout(
new MigLayout("insets 0 0 0 0", "[grow,fill][grow,fill][grow,fill]", "[]"));
buttonsPanel.setLayout(new MigLayout("insets 0 0 0 0",
"[grow,fill][grow,fill][grow,fill]", "[]"));
mNewButton.addActionListener(this);
mNewButton.setToolTipText("Adds a new alias");
@@ -128,8 +130,8 @@ public class AliasController extends JPanel
JPanel listAndButtonsPanel = new JPanel();
listAndButtonsPanel.setLayout(
new MigLayout("insets 0 0 0 0", "[grow,fill]", "[grow,fill][]"));
listAndButtonsPanel.setLayout(new MigLayout("insets 0 0 0 0", "[grow,fill]",
"[grow,fill][]"));
listAndButtonsPanel.add(tableScroller, "wrap");
listAndButtonsPanel.add(buttonsPanel);

View File

@@ -1,6 +1,7 @@
/*******************************************************************************
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2016 Dennis Sheirer
* Copyright (C) 2014-2019 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
@@ -14,8 +15,8 @@
*
* 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.audio.broadcast;
import com.jidesoft.swing.JideSplitPane;
@@ -23,6 +24,7 @@ import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.gui.editor.Editor;
import io.github.dsheirer.gui.editor.EmptyEditor;
import io.github.dsheirer.icon.IconManager;
import io.github.dsheirer.preference.UserPreferences;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -51,6 +53,7 @@ public class BroadcastPanel extends JPanel implements ActionListener, ListSelect
private BroadcastModel mBroadcastModel;
private AliasModel mAliasModel;
private IconManager mIconManager;
private UserPreferences mUserPreferences;
private BroadcastStatusPanel mBroadcastStatusPanel;
private JideSplitPane mSplitPane;
@@ -60,12 +63,14 @@ public class BroadcastPanel extends JPanel implements ActionListener, ListSelect
private JButton mCopyButton = new JButton(COPY_BROADCAST_CONFIGURATION);
private JButton mDeleteButton = new JButton(DELETE_BROADCAST_CONFIGURATION);
public BroadcastPanel(BroadcastModel broadcastModel, AliasModel aliasModel, IconManager iconManager)
public BroadcastPanel(BroadcastModel broadcastModel, AliasModel aliasModel, IconManager iconManager,
UserPreferences userPreferences)
{
mBroadcastModel = broadcastModel;
mAliasModel = aliasModel;
mIconManager = iconManager;
mEditor = mEmptyEditor;
mUserPreferences = userPreferences;
init();
}
@@ -74,7 +79,8 @@ public class BroadcastPanel extends JPanel implements ActionListener, ListSelect
{
setLayout(new MigLayout("insets 0 0 0 0 ", "[grow,fill]", "[grow,fill]"));
mBroadcastStatusPanel = new BroadcastStatusPanel(mBroadcastModel);
mBroadcastStatusPanel = new BroadcastStatusPanel(mBroadcastModel, mUserPreferences,
"broadcast.panel.broadcast.status.panel");
mBroadcastStatusPanel.getTable().setAutoCreateRowSorter(true);
mBroadcastStatusPanel.getTable().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

View File

@@ -1,6 +1,7 @@
/*******************************************************************************
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
* Copyright (C) 2014-2019 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
@@ -14,10 +15,12 @@
*
* 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.audio.broadcast;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
import net.miginfocom.swing.MigLayout;
import javax.swing.JLabel;
@@ -32,12 +35,17 @@ import java.awt.Component;
public class BroadcastStatusPanel extends JPanel
{
private JTable mTable;
private JTableColumnWidthMonitor mColumnWidthMonitor;
private JScrollPane mScrollPane;
private BroadcastModel mBroadcastModel;
private UserPreferences mUserPreferences;
private String mPreferenceKey;
public BroadcastStatusPanel(BroadcastModel broadcastModel)
public BroadcastStatusPanel(BroadcastModel broadcastModel, UserPreferences userPreferences, String preferenceKey)
{
mBroadcastModel = broadcastModel;
mUserPreferences = userPreferences;
mPreferenceKey = preferenceKey;
init();
}
@@ -57,6 +65,7 @@ public class BroadcastStatusPanel extends JPanel
renderer.setHorizontalAlignment(SwingConstants.CENTER);
mTable.getColumnModel().getColumn(BroadcastModel.COLUMN_BROADCASTER_STATUS).setCellRenderer(new StatusCellRenderer());
mColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mTable, mPreferenceKey);
mScrollPane = new JScrollPane(mTable);

View File

@@ -33,6 +33,7 @@ import io.github.dsheirer.identifier.decoder.ChannelStateIdentifier;
import io.github.dsheirer.module.ProcessingChain;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.preference.identifier.TalkgroupFormatPreference;
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
import io.github.dsheirer.sample.Broadcaster;
import io.github.dsheirer.sample.Listener;
import net.miginfocom.swing.MigLayout;
@@ -58,6 +59,7 @@ import java.util.Map;
public class ChannelMetadataPanel extends JPanel implements ListSelectionListener
{
private static final String TABLE_PREFERENCE_KEY = "channel.metadata.panel";
private ChannelModel mChannelModel;
private ChannelProcessingManager mChannelProcessingManager;
private IconManager mIconManager;
@@ -66,6 +68,7 @@ public class ChannelMetadataPanel extends JPanel implements ListSelectionListene
private Broadcaster<ProcessingChain> mSelectedProcessingChainBroadcaster = new Broadcaster<>();
private Map<State,Color> mBackgroundColors = new HashMap<>();
private Map<State,Color> mForegroundColors = new HashMap<>();
private JTableColumnWidthMonitor mTableColumnMonitor;
/**
* Table view for currently decoding channel metadata
@@ -108,6 +111,9 @@ public class ChannelMetadataPanel extends JPanel implements ListSelectionListene
mTable.getColumnModel().getColumn(ChannelMetadataModel.COLUMN_CONFIGURATION_FREQUENCY)
.setCellRenderer(new FrequencyCellRenderer());
//Add a table column width monitor to store/restore column widths
mTableColumnMonitor = new JTableColumnWidthMonitor(mUserPreferences, mTable, TABLE_PREFERENCE_KEY);
JScrollPane scrollPane = new JScrollPane(mTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

View File

@@ -1,6 +1,7 @@
/*******************************************************************************
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
* Copyright (C) 2014-2019 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
@@ -14,8 +15,8 @@
*
* 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.channel.metadata;
import com.jidesoft.swing.JideSplitPane;
@@ -33,10 +34,9 @@ import net.miginfocom.swing.MigLayout;
import javax.swing.JPanel;
import java.awt.Color;
public class ChannelMetadataViewer extends JPanel
public class NowPlayingPanel extends JPanel
{
private ChannelMetadataPanel mChannelMetadataPanel;
private ChannelDetailPanel mChannelDetailPanel;
private DecodeEventPanel mDecodeEventPanel;
private MessageActivityPanel mMessageActivityPanel;
@@ -45,12 +45,12 @@ public class ChannelMetadataViewer extends JPanel
* GUI panel that combines the currently decoding channels metadata table and viewers for channel details,
* messages, events, and spectral view.
*/
public ChannelMetadataViewer(ChannelModel channelModel, ChannelProcessingManager channelProcessingManager,
IconManager iconManager, AliasModel aliasModel, UserPreferences userPreferences)
public NowPlayingPanel(ChannelModel channelModel, ChannelProcessingManager channelProcessingManager,
IconManager iconManager, AliasModel aliasModel, UserPreferences userPreferences)
{
mChannelDetailPanel = new ChannelDetailPanel(channelProcessingManager);
mDecodeEventPanel = new DecodeEventPanel(iconManager, userPreferences, aliasModel);
mMessageActivityPanel = new MessageActivityPanel(channelProcessingManager);
mMessageActivityPanel = new MessageActivityPanel(userPreferences);
mChannelMetadataPanel = new ChannelMetadataPanel(channelModel, channelProcessingManager, iconManager, userPreferences);
init();
@@ -64,7 +64,6 @@ public class ChannelMetadataViewer extends JPanel
tabbedPane.addTab("Details", mChannelDetailPanel);
tabbedPane.addTab("Events", mDecodeEventPanel);
tabbedPane.addTab("Messages", mMessageActivityPanel);
// tabbedPane.addTab("Spectrum", mChannelSpectrumPanel);
tabbedPane.setFont(this.getFont());
tabbedPane.setForeground(Color.BLACK);

View File

@@ -1,6 +1,7 @@
/*******************************************************************************
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
* Copyright (C) 2014-2019 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
@@ -14,8 +15,8 @@
*
* 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.controller;
import com.jidesoft.swing.JideTabbedPane;
@@ -25,7 +26,7 @@ import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.audio.broadcast.BroadcastPanel;
import io.github.dsheirer.audio.playback.AudioPanel;
import io.github.dsheirer.audio.playback.AudioPlaybackManager;
import io.github.dsheirer.channel.metadata.ChannelMetadataViewer;
import io.github.dsheirer.channel.metadata.NowPlayingPanel;
import io.github.dsheirer.controller.channel.ChannelController;
import io.github.dsheirer.controller.channel.ChannelModel;
import io.github.dsheirer.controller.channel.ChannelProcessingManager;
@@ -41,7 +42,6 @@ import io.github.dsheirer.source.tuner.TunerViewPanel;
import net.miginfocom.swing.MigLayout;
import javax.swing.JPanel;
import javax.swing.JTable;
import java.awt.Color;
import java.awt.Dimension;
@@ -53,27 +53,18 @@ public class ControllerPanel extends JPanel
private AudioPanel mAudioPanel;
private BroadcastPanel mBroadcastPanel;
private ChannelController mChannelController;
private ChannelMetadataViewer mChannelMetadataViewer;
private NowPlayingPanel mNowPlayingPanel;
private ChannelModel mChannelModel;
private MapPanel mMapPanel;
private TunerViewPanel mTunerManagerPanel;
private BroadcastModel mBroadcastModel;
private JideTabbedPane mTabbedPane;
protected JTable mChannelActivityTable = new JTable();
public ControllerPanel(AudioPlaybackManager audioPlaybackManager,
AliasModel aliasModel,
BroadcastModel broadcastModel,
ChannelModel channelModel,
ChannelMapModel channelMapModel,
ChannelProcessingManager channelProcessingManager,
IconManager iconManager,
MapService mapService,
SettingsManager settingsManager,
SourceManager sourceManager,
TunerModel tunerModel,
UserPreferences userPreferences)
public ControllerPanel(AudioPlaybackManager audioPlaybackManager, AliasModel aliasModel, BroadcastModel broadcastModel,
ChannelModel channelModel, ChannelMapModel channelMapModel, ChannelProcessingManager channelProcessingManager,
IconManager iconManager, MapService mapService, SettingsManager settingsManager,
SourceManager sourceManager, TunerModel tunerModel, UserPreferences userPreferences)
{
mBroadcastModel = broadcastModel;
mChannelModel = channelModel;
@@ -81,19 +72,19 @@ public class ControllerPanel extends JPanel
mAudioPanel = new AudioPanel(iconManager, userPreferences, settingsManager, sourceManager, audioPlaybackManager,
aliasModel);
mChannelMetadataViewer = new ChannelMetadataViewer(channelModel, channelProcessingManager, iconManager,
mNowPlayingPanel = new NowPlayingPanel(channelModel, channelProcessingManager, iconManager,
aliasModel, userPreferences);
mMapPanel = new MapPanel(mapService, aliasModel, iconManager, settingsManager);
mBroadcastPanel = new BroadcastPanel(broadcastModel, aliasModel, iconManager);
mBroadcastPanel = new BroadcastPanel(broadcastModel, aliasModel, iconManager, userPreferences);
mChannelController = new ChannelController(channelModel, channelProcessingManager, channelMapModel,
sourceManager, aliasModel);
sourceManager, aliasModel, userPreferences);
mAliasController = new AliasController(aliasModel, broadcastModel, iconManager);
mAliasController = new AliasController(aliasModel, broadcastModel, iconManager, userPreferences);
mTunerManagerPanel = new TunerViewPanel(tunerModel);
mTunerManagerPanel = new TunerViewPanel(tunerModel, userPreferences);
init();
}
@@ -108,7 +99,7 @@ public class ControllerPanel extends JPanel
mTabbedPane = new JideTabbedPane();
mTabbedPane.setFont(this.getFont());
mTabbedPane.setForeground(Color.BLACK);
mTabbedPane.addTab("Now Playing", mChannelMetadataViewer);
mTabbedPane.addTab("Now Playing", mNowPlayingPanel);
mTabbedPane.addTab("Aliases", mAliasController);
mTabbedPane.addTab("Channels", mChannelController);
mTabbedPane.addTab("Map", mMapPanel);

View File

@@ -1,23 +1,29 @@
/*******************************************************************************
* sdr-trunk
* Copyright (C) 2014-2018 Dennis Sheirer
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 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 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.
* 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/>
*
******************************************************************************/
* 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.controller.channel;
import com.jidesoft.swing.JideSplitPane;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
import io.github.dsheirer.source.SourceManager;
import net.coderazzi.filters.gui.AutoChoices;
import net.coderazzi.filters.gui.TableFilterHeader;
@@ -43,11 +49,14 @@ public class ChannelController extends JPanel implements ActionListener, ListSel
{
private static final long serialVersionUID = 1L;
private static final String TABLE_PREFERENCE_KEY = "channel.controller";
private ChannelModel mChannelModel;
private ChannelProcessingManager mChannelProcessingManager;
private JTable mChannelTable;
private JTableColumnWidthMonitor mColumnWidthMonitor;
private TableFilterHeader mTableFilterHeader;
private ChannelEditor mEditor;
private UserPreferences mUserPreferences;
private static final String NEW_CHANNEL = "New";
private static final String COPY_CHANNEL = "Copy";
@@ -57,17 +66,16 @@ public class ChannelController extends JPanel implements ActionListener, ListSel
private JButton mCopyChannelButton = new JButton(COPY_CHANNEL);
private JButton mDeleteChannelButton = new JButton(DELETE_CHANNEL);
public ChannelController(ChannelModel channelModel,
ChannelProcessingManager channelProcessingManager,
ChannelMapModel channelMapModel,
SourceManager sourceManager,
AliasModel aliasModel)
public ChannelController(ChannelModel channelModel, ChannelProcessingManager channelProcessingManager,
ChannelMapModel channelMapModel, SourceManager sourceManager, AliasModel aliasModel,
UserPreferences userPreferences)
{
mChannelModel = channelModel;
mChannelProcessingManager = channelProcessingManager;
mEditor = new ChannelEditor(channelModel, channelProcessingManager, channelMapModel, sourceManager, aliasModel);
mChannelModel.addListener(mEditor);
mChannelProcessingManager.addChannelEventListener(mEditor);
mUserPreferences = userPreferences;
init();
}
@@ -82,6 +90,7 @@ public class ChannelController extends JPanel implements ActionListener, ListSel
mChannelTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
mChannelTable.getSelectionModel().addListSelectionListener(this);
mChannelTable.setAutoCreateRowSorter(true);
mColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mChannelTable, TABLE_PREFERENCE_KEY);
mTableFilterHeader = new TableFilterHeader(mChannelTable, AutoChoices.ENABLED);
mTableFilterHeader.setFilterOnUpdates(true);

View File

@@ -78,6 +78,7 @@ import java.awt.AWTException;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -97,8 +98,12 @@ public class SDRTrunk implements Listener<TunerEvent>
private final static Logger mLog = LoggerFactory.getLogger(SDRTrunk.class);
private static final String PROPERTY_BROADCAST_STATUS_VISIBLE = "main.broadcast.status.visible";
private boolean mBroadcastStatusVisible;
private static final String BASE_WINDOW_NAME = "sdrtrunk.main.window";
private static final String CONTROLLER_PANEL_IDENTIFIER = BASE_WINDOW_NAME + ".control.panel";
private static final String SPECTRAL_PANEL_IDENTIFIER = BASE_WINDOW_NAME + ".spectral.panel";
private static final String WINDOW_FRAME_IDENTIFIER = BASE_WINDOW_NAME + ".frame";
private boolean mBroadcastStatusVisible;
private AudioPacketManager mAudioPacketManager;
private IconManager mIconManager;
private BroadcastStatusPanel mBroadcastStatusPanel;
@@ -271,15 +276,45 @@ public class SDRTrunk implements Listener<TunerEvent>
*/
mTitle = SystemProperties.getInstance().getApplicationName();
mMainGui.setTitle(mTitle);
mMainGui.setSize(new Dimension(1280, 800));
mMainGui.setLocationRelativeTo(null);
Point location = mUserPreferences.getSwingPreference().getLocation(WINDOW_FRAME_IDENTIFIER);
if(location != null)
{
mMainGui.setLocation(location);
}
else
{
mMainGui.setLocationRelativeTo(null);
}
mMainGui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mMainGui.addWindowListener(new ShutdownMonitor());
//Set preferred sizes to influence the split
Dimension dimension = mUserPreferences.getSwingPreference().getDimension(WINDOW_FRAME_IDENTIFIER);
mSpectralPanel.setPreferredSize(new Dimension(1280, 300));
mControllerPanel.setPreferredSize(new Dimension(1280, 500));
if(dimension != null)
{
Dimension spectral = mUserPreferences.getSwingPreference().getDimension(SPECTRAL_PANEL_IDENTIFIER);
if(spectral != null)
{
mSpectralPanel.setSize(spectral);
}
Dimension controller = mUserPreferences.getSwingPreference().getDimension(CONTROLLER_PANEL_IDENTIFIER);
if(controller != null)
{
mControllerPanel.setSize(controller);
}
mMainGui.setSize(dimension);
}
else
{
mMainGui.setSize(new Dimension(1280, 800));
}
mSplitPane = new JideSplitPane(JideSplitPane.VERTICAL_SPLIT);
mSplitPane.setDividerSize(5);
mSplitPane.add(mSpectralPanel);
@@ -424,6 +459,10 @@ public class SDRTrunk implements Listener<TunerEvent>
private void processShutdown()
{
mLog.info("Application shutdown started ...");
mUserPreferences.getSwingPreference().setLocation(WINDOW_FRAME_IDENTIFIER, mMainGui.getLocation());
mUserPreferences.getSwingPreference().setDimension(WINDOW_FRAME_IDENTIFIER, mMainGui.getSize());
mUserPreferences.getSwingPreference().setDimension(SPECTRAL_PANEL_IDENTIFIER, mSpectralPanel.getSize());
mUserPreferences.getSwingPreference().setDimension(CONTROLLER_PANEL_IDENTIFIER, mControllerPanel.getSize());
mJavaFxWindowManager.shutdown();
mLog.info("Stopping channels ...");
mChannelProcessingManager.shutdown();
@@ -443,7 +482,8 @@ public class SDRTrunk implements Listener<TunerEvent>
{
if(mBroadcastStatusPanel == null)
{
mBroadcastStatusPanel = new BroadcastStatusPanel(mBroadcastModel);
mBroadcastStatusPanel = new BroadcastStatusPanel(mBroadcastModel, mUserPreferences,
"application.broadcast.status.panel");
mBroadcastStatusPanel.setPreferredSize(new Dimension(880, 70));
mBroadcastStatusPanel.getTable().setEnabled(false);
}

View File

@@ -1,7 +1,7 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2018 Dennis Sheirer
* Copyright (C) 2014-2019 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
@@ -34,6 +34,7 @@ import io.github.dsheirer.identifier.Role;
import io.github.dsheirer.module.ProcessingChain;
import io.github.dsheirer.preference.PreferenceType;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
import io.github.dsheirer.sample.Listener;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
@@ -55,10 +56,12 @@ import java.util.List;
public class DecodeEventPanel extends JPanel implements Listener<ProcessingChain>
{
private final static Logger mLog = LoggerFactory.getLogger(DecodeEventPanel.class);
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger(DecodeEventPanel.class);
private static final String TABLE_PREFERENCE_KEY = "decode.event.panel";
private JTable mTable;
private JTableColumnWidthMonitor mTableColumnWidthMonitor;
private DecodeEventModel mEmptyDecodeEventModel;
private JScrollPane mEmptyScroller;
private IconManager mIconManager;
@@ -83,6 +86,7 @@ public class DecodeEventPanel extends JPanel implements Listener<ProcessingChain
mTable = new JTable(mEmptyDecodeEventModel);
mTable.setAutoCreateRowSorter(true);
mTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
mTableColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mTable, TABLE_PREFERENCE_KEY);
updateCellRenderers();
mEmptyScroller = new JScrollPane(mTable);
@@ -127,12 +131,17 @@ public class DecodeEventPanel extends JPanel implements Listener<ProcessingChain
public void receive(ProcessingChain processingChain)
{
EventQueue.invokeLater(() -> {
//Dispose the current column width monitor and recreate after we swap out the table model
mTableColumnWidthMonitor.dispose();
mTable.setModel(processingChain != null ? processingChain.getDecodeEventModel() : mEmptyDecodeEventModel);
if(processingChain != null)
{
updateCellRenderers();
}
mTableColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mTable, TABLE_PREFERENCE_KEY);
});
}
@@ -162,17 +171,6 @@ public class DecodeEventPanel extends JPanel implements Listener<ProcessingChain
if(value instanceof IdentifierCollection)
{
List<Identifier> identifiers = ((IdentifierCollection)value).getIdentifiers(mRole);
// if(identifiers.size() > 1)
// {
// StringBuilder sb = new StringBuilder();
// sb.append("Multiple Identifiers:\n");
// for(Identifier identifier: identifiers)
// {
// sb.append("ID:").append(identifier.debug()).append("\n");
// }
// mLog.debug(sb.toString());
// }
label.setText(format(identifiers));
}
else

View File

@@ -1,6 +1,7 @@
/*******************************************************************************
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2017 Dennis Sheirer
* Copyright (C) 2014-2019 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
@@ -14,17 +15,18 @@
*
* 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.module.decode.event;
import com.jidesoft.swing.JideButton;
import com.jidesoft.swing.JideSplitButton;
import io.github.dsheirer.controller.channel.ChannelProcessingManager;
import io.github.dsheirer.filter.FilterEditorPanel;
import io.github.dsheirer.filter.FilterSet;
import io.github.dsheirer.message.IMessage;
import io.github.dsheirer.module.ProcessingChain;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
import io.github.dsheirer.sample.Listener;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
@@ -49,26 +51,24 @@ import java.awt.event.MouseListener;
public class MessageActivityPanel extends JPanel implements Listener<ProcessingChain>
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger(MessageActivityPanel.class);
private static final String TABLE_PREFERENCE_KEY = "message.activity.panel";
private static MessageActivityModel EMPTY_MODEL = new MessageActivityModel();
private JTable mTable = new JTable(EMPTY_MODEL);
private JTableColumnWidthMonitor mTableColumnWidthMonitor;
private UserPreferences mUserPreferences;
private MessageManagementPanel mManagementPanel = new MessageManagementPanel();
private ChannelProcessingManager mChannelProcessingManager;
public MessageActivityPanel(ChannelProcessingManager channelProcessingManager)
public MessageActivityPanel(UserPreferences userPreferences)
{
mChannelProcessingManager = channelProcessingManager;
mUserPreferences = userPreferences;
setLayout(new MigLayout("insets 0 0 0 0", "[][grow,fill]", "[]0[grow,fill]"));
add(mManagementPanel, "span,growx");
add(new JScrollPane(mTable), "span,grow");
mTableColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mTable, TABLE_PREFERENCE_KEY);
}
@Override
@@ -79,6 +79,8 @@ public class MessageActivityPanel extends JPanel implements Listener<ProcessingC
@Override
public void run()
{
//Remove the existing table column width monitor and replace after swapping the table model
mTableColumnWidthMonitor.dispose();
mTable.setModel(processingChain != null ? processingChain.getMessageActivityModel() : EMPTY_MODEL);
mTable.getColumnModel().getColumn(0).setPreferredWidth(18);
@@ -93,6 +95,7 @@ public class MessageActivityPanel extends JPanel implements Listener<ProcessingC
{
mManagementPanel.disableButtons();
}
mTableColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mTable, TABLE_PREFERENCE_KEY);
}
});
}

View File

@@ -28,6 +28,7 @@ import io.github.dsheirer.preference.identifier.TalkgroupFormatPreference;
import io.github.dsheirer.preference.playlist.PlaylistPreference;
import io.github.dsheirer.preference.source.ChannelMultiFrequencyPreference;
import io.github.dsheirer.preference.source.TunerPreference;
import io.github.dsheirer.preference.swing.SwingPreference;
import io.github.dsheirer.sample.Listener;
/**
@@ -55,6 +56,7 @@ public class UserPreferences implements Listener<PreferenceType>
private PlaylistPreference mPlaylistPreference;
private TalkgroupFormatPreference mTalkgroupFormatPreference;
private TunerPreference mTunerPreference;
private SwingPreference mSwingPreference = new SwingPreference();
/**
* Constructs a new user preferences instance
@@ -120,6 +122,15 @@ public class UserPreferences implements Listener<PreferenceType>
return mTunerPreference;
}
/**
* Swing window location/size user preferences
*/
public SwingPreference getSwingPreference()
{
return mSwingPreference;
}
/**
* Loads the managed preferences
*/

View File

@@ -0,0 +1,154 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 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.preference.swing;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.util.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.JTable;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.TableColumnModel;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Monitors a JTable column model and persists column width changes to the user preferences. Restores
* previous column width preferred sizes on application restart.
*/
public class JTableColumnWidthMonitor
{
private static final Logger mLog = LoggerFactory.getLogger(JTableColumnWidthMonitor.class);
private UserPreferences mUserPreferences;
private JTable mTable;
private String mKey;
private ColumnResizeListener mColumnResizeListener = new ColumnResizeListener();
private AtomicBoolean mSaveInProgress = new AtomicBoolean();
/**
* Constructs a column width monitor.
*
* @param userPreferences to store column widths
* @param table to monitor for column width changes
* @param key that uniquely identifies the table to monitor
*/
public JTableColumnWidthMonitor(UserPreferences userPreferences, JTable table, String key)
{
mUserPreferences = userPreferences;
mTable = table;
mKey = key;
restoreColumnWidths();
mTable.getColumnModel().addColumnModelListener(mColumnResizeListener);
}
/**
* Prepares this monitor for disposal by unregistering as a listener to the table column model.
*/
public void dispose()
{
if(mTable != null && mColumnResizeListener != null)
{
mTable.getColumnModel().removeColumnModelListener(mColumnResizeListener);
}
mTable = null;
mUserPreferences = null;
}
/**
* Sets the preferred column widths on the table from persisted settings
*/
private void restoreColumnWidths()
{
TableColumnModel model = mTable.getColumnModel();
for(int x = 0; x < model.getColumnCount(); x++)
{
int width = mUserPreferences.getSwingPreference().getInt(getColumnKey(x), Integer.MAX_VALUE);
if(width != Integer.MAX_VALUE)
{
model.getColumn(x).setPreferredWidth(width);
}
}
}
/**
* Stores the current column widths to the user preferences
*/
private void storeColumnWidths()
{
TableColumnModel model = mTable.getColumnModel();
for(int x = 0; x < model.getColumnCount(); x++)
{
mUserPreferences.getSwingPreference().setInt(getColumnKey(x), model.getColumn(x).getWidth());
}
}
/**
* Constructs a preference key for the column number
*/
private String getColumnKey(int column)
{
return mKey + ".column." + column;
}
/**
* Table column model listener.
*/
class ColumnResizeListener implements TableColumnModelListener
{
@Override
public void columnMarginChanged(ChangeEvent e)
{
if(mSaveInProgress.compareAndSet(false, true))
{
ThreadPool.SCHEDULED.schedule(new ColumnWidthSaveTask(), 2, TimeUnit.SECONDS);
}
}
@Override
public void columnAdded(TableColumnModelEvent e){}
@Override
public void columnRemoved(TableColumnModelEvent e){}
@Override
public void columnMoved(TableColumnModelEvent e){}
@Override
public void columnSelectionChanged(ListSelectionEvent e){}
}
public class ColumnWidthSaveTask implements Runnable
{
@Override
public void run()
{
storeColumnWidths();
mSaveInProgress.set(false);
}
}
}

View File

@@ -0,0 +1,148 @@
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 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.preference.swing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.Dimension;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.util.prefs.Preferences;
/**
* User preference settings for Swing windows and components.
*/
public class SwingPreference
{
private static final Logger mLog = LoggerFactory.getLogger(SwingPreference.class);
private static final String LOCATION_X = ".x";
private static final String LOCATION_Y = ".y";
private static final String SIZE_HEIGHT = ".height";
private static final String SIZE_WIDTH = ".width";
private Preferences mPreferences = Preferences.userNodeForPackage(SwingPreference.class);
public SwingPreference()
{
}
/**
* Returns the stored swing related integer value
* @param key for accessing the value
* @param defaultValue to return if the value has not yet been persisted
* @return value or default value
*/
public int getInt(String key, int defaultValue)
{
return mPreferences.getInt(key, defaultValue);
}
/**
* Stores the swing related integer value
* @param key to reference the value
*/
public void setInt(String key, int value)
{
mPreferences.putInt(key, value);
}
/**
* Returns the persisted window location for the specified preference key.
* @param key identifying the window
* @return location or null
*/
public Point getLocation(String key)
{
int x = mPreferences.getInt(key + LOCATION_X, Integer.MAX_VALUE);
int y = mPreferences.getInt(key + LOCATION_Y, Integer.MAX_VALUE);
if(x != Integer.MAX_VALUE && y != Integer.MAX_VALUE)
{
Point location = new Point(x,y);
if(isValidWindowLocation(location))
{
return location;
}
}
return null;
}
/**
* Stores the current window location
* @param key to identify the window
* @param location to persist
*/
public void setLocation(String key, Point location)
{
mPreferences.putInt(key + LOCATION_X, location.x);
mPreferences.putInt(key + LOCATION_Y, location.y);
}
/**
* Returns the stored size/dimension of the window identified by the key argument.
* @param key to identify the window
* @return dimension or null
*/
public Dimension getDimension(String key)
{
int height = mPreferences.getInt(key + SIZE_HEIGHT, Integer.MAX_VALUE);
int width = mPreferences.getInt(key + SIZE_WIDTH, Integer.MAX_VALUE);
if(height != Integer.MAX_VALUE && width != Integer.MAX_VALUE)
{
return new Dimension(width, height);
}
return null;
}
public void setDimension(String key, Dimension dimension)
{
mPreferences.putInt(key + SIZE_HEIGHT, dimension.height);
mPreferences.putInt(key + SIZE_WIDTH, dimension.width);
}
/**
* Tests a stored window location to determine if it can be displayed on the currently available
* graphics display devices so that we don't position a window at a previously available location
* that is not currently available.
*
* @param location to test
* @return true if the location is displayable.
*/
private boolean isValidWindowLocation(Point location)
{
for(GraphicsDevice gd:GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices())
{
if(gd.getDefaultConfiguration().getBounds().contains(location))
{
return true;
}
}
return false;
}
}

View File

@@ -1,24 +1,28 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014-2016 Dennis Sheirer
/*
* ******************************************************************************
* sdrtrunk
* Copyright (C) 2014-2019 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 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.
* 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/>
******************************************************************************/
* 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.source.tuner;
import com.jidesoft.swing.JideSplitPane;
import io.github.dsheirer.preference.UserPreferences;
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
import io.github.dsheirer.sample.Listener;
import io.github.dsheirer.source.tuner.TunerEvent.Event;
import net.miginfocom.swing.MigLayout;
@@ -49,17 +53,21 @@ public class TunerViewPanel extends JPanel
{
private static final long serialVersionUID = 1L;
private final static Logger mLog = LoggerFactory.getLogger(TunerViewPanel.class);
private static final String TABLE_PREFERENCE_KEY = "tuner.view.panel";
private TunerModel mTunerModel;
private JTable mTunerTable;
private JTableColumnWidthMonitor mColumnWidthMonitor;
private TableRowSorter<TunerModel> mRowSorter;
private JideSplitPane mSplitPane;
private TunerEditor mTunerEditor;
private UserPreferences mUserPreferences;
public TunerViewPanel(TunerModel tunerModel)
public TunerViewPanel(TunerModel tunerModel, UserPreferences userPreferences)
{
mTunerModel = tunerModel;
mTunerEditor = new TunerEditor(mTunerModel.getTunerConfigurationModel());
mUserPreferences = userPreferences;
init();
}
@@ -149,6 +157,7 @@ public class TunerViewPanel extends JPanel
TableCellRenderer renderer = new LinkCellRenderer();
mTunerTable.getColumnModel().getColumn(TunerModel.SPECTRAL_DISPLAY_NEW).setCellRenderer(renderer);
mColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mTunerTable, TABLE_PREFERENCE_KEY);
JScrollPane listScroller = new JScrollPane(mTunerTable);
listScroller.setPreferredSize(new Dimension(400, 20));