From 79b4b30ec7f22d2501a6e5dfb06696c6569cc4e2 Mon Sep 17 00:00:00 2001 From: Denny Date: Fri, 17 Feb 2017 17:53:42 -0500 Subject: [PATCH 01/13] Resolves issue with audio broadcasters attempting to reconnect if a connection attempt is not successful. --- src/audio/broadcast/icecast/IcecastHTTPAudioBroadcaster.java | 5 +++-- src/audio/broadcast/icecast/IcecastTCPAudioBroadcaster.java | 4 ++-- .../broadcast/shoutcast/v1/ShoutcastV1AudioBroadcaster.java | 2 ++ .../broadcast/shoutcast/v2/ShoutcastV2AudioBroadcaster.java | 2 ++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/audio/broadcast/icecast/IcecastHTTPAudioBroadcaster.java b/src/audio/broadcast/icecast/IcecastHTTPAudioBroadcaster.java index d42af8b5..935d4979 100644 --- a/src/audio/broadcast/icecast/IcecastHTTPAudioBroadcaster.java +++ b/src/audio/broadcast/icecast/IcecastHTTPAudioBroadcaster.java @@ -156,6 +156,8 @@ public class IcecastHTTPAudioBroadcaster extends IcecastAudioBroadcaster disconnect(); } + + mConnecting.set(false); } }; @@ -176,8 +178,6 @@ public class IcecastHTTPAudioBroadcaster extends IcecastAudioBroadcaster { mStreamingSession.closeNow(); } - - mConnecting.set(false); } /** @@ -256,6 +256,7 @@ public class IcecastHTTPAudioBroadcaster extends IcecastAudioBroadcaster mSocketConnector = null; mConnecting.set(false); + super.sessionClosed(session); } diff --git a/src/audio/broadcast/icecast/IcecastTCPAudioBroadcaster.java b/src/audio/broadcast/icecast/IcecastTCPAudioBroadcaster.java index 53f728c3..fa9cd8d5 100644 --- a/src/audio/broadcast/icecast/IcecastTCPAudioBroadcaster.java +++ b/src/audio/broadcast/icecast/IcecastTCPAudioBroadcaster.java @@ -147,6 +147,8 @@ public class IcecastTCPAudioBroadcaster extends IcecastAudioBroadcaster disconnect(); } + + mConnecting.set(false); } }; @@ -293,8 +295,6 @@ public class IcecastTCPAudioBroadcaster extends IcecastAudioBroadcaster setBroadcastState(BroadcastState.ERROR); disconnect(); } - - mConnecting.set(false); } @Override diff --git a/src/audio/broadcast/shoutcast/v1/ShoutcastV1AudioBroadcaster.java b/src/audio/broadcast/shoutcast/v1/ShoutcastV1AudioBroadcaster.java index 3bc83071..5d6d8dab 100644 --- a/src/audio/broadcast/shoutcast/v1/ShoutcastV1AudioBroadcaster.java +++ b/src/audio/broadcast/shoutcast/v1/ShoutcastV1AudioBroadcaster.java @@ -168,6 +168,8 @@ public class ShoutcastV1AudioBroadcaster extends AudioBroadcaster disconnect(); } + + mConnecting.set(false); } }; diff --git a/src/audio/broadcast/shoutcast/v2/ShoutcastV2AudioBroadcaster.java b/src/audio/broadcast/shoutcast/v2/ShoutcastV2AudioBroadcaster.java index cd4cadaf..341b31bf 100644 --- a/src/audio/broadcast/shoutcast/v2/ShoutcastV2AudioBroadcaster.java +++ b/src/audio/broadcast/shoutcast/v2/ShoutcastV2AudioBroadcaster.java @@ -204,6 +204,8 @@ public class ShoutcastV2AudioBroadcaster extends AudioBroadcaster implements IBr disconnect(); } + + mConnecting.set(false); } }; From f3605db0edb8c2f7bb6147854b3d23af10c3e8b7 Mon Sep 17 00:00:00 2001 From: Denny Date: Fri, 17 Feb 2017 18:08:01 -0500 Subject: [PATCH 02/13] Resolves issue where metadata is UTF-8 URL encoded versus UTF-8 String encoding. --- src/audio/broadcast/shoutcast/v2/ultravox/UltravoxMetadata.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/broadcast/shoutcast/v2/ultravox/UltravoxMetadata.java b/src/audio/broadcast/shoutcast/v2/ultravox/UltravoxMetadata.java index 6a124355..0372fc6b 100644 --- a/src/audio/broadcast/shoutcast/v2/ultravox/UltravoxMetadata.java +++ b/src/audio/broadcast/shoutcast/v2/ultravox/UltravoxMetadata.java @@ -65,7 +65,7 @@ public enum UltravoxMetadata { StringBuilder sb = new StringBuilder(); sb.append("<").append(getXMLTag()).append(">"); - sb.append(URLEncoder.encode(value, "UTF-8")); + sb.append(new String(value.getBytes(), "UTF-8")); sb.append(""); return sb.toString(); From 234e313b7a76ee13a70ffaa7cff239dbf7cfca4c Mon Sep 17 00:00:00 2001 From: Denny Date: Mon, 20 Feb 2017 20:19:47 -0500 Subject: [PATCH 03/13] Resolves issue with Null Pointer exception in alias list --- src/alias/AliasModel.java | 527 +++++++++++++++++++------------------- 1 file changed, 265 insertions(+), 262 deletions(-) diff --git a/src/alias/AliasModel.java b/src/alias/AliasModel.java index a46bd532..c8ca2aba 100644 --- a/src/alias/AliasModel.java +++ b/src/alias/AliasModel.java @@ -1,22 +1,28 @@ /******************************************************************************* * SDR Trunk * Copyright (C) 2014-2016 Dennis Sheirer - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ package alias; +import alias.AliasEvent.Event; +import alias.id.broadcast.BroadcastChannel; +import sample.Broadcaster; +import sample.Listener; + +import javax.swing.table.AbstractTableModel; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -24,195 +30,192 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; -import javax.swing.table.AbstractTableModel; - -import alias.id.broadcast.BroadcastChannel; -import sample.Broadcaster; -import sample.Listener; -import alias.AliasEvent.Event; - /** * Alias Model */ public class AliasModel extends AbstractTableModel { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - public static final int COLUMN_LIST = 0; - public static final int COLUMN_GROUP = 1; - public static final int COLUMN_NAME = 2; - public static final int COLUMN_ICON = 3; - public static final int COLUMN_COLOR = 4; + public static final int COLUMN_LIST = 0; + public static final int COLUMN_GROUP = 1; + public static final int COLUMN_NAME = 2; + public static final int COLUMN_ICON = 3; + public static final int COLUMN_COLOR = 4; - private List mAliases = new CopyOnWriteArrayList<>(); - private Broadcaster mAliasEventBroadcaster = new Broadcaster<>(); - private Map mAliasListMap = new HashMap<>(); + private List mAliases = new CopyOnWriteArrayList<>(); + private Broadcaster mAliasEventBroadcaster = new Broadcaster<>(); + private Map mAliasListMap = new HashMap<>(); - public AliasModel() - { - } + public AliasModel() + { + } - /** - * Unmodifiable list of all aliases currently in the model - */ - public List getAliases() - { - return Collections.unmodifiableList( mAliases ); - } - - public Alias getAliasAtIndex( int row ) - { - if( mAliases.size() >= row ) - { - return mAliases.get( row ); - } - - return null; - } - - public AliasList getAliasList( String name ) - { - if( mAliasListMap.containsKey( name ) ) - { - return mAliasListMap.get( name ); - } - - AliasList aliasList = new AliasList( name ); - - for( Alias alias: mAliases ) - { - if( alias.getList().equalsIgnoreCase( name ) ) - { - aliasList.addAlias( alias ); - } - } + /** + * Unmodifiable list of all aliases currently in the model + */ + public List getAliases() + { + return Collections.unmodifiableList(mAliases); + } - mAliasListMap.put( name, aliasList ); + public Alias getAliasAtIndex(int row) + { + if(mAliases.size() >= row) + { + return mAliases.get(row); + } - //Register the new alias list to receive updates from this model - addListener( aliasList ); - - return aliasList; - } - - /** - * Returns a list of unique alias list names from across the alias set - */ - public List getListNames() - { - List listNames = new ArrayList<>(); - - for( Alias alias: mAliases ) - { - if( alias.hasList() && !listNames.contains( alias.getList() ) ) - { - listNames.add( alias.getList() ); - } - } - - Collections.sort( listNames ); - - return listNames; - } - - /** - * Returns a list of alias group names for all aliases - */ - public List getGroupNames() - { - List groupNames = new ArrayList<>(); + return null; + } - for( Alias alias: mAliases ) - { - if( alias.hasGroup() && !groupNames.contains( alias.getGroup() ) ) - { - groupNames.add( alias.getGroup() ); - } - } + public AliasList getAliasList(String name) + { + if(name != null && mAliasListMap.containsKey(name)) + { + return mAliasListMap.get(name); + } - Collections.sort( groupNames ); - - return groupNames; - } + AliasList aliasList = new AliasList(name); - /** - * Returns a list of alias group names for all aliases that have a matching - * list name value - */ - public List getGroupNames( String listName ) - { - List groupNames = new ArrayList<>(); + if(name != null) + { + for(Alias alias : mAliases) + { + if(alias.getList().equalsIgnoreCase(name)) + { + aliasList.addAlias(alias); + } + } - if( listName != null ) - { - for( Alias alias: mAliases ) - { - if( alias.hasList() && - alias.hasGroup() && - listName.equals( alias.getList() ) && - !groupNames.contains( alias.getGroup() ) ) - { - groupNames.add( alias.getGroup() ); - } - } - } + mAliasListMap.put(name, aliasList); - Collections.sort( groupNames ); - - return groupNames; - } + //Register the new alias list to receive updates from this model + addListener(aliasList); + } - /** - * Bulk loading of aliases - */ - public void addAliases( List aliases ) - { - for( Alias alias: aliases ) - { - addAlias( alias ); - } - } + return aliasList; + } - /** - * Adds the alias to the model - */ - public int addAlias( Alias alias ) - { - if( alias != null ) - { - mAliases.add( alias ); + /** + * Returns a list of unique alias list names from across the alias set + */ + public List getListNames() + { + List listNames = new ArrayList<>(); - int index = mAliases.size() - 1; + for(Alias alias : mAliases) + { + if(alias.hasList() && !listNames.contains(alias.getList())) + { + listNames.add(alias.getList()); + } + } - fireTableRowsInserted( index, index ); - - broadcast( new AliasEvent( alias, Event.ADD ) ); + Collections.sort(listNames); - return index; - } - - return -1; - } - - /** - * Removes the channel from the model and broadcasts a channel remove event - */ - public void removeAlias( Alias alias ) - { - if( alias != null ) - { - int index = mAliases.indexOf( alias ); - - mAliases.remove( alias ); - - fireTableRowsDeleted( index, index ); - - broadcast( new AliasEvent( alias, Event.DELETE ) ); - } - } + return listNames; + } + + /** + * Returns a list of alias group names for all aliases + */ + public List getGroupNames() + { + List groupNames = new ArrayList<>(); + + for(Alias alias : mAliases) + { + if(alias.hasGroup() && !groupNames.contains(alias.getGroup())) + { + groupNames.add(alias.getGroup()); + } + } + + Collections.sort(groupNames); + + return groupNames; + } + + /** + * Returns a list of alias group names for all aliases that have a matching + * list name value + */ + public List getGroupNames(String listName) + { + List groupNames = new ArrayList<>(); + + if(listName != null) + { + for(Alias alias : mAliases) + { + if(alias.hasList() && + alias.hasGroup() && + listName.equals(alias.getList()) && + !groupNames.contains(alias.getGroup())) + { + groupNames.add(alias.getGroup()); + } + } + } + + Collections.sort(groupNames); + + return groupNames; + } + + /** + * Bulk loading of aliases + */ + public void addAliases(List aliases) + { + for(Alias alias : aliases) + { + addAlias(alias); + } + } + + /** + * Adds the alias to the model + */ + public int addAlias(Alias alias) + { + if(alias != null) + { + mAliases.add(alias); + + int index = mAliases.size() - 1; + + fireTableRowsInserted(index, index); + + broadcast(new AliasEvent(alias, Event.ADD)); + + return index; + } + + return -1; + } + + /** + * Removes the channel from the model and broadcasts a channel remove event + */ + public void removeAlias(Alias alias) + { + if(alias != null) + { + int index = mAliases.indexOf(alias); + + mAliases.remove(alias); + + fireTableRowsDeleted(index, index); + + broadcast(new AliasEvent(alias, Event.DELETE)); + } + } /** * Renames any broadcast channels that have the previous name. + * * @param previousName to rename * @param newName to assign to the broadcast channel */ @@ -223,11 +226,11 @@ public class AliasModel extends AbstractTableModel return; } - for(Alias alias: mAliases) + for(Alias alias : mAliases) { if(alias.hasBroadcastChannel(previousName)) { - for(BroadcastChannel broadcastChannel: alias.getBroadcastChannels()) + for(BroadcastChannel broadcastChannel : alias.getBroadcastChannels()) { if(broadcastChannel.getChannelName().contentEquals(previousName)) { @@ -238,85 +241,85 @@ public class AliasModel extends AbstractTableModel } } - @Override - public int getRowCount() - { - return mAliases.size(); - } + @Override + public int getRowCount() + { + return mAliases.size(); + } - @Override - public int getColumnCount() - { - return 5; - } + @Override + public int getColumnCount() + { + return 5; + } - @Override - public String getColumnName( int columnIndex ) - { - switch( columnIndex ) - { - case COLUMN_LIST: - return "List"; - case COLUMN_GROUP: - return "Group"; - case COLUMN_NAME: - return "Name"; - case COLUMN_ICON: - return "Icon"; - case COLUMN_COLOR: - return "Color"; - } - - return null; - } + @Override + public String getColumnName(int columnIndex) + { + switch(columnIndex) + { + case COLUMN_LIST: + return "List"; + case COLUMN_GROUP: + return "Group"; + case COLUMN_NAME: + return "Name"; + case COLUMN_ICON: + return "Icon"; + case COLUMN_COLOR: + return "Color"; + } - @Override - public Class getColumnClass( int columnIndex ) - { - if( columnIndex == COLUMN_COLOR ) - { - return Integer.class; - } - - return String.class; - } + return null; + } - @Override - public boolean isCellEditable( int rowIndex, int columnIndex ) - { - return false; - } + @Override + public Class getColumnClass(int columnIndex) + { + if(columnIndex == COLUMN_COLOR) + { + return Integer.class; + } - @Override - public Object getValueAt( int rowIndex, int columnIndex ) - { - Alias alias = mAliases.get( rowIndex ); - - switch( columnIndex ) - { - case COLUMN_LIST: - return alias.getList(); - case COLUMN_GROUP: - return alias.getGroup(); - case COLUMN_NAME: - return alias.getName(); - case COLUMN_ICON: - return alias.getIconName(); - case COLUMN_COLOR: - return alias.getColor(); - } - - return null; - } + return String.class; + } - @Override - public void setValueAt( Object aValue, int rowIndex, int columnIndex ) - { - throw new IllegalArgumentException( "Not yet implemented" ); - } - - public void broadcast( AliasEvent event ) - { + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) + { + return false; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) + { + Alias alias = mAliases.get(rowIndex); + + switch(columnIndex) + { + case COLUMN_LIST: + return alias.getList(); + case COLUMN_GROUP: + return alias.getGroup(); + case COLUMN_NAME: + return alias.getName(); + case COLUMN_ICON: + return alias.getIconName(); + case COLUMN_COLOR: + return alias.getColor(); + } + + return null; + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) + { + throw new IllegalArgumentException("Not yet implemented"); + } + + public void broadcast(AliasEvent event) + { Alias alias = event.getAlias(); //Validate the alias following a user action that changed the alias or any alias IDs @@ -325,23 +328,23 @@ public class AliasModel extends AbstractTableModel alias.validate(); } - if( event.getEvent() == Event.CHANGE ) - { - int index = mAliases.indexOf( event.getAlias() ); - - fireTableRowsUpdated( index, index ); - } - - mAliasEventBroadcaster.broadcast( event ); - } - - public void addListener( Listener listener ) - { - mAliasEventBroadcaster.addListener( listener ); - } - - public void removeListener( Listener listener ) - { - mAliasEventBroadcaster.removeListener( listener ); - } + if(event.getEvent() == Event.CHANGE) + { + int index = mAliases.indexOf(event.getAlias()); + + fireTableRowsUpdated(index, index); + } + + mAliasEventBroadcaster.broadcast(event); + } + + public void addListener(Listener listener) + { + mAliasEventBroadcaster.addListener(listener); + } + + public void removeListener(Listener listener) + { + mAliasEventBroadcaster.removeListener(listener); + } } From 9515dfa380a28e00d4f0236a8d7d7d63094fd733 Mon Sep 17 00:00:00 2001 From: Denny Date: Mon, 20 Feb 2017 20:25:43 -0500 Subject: [PATCH 04/13] Incrementing build for 0.3.0 beta #5 --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index bce263e7..f4471f28 100644 --- a/build/build.xml +++ b/build/build.xml @@ -7,7 +7,7 @@ - + From 2058fcbc1d2a124c725e1ab1692c511e52467d14 Mon Sep 17 00:00:00 2001 From: Denny Date: Fri, 24 Feb 2017 05:23:48 -0500 Subject: [PATCH 05/13] Resolves issue #206 - alias list throws NPE on aliases that don't have a list name specified. --- src/alias/AliasModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alias/AliasModel.java b/src/alias/AliasModel.java index c8ca2aba..1389d299 100644 --- a/src/alias/AliasModel.java +++ b/src/alias/AliasModel.java @@ -82,7 +82,7 @@ public class AliasModel extends AbstractTableModel { for(Alias alias : mAliases) { - if(alias.getList().equalsIgnoreCase(name)) + if(alias.hasList() && alias.getList().equalsIgnoreCase(name)) { aliasList.addAlias(alias); } From 8660002f939303c38d11aeeef33577f5b23e114a Mon Sep 17 00:00:00 2001 From: Denny Date: Fri, 24 Feb 2017 05:24:38 -0500 Subject: [PATCH 06/13] Incrementing build to beta 6 --- build/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build.xml b/build/build.xml index f4471f28..f44429b9 100644 --- a/build/build.xml +++ b/build/build.xml @@ -7,7 +7,7 @@ - + From 4eb66e604546dc63b77814e76a09dbe30e389fa8 Mon Sep 17 00:00:00 2001 From: Denny Date: Sat, 25 Feb 2017 06:18:59 -0500 Subject: [PATCH 07/13] Updated readme file with screen shot and link to new Version 0.3.0 user's manual. --- README.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 04a52ab9..9a68ca4b 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,10 @@ A cross-platform java application for decoding, monitoring, recording and streaming trunked mobile and related radio protocols using Software Defined Radios (SDR). * [Getting Started](https://github.com/DSheirer/sdrtrunk/wiki/GettingStarted) -* [User's Manual](https://github.com/DSheirer/sdrtrunk/wiki/UserManual) +* [User's Manual Version 0.2.0](https://github.com/DSheirer/sdrtrunk/wiki/UserManual) +* [User's Manual Version 0.3.0](https://github.com/DSheirer/sdrtrunk/wiki/UserManual_Version0.3.0) * [Download](https://github.com/DSheirer/sdrtrunk/releases) * [Support](https://groups.google.com/forum/#!forum/sdrtrunk) -![](https://github.com/DSheirer/sdrtrunk/wiki/images/SDRTrunk_application.png) - +![sdrtrunk Application Overview - Version 0.3.0](https://github.com/DSheirer/sdrtrunk/wiki/images/ApplicationOverview_V0.3.0.png) +**Figure 1:** sdrtrunk **Version 0.3.0** Application Screenshot \ No newline at end of file From 119370c46e864361549568d1484c98c0aefa6f89 Mon Sep 17 00:00:00 2001 From: Denny Date: Sat, 25 Feb 2017 14:57:25 -0500 Subject: [PATCH 08/13] Resolves issue with FCD2 tuner frequency. --- src/source/tuner/TunerModel.java | 2 +- .../tuner/fcd/proplusV2/FCD2TunerController.java | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/source/tuner/TunerModel.java b/src/source/tuner/TunerModel.java index 09a74804..6945174f 100644 --- a/src/source/tuner/TunerModel.java +++ b/src/source/tuner/TunerModel.java @@ -108,7 +108,7 @@ public class TunerModel extends AbstractTableModel implements Listener= MINIMUM_TUNABLE_FREQUENCY && + fcd2.getFrequency() <= MAXIMUM_TUNABLE_FREQUENCY) + { + frequency = fcd2.getFrequency(); + } + + setFrequency(frequency); setLNAGain(fcd2.getGainLNA()); setMixerGain(fcd2.getGainMixer()); From a4a339b50571a375472d368e6eb567d8bee99b03 Mon Sep 17 00:00:00 2001 From: Denny Date: Sat, 25 Feb 2017 14:58:51 -0500 Subject: [PATCH 09/13] Resolves issue with FCD2 tuner frequency. --- src/source/tuner/TunerModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/source/tuner/TunerModel.java b/src/source/tuner/TunerModel.java index 6945174f..09a74804 100644 --- a/src/source/tuner/TunerModel.java +++ b/src/source/tuner/TunerModel.java @@ -108,7 +108,7 @@ public class TunerModel extends AbstractTableModel implements Listener Date: Sat, 25 Feb 2017 16:03:35 -0500 Subject: [PATCH 10/13] Removes assert() usage throughout project and replaces with Validate from apache commons. --- src/alias/id/WildcardID.java | 4 +++- .../broadcast/shoutcast/v2/ShoutcastV2Configuration.java | 3 ++- .../shoutcast/v2/ultravox/NegotiateMaxPayloadSize.java | 6 ++++-- .../broadcast/shoutcast/v2/ultravox/UltravoxMessage.java | 3 ++- src/bits/BinaryMessage.java | 5 +++-- src/bits/MultiSyncPatternMatcher.java | 4 +++- src/channel/metadata/ChannelMetadataPanel.java | 3 ++- src/dsp/filter/FloatFIRFilter.java | 3 ++- src/dsp/filter/FloatHalfBandFilter.java | 3 ++- src/dsp/filter/FloatHalfBandNoDecimateFilter.java | 3 ++- src/dsp/filter/cic/ComplexPrimeCICDecimate.java | 3 ++- src/dsp/filter/cic/RealPrimeCICDecimate.java | 3 ++- src/dsp/filter/halfband/real/HalfBandFilter.java | 4 +++- src/dsp/filter/interpolator/RealInterpolator.java | 3 ++- .../filter/polyphase/PolyphaseFIRInterpolatingFilter.java | 3 ++- src/dsp/gain/DirectGainControl.java | 3 ++- src/record/wave/MonoWaveReader.java | 3 ++- src/record/wave/WaveWriter.java | 6 ++++-- src/sample/adapter/ChannelShortAdapter.java | 3 ++- src/sample/complex/ComplexToComplexBufferAssembler.java | 3 ++- src/spectrum/SpectrumPanel.java | 5 +++-- src/util/XTEA.java | 6 ++++-- 22 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/alias/id/WildcardID.java b/src/alias/id/WildcardID.java index d4d00c3f..c5f47086 100644 --- a/src/alias/id/WildcardID.java +++ b/src/alias/id/WildcardID.java @@ -18,6 +18,8 @@ ******************************************************************************/ package alias.id; +import org.apache.commons.lang3.Validate; + import java.util.regex.Pattern; public class WildcardID implements Comparable @@ -45,7 +47,7 @@ public class WildcardID implements Comparable */ public WildcardID(String value) { - assert(value != null && value.contains(WILDCARD) && value.length() < 10); + Validate.isTrue(value != null && value.contains(WILDCARD) && value.length() < 10); mValue = value; diff --git a/src/audio/broadcast/shoutcast/v2/ShoutcastV2Configuration.java b/src/audio/broadcast/shoutcast/v2/ShoutcastV2Configuration.java index c7fafe6a..b3ba1212 100644 --- a/src/audio/broadcast/shoutcast/v2/ShoutcastV2Configuration.java +++ b/src/audio/broadcast/shoutcast/v2/ShoutcastV2Configuration.java @@ -21,6 +21,7 @@ package audio.broadcast.shoutcast.v2; import audio.broadcast.BroadcastConfiguration; import audio.broadcast.BroadcastFormat; import audio.broadcast.BroadcastServerType; +import org.apache.commons.lang3.Validate; import javax.xml.bind.annotation.XmlAttribute; @@ -90,7 +91,7 @@ public class ShoutcastV2Configuration extends BroadcastConfiguration */ public void setStreamID(int streamID) { - assert(1 <= streamID && streamID <= Integer.MAX_VALUE); + Validate.isTrue(1 <= streamID && streamID <= Integer.MAX_VALUE); mStreamID = streamID; } diff --git a/src/audio/broadcast/shoutcast/v2/ultravox/NegotiateMaxPayloadSize.java b/src/audio/broadcast/shoutcast/v2/ultravox/NegotiateMaxPayloadSize.java index 11321319..1c7cf728 100644 --- a/src/audio/broadcast/shoutcast/v2/ultravox/NegotiateMaxPayloadSize.java +++ b/src/audio/broadcast/shoutcast/v2/ultravox/NegotiateMaxPayloadSize.java @@ -18,6 +18,8 @@ ******************************************************************************/ package audio.broadcast.shoutcast.v2.ultravox; +import org.apache.commons.lang3.Validate; + public class NegotiateMaxPayloadSize extends UltravoxMessage { /** @@ -47,8 +49,8 @@ public class NegotiateMaxPayloadSize extends UltravoxMessage */ public void setMaximumPayloadSize(int desiredMaximum, int minimum) { - assert(desiredMaximum <= 16377); - assert(minimum <= 16377); + Validate.isTrue(desiredMaximum <= 16377); + Validate.isTrue(minimum <= 16377); StringBuilder sb = new StringBuilder(); sb.append(desiredMaximum).append(":").append(minimum); diff --git a/src/audio/broadcast/shoutcast/v2/ultravox/UltravoxMessage.java b/src/audio/broadcast/shoutcast/v2/ultravox/UltravoxMessage.java index eb099b20..99180df8 100644 --- a/src/audio/broadcast/shoutcast/v2/ultravox/UltravoxMessage.java +++ b/src/audio/broadcast/shoutcast/v2/ultravox/UltravoxMessage.java @@ -19,6 +19,7 @@ package audio.broadcast.shoutcast.v2.ultravox; import bits.BinaryMessage; +import org.apache.commons.lang3.Validate; import java.util.Arrays; @@ -154,7 +155,7 @@ public abstract class UltravoxMessage */ public void setSendQueuePriority(int priority) { - assert(0 <= priority && priority <= 7); + Validate.isTrue(0 <= priority && priority <= 7); mMessage.setInt(priority, SEND_QUEUE_PRIORITY); } diff --git a/src/bits/BinaryMessage.java b/src/bits/BinaryMessage.java index 56e21a12..31516602 100644 --- a/src/bits/BinaryMessage.java +++ b/src/bits/BinaryMessage.java @@ -22,6 +22,7 @@ import java.util.BitSet; import java.util.logging.LogManager; import edac.CRC; +import org.apache.commons.lang3.Validate; public class BinaryMessage extends BitSet { @@ -456,7 +457,7 @@ public class BinaryMessage extends BitSet */ public byte getByte(int index) { - assert((index + 7) <= size()); + Validate.isTrue((index + 7) <= size()); int value = 0; @@ -481,7 +482,7 @@ public class BinaryMessage extends BitSet */ public void setByte(int index, byte value) { - assert((index + 8) <= size()); + Validate.isTrue((index + 8) <= size()); int mask = 0x80; diff --git a/src/bits/MultiSyncPatternMatcher.java b/src/bits/MultiSyncPatternMatcher.java index 41f967ae..6de0d5ed 100644 --- a/src/bits/MultiSyncPatternMatcher.java +++ b/src/bits/MultiSyncPatternMatcher.java @@ -17,6 +17,8 @@ ******************************************************************************/ package bits; +import org.apache.commons.lang3.Validate; + import java.util.ArrayList; import java.util.List; @@ -39,7 +41,7 @@ public class MultiSyncPatternMatcher public MultiSyncPatternMatcher( int syncSize ) { - assert( syncSize < 64 ); + Validate.isTrue(syncSize < 64); //Setup a bit mask of all ones the length of the sync pattern mMask = (long)( ( Math.pow( 2, syncSize ) ) - 1 ); diff --git a/src/channel/metadata/ChannelMetadataPanel.java b/src/channel/metadata/ChannelMetadataPanel.java index 5fa80231..bd3fcbb1 100644 --- a/src/channel/metadata/ChannelMetadataPanel.java +++ b/src/channel/metadata/ChannelMetadataPanel.java @@ -26,6 +26,7 @@ import controller.channel.ChannelUtils; import icon.IconManager; import module.ProcessingChain; import net.miginfocom.swing.MigLayout; +import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import properties.SystemProperties; @@ -140,7 +141,7 @@ public class ChannelMetadataPanel extends JPanel implements ListSelectionListene public AliasedValueCellRenderer(Attribute attribute) { - assert(attribute != null); + Validate.isTrue(attribute != null); mAttribute = attribute; setHorizontalAlignment(JLabel.CENTER); } diff --git a/src/dsp/filter/FloatFIRFilter.java b/src/dsp/filter/FloatFIRFilter.java index 8355fbf0..16c0a39c 100644 --- a/src/dsp/filter/FloatFIRFilter.java +++ b/src/dsp/filter/FloatFIRFilter.java @@ -19,6 +19,7 @@ package dsp.filter; import java.util.ArrayList; +import org.apache.commons.lang3.Validate; import sample.real.RealSampleListener; public class FloatFIRFilter implements RealSampleListener @@ -139,7 +140,7 @@ public class FloatFIRFilter implements RealSampleListener private void generateIndexMap( int size ) { //Ensure we have an odd size - assert( size % 2 == 1 ); + Validate.isTrue(size % 2 == 1); mIndexMap = new int[ size ][ size ]; diff --git a/src/dsp/filter/FloatHalfBandFilter.java b/src/dsp/filter/FloatHalfBandFilter.java index 56fae571..1d65deec 100644 --- a/src/dsp/filter/FloatHalfBandFilter.java +++ b/src/dsp/filter/FloatHalfBandFilter.java @@ -19,6 +19,7 @@ package dsp.filter; import java.util.ArrayList; +import org.apache.commons.lang3.Validate; import sample.real.RealSampleListener; public class FloatHalfBandFilter implements RealSampleListener @@ -149,7 +150,7 @@ public class FloatHalfBandFilter implements RealSampleListener private void generateIndexMap( int size ) { //Ensure we have an odd size - assert( size % 2 == 1 ); + Validate.isTrue(size % 2 == 1); int mapWidth = ( ( size + 1 ) / 2 ) + 1; diff --git a/src/dsp/filter/FloatHalfBandNoDecimateFilter.java b/src/dsp/filter/FloatHalfBandNoDecimateFilter.java index 6f38db1f..f2561bce 100644 --- a/src/dsp/filter/FloatHalfBandNoDecimateFilter.java +++ b/src/dsp/filter/FloatHalfBandNoDecimateFilter.java @@ -19,6 +19,7 @@ package dsp.filter; import java.util.ArrayList; +import org.apache.commons.lang3.Validate; import sample.real.RealSampleListener; public class FloatHalfBandNoDecimateFilter implements RealSampleListener @@ -139,7 +140,7 @@ public class FloatHalfBandNoDecimateFilter implements RealSampleListener private void generateIndexMap( int size ) { //Ensure we have an odd size - assert( size % 2 == 1 ); + Validate.isTrue(size % 2 == 1); int mapWidth = ( ( size + 1 ) / 2 ) + 1; diff --git a/src/dsp/filter/cic/ComplexPrimeCICDecimate.java b/src/dsp/filter/cic/ComplexPrimeCICDecimate.java index 80b0c206..72a869d0 100644 --- a/src/dsp/filter/cic/ComplexPrimeCICDecimate.java +++ b/src/dsp/filter/cic/ComplexPrimeCICDecimate.java @@ -20,6 +20,7 @@ package dsp.filter.cic; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.Validate; import sample.Listener; import sample.complex.ComplexBuffer; import sample.complex.ComplexSampleListener; @@ -67,7 +68,7 @@ public class ComplexPrimeCICDecimate implements Listener public ComplexPrimeCICDecimate( int decimation, int order, int passFrequency, int attenuation, WindowType windowType ) { - assert( decimation <= 700 ); + Validate.isTrue(decimation <= 700); List stageSizes = getPrimeFactors( decimation ); diff --git a/src/dsp/filter/cic/RealPrimeCICDecimate.java b/src/dsp/filter/cic/RealPrimeCICDecimate.java index 8e359cea..36964a05 100644 --- a/src/dsp/filter/cic/RealPrimeCICDecimate.java +++ b/src/dsp/filter/cic/RealPrimeCICDecimate.java @@ -20,6 +20,7 @@ package dsp.filter.cic; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -81,7 +82,7 @@ public class RealPrimeCICDecimate public RealPrimeCICDecimate( int decimation, int order, int passFrequency, int attenuation, WindowType windowType, int outputBufferSize ) { - assert( decimation <= 700 ); + Validate.isTrue(decimation <= 700); mOutputBufferSize = outputBufferSize; diff --git a/src/dsp/filter/halfband/real/HalfBandFilter.java b/src/dsp/filter/halfband/real/HalfBandFilter.java index 7b84616f..831c8b5c 100644 --- a/src/dsp/filter/halfband/real/HalfBandFilter.java +++ b/src/dsp/filter/halfband/real/HalfBandFilter.java @@ -17,6 +17,8 @@ ******************************************************************************/ package dsp.filter.halfband.real; +import org.apache.commons.lang3.Validate; + public class HalfBandFilter { private float[] mBuffer; @@ -122,7 +124,7 @@ public class HalfBandFilter private void generateIndexMap( int size ) { //Ensure we have an odd size - assert( size % 2 == 1 ); + Validate.isTrue(size % 2 == 1); int mapWidth = ( ( size + 1 ) / 2 ) + 1; diff --git a/src/dsp/filter/interpolator/RealInterpolator.java b/src/dsp/filter/interpolator/RealInterpolator.java index f840a3ed..26941ac0 100644 --- a/src/dsp/filter/interpolator/RealInterpolator.java +++ b/src/dsp/filter/interpolator/RealInterpolator.java @@ -1,5 +1,6 @@ package dsp.filter.interpolator; +import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,7 +32,7 @@ public class RealInterpolator extends Interpolator public float filter( float[] samples, int offset, float mu ) { /* Ensure we have enough samples in the array */ - assert( samples.length >= offset + 7 ); + Validate.isTrue(samples.length >= offset + 7); /* Identify the filter bank that corresponds to mu */ int index = (int)( NSTEPS * mu ); diff --git a/src/dsp/filter/polyphase/PolyphaseFIRInterpolatingFilter.java b/src/dsp/filter/polyphase/PolyphaseFIRInterpolatingFilter.java index 65b41b46..992a14a6 100644 --- a/src/dsp/filter/polyphase/PolyphaseFIRInterpolatingFilter.java +++ b/src/dsp/filter/polyphase/PolyphaseFIRInterpolatingFilter.java @@ -18,6 +18,7 @@ ******************************************************************************/ package dsp.filter.polyphase; +import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,7 +54,7 @@ public class PolyphaseFIRInterpolatingFilter public PolyphaseFIRInterpolatingFilter( double[] coefficients, int interpolation ) { /* Ensure coefficients are an integral multiple of the interpolation factor */ - assert( coefficients.length % interpolation == 0 ); + Validate.isTrue(coefficients.length % interpolation == 0); mTaps = coefficients; diff --git a/src/dsp/gain/DirectGainControl.java b/src/dsp/gain/DirectGainControl.java index 2f9ab934..01c167c8 100644 --- a/src/dsp/gain/DirectGainControl.java +++ b/src/dsp/gain/DirectGainControl.java @@ -17,6 +17,7 @@ ******************************************************************************/ package dsp.gain; +import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,7 +50,7 @@ public class DirectGainControl implements GainController, RealSampleListener */ public DirectGainControl( float gain, float minimum, float maximum, float increment ) { - assert( minimum > 0 ); + Validate.isTrue(minimum > 0); mDefaultGain = gain; mGain = gain; diff --git a/src/record/wave/MonoWaveReader.java b/src/record/wave/MonoWaveReader.java index 25b076e9..a03cf94f 100644 --- a/src/record/wave/MonoWaveReader.java +++ b/src/record/wave/MonoWaveReader.java @@ -18,6 +18,7 @@ ******************************************************************************/ package record.wave; +import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sample.ConversionUtils; @@ -58,7 +59,7 @@ public class MonoWaveReader implements AutoCloseable */ public MonoWaveReader(Path path, boolean realTime) throws IOException { - assert( path != null ); + Validate.isTrue(path != null); mPath = path; mRealTime = realTime; diff --git a/src/record/wave/WaveWriter.java b/src/record/wave/WaveWriter.java index c5e37b24..a7733e69 100644 --- a/src/record/wave/WaveWriter.java +++ b/src/record/wave/WaveWriter.java @@ -17,6 +17,8 @@ ******************************************************************************/ package record.wave; +import org.apache.commons.lang3.Validate; + import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; @@ -59,8 +61,8 @@ public class WaveWriter implements AutoCloseable public WaveWriter( AudioFormat format, Path file, long maxSize ) throws IOException { - assert( format != null ); - assert( file != null ); + Validate.isTrue(format != null); + Validate.isTrue( file != null ); mAudioFormat = format; mFile = file; diff --git a/src/sample/adapter/ChannelShortAdapter.java b/src/sample/adapter/ChannelShortAdapter.java index 6245a250..e974f82a 100644 --- a/src/sample/adapter/ChannelShortAdapter.java +++ b/src/sample/adapter/ChannelShortAdapter.java @@ -20,6 +20,7 @@ package sample.adapter; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import org.apache.commons.lang3.Validate; import source.mixer.MixerChannel; /** @@ -34,7 +35,7 @@ public class ChannelShortAdapter implements ISampleAdapter public ChannelShortAdapter( MixerChannel channel ) { /* Only use with LEFT/RIGHT channels */ - assert( channel != MixerChannel.MONO ); + Validate.isTrue(channel != MixerChannel.MONO); mMixerChannel = channel; } diff --git a/src/sample/complex/ComplexToComplexBufferAssembler.java b/src/sample/complex/ComplexToComplexBufferAssembler.java index 66dd239a..586d21c3 100644 --- a/src/sample/complex/ComplexToComplexBufferAssembler.java +++ b/src/sample/complex/ComplexToComplexBufferAssembler.java @@ -17,6 +17,7 @@ ******************************************************************************/ package sample.complex; +import org.apache.commons.lang3.Validate; import sample.Listener; /** @@ -32,7 +33,7 @@ public class ComplexToComplexBufferAssembler implements ComplexSampleListener public ComplexToComplexBufferAssembler( int bufferSize ) { - assert( bufferSize % 2 == 0 ); + Validate.isTrue(bufferSize % 2 == 0); mBufferSize = bufferSize; mBuffer = new float[ mBufferSize ]; diff --git a/src/spectrum/SpectrumPanel.java b/src/spectrum/SpectrumPanel.java index d2295cbe..d16b35a8 100644 --- a/src/spectrum/SpectrumPanel.java +++ b/src/spectrum/SpectrumPanel.java @@ -30,6 +30,7 @@ import java.util.Arrays; import javax.swing.JPanel; +import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -282,7 +283,7 @@ public class SpectrumPanel extends JPanel */ public void setZoom( int zoom ) { - assert( 0 <= zoom && zoom <= 5 ); + Validate.isTrue( 0 <= zoom && zoom <= 5 ); mZoom = zoom; } @@ -305,7 +306,7 @@ public class SpectrumPanel extends JPanel */ public void setSampleSize( double sampleSize ) { - assert( 2.0 <= sampleSize && sampleSize <= 32.0 ); + Validate.isTrue(2.0 <= sampleSize && sampleSize <= 32.0); mDBScale = (float)( 20.0 * Math.log10( Math.pow( 2.0, sampleSize - 1 ) ) ); } diff --git a/src/util/XTEA.java b/src/util/XTEA.java index 575c92c8..9ab8c48c 100644 --- a/src/util/XTEA.java +++ b/src/util/XTEA.java @@ -18,6 +18,8 @@ ******************************************************************************/ package util; +import org.apache.commons.lang3.Validate; + import java.util.Arrays; public class XTEA @@ -58,7 +60,7 @@ public class XTEA */ public void setKey(byte[] key) { - assert(key.length == 16); + Validate.isTrue(key.length == 16); int keyInts[] = new int[8]; @@ -94,7 +96,7 @@ public class XTEA */ public byte[] encrypt(byte[] plainText) { - assert(plainText.length == 8); + Validate.isTrue(plainText.length == 8); //Convert the 8 bytes of plaintext to 2 integers int result0 = (plainText[3] << 0) & MASK0 | (plainText[2] << 8) & MASK1 | From 9ef156b06162383637abdc969c6950e2e306ae73 Mon Sep 17 00:00:00 2001 From: Denny Date: Sun, 26 Feb 2017 05:47:26 -0500 Subject: [PATCH 11/13] Resolves issue with spectral display rendering artifacts from cursor frequency readout when accessing menu items directly above the spectral display. --- src/spectrum/OverlayPanel.java | 1474 +++++++++++++++----------------- 1 file changed, 711 insertions(+), 763 deletions(-) diff --git a/src/spectrum/OverlayPanel.java b/src/spectrum/OverlayPanel.java index d826a61c..ae0c23fc 100644 --- a/src/spectrum/OverlayPanel.java +++ b/src/spectrum/OverlayPanel.java @@ -1,44 +1,30 @@ /******************************************************************************* - * SDR Trunk - * Copyright (C) 2014,2015 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 + * 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 + * ******************************************************************************/ package spectrum; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.RenderingHints; -import java.awt.Stroke; -import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; -import java.awt.geom.Line2D; -import java.awt.geom.Rectangle2D; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.concurrent.CopyOnWriteArrayList; - -import javax.swing.JPanel; - +import controller.channel.Channel; +import controller.channel.Channel.ChannelType; +import controller.channel.ChannelEvent; +import controller.channel.ChannelEventListener; +import controller.channel.ChannelModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import settings.ColorSetting; import settings.ColorSetting.ColorSettingName; import settings.Setting; @@ -47,151 +33,151 @@ import settings.SettingsManager; import source.tuner.TunerChannel; import source.tuner.frequency.FrequencyChangeEvent; import source.tuner.frequency.IFrequencyChangeProcessor; -import controller.channel.Channel; -import controller.channel.Channel.ChannelType; -import controller.channel.ChannelEvent; -import controller.channel.ChannelEventListener; -import controller.channel.ChannelModel; -public class OverlayPanel extends JPanel - implements ChannelEventListener, - IFrequencyChangeProcessor, - SettingChangeListener +import javax.swing.*; +import java.awt.*; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.geom.Line2D; +import java.awt.geom.Rectangle2D; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.concurrent.CopyOnWriteArrayList; + +public class OverlayPanel extends JPanel implements ChannelEventListener, IFrequencyChangeProcessor, + SettingChangeListener { - private static final long serialVersionUID = 1L; - - private final static Logger mLog = - LoggerFactory.getLogger( OverlayPanel.class ); + private static final long serialVersionUID = 1L; - private final static RenderingHints RENDERING_HINTS = - new RenderingHints( RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON ); + private final static Logger mLog = LoggerFactory.getLogger(OverlayPanel.class); - static - { - RENDERING_HINTS.put( RenderingHints.KEY_RENDERING, - RenderingHints.VALUE_RENDER_QUALITY ); - } - - private final static BasicStroke DASHED_STROKE = new BasicStroke(0.8f, - BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 5.0f, new float[] {2.0f, 4.0f}, 0.0f); - - private static DecimalFormat CURSOR_FORMAT = new DecimalFormat( "000.00000" ); - private long mFrequency = 0; - private int mBandwidth = 0; - private Point mCursorLocation = new Point( 0, 0 ); - private boolean mCursorVisible = false; + private final static RenderingHints RENDERING_HINTS = new RenderingHints(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); - private DFTSize mDFTSize = DFTSize.FFT04096; - private int mZoom = 0; - private int mDFTZoomWindowOffset = 0; - - /** - * Colors used by this component - */ - private Color mColorChannelConfig; - private Color mColorChannelConfigProcessing; - private Color mColorChannelConfigSelected; - private Color mColorSpectrumBackground; - private Color mColorSpectrumCursor; - private Color mColorSpectrumLine; - - //Currently visible/displayable channels - private CopyOnWriteArrayList mVisibleChannels = new CopyOnWriteArrayList(); - private ChannelDisplay mChannelDisplay = ChannelDisplay.ALL; - - //Defines the offset at the bottom of the spectral display to account for - //the frequency labels - private double mSpectrumInset = 20.0d; - private LabelSizeManager mLabelSizeMonitor = new LabelSizeManager(); - - private SettingsManager mSettingsManager; - private ChannelModel mChannelModel; - /** - * Translucent overlay panel for displaying channel configurations, - * processing channels, selected channels, frequency labels and lines, and - * a cursor with a frequency readout. - */ - public OverlayPanel( SettingsManager settingsManager, - ChannelModel channelModel ) + static { - mSettingsManager = settingsManager; - - if( mSettingsManager != null ) - { - mSettingsManager.addListener( this ); - } - - mChannelModel = channelModel; - - if( mChannelModel != null ) - { - mChannelModel.addListener( this ); - } - - addComponentListener( mLabelSizeMonitor ); - - //Set the background transparent, so the spectrum display can be seen - setOpaque( false ); - - //Fetch color settings from settings manager - setColors(); + RENDERING_HINTS.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + } + + private final static BasicStroke DASHED_STROKE = new BasicStroke(0.8f, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, 5.0f, new float[]{2.0f, 4.0f}, 0.0f); + + private static DecimalFormat CURSOR_FORMAT = new DecimalFormat("000.00000"); + private long mFrequency = 0; + private int mBandwidth = 0; + private Point mCursorLocation = new Point(0, 0); + private boolean mCursorVisible = false; + + private DFTSize mDFTSize = DFTSize.FFT04096; + private int mZoom = 0; + private int mDFTZoomWindowOffset = 0; + + /** + * Colors used by this component + */ + private Color mColorChannelConfig; + private Color mColorChannelConfigProcessing; + private Color mColorChannelConfigSelected; + private Color mColorSpectrumBackground; + private Color mColorSpectrumCursor; + private Color mColorSpectrumLine; + + //Currently visible/displayable channels + private CopyOnWriteArrayList mVisibleChannels = new CopyOnWriteArrayList(); + private ChannelDisplay mChannelDisplay = ChannelDisplay.ALL; + + //Defines the offset at the bottom of the spectral display to account for + //the frequency labels + private double mSpectrumInset = 20.0d; + private LabelSizeManager mLabelSizeMonitor = new LabelSizeManager(); + + private SettingsManager mSettingsManager; + private ChannelModel mChannelModel; + + /** + * Translucent overlay panel for displaying channel configurations, + * processing channels, selected channels, frequency labels and lines, and + * a cursor with a frequency readout. + */ + public OverlayPanel(SettingsManager settingsManager, ChannelModel channelModel) + { + mSettingsManager = settingsManager; + + if(mSettingsManager != null) + { + mSettingsManager.addListener(this); + } + + mChannelModel = channelModel; + + if(mChannelModel != null) + { + mChannelModel.addListener(this); + } + + addComponentListener(mLabelSizeMonitor); + + //Set the background transparent, so the spectrum display can be seen + setOpaque(false); + + //Fetch color settings from settings manager + setColors(); + } + + public void dispose() + { + if(mChannelModel != null) + { + mChannelModel.removeListener(this); + } + + mChannelModel = null; + + mVisibleChannels.clear(); + + if(mSettingsManager != null) + { + mSettingsManager.removeListener(this); + } + + mSettingsManager = null; + } + + /** + * Sets/changes the DFT bin size + */ + public void setDFTSize(DFTSize size) + { + mDFTSize = size; + } + + public ChannelDisplay getChannelDisplay() + { + return mChannelDisplay; + } + + public void setChannelDisplay(ChannelDisplay display) + { + mChannelDisplay = display; + } + + public void setCursorLocation(Point point) + { + mCursorLocation = point; + + repaint(); + } + + public void setCursorVisible(boolean visible) + { + mCursorVisible = visible; + + repaint(); } - - public void dispose() - { - if( mChannelModel != null ) - { - mChannelModel.removeListener( this ); - } - - mChannelModel = null; - - mVisibleChannels.clear(); - - if( mSettingsManager != null ) - { - mSettingsManager.removeListener( this ); - } - - mSettingsManager = null; - } - - /** - * Sets/changes the DFT bin size - */ - public void setDFTSize( DFTSize size ) - { - mDFTSize = size; - } - - public ChannelDisplay getChannelDisplay() - { - return mChannelDisplay; - } - public void setChannelDisplay( ChannelDisplay display ) - { - mChannelDisplay = display; - } - - public void setCursorLocation( Point point ) - { - mCursorLocation = point; - - repaint(); - } - - public void setCursorVisible( boolean visible ) - { - mCursorVisible = visible; - - repaint(); - } - /** * Sets the current zoom level (2^zoom) - * + * * 0 No Zoom * 1 2x Zoom * 2 4x Zoom @@ -199,745 +185,707 @@ public class OverlayPanel extends JPanel * 4 16x Zoom * 5 32x Zoom * 6 64x Zoom - * + * * @param zoom level, 0 - 6. * @param offset into the FFT bins for start zoom window */ - public void setZoom( int zoom ) - { - mZoom = zoom; - - mLabelSizeMonitor.update(); - } - - public void setZoomWindowOffset( int offset ) - { - mDFTZoomWindowOffset = offset; - } - - /** - * Fetches the color settings from the settings manager - */ - private void setColors() - { - mColorChannelConfig = getColor( ColorSettingName.CHANNEL_CONFIG ); - - mColorChannelConfigProcessing = - getColor( ColorSettingName.CHANNEL_CONFIG_PROCESSING ); - - mColorChannelConfigSelected = - getColor( ColorSettingName.CHANNEL_CONFIG_SELECTED ); - - mColorSpectrumCursor = getColor( ColorSettingName.SPECTRUM_CURSOR ); - - mColorSpectrumLine = getColor( ColorSettingName.SPECTRUM_LINE ); - - mColorSpectrumBackground = - getColor( ColorSettingName.SPECTRUM_BACKGROUND ); - } - - /** - * Fetches a named color setting from the settings manager. If the setting - * doesn't exist, creates the setting using the defaultColor - */ - private Color getColor( ColorSettingName name ) - { - ColorSetting setting = mSettingsManager.getColorSetting( name ); - - return setting.getColor(); - } - - /** - * Monitors for setting changes. Colors can be changed by external actions - * and will automatically update in this class - */ - @Override - public void settingChanged( Setting setting ) + public void setZoom(int zoom) { - if( setting instanceof ColorSetting ) - { - ColorSetting colorSetting = (ColorSetting)setting; - - switch( colorSetting.getColorSettingName() ) - { - case CHANNEL_CONFIG: - mColorChannelConfig = colorSetting.getColor(); - break; - case CHANNEL_CONFIG_PROCESSING: - mColorChannelConfigProcessing = colorSetting.getColor(); - break; - case CHANNEL_CONFIG_SELECTED: - mColorChannelConfigSelected = colorSetting.getColor(); - break; - case SPECTRUM_BACKGROUND: - mColorSpectrumBackground = colorSetting.getColor(); - break; - case SPECTRUM_CURSOR: - mColorSpectrumCursor = colorSetting.getColor(); - break; - case SPECTRUM_LINE: - mColorSpectrumLine = colorSetting.getColor(); - break; - default: - break; - } - } + mZoom = zoom; + + mLabelSizeMonitor.update(); } - - /** - * Renders the channel configs, lines, labels, and cursor - */ - @Override - public void paintComponent( Graphics g ) - { - super.paintComponent( g ); - - Graphics2D graphics = (Graphics2D) g; - graphics.setBackground( mColorSpectrumBackground ); - graphics.setRenderingHints( RENDERING_HINTS ); - - drawFrequencies( graphics ); - drawChannels( graphics ); - drawCursor( graphics ); + public void setZoomWindowOffset(int offset) + { + mDFTZoomWindowOffset = offset; } /** - * Draws a cursor on the panel, whenever the mouse is hovering over the + * Fetches the color settings from the settings manager + */ + private void setColors() + { + mColorChannelConfig = getColor(ColorSettingName.CHANNEL_CONFIG); + + mColorChannelConfigProcessing = getColor(ColorSettingName.CHANNEL_CONFIG_PROCESSING); + + mColorChannelConfigSelected = getColor(ColorSettingName.CHANNEL_CONFIG_SELECTED); + + mColorSpectrumCursor = getColor(ColorSettingName.SPECTRUM_CURSOR); + + mColorSpectrumLine = getColor(ColorSettingName.SPECTRUM_LINE); + + mColorSpectrumBackground = getColor(ColorSettingName.SPECTRUM_BACKGROUND); + } + + /** + * Fetches a named color setting from the settings manager. If the setting + * doesn't exist, creates the setting using the defaultColor + */ + private Color getColor(ColorSettingName name) + { + ColorSetting setting = mSettingsManager.getColorSetting(name); + + return setting.getColor(); + } + + /** + * Monitors for setting changes. Colors can be changed by external actions + * and will automatically update in this class + */ + @Override + public void settingChanged(Setting setting) + { + if(setting instanceof ColorSetting) + { + ColorSetting colorSetting = (ColorSetting)setting; + + switch(colorSetting.getColorSettingName()) + { + case CHANNEL_CONFIG: + mColorChannelConfig = colorSetting.getColor(); + break; + case CHANNEL_CONFIG_PROCESSING: + mColorChannelConfigProcessing = colorSetting.getColor(); + break; + case CHANNEL_CONFIG_SELECTED: + mColorChannelConfigSelected = colorSetting.getColor(); + break; + case SPECTRUM_BACKGROUND: + mColorSpectrumBackground = colorSetting.getColor(); + break; + case SPECTRUM_CURSOR: + mColorSpectrumCursor = colorSetting.getColor(); + break; + case SPECTRUM_LINE: + mColorSpectrumLine = colorSetting.getColor(); + break; + default: + break; + } + } + } + + /** + * Renders the channel configs, lines, labels, and cursor + */ + @Override + public void paintComponent(Graphics g) + { + super.paintComponent(g); + + Graphics2D graphics = (Graphics2D)g; + graphics.setBackground(mColorSpectrumBackground); + + graphics.setRenderingHints(RENDERING_HINTS); + + drawFrequencies(graphics); + drawChannels(graphics); + drawCursor(graphics); + } + + /** + * Draws a cursor on the panel, whenever the mouse is hovering over the * panel */ - private void drawCursor( Graphics2D graphics ) + private void drawCursor(Graphics2D graphics) { - if( mCursorVisible ) - { - drawFrequencyLine( graphics, - mCursorLocation.x, - mColorSpectrumCursor ); + if(mCursorVisible) + { + drawFrequencyLine(graphics, mCursorLocation.x, mColorSpectrumCursor); - String frequency = CURSOR_FORMAT.format( - getFrequencyFromAxis( mCursorLocation.getX() ) / 1E6D ); + String frequency = CURSOR_FORMAT.format(getFrequencyFromAxis(mCursorLocation.getX()) / 1E6D); - graphics.drawString( frequency , - mCursorLocation.x + 5, - mCursorLocation.y ); + FontMetrics fontMetrics = graphics.getFontMetrics(this.getFont()); - if( mZoom != 0 ) - { - graphics.drawString( "Zoom: " + (int)Math.pow( 2.0, mZoom ) + "x", - mCursorLocation.x + 17, mCursorLocation.y + 11 ); - } - } + Rectangle2D rect = fontMetrics.getStringBounds(frequency, graphics); + + if(mCursorLocation.y > rect.getHeight()) + { + graphics.drawString(frequency, mCursorLocation.x + 5, mCursorLocation.y); + } + + if(mZoom != 0) + { + graphics.drawString("Zoom: " + (int)Math.pow(2.0, mZoom) + "x", mCursorLocation.x + 17, + mCursorLocation.y + 11); + } + } } - + /** * Draws the frequency lines and labels every 10kHz */ - private void drawFrequencies( Graphics2D graphics ) + private void drawFrequencies(Graphics2D graphics) { - Stroke currentStroke = graphics.getStroke(); - -// graphics.setStroke( DASHED_STROKE ); + Stroke currentStroke = graphics.getStroke(); - long minFrequency = getMinDisplayFrequency(); - long maxFrequency = getMaxDisplayFrequency(); + long minFrequency = getMinDisplayFrequency(); + long maxFrequency = getMaxDisplayFrequency(); - //Frequency increments for label and tick spacing - int label = mLabelSizeMonitor.getLabelIncrement( graphics ); - int major = mLabelSizeMonitor.getMajorTickIncrement( graphics ); - int minor = mLabelSizeMonitor.getMinorTickIncrement( graphics ); + //Frequency increments for label and tick spacing + int label = mLabelSizeMonitor.getLabelIncrement(graphics); + int major = mLabelSizeMonitor.getMajorTickIncrement(graphics); + int minor = mLabelSizeMonitor.getMinorTickIncrement(graphics); - //Avoid divide by zero error - if( minor == 0 ) - { - minor = 1; - } - - //Adjust the start frequency to a multiple of the minor tick spacing - long frequency = minFrequency - ( minFrequency % minor ); - - while( frequency < maxFrequency ) - { - if( frequency % label == 0 ) - { - drawFrequencyLineAndLabel( graphics, frequency ); - } - else if( frequency % major == 0 ) - { - drawTickLine( graphics, frequency, true ); - } - else - { - drawTickLine( graphics, frequency, false ); - } - - frequency += minor; - } - -// graphics.setStroke( currentStroke ); + //Avoid divide by zero error + if(minor == 0) + { + minor = 1; + } + + //Adjust the start frequency to a multiple of the minor tick spacing + long frequency = minFrequency - (minFrequency % minor); + + while(frequency < maxFrequency) + { + if(frequency % label == 0) + { + drawFrequencyLineAndLabel(graphics, frequency); + } + else if(frequency % major == 0) + { + drawTickLine(graphics, frequency, true); + } + else + { + drawTickLine(graphics, frequency, false); + } + + frequency += minor; + } } - + /** * Draws a vertical line and a corresponding frequency label at the bottom */ - private void drawFrequencyLineAndLabel( Graphics2D graphics, long frequency ) + private void drawFrequencyLineAndLabel(Graphics2D graphics, long frequency) { - double xAxis = getAxisFromFrequency( frequency ); - - drawFrequencyLine( graphics, xAxis, mColorSpectrumLine ); - - drawTickLine( graphics, frequency, false ); + double xAxis = getAxisFromFrequency(frequency); - graphics.setColor( mColorSpectrumLine ); + drawFrequencyLine(graphics, xAxis, mColorSpectrumLine); - drawFrequencyLabel( graphics, xAxis, frequency ); + drawTickLine(graphics, frequency, false); + + graphics.setColor(mColorSpectrumLine); + + drawFrequencyLabel(graphics, xAxis, frequency); } /** * Draws a vertical line at the xaxis */ - private void drawTickLine( Graphics2D graphics, long frequency, boolean major ) + private void drawTickLine(Graphics2D graphics, long frequency, boolean major) { - graphics.setColor( mColorSpectrumLine ); - - double xAxis = getAxisFromFrequency( frequency ); + graphics.setColor(mColorSpectrumLine); - double start = getSize().getHeight() - mSpectrumInset; - double end = start + ( major ? 9.0d : 3.0d ); - - graphics.draw( new Line2D.Double( xAxis, start, xAxis, end ) ); + double xAxis = getAxisFromFrequency(frequency); + + double start = getSize().getHeight() - mSpectrumInset; + double end = start + (major ? 9.0d : 3.0d); + + graphics.draw(new Line2D.Double(xAxis, start, xAxis, end)); } /** * Draws a vertical line at the xaxis */ - private void drawFrequencyLine( Graphics2D graphics, double xaxis, Color color ) + private void drawFrequencyLine(Graphics2D graphics, double xaxis, Color color) { - graphics.setColor( color ); - - graphics.draw( new Line2D.Double( xaxis, 0.0d, - xaxis, getSize().getHeight() - mSpectrumInset ) ); + graphics.setColor(color); + + graphics.draw(new Line2D.Double(xaxis, 0.0d, xaxis, getSize().getHeight() - mSpectrumInset)); } /** * Draws a vertical line at the xaxis */ - private void drawChannelCenterLine( Graphics2D graphics, double xaxis ) + private void drawChannelCenterLine(Graphics2D graphics, double xaxis) { - double height = getSize().getHeight() - mSpectrumInset; + double height = getSize().getHeight() - mSpectrumInset; - graphics.setColor( Color.LIGHT_GRAY ); + graphics.setColor(Color.LIGHT_GRAY); - graphics.draw( new Line2D.Double( xaxis, height * 0.65d, - xaxis, height - 1.0d ) ); + graphics.draw(new Line2D.Double(xaxis, height * 0.65d, xaxis, height - 1.0d)); } - + /** * Draws a vertical line at the xaxis */ - private void drawAFC( Graphics2D graphics, double frequencyAxis, double errorAxis ) + private void drawAFC(Graphics2D graphics, double frequencyAxis, double errorAxis) { - double height = getSize().getHeight() - mSpectrumInset; - double lineHeight = height * 0.75d; + double height = getSize().getHeight() - mSpectrumInset; + double lineHeight = height * 0.75d; - graphics.setColor( Color.YELLOW ); + graphics.setColor(Color.YELLOW); - //Vertical frequency error line - graphics.draw( new Line2D.Double( errorAxis, lineHeight, - errorAxis, height - 1.0d ) ); + //Vertical frequency error line + graphics.draw(new Line2D.Double(errorAxis, lineHeight, errorAxis, height - 1.0d)); - //Horizontal line connecting frequency and error lines - graphics.draw( new Line2D.Double( frequencyAxis, lineHeight, - errorAxis, lineHeight ) ); + //Horizontal line connecting frequency and error lines + graphics.draw(new Line2D.Double(frequencyAxis, lineHeight, errorAxis, lineHeight)); } - + /** * Returns the x-axis value corresponding to the frequency */ - private double getAxisFromFrequency( long frequency ) + private double getAxisFromFrequency(long frequency) { - double screenWidth = (double)getSize().getWidth(); + double screenWidth = (double)getSize().getWidth(); - double pixelsPerBin = screenWidth / (double)mDFTSize.getSize(); - - double pixelOffsetToMinDisplayFrequency = pixelsPerBin * 2.0d; + double pixelsPerBin = screenWidth / (double)mDFTSize.getSize(); - //Calculate frequency offset from the min frequency - double frequencyOffset = (double)( frequency - getMinDisplayFrequency() ); + double pixelOffsetToMinDisplayFrequency = pixelsPerBin * 2.0d; - //Determine ratio of frequency offset to overall bandwidth - double ratio = frequencyOffset / (double)getDisplayBandwidth(); + //Calculate frequency offset from the min frequency + double frequencyOffset = (double)(frequency - getMinDisplayFrequency()); - //Apply the ratio to the screen width minus 1 bin width - double screenOffset = screenWidth * ratio; - - return pixelOffsetToMinDisplayFrequency + screenOffset; + //Determine ratio of frequency offset to overall bandwidth + double ratio = frequencyOffset / (double)getDisplayBandwidth(); + + //Apply the ratio to the screen width minus 1 bin width + double screenOffset = screenWidth * ratio; + + return pixelOffsetToMinDisplayFrequency + screenOffset; } /** * Returns the frequency corresponding to the x-axis value using the current * zoom level. */ - public long getFrequencyFromAxis( double xAxis ) + public long getFrequencyFromAxis(double xAxis) { - double width = getSize().getWidth(); - - double offset = xAxis / width; - - long frequency = getMinDisplayFrequency() + - Math.round( (double)getDisplayBandwidth() * offset ); - - if( frequency > ( getMaxFrequency() ) ) - { - frequency = getMaxFrequency(); - } - - return frequency; + double width = getSize().getWidth(); + + double offset = xAxis / width; + + long frequency = getMinDisplayFrequency() + Math.round((double)getDisplayBandwidth() * offset); + + if(frequency > (getMaxFrequency())) + { + frequency = getMaxFrequency(); + } + + return frequency; } /** * Draws a frequency label at the x-axis position, at the bottom of the panel */ - private void drawFrequencyLabel( Graphics2D graphics, - double xaxis, - long frequency ) + private void drawFrequencyLabel(Graphics2D graphics, double xaxis, long frequency) { - String label = mLabelSizeMonitor.format( frequency ); - - FontMetrics fontMetrics = graphics.getFontMetrics( this.getFont() ); + String label = mLabelSizeMonitor.format(frequency); - Rectangle2D rect = fontMetrics.getStringBounds( label, graphics ); + FontMetrics fontMetrics = graphics.getFontMetrics(this.getFont()); - float xOffset = (float)rect.getWidth() / 2; + Rectangle2D rect = fontMetrics.getStringBounds(label, graphics); - graphics.drawString( label, (float)( xaxis - xOffset ), - (float)( getSize().getHeight() - 2.0f ) ); + float xOffset = (float)rect.getWidth() / 2; + + graphics.drawString(label, (float)(xaxis - xOffset), (float)(getSize().getHeight() - 2.0f)); } - + /** * Draws visible channel configs as translucent shaded frequency regions */ - private void drawChannels( Graphics2D graphics ) + private void drawChannels(Graphics2D graphics) { - for( Channel channel: mVisibleChannels ) - { - if( mChannelDisplay == ChannelDisplay.ALL || - ( mChannelDisplay == ChannelDisplay.ENABLED && - channel.getEnabled() ) ) - { - //Choose the correct background color to use - if( channel.isSelected() ) - { - graphics.setColor( mColorChannelConfigSelected ); - } - else if( channel.getEnabled() ) - { - graphics.setColor( mColorChannelConfigProcessing ); - } - else - { - graphics.setColor( mColorChannelConfig ); - } - - TunerChannel tunerChannel = channel.getTunerChannel(); - - if( tunerChannel != null ) + for(Channel channel : mVisibleChannels) + { + if(mChannelDisplay == ChannelDisplay.ALL || + (mChannelDisplay == ChannelDisplay.ENABLED && channel.getEnabled())) + { + //Choose the correct background color to use + if(channel.isSelected()) { - double xAxis = getAxisFromFrequency( tunerChannel.getFrequency() ); + graphics.setColor(mColorChannelConfigSelected); + } + else if(channel.getEnabled()) + { + graphics.setColor(mColorChannelConfigProcessing); + } + else + { + graphics.setColor(mColorChannelConfig); + } - double width = (double)( tunerChannel.getBandwidth() ) / - (double)getDisplayBandwidth() * getSize().getWidth(); - - Rectangle2D.Double box = - new Rectangle2D.Double( xAxis - ( width / 2.0d ), - 0.0d, width, getSize().getHeight() - mSpectrumInset ); + TunerChannel tunerChannel = channel.getTunerChannel(); + + if(tunerChannel != null) + { + double xAxis = getAxisFromFrequency(tunerChannel.getFrequency()); + + double width = (double)(tunerChannel.getBandwidth()) / (double)getDisplayBandwidth() * getSize().getWidth(); + + Rectangle2D.Double box = + new Rectangle2D.Double(xAxis - (width / 2.0d), 0.0d, width, getSize().getHeight() - mSpectrumInset); //Fill the box with the correct color - graphics.fill( box ); + graphics.fill(box); - graphics.draw( box ); + graphics.draw(box); //Change to the line color to render the channel name, etc. - graphics.setColor( mColorSpectrumLine ); + graphics.setColor(mColorSpectrumLine); //Draw the labels starting at yAxis position 0 double yAxis = 0; - + //Draw the system label and adjust the y-axis position String system = channel.hasSystem() ? channel.getSystem() : " "; - - yAxis += drawLabel( graphics, - system, - this.getFont(), - xAxis, - yAxis, - width ); + + yAxis += drawLabel(graphics, system, this.getFont(), xAxis, yAxis, width); //Draw the site label and adjust the y-axis position String site = channel.hasSite() ? channel.getSite() : " "; - yAxis += drawLabel( graphics, - site, - this.getFont(), - xAxis, - yAxis, - width ); + yAxis += drawLabel(graphics, site, this.getFont(), xAxis, yAxis, width); //Draw the channel label and adjust the y-axis position - yAxis += drawLabel( graphics, - channel.getName(), - this.getFont(), - xAxis, - yAxis, - width ); - + yAxis += drawLabel(graphics, channel.getName(), this.getFont(), xAxis, yAxis, width); + //Draw the decoder label - drawLabel( graphics, channel.getDecodeConfiguration().getDecoderType().getShortDisplayString(), - this.getFont(), xAxis, yAxis, width ); - - long frequency = tunerChannel.getFrequency(); - - double frequencyAxis = getAxisFromFrequency( frequency ); - - drawChannelCenterLine( graphics, frequencyAxis ); + drawLabel(graphics, channel.getDecodeConfiguration().getDecoderType().getShortDisplayString(), + this.getFont(), xAxis, yAxis, width); + + long frequency = tunerChannel.getFrequency(); + + double frequencyAxis = getAxisFromFrequency(frequency); + + drawChannelCenterLine(graphics, frequencyAxis); /* Draw Automatic Frequency Control line */ int correction = channel.getChannelFrequencyCorrection(); - - if( correction != 0 ) + + if(correction != 0) { - long error = frequency + correction; - - drawAFC( graphics, frequencyAxis, getAxisFromFrequency( error ) ); + long error = frequency + correction; + + drawAFC(graphics, frequencyAxis, getAxisFromFrequency(error)); } } - } - } + } + } } - - + + /** * Draws a textual label at the x/y position, clipping the end of the text * to fit within the maxwidth value. - * + * * @return height of the drawn label */ - private double drawLabel( Graphics2D graphics, String text, Font font, - double x, double baseY, double maxWidth ) + private double drawLabel(Graphics2D graphics, String text, Font font, double x, double baseY, double maxWidth) { - FontMetrics fontMetrics = graphics.getFontMetrics( font ); - - Rectangle2D label = fontMetrics.getStringBounds( text, graphics ); - + FontMetrics fontMetrics = graphics.getFontMetrics(font); + + Rectangle2D label = fontMetrics.getStringBounds(text, graphics); + double offset = label.getWidth() / 2.0d; double y = baseY + label.getHeight(); - + /** * If the label is wider than the max width, left justify the text and * clip the end of it */ - if( offset > ( maxWidth / 2.0d ) ) + if(offset > (maxWidth / 2.0d)) { - label.setRect( x - ( maxWidth / 2.0d ), - y - label.getHeight(), - maxWidth, - label.getHeight() ); - - graphics.setClip( label ); + label.setRect(x - (maxWidth / 2.0d), y - label.getHeight(), maxWidth, label.getHeight()); - graphics.drawString( text, - (float)( x - ( maxWidth / 2.0d ) ), (float)y ); - - graphics.setClip( null ); + graphics.setClip(label); + + graphics.drawString(text, (float)(x - (maxWidth / 2.0d)), (float)y); + + graphics.setClip(null); } else { - graphics.drawString( text, (float)( x - offset ), (float)y ); + graphics.drawString(text, (float)(x - offset), (float)y); } - + return label.getHeight(); } /** * Frequency change event handler */ - @Override - public void frequencyChanged( FrequencyChangeEvent event ) - { - switch( event.getEvent() ) - { - case NOTIFICATION_SAMPLE_RATE_CHANGE: - mBandwidth = event.getValue().intValue(); - mLabelSizeMonitor.update(); - break; - case NOTIFICATION_FREQUENCY_CHANGE: - mFrequency = event.getValue().longValue(); - mLabelSizeMonitor.update(); - break; - default: - break; - } - - /** - * Reset the visible channels list - */ - mVisibleChannels.clear(); - mVisibleChannels.addAll( - mChannelModel.getChannelsInFrequencyRange( getMinFrequency(), - getMaxFrequency() ) ); - } - - /** - * Channel change event handler - */ @Override - @SuppressWarnings( "incomplete-switch" ) - public void channelChanged( ChannelEvent event ) - { - Channel channel = event.getChannel(); - - switch( event.getEvent() ) - { - case NOTIFICATION_ADD: - case NOTIFICATION_PROCESSING_START: - if( !mVisibleChannels.contains( channel ) && - channel.isWithin( getMinFrequency(), getMaxFrequency() ) ) - { - mVisibleChannels.add( channel ); - } - break; - case NOTIFICATION_DELETE: - mVisibleChannels.remove( channel ); - break; - case NOTIFICATION_PROCESSING_STOP: - if( channel.getChannelType() == ChannelType.TRAFFIC ) - { - mVisibleChannels.remove( channel ); - } - break; - case NOTIFICATION_CONFIGURATION_CHANGE: - if( mVisibleChannels.contains( channel ) && - !channel.isWithin( getMinFrequency(), getMaxFrequency() ) ) - { - mVisibleChannels.remove( channel ); - } - - if( !mVisibleChannels.contains( channel ) && - channel.isWithin( getMinFrequency(), getMaxFrequency() ) ) - { - mVisibleChannels.add( channel ); - } - break; - default: - break; - } - - repaint(); - } - - public int getBandwidth() + public void frequencyChanged(FrequencyChangeEvent event) { - return mBandwidth; - } - - /** - * Currently displayed minimum frequency - */ - public long getMinFrequency() - { - return mFrequency - ( mBandwidth / 2 ); - } - - /** - * Currently displayed maximum frequency - */ - public long getMaxFrequency() - { - return mFrequency + ( mBandwidth / 2 ); - } - - public boolean containsFrequency( long frequency ) - { - return Math.abs( mFrequency - frequency ) <= ( mBandwidth / 2 ); - } - - private long getMinDisplayFrequency() - { - double bandwidthPerBin = (double)mBandwidth / (double)( mDFTSize.getSize() ); - - return getMinFrequency() + (int)( ( mDFTZoomWindowOffset ) * bandwidthPerBin ); - } - - private long getMaxDisplayFrequency() - { - return getMinDisplayFrequency() + getDisplayBandwidth(); - } - - private int getDisplayBandwidth() - { - if( mZoom != 0 ) - { - return mBandwidth / (int)Math.pow( 2.0, mZoom ); - } - - return mBandwidth; - } - - /** - * Returns a list of channel configs that contain the frequency within their - * min/max frequency settings. - */ - public ArrayList getChannelsAtFrequency( long frequency ) - { - ArrayList configs = new ArrayList(); - - for( Channel config: mVisibleChannels ) - { - TunerChannel channel = config.getTunerChannel(); - - if( channel != null && - channel.getMinFrequency() <= frequency && - channel.getMaxFrequency() >= frequency ) - { - configs.add( config ); - } - } - - return configs; - } - - @Override - public void settingDeleted( Setting setting ) { /* not implemented */ } - - /** - * Calculates correct spacing and format for frequency labels and major/minor - * tick lines based on current frequency, bandwidth, zoom and screen size. - */ - public class LabelSizeManager implements ComponentListener - { - private static final double LABEL_FILL_THRESHOLD = 0.5d; - - private DecimalFormat mFrequencyFormat = new DecimalFormat( "0.0" ); - - private boolean mUpdateRequired = true; - private int mLabelIncrement = 1; - private int mMajorTickIncrement = 1; - private int mMinorTickIncrement = 1; - - public String format( long frequency ) - { - return mFrequencyFormat.format( (double)frequency / 1E6D ); - } - - private void setPrecision( int precision ) - { - if( precision < 1 ) - { - precision = 1; - } - - if( precision > 5 ) - { - precision = 5; - } - - mFrequencyFormat.setMinimumFractionDigits( precision ); - mFrequencyFormat.setMaximumFractionDigits( precision ); - } - - private void update( Graphics2D graphics ) - { - if( mUpdateRequired ) - { - //Set maximum precision as a starting point - setPrecision( 5 ); - - FontMetrics fontMetrics = - graphics.getFontMetrics( OverlayPanel.this.getFont() ); - - int maxLabelWidth = fontMetrics.stringWidth( format( getMaxDisplayFrequency() ) ); - - double maxLabels = ( (double)OverlayPanel.this.getWidth() * - LABEL_FILL_THRESHOLD ) / - (double)maxLabelWidth; - - //Calculate the next smallest base 10 value for the major increment - int power = (int)Math.log10( (double)getDisplayBandwidth() / maxLabels ); - - //Set the number of decimal places to display in frequency labels - int precision = 5 - power; - - int start = (int)Math.pow( 10.0, power + 1 ); - - int minimum = (int)Math.pow( 10.0, power ); - - int labelIncrement = start; - - while( ( (double)getDisplayBandwidth() / - (double)labelIncrement ) < maxLabels && - labelIncrement >= minimum ) - { - labelIncrement /= 2; - precision++; - } - - if( labelIncrement == minimum ) - { - precision = 5 - power; - } - - setPrecision( precision ); - - mLabelIncrement = labelIncrement; - mMajorTickIncrement = labelIncrement / 2; - mMinorTickIncrement = labelIncrement / 10; - - mUpdateRequired = false; - } - } - - /** - * Forces the display to update the label and frequency display - * calculations - */ - public void update() - { - mUpdateRequired = true; - } - - public int getMajorTickIncrement( Graphics2D graphics ) - { - //Check to see if a calculation update is scheduled - update( graphics ); - - return mMajorTickIncrement; - } - - public int getMinorTickIncrement( Graphics2D graphics ) - { - return mMinorTickIncrement; - } - - public int getLabelIncrement( Graphics2D graphics ) - { - return mLabelIncrement; - } - - @Override - public void componentResized( ComponentEvent arg0 ) + switch(event.getEvent()) { - update(); + case NOTIFICATION_SAMPLE_RATE_CHANGE: + mBandwidth = event.getValue().intValue(); + mLabelSizeMonitor.update(); + break; + case NOTIFICATION_FREQUENCY_CHANGE: + mFrequency = event.getValue().longValue(); + mLabelSizeMonitor.update(); + break; + default: + break; } - public void componentHidden( ComponentEvent arg0 ) {} - public void componentMoved( ComponentEvent arg0 ) {} - public void componentShown( ComponentEvent arg0 ) {} + /** + * Reset the visible channels list + */ + mVisibleChannels.clear(); + mVisibleChannels.addAll(mChannelModel.getChannelsInFrequencyRange(getMinFrequency(), getMaxFrequency())); + } - } + /** + * Channel change event handler + */ + @Override + @SuppressWarnings("incomplete-switch") + public void channelChanged(ChannelEvent event) + { + Channel channel = event.getChannel(); - public enum ChannelDisplay - { - ALL, ENABLED, NONE; - } + switch(event.getEvent()) + { + case NOTIFICATION_ADD: + case NOTIFICATION_PROCESSING_START: + if(!mVisibleChannels.contains(channel) && channel.isWithin(getMinFrequency(), getMaxFrequency())) + { + mVisibleChannels.add(channel); + } + break; + case NOTIFICATION_DELETE: + mVisibleChannels.remove(channel); + break; + case NOTIFICATION_PROCESSING_STOP: + if(channel.getChannelType() == ChannelType.TRAFFIC) + { + mVisibleChannels.remove(channel); + } + break; + case NOTIFICATION_CONFIGURATION_CHANGE: + if(mVisibleChannels.contains(channel) && !channel.isWithin(getMinFrequency(), getMaxFrequency())) + { + mVisibleChannels.remove(channel); + } + + if(!mVisibleChannels.contains(channel) && channel.isWithin(getMinFrequency(), getMaxFrequency())) + { + mVisibleChannels.add(channel); + } + break; + default: + break; + } + + repaint(); + } + + public int getBandwidth() + { + return mBandwidth; + } + + /** + * Currently displayed minimum frequency + */ + public long getMinFrequency() + { + return mFrequency - (mBandwidth / 2); + } + + /** + * Currently displayed maximum frequency + */ + public long getMaxFrequency() + { + return mFrequency + (mBandwidth / 2); + } + + public boolean containsFrequency(long frequency) + { + return Math.abs(mFrequency - frequency) <= (mBandwidth / 2); + } + + private long getMinDisplayFrequency() + { + double bandwidthPerBin = (double)mBandwidth / (double)(mDFTSize.getSize()); + + return getMinFrequency() + (int)((mDFTZoomWindowOffset) * bandwidthPerBin); + } + + private long getMaxDisplayFrequency() + { + return getMinDisplayFrequency() + getDisplayBandwidth(); + } + + private int getDisplayBandwidth() + { + if(mZoom != 0) + { + return mBandwidth / (int)Math.pow(2.0, mZoom); + } + + return mBandwidth; + } + + /** + * Returns a list of channel configs that contain the frequency within their + * min/max frequency settings. + */ + public ArrayList getChannelsAtFrequency(long frequency) + { + ArrayList configs = new ArrayList(); + + for(Channel config : mVisibleChannels) + { + TunerChannel channel = config.getTunerChannel(); + + if(channel != null && channel.getMinFrequency() <= frequency && channel.getMaxFrequency() >= frequency) + { + configs.add(config); + } + } + + return configs; + } + + @Override + public void settingDeleted(Setting setting) + { /* not implemented */ } + + /** + * Calculates correct spacing and format for frequency labels and major/minor + * tick lines based on current frequency, bandwidth, zoom and screen size. + */ + public class LabelSizeManager implements ComponentListener + { + private static final double LABEL_FILL_THRESHOLD = 0.5d; + + private DecimalFormat mFrequencyFormat = new DecimalFormat("0.0"); + + private boolean mUpdateRequired = true; + private int mLabelIncrement = 1; + private int mMajorTickIncrement = 1; + private int mMinorTickIncrement = 1; + + public String format(long frequency) + { + return mFrequencyFormat.format((double)frequency / 1E6D); + } + + private void setPrecision(int precision) + { + if(precision < 1) + { + precision = 1; + } + + if(precision > 5) + { + precision = 5; + } + + mFrequencyFormat.setMinimumFractionDigits(precision); + mFrequencyFormat.setMaximumFractionDigits(precision); + } + + private void update(Graphics2D graphics) + { + if(mUpdateRequired) + { + //Set maximum precision as a starting point + setPrecision(5); + + FontMetrics fontMetrics = + graphics.getFontMetrics(OverlayPanel.this.getFont()); + + int maxLabelWidth = fontMetrics.stringWidth(format(getMaxDisplayFrequency())); + + double maxLabels = ((double)OverlayPanel.this.getWidth() * LABEL_FILL_THRESHOLD) / (double)maxLabelWidth; + + //Calculate the next smallest base 10 value for the major increment + int power = (int)Math.log10((double)getDisplayBandwidth() / maxLabels); + + //Set the number of decimal places to display in frequency labels + int precision = 5 - power; + + int start = (int)Math.pow(10.0, power + 1); + + int minimum = (int)Math.pow(10.0, power); + + int labelIncrement = start; + + while(((double)getDisplayBandwidth() / (double)labelIncrement) < maxLabels && labelIncrement >= minimum) + { + labelIncrement /= 2; + precision++; + } + + if(labelIncrement == minimum) + { + precision = 5 - power; + } + + setPrecision(precision); + + mLabelIncrement = labelIncrement; + mMajorTickIncrement = labelIncrement / 2; + mMinorTickIncrement = labelIncrement / 10; + + mUpdateRequired = false; + } + } + + /** + * Forces the display to update the label and frequency display + * calculations + */ + public void update() + { + mUpdateRequired = true; + } + + public int getMajorTickIncrement(Graphics2D graphics) + { + //Check to see if a calculation update is scheduled + update(graphics); + + return mMajorTickIncrement; + } + + public int getMinorTickIncrement(Graphics2D graphics) + { + return mMinorTickIncrement; + } + + public int getLabelIncrement(Graphics2D graphics) + { + return mLabelIncrement; + } + + @Override + public void componentResized(ComponentEvent arg0) + { + update(); + } + + public void componentHidden(ComponentEvent arg0) + { + } + + public void componentMoved(ComponentEvent arg0) + { + } + + public void componentShown(ComponentEvent arg0) + { + } + + } + + public enum ChannelDisplay + { + ALL, ENABLED, NONE; + } } From 5e731d0e9fed32a185b831ef05236195c45bf8da Mon Sep 17 00:00:00 2001 From: Denny Date: Sun, 26 Feb 2017 06:51:58 -0500 Subject: [PATCH 12/13] Resolves issue with alias list and group combo box value editing. --- src/alias/AliasNameEditor.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/alias/AliasNameEditor.java b/src/alias/AliasNameEditor.java index 6c6ee06b..3c205941 100644 --- a/src/alias/AliasNameEditor.java +++ b/src/alias/AliasNameEditor.java @@ -40,10 +40,11 @@ public class AliasNameEditor extends Editor { private static final long serialVersionUID = 1L; - private static ComboBoxModel EMPTY_MODEL = new DefaultComboBoxModel<>(); + private static ComboBoxModel EMPTY_LIST_MODEL = new DefaultComboBoxModel<>(); + private static ComboBoxModel EMPTY_GROUP_MODEL = new DefaultComboBoxModel<>(); - private JComboBox mListCombo = new JComboBox<>(EMPTY_MODEL); - private JComboBox mGroupCombo = new JComboBox<>(EMPTY_MODEL); + private JComboBox mListCombo = new JComboBox<>(EMPTY_LIST_MODEL); + private JComboBox mGroupCombo = new JComboBox<>(EMPTY_GROUP_MODEL); private JComboBox mIconCombo; private JTextField mName; private JButton mButtonColor; @@ -110,7 +111,7 @@ public class AliasNameEditor extends Editor if(groups.isEmpty()) { - mGroupCombo.setModel(EMPTY_MODEL); + mGroupCombo.setModel(EMPTY_GROUP_MODEL); } else { @@ -238,7 +239,7 @@ public class AliasNameEditor extends Editor if(listNames.isEmpty()) { - mListCombo.setModel(EMPTY_MODEL); + mListCombo.setModel(EMPTY_LIST_MODEL); } else { @@ -253,7 +254,7 @@ public class AliasNameEditor extends Editor if(groupNames.isEmpty()) { - mGroupCombo.setModel(EMPTY_MODEL); + mGroupCombo.setModel(EMPTY_GROUP_MODEL); } else { @@ -285,8 +286,8 @@ public class AliasNameEditor extends Editor } else { - mListCombo.setModel(EMPTY_MODEL); - mGroupCombo.setModel(EMPTY_MODEL); + mListCombo.setModel(EMPTY_LIST_MODEL); + mGroupCombo.setModel(EMPTY_GROUP_MODEL); mName.setText(null); mButtonColor.setBackground(getBackground()); From 09cf4fcfd7d4a7e81474e6289531b07a9b3f198e Mon Sep 17 00:00:00 2001 From: Denny Date: Sun, 26 Feb 2017 10:29:14 -0500 Subject: [PATCH 13/13] Resolves issue with empty string list models in channel editor --- .../channel/NameConfigurationEditor.java | 442 +++++++++--------- 1 file changed, 220 insertions(+), 222 deletions(-) diff --git a/src/controller/channel/NameConfigurationEditor.java b/src/controller/channel/NameConfigurationEditor.java index e0525bdf..fc8961de 100644 --- a/src/controller/channel/NameConfigurationEditor.java +++ b/src/controller/channel/NameConfigurationEditor.java @@ -1,269 +1,267 @@ /******************************************************************************* * SDR Trunk * Copyright (C) 2014-2016 Dennis Sheirer - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see ******************************************************************************/ package controller.channel; +import alias.AliasModel; import gui.editor.Editor; +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.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collections; import java.util.List; -import javax.swing.ComboBoxModel; -import javax.swing.DefaultComboBoxModel; -import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JTextField; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.miginfocom.swing.MigLayout; -import alias.AliasModel; - public class NameConfigurationEditor extends Editor implements DocumentListener { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - private final static Logger mLog = LoggerFactory.getLogger( NameConfigurationEditor.class ); + private final static Logger mLog = LoggerFactory.getLogger(NameConfigurationEditor.class); - private static ComboBoxModel EMPTY_MODEL = new DefaultComboBoxModel<>(); + private static ComboBoxModel EMPTY_SYSTEM_MODEL = new DefaultComboBoxModel<>(); + private static ComboBoxModel EMPTY_SITE_MODEL = new DefaultComboBoxModel<>(); + private static ComboBoxModel EMPTY_ALIAS_LIST_MODEL = new DefaultComboBoxModel<>(); - private AliasModel mAliasModel; - private ChannelModel mChannelModel; - - private JTextField mChannelName; - private JComboBox mSystemNameCombo; - private JComboBox mSiteNameCombo; - private JComboBox mAliasListCombo; - - public NameConfigurationEditor( AliasModel aliasModel, ChannelModel model ) - { - mAliasModel = aliasModel; - mChannelModel = model; + private AliasModel mAliasModel; + private ChannelModel mChannelModel; - init(); - } - - private void init() - { - setLayout( new MigLayout( "fill,wrap 4", "[right][grow,fill][right][grow,fill]", "[][][grow]" ) ); + private JTextField mChannelName; + private JComboBox mSystemNameCombo; + private JComboBox mSiteNameCombo; + private JComboBox mAliasListCombo; - mChannelName = new JTextField( "" ); - mChannelName.getDocument().addDocumentListener( this ); - mChannelName.setEnabled( false ); + public NameConfigurationEditor(AliasModel aliasModel, ChannelModel model) + { + mAliasModel = aliasModel; + mChannelModel = model; - add( new JLabel( "Name:" ) ); - add( mChannelName ); + init(); + } - mSystemNameCombo = new JComboBox<>( EMPTY_MODEL ); - mSystemNameCombo.setEnabled( false ); - mSystemNameCombo.setEditable( true ); - mSystemNameCombo.addActionListener( new ActionListener() - { - @Override - public void actionPerformed( ActionEvent e ) - { - Object selected = mSystemNameCombo.getSelectedItem(); - - if( selected != null ) - { - String system = (String)selected; - - List sites = mChannelModel.getSites( system ); + private void init() + { + setLayout(new MigLayout("fill,wrap 4", "[right][grow,fill][right][grow,fill]", "[][][grow]")); - if( !sites.contains( getItem().getSite() ) ) - { - sites.add( getItem().getSite() ); - } - - if( sites.isEmpty() ) - { - mSiteNameCombo.setModel( EMPTY_MODEL ); - } - else - { - mSiteNameCombo.setModel( new DefaultComboBoxModel( - sites.toArray( new String[ sites.size() ] ) ) );; - } - - mSiteNameCombo.setSelectedItem( getItem().getSite() ); - } - - setModified( true ); - } - } ); - - add( new JLabel( "System:" ) ); - add( mSystemNameCombo ); + mChannelName = new JTextField(""); + mChannelName.getDocument().addDocumentListener(this); + mChannelName.setEnabled(false); - mAliasListCombo = new JComboBox(); - mAliasListCombo.setEnabled( false ); - mAliasListCombo.setEditable( true ); - mAliasListCombo.addActionListener( new ActionListener() - { - @Override - public void actionPerformed( ActionEvent e ) - { - setModified( true ); - } - } ); - - add( new JLabel( "Alias List:" ) ); - add( mAliasListCombo ); - - mSiteNameCombo = new JComboBox<>( EMPTY_MODEL ); - mSiteNameCombo.setEnabled( false ); - mSiteNameCombo.setEditable( true ); - mSiteNameCombo.addActionListener( new ActionListener() - { - @Override - public void actionPerformed( ActionEvent e ) - { - setModified( true ); - } - } ); - - add( new JLabel( "Site:" ) ); - add( mSiteNameCombo ); - } - - @Override - public void save() - { - if( hasItem() && isModified() ) - { - getItem().setName( mChannelName.getText() ); - - Object system = mSystemNameCombo.getSelectedItem(); - getItem().setSystem( ( system == null ? null : (String)system ) ); + add(new JLabel("Name:")); + add(mChannelName); - Object site = mSiteNameCombo.getSelectedItem(); - getItem().setSite( ( site == null ? null : (String)site ) ); + mSystemNameCombo = new JComboBox<>(EMPTY_SYSTEM_MODEL); + mSystemNameCombo.setEnabled(false); + mSystemNameCombo.setEditable(true); + mSystemNameCombo.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + Object selected = mSystemNameCombo.getSelectedItem(); - Object aliasList = mAliasListCombo.getSelectedItem(); - getItem().setAliasListName( aliasList == null ? null : (String)aliasList ); - } - - setModified( false ); - } + if(selected != null) + { + String system = (String)selected; - private void setControlsEnabled( boolean enabled ) - { - if( mChannelName.isEnabled() != enabled ) - { - mChannelName.setEnabled( enabled ); - } + List sites = mChannelModel.getSites(system); - if( mAliasListCombo.isEnabled() != enabled ) - { - mAliasListCombo.setEnabled( enabled ); - } + if(!sites.contains(getItem().getSite())) + { + sites.add(getItem().getSite()); + } - if( mSystemNameCombo.isEnabled() != enabled ) - { - mSystemNameCombo.setEnabled( enabled ); - } - - if( mSiteNameCombo.isEnabled() != enabled ) - { - mSiteNameCombo.setEnabled( enabled ); - } - } + if(sites.isEmpty()) + { + mSiteNameCombo.setModel(EMPTY_SITE_MODEL); + } + else + { + mSiteNameCombo.setModel(new DefaultComboBoxModel( + sites.toArray(new String[sites.size()]))); + ; + } - @Override - public void setItem( Channel channel ) - { - super.setItem( channel ); - - if( hasItem() ) - { - setControlsEnabled( true ); - - mChannelName.setText( channel.getName() ); + mSiteNameCombo.setSelectedItem(getItem().getSite()); + } - List systems = mChannelModel.getSystems(); - - if( systems.isEmpty() ) - { - mSystemNameCombo.setModel( EMPTY_MODEL ); - } - else - { - mSystemNameCombo.setModel( new DefaultComboBoxModel( - systems.toArray( new String[ systems.size() ] ) ) );; - } - - mSystemNameCombo.setSelectedItem( channel.getSystem() ); + setModified(true); + } + }); - List sites = mChannelModel.getSites( channel.getSystem() ); + add(new JLabel("System:")); + add(mSystemNameCombo); - if( sites.isEmpty() ) - { - mSiteNameCombo.setModel( EMPTY_MODEL ); - } - else - { - mSiteNameCombo.setModel( new DefaultComboBoxModel( - sites.toArray( new String[ sites.size() ] ) ) );; - } + mAliasListCombo = new JComboBox(EMPTY_ALIAS_LIST_MODEL); + mAliasListCombo.setEnabled(false); + mAliasListCombo.setEditable(true); + mAliasListCombo.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + setModified(true); + } + }); - if( channel.getSite() != null ) - { - mSiteNameCombo.setSelectedItem( channel.getSite() ); - } - - List lists = mAliasModel.getListNames(); - Collections.sort( lists ); - mAliasListCombo.setModel( new DefaultComboBoxModel( - lists.toArray( new String[ lists.size() ] ) ) ); - - if( channel.getAliasListName() != null ) - { - mAliasListCombo.setSelectedItem( channel.getAliasListName() ); - } - } - else - { - setControlsEnabled( false ); - mChannelName.setText( null ); - } - - setModified( false ); - } + add(new JLabel("Alias List:")); + add(mAliasListCombo); - @Override - public void insertUpdate( DocumentEvent e ) - { - setModified( true ); - } + mSiteNameCombo = new JComboBox<>(EMPTY_SITE_MODEL); + mSiteNameCombo.setEnabled(false); + mSiteNameCombo.setEditable(true); + mSiteNameCombo.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + setModified(true); + } + }); - @Override - public void changedUpdate( DocumentEvent e ) - { - setModified( true ); - } - - @Override - public void removeUpdate( DocumentEvent e ) - { - setModified( true ); - } + add(new JLabel("Site:")); + add(mSiteNameCombo); + } + + @Override + public void save() + { + if(hasItem() && isModified()) + { + getItem().setName(mChannelName.getText()); + + Object system = mSystemNameCombo.getSelectedItem(); + getItem().setSystem((system == null ? null : (String)system)); + + Object site = mSiteNameCombo.getSelectedItem(); + getItem().setSite((site == null ? null : (String)site)); + + Object aliasList = mAliasListCombo.getSelectedItem(); + getItem().setAliasListName(aliasList == null ? null : (String)aliasList); + } + + setModified(false); + } + + private void setControlsEnabled(boolean enabled) + { + if(mChannelName.isEnabled() != enabled) + { + mChannelName.setEnabled(enabled); + } + + if(mAliasListCombo.isEnabled() != enabled) + { + mAliasListCombo.setEnabled(enabled); + } + + if(mSystemNameCombo.isEnabled() != enabled) + { + mSystemNameCombo.setEnabled(enabled); + } + + if(mSiteNameCombo.isEnabled() != enabled) + { + mSiteNameCombo.setEnabled(enabled); + } + } + + @Override + public void setItem(Channel channel) + { + super.setItem(channel); + + if(hasItem()) + { + setControlsEnabled(true); + + mChannelName.setText(channel.getName()); + + List systems = mChannelModel.getSystems(); + + if(systems.isEmpty()) + { + mSystemNameCombo.setModel(EMPTY_SYSTEM_MODEL); + } + else + { + mSystemNameCombo.setModel(new DefaultComboBoxModel( + systems.toArray(new String[systems.size()]))); + ; + } + + mSystemNameCombo.setSelectedItem(channel.getSystem()); + + List sites = mChannelModel.getSites(channel.getSystem()); + + if(sites.isEmpty()) + { + mSiteNameCombo.setModel(EMPTY_SITE_MODEL); + } + else + { + mSiteNameCombo.setModel(new DefaultComboBoxModel( + sites.toArray(new String[sites.size()]))); + ; + } + + if(channel.getSite() != null) + { + mSiteNameCombo.setSelectedItem(channel.getSite()); + } + + List lists = mAliasModel.getListNames(); + Collections.sort(lists); + mAliasListCombo.setModel(new DefaultComboBoxModel( + lists.toArray(new String[lists.size()]))); + + if(channel.getAliasListName() != null) + { + mAliasListCombo.setSelectedItem(channel.getAliasListName()); + } + } + else + { + setControlsEnabled(false); + mChannelName.setText(null); + } + + setModified(false); + } + + @Override + public void insertUpdate(DocumentEvent e) + { + setModified(true); + } + + @Override + public void changedUpdate(DocumentEvent e) + { + setModified(true); + } + + @Override + public void removeUpdate(DocumentEvent e) + { + setModified(true); + } }