diff --git a/src/main/java/io/github/dsheirer/alias/AliasEvent.java b/src/main/java/io/github/dsheirer/alias/AliasEvent.java
deleted file mode 100644
index f0370ae6..00000000
--- a/src/main/java/io/github/dsheirer/alias/AliasEvent.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*******************************************************************************
- * 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 io.github.dsheirer.alias;
-
-public class AliasEvent
-{
- private Alias mAlias;
- private Event mEvent;
-
- /**
- * AliasEvent - event describing any changes to an alias
- * @param alias - alias that changed
- * @param event - change event
- */
- public AliasEvent( Alias alias, Event event )
- {
- mAlias = alias;
- mEvent = event;
- }
-
- public Alias getAlias()
- {
- return mAlias;
- }
-
- public Event getEvent()
- {
- return mEvent;
- }
-
- /**
- * Channel events to describe the specific event
- */
- public enum Event
- {
- ADD,
- CHANGE,
- DELETE;
- }
-}
diff --git a/src/main/java/io/github/dsheirer/alias/AliasFactory.java b/src/main/java/io/github/dsheirer/alias/AliasFactory.java
index 2618e47d..095d85ee 100644
--- a/src/main/java/io/github/dsheirer/alias/AliasFactory.java
+++ b/src/main/java/io/github/dsheirer/alias/AliasFactory.java
@@ -51,6 +51,9 @@ import io.github.dsheirer.alias.id.tone.TonesID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
+import java.util.List;
+
public class AliasFactory
{
private static final Logger mLog = LoggerFactory.getLogger(AliasFactory.class);
@@ -180,32 +183,56 @@ public class AliasFactory
return null;
}
- public static Alias copyOf(Alias original)
+ public static Alias shallowCopyOf(Alias original)
{
Alias copy = new Alias(original.getName());
copy.setAliasListName(original.getAliasListName());
copy.setGroup(original.getGroup());
copy.setColor(original.getColor());
copy.setIconName(original.getIconName());
+ return copy;
+ }
+
+ public static List copyAliasIDs(Alias original)
+ {
+ List aliasIDS = new ArrayList<>();
for(AliasID id : original.getAliasIdentifiers())
{
- AliasID copyID = copyOf(id);
-
- if(copyID != null)
- {
- copy.addAliasID(copyID);
- }
+ aliasIDS.add(copyOf(id));
}
- for(AliasAction action : original.getAliasActions())
- {
- AliasAction copyAction = copyOf(action);
+ return aliasIDS;
+ }
- if(copyAction != null)
- {
- copy.addAliasAction(copyAction);
- }
+ public static List copyAliasActions(Alias original)
+ {
+ List actions = new ArrayList<>();
+
+ for(AliasAction aliasAction: original.getAliasActions())
+ {
+ actions.add(copyOf(aliasAction));
+ }
+
+ return actions;
+ }
+
+ public static Alias copyOf(Alias original)
+ {
+ Alias copy = shallowCopyOf(original);
+
+ List aliasIDS = copyAliasIDs(original);
+
+ for(AliasID aliasID: aliasIDS)
+ {
+ copy.addAliasID(aliasID);
+ }
+
+ List actions = copyAliasActions(original);
+
+ for(AliasAction action: actions)
+ {
+ copy.addAliasAction(action);
}
return copy;
diff --git a/src/main/java/io/github/dsheirer/alias/AliasList.java b/src/main/java/io/github/dsheirer/alias/AliasList.java
index 6c2293ea..ce96e121 100644
--- a/src/main/java/io/github/dsheirer/alias/AliasList.java
+++ b/src/main/java/io/github/dsheirer/alias/AliasList.java
@@ -45,19 +45,27 @@ import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
import io.github.dsheirer.identifier.tone.ToneIdentifier;
import io.github.dsheirer.identifier.tone.ToneSequence;
import io.github.dsheirer.protocol.Protocol;
-import io.github.dsheirer.sample.Listener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
/**
* List of aliases that share the same alias list name and provides convenient methods for looking up alias
* objects that match an identifier.
*/
-public class AliasList implements Listener
+public class AliasList
{
private final static Logger mLog = LoggerFactory.getLogger(AliasList.class);
private Map mTalkgroupProtocolMap = new EnumMap<>(Protocol.class);
@@ -96,10 +104,7 @@ public class AliasList implements Listener
{
if(alias != null)
{
- for(AliasID aliasID : alias.getAliasIdentifiers())
- {
- addAliasID(aliasID, alias);
- }
+ alias.getAliasIdentifiers().stream().forEach(aliasID -> addAliasID(aliasID, alias));
}
if(alias.hasActions())
@@ -107,7 +112,10 @@ public class AliasList implements Listener
mHasAliasActions = true;
}
- mAliases.add(alias);
+ if(!mAliases.contains(alias))
+ {
+ mAliases.add(alias);
+ }
}
/**
@@ -174,7 +182,7 @@ public class AliasList implements Listener
radioRangeAliasList.add(radioRange, alias);
break;
case ESN:
- String esn = ((Esn) id).getEsn();
+ String esn = ((Esn)id).getEsn();
if(esn != null && !esn.isEmpty())
{
@@ -184,7 +192,7 @@ public class AliasList implements Listener
case STATUS:
int userStatus = ((UserStatusID)id).getStatus();
- if(mUserStatusMap.containsKey(userStatus))
+ if(mUserStatusMap.containsKey(userStatus) && !mUserStatusMap.get(userStatus).equals(alias))
{
id.setOverlap(true);
@@ -203,7 +211,7 @@ public class AliasList implements Listener
case UNIT_STATUS:
int unitStatus = ((UnitStatusID)id).getStatus();
- if(mUnitStatusMap.containsKey(unitStatus))
+ if(mUnitStatusMap.containsKey(unitStatus) && !mUnitStatusMap.get(unitStatus).equals(alias))
{
id.setOverlap(true);
@@ -224,7 +232,7 @@ public class AliasList implements Listener
if(toneSequence != null)
{
- if(mToneSequenceMap.containsKey(toneSequence))
+ if(mToneSequenceMap.containsKey(toneSequence) && !mToneSequenceMap.get(toneSequence).equals(alias))
{
id.setOverlap(true);
@@ -232,7 +240,7 @@ public class AliasList implements Listener
for(AliasID aliasID: existing.getAliasIdentifiers())
{
- if(aliasID instanceof TonesID && ((TonesID)aliasID).equals(id))
+ if(aliasID instanceof TonesID && aliasID.equals(id))
{
aliasID.setOverlap(true);
}
@@ -253,112 +261,50 @@ public class AliasList implements Listener
}
}
- /**
- * Removes the alias and alias identifier to the internal type mapping.
- */
- private void removeAliasID(AliasID id, Alias alias)
- {
- try
- {
- switch(id.getType())
- {
- case TALKGROUP:
- Talkgroup talkgroup = (Talkgroup)id;
-
- TalkgroupAliasList talkgroupAliasList = mTalkgroupProtocolMap.get(talkgroup.getProtocol());
-
- if(talkgroupAliasList != null)
- {
- talkgroupAliasList.remove(talkgroup, alias);
- }
- break;
- case TALKGROUP_RANGE:
- TalkgroupRange talkgroupRange = (TalkgroupRange)id;
-
- TalkgroupAliasList talkgroupRangeAliasList = mTalkgroupProtocolMap.get(talkgroupRange.getProtocol());
-
- if(talkgroupRangeAliasList != null)
- {
- talkgroupRangeAliasList.remove(talkgroupRange, alias);
- }
- break;
- case RADIO_ID:
- Radio radio = (Radio)id;
-
- RadioAliasList radioAliasList = mRadioProtocolMap.get(radio.getProtocol());
-
- if(radioAliasList != null)
- {
- radioAliasList.remove(radio, alias);
- }
- break;
- case RADIO_ID_RANGE:
- RadioRange radioRange = (RadioRange)id;
-
- RadioAliasList radioRangeAliasList = mRadioProtocolMap.get(radioRange.getProtocol());
-
- if(radioRangeAliasList != null)
- {
- radioRangeAliasList.remove(radioRange, alias);
- }
- break;
- case ESN:
- String esn = ((Esn) id).getEsn();
-
- if(esn != null && !esn.isEmpty())
- {
- String key = esn.toLowerCase();
-
- if(mESNMap.containsKey(key) && mESNMap.get(key) == alias)
- {
- mESNMap.remove(key);
- }
- }
- break;
- case STATUS:
- int status = ((UserStatusID)id).getStatus();
-
- if(mUserStatusMap.containsKey(status) && mUserStatusMap.get(status) == alias)
- {
- mUserStatusMap.remove(status);
- }
- break;
- case UNIT_STATUS:
- int unitStatus = ((UnitStatusID)id).getStatus();
-
- if(mUnitStatusMap.containsKey(unitStatus) && mUnitStatusMap.get(unitStatus) == alias)
- {
- mUnitStatusMap.remove(unitStatus);
- }
- break;
- case TONES:
- ToneSequence toneSequence = ((TonesID)id).getToneSequence();
-
- if(toneSequence != null && mToneSequenceMap.containsKey(toneSequence) &&
- mToneSequenceMap.get(toneSequence) == alias)
- {
- mToneSequenceMap.remove(toneSequence);
- }
- break;
- }
- }
- catch(Exception e)
- {
- mLog.error("Couldn't remove alias ID " + id + " for alias " + alias, e);
- }
- }
-
/**
* Removes the alias from this list
*/
public void removeAlias(Alias alias)
{
- for(AliasID aliasID: alias.getAliasIdentifiers())
+ //Note: because the alias' identifiers could have changed from when we initially added the alias, we have to
+ //inspect every collection and map to remove the alias completely.
+ mAliases.remove(alias);
+
+ mTalkgroupProtocolMap.values().stream().forEach(talkgroupAliasList -> talkgroupAliasList.remove(alias));
+ mRadioProtocolMap.values().stream().forEach(radioAliasList -> radioAliasList.remove(alias));
+
+ Collection collection = Collections.singleton(alias);
+ mESNMap.values().removeAll(collection);
+ mUnitStatusMap.values().removeAll(collection);
+ mUserStatusMap.values().removeAll(collection);
+ mToneSequenceMap.values().removeAll(collection);
+
+ validate();
+ }
+
+ /**
+ * Identifies all aliases with an alias identifier that has the overlap flag set, resets the flag, and then readds
+ * each alias back to this alias list so that overlap can be detected again.
+ */
+ public void validate()
+ {
+ Set overlapAliases = new HashSet<>();
+
+ List aliases = new ArrayList<>(mAliases);
+
+ for(Alias alias: aliases)
{
- removeAliasID(aliasID, alias);
+ for(AliasID aliasID: alias.getAliasIdentifiers())
+ {
+ if(aliasID.overlapProperty().get())
+ {
+ aliasID.setOverlap(false);
+ overlapAliases.add(alias);
+ }
+ }
}
- mAliases.remove(alias);
+ overlapAliases.stream().forEach(alias -> addAlias(alias));
}
/**
@@ -402,32 +348,15 @@ public class AliasList implements Listener
}
/**
- * Receive alias change event notifications and modify this list accordingly
+ * Updates the alias by removing it from this list and then adding it back to this list when the list name matches.
*/
- @Override
- public void receive(AliasEvent event)
+ public void updateAlias(Alias alias)
{
- if(hasName())
- {
- Alias alias = event.getAlias();
+ removeAlias(alias);
- switch(event.getEvent())
- {
- case ADD:
- if(alias.getAliasListName() != null && getName().equalsIgnoreCase(alias.getAliasListName()))
- {
- addAlias(alias);
- }
- break;
- case DELETE:
- if(alias.getAliasListName() != null && getName().equalsIgnoreCase(alias.getAliasListName()))
- {
- removeAlias(alias);
- }
- break;
- default:
- break;
- }
+ if(hasName() && getName().equals(alias.getAliasListName()))
+ {
+ addAlias(alias);
}
}
@@ -659,34 +588,6 @@ public class AliasList implements Listener
return channels;
}
- /**
- * Identifies all aliases that have alias identifiers that match the alias ID and are in the same alias list.
- * @param alias for the list to search
- * @param aliasID to find matches
- * @return list of one or more aliases that have matching alias identifiers
- */
- public List getOverlappingAliases(Alias alias, AliasID aliasID)
- {
- List aliases = new ArrayList<>();
-
- for(Alias otherAlias: mAliases)
- {
- if(otherAlias != alias)
- {
- for(AliasID otherId: otherAlias.getAliasIdentifiers())
- {
- if(otherId.matches(aliasID) || otherId.overlaps(aliasID))
- {
- aliases.add(otherAlias);
- continue;
- }
- }
- }
- }
-
- return aliases;
- }
-
/**
* Listing of talkgroups and ranges for a specific protocol
*/
@@ -759,21 +660,13 @@ public class AliasList implements Listener
mTalkgroupRangeAliasMap.put(talkgroupRange, alias);
}
- public void remove(Talkgroup talkgroup, Alias alias)
+ /**
+ * Removes the alias from both the talkgroup and the talkgroup range maps.
+ */
+ public void remove(Alias alias)
{
- if(mTalkgroupAliasMap.containsKey(talkgroup.getValue()) && mTalkgroupAliasMap.get(talkgroup.getValue()) == alias)
- {
- mTalkgroupAliasMap.remove(talkgroup.getValue());
- }
- }
-
- public void remove(TalkgroupRange talkgroupRange, Alias alias)
- {
- //Only remove the entry if both the key and the value match
- if(mTalkgroupRangeAliasMap.containsKey(talkgroupRange) && mTalkgroupRangeAliasMap.get(talkgroupRange) == alias)
- {
- mTalkgroupRangeAliasMap.remove(talkgroupRange);
- }
+ mTalkgroupAliasMap.values().removeAll(Collections.singleton(alias));
+ mTalkgroupRangeAliasMap.values().removeAll(Collections.singleton(alias));
}
}
@@ -849,22 +742,13 @@ public class AliasList implements Listener
mRadioRangeAliasMap.put(radioRange, alias);
}
- public void remove(Radio radio, Alias alias)
+ /**
+ * Removes the alias from both the radio and the radio range maps.
+ */
+ public void remove(Alias alias)
{
- //Only remove the entry if both the key and the value match
- if(mRadioAliasMap.containsKey(radio.getValue()) && mRadioAliasMap.get(radio.getValue()) == alias)
- {
- mRadioAliasMap.remove(radio.getValue());
- }
- }
-
- public void remove(RadioRange radioRange, Alias alias)
- {
- //Only remove the entry if both the key and the value match
- if(mRadioRangeAliasMap.containsKey(radioRange) && mRadioRangeAliasMap.get(radioRange) == alias)
- {
- mRadioRangeAliasMap.remove(radioRange);
- }
+ mRadioAliasMap.values().removeAll(Collections.singleton(alias));
+ mRadioRangeAliasMap.values().removeAll(Collections.singleton(alias));
}
}
}
diff --git a/src/main/java/io/github/dsheirer/alias/AliasModel.java b/src/main/java/io/github/dsheirer/alias/AliasModel.java
index e14e6457..e215f029 100644
--- a/src/main/java/io/github/dsheirer/alias/AliasModel.java
+++ b/src/main/java/io/github/dsheirer/alias/AliasModel.java
@@ -26,8 +26,6 @@ import io.github.dsheirer.alias.id.AliasIDType;
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
import io.github.dsheirer.identifier.IdentifierCollection;
import io.github.dsheirer.identifier.configuration.AliasListConfigurationIdentifier;
-import io.github.dsheirer.sample.Broadcaster;
-import io.github.dsheirer.sample.Listener;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
@@ -51,7 +49,6 @@ public class AliasModel
public static final String NO_ALIAS_LIST = "(No Alias List)";
private ObservableList mAliases = FXCollections.observableArrayList(Alias.extractor());
private ObservableList mAliasListNames = FXCollections.observableArrayList();
- private Broadcaster mAliasEventBroadcaster = new Broadcaster<>();
private Map mAliasListMap = new HashMap<>();
public AliasModel()
@@ -135,7 +132,8 @@ public class AliasModel
}
AliasList mapValue = mAliasListMap.get(name);
- if (mapValue != null) {
+ if (mapValue != null)
+ {
return mapValue;
}
@@ -151,9 +149,6 @@ public class AliasModel
mAliasListMap.put(name, aliasList);
- //Register the new alias list to receive updates from this model
- addListener(aliasList);
-
return aliasList;
}
@@ -199,18 +194,19 @@ public class AliasModel
/**
* Adds the alias to the model
*/
- public int addAlias(Alias alias)
+ public void addAlias(Alias alias)
{
- if(alias != null)
+ if(mAliases.contains(alias))
{
- mAliases.add(alias);
- addAliasList(alias.getAliasListName());
- int index = mAliases.size() - 1;
- broadcast(new AliasEvent(alias, AliasEvent.Event.ADD));
- return index;
+ removeAlias(alias);
}
- return -1;
+ mAliases.add(alias);
+ }
+
+ private boolean hasAliasList(String aliasListName)
+ {
+ return aliasListName != null && mAliasListMap.containsKey(aliasListName);
}
public void addAliasList(String aliasListName)
@@ -220,7 +216,6 @@ public class AliasModel
if(!mAliasListNames.contains(aliasListName))
{
mAliasListNames.add(aliasListName);
- FXCollections.sort(mAliasListNames);
}
}
else if(!mAliasListNames.contains(NO_ALIAS_LIST))
@@ -232,14 +227,18 @@ public class AliasModel
}
/**
- * Removes the channel from the model and broadcasts a channel remove event
+ * Removes the alias from this model and an alias list (if one exists)
*/
public void removeAlias(Alias alias)
{
if(alias != null)
{
mAliases.remove(alias);
- broadcast(new AliasEvent(alias, AliasEvent.Event.DELETE));
+
+ if(hasAliasList(alias.getAliasListName()))
+ {
+ getAliasList(alias.getAliasListName()).removeAlias(alias);
+ }
}
}
@@ -328,32 +327,8 @@ public class AliasModel
}
}
- public void broadcast(AliasEvent event)
- {
- Alias alias = event.getAlias();
-
- //Validate the alias following a user action that changed the alias or any alias IDs
- if(alias != null)
- {
- alias.validate();
- }
-
- mAliasEventBroadcaster.broadcast(event);
- }
-
- public void addListener(Listener listener)
- {
- mAliasEventBroadcaster.addListener(listener);
- }
-
- public void removeListener(Listener listener)
- {
- mAliasEventBroadcaster.removeListener(listener);
- }
-
-
/**
- * Observable list change listener for both channels and traffic channels lists
+ * Monitors alias additions and removals and updates alias lists
*/
public class AliasListChangeListener implements ListChangeListener
{
@@ -366,21 +341,27 @@ public class AliasModel
{
for(Alias alias: change.getAddedSubList())
{
- mAliasEventBroadcaster.broadcast(new AliasEvent(alias, AliasEvent.Event.ADD));
+ addAliasList(alias.getAliasListName());
+
+ if(hasAliasList(alias.getAliasListName()))
+ {
+ getAliasList(alias.getAliasListName()).addAlias(alias);
+ }
}
}
else if(change.wasRemoved())
{
for(Alias alias: change.getRemoved())
{
- mAliasEventBroadcaster.broadcast(new AliasEvent(alias, AliasEvent.Event.DELETE));
- }
- }
- else if(change.wasUpdated())
- {
- for(int x = change.getFrom(); x < change.getTo(); x++)
- {
- mAliasEventBroadcaster.broadcast(new AliasEvent(change.getList().get(x), AliasEvent.Event.CHANGE));
+ if(hasAliasList(alias.getAliasListName()))
+ {
+ AliasList aliasList = getAliasList(alias.getName());
+
+ if(alias != null)
+ {
+ aliasList.removeAlias(alias);
+ }
+ }
}
}
}
diff --git a/src/main/java/io/github/dsheirer/alias/action/AliasActionListener.java b/src/main/java/io/github/dsheirer/alias/action/AliasActionListener.java
deleted file mode 100644
index 36e863d7..00000000
--- a/src/main/java/io/github/dsheirer/alias/action/AliasActionListener.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*******************************************************************************
- * 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 io.github.dsheirer.alias.action;
-
-import io.github.dsheirer.alias.AliasEvent;
-
-/**
- * Interface for receiving alias events. Each listener will receive
- * notification of all alias events.
- */
-public interface AliasActionListener
-{
- /**
- * Notifies the listener that an alias event has occurred
- */
- public void aliasChanged( AliasEvent event );
-}
diff --git a/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasConfigurationEditor.java b/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasConfigurationEditor.java
index 4a18b7b2..d436fed1 100644
--- a/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasConfigurationEditor.java
+++ b/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasConfigurationEditor.java
@@ -74,6 +74,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import java.util.function.Predicate;
/**
* Editor for aliases
@@ -97,7 +98,8 @@ public class AliasConfigurationEditor extends SplitPane
private ComboBox mAliasListNameComboBox;
private Button mNewAliasListButton;
private FilteredList mAliasFilteredList;
- private AliasFilterMonitor mAliasFilterMonitor;
+ private SortedList mAliasSortedList;
+ private AliasPredicate mAliasPredicate;
public AliasConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
{
@@ -124,7 +126,6 @@ public class AliasConfigurationEditor extends SplitPane
*/
public void show(Alias alias)
{
- mLog.debug("Showing: " + alias.getName());
if(alias != null)
{
String aliasList = alias.getAliasListName();
@@ -224,20 +225,40 @@ public class AliasConfigurationEditor extends SplitPane
if(mSearchField == null)
{
mSearchField = TextFields.createClearableTextField();
-
+ mSearchField.textProperty().addListener((observable, oldValue, newValue) -> update());
}
return mSearchField;
}
+ private void update()
+ {
+ getAliasFilteredList().setPredicate(null);
+ getAliasPredicate().setAliasListName(getAliasListNameComboBox().getSelectionModel().getSelectedItem());
+ getAliasPredicate().setSearchText(getSearchField().getText());
+ getAliasFilteredList().setPredicate(getAliasPredicate());
+ }
+
+ private AliasPredicate getAliasPredicate()
+ {
+ if(mAliasPredicate == null)
+ {
+ mAliasPredicate = new AliasPredicate();
+ mAliasPredicate.setAliasListName(getAliasListNameComboBox().getSelectionModel().getSelectedItem());
+ }
+
+ return mAliasPredicate;
+ }
+
private ComboBox getAliasListNameComboBox()
{
if(mAliasListNameComboBox == null)
{
mAliasListNameComboBox = new ComboBox<>(mPlaylistManager.getAliasModel().aliasListNames());
mAliasListNameComboBox.getSelectionModel().selectedItemProperty()
- .addListener((observable, oldValue, newValue) -> {
+ .addListener((ObservableValue extends String> observable, String oldValue, String newValue) -> {
getNewAliasButton().setDisable(newValue == null || newValue.contentEquals(AliasModel.NO_ALIAS_LIST));
+ update();
});
if(mAliasListNameComboBox.getItems().size() > 1)
@@ -362,15 +383,7 @@ public class AliasConfigurationEditor extends SplitPane
recordColumn, streamColumn, idsColumn, errorsColumn);
mAliasTableView.setPlaceholder(getPlaceholderLabel());
-
- //Sorting and filtering for the table
- mAliasFilteredList = new FilteredList<>(mPlaylistManager.getAliasModel().aliasList(),
- alias -> alias.matchesAliasList(getAliasListNameComboBox().getSelectionModel().getSelectedItem()));
- mAliasFilterMonitor = new AliasFilterMonitor();
-
- SortedList sortedList = new SortedList<>(mAliasFilteredList);
- sortedList.comparatorProperty().bind(mAliasTableView.comparatorProperty());
- mAliasTableView.setItems(sortedList);
+ mAliasTableView.setItems(getAliasSortedList());
mAliasTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
mAliasTableView.getSelectionModel().selectedItemProperty()
.addListener((observable, oldValue, newValue) -> {
@@ -381,6 +394,27 @@ public class AliasConfigurationEditor extends SplitPane
return mAliasTableView;
}
+ private FilteredList getAliasFilteredList()
+ {
+ if(mAliasFilteredList == null)
+ {
+ mAliasFilteredList = new FilteredList<>(mPlaylistManager.getAliasModel().aliasList(), getAliasPredicate());
+ }
+
+ return mAliasFilteredList;
+ }
+
+ private SortedList getAliasSortedList()
+ {
+ if(mAliasSortedList == null)
+ {
+ mAliasSortedList = new SortedList<>(getAliasFilteredList());
+ mAliasSortedList.comparatorProperty().bind(getAliasTableView().comparatorProperty());
+ }
+
+ return mAliasSortedList;
+ }
+
private Label getPlaceholderLabel()
{
if(mPlaceholderLabel == null)
@@ -417,7 +451,7 @@ public class AliasConfigurationEditor extends SplitPane
mNewAliasButton.setAlignment(Pos.CENTER);
mNewAliasButton.setMaxWidth(Double.MAX_VALUE);
mNewAliasButton.setOnAction(event -> {
- Alias alias = new Alias();
+ Alias alias = new Alias("New Alias");
alias.setAliasListName(getAliasListNameComboBox().getSelectionModel().getSelectedItem());
mPlaylistManager.getAliasModel().addAlias(alias);
@@ -477,7 +511,7 @@ public class AliasConfigurationEditor extends SplitPane
mCloneAliasButton.setMaxWidth(Double.MAX_VALUE);
mCloneAliasButton.setOnAction(event -> {
Alias original = getAliasTableView().getSelectionModel().getSelectedItem();
- Alias copy = AliasFactory.copyOf(original);
+ Alias copy = AliasFactory.shallowCopyOf(original);
mPlaylistManager.getAliasModel().addAlias(copy);
getAliasTableView().getSelectionModel().clearSelection();
getAliasTableView().getSelectionModel().select(copy);
@@ -765,47 +799,57 @@ public class AliasConfigurationEditor extends SplitPane
}
/**
- * Updates the filtered set of aliases any time there is a change in the selected alias list name box, or when the
- * user types text in the search box.
+ * Alias filter predicate
*/
- public class AliasFilterMonitor
+ public class AliasPredicate implements Predicate
{
- public AliasFilterMonitor()
- {
- getAliasListNameComboBox().getSelectionModel().selectedItemProperty()
- .addListener((observable, oldValue, newValue) -> {
- refresh();
- });
+ private String mAliasListName;
+ private String mSearchText;
- getSearchField().textProperty().addListener((observable, oldValue, newValue) -> {
- refresh();
- });
+ @Override
+ public boolean test(Alias alias)
+ {
+ if(mAliasListName == null)
+ {
+ return false;
+ }
+ else if(mAliasListName.equals(alias.getAliasListName()))
+ {
+ if(alias.getName() == null)
+ {
+ return true;
+ }
+ else if(alias.getName().toLowerCase().contains(mSearchText))
+ {
+ return true;
+ }
+ else if(alias.getGroup() != null && alias.getGroup().toLowerCase().contains(mSearchText))
+ {
+ return true;
+ }
+ }
+
+ return false;
}
- public void refresh()
+ public void setAliasListName(String aliasListName)
{
- final String aliasListName = getAliasListNameComboBox().getSelectionModel().getSelectedItem();
- final String filter = getSearchField().getText();
+ if(aliasListName != null)
+ {
+ mAliasListName = aliasListName;
+ }
+ }
- mAliasFilteredList.setPredicate(alias -> {
- if(filter == null || filter.isEmpty())
- {
- return alias.matchesAliasList(aliasListName);
- }
-
- String lowerFilter = filter.toLowerCase();
-
- if(alias.getName() != null && alias.getName().toLowerCase().contains(lowerFilter))
- {
- return alias.matchesAliasList(aliasListName);
- }
- else if(alias.getGroup() != null && alias.getGroup().toLowerCase().contains(lowerFilter))
- {
- return alias.matchesAliasList(aliasListName);
- }
-
- return false;
- });
+ public void setSearchText(String searchText)
+ {
+ if(searchText != null)
+ {
+ mSearchText = searchText.toLowerCase();
+ }
+ else
+ {
+ mSearchText = null;
+ }
}
}
}
diff --git a/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasItemEditor.java b/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasItemEditor.java
index 5e15e74a..84a8053a 100644
--- a/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasItemEditor.java
+++ b/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasItemEditor.java
@@ -104,7 +104,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -360,49 +359,15 @@ public class AliasItemEditor extends Editor
alias.addAliasID(selected);
}
- AliasList aliasList = mPlaylistManager.getAliasModel().getAliasList(alias.getAliasListName());
- aliasList.removeAlias(alias);
-
- //Cleanup any alias identifiers that are marked as overlapping. To do this, we remove all of the
- //affected aliases, reset all of the overlap flags, and then add the aliases back to the alias list.
- Set aliasesToReset = new HashSet<>();
- for(AliasID aliasID: alias.getAliasIdentifiers())
- {
- if(aliasID.overlapProperty().get())
- {
- aliasID.overlapProperty().set(false);
- List overlapAliases = aliasList.getOverlappingAliases(alias, aliasID);
- aliasesToReset.addAll(overlapAliases);
- }
- }
-
- //Remove overlap aliases, reset them, and readd back to the alias list
- for(Alias resetAlias: aliasesToReset)
- {
- aliasList.removeAlias(resetAlias);
- for(AliasID aliasID: resetAlias.getAliasIdentifiers())
- {
- aliasID.setOverlap(false);
- }
- }
-
//Remove and replace the remaining non-audio identifiers
alias.removeNonAudioIdentifiers();
for(AliasID aliasID: getIdentifiersList().getItems())
{
- aliasID.setOverlap(false);
//Create a copy of the identifier so that the alias and the editor don't have the same instance
alias.addAliasID(AliasFactory.copyOf(aliasID));
}
- //Add the aliases back to the alias list
- for(Alias resetAlias: aliasesToReset)
- {
- aliasList.addAlias(resetAlias);
- }
- aliasList.addAlias(alias);
-
//Remove and replace alias actions
alias.removeAllActions();
for(AliasAction aliasAction: getActionsList().getItems())
@@ -411,6 +376,9 @@ public class AliasItemEditor extends Editor
}
}
+ AliasList aliasList = mPlaylistManager.getAliasModel().getAliasList(alias.getAliasListName());
+ aliasList.updateAlias(alias);
+
//Reset the alias to refresh the editor.
setItem(alias);
diff --git a/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasViewByRecordingEditor.java b/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasViewByRecordingEditor.java
index b3cf0655..fd1dce41 100644
--- a/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasViewByRecordingEditor.java
+++ b/src/main/java/io/github/dsheirer/gui/playlist/alias/AliasViewByRecordingEditor.java
@@ -20,7 +20,6 @@
package io.github.dsheirer.gui.playlist.alias;
import io.github.dsheirer.alias.Alias;
-import io.github.dsheirer.alias.AliasEvent;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.playlist.PlaylistManager;
import javafx.collections.ListChangeListener;
@@ -315,7 +314,6 @@ public class AliasViewByRecordingEditor extends VBox
if(selectedAlias != null)
{
selectedAlias.setRecordable(true);
- mPlaylistManager.getAliasModel().broadcast(new AliasEvent(selectedAlias, AliasEvent.Event.CHANGE));
updateListFilters();
}
});
@@ -342,7 +340,6 @@ public class AliasViewByRecordingEditor extends VBox
for(Alias selectedAlias: selectedAliases)
{
selectedAlias.setRecordable(true);
- mPlaylistManager.getAliasModel().broadcast(new AliasEvent(selectedAlias, AliasEvent.Event.CHANGE));
}
updateListFilters();
@@ -368,7 +365,6 @@ public class AliasViewByRecordingEditor extends VBox
if(selectedAlias != null)
{
selectedAlias.setRecordable(false);
- mPlaylistManager.getAliasModel().broadcast(new AliasEvent(selectedAlias, AliasEvent.Event.CHANGE));
updateListFilters();
}
});
@@ -395,7 +391,6 @@ public class AliasViewByRecordingEditor extends VBox
for(Alias selectedAlias: selectedAliases)
{
selectedAlias.setRecordable(false);
- mPlaylistManager.getAliasModel().broadcast(new AliasEvent(selectedAlias, AliasEvent.Event.CHANGE));
}
updateListFilters();
diff --git a/src/main/java/io/github/dsheirer/gui/playlist/streaming/StreamAliasSelectionEditor.java b/src/main/java/io/github/dsheirer/gui/playlist/streaming/StreamAliasSelectionEditor.java
index d2865d7c..54838849 100644
--- a/src/main/java/io/github/dsheirer/gui/playlist/streaming/StreamAliasSelectionEditor.java
+++ b/src/main/java/io/github/dsheirer/gui/playlist/streaming/StreamAliasSelectionEditor.java
@@ -23,7 +23,6 @@
package io.github.dsheirer.gui.playlist.streaming;
import io.github.dsheirer.alias.Alias;
-import io.github.dsheirer.alias.AliasEvent;
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
import io.github.dsheirer.playlist.PlaylistManager;
@@ -312,7 +311,6 @@ public class StreamAliasSelectionEditor extends VBox
if(selectedAlias != null && stream != null)
{
selectedAlias.addAliasID(new BroadcastChannel(stream));
- mPlaylistManager.getAliasModel().broadcast(new AliasEvent(selectedAlias, AliasEvent.Event.CHANGE));
updateListFilters();
}
});
@@ -344,7 +342,6 @@ public class StreamAliasSelectionEditor extends VBox
for(Alias selectedAlias: selectedAliases)
{
selectedAlias.addAliasID(new BroadcastChannel(stream));
- mPlaylistManager.getAliasModel().broadcast(new AliasEvent(selectedAlias, AliasEvent.Event.CHANGE));
}
updateListFilters();
@@ -372,7 +369,6 @@ public class StreamAliasSelectionEditor extends VBox
if(selectedAlias != null && stream != null)
{
selectedAlias.removeBroadcastChannel(stream);
- mPlaylistManager.getAliasModel().broadcast(new AliasEvent(selectedAlias, AliasEvent.Event.CHANGE));
updateListFilters();
}
});
@@ -400,7 +396,6 @@ public class StreamAliasSelectionEditor extends VBox
for(Alias selectedAlias: selectedAliases)
{
selectedAlias.removeBroadcastChannel(stream);
- mPlaylistManager.getAliasModel().broadcast(new AliasEvent(selectedAlias, AliasEvent.Event.CHANGE));
}
updateListFilters();
diff --git a/src/main/java/io/github/dsheirer/playlist/PlaylistManager.java b/src/main/java/io/github/dsheirer/playlist/PlaylistManager.java
index 65e58d29..77edd599 100644
--- a/src/main/java/io/github/dsheirer/playlist/PlaylistManager.java
+++ b/src/main/java/io/github/dsheirer/playlist/PlaylistManager.java
@@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.JacksonXmlModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.audio.broadcast.BroadcastModel;
import io.github.dsheirer.controller.channel.Channel.ChannelType;
@@ -41,6 +42,7 @@ import io.github.dsheirer.service.radioreference.RadioReference;
import io.github.dsheirer.source.SourceManager;
import io.github.dsheirer.source.tuner.TunerModel;
import io.github.dsheirer.util.ThreadPool;
+import javafx.collections.ListChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -108,10 +110,7 @@ public class PlaylistManager implements Listener
//save the playlist when there are any changes
mChannelModel.addListener(this);
- mAliasModel.addListener(t -> {
- //Save the playlist for all alias events
- schedulePlaylistSave();
- });
+ mAliasModel.aliasList().addListener((ListChangeListener)c -> schedulePlaylistSave());
mChannelMapModel.addListener(t -> {
//Save the playlist for all channel map events