#82 WIP - reorganizing icon management and extracting icon model from the settings manager.

This commit is contained in:
Denny
2017-01-08 15:01:53 -05:00
parent 4481560c41
commit 488dc9da4c
17 changed files with 1796 additions and 1182 deletions

View File

@@ -1,369 +1,356 @@
package alias;
import audio.broadcast.BroadcastModel;
import com.jidesoft.swing.JideSplitPane;
import gui.editor.Editor;
import icon.IconManager;
import net.coderazzi.filters.gui.AutoChoices;
import net.coderazzi.filters.gui.TableFilterHeader;
import net.miginfocom.swing.MigLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Rectangle;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import net.coderazzi.filters.gui.AutoChoices;
import net.coderazzi.filters.gui.TableFilterHeader;
import net.miginfocom.swing.MigLayout;
import settings.SettingsManager;
import com.jidesoft.swing.JideSplitPane;
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 long serialVersionUID = 1L;
private AliasModel mAliasModel;
private JTable mAliasTable;
private TableFilterHeader mTableFilterHeader;
private AliasEditor mAliasEditor;
private MultipleAliasEditor mMultipleAliasEditor;
private JideSplitPane mSplitPane;
private static final String NEW_ALIAS = "New";
private static final String COPY_ALIAS = "Copy";
private static final String DELETE_ALIAS = "Delete";
private JButton mNewButton = new JButton( NEW_ALIAS );
private JButton mCopyButton = new JButton( COPY_ALIAS );
private JButton mDeleteButton = new JButton( DELETE_ALIAS );
private IconCellRenderer mIconCellRenderer;
private AliasModel mAliasModel;
private JTable mAliasTable;
private TableFilterHeader mTableFilterHeader;
private AliasEditor mAliasEditor;
private MultipleAliasEditor mMultipleAliasEditor;
private JideSplitPane mSplitPane;
public AliasController(AliasModel aliasModel, BroadcastModel broadcastModel, SettingsManager settingsManager )
{
mAliasModel = aliasModel;
private static final String NEW_ALIAS = "New";
private static final String COPY_ALIAS = "Copy";
private static final String DELETE_ALIAS = "Delete";
mAliasEditor = new AliasEditor( mAliasModel, broadcastModel, settingsManager );
mMultipleAliasEditor = new MultipleAliasEditor( mAliasModel, broadcastModel, settingsManager );
private JButton mNewButton = new JButton(NEW_ALIAS);
private JButton mCopyButton = new JButton(COPY_ALIAS);
private JButton mDeleteButton = new JButton(DELETE_ALIAS);
mIconCellRenderer = new IconCellRenderer( settingsManager );
init();
mAliasModel.addListener( mAliasEditor );
}
private void init()
{
setLayout( new MigLayout( "insets 0 0 0 0",
"[grow,fill]",
"[grow,fill]") );
private IconCellRenderer mIconCellRenderer;
//System Configuration View and Editor
mAliasTable = new JTable( mAliasModel );
mAliasTable.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
mAliasTable.getSelectionModel().addListSelectionListener( this );
mAliasTable.setAutoCreateRowSorter( true );
mAliasTable.getColumnModel().getColumn( AliasModel.COLUMN_COLOR )
.setCellRenderer( new ColorCellRenderer() );
mAliasTable.getColumnModel().getColumn( AliasModel.COLUMN_ICON )
.setCellRenderer( mIconCellRenderer );
public AliasController(AliasModel aliasModel, BroadcastModel broadcastModel, IconManager iconManager)
{
mAliasModel = aliasModel;
mTableFilterHeader = new TableFilterHeader( mAliasTable, AutoChoices.ENABLED );
mTableFilterHeader.setFilterOnUpdates( true );
JScrollPane tableScroller = new JScrollPane( mAliasTable );
mAliasEditor = new AliasEditor(mAliasModel, broadcastModel, iconManager);
mMultipleAliasEditor = new MultipleAliasEditor(mAliasModel, broadcastModel, iconManager);
JPanel buttonsPanel = new JPanel();
buttonsPanel.setLayout(
new MigLayout( "insets 0 0 0 0", "[grow,fill][grow,fill][grow,fill]", "[]") );
mIconCellRenderer = new IconCellRenderer(iconManager);
mNewButton.addActionListener( this );
mNewButton.setToolTipText( "Adds a new alias" );
buttonsPanel.add( mNewButton );
mCopyButton.addActionListener( this );
mCopyButton.setEnabled( false );
mCopyButton.setToolTipText( "Creates a copy of the currently selected alias and adds it" );
buttonsPanel.add( mCopyButton );
init();
mDeleteButton.addActionListener( this );
mDeleteButton.setEnabled( false );
mDeleteButton.setToolTipText( "Deletes the currently selected alias" );
buttonsPanel.add( mDeleteButton );
JPanel listAndButtonsPanel = new JPanel();
mAliasModel.addListener(mAliasEditor);
}
listAndButtonsPanel.setLayout(
new MigLayout( "insets 0 0 0 0", "[grow,fill]", "[grow,fill][]") );
private void init()
{
setLayout(new MigLayout("insets 0 0 0 0",
"[grow,fill]",
"[grow,fill]"));
listAndButtonsPanel.add( tableScroller, "wrap" );
listAndButtonsPanel.add( buttonsPanel );
mSplitPane = new JideSplitPane( JideSplitPane.HORIZONTAL_SPLIT );
mSplitPane.setDividerSize( 5 );
mSplitPane.setShowGripper( true );
mSplitPane.add( listAndButtonsPanel );
mSplitPane.add( mAliasEditor );
//System Configuration View and Editor
mAliasTable = new JTable(mAliasModel);
mAliasTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
mAliasTable.getSelectionModel().addListSelectionListener(this);
mAliasTable.setAutoCreateRowSorter(true);
add( mSplitPane );
}
mAliasTable.getColumnModel().getColumn(AliasModel.COLUMN_COLOR)
.setCellRenderer(new ColorCellRenderer());
/**
* Sets the editor argument as the currently visible alias editor
*/
private void setEditor( Editor<?> editor )
{
if( mSplitPane.getComponentCount() == 3 )
{
Component component = mSplitPane.getComponent( 2 );
if( component instanceof Editor<?> && component != editor )
{
//Get current divider location so that we can reapply it after
//changing out the editors, so that the interface doesn't move
int location = mSplitPane.getDividerLocation( 0 );
((Editor<?>)component).setItem( null );
mSplitPane.remove( component );
editor.setPreferredSize( new Dimension( 100, 100 ) );
mSplitPane.add( editor );
mSplitPane.validate();
mSplitPane.setDividerLocation( 0, location );
mSplitPane.repaint();
}
}
}
private Alias getAlias( int selectedRow )
{
if( selectedRow >= 0 )
{
int index = mAliasTable.convertRowIndexToModel( selectedRow );
return mAliasModel.getAliasAtIndex( index );
}
return null;
}
mAliasTable.getColumnModel().getColumn(AliasModel.COLUMN_ICON)
.setCellRenderer(mIconCellRenderer);
@Override
public void valueChanged( ListSelectionEvent event )
{
//Limits event firing to only when selection is complete
if( !event.getValueIsAdjusting() )
{
int[] selectedRows = mAliasTable.getSelectedRows();
mTableFilterHeader = new TableFilterHeader(mAliasTable, AutoChoices.ENABLED);
mTableFilterHeader.setFilterOnUpdates(true);
if( selectedRows.length == 0 )
{
mAliasEditor.setItem( null );
mCopyButton.setEnabled( false );
mDeleteButton.setEnabled( false );
}
else if( selectedRows.length == 1 )
{
setEditor( mAliasEditor );
Alias selectedAlias = getAlias( selectedRows[ 0 ] );
mAliasEditor.setItem( selectedAlias );
if( selectedAlias != null )
{
mCopyButton.setEnabled( true );
mDeleteButton.setEnabled( true );
}
else
{
mCopyButton.setEnabled( false );
mDeleteButton.setEnabled( false );
}
}
else
{
setEditor( mMultipleAliasEditor );
mCopyButton.setEnabled( true );
mDeleteButton.setEnabled( true );
JScrollPane tableScroller = new JScrollPane(mAliasTable);
List<Alias> selectedAliases = new ArrayList<Alias>();
for( int selectedRow: selectedRows )
{
Alias alias = getAlias( selectedRow );
JPanel buttonsPanel = new JPanel();
selectedAliases.add( alias );
}
mMultipleAliasEditor.setItem( selectedAliases );
}
}
}
buttonsPanel.setLayout(
new MigLayout("insets 0 0 0 0", "[grow,fill][grow,fill][grow,fill]", "[]"));
/**
* Adds the alias to the alias table/model and scrolls the view it
*/
private void addAlias( Alias alias )
{
//HACK: when inserting a row to the model, the JTable gets
//notified and attempts to tell the coderazzi table filter
//adaptive choices filter to refresh before the table filter is
//notified of the row additions, causing an index out of bounds
//exception. We turn off adaptive choices temporarily, add the
//channel, and turn on adaptive choices again.
mTableFilterHeader.setAdaptiveChoices( false );
int index = mAliasModel.addAlias( alias );
mNewButton.addActionListener(this);
mNewButton.setToolTipText("Adds a new alias");
buttonsPanel.add(mNewButton);
mTableFilterHeader.setAdaptiveChoices( true );
mCopyButton.addActionListener(this);
mCopyButton.setEnabled(false);
mCopyButton.setToolTipText("Creates a copy of the currently selected alias and adds it");
buttonsPanel.add(mCopyButton);
if( index >= 0 )
{
int translatedIndex = mAliasTable.convertRowIndexToView( index );
mAliasTable.setRowSelectionInterval( translatedIndex, translatedIndex );
mAliasTable.scrollRectToVisible(
new Rectangle( mAliasTable.getCellRect( translatedIndex, 0, true ) ) );
}
}
private List<Alias> getSelectedAliases()
{
List<Alias> selected = new ArrayList<>();
int[] rows = mAliasTable.getSelectedRows();
mDeleteButton.addActionListener(this);
mDeleteButton.setEnabled(false);
mDeleteButton.setToolTipText("Deletes the currently selected alias");
buttonsPanel.add(mDeleteButton);
for( int row: rows )
{
if( row >= 0 )
{
Alias alias = mAliasModel.getAliasAtIndex( mAliasTable.convertRowIndexToModel( row ) );
if( alias != null )
{
selected.add( alias );
}
}
}
return selected;
}
JPanel listAndButtonsPanel = new JPanel();
/**
* Responds to New, Copy and Delete Channel button invocations
*/
@Override
public void actionPerformed( ActionEvent event )
{
switch( event.getActionCommand() )
{
case NEW_ALIAS:
addAlias( new Alias( "New Alias" ) );
break;
case COPY_ALIAS:
for( Alias alias: getSelectedAliases() )
{
addAlias( AliasFactory.copyOf( alias ) );
}
break;
case DELETE_ALIAS:
List<Alias> toDelete = getSelectedAliases();
listAndButtonsPanel.setLayout(
new MigLayout("insets 0 0 0 0", "[grow,fill]", "[grow,fill][]"));
if( toDelete != null && !toDelete.isEmpty() )
{
String title = toDelete.size() == 1 ? "Delete Alias?" : "Delete Aliases?";
String prompt = toDelete.size() == 1 ? "Do you want to delete this alias?" :
"Do you want to delete these " + toDelete.size() + " aliases?";
int choice = JOptionPane.showConfirmDialog( AliasController.this,
prompt, title, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE );
if( choice == JOptionPane.YES_OPTION )
{
for( Alias alias: toDelete )
{
mAliasModel.removeAlias( alias );
}
}
}
break;
default:
break;
}
}
listAndButtonsPanel.add(tableScroller, "wrap");
listAndButtonsPanel.add(buttonsPanel);
/**
* Colorizes the cell based on the cell's integer value
*/
public class ColorCellRenderer extends DefaultTableCellRenderer
{
private static final long serialVersionUID = 1L;
mSplitPane = new JideSplitPane(JideSplitPane.HORIZONTAL_SPLIT);
mSplitPane.setDividerSize(5);
mSplitPane.setShowGripper(true);
mSplitPane.add(listAndButtonsPanel);
mSplitPane.add(mAliasEditor);
@Override
public Component getTableCellRendererComponent( JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column )
{
JLabel label = (JLabel)super.getTableCellRendererComponent( table,
value, isSelected, hasFocus, row, column );
add(mSplitPane);
}
label.setBackground( new Color( (int)value ) );
label.setText( "" );
return label;
}
}
/**
* Displays cell's icon and name
*/
public class IconCellRenderer extends DefaultTableCellRenderer
{
private static final long serialVersionUID = 1L;
private SettingsManager mSettingsManager;
public IconCellRenderer( SettingsManager settingsManager )
{
mSettingsManager = settingsManager;
}
/**
* Sets the editor argument as the currently visible alias editor
*/
private void setEditor(Editor<?> editor)
{
if(mSplitPane.getComponentCount() == 3)
{
Component component = mSplitPane.getComponent(2);
@Override
public Component getTableCellRendererComponent( JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column )
{
JLabel label = (JLabel)super.getTableCellRendererComponent( table,
value, isSelected, hasFocus, row, column );
if(component instanceof Editor<?> && component != editor)
{
//Get current divider location so that we can reapply it after
//changing out the editors, so that the interface doesn't move
int location = mSplitPane.getDividerLocation(0);
ImageIcon icon = mSettingsManager.getImageIcon( label.getText(), 12 );
((Editor<?>) component).setItem(null);
if( icon != null )
{
label.setIcon( icon );
}
return label;
}
}
mSplitPane.remove(component);
editor.setPreferredSize(new Dimension(100, 100));
mSplitPane.add(editor);
mSplitPane.validate();
mSplitPane.setDividerLocation(0, location);
mSplitPane.repaint();
}
}
}
private Alias getAlias(int selectedRow)
{
if(selectedRow >= 0)
{
int index = mAliasTable.convertRowIndexToModel(selectedRow);
return mAliasModel.getAliasAtIndex(index);
}
return null;
}
@Override
public void valueChanged(ListSelectionEvent event)
{
//Limits event firing to only when selection is complete
if(!event.getValueIsAdjusting())
{
int[] selectedRows = mAliasTable.getSelectedRows();
if(selectedRows.length == 0)
{
mAliasEditor.setItem(null);
mCopyButton.setEnabled(false);
mDeleteButton.setEnabled(false);
}
else if(selectedRows.length == 1)
{
setEditor(mAliasEditor);
Alias selectedAlias = getAlias(selectedRows[0]);
mAliasEditor.setItem(selectedAlias);
if(selectedAlias != null)
{
mCopyButton.setEnabled(true);
mDeleteButton.setEnabled(true);
}
else
{
mCopyButton.setEnabled(false);
mDeleteButton.setEnabled(false);
}
}
else
{
setEditor(mMultipleAliasEditor);
mCopyButton.setEnabled(true);
mDeleteButton.setEnabled(true);
List<Alias> selectedAliases = new ArrayList<Alias>();
for(int selectedRow : selectedRows)
{
Alias alias = getAlias(selectedRow);
selectedAliases.add(alias);
}
mMultipleAliasEditor.setItem(selectedAliases);
}
}
}
/**
* Adds the alias to the alias table/model and scrolls the view it
*/
private void addAlias(Alias alias)
{
//HACK: when inserting a row to the model, the JTable gets
//notified and attempts to tell the coderazzi table filter
//adaptive choices filter to refresh before the table filter is
//notified of the row additions, causing an index out of bounds
//exception. We turn off adaptive choices temporarily, add the
//channel, and turn on adaptive choices again.
mTableFilterHeader.setAdaptiveChoices(false);
int index = mAliasModel.addAlias(alias);
mTableFilterHeader.setAdaptiveChoices(true);
if(index >= 0)
{
int translatedIndex = mAliasTable.convertRowIndexToView(index);
mAliasTable.setRowSelectionInterval(translatedIndex, translatedIndex);
mAliasTable.scrollRectToVisible(
new Rectangle(mAliasTable.getCellRect(translatedIndex, 0, true)));
}
}
private List<Alias> getSelectedAliases()
{
List<Alias> selected = new ArrayList<>();
int[] rows = mAliasTable.getSelectedRows();
for(int row : rows)
{
if(row >= 0)
{
Alias alias = mAliasModel.getAliasAtIndex(mAliasTable.convertRowIndexToModel(row));
if(alias != null)
{
selected.add(alias);
}
}
}
return selected;
}
/**
* Responds to New, Copy and Delete Channel button invocations
*/
@Override
public void actionPerformed(ActionEvent event)
{
switch(event.getActionCommand())
{
case NEW_ALIAS:
addAlias(new Alias("New Alias"));
break;
case COPY_ALIAS:
for(Alias alias : getSelectedAliases())
{
addAlias(AliasFactory.copyOf(alias));
}
break;
case DELETE_ALIAS:
List<Alias> toDelete = getSelectedAliases();
if(toDelete != null && !toDelete.isEmpty())
{
String title = toDelete.size() == 1 ? "Delete Alias?" : "Delete Aliases?";
String prompt = toDelete.size() == 1 ? "Do you want to delete this alias?" :
"Do you want to delete these " + toDelete.size() + " aliases?";
int choice = JOptionPane.showConfirmDialog(AliasController.this,
prompt, title, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
if(choice == JOptionPane.YES_OPTION)
{
for(Alias alias : toDelete)
{
mAliasModel.removeAlias(alias);
}
}
}
break;
default:
break;
}
}
/**
* Colorizes the cell based on the cell's integer value
*/
public class ColorCellRenderer extends DefaultTableCellRenderer
{
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column)
{
JLabel label = (JLabel) super.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
label.setBackground(new Color((int) value));
label.setText("");
return label;
}
}
/**
* Displays cell's icon and name
*/
public class IconCellRenderer extends DefaultTableCellRenderer
{
private static final long serialVersionUID = 1L;
private IconManager mIconManager;
public IconCellRenderer(IconManager iconManager)
{
mIconManager = iconManager;
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column)
{
JLabel label = (JLabel) super.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
ImageIcon icon = mIconManager.getIcon(label.getText(), 12);
if(icon != null)
{
label.setIcon(icon);
}
return label;
}
}
}

View File

@@ -28,6 +28,7 @@ import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JSeparator;
import icon.IconManager;
import net.miginfocom.swing.MigLayout;
import sample.Listener;
import settings.SettingsManager;
@@ -50,10 +51,10 @@ public class AliasEditor extends Editor<Alias>
private AliasIdentifierEditor mAliasIdentifierEditor;
private AliasActionEditor mAliasActionEditor;
public AliasEditor(AliasModel aliasModel, BroadcastModel broadcastModel, SettingsManager settingsManager )
public AliasEditor(AliasModel aliasModel, BroadcastModel broadcastModel, IconManager iconManager )
{
mAliasModel = aliasModel;
mAliasNameEditor = new AliasNameEditor( mAliasModel, settingsManager );
mAliasNameEditor = new AliasNameEditor( mAliasModel, iconManager );
mAliasIdentifierEditor = new AliasIdentifierEditor( aliasModel, broadcastModel );
mAliasActionEditor = new AliasActionEditor( aliasModel );

View File

@@ -1,291 +1,278 @@
package alias;
import alias.AliasEvent.Event;
import gui.editor.Editor;
import icon.Icon;
import icon.IconCellRenderer;
import icon.IconManager;
import map.MapIcon;
import net.miginfocom.swing.MigLayout;
import settings.SettingsManager;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import map.IconManager;
import map.MapIcon;
import map.MapIconListCellRenderer;
import net.miginfocom.swing.MigLayout;
import settings.SettingsManager;
import alias.AliasEvent.Event;
public class AliasNameEditor extends Editor<Alias>
{
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
private static ComboBoxModel<String> EMPTY_MODEL = new DefaultComboBoxModel<>();
private static ComboBoxModel<String> EMPTY_MODEL = new DefaultComboBoxModel<>();
private JComboBox<String> mListCombo = new JComboBox<>( EMPTY_MODEL );
private JComboBox<String> mGroupCombo = new JComboBox<>( EMPTY_MODEL );
private JComboBox<MapIcon> mMapIconCombo;
private JComboBox<String> mListCombo = new JComboBox<>(EMPTY_MODEL);
private JComboBox<String> mGroupCombo = new JComboBox<>(EMPTY_MODEL);
private JComboBox<Icon> mIconCombo;
private JTextField mName;
private JButton mButtonColor;
private JButton mBtnIconManager;
private AliasModel mAliasModel;
private SettingsManager mSettingsManager;
public AliasNameEditor( AliasModel aliasModel, SettingsManager settingsManager )
{
mAliasModel = aliasModel;
mSettingsManager = settingsManager;
init();
}
private void init()
{
setLayout( new MigLayout( "fill,wrap 2", "[right][grow,fill]",
"[][][][][][][grow]" ) );
private IconManager mIconManager;
add( new JLabel( "Name:" ) );
mName = new JTextField();
mName.getDocument().addDocumentListener( new DocumentListener()
{
@Override
public void removeUpdate( DocumentEvent e )
{
setModified( true );
}
@Override
public void insertUpdate( DocumentEvent e )
{
setModified( true );
}
@Override
public void changedUpdate( DocumentEvent e ){}
} );
add( mName, "wrap" );
public AliasNameEditor(AliasModel aliasModel, IconManager iconManager)
{
mAliasModel = aliasModel;
mIconManager = iconManager;
add( new JLabel( "List:" ) );
mListCombo.setEditable( true );
mListCombo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
if( mListCombo.getSelectedItem() != null )
{
List<String> groups = mAliasModel
.getGroupNames( (String)mListCombo.getSelectedItem() );
if( groups.isEmpty() )
{
mGroupCombo.setModel( EMPTY_MODEL );
}
else
{
mGroupCombo.setModel( new DefaultComboBoxModel<String>(
groups.toArray( new String[ groups.size() ] ) ) );;
}
}
setModified( true );
}
} );
add( mListCombo, "wrap" );
init();
}
add( new JLabel( "Group:" ) );
mGroupCombo.setEditable( true );
mGroupCombo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( mGroupCombo, "wrap" );
private void init()
{
setLayout(new MigLayout("fill,wrap 2", "[right][grow,fill]",
"[][][][][][][grow]"));
add( new JLabel( "Color:" ) );
mButtonColor = new JButton( "Select ..." );
mButtonColor.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
add(new JLabel("Name:"));
mName = new JTextField();
mName.getDocument().addDocumentListener(new DocumentListener()
{
@Override
public void removeUpdate(DocumentEvent e)
{
Color newColor = JColorChooser.showDialog(
AliasNameEditor.this,
"Choose color for this alias",
( hasItem() ? getItem().getMapColor() : null ) );
if( newColor != null )
{
mButtonColor.setForeground( newColor );
mButtonColor.setBackground( newColor );
setModified( true );
}
setModified(true);
}
} );
add( mButtonColor, "wrap" );
add( new JLabel( "Icon:" ) );
mMapIconCombo = new JComboBox<MapIcon>( mSettingsManager.getMapIcons() );
MapIconListCellRenderer renderer = new MapIconListCellRenderer();
renderer.setPreferredSize( new Dimension( 200, 30 ) );
mMapIconCombo.setRenderer( renderer );
mMapIconCombo.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
setModified( true );
}
} );
add( mMapIconCombo, "wrap" );
//Dummy place holder
add( new JLabel() );
mBtnIconManager = new JButton( "Icon Manager" );
mBtnIconManager.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
@Override
public void insertUpdate(DocumentEvent e)
{
final IconManager iconManager =
new IconManager( mSettingsManager, AliasNameEditor.this );
EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
iconManager.setVisible( true );
}
} );
setModified(true);
}
} );
add( mBtnIconManager, "span 2,wrap" );
setModified( false );
}
@Override
public void changedUpdate(DocumentEvent e)
{
}
});
add(mName, "wrap");
@Override
public void setItem( Alias alias )
{
super.setItem( alias );
if( hasItem() )
{
mName.setText( alias.getName() );
List<String> listNames = mAliasModel.getListNames();
if( listNames.isEmpty() )
{
mListCombo.setModel( EMPTY_MODEL );
}
else
{
mListCombo.setModel( new DefaultComboBoxModel<String>(
listNames.toArray( new String[ listNames.size() ] ) ) );;
}
mListCombo.setSelectedItem( alias.getList() );
List<String> groupNames = mAliasModel.getGroupNames( alias.getList() );
if( groupNames.isEmpty() )
{
mGroupCombo.setModel( EMPTY_MODEL );
}
else
{
mGroupCombo.setModel( new DefaultComboBoxModel<String>(
groupNames.toArray( new String[ groupNames.size() ] ) ) );;
}
mGroupCombo.setSelectedItem( alias.getGroup() );
Color color = alias.getMapColor();
mButtonColor.setBackground( color );
mButtonColor.setForeground( color );
String iconName = alias.getIconName();
if( iconName == null )
{
iconName = SettingsManager.DEFAULT_ICON;
}
MapIcon savedIcon = mSettingsManager.getMapIcon( iconName );
if( savedIcon != null )
{
mMapIconCombo.setSelectedItem( savedIcon );
}
}
else
{
mListCombo.setModel( EMPTY_MODEL );
mGroupCombo.setModel( EMPTY_MODEL );
mName.setText( null );
mButtonColor.setBackground( getBackground() );
mButtonColor.setForeground( getForeground() );
}
repaint();
setModified( false );
}
add(new JLabel("List:"));
mListCombo.setEditable(true);
mListCombo.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
if(mListCombo.getSelectedItem() != null)
{
List<String> groups = mAliasModel
.getGroupNames((String) mListCombo.getSelectedItem());
@Override
public void save()
{
if( hasItem() && isModified() )
{
Alias alias = getItem();
if( mListCombo.getSelectedItem() != null )
{
alias.setList( (String)mListCombo.getSelectedItem() );
}
if( mGroupCombo.getSelectedItem() != null )
{
alias.setGroup( (String)mGroupCombo.getSelectedItem() );
}
if(groups.isEmpty())
{
mGroupCombo.setModel(EMPTY_MODEL);
}
else
{
mGroupCombo.setModel(new DefaultComboBoxModel<String>(
groups.toArray(new String[groups.size()])));
;
}
}
alias.setName( mName.getText() );
setModified(true);
}
});
add(mListCombo, "wrap");
alias.setColor( mButtonColor.getBackground().getRGB() );
add(new JLabel("Group:"));
mGroupCombo.setEditable(true);
mGroupCombo.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mGroupCombo, "wrap");
if( mMapIconCombo.getSelectedItem() != null )
{
alias.setIconName( ((MapIcon)mMapIconCombo.getSelectedItem()).getName() );
}
setModified( false );
add(new JLabel("Color:"));
//Broadcast an alias change event to save the updates
mAliasModel.broadcast( new AliasEvent( getItem(), Event.CHANGE ) );
}
}
mButtonColor = new JButton("Select ...");
mButtonColor.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
Color newColor = JColorChooser.showDialog(
AliasNameEditor.this,
"Choose color for this alias",
(hasItem() ? getItem().getMapColor() : null));
if(newColor != null)
{
mButtonColor.setForeground(newColor);
mButtonColor.setBackground(newColor);
setModified(true);
}
}
});
add(mButtonColor, "wrap");
add(new JLabel("Icon:"));
mIconCombo = new JComboBox<Icon>(mIconManager.getIcons());
IconCellRenderer renderer = new IconCellRenderer(mIconManager);
renderer.setPreferredSize(new Dimension(200, 30));
mIconCombo.setRenderer( renderer );
mIconCombo.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
setModified(true);
}
});
add(mIconCombo, "wrap");
//Dummy place holder
add(new JLabel());
mBtnIconManager = new JButton("Icon Manager");
mBtnIconManager.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent arg0)
{
mIconManager.showEditor(AliasNameEditor.this);
}
});
add(mBtnIconManager, "span 2,wrap");
setModified(false);
}
@Override
public void setItem(Alias alias)
{
super.setItem(alias);
if(hasItem())
{
mName.setText(alias.getName());
List<String> listNames = mAliasModel.getListNames();
if(listNames.isEmpty())
{
mListCombo.setModel(EMPTY_MODEL);
}
else
{
mListCombo.setModel(new DefaultComboBoxModel<String>(
listNames.toArray(new String[listNames.size()])));
;
}
mListCombo.setSelectedItem(alias.getList());
List<String> groupNames = mAliasModel.getGroupNames(alias.getList());
if(groupNames.isEmpty())
{
mGroupCombo.setModel(EMPTY_MODEL);
}
else
{
mGroupCombo.setModel(new DefaultComboBoxModel<String>(
groupNames.toArray(new String[groupNames.size()])));
;
}
mGroupCombo.setSelectedItem(alias.getGroup());
Color color = alias.getMapColor();
mButtonColor.setBackground(color);
mButtonColor.setForeground(color);
String iconName = alias.getIconName();
if(iconName == null)
{
iconName = SettingsManager.DEFAULT_ICON;
}
Icon savedIcon = mIconManager.getModel().getIcon(iconName);
if(savedIcon != null)
{
mIconCombo.setSelectedItem(savedIcon);
}
}
else
{
mListCombo.setModel(EMPTY_MODEL);
mGroupCombo.setModel(EMPTY_MODEL);
mName.setText(null);
mButtonColor.setBackground(getBackground());
mButtonColor.setForeground(getForeground());
}
repaint();
setModified(false);
}
@Override
public void save()
{
if(hasItem() && isModified())
{
Alias alias = getItem();
if(mListCombo.getSelectedItem() != null)
{
alias.setList((String) mListCombo.getSelectedItem());
}
if(mGroupCombo.getSelectedItem() != null)
{
alias.setGroup((String) mGroupCombo.getSelectedItem());
}
alias.setName(mName.getText());
alias.setColor(mButtonColor.getBackground().getRGB());
if(mIconCombo.getSelectedItem() != null)
{
alias.setIconName(((MapIcon) mIconCombo.getSelectedItem()).getName());
}
setModified(false);
//Broadcast an alias change event to save the updates
mAliasModel.broadcast(new AliasEvent(getItem(), Event.CHANGE));
}
}
}

View File

@@ -3,14 +3,13 @@ package alias;
import alias.id.AliasIDType;
import alias.id.broadcast.BroadcastChannel;
import audio.broadcast.BroadcastModel;
import com.sun.org.apache.xpath.internal.operations.Mult;
import gui.editor.Editor;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
@@ -24,16 +23,16 @@ import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import map.IconManager;
import icon.Icon;
import icon.IconManager;
import map.MapIcon;
import map.MapIconListCellRenderer;
import icon.IconCellRenderer;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sample.Listener;
import settings.SettingsManager;
import alias.AliasEvent.Event;
import alias.id.priority.Priority;
@@ -54,7 +53,7 @@ public class MultipleAliasEditor extends Editor<List<Alias>>
private JCheckBox mGroupCheckBox = new JCheckBox("Group");
private JComboBox<String> mGroupCombo = new JComboBox<>();
private JCheckBox mIconCheckBox = new JCheckBox("Icon");
private JComboBox<MapIcon> mMapIconCombo;
private JComboBox<Icon> mIconCombo;
private JCheckBox mColorCheckBox = new JCheckBox("Color");
private JButton mButtonColor;
private JButton mBtnIconManager;
@@ -68,13 +67,13 @@ public class MultipleAliasEditor extends Editor<List<Alias>>
private AliasModel mAliasModel;
private BroadcastModel mBroadcastModel;
private SettingsManager mSettingsManager;
private IconManager mIconManager;
public MultipleAliasEditor(AliasModel aliasModel, BroadcastModel broadcastModel, SettingsManager settingsManager)
public MultipleAliasEditor(AliasModel aliasModel, BroadcastModel broadcastModel, IconManager iconManager)
{
mAliasModel = aliasModel;
mBroadcastModel = broadcastModel;
mSettingsManager = settingsManager;
mIconManager = iconManager;
mAliasModel.addListener(this);
@@ -139,12 +138,12 @@ public class MultipleAliasEditor extends Editor<List<Alias>>
add(mIconCheckBox);
mMapIconCombo = new JComboBox<MapIcon>(mSettingsManager.getMapIcons());
mIconCombo = new JComboBox<Icon>(mIconManager.getIcons());
MapIconListCellRenderer renderer = new MapIconListCellRenderer();
IconCellRenderer renderer = new IconCellRenderer(mIconManager);
renderer.setPreferredSize(new Dimension(200, 30));
mMapIconCombo.setRenderer(renderer);
add(mMapIconCombo, "wrap");
mIconCombo.setRenderer(renderer);
add(mIconCombo, "wrap");
//Dummy place holder
add(new JLabel());
@@ -155,17 +154,7 @@ public class MultipleAliasEditor extends Editor<List<Alias>>
@Override
public void actionPerformed(ActionEvent arg0)
{
final IconManager iconManager =
new IconManager(mSettingsManager, MultipleAliasEditor.this);
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
iconManager.setVisible(true);
}
});
mIconManager.showEditor(MultipleAliasEditor.this);
}
});
@@ -363,9 +352,9 @@ public class MultipleAliasEditor extends Editor<List<Alias>>
if (mIconCheckBox.isSelected())
{
if (mMapIconCombo.getSelectedItem() != null)
if (mIconCombo.getSelectedItem() != null)
{
alias.setIconName(((MapIcon) mMapIconCombo.getSelectedItem()).getName());
alias.setIconName(((MapIcon) mIconCombo.getSelectedItem()).getName());
}
else
{

View File

@@ -29,6 +29,7 @@ import javax.swing.event.ChangeListener;
import audio.broadcast.BroadcastModel;
import audio.broadcast.BroadcastPanel;
import icon.IconManager;
import map.MapPanel;
import map.MapService;
import module.decode.event.CallEventPanel;
@@ -78,6 +79,7 @@ public class ControllerPanel extends JPanel
ChannelModel channelModel,
ChannelMapModel channelMapModel,
ChannelProcessingManager channelProcessingManager,
IconManager iconManager,
MapService mapService,
SettingsManager settingsManager,
SourceManager sourceManager,
@@ -104,8 +106,7 @@ public class ControllerPanel extends JPanel
mChannelController = new ChannelController(channelModel, channelMapModel,
sourceManager, aliasModel);
mAliasController = new AliasController(aliasModel, broadcastModel, settingsManager);
mAliasController = new AliasController(aliasModel, broadcastModel, iconManager);
mTunerManagerPanel = new TunerViewPanel(tunerModel);
init();

View File

@@ -30,7 +30,7 @@ import controller.channel.ChannelModel;
import controller.channel.ChannelProcessingManager;
import controller.channel.ChannelSelectionManager;
import controller.channel.map.ChannelMapModel;
import map.IconManager;
import icon.IconManager;
import map.MapService;
import module.log.EventLogManager;
import net.miginfocom.swing.MigLayout;
@@ -66,6 +66,7 @@ public class SDRTrunk implements Listener<TunerEvent>
{
private final static Logger mLog = LoggerFactory.getLogger(SDRTrunk.class);
private IconManager mIconManager;
private ControllerPanel mControllerPanel;
private SettingsManager mSettingsManager;
private SpectralDisplayPanel mSpectralPanel;
@@ -105,6 +106,8 @@ public class SDRTrunk implements Listener<TunerEvent>
ThreadPoolManager threadPoolManager = new ThreadPoolManager();
mIconManager = new IconManager(threadPoolManager);
mSettingsManager = new SettingsManager(threadPoolManager, tunerConfigurationModel);
AliasModel aliasModel = new AliasModel();
@@ -144,7 +147,7 @@ public class SDRTrunk implements Listener<TunerEvent>
channelProcessingManager.addMessageListener(mapService);
mControllerPanel = new ControllerPanel(audioManager, aliasModel, broadcastModel,
channelModel, channelMapModel, channelProcessingManager,
channelModel, channelMapModel, channelProcessingManager, mIconManager,
mapService, mSettingsManager, sourceManager, tunerModel);
mSpectralPanel = new SpectralDisplayPanel(channelModel,
@@ -268,16 +271,7 @@ public class SDRTrunk implements Listener<TunerEvent>
@Override
public void actionPerformed(ActionEvent arg0)
{
final IconManager iconManager = new IconManager(mSettingsManager, mMainGui);
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
iconManager.setVisible(true);
}
});
mIconManager.showEditor(mMainGui);
}
});
fileMenu.add(settingsMenu);

99
src/icon/Icon.java Normal file
View File

@@ -0,0 +1,99 @@
/*******************************************************************************
* 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 icon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
@XmlRootElement(name = "icon")
public class Icon implements Comparable<Icon>
{
private final static Logger mLog = LoggerFactory.getLogger(Icon.class);
protected String mName;
private String mPath;
private ImageIcon mImageIcon;
public Icon()
{
//No-arg JAXB constructor
}
public Icon(String name, String path)
{
mName = name;
mPath = path;
}
@XmlAttribute(name = "name")
public String getName()
{
return mName;
}
public void setName(String name)
{
mName = name;
}
public String toString()
{
return mName;
}
@XmlAttribute(name = "path")
public String getPath()
{
return mPath;
}
public void setPath(String path)
{
mPath = path;
}
@XmlTransient
public ImageIcon getIcon()
{
if(mImageIcon == null && mPath != null)
{
try
{
mImageIcon = new ImageIcon(mPath);
}
catch(Exception e)
{
mLog.error("Error loading Icon [" + mPath + "]", e);
}
}
return mImageIcon;
}
@Override
public int compareTo(Icon otherIcon)
{
return getName().compareTo(otherIcon.getName());
}
}

View File

@@ -0,0 +1,64 @@
/*******************************************************************************
* 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 icon;
import javax.swing.*;
import java.awt.*;
public class IconCellRenderer extends JLabel implements ListCellRenderer<Icon>
{
private static final long serialVersionUID = 1L;
private IconManager mIconManager;
public IconCellRenderer(IconManager iconManager)
{
mIconManager = iconManager;
setOpaque(true);
}
@Override
public Component getListCellRendererComponent(JList<? extends Icon> list, Icon icon, int index,
boolean isSelected, boolean cellHasFocus)
{
setIcon(mIconManager.getIcon(icon.getName(), 24));
if(icon == mIconManager.getModel().getDefaultIcon())
{
setText(icon.toString() + " (default)");
}
else
{
setText(icon.toString());
}
if(isSelected)
{
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}
else
{
setBackground(list.getBackground());
setForeground(list.getForeground());
}
return this;
}
}

432
src/icon/IconManager.java Normal file
View File

@@ -0,0 +1,432 @@
/*******************************************************************************
* 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 icon;
import controller.ThreadPoolManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import properties.SystemProperties;
import javax.swing.*;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public class IconManager
{
private final static Logger mLog = LoggerFactory.getLogger(IconManager.class);
private Path mIconFolderPath;
private Path mIconFilePath;
private Path mIconBackupFilePath;
private Path mIconLockFilePath;
private ThreadPoolManager mThreadPoolManager;
private IconViewer mIconViewer;
private IconModel mIconModel;
private AtomicBoolean mSavingIcons = new AtomicBoolean();
private Map<String, ImageIcon> mResizedIcons = new HashMap<>();
public IconManager(ThreadPoolManager threadPoolManager)
{
mThreadPoolManager = threadPoolManager;
}
/**
* Display the icon editor centered over the specified component.
*
* @param centerOnComponent to center the editor
*/
public void showEditor(Component centerOnComponent)
{
if(mIconViewer == null)
{
mIconViewer = new IconViewer(this);
mIconViewer.setLocationRelativeTo(centerOnComponent);
if(mIconViewer.isVisible())
{
mIconViewer.requestFocus();
}
else
{
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
mIconViewer.setVisible(true);
}
});
}
}
}
public IconModel getModel()
{
if(mIconModel == null)
{
IconSet loadedIcons = load();
mIconModel = new IconModel(loadedIcons);
mIconModel.addListDataListener(new ListDataListener()
{
@Override
public void intervalAdded(ListDataEvent e)
{
scheduleSave();
}
@Override
public void intervalRemoved(ListDataEvent e)
{
scheduleSave();
}
@Override
public void contentsChanged(ListDataEvent e)
{
scheduleSave();
}
});
}
return mIconModel;
}
/**
* All icons in a sorted array
*/
public Icon[] getIcons()
{
return getModel().getIconsAsArray();
}
/**
* Returns named icon scaled to the specified height. Utilizes an internal map to retain scaled icons so that they
* are only scaled/generated once.
*
* @param name - name of icon
* @param height - height of icon in pixels
* @return - scaled named icon (if it exists) or a scaled version of the default icon
*/
public ImageIcon getIcon(String name, int height)
{
if(name == null)
{
name = getModel().getDefaultIcon().getName();
}
String scaledIconName = name + height;
if(mResizedIcons.containsKey(scaledIconName))
{
return mResizedIcons.get(scaledIconName);
}
Icon icon = getModel().getIcon(name);
ImageIcon scaledIcon = getScaledIcon(icon.getIcon(), height);
mResizedIcons.put(scaledIconName, scaledIcon);
return scaledIcon;
}
/**
* Scales the icon to the new pixel height value
*
* @param original image icon
* @param height new height to scale the image (width will be scaled accordingly)
* @return
*/
private static ImageIcon getScaledIcon(ImageIcon original, int height)
{
double scale = (double) original.getIconHeight() / (double) height;
int scaledWidth = (int) ((double) original.getIconWidth() / scale);
Image scaledImage = original.getImage().getScaledInstance(scaledWidth,
height, java.awt.Image.SCALE_SMOOTH);
return new ImageIcon(scaledImage);
}
/**
* Folder where icon, backup and lock files are stored
*/
private Path getIconFolderPath()
{
if(mIconFolderPath == null)
{
SystemProperties props = SystemProperties.getInstance();
mIconFolderPath = props.getApplicationFolder("settings");
}
return mIconFolderPath;
}
/**
* Path to current icon file
*/
private Path getIconFilePath()
{
if(mIconFilePath == null)
{
mIconFilePath = getIconFolderPath().resolve("icons.xml");
}
return mIconFilePath;
}
/**
* Path to most recent playlist backup
*/
private Path getIconBackupFilePath()
{
if(mIconBackupFilePath == null)
{
mIconBackupFilePath = getIconFolderPath().resolve("icons.backup");
}
return mIconBackupFilePath;
}
/**
* Path to playlist lock file that is created prior to saving a playlist and removed immediately thereafter.
* Presence of a lock file indicates an incomplete or corrupt playlist file on startup.
*/
private Path getIconLockFilePath()
{
if(mIconLockFilePath == null)
{
mIconLockFilePath = getIconFolderPath().resolve("icons.lock");
}
return mIconLockFilePath;
}
/**
* Saves the current playlist
*/
private void save()
{
IconSet iconSet = getModel().getIconSet();
JAXBContext context = null;
//Create a backup copy of the current playlist
if(Files.exists(getIconFilePath()))
{
try
{
Files.copy(getIconFilePath(), getIconBackupFilePath(), StandardCopyOption.REPLACE_EXISTING);
}
catch(Exception e)
{
mLog.error("Error creating backup copy of current icons prior to saving updates [" +
getIconFilePath().toString() + "]", e);
}
}
//Create a temporary lock file to signify that we're in the process of updating the playlist
if(!Files.exists(getIconLockFilePath()))
{
try
{
Files.createFile(getIconLockFilePath());
}
catch(IOException e)
{
mLog.error("Error creating temporary lock file prior to saving icons [" +
getIconLockFilePath().toString() + "]", e);
}
}
try(OutputStream out = Files.newOutputStream(getIconFilePath()))
{
context = JAXBContext.newInstance(IconSet.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.marshal(iconSet, out);
out.flush();
//Remove the playlist lock file to indicate that we successfully saved the file
if(Files.exists(getIconLockFilePath()))
{
Files.delete(getIconLockFilePath());
}
}
catch(JAXBException je)
{
mLog.error("JAXB exception while serializing icons to a file [" + getIconFilePath().toString() + "]", je);
}
catch(IOException ioe)
{
mLog.error("IO error while writing icons to a file [" + getIconFilePath().toString() + "]", ioe);
}
catch(Exception e)
{
mLog.error("Error while saving icons [" + getIconFilePath().toString() + "]", e);
}
}
/**
* Loads icons from file or creates a default set of icons
*/
public IconSet load()
{
mLog.info("loading icons file [" + getIconFilePath().toString() + "]");
IconSet iconSet = null;
//Check for a lock file that indicates the previous save attempt was incomplete or had an error
if(Files.exists(getIconLockFilePath()))
{
try
{
//Remove the previous icons file
Files.delete(getIconFilePath());
//Copy the backup file to restore the previous icons file
if(Files.exists(getIconBackupFilePath()))
{
Files.copy(getIconBackupFilePath(), getIconFilePath());
}
//Remove the lock file
Files.delete(getIconLockFilePath());
}
catch(IOException ioe)
{
mLog.error("Previous icons save attempt was incomplete and there was an error restoring the " +
"icons backup file", ioe);
}
}
if(Files.exists(getIconFilePath()))
{
JAXBContext context = null;
try(InputStream in = Files.newInputStream(getIconFilePath()))
{
context = JAXBContext.newInstance(IconSet.class);
Unmarshaller m = context.createUnmarshaller();
iconSet = (IconSet) m.unmarshal(in);
}
catch(JAXBException je)
{
mLog.error("JAXB exception while loading/unmarshalling icons", je);
}
catch(IOException ioe)
{
mLog.error("IO error while reading icons file", ioe);
}
}
else
{
mLog.info("Icons file not found at [" + getIconFilePath().toString() + "]");
}
if(iconSet == null)
{
iconSet = getDefaultIconSet();
}
return iconSet;
}
/**
* Creates a default icon set
*/
private IconSet getDefaultIconSet()
{
IconSet iconSet = new IconSet();
Icon defaultIcon = new Icon(IconModel.DEFAULT_ICON, "images/no_icon.png");
iconSet.add(defaultIcon);
iconSet.setDefaultIcon(defaultIcon.getName());
iconSet.add(new Icon("Ambulance", "images/ambulance.png"));
iconSet.add(new Icon("Block Truck", "images/concrete_block_truck.png"));
iconSet.add(new Icon("CWID", "images/cwid.png"));
iconSet.add(new Icon("Dispatcher", "images/dispatcher.png"));
iconSet.add(new Icon("Dump Truck", "images/dump_truck_red.png"));
iconSet.add(new Icon("Fire Truck", "images/fire_truck.png"));
iconSet.add(new Icon("Garbage Truck", "images/garbage_truck.png"));
iconSet.add(new Icon("Loader", "images/loader.png"));
iconSet.add(new Icon("Police", "images/police.png"));
iconSet.add(new Icon("Propane Truck", "images/propane_truck.png"));
iconSet.add(new Icon("Rescue Truck", "images/rescue_truck.png"));
iconSet.add(new Icon("School Bus", "images/school_bus.png"));
iconSet.add(new Icon("Taxi", "images/taxi.png"));
iconSet.add(new Icon("Train", "images/train.png"));
iconSet.add(new Icon("Transport Bus", "images/opt_bus.png"));
iconSet.add(new Icon("Van", "images/van.png"));
return iconSet;
}
/**
* Schedules an icon file save task. Subsequent calls to this method will be ignored until the save event occurs,
* thus limiting repetitive saving to a minimum.
*/
private void scheduleSave()
{
if(mSavingIcons.compareAndSet(false, true))
{
mThreadPoolManager.scheduleOnce(new IconSaveTask(), 2, TimeUnit.SECONDS);
}
}
/**
* Resets the playlist save pending flag to false and proceeds to save the playlist.
*/
public class IconSaveTask implements Runnable
{
@Override
public void run()
{
save();
mSavingIcons.set(false);
}
}
}

150
src/icon/IconModel.java Normal file
View File

@@ -0,0 +1,150 @@
/*******************************************************************************
* 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 icon;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class IconModel extends DefaultListModel<Icon>
{
public static final String DEFAULT_ICON = "No Icon";
private Icon mDefaultIcon;
private Map<String,Icon> mIconMap = new HashMap();
public IconModel(IconSet iconSet)
{
for(Icon icon: iconSet.getIcons())
{
this.addElement(icon);
}
String defaultIconName = iconSet.getDefaultIcon();
if(defaultIconName == null)
{
defaultIconName = DEFAULT_ICON;
}
Icon defaultIcon = mIconMap.get(defaultIconName);
if(defaultIcon != null)
{
mDefaultIcon = defaultIcon;
}
else
{
mDefaultIcon = new Icon(DEFAULT_ICON, "images/no_icon.png");
}
}
/**
* Icons in an array - suitable for use in a JComboBox
*/
public Icon[] getIconsAsArray()
{
List<Icon> icons = new ArrayList<>(mIconMap.values());
Collections.sort(icons);
return icons.toArray(new Icon[icons.size()]);
}
public Icon getDefaultIcon()
{
return mDefaultIcon;
}
/**
* Indicates if this model contains an icon with the specified name
* @param name to check
* @return true if name is not null and not empty and the internal map contains an icon matching name
*/
public boolean hasIcon(String name)
{
return name != null && !name.isEmpty() && mIconMap.containsKey(name);
}
public void setDefaultIcon(Icon icon)
{
if(icon != null)
{
mDefaultIcon = icon;
int index = indexOf(icon);
fireContentsChanged(icon, index, index);
}
}
/**
* Returns the named icon or the default icon if the named icon does not exist
*/
public Icon getIcon(String name)
{
if(name == null)
{
return mDefaultIcon;
}
Icon icon = mIconMap.get(name);
if(icon == null)
{
icon = mDefaultIcon;
}
return icon;
}
@Override
public void addElement(Icon icon)
{
super.addElement(icon);
mIconMap.put(icon.getName(), icon);
}
@Override
public boolean removeElement(Object object)
{
if(object instanceof Icon)
{
mIconMap.remove(((Icon)object).getName());
}
return super.removeElement(object);
}
/**
* Creates a new icon set from a snapshot of the icons contained in this model
*/
public IconSet getIconSet()
{
IconSet iconSet = new IconSet();
iconSet.setIcons(new ArrayList<Icon>(mIconMap.values()));
iconSet.setDefaultIcon(getDefaultIcon().getName());
return iconSet;
}
}

175
src/icon/IconSelector.java Normal file
View File

@@ -0,0 +1,175 @@
/*******************************************************************************
* 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 icon;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
public class IconSelector extends JDialog implements DocumentListener
{
private IconModel mIconModel;
private JTextField mNameText;
private JTextField mFileLabel;
private JButton mFileChooserButton;
private JButton mOKButton;
private JButton mCancelButton;
/**
* Window for selecting an Icon to add to the Icon Model
*
* @param owner for this modal dialog
* @param iconModel to receive the added/selected icon
*/
public IconSelector(Frame owner, IconModel iconModel)
{
super(owner, "Add Icon", true);
mIconModel = iconModel;
init();
setLocationRelativeTo(owner);
}
private void init()
{
setSize(250, 170);
JPanel contentPanel = new JPanel();
contentPanel.setPreferredSize(new Dimension(250, 170));
contentPanel.setLayout(new MigLayout("insets 1 1 1 1", "[align right][align left,grow,fill]", "[][][][grow,fill][]"));
contentPanel.add(new JLabel("Name"));
mNameText = new JTextField();
mNameText.getDocument().addDocumentListener(this);
contentPanel.add(mNameText, "wrap");
contentPanel.add(new JLabel("File"));
mFileLabel = new JTextField();
mFileLabel.setEnabled(false);
contentPanel.add(mFileLabel, "wrap");
mFileChooserButton = new JButton("Select File ...");
mFileChooserButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
JFileChooser fileChooser = new JFileChooser();
// fileChooser.setSelectedFile(null);
//Add a custom file filter and disable the default
fileChooser.addChoosableFileFilter(new ImageFilter());
fileChooser.setAcceptAllFileFilterUsed(false);
int returnVal = fileChooser.showDialog(IconSelector.this, "Select");
if(returnVal == JFileChooser.APPROVE_OPTION)
{
File file = fileChooser.getSelectedFile();
if(file != null)
{
mFileLabel.setText(file.getAbsolutePath());
checkButtons();
}
}
}
});
contentPanel.add(mFileChooserButton, "span,align center");
contentPanel.add(new JLabel(), "wrap");
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new MigLayout("", "[grow,fill][grow,fill]", "[]"));
mOKButton = new JButton("OK");
mOKButton.setEnabled(false);
mOKButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
String name = mNameText.getText();
String path = mFileLabel.getText();
Icon icon = new Icon(name, path);
mIconModel.addElement(icon);
IconSelector.this.dispose();
}
});
mCancelButton = new JButton("Cancel");
mCancelButton.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
IconSelector.this.dispose();
}
});
buttonPanel.add(mOKButton);
buttonPanel.add(mCancelButton);
contentPanel.add(buttonPanel, "span,grow");
add(contentPanel);
}
private void checkButtons()
{
String name = mNameText.getText();
String path = mFileLabel.getText();
mOKButton.setEnabled(name != null && path != null && !path.isEmpty() && !mIconModel.hasIcon(name));
}
@Override
public void insertUpdate(DocumentEvent e)
{
checkButtons();
}
@Override
public void removeUpdate(DocumentEvent e)
{
checkButtons();
}
@Override
public void changedUpdate(DocumentEvent e)
{
checkButtons();
}
}

76
src/icon/IconSet.java Normal file
View File

@@ -0,0 +1,76 @@
/*******************************************************************************
* 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 icon;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
import java.util.List;
@XmlRootElement(name="iconset")
public class IconSet
{
private String mDefaultIcon;
private List<Icon> mIcons = new ArrayList<>();
public IconSet()
{
//No-arg JAXB constructor
}
public void add(Icon icon)
{
mIcons.add(icon);
}
public void remove(Icon icon)
{
mIcons.remove(icon);
}
@XmlElementWrapper(name="icons")
@XmlElement(name = "icon")
public List<Icon> getIcons()
{
if(mIcons == null)
{
mIcons = new ArrayList<>();
}
return mIcons;
}
public void setIcons(List<Icon> icons)
{
mIcons = icons;
}
@XmlAttribute(name = "default")
public String getDefaultIcon()
{
return mDefaultIcon;
}
public void setDefaultIcon(String name)
{
mDefaultIcon = name;
}
}

137
src/icon/IconViewer.java Normal file
View File

@@ -0,0 +1,137 @@
/*******************************************************************************
* 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 icon;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class IconViewer extends JFrame implements ActionListener
{
private static final long serialVersionUID = 1L;
private static final Logger mLog = LoggerFactory.getLogger(IconViewer.class);
private static final String ADD = "Add";
private static final String DEFAULT = "Set Default";
private static final String DELETE = "Delete";
private JButton mAddButton;
private JButton mDeleteButton;
private JButton mDefaultButton;
private JList<Icon> mIconList;
private IconManager mIconManager;
public IconViewer(IconManager model)
{
mIconManager = model;
init();
}
private void init()
{
setTitle("Icon Viewer");
setSize(400, 400);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLayout(new MigLayout("", "[grow,fill]", "[grow,fill]"));
/**
* Editor Panel
*/
JPanel editorPanel = new JPanel();
editorPanel.setLayout(new MigLayout("insets 1 1 1 1", "[grow,fill][grow,fill][grow,fill]", "[grow,fill][]"));
mIconList = new JList<>(mIconManager.getModel());
IconCellRenderer renderer = new IconCellRenderer(mIconManager);
renderer.setPreferredSize(new Dimension(200, 30));
mIconList.setCellRenderer(renderer);
mIconList.addListSelectionListener(new ListSelectionListener()
{
@Override
public void valueChanged(ListSelectionEvent e)
{
checkButtons();
}
});
editorPanel.add(new JScrollPane(mIconList), "span");
mAddButton = new JButton(ADD);
mAddButton.addActionListener(this);
editorPanel.add(mAddButton);
mDeleteButton = new JButton(DELETE);
mDeleteButton.addActionListener(this);
mDeleteButton.setEnabled(false);
editorPanel.add(mDeleteButton);
mDefaultButton = new JButton(DEFAULT);
mDefaultButton.addActionListener(this);
mDefaultButton.setEnabled(false);
editorPanel.add(mDefaultButton, "wrap");
add(editorPanel);
}
private void checkButtons()
{
Icon selected = mIconList.getSelectedValue();
mDefaultButton.setEnabled(selected != null && selected != mIconManager.getModel().getDefaultIcon());
mDeleteButton.setEnabled(selected != null && selected != mIconManager.getModel().getDefaultIcon());
}
public void actionPerformed(ActionEvent e)
{
Icon selected = mIconList.getSelectedValue();
switch(e.getActionCommand())
{
case ADD:
IconSelector iconSelector = new IconSelector(this, mIconManager.getModel());
iconSelector.setVisible(true);
break;
case DELETE:
if(selected != null)
{
int choice = JOptionPane.showConfirmDialog(IconViewer.this,
"Are you sure you want to delete this icon?", "Delete Icon?", JOptionPane.YES_NO_OPTION);
if(choice == JOptionPane.YES_OPTION)
{
mIconManager.getModel().removeElement(selected);
}
}
break;
case DEFAULT:
if(selected != null)
{
mIconManager.getModel().setDefaultIcon(selected);
}
break;
}
checkButtons();
}
}

74
src/icon/ImageFilter.java Normal file
View File

@@ -0,0 +1,74 @@
/*******************************************************************************
* 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 icon;
import javax.swing.filechooser.FileFilter;
import java.io.File;
public class ImageFilter extends FileFilter
{
//Accept all directories and all gif, jpg, tiff, or png files.
public boolean accept(File f)
{
if(f.isDirectory())
{
return true;
}
String extension = getExtension(f);
if(extension != null)
{
if(extension.equals("tiff") ||
extension.equals("tif") ||
extension.equals("gif") ||
extension.equals("jpeg") ||
extension.equals("jpg") ||
extension.equals("png"))
{
return true;
}
else
{
return false;
}
}
return false;
}
//The description of this filter
public String getDescription()
{
return "Images (*.gif,*.jpg,*.png.";
}
public String getExtension(File f)
{
String ext = null;
String s = f.getName();
int i = s.lastIndexOf('.');
if(i > 0 && i < s.length() - 1)
{
ext = s.substring(i + 1).toLowerCase();
}
return ext;
}
}

View File

@@ -1,495 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package map;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.Arrays;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;
import net.miginfocom.swing.MigLayout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import settings.Setting;
import settings.SettingChangeListener;
import settings.SettingsManager;
public class IconManager extends JFrame
implements ActionListener, SettingChangeListener
{
public enum Mode { NORMAL, NEW, EDIT }
private static final long serialVersionUID = 1L;
private final static Logger mLog =
LoggerFactory.getLogger( IconManager.class );
private static final String sMSG_NEW = "Type a name for the new icon, "
+ "select the file, and click Save,\nor Cancel to reset";
private static final String sMSG_EDIT = "Change the name for the selected \n"
+ "icon and/or the file, and click Save\nto update, or Cancel to reset";
private static final String sMSG_NORMAL = "Select an icon to edit, or \n"
+ "click New to add an icon";
private JTextField mIconName;
private JTextField mIconPath;
private JButton mButtonLeft = new JButton( "New" );
private JButton mButtonRight = new JButton( "Edit" );
private JButton mButtonFile = new JButton( "File" );
private JTextArea mInstructionLabel = new JTextArea();
private JList<MapIcon> mIconList;
private JFileChooser mFileChooser;
private Mode mMode = Mode.NORMAL;
private SettingsManager mSettingsManager;
public IconManager( SettingsManager settingsManager, Component displayOver )
{
mSettingsManager = settingsManager;
init( displayOver );
}
private void init( Component displayOver )
{
setTitle( "Icon Manager" );
setLocationRelativeTo( displayOver );
setSize( 400, 400 );
setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
setLayout( new MigLayout( "", "[grow,fill]", "[grow,fill]" ) );
/**
* Editor Panel
*/
JPanel editorPanel = new JPanel();
editorPanel.setLayout( new MigLayout( "", "", "[][][][grow,fill]" ) );
mButtonFile.addActionListener( this );
editorPanel.add( mButtonFile, "align right" );
mIconPath = new JTextField();
editorPanel.add( mIconPath, "grow,wrap" );
editorPanel.add( new JLabel( "Name:" ), "align right" );
mIconName = new JTextField();
editorPanel.add( mIconName, "grow,wrap" );
mButtonLeft.addActionListener( this );
editorPanel.add( mButtonLeft );
mButtonRight.addActionListener( this );
mButtonRight.setEnabled( false );
editorPanel.add( mButtonRight, "wrap" );
mInstructionLabel.setText( sMSG_NORMAL );
mInstructionLabel.setRows( 3 );
mInstructionLabel.setBackground( getBackground() );
editorPanel.add( mInstructionLabel, "span,grow,wrap" );
/**
* MapIcon list
*/
MapIcon[] icons = mSettingsManager.getMapIcons();
Arrays.sort( icons );
mIconList = new JList<MapIcon>( icons );
MapIconListCellRenderer renderer = new MapIconListCellRenderer();
renderer.setPreferredSize( new Dimension( 200, 30 ) );
mIconList.setCellRenderer( renderer );
mIconList.addListSelectionListener( new ListSelectionListener()
{
@Override
public void valueChanged( ListSelectionEvent event )
{
/**
* Refresh the display by setting the mode to normal. If we
* were in editing or new mode, and the user clicks in the list
* throw away the changes and set the mode to normal
*/
setMode( Mode.NORMAL );
}
} );
mIconList.addMouseListener( new MouseListener()
{
@Override
public void mouseClicked( MouseEvent event )
{
if( event.getButton() == MouseEvent.BUTTON3 )
{
//Select the item
mIconList.setSelectedIndex(
mIconList.locationToIndex( event.getPoint() ) );
//Determine if it can be deleted
final MapIcon icon = mIconList.getSelectedValue();
if( icon != null )
{
JPopupMenu context = new JPopupMenu();
JMenuItem setDefault = new JMenuItem( "Set As Default" );
setDefault.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
mSettingsManager.setDefaultIcon( icon );
refreshList();
}
} );
context.add( setDefault );
if( icon.isEditable() )
{
JMenuItem deleteItem = new JMenuItem( "Delete Icon" );
deleteItem.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
mSettingsManager.deleteMapIcon( icon );
}
} );
context.add( deleteItem );
}
context.show( mIconList, event.getX(), event.getY() );
}
}
}
//Unused
public void mouseEntered( MouseEvent arg0 ) {}
public void mouseExited( MouseEvent arg0 ) {}
public void mousePressed( MouseEvent arg0 ) {}
public void mouseReleased( MouseEvent arg0 ) {}
} );
JScrollPane scroller = new JScrollPane( mIconList );
/**
* Splitpane to hold editor and icon list
*/
JSplitPane splitPane = new JSplitPane( JSplitPane.VERTICAL_SPLIT,
scroller,
editorPanel );
splitPane.setResizeWeight( 0.7D );
add( splitPane );
}
private void setMode( Mode mode )
{
MapIcon selected = mIconList.getSelectedValue();
switch( mode )
{
case NORMAL:
setTitle( "Icon Manager" );
mButtonLeft.setText( "New" );
mButtonRight.setText( "Edit" );
if( selected != null )
{
if( selected.isEditable() )
{
mButtonRight.setEnabled( true );
mIconName.setText( selected.getName() );
mIconPath.setText( selected.getPath() );
}
else
{
mButtonRight.setEnabled( false );
mIconName.setText( selected.getName() + " [NO EDIT]" );
mIconPath.setText( null );
}
}
else
{
mButtonRight.setEnabled( false );
mIconName.setText( null );
mIconPath.setText( null );
}
mInstructionLabel.setText( sMSG_NORMAL );
break;
case EDIT:
if( selected != null )
{
setTitle( "Icon Manager - editing [" + selected.getName() + "]" );
}
else
{
setTitle( "Icon Manager - edit [*]" );
}
mButtonLeft.setText( "Save" );
mButtonRight.setText( "Cancel" );
mButtonRight.setEnabled( true );
mInstructionLabel.setText( sMSG_EDIT );
break;
case NEW:
setTitle( "Icon Manager - add new icon" );
mButtonLeft.setText( "Save" );
mButtonRight.setText( "Cancel" );
mButtonRight.setEnabled( true );
mIconName.setText( null );
mIconPath.setText( null );
mInstructionLabel.setText( sMSG_NEW );
break;
}
mMode = mode;
repaint();
}
public void actionPerformed(ActionEvent e)
{
if( e.getSource() == mButtonFile )
{
if ( mFileChooser == null )
{
mFileChooser = new JFileChooser();
//Add a custom file filter and disable the default
mFileChooser.addChoosableFileFilter( new ImageFilter() );
mFileChooser.setAcceptAllFileFilterUsed( false );
}
int returnVal = mFileChooser.showDialog( this, "Select" );
if ( returnVal == JFileChooser.APPROVE_OPTION )
{
File file = mFileChooser.getSelectedFile();
if( file != null )
{
mIconPath.setText( file.getAbsolutePath() );
}
}
//Reset the file chooser for the next time it's shown.
mFileChooser.setSelectedFile( null );
}
else if( e.getSource() == mButtonLeft )
{
switch( mMode )
{
case EDIT: //Save
save();
break;
case NEW: //Save
save();
break;
case NORMAL:
setMode( Mode.NEW );
break;
}
}
else if( e.getSource() == mButtonRight )
{
switch( mMode )
{
case EDIT: //Cancel
case NEW: //Cancel
setMode( Mode.NORMAL );
break;
case NORMAL: //Edit
setMode( Mode.EDIT );
break;
}
}
}
private void refreshList()
{
MapIcon[] icons = mSettingsManager.getMapIcons();
Arrays.sort( icons );
mIconList.setListData( icons );
repaint();
}
private void save()
{
String name = mIconName.getText();
String path = mIconPath.getText();
switch( mMode )
{
case NEW:
if( name != null && !name.isEmpty() )
{
if( path != null && !path.isEmpty() )
{
mSettingsManager.addMapIcon( new MapIcon( name, path, true ) );
}
else
{
JOptionPane.showMessageDialog( this,
"Please select an image file",
"Filename and path missing",
JOptionPane.ERROR_MESSAGE );
}
}
else
{
JOptionPane.showMessageDialog( this,
"Please type a name for the new icon",
"Name missing",
JOptionPane.ERROR_MESSAGE );
}
break;
case EDIT:
MapIcon selected = mIconList.getSelectedValue();
if( name != null && !name.isEmpty() )
{
if( path != null && !path.isEmpty() )
{
selected.setName( name );
selected.setPath( path );
mSettingsManager.updatMapIcon( selected, name, path );
}
else
{
JOptionPane.showMessageDialog( this,
"Please select an image file",
"Filename and path missing",
JOptionPane.ERROR_MESSAGE );
}
}
else
{
JOptionPane.showMessageDialog( this,
"Please type a name for the new icon",
"Name missing",
JOptionPane.ERROR_MESSAGE );
}
break;
default:
break;
}
}
public class ImageFilter extends FileFilter
{
//Accept all directories and all gif, jpg, tiff, or png files.
public boolean accept(File f)
{
if ( f.isDirectory() )
{
return true;
}
String extension = getExtension( f );
if (extension != null)
{
if (extension.equals( "tiff" ) ||
extension.equals( "tif" ) ||
extension.equals( "gif" ) ||
extension.equals( "jpeg" ) ||
extension.equals( "jpg" ) ||
extension.equals( "png" ) )
{
return true;
}
else
{
return false;
}
}
return false;
}
//The description of this filter
public String getDescription()
{
return "Images (*.gif,*.jpg,*.png.";
}
public String getExtension( File f )
{
String ext = null;
String s = f.getName();
int i = s.lastIndexOf('.');
if (i > 0 && i < s.length() - 1) {
ext = s.substring(i+1).toLowerCase();
}
return ext;
}
}
@Override
public void settingChanged( Setting setting )
{
if( setting instanceof MapIcon )
{
refreshList();
setMode( Mode.NORMAL );
}
}
@Override
public void settingDeleted( Setting setting )
{
if( setting instanceof MapIcon )
{
refreshList();
setMode( Mode.NORMAL );
}
}
}

View File

@@ -1,57 +0,0 @@
/*******************************************************************************
* SDR Trunk
* Copyright (C) 2014 Dennis Sheirer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
******************************************************************************/
package map;
import java.awt.Component;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
public class MapIconListCellRenderer extends JLabel
implements ListCellRenderer<MapIcon>
{
private static final long serialVersionUID = 1L;
public MapIconListCellRenderer()
{
setOpaque( true );
}
@Override
public Component getListCellRendererComponent(
JList<? extends MapIcon> list, MapIcon value, int index,
boolean isSelected, boolean cellHasFocus )
{
setIcon( value.getImageIcon() );
setText( value.toString() );
if ( isSelected )
{
setBackground( list.getSelectionBackground() );
setForeground( list.getSelectionForeground() );
}
else
{
setBackground( list.getBackground() );
setForeground( list.getForeground() );
}
return this;
}
}

View File

@@ -432,9 +432,9 @@ public class PlaylistManager implements ChannelEventListener
@Override
public void run()
{
mPlaylistSavePending.set(false);
save();
mPlaylistSavePending.set(false);
}
}
}